diff --git a/build.sh b/build.sh index cbcd805..f6ad2e3 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,6 @@ # Build Sloth cargo build +rm output.o FILENAME="$1" # Compile standard library ./target/debug/sloth std/extern.sloth std/stdmath.sloth std/stdio.sloth $FILENAME diff --git a/examples/mutable.sloth b/examples/mutable.sloth new file mode 100644 index 0000000..7ea6a96 --- /dev/null +++ b/examples/mutable.sloth @@ -0,0 +1,7 @@ +fn main() { + val test = 0; + println(istr(test)); + #test = 1; + println(istr(test)); + return 0; +} diff --git a/sloth/src/analysis/setup.rs b/sloth/src/analysis/setup.rs index 3110f77..522d757 100644 --- a/sloth/src/analysis/setup.rs +++ b/sloth/src/analysis/setup.rs @@ -35,6 +35,22 @@ impl Populator { name: "Float".to_owned(), is_list: false, }), + true, + )?; + table.insert(identifier.to_owned(), symbol); + } + StmtKind::DefineValue { + identifier, typ, .. + } => { + // When a variable is defined add it to the symbol table of the current scope. + let symbol = self.build_value_symbol( + node.line(), + &table, + &typ.clone().unwrap_or(TypeIdentifier { + name: "Float".to_owned(), + is_list: false, + }), + false, )?; table.insert(identifier.to_owned(), symbol); } @@ -56,7 +72,7 @@ impl Populator { for input in inputs { let symbol = - self.build_value_symbol(node.line(), &body_table, &input.typ)?; + self.build_value_symbol(node.line(), &body_table, &input.typ, true)?; body_table.insert(input.identifier.to_owned(), symbol); } } @@ -70,6 +86,7 @@ impl Populator { let symbol = Symbol::Value(ValueSymbol { typ: Type::Integer, id: self.reserve_id(), + mutable: true, }); body_table.insert(identifier.to_owned(), symbol); @@ -90,6 +107,7 @@ impl Populator { line: u32, table: &SymbolTable, typ: &TypeIdentifier, + mutab: bool, ) -> Result { let typ = table .get_type(typ) @@ -98,6 +116,7 @@ impl Populator { Ok(Symbol::Value(ValueSymbol { typ, id: self.reserve_id(), + mutable: mutab, })) } @@ -129,8 +148,10 @@ impl Populator { typ: Type::Function { inputs, output: output.into(), + }, id: self.reserve_id(), + mutable: true, })) } } @@ -167,6 +188,9 @@ pub(super) fn propagate_types_stmt(node: &mut Stmt) -> Result<(), AnalysisError> StmtKind::DefineVariable { value, .. } => { propagate_types(value)?; } + StmtKind::DefineValue { value, .. } => { + propagate_types(value)?; + } StmtKind::AssignVariable { value, .. } => { propagate_types(value)?; } diff --git a/sloth/src/codegen/mod.rs b/sloth/src/codegen/mod.rs index 59f1ea6..7678856 100644 --- a/sloth/src/codegen/mod.rs +++ b/sloth/src/codegen/mod.rs @@ -233,14 +233,29 @@ impl<'ctx> Codegen<'ctx> { self.builder.build_store(ptr, init_value); self.references.insert(symbol.id, ptr); } - StmtKind::AssignVariable { identifier, value } => { + StmtKind::DefineValue { + identifier, value, .. + } => { let table = code.symtable.clone(); let symbol = table.get_value(identifier).unwrap(); - let ptr = self.references.get(&symbol.id).unwrap(); + let ptr = self.codegen_alloca(self.type_as_basic_type(symbol.typ), identifier); let init_value = self.codegen_expr(value).unwrap(); - self.builder.build_store(*ptr, init_value); + self.builder.build_store(ptr, init_value); + self.references.insert(symbol.id, ptr); + } + StmtKind::AssignVariable { identifier, value } => { + let table = code.symtable.clone(); + let symbol = table.get_value(identifier).unwrap(); + if symbol.mutable { + let ptr = self.references.get(&symbol.id).unwrap(); + let init_value = self.codegen_expr(value).unwrap(); + + self.builder.build_store(*ptr, init_value); + } else { + panic!("Val not mutable!"); + } } StmtKind::DefineFunction(function) => { let table = code.symtable.clone(); diff --git a/sloth/src/main.rs b/sloth/src/main.rs index c181a3b..23946b2 100644 --- a/sloth/src/main.rs +++ b/sloth/src/main.rs @@ -100,6 +100,7 @@ fn mk_symtable() -> SymbolTable { output: Box::new(Type::Integer), }, id: 0, + mutable: true, }); let dummyf = Symbol::Value(ValueSymbol { @@ -108,6 +109,7 @@ fn mk_symtable() -> SymbolTable { output: Box::new(Type::Float), }, id: 0, + mutable: true, }); let dummyb = Symbol::Value(ValueSymbol { @@ -116,6 +118,7 @@ fn mk_symtable() -> SymbolTable { output: Box::new(Type::Boolean), }, id: 0, + mutable: true, }); let dummys = Symbol::Value(ValueSymbol { @@ -124,6 +127,7 @@ fn mk_symtable() -> SymbolTable { output: Box::new(Type::Boolean), }, id: 0, + mutable: true, }); global_symtable.insert("vlen".into(), dummyi.clone()); diff --git a/sloth/src/parser/ast.rs b/sloth/src/parser/ast.rs index 74500ef..7bc2c1b 100644 --- a/sloth/src/parser/ast.rs +++ b/sloth/src/parser/ast.rs @@ -195,6 +195,7 @@ impl Stmt { children.push(body.as_node()); } StmtKind::DefineVariable { value, .. } => children.push(value.as_node()), + StmtKind::DefineValue { value, .. } => children.push(value.as_node()), StmtKind::AssignVariable { value, .. } => children.push(value.as_node()), StmtKind::DefineFunction(Function { kind, .. }) => { if let FunctionKind::Normal { body } = kind { @@ -233,6 +234,11 @@ pub enum StmtKind { value: Expr, typ: Option, }, + DefineValue { + identifier: String, + value: Expr, + typ: Option, + }, AssignVariable { identifier: String, value: Expr, diff --git a/sloth/src/parser/graph.rs b/sloth/src/parser/graph.rs index 7b56b56..a76bf4c 100644 --- a/sloth/src/parser/graph.rs +++ b/sloth/src/parser/graph.rs @@ -85,6 +85,20 @@ impl GraphBuilder { self.traverse_expr0(iterator)?; self.traverse_stmt0(body)?; } + StmtKind::DefineValue { + identifier, + value, + typ, + } => { + writeln!( + &mut self.graph, + "N{} [shape=box label=\"DefineValue\\n\\nIdentifier={}\\lType={}\\l\"];", + stmt.id, + identifier, + typ.clone().unwrap() + )?; + self.traverse_expr0(value)?; + } StmtKind::DefineVariable { identifier, value, @@ -277,6 +291,10 @@ impl GraphBuilder { writeln!(&mut self.graph, "N{} -> N{};", stmt.id, value.id)?; self.traverse_expr(value)?; } + StmtKind::DefineValue { value, .. } => { + writeln!(&mut self.graph, "N{} -> N{};", stmt.id, value.id)?; + self.traverse_expr(value)?; + } StmtKind::AssignVariable { value, .. } => { writeln!(&mut self.graph, "N{} -> N{};", stmt.id, value.id)?; self.traverse_expr(value)?; diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs index 75ef1b2..54534c4 100644 --- a/sloth/src/parser/stmt.rs +++ b/sloth/src/parser/stmt.rs @@ -16,6 +16,7 @@ impl<'a> AstParser<'a> { TokenType::While => self.while_stmt(), TokenType::For => self.for_stmt(), TokenType::Var => self.define_variable(), + TokenType::Val => self.define_value(), TokenType::Fn => self.define_function(false), TokenType::Return => self.return_stmt(), @@ -149,6 +150,37 @@ impl<'a> AstParser<'a> { )) } + fn define_value(&mut self) -> Result { + // Consume the val token + self.consume(TokenType::Val, "Expected val")?; + + // Get the identifier and type + let identifier = self.consume_identifier()?; + let typ = if self.consume(TokenType::Colon, "Expected ':'").is_ok() { + self.consume_type().ok() + } else { + None + }; + + // Get the default value + self.consume(TokenType::Eq, "Expected '='")?; + let value = self.expression()?; + + self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?; + + let kind = StmtKind::DefineValue { + identifier, + value, + typ, + }; + + Ok(Stmt::new( + self.reserve_id(), + self.line, + kind, + self.top.clone(), + )) + } // TODO: Make argument types optional fn define_function(&mut self, is_foreign: bool) -> Result { // Consume the fn token diff --git a/sloth/src/symtable.rs b/sloth/src/symtable.rs index 549bb59..06c0026 100644 --- a/sloth/src/symtable.rs +++ b/sloth/src/symtable.rs @@ -143,6 +143,7 @@ pub enum Symbol { pub struct ValueSymbol { pub typ: Type, pub id: i32, + pub mutable: bool, } #[derive(Clone, Debug, PartialEq, PartialOrd)]