exprforge 0.2.0 → 0.3.0
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/README.md +288 -21
- package/emitters/cobol.js +478 -0
- package/emitters/exprsyntax.js +81 -0
- package/emitters/fortran.js +169 -0
- package/emitters/julia.js +67 -0
- package/emitters/perl.js +95 -0
- package/emitters/php.js +79 -0
- package/emitters/registry.js +8 -0
- package/emitters/scheme.js +154 -0
- package/emitters/zig.js +126 -0
- package/evaluate.js +109 -0
- package/expr.js +313 -0
- package/fn.js +117 -0
- package/index.js +14 -2
- package/math/index.js +9 -1
- package/package.json +5 -2
- package/samples/math-demo.js +8 -4
package/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// exprforge/index.js
|
|
2
2
|
const { num, v, bin, call, add, mul, sub, div, neg, letIn, letChain, cmp, select, outputs, collectLets } = require("./ast.js");
|
|
3
3
|
const { forComponents } = require("./util.js");
|
|
4
|
+
const { expr } = require("./expr.js");
|
|
5
|
+
const { fn } = require("./fn.js");
|
|
6
|
+
const { evaluate } = require("./evaluate.js");
|
|
4
7
|
const emitters = require("./emitters/registry.js");
|
|
5
8
|
const { catmullRomAst } = require("./samples/catmull-rom.js");
|
|
6
9
|
const { fibonacciAst } = require("./samples/fibonacci.js");
|
|
@@ -12,10 +15,10 @@ const { mathDemoAst } = require("./samples/math-demo.js");
|
|
|
12
15
|
* Run every registered emitter against one AST function definition.
|
|
13
16
|
* Returns { [lang]: { ext, source } }.
|
|
14
17
|
*/
|
|
15
|
-
function emitAll(
|
|
18
|
+
function emitAll(fnDef) {
|
|
16
19
|
const result = {};
|
|
17
20
|
for (const [lang, emitter] of Object.entries(emitters)) {
|
|
18
|
-
result[lang] = { ext: emitter.ext, source: emitter.emitFunction(
|
|
21
|
+
result[lang] = { ext: emitter.ext, source: emitter.emitFunction(fnDef) };
|
|
19
22
|
}
|
|
20
23
|
return result;
|
|
21
24
|
}
|
|
@@ -25,6 +28,15 @@ module.exports = {
|
|
|
25
28
|
num, v, bin, call, add, mul, sub, div, neg, letIn, letChain, cmp, select, outputs, collectLets,
|
|
26
29
|
// Authoring convenience — not an AST primitive, see util.js.
|
|
27
30
|
forComponents,
|
|
31
|
+
// Infix syntax sugar over the builders above — same Nodes, see expr.js.
|
|
32
|
+
expr,
|
|
33
|
+
// Full function-body syntax (let/return) on top of expr's grammar —
|
|
34
|
+
// see fn.js. "fn's contain expr's": every expression inside a fn`...`
|
|
35
|
+
// template is parsed by the exact same engine expr() uses.
|
|
36
|
+
fn,
|
|
37
|
+
// A native interpreter over the AST -- evaluate(fn, args) computes a
|
|
38
|
+
// result directly in JS, no codegen/compile step. See evaluate.js.
|
|
39
|
+
evaluate,
|
|
28
40
|
// Built-in example formulas — see samples/ for the source.
|
|
29
41
|
catmullRomAst,
|
|
30
42
|
fibonacciAst,
|
package/math/index.js
CHANGED
|
@@ -67,6 +67,14 @@ function cross3(ax, ay, az, bx, by, bz) {
|
|
|
67
67
|
// with another normalize3() binding inside the same function body, and a
|
|
68
68
|
// process-wide counter trivially guarantees that regardless of how many
|
|
69
69
|
// times normalize3 is called across however many functions.
|
|
70
|
+
//
|
|
71
|
+
// The name itself starts with a letter, not "__" -- confirmed against a
|
|
72
|
+
// real Fortran compiler ("Invalid character in name") that a leading
|
|
73
|
+
// underscore isn't a valid identifier start there, unlike JS/Python/etc.
|
|
74
|
+
// This is an internal implementation detail (never part of any documented
|
|
75
|
+
// return value or public name), so there's nothing for a leading-"__"
|
|
76
|
+
// convention to usefully signal here that a portable identifier can't
|
|
77
|
+
// signal just as well.
|
|
70
78
|
let normalizeGensymCounter = 0;
|
|
71
79
|
|
|
72
80
|
// Safe-normalize a 3-D vector. Returns { x, y, z } (same shape as cross3).
|
|
@@ -85,7 +93,7 @@ let normalizeGensymCounter = 0;
|
|
|
85
93
|
// name avoids a "duplicate let binding name" throw if normalize3 is called
|
|
86
94
|
// more than once inside one function (e.g. normalizing two vectors).
|
|
87
95
|
function normalize3(x, y, z, fx = num(0), fy = num(1), fz = num(0)) {
|
|
88
|
-
const lenName = `
|
|
96
|
+
const lenName = `efMathNrmLen${normalizeGensymCounter++}`;
|
|
89
97
|
return {
|
|
90
98
|
x: letIn(lenName, len3(x, y, z), safeDiv(x, v(lenName), fx)),
|
|
91
99
|
y: safeDiv(y, v(lenName), fy),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exprforge",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Author a math expression once as an AST, emit identical-behavior implementations in JS, TypeScript, Python, C#, Lua, QB64, C, Java, Go, and
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Author a math expression once as an AST (or readable infix text via expr/fn), emit identical-behavior implementations in JS, TypeScript, Python, C#, Lua, QB64, C, Java, Go, Rust, Perl, PHP, Julia, Fortran, Zig, Scheme, and COBOL, plus a native evaluator and its own readable syntax printer.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"exports": {
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"index.js",
|
|
14
14
|
"ast.js",
|
|
15
15
|
"util.js",
|
|
16
|
+
"expr.js",
|
|
17
|
+
"fn.js",
|
|
18
|
+
"evaluate.js",
|
|
16
19
|
"build.js",
|
|
17
20
|
"emitters/",
|
|
18
21
|
"samples/",
|
package/samples/math-demo.js
CHANGED
|
@@ -10,17 +10,21 @@
|
|
|
10
10
|
const { v, num, outputs } = require("../ast.js");
|
|
11
11
|
const { safeDiv, dot3, len3, cross3, normalize3, clamp } = require("../math/index.js");
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
// "byy", not "by": BY is a reserved COBOL keyword (BY REFERENCE/BY VALUE/
|
|
14
|
+
// BY CONTENT) -- confirmed against a real compiler ("syntax error,
|
|
15
|
+
// unexpected BY") that it can't be used as a data-item name there, same
|
|
16
|
+
// kind of unavoidable per-language collision as "len"/"mag" below.
|
|
17
|
+
const MATH_DEMO_PARAMS = ["ax", "ay", "az", "bx", "byy", "bz", "t", "lo", "hi"];
|
|
14
18
|
|
|
15
|
-
const cross = cross3(v("ax"), v("ay"), v("az"), v("bx"), v("
|
|
19
|
+
const cross = cross3(v("ax"), v("ay"), v("az"), v("bx"), v("byy"), v("bz"));
|
|
16
20
|
const normA = normalize3(v("ax"), v("ay"), v("az"));
|
|
17
|
-
const normB = normalize3(v("bx"), v("
|
|
21
|
+
const normB = normalize3(v("bx"), v("byy"), v("bz"));
|
|
18
22
|
|
|
19
23
|
const MathDemo = {
|
|
20
24
|
name: "MathDemo",
|
|
21
25
|
params: MATH_DEMO_PARAMS,
|
|
22
26
|
body: outputs({
|
|
23
|
-
dot: dot3(v("ax"), v("ay"), v("az"), v("bx"), v("
|
|
27
|
+
dot: dot3(v("ax"), v("ay"), v("az"), v("bx"), v("byy"), v("bz")),
|
|
24
28
|
// "mag", not "len": LEN is a reserved QB64 builtin (string/array
|
|
25
29
|
// length) -- see test/conformance.test.js's normalizeXAst comment.
|
|
26
30
|
mag: len3(v("ax"), v("ay"), v("az")),
|