Browse Source

add query and improve UX

Kyle 1 month ago
parent
commit
a02ce5f408
1 changed files with 42 additions and 9 deletions
  1. 42 9
      main.js

+ 42 - 9
main.js

@@ -11,6 +11,7 @@ var onlyUnique = (v, i, a) => a.indexOf(v) === i;
11 11
 
12 12
 function calcExpression(expression) {
13 13
   if (typeof expression === 'string') return parseFloat(expression);
14
+  if (!expression) return null;
14 15
   return op_funcs[expression.action](
15 16
     calcExpression(expression.args[0]),
16 17
     calcExpression(expression.args[1])
@@ -26,10 +27,23 @@ function substituteVariable(expression, variable, substitute) {
26 27
   };
27 28
 }
28 29
 
30
+function doesSolve(variable, state) {
31
+  var varState = state.find(x => x.name === variable);
32
+  var notVarState = state.filter(x => x.name !== variable);
33
+  if (!varState) return null;
34
+  if (varState.depends.length === 0) return true;
35
+  var expression = varState.depends.every(
36
+    d => doesSolve(d, notVarState)
37
+  );
38
+  return expression;
39
+}
40
+
29 41
 function expressionFor(variable, state) {
30 42
   var varState = state.find(x => x.name === variable);
43
+  var notVarState = state.filter(x => x.name !== variable);
44
+  if (!varState) return variable;
31 45
   var expression = varState.depends.reduce(
32
-    (r, d) => substituteVariable(r, d, expressionFor(d, state)),
46
+    (r, d) => substituteVariable(r, d, expressionFor(d, notVarState)),
33 47
     varState.solved
34 48
   );
35 49
   return expression;
@@ -49,13 +63,15 @@ function mergeState(a, b) {
49 63
   });
50 64
 }
51 65
 
52
-function solve(lines, state=[]) {
66
+function compile(lines, state=[]) {
53 67
   if (lines.length === 0) return state;
54 68
   var new_state = extractSolutions(lines[0]);
55
-  return solve(lines.slice(1), mergeState(new_state, state));
69
+  var merged = new_state ? mergeState(new_state, state) : state;
70
+  return compile(lines.slice(1), merged);
56 71
 }
57 72
 
58 73
 function render(tree) {
74
+  if (!tree) return ''
59 75
   if (typeof tree === 'string') {
60 76
     return tree;
61 77
   }
@@ -94,9 +110,21 @@ function solveFor(variable, tree) {
94 110
   return flipRight || flipLeft;
95 111
 }
96 112
 
113
+function validateTree(expression) {
114
+  return (
115
+    expression
116
+    && (
117
+      typeof expression === 'string'
118
+      || expression.args.every(a => validateTree(a))
119
+      && expression.action
120
+    )
121
+  )
122
+}
123
+
97 124
 function extractSolutions(expression) {
98 125
   var vars = expression.filter(p => !ops.includes(p) && isNaN(parseFloat(p)));
99 126
   var tree = lex(expression);
127
+  if (!(validateTree(tree) && typeof tree !== 'string')) return null
100 128
   return vars.map(v => ({
101 129
     name: v,
102 130
     solved: solveFor(v, tree),
@@ -138,12 +166,17 @@ window.onload = function () {
138 166
   const results = document.querySelector('.results');
139 167
 
140 168
   function onchange(e) {
141
-    var lines = input.value.match(/^.*([\n\r]+|$)/gm).map(
142
-      l => l.replace(/\n/g,'')
143
-    ).map(split)
144
-    var state = solve(lines)
145
-    result = state.map(s => [s.name, expressionFor(s.name, state)]).map(
146
-      x => `${x[0]} = ${calcExpression(x[1])} = ${render(x[1])}`
169
+    var lines = input.value.split('\n').map(split)
170
+    var state = compile(lines)
171
+    var debug = state.map(s => [s.name, doesSolve(s.name, state) ? expressionFor(s.name, state) : null]).map(
172
+      x => x[1] ? `${x[0]} = ${calcExpression(x[1])} = ${render(x[1])}` : ''
173
+    )
174
+    var result = lines.map(
175
+      l => l[0] === '?'
176
+        ? l.slice(1).map(
177
+          x => [x, expressionFor(x, state)]
178
+        ).map(x => [x[0], render(x[1])].concat(doesSolve(x[0], state) ? [calcExpression(x[1])] : []).join(' = ')).join('; ')
179
+        : ''
147 180
     )
148 181
     results.textContent = result.join('\n');
149 182
   }