diff --git a/examples/fibonacci/fib.tp b/examples/fibonacci/fib.tp index 64cac89..92311a6 100644 --- a/examples/fibonacci/fib.tp +++ b/examples/fibonacci/fib.tp @@ -1,8 +1,7 @@ -println("Fibonacci sequence:") -let fib = [1,1] +fn fib(n: u64): + if n < 2: + n + else: + fib(n-1) + fib(n-2) -let r=10 - -for i in 2..r: - fib.push(fib[i-2] + fib[i-1]) - println(fib) +println(fib(10)) \ No newline at end of file diff --git a/src/compiler/assembly_pass.rs b/src/compiler/assembly_pass.rs index 63db826..993ab19 100644 --- a/src/compiler/assembly_pass.rs +++ b/src/compiler/assembly_pass.rs @@ -181,7 +181,8 @@ impl AsmPass { ); } Statement::ObjectStmt { name, fields } => { - self.chunk.add_object_def(&name.lexeme, fields); + self.chunk + .add_object_def(&format!("{}/{}", namespace, &name.lexeme), fields); } Statement::GuardStatement { .. } => { unimplemented!("guard statement") @@ -229,12 +230,7 @@ impl AsmPass { self.emit(Goto(0)); let goto_addr2 = self.chunk.code.len() - 1; // placeholder self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len()); - self.compile_statements( - else_branch, - symbols, - registry, - namespace, - )?; + self.compile_statements(else_branch, symbols, registry, namespace)?; self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len()); } Expression::LetExpression { @@ -243,13 +239,13 @@ impl AsmPass { let name = name.lexeme.as_str(); let var = symbols.get(name); if let Some(Symbol::Variable { var_type, .. }) = var { - let inferred_type = infer_type(initializer, symbols).map_err(|e| self.error_at_line(e))?; - let calculated_type = - calculate_type(var_type, &inferred_type).map_err(|e| self.error_at_line(e))?; + let inferred_type = + infer_type(initializer, symbols).map_err(|e| self.error_at_line(e))?; + let calculated_type = calculate_type(var_type, &inferred_type) + .map_err(|e| self.error_at_line(e))?; if var_type != &Unknown && var_type != &calculated_type { - return Err( - self.error_at_line(IncompatibleTypes(var_type.clone(), calculated_type)) - ); + return Err(self + .error_at_line(IncompatibleTypes(var_type.clone(), calculated_type))); } let name_index = self.chunk.add_var(var_type, name); self.vars.insert(name.to_string(), name_index); @@ -262,13 +258,14 @@ impl AsmPass { Expression::FunctionCall { name, arguments, .. } => { - let name_index = self - .chunk - .find_constant(name) - .unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string()))); - let function = symbols.get(name); + let qname = format!("{}/{}", namespace, name); + let function = symbols.get(&qname).or(symbols.get(name)); match function { Some(Symbol::Function { parameters, .. }) => { + let name_index = self.chunk.find_constant(&qname).unwrap_or_else(|| { + self.chunk.add_constant(Value::String(qname.to_string())) + }); + self.get_arguments_in_order( namespace, symbols, registry, arguments, parameters, )?; @@ -277,6 +274,9 @@ impl AsmPass { } // constructor function Some(Symbol::Object { fields, .. }) => { + let name_index = self.chunk.find_constant(&qname).unwrap_or_else(|| { + self.chunk.add_constant(Value::String(qname.to_string())) + }); self.get_arguments_in_order( namespace, symbols, registry, arguments, fields, )?; @@ -285,12 +285,20 @@ impl AsmPass { // maybe global function _ => { if let Some(fun) = GLOBAL_FUNCTIONS.get(name) { - self.get_arguments_in_order(namespace, symbols, registry, arguments, &fun.parameters)?; + self.get_arguments_in_order( + namespace, + symbols, + registry, + arguments, + &fun.parameters, + )?; + let name_index = self.chunk.find_constant(name).unwrap_or_else(|| { + self.chunk.add_constant(Value::String(name.to_string())) + }); self.emit(Call(name_index, fun.arity())); } else { - return Err( - self.error_at_line(CompilerError::FunctionNotFound(name.to_string())) - ); + return Err(self + .error_at_line(CompilerError::FunctionNotFound(name.to_string()))); } } } @@ -302,7 +310,9 @@ impl AsmPass { .. } => { self.compile_expression(namespace, receiver, symbols, registry)?; - let receiver_type = infer_type(receiver, symbols).map_err(|e|self.error_at_line(e))?.to_string(); + let receiver_type = infer_type(receiver, symbols) + .map_err(|e| self.error_at_line(e))? + .to_string(); let type_index = self.chunk.find_constant(&receiver_type).unwrap_or_else(|| { self.chunk @@ -313,7 +323,8 @@ impl AsmPass { self.chunk .add_constant(Value::String(method_name.to_string())) }); - let signature = lookup(&receiver_type, method_name).map_err(|e| self.error_at_line(e))?; + let signature = + lookup(&receiver_type, method_name).map_err(|e| self.error_at_line(e))?; if signature.arity() != arguments.len() { return Err(self.error_at_line(CompilerError::IllegalArgumentsException( format!("{}.{}", receiver_type, method_name), @@ -456,8 +467,7 @@ impl AsmPass { self.vars.insert(name.to_string(), loop_var_name_index); // 3. start index - let end= - if let Expression::Range { lower, upper, .. } = range.deref() { + let end = if let Expression::Range { lower, upper, .. } = range.deref() { self.compile_expression(namespace, lower, symbols, registry)?; upper.clone() } else { @@ -495,10 +505,13 @@ impl AsmPass { for parameter in parameters { if let NamedParameter { name, value, .. } = argument { if name.lexeme == parameter.name.lexeme { - let value_type = infer_type(value, symbols).map_err(|e| self.error_at_line(e))?; + let value_type = + infer_type(value, symbols).map_err(|e| self.error_at_line(e))?; if parameter.var_type != value_type { - return Err(self - .error_at_line(IncompatibleTypes(parameter.var_type.clone(), value_type))); + return Err(self.error_at_line(IncompatibleTypes( + parameter.var_type.clone(), + value_type, + ))); } else { self.compile_expression(namespace, argument, symbols, registry)?; break; diff --git a/src/compiler/compiler_tests.rs b/src/compiler/compiler_tests.rs index d6e7357..d4d9135 100644 --- a/src/compiler/compiler_tests.rs +++ b/src/compiler/compiler_tests.rs @@ -144,7 +144,7 @@ let p = Person(name: "Sander") p"#); assert!(r.is_ok()); assert_eq!( - r#"Person: [("name", String("Sander"))]"#, + r#"main/Person: [("name", String("Sander"))]"#, format!("{}", r.unwrap().to_string()) ); } diff --git a/src/compiler/scan_pass.rs b/src/compiler/scan_pass.rs index b51c594..b5b40e6 100644 --- a/src/compiler/scan_pass.rs +++ b/src/compiler/scan_pass.rs @@ -6,7 +6,6 @@ use crate::compiler::tokens::{ use crate::errors::CompilerError::{IllegalCharLength, UnexpectedIdentifier, Unterminated}; use crate::errors::{CompilerError, CompilerErrorAtLine}; use crate::keywords; -use axum::http::header::ToStrError; pub fn scan(source: &str) -> Result, CompilerErrorAtLine> { let scanner = Scanner { @@ -16,6 +15,8 @@ pub fn scan(source: &str) -> Result, CompilerErrorAtLine> { line: 1, tokens: vec![], new_line: true, + spaces: 0, + spaces_in_indent: 0, }; scanner.scan() } @@ -33,10 +34,30 @@ impl Scanner { fn scan_token(&mut self) -> Result<(), CompilerErrorAtLine> { let c = self.advance(); - if self.new_line && (c == ' ' || c == '\t') { - self.add_token(TokenType::Indent); - self.new_line = false; + + if self.new_line && (c == '\t' || c == ' ') { + // first indent using spaces determines how many spaces form an indent + if c == ' ' { + self.spaces += 1; + } else { + self.add_token(TokenType::Indent); + } } else { + if self.new_line { + self.new_line = false; + if self.spaces_in_indent == 0 { + self.spaces_in_indent = self.spaces; + } + let indents = if self.spaces_in_indent > 0 { + self.spaces / self.spaces_in_indent + } else { + 0 + }; + self.spaces = 0; + for _ in 0..indents { + self.add_token(TokenType::Indent); + } + } if c != '\n' { self.new_line = false; } @@ -346,6 +367,8 @@ struct Scanner { tokens: Vec, line: usize, new_line: bool, + spaces: usize, + spaces_in_indent: usize, } fn is_digit_or_scientific(c: char) -> bool { diff --git a/src/vm.rs b/src/vm.rs index 27d4a86..9460bc0 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -44,8 +44,8 @@ pub fn interpret(registry: Guard>, function: &str) -> Result) -> Result { - let mut vm = Vm::new(&Arc::new(HashMap::new())); +pub fn interpret_function(chunk: &AsmChunk, args: Vec, registry: Arc) -> Result { + let mut vm = Vm::new(®istry); vm.run_function(chunk, args) } @@ -148,7 +148,8 @@ impl Vm { TokenType::I32 => value = value.cast_i32()?, _ => {} }; - self.local_vars.insert(name.to_string(), Rc::new(RefCell::new(value))); //insert or update + self.local_vars + .insert(name.to_string(), Rc::new(RefCell::new(value))); //insert or update } Op::DefMap(len) => { let mut map = HashMap::new(); @@ -203,12 +204,17 @@ impl Vm { let function_name = chunk.constants[*function_name_index].to_string(); if let Some(fun) = GLOBAL_FUNCTIONS.get(&function_name) { - let return_value = (fun.function)(Rc::new(RefCell::new(Value::Void)).borrow_mut(), args)?; + let return_value = + (fun.function)(Rc::new(RefCell::new(Value::Void)).borrow_mut(), args)?; self.push(Rc::new(RefCell::new(return_value))); } else { - let function_chunk = self.registry.get(&function_name).or_else(|| { - self.registry.get(&format!("{}/{}", context, function_name)) - }); + let function_chunk = self + .registry + .get(&function_name) + .or_else(|| { + self.registry.get(&format!("{}/{}", context, function_name)) + }) + .or(self.registry.get(&function_name)); if function_chunk.is_none() { let constructor = chunk.object_defs.get(&function_name); @@ -235,7 +241,7 @@ impl Vm { return Err(RuntimeError::FunctionNotFound(function_name)); } } else { - let result = interpret_function(function_chunk.unwrap(), args)?; + let result = interpret_function(function_chunk.unwrap(), args, self.registry.clone())?; self.push(Rc::new(RefCell::new(result))); } }