@tabnas/expr 0.5.17 → 0.5.18
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/dist/expr.d.ts +1 -1
- package/dist/expr.js +1 -1
- package/dist/translate.js +237 -38
- package/dist/translate.js.map +1 -1
- package/package.json +1 -1
- package/src/expr.ts +1 -1
- package/src/translate.ts +237 -38
package/dist/expr.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ declare const testing: {
|
|
|
62
62
|
prattify: typeof prattify;
|
|
63
63
|
opify: (x: any) => any;
|
|
64
64
|
};
|
|
65
|
-
declare const VERSION = "0.5.
|
|
65
|
+
declare const VERSION = "0.5.18";
|
|
66
66
|
export { VERSION, Expr, evaluation, simplify, parseSimplified, testing };
|
|
67
67
|
export type { ExprOptions, OpDef, Op, Evaluate };
|
|
68
68
|
export { translate } from './translate';
|
package/dist/expr.js
CHANGED
|
@@ -1420,7 +1420,7 @@ exports.testing = testing;
|
|
|
1420
1420
|
// VERSION is this package's version. It MUST equal package.json "version":
|
|
1421
1421
|
// the release orchestrator rewrites both, and the version test fails the
|
|
1422
1422
|
// build if they drift. Mirrors `const VERSION` in go/expr.go.
|
|
1423
|
-
const VERSION = '0.5.
|
|
1423
|
+
const VERSION = '0.5.18';
|
|
1424
1424
|
exports.VERSION = VERSION;
|
|
1425
1425
|
// The translation parts a host composes a translation from (admin ADR-27):
|
|
1426
1426
|
// the manifest and the alchemy sources, generated by ../embed-translate.js.
|
package/dist/translate.js
CHANGED
|
@@ -39,7 +39,7 @@ const TRANSLATION = Object.freeze({
|
|
|
39
39
|
"loss": [
|
|
40
40
|
"Comments, spacing, implicit lists and maps, and the document's own spelling of strings and numbers are not kept: every list is written in brackets, every object in braces with its keys quoted, every string double-quoted and every number as JSON writes it.",
|
|
41
41
|
"An operation of the default operators is written in infix, and a term that would need parentheses, which read back as a group, is written as a list instead, which reads back as the same tree.",
|
|
42
|
-
"A list whose first element is an object whose src member is a default operator's source text, as the reader's own value describes an operator, is written with that text in the object's place, as an operation where its count makes one: only the src member is read, and the object's other members, the token the operator was read from among them, are not kept.",
|
|
42
|
+
"A list whose first element is an object whose src member is a default operator's source text, as the reader's own value describes an operator, is written with that text in the object's place, as an operation where its count makes one: only the src member is read, and the object's other members, the token the operator was read from among them, are not kept. A list whose first element is an object with any other src that is not empty, zero, false or null, as a C syntax tree's token has, is refused with TARGET_VALUE_UNREPRESENTABLE, since the reader would read that src alone as the list's operator.",
|
|
43
43
|
"A negative number is written with its sign, which reads back as the operator - applied to the number's magnitude.",
|
|
44
44
|
"A number that is not finite is written as the string Infinity, -Infinity or NaN."
|
|
45
45
|
]
|
|
@@ -54,7 +54,7 @@ const TRANSLATION = Object.freeze({
|
|
|
54
54
|
; its reverse, takes them back. Nothing else here is the host's to call.
|
|
55
55
|
;
|
|
56
56
|
; Both are the identity. The reader builds its trees on jsonic's values,
|
|
57
|
-
; so
|
|
57
|
+
; so a plain tree is already an expression tree: a list whose first
|
|
58
58
|
; element is a default operator and whose count makes an operation is
|
|
59
59
|
; one, and the render writes it in infix, the operator being its source
|
|
60
60
|
; text (\`+\`, \`-\`, \`*\`, \`/\`, \`%\`, or \`(\` for a group) or an object that
|
|
@@ -63,11 +63,22 @@ const TRANSLATION = Object.freeze({
|
|
|
63
63
|
; render writes as jsonic. A list that only looks like an operation
|
|
64
64
|
; reads back as the same tree either way, once each operator is reduced
|
|
65
65
|
; to its source text as the shared fixtures' simplifier, Go's \`Simplify\`
|
|
66
|
-
; and Rust's \`simplify\` reduce it
|
|
67
|
-
;
|
|
68
|
-
;
|
|
69
|
-
;
|
|
70
|
-
;
|
|
66
|
+
; and Rust's \`simplify\` reduce it.
|
|
67
|
+
;
|
|
68
|
+
; The plain trees that are not expression trees are the lists led by an
|
|
69
|
+
; object whose \`src\` member the simplifiers read as an operator that is
|
|
70
|
+
; not a default one, as they read a C syntax tree's tokens: they keep
|
|
71
|
+
; that \`src\` alone, so no document reads back as such a list. The render
|
|
72
|
+
; refuses it, with TARGET_VALUE_UNREPRESENTABLE and the object's path,
|
|
73
|
+
; rather than this embedding, since the render meets such a list from
|
|
74
|
+
; any source, one of the schema \`expr\` too, which reaches the render
|
|
75
|
+
; without an embedding, and it already holds the first object of a list
|
|
76
|
+
; to read the operator that object describes.
|
|
77
|
+
;
|
|
78
|
+
; What the round trip changes is what the render's conventions change
|
|
79
|
+
; (the manifest's loss list): an operator's description is written as
|
|
80
|
+
; its source text, a negative number reads back as the operator \`-\`
|
|
81
|
+
; applied to its magnitude, and a number that is not finite as a string.
|
|
71
82
|
|
|
72
83
|
; The embedding: a plain tree's events in, the same events out.
|
|
73
84
|
def expr-embed [input]
|
|
@@ -96,6 +107,15 @@ def expr-unembed [input]
|
|
|
96
107
|
; text is, or the operator an object describes, read by its \`src\` member
|
|
97
108
|
; as those simplifiers read it, when that is a default operator's source.
|
|
98
109
|
;
|
|
110
|
+
; The simplifiers read any list led by an object with a \`src\` member that
|
|
111
|
+
; way, and keep that member's value alone: TypeScript's \`simplify\` where
|
|
112
|
+
; the \`src\` is not empty, zero, false or null, and Go's \`SimplifyOrdered\`
|
|
113
|
+
; and Rust's \`simplify\` where it is a string other than the empty one. So
|
|
114
|
+
; a list led by an object whose \`src\` they read and is not a default
|
|
115
|
+
; operator's source, as the tokens a C syntax tree puts first in a node's
|
|
116
|
+
; children are, is no tree of the reader's: no document reads back as
|
|
117
|
+
; it, and the render refuses it (below).
|
|
118
|
+
;
|
|
99
119
|
; Every value is written so that the reader builds the same tree from it:
|
|
100
120
|
;
|
|
101
121
|
; - An operation is written in infix: \`a+b\` for a list of an infix
|
|
@@ -118,6 +138,17 @@ def expr-unembed [input]
|
|
|
118
138
|
; its sign, which the reader reads as the operator \`-\` applied to the
|
|
119
139
|
; number's magnitude, and a number that is not finite, which jsonic
|
|
120
140
|
; has no spelling for, as the string \`Infinity\`, \`-Infinity\` or \`NaN\`.
|
|
141
|
+
; - A list whose first element is an object with a \`src\` member that the
|
|
142
|
+
; simplifiers read is written as an operation only where that \`src\` is
|
|
143
|
+
; a default operator's source text, as the reader's own value describes
|
|
144
|
+
; the operator (the manifest's loss list says the object's other
|
|
145
|
+
; members are not kept). With any other such \`src\` the list fails with
|
|
146
|
+
; TARGET_VALUE_UNREPRESENTABLE, naming the object's path, in jq's
|
|
147
|
+
; syntax, and its \`src\` as the render writes it. The \`src\` is judged as
|
|
148
|
+
; it is written, since that is what the reader reads: a number that is
|
|
149
|
+
; not finite as a string, and a negative number as the operation its
|
|
150
|
+
; sign makes, a list. An object whose \`src\` is empty, zero, false or
|
|
151
|
+
; null is written as it is, and reads back as itself.
|
|
121
152
|
;
|
|
122
153
|
; No white space is written, since jsonic reads a space between two
|
|
123
154
|
; values as an implicit list, and the document ends with one line break.
|
|
@@ -143,16 +174,25 @@ def expr-unembed [input]
|
|
|
143
174
|
; [:list :first] a list whose first element, an object,
|
|
144
175
|
; is being held, which decides how the
|
|
145
176
|
; list is written
|
|
146
|
-
; [:list :stream
|
|
147
|
-
; until an element is written
|
|
177
|
+
; [:list :stream index] a list written as it is read; index is
|
|
178
|
+
; [] until an element is written, and then
|
|
179
|
+
; the decimal digits of the last one's
|
|
180
|
+
; index, most significant first
|
|
148
181
|
; [:list :hold items] a held list, and the items read so far
|
|
149
|
-
; [:map :stream first :key]
|
|
150
|
-
;
|
|
151
|
-
; [:map :stream :value]
|
|
182
|
+
; [:map :stream :first :key] an object written as it is read, its
|
|
183
|
+
; first key or its end due
|
|
184
|
+
; [:map :stream [:value k]] the same, the value of the key k due
|
|
185
|
+
; [:map :stream [:after k] :key] the same, after the member of the key
|
|
186
|
+
; k, its next key or its end due
|
|
152
187
|
; [:map :hold parts :key] an object inside a held list, or the
|
|
153
188
|
; first element of a list, and its
|
|
154
189
|
; members' texts
|
|
155
|
-
; [:map :hold parts [:value k]] the same, the value of the key k due
|
|
190
|
+
; [:map :hold parts [:value k]] the same, the value of the key k due,
|
|
191
|
+
; k quoted
|
|
192
|
+
;
|
|
193
|
+
; The markers say where the render is, which only a refusal reads: the
|
|
194
|
+
; list a value is in, and its index, or the object and its key. alchemy
|
|
195
|
+
; has no arithmetic, so an index goes up a digit at a time.
|
|
156
196
|
;
|
|
157
197
|
; An item is \`[text class list head]\`: the text a value is written as;
|
|
158
198
|
; its class, \`:infix2\` for an operation of \`+\` or \`-\`, \`:infix3\` for one
|
|
@@ -190,19 +230,65 @@ def expr-src-op [part]
|
|
|
190
230
|
case "\\"src\\":\\"(\\"" "("
|
|
191
231
|
case _ :none
|
|
192
232
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
233
|
+
; Whether a held object's member is its \`src\`: a member's text is its
|
|
234
|
+
; quoted key, a colon and its value's text, and a quoted key ends at its
|
|
235
|
+
; first unescaped quote, so the member is \`src\` exactly when its text
|
|
236
|
+
; begins with "src":.
|
|
237
|
+
def expr-is-src [part]
|
|
238
|
+
expr-leads "\\"src\\":" part
|
|
239
|
+
|
|
240
|
+
; The text of a \`src\` member's value, what follows its key and colon.
|
|
241
|
+
def expr-src-value [part]
|
|
242
|
+
let [pieces (split "\\"src\\":" part)]
|
|
243
|
+
string-join "\\"src\\":" (map (fn [i] (expr-at pieces i)) (filter expr-after-first (indices pieces)))
|
|
244
|
+
|
|
245
|
+
def expr-after-first [i]
|
|
246
|
+
match i
|
|
247
|
+
case 0 false
|
|
196
248
|
case _ true
|
|
197
249
|
|
|
198
|
-
;
|
|
199
|
-
; \`src\` member
|
|
200
|
-
;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
250
|
+
; Whether a simplifier takes a list led by an object for an operation,
|
|
251
|
+
; the object's \`src\` member's value written as this text: TypeScript's
|
|
252
|
+
; does where the value is not empty, zero, false or null, and Go's and
|
|
253
|
+
; Rust's where it is a string other than the empty one, a narrower set.
|
|
254
|
+
; The value is judged as written, which is what the reader reads: a
|
|
255
|
+
; number that is not finite is written as a string, and a negative one
|
|
256
|
+
; with its sign, which reads back as an operation, a list.
|
|
257
|
+
def expr-src-read [text]
|
|
258
|
+
match text
|
|
259
|
+
case "\\"\\"" false
|
|
260
|
+
case "false" false
|
|
261
|
+
case "null" false
|
|
262
|
+
case _
|
|
263
|
+
match (is-number text)
|
|
264
|
+
case false true
|
|
265
|
+
case true
|
|
266
|
+
match (expr-at (split "-" text) 0)
|
|
267
|
+
case "" true
|
|
268
|
+
case _
|
|
269
|
+
match (compare (number text) 0)
|
|
270
|
+
case :equal false
|
|
271
|
+
case _ true
|
|
272
|
+
|
|
273
|
+
; What a held object makes of a list it is the first element of, from its
|
|
274
|
+
; members' texts: the default operator its \`src\` member names, as the
|
|
275
|
+
; reader's description of an operator does; :none where it has no \`src\`,
|
|
276
|
+
; or one no simplifier reads; and \`[:foreign text]\` for any other \`src\`,
|
|
277
|
+
; text its value as written. Where a key repeats, the last member is the
|
|
278
|
+
; one the reader keeps.
|
|
279
|
+
def expr-src-of [parts]
|
|
280
|
+
let [srcs (filter expr-is-src parts)]
|
|
281
|
+
match (count srcs)
|
|
204
282
|
case 0 :none
|
|
205
|
-
case _
|
|
283
|
+
case _
|
|
284
|
+
let [part (top srcs)]
|
|
285
|
+
match (expr-src-op part)
|
|
286
|
+
case :none
|
|
287
|
+
let [text (expr-src-value part)]
|
|
288
|
+
match (expr-src-read text)
|
|
289
|
+
case true [:foreign text]
|
|
290
|
+
case false :none
|
|
291
|
+
case op op
|
|
206
292
|
|
|
207
293
|
; An item as its list holds it: the first one, where it is an operator,
|
|
208
294
|
; as that operator's text, so that a description is written as the
|
|
@@ -306,6 +392,10 @@ def expr-top [s]
|
|
|
306
392
|
case 0 :none
|
|
307
393
|
case _ (top s)
|
|
308
394
|
|
|
395
|
+
; A vector's item at a position.
|
|
396
|
+
def expr-at [v i]
|
|
397
|
+
get-path (path i) v
|
|
398
|
+
|
|
309
399
|
def expr-mark [marker s]
|
|
310
400
|
push marker (pop s)
|
|
311
401
|
|
|
@@ -316,11 +406,11 @@ def expr-mark [marker s]
|
|
|
316
406
|
def expr-stream-value [s text inner]
|
|
317
407
|
match (expr-top s)
|
|
318
408
|
case :none (expr-push-or-done [] inner [text])
|
|
319
|
-
case [:list :stream
|
|
320
|
-
match
|
|
321
|
-
case
|
|
322
|
-
case
|
|
323
|
-
case [:map :stream :value] (expr-push-or-done (expr-mark [:map :stream
|
|
409
|
+
case [:list :stream index]
|
|
410
|
+
match index
|
|
411
|
+
case [] (expr-push-or-done (expr-mark [:list :stream ["0"]] s) inner [text])
|
|
412
|
+
case _ (expr-push-or-done (expr-mark [:list :stream (expr-count-up index)] s) inner ["," text])
|
|
413
|
+
case [:map :stream [:value k]] (expr-push-or-done (expr-mark [:map :stream [:after k] :key] s) inner [text])
|
|
324
414
|
|
|
325
415
|
def expr-push-or-done [s inner out]
|
|
326
416
|
match inner
|
|
@@ -353,7 +443,7 @@ def expr-held [s item]
|
|
|
353
443
|
; \`[\` first, and the rest of the list as it is read.
|
|
354
444
|
def expr-first-held [s item]
|
|
355
445
|
match item
|
|
356
|
-
case [text _ _ :none] (transition (expr-mark [:list :stream
|
|
446
|
+
case [text _ _ :none] (transition (expr-mark [:list :stream ["0"]] s) ["[" text])
|
|
357
447
|
case _ (transition (expr-mark [:list :hold [(expr-lead [] item)]] s) [])
|
|
358
448
|
|
|
359
449
|
; Whether the top of the stack holds what is read.
|
|
@@ -374,10 +464,10 @@ def expr-decide [s mode event]
|
|
|
374
464
|
match [mode event]
|
|
375
465
|
case [:stream (scalar value)]
|
|
376
466
|
match (expr-op value)
|
|
377
|
-
case :none [(expr-mark [:list :stream
|
|
467
|
+
case :none [(expr-mark [:list :stream []] s) "["]
|
|
378
468
|
case _ [(expr-mark [:list :hold []] s) ""]
|
|
379
469
|
case [:stream object-start] [(expr-mark [:list :first] s) ""]
|
|
380
|
-
case [:stream _] [(expr-mark [:list :stream
|
|
470
|
+
case [:stream _] [(expr-mark [:list :stream []] s) "["]
|
|
381
471
|
case _ [(expr-mark [:list :hold []] s) ""]
|
|
382
472
|
|
|
383
473
|
; A value where one is due: a scalar, or a container's start.
|
|
@@ -391,7 +481,7 @@ def expr-value [s event]
|
|
|
391
481
|
case false
|
|
392
482
|
match event
|
|
393
483
|
case (scalar value) (expr-stream-value s (expr-scalar-text value) :none)
|
|
394
|
-
case object-start (expr-stream-value s "{" [:map :stream
|
|
484
|
+
case object-start (expr-stream-value s "{" [:map :stream :first :key])
|
|
395
485
|
case array-start (expr-stream-value s "" [:pending :stream])
|
|
396
486
|
|
|
397
487
|
; The first element of a list, once the list has decided: what the
|
|
@@ -420,21 +510,130 @@ def expr-closed [s text]
|
|
|
420
510
|
|
|
421
511
|
def expr-key [s name]
|
|
422
512
|
match (expr-top s)
|
|
423
|
-
case [:map :stream first :key]
|
|
424
|
-
|
|
425
|
-
case true (transition (expr-mark [:map :stream :value] s) [(quoted name) ":"])
|
|
426
|
-
case false (transition (expr-mark [:map :stream :value] s) ["," (quoted name) ":"])
|
|
513
|
+
case [:map :stream :first :key] (transition (expr-mark [:map :stream [:value name]] s) [(quoted name) ":"])
|
|
514
|
+
case [:map :stream [:after _] :key] (transition (expr-mark [:map :stream [:value name]] s) ["," (quoted name) ":"])
|
|
427
515
|
case [:map :hold parts :key] (transition (expr-mark [:map :hold parts [:value (quoted name)]] s) [])
|
|
428
516
|
case _ (fail :protocol-order "the events hold a key where a value is due, which a tree's never do")
|
|
429
517
|
|
|
518
|
+
; An object ends. A held one becomes an item, which records the operator
|
|
519
|
+
; it describes; one that is the first element of a list, with a \`src\` a
|
|
520
|
+
; simplifier would read as that list's operator and no default one, is
|
|
521
|
+
; refused.
|
|
430
522
|
def expr-object-end [s]
|
|
431
523
|
match (expr-top s)
|
|
432
524
|
case [:map :stream _ :key] (expr-closed (pop s) "}")
|
|
433
525
|
case [:map :hold parts :key]
|
|
434
526
|
let [text (string-join "" ["{" (string-join "," parts) "}"])]
|
|
435
|
-
|
|
527
|
+
match (expr-src-of parts)
|
|
528
|
+
case [:foreign src]
|
|
529
|
+
match (expr-leads-list (pop s))
|
|
530
|
+
case true (expr-refuse (pop s) src)
|
|
531
|
+
case false (expr-held (pop s) [text :atom text :none])
|
|
532
|
+
case described (expr-held (pop s) [text :atom text described])
|
|
436
533
|
case _ (fail :protocol-order "the events end an object that is not open, or one whose member has no value, which a tree's never do")
|
|
437
534
|
|
|
535
|
+
; Whether the top of the stack is a list whose first element is due, so
|
|
536
|
+
; that an object ending there is its first element.
|
|
537
|
+
def expr-leads-list [s]
|
|
538
|
+
match (expr-top s)
|
|
539
|
+
case [:list :first] true
|
|
540
|
+
case [:list :hold []] true
|
|
541
|
+
case _ false
|
|
542
|
+
|
|
543
|
+
; A list led by an object whose \`src\` a simplifier would read as the
|
|
544
|
+
; list's operator, and which is no default operator's source text: no
|
|
545
|
+
; document reads back as the tree, so it is refused, naming the object,
|
|
546
|
+
; by the markers of the containers it is in, and its \`src\` as the render
|
|
547
|
+
; writes it.
|
|
548
|
+
def expr-refuse [s src]
|
|
549
|
+
fail :unrepresentable (string-join "" ["the object at " (expr-path-text s) " is the first element of a list and has the src " src ", which expr's reader would read back as the list's operator, keeping only the src; the render writes such a list only where the src is a default operator's source text"])
|
|
550
|
+
|
|
551
|
+
; The path to the value being read, from the markers of the containers it
|
|
552
|
+
; is in, in jq's syntax as aless prints and reads one: \`.name\` for a
|
|
553
|
+
; member whose key is a word, \`."key"\` for one whose key is not, and \`[i]\`
|
|
554
|
+
; for an element, \`.[i]\` at the root. While a value is read, the list it
|
|
555
|
+
; is in is held, written as it is read or deciding on its first element,
|
|
556
|
+
; and the object it is in has the value's key, held or written.
|
|
557
|
+
def expr-path-text [s]
|
|
558
|
+
let [text (string-join "" (map expr-path-part s))]
|
|
559
|
+
match (expr-at s 0)
|
|
560
|
+
case [:map _ _ _] text
|
|
561
|
+
case _ (string-join "" ["." text])
|
|
562
|
+
|
|
563
|
+
def expr-path-part [marker]
|
|
564
|
+
match marker
|
|
565
|
+
case [:list :first] "[0]"
|
|
566
|
+
case [:list :stream index] (string-join "" ["[" (string-join "" index) "]"])
|
|
567
|
+
case [:list :hold items] (string-join "" ["[" (scalar-text csv-options (count items)) "]"])
|
|
568
|
+
case [:map :stream [:after k] :key] (expr-path-key k)
|
|
569
|
+
case [:map :hold _ [:value k]] (expr-path-key (unquoted k))
|
|
570
|
+
|
|
571
|
+
; A key as a path writes it: bare where it is a word, letters, digits and
|
|
572
|
+
; underscores not led by a digit, and quoted otherwise.
|
|
573
|
+
def expr-path-key [name]
|
|
574
|
+
match [(length name) (chars-within [[48 57] [65 90] [95 95] [97 122]] name)]
|
|
575
|
+
case [0 _] (string-join "" ["." (quoted name)])
|
|
576
|
+
case [_ false] (string-join "" ["." (quoted name)])
|
|
577
|
+
case _
|
|
578
|
+
match (count (filter (fn [digit] (expr-leads digit name)) ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"]))
|
|
579
|
+
case 0 (string-join "" ["." name])
|
|
580
|
+
case _ (string-join "" ["." (quoted name)])
|
|
581
|
+
|
|
582
|
+
; Whether a string that is not empty begins with another.
|
|
583
|
+
def expr-leads [lead text]
|
|
584
|
+
match (expr-at (split lead text) 0)
|
|
585
|
+
case "" true
|
|
586
|
+
case _ false
|
|
587
|
+
|
|
588
|
+
; The digits of the next index: the last digit up by one, and a 9
|
|
589
|
+
; carried.
|
|
590
|
+
def expr-count-up [digits]
|
|
591
|
+
match (top digits)
|
|
592
|
+
case "9" (expr-carry digits)
|
|
593
|
+
case digit (push (expr-digit-up digit) (pop digits))
|
|
594
|
+
|
|
595
|
+
def expr-digit-up [digit]
|
|
596
|
+
match digit
|
|
597
|
+
case "0" "1"
|
|
598
|
+
case "1" "2"
|
|
599
|
+
case "2" "3"
|
|
600
|
+
case "3" "4"
|
|
601
|
+
case "4" "5"
|
|
602
|
+
case "5" "6"
|
|
603
|
+
case "6" "7"
|
|
604
|
+
case "7" "8"
|
|
605
|
+
case "8" "9"
|
|
606
|
+
|
|
607
|
+
; The digits after ones that end in a 9: the nines at the end become
|
|
608
|
+
; zeros and the digit before them goes up, or, where every digit is a 9, a
|
|
609
|
+
; 1 leads zeros one more than there were nines. Written as one string, a
|
|
610
|
+
; 9 for each nine and a bar for any other digit, the digits split at the
|
|
611
|
+
; bars, and what comes before the last bar is as long as the position of
|
|
612
|
+
; the digit that goes up.
|
|
613
|
+
def expr-carry [digits]
|
|
614
|
+
let [runs (split "|" (string-join "" (map expr-nine-or-bar digits)))]
|
|
615
|
+
match (count runs)
|
|
616
|
+
case 1 (push "0" (map expr-one-then-zero (indices digits)))
|
|
617
|
+
case _
|
|
618
|
+
let [up (length (string-join "|" (pop runs)))]
|
|
619
|
+
map (fn [i] (expr-carried digits up i)) (indices digits)
|
|
620
|
+
|
|
621
|
+
def expr-nine-or-bar [digit]
|
|
622
|
+
match digit
|
|
623
|
+
case "9" "9"
|
|
624
|
+
case _ "|"
|
|
625
|
+
|
|
626
|
+
def expr-one-then-zero [i]
|
|
627
|
+
match i
|
|
628
|
+
case 0 "1"
|
|
629
|
+
case _ "0"
|
|
630
|
+
|
|
631
|
+
def expr-carried [digits up i]
|
|
632
|
+
match (compare i up)
|
|
633
|
+
case :less (expr-at digits i)
|
|
634
|
+
case :equal (expr-digit-up (expr-at digits i))
|
|
635
|
+
case _ "0"
|
|
636
|
+
|
|
438
637
|
def expr-array-end [s]
|
|
439
638
|
match (expr-top s)
|
|
440
639
|
case [:pending mode] (expr-close s [:pending mode])
|
|
@@ -447,7 +646,7 @@ def expr-due [s event]
|
|
|
447
646
|
case :none (expr-value s event)
|
|
448
647
|
case [:pending mode] (expr-first s mode event)
|
|
449
648
|
case [:list _ _] (expr-value s event)
|
|
450
|
-
case [:map :stream :value] (expr-value s event)
|
|
649
|
+
case [:map :stream [:value _]] (expr-value s event)
|
|
451
650
|
case [:map :hold _ [:value _]] (expr-value s event)
|
|
452
651
|
case _ (fail :protocol-order "the events hold a value where a key is due, which a tree's never do")
|
|
453
652
|
|
package/dist/translate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translate.js","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":";AAAA,yDAAyD;;
|
|
1
|
+
{"version":3,"file":"translate.js","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":";AAAA,yDAAyD;;QAqrBvD,SAAS;AApqBX,MAAM,WAAW,GAAqB,MAAM,CAAC,MAAM,CAAC;IAClD,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CX;IACC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCrD,EAAE,CAAC;IACF,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAskBvD,EAAE,CAAC;CACH,CAAC,CAAA;AAEF,SAAS,SAAS;IAChB,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
package/package.json
CHANGED
package/src/expr.ts
CHANGED
|
@@ -1700,7 +1700,7 @@ const testing = {
|
|
|
1700
1700
|
// VERSION is this package's version. It MUST equal package.json "version":
|
|
1701
1701
|
// the release orchestrator rewrites both, and the version test fails the
|
|
1702
1702
|
// build if they drift. Mirrors `const VERSION` in go/expr.go.
|
|
1703
|
-
const VERSION = '0.5.
|
|
1703
|
+
const VERSION = '0.5.18'
|
|
1704
1704
|
|
|
1705
1705
|
export { VERSION, Expr, evaluation, simplify, parseSimplified, testing }
|
|
1706
1706
|
|
package/src/translate.ts
CHANGED
|
@@ -52,7 +52,7 @@ const TRANSLATION: TranslationParts = Object.freeze({
|
|
|
52
52
|
"loss": [
|
|
53
53
|
"Comments, spacing, implicit lists and maps, and the document's own spelling of strings and numbers are not kept: every list is written in brackets, every object in braces with its keys quoted, every string double-quoted and every number as JSON writes it.",
|
|
54
54
|
"An operation of the default operators is written in infix, and a term that would need parentheses, which read back as a group, is written as a list instead, which reads back as the same tree.",
|
|
55
|
-
"A list whose first element is an object whose src member is a default operator's source text, as the reader's own value describes an operator, is written with that text in the object's place, as an operation where its count makes one: only the src member is read, and the object's other members, the token the operator was read from among them, are not kept.",
|
|
55
|
+
"A list whose first element is an object whose src member is a default operator's source text, as the reader's own value describes an operator, is written with that text in the object's place, as an operation where its count makes one: only the src member is read, and the object's other members, the token the operator was read from among them, are not kept. A list whose first element is an object with any other src that is not empty, zero, false or null, as a C syntax tree's token has, is refused with TARGET_VALUE_UNREPRESENTABLE, since the reader would read that src alone as the list's operator.",
|
|
56
56
|
"A negative number is written with its sign, which reads back as the operator - applied to the number's magnitude.",
|
|
57
57
|
"A number that is not finite is written as the string Infinity, -Infinity or NaN."
|
|
58
58
|
]
|
|
@@ -67,7 +67,7 @@ const TRANSLATION: TranslationParts = Object.freeze({
|
|
|
67
67
|
; its reverse, takes them back. Nothing else here is the host's to call.
|
|
68
68
|
;
|
|
69
69
|
; Both are the identity. The reader builds its trees on jsonic's values,
|
|
70
|
-
; so
|
|
70
|
+
; so a plain tree is already an expression tree: a list whose first
|
|
71
71
|
; element is a default operator and whose count makes an operation is
|
|
72
72
|
; one, and the render writes it in infix, the operator being its source
|
|
73
73
|
; text (\`+\`, \`-\`, \`*\`, \`/\`, \`%\`, or \`(\` for a group) or an object that
|
|
@@ -76,11 +76,22 @@ const TRANSLATION: TranslationParts = Object.freeze({
|
|
|
76
76
|
; render writes as jsonic. A list that only looks like an operation
|
|
77
77
|
; reads back as the same tree either way, once each operator is reduced
|
|
78
78
|
; to its source text as the shared fixtures' simplifier, Go's \`Simplify\`
|
|
79
|
-
; and Rust's \`simplify\` reduce it
|
|
80
|
-
;
|
|
81
|
-
;
|
|
82
|
-
;
|
|
83
|
-
;
|
|
79
|
+
; and Rust's \`simplify\` reduce it.
|
|
80
|
+
;
|
|
81
|
+
; The plain trees that are not expression trees are the lists led by an
|
|
82
|
+
; object whose \`src\` member the simplifiers read as an operator that is
|
|
83
|
+
; not a default one, as they read a C syntax tree's tokens: they keep
|
|
84
|
+
; that \`src\` alone, so no document reads back as such a list. The render
|
|
85
|
+
; refuses it, with TARGET_VALUE_UNREPRESENTABLE and the object's path,
|
|
86
|
+
; rather than this embedding, since the render meets such a list from
|
|
87
|
+
; any source, one of the schema \`expr\` too, which reaches the render
|
|
88
|
+
; without an embedding, and it already holds the first object of a list
|
|
89
|
+
; to read the operator that object describes.
|
|
90
|
+
;
|
|
91
|
+
; What the round trip changes is what the render's conventions change
|
|
92
|
+
; (the manifest's loss list): an operator's description is written as
|
|
93
|
+
; its source text, a negative number reads back as the operator \`-\`
|
|
94
|
+
; applied to its magnitude, and a number that is not finite as a string.
|
|
84
95
|
|
|
85
96
|
; The embedding: a plain tree's events in, the same events out.
|
|
86
97
|
def expr-embed [input]
|
|
@@ -109,6 +120,15 @@ def expr-unembed [input]
|
|
|
109
120
|
; text is, or the operator an object describes, read by its \`src\` member
|
|
110
121
|
; as those simplifiers read it, when that is a default operator's source.
|
|
111
122
|
;
|
|
123
|
+
; The simplifiers read any list led by an object with a \`src\` member that
|
|
124
|
+
; way, and keep that member's value alone: TypeScript's \`simplify\` where
|
|
125
|
+
; the \`src\` is not empty, zero, false or null, and Go's \`SimplifyOrdered\`
|
|
126
|
+
; and Rust's \`simplify\` where it is a string other than the empty one. So
|
|
127
|
+
; a list led by an object whose \`src\` they read and is not a default
|
|
128
|
+
; operator's source, as the tokens a C syntax tree puts first in a node's
|
|
129
|
+
; children are, is no tree of the reader's: no document reads back as
|
|
130
|
+
; it, and the render refuses it (below).
|
|
131
|
+
;
|
|
112
132
|
; Every value is written so that the reader builds the same tree from it:
|
|
113
133
|
;
|
|
114
134
|
; - An operation is written in infix: \`a+b\` for a list of an infix
|
|
@@ -131,6 +151,17 @@ def expr-unembed [input]
|
|
|
131
151
|
; its sign, which the reader reads as the operator \`-\` applied to the
|
|
132
152
|
; number's magnitude, and a number that is not finite, which jsonic
|
|
133
153
|
; has no spelling for, as the string \`Infinity\`, \`-Infinity\` or \`NaN\`.
|
|
154
|
+
; - A list whose first element is an object with a \`src\` member that the
|
|
155
|
+
; simplifiers read is written as an operation only where that \`src\` is
|
|
156
|
+
; a default operator's source text, as the reader's own value describes
|
|
157
|
+
; the operator (the manifest's loss list says the object's other
|
|
158
|
+
; members are not kept). With any other such \`src\` the list fails with
|
|
159
|
+
; TARGET_VALUE_UNREPRESENTABLE, naming the object's path, in jq's
|
|
160
|
+
; syntax, and its \`src\` as the render writes it. The \`src\` is judged as
|
|
161
|
+
; it is written, since that is what the reader reads: a number that is
|
|
162
|
+
; not finite as a string, and a negative number as the operation its
|
|
163
|
+
; sign makes, a list. An object whose \`src\` is empty, zero, false or
|
|
164
|
+
; null is written as it is, and reads back as itself.
|
|
134
165
|
;
|
|
135
166
|
; No white space is written, since jsonic reads a space between two
|
|
136
167
|
; values as an implicit list, and the document ends with one line break.
|
|
@@ -156,16 +187,25 @@ def expr-unembed [input]
|
|
|
156
187
|
; [:list :first] a list whose first element, an object,
|
|
157
188
|
; is being held, which decides how the
|
|
158
189
|
; list is written
|
|
159
|
-
; [:list :stream
|
|
160
|
-
; until an element is written
|
|
190
|
+
; [:list :stream index] a list written as it is read; index is
|
|
191
|
+
; [] until an element is written, and then
|
|
192
|
+
; the decimal digits of the last one's
|
|
193
|
+
; index, most significant first
|
|
161
194
|
; [:list :hold items] a held list, and the items read so far
|
|
162
|
-
; [:map :stream first :key]
|
|
163
|
-
;
|
|
164
|
-
; [:map :stream :value]
|
|
195
|
+
; [:map :stream :first :key] an object written as it is read, its
|
|
196
|
+
; first key or its end due
|
|
197
|
+
; [:map :stream [:value k]] the same, the value of the key k due
|
|
198
|
+
; [:map :stream [:after k] :key] the same, after the member of the key
|
|
199
|
+
; k, its next key or its end due
|
|
165
200
|
; [:map :hold parts :key] an object inside a held list, or the
|
|
166
201
|
; first element of a list, and its
|
|
167
202
|
; members' texts
|
|
168
|
-
; [:map :hold parts [:value k]] the same, the value of the key k due
|
|
203
|
+
; [:map :hold parts [:value k]] the same, the value of the key k due,
|
|
204
|
+
; k quoted
|
|
205
|
+
;
|
|
206
|
+
; The markers say where the render is, which only a refusal reads: the
|
|
207
|
+
; list a value is in, and its index, or the object and its key. alchemy
|
|
208
|
+
; has no arithmetic, so an index goes up a digit at a time.
|
|
169
209
|
;
|
|
170
210
|
; An item is \`[text class list head]\`: the text a value is written as;
|
|
171
211
|
; its class, \`:infix2\` for an operation of \`+\` or \`-\`, \`:infix3\` for one
|
|
@@ -203,19 +243,65 @@ def expr-src-op [part]
|
|
|
203
243
|
case "\\"src\\":\\"(\\"" "("
|
|
204
244
|
case _ :none
|
|
205
245
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
246
|
+
; Whether a held object's member is its \`src\`: a member's text is its
|
|
247
|
+
; quoted key, a colon and its value's text, and a quoted key ends at its
|
|
248
|
+
; first unescaped quote, so the member is \`src\` exactly when its text
|
|
249
|
+
; begins with "src":.
|
|
250
|
+
def expr-is-src [part]
|
|
251
|
+
expr-leads "\\"src\\":" part
|
|
252
|
+
|
|
253
|
+
; The text of a \`src\` member's value, what follows its key and colon.
|
|
254
|
+
def expr-src-value [part]
|
|
255
|
+
let [pieces (split "\\"src\\":" part)]
|
|
256
|
+
string-join "\\"src\\":" (map (fn [i] (expr-at pieces i)) (filter expr-after-first (indices pieces)))
|
|
257
|
+
|
|
258
|
+
def expr-after-first [i]
|
|
259
|
+
match i
|
|
260
|
+
case 0 false
|
|
209
261
|
case _ true
|
|
210
262
|
|
|
211
|
-
;
|
|
212
|
-
; \`src\` member
|
|
213
|
-
;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
263
|
+
; Whether a simplifier takes a list led by an object for an operation,
|
|
264
|
+
; the object's \`src\` member's value written as this text: TypeScript's
|
|
265
|
+
; does where the value is not empty, zero, false or null, and Go's and
|
|
266
|
+
; Rust's where it is a string other than the empty one, a narrower set.
|
|
267
|
+
; The value is judged as written, which is what the reader reads: a
|
|
268
|
+
; number that is not finite is written as a string, and a negative one
|
|
269
|
+
; with its sign, which reads back as an operation, a list.
|
|
270
|
+
def expr-src-read [text]
|
|
271
|
+
match text
|
|
272
|
+
case "\\"\\"" false
|
|
273
|
+
case "false" false
|
|
274
|
+
case "null" false
|
|
275
|
+
case _
|
|
276
|
+
match (is-number text)
|
|
277
|
+
case false true
|
|
278
|
+
case true
|
|
279
|
+
match (expr-at (split "-" text) 0)
|
|
280
|
+
case "" true
|
|
281
|
+
case _
|
|
282
|
+
match (compare (number text) 0)
|
|
283
|
+
case :equal false
|
|
284
|
+
case _ true
|
|
285
|
+
|
|
286
|
+
; What a held object makes of a list it is the first element of, from its
|
|
287
|
+
; members' texts: the default operator its \`src\` member names, as the
|
|
288
|
+
; reader's description of an operator does; :none where it has no \`src\`,
|
|
289
|
+
; or one no simplifier reads; and \`[:foreign text]\` for any other \`src\`,
|
|
290
|
+
; text its value as written. Where a key repeats, the last member is the
|
|
291
|
+
; one the reader keeps.
|
|
292
|
+
def expr-src-of [parts]
|
|
293
|
+
let [srcs (filter expr-is-src parts)]
|
|
294
|
+
match (count srcs)
|
|
217
295
|
case 0 :none
|
|
218
|
-
case _
|
|
296
|
+
case _
|
|
297
|
+
let [part (top srcs)]
|
|
298
|
+
match (expr-src-op part)
|
|
299
|
+
case :none
|
|
300
|
+
let [text (expr-src-value part)]
|
|
301
|
+
match (expr-src-read text)
|
|
302
|
+
case true [:foreign text]
|
|
303
|
+
case false :none
|
|
304
|
+
case op op
|
|
219
305
|
|
|
220
306
|
; An item as its list holds it: the first one, where it is an operator,
|
|
221
307
|
; as that operator's text, so that a description is written as the
|
|
@@ -319,6 +405,10 @@ def expr-top [s]
|
|
|
319
405
|
case 0 :none
|
|
320
406
|
case _ (top s)
|
|
321
407
|
|
|
408
|
+
; A vector's item at a position.
|
|
409
|
+
def expr-at [v i]
|
|
410
|
+
get-path (path i) v
|
|
411
|
+
|
|
322
412
|
def expr-mark [marker s]
|
|
323
413
|
push marker (pop s)
|
|
324
414
|
|
|
@@ -329,11 +419,11 @@ def expr-mark [marker s]
|
|
|
329
419
|
def expr-stream-value [s text inner]
|
|
330
420
|
match (expr-top s)
|
|
331
421
|
case :none (expr-push-or-done [] inner [text])
|
|
332
|
-
case [:list :stream
|
|
333
|
-
match
|
|
334
|
-
case
|
|
335
|
-
case
|
|
336
|
-
case [:map :stream :value] (expr-push-or-done (expr-mark [:map :stream
|
|
422
|
+
case [:list :stream index]
|
|
423
|
+
match index
|
|
424
|
+
case [] (expr-push-or-done (expr-mark [:list :stream ["0"]] s) inner [text])
|
|
425
|
+
case _ (expr-push-or-done (expr-mark [:list :stream (expr-count-up index)] s) inner ["," text])
|
|
426
|
+
case [:map :stream [:value k]] (expr-push-or-done (expr-mark [:map :stream [:after k] :key] s) inner [text])
|
|
337
427
|
|
|
338
428
|
def expr-push-or-done [s inner out]
|
|
339
429
|
match inner
|
|
@@ -366,7 +456,7 @@ def expr-held [s item]
|
|
|
366
456
|
; \`[\` first, and the rest of the list as it is read.
|
|
367
457
|
def expr-first-held [s item]
|
|
368
458
|
match item
|
|
369
|
-
case [text _ _ :none] (transition (expr-mark [:list :stream
|
|
459
|
+
case [text _ _ :none] (transition (expr-mark [:list :stream ["0"]] s) ["[" text])
|
|
370
460
|
case _ (transition (expr-mark [:list :hold [(expr-lead [] item)]] s) [])
|
|
371
461
|
|
|
372
462
|
; Whether the top of the stack holds what is read.
|
|
@@ -387,10 +477,10 @@ def expr-decide [s mode event]
|
|
|
387
477
|
match [mode event]
|
|
388
478
|
case [:stream (scalar value)]
|
|
389
479
|
match (expr-op value)
|
|
390
|
-
case :none [(expr-mark [:list :stream
|
|
480
|
+
case :none [(expr-mark [:list :stream []] s) "["]
|
|
391
481
|
case _ [(expr-mark [:list :hold []] s) ""]
|
|
392
482
|
case [:stream object-start] [(expr-mark [:list :first] s) ""]
|
|
393
|
-
case [:stream _] [(expr-mark [:list :stream
|
|
483
|
+
case [:stream _] [(expr-mark [:list :stream []] s) "["]
|
|
394
484
|
case _ [(expr-mark [:list :hold []] s) ""]
|
|
395
485
|
|
|
396
486
|
; A value where one is due: a scalar, or a container's start.
|
|
@@ -404,7 +494,7 @@ def expr-value [s event]
|
|
|
404
494
|
case false
|
|
405
495
|
match event
|
|
406
496
|
case (scalar value) (expr-stream-value s (expr-scalar-text value) :none)
|
|
407
|
-
case object-start (expr-stream-value s "{" [:map :stream
|
|
497
|
+
case object-start (expr-stream-value s "{" [:map :stream :first :key])
|
|
408
498
|
case array-start (expr-stream-value s "" [:pending :stream])
|
|
409
499
|
|
|
410
500
|
; The first element of a list, once the list has decided: what the
|
|
@@ -433,21 +523,130 @@ def expr-closed [s text]
|
|
|
433
523
|
|
|
434
524
|
def expr-key [s name]
|
|
435
525
|
match (expr-top s)
|
|
436
|
-
case [:map :stream first :key]
|
|
437
|
-
|
|
438
|
-
case true (transition (expr-mark [:map :stream :value] s) [(quoted name) ":"])
|
|
439
|
-
case false (transition (expr-mark [:map :stream :value] s) ["," (quoted name) ":"])
|
|
526
|
+
case [:map :stream :first :key] (transition (expr-mark [:map :stream [:value name]] s) [(quoted name) ":"])
|
|
527
|
+
case [:map :stream [:after _] :key] (transition (expr-mark [:map :stream [:value name]] s) ["," (quoted name) ":"])
|
|
440
528
|
case [:map :hold parts :key] (transition (expr-mark [:map :hold parts [:value (quoted name)]] s) [])
|
|
441
529
|
case _ (fail :protocol-order "the events hold a key where a value is due, which a tree's never do")
|
|
442
530
|
|
|
531
|
+
; An object ends. A held one becomes an item, which records the operator
|
|
532
|
+
; it describes; one that is the first element of a list, with a \`src\` a
|
|
533
|
+
; simplifier would read as that list's operator and no default one, is
|
|
534
|
+
; refused.
|
|
443
535
|
def expr-object-end [s]
|
|
444
536
|
match (expr-top s)
|
|
445
537
|
case [:map :stream _ :key] (expr-closed (pop s) "}")
|
|
446
538
|
case [:map :hold parts :key]
|
|
447
539
|
let [text (string-join "" ["{" (string-join "," parts) "}"])]
|
|
448
|
-
|
|
540
|
+
match (expr-src-of parts)
|
|
541
|
+
case [:foreign src]
|
|
542
|
+
match (expr-leads-list (pop s))
|
|
543
|
+
case true (expr-refuse (pop s) src)
|
|
544
|
+
case false (expr-held (pop s) [text :atom text :none])
|
|
545
|
+
case described (expr-held (pop s) [text :atom text described])
|
|
449
546
|
case _ (fail :protocol-order "the events end an object that is not open, or one whose member has no value, which a tree's never do")
|
|
450
547
|
|
|
548
|
+
; Whether the top of the stack is a list whose first element is due, so
|
|
549
|
+
; that an object ending there is its first element.
|
|
550
|
+
def expr-leads-list [s]
|
|
551
|
+
match (expr-top s)
|
|
552
|
+
case [:list :first] true
|
|
553
|
+
case [:list :hold []] true
|
|
554
|
+
case _ false
|
|
555
|
+
|
|
556
|
+
; A list led by an object whose \`src\` a simplifier would read as the
|
|
557
|
+
; list's operator, and which is no default operator's source text: no
|
|
558
|
+
; document reads back as the tree, so it is refused, naming the object,
|
|
559
|
+
; by the markers of the containers it is in, and its \`src\` as the render
|
|
560
|
+
; writes it.
|
|
561
|
+
def expr-refuse [s src]
|
|
562
|
+
fail :unrepresentable (string-join "" ["the object at " (expr-path-text s) " is the first element of a list and has the src " src ", which expr's reader would read back as the list's operator, keeping only the src; the render writes such a list only where the src is a default operator's source text"])
|
|
563
|
+
|
|
564
|
+
; The path to the value being read, from the markers of the containers it
|
|
565
|
+
; is in, in jq's syntax as aless prints and reads one: \`.name\` for a
|
|
566
|
+
; member whose key is a word, \`."key"\` for one whose key is not, and \`[i]\`
|
|
567
|
+
; for an element, \`.[i]\` at the root. While a value is read, the list it
|
|
568
|
+
; is in is held, written as it is read or deciding on its first element,
|
|
569
|
+
; and the object it is in has the value's key, held or written.
|
|
570
|
+
def expr-path-text [s]
|
|
571
|
+
let [text (string-join "" (map expr-path-part s))]
|
|
572
|
+
match (expr-at s 0)
|
|
573
|
+
case [:map _ _ _] text
|
|
574
|
+
case _ (string-join "" ["." text])
|
|
575
|
+
|
|
576
|
+
def expr-path-part [marker]
|
|
577
|
+
match marker
|
|
578
|
+
case [:list :first] "[0]"
|
|
579
|
+
case [:list :stream index] (string-join "" ["[" (string-join "" index) "]"])
|
|
580
|
+
case [:list :hold items] (string-join "" ["[" (scalar-text csv-options (count items)) "]"])
|
|
581
|
+
case [:map :stream [:after k] :key] (expr-path-key k)
|
|
582
|
+
case [:map :hold _ [:value k]] (expr-path-key (unquoted k))
|
|
583
|
+
|
|
584
|
+
; A key as a path writes it: bare where it is a word, letters, digits and
|
|
585
|
+
; underscores not led by a digit, and quoted otherwise.
|
|
586
|
+
def expr-path-key [name]
|
|
587
|
+
match [(length name) (chars-within [[48 57] [65 90] [95 95] [97 122]] name)]
|
|
588
|
+
case [0 _] (string-join "" ["." (quoted name)])
|
|
589
|
+
case [_ false] (string-join "" ["." (quoted name)])
|
|
590
|
+
case _
|
|
591
|
+
match (count (filter (fn [digit] (expr-leads digit name)) ["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"]))
|
|
592
|
+
case 0 (string-join "" ["." name])
|
|
593
|
+
case _ (string-join "" ["." (quoted name)])
|
|
594
|
+
|
|
595
|
+
; Whether a string that is not empty begins with another.
|
|
596
|
+
def expr-leads [lead text]
|
|
597
|
+
match (expr-at (split lead text) 0)
|
|
598
|
+
case "" true
|
|
599
|
+
case _ false
|
|
600
|
+
|
|
601
|
+
; The digits of the next index: the last digit up by one, and a 9
|
|
602
|
+
; carried.
|
|
603
|
+
def expr-count-up [digits]
|
|
604
|
+
match (top digits)
|
|
605
|
+
case "9" (expr-carry digits)
|
|
606
|
+
case digit (push (expr-digit-up digit) (pop digits))
|
|
607
|
+
|
|
608
|
+
def expr-digit-up [digit]
|
|
609
|
+
match digit
|
|
610
|
+
case "0" "1"
|
|
611
|
+
case "1" "2"
|
|
612
|
+
case "2" "3"
|
|
613
|
+
case "3" "4"
|
|
614
|
+
case "4" "5"
|
|
615
|
+
case "5" "6"
|
|
616
|
+
case "6" "7"
|
|
617
|
+
case "7" "8"
|
|
618
|
+
case "8" "9"
|
|
619
|
+
|
|
620
|
+
; The digits after ones that end in a 9: the nines at the end become
|
|
621
|
+
; zeros and the digit before them goes up, or, where every digit is a 9, a
|
|
622
|
+
; 1 leads zeros one more than there were nines. Written as one string, a
|
|
623
|
+
; 9 for each nine and a bar for any other digit, the digits split at the
|
|
624
|
+
; bars, and what comes before the last bar is as long as the position of
|
|
625
|
+
; the digit that goes up.
|
|
626
|
+
def expr-carry [digits]
|
|
627
|
+
let [runs (split "|" (string-join "" (map expr-nine-or-bar digits)))]
|
|
628
|
+
match (count runs)
|
|
629
|
+
case 1 (push "0" (map expr-one-then-zero (indices digits)))
|
|
630
|
+
case _
|
|
631
|
+
let [up (length (string-join "|" (pop runs)))]
|
|
632
|
+
map (fn [i] (expr-carried digits up i)) (indices digits)
|
|
633
|
+
|
|
634
|
+
def expr-nine-or-bar [digit]
|
|
635
|
+
match digit
|
|
636
|
+
case "9" "9"
|
|
637
|
+
case _ "|"
|
|
638
|
+
|
|
639
|
+
def expr-one-then-zero [i]
|
|
640
|
+
match i
|
|
641
|
+
case 0 "1"
|
|
642
|
+
case _ "0"
|
|
643
|
+
|
|
644
|
+
def expr-carried [digits up i]
|
|
645
|
+
match (compare i up)
|
|
646
|
+
case :less (expr-at digits i)
|
|
647
|
+
case :equal (expr-digit-up (expr-at digits i))
|
|
648
|
+
case _ "0"
|
|
649
|
+
|
|
451
650
|
def expr-array-end [s]
|
|
452
651
|
match (expr-top s)
|
|
453
652
|
case [:pending mode] (expr-close s [:pending mode])
|
|
@@ -460,7 +659,7 @@ def expr-due [s event]
|
|
|
460
659
|
case :none (expr-value s event)
|
|
461
660
|
case [:pending mode] (expr-first s mode event)
|
|
462
661
|
case [:list _ _] (expr-value s event)
|
|
463
|
-
case [:map :stream :value] (expr-value s event)
|
|
662
|
+
case [:map :stream [:value _]] (expr-value s event)
|
|
464
663
|
case [:map :hold _ [:value _]] (expr-value s event)
|
|
465
664
|
case _ (fail :protocol-order "the events hold a value where a key is due, which a tree's never do")
|
|
466
665
|
|