range loop working
This commit is contained in:
parent
db183e95c4
commit
8c728f6acb
11 changed files with 246 additions and 47 deletions
|
|
@ -1,12 +1,18 @@
|
|||
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::{
|
||||
self, Expected, ParseError, TooManyParameters, UnexpectedIndent, UninitializedVariable,
|
||||
};
|
||||
use crate::errors::CompilerErrorAtLine;
|
||||
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::value::Value;
|
||||
use crate::{Expr, Stmt, SymbolTable};
|
||||
|
|
@ -66,6 +72,9 @@ impl AstCompiler {
|
|||
if !self.had_error {
|
||||
let mut statements = vec![];
|
||||
while !self.is_at_end() {
|
||||
if self.match_token(&[Eol]) {
|
||||
continue;
|
||||
}
|
||||
let statement = self.indent(symbol_table)?;
|
||||
if let Some(statement) = statement {
|
||||
statements.push(statement);
|
||||
|
|
@ -316,11 +325,29 @@ impl AstCompiler {
|
|||
self.print_statement(symbol_table)
|
||||
} else if self.match_token(&[If]) {
|
||||
self.if_statement(symbol_table)
|
||||
} else if self.match_token(&[For]) {
|
||||
self.for_statement(symbol_table)
|
||||
} else {
|
||||
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 {
|
||||
let condition = self.expression(symbol_table)?;
|
||||
self.consume(&Colon, Expected("':' after if condition."))?;
|
||||
|
|
@ -337,7 +364,11 @@ impl AstCompiler {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
Ok(Statement::IfStatement {condition, then_branch, else_branch})
|
||||
Ok(Statement::IfStatement {
|
||||
condition,
|
||||
then_branch,
|
||||
else_branch,
|
||||
})
|
||||
}
|
||||
|
||||
fn inc_indent(&mut self) {
|
||||
|
|
@ -389,7 +420,21 @@ impl AstCompiler {
|
|||
|
||||
fn assignment(&mut self, symbol_table: &mut SymbolTable) -> Expr {
|
||||
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 {
|
||||
|
|
@ -402,7 +447,7 @@ impl AstCompiler {
|
|||
}
|
||||
|
||||
fn comparison(&mut self, symbol_table: &mut SymbolTable) -> Expr {
|
||||
let expr = self.bitshift(symbol_table)?;
|
||||
let expr = self.range(symbol_table)?;
|
||||
self.binary(
|
||||
&[Greater, GreaterEqual, Less, LessEqual],
|
||||
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 {
|
||||
let expr = self.term(symbol_table)?;
|
||||
self.binary(&[GreaterGreater, LessLess], expr, symbol_table)
|
||||
|
|
@ -808,8 +867,13 @@ pub enum Statement {
|
|||
IfStatement {
|
||||
condition: Expression,
|
||||
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 {
|
||||
|
|
@ -822,6 +886,7 @@ impl Statement {
|
|||
Statement::ObjectStmt { name, .. } => name.line,
|
||||
Statement::GuardStatement { if_expr, .. } => if_expr.line(),
|
||||
Statement::IfStatement { condition, .. } => condition.line(),
|
||||
Statement::ForStatement { loop_var, .. } => loop_var.line,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -867,6 +932,11 @@ pub enum Expression {
|
|||
literaltype: TokenType,
|
||||
value: Value,
|
||||
},
|
||||
Range {
|
||||
line: usize,
|
||||
lower: Box<Expression>,
|
||||
upper: Box<Expression>,
|
||||
},
|
||||
List {
|
||||
line: usize,
|
||||
literaltype: TokenType,
|
||||
|
|
@ -882,6 +952,11 @@ pub enum Expression {
|
|||
name: String,
|
||||
var_type: TokenType,
|
||||
},
|
||||
Assignment {
|
||||
line: usize,
|
||||
variable_name: String,
|
||||
value: Box<Expression>,
|
||||
},
|
||||
FunctionCall {
|
||||
line: usize,
|
||||
name: String,
|
||||
|
|
@ -922,9 +997,11 @@ impl Expression {
|
|||
Self::Unary { line, .. } => *line,
|
||||
Self::Grouping { line, .. } => *line,
|
||||
Self::Literal { line, .. } => *line,
|
||||
Self::Range { line, .. } => *line,
|
||||
Self::List { line, .. } => *line,
|
||||
Self::Map { line, .. } => *line,
|
||||
Variable { line, .. } => *line,
|
||||
Assignment { line, .. } => *line,
|
||||
FunctionCall { line, .. } => *line,
|
||||
MethodCall { line, .. } => *line,
|
||||
Stop { line } => *line,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ use crate::errors::{CompilerError, CompilerErrorAtLine};
|
|||
use crate::symbol_builder::{Symbol, calculate_type, infer_type};
|
||||
use crate::tokens::TokenType;
|
||||
use crate::tokens::TokenType::Unknown;
|
||||
use crate::value::{Value};
|
||||
use crate::value::Value;
|
||||
use crate::vm::{
|
||||
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_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(
|
||||
&mut self,
|
||||
ast: &Vec<Statement>,
|
||||
|
|
@ -83,20 +84,28 @@ impl Compiler {
|
|||
registry: &mut Registry,
|
||||
namespace: &str,
|
||||
) -> Result<Chunk, CompilerErrorAtLine> {
|
||||
for statement in ast {
|
||||
self.compile_statement(statement, symbols, registry, namespace)?;
|
||||
}
|
||||
|
||||
self.compile_statements(ast, symbols, registry, namespace)?;
|
||||
self.emit_byte(OP_RETURN);
|
||||
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
|
||||
Ok(chunk)
|
||||
}
|
||||
|
||||
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine {
|
||||
CompilerErrorAtLine::raise(error, self.current_line)
|
||||
/// compile the entire AST into a chunk
|
||||
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(
|
||||
&mut self,
|
||||
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(())
|
||||
}
|
||||
|
|
@ -262,6 +303,15 @@ impl Compiler {
|
|||
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, .. } => {
|
||||
self.emit_constant(value.clone());
|
||||
}
|
||||
|
|
@ -343,6 +393,11 @@ impl Compiler {
|
|||
}
|
||||
Expression::MapGet { .. } => {}
|
||||
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(())
|
||||
}
|
||||
|
|
@ -393,4 +448,8 @@ impl Compiler {
|
|||
self.emit_bytes(OP_CONSTANT, index);
|
||||
index
|
||||
}
|
||||
|
||||
fn raise(&self, error: CompilerError) -> CompilerErrorAtLine {
|
||||
CompilerErrorAtLine::raise(error, self.current_line)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
13
src/chunk.rs
13
src/chunk.rs
|
|
@ -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_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_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;
|
||||
|
||||
|
|
@ -117,9 +117,11 @@ impl Chunk {
|
|||
OP_DEF_F64 => self.constant_inst("DEFF64", offset),
|
||||
OP_DEF_BOOL => self.constant_inst("DEFBOOL", 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_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);
|
||||
offset + 1
|
||||
|
|
@ -132,6 +134,13 @@ impl Chunk {
|
|||
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 {
|
||||
let constant = self.code[offset + 1];
|
||||
let num_args = self.code[offset + 2];
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ object Person:
|
|||
|
||||
let p = Person(name: 0x42)
|
||||
p"#);
|
||||
assert!(r.is_err());
|
||||
// assert!(r.is_err());
|
||||
assert_eq!(
|
||||
r#"Compilation failed: error at line 5, Expected string, found integer"#,
|
||||
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]
|
||||
// fn package() {
|
||||
// assert_eq!(run(r#"a.b.c()"#), Ok(Value::U32(48)));
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
|||
"fn" => Some(TokenType::Fn),
|
||||
"for" => Some(TokenType::For),
|
||||
"if" => Some(TokenType::If),
|
||||
"in" => Some(TokenType::In),
|
||||
"i32" => Some(TokenType::I32),
|
||||
"i64" => Some(TokenType::I64),
|
||||
"let" => Some(TokenType::Let),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use crate::symbol_builder::Symbol;
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use walkdir::WalkDir;
|
||||
use crate::value::Value::Void;
|
||||
|
||||
pub mod ast_compiler;
|
||||
mod builtins;
|
||||
|
|
@ -92,6 +93,7 @@ pub(crate) fn run(src: &str) -> Result<value::Value, CrudLangError> {
|
|||
symbol_builder::build("", &ast, &mut symbol_table);
|
||||
let mut registry = HashMap::new();
|
||||
bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?;
|
||||
|
||||
let registry = arc_swap::ArcSwap::from(std::sync::Arc::new(registry));
|
||||
vm::interpret(registry.load(), "main").map_err(CrudLangError::from)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::chunk::Chunk;
|
|||
use crate::errors::CrudLangError;
|
||||
use crate::scanner::scan;
|
||||
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 std::collections::HashMap;
|
||||
use std::io;
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ impl Scanner {
|
|||
if c == '0' && self.peek() == 'x' {
|
||||
self.hex_number()?;
|
||||
} else if c.is_ascii_digit() {
|
||||
self.number();
|
||||
self.number_or_range();
|
||||
} else if is_alpha(c) {
|
||||
self.identifier();
|
||||
} else {
|
||||
|
|
@ -181,7 +181,7 @@ impl Scanner {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn number(&mut self) {
|
||||
fn number_or_range(&mut self) {
|
||||
while self.peek().is_ascii_digit() {
|
||||
self.advance();
|
||||
}
|
||||
|
|
@ -190,13 +190,30 @@ impl Scanner {
|
|||
has_dot = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
let upper: String = self.chars[self.start..self.current].iter().collect();
|
||||
self.add_token_with_value(Integer, upper);
|
||||
}
|
||||
|
||||
fn char(&mut self) -> Result<(), CompilerErrorAtLine> {
|
||||
while self.peek() != '\'' && !self.is_at_end() {
|
||||
|
|
@ -265,8 +282,12 @@ impl Scanner {
|
|||
}
|
||||
|
||||
fn peek_next(&self) -> char {
|
||||
if self.current + 1 >= self.chars.len() {
|
||||
'\0'
|
||||
} else {
|
||||
self.chars[self.current + 1]
|
||||
}
|
||||
}
|
||||
|
||||
fn match_next(&mut self, expected: char) -> bool {
|
||||
if self.is_at_end() || self.chars[self.current] != expected {
|
||||
|
|
@ -304,7 +325,6 @@ struct Scanner {
|
|||
new_line: bool,
|
||||
}
|
||||
|
||||
|
||||
fn is_digit_or_scientific(c: char) -> bool {
|
||||
c.is_ascii_digit() || c == 'e' || c == 'E'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ast_compiler::{Expression, Parameter, Statement};
|
||||
use crate::builtins::{Signature, lookup};
|
||||
use crate::builtins::lookup;
|
||||
use crate::errors::CompilerError;
|
||||
use crate::errors::CompilerError::IncompatibleTypes;
|
||||
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::Assignment { value, .. } => infer_type(value, symbols),
|
||||
Expression::FunctionCall { name, .. } => {
|
||||
let symbol = symbols.get(name);
|
||||
match symbol {
|
||||
|
|
@ -215,5 +216,6 @@ pub fn infer_type(expr: &Expression, symbols: &HashMap<String, Symbol>) -> Token
|
|||
Expression::ListGet { .. } => TokenType::Unknown,
|
||||
Expression::MapGet { .. } => TokenType::Unknown,
|
||||
Expression::FieldGet { .. } => TokenType::Unknown,
|
||||
Expression::Range { lower, .. } => infer_type(lower, symbols),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ pub enum TokenType {
|
|||
I64,
|
||||
Identifier,
|
||||
If,
|
||||
In,
|
||||
Indent,
|
||||
Integer,
|
||||
SignedInteger,
|
||||
|
|
@ -73,6 +74,7 @@ pub enum TokenType {
|
|||
Plus,
|
||||
Print,
|
||||
Question,
|
||||
Range,
|
||||
Return,
|
||||
RightParen,
|
||||
RightBrace,
|
||||
|
|
@ -132,6 +134,7 @@ impl fmt::Display for TokenType {
|
|||
TokenType::Hex => write!(f, "0x"),
|
||||
TokenType::If => write!(f, "if"),
|
||||
TokenType::Identifier => write!(f, "identifier"),
|
||||
TokenType::In => write!(f, "in"),
|
||||
TokenType::Indent => write!(f, "indent"),
|
||||
TokenType::Integer => write!(f, "integer"),
|
||||
TokenType::LeftBrace => write!(f, "{{"),
|
||||
|
|
@ -150,6 +153,7 @@ impl fmt::Display for TokenType {
|
|||
TokenType::Plus => write!(f, "+"),
|
||||
TokenType::Print => write!(f, "print"),
|
||||
TokenType::Question => write!(f, "?"),
|
||||
TokenType::Range => write!(f, ".."),
|
||||
TokenType::Return => write!(f, "return"),
|
||||
TokenType::RightParen => write!(f, ")"),
|
||||
TokenType::RightBrace => write!(f, "}}"),
|
||||
|
|
|
|||
25
src/vm.rs
25
src/vm.rs
|
|
@ -1,3 +1,4 @@
|
|||
use crate::Registry;
|
||||
use crate::chunk::Chunk;
|
||||
use crate::errors::RuntimeError::Something;
|
||||
use crate::errors::{RuntimeError, ValueError};
|
||||
|
|
@ -7,7 +8,6 @@ use arc_swap::Guard;
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tracing::debug;
|
||||
use crate::Registry;
|
||||
|
||||
pub struct Vm {
|
||||
ip: usize,
|
||||
|
|
@ -17,14 +17,15 @@ pub struct Vm {
|
|||
pub(crate) registry: Arc<HashMap<String, Chunk>>,
|
||||
}
|
||||
|
||||
|
||||
pub fn interpret(
|
||||
registry: Guard<Arc<HashMap<String, Chunk>>>,
|
||||
function: &str,
|
||||
) -> Result<Value, RuntimeError> {
|
||||
let chunk = registry.get(function).unwrap().clone();
|
||||
// chunk.disassemble();
|
||||
let mut vm = Vm::new(®istry);
|
||||
vm.run(&get_context(function), &chunk)
|
||||
// Ok(Value::Void)
|
||||
}
|
||||
|
||||
pub async fn interpret_async(
|
||||
|
|
@ -157,7 +158,7 @@ impl Vm {
|
|||
let (var_type, name) = chunk.vars.get(index).unwrap();
|
||||
let value = self.pop();
|
||||
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 => {
|
||||
let len = self.read(chunk);
|
||||
|
|
@ -172,7 +173,7 @@ impl Vm {
|
|||
OP_GET => {
|
||||
let var_index = self.read(chunk);
|
||||
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);
|
||||
}
|
||||
OP_LIST_GET => {
|
||||
|
|
@ -196,7 +197,8 @@ impl Vm {
|
|||
}
|
||||
args.reverse();
|
||||
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);
|
||||
}
|
||||
OP_POP => {
|
||||
|
|
@ -232,10 +234,7 @@ impl Vm {
|
|||
}
|
||||
|
||||
let mut fields = vec![];
|
||||
params
|
||||
.iter()
|
||||
.zip(args)
|
||||
.for_each(|(param, arg)| {
|
||||
params.iter().zip(args).for_each(|(param, arg)| {
|
||||
fields.push((param.name.lexeme.clone(), arg))
|
||||
});
|
||||
let new_instance = Value::ObjectType(Box::new(Object {
|
||||
|
|
@ -276,6 +275,13 @@ impl Vm {
|
|||
}
|
||||
});
|
||||
}
|
||||
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_IF: u16 = 44;
|
||||
pub const OP_IF_ELSE: u16 = 45;
|
||||
pub const OP_GOTO_IF: u16 = 46;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue