-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path2-improved.js
More file actions
99 lines (85 loc) · 2.17 KB
/
2-improved.js
File metadata and controls
99 lines (85 loc) · 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
'use strict';
const OPERATORS = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b,
};
class NumberExpression {
constructor(value) {
this.value = parseFloat(value);
}
interpret() {
return this.value;
}
}
class VariableExpression {
constructor(name) {
this.name = name;
}
interpret(context) {
if (!(this.name in context)) {
throw new Error(`Variable "${this.name}" is not defined`);
}
return context[this.name];
}
}
class OperationExpression {
constructor(operator, operands) {
this.operator = operator;
this.operands = operands;
}
interpret(context) {
const toValues = (operand) => operand.interpret(context);
const args = this.operands.map(toValues);
const operator = OPERATORS[this.operator];
if (!operator) throw new Error(`Unknown operator: ${operator}`);
return args.reduce(operator);
}
}
const tokenize = (source) => {
const stack = [];
const parentStack = [];
let current = stack;
const tokens = source
.replaceAll('(', ' ( ')
.replaceAll(')', ' ) ')
.trim()
.split(/\s+/);
for (const token of tokens) {
if (token === '(') {
const newStack = [];
current.push(newStack);
parentStack.push(current);
current = newStack;
} else if (token === ')') {
current = parentStack.pop();
} else {
current.push(token);
}
}
return stack[0];
};
const parse = (tokens) => {
if (!Array.isArray(tokens)) {
const isVar = isNaN(tokens);
const Expression = isVar ? VariableExpression : NumberExpression;
return new Expression(tokens);
}
const operator = tokens[0];
const operands = tokens.slice(1);
const operandExpressions = operands.map(parse);
return new OperationExpression(operator, operandExpressions);
};
const evaluate = (input, context = {}) => {
const tokens = tokenize(input);
console.log({ tokens });
const expression = parse(tokens);
return expression.interpret(context);
};
// Usage
const program = '(+ 2 (* x 5) (- y 2))';
const context = { x: 3, y: 7 };
const result = evaluate(program, context);
const expected = 2 + 3 * 5 + (7 - 2);
console.log({ expected, result });