From a8850cc5472d3b93760981e8586966f57b7355ca Mon Sep 17 00:00:00 2001 From: Shautvast Date: Tue, 28 Oct 2025 07:27:16 +0100 Subject: [PATCH] implemented list literals including operations on lists experimenting with arenas --- Cargo.lock | 4 + Cargo.toml | 1 + src/ast_compiler.rs | 42 ++- src/bytecode_compiler.rs | 24 +- src/chunk.rs | 23 +- src/compiler.rs | 554 --------------------------------------- src/lib.rs | 11 +- src/main.rs | 5 +- src/value.rs | 89 ++++--- src/vm.rs | 18 +- 10 files changed, 138 insertions(+), 633 deletions(-) delete mode 100644 src/compiler.rs diff --git a/Cargo.lock b/Cargo.lock index 6485a35..480d129 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,6 +124,9 @@ name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +dependencies = [ + "serde", +] [[package]] name = "byteorder" @@ -197,6 +200,7 @@ version = "0.1.0" dependencies = [ "anyhow", "axum", + "bumpalo", "chrono", "dotenv", "log", diff --git a/Cargo.toml b/Cargo.toml index 03ba4c4..67360ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ tracing-subscriber = "0.3.20" anyhow = "1.0" tower-livereload = "0.9.6" log = "0.4.28" +bumpalo = { version = "3.19", features = ["collections", "boxed", "serde"] } diff --git a/src/ast_compiler.rs b/src/ast_compiler.rs index f19ca9a..20a255b 100644 --- a/src/ast_compiler.rs +++ b/src/ast_compiler.rs @@ -1,4 +1,4 @@ -use crate::tokens::TokenType::{Bang, Bool, Char, Colon, Date, Eol, Equal, F32, F64, False, FloatingPoint, Fn, Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print, RightParen, SingleRightArrow, Slash, Star, True, U32, U64, StringType}; +use crate::tokens::TokenType::{Bang, Bool, Char, Colon, Date, Eol, Equal, F32, F64, False, FloatingPoint, Fn, Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, If, Indent, Integer, LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print, RightParen, SingleRightArrow, Slash, Star, StringType, True, U32, U64, RightBracket}; use crate::tokens::{Token, TokenType}; use crate::value::Value; use log::debug; @@ -282,7 +282,9 @@ impl AstCompiler { fn primary(&mut self) -> anyhow::Result { debug!("primary {:?}", self.peek()); - Ok(if self.match_token(vec![False]) { + Ok(if self.match_token(vec![LeftBracket]) { + self.list()? + } else if self.match_token(vec![False]) { Expression::Literal { line: self.peek().line, literaltype: Bool, @@ -330,6 +332,22 @@ impl AstCompiler { }) } + fn list(&mut self) -> anyhow::Result { + let mut list = vec![]; + while !self.match_token(vec![RightBracket]){ + list.push(self.expression()?); + if self.peek().token_type == TokenType::Comma { + self.advance(); + } else { + self.consume(RightBracket, "Expect ']' after list.")?; + break; + } + } + Ok(Expression::List { + values: list, literaltype: ListType, line: self.peek().line}, + ) + } + fn variable_lookup(&mut self, token: &Token) -> anyhow::Result { let (var_name, var_type) = self .vars @@ -437,9 +455,11 @@ fn calculate_type( declared_type: Option, inferred_type: TokenType, ) -> anyhow::Result { - println!("declared type {:?} inferred type: {:?}", declared_type, inferred_type); + println!( + "declared type {:?} inferred type: {:?}", + declared_type, inferred_type + ); Ok(if let Some(declared_type) = declared_type { - if declared_type != inferred_type { match (declared_type, inferred_type) { (I32, I64) => I32, @@ -448,7 +468,7 @@ fn calculate_type( (F64, I64) => F64, (U64, I64) => U64, (U64, I32) => U64, - (StringType, Text) => StringType, + (StringType, _) => StringType, // meh, this all needs rigorous testing _ => { return Err(anyhow::anyhow!( "Incompatible types. Expected {}, found {}", @@ -464,7 +484,6 @@ fn calculate_type( match inferred_type { Integer | I64 => I64, FloatingPoint => F64, - Text => Text, Bool => Bool, Date => Date, ListType => ListType, @@ -532,6 +551,11 @@ pub enum Expression { literaltype: TokenType, value: Value, }, + List { + line: usize, + literaltype: TokenType, + values: Vec, + }, Variable { line: usize, name: String, @@ -550,8 +574,9 @@ impl Expression { match self { Self::Binary { line, .. } => *line, Self::Unary { line, .. } => *line, - Self::Grouping { line, expression } => *line, + Self::Grouping { line, .. } => *line, Self::Literal { line, .. } => *line, + Self::List { line, .. } => *line, Self::Variable { line, .. } => *line, Self::FunctionCall { line, .. } => *line, } @@ -615,8 +640,9 @@ impl Expression { } } } - Self::Grouping { line, expression } => expression.infer_type(), + Self::Grouping { expression,.. } => expression.infer_type(), Self::Literal { literaltype, .. } => literaltype.clone(), + Self::List { literaltype, .. } => literaltype.clone(), Self::Unary { right, .. } => right.infer_type(), Self::Variable { var_type, .. } => var_type.clone(), Self::FunctionCall { return_type, .. } => return_type.clone(), diff --git a/src/bytecode_compiler.rs b/src/bytecode_compiler.rs index 99fd10b..eba569c 100644 --- a/src/bytecode_compiler.rs +++ b/src/bytecode_compiler.rs @@ -1,13 +1,13 @@ -use crate::ast_compiler::{Expression, Function, Parameter, Statement}; +use crate::ast_compiler::{Expression, Function, Statement}; use crate::chunk::Chunk; use crate::tokens::TokenType; use crate::value::Value; use crate::vm::{ OP_ADD, OP_AND, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_CHAR, - OP_DEF_DATE, OP_DEF_F32, OP_DEF_F64, OP_DEF_FN, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, + OP_DEF_DATE, OP_DEF_F32, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEF_STRUCT, OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, - OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, OP_PRINT, - OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, + OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, + OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, }; use std::collections::HashMap; @@ -17,7 +17,7 @@ pub fn compile(ast: &Vec) -> anyhow::Result { pub(crate) fn compile_function(function: &Function) -> anyhow::Result { let mut compiler = Compiler::new(&function.name.lexeme); - for parm in &function.parameters{ + for parm in &function.parameters { let name = parm.name.lexeme.clone(); let name_index = compiler.chunk.add_constant(Value::String(name.clone())); compiler.vars.insert(name, name_index); @@ -71,7 +71,10 @@ impl Compiler { let name_index = self.chunk.add_constant(Value::String(name.lexeme.clone())); self.vars.insert(name.lexeme.clone(), name_index); self.compile_expression(initializer)?; - self.define_variable(var_type, name_index)? + self.define_variable(var_type, name_index)?; + if let Expression::List {values, .. } = initializer { + self.emit_byte(values.len() as u16); + } } Statement::PrintStmt { value } => { self.compile_expression(value)?; @@ -84,8 +87,7 @@ impl Compiler { let function_name = function.name.lexeme.clone(); let compiled_function = compile_function(function)?; let name_index = self.chunk.add_function(compiled_function); - self.functions - .insert(function_name, name_index); + self.functions.insert(function_name, name_index); } } Ok(()) @@ -108,6 +110,12 @@ impl Compiler { self.emit_bytes(OP_GET, *name_index as u16); } Expression::Literal { value, .. } => self.emit_constant(value), + Expression::List { values, .. } => { + for expr in values { + self.compile_expression(expr)?; + } + // self.emit_bytes(OP_NEW_LIST, values.len() as u16); + } Expression::Grouping { expression, .. } => self.compile_expression(expression)?, Expression::Unary { operator, right, .. diff --git a/src/chunk.rs b/src/chunk.rs index 36942e6..a8dd006 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -1,10 +1,9 @@ -use std::collections::HashMap; use crate::value::Value; use crate::vm::{ - OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_MULTIPLY, - OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL, - OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP, OP_DEFINE, OP_GET,OP_DEF_STRING, - OP_DEF_I32, OP_DEF_I64, OP_DEF_F32, OP_DEF_F64, OP_DEF_BOOL, OP_CALL + OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32, + OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_STRING, OP_DEFINE, OP_DIVIDE, OP_EQUAL, + 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, }; pub struct Chunk { @@ -12,10 +11,9 @@ pub struct Chunk { pub code: Vec, pub constants: Vec, lines: Vec, - pub(crate) functions: Vec + pub(crate) functions: Vec, } - impl Chunk { pub fn new(name: &str) -> Chunk { Chunk { @@ -43,7 +41,7 @@ impl Chunk { } pub fn disassemble(&self) { - for f in &self.functions{ + for f in &self.functions { f.disassemble(); } println!("== {} ==", self.name); @@ -92,6 +90,7 @@ impl Chunk { OP_DEF_BOOL => self.constant_inst("DEFBOOL", offset), OP_CALL => self.call_inst("CALL", offset), OP_GET => self.constant_inst("GET", offset), + OP_DEF_LIST => self.new_inst("DEFLIST", offset), _ => { println!("Unknown instruction {}", instruction); offset + 1 @@ -111,6 +110,14 @@ impl Chunk { offset + 3 } + fn new_inst(&self, name: &str, offset: usize) -> usize { + let constant = self.code[offset + 1]; + let len = self.code[offset + 2]; + print!("{} len: {}:", name, len); + self.print_value(&self.constants[constant as usize]); + offset + 3 + } + fn constant_inst(&self, name: &str, offset: usize) -> usize { let constant = self.code[offset + 1]; print!("{} {}:", name, constant); diff --git a/src/compiler.rs b/src/compiler.rs deleted file mode 100644 index 217e142..0000000 --- a/src/compiler.rs +++ /dev/null @@ -1,554 +0,0 @@ -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_DEF_BOOL, OP_DEF_CHAR, OP_DEF_DATE, - OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEF_STRUCT, - OP_DEFINE, OP_DIVIDE, OP_EQUAL, 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, -}; -use anyhow::anyhow; -use std::collections::HashMap; -use std::sync::LazyLock; -use tracing::debug; - -macro_rules! parse_num { - ($s:ident, $variant:ident, $number:ident) => {{ - $s.typestack.push(TokenType::$variant); - Value::$variant($number.parse()?) - }}; -} - -pub fn compile(source: &str) -> anyhow::Result { - let tokens = scan(source); - 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], - tokens: &tokens, - current: 0, - typestack: vec![], - locals: vec![], - previous: 0, - had_error: false, - }; - compiler.compile() -} - -struct Compiler<'a> { - source: Vec, - chunk: Chunk, - tokens: &'a Vec, - current: usize, - previous_token: &'a Token, - current_token: &'a Token, - typestack: Vec, - locals: Vec, - previous: usize, - had_error: bool, -} - -impl<'a> Compiler<'a> { - fn compile(mut self) -> anyhow::Result { - while !self.match_token(TokenType::Eof) { - self.declaration()?; - } - - // self.expression()?; - - // self.consume(TokenType::Eof, "Expect end of expression.")?; - self.emit_byte(OP_RETURN); - Ok(self.chunk) - } - - fn declaration(&mut self) -> anyhow::Result<()> { - 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")?; - let mut declared_type = None; - if self.check(TokenType::Colon) { - self.consume(TokenType::Colon, "must not happen")?; - match self.current_token.token_type { - TokenType::I32 - | TokenType::I64 - | TokenType::U32 - | TokenType::U64 - | TokenType::Date - | TokenType::StringType - | TokenType::Char - | TokenType::Bool - | TokenType::ListType - | TokenType::MapType => declared_type = Some(self.current_token.token_type), - _ => return Err(anyhow!("Invalid type {:?}", self.current_token.token_type)), - } - self.advance()?; - } - if self.match_token(TokenType::Equal) { - self.expression(declared_type)?; - let derived_type = Some(&self.previous_token.token_type); - self.consume(TokenType::Eol, "Expect end of line")?; - self.define_variable(declared_type, derived_type, index)?; - } else { - return Err(anyhow!( - "You cannot declare a variable without initializing it." - )); - } - Ok(()) - } - - fn parse_variable(&mut self, message: &str) -> anyhow::Result { - self.consume(TokenType::Identifier, message)?; - self.identifier_constant(self.previous_token) - } - - fn identifier_constant(&mut self, token: &Token) -> anyhow::Result { - let name = token.lexeme.clone(); - let index = self.chunk.add_constant(Value::String(name)); - Ok(index) - } - - fn define_variable( - &mut self, - var_type: Option, - derived_type: Option<&TokenType>, - index: usize, - ) -> anyhow::Result<()> { - let def_op = match var_type { - Some(TokenType::I32) => OP_DEF_I32, - Some(TokenType::I64) => OP_DEF_I64, - Some(TokenType::U32) => OP_DEF_I64, - Some(TokenType::U64) => OP_DEF_I64, - Some(TokenType::Date) => OP_DEF_DATE, - Some(TokenType::StringType) => OP_DEF_STRING, - Some(TokenType::Char) => OP_DEF_CHAR, - Some(TokenType::Bool) => OP_DEF_BOOL, - Some(TokenType::ListType) => OP_DEF_LIST, - Some(TokenType::MapType) => OP_DEF_MAP, - Some(TokenType::Object) => OP_DEF_STRUCT, - _ => match derived_type { - Some(TokenType::StringType) => OP_DEF_STRING, - Some(TokenType::Bool) => OP_DEF_BOOL, - Some(TokenType::Char) => OP_DEF_CHAR, - Some(TokenType::F64) => OP_DEF_F64, - Some(TokenType::I64) => OP_DEF_I64, - Some(TokenType::ListType) => OP_DEF_LIST, - Some(TokenType::MapType) => OP_DEF_MAP, - _ => OP_DEFINE, - }, - }; - - self.emit_bytes(def_op, index as u16); - Ok(()) - } - - fn statement(&mut self) -> anyhow::Result<()> { - if self.match_token(TokenType::Print) { - self.print_statement() - } else { - self.expression_statement() - } - } - - fn expression_statement(&mut self) -> anyhow::Result<()> { - debug!("expression statement"); - self.expression(None)?; - self.emit_byte(OP_POP); - Ok(()) - } - - fn print_statement(&mut self) -> anyhow::Result<()> { - self.expression(None)?; - self.consume( - TokenType::Eol, - "No further statements expected. Please start on a new line after the first one.\n", - )?; - self.emit_byte(OP_PRINT); - Ok(()) - } - - fn advance(&mut self) -> anyhow::Result<()> { - if self.current < self.tokens.len() - 1 { - self.previous = self.current; - self.previous_token = &self.tokens[self.previous]; - self.current += 1; - self.current_token = &self.tokens[self.current]; - } - if let TokenType::Error = self.current_token.token_type { - self.had_error = true; - Err(anyhow!( - "Error at {} on line {}", - self.current_token.lexeme, - self.current_token.line - )) - } else { - Ok(()) - } - } - - fn consume(&mut self, token_type: TokenType, message: &str) -> anyhow::Result<()> { - if token_type == self.current_token.token_type { - self.advance() - } else { - Err(anyhow!( - r#"{} at line {}: "{}""#, - message, - self.current_token.line + 1, - self.source[self.current_token.line] - )) - } - } - - fn match_token(&mut self, token_type: TokenType) -> bool { - if !self.check(token_type) { - false - } else { - self.advance().expect("token expected"); - true - } - } - - fn check(&mut self, token_type: TokenType) -> bool { - self.current_token.token_type == token_type - } - - fn expression(&mut self, expected_type: Option) -> anyhow::Result<()> { - self.parse_precedence(PREC_ASSIGNMENT, expected_type)?; - - Ok(()) - } - - fn parse_precedence( - &mut self, - precedence: usize, - expected_type: Option, - ) -> anyhow::Result<()> { - self.advance()?; - let rule = get_rule(&self.previous_token.token_type); - debug!("Precedence rule: {:?}", rule); - if let Some(prefix) = rule.prefix { - prefix(self, expected_type)?; - while precedence <= get_rule(&self.current_token.token_type).precedence { - self.advance()?; - let infix_rule = get_rule(&self.previous_token.token_type).infix; - if let Some(infix) = infix_rule { - infix(self, expected_type)?; - } - } - } else { - return Err(anyhow!("Expect expression.")); - } - Ok(()) - } - - fn emit_byte(&mut self, byte: u16) { - self.chunk.add(byte, self.previous_token.line); - } - - fn emit_bytes(&mut self, b1: u16, b2: u16) { - self.emit_byte(b1); - self.emit_byte(b2); - } - - fn emit_constant(&mut self, value: Value) { - let index = self.chunk.add_constant(value); - self.emit_bytes(OP_CONSTANT, index as u16); - } -} - -type ParseFn = fn(&mut Compiler, expected_type: Option) -> anyhow::Result<()>; - -#[derive(Debug)] -struct Rule { - prefix: Option, - infix: Option, - precedence: usize, -} - -impl Rule { - fn new(prefix: Option, infix: Option, precedence: usize) -> Self { - Self { - prefix, - infix, - precedence, - } - } -} - -fn number(s: &mut Compiler, mut expected_type: Option) -> anyhow::Result<()> { - debug!("number: expected type {:?}", expected_type); - - // coerce unknown numeric type to the expected type of the expression if any - if let None = expected_type { - if !s.typestack.is_empty() { - expected_type = Some(*s.typestack.last().unwrap()); - } - } - - let number = &s.previous_token.lexeme; - let value = if let Some(expected_type) = expected_type { - match expected_type { - TokenType::I32 => parse_num!(s, I32, number), - TokenType::I64 => parse_num!(s, I64, number), - TokenType::U32 => parse_num!(s, U32, number), - TokenType::U64 => parse_num!(s, U64, number), - TokenType::F32 => parse_num!(s, F32, number), - TokenType::F64 => parse_num!(s, F64, number), - - _ => { - return Err(anyhow!( - "Invalid type: expected {} value, got {}({})", - expected_type, - &s.previous_token.token_type, - number - )); - } - } - } else { - match s.previous_token.token_type { - TokenType::Integer => Value::I64(number.parse()?), - TokenType::FloatingPoint => Value::F64(number.parse()?), - _ => panic!("I did not think this would happen") - } - }; - s.emit_constant(value); - Ok(()) -} - -fn literal(s: &mut Compiler, expected_type: Option) -> anyhow::Result<()> { - let actual_type = &s.previous_token.token_type; - if let Some(expected_type) = expected_type { - match (actual_type, expected_type) { - (TokenType::False, TokenType::Bool) => { - s.typestack.push(TokenType::Bool); - s.emit_constant(Value::Bool(false)) - } - (TokenType::True, TokenType::Bool) => { - s.typestack.push(TokenType::Bool); - s.emit_constant(Value::Bool(true)) - } - (TokenType::StringType, TokenType::StringType) => { - s.typestack.push(TokenType::StringType); - s.emit_constant(Value::String(s.previous_token.lexeme.clone())) - } - //list - //map - //struct value - _ => { - return Err(anyhow!( - "Invalid type: expected {} value, got {}({})", - expected_type, - &s.previous_token.token_type, - s.previous_token.lexeme - )); - } - } - } else { - match actual_type { - TokenType::False => s.emit_constant(Value::Bool(false)), - TokenType::True => s.emit_constant(Value::Bool(true)), - TokenType::StringType => s.emit_constant(Value::String(s.previous_token.lexeme.clone())), - _ => {} - } - } - Ok(()) -} - -fn skip(s: &mut Compiler, _expected_type: Option) -> anyhow::Result<()> { - Ok(()) -} - -fn grouping(s: &mut Compiler, _expected_type: Option) -> anyhow::Result<()> { - s.expression(None)?; - s.consume(TokenType::RightParen, "Expect ')' after expression.") -} - -fn unary(s: &mut Compiler, expected_type: Option) -> anyhow::Result<()> { - let operator_type = s.previous_token.token_type; - - s.parse_precedence(PREC_UNARY, None)?; - - match operator_type { - TokenType::Minus => { - s.emit_byte(OP_NEGATE); - } - TokenType::Bang => { - s.emit_byte(OP_NOT); - } - _ => unimplemented!("unary other than ! and -"), - } - Ok(()) -} - -fn binary(s: &mut Compiler, expected_type: Option) -> anyhow::Result<()> { - let operator_type = &s.previous_token.token_type; - debug!("operator {:?}", operator_type); - debug!("expected type {:?}", expected_type); - let rule = get_rule(operator_type); - s.parse_precedence(rule.precedence + 1, None)?; - match operator_type { - TokenType::Plus => s.emit_byte(OP_ADD), - TokenType::Minus => s.emit_byte(OP_SUBTRACT), - TokenType::Star => s.emit_byte(OP_MULTIPLY), - TokenType::Slash => s.emit_byte(OP_DIVIDE), - TokenType::BitAnd => s.emit_byte(OP_BITAND), - TokenType::BitOr => s.emit_byte(OP_BITOR), - TokenType::BitXor => s.emit_byte(OP_BITXOR), - TokenType::GreaterGreater => s.emit_byte(OP_SHR), - TokenType::LessLess => s.emit_byte(OP_SHL), - TokenType::EqualEqual => s.emit_byte(OP_EQUAL), - TokenType::Greater => s.emit_byte(OP_GREATER), - TokenType::GreaterEqual => s.emit_byte(OP_GREATER_EQUAL), - TokenType::Less => s.emit_byte(OP_LESS), - TokenType::LessEqual => s.emit_byte(OP_LESS_EQUAL), - _ => unimplemented!("binary other than plus, minus, star, slash"), - } - Ok(()) -} - -fn variable(s: &mut Compiler, expected_type: Option) -> 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() -} - -static RULES: LazyLock> = LazyLock::new(|| { - let mut rules: HashMap = HashMap::new(); - 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::Date, 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::FloatingPoint, Rule::new(Some(number), None, PREC_NONE)); - rules.insert( - TokenType::Greater, - Rule::new(None, Some(binary), PREC_COMPARISON), - ); - rules.insert( - TokenType::GreaterEqual, - Rule::new(None, Some(binary), PREC_COMPARISON), - ); - rules.insert( - TokenType::GreaterGreater, - Rule::new(None, Some(binary), PREC_BITSHIFT), - ); - rules.insert(TokenType::I32, Rule::new(None, None, PREC_NONE)); - rules.insert(TokenType::I64, Rule::new(None, None, PREC_NONE)); - rules.insert( - TokenType::Identifier, - Rule::new(Some(variable), None, PREC_NONE), - ); - rules.insert(TokenType::Integer, Rule::new(Some(number), 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(grouping), None, PREC_NONE), - ); - rules.insert( - TokenType::Less, - Rule::new(None, Some(binary), PREC_COMPARISON), - ); - rules.insert( - TokenType::LessEqual, - Rule::new(None, Some(binary), PREC_COMPARISON), - ); - rules.insert( - TokenType::LessLess, - Rule::new(None, Some(binary), PREC_BITSHIFT), - ); - 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::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::StringType, Rule::new(Some(literal), None, PREC_NONE)); - rules.insert( - TokenType::BitAnd, - Rule::new(None, Some(binary), PREC_BITAND), - ); - rules.insert(TokenType::StringType, Rule::new(None, None, PREC_NONE)); - rules.insert(TokenType::Struct, Rule::new(None, None, PREC_NONE)); - rules.insert(TokenType::True, Rule::new(Some(literal), None, PREC_NONE)); - rules.insert(TokenType::U32, Rule::new(None, None, PREC_NONE)); - rules.insert(TokenType::U64, Rule::new(None, None, PREC_NONE)); - rules.insert(TokenType::While, Rule::new(None, None, PREC_NONE)); - - rules -}); - -const PREC_NONE: usize = 0; -const PREC_ASSIGNMENT: usize = 1; -const PREC_OR: usize = 2; -const PREC_AND: usize = 3; -const PREC_BITAND: usize = 4; -const PREC_BITOR: usize = 5; -const PREC_BITXOR: usize = 6; -const PREC_EQUALITY: usize = 7; -const PREC_COMPARISON: usize = 8; -const PREC_BITSHIFT: usize = 9; -const PREC_TERM: usize = 10; -const PREC_FACTOR: usize = 11; -const PREC_UNARY: usize = 12; -const PREC_CALL: usize = 13; -const PREC_PRIMARY: usize = 14; - -enum ValueType { - DateType, - BoolType, - CharType, - F32Type, - F64Type, - I32Type, - I64Type, - ObjectType, - U32Type, - U64Type, - StringType, - ListType, - MapType, -} diff --git a/src/lib.rs b/src/lib.rs index e18eb3b..df89024 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,8 @@ -pub mod chunk; -pub mod compiler; -mod keywords; pub mod scanner; -mod tokens; -mod value; -pub mod vm; pub mod ast_compiler; pub mod bytecode_compiler; +pub mod vm; +mod chunk; +mod keywords; +mod tokens; +mod value; diff --git a/src/main.rs b/src/main.rs index 7c8ae73..bbd5408 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,9 +8,10 @@ fn main() -> anyhow::Result<()> { let tokens = scan( r#" -fn main(a: string) -> u32: +fn main(a: list) -> list: a + 42 -let text = "hello " + +let text:list = ["hello "] main(text)"#, ); println!("{:?}", tokens); diff --git a/src/value.rs b/src/value.rs index 26a0b07..0f67cb7 100644 --- a/src/value.rs +++ b/src/value.rs @@ -2,7 +2,7 @@ use anyhow::anyhow; use chrono::{DateTime, Utc}; use std::cmp::Ordering; use std::collections::HashMap; -use std::fmt::{Display, Formatter, write}; +use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub}; @@ -114,18 +114,6 @@ impl Into for DateTime { } } -impl Into for Vec { - fn into(self) -> Value { - Value::List(self) - } -} - -impl Into for HashMap { - fn into(self) -> Value { - Value::Map(self) - } -} - impl Display for Value { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match &self { @@ -167,26 +155,37 @@ impl Add<&Value> for &Value { type Output = anyhow::Result; fn add(self, rhs: &Value) -> Self::Output { - match (self, rhs) { - (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a + b)), - (Value::I64(a), Value::I64(b)) => Ok(Value::I64(a + b)), - (Value::U32(a), Value::U32(b)) => Ok(Value::U32(a + b)), - (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a + b)), - (Value::F32(a), Value::F32(b)) => Ok(Value::F32(a + b)), - (Value::F64(a), Value::F64(b)) => Ok(Value::F64(a + b)), - (Value::String(s), Value::I32(i)) => Ok(Value::String(format!("{}{}", s, i))), - (Value::String(s), Value::I64(i)) => Ok(Value::String(format!("{}{}", s, i))), - (Value::String(s), Value::U32(u)) => Ok(Value::String(format!("{}{}", s, u))), - (Value::String(s), Value::U64(u)) => Ok(Value::String(format!("{}{}", s, u))), - (Value::String(s), Value::F32(f)) => Ok(Value::String(format!("{}{}", s, f))), - (Value::String(s), Value::F64(f)) => Ok(Value::String(format!("{}{}", s, f))), - (Value::String(s), Value::Bool(b)) => Ok(Value::String(format!("{}{}", s, b))), - (Value::String(s), Value::Char(c)) => Ok(Value::String(format!("{}{}", s, c))), - (Value::String(s1), Value::String(s2)) => Ok(Value::String(format!("{}{}", s1, s2))), - (Value::String(s1), Value::List(l)) => Ok(Value::String(format!("{}{:?}", s1, l))), - (Value::String(s1), Value::Map(m)) => Ok(Value::String(format!("{}{:?}", s1, m))), - //enum? - _ => Err(anyhow!("Cannot add")), + if let Value::List(s) = self { + let mut copy = s.clone(); + copy.push(rhs.clone()); + Ok(Value::List(copy)) + } else if let Value::List(rhs) = rhs { + let mut copy = rhs.clone(); + copy.push(self.clone()); + Ok(Value::List(copy)) + } else { + match (self, rhs) { + (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a + b)), + (Value::I64(a), Value::I64(b)) => Ok(Value::I64(a + b)), + (Value::U32(a), Value::U32(b)) => Ok(Value::U32(a + b)), + (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a + b)), + (Value::F32(a), Value::F32(b)) => Ok(Value::F32(a + b)), + (Value::F64(a), Value::F64(b)) => Ok(Value::F64(a + b)), + (Value::String(s), Value::I32(i)) => Ok(Value::String(format!("{}{}", s, i))), + (Value::String(s), Value::I64(i)) => Ok(Value::String(format!("{}{}", s, i))), + (Value::String(s), Value::U32(u)) => Ok(Value::String(format!("{}{}", s, u))), + (Value::String(s), Value::U64(u)) => Ok(Value::String(format!("{}{}", s, u))), + (Value::String(s), Value::F32(f)) => Ok(Value::String(format!("{}{}", s, f))), + (Value::String(s), Value::F64(f)) => Ok(Value::String(format!("{}{}", s, f))), + (Value::String(s), Value::Bool(b)) => Ok(Value::String(format!("{}{}", s, b))), + (Value::String(s), Value::Char(c)) => Ok(Value::String(format!("{}{}", s, c))), + (Value::String(s1), Value::String(s2)) => { + Ok(Value::String(format!("{}{}", s1, s2))) + } + (Value::String(s1), Value::Map(m)) => Ok(Value::String(format!("{}{:?}", s1, m))), + //enum? + _ => Err(anyhow!("Cannot add")), + } } } } @@ -333,18 +332,18 @@ impl PartialEq for Value { (Value::String(a), Value::String(b)) => a == b, (Value::Char(a), Value::Char(b)) => a == b, (Value::Date(a), Value::Date(b)) => a == b, - (Value::List(a), Value::List(b)) => a == b, - (Value::Map(a), Value::Map(b)) => { - let mut equal = true; - for (k, v) in a.iter() { - if !b.contains_key(k) || b.get(k).unwrap() != v { - //safe unwrap - equal = false; - break; - } - } - equal - } + // (Value::List(a), Value::List(b)) => a == b, + // (Value::Map(a), Value::Map(b)) => { + // let mut equal = true; + // for (k, v) in a.iter() { + // if !b.contains_key(k) || b.get(k).unwrap() != v { + // //safe unwrap + // equal = false; + // break; + // } + // } + // equal + // } // struct? _ => false, //? } diff --git a/src/vm.rs b/src/vm.rs index 75c057b..9982cc9 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,6 +1,7 @@ use crate::chunk::Chunk; use crate::value::Value; use anyhow::anyhow; +use bumpalo::Bump; use std::collections::HashMap; use tracing::debug; @@ -24,6 +25,7 @@ pub struct Vm { stack: Vec, local_vars: HashMap, error_occurred: bool, + arena: Bump, } pub fn interpret(chunk: &Chunk) -> anyhow::Result { @@ -32,6 +34,7 @@ pub fn interpret(chunk: &Chunk) -> anyhow::Result { stack: vec![], local_vars: HashMap::new(), error_occurred: false, + arena: Bump::new(), }; vm.run(chunk, vec![]) } @@ -42,13 +45,14 @@ pub fn interpret_function(chunk: &Chunk, args: Vec) -> anyhow::Result) -> anyhow::Result { - for arg in args{ + for arg in args { self.push(arg); } loop { @@ -121,7 +125,16 @@ impl Vm { OP_DEF_CHAR => define_var!(self, Char, chunk), OP_DEF_BOOL => define_var!(self, Bool, chunk), OP_DEF_DATE => define_var!(self, Date, chunk), - OP_DEF_LIST => define_var!(self, List, chunk), + OP_DEF_LIST => { + let name = self.read_name(chunk); + let len = self.read(chunk); + let mut list = vec![]; + for _ in 0..len { + let value = self.pop(); + list.push(value); + } + self.local_vars.insert(name, Value::List(list)); + } OP_DEF_MAP => define_var!(self, Map, chunk), OP_DEF_STRUCT => define_var!(self, Struct, chunk), OP_GET => { @@ -236,3 +249,4 @@ pub const OP_DEF_MAP: u16 = 37; pub const OP_DEF_STRUCT: u16 = 38; pub const OP_DEF_F32: u16 = 39; pub const OP_DEF_F64: u16 = 40; +// pub const OP_NEW_LIST: u16 = 40;