Emmy as JavaScript library (6)
(This post is part of a series, all with the same title) (and needs lots more text to actually explain things)
<script src="https://kloimhardt.github.io/blog/js/emmy.js/build/emmy_bundle.js"></script>
<script> var loadEnv = (name) => { window[name] = emmy[name]; return name; } </script>
Refactor symbol and 1/2 into specialchars. Move JSON.parse from textToJson to expressionToJs. Move the "blank" out of code into newEval
var symbol = emmy.symbol;
var specialchars =
[["symbol_$1", /\'(\w+)/g],
["[ / $1 $2 ],", /(\d+)\/(\d+)/g]];
var mathfns =
[["div", /\//g],
["mul", /\*/g],
["sub", /\-/g],
["add", /\+/g],
["expt", /\^/g]]
mathfns.map(x=> x[0]).map(loadEnv);
var replaceMath = (txt) =>
specialchars.concat(mathfns)
.reduce((s,r) => s.replace(r[1],r[0]), txt);
var swapFirst = (j) =>
j.constructor == Array && mathfns.map(x=> x[0]).includes(j[1])
? [j[1], j[0]].concat(j.slice(2)).map(swapFirst)
: j.constructor == Array
? j.map(swapFirst)
: j;
var insertCommas = (txt) =>
txt.replace(/(\w+)/g,'"$1",')
.replace(/\,\s+\]/g," ]");
var makeBrackets = (txt) =>
txt.trim()
.replace(/\(/g,"[ ")
.replace(/\)/g," ],")
.replace(/,$/,"");
var textToJson = (txt) =>
insertCommas(replaceMath(makeBrackets(txt)));
var drv = emmy.D;
var replaceD = (j) =>
j.constructor == Array
? j.map(replaceD)
: j == "D" ? "drv" : j;
["to_infix", "simplify"].map(loadEnv);
var preAmble = (j) =>
j[0] != "define"
? ["to_infix", ["simplify", j]]
: j;
var modifyJson = (j) => preAmble(replaceD(swapFirst(j)));
var makeFun = (j, callBack) =>
"var " + j[1][0] + " = (" + j[1].slice(1) + ") => "
+ callBack(j[2]) +";";
var makeFunFun = (j, callBack) =>
"var " + j[1][0][0] + " = (" + j[1][0].slice(1) + ") => "
+ "(" + j[1].slice(1) +") => " + callBack(j[2]) + ";";
var smap = (f, v) =>
v.length === 1
? f(v[0]) +";"
: f(v[0]) +"; " + smap(f, v.slice(1));
var makeLet = (j, callBack) =>
"{" + smap((l) => "let " + l[0] + " = " + callBack(l[1]), j[1])
+ " return " + callBack(j[2]) + "; }"
var jsonToJs = (j) =>
j.constructor == Array && j[0] === "let"
? makeLet(j, jsonToJs)
:j.constructor == Array && j[0] === "define"
&& j[1].constructor == Array
&& j[1][0].constructor == Array
? makeFunFun(j, jsonToJs)
:j.constructor == Array && j[0] === "define"
&& j[1].constructor == Array
? makeFun(j, jsonToJs)
:j.constructor == Array && j[0] === "define"
&& j[1].constructor == String
? "var " + j[1] + " = " + jsonToJs(j[2]) + ";"
:j.constructor == String && j.substring(0, 7) == "symbol_"
? 'symbol("' + j.substring(7, j.length) + '")'
:j.constructor == Array
? jsonToJs(j[0]) + "(" + j.slice(1).map(jsonToJs) + ")"
: j;
var expressionToJs = (expr) =>
jsonToJs(modifyJson(JSON.parse(textToJson(expr))));
var literal_function = emmy.literal_function;
["sin", "cos", "velocity", "dot_product",
"up", "Gamma", "compose"].map(loadEnv); null;
<script> var oldEval = window.eval; var newEval = (txt) => txt.substr(0, 2) === ";(" ? expressionToJs(txt.substr(1)) : txt[0] === "(" && txt[txt.length - 1] != " " ? textToJson(txt) : txt[0] === "(" ? oldEval(expressionToJs(txt)) : txt[txt.length - 1] != ";" ? "Add ; to JS: " + txt : oldEval(txt); window.eval = newEval; </script>
What we have up to now
((1 / 2) / 2)
(3 * (1 / 2))
(1 + (((2 / 3) - 4) * 5))
(2 ^ 3)
(1 + (cos 0))
(+ 1 (cos 0))
((sin ^ 2) (314 / 100))
((cos (sin 0)) + (((2 / 3) - 4) * (5 ^ 2)))
(+ (cos (sin 0)) (* (- (/ 2 3) 4) (expt 5 2)))
(3 * (cos 0))
((3 * cos) 0)
(cos 'x)
((3 * (sin ^ 2)) 'x)
((D (3 * (sin ^ 2))) 'x)
(define value 6)
(1 + value)
(define (funame x) (x + 1))
(funame 4)
(define ((ffuname x) y) (x + y))
((ffuname 4) 5)
(define (fulet x) (let ((y 1)) (+ x y)))
(fulet 4)
(1 + 1/2)
Implementation of new functionality
Make floating point and negative numbers possible.
;(define (f-1-2 x) x)
var _specialchars =
[["", /\:/g],
["symbol_$1", /\'(\w+)/g],
["$1_dot_$2", /(\d+)\.(\d+)/g],
[" minus_$2", /(\s+)\-(\w+)/g],
["$1_", /(\w+)\-/g],
["[ / $1 $2 ],", /(\w+)\/(\d+)/g]];
var specialchars = _specialchars;
var post_specialchars =
[["$1.$2", /(\d+)_dot_(\d+)/],
["-$1", /minus_(\w+)/]]
var _replaceD = replaceD;
var replaceD = (j) =>
j.constructor == String && j == "D"
? "drv"
: j.constructor == String
? post_specialchars.reduce((s,r) => s.replace(r[1],r[0]), j)
: _replaceD(j);
;(define (f-1-2 x) x)
(-1.7 + 2.9)
loadEnv("pi");
(* -:pi/2)
var identity = x => x;
var edgeCases = (j) =>
j[0] === "define"
&& j[2].constructor == Array && j[2][0] === "let"
&& j[1].constructor == String
? ["identity", "'let not allowed in variable definition'"]
: j;
var letFlat2 = (j) =>
j[0] === "let"
? j[1].concat(letFlat2(j[2]))
: [j];
var constructLet = (j) =>
["let", j.slice(0, j.length - 1), j[j.length - 1]]
var letFlat = (j) =>
j.constructor == Array && j[0] === "let"
? constructLet(letFlat2(j))
: j.constructor == Array
? j.map(letFlat)
: j;
var _modifyJson = modifyJson
var modifyJson = (j) => _modifyJson(letFlat(edgeCases(j)));
(identity 1/2)
(define (fu z) (let ((x 1)) (let ((y 2)) (+ x y z))))
(fu 7)
(define value1 (let ...)) is excluded explicitely.
(define value1 (let ((x 1)) (+ x 1)))
var __specialchars =
[["__gt_", /->/g]].concat(specialchars);
var specialchars = __specialchars;
(define F->G 3)
(identity F->G)
loadEnv("nth");
var time = x => nth(x, 0);
(time (up 't (up 'r 'phi) (up 'rdot 'phidot)))
var jsonCode = textToJson("(lambda (x y) (+ x y))");
var makeLambda = (j, callBack) =>
"(" + j[1] + ") => " + callBack(j[2]) +";";
makeLambda(jsonCode, e => "<" + e + ">");
var _jsonToJs = jsonToJs;
var jsonToJs = (j) =>
j.constructor == Array && j[0] === "lambda"
? makeLambda(j, jsonToJs)
: _jsonToJs(j);
(define funame (lambda (x y) (+ x y)))
(funame 1 2)
(define (fu x)
(let ((ffu (lambda (y)
(let ((r 1))
(+ y x r)))))
ffu))
((fu 3) 4)
var _post_specialchars =
[["symbol_$1^$2", /symbol_(\w+)expt(\w+)/],
["$1e-$2", /(\d+)e_(\d+)/]].concat(post_specialchars);
var post_specialchars = _post_specialchars;
('v_r^x ^ 4)
(3 * 1.0e-11)
Take a look at all 109 examples of the SICMechanics book part one
The compiler now is in a state to run all 109 examples of the first part of the SICMechanics book.