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",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"log",
|
||||||
"log4rs",
|
"log4rs",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
||||||
|
|
@ -19,3 +19,4 @@ tracing = "0.1.41"
|
||||||
tracing-subscriber = "0.3.20"
|
tracing-subscriber = "0.3.20"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
tower-livereload = "0.9.6"
|
tower-livereload = "0.9.6"
|
||||||
|
log = "0.4.28"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::value::Value;
|
||||||
use crate::vm::{
|
use crate::vm::{
|
||||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY,
|
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_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 {
|
pub struct Chunk {
|
||||||
|
|
@ -73,6 +73,8 @@ impl Chunk {
|
||||||
OP_EQUAL => self.simple_inst("EQ", offset),
|
OP_EQUAL => self.simple_inst("EQ", offset),
|
||||||
OP_PRINT => self.simple_inst("PRT", offset),
|
OP_PRINT => self.simple_inst("PRT", offset),
|
||||||
OP_POP => self.simple_inst("POP", 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");
|
println!("Unknown instruction");
|
||||||
offset + 1
|
offset + 1
|
||||||
|
|
|
||||||
157
src/compiler.rs
157
src/compiler.rs
|
|
@ -2,7 +2,11 @@ use crate::chunk::Chunk;
|
||||||
use crate::scanner::scan;
|
use crate::scanner::scan;
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use crate::value::Value;
|
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 anyhow::anyhow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
@ -13,6 +17,7 @@ pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
||||||
debug!("Scanned tokens: {:?}", tokens);
|
debug!("Scanned tokens: {:?}", tokens);
|
||||||
|
|
||||||
let mut compiler = Compiler {
|
let mut compiler = Compiler {
|
||||||
|
source: source.lines().map(|s| s.to_string()).collect(),
|
||||||
chunk: Chunk::new("main"),
|
chunk: Chunk::new("main"),
|
||||||
previous_token: &tokens[0],
|
previous_token: &tokens[0],
|
||||||
current_token: &tokens[0],
|
current_token: &tokens[0],
|
||||||
|
|
@ -25,6 +30,7 @@ pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Compiler<'a> {
|
struct Compiler<'a> {
|
||||||
|
source: Vec<String>,
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
tokens: &'a Vec<Token>,
|
tokens: &'a Vec<Token>,
|
||||||
current: usize,
|
current: usize,
|
||||||
|
|
@ -36,8 +42,6 @@ struct Compiler<'a> {
|
||||||
|
|
||||||
impl<'a> Compiler<'a> {
|
impl<'a> Compiler<'a> {
|
||||||
fn compile(mut self) -> anyhow::Result<Chunk> {
|
fn compile(mut self) -> anyhow::Result<Chunk> {
|
||||||
|
|
||||||
|
|
||||||
while !self.match_token(TokenType::Eof) {
|
while !self.match_token(TokenType::Eof) {
|
||||||
self.declaration()?;
|
self.declaration()?;
|
||||||
}
|
}
|
||||||
|
|
@ -50,8 +54,42 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declaration(&mut self) -> anyhow::Result<()> {
|
fn declaration(&mut self) -> anyhow::Result<()> {
|
||||||
|
if self.match_token(TokenType::Let) {
|
||||||
|
self.let_declaration()
|
||||||
|
} else {
|
||||||
self.statement()
|
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<()> {
|
fn statement(&mut self) -> anyhow::Result<()> {
|
||||||
if self.match_token(TokenType::Print) {
|
if self.match_token(TokenType::Print) {
|
||||||
|
|
@ -62,6 +100,7 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression_statement(&mut self) -> anyhow::Result<()> {
|
fn expression_statement(&mut self) -> anyhow::Result<()> {
|
||||||
|
debug!("expression statement");
|
||||||
self.expression()?;
|
self.expression()?;
|
||||||
self.emit_byte(OP_POP);
|
self.emit_byte(OP_POP);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -69,7 +108,7 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
fn print_statement(&mut self) -> anyhow::Result<()> {
|
fn print_statement(&mut self) -> anyhow::Result<()> {
|
||||||
self.expression()?;
|
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);
|
self.emit_byte(OP_PRINT);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +136,12 @@ impl<'a> Compiler<'a> {
|
||||||
if token_type == self.current_token.token_type {
|
if token_type == self.current_token.token_type {
|
||||||
self.advance()
|
self.advance()
|
||||||
} else {
|
} 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<()> {
|
fn expression(&mut self) -> anyhow::Result<()> {
|
||||||
self.parse_precedence(PREC_ASSIGNMENT)?;
|
self.parse_precedence(PREC_ASSIGNMENT)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,14 +227,19 @@ fn number(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
|
|
||||||
fn literal(s: &mut Compiler) -> anyhow::Result<()> {
|
fn literal(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
match s.previous_token.token_type {
|
match s.previous_token.token_type {
|
||||||
TokenType::False => s.emit_byte(OP_FALSE),
|
TokenType::False => s.emit_constant(Value::Bool(false)),
|
||||||
TokenType::True => s.emit_byte(OP_TRUE),
|
TokenType::True => s.emit_constant(Value::Bool(true)),
|
||||||
TokenType::String => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
TokenType::String => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn skip(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
|
// s.advance()
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn grouping(s: &mut Compiler) -> anyhow::Result<()> {
|
fn grouping(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
s.expression()?;
|
s.expression()?;
|
||||||
s.consume(TokenType::RightParen, "Expect ')' after expression.")
|
s.consume(TokenType::RightParen, "Expect ')' after expression.")
|
||||||
|
|
@ -237,6 +287,12 @@ fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
Ok(())
|
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 {
|
fn get_rule(operator_type: &TokenType) -> &'static Rule {
|
||||||
debug!("{:?}", operator_type);
|
debug!("{:?}", operator_type);
|
||||||
RULES.get(operator_type).unwrap()
|
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(|| {
|
static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
let mut rules: HashMap<TokenType, Rule> = HashMap::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::Bang, Rule::new(Some(unary), None, PREC_UNARY));
|
||||||
rules.insert(TokenType::BangEqual, Rule::new(None, None, PREC_EQUALITY));
|
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::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(
|
rules.insert(
|
||||||
TokenType::EqualEqual,
|
TokenType::EqualEqual,
|
||||||
Rule::new(None, Some(binary), PREC_EQUALITY),
|
Rule::new(None, Some(binary), PREC_EQUALITY),
|
||||||
);
|
);
|
||||||
|
rules.insert(TokenType::False, Rule::new(Some(literal), None, PREC_NONE));
|
||||||
rules.insert(
|
rules.insert(
|
||||||
TokenType::Greater,
|
TokenType::Greater,
|
||||||
Rule::new(None, Some(binary), PREC_COMPARISON),
|
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||||
|
|
@ -282,6 +334,19 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
TokenType::GreaterGreater,
|
TokenType::GreaterGreater,
|
||||||
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
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(
|
rules.insert(
|
||||||
TokenType::Less,
|
TokenType::Less,
|
||||||
Rule::new(None, Some(binary), PREC_COMPARISON),
|
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||||
|
|
@ -294,41 +359,35 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
TokenType::LessLess,
|
TokenType::LessLess,
|
||||||
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
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(
|
rules.insert(
|
||||||
TokenType::LogicalAnd,
|
TokenType::LogicalAnd,
|
||||||
Rule::new(None, Some(binary), PREC_AND),
|
Rule::new(None, Some(binary), PREC_AND),
|
||||||
);
|
);
|
||||||
rules.insert(TokenType::LogicalOr, Rule::new(None, Some(binary), PREC_OR));
|
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(
|
rules.insert(
|
||||||
TokenType::BitAnd,
|
TokenType::BitAnd,
|
||||||
Rule::new(None, Some(binary), PREC_BITAND),
|
Rule::new(None, Some(binary), PREC_BITAND),
|
||||||
);
|
);
|
||||||
rules.insert(TokenType::BitOr, Rule::new(None, Some(binary), PREC_BITOR));
|
rules.insert(TokenType::StringType, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(
|
|
||||||
TokenType::BitXor,
|
|
||||||
Rule::new(None, Some(binary), PREC_BITXOR),
|
|
||||||
);
|
|
||||||
rules.insert(TokenType::Fn, Rule::new(None, None, PREC_NONE));
|
|
||||||
rules.insert(TokenType::Struct, 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::True, Rule::new(Some(literal), 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::U32Type, Rule::new(None, 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::U64Type, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::I32Type, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::While, 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
|
rules
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,28 @@ use crate::tokens::TokenType;
|
||||||
|
|
||||||
pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
||||||
match lexeme {
|
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),
|
"and" => Some(TokenType::LogicalAnd),
|
||||||
|
"bool" => Some(TokenType::BoolType),
|
||||||
|
"char" => Some(TokenType::CharType),
|
||||||
|
"date" => Some(TokenType::DateType),
|
||||||
"else" => Some(TokenType::Else),
|
"else" => Some(TokenType::Else),
|
||||||
"false" => Some(TokenType::False),
|
"false" => Some(TokenType::False),
|
||||||
"true" => Some(TokenType::True),
|
"fn" => Some(TokenType::Fn),
|
||||||
"for" => Some(TokenType::For),
|
"for" => Some(TokenType::For),
|
||||||
"if" => Some(TokenType::If),
|
"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),
|
"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),
|
"while" => Some(TokenType::While),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
21
src/main.rs
21
src/main.rs
|
|
@ -1,12 +1,23 @@
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let chunk = crudlang::compiler::compile("\"hello \" + 42")?;
|
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();
|
chunk.disassemble();
|
||||||
|
|
||||||
let result = crudlang::vm::interpret(chunk);
|
let result = crudlang::vm::interpret(chunk)?;
|
||||||
println!("{:?}", result);
|
println!("{}", result);
|
||||||
Ok(())
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ impl Scanner {
|
||||||
self.start = self.current;
|
self.start = self.current;
|
||||||
self.scan_token();
|
self.scan_token();
|
||||||
}
|
}
|
||||||
|
self.add_token(TokenType::Eol);
|
||||||
self.add_token(TokenType::Eof);
|
self.add_token(TokenType::Eof);
|
||||||
self.tokens
|
self.tokens
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +104,7 @@ impl Scanner {
|
||||||
'\n' => {
|
'\n' => {
|
||||||
self.line += 1;
|
self.line += 1;
|
||||||
self.new_line = true;
|
self.new_line = true;
|
||||||
|
self.add_token(TokenType::Eol);
|
||||||
}
|
}
|
||||||
'&' => {
|
'&' => {
|
||||||
let t = if self.match_next('&') {
|
let t = if self.match_next('&') {
|
||||||
|
|
|
||||||
|
|
@ -22,60 +22,66 @@ enum Value {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, Clone, Copy, Hash)]
|
||||||
pub(crate) enum TokenType {
|
pub(crate) enum TokenType {
|
||||||
Error,
|
|
||||||
LeftParen,
|
|
||||||
RightParen,
|
|
||||||
LeftBrace,
|
|
||||||
RightBrace,
|
|
||||||
LeftBracket,
|
|
||||||
RightBracket,
|
|
||||||
Colon,
|
|
||||||
Semicolon,
|
|
||||||
Comma,
|
|
||||||
Dot,
|
|
||||||
Star,
|
|
||||||
Slash,
|
|
||||||
Plus,
|
|
||||||
Minus,
|
|
||||||
Not,
|
|
||||||
Hash,
|
|
||||||
Bang,
|
Bang,
|
||||||
BangEqual,
|
BangEqual,
|
||||||
EqualEqual,
|
|
||||||
Equal,
|
|
||||||
Greater,
|
|
||||||
Less,
|
|
||||||
GreaterEqual,
|
|
||||||
GreaterGreater,
|
|
||||||
LessLess,
|
|
||||||
LessEqual,
|
|
||||||
Indent,
|
|
||||||
Identifier,
|
|
||||||
String,
|
|
||||||
Number,
|
|
||||||
LogicalAnd,
|
|
||||||
LogicalOr,
|
|
||||||
BitAnd,
|
BitAnd,
|
||||||
BitOr,
|
BitOr,
|
||||||
BitXor,
|
BitXor,
|
||||||
Fn,
|
BoolType,
|
||||||
Struct,
|
CharType,
|
||||||
|
Colon,
|
||||||
|
Comma,
|
||||||
|
DateType,
|
||||||
|
Dot,
|
||||||
Else,
|
Else,
|
||||||
False,
|
|
||||||
True,
|
|
||||||
Null,
|
|
||||||
If,
|
|
||||||
While,
|
|
||||||
For,
|
|
||||||
Return,
|
|
||||||
Print,
|
|
||||||
Eof,
|
Eof,
|
||||||
U32Type,
|
Eol,
|
||||||
U64Type,
|
Equal,
|
||||||
|
EqualEqual,
|
||||||
|
Error,
|
||||||
|
False,
|
||||||
|
Fn,
|
||||||
|
For,
|
||||||
|
Greater,
|
||||||
|
GreaterEqual,
|
||||||
|
GreaterGreater,
|
||||||
|
Hash,
|
||||||
I32Type,
|
I32Type,
|
||||||
I64Type,
|
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,
|
StringType,
|
||||||
|
Struct,
|
||||||
|
True,
|
||||||
|
U32Type,
|
||||||
|
U64Type,
|
||||||
|
While,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for TokenType {
|
impl Eq for TokenType {
|
||||||
|
|
|
||||||
49
src/vm.rs
49
src/vm.rs
|
|
@ -1,13 +1,15 @@
|
||||||
use crate::chunk::Chunk;
|
use crate::chunk::Chunk;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use std::collections::HashMap;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn interpret(chunk: Chunk) -> Result {
|
pub fn interpret(chunk: Chunk) -> anyhow::Result<Value> {
|
||||||
let mut vm = Vm {
|
let mut vm = Vm {
|
||||||
chunk,
|
chunk,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
|
local_vars: HashMap::new(),
|
||||||
};
|
};
|
||||||
vm.run()
|
vm.run()
|
||||||
}
|
}
|
||||||
|
|
@ -16,26 +18,21 @@ pub struct Vm {
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
stack: Vec<Value>,
|
stack: Vec<Value>,
|
||||||
|
local_vars: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
fn run(&mut self) -> Result {
|
fn run(&mut self) -> anyhow::Result<Value> {
|
||||||
loop {
|
loop {
|
||||||
debug!("[");
|
debug!("{:?}", self.stack);
|
||||||
for value in self.stack.iter() {
|
|
||||||
debug!("{:?} ", value);
|
|
||||||
}
|
|
||||||
debug!("]");
|
|
||||||
let opcode = self.chunk.code[self.ip];
|
let opcode = self.chunk.code[self.ip];
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
match opcode {
|
match opcode {
|
||||||
OP_CONSTANT => {
|
OP_CONSTANT | OP_FALSE | OP_TRUE => {
|
||||||
let value = &self.chunk.constants[self.chunk.code[self.ip] as usize];
|
let value = &self.chunk.constants[self.chunk.code[self.ip] as usize];
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
self.push(value.clone());
|
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_ADD => binary_op(self, |a, b| a + b),
|
||||||
OP_SUBTRACT => 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),
|
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_BITXOR => binary_op(self, |a, b| a ^ b),
|
||||||
OP_NEGATE => unary_op(self, |a| -a),
|
OP_NEGATE => unary_op(self, |a| -a),
|
||||||
OP_RETURN => {
|
OP_RETURN => {
|
||||||
|
debug!("return {:?}", self.stack);
|
||||||
return if self.stack.is_empty() {
|
return if self.stack.is_empty() {
|
||||||
Result::Ok(Value::Void)
|
Ok(Value::Void)
|
||||||
} else {
|
} else {
|
||||||
return Result::Ok(self.pop());
|
Ok(self.pop())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
OP_SHL => binary_op(self, |a, b| a << b),
|
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 => binary_op(self, |a, b| Ok(Value::Bool(a < b))),
|
||||||
OP_LESS_EQUAL => 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 => {
|
OP_PRINT => {
|
||||||
|
debug!("print {:?}", self.stack);
|
||||||
let v = self.pop();
|
let v = self.pop();
|
||||||
println!("{}", v);
|
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) {
|
fn reset_stack(&mut self) {
|
||||||
self.stack.clear();
|
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_CONSTANT: u16 = 1;
|
||||||
pub const OP_ADD: u16 = 2;
|
pub const OP_ADD: u16 = 2;
|
||||||
pub const OP_SUBTRACT: u16 = 3;
|
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_SHR: u16 = 23;
|
||||||
pub const OP_SHL: u16 = 24;
|
pub const OP_SHL: u16 = 24;
|
||||||
pub const OP_POP: u16 = 25;
|
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