exprforge 0.1.0 → 0.2.1

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,48 @@
1
+ // exprforge/samples/math-demo.js
2
+ // Not a worked example -- a conformance-test fixture for math/index.js,
3
+ // same role samples/kitchen-sink.js plays for the core Math intrinsics:
4
+ // exercises every exprforge/math helper in one suite, purely so
5
+ // test/conformance.test.js can prove the generated code agrees across
6
+ // every target. Calls normalize3() twice (once per input vector) in the
7
+ // same function specifically to prove its internal gensym'd let-binding
8
+ // doesn't collide with itself -- see the comment on normalizeGensymCounter
9
+ // in math/index.js.
10
+ const { v, num, outputs } = require("../ast.js");
11
+ const { safeDiv, dot3, len3, cross3, normalize3, clamp } = require("../math/index.js");
12
+
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"];
18
+
19
+ const cross = cross3(v("ax"), v("ay"), v("az"), v("bx"), v("byy"), v("bz"));
20
+ const normA = normalize3(v("ax"), v("ay"), v("az"));
21
+ const normB = normalize3(v("bx"), v("byy"), v("bz"));
22
+
23
+ const MathDemo = {
24
+ name: "MathDemo",
25
+ params: MATH_DEMO_PARAMS,
26
+ body: outputs({
27
+ dot: dot3(v("ax"), v("ay"), v("az"), v("bx"), v("byy"), v("bz")),
28
+ // "mag", not "len": LEN is a reserved QB64 builtin (string/array
29
+ // length) -- see test/conformance.test.js's normalizeXAst comment.
30
+ mag: len3(v("ax"), v("ay"), v("az")),
31
+ crossX: cross.x,
32
+ crossY: cross.y,
33
+ crossZ: cross.z,
34
+ normAX: normA.x,
35
+ normAY: normA.y,
36
+ normAZ: normA.z,
37
+ normBX: normB.x,
38
+ normBY: normB.y,
39
+ normBZ: normB.z,
40
+ clamped: clamp(v("t"), v("lo"), v("hi")),
41
+ // ax/bx as numerator/denominator: exercises both the safe path
42
+ // (bx away from zero) and the fallback (bx == 0, see
43
+ // test/conformance.test.js's math-demo input rows).
44
+ safeDivResult: safeDiv(v("ax"), v("bx"), num(-1)),
45
+ }),
46
+ };
47
+
48
+ module.exports = { mathDemoAst: MathDemo };
@@ -15,7 +15,12 @@
15
15
  // IMPORTANT for QB64: function/SUB names must be unique across the entire
16
16
  // QB64 compilation unit. The SpEf prefix (SplineExprforge) exists to avoid
17
17
  // collisions with hand-written code elsewhere in that project.
18
- const { num, v, call, add, mul, sub, div, neg, letIn, select, cmp, outputs } = require("../ast.js");
18
+ //
19
+ // mfLetChain/apLetChain/rfLetChain/SpEfCrWeights use letChain() (ast.js)
20
+ // instead of hand-nested letIn calls -- apLetChain was 14 levels deep
21
+ // before, all hand-balanced closing parens with no real hierarchy behind
22
+ // the nesting, exactly the kind of thing that's easy to miscount editing.
23
+ const { num, v, call, add, mul, sub, div, neg, letChain, select, cmp, outputs } = require("../ast.js");
19
24
 
20
25
  // ── Helpers ──────────────────────────────────────────────────────────────
21
26
  const PI = num(3.141592653589793);
@@ -66,17 +71,20 @@ const MF_PARAMS = ["tx", "ty", "tz"];
66
71
  const nearVert = cmp(call("abs", v("ty")), ">", num(0.98));
67
72
 
68
73
  function mfLetChain(body) {
69
- return letIn("wy", select(nearVert, num(0), num(1)),
70
- letIn("wz", select(nearVert, num(1), num(0)),
71
- letIn("crossX", sub(mul(v("ty"), v("wz")), mul(v("tz"), v("wy"))),
72
- letIn("crossY", neg(mul(v("tx"), v("wz"))),
73
- letIn("crossZ", mul(v("tx"), v("wy")),
74
- letIn("rLen", len3(v("crossX"), v("crossY"), v("crossZ")),
75
- letIn("rxN", safeDiv(v("crossX"), "rLen", num(0)),
76
- letIn("ryN", safeDiv(v("crossY"), "rLen", num(0)),
77
- letIn("rzN", safeDiv(v("crossZ"), "rLen", num(1)),
78
- body
79
- )))))))));
74
+ return letChain(
75
+ [
76
+ ["wy", select(nearVert, num(0), num(1))],
77
+ ["wz", select(nearVert, num(1), num(0))],
78
+ ["crossX", sub(mul(v("ty"), v("wz")), mul(v("tz"), v("wy")))],
79
+ ["crossY", neg(mul(v("tx"), v("wz")))],
80
+ ["crossZ", mul(v("tx"), v("wy"))],
81
+ ["rLen", len3(v("crossX"), v("crossY"), v("crossZ"))],
82
+ ["rxN", safeDiv(v("crossX"), "rLen", num(0))],
83
+ ["ryN", safeDiv(v("crossY"), "rLen", num(0))],
84
+ ["rzN", safeDiv(v("crossZ"), "rLen", num(1))],
85
+ ],
86
+ body,
87
+ );
80
88
  }
81
89
 
82
90
  // U = R × T (using normalized R) — a cyclic permutation, not one formula,
