switched to thiserror for better error handling
This commit is contained in:
parent
0bd6048083
commit
55a30afd06
11 changed files with 252 additions and 174 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -195,7 +195,6 @@ dependencies = [
|
||||||
name = "crudlang"
|
name = "crudlang"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
|
@ -203,6 +202,7 @@ dependencies = [
|
||||||
"log4rs",
|
"log4rs",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-postgres",
|
"tokio-postgres",
|
||||||
"tower",
|
"tower",
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ tower-http = { version = "0.6", features = ["fs"] }
|
||||||
tower = "0.5.0"
|
tower = "0.5.0"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-subscriber = "0.3.20"
|
tracing-subscriber = "0.3.20"
|
||||||
anyhow = "1.0"
|
|
||||||
tower-livereload = "0.9.6"
|
tower-livereload = "0.9.6"
|
||||||
log = "0.4.28"
|
log = "0.4.28"
|
||||||
walkdir = "2.5.0"
|
walkdir = "2.5.0"
|
||||||
|
thiserror = "2.0.17"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
|
use crate::errors::CompilerError::{self, Expected, IncompatibleTypes, ParseError, TooManyParameters, TypeError, UnexpectedIndent, UninitializedVariable};
|
||||||
use crate::tokens::TokenType::{
|
use crate::tokens::TokenType::{
|
||||||
Bang, Bool, Char, Colon, Date, Eof, Eol, Equal, F32, F64, False, FloatingPoint, Fn, Greater,
|
Bang, Bool, Char, Colon, Date, Eof, Eol, Equal, False, FloatingPoint, Fn, Greater, GreaterEqual, GreaterGreater,
|
||||||
GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftBrace, LeftBracket,
|
Identifier, Indent, Integer, LeftBrace, LeftBracket, LeftParen, Less, LessEqual, LessLess,
|
||||||
LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus, Print,
|
Let, ListType, MapType, Minus, Object, Plus, Print, RightBrace, RightBracket, RightParen, SignedInteger,
|
||||||
RightBrace, RightBracket, RightParen, SignedInteger, SingleRightArrow, Slash, Star, StringType,
|
SingleRightArrow, Slash, Star, StringType, True, UnsignedInteger, F32, F64,
|
||||||
True, U32, U64, UnsignedInteger,
|
I32, I64, U32, U64,
|
||||||
};
|
};
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use anyhow::anyhow;
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn compile(tokens: Vec<Token>) -> anyhow::Result<Vec<Statement>> {
|
pub fn compile(tokens: Vec<Token>) -> Result<Vec<Statement>, CompilerError> {
|
||||||
let mut compiler = AstCompiler::new(tokens);
|
let mut compiler = AstCompiler::new(tokens);
|
||||||
compiler.compile_tokens()
|
compiler.compile_tokens()
|
||||||
}
|
}
|
||||||
|
|
@ -49,13 +49,13 @@ impl AstCompiler {
|
||||||
self.current = 0;
|
self.current = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_tokens(&mut self) -> anyhow::Result<Vec<Statement>> {
|
fn compile_tokens(&mut self) -> Result<Vec<Statement>,CompilerError> {
|
||||||
self.collect_functions()?;
|
self.collect_functions()?;
|
||||||
self.reset();
|
self.reset();
|
||||||
self.compile()
|
self.compile()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(&mut self) -> anyhow::Result<Vec<Statement>> {
|
fn compile(&mut self) -> Result<Vec<Statement>, CompilerError> {
|
||||||
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() {
|
||||||
|
|
@ -68,23 +68,23 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
Ok(statements)
|
Ok(statements)
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("Compilation failed."))
|
Err(CompilerError::Failure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_functions(&mut self) -> anyhow::Result<()> {
|
fn collect_functions(&mut self) -> Result<(), CompilerError> {
|
||||||
while !self.is_at_end() {
|
while !self.is_at_end() {
|
||||||
if self.match_token(vec![Fn]) {
|
if self.match_token(vec![Fn]) {
|
||||||
let name_token = self.consume(Identifier, "Expect function name.")?;
|
let name_token = self.consume(Identifier, Expected("function name."))?;
|
||||||
self.consume(LeftParen, "Expect '(' after function name.")?;
|
self.consume(LeftParen, Expected("'(' after function name."))?;
|
||||||
let mut parameters = vec![];
|
let mut parameters = vec![];
|
||||||
while !self.check(RightParen) {
|
while !self.check(RightParen) {
|
||||||
if parameters.len() >= 25 {
|
if parameters.len() >= 25 {
|
||||||
return Err(anyhow::anyhow!("Too many parameters."));
|
return Err(TooManyParameters);
|
||||||
}
|
}
|
||||||
let parm_name = self.consume(Identifier, "Expect parameter name.")?;
|
let parm_name = self.consume(Identifier, Expected("a parameter name."))?;
|
||||||
|
|
||||||
self.consume(Colon, "Expect : after parameter name")?;
|
self.consume(Colon, Expected(": after parameter name"))?;
|
||||||
let var_type = self.peek().token_type;
|
let var_type = self.peek().token_type;
|
||||||
self.vars.push(Expression::Variable {
|
self.vars.push(Expression::Variable {
|
||||||
name: parm_name.lexeme.to_string(),
|
name: parm_name.lexeme.to_string(),
|
||||||
|
|
@ -100,15 +100,15 @@ impl AstCompiler {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.consume(RightParen, "Expect ')' after parameters.")?;
|
self.consume(RightParen, Expected(" ')' after parameters."))?;
|
||||||
let return_type = if self.check(SingleRightArrow) {
|
let return_type = if self.check(SingleRightArrow) {
|
||||||
self.consume(SingleRightArrow, "")?;
|
self.consume(SingleRightArrow, Expected("->"))?;
|
||||||
self.advance().token_type
|
self.advance().token_type
|
||||||
} else {
|
} else {
|
||||||
TokenType::Void
|
TokenType::Void
|
||||||
};
|
};
|
||||||
self.consume(Colon, "Expect colon (:) after function declaration.")?;
|
self.consume(Colon, Expected("colon (:) after function declaration."))?;
|
||||||
self.consume(Eol, "Expect end of line.")?;
|
self.consume(Eol, Expected("end of line."))?;
|
||||||
|
|
||||||
let function = Function {
|
let function = Function {
|
||||||
name: name_token.clone(),
|
name: name_token.clone(),
|
||||||
|
|
@ -125,7 +125,7 @@ impl AstCompiler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn indent(&mut self) -> anyhow::Result<Option<Statement>> {
|
fn indent(&mut self) -> Result<Option<Statement>, CompilerError> {
|
||||||
let expected_indent = *self.indent.last().unwrap();
|
let expected_indent = *self.indent.last().unwrap();
|
||||||
// skip empty lines
|
// skip empty lines
|
||||||
while self.check(Eol) {
|
while self.check(Eol) {
|
||||||
|
|
@ -138,10 +138,9 @@ impl AstCompiler {
|
||||||
indent_on_line += 1;
|
indent_on_line += 1;
|
||||||
}
|
}
|
||||||
if indent_on_line > expected_indent {
|
if indent_on_line > expected_indent {
|
||||||
panic!(
|
Err(UnexpectedIndent(
|
||||||
"unexpected indent level {} vs expected {}",
|
|
||||||
indent_on_line, expected_indent
|
indent_on_line, expected_indent
|
||||||
);
|
))
|
||||||
} else if indent_on_line < expected_indent {
|
} else if indent_on_line < expected_indent {
|
||||||
self.indent.pop();
|
self.indent.pop();
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
|
@ -150,7 +149,7 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declaration(&mut self) -> anyhow::Result<Statement> {
|
fn declaration(&mut self) -> Result<Statement, CompilerError> {
|
||||||
if self.match_token(vec![Fn]) {
|
if self.match_token(vec![Fn]) {
|
||||||
self.function_declaration()
|
self.function_declaration()
|
||||||
} else if self.match_token(vec![Let]) {
|
} else if self.match_token(vec![Let]) {
|
||||||
|
|
@ -162,10 +161,10 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn object_declaration(&mut self) -> anyhow::Result<Statement> {
|
fn object_declaration(&mut self) -> Result<Statement, CompilerError> {
|
||||||
let type_name = self.consume(Identifier, "Expect object name.")?;
|
let type_name = self.consume(Identifier, Expected("object name."))?;
|
||||||
self.consume(Colon, "Expect ':' after object name.")?;
|
self.consume(Colon, Expected("':' after object name."))?;
|
||||||
self.consume(Eol, "Expect end of line.")?;
|
self.consume(Eol, Expected("end of line."))?;
|
||||||
|
|
||||||
let mut fields = vec![];
|
let mut fields = vec![];
|
||||||
|
|
||||||
|
|
@ -181,13 +180,13 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !done {
|
if !done {
|
||||||
let field_name = self.consume(Identifier, "Expect an object field name.")?;
|
let field_name = self.consume(Identifier, Expected("an object field name."))?;
|
||||||
self.consume(Colon, "Expect ':' after field name.")?;
|
self.consume(Colon, Expected("':' after field name."))?;
|
||||||
let field_type = self.peek().token_type;
|
let field_type = self.peek().token_type;
|
||||||
if field_type.is_type() {
|
if field_type.is_type() {
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("Expected a type"))?
|
Err(Expected("a type"))?
|
||||||
}
|
}
|
||||||
fields.push(Parameter {
|
fields.push(Parameter {
|
||||||
name: field_name,
|
name: field_name,
|
||||||
|
|
@ -195,26 +194,26 @@ impl AstCompiler {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.consume(Eol, "Expect end of line.")?;
|
self.consume(Eol, Expected("end of line."))?;
|
||||||
Ok(Statement::ObjectStmt {
|
Ok(Statement::ObjectStmt {
|
||||||
name: type_name,
|
name: type_name,
|
||||||
fields,
|
fields,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_declaration(&mut self) -> anyhow::Result<Statement> {
|
fn function_declaration(&mut self) -> Result<Statement, CompilerError> {
|
||||||
let name_token = self.consume(Identifier, "Expect function name.")?;
|
let name_token = self.consume(Identifier, Expected("function name."))?;
|
||||||
self.consume(LeftParen, "Expect '(' after function name.")?;
|
self.consume(LeftParen, Expected("'(' after function name."))?;
|
||||||
while !self.check(RightParen) {
|
while !self.check(RightParen) {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.consume(RightParen, "Expect ')' after parameters.")?;
|
self.consume(RightParen, Expected("')' after parameters."))?;
|
||||||
while !self.check(Colon) {
|
while !self.check(Colon) {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
self.consume(Colon, "2Expect colon (:) after function declaration.")?;
|
self.consume(Colon, Expected("colon (:) after function declaration."))?;
|
||||||
self.consume(Eol, "Expect end of line.")?;
|
self.consume(Eol, Expected("end of line."))?;
|
||||||
|
|
||||||
let current_indent = self.indent.last().unwrap();
|
let current_indent = self.indent.last().unwrap();
|
||||||
self.indent.push(current_indent + 1);
|
self.indent.push(current_indent + 1);
|
||||||
|
|
@ -228,8 +227,8 @@ impl AstCompiler {
|
||||||
Ok(function_stmt)
|
Ok(function_stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn let_declaration(&mut self) -> anyhow::Result<Statement> {
|
fn let_declaration(&mut self) -> Result<Statement, CompilerError> {
|
||||||
let name_token = self.consume(Identifier, "Expect variable name.")?;
|
let name_token = self.consume(Identifier, Expected("variable name."))?;
|
||||||
|
|
||||||
let declared_type = if self.check(Colon) {
|
let declared_type = if self.check(Colon) {
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
@ -240,14 +239,14 @@ impl AstCompiler {
|
||||||
|
|
||||||
if self.match_token(vec![Equal]) {
|
if self.match_token(vec![Equal]) {
|
||||||
let initializer = self.expression()?;
|
let initializer = self.expression()?;
|
||||||
self.consume(Eol, "Expect end of line after initializer.")?;
|
self.consume(Eol, Expected("end of line after initializer."))?;
|
||||||
|
|
||||||
let inferred_type = initializer.infer_type();
|
let inferred_type = initializer.infer_type();
|
||||||
let var_type = match calculate_type(declared_type, inferred_type) {
|
let var_type = match calculate_type(declared_type, inferred_type) {
|
||||||
Ok(var_type) => var_type,
|
Ok(var_type) => var_type,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.had_error = true;
|
self.had_error = true;
|
||||||
return Err(anyhow!("error at line {}: {}", name_token.line, e));
|
return Err(TypeError(name_token.line, Box::new(e)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.vars.push(Expression::Variable {
|
self.vars.push(Expression::Variable {
|
||||||
|
|
@ -261,11 +260,11 @@ impl AstCompiler {
|
||||||
initializer,
|
initializer,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("Uninitialized variables are not allowed."))?
|
Err(UninitializedVariable)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement(&mut self) -> anyhow::Result<Statement> {
|
fn statement(&mut self) -> Result<Statement, CompilerError> {
|
||||||
if self.match_token(vec![Print]) {
|
if self.match_token(vec![Print]) {
|
||||||
self.print_statement()
|
self.print_statement()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -273,68 +272,68 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_statement(&mut self) -> anyhow::Result<Statement> {
|
fn print_statement(&mut self) -> Result<Statement, CompilerError> {
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
self.consume(Eol, "Expect end of line after print statement.")?;
|
self.consume(Eol, Expected("end of line after print statement."))?;
|
||||||
Ok(Statement::PrintStmt { value: expr })
|
Ok(Statement::PrintStmt { value: expr })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr_statement(&mut self) -> anyhow::Result<Statement> {
|
fn expr_statement(&mut self) -> Result<Statement, CompilerError> {
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
self.consume(Eol, "Expect end of line after expression.")?;
|
self.consume(Eol, Expected("end of line after expression."))?;
|
||||||
Ok(Statement::ExpressionStmt { expression: expr })
|
Ok(Statement::ExpressionStmt { expression: expr })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> anyhow::Result<Expression> {
|
fn expression(&mut self) -> Result<Expression, CompilerError> {
|
||||||
self.or()
|
self.or()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn or(&mut self) -> anyhow::Result<Expression> {
|
fn or(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.and()?;
|
let expr = self.and()?;
|
||||||
self.binary(vec![TokenType::LogicalOr], expr)
|
self.binary(vec![TokenType::LogicalOr], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn and(&mut self) -> anyhow::Result<Expression> {
|
fn and(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.bit_and()?;
|
let expr = self.bit_and()?;
|
||||||
self.binary(vec![TokenType::LogicalAnd], expr)
|
self.binary(vec![TokenType::LogicalAnd], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bit_and(&mut self) -> anyhow::Result<Expression> {
|
fn bit_and(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.bit_or()?;
|
let expr = self.bit_or()?;
|
||||||
self.binary(vec![TokenType::BitAnd], expr)
|
self.binary(vec![TokenType::BitAnd], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bit_or(&mut self) -> anyhow::Result<Expression> {
|
fn bit_or(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.bit_xor()?;
|
let expr = self.bit_xor()?;
|
||||||
self.binary(vec![TokenType::BitOr], expr)
|
self.binary(vec![TokenType::BitOr], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bit_xor(&mut self) -> anyhow::Result<Expression> {
|
fn bit_xor(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.equality()?;
|
let expr = self.equality()?;
|
||||||
self.binary(vec![TokenType::BitXor], expr)
|
self.binary(vec![TokenType::BitXor], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equality(&mut self) -> anyhow::Result<Expression> {
|
fn equality(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.comparison()?;
|
let expr = self.comparison()?;
|
||||||
self.binary(vec![TokenType::EqualEqual, TokenType::BangEqual], expr)
|
self.binary(vec![TokenType::EqualEqual, TokenType::BangEqual], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comparison(&mut self) -> anyhow::Result<Expression> {
|
fn comparison(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.bitshift()?;
|
let expr = self.bitshift()?;
|
||||||
self.binary(vec![Greater, GreaterEqual, Less, LessEqual], expr)
|
self.binary(vec![Greater, GreaterEqual, Less, LessEqual], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bitshift(&mut self) -> anyhow::Result<Expression> {
|
fn bitshift(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.term()?;
|
let expr = self.term()?;
|
||||||
self.binary(vec![GreaterGreater, LessLess], expr)
|
self.binary(vec![GreaterGreater, LessLess], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term(&mut self) -> anyhow::Result<Expression> {
|
fn term(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.factor()?;
|
let expr = self.factor()?;
|
||||||
self.binary(vec![Minus, Plus], expr)
|
self.binary(vec![Minus, Plus], expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn factor(&mut self) -> anyhow::Result<Expression> {
|
fn factor(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let expr = self.unary()?;
|
let expr = self.unary()?;
|
||||||
self.binary(vec![Slash, Star], expr)
|
self.binary(vec![Slash, Star], expr)
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +342,7 @@ impl AstCompiler {
|
||||||
&mut self,
|
&mut self,
|
||||||
types: Vec<TokenType>,
|
types: Vec<TokenType>,
|
||||||
mut expr: Expression,
|
mut expr: Expression,
|
||||||
) -> anyhow::Result<Expression> {
|
) -> Result<Expression, CompilerError> {
|
||||||
while self.match_token(types.clone()) {
|
while self.match_token(types.clone()) {
|
||||||
let operator = self.previous().clone();
|
let operator = self.previous().clone();
|
||||||
let right = self.comparison()?;
|
let right = self.comparison()?;
|
||||||
|
|
@ -357,7 +356,7 @@ impl AstCompiler {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(&mut self) -> anyhow::Result<Expression> {
|
fn unary(&mut self) -> Result<Expression, CompilerError> {
|
||||||
if self.match_token(vec![Bang, Minus]) {
|
if self.match_token(vec![Bang, Minus]) {
|
||||||
let operator = self.previous().clone();
|
let operator = self.previous().clone();
|
||||||
let right = self.unary()?;
|
let right = self.unary()?;
|
||||||
|
|
@ -371,7 +370,7 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primary(&mut self) -> anyhow::Result<Expression> {
|
fn primary(&mut self) -> Result<Expression, CompilerError> {
|
||||||
debug!("primary {:?}", self.peek());
|
debug!("primary {:?}", self.peek());
|
||||||
Ok(if self.match_token(vec![LeftBracket]) {
|
Ok(if self.match_token(vec![LeftBracket]) {
|
||||||
self.list()?
|
self.list()?
|
||||||
|
|
@ -393,13 +392,13 @@ impl AstCompiler {
|
||||||
Expression::Literal {
|
Expression::Literal {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
literaltype: Integer,
|
literaltype: Integer,
|
||||||
value: Value::I64(self.previous().lexeme.parse()?),
|
value: Value::I64(self.previous().lexeme.parse().map_err(|e|ParseError(format!("{:?}",e)))?),
|
||||||
}
|
}
|
||||||
} else if self.match_token(vec![FloatingPoint]) {
|
} else if self.match_token(vec![FloatingPoint]) {
|
||||||
Expression::Literal {
|
Expression::Literal {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
literaltype: FloatingPoint,
|
literaltype: FloatingPoint,
|
||||||
value: Value::F64(self.previous().lexeme.parse()?),
|
value: Value::F64(self.previous().lexeme.parse().map_err(|e|ParseError(format!("{:?}",e)))?),
|
||||||
}
|
}
|
||||||
} else if self.match_token(vec![StringType]) {
|
} else if self.match_token(vec![StringType]) {
|
||||||
Expression::Literal {
|
Expression::Literal {
|
||||||
|
|
@ -415,7 +414,7 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
} else if self.match_token(vec![LeftParen]) {
|
} else if self.match_token(vec![LeftParen]) {
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
self.consume(RightParen, "Expect ')' after expression.")?;
|
self.consume(RightParen, Expected("')' after expression."))?;
|
||||||
Expression::Grouping {
|
Expression::Grouping {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
expression: Box::new(expr),
|
expression: Box::new(expr),
|
||||||
|
|
@ -431,14 +430,14 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(&mut self) -> anyhow::Result<Expression> {
|
fn list(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let mut list = vec![];
|
let mut list = vec![];
|
||||||
while !self.match_token(vec![RightBracket]) {
|
while !self.match_token(vec![RightBracket]) {
|
||||||
list.push(self.expression()?);
|
list.push(self.expression()?);
|
||||||
if self.peek().token_type == TokenType::Comma {
|
if self.peek().token_type == TokenType::Comma {
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
} else {
|
||||||
self.consume(RightBracket, "Expect ']' after list.")?;
|
self.consume(RightBracket, Expected("']' at the end of the list."))?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -449,17 +448,17 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&mut self) -> anyhow::Result<Expression> {
|
fn map(&mut self) -> Result<Expression, CompilerError> {
|
||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
while !self.match_token(vec![RightBrace]) {
|
while !self.match_token(vec![RightBrace]) {
|
||||||
let key = self.expression()?;
|
let key = self.expression()?;
|
||||||
self.consume(Colon, "Expect ':' after map key.")?;
|
self.consume(Colon, Expected("':' after map key."))?;
|
||||||
let value = self.expression()?;
|
let value = self.expression()?;
|
||||||
entries.push((key, value));
|
entries.push((key, value));
|
||||||
if self.peek().token_type == TokenType::Comma {
|
if self.peek().token_type == TokenType::Comma {
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
} else {
|
||||||
self.consume(RightBrace, "Expect '}' after map.")?;
|
self.consume(RightBrace, Expected("'}' after map."))?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -470,7 +469,7 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variable_lookup(&mut self, token: &Token) -> anyhow::Result<Expression> {
|
fn variable_lookup(&mut self, token: &Token) -> Result<Expression, CompilerError> {
|
||||||
let (var_name, var_type) = self
|
let (var_name, var_type) = self
|
||||||
.vars
|
.vars
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -482,7 +481,7 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.find(|e| e.0 == &token.lexeme)
|
.find(|e| e.0 == &token.lexeme)
|
||||||
.ok_or_else(|| return anyhow::anyhow!("Unknown variable: {:?}", token))?;
|
.ok_or_else(|| return CompilerError::UndeclaredVariable(token.clone()))?;
|
||||||
Ok(Expression::Variable {
|
Ok(Expression::Variable {
|
||||||
name: var_name.to_string(),
|
name: var_name.to_string(),
|
||||||
var_type: var_type.clone(),
|
var_type: var_type.clone(),
|
||||||
|
|
@ -490,20 +489,19 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_call(&mut self, name: String) -> anyhow::Result<Expression> {
|
fn function_call(&mut self, name: String) -> Result<Expression, CompilerError> {
|
||||||
let function_name = self.functions.get(&name).unwrap().name.lexeme.clone();
|
let function_name = self.functions.get(&name).unwrap().name.lexeme.clone();
|
||||||
let function = self.functions.get(&function_name).unwrap().clone();
|
let function = self.functions.get(&function_name).unwrap().clone();
|
||||||
|
|
||||||
let mut arguments = vec![];
|
let mut arguments = vec![];
|
||||||
while !self.match_token(vec![RightParen]) {
|
while !self.match_token(vec![RightParen]) {
|
||||||
if arguments.len() >= 25 {
|
if arguments.len() >= 25 {
|
||||||
return Err(anyhow::anyhow!("Too many parameters."));
|
return Err(TooManyParameters);
|
||||||
}
|
}
|
||||||
let arg = self.expression()?;
|
let arg = self.expression()?;
|
||||||
let arg_type = arg.infer_type();
|
let arg_type = arg.infer_type();
|
||||||
if arg_type != function.parameters[arguments.len()].var_type {
|
if arg_type != function.parameters[arguments.len()].var_type {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(IncompatibleTypes(
|
||||||
"Incompatible argument types. Expected {}, found {}",
|
|
||||||
function.parameters[arguments.len()].var_type,
|
function.parameters[arguments.len()].var_type,
|
||||||
arg_type
|
arg_type
|
||||||
));
|
));
|
||||||
|
|
@ -512,7 +510,7 @@ impl AstCompiler {
|
||||||
if self.peek().token_type == TokenType::Comma {
|
if self.peek().token_type == TokenType::Comma {
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
} else {
|
||||||
self.consume(RightParen, "Expect ')' after arguments.")?;
|
self.consume(RightParen, Expected("')' after arguments."))?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -525,16 +523,17 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(&mut self, token_type: TokenType, message: &str) -> anyhow::Result<Token> {
|
fn consume(&mut self, token_type: TokenType, message: CompilerError) -> Result<Token, CompilerError> {
|
||||||
if self.check(token_type) {
|
if self.check(token_type) {
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
} else {
|
||||||
self.had_error = true;
|
self.had_error = true;
|
||||||
return Err(anyhow::anyhow!(
|
// return Err(anyhow::anyhow!(
|
||||||
"{} at {:?}",
|
// "{} at {:?}",
|
||||||
message.to_string(),
|
// message.to_string(),
|
||||||
self.peek()
|
// self.peek()
|
||||||
));
|
// ));
|
||||||
|
return Err(message);
|
||||||
}
|
}
|
||||||
Ok(self.previous().clone())
|
Ok(self.previous().clone())
|
||||||
}
|
}
|
||||||
|
|
@ -580,7 +579,7 @@ impl AstCompiler {
|
||||||
fn calculate_type(
|
fn calculate_type(
|
||||||
declared_type: Option<TokenType>,
|
declared_type: Option<TokenType>,
|
||||||
inferred_type: TokenType,
|
inferred_type: TokenType,
|
||||||
) -> anyhow::Result<TokenType> {
|
) -> Result<TokenType, CompilerError> {
|
||||||
Ok(if let Some(declared_type) = declared_type {
|
Ok(if let Some(declared_type) = declared_type {
|
||||||
if declared_type != inferred_type {
|
if declared_type != inferred_type {
|
||||||
match (declared_type, inferred_type) {
|
match (declared_type, inferred_type) {
|
||||||
|
|
@ -596,8 +595,7 @@ fn calculate_type(
|
||||||
(U64, I32) => U64,
|
(U64, I32) => U64,
|
||||||
(StringType, _) => StringType, // meh, this all needs rigorous testing. Update: this is in progress
|
(StringType, _) => StringType, // meh, this all needs rigorous testing. Update: this is in progress
|
||||||
_ => {
|
_ => {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(IncompatibleTypes(
|
||||||
"Incompatible types. Expected {}, found {}",
|
|
||||||
declared_type,
|
declared_type,
|
||||||
inferred_type
|
inferred_type
|
||||||
));
|
));
|
||||||
|
|
@ -615,7 +613,7 @@ fn calculate_type(
|
||||||
ListType => ListType,
|
ListType => ListType,
|
||||||
MapType => MapType,
|
MapType => MapType,
|
||||||
Object => Object,
|
Object => Object,
|
||||||
_ => panic!("Unexpected type"),
|
_ => return Err(CompilerError::UnexpectedType(inferred_type)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ use crate::vm::{
|
||||||
OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
|
OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use crate::errors::CompilerError;
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
namespace: Option<&str>,
|
namespace: Option<&str>,
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
) -> anyhow::Result<()> {
|
) -> Result<(),CompilerError> {
|
||||||
compile_name(ast, namespace, registry)
|
compile_name(ast, namespace, registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ pub(crate) fn compile_function(
|
||||||
function: &Function,
|
function: &Function,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
) -> anyhow::Result<Chunk> {
|
) -> Result<Chunk, CompilerError> {
|
||||||
let mut compiler = Compiler::new(&function.name.lexeme);
|
let mut compiler = Compiler::new(&function.name.lexeme);
|
||||||
for parm in &function.parameters {
|
for parm in &function.parameters {
|
||||||
let name = parm.name.lexeme.clone();
|
let name = parm.name.lexeme.clone();
|
||||||
|
|
@ -39,7 +40,7 @@ pub(crate) fn compile_name(
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
namespace: Option<&str>,
|
namespace: Option<&str>,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
) -> anyhow::Result<()> {
|
) -> Result<(),CompilerError> {
|
||||||
let name=namespace.unwrap_or("main");
|
let name=namespace.unwrap_or("main");
|
||||||
let compiler = Compiler::new(name);
|
let compiler = Compiler::new(name);
|
||||||
let chunk = compiler.compile(ast, registry, name)?;
|
let chunk = compiler.compile(ast, registry, name)?;
|
||||||
|
|
@ -74,7 +75,7 @@ impl Compiler {
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
) -> anyhow::Result<Chunk> {
|
) -> Result<Chunk, CompilerError> {
|
||||||
//TODO can likely be removed
|
//TODO can likely be removed
|
||||||
for statement in ast {
|
for statement in ast {
|
||||||
if let Statement::FunctionStmt { function } = statement {
|
if let Statement::FunctionStmt { function } = statement {
|
||||||
|
|
@ -99,7 +100,7 @@ impl Compiler {
|
||||||
statement: &Statement,
|
statement: &Statement,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
) -> anyhow::Result<()> {
|
) -> Result<(), CompilerError> {
|
||||||
self.current_line = statement.line();
|
self.current_line = statement.line();
|
||||||
match statement {
|
match statement {
|
||||||
Statement::VarStmt {
|
Statement::VarStmt {
|
||||||
|
|
@ -140,7 +141,7 @@ impl Compiler {
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
expression: &Expression,
|
expression: &Expression,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
) -> anyhow::Result<()> {
|
) -> Result<(), CompilerError> {
|
||||||
match expression {
|
match expression {
|
||||||
Expression::FunctionCall {
|
Expression::FunctionCall {
|
||||||
name, arguments, ..
|
name, arguments, ..
|
||||||
|
|
@ -229,7 +230,7 @@ impl Compiler {
|
||||||
var_type: &TokenType,
|
var_type: &TokenType,
|
||||||
name_index: usize,
|
name_index: usize,
|
||||||
initializer: &Expression,
|
initializer: &Expression,
|
||||||
) -> anyhow::Result<()> {
|
) -> Result<(), CompilerError> {
|
||||||
let def_op = match var_type {
|
let def_op = match var_type {
|
||||||
TokenType::I32 => OP_DEF_I32,
|
TokenType::I32 => OP_DEF_I32,
|
||||||
TokenType::I64 => OP_DEF_I64,
|
TokenType::I64 => OP_DEF_I64,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::compile;
|
use crate::{compile, run};
|
||||||
use crate::scanner::scan;
|
use crate::scanner::scan;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vm::interpret;
|
use crate::vm::interpret;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literal_int() {
|
fn literal_int() {
|
||||||
assert!(compile("1").is_ok());
|
assert_eq!(run("1"), Ok(Value::I64(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -52,7 +52,7 @@ mod tests {
|
||||||
if let Err(e) = &r {
|
if let Err(e) = &r {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"error at line 1: Incompatible types. Expected u32, found i32/64"
|
"Type mismatch at line 1: Incompatible types. Expected u32, found i32/64"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +64,7 @@ mod tests {
|
||||||
if let Err(e) = &r {
|
if let Err(e) = &r {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"error at line 1: Incompatible types. Expected u64, found i32/64"
|
"Type mismatch at line 1: Incompatible types. Expected u64, found i32/64"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ mod tests {
|
||||||
if let Err(e) = &r {
|
if let Err(e) = &r {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
e.to_string(),
|
e.to_string(),
|
||||||
"error at line 1: Incompatible types. Expected u64, found string"
|
"Type mismatch at line 1: Incompatible types. Expected u64, found string"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
61
src/errors.rs
Normal file
61
src/errors.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
use crate::tokens::{Token, TokenType};
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Compiler(#[from] CompilerError),
|
||||||
|
#[error(transparent)]
|
||||||
|
Runtime(#[from] RuntimeError),
|
||||||
|
#[error("Platform error {0}")]
|
||||||
|
Platform(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
pub enum CompilerError {
|
||||||
|
#[error("Compilation failed")]
|
||||||
|
Failure,
|
||||||
|
#[error("Too many parameters")]
|
||||||
|
TooManyParameters,
|
||||||
|
#[error("Expected {0}")]
|
||||||
|
Expected(&'static str),
|
||||||
|
#[error("unexpected indent level {0} vs expected {1}")]
|
||||||
|
UnexpectedIndent(usize,usize),
|
||||||
|
#[error("Type mismatch at line {0}: {1}")]
|
||||||
|
TypeError(usize, Box<CompilerError>),
|
||||||
|
#[error("Uninitialized variables are not allowed.")]
|
||||||
|
UninitializedVariable,
|
||||||
|
#[error("Incompatible types. Expected {0}, found {1}")]
|
||||||
|
IncompatibleTypes(TokenType, TokenType),
|
||||||
|
#[error("Error parsing number {0}")]
|
||||||
|
ParseError(String),
|
||||||
|
#[error("Undeclared variable: {0:?}")]
|
||||||
|
UndeclaredVariable(Token),
|
||||||
|
#[error("Unexpected identifier at line {0}")]
|
||||||
|
UnexpectedIdentifier(usize),
|
||||||
|
#[error("Unterminated {0} at line {1}")]
|
||||||
|
Unterminated(&'static str, usize),
|
||||||
|
#[error("Illegal char length for {0} at line {1}")]
|
||||||
|
IllegalCharLength(String, usize),
|
||||||
|
#[error("Unexpected type {0}")]
|
||||||
|
UnexpectedType(TokenType)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
pub enum RuntimeError {
|
||||||
|
#[error("Error while executing")]
|
||||||
|
Value(#[from] ValueError),
|
||||||
|
#[error("Error occurred")]
|
||||||
|
Something,
|
||||||
|
#[error("Expected {0}, got {1}")]
|
||||||
|
Expected(&'static str, &'static str),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
pub enum ValueError {
|
||||||
|
#[error("{0}")]
|
||||||
|
CannotAnd(&'static str),
|
||||||
|
#[error("{0}")]
|
||||||
|
Some(&'static str),
|
||||||
|
}
|
||||||
20
src/lib.rs
20
src/lib.rs
|
|
@ -1,20 +1,32 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use crate::scanner::scan;
|
use crate::scanner::scan;
|
||||||
|
use crate::value::Value;
|
||||||
|
use crate::vm::interpret;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use crate::errors::Error;
|
||||||
|
|
||||||
pub mod ast_compiler;
|
pub mod ast_compiler;
|
||||||
pub mod bytecode_compiler;
|
pub mod bytecode_compiler;
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
|
mod compiler_tests;
|
||||||
mod keywords;
|
mod keywords;
|
||||||
pub mod scanner;
|
pub mod scanner;
|
||||||
mod compiler_tests;
|
|
||||||
mod tokens;
|
mod tokens;
|
||||||
mod value;
|
mod value;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
pub mod errors;
|
||||||
|
|
||||||
pub fn compile(src: &str) -> anyhow::Result<HashMap<String, chunk::Chunk>> {
|
pub fn compile(src: &str) -> Result<HashMap<String, chunk::Chunk>, Error> {
|
||||||
let tokens = scan(src)?;
|
let tokens = scan(src)?;
|
||||||
let mut registry = HashMap::new();
|
let mut registry = HashMap::new();
|
||||||
let ast= ast_compiler::compile(tokens)?;
|
let ast = ast_compiler::compile(tokens)?;
|
||||||
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
||||||
Ok(registry)
|
Ok(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run(src: &str) -> Result<Value, Error> {
|
||||||
|
let tokens = scan(src)?;
|
||||||
|
let mut registry = HashMap::new();
|
||||||
|
let ast = ast_compiler::compile(tokens)?;
|
||||||
|
bytecode_compiler::compile(None, &ast, &mut registry)?;
|
||||||
|
interpret(®istry, "main").map_err(Error::from)
|
||||||
|
}
|
||||||
|
|
|
||||||
21
src/main.rs
21
src/main.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use axum::extract::{Path, State};
|
use axum::extract::{State};
|
||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use axum::{Json, Router};
|
use axum::{Json, Router};
|
||||||
|
|
@ -9,12 +9,13 @@ use crudlang::scanner::scan;
|
||||||
use crudlang::vm::{interpret, interpret_async};
|
use crudlang::vm::{interpret, interpret_async};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::hash::Hash;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
use crudlang::errors::Error;
|
||||||
|
use crudlang::errors::Error::Platform;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> Result<(), crudlang::errors::Error> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let mut paths = HashMap::new();
|
let mut paths = HashMap::new();
|
||||||
|
|
@ -23,12 +24,12 @@ async fn main() -> anyhow::Result<()> {
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if path.is_file() && path.ends_with("web.crud") {
|
if path.is_file() && path.ends_with("web.crud") {
|
||||||
print!("compiling {:?}: ", path);
|
print!("compiling {:?}: ", path);
|
||||||
let source = fs::read_to_string(path)?;
|
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
||||||
let tokens = scan(&source)?;
|
let tokens = scan(&source)?;
|
||||||
match ast_compiler::compile(tokens) {
|
match ast_compiler::compile(tokens) {
|
||||||
Ok(statements) => {
|
Ok(statements) => {
|
||||||
let path = path
|
let path = path
|
||||||
.strip_prefix("source")?
|
.strip_prefix("source").map_err(|e|Platform(e.to_string()))?
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.replace(".crud", "");
|
.replace(".crud", "");
|
||||||
|
|
@ -58,13 +59,17 @@ async fn main() -> anyhow::Result<()> {
|
||||||
get(handle_get).with_state(state.clone()),
|
get(handle_get).with_state(state.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.map_err(map_underlying())?;
|
||||||
println!("listening on {}", listener.local_addr()?);
|
println!("listening on {}", listener.local_addr().map_err(map_underlying())?);
|
||||||
axum::serve(listener, app).await?;
|
axum::serve(listener, app).await.map_err(map_underlying())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn map_underlying() -> fn(std::io::Error) -> Error {
|
||||||
|
|e| Error::Platform(e.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct AppState {
|
struct AppState {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use anyhow::anyhow;
|
|
||||||
use crate::tokens::TokenType::{BitXor, FloatingPoint, Integer};
|
use crate::tokens::TokenType::{BitXor, FloatingPoint, Integer};
|
||||||
use crate::{
|
use crate::{
|
||||||
keywords,
|
keywords,
|
||||||
|
|
@ -7,8 +6,10 @@ use crate::{
|
||||||
TokenType::{self},
|
TokenType::{self},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::errors::CompilerError;
|
||||||
|
use crate::errors::CompilerError::{IllegalCharLength, UnexpectedIdentifier, Unterminated};
|
||||||
|
|
||||||
pub fn scan(source: &str) -> anyhow::Result<Vec<Token>> {
|
pub fn scan(source: &str) -> Result<Vec<Token>, CompilerError> {
|
||||||
let scanner = Scanner {
|
let scanner = Scanner {
|
||||||
chars: source.chars().collect(),
|
chars: source.chars().collect(),
|
||||||
current: 0,
|
current: 0,
|
||||||
|
|
@ -21,7 +22,7 @@ pub fn scan(source: &str) -> anyhow::Result<Vec<Token>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scanner {
|
impl Scanner {
|
||||||
fn scan(mut self) -> anyhow::Result<Vec<Token>> {
|
fn scan(mut self) -> Result<Vec<Token>, CompilerError> {
|
||||||
while !self.is_at_end() {
|
while !self.is_at_end() {
|
||||||
self.start = self.current;
|
self.start = self.current;
|
||||||
self.scan_token()?;
|
self.scan_token()?;
|
||||||
|
|
@ -31,7 +32,7 @@ impl Scanner {
|
||||||
Ok(self.tokens)
|
Ok(self.tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_token(&mut self) -> anyhow::Result<()>{
|
fn scan_token(&mut self) -> Result<(),CompilerError> {
|
||||||
let c = self.advance();
|
let c = self.advance();
|
||||||
if self.new_line && (c == ' ' || c == '\t') {
|
if self.new_line && (c == ' ' || c == '\t') {
|
||||||
self.add_token(TokenType::Indent);
|
self.add_token(TokenType::Indent);
|
||||||
|
|
@ -138,7 +139,7 @@ impl Scanner {
|
||||||
} else if is_alpha(c) {
|
} else if is_alpha(c) {
|
||||||
self.identifier();
|
self.identifier();
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!("Unexpected identifier at line {}", self.line));
|
return Err(UnexpectedIdentifier(self.line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,13 +174,13 @@ impl Scanner {
|
||||||
self.add_token_with_value(if has_dot { FloatingPoint } else { Integer }, value);
|
self.add_token_with_value(if has_dot { FloatingPoint } else { Integer }, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn char(&mut self) -> anyhow::Result<()>{
|
fn char(&mut self) -> Result<(), CompilerError>{
|
||||||
while self.peek() != '\'' && !self.is_at_end() {
|
while self.peek() != '\'' && !self.is_at_end() {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
return Err(anyhow!("Unterminated char at {}", self.line))
|
return Err(Unterminated("char", self.line))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
@ -188,13 +189,13 @@ impl Scanner {
|
||||||
.iter()
|
.iter()
|
||||||
.collect();
|
.collect();
|
||||||
if value.len() != 1 {
|
if value.len() != 1 {
|
||||||
return Err(anyhow!("Illegal char length for {} at line {}", value, self.line))
|
return Err(IllegalCharLength(value, self.line))
|
||||||
}
|
}
|
||||||
self.add_token_with_value(TokenType::Char, value);
|
self.add_token_with_value(TokenType::Char, value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(&mut self) -> anyhow::Result<()>{
|
fn string(&mut self) -> Result<(),CompilerError> {
|
||||||
while self.peek() != '"' && !self.is_at_end() {
|
while self.peek() != '"' && !self.is_at_end() {
|
||||||
if self.peek() == '\n' {
|
if self.peek() == '\n' {
|
||||||
self.line += 1;
|
self.line += 1;
|
||||||
|
|
@ -203,7 +204,7 @@ impl Scanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_at_end() {
|
if self.is_at_end() {
|
||||||
return Err(anyhow!("Unterminated string at {}", self.line))
|
return Err(Unterminated("string", self.line))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
|
||||||
72
src/value.rs
72
src/value.rs
|
|
@ -1,10 +1,10 @@
|
||||||
use anyhow::anyhow;
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
||||||
|
use crate::errors::ValueError;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
|
|
@ -143,7 +143,7 @@ fn to_string(f: &mut Formatter, map: &HashMap<Value, Value>) -> std::fmt::Result
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Neg for &Value {
|
impl Neg for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
|
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -151,13 +151,13 @@ impl Neg for &Value {
|
||||||
Value::I64(i) => Ok(Value::I64(-i)),
|
Value::I64(i) => Ok(Value::I64(-i)),
|
||||||
Value::F32(i) => Ok(Value::F32(-i)),
|
Value::F32(i) => Ok(Value::F32(-i)),
|
||||||
Value::F64(i) => Ok(Value::F64(-i)),
|
Value::F64(i) => Ok(Value::F64(-i)),
|
||||||
_ => Err(anyhow!("Cannot negate")),
|
_ => Err(ValueError::Some("Cannot negate")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add<&Value> for &Value {
|
impl Add<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
|
|
||||||
fn add(self, rhs: &Value) -> Self::Output {
|
fn add(self, rhs: &Value) -> Self::Output {
|
||||||
if let Value::List(s) = self {
|
if let Value::List(s) = self {
|
||||||
|
|
@ -189,14 +189,14 @@ impl Add<&Value> for &Value {
|
||||||
}
|
}
|
||||||
(Value::String(s1), Value::Map(m)) => Ok(Value::String(format!("{}{:?}", s1, m))),
|
(Value::String(s1), Value::Map(m)) => Ok(Value::String(format!("{}{:?}", s1, m))),
|
||||||
//enum?
|
//enum?
|
||||||
_ => Err(anyhow!("Cannot add")),
|
_ => Err(ValueError::Some("Cannot add")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sub<&Value> for &Value {
|
impl Sub<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
|
|
||||||
fn sub(self, rhs: &Value) -> Self::Output {
|
fn sub(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
|
|
@ -207,13 +207,13 @@ impl Sub<&Value> for &Value {
|
||||||
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a - b)),
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a - b)),
|
||||||
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a - b)),
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a - b)),
|
||||||
//enum?
|
//enum?
|
||||||
_ => Err(anyhow!("Cannot subtract")),
|
_ => Err(ValueError::Some("Cannot subtract")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul<&Value> for &Value {
|
impl Mul<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
|
|
||||||
fn mul(self, rhs: &Value) -> Self::Output {
|
fn mul(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
|
|
@ -223,13 +223,13 @@ impl Mul<&Value> for &Value {
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a * b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a * b)),
|
||||||
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a * b)),
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a * b)),
|
||||||
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a * b)),
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a * b)),
|
||||||
_ => Err(anyhow!("Cannot multiply")),
|
_ => Err(ValueError::Some("Cannot multiply")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Div<&Value> for &Value {
|
impl Div<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
|
|
||||||
fn div(self, rhs: &Value) -> Self::Output {
|
fn div(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
|
|
@ -239,52 +239,52 @@ impl Div<&Value> for &Value {
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a / b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a / b)),
|
||||||
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a / b)),
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a / b)),
|
||||||
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a / b)),
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a / b)),
|
||||||
_ => Err(anyhow!("Cannot divide")),
|
_ => Err(ValueError::Some("Cannot divide")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitAnd<&Value> for &Value {
|
impl BitAnd<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
fn bitand(self, rhs: &Value) -> Self::Output {
|
fn bitand(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a & b)),
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a & b)),
|
||||||
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a & b)),
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a & b)),
|
||||||
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a & b)),
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a & b)),
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a & b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a & b)),
|
||||||
_ => Err(anyhow!("Cannot do bitwise-and on")),
|
_ => Err(ValueError::Some("Cannot do bitwise-and on")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitOr<&Value> for &Value {
|
impl BitOr<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
fn bitor(self, rhs: &Value) -> Self::Output {
|
fn bitor(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a | b)),
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a | b)),
|
||||||
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a | b)),
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a | b)),
|
||||||
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a | b)),
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a | b)),
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a | b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a | b)),
|
||||||
_ => Err(anyhow!("Cannot do bitwise-or on")),
|
_ => Err(ValueError::Some("Cannot do bitwise-or on")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitXor<&Value> for &Value {
|
impl BitXor<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
fn bitxor(self, rhs: &Value) -> Self::Output {
|
fn bitxor(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a ^ b)),
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a ^ b)),
|
||||||
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a ^ b)),
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a ^ b)),
|
||||||
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a ^ b)),
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a ^ b)),
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a ^ b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a ^ b)),
|
||||||
_ => Err(anyhow!("Cannot do bitwise-xor on")),
|
_ => Err(ValueError::Some("Cannot do bitwise-xor on")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Not for &Value {
|
impl Not for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
|
|
||||||
fn not(self) -> Self::Output {
|
fn not(self) -> Self::Output {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -293,33 +293,33 @@ impl Not for &Value {
|
||||||
Value::I64(i64) => Ok(Value::I64(!i64)),
|
Value::I64(i64) => Ok(Value::I64(!i64)),
|
||||||
Value::U32(u32) => Ok(Value::U32(!u32)),
|
Value::U32(u32) => Ok(Value::U32(!u32)),
|
||||||
Value::U64(u64) => Ok(Value::U64(!u64)),
|
Value::U64(u64) => Ok(Value::U64(!u64)),
|
||||||
_ => Err(anyhow!("Cannot calculate not")),
|
_ => Err(ValueError::Some("Cannot calculate not")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shl<&Value> for &Value {
|
impl Shl<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
fn shl(self, rhs: &Value) -> Self::Output {
|
fn shl(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a << b)),
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a << b)),
|
||||||
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a << b)),
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a << b)),
|
||||||
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a << b)),
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a << b)),
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a << b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a << b)),
|
||||||
_ => Err(anyhow!("Cannot shift left on")),
|
_ => Err(ValueError::Some("Cannot shift left on")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shr<&Value> for &Value {
|
impl Shr<&Value> for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = Result<Value, ValueError>;
|
||||||
fn shr(self, rhs: &Value) -> Self::Output {
|
fn shr(self, rhs: &Value) -> Self::Output {
|
||||||
match (self, rhs) {
|
match (self, rhs) {
|
||||||
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a >> b)),
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a >> b)),
|
||||||
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a >> b)),
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a >> b)),
|
||||||
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a >> b)),
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a >> b)),
|
||||||
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a >> b)),
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a >> b)),
|
||||||
_ => Err(anyhow!("Cannot shift right on")),
|
_ => Err(ValueError::Some("Cannot shift right on")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -337,19 +337,19 @@ impl PartialEq for Value {
|
||||||
(Value::String(a), Value::String(b)) => a == b,
|
(Value::String(a), Value::String(b)) => a == b,
|
||||||
(Value::Char(a), Value::Char(b)) => a == b,
|
(Value::Char(a), Value::Char(b)) => a == b,
|
||||||
(Value::Date(a), Value::Date(b)) => a == b,
|
(Value::Date(a), Value::Date(b)) => a == b,
|
||||||
// (Value::List(a), Value::List(b)) => a == b,
|
(Value::List(a), Value::List(b)) => a == b,
|
||||||
// (Value::Map(a), Value::Map(b)) => {
|
(Value::Map(a), Value::Map(b)) => {
|
||||||
// let mut equal = true;
|
let mut equal = true;
|
||||||
// for (k, v) in a.iter() {
|
for (k, v) in a.iter() {
|
||||||
// if !b.contains_key(k) || b.get(k).unwrap() != v {
|
if !b.contains_key(k) || b.get(k).unwrap() != v {
|
||||||
// //safe unwrap
|
//safe unwrap
|
||||||
// equal = false;
|
equal = false;
|
||||||
// break;
|
break;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// equal
|
equal
|
||||||
// }
|
}
|
||||||
// struct?
|
// TODO objects
|
||||||
_ => false, //?
|
_ => false, //?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
src/vm.rs
28
src/vm.rs
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::chunk::Chunk;
|
use crate::chunk::Chunk;
|
||||||
|
use crate::errors::RuntimeError::{Something};
|
||||||
|
use crate::errors::{RuntimeError, ValueError};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use anyhow::anyhow;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
|
@ -11,9 +12,8 @@ macro_rules! define_var {
|
||||||
if let Value::$variant(_) = value {
|
if let Value::$variant(_) = value {
|
||||||
$self.local_vars.insert(name, value);
|
$self.local_vars.insert(name, value);
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!(
|
return Err(RuntimeError::Expected(
|
||||||
concat!("Expected ", stringify!($variant), ", got {:?}"),
|
stringify!($variant), stringify!(value),
|
||||||
value
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
@ -27,7 +27,7 @@ pub struct Vm<'a> {
|
||||||
registry: &'a HashMap<String, Chunk>,
|
registry: &'a HashMap<String, Chunk>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> anyhow::Result<Value> {
|
pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> Result<Value, RuntimeError> {
|
||||||
let chunk = registry.get(function).unwrap().clone();
|
let chunk = registry.get(function).unwrap().clone();
|
||||||
// for (key,value) in registry.iter() {
|
// for (key,value) in registry.iter() {
|
||||||
// println!("{}", key);
|
// println!("{}", key);
|
||||||
|
|
@ -43,7 +43,7 @@ pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> anyhow::R
|
||||||
vm.run(&chunk, vec![])
|
vm.run(&chunk, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str) -> anyhow::Result<Value> {
|
pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str) -> Result<Value, RuntimeError> {
|
||||||
let chunk = registry.get(function).unwrap().clone();
|
let chunk = registry.get(function).unwrap().clone();
|
||||||
let mut vm = Vm {
|
let mut vm = Vm {
|
||||||
ip: 0,
|
ip: 0,
|
||||||
|
|
@ -55,7 +55,7 @@ pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str)
|
||||||
vm.run(&chunk, vec![])
|
vm.run(&chunk, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> anyhow::Result<Value> {
|
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
let mut vm = Vm {
|
let mut vm = Vm {
|
||||||
ip: 0,
|
ip: 0,
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
|
|
@ -67,13 +67,13 @@ pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> anyhow::Result<Val
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Vm<'a> {
|
impl <'a> Vm<'a> {
|
||||||
fn run(&mut self, chunk: &Chunk, args: Vec<Value>) -> anyhow::Result<Value> {
|
fn run(&mut self, chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.push(arg);
|
self.push(arg);
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
if self.error_occurred {
|
if self.error_occurred {
|
||||||
return Err(anyhow!("Error occurred"));
|
return Err(Something);
|
||||||
}
|
}
|
||||||
debug!("{:?}", self.stack);
|
debug!("{:?}", self.stack);
|
||||||
let opcode = chunk.code[self.ip];
|
let opcode = chunk.code[self.ip];
|
||||||
|
|
@ -91,14 +91,14 @@ impl <'a> Vm<'a> {
|
||||||
if let (Value::Bool(a), Value::Bool(b)) = (a, b) {
|
if let (Value::Bool(a), Value::Bool(b)) = (a, b) {
|
||||||
Ok(Value::Bool(*a && *b))
|
Ok(Value::Bool(*a && *b))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Cannot and"))
|
Err(ValueError::Some("Cannot and"))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
OP_OR => binary_op(self, |a, b| {
|
OP_OR => binary_op(self, |a, b| {
|
||||||
if let (Value::Bool(a), Value::Bool(b)) = (a, b) {
|
if let (Value::Bool(a), Value::Bool(b)) = (a, b) {
|
||||||
Ok(Value::Bool(*a || *b))
|
Ok(Value::Bool(*a || *b))
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Cannot compare"))
|
Err(ValueError::Some("Cannot compare"))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
OP_NOT => unary_op(self, |a| !a),
|
OP_NOT => unary_op(self, |a| !a),
|
||||||
|
|
@ -210,7 +210,7 @@ impl <'a> Vm<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary_op(vm: &mut Vm, op: impl Fn(&Value, &Value) -> anyhow::Result<Value> + Copy) {
|
fn binary_op(vm: &mut Vm, op: impl Fn(&Value, &Value) -> Result<Value, ValueError> + Copy) {
|
||||||
let b = vm.pop();
|
let b = vm.pop();
|
||||||
let a = vm.pop();
|
let a = vm.pop();
|
||||||
|
|
||||||
|
|
@ -218,13 +218,13 @@ fn binary_op(vm: &mut Vm, op: impl Fn(&Value, &Value) -> anyhow::Result<Value> +
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => vm.push(result),
|
Ok(result) => vm.push(result),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error: {} {:?} and {:?}", e.to_string(), a, b);
|
|
||||||
vm.error_occurred = true;
|
vm.error_occurred = true;
|
||||||
|
println!("Error: {} {:?} and {:?}", e.to_string(), a, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary_op(stack: &mut Vm, op: impl Fn(&Value) -> anyhow::Result<Value> + Copy) {
|
fn unary_op(stack: &mut Vm, op: impl Fn(&Value) -> Result<Value, ValueError> + Copy) {
|
||||||
let a = stack.pop();
|
let a = stack.pop();
|
||||||
let result = op(&a);
|
let result = op(&a);
|
||||||
match result {
|
match result {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue