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