fixed multiple issues with indenting and recursive method calls

This commit is contained in:
Shautvast 2025-12-13 15:28:05 +01:00
parent 38de69dc93
commit e5b03d9037
5 changed files with 90 additions and 49 deletions

View file

@ -1,8 +1,7 @@
println("Fibonacci sequence:") fn fib(n: u64):
let fib = [1,1] if n < 2:
n
else:
fib(n-1) + fib(n-2)
let r=10 println(fib(10))
for i in 2..r:
fib.push(fib[i-2] + fib[i-1])
println(fib)

View file

@ -181,7 +181,8 @@ impl AsmPass {
); );
} }
Statement::ObjectStmt { name, fields } => { Statement::ObjectStmt { name, fields } => {
self.chunk.add_object_def(&name.lexeme, fields); self.chunk
.add_object_def(&format!("{}/{}", namespace, &name.lexeme), fields);
} }
Statement::GuardStatement { .. } => { Statement::GuardStatement { .. } => {
unimplemented!("guard statement") unimplemented!("guard statement")
@ -229,12 +230,7 @@ impl AsmPass {
self.emit(Goto(0)); self.emit(Goto(0));
let goto_addr2 = self.chunk.code.len() - 1; // placeholder let goto_addr2 = self.chunk.code.len() - 1; // placeholder
self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len()); self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len());
self.compile_statements( self.compile_statements(else_branch, symbols, registry, namespace)?;
else_branch,
symbols,
registry,
namespace,
)?;
self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len()); self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len());
} }
Expression::LetExpression { Expression::LetExpression {
@ -243,13 +239,13 @@ impl AsmPass {
let name = name.lexeme.as_str(); let name = name.lexeme.as_str();
let var = symbols.get(name); let var = symbols.get(name);
if let Some(Symbol::Variable { var_type, .. }) = var { if let Some(Symbol::Variable { var_type, .. }) = var {
let inferred_type = infer_type(initializer, symbols).map_err(|e| self.error_at_line(e))?; let inferred_type =
let calculated_type = infer_type(initializer, symbols).map_err(|e| self.error_at_line(e))?;
calculate_type(var_type, &inferred_type).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 { if var_type != &Unknown && var_type != &calculated_type {
return Err( return Err(self
self.error_at_line(IncompatibleTypes(var_type.clone(), calculated_type)) .error_at_line(IncompatibleTypes(var_type.clone(), calculated_type)));
);
} }
let name_index = self.chunk.add_var(var_type, name); let name_index = self.chunk.add_var(var_type, name);
self.vars.insert(name.to_string(), name_index); self.vars.insert(name.to_string(), name_index);
@ -262,13 +258,14 @@ impl AsmPass {
Expression::FunctionCall { Expression::FunctionCall {
name, arguments, .. name, arguments, ..
} => { } => {
let name_index = self let qname = format!("{}/{}", namespace, name);
.chunk let function = symbols.get(&qname).or(symbols.get(name));
.find_constant(name)
.unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string())));
let function = symbols.get(name);
match function { match function {
Some(Symbol::Function { parameters, .. }) => { 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( self.get_arguments_in_order(
namespace, symbols, registry, arguments, parameters, namespace, symbols, registry, arguments, parameters,
)?; )?;
@ -277,6 +274,9 @@ impl AsmPass {
} }
// constructor function // constructor function
Some(Symbol::Object { fields, .. }) => { 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( self.get_arguments_in_order(
namespace, symbols, registry, arguments, fields, namespace, symbols, registry, arguments, fields,
)?; )?;
@ -285,12 +285,20 @@ impl AsmPass {
// maybe global function // maybe global function
_ => { _ => {
if let Some(fun) = GLOBAL_FUNCTIONS.get(name) { 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())); self.emit(Call(name_index, fun.arity()));
} else { } else {
return Err( return Err(self
self.error_at_line(CompilerError::FunctionNotFound(name.to_string())) .error_at_line(CompilerError::FunctionNotFound(name.to_string())));
);
} }
} }
} }
@ -302,7 +310,9 @@ impl AsmPass {
.. ..
} => { } => {
self.compile_expression(namespace, receiver, symbols, registry)?; 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(|| { let type_index = self.chunk.find_constant(&receiver_type).unwrap_or_else(|| {
self.chunk self.chunk
@ -313,7 +323,8 @@ impl AsmPass {
self.chunk self.chunk
.add_constant(Value::String(method_name.to_string())) .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() { if signature.arity() != arguments.len() {
return Err(self.error_at_line(CompilerError::IllegalArgumentsException( return Err(self.error_at_line(CompilerError::IllegalArgumentsException(
format!("{}.{}", receiver_type, method_name), format!("{}.{}", receiver_type, method_name),
@ -456,8 +467,7 @@ impl AsmPass {
self.vars.insert(name.to_string(), loop_var_name_index); self.vars.insert(name.to_string(), loop_var_name_index);
// 3. start index // 3. start index
let end= let end = if let Expression::Range { lower, upper, .. } = range.deref() {
if let Expression::Range { lower, upper, .. } = range.deref() {
self.compile_expression(namespace, lower, symbols, registry)?; self.compile_expression(namespace, lower, symbols, registry)?;
upper.clone() upper.clone()
} else { } else {
@ -495,10 +505,13 @@ impl AsmPass {
for parameter in parameters { for parameter in parameters {
if let NamedParameter { name, value, .. } = argument { if let NamedParameter { name, value, .. } = argument {
if name.lexeme == parameter.name.lexeme { 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 { if parameter.var_type != value_type {
return Err(self return Err(self.error_at_line(IncompatibleTypes(
.error_at_line(IncompatibleTypes(parameter.var_type.clone(), value_type))); parameter.var_type.clone(),
value_type,
)));
} else { } else {
self.compile_expression(namespace, argument, symbols, registry)?; self.compile_expression(namespace, argument, symbols, registry)?;
break; break;

View file

@ -144,7 +144,7 @@ let p = Person(name: "Sander")
p"#); p"#);
assert!(r.is_ok()); assert!(r.is_ok());
assert_eq!( assert_eq!(
r#"Person: [("name", String("Sander"))]"#, r#"main/Person: [("name", String("Sander"))]"#,
format!("{}", r.unwrap().to_string()) format!("{}", r.unwrap().to_string())
); );
} }

View file

@ -6,7 +6,6 @@ use crate::compiler::tokens::{
use crate::errors::CompilerError::{IllegalCharLength, UnexpectedIdentifier, Unterminated}; use crate::errors::CompilerError::{IllegalCharLength, UnexpectedIdentifier, Unterminated};
use crate::errors::{CompilerError, CompilerErrorAtLine}; use crate::errors::{CompilerError, CompilerErrorAtLine};
use crate::keywords; use crate::keywords;
use axum::http::header::ToStrError;
pub fn scan(source: &str) -> Result<Vec<Token>, CompilerErrorAtLine> { pub fn scan(source: &str) -> Result<Vec<Token>, CompilerErrorAtLine> {
let scanner = Scanner { let scanner = Scanner {
@ -16,6 +15,8 @@ pub fn scan(source: &str) -> Result<Vec<Token>, CompilerErrorAtLine> {
line: 1, line: 1,
tokens: vec![], tokens: vec![],
new_line: true, new_line: true,
spaces: 0,
spaces_in_indent: 0,
}; };
scanner.scan() scanner.scan()
} }
@ -33,10 +34,30 @@ impl Scanner {
fn scan_token(&mut self) -> Result<(), CompilerErrorAtLine> { fn scan_token(&mut self) -> Result<(), CompilerErrorAtLine> {
let c = self.advance(); let c = self.advance();
if self.new_line && (c == ' ' || c == '\t') {
self.add_token(TokenType::Indent); if self.new_line && (c == '\t' || c == ' ') {
self.new_line = false; // first indent using spaces determines how many spaces form an indent
if c == ' ' {
self.spaces += 1;
} else { } 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' { if c != '\n' {
self.new_line = false; self.new_line = false;
} }
@ -346,6 +367,8 @@ struct Scanner {
tokens: Vec<Token>, tokens: Vec<Token>,
line: usize, line: usize,
new_line: bool, new_line: bool,
spaces: usize,
spaces_in_indent: usize,
} }
fn is_digit_or_scientific(c: char) -> bool { fn is_digit_or_scientific(c: char) -> bool {

View file

@ -44,8 +44,8 @@ pub fn interpret(registry: Guard<Arc<AsmRegistry>>, function: &str) -> Result<Va
vm.run(&get_context(function), &chunk) vm.run(&get_context(function), &chunk)
} }
pub fn interpret_function(chunk: &AsmChunk, args: Vec<Value>) -> Result<Value, RuntimeError> { pub fn interpret_function(chunk: &AsmChunk, args: Vec<Value>, registry: Arc<AsmRegistry>) -> Result<Value, RuntimeError> {
let mut vm = Vm::new(&Arc::new(HashMap::new())); let mut vm = Vm::new(&registry);
vm.run_function(chunk, args) vm.run_function(chunk, args)
} }
@ -148,7 +148,8 @@ impl Vm {
TokenType::I32 => value = value.cast_i32()?, 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) => { Op::DefMap(len) => {
let mut map = HashMap::new(); let mut map = HashMap::new();
@ -203,12 +204,17 @@ impl Vm {
let function_name = chunk.constants[*function_name_index].to_string(); let function_name = chunk.constants[*function_name_index].to_string();
if let Some(fun) = GLOBAL_FUNCTIONS.get(&function_name) { 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))); self.push(Rc::new(RefCell::new(return_value)));
} else { } else {
let function_chunk = self.registry.get(&function_name).or_else(|| { let function_chunk = self
.registry
.get(&function_name)
.or_else(|| {
self.registry.get(&format!("{}/{}", context, function_name)) self.registry.get(&format!("{}/{}", context, function_name))
}); })
.or(self.registry.get(&function_name));
if function_chunk.is_none() { if function_chunk.is_none() {
let constructor = chunk.object_defs.get(&function_name); let constructor = chunk.object_defs.get(&function_name);
@ -235,7 +241,7 @@ impl Vm {
return Err(RuntimeError::FunctionNotFound(function_name)); return Err(RuntimeError::FunctionNotFound(function_name));
} }
} else { } 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))); self.push(Rc::new(RefCell::new(result)));
} }
} }