🙃
This commit is contained in:
18
src/cell.rs
18
src/cell.rs
@@ -4,13 +4,13 @@ use crate::evaluator::*;
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Cell {
|
pub struct Cell {
|
||||||
eval: Option<Eval>,
|
eval: Eval,
|
||||||
raw: String,
|
raw: String,
|
||||||
deps: HashSet<CellRef>,
|
deps: HashSet<CellRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cell {
|
impl Cell {
|
||||||
pub fn new(eval: Option<Eval>, raw: String) -> Self {
|
pub fn new(eval: Eval, raw: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
eval,
|
eval,
|
||||||
raw,
|
raw,
|
||||||
@@ -22,9 +22,21 @@ impl Cell {
|
|||||||
self.raw.clone()
|
self.raw.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(&self) -> Option<Eval> {
|
pub fn eval(&self) -> Eval {
|
||||||
self.eval.clone()
|
self.eval.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_dep(&mut self, dep: CellRef) {
|
||||||
|
self.deps.insert(dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_deps(&mut self) {
|
||||||
|
self.deps.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_eval(&mut self, eval: Eval) {
|
||||||
|
self.eval = eval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -7,14 +7,12 @@ use std::fmt;
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Eval {
|
pub enum Eval {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Expr(Expr),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Eval {
|
impl fmt::Display for Eval {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Eval::Literal(lit) => write!(f, "{lit:?}"),
|
Eval::Literal(lit) => write!(f, "{lit:?}"),
|
||||||
Eval::Expr(expr) => write!(f, "({expr})"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,20 +33,26 @@ impl Evaluator {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut eval: Option<Eval> = None;
|
let eval: Eval;
|
||||||
|
|
||||||
if let Some(c) = raw_val.chars().nth(0)
|
if let Some(c) = raw_val.chars().nth(0)
|
||||||
&& c == '='
|
&& c == '='
|
||||||
{
|
{
|
||||||
if let Ok(e) = self.evaluate(raw_val[1..].to_owned()) {
|
eval = self.evaluate(raw_val[1..].to_owned())?;
|
||||||
eval = Some(e);
|
} else {
|
||||||
};
|
match self.evaluate(raw_val.to_owned()) {
|
||||||
|
Ok(e) => {
|
||||||
|
eval = e;
|
||||||
|
}
|
||||||
|
Err(_) => eval = Eval::Literal(Literal::String(raw_val.to_owned())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cells.insert(cell_ref, Cell::new(eval, raw_val));
|
self.cells.insert(cell_ref, Cell::new(eval, raw_val));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cell(&mut self, cell_ref: CellRef) -> Result<(String, Option<Eval>), String> {
|
pub fn get_cell(&mut self, cell_ref: CellRef) -> Result<(String, Eval), String> {
|
||||||
if !self.cells.contains_key(&cell_ref) {
|
if !self.cells.contains_key(&cell_ref) {
|
||||||
return Err(format!("Cell at {:?} not found.", cell_ref));
|
return Err(format!("Cell at {:?} not found.", cell_ref));
|
||||||
}
|
}
|
||||||
@@ -58,14 +62,16 @@ impl Evaluator {
|
|||||||
Ok((cell.raw(), cell.eval()))
|
Ok((cell.raw(), cell.eval()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluate(&self, str: String) -> Result<Eval, String> {
|
pub fn evaluate(&mut self, str: String) -> Result<Eval, String> {
|
||||||
let mut expr = parse(&str)?;
|
let (mut expr, mut deps) = parse(&str)?;
|
||||||
|
|
||||||
self.evaluate_expr(&mut expr)
|
self.evaluate_expr(&mut expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate_expr(&self, expr: &mut Expr) -> Result<Eval, String> {
|
fn evaluate_expr(&mut self, expr: &mut Expr) -> Result<Eval, String> {
|
||||||
let res = match expr {
|
let res = match expr {
|
||||||
Expr::Literal(lit) => Eval::Literal(lit.clone()),
|
Expr::Literal(lit) => Eval::Literal(lit.clone()),
|
||||||
|
Expr::CellRef(re) => self.get_cell(re.to_owned())?.1,
|
||||||
Expr::Infix { op, lhs, rhs } => {
|
Expr::Infix { op, lhs, rhs } => {
|
||||||
let lval = self.evaluate_expr(lhs)?;
|
let lval = self.evaluate_expr(lhs)?;
|
||||||
let rval = self.evaluate_expr(rhs)?;
|
let rval = self.evaluate_expr(rhs)?;
|
||||||
@@ -101,7 +107,6 @@ fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
|||||||
|
|
||||||
Err("Evaluation error: expected string or numeric types for ADD function.".to_string())
|
Err("Evaluation error: expected string or numeric types for ADD function.".to_string())
|
||||||
}
|
}
|
||||||
_ => return Err("Evalutation error: expected literals for ADD function.".to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +119,6 @@ fn eval_sub(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
|||||||
|
|
||||||
Err("Evaluation error: expected string or numeric types for SUB function.".to_string())
|
Err("Evaluation error: expected string or numeric types for SUB function.".to_string())
|
||||||
}
|
}
|
||||||
_ => return Err("Evalutation error: expected literals for SUB function.".to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||||
@@ -126,7 +130,6 @@ fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
|||||||
|
|
||||||
Err("Evaluation error: expected string or numeric types for MUL function.".to_string())
|
Err("Evaluation error: expected string or numeric types for MUL function.".to_string())
|
||||||
}
|
}
|
||||||
_ => return Err("Evalutation error: expected literals for MUL function.".to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||||
@@ -138,7 +141,6 @@ fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
|||||||
|
|
||||||
Err("Evaluation error: expected string or numeric types for DIV function.".to_string())
|
Err("Evaluation error: expected string or numeric types for DIV function.".to_string())
|
||||||
}
|
}
|
||||||
_ => return Err("Evalutation error: expected literals for DIV function.".to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{cell::CellRef, tokenizer::*};
|
use crate::{cell::CellRef, tokenizer::*};
|
||||||
use std::fmt;
|
use std::{collections::HashSet, fmt};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum PrefixOp {
|
pub enum PrefixOp {
|
||||||
@@ -154,19 +154,24 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(input: &str) -> Result<Expr, String> {
|
pub fn parse(input: &str) -> Result<(Expr, HashSet<CellRef>), String> {
|
||||||
let mut tokenizer = Tokenizer::new(input)?;
|
let mut tokenizer = Tokenizer::new(input)?;
|
||||||
// println!("{:?}", tokenizer.tokens);
|
// println!("{:?}", tokenizer.tokens);
|
||||||
_parse(&mut tokenizer, 0)
|
let mut deps = HashSet::new();
|
||||||
|
Ok((_parse(&mut tokenizer, 0, &mut deps)?, deps))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _parse(input: &mut Tokenizer, min_prec: u8) -> Result<Expr, String> {
|
pub fn _parse(
|
||||||
|
input: &mut Tokenizer,
|
||||||
|
min_prec: u8,
|
||||||
|
deps: &mut HashSet<CellRef>,
|
||||||
|
) -> Result<Expr, String> {
|
||||||
let mut lhs = match input.next() {
|
let mut lhs = match input.next() {
|
||||||
Token::Literal(it) => Expr::Literal(it),
|
Token::Literal(it) => Expr::Literal(it),
|
||||||
Token::Identifier(id) if id == "true" => Expr::Literal(Literal::Boolean(true)),
|
Token::Identifier(id) if id == "true" => Expr::Literal(Literal::Boolean(true)),
|
||||||
Token::Identifier(id) if id == "false" => Expr::Literal(Literal::Boolean(false)),
|
Token::Identifier(id) if id == "false" => Expr::Literal(Literal::Boolean(false)),
|
||||||
Token::Paren('(') => {
|
Token::Paren('(') => {
|
||||||
let lhs = _parse(input, 0)?;
|
let lhs = _parse(input, 0, deps)?;
|
||||||
if input.next() != Token::Paren(')') {
|
if input.next() != Token::Paren(')') {
|
||||||
return Err(format!("Parse error: expected closing paren."));
|
return Err(format!("Parse error: expected closing paren."));
|
||||||
}
|
}
|
||||||
@@ -180,7 +185,7 @@ pub fn _parse(input: &mut Tokenizer, min_prec: u8) -> Result<Expr, String> {
|
|||||||
it => return Err(format!("Parse error: unknown prefix operator {:?}.", it)),
|
it => return Err(format!("Parse error: unknown prefix operator {:?}.", it)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let rhs = _parse(input, prefix_op.prec().1)?;
|
let rhs = _parse(input, prefix_op.prec().1, deps)?;
|
||||||
|
|
||||||
Expr::Prefix {
|
Expr::Prefix {
|
||||||
op: prefix_op,
|
op: prefix_op,
|
||||||
@@ -209,7 +214,7 @@ pub fn _parse(input: &mut Tokenizer, min_prec: u8) -> Result<Expr, String> {
|
|||||||
input.next(); // Skip comma
|
input.next(); // Skip comma
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg = _parse(input, 0)?;
|
let arg = _parse(input, 0, deps)?;
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +223,11 @@ pub fn _parse(input: &mut Tokenizer, min_prec: u8) -> Result<Expr, String> {
|
|||||||
args: args,
|
args: args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => Expr::CellRef(CellRef::new(id)?),
|
_ => {
|
||||||
|
let cell_ref = CellRef::new(id)?;
|
||||||
|
deps.insert(cell_ref);
|
||||||
|
Expr::CellRef(cell_ref)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
it => return Err(format!("Parse error: did not expect token {:?}.", it)),
|
it => return Err(format!("Parse error: did not expect token {:?}.", it)),
|
||||||
@@ -246,7 +255,7 @@ pub fn _parse(input: &mut Tokenizer, min_prec: u8) -> Result<Expr, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input.next();
|
input.next();
|
||||||
let rhs = _parse(input, r_prec)?;
|
let rhs = _parse(input, r_prec, deps)?;
|
||||||
lhs = Expr::Infix {
|
lhs = Expr::Infix {
|
||||||
op: infix_op,
|
op: infix_op,
|
||||||
lhs: Box::new(lhs),
|
lhs: Box::new(lhs),
|
||||||
|
|||||||
Reference in New Issue
Block a user