fixed multiple issues with indenting and recursive method calls
This commit is contained in:
parent
38de69dc93
commit
e5b03d9037
5 changed files with 90 additions and 49 deletions
|
|
@ -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)
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
self.add_token(TokenType::Indent);
|
||||||
|
}
|
||||||
} else {
|
} 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 {
|
||||||
|
|
|
||||||
22
src/vm.rs
22
src/vm.rs
|
|
@ -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(®istry);
|
||||||
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
|
||||||
self.registry.get(&format!("{}/{}", context, function_name))
|
.registry
|
||||||
});
|
.get(&function_name)
|
||||||
|
.or_else(|| {
|
||||||
|
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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue