1 2 /* 3 A structure describing an operation. 4 */ 5 struct Operation { 6 const char *args; 7 runOperation8 virtual Cell *run() { return nullptr; } runnOperation9 virtual double runn(double a) { return 0; } runtOperation10 virtual Cell *runt(Text *t) { return nullptr; } runlOperation11 virtual Cell *runl(Grid *l) { return nullptr; } rungOperation12 virtual Cell *rung(Grid *g) { return nullptr; } runcOperation13 virtual Cell *runc(Cell *c) { return nullptr; } runnnOperation14 virtual double runnn(double a, double b) { return 0; } 15 }; 16 17 WX_DECLARE_STRING_HASH_MAP(Operation *, wxHashMapOperation); 18 WX_DECLARE_STRING_HASH_MAP(Cell *, wxHashMapCell); 19 20 /* 21 Provides running evaluation of a grid. 22 */ 23 struct Evaluator { 24 wxHashMapOperation ops; 25 wxHashMapCell vars; 26 bool vert; 27 ~EvaluatorEvaluator28 ~Evaluator() { 29 while (ops.size()) { 30 delete ops.begin()->second; 31 ops.erase(ops.begin()); 32 } 33 while (vars.size()) { 34 delete vars.begin()->second; 35 vars.erase(vars.begin()); 36 } 37 } 38 39 #define OP(_n, _c, _args, _f) \ 40 { \ 41 struct _op : Operation { \ 42 _op() { args = _args; }; \ 43 _f { return _c; }; \ 44 }; \ 45 ops[L## #_n] = new _op(); \ 46 } 47 48 #define OPNN(_n, _c) OP(_n, _c, "nn", double runnn(double a, double b)) 49 #define OPN(_n, _c) OP(_n, _c, "n", double runn(double a)) 50 #define OPT(_n, _c) OP(_n, _c, "t", Cell *runt(Text *t)) 51 #define OPL(_n, _c) OP(_n, _c, "l", Cell *runl(Grid *a)) 52 #define OPG(_n, _c) OP(_n, _c, "g", Cell *rung(Grid *a)) 53 InitEvaluator54 void Init() { 55 OPNN(+, a + b); 56 OPNN(-, a - b); 57 OPNN(*, a * b); 58 OPNN(/, b != 0 ? a / b : 0); 59 OPNN(<, double(a < b)); 60 OPNN(>, double(a > b)); 61 OPNN(<=, double(a <= b)); 62 OPNN(>=, double(a >= b)); 63 OPNN(=, double(a == b)); 64 OPNN(==, double(a == b)); 65 OPNN(!=, double(a != b)); 66 OPNN(<>, double(a != b)); 67 OPN(inc, a + 1); 68 OPN(dec, a - 1); 69 OPN(neg, -a); 70 OPT(graph, t->Graph()); 71 OPL(sum, a->Sum()) 72 OPG(transpose, a->Transpose()) 73 struct _if : Operation { 74 _if() { args = "nLL"; }; 75 }; 76 ops[L"if"] = new _if(); 77 } 78 InferCellTypeEvaluator79 int InferCellType(Text &t) { 80 if (ops[t.t]) 81 return CT_CODE; 82 else 83 return CT_DATA; 84 } 85 LookupEvaluator86 Cell *Lookup(wxString &name) { 87 wxHashMapCell::iterator lookup = vars.find(name); 88 return (lookup != vars.end()) ? lookup->second->Clone(nullptr) : nullptr; 89 } 90 IsValidSymbolEvaluator91 bool IsValidSymbol(wxString const &symbol) const { return !symbol.IsEmpty(); } SetSymbolEvaluator92 void SetSymbol(wxString const &symbol, Cell *val) { 93 if (!this->IsValidSymbol(symbol)) { 94 DELETEP(val); 95 return; 96 } 97 Cell *old = vars[symbol]; 98 DELETEP(old); 99 vars[symbol] = val; 100 } 101 AssignEvaluator102 void Assign(Cell const *sym, Cell const *val) { 103 this->SetSymbol(sym->text.t, val->Clone(nullptr)); 104 if (sym->grid && val->grid) this->DestructuringAssign(sym->grid, val->Clone(nullptr)); 105 } 106 DestructuringAssignEvaluator107 void DestructuringAssign(Grid const *names, Cell *val) { 108 Grid const *ng = names; 109 Grid const *vg = val->grid; 110 if (ng->xs == vg->xs && ng->ys == vg->ys) { 111 loop(x, ng->xs) loop(y, ng->ys) { 112 Cell *nc = ng->C(x, y); 113 Cell *vc = vg->C(x, y); 114 this->SetSymbol(nc->text.t, vc->Clone(nullptr)); 115 } 116 } 117 DELETEP(val); 118 } 119 FindOpEvaluator120 Operation *FindOp(wxString &name) { return ops[name]; } 121 ExecuteEvaluator122 Cell *Execute(Operation *op) { return op->run(); } 123 ExecuteEvaluator124 Cell *Execute(Operation *op, Cell *left) { 125 Text &t = left->text; 126 Grid *g = left->grid; 127 switch (op->args[0]) { 128 case 'n': 129 if (t.t.Len()) 130 return t.SetNum(op->runn(t.GetNum())); 131 else if (g) 132 foreachcellingrid(c, g) c = Execute(op, c)->SetParent(left); 133 break; 134 case 't': 135 if (t.t.Len()) 136 return op->runt(&t); 137 else if (g) 138 foreachcellingrid(c, g) c = Execute(op, c)->SetParent(left); 139 break; 140 case 'l': 141 if (g) { 142 if (g->xs == 1 || g->ys == 1) return op->runl(g); 143 Vector<Grid *> gs; 144 g->Split(gs, vert); 145 g = new Grid(vert ? gs.size() : 1, vert ? 1 : gs.size()); 146 Cell *c = new Cell(nullptr, left, CT_DATA, g); 147 loopv(i, gs) g->C(vert ? i : 0, vert ? 0 : i) = op->runl(gs[i])->SetParent(c); 148 gs.setsize_nd(0); 149 return c; 150 } 151 break; 152 case 'g': 153 if (g) return op->rung(g); 154 break; 155 case 'c': return op->runc(left); 156 } 157 return left; 158 } 159 ExecuteEvaluator160 Cell *Execute(Operation *op, Cell *left, Cell *right) { 161 if (!(right = right->Eval(*this))) return left; 162 Text &t1 = left->text; 163 Text &t2 = right->text; 164 Grid *g1 = left->grid; 165 Grid *g2 = right->grid; 166 switch (op->args[0]) { 167 case 'n': 168 if (t1.t.Len() && t2.t.Len()) 169 t1.SetNum(op->runnn(t1.GetNum(), t2.GetNum())); 170 else if (g1 && g2 && g1->xs == g2->xs && g1->ys == g2->ys) { 171 Grid *g = new Grid(g1->xs, g1->ys); 172 Cell *c = new Cell(nullptr, left, CT_DATA, g); 173 loop(x, g->xs) loop(y, g->ys) { 174 Cell *&c1 = g1->C(x, y); 175 Cell *&c2 = g2->C(x, y); 176 g->C(x, y) = Execute(op, c1, c2)->SetParent(c); 177 c1 = c2 = nullptr; 178 } 179 delete g1; 180 delete g2; 181 return c; 182 } else if (g1 && t2.t.Len()) { 183 foreachcellingrid(c, g1) c = 184 Execute(op, c, right->Clone(nullptr))->SetParent(left); 185 } 186 break; 187 } 188 delete right; 189 return left; 190 } 191 ExecuteEvaluator192 Cell *Execute(Operation *op, Cell *left, Cell *a, Cell *b) // IF is sofar the only ternary 193 { 194 Text &l = left->text; 195 if (!l.t.Len()) return left; 196 bool cond = l.GetNum() != 0; 197 delete left; 198 return (cond ? a : b)->Eval(*this); 199 } 200 EvalEvaluator201 void Eval(Cell *root) { 202 Cell *c = root->Eval(*this); 203 DELETEP(c); 204 } 205 }; 206