mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-01-31 17:09:13 +01:00
Created 'Identifier' struct that contains prime count and name without primes (ticks ')
This commit is contained in:
parent
374a449eab
commit
9acdd71589
@ -3,8 +3,8 @@ use crate::lexer::TokenKind;
|
||||
/// A tree structure of a statement.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Stmt {
|
||||
VarDecl(String, Box<Expr>),
|
||||
FnDecl(String, Vec<String>, Box<Expr>),
|
||||
VarDecl(Identifier, Box<Expr>),
|
||||
FnDecl(Identifier, 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.
|
||||
Expr(Box<Expr>),
|
||||
@ -16,8 +16,41 @@ pub enum Expr {
|
||||
Binary(Box<Expr>, TokenKind, Box<Expr>),
|
||||
Unary(TokenKind, Box<Expr>),
|
||||
Unit(String, Box<Expr>),
|
||||
Var(String),
|
||||
Var(Identifier),
|
||||
Group(Box<Expr>),
|
||||
FnCall(String, Vec<Expr>),
|
||||
FnCall(Identifier, Vec<Expr>),
|
||||
Literal(f64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Identifier {
|
||||
pub full_name: String,
|
||||
pub pure_name: String,
|
||||
pub prime_count: i32,
|
||||
}
|
||||
|
||||
impl Identifier {
|
||||
pub fn from_full_name(full_name: &str) -> Self {
|
||||
let (pure_name, prime_count) = separate_identifier_and_prime(full_name);
|
||||
|
||||
Identifier {
|
||||
full_name: full_name.to_string(),
|
||||
pure_name,
|
||||
prime_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn separate_identifier_and_prime(identifier: &str) -> (String, i32) {
|
||||
let mut prim_count = 0;
|
||||
let mut pure_identifier = identifier.to_string();
|
||||
|
||||
loop {
|
||||
if pure_identifier.ends_with("'") {
|
||||
pure_identifier.pop();
|
||||
prim_count += 1;
|
||||
} else {
|
||||
return (pure_identifier, prim_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::ast::Identifier;
|
||||
use crate::ast::{Expr, Stmt};
|
||||
use crate::calculus;
|
||||
use crate::kalk_num::KalkNum;
|
||||
@ -46,14 +47,17 @@ impl<'a> Context<'a> {
|
||||
// Insert the last value into the `ans` variable.
|
||||
self.symbol_table.set(if (&num.unit).len() > 0 {
|
||||
Stmt::VarDecl(
|
||||
String::from("ans"),
|
||||
Identifier::from_full_name("ans"),
|
||||
Box::new(Expr::Unit(
|
||||
num.unit.clone(),
|
||||
Box::new(Expr::Literal(num.to_f64())),
|
||||
)),
|
||||
)
|
||||
} else {
|
||||
Stmt::VarDecl(String::from("ans"), Box::new(Expr::Literal(num.to_f64())))
|
||||
Stmt::VarDecl(
|
||||
Identifier::from_full_name("ans"),
|
||||
Box::new(Expr::Literal(num.to_f64())),
|
||||
)
|
||||
});
|
||||
|
||||
if i == statements.len() - 1 {
|
||||
@ -130,7 +134,8 @@ fn eval_binary_expr(
|
||||
// move this to the match statement further down.
|
||||
if let Expr::Var(right_unit) = right_expr {
|
||||
let left_unit = eval_expr(context, left_expr, "")?.unit;
|
||||
return convert_unit(context, left_expr, &left_unit, &right_unit); // TODO: Avoid evaluating this twice.
|
||||
return convert_unit(context, left_expr, &left_unit, &right_unit.full_name);
|
||||
// TODO: Avoid evaluating this twice.
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,9 +207,10 @@ pub fn convert_unit(
|
||||
if let Some(Stmt::UnitDecl(_, _, unit_def)) =
|
||||
context.symbol_table.get_unit(to_unit, from_unit).cloned()
|
||||
{
|
||||
context
|
||||
.symbol_table
|
||||
.insert(Stmt::VarDecl(DECL_UNIT.into(), Box::new(expr.clone())));
|
||||
context.symbol_table.insert(Stmt::VarDecl(
|
||||
Identifier::from_full_name(DECL_UNIT),
|
||||
Box::new(expr.clone()),
|
||||
));
|
||||
|
||||
Ok(KalkNum::new(
|
||||
eval_expr(context, &unit_def, "")?.value,
|
||||
@ -217,25 +223,28 @@ pub fn convert_unit(
|
||||
|
||||
fn eval_var_expr(
|
||||
context: &mut Context,
|
||||
identifier: &str,
|
||||
identifier: &Identifier,
|
||||
unit: &str,
|
||||
) -> Result<KalkNum, CalcError> {
|
||||
// If there is a constant with this name, return a literal expression with its value
|
||||
if let Some(value) = prelude::CONSTANTS.get(identifier) {
|
||||
if let Some(value) = prelude::CONSTANTS.get(identifier.full_name.as_ref() as &str) {
|
||||
return eval_expr(context, &Expr::Literal(*value), unit);
|
||||
}
|
||||
|
||||
if identifier == "n" {
|
||||
if identifier.full_name == "n" {
|
||||
if let Some(value) = context.sum_n_value {
|
||||
return Ok(KalkNum::from(value));
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the variable in the symbol table
|
||||
let var_decl = context.symbol_table.get_var(identifier).cloned();
|
||||
let var_decl = context
|
||||
.symbol_table
|
||||
.get_var(identifier.full_name.as_ref() as &str)
|
||||
.cloned();
|
||||
match var_decl {
|
||||
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr, unit),
|
||||
_ => Err(CalcError::UndefinedVar(identifier.into())),
|
||||
_ => Err(CalcError::UndefinedVar(identifier.full_name)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,9 +263,9 @@ fn eval_group_expr(context: &mut Context, expr: &Expr, unit: &str) -> Result<Kal
|
||||
eval_expr(context, expr, unit)
|
||||
}
|
||||
|
||||
fn eval_fn_call_expr(
|
||||
pub(crate) fn eval_fn_call_expr(
|
||||
context: &mut Context,
|
||||
identifier: &str,
|
||||
identifier: &Identifier,
|
||||
expressions: &[Expr],
|
||||
unit: &str,
|
||||
) -> Result<KalkNum, CalcError> {
|
||||
@ -282,7 +291,7 @@ fn eval_fn_call_expr(
|
||||
}
|
||||
|
||||
// Special functions
|
||||
match identifier {
|
||||
match identifier.full_name.as_ref() {
|
||||
"sum" | "Σ" => {
|
||||
// Make sure exactly 3 arguments were supplied.
|
||||
if expressions.len() != 3 {
|
||||
@ -317,20 +326,20 @@ fn eval_fn_call_expr(
|
||||
));
|
||||
}
|
||||
|
||||
return calculus::integrate(context, expressions);
|
||||
return calculus::integrate(context, &expressions[0], &expressions[1], &expressions[2]);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// Symbol Table
|
||||
let stmt_definition = context.symbol_table.get_fn(identifier).cloned();
|
||||
let stmt_definition = context.symbol_table.get_fn(&identifier.full_name).cloned();
|
||||
|
||||
match stmt_definition {
|
||||
Some(Stmt::FnDecl(_, arguments, fn_body)) => {
|
||||
if arguments.len() != expressions.len() {
|
||||
return Err(CalcError::IncorrectAmountOfArguments(
|
||||
arguments.len(),
|
||||
identifier.into(),
|
||||
identifier.full_name,
|
||||
expressions.len(),
|
||||
));
|
||||
}
|
||||
@ -339,13 +348,16 @@ fn eval_fn_call_expr(
|
||||
for (i, argument) in arguments.iter().enumerate() {
|
||||
eval_stmt(
|
||||
context,
|
||||
&Stmt::VarDecl(argument.clone(), Box::new(expressions[i].clone())),
|
||||
&Stmt::VarDecl(
|
||||
Identifier::from_full_name(argument),
|
||||
Box::new(expressions[i].clone()),
|
||||
),
|
||||
)?;
|
||||
}
|
||||
|
||||
eval_expr(context, &fn_body, unit)
|
||||
}
|
||||
_ => Err(CalcError::UndefinedFn(identifier.into())),
|
||||
_ => Err(CalcError::UndefinedFn(identifier.full_name)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::ast::Identifier;
|
||||
use crate::ast::{Expr, Stmt};
|
||||
use crate::lexer::TokenKind;
|
||||
use crate::parser::CalcError;
|
||||
@ -44,7 +45,7 @@ impl Expr {
|
||||
symbol_table: &mut SymbolTable,
|
||||
unknown_var: &str,
|
||||
) -> Result<Self, CalcError> {
|
||||
let target_expr = Expr::Var(unknown_var.into());
|
||||
let target_expr = Expr::Var(Identifier::from_full_name(unknown_var));
|
||||
let result = invert(target_expr, symbol_table, self, unknown_var);
|
||||
|
||||
Ok(result?.0)
|
||||
@ -80,7 +81,7 @@ fn invert(
|
||||
Expr::FnCall(identifier, arguments) => invert_fn_call(
|
||||
target_expr,
|
||||
symbol_table,
|
||||
&identifier,
|
||||
identifier,
|
||||
arguments,
|
||||
unknown_var,
|
||||
),
|
||||
@ -166,14 +167,20 @@ fn invert_binary(
|
||||
TokenKind::Power => {
|
||||
return if contains_var(symbol_table, left, unknown_var) {
|
||||
invert(
|
||||
Expr::FnCall("root".into(), vec![target_expr, right.clone()]),
|
||||
Expr::FnCall(
|
||||
Identifier::from_full_name("root"),
|
||||
vec![target_expr, right.clone()],
|
||||
),
|
||||
symbol_table,
|
||||
right,
|
||||
unknown_var,
|
||||
)
|
||||
} else {
|
||||
invert(
|
||||
Expr::FnCall("log".into(), vec![target_expr, left.clone()]),
|
||||
Expr::FnCall(
|
||||
Identifier::from_full_name("log"),
|
||||
vec![target_expr, left.clone()],
|
||||
),
|
||||
symbol_table,
|
||||
right,
|
||||
unknown_var,
|
||||
@ -240,7 +247,7 @@ fn invert_unit(
|
||||
let x = Expr::Binary(
|
||||
Box::new(target_expr),
|
||||
TokenKind::ToKeyword,
|
||||
Box::new(Expr::Var(identifier.into())),
|
||||
Box::new(Expr::Var(Identifier::from_full_name(identifier))),
|
||||
);
|
||||
invert(x, symbol_table, expr, unknown_var)
|
||||
}
|
||||
@ -248,38 +255,41 @@ fn invert_unit(
|
||||
fn invert_var(
|
||||
target_expr: Expr,
|
||||
symbol_table: &mut SymbolTable,
|
||||
identifier: &str,
|
||||
identifier: &Identifier,
|
||||
unknown_var: &str,
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
if identifier == unknown_var {
|
||||
Ok((target_expr, Expr::Var(identifier.into())))
|
||||
} else if let Some(Stmt::VarDecl(_, var_expr)) = symbol_table.get_var(identifier).cloned() {
|
||||
if identifier.full_name == unknown_var {
|
||||
Ok((target_expr, Expr::Var(*identifier)))
|
||||
} else if let Some(Stmt::VarDecl(_, var_expr)) =
|
||||
symbol_table.get_var(&identifier.full_name).cloned()
|
||||
{
|
||||
invert(target_expr, symbol_table, &var_expr, unknown_var)
|
||||
} else {
|
||||
Ok((target_expr, Expr::Var(identifier.into())))
|
||||
Ok((target_expr, Expr::Var(*identifier)))
|
||||
}
|
||||
}
|
||||
|
||||
fn invert_fn_call(
|
||||
target_expr: Expr,
|
||||
symbol_table: &mut SymbolTable,
|
||||
identifier: &str,
|
||||
identifier: &Identifier,
|
||||
arguments: &Vec<Expr>,
|
||||
unknown_var: &str,
|
||||
) -> Result<(Expr, Expr), CalcError> {
|
||||
// If prelude function
|
||||
match arguments.len() {
|
||||
1 => {
|
||||
if prelude::UNARY_FUNCS.contains_key(identifier) {
|
||||
if let Some(fn_inv) = INVERSE_UNARY_FUNCS.get(identifier) {
|
||||
if prelude::UNARY_FUNCS.contains_key(identifier.full_name.as_ref() as &str) {
|
||||
if let Some(fn_inv) = INVERSE_UNARY_FUNCS.get(identifier.full_name.as_ref() as &str)
|
||||
{
|
||||
return invert(
|
||||
Expr::FnCall(fn_inv.to_string(), vec![target_expr]),
|
||||
Expr::FnCall(Identifier::from_full_name(fn_inv), vec![target_expr]),
|
||||
symbol_table,
|
||||
&arguments[0],
|
||||
unknown_var,
|
||||
);
|
||||
} else {
|
||||
match identifier {
|
||||
match identifier.full_name.as_ref() {
|
||||
"sqrt" => {
|
||||
return invert(
|
||||
Expr::Binary(
|
||||
@ -295,7 +305,7 @@ fn invert_fn_call(
|
||||
_ => {
|
||||
return Err(CalcError::UnableToInvert(format!(
|
||||
"Function '{}'",
|
||||
identifier
|
||||
identifier.full_name
|
||||
)));
|
||||
}
|
||||
}
|
||||
@ -303,10 +313,10 @@ fn invert_fn_call(
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
if prelude::BINARY_FUNCS.contains_key(identifier) {
|
||||
if prelude::BINARY_FUNCS.contains_key(identifier.full_name.as_ref() as &str) {
|
||||
return Err(CalcError::UnableToInvert(format!(
|
||||
"Function '{}'",
|
||||
identifier
|
||||
identifier.full_name
|
||||
)));
|
||||
}
|
||||
}
|
||||
@ -314,18 +324,19 @@ fn invert_fn_call(
|
||||
}
|
||||
|
||||
// Get the function definition from the symbol table.
|
||||
let (parameters, body) =
|
||||
if let Some(Stmt::FnDecl(_, parameters, body)) = symbol_table.get_fn(identifier).cloned() {
|
||||
(parameters, body)
|
||||
} else {
|
||||
return Err(CalcError::UndefinedFn(identifier.into()));
|
||||
};
|
||||
let (parameters, body) = if let Some(Stmt::FnDecl(_, parameters, body)) =
|
||||
symbol_table.get_fn(&identifier.full_name).cloned()
|
||||
{
|
||||
(parameters, body)
|
||||
} else {
|
||||
return Err(CalcError::UndefinedFn(identifier.full_name));
|
||||
};
|
||||
|
||||
// Make sure the input is valid.
|
||||
if parameters.len() != arguments.len() {
|
||||
return Err(CalcError::IncorrectAmountOfArguments(
|
||||
parameters.len(),
|
||||
identifier.into(),
|
||||
identifier.full_name,
|
||||
arguments.len(),
|
||||
));
|
||||
}
|
||||
@ -334,7 +345,7 @@ fn invert_fn_call(
|
||||
let mut parameters_iter = parameters.iter();
|
||||
for argument in arguments {
|
||||
symbol_table.insert(Stmt::VarDecl(
|
||||
parameters_iter.next().unwrap().to_string(),
|
||||
Identifier::from_full_name(¶meters_iter.next().unwrap().to_string()),
|
||||
Box::new(argument.clone()),
|
||||
));
|
||||
}
|
||||
@ -353,8 +364,10 @@ pub fn contains_var(symbol_table: &SymbolTable, expr: &Expr, var_name: &str) ->
|
||||
Expr::Unary(_, expr) => contains_var(symbol_table, expr, var_name),
|
||||
Expr::Unit(_, expr) => contains_var(symbol_table, expr, var_name),
|
||||
Expr::Var(identifier) => {
|
||||
identifier == var_name
|
||||
|| if let Some(Stmt::VarDecl(_, var_expr)) = symbol_table.get_var(identifier) {
|
||||
identifier.full_name == var_name
|
||||
|| if let Some(Stmt::VarDecl(_, var_expr)) =
|
||||
symbol_table.get_var(&identifier.full_name)
|
||||
{
|
||||
contains_var(symbol_table, var_expr, var_name)
|
||||
} else {
|
||||
false
|
||||
@ -409,6 +422,7 @@ fn multiply_into(expr: &Expr, base_expr: &Expr) -> Result<Expr, CalcError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ast::Expr;
|
||||
use crate::ast::Identifier;
|
||||
use crate::lexer::TokenKind::*;
|
||||
use crate::parser::DECL_UNIT;
|
||||
use crate::symbol_table::SymbolTable;
|
||||
@ -416,7 +430,9 @@ mod tests {
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
fn decl_unit() -> Box<Expr> {
|
||||
Box::new(Expr::Var(crate::parser::DECL_UNIT.into()))
|
||||
Box::new(Expr::Var(Identifier::from_full_name(
|
||||
crate::parser::DECL_UNIT,
|
||||
)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::ast::Identifier;
|
||||
use crate::kalk_num::KalkNum;
|
||||
use crate::{
|
||||
ast::{Expr, Stmt},
|
||||
@ -205,7 +206,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||
if let TokenKind::Equals = peek(context).kind {
|
||||
// Use the "function call" expression that was parsed, and put its values into a function declaration statement instead.
|
||||
if let Expr::FnCall(identifier, parameters) = primary {
|
||||
if !prelude::is_prelude_func(&identifier) {
|
||||
if !prelude::is_prelude_func(&identifier.full_name) {
|
||||
advance(context);
|
||||
let expr = parse_expr(context)?;
|
||||
let mut parameter_identifiers = Vec::new();
|
||||
@ -215,7 +216,7 @@ fn parse_identifier_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||
// Extract these.
|
||||
for parameter in parameters {
|
||||
if let Expr::Var(parameter_identifier) = parameter {
|
||||
parameter_identifiers.push(parameter_identifier);
|
||||
parameter_identifiers.push(parameter_identifier.full_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,7 +246,10 @@ fn parse_var_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||
return Err(CalcError::VariableReferencesItself);
|
||||
}
|
||||
|
||||
Ok(Stmt::VarDecl(identifier.value, Box::new(expr)))
|
||||
Ok(Stmt::VarDecl(
|
||||
Identifier::from_full_name(&identifier.value),
|
||||
Box::new(expr),
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_unit_decl_stmt(context: &mut Context) -> Result<Stmt, CalcError> {
|
||||
@ -309,9 +313,10 @@ fn parse_equation(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
return Err(CalcError::UnableToSolveEquation);
|
||||
}
|
||||
|
||||
context
|
||||
.symbol_table
|
||||
.insert(Stmt::VarDecl(var_name.into(), Box::new(inverted.clone())));
|
||||
context.symbol_table.insert(Stmt::VarDecl(
|
||||
Identifier::from_full_name(var_name),
|
||||
Box::new(inverted.clone()),
|
||||
));
|
||||
return Ok(inverted);
|
||||
}
|
||||
|
||||
@ -323,7 +328,7 @@ fn parse_to(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
|
||||
if match_token(context, TokenKind::ToKeyword) {
|
||||
advance(context);
|
||||
let right = Expr::Var(advance(context).value.clone()); // Parse this as a variable for now.
|
||||
let right = Expr::Var(Identifier::from_full_name(&advance(context).value)); // Parse this as a variable for now.
|
||||
|
||||
return Ok(Expr::Binary(
|
||||
Box::new(left),
|
||||
@ -469,7 +474,7 @@ fn parse_group_fn(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
let expr = parse_expr(context)?;
|
||||
advance(context);
|
||||
|
||||
Ok(Expr::FnCall(name.to_string(), vec![expr]))
|
||||
Ok(Expr::FnCall(Identifier::from_full_name(name), vec![expr]))
|
||||
}
|
||||
|
||||
fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
@ -480,7 +485,10 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
// If there is a function with this name, parse it as a function, with the next token as the argument.
|
||||
if context.symbol_table.contains_fn(&identifier.value) {
|
||||
let parameter = Expr::Literal(string_to_num(&advance(context).value));
|
||||
return Ok(Expr::FnCall(identifier.value, vec![parameter]));
|
||||
return Ok(Expr::FnCall(
|
||||
Identifier::from_full_name(&identifier.value),
|
||||
vec![parameter],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,32 +522,37 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
context.is_in_integral = false;
|
||||
}
|
||||
|
||||
return Ok(Expr::FnCall(identifier.value, parameters));
|
||||
return Ok(Expr::FnCall(
|
||||
Identifier::from_full_name(&identifier.value),
|
||||
parameters,
|
||||
));
|
||||
}
|
||||
|
||||
// Eg. dx inside an integral, should be parsed as *one* identifier
|
||||
if context.is_in_integral && identifier.value.starts_with("d") {
|
||||
return Ok(Expr::Var(identifier.value));
|
||||
return Ok(Expr::Var(Identifier::from_full_name(&identifier.value)));
|
||||
}
|
||||
|
||||
// Eg. x
|
||||
if parse_as_var_instead || context.symbol_table.contains_var(&identifier.value) {
|
||||
Ok(Expr::Var(identifier.value))
|
||||
Ok(Expr::Var(Identifier::from_full_name(&identifier.value)))
|
||||
} else if context.parsing_unit_decl {
|
||||
context.unit_decl_base_unit = Some(identifier.value);
|
||||
Ok(Expr::Var(DECL_UNIT.into()))
|
||||
Ok(Expr::Var(Identifier::from_full_name(DECL_UNIT)))
|
||||
} else {
|
||||
if let Some(equation_var) = &context.equation_variable {
|
||||
if &identifier.value == equation_var {
|
||||
return Ok(Expr::Var(identifier.value));
|
||||
return Ok(Expr::Var(Identifier::from_full_name(&identifier.value)));
|
||||
}
|
||||
} else if context.contains_equal_sign {
|
||||
context.equation_variable = Some(identifier.value.clone());
|
||||
return Ok(Expr::Var(identifier.value));
|
||||
return Ok(Expr::Var(Identifier::from_full_name(&identifier.value)));
|
||||
}
|
||||
|
||||
let mut chars = identifier.value.chars();
|
||||
let mut left = Expr::Var(chars.next().unwrap().to_string());
|
||||
let mut left = Expr::Var(Identifier::from_full_name(
|
||||
&chars.next().unwrap().to_string(),
|
||||
));
|
||||
|
||||
// Turn each individual character into its own variable reference.
|
||||
// This parses eg `xy` as `x*y` instead of *one* variable.
|
||||
@ -556,7 +569,7 @@ fn parse_identifier(context: &mut Context) -> Result<Expr, CalcError> {
|
||||
|
||||
parse_exponent(context)?
|
||||
} else {
|
||||
Expr::Var(c.to_string())
|
||||
Expr::Var(Identifier::from_full_name(&c.to_string()))
|
||||
};
|
||||
|
||||
left = Expr::Binary(Box::new(left), TokenKind::Star, Box::new(right));
|
||||
@ -610,6 +623,7 @@ fn string_to_num(value: &str) -> f64 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::Identifier;
|
||||
use crate::lexer::{Token, TokenKind::*};
|
||||
use crate::test_helpers::*;
|
||||
use wasm_bindgen_test::*;
|
||||
@ -763,7 +777,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse(tokens).unwrap(),
|
||||
Stmt::VarDecl(
|
||||
String::from("x"),
|
||||
Identifier::from_full_name("x"),
|
||||
binary(literal(1f64), Plus, literal(2f64))
|
||||
)
|
||||
);
|
||||
@ -787,7 +801,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
parse(tokens).unwrap(),
|
||||
Stmt::FnDecl(
|
||||
String::from("f"),
|
||||
Identifier::from_full_name("f"),
|
||||
vec![String::from("x")],
|
||||
binary(literal(1f64), Plus, literal(2f64))
|
||||
)
|
||||
@ -813,7 +827,7 @@ mod tests {
|
||||
|
||||
// Add the function to the symbol table first, in order to prevent errors.
|
||||
context.symbol_table.set(Stmt::FnDecl(
|
||||
String::from("f"),
|
||||
Identifier::from_full_name("f"),
|
||||
vec![String::from("x")],
|
||||
literal(1f64),
|
||||
));
|
||||
@ -822,7 +836,7 @@ mod tests {
|
||||
parse_with_context(&mut context, tokens).unwrap(),
|
||||
Stmt::Expr(binary(
|
||||
Box::new(Expr::FnCall(
|
||||
String::from("f"),
|
||||
Identifier::from_full_name("f"),
|
||||
vec![*binary(literal(1f64), Plus, literal(2f64))]
|
||||
)),
|
||||
Plus,
|
||||
|
@ -18,7 +18,8 @@ impl SymbolTable {
|
||||
pub fn insert(&mut self, value: Stmt) -> &mut Self {
|
||||
match &value {
|
||||
Stmt::VarDecl(identifier, _) => {
|
||||
self.hashmap.insert(format!("var.{}", identifier), value);
|
||||
self.hashmap
|
||||
.insert(format!("var.{}", identifier.full_name), value);
|
||||
}
|
||||
Stmt::UnitDecl(identifier, to_unit, _) => {
|
||||
self.unit_types.insert(identifier.to_string(), ());
|
||||
@ -27,7 +28,8 @@ impl SymbolTable {
|
||||
.insert(format!("unit.{}.{}", identifier, to_unit), value);
|
||||
}
|
||||
Stmt::FnDecl(identifier, _, _) => {
|
||||
self.hashmap.insert(format!("fn.{}", identifier), value);
|
||||
self.hashmap
|
||||
.insert(format!("fn.{}", identifier.full_name), value);
|
||||
}
|
||||
_ => panic!("Can only insert VarDecl, UnitDecl and FnDecl into symbol table."),
|
||||
}
|
||||
@ -49,11 +51,15 @@ impl SymbolTable {
|
||||
|
||||
pub fn set(&mut self, value: Stmt) {
|
||||
let existing_item = match &value {
|
||||
Stmt::VarDecl(identifier, _) => self.hashmap.get_mut(&format!("var.{}", identifier)),
|
||||
Stmt::VarDecl(identifier, _) => self
|
||||
.hashmap
|
||||
.get_mut(&format!("var.{}", identifier.full_name)),
|
||||
Stmt::UnitDecl(identifier, to_unit, _) => self
|
||||
.hashmap
|
||||
.get_mut(&format!("unit.{}.{}", identifier, to_unit)),
|
||||
Stmt::FnDecl(identifier, _, _) => self.hashmap.get_mut(&format!("fn.{}", identifier)),
|
||||
Stmt::FnDecl(identifier, _, _) => self
|
||||
.hashmap
|
||||
.get_mut(&format!("fn.{}", identifier.full_name)),
|
||||
_ => panic!("Can only set VarDecl, UnitDecl and FnDecl in symbol table."),
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::ast::Expr;
|
||||
use crate::ast::Identifier;
|
||||
use crate::ast::Stmt;
|
||||
use crate::lexer::Token;
|
||||
use crate::lexer::TokenKind;
|
||||
@ -17,11 +18,14 @@ pub fn literal(value: f64) -> Box<Expr> {
|
||||
}
|
||||
|
||||
pub fn var(identifier: &str) -> Box<Expr> {
|
||||
Box::new(Expr::Var(identifier.into()))
|
||||
Box::new(Expr::Var(Identifier::from_full_name(identifier)))
|
||||
}
|
||||
|
||||
pub fn fn_call(identifier: &str, arguments: Vec<Expr>) -> Box<Expr> {
|
||||
Box::new(Expr::FnCall(identifier.into(), arguments))
|
||||
Box::new(Expr::FnCall(
|
||||
Identifier::from_full_name(identifier),
|
||||
arguments,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn binary(left: Box<Expr>, op: TokenKind, right: Box<Expr>) -> Box<Expr> {
|
||||
@ -41,11 +45,11 @@ pub fn unit(identifier: &str, expr: Box<Expr>) -> Box<Expr> {
|
||||
}
|
||||
|
||||
pub fn var_decl(identifier: &str, value: Box<Expr>) -> Stmt {
|
||||
Stmt::VarDecl(identifier.into(), value)
|
||||
Stmt::VarDecl(Identifier::from_full_name(identifier), value)
|
||||
}
|
||||
|
||||
pub fn fn_decl(identifier: &str, parameters: Vec<String>, value: Box<Expr>) -> Stmt {
|
||||
Stmt::FnDecl(identifier.into(), parameters, value)
|
||||
Stmt::FnDecl(Identifier::from_full_name(identifier), parameters, value)
|
||||
}
|
||||
|
||||
pub fn unit_decl(unit: &str, base_unit: &str, expr: Box<Expr>) -> Stmt {
|
||||
|
Loading…
Reference in New Issue
Block a user