variable declarations
This commit is contained in:
parent
6dd22f5e4e
commit
1d58725559
9 changed files with 231 additions and 129 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -199,6 +199,7 @@ dependencies = [
|
|||
"axum",
|
||||
"chrono",
|
||||
"dotenv",
|
||||
"log",
|
||||
"log4rs",
|
||||
"reqwest",
|
||||
"serde",
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@ tracing = "0.1.41"
|
|||
tracing-subscriber = "0.3.20"
|
||||
anyhow = "1.0"
|
||||
tower-livereload = "0.9.6"
|
||||
log = "0.4.28"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::value::Value;
|
|||
use crate::vm::{
|
||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY,
|
||||
OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE, OP_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL,
|
||||
OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP,
|
||||
OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP, OP_DEFINE, OP_GET
|
||||
};
|
||||
|
||||
pub struct Chunk {
|
||||
|
|
@ -73,6 +73,8 @@ impl Chunk {
|
|||
OP_EQUAL => self.simple_inst("EQ", offset),
|
||||
OP_PRINT => self.simple_inst("PRT", offset),
|
||||
OP_POP => self.simple_inst("POP", offset),
|
||||
OP_DEFINE => self.constant_inst("DEF", offset),
|
||||
OP_GET => self.constant_inst("GET", offset),
|
||||
_ => {
|
||||
println!("Unknown instruction");
|
||||
offset + 1
|
||||
|
|
|
|||
163
src/compiler.rs
163
src/compiler.rs
|
|
@ -2,7 +2,11 @@ use crate::chunk::Chunk;
|
|||
use crate::scanner::scan;
|
||||
use crate::tokens::{Token, TokenType};
|
||||
use crate::value::Value;
|
||||
use crate::vm::{OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_EQUAL, OP_FALSE, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_TRUE};
|
||||
use crate::vm::{
|
||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_FALSE,
|
||||
OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT,
|
||||
OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_TRUE,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::LazyLock;
|
||||
|
|
@ -13,6 +17,7 @@ pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
|||
debug!("Scanned tokens: {:?}", tokens);
|
||||
|
||||
let mut compiler = Compiler {
|
||||
source: source.lines().map(|s| s.to_string()).collect(),
|
||||
chunk: Chunk::new("main"),
|
||||
previous_token: &tokens[0],
|
||||
current_token: &tokens[0],
|
||||
|
|
@ -25,6 +30,7 @@ pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
|||
}
|
||||
|
||||
struct Compiler<'a> {
|
||||
source: Vec<String>,
|
||||
chunk: Chunk,
|
||||
tokens: &'a Vec<Token>,
|
||||
current: usize,
|
||||
|
|
@ -36,8 +42,6 @@ struct Compiler<'a> {
|
|||
|
||||
impl<'a> Compiler<'a> {
|
||||
fn compile(mut self) -> anyhow::Result<Chunk> {
|
||||
|
||||
|
||||
while !self.match_token(TokenType::Eof) {
|
||||
self.declaration()?;
|
||||
}
|
||||
|
|
@ -50,7 +54,41 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
|
||||
fn declaration(&mut self) -> anyhow::Result<()> {
|
||||
self.statement()
|
||||
if self.match_token(TokenType::Let) {
|
||||
self.let_declaration()
|
||||
} else {
|
||||
self.statement()
|
||||
}
|
||||
}
|
||||
|
||||
fn let_declaration(&mut self) -> anyhow::Result<()> {
|
||||
let index = self.parse_variable("Expect variable name")?;
|
||||
if self.match_token(TokenType::Equal) {
|
||||
self.expression()?;
|
||||
self.consume(TokenType::Eol, "Expect end of line")?;
|
||||
self.define_variable(index)?;
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
"You cannot declare a variable without initializing it."
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_variable(&mut self, message: &str) -> anyhow::Result<usize> {
|
||||
self.consume(TokenType::Identifier, message)?;
|
||||
self.identifier_constant(self.previous_token)
|
||||
}
|
||||
|
||||
fn identifier_constant(&mut self, token: &Token) -> anyhow::Result<usize> {
|
||||
let name = token.lexeme.clone();
|
||||
let index = self.chunk.add_constant(Value::String(name));
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
fn define_variable(&mut self, index: usize) -> anyhow::Result<()> {
|
||||
self.emit_bytes(OP_DEFINE, index as u16);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn statement(&mut self) -> anyhow::Result<()> {
|
||||
|
|
@ -61,7 +99,8 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn expression_statement(&mut self) -> anyhow::Result<()>{
|
||||
fn expression_statement(&mut self) -> anyhow::Result<()> {
|
||||
debug!("expression statement");
|
||||
self.expression()?;
|
||||
self.emit_byte(OP_POP);
|
||||
Ok(())
|
||||
|
|
@ -69,7 +108,7 @@ impl<'a> Compiler<'a> {
|
|||
|
||||
fn print_statement(&mut self) -> anyhow::Result<()> {
|
||||
self.expression()?;
|
||||
// self.consume(TokenType::Semicolon, "Expect ';' after value.")?;
|
||||
self.consume(TokenType::Eol, "No further expressions expected. Please continue on a new line after the first.\n")?;
|
||||
self.emit_byte(OP_PRINT);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -97,7 +136,12 @@ impl<'a> Compiler<'a> {
|
|||
if token_type == self.current_token.token_type {
|
||||
self.advance()
|
||||
} else {
|
||||
Err(anyhow!("{}", message))
|
||||
Err(anyhow!(
|
||||
r#"{} at line {}: "{}""#,
|
||||
message,
|
||||
self.current_token.line + 1,
|
||||
self.source[self.current_token.line]
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +160,7 @@ impl<'a> Compiler<'a> {
|
|||
|
||||
fn expression(&mut self) -> anyhow::Result<()> {
|
||||
self.parse_precedence(PREC_ASSIGNMENT)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +178,7 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow!("Expect expression."));
|
||||
return Err(anyhow!("Expect expression."));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -182,14 +227,19 @@ fn number(s: &mut Compiler) -> anyhow::Result<()> {
|
|||
|
||||
fn literal(s: &mut Compiler) -> anyhow::Result<()> {
|
||||
match s.previous_token.token_type {
|
||||
TokenType::False => s.emit_byte(OP_FALSE),
|
||||
TokenType::True => s.emit_byte(OP_TRUE),
|
||||
TokenType::False => s.emit_constant(Value::Bool(false)),
|
||||
TokenType::True => s.emit_constant(Value::Bool(true)),
|
||||
TokenType::String => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn skip(s: &mut Compiler) -> anyhow::Result<()> {
|
||||
// s.advance()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn grouping(s: &mut Compiler) -> anyhow::Result<()> {
|
||||
s.expression()?;
|
||||
s.consume(TokenType::RightParen, "Expect ')' after expression.")
|
||||
|
|
@ -237,6 +287,12 @@ fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn variable(s: &mut Compiler) -> anyhow::Result<()> {
|
||||
let index = s.identifier_constant(s.previous_token)?;
|
||||
s.emit_bytes(OP_GET, index as u16);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_rule(operator_type: &TokenType) -> &'static Rule {
|
||||
debug!("{:?}", operator_type);
|
||||
RULES.get(operator_type).unwrap()
|
||||
|
|
@ -244,32 +300,28 @@ fn get_rule(operator_type: &TokenType) -> &'static Rule {
|
|||
|
||||
static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||
let mut rules: HashMap<TokenType, Rule> = HashMap::new();
|
||||
rules.insert(
|
||||
TokenType::LeftParen,
|
||||
Rule::new(Some(binary), None, PREC_NONE),
|
||||
);
|
||||
rules.insert(TokenType::RightParen, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::LeftBrace, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::RightBrace, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::LeftBracket, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::RightBracket, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Comma, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Dot, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::Minus,
|
||||
Rule::new(Some(unary), Some(binary), PREC_TERM),
|
||||
);
|
||||
rules.insert(TokenType::Plus, Rule::new(None, Some(binary), PREC_TERM));
|
||||
rules.insert(TokenType::Colon, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Slash, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||
rules.insert(TokenType::Star, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||
rules.insert(TokenType::Bang, Rule::new(Some(unary), None, PREC_UNARY));
|
||||
rules.insert(TokenType::BangEqual, Rule::new(None, None, PREC_EQUALITY));
|
||||
rules.insert(TokenType::BitOr, Rule::new(None, Some(binary), PREC_BITOR));
|
||||
rules.insert(
|
||||
TokenType::BitXor,
|
||||
Rule::new(None, Some(binary), PREC_BITXOR),
|
||||
);
|
||||
rules.insert(TokenType::Colon, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Comma, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::DateType, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Dot, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Else, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Eof, Rule::new(Some(skip), None, PREC_NONE));
|
||||
rules.insert(TokenType::Eol, Rule::new(Some(skip), None, PREC_NONE));
|
||||
rules.insert(TokenType::Equal, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::False, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Fn, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::EqualEqual,
|
||||
Rule::new(None, Some(binary), PREC_EQUALITY),
|
||||
);
|
||||
rules.insert(TokenType::False, Rule::new(Some(literal), None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::Greater,
|
||||
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||
|
|
@ -282,6 +334,19 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
|||
TokenType::GreaterGreater,
|
||||
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
||||
);
|
||||
rules.insert(TokenType::I32Type, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::I64Type, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::Identifier,
|
||||
Rule::new(Some(variable), None, PREC_NONE),
|
||||
);
|
||||
rules.insert(TokenType::Indent, Rule::new(Some(skip), None, PREC_NONE));
|
||||
rules.insert(TokenType::LeftBrace, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::LeftBracket, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::LeftParen,
|
||||
Rule::new(Some(binary), None, PREC_NONE),
|
||||
);
|
||||
rules.insert(
|
||||
TokenType::Less,
|
||||
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||
|
|
@ -294,41 +359,35 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
|||
TokenType::LessLess,
|
||||
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
||||
);
|
||||
rules.insert(TokenType::Identifier, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::String, Rule::new(Some(literal), None, PREC_NONE));
|
||||
rules.insert(TokenType::Number, Rule::new(Some(number), None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::LogicalAnd,
|
||||
Rule::new(None, Some(binary), PREC_AND),
|
||||
);
|
||||
rules.insert(TokenType::LogicalOr, Rule::new(None, Some(binary), PREC_OR));
|
||||
rules.insert(
|
||||
TokenType::Minus,
|
||||
Rule::new(Some(unary), Some(binary), PREC_TERM),
|
||||
);
|
||||
rules.insert(TokenType::Number, Rule::new(Some(number), None, PREC_NONE));
|
||||
rules.insert(TokenType::Plus, Rule::new(None, Some(binary), PREC_TERM));
|
||||
rules.insert(TokenType::Print, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Return, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::RightParen, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::RightBrace, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::RightBracket, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Slash, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||
rules.insert(TokenType::Star, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||
rules.insert(TokenType::String, Rule::new(Some(literal), None, PREC_NONE));
|
||||
rules.insert(
|
||||
TokenType::BitAnd,
|
||||
Rule::new(None, Some(binary), PREC_BITAND),
|
||||
);
|
||||
rules.insert(TokenType::BitOr, Rule::new(None, Some(binary), PREC_BITOR));
|
||||
rules.insert(
|
||||
TokenType::BitXor,
|
||||
Rule::new(None, Some(binary), PREC_BITXOR),
|
||||
);
|
||||
rules.insert(TokenType::Fn, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::StringType, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Struct, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Else, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::False, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::True, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::While, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Print, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Return, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::Eof, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::True, Rule::new(Some(literal), None, PREC_NONE));
|
||||
rules.insert(TokenType::U32Type, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::U64Type, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::I32Type, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::I64Type, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::DateType, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::StringType, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::False, Rule::new(Some(literal), None, PREC_NONE));
|
||||
rules.insert(TokenType::True, Rule::new(Some(literal), None, PREC_NONE));
|
||||
rules.insert(TokenType::Indent, Rule::new(None, None, PREC_NONE));
|
||||
rules.insert(TokenType::While, Rule::new(None, None, PREC_NONE));
|
||||
|
||||
rules
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,19 +2,28 @@ use crate::tokens::TokenType;
|
|||
|
||||
pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
||||
match lexeme {
|
||||
"fn" => Some(TokenType::Fn),
|
||||
"struct" => Some(TokenType::Struct),
|
||||
"u32" => Some(TokenType::U32Type),
|
||||
"string" => Some(TokenType::StringType),
|
||||
"date" => Some(TokenType::DateType),
|
||||
"print" => Some(TokenType::Print),
|
||||
"and" => Some(TokenType::LogicalAnd),
|
||||
"bool" => Some(TokenType::BoolType),
|
||||
"char" => Some(TokenType::CharType),
|
||||
"date" => Some(TokenType::DateType),
|
||||
"else" => Some(TokenType::Else),
|
||||
"false" => Some(TokenType::False),
|
||||
"true" => Some(TokenType::True),
|
||||
"fn" => Some(TokenType::Fn),
|
||||
"for" => Some(TokenType::For),
|
||||
"if" => Some(TokenType::If),
|
||||
"i32" => Some(TokenType::I32Type),
|
||||
"i64" => Some(TokenType::I64Type),
|
||||
"let" => Some(TokenType::Let),
|
||||
"list" => Some(TokenType::ListType),
|
||||
"map" => Some(TokenType::MapType),
|
||||
"or" => Some(TokenType::LogicalOr),
|
||||
"object" => Some(TokenType::ObjectType),
|
||||
"print" => Some(TokenType::Print),
|
||||
"struct" => Some(TokenType::Struct),
|
||||
"string" => Some(TokenType::StringType),
|
||||
"true" => Some(TokenType::True),
|
||||
"u32" => Some(TokenType::U32Type),
|
||||
"u64" => Some(TokenType::U64Type),
|
||||
"while" => Some(TokenType::While),
|
||||
|
||||
_ => None,
|
||||
|
|
|
|||
23
src/main.rs
23
src/main.rs
|
|
@ -1,12 +1,23 @@
|
|||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let chunk = crudlang::compiler::compile("\"hello \" + 42")?;
|
||||
chunk.disassemble();
|
||||
let chunk = crudlang::compiler::compile(
|
||||
r#"let a = "hello " + 42
|
||||
print a print a
|
||||
print a"#,
|
||||
);
|
||||
match chunk {
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
return Ok(());
|
||||
}
|
||||
Ok(chunk) => {
|
||||
chunk.disassemble();
|
||||
|
||||
let result = crudlang::vm::interpret(chunk)?;
|
||||
println!("{}", result);
|
||||
}
|
||||
}
|
||||
|
||||
let result = crudlang::vm::interpret(chunk);
|
||||
println!("{:?}", result);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ impl Scanner {
|
|||
self.start = self.current;
|
||||
self.scan_token();
|
||||
}
|
||||
self.add_token(TokenType::Eol);
|
||||
self.add_token(TokenType::Eof);
|
||||
self.tokens
|
||||
}
|
||||
|
|
@ -103,6 +104,7 @@ impl Scanner {
|
|||
'\n' => {
|
||||
self.line += 1;
|
||||
self.new_line = true;
|
||||
self.add_token(TokenType::Eol);
|
||||
}
|
||||
'&' => {
|
||||
let t = if self.match_next('&') {
|
||||
|
|
|
|||
|
|
@ -22,60 +22,66 @@ enum Value {
|
|||
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Hash)]
|
||||
pub(crate) enum TokenType {
|
||||
Error,
|
||||
LeftParen,
|
||||
RightParen,
|
||||
LeftBrace,
|
||||
RightBrace,
|
||||
LeftBracket,
|
||||
RightBracket,
|
||||
Colon,
|
||||
Semicolon,
|
||||
Comma,
|
||||
Dot,
|
||||
Star,
|
||||
Slash,
|
||||
Plus,
|
||||
Minus,
|
||||
Not,
|
||||
Hash,
|
||||
Bang,
|
||||
BangEqual,
|
||||
EqualEqual,
|
||||
Equal,
|
||||
Greater,
|
||||
Less,
|
||||
GreaterEqual,
|
||||
GreaterGreater,
|
||||
LessLess,
|
||||
LessEqual,
|
||||
Indent,
|
||||
Identifier,
|
||||
String,
|
||||
Number,
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
Fn,
|
||||
Struct,
|
||||
BoolType,
|
||||
CharType,
|
||||
Colon,
|
||||
Comma,
|
||||
DateType,
|
||||
Dot,
|
||||
Else,
|
||||
False,
|
||||
True,
|
||||
Null,
|
||||
If,
|
||||
While,
|
||||
For,
|
||||
Return,
|
||||
Print,
|
||||
Eof,
|
||||
U32Type,
|
||||
U64Type,
|
||||
Eol,
|
||||
Equal,
|
||||
EqualEqual,
|
||||
Error,
|
||||
False,
|
||||
Fn,
|
||||
For,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
GreaterGreater,
|
||||
Hash,
|
||||
I32Type,
|
||||
I64Type,
|
||||
DateType,
|
||||
If,
|
||||
Indent,
|
||||
Identifier,
|
||||
LeftBrace,
|
||||
LeftBracket,
|
||||
LeftParen,
|
||||
Less,
|
||||
LessEqual,
|
||||
LessLess,
|
||||
Let,
|
||||
ListType,
|
||||
MapType,
|
||||
LogicalAnd,
|
||||
LogicalOr,
|
||||
Minus,
|
||||
Not,
|
||||
Number,
|
||||
ObjectType,
|
||||
Plus,
|
||||
Print,
|
||||
Return,
|
||||
RightParen,
|
||||
RightBrace,
|
||||
RightBracket,
|
||||
Semicolon,
|
||||
Slash,
|
||||
Star,
|
||||
String,
|
||||
StringType,
|
||||
Struct,
|
||||
True,
|
||||
U32Type,
|
||||
U64Type,
|
||||
While,
|
||||
}
|
||||
|
||||
impl Eq for TokenType {
|
||||
|
|
|
|||
49
src/vm.rs
49
src/vm.rs
|
|
@ -1,13 +1,15 @@
|
|||
use crate::chunk::Chunk;
|
||||
use crate::value::Value;
|
||||
use anyhow::anyhow;
|
||||
use std::collections::HashMap;
|
||||
use tracing::debug;
|
||||
|
||||
pub fn interpret(chunk: Chunk) -> Result {
|
||||
pub fn interpret(chunk: Chunk) -> anyhow::Result<Value> {
|
||||
let mut vm = Vm {
|
||||
chunk,
|
||||
ip: 0,
|
||||
stack: vec![],
|
||||
local_vars: HashMap::new(),
|
||||
};
|
||||
vm.run()
|
||||
}
|
||||
|
|
@ -16,26 +18,21 @@ pub struct Vm {
|
|||
chunk: Chunk,
|
||||
ip: usize,
|
||||
stack: Vec<Value>,
|
||||
local_vars: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl Vm {
|
||||
fn run(&mut self) -> Result {
|
||||
fn run(&mut self) -> anyhow::Result<Value> {
|
||||
loop {
|
||||
debug!("[");
|
||||
for value in self.stack.iter() {
|
||||
debug!("{:?} ", value);
|
||||
}
|
||||
debug!("]");
|
||||
debug!("{:?}", self.stack);
|
||||
let opcode = self.chunk.code[self.ip];
|
||||
self.ip += 1;
|
||||
match opcode {
|
||||
OP_CONSTANT => {
|
||||
OP_CONSTANT | OP_FALSE | OP_TRUE => {
|
||||
let value = &self.chunk.constants[self.chunk.code[self.ip] as usize];
|
||||
self.ip += 1;
|
||||
self.push(value.clone());
|
||||
}
|
||||
OP_FALSE => self.push(Value::Bool(false)),
|
||||
OP_TRUE => self.push(Value::Bool(true)),
|
||||
OP_ADD => binary_op(self, |a, b| a + b),
|
||||
OP_SUBTRACT => binary_op(self, |a, b| a - b),
|
||||
OP_MULTIPLY => binary_op(self, |a, b| a * b),
|
||||
|
|
@ -60,10 +57,11 @@ impl Vm {
|
|||
OP_BITXOR => binary_op(self, |a, b| a ^ b),
|
||||
OP_NEGATE => unary_op(self, |a| -a),
|
||||
OP_RETURN => {
|
||||
debug!("return {:?}", self.stack);
|
||||
return if self.stack.is_empty() {
|
||||
Result::Ok(Value::Void)
|
||||
Ok(Value::Void)
|
||||
} else {
|
||||
return Result::Ok(self.pop());
|
||||
Ok(self.pop())
|
||||
};
|
||||
}
|
||||
OP_SHL => binary_op(self, |a, b| a << b),
|
||||
|
|
@ -74,14 +72,32 @@ impl Vm {
|
|||
OP_LESS => binary_op(self, |a, b| Ok(Value::Bool(a < b))),
|
||||
OP_LESS_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a <= b))),
|
||||
OP_PRINT => {
|
||||
debug!("print {:?}", self.stack);
|
||||
let v = self.pop();
|
||||
println!("{}", v);
|
||||
}
|
||||
OP_DEFINE => {
|
||||
let name = self.read_constant();
|
||||
let value = self.pop();
|
||||
self.local_vars.insert(name, value);
|
||||
}
|
||||
OP_GET => {
|
||||
let name = self.read_constant();
|
||||
let value = self.local_vars.get(&name).unwrap();
|
||||
self.push(value.clone()); // not happy
|
||||
debug!("after get {:?}", self.stack);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_constant(&mut self) -> String {
|
||||
let name = self.chunk.constants[self.chunk.code[self.ip] as usize].to_string();
|
||||
self.ip += 1;
|
||||
name
|
||||
}
|
||||
|
||||
fn reset_stack(&mut self) {
|
||||
self.stack.clear();
|
||||
}
|
||||
|
|
@ -117,13 +133,6 @@ fn unary_op(stack: &mut Vm, op: impl Fn(&Value) -> anyhow::Result<Value> + Copy)
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Result {
|
||||
Ok(Value),
|
||||
CompileError,
|
||||
Error,
|
||||
}
|
||||
|
||||
pub const OP_CONSTANT: u16 = 1;
|
||||
pub const OP_ADD: u16 = 2;
|
||||
pub const OP_SUBTRACT: u16 = 3;
|
||||
|
|
@ -149,3 +158,5 @@ pub const OP_BITXOR: u16 = 22;
|
|||
pub const OP_SHR: u16 = 23;
|
||||
pub const OP_SHL: u16 = 24;
|
||||
pub const OP_POP: u16 = 25;
|
||||
pub const OP_DEFINE: u16 = 26;
|
||||
pub const OP_GET: u16 = 27;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue