aboutsummaryrefslogtreecommitdiffstats
path: root/examples/json.aup
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-13 06:16:12 +0100
committereunhhu <[email protected]>2026-10-13 06:16:12 +0100
commit6209ddb42b953902828972b2e09f0296a51fe565 (patch)
tree51be65e5831760c3d416f9ed1431f39dfd569e6a /examples/json.aup
parent557a69ef5102292eceb25f823ebcfc989810ab0c (diff)
downloadaup-6209ddb42b953902828972b2e09f0296a51fe565.tar.gz
aup-6209ddb42b953902828972b2e09f0296a51fe565.zip
Formats, joins, slices, lets of bytes and text, while and && and || that decide alone (Pure 027's stage 2a): {v:08x}, {p:.2f} (Python's mini-language, [0][width][.digits][d x X b o f]), a + b of texts or of bytes, b[a .. c] of bytes and of texts (a cut inside a character failing as encoding), byte(n), let s = bytes or text (16 of each a handler, s = s + e appending in place), while c { } as a count to 2^53 that breaks when c is false, && and || computing their right side only where it decides (an AND or OR still where it cannot fail: comparisons, states and fields, a walked item's fields, a number plus a small literal, what the left side computed; every module of the apps and benchmarks byte for byte the same but json's); examples/json.aup, examples/sha256.aup in formats and joined bytes; 14 diagnostics, one accepted form, 144 random formats against Python's format() and an app cutting at commas
Diffstat (limited to 'examples/json.aup')
-rw-r--r--examples/json.aup84
1 files changed, 84 insertions, 0 deletions
diff --git a/examples/json.aup b/examples/json.aup
new file mode 100644
index 0000000..9e6faec
--- /dev/null
+++ b/examples/json.aup
@@ -0,0 +1,84 @@
+# Whether a message's bytes are one JSON text (RFC 8259), read once from the start with a stack of the arrays and
+# objects open. Input that is not UTF-8 fails as encoding: it is no JSON text either.
+state valid = false
+input check = message { data: bytes }
+
+fn space(b) = b == 0x20 || b == 0x09 || b == 0x0a || b == 0x0d
+fn digit(b) = b >= 0x30 && b <= 0x39
+fn hex(b) = digit(b) || (b >= 0x61 && b <= 0x66) || (b >= 0x41 && b <= 0x46)
+
+on check {
+ let t = text(check.data)
+ let d = bytes(t)
+ let n, i, mode, ok = d.bytes, 0, 0, true # mode 0: a value, 1: after one, 2: a key, 3: a key or }, 4: a value or ]
+ let open: list of i64
+ while ok {
+ while i < n && space(d[i]) { i = i + 1 }
+ if i == n {
+ ok = mode == 1 && open.count == 0
+ break
+ }
+ let b = d[i]
+ if mode == 1 {
+ if open.count == 0 { ok = false }
+ else if b == 0x2c { mode = if open.last == 0x5b { 0 } else { 2 } }
+ else if b == open.last + 2 { open.remove(open.count - 1) }
+ else { ok = false }
+ i = i + 1
+ } else if mode == 3 && b == 0x7d || mode == 4 && b == 0x5d {
+ open.remove(open.count - 1)
+ mode = 1
+ i = i + 1
+ } else if mode == 2 || mode == 3 {
+ if b != 0x22 { ok = false }
+ mode = 5 # the key, then ':'
+ } else if b == 0x5b || b == 0x7b {
+ open.append(b)
+ mode = if b == 0x5b { 4 } else { 3 }
+ i = i + 1
+ } else if b == 0x22 || mode == 5 {
+ i = i + 1 # a string: no control bytes, escapes as RFC 8259 writes them
+ while i < n && d[i] != 0x22 && ok {
+ if d[i] < 0x20 { ok = false }
+ else if d[i] == 0x5c && i + 1 < n && d[i + 1] == 0x75 {
+ ok = i + 5 < n && hex(d[i + 2]) && hex(d[i + 3]) && hex(d[i + 4]) && hex(d[i + 5])
+ i = i + 6
+ } else if d[i] == 0x5c {
+ ok = i + 1 < n && (d[i + 1] == 0x22 || d[i + 1] == 0x5c || d[i + 1] == 0x2f || d[i + 1] == 0x62 ||
+ d[i + 1] == 0x66 || d[i + 1] == 0x6e || d[i + 1] == 0x72 || d[i + 1] == 0x74)
+ i = i + 2
+ } else { i = i + 1 }
+ }
+ ok = ok && i < n
+ i = i + 1
+ if mode == 5 {
+ while i < n && space(d[i]) { i = i + 1 }
+ ok = ok && i < n && d[i] == 0x3a
+ i = i + 1
+ mode = 0
+ } else { mode = 1 }
+ } else if b == 0x2d || digit(b) { # -?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?
+ if b == 0x2d { i = i + 1 }
+ ok = i < n && digit(d[i])
+ if ok && d[i] == 0x30 { i = i + 1 } else { while i < n && digit(d[i]) { i = i + 1 } }
+ if ok && i < n && d[i] == 0x2e {
+ i = i + 1
+ ok = i < n && digit(d[i])
+ while i < n && digit(d[i]) { i = i + 1 }
+ }
+ if ok && i < n && (d[i] == 0x65 || d[i] == 0x45) {
+ i = i + 1
+ if i < n && (d[i] == 0x2b || d[i] == 0x2d) { i = i + 1 }
+ ok = i < n && digit(d[i])
+ while i < n && digit(d[i]) { i = i + 1 }
+ }
+ mode = 1
+ } else {
+ let word = if b == 0x74 { "true" } else if b == 0x66 { "false" } else { "null" }
+ ok = i + word.bytes <= n && t[i .. i + word.bytes] == word
+ i = i + word.bytes
+ mode = 1
+ }
+ }
+ valid = ok
+}