mirror of
https://github.com/PaddiM8/kalker.git
synced 2025-06-23 19:21:26 +02:00
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:
parent
01aa30c2c1
commit
0dac28bb42
@ -10,16 +10,6 @@ pub struct Context<'a> {
|
|||||||
|
|
||||||
impl<'a> Context<'a> {
|
impl<'a> Context<'a> {
|
||||||
pub fn new(angle_unit: Unit, symbol_table: &'a mut SymbolTable) -> Self {
|
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 {
|
Context {
|
||||||
angle_unit: angle_unit.clone(),
|
angle_unit: angle_unit.clone(),
|
||||||
symbol_table,
|
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> {
|
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();
|
let var_decl = context.symbol_table.get(identifier).cloned();
|
||||||
match var_decl {
|
match var_decl {
|
||||||
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
|
Some(Stmt::VarDecl(_, expr)) => eval_expr(context, &expr),
|
||||||
|
@ -121,15 +121,13 @@ fn parse_factor(context: &mut Context) -> Result<Expr, String> {
|
|||||||
while match_token(context, TokenKind::Star)
|
while match_token(context, TokenKind::Star)
|
||||||
|| match_token(context, TokenKind::Slash)
|
|| match_token(context, TokenKind::Slash)
|
||||||
|| match_token(context, TokenKind::Identifier)
|
|| 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 the next token is an identifier, assume it's multiplication. Eg. 3y
|
||||||
if let TokenKind::Identifier = op {
|
let op = match peek(context).kind {
|
||||||
op = TokenKind::Star;
|
TokenKind::Identifier | TokenKind::Literal => TokenKind::Star,
|
||||||
} else {
|
_ => advance(context).kind.clone(),
|
||||||
advance(context);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
let right = parse_unary(context)?;
|
let right = parse_unary(context)?;
|
||||||
left = Expr::Binary(Box::new(left), op, Box::new(right));
|
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
|
// 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 {
|
fn peek<'a>(context: &'a mut Context) -> &'a Token {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
use FuncType::*;
|
use FuncType::*;
|
||||||
|
|
||||||
pub const CONSTANTS: &[(&str, &str)] = &[
|
pub const CONSTANTS: phf::Map<&'static str, &'static str> = phf::phf_map! {
|
||||||
("pi", "3.14159265"),
|
"pi" => "3.14159265",
|
||||||
("π", "3.14159265"),
|
"π" => "3.14159265",
|
||||||
("e", "2.71828182"),
|
"e" => "2.71828182",
|
||||||
("tau", "6.28318530"),
|
"tau" => "6.28318530",
|
||||||
("τ", "6.28318530"),
|
"τ" => "6.28318530",
|
||||||
("phi", "1.61803398"),
|
"phi" => "1.61803398",
|
||||||
("ϕ", "1.61803398"),
|
"ϕ" => "1.61803398",
|
||||||
];
|
};
|
||||||
|
|
||||||
use crate::ast::Unit;
|
use crate::ast::Unit;
|
||||||
use funcs::*;
|
use funcs::*;
|
||||||
|
@ -20,9 +20,13 @@ impl SymbolTable {
|
|||||||
self.hashmap.get(key)
|
self.hashmap.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_func(&self, key: &str) -> bool {
|
pub fn contains_var(&self, identifier: &str) -> bool {
|
||||||
prelude::UNARY_FUNCS.contains_key(key)
|
prelude::CONSTANTS.contains_key(identifier) || self.hashmap.contains_key(identifier)
|
||||||
|| prelude::UNARY_FUNCS.contains_key(key)
|
}
|
||||||
|| self.hashmap.contains_key(&format!("{}()", key))
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user