@@ -101,23 +109,26 @@ const SpEfMkFrame = {
101
109
  const AP_PARAMS = ["wx", "wy_wire", "wz_wire", "tx", "ty", "tz", "prDeg", "so"];
102
110
 
103
111
  function apLetChain(body) {
104
- return letIn("wy", select(nearVert, num(0), num(1)),
105
- letIn("wz", select(nearVert, num(1), num(0)),
106
- letIn("crossX", sub(mul(v("ty"), v("wz")), mul(v("tz"), v("wy"))),
107
- letIn("crossY", neg(mul(v("tx"), v("wz"))),
108
- letIn("crossZ", mul(v("tx"), v("wy")),
109
- letIn("rLen", len3(v("crossX"), v("crossY"), v("crossZ")),
110
- letIn("rxN", safeDiv(v("crossX"), "rLen", num(0)),
111
- letIn("ryN", safeDiv(v("crossY"), "rLen", num(0)),
112
- letIn("rzN", safeDiv(v("crossZ"), "rLen", num(1)),
113
- letIn("ux", sub(mul(v("ryN"), v("tz")), mul(v("rzN"), v("ty"))),
114
- letIn("uy", sub(mul(v("rzN"), v("tx")), mul(v("rxN"), v("tz"))),
115
- letIn("uz", sub(mul(v("rxN"), v("ty")), mul(v("ryN"), v("tx"))),
116
- letIn("rad", degToRad(v("prDeg")),
117
- letIn("c", call("cos", v("rad")),
118
- letIn("s", call("sin", v("rad")),
119
- body
120
- )))))))))))))));
112
+ return letChain(
113
+ [
114
+ ["wy", select(nearVert, num(0), num(1))],
115
+ ["wz", select(nearVert, num(1), num(0))],
116
+ ["crossX", sub(mul(v("ty"), v("wz")), mul(v("tz"), v("wy")))],
117
+ ["crossY", neg(mul(v("tx"), v("wz")))],
118
+ ["crossZ", mul(v("tx"), v("wy"))],
119
+ ["rLen", len3(v("crossX"), v("crossY"), v("crossZ"))],
120
+ ["rxN", safeDiv(v("crossX"), "rLen", num(0))],
121
+ ["ryN", safeDiv(v("crossY"), "rLen", num(0))],
122
+ ["rzN", safeDiv(v("crossZ"), "rLen", num(1))],
123
+ ["ux", sub(mul(v("ryN"), v("tz")), mul(v("rzN"), v("ty")))],
124
+ ["uy", sub(mul(v("rzN"), v("tx")), mul(v("rxN"), v("tz")))],
125
+ ["uz", sub(mul(v("rxN"), v("ty")), mul(v("ryN"), v("tx")))],
126
+ ["rad", degToRad(v("prDeg"))],
127
+ ["c", call("cos", v("rad"))],
128
+ ["s", call("sin", v("rad"))],
129
+ ],
130
+ body,
131
+ );
121
132
  }
122
133
 
123
134
  const SpEfActualPos = {
@@ -139,10 +150,14 @@ const SpEfActualPos = {
139
150
  const RF_PARAMS = ["ux", "uy", "uz", "rx", "ry", "rz", "crDeg"];
140
151
 
141
152
  function rfLetChain(body) {
142
- return letIn("rad", degToRad(v("crDeg")),
143
- letIn("c", call("cos", v("rad")),
144
- letIn("s", call("sin", v("rad")),
145
- body)));
153
+ return letChain(
154
+ [
155
+ ["rad", degToRad(v("crDeg"))],
156
+ ["c", call("cos", v("rad"))],
157
+ ["s", call("sin", v("rad"))],
158
+ ],
159
+ body,
160
+ );
146
161
  }
147
162
 
148
163
  const SpEfRollFrame = {
@@ -167,15 +182,18 @@ const CRW_PARAMS = ["t"];
167
182
  const SpEfCrWeights = {
168
183
  name: "SpEfCrWeights",
169
184
  params: CRW_PARAMS,
170
- body: letIn("t2", mul(v("t"), v("t")),
171
- letIn("t3", mul(v("t2"), v("t")),
172
- outputs({
173
- w0: mul(num(0.5), add(neg(v("t3")), mul(num(2), v("t2")), neg(v("t")))),
174
- w1: mul(num(0.5), add(mul(num(3), v("t3")), mul(num(-5), v("t2")), num(2))),
175
- w2: mul(num(0.5), add(mul(num(-3), v("t3")), mul(num(4), v("t2")), v("t"))),
176
- w3: mul(num(0.5), add(v("t3"), neg(v("t2")))),
177
- })
178
- )),
185
+ body: letChain(
186
+ [
187
+ ["t2", mul(v("t"), v("t"))],
188
+ ["t3", mul(v("t2"), v("t"))],
189
+ ],
190
+ outputs({
191
+ w0: mul(num(0.5), add(neg(v("t3")), mul(num(2), v("t2")), neg(v("t")))),
192
+ w1: mul(num(0.5), add(mul(num(3), v("t3")), mul(num(-5), v("t2")), num(2))),
193
+ w2: mul(num(0.5), add(mul(num(-3), v("t3")), mul(num(4), v("t2")), v("t"))),
194
+ w3: mul(num(0.5), add(v("t3"), neg(v("t2")))),
195
+ }),
196
+ ),
179
197
  };
180
198
 
181
199
  // ── Exports ──────────────────────────────────────────────────────────────