Commit 1a36a16
authored
Conformance fixes and performance optimizations (#13)
* Fix signature validation for variadic, optional-skip, context, and u-type
Addresses four conformance gaps in function signature validation
against the JSONata spec:
- Variadic overflow: cap consumption to leave room for mandatory
params that follow, preventing spurious T0410 "too few arguments"
errors when a trailing fixed param is present after a variadic.
- Optional-skip: when an optional param's type doesn't match, skip
the spec and retry the same arg against the next spec instead of
raising T0410.
- '-' (context) modifier: inject the current focus value when the
argument is absent. Adds Context field to ParamSpec and threads
focus through processCallArgs / validateCallArgs.
- 'u' type specifier (union of primitives: bool, number, string,
null). Recognised by both the parser and evaluator.
Adds test cases 035-040 covering each scenario end-to-end.
* Return T0410 from $split on non-string input
$split previously returned nil (undefined) for non-string arguments,
which matched the jsonata-js reference implementation but diverged
from the JSONata spec, which prescribes a T0410 type error.
Align with the spec by returning T0410 for non-string args, and
update case016/case017 to expect the error code instead of an
undefined result.
* Sort raw map keys for deterministic iteration
When a Go native map[string]any enters the evaluator (via DecodeRawMap
or MapKeys/MapRange in paths that walk raw maps), iteration order was
Go-randomised, which leaked into ordering-sensitive operations like
$keys, $lookup fallbacks, and aggregate results.
Sort keys alphabetically using slices.Sorted(maps.Keys(m)) before
iteration so identical inputs produce identical outputs across runs.
* Pre-parse function signatures at registration
Signature strings were re-parsed on every SignedBuiltin / Lambda call
via parser.ParseSig, which is pure overhead since the string never
changes after the function is defined.
Parse once and cache:
- Add ParsedSig []parser.ParamSpec to SignedBuiltin and Lambda.
- Introduce a newSignedBuiltin helper in functions/register.go that
parses at construction time; use it for signature-carrying
registrations.
- Populate Lambda.ParsedSig once in evalLambda when the signature is
compiled from the AST.
- Replace the per-call parser.ParseSig() lookups in evalFunction and
callFunction with direct reads of the cached ParsedSig slice.
Hot-path-only change; no behavioural difference.
* Optimize eval hot paths: float arith, DeepEqual, HOF buffers
Five targeted hot-path optimisations in the evaluator and function
dispatch layer:
- Arithmetic fast-path (eval_binary.go): when both operands are
already float64, bypass the generic numeric-coercion path and go
straight to evalArithFloat64. This is the common case for numeric
expressions after AST evaluation.
- DeepEqual primitive fast-path (value.go): for same-type float64 /
string / bool comparisons, skip normalizeNumber and compare
directly. Drops a per-call allocation that showed up in profiles
on equality-heavy expressions.
- Sequence collapse (value.go): use slices.Clip in CollapseSequence
and CollapseToSlice instead of slices.Clone. Since the sequence is
being discarded, we can transfer ownership of the backing array
rather than allocating a copy.
- HOF argument buffers (hof_funcs.go, object_funcs.go): replace the
per-iteration hofArgs slice with reusable hofArity / hofArgsBuf /
fillHofArgs helpers applied to $map, $filter, $single, $reduce,
$sift, and $each. Same arity detection, zero per-iteration
allocation.
- Sort comparator args (array_funcs.go): pre-allocate the 2-element
sortArgs slice once per $sort call instead of rebuilding it on
each comparator invocation.
No behavioural changes; all existing tests pass.
* Add EvalMap, EvalBytesWithVars; expose via WASM; fix gjson docs
Extends the public Expression API and the WASM bridge with two
evaluation paths that were previously only reachable from the
StreamEvaluator or the byte-level API, and cleans up the docs to
match how gjson is actually used.
Expression API (gnata.go):
- EvalMap(ctx, data map[string]json.RawMessage): O(1) top-level key
lookup via DecodeRawMap, with gjson fast paths for nested access
inside each RawMessage. Useful when the caller already has the
JSON decoded into a map and wants to avoid re-serialising.
- EvalBytesWithVars(ctx, data json.RawMessage, vars map[string]any):
evaluate raw JSON bytes with external $-variable bindings, while
keeping the gjson fast-path eligible.
WASM bridge (wasm/main.go, playground.html):
- Export two new JS functions, gnataEvalMap and gnataEvalWithVars,
mirroring the new Expression methods. gnataEvalMap takes a JS
object and feeds its top-level keys as json.RawMessage values;
gnataEvalWithVars takes a vars JSON blob for $-bindings.
- Route gnataEval and gnataEvalHandle through EvalBytes so they
also benefit from the gjson fast path.
- Add JS wrappers in playground.html so the new exports are usable
from the browser playground.
Documentation (README.md, AGENTS.md):
- Fix the StreamEvaluator description: the hot path uses
gjson.GetBytes per fast-path expression, not a single
gjson.GetManyBytes call for the whole event.
- Update the public-API list in README to include EvalMap and
EvalBytesWithVars, and expand the WASM section with a table of
all six exported JS functions.1 parent db5bf98 commit 1a36a16
25 files changed
Lines changed: 440 additions & 150 deletions
File tree
- functions
- internal
- evaluator
- parser
- testdata/groups
- function-signatures
- function-split
- wasm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
| 100 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
148 | 148 | | |
149 | 149 | | |
150 | 150 | | |
151 | | - | |
| 151 | + | |
152 | 152 | | |
153 | 153 | | |
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
159 | | - | |
| 159 | + | |
160 | 160 | | |
161 | 161 | | |
162 | 162 | | |
| |||
421 | 421 | | |
422 | 422 | | |
423 | 423 | | |
424 | | - | |
| 424 | + | |
425 | 425 | | |
426 | 426 | | |
427 | 427 | | |
| |||
485 | 485 | | |
486 | 486 | | |
487 | 487 | | |
488 | | - | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
489 | 500 | | |
490 | 501 | | |
491 | 502 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
| 132 | + | |
132 | 133 | | |
133 | | - | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
134 | 137 | | |
135 | 138 | | |
136 | 139 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
17 | 16 | | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
27 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
28 | 47 | | |
29 | | - | |
30 | | - | |
31 | 48 | | |
32 | 49 | | |
33 | 50 | | |
| |||
56 | 73 | | |
57 | 74 | | |
58 | 75 | | |
| 76 | + | |
59 | 77 | | |
60 | | - | |
| 78 | + | |
61 | 79 | | |
62 | 80 | | |
63 | 81 | | |
| |||
94 | 112 | | |
95 | 113 | | |
96 | 114 | | |
| 115 | + | |
97 | 116 | | |
98 | | - | |
| 117 | + | |
99 | 118 | | |
100 | 119 | | |
101 | 120 | | |
| |||
151 | 170 | | |
152 | 171 | | |
153 | 172 | | |
| 173 | + | |
154 | 174 | | |
155 | | - | |
| 175 | + | |
156 | 176 | | |
157 | 177 | | |
158 | 178 | | |
| |||
218 | 238 | | |
219 | 239 | | |
220 | 240 | | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
221 | 248 | | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
236 | 258 | | |
237 | 259 | | |
238 | 260 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
158 | 158 | | |
159 | 159 | | |
160 | 160 | | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
173 | 173 | | |
174 | | - | |
175 | 174 | | |
176 | 175 | | |
177 | 176 | | |
| |||
199 | 198 | | |
200 | 199 | | |
201 | 200 | | |
| 201 | + | |
202 | 202 | | |
203 | 203 | | |
204 | | - | |
| 204 | + | |
205 | 205 | | |
206 | 206 | | |
207 | 207 | | |
| |||
242 | 242 | | |
243 | 243 | | |
244 | 244 | | |
| 245 | + | |
245 | 246 | | |
246 | 247 | | |
247 | | - | |
| 248 | + | |
| 249 | + | |
248 | 250 | | |
249 | 251 | | |
250 | 252 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
5 | 8 | | |
6 | 9 | | |
7 | 10 | | |
| |||
77 | 80 | | |
78 | 81 | | |
79 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
80 | 88 | | |
81 | 89 | | |
82 | 90 | | |
83 | 91 | | |
84 | 92 | | |
85 | 93 | | |
86 | | - | |
87 | | - | |
| 94 | + | |
| 95 | + | |
88 | 96 | | |
89 | 97 | | |
90 | 98 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
424 | 424 | | |
425 | 425 | | |
426 | 426 | | |
427 | | - | |
| 427 | + | |
428 | 428 | | |
429 | 429 | | |
430 | 430 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
223 | 223 | | |
224 | 224 | | |
225 | 225 | | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
226 | 282 | | |
227 | 283 | | |
228 | 284 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
178 | 178 | | |
179 | 179 | | |
180 | 180 | | |
181 | | - | |
182 | | - | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
183 | 184 | | |
184 | 185 | | |
185 | 186 | | |
186 | 187 | | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
193 | 195 | | |
0 commit comments