Made it possible for the parser to parse combined variables, eg. xy, so that the user does not have to write the multiplication sign.

This commit is contained in:
PaddiM8 2020-05-30 17:56:16 +02:00
parent 01aa30c2c1
commit 0dac28bb42
4 changed files with 46 additions and 31 deletions

View File

@ -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<f64, String> {
// 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),

View File

@ -121,15 +121,13 @@ fn parse_factor(context: &mut Context) -> Result<Expr, String> {
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<Expr, String> {
}
// 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 {

View File

@ -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::*;

View File

@ -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))
}
}