range loop working

This commit is contained in:
Shautvast 2025-11-17 07:11:38 +01:00
parent db183e95c4
commit 8c728f6acb
11 changed files with 246 additions and 47 deletions

View file

@ -1,12 +1,18 @@
use crate::ast_compiler::Expression::{ use crate::ast_compiler::Expression::{
FieldGet, FunctionCall, ListGet, MapGet, MethodCall, NamedParameter, Stop, Variable, Assignment, FieldGet, FunctionCall, ListGet, MapGet, MethodCall, NamedParameter, Stop, Variable,
}; };
use crate::errors::CompilerError::{ use crate::errors::CompilerError::{
self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable, self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable,
}; };
use crate::errors::CompilerErrorAtLine; use crate::errors::CompilerErrorAtLine;
use crate::symbol_builder::{Symbol, calculate_type, infer_type}; use crate::symbol_builder::{Symbol, calculate_type, infer_type};
use crate::tokens::TokenType::{Bang, Bool, Char, Colon, DateTime, Dot, Eof, Eol, Equal, False, FloatingPoint, Fn, Greater, GreaterEqual, GreaterGreater, Identifier, If, Indent, Integer, LeftBrace, LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print, RightBrace, RightBracket, RightParen, SingleRightArrow, Slash, Star, StringType, True, U32, U64, Unknown, Else}; use crate::tokens::TokenType::{
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For,
Greater, GreaterEqual, GreaterGreater, Identifier, If, In, Indent, Integer, LeftBrace,
LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus,
Print, Range, RightBrace, RightBracket, RightParen, SingleRightArrow, Slash, Star, StringType,
True, U32, U64, Unknown,
};
use crate::tokens::{Token, TokenType}; use crate::tokens::{Token, TokenType};
use crate::value::Value; use crate::value::Value;
use crate::{Expr, Stmt, SymbolTable}; use crate::{Expr, Stmt, SymbolTable};
@ -66,6 +72,9 @@ impl AstCompiler {
if !self.had_error { if !self.had_error {
let mut statements = vec![]; let mut statements = vec![];
while !self.is_at_end() { while !self.is_at_end() {
if self.match_token(&[Eol]) {
continue;
}
let statement = self.indent(symbol_table)?; let statement = self.indent(symbol_table)?;
if let Some(statement) = statement { if let Some(statement) = statement {
statements.push(statement); statements.push(statement);
@ -316,11 +325,29 @@ impl AstCompiler {
self.print_statement(symbol_table) self.print_statement(symbol_table)
} else if self.match_token(&[If]) { } else if self.match_token(&[If]) {
self.if_statement(symbol_table) self.if_statement(symbol_table)
} else if self.match_token(&[For]) {
self.for_statement(symbol_table)
} else { } else {
self.expr_statement(symbol_table) self.expr_statement(symbol_table)
} }
} }
fn for_statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt {
let loop_var = self.consume(&Identifier, Expected("loop variable name."))?;
self.consume(&In, Expected("'in' after loop variable name."))?;
let range = self.expression(symbol_table)?;
self.consume(&Colon, Expected("colon after range expression"))?;
self.consume(&Eol, Expected("end of line after for expression."))?;
self.inc_indent();
let body = self.compile(symbol_table)?;
Ok(Statement::ForStatement {
loop_var,
range,
body,
})
}
fn if_statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt { fn if_statement(&mut self, symbol_table: &mut SymbolTable) -> Stmt {
let condition = self.expression(symbol_table)?; let condition = self.expression(symbol_table)?;
self.consume(&Colon, Expected("':' after if condition."))?; self.consume(&Colon, Expected("':' after if condition."))?;
@ -337,7 +364,11 @@ impl AstCompiler {
} else { } else {
None None
}; };
Ok(Statement::IfStatement {condition, then_branch, else_branch}) Ok(Statement::IfStatement {
condition,
then_branch,
else_branch,
})
} }
fn inc_indent(&mut self) { fn inc_indent(&mut self) {
@ -389,7 +420,21 @@ impl AstCompiler {
fn assignment(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn assignment(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let expr = self.equality(symbol_table)?; let expr = self.equality(symbol_table)?;
self.binary(&[TokenType::Equal], expr, symbol_table) if self.match_token(&[Equal]) {
let operator = self.previous().clone();
let right = self.comparison(symbol_table)?;
if let Variable { name, .. } = expr {
Ok(Assignment {
line: operator.line,
variable_name: name.to_string(),
value: Box::new(right),
})
} else {
Err(self.raise(CompilerError::Failure))
}
} else {
Ok(expr)
}
} }
fn equality(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn equality(&mut self, symbol_table: &mut SymbolTable) -> Expr {
@ -402,7 +447,7 @@ impl AstCompiler {
} }
fn comparison(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn comparison(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let expr = self.bitshift(symbol_table)?; let expr = self.range(symbol_table)?;
self.binary( self.binary(
&[Greater, GreaterEqual, Less, LessEqual], &[Greater, GreaterEqual, Less, LessEqual],
expr, expr,
@ -410,6 +455,20 @@ impl AstCompiler {
) )
} }
fn range(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let mut expr = self.bitshift(symbol_table)?;
if self.match_token(&[Range]) {
let operator = self.previous().clone();
let right = self.expression(symbol_table)?;
expr = Expression::Range {
line: operator.line,
lower: Box::new(expr),
upper: Box::new(right),
};
}
Ok(expr)
}
fn bitshift(&mut self, symbol_table: &mut SymbolTable) -> Expr { fn bitshift(&mut self, symbol_table: &mut SymbolTable) -> Expr {
let expr = self.term(symbol_table)?; let expr = self.term(symbol_table)?;
self.binary(&[GreaterGreater, LessLess], expr, symbol_table) self.binary(&[GreaterGreater, LessLess], expr, symbol_table)
@ -805,11 +864,16 @@ pub enum Statement {
if_expr: Expression, if_expr: Expression,
then_expr: Expression, then_expr: Expression,
}, },
IfStatement{ IfStatement {
condition: Expression, condition: Expression,
then_branch: Vec<Statement>, then_branch: Vec<Statement>,
else_branch: Option<Vec<Statement>> else_branch: Option<Vec<Statement>>,
} },
ForStatement {
loop_var: Token,
range: Expression,
body: Vec<Statement>,
},
} }
impl Statement { impl Statement {
@ -822,6 +886,7 @@ impl Statement {
Statement::ObjectStmt { name, .. } => name.line, Statement::ObjectStmt { name, .. } => name.line,
Statement::GuardStatement { if_expr, .. } => if_expr.line(), Statement::GuardStatement { if_expr, .. } => if_expr.line(),
Statement::IfStatement { condition, .. } => condition.line(), Statement::IfStatement { condition, .. } => condition.line(),
Statement::ForStatement { loop_var, .. } => loop_var.line,
} }
} }
} }
@ -867,6 +932,11 @@ pub enum Expression {
literaltype: TokenType, literaltype: TokenType,
value: Value, value: Value,
}, },
Range {
line: usize,
lower: Box<Expression>,
upper: Box<Expression>,
},
List { List {
line: usize, line: usize,
literaltype: TokenType, literaltype: TokenType,
@ -882,6 +952,11 @@ pub enum Expression {
name: String, name: String,
var_type: TokenType, var_type: TokenType,
}, },
Assignment {
line: usize,
variable_name: String,
value: Box<Expression>,
},
FunctionCall { FunctionCall {
line: usize, line: usize,
name: String, name: String,
@ -922,9 +997,11 @@ impl Expression {
Self::Unary { line, .. } => *line, Self::Unary { line, .. } => *line,
Self::Grouping { line, .. } => *line, Self::Grouping { line, .. } => *line,
Self::Literal { line, .. } => *line, Self::Literal { line, .. } => *line,
Self::Range { line, .. } => *line,
Self::List { line, .. } => *line, Self::List { line, .. } => *line,
Self::Map { line, .. } => *line, Self::Map { line, .. } => *line,
Variable { line, .. } => *line, Variable { line, .. } => *line,
Assignment { line, .. } => *line,
FunctionCall { line, .. } => *line, FunctionCall { line, .. } => *line,
MethodCall { line, .. } => *line, MethodCall { line, .. } => *line,
Stop { line } => *line, Stop { line } => *line,

View file

@ -7,10 +7,10 @@ use crate::errors::{CompilerError, CompilerErrorAtLine};
use crate::symbol_builder::{Symbol, calculate_type, infer_type}; use crate::symbol_builder::{Symbol, calculate_type, infer_type};
use crate::tokens::TokenType; use crate::tokens::TokenType;
use crate::tokens::TokenType::Unknown; use crate::tokens::TokenType::Unknown;
use crate::value::{Value}; use crate::value::Value;
use crate::vm::{ use crate::vm::{
OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CALL_BUILTIN, OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CALL_BUILTIN,
OP_CONSTANT, OP_DEF_LIST, OP_DEF_MAP, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_CONSTANT, OP_DEF_LIST, OP_DEF_MAP, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GOTO_IF, OP_GREATER,
OP_GREATER_EQUAL, OP_IF, OP_IF_ELSE, OP_LESS, OP_LESS_EQUAL, OP_LIST_GET, OP_MULTIPLY, OP_GREATER_EQUAL, OP_IF, OP_IF_ELSE, OP_LESS, OP_LESS_EQUAL, OP_LIST_GET, OP_MULTIPLY,
OP_NEGATE, OP_NOT, OP_OR, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_NEGATE, OP_NOT, OP_OR, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
}; };
@ -76,6 +76,7 @@ impl Compiler {
} }
} }
/// compile the entire AST into a chunk, adding a RETURN OP
pub(crate) fn compile( pub(crate) fn compile(
&mut self, &mut self,
ast: &Vec<Statement>, ast: &Vec<Statement>,
@ -83,20 +84,28 @@ impl Compiler {
registry: &mut Registry, registry: &mut Registry,
namespace: &str, namespace: &str,
) -> Result<Chunk, CompilerErrorAtLine> { ) -> Result<Chunk, CompilerErrorAtLine> {
for statement in ast { self.compile_statements(ast, symbols, registry, namespace)?;
self.compile_statement(statement, symbols, registry, namespace)?;
}
self.emit_byte(OP_RETURN); self.emit_byte(OP_RETURN);
let chunk = self.chunk.clone(); let chunk = self.chunk.clone();
self.chunk.code.clear(); // in case the compiler is reused, clear it for the next compilation. This is for the REPL self.chunk.code.clear(); // in case the compiler is reused, clear it for the next compilation. This is for the REPL
Ok(chunk) Ok(chunk)
} }
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine { /// compile the entire AST into a chunk
CompilerErrorAtLine::raise(error, self.current_line) fn compile_statements(
&mut self,
ast: &Vec<Statement>,
symbols: &SymbolTable,
registry: &mut Registry,
namespace: &str,
) -> Result<(), CompilerErrorAtLine> {
for statement in ast {
self.compile_statement(statement, symbols, registry, namespace)?;
}
Ok(())
} }
/// compile a single statement
fn compile_statement( fn compile_statement(
&mut self, &mut self,
statement: &Statement, statement: &Statement,
@ -174,6 +183,38 @@ impl Compiler {
)?; )?;
} }
} }
Statement::ForStatement {
loop_var,
range,
body,
} => {
// 1. step var index
let step_const_index = self.emit_constant(Value::I64(1));
// 2. range expression
self.compile_expression(namespace, range, symbols, registry)?;
//save the constants for lower and upper bounds of the range
let start_index = self.chunk.constants.len() - 1;
let end_index = self.chunk.constants.len() - 2;
let name = loop_var.lexeme.as_str();
let loop_var_name_index = self.chunk.add_var(&loop_var.token_type, name);
self.vars.insert(name.to_string(), loop_var_name_index);
// 3. start index
self.emit_bytes(OP_CONSTANT, start_index as u16);
self.emit_bytes(OP_ASSIGN, loop_var_name_index as u16);
let return_addr = self.chunk.code.len();
self.compile_statements(body, symbols, registry, namespace)?;
self.emit_bytes(OP_GET, loop_var_name_index as u16);
self.emit_bytes(OP_CONSTANT, step_const_index);
self.emit_byte(OP_ADD);
self.emit_bytes(OP_ASSIGN, loop_var_name_index as u16);
self.emit_bytes(OP_CONSTANT, end_index as u16);
self.emit_bytes(OP_GET, loop_var_name_index as u16);
self.emit_byte(OP_GREATER_EQUAL);
self.emit_bytes(OP_GOTO_IF, return_addr as u16);
}
} }
Ok(()) Ok(())
} }
@ -262,6 +303,15 @@ impl Compiler {
return Err(self.raise(UndeclaredVariable(name.to_string()))); return Err(self.raise(UndeclaredVariable(name.to_string())));
} }
} }
Expression::Assignment { variable_name, value, .. } => {
self.compile_expression(namespace, value, symbols, registry)?;
let name_index = self.vars.get(variable_name);
if let Some(name_index) = name_index {
self.emit_bytes(OP_ASSIGN, *name_index as u16);
} else {
return Err(self.raise(UndeclaredVariable(variable_name.to_string())));
}
}
Expression::Literal { value, .. } => { Expression::Literal { value, .. } => {
self.emit_constant(value.clone()); self.emit_constant(value.clone());
} }
@ -343,6 +393,11 @@ impl Compiler {
} }
Expression::MapGet { .. } => {} Expression::MapGet { .. } => {}
Expression::FieldGet { .. } => {} Expression::FieldGet { .. } => {}
Expression::Range { lower, upper, .. } => {
// opposite order, because we have to assign last one first to the loop variable
self.compile_expression(namespace, upper, symbols, registry)?;
self.compile_expression(namespace, lower, symbols, registry)?;
}
} }
Ok(()) Ok(())
} }
@ -393,4 +448,8 @@ impl Compiler {
self.emit_bytes(OP_CONSTANT, index); self.emit_bytes(OP_CONSTANT, index);
index index
} }
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine {
CompilerErrorAtLine::raise(error, self.current_line)
}
} }

