-
Notifications
You must be signed in to change notification settings - Fork 1
/
ExpressionStr.js
87 lines (81 loc) · 2.61 KB
/
ExpressionStr.js
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
/**
* Parse string expressions like "L x[L y[x(y)]]" into a UserExpression.
*
* This isn't used in the app itself, but is useful for testing and development
* purposes.
*
* @flow
*/
import {
UserFuncCall,
UserLambda,
UserReference,
UserVariable,
} from './types'
import type {UserExpression} from './types';
export const parseExpr = (str: string): UserExpression => {
// Allow redundant whitespace.
str = str.trim();
if (str.endsWith(']')) {
// Expression like "L x[x(x)]"
assertSame('L ', str.substring(0, 2));
const openBracketIndex = str.indexOf('[');
const varName = str.substring(2, openBracketIndex).trim();
const bodyStr =
str.substring(openBracketIndex + 1, str.length - 1).trim();
let body;
if (bodyStr == '_') {
body = null;
} else {
body = parseExpr(bodyStr);
}
return UserLambda.make(varName, body);
} else if (str.endsWith(")")) {
let level = 1;
let index = str.length - 1;
while (level > 0) {
index--;
if (str.charAt(index) == ')') {
level++;
} else if (str.charAt(index) == '(') {
level--;
}
}
// Now index is the index of the open-paren character.
const funcStr = str.substring(0, index);
const argStr = str.substring(index + 1, str.length - 1);
return UserFuncCall.make(
parseExpr(funcStr), parseExpr(argStr));
} else if (str === str.toUpperCase()) {
assertNoBrackets(str);
return UserReference.make(str);
} else {
assertNoBrackets(str);
return UserVariable.make(str);
}
};
const assertNoBrackets = (str: string) => {
const message = "Unexpected string " + str;
assert(str.indexOf("(") === -1, message);
assert(str.indexOf(")") === -1, message);
assert(str.indexOf("[") === -1, message);
assert(str.indexOf("]") === -1, message);
};
const assertSame = (val1: any, val2: any) => {
assert(val1 === val2, `Expected ${val1} got ${val2}.`);
};
const assert = (condition: bool, message: string) => {
if (!condition) {
throw new Error(message || 'Assertion failed.');
}
};
export const formatExpr = (expr: UserExpression): string => {
return expr.match({
userLambda: ({body, varName}) =>
`L ${varName}[${body ? formatExpr(body) : '_'}]`,
userFuncCall: ({func, arg}) =>
`${formatExpr(func)}(${formatExpr(arg)})`,
userVariable: ({varName}) => varName,
userReference: ({defName}) => defName,
});
};