type inference and building the symbol table earlier in the process. Not perfect: duplicated code, no namespaces of the names in the table
This commit is contained in:
parent
9ee8f193aa
commit
cbc7f6ce7a
7 changed files with 378 additions and 169 deletions
|
|
@ -174,13 +174,14 @@ more date functions will have to follow.
|
||||||
**lists**
|
**lists**
|
||||||
```
|
```
|
||||||
let list = ["foo", "bar", 1, 1.0]
|
let list = ["foo", "bar", 1, 1.0]
|
||||||
print(list[1])
|
list[1]
|
||||||
=> "bar"
|
=> "bar"
|
||||||
```
|
```
|
||||||
No generic types (yet). A list can hold any type.
|
No generic types (yet). A list can hold any type.
|
||||||
* lists support appending with +
|
* lists support appending with +
|
||||||
```
|
```
|
||||||
let list2 = list + "baz"
|
let list2 = list + "baz"
|
||||||
|
=>["foo", "bar", 1, 1.0, "baz"]
|
||||||
```
|
```
|
||||||
_note to self: implement adding 2 lists_
|
_note to self: implement adding 2 lists_
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,30 @@ use crate::ast_compiler::Expression::{
|
||||||
FieldGet, FunctionCall, ListGet, MapGet, NamedParameter, Stop, Variable,
|
FieldGet, FunctionCall, ListGet, MapGet, NamedParameter, Stop, Variable,
|
||||||
};
|
};
|
||||||
use crate::errors::CompilerError::{
|
use crate::errors::CompilerError::{
|
||||||
self, Expected, IncompatibleTypes, ParseError, TooManyParameters, TypeError,
|
self, Expected, ParseError, TooManyParameters, UndeclaredVariable, UnexpectedIndent,
|
||||||
UndeclaredVariable, UnexpectedIndent, UninitializedVariable,
|
UninitializedVariable,
|
||||||
};
|
};
|
||||||
use crate::errors::CompilerErrorAtLine;
|
use crate::errors::CompilerErrorAtLine;
|
||||||
|
use crate::symbol_builder::{Symbol, calculate_type, infer_type};
|
||||||
use crate::tokens::TokenType::{
|
use crate::tokens::TokenType::{
|
||||||
Bang, Bool, Char, Colon, DateTime, Dot, Eof, Eol, Equal, F32, F64, False, FloatingPoint, Fn,
|
Bang, Bool, Char, Colon, DateTime, Dot, Eof, Eol, Equal, F32, F64, False, FloatingPoint, Fn,
|
||||||
Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftBrace,
|
Greater, GreaterEqual, GreaterGreater, I32, I64, Identifier, Indent, Integer, LeftBrace,
|
||||||
LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus,
|
LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus,
|
||||||
Print, RightBrace, RightBracket, RightParen, SignedInteger, SingleRightArrow, Slash, Star,
|
Print, RightBrace, RightBracket, RightParen, SignedInteger, SingleRightArrow, Slash, Star,
|
||||||
StringType, True, U32, U64, UnsignedInteger,
|
StringType, True, U32, U64, Unknown, UnsignedInteger,
|
||||||
};
|
};
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use tokio_postgres::fallible_iterator::FallibleIterator;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
path: Option<&str>,
|
path: Option<&str>,
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
||||||
let mut compiler = AstCompiler::new(path.unwrap_or(""), tokens);
|
let mut compiler = AstCompiler::new(path.unwrap_or(""), tokens);
|
||||||
compiler.compile_tokens()
|
compiler.compile_tokens(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -55,17 +57,23 @@ impl AstCompiler {
|
||||||
self.current = 0;
|
self.current = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_tokens(&mut self) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
fn compile_tokens(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
||||||
self.reset();
|
self.reset();
|
||||||
self.compile()
|
self.compile(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(&mut self) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
fn compile(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Vec<Statement>, CompilerErrorAtLine> {
|
||||||
self.current_line();
|
self.current_line();
|
||||||
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() {
|
||||||
let statement = self.indent()?;
|
let statement = self.indent(symbol_table)?;
|
||||||
if let Some(statement) = statement {
|
if let Some(statement) = statement {
|
||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -83,7 +91,10 @@ impl AstCompiler {
|
||||||
CompilerErrorAtLine::raise(error, self.current_line())
|
CompilerErrorAtLine::raise(error, self.current_line())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn indent(&mut self) -> Result<Option<Statement>, CompilerErrorAtLine> {
|
fn indent(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Option<Statement>, CompilerErrorAtLine> {
|
||||||
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) {
|
||||||
|
|
@ -101,39 +112,48 @@ impl AstCompiler {
|
||||||
self.indent.pop();
|
self.indent.pop();
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(self.declaration()?))
|
Ok(Some(self.declaration(symbol_table)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declaration(&mut self) -> Result<Statement, CompilerErrorAtLine> {
|
fn declaration(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
if self.match_token(vec![Fn]) {
|
if self.match_token(vec![Fn]) {
|
||||||
self.function_declaration()
|
self.function_declaration(symbol_table)
|
||||||
} else if self.match_token(vec![Let]) {
|
} else if self.match_token(vec![Let]) {
|
||||||
self.let_declaration()
|
self.let_declaration(symbol_table)
|
||||||
} else if self.match_token(vec![Object]) {
|
} else if self.match_token(vec![Object]) {
|
||||||
self.object_declaration()
|
self.object_declaration()
|
||||||
} else if self.match_token(vec![TokenType::Pipe]) {
|
} else if self.match_token(vec![TokenType::Pipe]) {
|
||||||
self.guard_declaration()
|
self.guard_declaration(symbol_table)
|
||||||
} else {
|
} else {
|
||||||
self.statement()
|
self.statement(symbol_table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// | /. -> service.get_all()
|
// | /. -> service.get_all()
|
||||||
// | /{uuid} -> service.get(uuid)?
|
// | /{uuid} -> service.get(uuid)?
|
||||||
// | ?{query.firstname} -> service.get_by_firstname(fname)?
|
// | ?{query.firstname} -> service.get_by_firstname(fname)?
|
||||||
fn guard_declaration(&mut self) -> Result<Statement, CompilerErrorAtLine> {
|
fn guard_declaration(
|
||||||
let if_expr = self.guard_if_expr()?;
|
&mut self,
|
||||||
let then_expr = self.expression()?;
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
|
let if_expr = self.guard_if_expr(symbol_table)?;
|
||||||
|
let then_expr = self.expression(symbol_table)?;
|
||||||
Ok(Statement::GuardStatement { if_expr, then_expr })
|
Ok(Statement::GuardStatement { if_expr, then_expr })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guard_if_expr(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn guard_if_expr(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
while !self.check(SingleRightArrow) {
|
while !self.check(SingleRightArrow) {
|
||||||
if self.match_token(vec![Slash]) {
|
if self.match_token(vec![Slash]) {
|
||||||
return self.path_guard_expr();
|
return self.path_guard_expr();
|
||||||
} else if self.match_token(vec![TokenType::Question]) {
|
} else if self.match_token(vec![TokenType::Question]) {
|
||||||
return self.query_guard_expr();
|
return self.query_guard_expr(symbol_table);
|
||||||
} else {
|
} else {
|
||||||
return Err(self.raise(Expected("-> or ?")));
|
return Err(self.raise(Expected("-> or ?")));
|
||||||
}
|
}
|
||||||
|
|
@ -143,9 +163,12 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query_guard_expr(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn query_guard_expr(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
if self.match_token(vec![LeftBrace]) {
|
if self.match_token(vec![LeftBrace]) {
|
||||||
let query_params = self.expression()?;
|
let query_params = self.expression(symbol_table)?;
|
||||||
self.consume(RightBrace, Expected("'}' after guard expression."))?;
|
self.consume(RightBrace, Expected("'}' after guard expression."))?;
|
||||||
Ok(query_params)
|
Ok(query_params)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -211,7 +234,10 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_declaration(&mut self) -> Result<Statement, CompilerErrorAtLine> {
|
fn function_declaration(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
let name_token = self.consume(Identifier, Expected("function name."))?;
|
let name_token = self.consume(Identifier, Expected("function name."))?;
|
||||||
self.consume(LeftParen, Expected("'(' after function name."))?;
|
self.consume(LeftParen, Expected("'(' after function name."))?;
|
||||||
let mut parameters = vec![];
|
let mut parameters = vec![];
|
||||||
|
|
@ -246,7 +272,7 @@ impl AstCompiler {
|
||||||
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);
|
||||||
|
|
||||||
let body = self.compile()?;
|
let body = self.compile(symbol_table)?;
|
||||||
|
|
||||||
let function = Function {
|
let function = Function {
|
||||||
name: name_token.clone(),
|
name: name_token.clone(),
|
||||||
|
|
@ -258,7 +284,10 @@ impl AstCompiler {
|
||||||
Ok(Statement::FunctionStmt { function })
|
Ok(Statement::FunctionStmt { function })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn let_declaration(&mut self) -> Result<Statement, CompilerErrorAtLine> {
|
fn let_declaration(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
if self.peek().token_type.is_type() {
|
if self.peek().token_type.is_type() {
|
||||||
return Err(self.raise(CompilerError::KeywordNotAllowedAsIdentifier(
|
return Err(self.raise(CompilerError::KeywordNotAllowedAsIdentifier(
|
||||||
self.peek().token_type.clone(),
|
self.peek().token_type.clone(),
|
||||||
|
|
@ -274,25 +303,24 @@ impl AstCompiler {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.match_token(vec![Equal]) {
|
if self.match_token(vec![Equal]) {
|
||||||
let initializer = self.expression()?;
|
let initializer = self.expression(symbol_table)?;
|
||||||
|
let declared_type = declared_type.unwrap_or(Unknown);
|
||||||
|
let inferred_type = initializer.infer_type();
|
||||||
|
let var_type =
|
||||||
|
calculate_type(&declared_type, &inferred_type).map_err(|e| self.raise(e))?;
|
||||||
|
symbol_table.insert(
|
||||||
|
name_token.lexeme.clone(),
|
||||||
|
Symbol::Variable {
|
||||||
|
name: name_token.lexeme.clone(),
|
||||||
|
var_type: var_type.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
self.consume(Eol, Expected("end of line after initializer."))?;
|
self.consume(Eol, Expected("end of line after initializer."))?;
|
||||||
|
|
||||||
// let inferred_type = initializer.infer_type();
|
|
||||||
// let var_type = match calculate_type(declared_type, inferred_type) {
|
|
||||||
// Ok(var_type) => var_type,
|
|
||||||
// Err(e) => {
|
|
||||||
// self.had_error = true;
|
|
||||||
// return Err(self.raise(TypeError(Box::new(e))));
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// self.vars.push(Variable {
|
|
||||||
// name: name_token.lexeme.to_string(),
|
|
||||||
// var_type,
|
|
||||||
// line: name_token.line,
|
|
||||||
// });
|
|
||||||
Ok(Statement::VarStmt {
|
Ok(Statement::VarStmt {
|
||||||
name: name_token,
|
name: name_token,
|
||||||
var_type: declared_type.unwrap_or(TokenType::Unknown),
|
var_type,
|
||||||
initializer,
|
initializer,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -300,90 +328,141 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement(&mut self) -> Result<Statement, CompilerErrorAtLine> {
|
fn statement(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
if self.match_token(vec![Print]) {
|
if self.match_token(vec![Print]) {
|
||||||
self.print_statement()
|
self.print_statement(symbol_table)
|
||||||
} else {
|
} else {
|
||||||
self.expr_statement()
|
self.expr_statement(symbol_table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_statement(&mut self) -> Result<Statement, CompilerErrorAtLine> {
|
fn print_statement(
|
||||||
let expr = self.expression()?;
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
|
let expr = self.expression(symbol_table)?;
|
||||||
self.consume(Eol, Expected("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) -> Result<Statement, CompilerErrorAtLine> {
|
fn expr_statement(
|
||||||
let expr = self.expression()?;
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Statement, CompilerErrorAtLine> {
|
||||||
|
let expr = self.expression(symbol_table)?;
|
||||||
if !self.is_at_end() {
|
if !self.is_at_end() {
|
||||||
self.consume(Eol, Expected("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) -> Result<Expression, CompilerErrorAtLine> {
|
fn expression(
|
||||||
self.or()
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
self.or(symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn or(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn or(
|
||||||
let expr = self.and()?;
|
&mut self,
|
||||||
self.binary(vec![TokenType::LogicalOr], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.and(symbol_table)?;
|
||||||
|
self.binary(vec![TokenType::LogicalOr], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn and(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn and(
|
||||||
let expr = self.bit_and()?;
|
&mut self,
|
||||||
self.binary(vec![TokenType::LogicalAnd], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.bit_and(symbol_table)?;
|
||||||
|
self.binary(vec![TokenType::LogicalAnd], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bit_and(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn bit_and(
|
||||||
let expr = self.bit_or()?;
|
&mut self,
|
||||||
self.binary(vec![TokenType::BitAnd], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.bit_or(symbol_table)?;
|
||||||
|
self.binary(vec![TokenType::BitAnd], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bit_or(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn bit_or(
|
||||||
let expr = self.bit_xor()?;
|
&mut self,
|
||||||
self.binary(vec![TokenType::Pipe], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.bit_xor(symbol_table)?;
|
||||||
|
self.binary(vec![TokenType::Pipe], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bit_xor(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn bit_xor(
|
||||||
let expr = self.equality()?;
|
&mut self,
|
||||||
self.binary(vec![TokenType::BitXor], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.equality(symbol_table)?;
|
||||||
|
self.binary(vec![TokenType::BitXor], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equality(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn equality(
|
||||||
let expr = self.comparison()?;
|
&mut self,
|
||||||
self.binary(vec![TokenType::EqualEqual, TokenType::BangEqual], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.comparison(symbol_table)?;
|
||||||
|
self.binary(
|
||||||
|
vec![TokenType::EqualEqual, TokenType::BangEqual],
|
||||||
|
expr,
|
||||||
|
symbol_table,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn comparison(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn comparison(
|
||||||
let expr = self.bitshift()?;
|
&mut self,
|
||||||
self.binary(vec![Greater, GreaterEqual, Less, LessEqual], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.bitshift(symbol_table)?;
|
||||||
|
self.binary(
|
||||||
|
vec![Greater, GreaterEqual, Less, LessEqual],
|
||||||
|
expr,
|
||||||
|
symbol_table,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bitshift(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn bitshift(
|
||||||
let expr = self.term()?;
|
&mut self,
|
||||||
self.binary(vec![GreaterGreater, LessLess], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.term(symbol_table)?;
|
||||||
|
self.binary(vec![GreaterGreater, LessLess], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn term(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn term(
|
||||||
let expr = self.factor()?;
|
&mut self,
|
||||||
self.binary(vec![Minus, Plus], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.factor(symbol_table)?;
|
||||||
|
self.binary(vec![Minus, Plus], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn factor(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn factor(
|
||||||
let expr = self.unary()?;
|
&mut self,
|
||||||
self.binary(vec![Slash, Star], expr)
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.unary(symbol_table)?;
|
||||||
|
self.binary(vec![Slash, Star], expr, symbol_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary(
|
fn binary(
|
||||||
&mut self,
|
&mut self,
|
||||||
types: Vec<TokenType>,
|
types: Vec<TokenType>,
|
||||||
mut expr: Expression,
|
mut expr: Expression,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
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(symbol_table)?;
|
||||||
expr = Expression::Binary {
|
expr = Expression::Binary {
|
||||||
line: operator.line,
|
line: operator.line,
|
||||||
left: Box::new(expr),
|
left: Box::new(expr),
|
||||||
|
|
@ -394,32 +473,37 @@ impl AstCompiler {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn unary(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
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(symbol_table)?;
|
||||||
Ok(Expression::Unary {
|
Ok(Expression::Unary {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
operator,
|
operator,
|
||||||
right: Box::new(right),
|
right: Box::new(right),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
let expr = self.get();
|
let expr = self.get(symbol_table);
|
||||||
expr
|
expr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn get(
|
||||||
let expr = self.primary()?;
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let expr = self.primary(symbol_table)?;
|
||||||
|
|
||||||
if self.match_token(vec![LeftParen]) {
|
if self.match_token(vec![LeftParen]) {
|
||||||
let name = self.peek().clone();
|
let name = self.peek().clone();
|
||||||
self.advance();
|
self.advance();
|
||||||
self.function_call(name)
|
self.function_call(name, symbol_table)
|
||||||
} else if self.match_token(vec![LeftBracket]) {
|
} else if self.match_token(vec![LeftBracket]) {
|
||||||
let name = self.peek().clone();
|
let index = self.expression(symbol_table)?;
|
||||||
self.advance();
|
self.index(expr, index)
|
||||||
self.index(expr, name)
|
|
||||||
} else if self.match_token(vec![Dot]) {
|
} else if self.match_token(vec![Dot]) {
|
||||||
let name = self.peek().clone();
|
let name = self.peek().clone();
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
@ -432,19 +516,27 @@ impl AstCompiler {
|
||||||
fn index(
|
fn index(
|
||||||
&mut self,
|
&mut self,
|
||||||
operand: Expression,
|
operand: Expression,
|
||||||
index: Token,
|
index: Expression,
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
let get = (match operand {
|
let get = (match &operand {
|
||||||
Expression::Map { .. } => MapGet {
|
Expression::Map { .. } => MapGet {
|
||||||
key: index.lexeme.clone(),
|
key: Box::new(index),
|
||||||
},
|
},
|
||||||
Expression::List { .. } => ListGet {
|
Expression::List { .. } => ListGet {
|
||||||
list: Box::new(operand),
|
list: Box::new(operand),
|
||||||
index: index.lexeme.clone().parse().map_err(|_| {
|
index: Box::new(index),
|
||||||
self.raise(CompilerError::IllegalTypeToIndex(index.lexeme.clone()))
|
|
||||||
})?,
|
|
||||||
},
|
},
|
||||||
_ => return Err(self.raise(CompilerError::IllegalTypeToIndex("".to_string()))),
|
Variable { var_type, .. } => {
|
||||||
|
if var_type == &ListType {
|
||||||
|
ListGet {
|
||||||
|
list: Box::new(operand),
|
||||||
|
index: Box::new(index),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(self.raise(CompilerError::IllegalTypeToIndex(var_type.to_string())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err(self.raise(CompilerError::IllegalTypeToIndex("Unknown".to_string()))),
|
||||||
});
|
});
|
||||||
self.consume(RightBracket, Expected("']' after index."))?;
|
self.consume(RightBracket, Expected("']' after index."))?;
|
||||||
Ok(get)
|
Ok(get)
|
||||||
|
|
@ -461,12 +553,15 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn primary(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn primary(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
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(symbol_table)?
|
||||||
} else if self.match_token(vec![LeftBrace]) {
|
} else if self.match_token(vec![LeftBrace]) {
|
||||||
self.map()?
|
self.map(symbol_table)?
|
||||||
} else if self.match_token(vec![False]) {
|
} else if self.match_token(vec![False]) {
|
||||||
Expression::Literal {
|
Expression::Literal {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
|
|
@ -545,7 +640,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(symbol_table)?;
|
||||||
self.consume(RightParen, Expected("')' after expression."))?;
|
self.consume(RightParen, Expected("')' after expression."))?;
|
||||||
Expression::Grouping {
|
Expression::Grouping {
|
||||||
line: self.peek().line,
|
line: self.peek().line,
|
||||||
|
|
@ -556,9 +651,9 @@ impl AstCompiler {
|
||||||
debug!("{:?}", token);
|
debug!("{:?}", token);
|
||||||
// function call?
|
// function call?
|
||||||
if self.match_token(vec![LeftParen]) {
|
if self.match_token(vec![LeftParen]) {
|
||||||
self.function_call(token.clone())?
|
self.function_call(token.clone(), symbol_table)?
|
||||||
} else if self.match_token(vec![Colon]) {
|
} else if self.match_token(vec![Colon]) {
|
||||||
self.named_parameter(&token)?
|
self.named_parameter(&token, symbol_table)?
|
||||||
} else {
|
} else {
|
||||||
// } else if self.check(Dot) {
|
// } else if self.check(Dot) {
|
||||||
// chain of variable or function lookups?
|
// chain of variable or function lookups?
|
||||||
|
|
@ -586,13 +681,17 @@ impl AstCompiler {
|
||||||
// }
|
// }
|
||||||
// } else {
|
// } else {
|
||||||
// none of the above, must be a variable lookup
|
// none of the above, must be a variable lookup
|
||||||
self.variable_lookup(&token)?
|
self.variable_lookup(&token, symbol_table)?
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn named_parameter(&mut self, name: &Token) -> Result<Expression, CompilerErrorAtLine> {
|
fn named_parameter(
|
||||||
let value = self.expression()?;
|
&mut self,
|
||||||
|
name: &Token,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let value = self.expression(symbol_table)?;
|
||||||
let line = name.line;
|
let line = name.line;
|
||||||
Ok(NamedParameter {
|
Ok(NamedParameter {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
|
|
@ -601,10 +700,13 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn list(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
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(symbol_table)?);
|
||||||
if self.peek().token_type == TokenType::Comma {
|
if self.peek().token_type == TokenType::Comma {
|
||||||
self.advance();
|
self.advance();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -619,12 +721,15 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&mut self) -> Result<Expression, CompilerErrorAtLine> {
|
fn map(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
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(symbol_table)?;
|
||||||
self.consume(Colon, Expected("':' after map key."))?;
|
self.consume(Colon, Expected("':' after map key."))?;
|
||||||
let value = self.expression()?;
|
let value = self.expression(symbol_table)?;
|
||||||
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();
|
||||||
|
|
@ -640,21 +745,35 @@ impl AstCompiler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variable_lookup(&mut self, name: &Token) -> Result<Expression, CompilerErrorAtLine> {
|
fn variable_lookup(
|
||||||
|
&mut self,
|
||||||
|
name: &Token,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
|
let var = symbol_table.get(&name.lexeme);
|
||||||
|
let var_type = if let Some(Symbol::Variable { var_type, .. }) = var {
|
||||||
|
var_type
|
||||||
|
} else {
|
||||||
|
&Unknown
|
||||||
|
};
|
||||||
Ok(Variable {
|
Ok(Variable {
|
||||||
name: name.lexeme.to_string(),
|
name: name.lexeme.to_string(),
|
||||||
var_type: TokenType::Unknown,
|
var_type: var_type.clone(),
|
||||||
line: name.line,
|
line: name.line,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_call(&mut self, name: Token) -> Result<Expression, CompilerErrorAtLine> {
|
fn function_call(
|
||||||
|
&mut self,
|
||||||
|
name: Token,
|
||||||
|
symbol_table: &mut HashMap<String, Symbol>,
|
||||||
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
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(self.raise(TooManyParameters));
|
return Err(self.raise(TooManyParameters));
|
||||||
}
|
}
|
||||||
let arg = self.expression()?;
|
let arg = self.expression(symbol_table)?;
|
||||||
arguments.push(arg);
|
arguments.push(arg);
|
||||||
if self.peek().token_type == TokenType::Comma {
|
if self.peek().token_type == TokenType::Comma {
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
@ -826,11 +945,11 @@ pub enum Expression {
|
||||||
value: Box<Expression>,
|
value: Box<Expression>,
|
||||||
},
|
},
|
||||||
MapGet {
|
MapGet {
|
||||||
key: String,
|
key: Box<Expression>,
|
||||||
},
|
},
|
||||||
ListGet {
|
ListGet {
|
||||||
list: Box<Expression>,
|
list: Box<Expression>,
|
||||||
index: usize,
|
index: Box<Expression>,
|
||||||
},
|
},
|
||||||
FieldGet {
|
FieldGet {
|
||||||
field: String,
|
field: String,
|
||||||
|
|
@ -857,20 +976,86 @@ impl Expression {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn get_type(&self) -> &str {
|
pub fn infer_type(&self) -> TokenType {
|
||||||
// match self {
|
match self {
|
||||||
// Expression::Binary { .. } => "binary",
|
Expression::Binary {
|
||||||
// Expression::Unary { .. } => TokenType::Unknown,
|
left,
|
||||||
// Expression::Grouping { .. } => TokenType::Unknown,
|
operator,
|
||||||
// Expression::Literal { literaltype, .. } => literaltype.clone(),
|
right,
|
||||||
// Expression::List { literaltype, .. } => literaltype.clone(),
|
..
|
||||||
// Expression::Map { literaltype, .. } => literaltype.clone(),
|
} => {
|
||||||
// Expression::Variable { var_type, .. } => var_type.clone(),
|
let left_type = left.infer_type();
|
||||||
// Expression::FunctionCall { .. } => TokenType::Unknown,
|
let right_type = right.infer_type();
|
||||||
// Expression::Stop { .. } => TokenType::Unknown,
|
if vec![Greater, Less, GreaterEqual, LessEqual].contains(&operator.token_type) {
|
||||||
// Expression::NamedParameter { .. } => TokenType::Unknown,
|
Bool
|
||||||
// Expression::MapGet { .. } => TokenType::Unknown,
|
} else if left_type == right_type {
|
||||||
// Expression::ListGet { .. } => TokenType::Unknown,
|
// map to determined numeric type if yet undetermined (32 or 64 bits)
|
||||||
// }
|
match left_type {
|
||||||
// }
|
FloatingPoint => F64,
|
||||||
|
Integer => I64,
|
||||||
|
_ => left_type,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Plus = operator.token_type {
|
||||||
|
// includes string concatenation with numbers
|
||||||
|
// followed by type coercion to 64 bits for numeric types
|
||||||
|
debug!("coerce {} : {}", left_type, right_type);
|
||||||
|
match (left_type, right_type) {
|
||||||
|
(_, StringType) => StringType,
|
||||||
|
(StringType, _) => StringType,
|
||||||
|
(FloatingPoint, _) => F64,
|
||||||
|
(Integer, FloatingPoint) => F64,
|
||||||
|
(Integer, _) => I64,
|
||||||
|
(I64, Integer) => I64,
|
||||||
|
(F64, _) => F64,
|
||||||
|
(U64, U32) => U64,
|
||||||
|
(I64, I32) => I64,
|
||||||
|
// could add a date and a duration. future work
|
||||||
|
// could add a List and a value. also future work
|
||||||
|
// could add a Map and a tuple. Will I add tuple types? Future work!
|
||||||
|
_ => panic!("Unexpected coercion"),
|
||||||
|
}
|
||||||
|
// could have done some fall through here, but this will fail less gracefully,
|
||||||
|
// so if my thinking is wrong or incomplete it will panic
|
||||||
|
} else {
|
||||||
|
// type coercion to 64 bits for numeric types
|
||||||
|
debug!("coerce {} : {}", left_type, right_type);
|
||||||
|
match (left_type, right_type) {
|
||||||
|
(FloatingPoint, _) => F64,
|
||||||
|
(Integer, FloatingPoint) => F64,
|
||||||
|
(Integer, I64) => I64,
|
||||||
|
(I64, FloatingPoint) => F64,
|
||||||
|
(F64, _) => F64,
|
||||||
|
(U64, U32) => U64,
|
||||||
|
(I64, I32) => I64,
|
||||||
|
(I64, Integer) => I64,
|
||||||
|
_ => panic!("Unexpected coercion"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::Grouping { expression, .. } => expression.infer_type(),
|
||||||
|
Expression::Literal { literaltype, .. } => literaltype.clone(),
|
||||||
|
Expression::List { literaltype, .. } => literaltype.clone(),
|
||||||
|
Expression::Map { literaltype, .. } => literaltype.clone(),
|
||||||
|
Expression::Unary {
|
||||||
|
right, operator, ..
|
||||||
|
} => {
|
||||||
|
let literal_type = right.infer_type();
|
||||||
|
if literal_type == Integer && operator.token_type == Minus {
|
||||||
|
SignedInteger
|
||||||
|
} else {
|
||||||
|
UnsignedInteger
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::Variable { var_type, .. } => var_type.clone(),
|
||||||
|
Expression::Stop { .. } => TokenType::Unknown,
|
||||||
|
// Expression::PathMatch { .. } => TokenType::Unknown,
|
||||||
|
Expression::NamedParameter { .. } => TokenType::Unknown,
|
||||||
|
Expression::ListGet { .. } => TokenType::Unknown,
|
||||||
|
Expression::MapGet { .. } => TokenType::Unknown,
|
||||||
|
Expression::FieldGet { .. } => TokenType::Unknown,
|
||||||
|
FunctionCall { .. } => TokenType::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,12 +110,11 @@ impl Compiler {
|
||||||
let var = symbols.get(name);
|
let var = symbols.get(name);
|
||||||
if let Some(Symbol::Variable {
|
if let Some(Symbol::Variable {
|
||||||
var_type,
|
var_type,
|
||||||
initializer,
|
|
||||||
..
|
..
|
||||||
}) = var
|
}) = var
|
||||||
{
|
{
|
||||||
let inferred_type = infer_type(initializer, symbols);
|
let inferred_type = infer_type(initializer, symbols);
|
||||||
let calculated_type = calculate_type(var_type, &inferred_type, symbols)
|
let calculated_type = calculate_type(var_type, &inferred_type)
|
||||||
.map_err(|e| CompilerErrorAtLine::raise(e, statement.line()))?;
|
.map_err(|e| CompilerErrorAtLine::raise(e, statement.line()))?;
|
||||||
if var_type != &Unknown && var_type != &calculated_type {
|
if var_type != &Unknown && var_type != &calculated_type {
|
||||||
return Err(CompilerErrorAtLine::raise(
|
return Err(CompilerErrorAtLine::raise(
|
||||||
|
|
@ -298,8 +297,8 @@ impl Compiler {
|
||||||
NamedParameter { .. } => {}
|
NamedParameter { .. } => {}
|
||||||
Expression::ListGet { index, list} => {
|
Expression::ListGet { index, list} => {
|
||||||
self.compile_expression(namespace, list, symbols, registry)?;
|
self.compile_expression(namespace, list, symbols, registry)?;
|
||||||
|
self.compile_expression(namespace, index, symbols, registry)?;
|
||||||
self.emit_byte(OP_LIST_GET);
|
self.emit_byte(OP_LIST_GET);
|
||||||
self.emit_bytes((index >> 16) as u16, *index as u16);
|
|
||||||
}
|
}
|
||||||
Expression::MapGet { .. } => {}
|
Expression::MapGet { .. } => {}
|
||||||
Expression::FieldGet { .. } => {}
|
Expression::FieldGet { .. } => {}
|
||||||
|
|
|
||||||
18
src/lib.rs
18
src/lib.rs
|
|
@ -33,14 +33,18 @@ pub fn compile_sourcedir(source_dir: &str) -> Result<HashMap<String, Chunk>, Cru
|
||||||
print!("-- Compiling {} -- ", path);
|
print!("-- Compiling {} -- ", path);
|
||||||
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
let source = fs::read_to_string(path).map_err(map_underlying())?;
|
||||||
let tokens = scan(&source)?;
|
let tokens = scan(&source)?;
|
||||||
match ast_compiler::compile(Some(&path), tokens) {
|
let mut symbol_table = HashMap::new();
|
||||||
|
match ast_compiler::compile(Some(&path), tokens, &mut symbol_table) {
|
||||||
Ok(statements) => {
|
Ok(statements) => {
|
||||||
let path = path.strip_prefix(source_dir).unwrap().replace(".crud", "");
|
let path = path.strip_prefix(source_dir).unwrap().replace(".crud", "");
|
||||||
|
|
||||||
let mut symbol_table = HashMap::new();
|
|
||||||
symbol_builder::build(&path, &statements, &mut symbol_table);
|
symbol_builder::build(&path, &statements, &mut symbol_table);
|
||||||
|
bytecode_compiler::compile(
|
||||||
bytecode_compiler::compile(Some(&path), &statements, &symbol_table, &mut registry)?;
|
Some(&path),
|
||||||
|
&statements,
|
||||||
|
&symbol_table,
|
||||||
|
&mut registry,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
|
|
@ -59,8 +63,8 @@ pub fn map_underlying() -> fn(std::io::Error) -> CrudLangError {
|
||||||
|
|
||||||
pub fn recompile(src: &str, registry: &mut HashMap<String, Chunk>) -> Result<(), CrudLangError> {
|
pub fn recompile(src: &str, registry: &mut HashMap<String, Chunk>) -> Result<(), CrudLangError> {
|
||||||
let tokens = scan(src)?;
|
let tokens = scan(src)?;
|
||||||
let ast = ast_compiler::compile(None, tokens)?;
|
|
||||||
let mut symbol_table = HashMap::new();
|
let mut symbol_table = HashMap::new();
|
||||||
|
let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?;
|
||||||
symbol_builder::build("", &ast, &mut symbol_table);
|
symbol_builder::build("", &ast, &mut symbol_table);
|
||||||
bytecode_compiler::compile(None, &ast, &symbol_table, registry)?;
|
bytecode_compiler::compile(None, &ast, &symbol_table, registry)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -69,8 +73,8 @@ pub fn recompile(src: &str, registry: &mut HashMap<String, Chunk>) -> Result<(),
|
||||||
pub fn compile(src: &str) -> Result<HashMap<String, Chunk>, CrudLangError> {
|
pub fn compile(src: &str) -> Result<HashMap<String, Chunk>, CrudLangError> {
|
||||||
let tokens = scan(src)?;
|
let tokens = scan(src)?;
|
||||||
let mut registry = HashMap::new();
|
let mut registry = HashMap::new();
|
||||||
let ast = ast_compiler::compile(None, tokens)?;
|
|
||||||
let mut symbol_table = HashMap::new();
|
let mut symbol_table = HashMap::new();
|
||||||
|
let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?;
|
||||||
symbol_builder::build("", &ast, &mut symbol_table);
|
symbol_builder::build("", &ast, &mut symbol_table);
|
||||||
bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?;
|
bytecode_compiler::compile(None, &ast, &symbol_table, &mut registry)?;
|
||||||
Ok(registry)
|
Ok(registry)
|
||||||
|
|
@ -78,8 +82,8 @@ pub fn compile(src: &str) -> Result<HashMap<String, Chunk>, CrudLangError> {
|
||||||
|
|
||||||
pub(crate) fn run(src: &str) -> Result<Value, CrudLangError> {
|
pub(crate) fn run(src: &str) -> Result<Value, CrudLangError> {
|
||||||
let tokens = scan(src)?;
|
let tokens = scan(src)?;
|
||||||
let ast = ast_compiler::compile(None, tokens)?;
|
|
||||||
let mut symbol_table = HashMap::new();
|
let mut symbol_table = HashMap::new();
|
||||||
|
let ast = ast_compiler::compile(None, tokens, &mut symbol_table)?;
|
||||||
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)?;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
use crate::ast_compiler::{Expression, Parameter, Statement};
|
use crate::ast_compiler::{Expression, Parameter, Statement};
|
||||||
use crate::errors::CompilerError;
|
use crate::errors::CompilerError;
|
||||||
use crate::errors::CompilerError::{IncompatibleTypes, TypeError};
|
use crate::errors::CompilerError::{IncompatibleTypes, TypeError};
|
||||||
|
use crate::tokens::TokenType::{
|
||||||
|
Bool, DateTime, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less,
|
||||||
|
LessEqual, ListType, MapType, Minus, Object, Plus, SignedInteger, StringType, U32, U64,
|
||||||
|
Unknown, UnsignedInteger,
|
||||||
|
};
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use crate::tokens::TokenType::{Bool, F32, F64, FloatingPoint, Greater, GreaterEqual, I32, I64, Integer, Less, LessEqual, ListType, MapType, Minus, Object, Plus, SignedInteger, StringType, U32, U64, Unknown, UnsignedInteger, DateTime};
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
@ -16,7 +20,6 @@ pub enum Symbol {
|
||||||
Variable {
|
Variable {
|
||||||
name: String,
|
name: String,
|
||||||
var_type: TokenType,
|
var_type: TokenType,
|
||||||
initializer: Expression,
|
|
||||||
},
|
},
|
||||||
Object {
|
Object {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
@ -40,16 +43,18 @@ pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol
|
||||||
var_type,
|
var_type,
|
||||||
initializer,
|
initializer,
|
||||||
} => {
|
} => {
|
||||||
|
let key = make_qname(path, name);
|
||||||
|
if !symbols.contains_key(&key) {
|
||||||
|
// surely there's a better way to do this?
|
||||||
symbols.insert(
|
symbols.insert(
|
||||||
make_qname(path, name),
|
key,
|
||||||
Symbol::Variable {
|
Symbol::Variable {
|
||||||
name: name.lexeme.to_string(),
|
name: name.lexeme.to_string(),
|
||||||
var_type: var_type.clone(),
|
var_type: var_type.clone(),
|
||||||
initializer: initializer.clone(),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Statement::FunctionStmt { function } => {
|
Statement::FunctionStmt { function } => {
|
||||||
symbols.insert(
|
symbols.insert(
|
||||||
make_qname(path, &function.name),
|
make_qname(path, &function.name),
|
||||||
|
|
@ -88,7 +93,7 @@ pub fn _add_types(
|
||||||
initializer,
|
initializer,
|
||||||
} => {
|
} => {
|
||||||
let inferred_type = infer_type(initializer, symbols);
|
let inferred_type = infer_type(initializer, symbols);
|
||||||
let calculated_type = calculate_type(var_type, &inferred_type, symbols)?;
|
let calculated_type = calculate_type(var_type, &inferred_type)?;
|
||||||
let entry = symbols.get_mut(&format!("{}.{}", path, name.lexeme));
|
let entry = symbols.get_mut(&format!("{}.{}", path, name.lexeme));
|
||||||
if let Some(Symbol::Variable { var_type, .. }) = entry {
|
if let Some(Symbol::Variable { var_type, .. }) = entry {
|
||||||
*var_type = calculated_type;
|
*var_type = calculated_type;
|
||||||
|
|
@ -103,7 +108,6 @@ pub fn _add_types(
|
||||||
pub fn calculate_type(
|
pub fn calculate_type(
|
||||||
declared_type: &TokenType,
|
declared_type: &TokenType,
|
||||||
inferred_type: &TokenType,
|
inferred_type: &TokenType,
|
||||||
_symbols: &HashMap<String, Symbol>,
|
|
||||||
) -> Result<TokenType, CompilerError> {
|
) -> Result<TokenType, CompilerError> {
|
||||||
Ok(if declared_type != &Unknown {
|
Ok(if declared_type != &Unknown {
|
||||||
if declared_type != inferred_type {
|
if declared_type != inferred_type {
|
||||||
|
|
@ -118,6 +122,7 @@ pub fn calculate_type(
|
||||||
(F64, FloatingPoint) => F64,
|
(F64, FloatingPoint) => F64,
|
||||||
(U64, I64) => U64,
|
(U64, I64) => U64,
|
||||||
(U64, I32) => U64,
|
(U64, I32) => U64,
|
||||||
|
(I64, Integer) => I64,
|
||||||
(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(IncompatibleTypes(
|
return Err(IncompatibleTypes(
|
||||||
|
|
|
||||||
12
src/value.rs
12
src/value.rs
|
|
@ -57,6 +57,18 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cast_usize(self) -> Result<usize, ValueError> {
|
||||||
|
match self {
|
||||||
|
Value::U32(v) => Ok(v as usize),
|
||||||
|
Value::U64(v) => Ok(v as usize),
|
||||||
|
Value::I32(v) => Ok(v as usize),
|
||||||
|
Value::I64(v) => Ok(v as usize),
|
||||||
|
Value::F32(v) => Ok(v as usize),
|
||||||
|
Value::F64(v) => Ok(v as usize),
|
||||||
|
_ => Err(ValueError::IllegalCast),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cast_i32(self) -> Result<Self, ValueError> {
|
pub fn cast_i32(self) -> Result<Self, ValueError> {
|
||||||
match self {
|
match self {
|
||||||
Value::U32(v) => Ok(Value::I32(v as i32)),
|
Value::U32(v) => Ok(Value::I32(v as i32)),
|
||||||
|
|
|
||||||
21
src/vm.rs
21
src/vm.rs
|
|
@ -3,11 +3,11 @@ use crate::errors::RuntimeError::Something;
|
||||||
use crate::errors::{RuntimeError, ValueError};
|
use crate::errors::{RuntimeError, ValueError};
|
||||||
use crate::tokens::TokenType;
|
use crate::tokens::TokenType;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use axum::http::{Uri};
|
use arc_swap::Guard;
|
||||||
|
use axum::http::Uri;
|
||||||
|
use reqwest::get;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use arc_swap::Guard;
|
|
||||||
use reqwest::get;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
|
|
@ -18,7 +18,10 @@ pub struct Vm {
|
||||||
registry: Arc<HashMap<String, Chunk>>,
|
registry: Arc<HashMap<String, Chunk>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret(registry: Guard<Arc<HashMap<String, Chunk>>>, function: &str) -> Result<Value, RuntimeError> {
|
pub fn interpret(
|
||||||
|
registry: Guard<Arc<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);
|
||||||
|
|
@ -191,12 +194,10 @@ impl Vm {
|
||||||
self.push(value.clone()); // not happy , take ownership, no clone
|
self.push(value.clone()); // not happy , take ownership, no clone
|
||||||
}
|
}
|
||||||
OP_LIST_GET => {
|
OP_LIST_GET => {
|
||||||
let index_high = self.read(chunk);
|
let index = self.pop();
|
||||||
let index_low = self.read(chunk);
|
|
||||||
let index = (index_high <<16) + index_low;
|
|
||||||
let list = self.pop();
|
let list = self.pop();
|
||||||
if let Value::List(list) = list {
|
if let Value::List(list) = list {
|
||||||
self.push(list.get(index).cloned().unwrap())
|
self.push(list.get(index.cast_usize()?).cloned().unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OP_CALL => {
|
OP_CALL => {
|
||||||
|
|
@ -211,7 +212,9 @@ impl Vm {
|
||||||
args.reverse();
|
args.reverse();
|
||||||
|
|
||||||
let function_name = chunk.constants[function_name_index].to_string();
|
let function_name = chunk.constants[function_name_index].to_string();
|
||||||
let function_chunk = self.registry.get(&function_name)
|
let function_chunk = self
|
||||||
|
.registry
|
||||||
|
.get(&function_name)
|
||||||
.or_else(|| self.registry.get(&format!("{}/{}", context, function_name)));
|
.or_else(|| self.registry.get(&format!("{}/{}", context, function_name)));
|
||||||
if function_chunk.is_none() {
|
if function_chunk.is_none() {
|
||||||
return Err(RuntimeError::FunctionNotFound(function_name));
|
return Err(RuntimeError::FunctionNotFound(function_name));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue