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:")
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))

View file

@ -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;

View file

@ -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())
);
}

View file

@ -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<Vec<Token>, CompilerErrorAtLine> {
let scanner = Scanner {
@ -16,6 +15,8 @@ pub fn scan(source: &str) -> Result<Vec<Token>, 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<Token>,
line: usize,
new_line: bool,
spaces: usize,
spaces_in_indent: usize,
}
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)
}
pub fn interpret_function(chunk: &AsmChunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
let mut vm = Vm::new(&Arc::new(HashMap::new()));
pub fn interpret_function(chunk: &AsmChunk, args: Vec<Value>, registry: Arc<AsmRegistry>) -> Result<Value, RuntimeError> {
let mut vm = Vm::new(&registry);
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(|| {
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)));
}
}