🙃
This commit is contained in:
@@ -4,59 +4,93 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::evaluator::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cell {
|
||||
eval: Eval,
|
||||
raw: String,
|
||||
i_dep: HashSet<CellRef>,
|
||||
they_dep: HashSet<CellRef>,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn new(eval: Eval, raw: String) -> Self {
|
||||
Self {
|
||||
eval,
|
||||
raw,
|
||||
i_dep: HashSet::new(),
|
||||
they_dep: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> String {
|
||||
self.raw.clone()
|
||||
}
|
||||
|
||||
pub fn eval(&self) -> Eval {
|
||||
self.eval.clone()
|
||||
}
|
||||
|
||||
pub fn add_i_dep(&mut self, dep: CellRef) {
|
||||
self.i_dep.insert(dep);
|
||||
}
|
||||
|
||||
pub fn add_they_dep(&mut self, dep: CellRef) {
|
||||
self.they_dep.insert(dep);
|
||||
}
|
||||
|
||||
pub fn clear_i_dep(&mut self) {
|
||||
self.i_dep.clear();
|
||||
}
|
||||
|
||||
pub fn clear_they_dep(&mut self) {
|
||||
self.they_dep.clear();
|
||||
}
|
||||
|
||||
pub fn set_eval(&mut self, eval: Eval) {
|
||||
self.eval = eval;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct CellRef {
|
||||
pub row: usize,
|
||||
pub col: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Cell {
|
||||
reference: CellRef,
|
||||
eval: Eval,
|
||||
raw: String,
|
||||
precedents: HashSet<CellRef>, // Cells that this cell reads
|
||||
dependents: HashSet<CellRef>, // Cells that read this cell
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn new(reference: CellRef, eval: Eval, raw: String) -> Self {
|
||||
Self {
|
||||
reference,
|
||||
eval,
|
||||
raw,
|
||||
precedents: HashSet::new(),
|
||||
dependents: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_all(
|
||||
reference: CellRef,
|
||||
eval: Eval,
|
||||
raw: String,
|
||||
precedents: HashSet<CellRef>,
|
||||
dependents: HashSet<CellRef>,
|
||||
) -> Self {
|
||||
Self {
|
||||
reference,
|
||||
eval,
|
||||
raw,
|
||||
precedents,
|
||||
dependents,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> String {
|
||||
self.raw.to_owned()
|
||||
}
|
||||
pub fn eval(&self) -> Eval {
|
||||
self.eval.to_owned()
|
||||
}
|
||||
pub fn reference(&self) -> CellRef {
|
||||
self.reference.to_owned()
|
||||
}
|
||||
|
||||
pub fn set_raw(&mut self, raw: String) {
|
||||
self.raw = raw;
|
||||
}
|
||||
pub fn set_eval(&mut self, eval: Eval) {
|
||||
self.eval = eval;
|
||||
}
|
||||
pub fn set_ref(&mut self, reference: CellRef) {
|
||||
self.reference = reference;
|
||||
}
|
||||
|
||||
pub fn add_dep(&mut self, it: CellRef) {
|
||||
self.dependents.insert(it);
|
||||
}
|
||||
|
||||
pub fn remove_dep(&mut self, it: &CellRef) {
|
||||
self.dependents.remove(&it);
|
||||
}
|
||||
|
||||
pub fn add_prec(&mut self, it: CellRef) {
|
||||
self.precedents.insert(it);
|
||||
}
|
||||
|
||||
pub fn set_precs(&mut self, it: HashSet<CellRef>) {
|
||||
self.precedents = it;
|
||||
}
|
||||
|
||||
pub fn deps(&self) -> HashSet<CellRef> {
|
||||
self.dependents.to_owned()
|
||||
}
|
||||
|
||||
pub fn precs(&self) -> HashSet<CellRef> {
|
||||
self.precedents.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl CellRef {
|
||||
// Zero indexed
|
||||
pub fn new(s: String) -> Result<CellRef, String> {
|
||||
|
||||
@@ -8,49 +8,72 @@ use std::fmt;
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Eval {
|
||||
Literal(Literal),
|
||||
CellRef { eval: Box<Eval>, reference: CellRef },
|
||||
Range(Vec<Eval>),
|
||||
Unset,
|
||||
}
|
||||
|
||||
impl fmt::Display for Eval {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Eval::Literal(lit) => write!(f, "{lit:?}"),
|
||||
Eval::Range(it) => write!(f, "Range({it:?})"),
|
||||
Eval::CellRef { eval, reference } => write!(f, "EvalRef({eval:?}, {reference:?})"),
|
||||
Eval::Unset => write!(f, "Unset"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate(str: String, grid: Option<&Grid>) -> Result<(Eval, HashSet<CellRef>), String> {
|
||||
let (expr, deps) = parse(&str)?;
|
||||
let (expr, _) = parse(&str)?;
|
||||
|
||||
match evaluate_expr(&expr, grid) {
|
||||
Ok(it) => Ok((it, deps)),
|
||||
let mut precs = HashSet::new();
|
||||
|
||||
// Make evaulator adds precs for ranges
|
||||
match evaluate_expr(&expr, &mut precs, grid) {
|
||||
Ok(it) => Ok((it, precs)),
|
||||
Err(it) => Err(it),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_expr(expr: &Expr, grid: Option<&Grid>) -> Result<Eval, String> {
|
||||
fn evaluate_expr(
|
||||
expr: &Expr,
|
||||
precs: &mut HashSet<CellRef>,
|
||||
grid: Option<&Grid>,
|
||||
) -> Result<Eval, String> {
|
||||
let res = match expr {
|
||||
Expr::Literal(lit) => Eval::Literal(lit.clone()),
|
||||
Expr::CellRef(re) => {
|
||||
if let Some(g) = grid {
|
||||
g.get_cell(re.to_owned())?
|
||||
Eval::CellRef {
|
||||
eval: Box::new(
|
||||
g.get_cell(re.to_owned())
|
||||
.map_or(Eval::Unset, |cell| cell.eval()),
|
||||
),
|
||||
reference: {
|
||||
precs.insert(*re);
|
||||
*re
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return Err("Evaluation error: Found cell reference but no grid.".into());
|
||||
}
|
||||
}
|
||||
Expr::Infix { op, lhs, rhs } => {
|
||||
let lval = evaluate_expr(lhs, grid)?;
|
||||
let rval = evaluate_expr(rhs, grid)?;
|
||||
let lval = evaluate_expr(lhs, precs, grid)?;
|
||||
let rval = evaluate_expr(rhs, precs, grid)?;
|
||||
|
||||
match op {
|
||||
InfixOp::ADD => eval_add(&lval, &rval)?,
|
||||
InfixOp::SUB => eval_sub(&lval, &rval)?,
|
||||
InfixOp::MUL => eval_mul(&lval, &rval)?,
|
||||
InfixOp::DIV => eval_div(&lval, &rval)?,
|
||||
InfixOp::RANGE => eval_range(&lval, &rval, precs, grid)?,
|
||||
_ => return Err(format!("Evaluation error: Unsupported operator {:?}", op)),
|
||||
}
|
||||
}
|
||||
Expr::Prefix { op, expr } => {
|
||||
let val = evaluate_expr(expr, grid)?;
|
||||
let val = evaluate_expr(expr, precs, grid)?;
|
||||
|
||||
match op {
|
||||
PrefixOp::POS => eval_pos(&val)?,
|
||||
@@ -59,13 +82,115 @@ fn evaluate_expr(expr: &Expr, grid: Option<&Grid>) -> Result<Eval, String> {
|
||||
// _ => return Err(format!("Evaluation error: Unsupported operator {:?}", op)),
|
||||
}
|
||||
}
|
||||
Expr::Group(g) => evaluate_expr(g, grid)?,
|
||||
Expr::Group(g) => evaluate_expr(g, precs, grid)?,
|
||||
Expr::Function { name, args } => match name.as_str() {
|
||||
"AVG" => eval_avg(args, precs, grid)?,
|
||||
it => return Err(format!("Evaluation error: Unsupported function {}.", it)),
|
||||
},
|
||||
it => return Err(format!("Evaluation error: Unsupported expression {:?}", it)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn eval_range(
|
||||
lval: &Eval,
|
||||
rval: &Eval,
|
||||
precs: &mut HashSet<CellRef>,
|
||||
grid: Option<&Grid>,
|
||||
) -> Result<Eval, String> {
|
||||
match (lval, rval) {
|
||||
(
|
||||
Eval::CellRef {
|
||||
eval: _,
|
||||
reference: a_ref,
|
||||
},
|
||||
Eval::CellRef {
|
||||
eval: _,
|
||||
reference: b_ref,
|
||||
},
|
||||
) => {
|
||||
let mut cells = Vec::new();
|
||||
|
||||
// assume row-major expansion
|
||||
let row_start = a_ref.row.min(b_ref.row);
|
||||
let row_end = a_ref.row.max(b_ref.row);
|
||||
let col_start = a_ref.col.min(b_ref.col);
|
||||
let col_end = a_ref.col.max(b_ref.col);
|
||||
|
||||
for row in row_start..=row_end {
|
||||
for col in col_start..=col_end {
|
||||
let reference = CellRef { row, col };
|
||||
|
||||
let Some(g) = grid else {
|
||||
return Err("Evaluation error: Found cell range but no grid.".into());
|
||||
};
|
||||
|
||||
cells.push(Eval::CellRef {
|
||||
eval: Box::new(
|
||||
g.get_cell(reference.to_owned())
|
||||
.map_or(Eval::Unset, |cell| cell.eval()),
|
||||
),
|
||||
reference: {
|
||||
precs.insert(reference);
|
||||
reference
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Eval::Range(cells))
|
||||
}
|
||||
_ => Err("Evaluation error: expected cellref types for RANGE function.".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_avg(
|
||||
args: &Vec<Expr>,
|
||||
precs: &mut HashSet<CellRef>,
|
||||
grid: Option<&Grid>,
|
||||
) -> Result<Eval, String> {
|
||||
let mut res = 0.0;
|
||||
let mut count = 0;
|
||||
|
||||
for arg in args {
|
||||
match evaluate_expr(arg, precs, grid)? {
|
||||
Eval::Literal(Literal::Number(num)) => {
|
||||
res += num;
|
||||
count += 1;
|
||||
}
|
||||
Eval::Range(range) => {
|
||||
for cell in range {
|
||||
let Eval::CellRef { eval, reference: _ } = cell else {
|
||||
panic!("Found non cellref in evaluation time RANGE!.");
|
||||
};
|
||||
|
||||
if let Eval::Literal(Literal::Number(num)) = *eval {
|
||||
res += num;
|
||||
count += 1;
|
||||
} else if matches!(*eval, Eval::Unset) {
|
||||
continue;
|
||||
} else {
|
||||
return Err("Evaluation error: expected numeric types for AVG function."
|
||||
.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(
|
||||
"Evaluation error: expected numeric types for AVG function.".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
Err("Evaluation error: attempted to divide by zero.".to_string())
|
||||
} else {
|
||||
Ok(Eval::Literal(Literal::Number(res / count as f64)))
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_add(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||
match (lval, rval) {
|
||||
(Eval::Literal(a), Eval::Literal(b)) => {
|
||||
@@ -82,6 +207,9 @@ 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +220,9 @@ fn eval_sub(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
Err("Evaluation error: expected string or numeric types for SUB function.".to_string())
|
||||
Err("Evaluation error: expected numeric types for SUB function.".to_string())
|
||||
}
|
||||
_ => Err("Evaluation error: expected numeric types for SUB function.".to_string()),
|
||||
}
|
||||
}
|
||||
fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||
@@ -103,8 +232,9 @@ fn eval_mul(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
Err("Evaluation error: expected string or numeric types for MUL function.".to_string())
|
||||
Err("Evaluation error: expected numeric types for MUL function.".to_string())
|
||||
}
|
||||
_ => Err("Evaluation error: expected numeric types for MUL function.".to_string()),
|
||||
}
|
||||
}
|
||||
fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||
@@ -122,8 +252,9 @@ fn eval_div(lval: &Eval, rval: &Eval) -> Result<Eval, String> {
|
||||
return Ok(Eval::Literal(res));
|
||||
}
|
||||
|
||||
Err("Evaluation error: expected string or numeric types for DIV function.".to_string())
|
||||
Err("Evaluation error: expected numeric types for DIV function.".to_string())
|
||||
}
|
||||
_ => Err("Evaluation error: expected numeric types for DIV function.".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
cell::{Cell, CellRef},
|
||||
evaluator::{Eval, evaluate},
|
||||
@@ -16,38 +18,43 @@ impl Grid {
|
||||
cells: HashMap::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
pub fn set_cell(&mut self, cell_ref: CellRef, raw_val: String) -> Result<Eval, String> {
|
||||
pub fn update_cell(
|
||||
&mut self,
|
||||
cell_ref: CellRef,
|
||||
raw_val: String,
|
||||
) -> Result<Vec<CellRef>, String> {
|
||||
if self.cells.contains_key(&cell_ref) && self.cells[&cell_ref].raw() == raw_val {
|
||||
return self.get_cell(cell_ref);
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let eval: Eval;
|
||||
let deps: HashSet<CellRef>;
|
||||
let mut precs: HashSet<CellRef> = HashSet::new();
|
||||
let mut updated_cells = vec![cell_ref];
|
||||
|
||||
if let Some(c) = raw_val.chars().nth(0)
|
||||
&& c == '='
|
||||
{
|
||||
(eval, deps) = evaluate(raw_val[1..].to_owned(), Some(&self))?;
|
||||
// for dep in deps {}
|
||||
if raw_val.chars().nth(0) != Some('=') {
|
||||
eval = Eval::Literal(Literal::String(raw_val.to_owned()));
|
||||
} else {
|
||||
match evaluate(raw_val.to_owned(), Some(&self)) {
|
||||
Ok(e) => {
|
||||
(eval, deps) = e;
|
||||
}
|
||||
Err(_) => eval = Eval::Literal(Literal::String(raw_val.to_owned())),
|
||||
}
|
||||
// Evaluate raw expr and get precedents
|
||||
let (res_eval, res_precs) = evaluate(raw_val[1..].to_owned(), Some(&self))?;
|
||||
eval = res_eval;
|
||||
precs = res_precs;
|
||||
}
|
||||
|
||||
self.cells
|
||||
.insert(cell_ref, Cell::new(eval.clone(), raw_val));
|
||||
Ok(eval)
|
||||
if self.cells.contains_key(&cell_ref) {
|
||||
updated_cells = self
|
||||
.update_exisiting_cell(raw_val, eval, precs, cell_ref)?
|
||||
.into_iter()
|
||||
.chain(updated_cells)
|
||||
.collect();
|
||||
} else {
|
||||
self.create_cell(raw_val, eval, precs, cell_ref);
|
||||
}
|
||||
|
||||
Ok(updated_cells)
|
||||
}
|
||||
|
||||
// pub fn get_cell(&mut self, cell_ref: CellRef) -> Result<(String, Eval), String> {
|
||||
pub fn get_cell(&self, cell_ref: CellRef) -> Result<Eval, String> {
|
||||
pub fn get_cell(&self, cell_ref: CellRef) -> Result<Cell, String> {
|
||||
if !self.cells.contains_key(&cell_ref) {
|
||||
return Err(format!("Cell at {:?} not found.", cell_ref));
|
||||
}
|
||||
@@ -55,18 +62,200 @@ impl Grid {
|
||||
let cell = &self.cells[&cell_ref];
|
||||
|
||||
// Ok((cell.raw(), cell.eval()))
|
||||
Ok(cell.eval())
|
||||
Ok(cell.to_owned())
|
||||
}
|
||||
|
||||
pub fn add_cell_dep(&mut self, cell_ref: CellRef, dep_ref: CellRef) -> Result<(), String> {
|
||||
if !self.cells.contains_key(&cell_ref) {
|
||||
return Err(format!("Cell at {:?} not found.", cell_ref));
|
||||
pub fn get_cell_mut(&mut self, cell_ref: CellRef) -> Result<&mut Cell, String> {
|
||||
if let Some(res) = self.cells.get_mut(&cell_ref) {
|
||||
Ok(res)
|
||||
} else {
|
||||
Err(format!("Cell at {:?} not found.", cell_ref))
|
||||
}
|
||||
}
|
||||
|
||||
// This is a topological order on the precedents graph
|
||||
// i.e. if a requires b (e.g. a = 1 + b) then a -> b
|
||||
// so a comes before b in the topo order
|
||||
fn topo_order(&self, from: CellRef) -> Result<Vec<CellRef>, String> {
|
||||
let mut res: Vec<CellRef> = Vec::new();
|
||||
let mut search_set = Vec::new();
|
||||
let mut temp = HashSet::new();
|
||||
let mut perm = HashSet::new();
|
||||
|
||||
search_set.push(from);
|
||||
|
||||
let cell_data = &self.cells[&from];
|
||||
search_set.extend(cell_data.deps().iter());
|
||||
|
||||
temp.insert(from);
|
||||
perm.insert(from);
|
||||
|
||||
let mut searched = 1;
|
||||
|
||||
while searched != search_set.len() {
|
||||
if perm.contains(&search_set[searched]) {
|
||||
searched += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
self.topo_visit(
|
||||
search_set[searched],
|
||||
&mut temp,
|
||||
&mut perm,
|
||||
&mut search_set,
|
||||
&mut res,
|
||||
)?;
|
||||
searched += 1;
|
||||
}
|
||||
|
||||
if let Some(cell) = self.cells.get_mut(&cell_ref) {
|
||||
cell.add_i_dep(dep_ref);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn topo_visit(
|
||||
&self,
|
||||
cell: CellRef,
|
||||
temp: &mut HashSet<CellRef>,
|
||||
perm: &mut HashSet<CellRef>,
|
||||
search_set: &mut Vec<CellRef>,
|
||||
res: &mut Vec<CellRef>,
|
||||
) -> Result<(), String> {
|
||||
if perm.contains(&cell) {
|
||||
return Ok(());
|
||||
}
|
||||
if temp.contains(&cell) {
|
||||
return Err("Evalutation error: Cycle detected in cell refs.".into());
|
||||
}
|
||||
|
||||
temp.insert(cell);
|
||||
|
||||
if !self.cells.contains_key(&cell) {
|
||||
perm.insert(cell);
|
||||
res.push(cell);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let cell_data = &self.cells[&cell];
|
||||
|
||||
search_set.extend(cell_data.deps().iter());
|
||||
// search_set.extend(cell_data.precedents.iter().cloned());
|
||||
|
||||
for prec in cell_data.precs().iter() {
|
||||
self.topo_visit(*prec, temp, perm, search_set, res)?;
|
||||
}
|
||||
|
||||
perm.insert(cell);
|
||||
|
||||
res.push(cell);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_exisiting_cell(
|
||||
&mut self,
|
||||
raw: String,
|
||||
new_eval: Eval,
|
||||
new_precs: HashSet<CellRef>,
|
||||
cell_ref: CellRef,
|
||||
) -> Result<Vec<CellRef>, String> {
|
||||
let (old_precs, old_eval) = match self.cells.get_mut(&cell_ref) {
|
||||
Some(cell) => {
|
||||
cell.set_raw(raw);
|
||||
(cell.precs().clone(), cell.eval().clone())
|
||||
}
|
||||
None => return Ok(Vec::new()),
|
||||
};
|
||||
|
||||
// diffs (outside any borrow)
|
||||
let removed: Vec<_> = old_precs.difference(&new_precs).cloned().collect(); // old \ new
|
||||
let added: Vec<_> = new_precs.difference(&old_precs).cloned().collect(); // new \ old
|
||||
let eval_changed = old_eval != new_eval;
|
||||
|
||||
// ---- phase 2: apply (fresh borrows) ----
|
||||
for p in &removed {
|
||||
if let Some(c) = self.cells.get_mut(p) {
|
||||
c.remove_dep(&cell_ref);
|
||||
}
|
||||
}
|
||||
for p in &added {
|
||||
if let Some(c) = self.cells.get_mut(p) {
|
||||
c.add_dep(cell_ref);
|
||||
} else {
|
||||
self.cells.insert(
|
||||
*p,
|
||||
Cell::new_all(
|
||||
*p,
|
||||
Eval::Unset,
|
||||
"".into(),
|
||||
HashSet::new(),
|
||||
HashSet::from([cell_ref]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let cell = self.cells.get_mut(&cell_ref).unwrap(); // Should be impossible to crash
|
||||
cell.set_precs(new_precs);
|
||||
cell.set_eval(new_eval);
|
||||
|
||||
if eval_changed {
|
||||
self.propagate(cell_ref)
|
||||
} else {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
fn create_cell(&mut self, raw: String, eval: Eval, precs: HashSet<CellRef>, cell_ref: CellRef) {
|
||||
for prec in &precs {
|
||||
if let Some(it) = self.cells.get_mut(&prec) {
|
||||
it.add_dep(cell_ref);
|
||||
} else {
|
||||
self.cells.insert(
|
||||
*prec,
|
||||
Cell::new_all(
|
||||
*prec,
|
||||
Eval::Unset,
|
||||
"".into(),
|
||||
HashSet::new(),
|
||||
HashSet::from([cell_ref]),
|
||||
),
|
||||
);
|
||||
|
||||
info!("{:?}", self.cells.get(&prec));
|
||||
}
|
||||
}
|
||||
|
||||
self.cells.insert(
|
||||
cell_ref,
|
||||
Cell::new_all(cell_ref, eval, raw, precs, HashSet::new()),
|
||||
);
|
||||
}
|
||||
|
||||
fn propagate(&mut self, from: CellRef) -> Result<Vec<CellRef>, String> {
|
||||
let mut res = Vec::new();
|
||||
let topo = self.topo_order(from)?;
|
||||
|
||||
for cell_ref in topo {
|
||||
res.push(cell_ref);
|
||||
|
||||
let raw = if let Some(cell) = self.cells.get(&cell_ref) {
|
||||
let s = cell.raw();
|
||||
if let Some(rest) = s.strip_prefix('=') {
|
||||
rest.to_owned()
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Now we dropped the borrow of self.cells before this point
|
||||
let (e, _) = evaluate(raw, Some(self))?;
|
||||
|
||||
if let Some(cell) = self.cells.get_mut(&cell_ref) {
|
||||
cell.set_eval(e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
evaluator::Eval,
|
||||
grid::Grid,
|
||||
messages::{LeadMsg, MsgType},
|
||||
tokenizer::Literal,
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
@@ -63,26 +64,45 @@ async fn accept_connection(stream: TcpStream) {
|
||||
let Some(cell_ref) = req.cell else { continue };
|
||||
let Some(raw) = req.raw else { continue };
|
||||
|
||||
match grid.set_cell(cell_ref.clone(), raw.to_owned()) {
|
||||
Ok(eval) => match eval {
|
||||
Eval::Literal(lit) => {
|
||||
let res = LeadMsg {
|
||||
msg_type: MsgType::Set,
|
||||
cell: Some(cell_ref),
|
||||
raw: Some(raw.to_string()),
|
||||
eval: Some(lit),
|
||||
};
|
||||
let _ = write
|
||||
.send(serde_json::to_string(&res).unwrap().into())
|
||||
.await;
|
||||
match grid.update_cell(cell_ref.clone(), raw.to_owned()) {
|
||||
Ok(updates) => {
|
||||
let mut msgs = Vec::new();
|
||||
|
||||
for update in &updates {
|
||||
if let Ok(cell) = grid.get_cell(*update) {
|
||||
let Eval::Literal(lit) = cell.eval() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
msgs.push(LeadMsg {
|
||||
msg_type: MsgType::Set,
|
||||
cell: Some(*update),
|
||||
raw: Some(cell.raw()),
|
||||
eval: Some(lit),
|
||||
bulk_msgs: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
let msg = LeadMsg {
|
||||
cell: None,
|
||||
raw: None,
|
||||
eval: None,
|
||||
bulk_msgs: Some(msgs),
|
||||
msg_type: MsgType::Bulk,
|
||||
};
|
||||
|
||||
let _ = write
|
||||
.send(serde_json::to_string(&msg).unwrap().into())
|
||||
.await;
|
||||
}
|
||||
Err(e) => {
|
||||
let res = LeadMsg {
|
||||
msg_type: MsgType::Error,
|
||||
cell: Some(cell_ref),
|
||||
raw: Some(e.to_string()),
|
||||
eval: None,
|
||||
bulk_msgs: None,
|
||||
};
|
||||
let _ = write
|
||||
.send(serde_json::to_string(&res).unwrap().into())
|
||||
|
||||
@@ -8,6 +8,7 @@ pub enum MsgType {
|
||||
Set,
|
||||
Get,
|
||||
Error,
|
||||
Bulk,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -16,4 +17,5 @@ pub struct LeadMsg {
|
||||
pub cell: Option<CellRef>,
|
||||
pub raw: Option<String>,
|
||||
pub eval: Option<Literal>,
|
||||
pub bulk_msgs: Option<Vec<LeadMsg>>,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use log::info;
|
||||
|
||||
use crate::{cell::CellRef, tokenizer::*};
|
||||
use std::{collections::HashSet, fmt};
|
||||
|
||||
@@ -21,6 +23,7 @@ pub enum InfixOp {
|
||||
SUB,
|
||||
AND,
|
||||
OR,
|
||||
RANGE,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@@ -57,6 +60,7 @@ pub trait Precedence {
|
||||
impl Precedence for InfixOp {
|
||||
fn prec(&self) -> (u8, u8) {
|
||||
match self {
|
||||
InfixOp::RANGE => (7, 8),
|
||||
InfixOp::MUL | InfixOp::DIV | InfixOp::AND => (3, 4),
|
||||
InfixOp::ADD | InfixOp::SUB | InfixOp::OR => (1, 2),
|
||||
}
|
||||
@@ -157,20 +161,21 @@ impl Expr {
|
||||
|
||||
pub fn parse(input: &str) -> Result<(Expr, HashSet<CellRef>), String> {
|
||||
let mut tokenizer = Tokenizer::new(input)?;
|
||||
// println!("{:?}", tokenizer.tokens);
|
||||
let mut deps = HashSet::new();
|
||||
Ok((_parse(&mut tokenizer, 0, &mut deps)?, deps))
|
||||
let mut precs = HashSet::new();
|
||||
let expr = _parse(&mut tokenizer, 0, &mut precs)?;
|
||||
info!("{}", expr.pretty());
|
||||
Ok((expr, precs))
|
||||
}
|
||||
|
||||
pub fn _parse(
|
||||
input: &mut Tokenizer,
|
||||
min_prec: u8,
|
||||
deps: &mut HashSet<CellRef>,
|
||||
precedents: &mut HashSet<CellRef>,
|
||||
) -> Result<Expr, String> {
|
||||
let mut lhs = match input.next() {
|
||||
Token::Literal(it) => Expr::Literal(it),
|
||||
Token::OpenParen => {
|
||||
let lhs = _parse(input, 0, deps)?;
|
||||
let lhs = _parse(input, 0, precedents)?;
|
||||
if input.next() != Token::CloseParen {
|
||||
return Err(format!("Parse error: expected closing paren."));
|
||||
}
|
||||
@@ -184,7 +189,7 @@ pub fn _parse(
|
||||
it => return Err(format!("Parse error: unknown prefix operator {:?}.", it)),
|
||||
};
|
||||
|
||||
let rhs = _parse(input, prefix_op.prec().1, deps)?;
|
||||
let rhs = _parse(input, prefix_op.prec().1, precedents)?;
|
||||
|
||||
Expr::Prefix {
|
||||
op: prefix_op,
|
||||
@@ -213,7 +218,7 @@ pub fn _parse(
|
||||
input.next(); // Skip comma
|
||||
}
|
||||
|
||||
let arg = _parse(input, 0, deps)?;
|
||||
let arg = _parse(input, 0, precedents)?;
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
@@ -224,7 +229,7 @@ pub fn _parse(
|
||||
}
|
||||
_ => {
|
||||
let cell_ref = CellRef::new(id)?;
|
||||
deps.insert(cell_ref);
|
||||
precedents.insert(cell_ref);
|
||||
Expr::CellRef(cell_ref)
|
||||
}
|
||||
},
|
||||
@@ -235,7 +240,7 @@ pub fn _parse(
|
||||
// In the reference article this is a loop with match
|
||||
// statement that breaks on Eof and closing paren but this is simpler and works as expected
|
||||
while let Token::Operator(op) = input.peek() {
|
||||
if "+-*/&|".contains(op) {
|
||||
if OPERATORS_STR.contains(op) {
|
||||
let infix_op = match op {
|
||||
'+' => InfixOp::ADD,
|
||||
'-' => InfixOp::SUB,
|
||||
@@ -243,6 +248,7 @@ pub fn _parse(
|
||||
'/' => InfixOp::DIV,
|
||||
'&' => InfixOp::AND,
|
||||
'|' => InfixOp::OR,
|
||||
':' => InfixOp::RANGE,
|
||||
it => {
|
||||
return Err(format!("Parse error: do not know infix operator {:?}.", it));
|
||||
}
|
||||
@@ -254,7 +260,7 @@ pub fn _parse(
|
||||
}
|
||||
|
||||
input.next();
|
||||
let rhs = _parse(input, r_prec, deps)?;
|
||||
let rhs = _parse(input, r_prec, precedents)?;
|
||||
lhs = Expr::Infix {
|
||||
op: infix_op,
|
||||
lhs: Box::new(lhs),
|
||||
|
||||
@@ -19,6 +19,8 @@ pub enum Token {
|
||||
Eof,
|
||||
}
|
||||
|
||||
pub const OPERATORS_STR: &str = "+-*/^!%&|:";
|
||||
|
||||
pub struct Tokenizer {
|
||||
pub tokens: Vec<Token>,
|
||||
}
|
||||
@@ -97,7 +99,7 @@ impl Tokenizer {
|
||||
string.push(ch);
|
||||
}
|
||||
tokens.push(Token::Literal(Literal::String(string)));
|
||||
} else if "+-*/^!%&|".contains(c) {
|
||||
} else if OPERATORS_STR.contains(c) {
|
||||
tokens.push(Token::Operator(c));
|
||||
chars.next();
|
||||
} else if "()".contains(c) {
|
||||
|
||||
Reference in New Issue
Block a user