nomen-lang 0.0.7 → 0.0.8

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.
Files changed (118) hide show
  1. package/NOMEN_AGENTS.md +235 -0
  2. package/core/System/Ansi.nm +150 -0
  3. package/core/System/Array.nm +358 -0
  4. package/core/System/BigInt.nm +887 -0
  5. package/core/System/Buffer.nm +526 -0
  6. package/core/System/Channel.nm +198 -0
  7. package/core/System/ClassBuffer.nm +229 -0
  8. package/core/System/Console.nm +211 -0
  9. package/core/System/Controls/Button.nm +138 -0
  10. package/core/System/Controls/CheckBox.nm +158 -0
  11. package/core/System/Controls/Container.nm +1562 -0
  12. package/core/System/Controls/Control.nm +28 -0
  13. package/core/System/Controls/Geometry.nm +101 -0
  14. package/core/System/Controls/Layout.nm +228 -0
  15. package/core/System/Controls/LayoutParams.nm +50 -0
  16. package/core/System/Controls/Text.nm +129 -0
  17. package/core/System/Controls/TextBox.nm +157 -0
  18. package/core/System/Controls/Window.nm +280 -0
  19. package/core/System/Disposable.nm +8 -0
  20. package/core/System/Enumerable.nm +10 -0
  21. package/core/System/Equatable.nm +10 -0
  22. package/core/System/Graph.nm +68 -0
  23. package/core/System/Hashable.nm +13 -0
  24. package/core/System/Init.nm +21 -0
  25. package/core/System/LinkedList.nm +64 -0
  26. package/core/System/List.nm +44 -0
  27. package/core/System/Map.nm +153 -0
  28. package/core/System/Math.nm +54 -0
  29. package/core/System/Mutex.nm +78 -0
  30. package/core/System/Nursery.nm +27 -0
  31. package/core/System/Sendable.nm +9 -0
  32. package/core/System/Set.nm +97 -0
  33. package/core/System/Stream/Directory.nm +176 -0
  34. package/core/System/Stream/File.nm +432 -0
  35. package/core/System/Stream/Http.nm +453 -0
  36. package/core/System/String.nm +154 -0
  37. package/core/System/StringBuilder.nm +249 -0
  38. package/core/System/Stringable.nm +8 -0
  39. package/core/System/Task.nm +263 -0
  40. package/core/System/Test.nm +241 -0
  41. package/core/System/Text/Json.nm +377 -0
  42. package/core/System/Text/JsonTree.nm +187 -0
  43. package/core/System/Text/Regex.nm +655 -0
  44. package/core/System/Time.nm +112 -0
  45. package/core/System/Tree.nm +70 -0
  46. package/core/System/Viewable.nm +27 -0
  47. package/core/System/bool.nm +66 -0
  48. package/core/System/char.nm +42 -0
  49. package/core/System/float.nm +43 -0
  50. package/core/System/int.nm +54 -0
  51. package/core/System/int64.nm +42 -0
  52. package/core/System/int8.nm +42 -0
  53. package/core/System/uint.nm +42 -0
  54. package/core/System/uint64.nm +42 -0
  55. package/core/System/uint8.nm +42 -0
  56. package/core/docs/System/Ansi.md +40 -0
  57. package/core/docs/System/Array.md +16 -0
  58. package/core/docs/System/BigInt.md +30 -0
  59. package/core/docs/System/Buffer.md +31 -0
  60. package/core/docs/System/Channel.md +10 -0
  61. package/core/docs/System/ClassBuffer.md +15 -0
  62. package/core/docs/System/Console.md +13 -0
  63. package/core/docs/System/Controls/Button.md +12 -0
  64. package/core/docs/System/Controls/CheckBox.md +15 -0
  65. package/core/docs/System/Controls/Container.md +82 -0
  66. package/core/docs/System/Controls/Control.md +5 -0
  67. package/core/docs/System/Controls/Geometry.md +26 -0
  68. package/core/docs/System/Controls/Layout.md +37 -0
  69. package/core/docs/System/Controls/LayoutParams.md +13 -0
  70. package/core/docs/System/Controls/Text.md +12 -0
  71. package/core/docs/System/Controls/TextBox.md +13 -0
  72. package/core/docs/System/Controls/Window.md +20 -0
  73. package/core/docs/System/Disposable.md +5 -0
  74. package/core/docs/System/Enumerable.md +5 -0
  75. package/core/docs/System/Graph.md +17 -0
  76. package/core/docs/System/Init.md +9 -0
  77. package/core/docs/System/LinkedList.md +16 -0
  78. package/core/docs/System/List.md +13 -0
  79. package/core/docs/System/Map.md +14 -0
  80. package/core/docs/System/Math.md +11 -0
  81. package/core/docs/System/Mutex.md +10 -0
  82. package/core/docs/System/Nursery.md +5 -0
  83. package/core/docs/System/Sendable.md +5 -0
  84. package/core/docs/System/Set.md +14 -0
  85. package/core/docs/System/Stream/Directory.md +12 -0
  86. package/core/docs/System/Stream/File.md +21 -0
  87. package/core/docs/System/String.md +14 -0
  88. package/core/docs/System/StringBuilder.md +12 -0
  89. package/core/docs/System/Stringable.md +5 -0
  90. package/core/docs/System/Task.md +15 -0
  91. package/core/docs/System/Text/Json.md +12 -0
  92. package/core/docs/System/Text/JsonTree.md +21 -0
  93. package/core/docs/System/Text/Regex.md +12 -0
  94. package/core/docs/System/Time.md +11 -0
  95. package/core/docs/System/Tree.md +18 -0
  96. package/core/docs/System/Viewable.md +5 -0
  97. package/core/docs/System/bool.md +9 -0
  98. package/core/docs/System/char.md +9 -0
  99. package/core/docs/System/float.md +9 -0
  100. package/core/docs/System/int.md +10 -0
  101. package/core/docs/System/int64.md +9 -0
  102. package/core/docs/System/int8.md +9 -0
  103. package/core/docs/System/uint.md +9 -0
  104. package/core/docs/System/uint64.md +9 -0
  105. package/core/docs/System/uint8.md +9 -0
  106. package/core/package.jsonc +4 -0
  107. package/dist/index.mjs +417 -5490
  108. package/package.json +33 -30
  109. package/src/args.ts +171 -0
  110. package/src/index.ts +53 -104
  111. package/src/init.ts +128 -0
  112. package/src/test.ts +6 -2
  113. package/test/fixtures/build/calc.test +0 -0
  114. package/test/fixtures/build/calc.test.c +0 -969
  115. package/test/fixtures/build/main.h +0 -170
  116. package/test/fixtures/calc.test.nm +0 -32
  117. package/tsconfig.json +0 -21
  118. package/vite.config.ts +0 -7
