diff --git a/src/interpreter.rs b/src/interpreter.rs index 45c4576..77c082f 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -10,16 +10,6 @@ pub struct Context<'a> { impl<'a> Context<'a> { pub fn new(angle_unit: Unit, symbol_table: &'a mut SymbolTable) -> Self { - for constant in prelude::CONSTANTS { - symbol_table.insert( - constant.0, - Stmt::VarDecl( - constant.0.to_string(), - Box::new(Expr::Literal(constant.1.to_string())), - ), - ); - } - Context { angle_unit: angle_unit.clone(), symbol_table, @@ -119,6 +109,12 @@ fn eval_unit_expr(context: &mut Context, expr: &Expr, kind: &TokenKind) -> Resul } fn eval_var_expr(context: &mut Context, identifier: &str) -> Result { + // If there is a constant with this name, return a literal expression with its value + if let Some(value) = prelude::CONSTANTS.get(identifier) { + return eval_expr(context, &Expr::Literal(value.to_string())); + } + + // Look for the variable in the symbol table let var_decl = context.symbol_table.get(identifier).cloned(); match var_decl { Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr), diff --git a/src/parser.rs b/src/parser.rs index 61bc7cd..67368be 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -121,15 +121,13 @@ fn parse_factor(context: &mut Context) -> Result { while match_token(context, TokenKind::Star) || match_token(context, TokenKind::Slash) || match_token(context, TokenKind::Identifier) + || match_token(context, TokenKind::Literal) { - let mut op = peek(context).kind.clone(); - // If the next token is an identifier, assume it's multiplication. Eg. 3y - if let TokenKind::Identifier = op { - op = TokenKind::Star; - } else { - advance(context); - } + let op = match peek(context).kind { + TokenKind::Identifier | TokenKind::Literal => TokenKind::Star, + _ => advance(context).kind.clone(), + }; let right = parse_unary(context)?; left = Expr::Binary(Box::new(left), op, Box::new(right)); @@ -221,7 +219,24 @@ fn parse_identifier(context: &mut Context) -> Result { } // Eg. x - Ok(Expr::Var(identifier.value)) + if context.symbol_table.contains_var(&identifier.value) { + return Ok(Expr::Var(identifier.value)); + } else { + let mut chars = identifier.value.chars(); + let mut left = Expr::Var(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. + for c in chars { + left = Expr::Binary( + Box::new(left), + TokenKind::Star, + Box::new(Expr::Var(c.to_string())), + ); + } + + return Ok(left); + } } fn peek<'a>(context: &'a mut Context) -> &'a Token { diff --git a/src/prelude.rs b/src/prelude.rs index 49732a2..006fb5d 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,14 +1,14 @@ use FuncType::*; -pub const CONSTANTS: &[(&str, &str)] = &[ - ("pi", "3.14159265"), - ("π", "3.14159265"), - ("e", "2.71828182"), - ("tau", "6.28318530"), - ("τ", "6.28318530"), - ("phi", "1.61803398"), - ("ϕ", "1.61803398"), -]; +pub const CONSTANTS: phf::Map<&'static str, &'static str> = phf::phf_map! { + "pi" => "3.14159265", + "π" => "3.14159265", + "e" => "2.71828182", + "tau" => "6.28318530", + "τ" => "6.28318530", + "phi" => "1.61803398", + "ϕ" => "1.61803398", +}; use crate::ast::Unit; use funcs::*; diff --git a/src/symbol_table.rs b/src/symbol_table.rs index 3cee347..213683e 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -20,9 +20,13 @@ impl SymbolTable { self.hashmap.get(key) } - pub fn contains_func(&self, key: &str) -> bool { - prelude::UNARY_FUNCS.contains_key(key) - || prelude::UNARY_FUNCS.contains_key(key) - || self.hashmap.contains_key(&format!("{}()", key)) + pub fn contains_var(&self, identifier: &str) -> bool { + prelude::CONSTANTS.contains_key(identifier) || self.hashmap.contains_key(identifier) + } + + pub fn contains_func(&self, identifier: &str) -> bool { + prelude::UNARY_FUNCS.contains_key(identifier) + || prelude::UNARY_FUNCS.contains_key(identifier) + || self.hashmap.contains_key(&format!("{}()", identifier)) } }