mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-02-01 17:39:13 +01:00
Added the unit
statement (very basic and experimental).
This commit is contained in:
parent
c0628855ae
commit
45adb1b526
@ -7,6 +7,7 @@ use crate::parser::Unit;
|
|||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
VarDecl(String, Box<Expr>),
|
VarDecl(String, Box<Expr>),
|
||||||
FnDecl(String, Vec<String>, Box<Expr>),
|
FnDecl(String, Vec<String>, Box<Expr>),
|
||||||
|
UnitDecl(String, String, Box<Expr>),
|
||||||
/// For simplicity, expressions can be put into statements. This is the form in which expressions are passed to the interpreter.
|
/// For simplicity, expressions can be put into statements. This is the form in which expressions are passed to the interpreter.
|
||||||
Expr(Box<Expr>),
|
Expr(Box<Expr>),
|
||||||
}
|
}
|
||||||
@ -16,7 +17,7 @@ pub enum Stmt {
|
|||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
Binary(Box<Expr>, TokenKind, Box<Expr>),
|
Binary(Box<Expr>, TokenKind, Box<Expr>),
|
||||||
Unary(TokenKind, Box<Expr>),
|
Unary(TokenKind, Box<Expr>),
|
||||||
Unit(Box<Expr>, TokenKind),
|
Unit(String, Box<Expr>),
|
||||||
Var(String),
|
Var(String),
|
||||||
Group(Box<Expr>),
|
Group(Box<Expr>),
|
||||||
FnCall(String, Vec<Expr>),
|
FnCall(String, Vec<Expr>),
|
||||||
|
@ -39,18 +39,15 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<Float, CalcError> {
|
fn eval_stmt(context: &mut Context, stmt: &Stmt) -> Result<Float, CalcError> {
|
||||||
match stmt {
|
match stmt {
|
||||||
Stmt::VarDecl(identifier, _) => eval_var_decl_stmt(context, stmt, identifier),
|
Stmt::VarDecl(_, _) => eval_var_decl_stmt(context, stmt),
|
||||||
Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context),
|
Stmt::FnDecl(_, _, _) => eval_fn_decl_stmt(context),
|
||||||
|
Stmt::UnitDecl(_, _, _) => eval_unit_decl_stmt(context),
|
||||||
Stmt::Expr(expr) => eval_expr_stmt(context, &expr),
|
Stmt::Expr(expr) => eval_expr_stmt(context, &expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_var_decl_stmt(
|
fn eval_var_decl_stmt(context: &mut Context, stmt: &Stmt) -> Result<Float, CalcError> {
|
||||||
context: &mut Context,
|
context.symbol_table.insert(stmt.clone());
|
||||||
stmt: &Stmt,
|
|
||||||
identifier: &str,
|
|
||||||
) -> Result<Float, CalcError> {
|
|
||||||
context.symbol_table.insert(&identifier, stmt.clone());
|
|
||||||
Ok(Float::with_val(context.precision, 1))
|
Ok(Float::with_val(context.precision, 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +55,10 @@ fn eval_fn_decl_stmt(context: &mut Context) -> Result<Float, CalcError> {
|
|||||||
Ok(Float::with_val(context.precision, 1)) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table.
|
Ok(Float::with_val(context.precision, 1)) // Nothing needs to happen here, since the parser will already have added the FnDecl's to the symbol table.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eval_unit_decl_stmt(context: &mut Context) -> Result<Float, CalcError> {
|
||||||
|
Ok(Float::with_val(context.precision, 1))
|
||||||
|
}
|
||||||
|
|
||||||
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
||||||
eval_expr(context, &expr)
|
eval_expr(context, &expr)
|
||||||
}
|
}
|
||||||
@ -66,7 +67,7 @@ fn eval_expr(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
|||||||
match expr {
|
match expr {
|
||||||
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right),
|
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right),
|
||||||
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr),
|
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr),
|
||||||
Expr::Unit(expr, kind) => eval_unit_expr(context, expr, kind),
|
Expr::Unit(_, expr) => eval_unit_expr(context, expr),
|
||||||
Expr::Var(identifier) => eval_var_expr(context, identifier),
|
Expr::Var(identifier) => eval_var_expr(context, identifier),
|
||||||
Expr::Literal(value) => eval_literal_expr(context, value),
|
Expr::Literal(value) => eval_literal_expr(context, value),
|
||||||
Expr::Group(expr) => eval_group_expr(context, &expr),
|
Expr::Group(expr) => eval_group_expr(context, &expr),
|
||||||
@ -78,12 +79,20 @@ fn eval_expr(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
|||||||
|
|
||||||
fn eval_binary_expr(
|
fn eval_binary_expr(
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
left: &Expr,
|
left_expr: &Expr,
|
||||||
op: &TokenKind,
|
op: &TokenKind,
|
||||||
right: &Expr,
|
right_expr: &Expr,
|
||||||
) -> Result<Float, CalcError> {
|
) -> Result<Float, CalcError> {
|
||||||
let left = eval_expr(context, &left)?;
|
let left = eval_expr(context, left_expr)?;
|
||||||
let right = eval_expr(context, &right)?;
|
let right = if let Expr::Unit(left_unit, _) = left_expr {
|
||||||
|
if let Expr::Unit(right_unit, right_unit_expr) = right_expr {
|
||||||
|
convert_unit(context, right_unit_expr, right_unit, &left_unit)?
|
||||||
|
} else {
|
||||||
|
eval_expr(context, right_expr)?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eval_expr(context, right_expr)?
|
||||||
|
};
|
||||||
|
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
TokenKind::Plus => left + right,
|
TokenKind::Plus => left + right,
|
||||||
@ -108,26 +117,26 @@ fn eval_unary_expr(context: &mut Context, op: &TokenKind, expr: &Expr) -> Result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_unit_expr(
|
fn eval_unit_expr(context: &mut Context, expr: &Expr) -> Result<Float, CalcError> {
|
||||||
|
eval_expr(context, expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_unit(
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
kind: &TokenKind,
|
from_unit: &str,
|
||||||
|
to_unit: &str,
|
||||||
) -> Result<Float, CalcError> {
|
) -> Result<Float, CalcError> {
|
||||||
let x = eval_expr(context, &expr);
|
if let Some(Stmt::UnitDecl(_, _, unit_def)) =
|
||||||
let unit = kind.to_unit()?;
|
context.symbol_table.get_unit(from_unit, to_unit).cloned()
|
||||||
|
{
|
||||||
|
context
|
||||||
|
.symbol_table
|
||||||
|
.insert(Stmt::VarDecl(String::from("u"), Box::new(expr.clone())));
|
||||||
|
|
||||||
// Don't do any angle conversions if the defauly angle unit is the same as the unit kind
|
eval_expr(context, &unit_def)
|
||||||
match unit {
|
} else {
|
||||||
Unit::Degrees | Unit::Radians => {
|
Err(CalcError::InvalidUnit)
|
||||||
if context.angle_unit == unit {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match unit {
|
|
||||||
Unit::Degrees => Ok(prelude::special_funcs::to_radians(x?)),
|
|
||||||
Unit::Radians => Ok(prelude::special_funcs::to_degrees(x?)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +147,7 @@ fn eval_var_expr(context: &mut Context, identifier: &str) -> Result<Float, CalcE
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Look for the variable in the symbol table
|
// Look for the variable in the symbol table
|
||||||
let var_decl = context.symbol_table.get(identifier).cloned();
|
let var_decl = context.symbol_table.get_var(identifier).cloned();
|
||||||
match var_decl {
|
match var_decl {
|
||||||
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
|
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
|
||||||
_ => Err(CalcError::UndefinedVar(identifier.into())),
|
_ => Err(CalcError::UndefinedVar(identifier.into())),
|
||||||
@ -202,7 +211,7 @@ fn eval_fn_call_expr(
|
|||||||
// then calculate the expression and add it to the total sum.
|
// then calculate the expression and add it to the total sum.
|
||||||
context
|
context
|
||||||
.symbol_table
|
.symbol_table
|
||||||
.set("n", Stmt::VarDecl(String::from("n"), Box::new(n_expr)));
|
.set(Stmt::VarDecl(String::from("n"), Box::new(n_expr)));
|
||||||
sum += eval_expr(context, &expressions[2])?;
|
sum += eval_expr(context, &expressions[2])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,10 +221,7 @@ fn eval_fn_call_expr(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Symbol Table
|
// Symbol Table
|
||||||
let stmt_definition = context
|
let stmt_definition = context.symbol_table.get_fn(identifier).cloned();
|
||||||
.symbol_table
|
|
||||||
.get(&format!("{}()", identifier))
|
|
||||||
.cloned();
|
|
||||||
|
|
||||||
match stmt_definition {
|
match stmt_definition {
|
||||||
Some(Stmt::FnDecl(_, arguments, fn_body)) => {
|
Some(Stmt::FnDecl(_, arguments, fn_body)) => {
|
||||||
@ -294,7 +300,7 @@ mod tests {
|
|||||||
assert!(fact_dec_result > 169.406 && fact_dec_result < 169.407);
|
assert!(fact_dec_result > 169.406 && fact_dec_result < 169.407);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
/*#[test]
|
||||||
fn test_unit() {
|
fn test_unit() {
|
||||||
let rad = Stmt::Expr(Box::new(Expr::Unit(literal("1"), Rad)));
|
let rad = Stmt::Expr(Box::new(Expr::Unit(literal("1"), Rad)));
|
||||||
let deg = Stmt::Expr(Box::new(Expr::Unit(literal("1"), Deg)));
|
let deg = Stmt::Expr(Box::new(Expr::Unit(literal("1"), Deg)));
|
||||||
@ -304,7 +310,7 @@ mod tests {
|
|||||||
(interpret(deg).unwrap().unwrap() - Float::with_val(PRECISION, 0.017456)).abs()
|
(interpret(deg).unwrap().unwrap() - Float::with_val(PRECISION, 0.017456)).abs()
|
||||||
< Float::with_val(PRECISION, 0.0001)
|
< Float::with_val(PRECISION, 0.0001)
|
||||||
);
|
);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_var() {
|
fn test_var() {
|
||||||
@ -312,7 +318,7 @@ mod tests {
|
|||||||
|
|
||||||
// Prepare by inserting a variable declaration in the symbol table.
|
// Prepare by inserting a variable declaration in the symbol table.
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
symbol_table.insert("x", var_decl("x", literal("1")));
|
symbol_table.insert(var_decl("x", literal("1")));
|
||||||
|
|
||||||
let mut context = Context::new(&mut symbol_table, &Unit::Radians, PRECISION);
|
let mut context = Context::new(&mut symbol_table, &Unit::Radians, PRECISION);
|
||||||
assert_eq!(context.interpret(vec![stmt]).unwrap().unwrap(), 1);
|
assert_eq!(context.interpret(vec![stmt]).unwrap().unwrap(), 1);
|
||||||
@ -345,14 +351,11 @@ mod tests {
|
|||||||
|
|
||||||
// Prepare by inserting a variable declaration in the symbol table.
|
// Prepare by inserting a variable declaration in the symbol table.
|
||||||
let mut symbol_table = SymbolTable::new();
|
let mut symbol_table = SymbolTable::new();
|
||||||
symbol_table.insert(
|
symbol_table.insert(fn_decl(
|
||||||
"f()",
|
"f",
|
||||||
fn_decl(
|
vec![String::from("x")],
|
||||||
"f",
|
binary(var("x"), TokenKind::Plus, literal("2")),
|
||||||
vec![String::from("x")],
|
));
|
||||||
binary(var("x"), TokenKind::Plus, literal("2")),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut context = Context::new(&mut symbol_table, &Unit::Radians, PRECISION);
|
let mut context = Context::new(&mut symbol_table, &Unit::Radians, PRECISION);
|
||||||
assert_eq!(context.interpret(vec![stmt]).unwrap().unwrap(), 3);
|
assert_eq!(context.interpret(vec![stmt]).unwrap().unwrap(), 3);
|
||||||
|
@ -16,6 +16,8 @@ pub enum TokenKind {
|
|||||||
Equals,
|
Equals,
|
||||||
Exclamation,
|
Exclamation,
|
||||||
|
|
||||||
|
UnitKeyword,
|
||||||
|
To,
|
||||||
Deg,
|
Deg,
|
||||||
Rad,
|
Rad,
|
||||||
|
|
||||||
@ -170,6 +172,8 @@ impl<'a> Lexer<'a> {
|
|||||||
let kind = match value.as_ref() {
|
let kind = match value.as_ref() {
|
||||||
"deg" | "°" => TokenKind::Deg,
|
"deg" | "°" => TokenKind::Deg,
|
||||||
"rad" => TokenKind::Rad,
|
"rad" => TokenKind::Rad,
|
||||||
|
"unit" => TokenKind::UnitKeyword,
|
||||||
|
"to" => TokenKind::To,
|
||||||
_ => TokenKind::Identifier,
|
_ => TokenKind::Identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ pub struct Context {
|
|||||||
pos: usize,
|
pos: usize,
|
||||||
symbol_table: SymbolTable,
|
symbol_table: SymbolTable,
|
||||||
angle_unit: Unit,
|
angle_unit: Unit,
|
||||||
|
parsing_unit_decl: bool,
|
||||||
|
unit_decl_base_unit: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
@ -28,6 +30,8 @@ impl Context {
|
|||||||
pos: 0,
|
pos: 0,
|
||||||
symbol_table: SymbolTable::new(),
|
symbol_table: SymbolTable::new(),
|
||||||
angle_unit: Unit::Radians,
|
angle_unit: Unit::Radians,
|
||||||
|
parsing_unit_decl: false,
|
||||||
|
unit_decl_base_unit: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +105,8 @@ fn parse_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
|||||||
TokenKind::OpenParenthesis => parse_identifier_stmt(context)?,
|
TokenKind::OpenParenthesis => parse_identifier_stmt(context)?,
|
||||||
_ => Stmt::Expr(Box::new(parse_expr(context)?)),
|
_ => Stmt::Expr(Box::new(parse_expr(context)?)),
|
||||||
});
|
});
|
||||||
|
} else if match_token(context, TokenKind::UnitKeyword) {
|
||||||
|
return parse_unit_decl_stmt(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
|
Ok(Stmt::Expr(Box::new(parse_expr(context)?)))
|
||||||
@ -132,9 +138,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
|||||||
|
|
||||||
// Insert the function declaration into the symbol table during parsing
|
// Insert the function declaration into the symbol table during parsing
|
||||||
// so that the parser can find out if particular functions exist.
|
// so that the parser can find out if particular functions exist.
|
||||||
context
|
context.symbol_table.insert(fn_decl.clone());
|
||||||
.symbol_table
|
|
||||||
.insert(&format!("{}()", identifier), fn_decl.clone());
|
|
||||||
|
|
||||||
return Ok(fn_decl);
|
return Ok(fn_decl);
|
||||||
}
|
}
|
||||||
@ -156,6 +160,29 @@ fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
|||||||
Ok(Stmt::VarDecl(identifier.value, Box::new(expr)))
|
Ok(Stmt::VarDecl(identifier.value, Box::new(expr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_unit_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||||
|
advance(context); // Unit keyword
|
||||||
|
let identifier = advance(context).clone();
|
||||||
|
consume(context, TokenKind::Equals)?;
|
||||||
|
|
||||||
|
// Parse the definition
|
||||||
|
context.parsing_unit_decl = true;
|
||||||
|
let def = parse_expr(context)?;
|
||||||
|
context.parsing_unit_decl = false;
|
||||||
|
|
||||||
|
let base_unit = if let Some(base_unit) = &context.unit_decl_base_unit {
|
||||||
|
base_unit.clone()
|
||||||
|
} else {
|
||||||
|
return Err(CalcError::InvalidUnit);
|
||||||
|
};
|
||||||
|
|
||||||
|
let stmt = Stmt::UnitDecl(identifier.value, base_unit, Box::new(def));
|
||||||
|
|
||||||
|
context.symbol_table.insert(stmt.clone());
|
||||||
|
|
||||||
|
Ok(stmt)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_expr(context: &mut Context) -> Result<Expr, CalcError> {
|
fn parse_expr(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
Ok(parse_sum(context)?)
|
Ok(parse_sum(context)?)
|
||||||
}
|
}
|
||||||
@ -175,7 +202,7 @@ fn parse_sum(context: &mut Context) -> Result<Expr, CalcError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
|
fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
let mut left = parse_unary(context)?;
|
let mut left = parse_unit(context)?;
|
||||||
|
|
||||||
while match_token(context, TokenKind::Star)
|
while match_token(context, TokenKind::Star)
|
||||||
|| match_token(context, TokenKind::Slash)
|
|| match_token(context, TokenKind::Slash)
|
||||||
@ -188,13 +215,27 @@ fn parse_factor(context: &mut Context) -> Result<Expr, CalcError> {
|
|||||||
_ => advance(context).kind.clone(),
|
_ => advance(context).kind.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let right = parse_unary(context)?;
|
let right = parse_unit(context)?;
|
||||||
left = Expr::Binary(Box::new(left), op, Box::new(right));
|
left = Expr::Binary(Box::new(left), op, Box::new(right));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(left)
|
Ok(left)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_unit(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
|
let expr = parse_unary(context)?;
|
||||||
|
let peek = &peek(&context).value;
|
||||||
|
|
||||||
|
if match_token(context, TokenKind::Identifier) && context.symbol_table.contains_unit(&peek) {
|
||||||
|
return Ok(Expr::Unit(
|
||||||
|
advance(context).value.to_string(),
|
||||||
|
Box::new(expr),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_unary(context: &mut Context) -> Result<Expr, CalcError> {
|
fn parse_unary(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
if match_token(context, TokenKind::Minus) {
|
if match_token(context, TokenKind::Minus) {
|
||||||
let op = advance(context).kind.clone();
|
let op = advance(context).kind.clone();
|
||||||
@ -236,11 +277,7 @@ fn parse_primary(context: &mut Context) -> Result<Expr, CalcError> {
|
|||||||
_ => Expr::Literal(advance(context).value.clone()),
|
_ => Expr::Literal(advance(context).value.clone()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_at_end(context) && peek(context).kind.is_unit() {
|
Ok(expr)
|
||||||
Ok(Expr::Unit(Box::new(expr), advance(context).kind.clone()))
|
|
||||||
} else {
|
|
||||||
Ok(expr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_group(context: &mut Context) -> Result<Expr, CalcError> {
|
fn parse_group(context: &mut Context) -> Result<Expr, CalcError> {
|
||||||
@ -295,7 +332,10 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Eg. x
|
// Eg. x
|
||||||
if context.symbol_table.contains_var(&identifier.value) {
|
if context.parsing_unit_decl {
|
||||||
|
context.unit_decl_base_unit = Some(identifier.value);
|
||||||
|
Ok(Expr::Var(String::from("u")))
|
||||||
|
} else if context.symbol_table.contains_var(&identifier.value) {
|
||||||
Ok(Expr::Var(identifier.value))
|
Ok(Expr::Var(identifier.value))
|
||||||
} else {
|
} else {
|
||||||
let mut chars = identifier.value.chars();
|
let mut chars = identifier.value.chars();
|
||||||
@ -315,19 +355,19 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(context: &mut Context) -> &Token {
|
fn peek(context: &Context) -> &Token {
|
||||||
&context.tokens[context.pos]
|
&context.tokens[context.pos]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_next(context: &mut Context) -> &Token {
|
fn peek_next(context: &Context) -> &Token {
|
||||||
&context.tokens[context.pos + 1]
|
&context.tokens[context.pos + 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn previous(context: &mut Context) -> &Token {
|
fn previous(context: &Context) -> &Token {
|
||||||
&context.tokens[context.pos - 1]
|
&context.tokens[context.pos - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_token(context: &mut Context, kind: TokenKind) -> bool {
|
fn match_token(context: &Context, kind: TokenKind) -> bool {
|
||||||
if is_at_end(context) {
|
if is_at_end(context) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -348,7 +388,7 @@ fn consume(context: &mut Context, kind: TokenKind) -> Result<&Token, CalcError>
|
|||||||
Err(CalcError::UnexpectedToken(kind))
|
Err(CalcError::UnexpectedToken(kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_at_end(context: &mut Context) -> bool {
|
fn is_at_end(context: &Context) -> bool {
|
||||||
context.pos >= context.tokens.len() || peek(context).kind == TokenKind::EOF
|
context.pos >= context.tokens.len() || peek(context).kind == TokenKind::EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +397,6 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::lexer::{Token, TokenKind::*};
|
use crate::lexer::{Token, TokenKind::*};
|
||||||
use crate::test_helpers::*;
|
use crate::test_helpers::*;
|
||||||
use test_case::test_case;
|
|
||||||
|
|
||||||
fn parse_with_context(context: &mut Context, tokens: Vec<Token>) -> Result<Stmt, CalcError> {
|
fn parse_with_context(context: &mut Context, tokens: Vec<Token>) -> Result<Stmt, CalcError> {
|
||||||
context.tokens = tokens;
|
context.tokens = tokens;
|
||||||
@ -447,7 +486,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test_case(Deg)]
|
/*#[test_case(Deg)]
|
||||||
#[test_case(Rad)]
|
#[test_case(Rad)]
|
||||||
fn test_unary(angle_unit: TokenKind) {
|
fn test_unary(angle_unit: TokenKind) {
|
||||||
let tokens = vec![
|
let tokens = vec![
|
||||||
@ -460,7 +499,7 @@ mod tests {
|
|||||||
parse(tokens).unwrap(),
|
parse(tokens).unwrap(),
|
||||||
Stmt::Expr(unary(Minus, Box::new(Expr::Unit(literal("1"), angle_unit))))
|
Stmt::Expr(unary(Minus, Box::new(Expr::Unit(literal("1"), angle_unit))))
|
||||||
);
|
);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_var_decl() {
|
fn test_var_decl() {
|
||||||
@ -517,10 +556,11 @@ mod tests {
|
|||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
|
|
||||||
// Add the function to the symbol table first, in order to prevent errors.
|
// Add the function to the symbol table first, in order to prevent errors.
|
||||||
context.symbol_table.set(
|
context.symbol_table.set(Stmt::FnDecl(
|
||||||
"f()",
|
String::from("f"),
|
||||||
Stmt::FnDecl(String::from("f"), vec![String::from("x")], literal("1")),
|
vec![String::from("x")],
|
||||||
);
|
literal("1"),
|
||||||
|
));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse_with_context(&mut context, tokens).unwrap(),
|
parse_with_context(&mut context, tokens).unwrap(),
|
||||||
|
@ -1,40 +1,79 @@
|
|||||||
use crate::{ast::Stmt, prelude};
|
use crate::{ast::Stmt, prelude};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct SymbolTable {
|
pub struct SymbolTable {
|
||||||
hashmap: HashMap<String, Stmt>,
|
hashmap: HashMap<String, Stmt>,
|
||||||
|
unit_types: HashMap<String, ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolTable {
|
impl SymbolTable {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SymbolTable {
|
SymbolTable {
|
||||||
hashmap: HashMap::new(),
|
hashmap: HashMap::new(),
|
||||||
|
unit_types: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, key: &str, value: Stmt) {
|
pub fn insert(&mut self, value: Stmt) -> Option<Stmt> {
|
||||||
self.hashmap.insert(key.into(), value);
|
match &value {
|
||||||
|
Stmt::VarDecl(identifier, _) => {
|
||||||
|
self.hashmap.insert(format!("var.{}", identifier), value)
|
||||||
|
}
|
||||||
|
Stmt::UnitDecl(identifier, to_unit, _) => {
|
||||||
|
self.unit_types.insert(identifier.to_string(), ());
|
||||||
|
self.unit_types.insert(to_unit.to_string(), ());
|
||||||
|
self.hashmap
|
||||||
|
.insert(format!("unit.{}.{}", identifier, to_unit), value)
|
||||||
|
}
|
||||||
|
Stmt::FnDecl(identifier, _, _) => {
|
||||||
|
self.hashmap.insert(format!("fn.{}", identifier), value)
|
||||||
|
}
|
||||||
|
_ => panic!("Can only insert VarDecl, UnitDecl and FnDecl into symbol table."),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &str) -> Option<&Stmt> {
|
pub fn get_var(&self, key: &str) -> Option<&Stmt> {
|
||||||
self.hashmap.get(key)
|
self.hashmap.get(&format!("var.{}", key))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, key: &str, value: Stmt) {
|
pub fn get_unit(&self, key: &str, to_unit: &str) -> Option<&Stmt> {
|
||||||
if let Some(stmt) = self.hashmap.get_mut(key) {
|
self.hashmap.get(&format!("unit.{}.{}", key, to_unit))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fn(&self, key: &str) -> Option<&Stmt> {
|
||||||
|
self.hashmap.get(&format!("fn.{}", key))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, value: Stmt) {
|
||||||
|
let existing_item = match &value {
|
||||||
|
Stmt::VarDecl(identifier, _) => self.hashmap.get_mut(&format!("var.{}", identifier)),
|
||||||
|
Stmt::UnitDecl(identifier, to_unit, _) => self
|
||||||
|
.hashmap
|
||||||
|
.get_mut(&format!("unit.{}.{}", identifier, to_unit)),
|
||||||
|
Stmt::FnDecl(identifier, _, _) => self.hashmap.get_mut(&format!("fn.{}", identifier)),
|
||||||
|
_ => panic!("Can only set VarDecl, UnitDecl and FnDecl in symbol table."),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(stmt) = existing_item {
|
||||||
*stmt = value;
|
*stmt = value;
|
||||||
} else {
|
} else {
|
||||||
self.insert(key, value);
|
self.insert(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_var(&self, identifier: &str) -> bool {
|
pub fn contains_var(&self, identifier: &str) -> bool {
|
||||||
prelude::CONSTANTS.contains_key(identifier) || self.hashmap.contains_key(identifier)
|
prelude::CONSTANTS.contains_key(identifier)
|
||||||
|
|| self.hashmap.contains_key(&format!("var.{}", identifier))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains_unit(&self, identifier: &str) -> bool {
|
||||||
|
self.unit_types.contains_key(identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_fn(&self, identifier: &str) -> bool {
|
pub fn contains_fn(&self, identifier: &str) -> bool {
|
||||||
prelude::UNARY_FUNCS.contains_key(identifier)
|
prelude::UNARY_FUNCS.contains_key(identifier)
|
||||||
|| prelude::UNARY_FUNCS.contains_key(identifier)
|
|| prelude::UNARY_FUNCS.contains_key(identifier)
|
||||||
|| self.hashmap.contains_key(&format!("{}()", identifier))
|
|| self.hashmap.contains_key(&format!("fn.{}", identifier))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user