@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.
@@ -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
+ ;