diff options
| author | eunhhu <[email protected]> | 2026-10-13 06:16:12 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-13 06:16:12 +0100 |
| commit | 6209ddb42b953902828972b2e09f0296a51fe565 (patch) | |
| tree | 51be65e5831760c3d416f9ed1431f39dfd569e6a /examples/json.aup | |
| parent | 557a69ef5102292eceb25f823ebcfc989810ab0c (diff) | |
| download | aup-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.aup | 84 |
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 +} |
