kas-npm
Version:
A lightweight JavaScript CAS for comparing expressions and equations. Forked from @Khan to use in NPM.
223 lines (214 loc) • 10.9 kB
JavaScript
#!/usr/bin/env node
/* TODO(charlie): fix these lint errors (http://eslint.org/docs/rules): */
/* eslint-disable no-var, comma-dangle, max-len, comma-spacing */
var fs = require("fs");
var path = require("path");
var jison = require("jison");
var grammar = {
lex: {
rules: [
["\\s+", "/* skip whitespace */"],
["\\\\space", "/* skip \\space */"],
["\\\\ ", "/* skip '\\ ' */"],
["[0-9]+\\.?", "return \"INT\""],
["([0-9]+)?\\.[0-9]+", "return \"FLOAT\""],
["\\*\\*", "return \"^\""],
["\\*", "return \"*\""],
["\\\\cdot|\u00b7", "return \"*\""],
["\\\\times|\u00d7", "return \"*\""],
["\\\\ast", "return \"*\""],
["\\/", "return \"/\""],
["\\\\div|\u00F7", "return \"/\""],
["-", "return \"-\""],
["\u2212", "return \"-\""], // minus
["\\+", "return \"+\""],
["\\^", "return \"^\""],
["\\(", "return \"(\""],
["\\)", "return \")\""],
["\\\\left\\(", "return \"(\""],
["\\\\right\\)", "return \")\""],
["\\[", "return \"[\""],
["\\]", "return \"]\""],
["\\{", "return \"{\""],
["\\}", "return \"}\""],
["\\\\left\\{", "return \"{\""],
["\\\\right\\}", "return \"}\""],
["_", "return \"_\""],
["\\|", "return \"|\""],
["\\\\left\\|", "return \"LEFT|\""],
["\\\\right\\|", "return \"RIGHT|\""],
["\\!", "return \"!\""], // not yet interpreted
["<=|>=|<>|<|>|=", "return \"SIGN\""],
["\\\\le", "yytext = \"<=\"; return \"SIGN\""],
["\\\\ge", "yytext = \">=\"; return \"SIGN\""],
["\\\\leq", "yytext = \"<=\"; return \"SIGN\""],
["\\\\geq", "yytext = \">=\"; return \"SIGN\""],
["=\\/=", "yytext = \"<>\"; return \"SIGN\""],
["\\\\ne", "yytext = \"<>\"; return \"SIGN\""],
["\\\\neq", "yytext = \"<>\"; return \"SIGN\""],
["\u2260", "yytext = \"<>\"; return \"SIGN\""], // ne
["\u2264", "yytext = \"<=\"; return \"SIGN\""], // le
["\u2265", "yytext = \">=\"; return \"SIGN\""], // ge
["\\\\frac", "return \"FRAC\""],
["\\\\dfrac", "return \"FRAC\""],
["sqrt|\\\\sqrt", "return \"sqrt\""],
["abs|\\\\abs", "return \"abs\""],
["ln|\\\\ln", "return \"ln\""],
["log|\\\\log", "return \"log\""],
["sin|cos|tan", "return \"TRIG\""],
["csc|sec|cot", "return \"TRIG\""],
["sinh|cosh|tanh", "return \"TRIG\""],
["csch|sech|coth", "return \"TRIG\""],
["\\\\sin", "yytext = \"sin\"; return \"TRIG\""],
["\\\\cos", "yytext = \"cos\"; return \"TRIG\""],
["\\\\tan", "yytext = \"tan\"; return \"TRIG\""],
["\\\\csc", "yytext = \"csc\"; return \"TRIG\""],
["\\\\sec", "yytext = \"sec\"; return \"TRIG\""],
["\\\\cot", "yytext = \"cot\"; return \"TRIG\""],
["\\\\arcsin", "yytext = \"arcsin\"; return \"TRIG\""],
["\\\\arccos", "yytext = \"arccos\"; return \"TRIG\""],
["\\\\arctan", "yytext = \"arctan\"; return \"TRIG\""],
["\\\\arccsc", "yytext = \"arccsc\"; return \"TRIG\""],
["\\\\arcsec", "yytext = \"arcsec\"; return \"TRIG\""],
["\\\\arccot", "yytext = \"arccot\"; return \"TRIG\""],
["arcsin|arccos|arctan","return \"TRIGINV\""],
["arccsc|arcsec|arccot","return \"TRIGINV\""],
["\\\\sinh", "yytext = \"sinh\"; return \"TRIG\""],
["\\\\cosh", "yytext = \"cosh\"; return \"TRIG\""],
["\\\\tanh", "yytext = \"tanh\"; return \"TRIG\""],
["\\\\csch", "yytext = \"csch\"; return \"TRIG\""],
["\\\\sech", "yytext = \"sech\"; return \"TRIG\""],
["\\\\coth", "yytext = \"tanh\"; return \"TRIG\""],
["pi", "return \"CONST\""],
["\u03C0", "yytext = \"pi\"; return \"CONST\""], // pi
["\\\\pi", "yytext = \"pi\"; return \"CONST\""],
["theta", "return \"VAR\""],
["\u03B8", "yytext = \"theta\"; return \"VAR\""], // theta
["\\\\theta", "yytext = \"theta\"; return \"VAR\""],
["phi", "return \"VAR\""],
["\u03C6", "yytext = \"phi\"; return \"VAR\""], // phi
["\\\\phi", "yytext = \"phi\"; return \"VAR\""],
["[a-zA-Z]", "return yy.symbolLexer(yytext)"],
["$", "return \"EOF\""],
[".", "return \"INVALID\""]
],
options: {
flex: true // pick longest matching token
}
},
operators: [
["right", "|"],
["left", "+", "-"],
["left", "*", "/"],
["left", "UMINUS"],
["right", "^"]
],
start: "equation",
bnf: {
"equation": [
["expression SIGN expression EOF", "return new yy.Eq($1, $2, $3);"],
["expression EOF", "return $1;"],
["EOF", "return new yy.Add([]);"]
],
"expression": [
["additive", "$$ = $1;"]
],
"additive": [
["additive + multiplicative", "$$ = yy.Add.createOrAppend($1, $3);"],
["additive - multiplicative", "$$ = yy.Add.createOrAppend($1, yy.Mul.handleNegative($3, \"subtract\"));"],
["multiplicative", "$$ = $1;", {prec: "+"}]
],
"multiplicative": [
// the second term in an implicit multiplication cannot be negative
["multiplicative triglog", "$$ = yy.Mul.fold(yy.Mul.createOrAppend($1, $2));"],
["multiplicative * negative", "$$ = yy.Mul.fold(yy.Mul.createOrAppend($1, $3));"],
["multiplicative / negative", "$$ = yy.Mul.fold(yy.Mul.handleDivide($1, $3));"],
["negative", "$$ = $1;"]
],
"negative": [
["- negative", "$$ = yy.Mul.handleNegative($2);", {prec: "UMINUS"}],
["triglog", "$$ = $1;"]
],
"trig": [
["TRIG", "$$ = [yytext];"]
],
"trigfunc": [
["trig", "$$ = $1;"],
["trig ^ negative", "$$ = $1.concat($3);"],
["TRIGINV", "$$ = [yytext];"]
],
"logbase": [
["ln", "$$ = yy.Log.natural();"],
["log", "$$ = yy.Log.common();"],
["log _ subscriptable", "$$ = $3;"]
],
"triglog": [
["trigfunc negative", "$$ = yy.Trig.create($1, $2);"],
["logbase negative", "$$ = yy.Log.create($1, $2);"],
["power", "$$ = $1;"]
],
"power": [
["primitive ^ negative", "$$ = new yy.Pow($1, $3);"],
["primitive", "$$ = $1;"]
],
"variable": [
["VAR", "$$ = yytext;"]
],
"subscriptable": [
["variable _ subscriptable", "$$ = new yy.Var($1, $3);"],
["variable", "$$ = new yy.Var($1);"],
["CONST", "$$ = new yy.Const(yytext.toLowerCase());"],
["INT", "$$ = yy.Int.create(Number(yytext));"],
["FLOAT", "$$ = yy.Float.create(Number(yytext));"],
["{ additive }", "$$ = $2.completeParse();"],
["( additive )", "$$ = $2.completeParse().addHint('parens');"] // this probably shouldn't be a hint...
],
"function": [
["FUNC", "$$ = yytext;"]
],
"invocation": [
["sqrt ( additive )", "$$ = yy.Pow.sqrt($3);"],
["sqrt { additive }", "$$ = yy.Pow.sqrt($3);"],
["sqrt [ additive ] { additive }", "$$ = new yy.Pow.nthroot($6, $3);"],
["abs ( additive )", "$$ = new yy.Abs($3);"],
["| additive |", "$$ = new yy.Abs($2);"],
["LEFT| additive RIGHT|", "$$ = new yy.Abs($2);"],
["function ( additive )", "$$ = new yy.Func($1, $3);"]
],
"primitive": [
["subscriptable", "$$ = $1;"],
["invocation", "$$ = $1;"],
["FRAC { additive } { additive }", "$$ = yy.Mul.handleDivide($3, $6);"]
]
}
};
var prelude = "// This is a @gene" + "rated file\n" +
"var _, KAS = {};\n\n" +
"if (typeof module === \"object\" && module.exports) {\n" +
" _ = require(\"underscore\");\n" +
" module.exports = KAS;\n" +
"} else {\n" +
" _ = window._;\n" +
" window.KAS = KAS;\n" +
"}\n\n" +
"(function(KAS) {\n\n";
var parser = (new jison.Generator(grammar)).generate({moduleType: "js"});
// NOTE(jeresig): We need to comment out these two labels as they appear to be
// invalid ES5 (they also aren't referenced anywhere so this seems safe).
parser = parser.replace(/(_token_stack:)/g, "//$1");
var postlude = "\n\nKAS.parser = parser;\n})(KAS);";
fs.writeFileSync(path.resolve(__dirname, "parser.js"), prelude + parser + postlude);
var unitPrelude = "// this is a @gene" + "rated file\n" +
"(function(KAS) {\n\n";
var unitEpilogue = "\n\nKAS.unitParser = parser;\n" +
"})(KAS);";
var unitParserInfile = path.resolve(__dirname, "unitvalue.jison");
var unitParserOutfile = path.resolve(__dirname, "unitparser.js");
var unitParserSource = fs.readFileSync(unitParserInfile);
var unitParser = new jison.Generator(unitParserSource.toString());
var generatedParser = unitParser.generate({ moduleType: "js" });
// NOTE(jeresig): We need to comment out these two labels as they appear to be
// invalid ES5 (they also aren't referenced anywhere so this seems safe).
generatedParser = generatedParser.replace(/(_token_stack:)/g, "//$1");
fs.writeFileSync(unitParserOutfile,
unitPrelude + generatedParser + unitEpilogue);