@khanacademy/kas 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE.txt +21 -0
- package/README.md +94 -0
- package/dist/es/index.js +2 -0
- package/dist/es/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.flow +2 -0
- package/dist/index.js.map +1 -0
- package/experimenter.html +75 -0
- package/package.json +38 -0
- package/src/__genfiles__/parser.js +840 -0
- package/src/__genfiles__/unitparser.js +679 -0
- package/src/__tests__/checking-form_test.js +76 -0
- package/src/__tests__/comparing_test.js +322 -0
- package/src/__tests__/compilation_test.js +97 -0
- package/src/__tests__/evaluating_test.js +73 -0
- package/src/__tests__/index_test.js +364 -0
- package/src/__tests__/parsing_test.js +480 -0
- package/src/__tests__/rendering_test.js +272 -0
- package/src/__tests__/transforming_test.js +331 -0
- package/src/__tests__/units_test.js +188 -0
- package/src/compare.js +69 -0
- package/src/index.js +2 -0
- package/src/nodes.js +3504 -0
- package/src/parser-generator.js +212 -0
- package/src/unitvalue.jison +161 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/* TODO(charlie): fix these lint errors (http://eslint.org/docs/rules): */
|
|
4
|
+
/* eslint-disable no-var, comma-dangle, max-len, comma-spacing */
|
|
5
|
+
|
|
6
|
+
var fs = require("fs");
|
|
7
|
+
var path = require("path");
|
|
8
|
+
var jison = require("jison");
|
|
9
|
+
|
|
10
|
+
var grammar = {
|
|
11
|
+
lex: {
|
|
12
|
+
rules: [
|
|
13
|
+
["\\s+", "/* skip whitespace */"],
|
|
14
|
+
["\\\\space", "/* skip \\space */"],
|
|
15
|
+
["\\\\ ", "/* skip '\\ ' */"],
|
|
16
|
+
["[0-9]+\\.?", "return \"INT\""],
|
|
17
|
+
["([0-9]+)?\\.[0-9]+", "return \"FLOAT\""],
|
|
18
|
+
["\\*\\*", "return \"^\""],
|
|
19
|
+
["\\*", "return \"*\""],
|
|
20
|
+
["\\\\cdot|\u00b7", "return \"*\""],
|
|
21
|
+
["\\\\times|\u00d7", "return \"*\""],
|
|
22
|
+
["\\\\ast", "return \"*\""],
|
|
23
|
+
["\\/", "return \"/\""],
|
|
24
|
+
["\\\\div|\u00F7", "return \"/\""],
|
|
25
|
+
["-", "return \"-\""],
|
|
26
|
+
["\u2212", "return \"-\""], // minus
|
|
27
|
+
["\\+", "return \"+\""],
|
|
28
|
+
["\\^", "return \"^\""],
|
|
29
|
+
["\\(", "return \"(\""],
|
|
30
|
+
["\\)", "return \")\""],
|
|
31
|
+
["\\\\left\\(", "return \"(\""],
|
|
32
|
+
["\\\\right\\)", "return \")\""],
|
|
33
|
+
["\\[", "return \"[\""],
|
|
34
|
+
["\\]", "return \"]\""],
|
|
35
|
+
["\\{", "return \"{\""],
|
|
36
|
+
["\\}", "return \"}\""],
|
|
37
|
+
["\\\\left\\{", "return \"{\""],
|
|
38
|
+
["\\\\right\\}", "return \"}\""],
|
|
39
|
+
["_", "return \"_\""],
|
|
40
|
+
["\\|", "return \"|\""],
|
|
41
|
+
["\\\\left\\|", "return \"LEFT|\""],
|
|
42
|
+
["\\\\right\\|", "return \"RIGHT|\""],
|
|
43
|
+
["\\!", "return \"!\""], // not yet interpreted
|
|
44
|
+
["<=|>=|<>|<|>|=", "return \"SIGN\""],
|
|
45
|
+
["\\\\le", "yytext = \"<=\"; return \"SIGN\""],
|
|
46
|
+
["\\\\ge", "yytext = \">=\"; return \"SIGN\""],
|
|
47
|
+
["\\\\leq", "yytext = \"<=\"; return \"SIGN\""],
|
|
48
|
+
["\\\\geq", "yytext = \">=\"; return \"SIGN\""],
|
|
49
|
+
["=\\/=", "yytext = \"<>\"; return \"SIGN\""],
|
|
50
|
+
["\\\\ne", "yytext = \"<>\"; return \"SIGN\""],
|
|
51
|
+
["\\\\neq", "yytext = \"<>\"; return \"SIGN\""],
|
|
52
|
+
["\u2260", "yytext = \"<>\"; return \"SIGN\""], // ne
|
|
53
|
+
["\u2264", "yytext = \"<=\"; return \"SIGN\""], // le
|
|
54
|
+
["\u2265", "yytext = \">=\"; return \"SIGN\""], // ge
|
|
55
|
+
["\\\\frac", "return \"FRAC\""],
|
|
56
|
+
["\\\\dfrac", "return \"FRAC\""],
|
|
57
|
+
["sqrt|\\\\sqrt", "return \"sqrt\""],
|
|
58
|
+
["abs|\\\\abs", "return \"abs\""],
|
|
59
|
+
["ln|\\\\ln", "return \"ln\""],
|
|
60
|
+
["log|\\\\log", "return \"log\""],
|
|
61
|
+
["sin|cos|tan", "return \"TRIG\""],
|
|
62
|
+
["csc|sec|cot", "return \"TRIG\""],
|
|
63
|
+
["sinh|cosh|tanh", "return \"TRIG\""],
|
|
64
|
+
["csch|sech|coth", "return \"TRIG\""],
|
|
65
|
+
["\\\\sin", "yytext = \"sin\"; return \"TRIG\""],
|
|
66
|
+
["\\\\cos", "yytext = \"cos\"; return \"TRIG\""],
|
|
67
|
+
["\\\\tan", "yytext = \"tan\"; return \"TRIG\""],
|
|
68
|
+
["\\\\csc", "yytext = \"csc\"; return \"TRIG\""],
|
|
69
|
+
["\\\\sec", "yytext = \"sec\"; return \"TRIG\""],
|
|
70
|
+
["\\\\cot", "yytext = \"cot\"; return \"TRIG\""],
|
|
71
|
+
["\\\\arcsin", "yytext = \"arcsin\"; return \"TRIG\""],
|
|
72
|
+
["\\\\arccos", "yytext = \"arccos\"; return \"TRIG\""],
|
|
73
|
+
["\\\\arctan", "yytext = \"arctan\"; return \"TRIG\""],
|
|
74
|
+
["\\\\arccsc", "yytext = \"arccsc\"; return \"TRIG\""],
|
|
75
|
+
["\\\\arcsec", "yytext = \"arcsec\"; return \"TRIG\""],
|
|
76
|
+
["\\\\arccot", "yytext = \"arccot\"; return \"TRIG\""],
|
|
77
|
+
["arcsin|arccos|arctan","return \"TRIGINV\""],
|
|
78
|
+
["arccsc|arcsec|arccot","return \"TRIGINV\""],
|
|
79
|
+
["\\\\sinh", "yytext = \"sinh\"; return \"TRIG\""],
|
|
80
|
+
["\\\\cosh", "yytext = \"cosh\"; return \"TRIG\""],
|
|
81
|
+
["\\\\tanh", "yytext = \"tanh\"; return \"TRIG\""],
|
|
82
|
+
["\\\\csch", "yytext = \"csch\"; return \"TRIG\""],
|
|
83
|
+
["\\\\sech", "yytext = \"sech\"; return \"TRIG\""],
|
|
84
|
+
["\\\\coth", "yytext = \"tanh\"; return \"TRIG\""],
|
|
85
|
+
["pi", "return \"CONST\""],
|
|
86
|
+
["\u03C0", "yytext = \"pi\"; return \"CONST\""], // pi
|
|
87
|
+
["\\\\pi", "yytext = \"pi\"; return \"CONST\""],
|
|
88
|
+
["theta", "return \"VAR\""],
|
|
89
|
+
["\u03B8", "yytext = \"theta\"; return \"VAR\""], // theta
|
|
90
|
+
["\\\\theta", "yytext = \"theta\"; return \"VAR\""],
|
|
91
|
+
["phi", "return \"VAR\""],
|
|
92
|
+
["\u03C6", "yytext = \"phi\"; return \"VAR\""], // phi
|
|
93
|
+
["\\\\phi", "yytext = \"phi\"; return \"VAR\""],
|
|
94
|
+
["[a-zA-Z]", "return yy.symbolLexer(yytext)"],
|
|
95
|
+
["$", "return \"EOF\""],
|
|
96
|
+
[".", "return \"INVALID\""]
|
|
97
|
+
],
|
|
98
|
+
options: {
|
|
99
|
+
flex: true // pick longest matching token
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
operators: [
|
|
103
|
+
["right", "|"],
|
|
104
|
+
["left", "+", "-"],
|
|
105
|
+
["left", "*", "/"],
|
|
106
|
+
["left", "UMINUS"],
|
|
107
|
+
["right", "^"]
|
|
108
|
+
],
|
|
109
|
+
start: "equation",
|
|
110
|
+
bnf: {
|
|
111
|
+
"equation": [
|
|
112
|
+
["expression SIGN expression EOF", "return new yy.Eq($1, $2, $3);"],
|
|
113
|
+
["expression EOF", "return $1;"],
|
|
114
|
+
["EOF", "return new yy.Add([]);"]
|
|
115
|
+
],
|
|
116
|
+
"expression": [
|
|
117
|
+
["additive", "$$ = $1;"]
|
|
118
|
+
],
|
|
119
|
+
"additive": [
|
|
120
|
+
["additive + multiplicative", "$$ = yy.Add.createOrAppend($1, $3);"],
|
|
121
|
+
["additive - multiplicative", "$$ = yy.Add.createOrAppend($1, yy.Mul.handleNegative($3, \"subtract\"));"],
|
|
122
|
+
["multiplicative", "$$ = $1;", {prec: "+"}]
|
|
123
|
+
],
|
|
124
|
+
"multiplicative": [
|
|
125
|
+
// the second term in an implicit multiplication cannot be negative
|
|
126
|
+
["multiplicative triglog", "$$ = yy.Mul.fold(yy.Mul.createOrAppend($1, $2));"],
|
|
127
|
+
["multiplicative * negative", "$$ = yy.Mul.fold(yy.Mul.createOrAppend($1, $3));"],
|
|
128
|
+
["multiplicative / negative", "$$ = yy.Mul.fold(yy.Mul.handleDivide($1, $3));"],
|
|
129
|
+
["negative", "$$ = $1;"]
|
|
130
|
+
],
|
|
131
|
+
"negative": [
|
|
132
|
+
["- negative", "$$ = yy.Mul.handleNegative($2);", {prec: "UMINUS"}],
|
|
133
|
+
["triglog", "$$ = $1;"]
|
|
134
|
+
],
|
|
135
|
+
"trig": [
|
|
136
|
+
["TRIG", "$$ = [yytext];"]
|
|
137
|
+
],
|
|
138
|
+
"trigfunc": [
|
|
139
|
+
["trig", "$$ = $1;"],
|
|
140
|
+
["trig ^ negative", "$$ = $1.concat($3);"],
|
|
141
|
+
["TRIGINV", "$$ = [yytext];"]
|
|
142
|
+
],
|
|
143
|
+
"logbase": [
|
|
144
|
+
["ln", "$$ = yy.Log.natural();"],
|
|
145
|
+
["log", "$$ = yy.Log.common();"],
|
|
146
|
+
["log _ subscriptable", "$$ = $3;"]
|
|
147
|
+
],
|
|
148
|
+
"triglog": [
|
|
149
|
+
["trigfunc negative", "$$ = yy.Trig.create($1, $2);"],
|
|
150
|
+
["logbase negative", "$$ = yy.Log.create($1, $2);"],
|
|
151
|
+
["power", "$$ = $1;"]
|
|
152
|
+
],
|
|
153
|
+
"power": [
|
|
154
|
+
["primitive ^ negative", "$$ = new yy.Pow($1, $3);"],
|
|
155
|
+
["primitive", "$$ = $1;"]
|
|
156
|
+
],
|
|
157
|
+
"variable": [
|
|
158
|
+
["VAR", "$$ = yytext;"]
|
|
159
|
+
],
|
|
160
|
+
"subscriptable": [
|
|
161
|
+
["variable _ subscriptable", "$$ = new yy.Var($1, $3);"],
|
|
162
|
+
["variable", "$$ = new yy.Var($1);"],
|
|
163
|
+
["CONST", "$$ = new yy.Const(yytext.toLowerCase());"],
|
|
164
|
+
["INT", "$$ = yy.Int.create(Number(yytext));"],
|
|
165
|
+
["FLOAT", "$$ = yy.Float.create(Number(yytext));"],
|
|
166
|
+
["{ additive }", "$$ = $2.completeParse();"],
|
|
167
|
+
["( additive )", "$$ = $2.completeParse().addHint('parens');"] // this probably shouldn't be a hint...
|
|
168
|
+
],
|
|
169
|
+
"function": [
|
|
170
|
+
["FUNC", "$$ = yytext;"]
|
|
171
|
+
],
|
|
172
|
+
"invocation": [
|
|
173
|
+
["sqrt ( additive )", "$$ = yy.Pow.sqrt($3);"],
|
|
174
|
+
["sqrt { additive }", "$$ = yy.Pow.sqrt($3);"],
|
|
175
|
+
["sqrt [ additive ] { additive }", "$$ = new yy.Pow.nthroot($6, $3);"],
|
|
176
|
+
["abs ( additive )", "$$ = new yy.Abs($3);"],
|
|
177
|
+
["| additive |", "$$ = new yy.Abs($2);"],
|
|
178
|
+
["LEFT| additive RIGHT|", "$$ = new yy.Abs($2);"],
|
|
179
|
+
["function ( additive )", "$$ = new yy.Func($1, $3);"]
|
|
180
|
+
],
|
|
181
|
+
"primitive": [
|
|
182
|
+
["subscriptable", "$$ = $1;"],
|
|
183
|
+
["invocation", "$$ = $1;"],
|
|
184
|
+
["FRAC { additive } { additive }", "$$ = yy.Mul.handleDivide($3, $6);"]
|
|
185
|
+
]
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
var prelude = "// This is a @gene" + "rated file\n" +
|
|
190
|
+
"import _ from \"underscore\";\n\n";
|
|
191
|
+
var parser = (new jison.Generator(grammar)).generate({moduleType: "js"});
|
|
192
|
+
// NOTE(jeresig): We need to comment out these two labels as they appear to be
|
|
193
|
+
// invalid ES5 (they also aren't referenced anywhere so this seems safe).
|
|
194
|
+
parser = parser.replace(/(_token_stack:)/g, "//$1");
|
|
195
|
+
var postlude = "\n\nexport {parser};\n";
|
|
196
|
+
|
|
197
|
+
fs.writeFileSync(path.resolve(__dirname, "__genfiles__", "parser.js"), prelude + parser + postlude);
|
|
198
|
+
|
|
199
|
+
var unitPrelude = "// this is a @gene" + "rated file\n\n";
|
|
200
|
+
var unitEpilogue = "\n\nexport const unitParser = parser;\n";
|
|
201
|
+
|
|
202
|
+
var unitParserInfile = path.resolve(__dirname, "unitvalue.jison");
|
|
203
|
+
var unitParserOutfile = path.resolve(__dirname, "__genfiles__", "unitparser.js");
|
|
204
|
+
|
|
205
|
+
var unitParserSource = fs.readFileSync(unitParserInfile);
|
|
206
|
+
var unitParser = new jison.Generator(unitParserSource.toString());
|
|
207
|
+
var generatedParser = unitParser.generate({ moduleType: "js" });
|
|
208
|
+
// NOTE(jeresig): We need to comment out these two labels as they appear to be
|
|
209
|
+
// invalid ES5 (they also aren't referenced anywhere so this seems safe).
|
|
210
|
+
generatedParser = generatedParser.replace(/(_token_stack:)/g, "//$1");
|
|
211
|
+
fs.writeFileSync(unitParserOutfile,
|
|
212
|
+
unitPrelude + generatedParser + unitEpilogue);
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/* Parse unit-tagged values. Examples:
|
|
2
|
+
* - 5.3x10^5 kg m / s^2
|
|
3
|
+
* - 5 mmHg
|
|
4
|
+
* - (3 * 10) (kg m) / s^2
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
%lex
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
00b5 - micro
|
|
11
|
+
212b - angstrom
|
|
12
|
+
00b0 - degree
|
|
13
|
+
2103 - degree celcius
|
|
14
|
+
2109 - degree fahrenheit
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
%%
|
|
18
|
+
"/" return 'DIV';
|
|
19
|
+
"(" return '(';
|
|
20
|
+
")" return ')';
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
The "x 10^" part of scientific notation. Accept this as one token to
|
|
24
|
+
disambiguate "x", "10", and "^", rather than parse them as confusing tokens
|
|
25
|
+
which could mean different things depending on context.
|
|
26
|
+
|
|
27
|
+
To be safe we accept the following:
|
|
28
|
+
- *
|
|
29
|
+
- x
|
|
30
|
+
- interpunct (00b7)
|
|
31
|
+
- bullet (2219)
|
|
32
|
+
- dot (22c5)
|
|
33
|
+
- multiplication sign (00d7)
|
|
34
|
+
*/
|
|
35
|
+
("*"|"x"|"\u00d7"|"\u2219"|"\u22c5"|"\u00b7")\s*"10"\s*"^" return 'POW';
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
At this point we can safely tokenize these things since they can no longer
|
|
39
|
+
appear as part of "x 10^".
|
|
40
|
+
*/
|
|
41
|
+
"^" return '^';
|
|
42
|
+
"*" return 'MUL';
|
|
43
|
+
[0-9]+"."[0-9]+ return 'FLOAT';
|
|
44
|
+
[0-9]+ return 'NAT';
|
|
45
|
+
"-" return 'NEG';
|
|
46
|
+
|
|
47
|
+
/*
|
|
48
|
+
Atom, meaning a single unit without exponent.
|
|
49
|
+
|
|
50
|
+
Symbols:
|
|
51
|
+
- 00b0 - degree sign
|
|
52
|
+
- 2103 - degree celcius
|
|
53
|
+
- 2109 - degree fahrenheit
|
|
54
|
+
- 212b - angstrom
|
|
55
|
+
- 00b5 - micro
|
|
56
|
+
*/
|
|
57
|
+
"\u00b0"(" "?)[cCfF] return 'ATOM';
|
|
58
|
+
"fl""."?" oz""."? return 'ATOM';
|
|
59
|
+
[\u00b5]?([A-Za-z-]+|[\u2103\u2109\u212b]) return 'ATOM';
|
|
60
|
+
|
|
61
|
+
\s+ /* skip whitespace */
|
|
62
|
+
<<EOF>> return 'EOF';
|
|
63
|
+
|
|
64
|
+
/lex
|
|
65
|
+
|
|
66
|
+
%start unitvalue
|
|
67
|
+
|
|
68
|
+
%%
|
|
69
|
+
|
|
70
|
+
unitvalue
|
|
71
|
+
: magnitude unit EOF
|
|
72
|
+
%{
|
|
73
|
+
return {
|
|
74
|
+
type: "unitMagnitude",
|
|
75
|
+
magnitude: $1,
|
|
76
|
+
unit: $2,
|
|
77
|
+
};
|
|
78
|
+
}%
|
|
79
|
+
| unit EOF
|
|
80
|
+
%{
|
|
81
|
+
return {
|
|
82
|
+
type: "unitStandalone",
|
|
83
|
+
unit: $1,
|
|
84
|
+
}
|
|
85
|
+
}%
|
|
86
|
+
;
|
|
87
|
+
|
|
88
|
+
magnitude
|
|
89
|
+
: float POW int
|
|
90
|
+
%{
|
|
91
|
+
$$ = $1 + "e" + $3;
|
|
92
|
+
}%
|
|
93
|
+
| float
|
|
94
|
+
{ $$ = $1; }
|
|
95
|
+
;
|
|
96
|
+
|
|
97
|
+
unit
|
|
98
|
+
: multatoms DIV multatoms
|
|
99
|
+
%{
|
|
100
|
+
$$ = {
|
|
101
|
+
num: $1,
|
|
102
|
+
denom: $3,
|
|
103
|
+
};
|
|
104
|
+
}%
|
|
105
|
+
| multatoms
|
|
106
|
+
%{
|
|
107
|
+
$$ = {
|
|
108
|
+
num: $1,
|
|
109
|
+
denom: null,
|
|
110
|
+
};
|
|
111
|
+
}%
|
|
112
|
+
;
|
|
113
|
+
|
|
114
|
+
multatoms
|
|
115
|
+
: expatom MUL multatoms
|
|
116
|
+
{ $$ = [$1].concat($3); }
|
|
117
|
+
| expatom multatoms
|
|
118
|
+
{ $$ = [$1].concat($2); }
|
|
119
|
+
| expatom
|
|
120
|
+
{ $$ = [$1]; }
|
|
121
|
+
;
|
|
122
|
+
|
|
123
|
+
expatom
|
|
124
|
+
: atom '^' nat
|
|
125
|
+
%{
|
|
126
|
+
$$ = {
|
|
127
|
+
name: $1,
|
|
128
|
+
pow: $3,
|
|
129
|
+
};
|
|
130
|
+
}%
|
|
131
|
+
| atom
|
|
132
|
+
%{
|
|
133
|
+
$$ = {
|
|
134
|
+
name: $1,
|
|
135
|
+
pow: 1,
|
|
136
|
+
};
|
|
137
|
+
}%
|
|
138
|
+
;
|
|
139
|
+
|
|
140
|
+
atom
|
|
141
|
+
: ATOM
|
|
142
|
+
{ $$ = yytext; }
|
|
143
|
+
;
|
|
144
|
+
|
|
145
|
+
float
|
|
146
|
+
: FLOAT
|
|
147
|
+
{ $$ = $1; }
|
|
148
|
+
| nat
|
|
149
|
+
{ $$ = $1; }
|
|
150
|
+
;
|
|
151
|
+
|
|
152
|
+
nat : NAT
|
|
153
|
+
{ $$ = $1; }
|
|
154
|
+
;
|
|
155
|
+
|
|
156
|
+
int
|
|
157
|
+
: NEG NAT
|
|
158
|
+
{ $$ = "-" + $2; }
|
|
159
|
+
| NAT
|
|
160
|
+
{ $$ = $1; }
|
|
161
|
+
;
|