@@ -0,0 +1,241 @@
1
+ // The runtime half of `nomen test`.
2
+ //
3
+ // `Tester` is handed to every `pub func <name> = (ref Tester t)` in a
4
+ // `*.test.nm` file by a `main` that the CLI generates. It records assertion
5
+ // results and benchmark statistics, and streams them to stdout as
6
+ // machine-readable records that the CLI parses back and renders.
7
+ //
8
+ // Record grammar — one record per line. Every record begins with the literal
9
+ // prefix "\nomen|" (backslash + "nomen|") so the CLI can recognise it, and its
10
+ // fields are separated by "|":
11
+ //
12
+ // \nomen|start|<test>
13
+ // \nomen|fail|<test>|<message>
14
+ // \nomen|done|<test>|<passed>|<failed>|<ns>
15
+ // \nomen|bench|<label>|<n>|<min>|<median>|<max>|<mean>|<stddev>
16
+ //
17
+ // A leading backslash was chosen over a control character because the C and
18
+ // aarch64 backends both mis-parse a "\x1f" escape that is immediately followed
19
+ // by an ASCII letter. "|" can still appear inside a <message>, but the CLI
20
+ // only splits fields up to the fixed arity of each record kind, so the
21
+ // message is taken verbatim from the remainder. Anything a test prints that
22
+ // does not start with "\nomen|" is forwarded verbatim and shown beneath the
23
+ // file when it fails.
24
+ //
25
+ // Escaping note: Nomen string escapes pass through to the target language
26
+ // (the C compiler / assembler), which then interpret them. So to emit a
27
+ // LITERAL backslash at runtime the source must write a doubled "\\": a single
28
+ // "\" would have "\n" read as a newline. The record strings below therefore
29
+ // use "\\nomen|", which the backend emits as "\\nomen|" and the C/assembler
30
+ // collapses to the runtime "\nomen|".
31
+ //
32
+ // See TESTING.md for the full design.
33
+
34
+ /**
35
+ * Records assertions and benchmarks for one test file.
36
+ *
37
+ * A test function receives the tester by mutable reference:
38
+ *
39
+ * import System/Test
40
+ *
41
+ * pub func test_add = (ref Tester t) {
42
+ * t.expect(add(1, 1) == 2, "1 + 1 should be 2")
43
+ * }
44
+ *
45
+ * Once an assertion in a test fails the remaining assertions in that test are
46
+ * skipped, so a single root cause reports as a single failure. Check
47
+ * `t.has_failed` to bail out of expensive follow-up work yourself.
48
+ **/
49
+ pub class Tester {
50
+ // Has the *current* test recorded a failure? Reset by `begin_test`.
51
+ pub var bool has_failed = false
52
+
53
+ // Assertion tallies for the current test.
54
+ var int passed = 0
55
+ var int failed = 0
56
+
57
+ // Tallies for the whole file, so `done` records stay per-test while the
58
+ // process still knows whether anything failed overall.
59
+ var int total_failed = 0
60
+
61
+ var string current = ""
62
+ var uint64 started = 0
63
+
64
+ // Benchmark capture state. `bench`/`bench_n` record the label and sample
65
+ // count here; the `nomen test` harness reads them after running the test
66
+ // function and drives the actual timing loop (Nomen can't store or call a
67
+ // function pointer, so the harness measures `bench_fn` itself). `bench_fn`
68
+ // is reconstructed by the harness from the call site, not stored here.
69
+ var bool bench_pending = false
70
+ var string bench_label = ""
71
+ var int bench_samples = 1000
72
+
73
+ // (harness) Start timing `name` and clear the per-test state. Called by
74
+ // the `main` that `nomen test` generates — not by test code.
75
+ pub func begin_test = (ref self, string name) {
76
+ self.has_failed = false
77
+ self.passed = 0
78
+ self.failed = 0
79
+ self.current = name
80
+ Console.write_line("\\nomen|start|" + name)
81
+ self.started = Time.now_ns()
82
+ }
83
+
84
+ // (harness) Close the current test and emit its `done` record.
85
+ pub func end_test = (ref self) {
86
+ const uint64 elapsed = Time.now_ns() - self.started
87
+ Console.write_line(
88
+ "\\nomen|done|" + self.current + "|\{self.passed}|\{self.failed}|\{elapsed}",
89
+ )
90
+ }
91
+
92
+ // (harness) Did anything in this file fail?
93
+ pub func any_failed = (self, out bool) {
94
+ return self.total_failed > 0
95
+ }
96
+
97
+ /**
98
+ * Record a passing or failing assertion. Does nothing once the current
99
+ * test has already failed.
100
+ *
101
+ * t.expect(result == 2, "add(1, 1) should be 2")
102
+ **/
103
+ pub func expect = (ref self, bool condition, string message) {
104
+ if self.has_failed {
105
+ return
106
+ }
107
+ if condition {
108
+ self.passed += 1
109
+ return
110
+ }
111
+ self.record_failure(message)
112
+ }
113
+
114
+ /**
115
+ * Record an unconditional failure. Useful for branches that should be
116
+ * unreachable.
117
+ *
118
+ * if !found {
119
+ * t.fail("expected to find the key")
120
+ * }
121
+ **/
122
+ pub func fail = (ref self, string message) {
123
+ if self.has_failed {
124
+ return
125
+ }
126
+ self.record_failure(message)
127
+ }
128
+
129
+ // Assert that a nullable value holds a value.
130
+ //
131
+ // Nomen has no generic methods, so there is one overload per nullable
132
+ // type the compiler can compare against `null`. Nullable *struct* values
133
+ // (`Point?`) are not supported by the backend yet — use
134
+ // `t.expect(p != null, "...")` once that gap closes.
135
+ pub func assert = (ref self, int? value, string message) {
136
+ self.expect(value != null, message)
137
+ }
138
+
139
+ pub func assert = (ref self, uint? value, string message) {
140
+ self.expect(value != null, message)
141
+ }
142
+
143
+ pub func assert = (ref self, int64? value, string message) {
144
+ self.expect(value != null, message)
145
+ }
146
+
147
+ pub func assert = (ref self, uint64? value, string message) {
148
+ self.expect(value != null, message)
149
+ }
150
+
151
+ pub func assert = (ref self, int8? value, string message) {
152
+ self.expect(value != null, message)
153
+ }
154
+
155
+ pub func assert = (ref self, uint8? value, string message) {
156
+ self.expect(value != null, message)
157
+ }
158
+
159
+ pub func assert = (ref self, float? value, string message) {
160
+ self.expect(value != null, message)
161
+ }
162
+
163
+ pub func assert = (ref self, bool? value, string message) {
164
+ self.expect(value != null, message)
165
+ }
166
+
167
+ pub func assert = (ref self, char? value, string message) {
168
+ self.expect(value != null, message)
169
+ }
170
+
171
+ pub func assert = (ref self, string? value, string message) {
172
+ self.expect(value != null, message)
173
+ }
174
+
175
+ /**
176
+ * Register a benchmark. The timing itself is run by the `nomen test`
177
+ * harness — Nomen cannot call a function pointer from a parameter (the C
178
+ * backend has no way to emit it), so `bench` only *captures* the function
179
+ * and the harness measures it and reports the result via `record_bench`.
180
+ *
181
+ * func add_once = () {
182
+ * const _ = add(1, 1)
183
+ * }
184
+ *
185
+ * pub func bench_add = (ref Tester t) {
186
+ * t.bench("add", add_once)
187
+ * }
188
+ *
189
+ * The harness warms up, then runs the function `t.bench_samples` times
190
+ * (default 1000, override with `bench_n`) and computes min / median /
191
+ * mean / max / stddev over the per-iteration durations.
192
+ **/
193
+ pub func bench = (ref self, string label, func () body) {
194
+ if self.has_failed {
195
+ return
196
+ }
197
+ self.bench_pending = true
198
+ self.bench_label = label
199
+ self.bench_samples = 1000
200
+ }
201
+
202
+ /**
203
+ * Like `bench`, but the harness runs exactly `samples` iterations. Use it
204
+ * for slow functions (where the default 1000 would dominate the suite) or
205
+ * for reproducible sample counts.
206
+ **/
207
+ pub func bench_n = (ref self, string label, func () body, int samples) {
208
+ if self.has_failed {
209
+ return
210
+ }
211
+ self.bench_pending = true
212
+ self.bench_label = label
213
+ self.bench_samples = samples
214
+ }
215
+
216
+ /**
217
+ * Emit a benchmark record. Called by the `nomen test` harness after it
218
+ * has measured `bench_fn` itself — durations are nanoseconds and the
219
+ * harness passes the summary statistics it computed.
220
+ *
221
+ * If a test has already recorded a failure, benchmarks are skipped and
222
+ * this is a no-op.
223
+ **/
224
+ pub func record_bench = (ref self, string label, int n, int min, int median, int max, float mean, float stddev) {
225
+ if self.has_failed {
226
+ return
227
+ }
228
+ Console.write_line(
229
+ "\\nomen|bench|" +
230
+ label +
231
+ "|\{n}|\{min}|\{median}|\{max}|\{mean}|\{stddev}",
232
+ )
233
+ }
234
+
235
+ func record_failure = (ref self, string message) {
236
+ self.failed += 1
237
+ self.total_failed += 1
238
+ self.has_failed = true
239
+ Console.write_line("\\nomen|fail|" + self.current + "|" + message)
240
+ }
241
+ }
@@ -0,0 +1,377 @@
1
+ // JSON serialize / deserialize for Nomen string values, written in pure Nomen.
2
+ //
3
+ // `serialize` quotes and escapes a string into a JSON string literal;
4
+ // `deserialize` parses a JSON string literal back into the raw value.
5
+ // Integer (de)serialization is handled by int.to_string() and int.parse()
6
+ // (see int.nm), so this struct only deals with JSON strings.
7
+ //
8
+ // `parse` / `stringify` use a JsonTree pool (flat Buffer-backed slot array)
9
+ // instead of per-node heap allocation, avoiding O(nodes) malloc/free per
10
+ // parse cycle. The caller creates a JsonTree once and resets it per document.
11
+
12
+ /**
13
+ * JSON serialization helpers — `serialize`/`deserialize` strings, `parse`/`stringify` via a JsonTree
14
+ **/
15
+ pub struct Json {
16
+ // Serialize a string to a JSON string literal, escaping the special
17
+ // characters ", \, newline, tab and carriage return.
18
+ pub func serialize = (string value, out string) {
19
+ var sb = StringBuilder()
20
+ sb.append_char('"')
21
+ var i = 0
22
+ var int len = value.length
23
+ while i < len; i += 1 {
24
+ var char c = value.at(i)
25
+ var int code = c as int
26
+ switch {
27
+ case code == 34 {
28
+ sb.append_string("\x5c\"")
29
+ }
30
+ case code == 92 {
31
+ sb.append_string("\x5c\x5c")
32
+ }
33
+ case code == 10 {
34
+ sb.append_string("\x5cn")
35
+ }
36
+ case code == 9 {
37
+ sb.append_string("\x5ct")
38
+ }
39
+ case code == 13 {
40
+ sb.append_string("\x5cr")
41
+ }
42
+ else {
43
+ sb.append_char(c)
44
+ }
45
+ }
46
+ }
47
+ sb.append_char('"')
48
+ return sb.to_string()
49
+ }
50
+
51
+ // Deserialize a JSON string literal to the raw, unescaped value.
52
+ pub func deserialize = (string json, out string) {
53
+ var sb = StringBuilder()
54
+ var int len = json.length
55
+ var i = 0
56
+ // skip up to the opening quote
57
+ while i < len; i += 1 {
58
+ if (json.at(i) as int) == 34 {
59
+ i += 1
60
+ break
61
+ }
62
+ }
63
+ // read until the unescaped closing quote, unescaping as we go
64
+ while i < len; i += 1 {
65
+ var char c = json.at(i)
66
+ var int code = c as int
67
+ if code == 34 {
68
+ break
69
+ }
70
+ if code == 92 {
71
+ i += 1
72
+ if i < len {
73
+ var char e = json.at(i)
74
+ var int ec = e as int
75
+ switch {
76
+ case ec == 110 {
77
+ sb.append_string("\n")
78
+ }
79
+ case ec == 116 {
80
+ sb.append_string("\t")
81
+ }
82
+ case ec == 114 {
83
+ sb.append_string("\r")
84
+ }
85
+ case ec == 34 {
86
+ sb.append_char('"')
87
+ }
88
+ case ec == 92 {
89
+ sb.append_string("\x5c")
90
+ }
91
+ else {
92
+ sb.append_char(e)
93
+ }
94
+ }
95
+ }
96
+ } else {
97
+ sb.append_char(c)
98
+ }
99
+ }
100
+ return sb.to_string()
101
+ }
102
+
103
+ // Parse a JSON document into tree. The caller provides a JsonTree pool
104
+ // which is reset and filled. Returns the index of the root node.
105
+ pub func parse = (string s, ref JsonTree tree, out int) {
106
+ tree.reset()
107
+ var pos = Buffer<int>()
108
+ pos.alloc_int(1)
109
+ pos.store_int(0, 0)
110
+ var int len = s.length
111
+ return json_parse_value(s, ref pos, len, ref tree)
112
+ }
113
+
114
+ // Serialize a node in the tree back to a JSON string.
115
+ pub func stringify = (ref JsonTree tree, int root, out string) {
116
+ var sb = StringBuilder()
117
+ json_ser_value(ref tree, root, ref sb)
118
+ return sb.to_string()
119
+ }
120
+ }
121
+
122
+ func json_skip_ws = (string s, ref Buffer<int> pos, int len) {
123
+ while pos.load_int(0) < len {
124
+ var int i = pos.load_int(0)
125
+ var int code = s.at(i) as int
126
+ if code == 32 || code == 9 || code == 10 || code == 13 {
127
+ pos.store_int(0, i + 1)
128
+ } else {
129
+ return
130
+ }
131
+ }
132
+ }
133
+
134
+ func json_parse_string = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
135
+ var int i = pos.load_int(0)
136
+ i += 1
137
+ var sb = StringBuilder()
138
+ while i < len; i += 1 {
139
+ var char c = s.at(i)
140
+ var int code = c as int
141
+ if code == 34 {
142
+ i += 1
143
+ break
144
+ }
145
+ if code == 92 {
146
+ i += 1
147
+ if i < len {
148
+ var char e = s.at(i)
149
+ var int ec = e as int
150
+ switch {
151
+ case ec == 110 {
152
+ sb.append_string("\n")
153
+ }
154
+ case ec == 116 {
155
+ sb.append_string("\t")
156
+ }
157
+ case ec == 114 {
158
+ sb.append_string("\r")
159
+ }
160
+ case ec == 34 {
161
+ sb.append_char('"')
162
+ }
163
+ case ec == 92 {
164
+ sb.append_string("\x5c")
165
+ }
166
+ else {
167
+ sb.append_char(e)
168
+ }
169
+ }
170
+ }
171
+ } else {
172
+ sb.append_char(c)
173
+ }
174
+ }
175
+ pos.store_int(0, i)
176
+ var int n = tree.alloc_node()
177
+ tree.set_kind(n, 3)
178
+ tree.set_text(n, sb.to_string())
179
+ return n
180
+ }
181
+
182
+ func json_parse_number = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
183
+ var int i = pos.load_int(0)
184
+ var int start = i
185
+ while i < len {
186
+ var int code = s.at(i) as int
187
+ if code == 45 || code == 43 || code == 46 || code == 101 || code == 69 || (code >= 48 && code <= 57) {
188
+ i += 1
189
+ } else {
190
+ break
191
+ }
192
+ }
193
+ pos.store_int(0, i)
194
+ var sb = StringBuilder()
195
+ var int j = start
196
+ while j < i; j += 1 {
197
+ sb.append_char(s.at(j))
198
+ }
199
+ var int n = tree.alloc_node()
200
+ tree.set_kind(n, 2)
201
+ tree.set_text(n, sb.to_string())
202
+ return n
203
+ }
204
+
205
+ func json_parse_literal = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
206
+ var int i = pos.load_int(0)
207
+ var int code = s.at(i) as int
208
+ var int n = tree.alloc_node()
209
+ var adv = 4
210
+ switch {
211
+ case code == 116 {
212
+ tree.set_kind(n, 1)
213
+ adv = 4
214
+ }
215
+ case code == 102 {
216
+ tree.set_kind(n, 6)
217
+ adv = 5
218
+ }
219
+ else {
220
+ tree.set_kind(n, 0)
221
+ adv = 4
222
+ }
223
+ }
224
+ pos.store_int(0, i + adv)
225
+ return n
226
+ }
227
+
228
+ func json_parse_value = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
229
+ json_skip_ws(s, ref pos, len)
230
+ var int i = pos.load_int(0)
231
+ if i >= len {
232
+ return tree.alloc_node()
233
+ }
234
+ var int code = s.at(i) as int
235
+ if code == 123 {
236
+ pos.store_int(0, i + 1)
237
+ var int n = tree.alloc_node()
238
+ tree.set_kind(n, 5)
239
+ tree.set_child(n, json_parse_pairs(s, ref pos, len, ref tree))
240
+ return n
241
+ }
242
+ if code == 91 {
243
+ pos.store_int(0, i + 1)
244
+ var int n = tree.alloc_node()
245
+ tree.set_kind(n, 4)
246
+ tree.set_child(n, json_parse_elements(s, ref pos, len, ref tree))
247
+ return n
248
+ }
249
+ if code == 34 {
250
+ return json_parse_string(s, ref pos, len, ref tree)
251
+ }
252
+ if code == 116 || code == 102 || code == 110 {
253
+ return json_parse_literal(s, ref pos, len, ref tree)
254
+ }
255
+ return json_parse_number(s, ref pos, len, ref tree)
256
+ }
257
+
258
+ func json_parse_elements = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
259
+ json_skip_ws(s, ref pos, len)
260
+ var int i = pos.load_int(0)
261
+ if i >= len {
262
+ return -1
263
+ }
264
+ if (s.at(i) as int) == 93 {
265
+ pos.store_int(0, i + 1)
266
+ return -1
267
+ }
268
+ var int elem = json_parse_value(s, ref pos, len, ref tree)
269
+ json_skip_ws(s, ref pos, len)
270
+ var int i2 = pos.load_int(0)
271
+ if i2 < len {
272
+ if (s.at(i2) as int) == 44 {
273
+ pos.store_int(0, i2 + 1)
274
+ }
275
+ }
276
+ tree.set_next(elem, json_parse_elements(s, ref pos, len, ref tree))
277
+ return elem
278
+ }
279
+
280
+ func json_parse_pairs = (string s, ref Buffer<int> pos, int len, ref JsonTree tree, out int) {
281
+ json_skip_ws(s, ref pos, len)
282
+ var int i = pos.load_int(0)
283
+ if i >= len {
284
+ return -1
285
+ }
286
+ if (s.at(i) as int) == 125 {
287
+ pos.store_int(0, i + 1)
288
+ return -1
289
+ }
290
+ json_skip_ws(s, ref pos, len)
291
+ var int key = json_parse_string(s, ref pos, len, ref tree)
292
+ json_skip_ws(s, ref pos, len)
293
+ var int i2 = pos.load_int(0)
294
+ if i2 < len {
295
+ if (s.at(i2) as int) == 58 {
296
+ pos.store_int(0, i2 + 1)
297
+ }
298
+ }
299
+ var int v = json_parse_value(s, ref pos, len, ref tree)
300
+ tree.set_val(key, v)
301
+ json_skip_ws(s, ref pos, len)
302
+ var int i3 = pos.load_int(0)
303
+ if i3 < len {
304
+ if (s.at(i3) as int) == 44 {
305
+ pos.store_int(0, i3 + 1)
306
+ }
307
+ }
308
+ tree.set_next(key, json_parse_pairs(s, ref pos, len, ref tree))
309
+ return key
310
+ }
311
+
312
+ func json_ser_list = (ref JsonTree tree, int first, ref StringBuilder sb) {
313
+ json_ser_value(ref tree, first, ref sb)
314
+ var int next = tree.get_next(first)
315
+ if next >= 0 {
316
+ sb.append_char(',')
317
+ json_ser_list(ref tree, next, ref sb)
318
+ }
319
+ }
320
+
321
+ func json_ser_pairs = (ref JsonTree tree, int first, ref StringBuilder sb) {
322
+ sb.append_char('"')
323
+ sb.append_string(tree.get_text(first))
324
+ sb.append_string("\":")
325
+ var int v = tree.get_val(first)
326
+ if v < 0 {
327
+ sb.append_string("null")
328
+ } else {
329
+ json_ser_value(ref tree, v, ref sb)
330
+ }
331
+ var int next = tree.get_next(first)
332
+ if next >= 0 {
333
+ sb.append_char(',')
334
+ json_ser_pairs(ref tree, next, ref sb)
335
+ }
336
+ }
337
+
338
+ func json_ser_value = (ref JsonTree tree, int n, ref StringBuilder sb) {
339
+ var int k = tree.get_kind(n)
340
+ if k == 0 {
341
+ sb.append_string("null")
342
+ return
343
+ }
344
+ if k == 1 {
345
+ sb.append_string("true")
346
+ return
347
+ }
348
+ if k == 6 {
349
+ sb.append_string("false")
350
+ return
351
+ }
352
+ if k == 2 {
353
+ sb.append_string(tree.get_text(n))
354
+ return
355
+ }
356
+ if k == 3 {
357
+ sb.append_char('"')
358
+ sb.append_string(tree.get_text(n))
359
+ sb.append_char('"')
360
+ return
361
+ }
362
+ if k == 4 {
363
+ sb.append_char('[')
364
+ var int child = tree.get_child(n)
365
+ if child >= 0 {
366
+ json_ser_list(ref tree, child, ref sb)
367
+ }
368
+ sb.append_char(']')
369
+ return
370
+ }
371
+ sb.append_char('{')
372
+ var int child = tree.get_child(n)
373
+ if child >= 0 {
374
+ json_ser_pairs(ref tree, child, ref sb)
375
+ }
376
+ sb.append_char('}')
377
+ }