View file

@ -5,7 +5,7 @@ use crate::vm::{
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32, OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32,
OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEFINE, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEFINE,
OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY,
OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,OP_ASSIGN,OP_GOTO_IF
}; };
use std::collections::HashMap; use std::collections::HashMap;
@ -117,9 +117,11 @@ impl Chunk {
OP_DEF_F64 => self.constant_inst("DEFF64", offset), OP_DEF_F64 => self.constant_inst("DEFF64", offset),
OP_DEF_BOOL => self.constant_inst("DEFBOOL", offset), OP_DEF_BOOL => self.constant_inst("DEFBOOL", offset),
OP_CALL => self.call_inst("CALL", offset), OP_CALL => self.call_inst("CALL", offset),
OP_GET => self.constant_inst("GET", offset), OP_GET => self.assign_inst("GET", offset),
OP_DEF_LIST => self.new_inst("DEFLIST", offset), OP_DEF_LIST => self.new_inst("DEFLIST", offset),
OP_DEF_MAP => self.new_inst("DEFMAP", offset), OP_DEF_MAP => self.new_inst("DEFMAP", offset),
OP_ASSIGN => self.assign_inst("ASSIGN", offset),
OP_GOTO_IF => self.constant_inst("GOTO_IF", offset),
_ => { _ => {
println!("Unknown instruction {}", instruction); println!("Unknown instruction {}", instruction);
offset + 1 offset + 1
@ -132,6 +134,13 @@ impl Chunk {
offset + 1 offset + 1
} }
fn assign_inst(&self, op: &str, offset: usize) -> usize {
let constant = self.code[offset + 1];
print!("{} {}:", op, constant);
println!("{}",self.vars.get(constant as usize).unwrap().1);
offset + 2
}
fn call_inst(&self, op: &str, offset: usize) -> usize { fn call_inst(&self, op: &str, offset: usize) -> usize {
let constant = self.code[offset + 1]; let constant = self.code[offset + 1];
let num_args = self.code[offset + 2]; let num_args = self.code[offset + 2];

View file

@ -156,7 +156,7 @@ object Person:
let p = Person(name: 0x42) let p = Person(name: 0x42)
p"#); p"#);
assert!(r.is_err()); // assert!(r.is_err());
assert_eq!( assert_eq!(
r#"Compilation failed: error at line 5, Expected string, found integer"#, r#"Compilation failed: error at line 5, Expected string, found integer"#,
format!("{}", r.unwrap_err().to_string()) format!("{}", r.unwrap_err().to_string())
@ -386,6 +386,24 @@ else:
); );
} }
#[test]
fn inline_comment(){
assert_eq!(run(r#"// this is a comment"#), Ok(Value::Void));
}
#[test]
fn range_loop() {
assert_eq!(
run(r#"
let sum=0
for a in 1..4:
sum = sum + a
sum
"#),
Ok(Value::I64(10))
);
}
// #[test] // #[test]
// fn package() { // fn package() {
// assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48))); // assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48)));

View file

@ -13,6 +13,7 @@ pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
"fn" => Some(TokenType::Fn), "fn" => Some(TokenType::Fn),
"for" => Some(TokenType::For), "for" => Some(TokenType::For),
"if" => Some(TokenType::If), "if" => Some(TokenType::If),
"in" => Some(TokenType::In),
"i32" => Some(TokenType::I32), "i32" => Some(TokenType::I32),
"i64" => Some(TokenType::I64), "i64" => Some(TokenType::I64),
"let" => Some(TokenType::Let), "let" => Some(TokenType::Let),

View file

@ -7,6 +7,7 @@ use crate::symbol_builder::Symbol;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
use walkdir::WalkDir; use walkdir::WalkDir;
use crate::value::Value::Void;
pub mod ast_compiler; pub mod ast_compiler;
mod builtins; mod builtins;
@ -92,6 +93,7 @@ pub(crate) fn run(src: &str) -> Result<value::Value, CrudLangError> {
symbol_builder::build("", &ast, &mut symbol_table); symbol_builder::build("", &ast, &mut symbol_table);
let mut registry = HashMap::new(); let mut registry = HashMap::new();
bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?; bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?;
let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(registry)); let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(registry));
vm::interpret(registry.load(), "main").map_err(CrudLangError::from) vm::interpret(registry.load(), "main").map_err(CrudLangError::from)
} }

View file

@ -2,7 +2,7 @@ use crate::chunk::Chunk;
use crate::errors::CrudLangError; use crate::errors::CrudLangError;
use crate::scanner::scan; use crate::scanner::scan;
use crate::vm::Vm; use crate::vm::Vm;
use crate::{ast_compiler, bytecode_compiler, map_underlying, recompile, symbol_builder}; use crate::{ast_compiler, bytecode_compiler, map_underlying, symbol_builder};
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use std::collections::HashMap; use std::collections::HashMap;
use std::io; use std::io;

View file

@ -142,7 +142,7 @@ impl Scanner {
if c == '0' && self.peek() == 'x' { if c == '0' && self.peek() == 'x' {
self.hex_number()?; self.hex_number()?;
} else if c.is_ascii_digit() { } else if c.is_ascii_digit() {
self.number(); self.number_or_range();
} else if is_alpha(c) { } else if is_alpha(c) {
self.identifier(); self.identifier();
} else { } else {
@ -181,7 +181,7 @@ impl Scanner {
Ok(()) Ok(())
} }
fn number(&mut self) { fn number_or_range(&mut self) {
while self.peek().is_ascii_digit() { while self.peek().is_ascii_digit() {
self.advance(); self.advance();
} }
@ -190,12 +190,29 @@ impl Scanner {
has_dot = true; has_dot = true;
self.advance(); self.advance();
} }
if self.peek() == '.' && self.peek_next() == '.' {
self.range_expression()
} else {
while is_digit_or_scientific(self.peek()) {
self.advance();
}
let value: String = self.chars[self.start..self.current].iter().collect();
self.add_token_with_value(if has_dot { FloatingPoint } else { Integer }, value);
}
}
while is_digit_or_scientific(self.peek()) { fn range_expression(&mut self) {
let lower: String = self.chars[self.start..self.current].iter().collect();
self.match_next('.');
self.match_next('.');
self.add_token_with_value(Integer, lower);
self.add_token(TokenType::Range);
self.start = self.current;
while self.peek().is_ascii_digit() {
self.advance(); self.advance();
} }
let value: String = self.chars[self.start..self.current].iter().collect(); let upper: String = self.chars[self.start..self.current].iter().collect();
self.add_token_with_value(if has_dot { FloatingPoint } else { Integer }, value); self.add_token_with_value(Integer, upper);
} }
fn char(&mut self) -> Result<(), CompilerErrorAtLine> { fn char(&mut self) -> Result<(), CompilerErrorAtLine> {
@ -265,11 +282,15 @@ impl Scanner {
} }
fn peek_next(&self) -> char { fn peek_next(&self) -> char {
self.chars[self.current + 1] if self.current + 1 >= self.chars.len() {
'\0'
} else {
self.chars[self.current + 1]
}
} }
fn match_next(&mut self, expected: char) -> bool { fn match_next(&mut self, expected: char) -> bool {
if self.is_at_end() || self.chars[self.current] != expected{ if self.is_at_end() || self.chars[self.current] != expected {
false false
} else { } else {
self.current += 1; self.current += 1;
@ -304,13 +325,12 @@ struct Scanner {
new_line: bool, new_line: bool,
} }
fn is_digit_or_scientific(c: char) -> bool { fn is_digit_or_scientific(c: char) -> bool {
c.is_ascii_digit() || c == 'e' || c == 'E' c.is_ascii_digit() || c == 'e' || c == 'E'
} }
fn is_alphanumeric(c: char) -> bool { fn is_alphanumeric(c: char) -> bool {
is_alpha(c) || c.is_ascii_digit() is_alpha(c) || c.is_ascii_digit()
} }
fn is_alpha(c: char) -> bool { fn is_alpha(c: char) -> bool {

View file

@ -1,5 +1,5 @@
use crate::ast_compiler::{Expression, Parameter, Statement}; use crate::ast_compiler::{Expression, Parameter, Statement};
use crate::builtins::{Signature, lookup}; use crate::builtins::lookup;
use crate::errors::CompilerError; use crate::errors::CompilerError;
use crate::errors::CompilerError::IncompatibleTypes; use crate::errors::CompilerError::IncompatibleTypes;
use crate::tokens::TokenType::{ use crate::tokens::TokenType::{
@ -186,6 +186,7 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
} }
} }
Expression::Variable { var_type, .. } => var_type.clone(), Expression::Variable { var_type, .. } => var_type.clone(),
Expression::Assignment { value, .. } => infer_type(value, symbols),
Expression::FunctionCall { name, .. } => { Expression::FunctionCall { name, .. } => {
let symbol = symbols.get(name); let symbol = symbols.get(name);
match symbol { match symbol {
@ -203,7 +204,7 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
if let Ok(signature) = lookup(&value.to_string(), method_name) { if let Ok(signature) = lookup(&value.to_string(), method_name) {
signature.return_type.clone() signature.return_type.clone()
} else { } else {
unreachable!()//? unreachable!() //?
} }
} else { } else {
infer_type(receiver, symbols) infer_type(receiver, symbols)
@ -215,5 +216,6 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
Expression::ListGet { .. } => TokenType::Unknown, Expression::ListGet { .. } => TokenType::Unknown,
Expression::MapGet { .. } => TokenType::Unknown, Expression::MapGet { .. } => TokenType::Unknown,
Expression::FieldGet { .. } => TokenType::Unknown, Expression::FieldGet { .. } => TokenType::Unknown,
Expression::Range { lower, .. } => infer_type(lower, symbols),
} }
} }

View file

@ -51,6 +51,7 @@ pub enum TokenType {
I64, I64,
Identifier, Identifier,
If, If,
In,
Indent, Indent,
Integer, Integer,
SignedInteger, SignedInteger,
@ -73,6 +74,7 @@ pub enum TokenType {
Plus, Plus,
Print, Print,
Question, Question,
Range,
Return, Return,
RightParen, RightParen,
RightBrace, RightBrace,
@ -132,6 +134,7 @@ impl fmt::Display for TokenType {
TokenType::Hex => write!(f, "0x"), TokenType::Hex => write!(f, "0x"),
TokenType::If => write!(f, "if"), TokenType::If => write!(f, "if"),
TokenType::Identifier => write!(f, "identifier"), TokenType::Identifier => write!(f, "identifier"),
TokenType::In => write!(f, "in"),
TokenType::Indent => write!(f, "indent"), TokenType::Indent => write!(f, "indent"),
TokenType::Integer => write!(f, "integer"), TokenType::Integer => write!(f, "integer"),
TokenType::LeftBrace => write!(f, "{{"), TokenType::LeftBrace => write!(f, "{{"),
@ -150,6 +153,7 @@ impl fmt::Display for TokenType {
TokenType::Plus => write!(f, "+"), TokenType::Plus => write!(f, "+"),
TokenType::Print => write!(f, "print"), TokenType::Print => write!(f, "print"),
TokenType::Question => write!(f, "?"), TokenType::Question => write!(f, "?"),
TokenType::Range => write!(f, ".."),
TokenType::Return => write!(f, "return"), TokenType::Return => write!(f, "return"),
TokenType::RightParen => write!(f, ")"), TokenType::RightParen => write!(f, ")"),
TokenType::RightBrace => write!(f, "}}"), TokenType::RightBrace => write!(f, "}}"),

View file

@ -1,3 +1,4 @@
use crate::Registry;
use crate::chunk::Chunk; use crate::chunk::Chunk;
use crate::errors::RuntimeError::Something; use crate::errors::RuntimeError::Something;
use crate::errors::{RuntimeError, ValueError}; use crate::errors::{RuntimeError, ValueError};
@ -7,7 +8,6 @@ use arc_swap::Guard;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use tracing::debug; use tracing::debug;
use crate::Registry;
pub struct Vm { pub struct Vm {
ip: usize, ip: usize,
@ -17,14 +17,15 @@ pub struct Vm {
pub(crate) registry: Arc<HashMap<String, Chunk>>, pub(crate) registry: Arc<HashMap<String, Chunk>>,
} }
pub fn interpret( pub fn interpret(
registry: Guard<Arc<HashMap<String, Chunk>>>, registry: Guard<Arc<HashMap<String, Chunk>>>,
function: &str, function: &str,
) -> Result<Value, RuntimeError> { ) -> Result<Value, RuntimeError> {
let chunk = registry.get(function).unwrap().clone(); let chunk = registry.get(function).unwrap().clone();
// chunk.disassemble();
let mut vm = Vm::new(&registry); let mut vm = Vm::new(&registry);
vm.run(&get_context(function), &chunk) vm.run(&get_context(function), &chunk)
// Ok(Value::Void)
} }
pub async fn interpret_async( pub async fn interpret_async(
@ -57,7 +58,7 @@ fn value_map(strings: HashMap<String, String>) -> HashMap<Value, Value> {
} }
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> { pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
let mut vm = Vm::new(& Arc::new(HashMap::new())); let mut vm = Vm::new(&Arc::new(HashMap::new()));
vm.run_function(chunk, args) vm.run_function(chunk, args)
} }
@ -157,7 +158,7 @@ impl Vm {
let (var_type, name) = chunk.vars.get(index).unwrap(); let (var_type, name) = chunk.vars.get(index).unwrap();
let value = self.pop(); let value = self.pop();
let value = Self::number(var_type, value)?; let value = Self::number(var_type, value)?;
self.local_vars.insert(name.to_string(), value); self.local_vars.insert(name.to_string(), value); //insert or update
} }
OP_DEF_MAP => { OP_DEF_MAP => {
let len = self.read(chunk); let len = self.read(chunk);
@ -172,7 +173,7 @@ impl Vm {
OP_GET => { OP_GET => {
let var_index = self.read(chunk); let var_index = self.read(chunk);
let (_, name_index) = chunk.vars.get(var_index).unwrap(); let (_, name_index) = chunk.vars.get(var_index).unwrap();
let value = self.local_vars.remove(name_index).unwrap(); let value = self.local_vars.get(name_index).unwrap().clone();
self.push(value); self.push(value);
} }
OP_LIST_GET => { OP_LIST_GET => {
@ -196,10 +197,11 @@ impl Vm {
} }
args.reverse(); args.reverse();
let receiver = self.pop(); let receiver = self.pop();
let return_value = crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?; let return_value =
crate::builtins::call(&receiver_type_name, &function_name, receiver, args)?;
self.push(return_value); self.push(return_value);
} }
OP_POP =>{ OP_POP => {
self.pop(); // discards the value self.pop(); // discards the value
} }
OP_CALL => { OP_CALL => {
@ -232,12 +234,9 @@ impl Vm {
} }
let mut fields = vec![]; let mut fields = vec![];
params params.iter().zip(args).for_each(|(param, arg)| {
.iter() fields.push((param.name.lexeme.clone(), arg))
.zip(args) });
.for_each(|(param, arg)| {
fields.push((param.name.lexeme.clone(), arg))
});
let new_instance = Value::ObjectType(Box::new(Object { let new_instance = Value::ObjectType(Box::new(Object {
definition: function_name, definition: function_name,
fields, fields,
@ -254,7 +253,7 @@ impl Vm {
OP_IF => { OP_IF => {
let condition = self.pop(); let condition = self.pop();
if condition == Value::Bool(true) { if condition == Value::Bool(true) {
if let Some(then) = self.registry.get(&format!("{}.?",chunk.name)){ if let Some(then) = self.registry.get(&format!("{}.?", chunk.name)) {
let result = interpret_function(then, vec![])?; let result = interpret_function(then, vec![])?;
self.push(result); self.push(result);
} }
@ -263,19 +262,26 @@ impl Vm {
OP_IF_ELSE => { OP_IF_ELSE => {
let condition = self.pop(); let condition = self.pop();
self.push(if condition == Value::Bool(true) { self.push(if condition == Value::Bool(true) {
if let Some(then) = self.registry.get(&format!("{}.?",chunk.name)){ if let Some(then) = self.registry.get(&format!("{}.?", chunk.name)) {
interpret_function(then, vec![])? interpret_function(then, vec![])?
} else { } else {
return Err(Something); return Err(Something);
} }
} else { } else {
if let Some(then) = self.registry.get(&format!("{}.:",chunk.name)){ if let Some(then) = self.registry.get(&format!("{}.:", chunk.name)) {
interpret_function(then, vec![])? interpret_function(then, vec![])?
} else { } else {
return Err(Something); return Err(Something);
} }
}); });
} }
OP_GOTO_IF => {
let b = self.pop();
let goto_addr = self.read(chunk);
if b == Value::Bool(true) {
self.ip = goto_addr;
}
}
_ => {} _ => {}
} }
} }
@ -389,3 +395,4 @@ pub const OP_LIST_GET: u16 = 42;
pub const OP_CALL_BUILTIN: u16 = 43; pub const OP_CALL_BUILTIN: u16 = 43;
pub const OP_IF: u16 = 44; pub const OP_IF: u16 = 44;
pub const OP_IF_ELSE: u16 = 45; pub const OP_IF_ELSE: u16 = 45;
pub const OP_GOTO_IF: u16 = 46;