@shd101wyy/yo 0.1.26 → 0.1.27
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/.github/skills/yo-async-effects/SKILL.md +4 -4
- package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
- package/.github/skills/yo-project-workflow/SKILL.md +6 -3
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
- package/.github/skills/yo-syntax/SKILL.md +7 -6
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +456 -438
- package/out/cjs/yo-cli.cjs +576 -543
- package/out/cjs/yo-lsp.cjs +559 -532
- package/out/esm/index.mjs +281 -263
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +13 -21
- package/std/allocator.yo +25 -40
- package/std/async.yo +3 -7
- package/std/build.yo +105 -151
- package/std/cli/arg_parser.yo +184 -169
- package/std/collections/array_list.yo +350 -314
- package/std/collections/btree_map.yo +142 -131
- package/std/collections/deque.yo +132 -128
- package/std/collections/hash_map.yo +542 -566
- package/std/collections/hash_set.yo +623 -687
- package/std/collections/linked_list.yo +275 -293
- package/std/collections/ordered_map.yo +113 -85
- package/std/collections/priority_queue.yo +73 -73
- package/std/crypto/md5.yo +191 -95
- package/std/crypto/random.yo +56 -64
- package/std/crypto/sha256.yo +151 -107
- package/std/encoding/base64.yo +87 -81
- package/std/encoding/hex.yo +43 -50
- package/std/encoding/html.yo +56 -81
- package/std/encoding/html_char_utils.yo +7 -13
- package/std/encoding/html_entities.yo +2248 -2253
- package/std/encoding/json.yo +316 -224
- package/std/encoding/punycode.yo +86 -116
- package/std/encoding/toml.yo +67 -66
- package/std/encoding/utf16.yo +37 -44
- package/std/env.yo +62 -91
- package/std/error.yo +7 -15
- package/std/fmt/display.yo +5 -9
- package/std/fmt/index.yo +8 -14
- package/std/fmt/to_string.yo +330 -315
- package/std/fmt/writer.yo +58 -87
- package/std/fs/dir.yo +83 -102
- package/std/fs/file.yo +147 -180
- package/std/fs/metadata.yo +45 -78
- package/std/fs/temp.yo +55 -65
- package/std/fs/types.yo +27 -40
- package/std/fs/walker.yo +53 -68
- package/std/gc.yo +5 -8
- package/std/glob.yo +30 -43
- package/std/http/client.yo +107 -120
- package/std/http/http.yo +106 -96
- package/std/http/index.yo +4 -6
- package/std/imm/list.yo +88 -93
- package/std/imm/map.yo +528 -464
- package/std/imm/set.yo +52 -57
- package/std/imm/sorted_map.yo +340 -286
- package/std/imm/sorted_set.yo +57 -63
- package/std/imm/string.yo +404 -345
- package/std/imm/vec.yo +173 -181
- package/std/io/reader.yo +3 -6
- package/std/io/writer.yo +4 -8
- package/std/libc/assert.yo +5 -9
- package/std/libc/ctype.yo +32 -22
- package/std/libc/dirent.yo +26 -25
- package/std/libc/errno.yo +164 -90
- package/std/libc/fcntl.yo +52 -45
- package/std/libc/float.yo +66 -44
- package/std/libc/limits.yo +42 -33
- package/std/libc/math.yo +53 -82
- package/std/libc/signal.yo +72 -47
- package/std/libc/stdatomic.yo +217 -188
- package/std/libc/stdint.yo +5 -29
- package/std/libc/stdio.yo +5 -29
- package/std/libc/stdlib.yo +32 -39
- package/std/libc/string.yo +5 -23
- package/std/libc/sys/stat.yo +58 -56
- package/std/libc/time.yo +5 -19
- package/std/libc/unistd.yo +5 -20
- package/std/libc/wctype.yo +6 -9
- package/std/libc/windows.yo +26 -30
- package/std/log.yo +41 -55
- package/std/net/addr.yo +102 -97
- package/std/net/dns.yo +27 -28
- package/std/net/errors.yo +50 -49
- package/std/net/tcp.yo +113 -124
- package/std/net/udp.yo +55 -66
- package/std/os/env.yo +35 -33
- package/std/os/signal.yo +15 -25
- package/std/path.yo +276 -311
- package/std/prelude.yo +6304 -4315
- package/std/process/command.yo +87 -103
- package/std/process/index.yo +12 -31
- package/std/regex/compiler.yo +196 -95
- package/std/regex/flags.yo +58 -39
- package/std/regex/index.yo +157 -173
- package/std/regex/match.yo +20 -31
- package/std/regex/node.yo +134 -152
- package/std/regex/parser.yo +283 -259
- package/std/regex/unicode.yo +172 -202
- package/std/regex/vm.yo +155 -171
- package/std/string/index.yo +5 -7
- package/std/string/rune.yo +45 -55
- package/std/string/string.yo +937 -964
- package/std/string/string_builder.yo +94 -104
- package/std/string/unicode.yo +46 -64
- package/std/sync/channel.yo +72 -73
- package/std/sync/cond.yo +31 -36
- package/std/sync/mutex.yo +30 -32
- package/std/sync/once.yo +13 -16
- package/std/sync/rwlock.yo +26 -31
- package/std/sync/waitgroup.yo +20 -25
- package/std/sys/advise.yo +16 -24
- package/std/sys/bufio/buf_reader.yo +77 -93
- package/std/sys/bufio/buf_writer.yo +52 -65
- package/std/sys/clock.yo +4 -9
- package/std/sys/constants.yo +77 -61
- package/std/sys/copy.yo +4 -10
- package/std/sys/dir.yo +26 -43
- package/std/sys/dns.yo +41 -61
- package/std/sys/errors.yo +95 -103
- package/std/sys/events.yo +45 -57
- package/std/sys/externs.yo +319 -267
- package/std/sys/fallocate.yo +7 -11
- package/std/sys/fcntl.yo +14 -22
- package/std/sys/file.yo +26 -40
- package/std/sys/future.yo +5 -8
- package/std/sys/iov.yo +12 -25
- package/std/sys/lock.yo +12 -13
- package/std/sys/mmap.yo +38 -43
- package/std/sys/path.yo +3 -8
- package/std/sys/perm.yo +7 -21
- package/std/sys/pipe.yo +5 -12
- package/std/sys/process.yo +23 -29
- package/std/sys/seek.yo +10 -12
- package/std/sys/signal.yo +7 -13
- package/std/sys/signals.yo +52 -35
- package/std/sys/socket.yo +63 -58
- package/std/sys/socketpair.yo +3 -6
- package/std/sys/sockinfo.yo +11 -20
- package/std/sys/statfs.yo +11 -34
- package/std/sys/statx.yo +25 -52
- package/std/sys/sysinfo.yo +15 -20
- package/std/sys/tcp.yo +62 -92
- package/std/sys/temp.yo +5 -9
- package/std/sys/time.yo +5 -15
- package/std/sys/timer.yo +6 -11
- package/std/sys/tty.yo +10 -18
- package/std/sys/udp.yo +22 -39
- package/std/sys/umask.yo +3 -6
- package/std/sys/unix.yo +33 -52
- package/std/testing/bench.yo +49 -52
- package/std/thread.yo +10 -15
- package/std/time/datetime.yo +105 -89
- package/std/time/duration.yo +43 -56
- package/std/time/instant.yo +13 -18
- package/std/time/sleep.yo +5 -9
- package/std/url/index.yo +184 -209
- package/std/worker.yo +6 -10
package/std/encoding/json.yo
CHANGED
|
@@ -12,21 +12,18 @@
|
|
|
12
12
|
//! v := json_parse(`{"x": 1}`);
|
|
13
13
|
//! println(json_stringify(v));
|
|
14
14
|
//! ```
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
{
|
|
19
|
-
{
|
|
20
|
-
{ ToString } :: import "../fmt";
|
|
21
|
-
|
|
15
|
+
open(import("../string"));
|
|
16
|
+
{ ArrayList } :: import("../collections/array_list");
|
|
17
|
+
{ snprintf } :: import("../libc/stdio");
|
|
18
|
+
{ Error, AnyError, Exception } :: import("../error");
|
|
19
|
+
{ ToString } :: import("../fmt");
|
|
22
20
|
// ============================================================================
|
|
23
21
|
// JsonError
|
|
24
22
|
// ============================================================================
|
|
25
|
-
|
|
26
23
|
/// JSON parsing error type.
|
|
27
24
|
JsonError :: enum(
|
|
28
25
|
/// Encountered an unexpected character at the given position.
|
|
29
|
-
UnexpectedChar(ch: u8, pos: usize),
|
|
26
|
+
UnexpectedChar(ch : u8, pos : usize),
|
|
30
27
|
/// Input ended unexpectedly.
|
|
31
28
|
UnexpectedEnd,
|
|
32
29
|
/// Failed to parse a numeric literal.
|
|
@@ -36,162 +33,156 @@ JsonError :: enum(
|
|
|
36
33
|
/// Invalid Unicode escape in a string.
|
|
37
34
|
InvalidUnicode,
|
|
38
35
|
/// Other error with a descriptive message.
|
|
39
|
-
Other(msg: String)
|
|
36
|
+
Other(msg : String)
|
|
40
37
|
);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
impl(
|
|
39
|
+
JsonError,
|
|
40
|
+
ToString(
|
|
41
|
+
to_string : (
|
|
42
|
+
self ->
|
|
43
|
+
match(
|
|
44
|
+
self,
|
|
45
|
+
.UnexpectedChar(ch, pos) => `unexpected character at position ${pos}`,
|
|
46
|
+
.UnexpectedEnd => `unexpected end of input`,
|
|
47
|
+
.InvalidNumber => `invalid number`,
|
|
48
|
+
.InvalidEscape => `invalid escape sequence`,
|
|
49
|
+
.InvalidUnicode => `invalid unicode`,
|
|
50
|
+
.Other(msg) => `JSON error: ${msg}`
|
|
51
|
+
)
|
|
51
52
|
)
|
|
52
53
|
)
|
|
53
|
-
)
|
|
54
|
-
|
|
54
|
+
);
|
|
55
55
|
impl(JsonError, Error());
|
|
56
|
-
|
|
57
|
-
export JsonError;
|
|
58
|
-
|
|
56
|
+
export(JsonError);
|
|
59
57
|
// ============================================================================
|
|
60
58
|
// JsonValue
|
|
61
59
|
// ============================================================================
|
|
62
|
-
|
|
63
60
|
/// Dynamically-typed JSON value tree.
|
|
64
61
|
JsonValue :: enum(
|
|
65
62
|
/// JSON null.
|
|
66
63
|
Null,
|
|
67
64
|
/// JSON boolean.
|
|
68
|
-
Bool(value: bool),
|
|
65
|
+
Bool(value : bool),
|
|
69
66
|
/// JSON number (IEEE 754 double).
|
|
70
|
-
Number(value: f64),
|
|
67
|
+
Number(value : f64),
|
|
71
68
|
/// JSON string.
|
|
72
|
-
Str(value: String),
|
|
69
|
+
Str(value : String),
|
|
73
70
|
/// JSON array of values.
|
|
74
|
-
Array(items: ArrayList(Self)),
|
|
71
|
+
Array(items : ArrayList(Self)),
|
|
75
72
|
/// JSON object with ordered key-value pairs.
|
|
76
|
-
Object(keys: ArrayList(String), values: ArrayList(Self))
|
|
73
|
+
Object(keys : ArrayList(String), values : ArrayList(Self))
|
|
77
74
|
);
|
|
78
|
-
|
|
79
75
|
// ============================================================================
|
|
80
76
|
// JsonKV - key/value pair convenience struct for Object
|
|
81
77
|
// ============================================================================
|
|
82
|
-
|
|
83
78
|
/// Key-value pair for JSON object entries.
|
|
84
79
|
JsonKV :: struct(
|
|
85
|
-
key
|
|
80
|
+
key : String,
|
|
86
81
|
value : JsonValue
|
|
87
82
|
);
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
impl(
|
|
84
|
+
JsonValue,
|
|
90
85
|
/// Get a field from an Object value by key. Returns `.None` if not an Object or key is missing.
|
|
91
|
-
get : (fn(self: Self, key: String) -> Option(JsonValue))(
|
|
92
|
-
match(
|
|
86
|
+
get : (fn(self : Self, key : String) -> Option(JsonValue))(
|
|
87
|
+
match(
|
|
88
|
+
self,
|
|
93
89
|
.Object(keys, values) => {
|
|
94
90
|
i := usize(0);
|
|
95
|
-
while
|
|
91
|
+
while(i < keys.len(), i = (i + usize(1)), {
|
|
96
92
|
cond(
|
|
97
93
|
(keys.get(i).unwrap() == key) => {
|
|
98
|
-
return
|
|
94
|
+
return(.Some(values.get(i).unwrap()));
|
|
99
95
|
},
|
|
100
96
|
true => ()
|
|
101
97
|
);
|
|
102
|
-
};
|
|
98
|
+
});
|
|
103
99
|
.None
|
|
104
100
|
},
|
|
105
|
-
_
|
|
101
|
+
_ =>.None
|
|
106
102
|
)
|
|
107
103
|
),
|
|
108
|
-
|
|
109
104
|
/// Get an element from an Array value by index.
|
|
110
|
-
at : (fn(self: Self, index: usize) -> Option(JsonValue))(
|
|
111
|
-
match(
|
|
105
|
+
at : (fn(self : Self, index : usize) -> Option(JsonValue))(
|
|
106
|
+
match(
|
|
107
|
+
self,
|
|
112
108
|
.Array(items) => items.get(index),
|
|
113
|
-
_
|
|
109
|
+
_ =>.None
|
|
114
110
|
)
|
|
115
111
|
),
|
|
116
|
-
|
|
117
112
|
/// Extract the boolean value, or `.None` if not a `Bool`.
|
|
118
|
-
as_bool : (fn(self: Self) -> Option(bool))(
|
|
119
|
-
match(
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
as_bool : (fn(self : Self) -> Option(bool))(
|
|
114
|
+
match(
|
|
115
|
+
self,
|
|
116
|
+
.Bool(b) =>.Some(b),
|
|
117
|
+
_ =>.None
|
|
122
118
|
)
|
|
123
119
|
),
|
|
124
|
-
|
|
125
120
|
/// Extract the numeric value, or `.None` if not a `Number`.
|
|
126
|
-
as_number : (fn(self: Self) -> Option(f64))(
|
|
127
|
-
match(
|
|
128
|
-
|
|
129
|
-
|
|
121
|
+
as_number : (fn(self : Self) -> Option(f64))(
|
|
122
|
+
match(
|
|
123
|
+
self,
|
|
124
|
+
.Number(n) =>.Some(n),
|
|
125
|
+
_ =>.None
|
|
130
126
|
)
|
|
131
127
|
),
|
|
132
|
-
|
|
133
128
|
/// Extract the string value, or `.None` if not a `Str`.
|
|
134
|
-
as_string : (fn(self: Self) -> Option(String))(
|
|
135
|
-
match(
|
|
136
|
-
|
|
137
|
-
|
|
129
|
+
as_string : (fn(self : Self) -> Option(String))(
|
|
130
|
+
match(
|
|
131
|
+
self,
|
|
132
|
+
.Str(s) =>.Some(s),
|
|
133
|
+
_ =>.None
|
|
138
134
|
)
|
|
139
135
|
),
|
|
140
|
-
|
|
141
136
|
/// Extract the array items, or `.None` if not an `Array`.
|
|
142
|
-
as_array : (fn(self: Self) -> Option(ArrayList(JsonValue)))(
|
|
143
|
-
match(
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
as_array : (fn(self : Self) -> Option(ArrayList(JsonValue)))(
|
|
138
|
+
match(
|
|
139
|
+
self,
|
|
140
|
+
.Array(items) =>.Some(items),
|
|
141
|
+
_ =>.None
|
|
146
142
|
)
|
|
147
143
|
),
|
|
148
|
-
|
|
149
144
|
/// Extract object entries as `ArrayList(JsonKV)`, or `.None` if not an `Object`.
|
|
150
|
-
as_object : (fn(self: Self) -> Option(ArrayList(JsonKV)))(
|
|
151
|
-
match(
|
|
145
|
+
as_object : (fn(self : Self) -> Option(ArrayList(JsonKV)))(
|
|
146
|
+
match(
|
|
147
|
+
self,
|
|
152
148
|
.Object(keys, values) => {
|
|
153
149
|
result := ArrayList(JsonKV).new();
|
|
154
150
|
i := usize(0);
|
|
155
|
-
while
|
|
156
|
-
result.push(JsonKV(key: keys.get(i).unwrap(), value: values.get(i).unwrap()));
|
|
157
|
-
};
|
|
151
|
+
while(i < keys.len(), i = (i + usize(1)), {
|
|
152
|
+
result.push(JsonKV(key : keys.get(i).unwrap(), value : values.get(i).unwrap()));
|
|
153
|
+
});
|
|
158
154
|
.Some(result)
|
|
159
155
|
},
|
|
160
|
-
_
|
|
156
|
+
_ =>.None
|
|
161
157
|
)
|
|
162
158
|
)
|
|
163
159
|
);
|
|
164
|
-
|
|
165
|
-
export JsonValue, JsonKV;
|
|
166
|
-
|
|
160
|
+
export(JsonValue, JsonKV);
|
|
167
161
|
// ============================================================================
|
|
168
162
|
// Parser state
|
|
169
163
|
// ============================================================================
|
|
170
|
-
|
|
171
164
|
_Parser :: object(
|
|
172
165
|
src : str,
|
|
173
166
|
pos : usize
|
|
174
167
|
);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
new : (fn(src: str) -> Self)(
|
|
178
|
-
Self(src: src, pos: usize(0))
|
|
168
|
+
impl(
|
|
169
|
+
_Parser,
|
|
170
|
+
new : (fn(src : str) -> Self)(
|
|
171
|
+
Self(src : src, pos : usize(0))
|
|
179
172
|
),
|
|
180
|
-
|
|
181
|
-
peek : (fn(self: Self) -> Option(u8))(
|
|
173
|
+
peek : (fn(self : Self) -> Option(u8))(
|
|
182
174
|
cond(
|
|
183
|
-
(self.pos < self.src.len())
|
|
184
|
-
true
|
|
175
|
+
(self.pos < self.src.len()) =>.Some(self.src.bytes(self.pos)),
|
|
176
|
+
true =>.None
|
|
185
177
|
)
|
|
186
178
|
),
|
|
187
|
-
|
|
188
|
-
advance : (fn(self: Self) -> unit)({
|
|
179
|
+
advance : (fn(self : Self) -> unit)({
|
|
189
180
|
self.pos = (self.pos + usize(1));
|
|
190
181
|
}),
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
182
|
+
skip_ws : (fn(self : Self) -> unit)({
|
|
183
|
+
while(runtime(true), {
|
|
184
|
+
match(
|
|
185
|
+
self.peek(),
|
|
195
186
|
.None => break,
|
|
196
187
|
.Some(c) => {
|
|
197
188
|
cond(
|
|
@@ -202,52 +193,69 @@ impl(_Parser,
|
|
|
202
193
|
);
|
|
203
194
|
}
|
|
204
195
|
);
|
|
205
|
-
};
|
|
196
|
+
});
|
|
206
197
|
}),
|
|
207
|
-
|
|
208
|
-
expect : (fn(self: Self, ch: u8) -> Result(unit, JsonError))({
|
|
198
|
+
expect : (fn(self : Self, ch : u8) -> Result(unit, JsonError))({
|
|
209
199
|
self.skip_ws();
|
|
210
|
-
match(
|
|
211
|
-
.
|
|
200
|
+
match(
|
|
201
|
+
self.peek(),
|
|
202
|
+
.None =>.Err(.UnexpectedEnd),
|
|
212
203
|
.Some(c) =>
|
|
213
204
|
cond(
|
|
214
205
|
(c == ch) => {
|
|
215
206
|
self.advance();
|
|
216
207
|
.Ok(())
|
|
217
208
|
},
|
|
218
|
-
true
|
|
209
|
+
true =>.Err(.UnexpectedChar(c, self.pos))
|
|
219
210
|
)
|
|
220
211
|
)
|
|
221
212
|
}),
|
|
222
|
-
|
|
223
|
-
parse_string : (fn(self: Self) -> Result(String, JsonError))({
|
|
213
|
+
parse_string : (fn(self : Self) -> Result(String, JsonError))({
|
|
224
214
|
self.advance(); // skip opening '"'
|
|
225
215
|
bytes := ArrayList(u8).new();
|
|
226
|
-
while
|
|
227
|
-
match(
|
|
228
|
-
.
|
|
216
|
+
while(runtime(true), {
|
|
217
|
+
match(
|
|
218
|
+
self.peek(),
|
|
219
|
+
.None => {
|
|
220
|
+
return(.Err(.UnexpectedEnd));
|
|
221
|
+
},
|
|
229
222
|
.Some(c) => {
|
|
230
223
|
cond(
|
|
231
|
-
(c == u8(34)) => {
|
|
224
|
+
(c == u8(34)) => {
|
|
225
|
+
// '"'
|
|
232
226
|
self.advance();
|
|
233
227
|
break;
|
|
234
228
|
},
|
|
235
|
-
(c == u8(92)) => {
|
|
229
|
+
(c == u8(92)) => {
|
|
230
|
+
// '\'
|
|
236
231
|
self.advance();
|
|
237
|
-
match(
|
|
238
|
-
.
|
|
232
|
+
match(
|
|
233
|
+
self.peek(),
|
|
234
|
+
.None => {
|
|
235
|
+
return(.Err(.UnexpectedEnd));
|
|
236
|
+
},
|
|
239
237
|
.Some(e) => {
|
|
240
238
|
self.advance();
|
|
241
239
|
cond(
|
|
242
|
-
(e == u8(110)) => bytes.push(u8(10)),
|
|
243
|
-
|
|
244
|
-
(e == u8(
|
|
245
|
-
|
|
246
|
-
(e == u8(
|
|
247
|
-
|
|
248
|
-
(e == u8(
|
|
249
|
-
|
|
250
|
-
|
|
240
|
+
(e == u8(110)) => bytes.push(u8(10)),
|
|
241
|
+
// \n
|
|
242
|
+
(e == u8(116)) => bytes.push(u8(9)),
|
|
243
|
+
// \t
|
|
244
|
+
(e == u8(114)) => bytes.push(u8(13)),
|
|
245
|
+
// \r
|
|
246
|
+
(e == u8(34)) => bytes.push(u8(34)),
|
|
247
|
+
// \"
|
|
248
|
+
(e == u8(92)) => bytes.push(u8(92)),
|
|
249
|
+
// \\
|
|
250
|
+
(e == u8(47)) => bytes.push(u8(47)),
|
|
251
|
+
// \/
|
|
252
|
+
(e == u8(98)) => bytes.push(u8(8)),
|
|
253
|
+
// \b
|
|
254
|
+
(e == u8(102)) => bytes.push(u8(12)),
|
|
255
|
+
// \f
|
|
256
|
+
true => {
|
|
257
|
+
return(.Err(.InvalidEscape));
|
|
258
|
+
}
|
|
251
259
|
);
|
|
252
260
|
}
|
|
253
261
|
);
|
|
@@ -259,23 +267,25 @@ impl(_Parser,
|
|
|
259
267
|
);
|
|
260
268
|
}
|
|
261
269
|
);
|
|
262
|
-
};
|
|
270
|
+
});
|
|
263
271
|
.Ok(String.from_bytes(bytes))
|
|
264
272
|
}),
|
|
265
|
-
|
|
266
|
-
parse_number : (fn(self: Self) -> Result(f64, JsonError))({
|
|
273
|
+
parse_number : (fn(self : Self) -> Result(f64, JsonError))({
|
|
267
274
|
start := self.pos;
|
|
268
|
-
match(
|
|
275
|
+
match(
|
|
276
|
+
self.peek(),
|
|
269
277
|
.Some(c) => {
|
|
270
278
|
cond(
|
|
271
|
-
(c == u8(45)) => self.advance(),
|
|
279
|
+
(c == u8(45)) => self.advance(),
|
|
280
|
+
// '-'
|
|
272
281
|
true => ()
|
|
273
282
|
);
|
|
274
283
|
},
|
|
275
284
|
.None => ()
|
|
276
285
|
);
|
|
277
|
-
while
|
|
278
|
-
match(
|
|
286
|
+
while(runtime(true), {
|
|
287
|
+
match(
|
|
288
|
+
self.peek(),
|
|
279
289
|
.Some(c) => {
|
|
280
290
|
cond(
|
|
281
291
|
((c >= u8(48)) && (c <= u8(57))) => self.advance(),
|
|
@@ -284,14 +294,17 @@ impl(_Parser,
|
|
|
284
294
|
},
|
|
285
295
|
.None => break
|
|
286
296
|
);
|
|
287
|
-
};
|
|
288
|
-
match(
|
|
297
|
+
});
|
|
298
|
+
match(
|
|
299
|
+
self.peek(),
|
|
289
300
|
.Some(c) => {
|
|
290
301
|
cond(
|
|
291
|
-
(c == u8(46)) => {
|
|
302
|
+
(c == u8(46)) => {
|
|
303
|
+
// '.'
|
|
292
304
|
self.advance();
|
|
293
|
-
while
|
|
294
|
-
match(
|
|
305
|
+
while(runtime(true), {
|
|
306
|
+
match(
|
|
307
|
+
self.peek(),
|
|
295
308
|
.Some(d) => {
|
|
296
309
|
cond(
|
|
297
310
|
((d >= u8(48)) && (d <= u8(57))) => self.advance(),
|
|
@@ -300,19 +313,22 @@ impl(_Parser,
|
|
|
300
313
|
},
|
|
301
314
|
.None => break
|
|
302
315
|
);
|
|
303
|
-
};
|
|
316
|
+
});
|
|
304
317
|
},
|
|
305
318
|
true => ()
|
|
306
319
|
);
|
|
307
320
|
},
|
|
308
321
|
.None => ()
|
|
309
322
|
);
|
|
310
|
-
match(
|
|
323
|
+
match(
|
|
324
|
+
self.peek(),
|
|
311
325
|
.Some(c) => {
|
|
312
326
|
cond(
|
|
313
|
-
((c == u8(101)) || (c == u8(69))) => {
|
|
327
|
+
((c == u8(101)) || (c == u8(69))) => {
|
|
328
|
+
// 'e' or 'E'
|
|
314
329
|
self.advance();
|
|
315
|
-
match(
|
|
330
|
+
match(
|
|
331
|
+
self.peek(),
|
|
316
332
|
.Some(s) => {
|
|
317
333
|
cond(
|
|
318
334
|
((s == u8(43)) || (s == u8(45))) => self.advance(),
|
|
@@ -321,8 +337,9 @@ impl(_Parser,
|
|
|
321
337
|
},
|
|
322
338
|
.None => ()
|
|
323
339
|
);
|
|
324
|
-
while
|
|
325
|
-
match(
|
|
340
|
+
while(runtime(true), {
|
|
341
|
+
match(
|
|
342
|
+
self.peek(),
|
|
326
343
|
.Some(d) => {
|
|
327
344
|
cond(
|
|
328
345
|
((d >= u8(48)) && (d <= u8(57))) => self.advance(),
|
|
@@ -331,7 +348,7 @@ impl(_Parser,
|
|
|
331
348
|
},
|
|
332
349
|
.None => break
|
|
333
350
|
);
|
|
334
|
-
};
|
|
351
|
+
});
|
|
335
352
|
},
|
|
336
353
|
true => ()
|
|
337
354
|
);
|
|
@@ -339,84 +356,108 @@ impl(_Parser,
|
|
|
339
356
|
.None => ()
|
|
340
357
|
);
|
|
341
358
|
num_len := (self.pos - start);
|
|
342
|
-
num_buf := ArrayList(u8).with_capacity(
|
|
359
|
+
num_buf := ArrayList(u8).with_capacity(num_len + usize(1));
|
|
343
360
|
j := usize(0);
|
|
344
|
-
while
|
|
345
|
-
num_buf.push(self.src.bytes(
|
|
346
|
-
};
|
|
361
|
+
while(j < num_len, j = (j + usize(1)), {
|
|
362
|
+
num_buf.push(self.src.bytes(start + j));
|
|
363
|
+
});
|
|
347
364
|
num_buf.push(u8(0));
|
|
348
365
|
num_ptr := *(char)(num_buf.ptr().unwrap());
|
|
349
|
-
{ atof } :: import
|
|
366
|
+
{ atof } :: import("../libc/stdlib");
|
|
350
367
|
val := atof(num_ptr);
|
|
351
368
|
.Ok(val)
|
|
352
369
|
})
|
|
353
370
|
);
|
|
354
|
-
|
|
355
371
|
// ============================================================================
|
|
356
372
|
// Recursive value parser (standalone for self-recursion support)
|
|
357
373
|
// ============================================================================
|
|
358
|
-
|
|
359
374
|
// Tiny helpers to avoid begin blocks in cond branches (works around codegen temp var issue)
|
|
360
|
-
_parse_true_lit :: (fn(p: _Parser) -> Result(JsonValue, JsonError))({
|
|
361
|
-
p.advance();
|
|
375
|
+
_parse_true_lit :: (fn(p : _Parser) -> Result(JsonValue, JsonError))({
|
|
376
|
+
p.advance();
|
|
377
|
+
p.advance();
|
|
378
|
+
p.advance();
|
|
379
|
+
p.advance();
|
|
362
380
|
.Ok(.Bool(true))
|
|
363
381
|
});
|
|
364
|
-
_parse_false_lit :: (fn(p: _Parser) -> Result(JsonValue, JsonError))({
|
|
365
|
-
p.advance();
|
|
382
|
+
_parse_false_lit :: (fn(p : _Parser) -> Result(JsonValue, JsonError))({
|
|
383
|
+
p.advance();
|
|
384
|
+
p.advance();
|
|
385
|
+
p.advance();
|
|
386
|
+
p.advance();
|
|
387
|
+
p.advance();
|
|
366
388
|
.Ok(.Bool(false))
|
|
367
389
|
});
|
|
368
|
-
_parse_null_lit :: (fn(p: _Parser) -> Result(JsonValue, JsonError))({
|
|
369
|
-
p.advance();
|
|
390
|
+
_parse_null_lit :: (fn(p : _Parser) -> Result(JsonValue, JsonError))({
|
|
391
|
+
p.advance();
|
|
392
|
+
p.advance();
|
|
393
|
+
p.advance();
|
|
394
|
+
p.advance();
|
|
370
395
|
.Ok(.Null)
|
|
371
396
|
});
|
|
372
|
-
|
|
373
|
-
_parse_value :: (fn(p: _Parser) -> Result(JsonValue, JsonError))({
|
|
397
|
+
_parse_value :: (fn(p : _Parser) -> Result(JsonValue, JsonError))({
|
|
374
398
|
p.skip_ws();
|
|
375
|
-
match(
|
|
376
|
-
.
|
|
399
|
+
match(
|
|
400
|
+
p.peek(),
|
|
401
|
+
.None =>.Err(.UnexpectedEnd),
|
|
377
402
|
.Some(c) =>
|
|
378
403
|
cond(
|
|
379
404
|
(c == u8(34)) =>
|
|
380
|
-
match(p.parse_string()
|
|
381
|
-
(c == u8(123)) => {
|
|
405
|
+
match(p.parse_string(),.Err(e) =>.Err(e),.Ok(s) =>.Ok(.Str(s))),
|
|
406
|
+
(c == u8(123)) => {
|
|
407
|
+
// '{' — parse object
|
|
382
408
|
p.advance();
|
|
383
409
|
keys := ArrayList(String).new();
|
|
384
410
|
vals := ArrayList(JsonValue).new();
|
|
385
411
|
p.skip_ws();
|
|
386
|
-
match(
|
|
412
|
+
match(
|
|
413
|
+
p.peek(),
|
|
387
414
|
.Some(c2) => {
|
|
388
415
|
cond(
|
|
389
416
|
(c2 == u8(125)) => {
|
|
390
417
|
p.advance();
|
|
391
|
-
return
|
|
418
|
+
return(.Ok(.Object(keys, vals)));
|
|
392
419
|
},
|
|
393
420
|
true => ()
|
|
394
421
|
);
|
|
395
422
|
},
|
|
396
423
|
.None => ()
|
|
397
424
|
);
|
|
398
|
-
while
|
|
425
|
+
while(runtime(true), {
|
|
399
426
|
p.skip_ws();
|
|
400
|
-
match(
|
|
401
|
-
.
|
|
427
|
+
match(
|
|
428
|
+
p.peek(),
|
|
429
|
+
.None => {
|
|
430
|
+
return(.Err(.UnexpectedEnd));
|
|
431
|
+
},
|
|
402
432
|
.Some(c2) => {
|
|
403
433
|
cond(
|
|
404
|
-
(c2 != u8(34)) => {
|
|
434
|
+
(c2 != u8(34)) => {
|
|
435
|
+
return(.Err(.UnexpectedChar(c2, p.pos)));
|
|
436
|
+
},
|
|
405
437
|
true => ()
|
|
406
438
|
);
|
|
407
439
|
}
|
|
408
440
|
);
|
|
409
441
|
key_r := p.parse_string();
|
|
410
|
-
match(
|
|
411
|
-
|
|
442
|
+
match(
|
|
443
|
+
key_r,
|
|
444
|
+
.Err(e) => {
|
|
445
|
+
return(.Err(e));
|
|
446
|
+
},
|
|
412
447
|
.Ok(key) => {
|
|
413
448
|
p.skip_ws();
|
|
414
|
-
match(
|
|
415
|
-
.
|
|
416
|
-
.
|
|
449
|
+
match(
|
|
450
|
+
p.expect(u8(58)),
|
|
451
|
+
.Err(e) => {
|
|
452
|
+
return(.Err(e));
|
|
453
|
+
},
|
|
454
|
+
.Ok(_) => ()
|
|
417
455
|
);
|
|
418
|
-
match(
|
|
419
|
-
|
|
456
|
+
match(
|
|
457
|
+
recur(p),
|
|
458
|
+
.Err(e) => {
|
|
459
|
+
return(.Err(e));
|
|
460
|
+
},
|
|
420
461
|
.Ok(val) => {
|
|
421
462
|
keys.push(key);
|
|
422
463
|
vals.push(val);
|
|
@@ -425,112 +466,162 @@ _parse_value :: (fn(p: _Parser) -> Result(JsonValue, JsonError))({
|
|
|
425
466
|
}
|
|
426
467
|
);
|
|
427
468
|
p.skip_ws();
|
|
428
|
-
match(
|
|
469
|
+
match(
|
|
470
|
+
p.peek(),
|
|
429
471
|
.Some(c2) => {
|
|
430
472
|
cond(
|
|
431
|
-
(c2 == u8(44)) => {
|
|
432
|
-
|
|
433
|
-
|
|
473
|
+
(c2 == u8(44)) => {
|
|
474
|
+
p.advance();
|
|
475
|
+
},
|
|
476
|
+
(c2 == u8(125)) => {
|
|
477
|
+
p.advance();
|
|
478
|
+
break;
|
|
479
|
+
},
|
|
480
|
+
true => {
|
|
481
|
+
return(.Err(.UnexpectedChar(c2, p.pos)));
|
|
482
|
+
}
|
|
434
483
|
);
|
|
435
484
|
},
|
|
436
|
-
.None => {
|
|
485
|
+
.None => {
|
|
486
|
+
return(.Err(.UnexpectedEnd));
|
|
487
|
+
}
|
|
437
488
|
);
|
|
438
|
-
};
|
|
489
|
+
});
|
|
439
490
|
.Ok(.Object(keys, vals))
|
|
440
491
|
},
|
|
441
|
-
(c == u8(91)) => {
|
|
492
|
+
(c == u8(91)) => {
|
|
493
|
+
// '[' — parse array
|
|
442
494
|
p.advance();
|
|
443
495
|
items := ArrayList(JsonValue).new();
|
|
444
496
|
p.skip_ws();
|
|
445
|
-
match(
|
|
497
|
+
match(
|
|
498
|
+
p.peek(),
|
|
446
499
|
.Some(c2) => {
|
|
447
500
|
cond(
|
|
448
501
|
(c2 == u8(93)) => {
|
|
449
502
|
p.advance();
|
|
450
|
-
return
|
|
503
|
+
return(.Ok(.Array(items)));
|
|
451
504
|
},
|
|
452
505
|
true => ()
|
|
453
506
|
);
|
|
454
507
|
},
|
|
455
508
|
.None => ()
|
|
456
509
|
);
|
|
457
|
-
while
|
|
458
|
-
match(
|
|
459
|
-
|
|
460
|
-
.
|
|
510
|
+
while(runtime(true), {
|
|
511
|
+
match(
|
|
512
|
+
recur(p),
|
|
513
|
+
.Err(e) => {
|
|
514
|
+
return(.Err(e));
|
|
515
|
+
},
|
|
516
|
+
.Ok(v) => {
|
|
517
|
+
items.push(v);
|
|
518
|
+
}
|
|
461
519
|
);
|
|
462
520
|
p.skip_ws();
|
|
463
|
-
match(
|
|
521
|
+
match(
|
|
522
|
+
p.peek(),
|
|
464
523
|
.Some(c2) => {
|
|
465
524
|
cond(
|
|
466
|
-
(c2 == u8(44)) => {
|
|
467
|
-
|
|
468
|
-
|
|
525
|
+
(c2 == u8(44)) => {
|
|
526
|
+
p.advance();
|
|
527
|
+
},
|
|
528
|
+
(c2 == u8(93)) => {
|
|
529
|
+
p.advance();
|
|
530
|
+
break;
|
|
531
|
+
},
|
|
532
|
+
true => {
|
|
533
|
+
return(.Err(.UnexpectedChar(c2, p.pos)));
|
|
534
|
+
}
|
|
469
535
|
);
|
|
470
536
|
},
|
|
471
|
-
.None => {
|
|
537
|
+
.None => {
|
|
538
|
+
return(.Err(.UnexpectedEnd));
|
|
539
|
+
}
|
|
472
540
|
);
|
|
473
|
-
};
|
|
541
|
+
});
|
|
474
542
|
.Ok(.Array(items))
|
|
475
543
|
},
|
|
476
544
|
(c == u8(116)) => _parse_true_lit(p),
|
|
477
545
|
(c == u8(102)) => _parse_false_lit(p),
|
|
478
546
|
(c == u8(110)) => _parse_null_lit(p),
|
|
479
547
|
true =>
|
|
480
|
-
match(p.parse_number()
|
|
548
|
+
match(p.parse_number(),.Err(e) =>.Err(e),.Ok(n) =>.Ok(.Number(n)))
|
|
481
549
|
)
|
|
482
550
|
)
|
|
483
551
|
});
|
|
484
|
-
|
|
485
552
|
// ============================================================================
|
|
486
553
|
// Public API
|
|
487
554
|
// ============================================================================
|
|
488
|
-
|
|
489
555
|
/// Parse a JSON string into a `JsonValue` tree. Throws via `Exception` on invalid input.
|
|
490
|
-
json_parse :: (fn(s: str, using(exn : Exception)) -> JsonValue)({
|
|
556
|
+
json_parse :: (fn(s : str, using(exn : Exception)) -> JsonValue)({
|
|
491
557
|
p := _Parser.new(s);
|
|
492
|
-
match(
|
|
558
|
+
match(
|
|
559
|
+
_parse_value(p),
|
|
493
560
|
.Ok(v) => v,
|
|
494
|
-
.Err(e) => exn.throw(dyn
|
|
561
|
+
.Err(e) => exn.throw(dyn(e))
|
|
495
562
|
)
|
|
496
563
|
});
|
|
497
|
-
|
|
498
|
-
export json_parse;
|
|
499
|
-
|
|
564
|
+
export(json_parse);
|
|
500
565
|
// ============================================================================
|
|
501
566
|
// Serialisation
|
|
502
567
|
// ============================================================================
|
|
503
|
-
|
|
504
|
-
_write_str_escaped :: (fn(s: String, out: ArrayList(u8)) -> unit)({
|
|
568
|
+
_write_str_escaped :: (fn(s : String, out : ArrayList(u8)) -> unit)({
|
|
505
569
|
out.push(u8(34)); // '"'
|
|
506
570
|
bytes := s.as_bytes();
|
|
507
571
|
i := usize(0);
|
|
508
|
-
while
|
|
572
|
+
while(i < bytes.len(), i = (i + usize(1)), {
|
|
509
573
|
b := bytes.get(i).unwrap();
|
|
510
574
|
cond(
|
|
511
|
-
(b == u8(34)) => {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
(b == u8(
|
|
516
|
-
|
|
575
|
+
(b == u8(34)) => {
|
|
576
|
+
out.push(u8(92));
|
|
577
|
+
out.push(u8(34));
|
|
578
|
+
},
|
|
579
|
+
(b == u8(92)) => {
|
|
580
|
+
out.push(u8(92));
|
|
581
|
+
out.push(u8(92));
|
|
582
|
+
},
|
|
583
|
+
(b == u8(10)) => {
|
|
584
|
+
out.push(u8(92));
|
|
585
|
+
out.push(u8(110));
|
|
586
|
+
},
|
|
587
|
+
(b == u8(9)) => {
|
|
588
|
+
out.push(u8(92));
|
|
589
|
+
out.push(u8(116));
|
|
590
|
+
},
|
|
591
|
+
(b == u8(13)) => {
|
|
592
|
+
out.push(u8(92));
|
|
593
|
+
out.push(u8(114));
|
|
594
|
+
},
|
|
595
|
+
true => {
|
|
596
|
+
out.push(b);
|
|
597
|
+
}
|
|
517
598
|
);
|
|
518
|
-
};
|
|
599
|
+
});
|
|
519
600
|
out.push(u8(34)); // '"'
|
|
520
601
|
});
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
602
|
+
_stringify_into :: (fn(value : JsonValue, out : ArrayList(u8)) -> unit)({
|
|
603
|
+
match(
|
|
604
|
+
value,
|
|
524
605
|
.Null => {
|
|
525
|
-
out.push(u8(110));
|
|
606
|
+
out.push(u8(110));
|
|
607
|
+
out.push(u8(117));
|
|
608
|
+
out.push(u8(108));
|
|
609
|
+
out.push(u8(108));
|
|
526
610
|
},
|
|
527
611
|
.Bool(b) => {
|
|
528
612
|
cond(
|
|
529
613
|
b => {
|
|
530
|
-
out.push(u8(116));
|
|
614
|
+
out.push(u8(116));
|
|
615
|
+
out.push(u8(114));
|
|
616
|
+
out.push(u8(117));
|
|
617
|
+
out.push(u8(101));
|
|
531
618
|
},
|
|
532
619
|
true => {
|
|
533
|
-
out.push(u8(102));
|
|
620
|
+
out.push(u8(102));
|
|
621
|
+
out.push(u8(97));
|
|
622
|
+
out.push(u8(108));
|
|
623
|
+
out.push(u8(115));
|
|
624
|
+
out.push(u8(101));
|
|
534
625
|
}
|
|
535
626
|
);
|
|
536
627
|
},
|
|
@@ -541,9 +632,9 @@ _stringify_into :: (fn(value: JsonValue, out: ArrayList(u8)) -> unit)({
|
|
|
541
632
|
s2 := String.from_cstr(buf_ptr).unwrap();
|
|
542
633
|
bytes := s2.as_bytes();
|
|
543
634
|
i := usize(0);
|
|
544
|
-
while
|
|
635
|
+
while(i < bytes.len(), i = (i + usize(1)), {
|
|
545
636
|
out.push(bytes.get(i).unwrap());
|
|
546
|
-
};
|
|
637
|
+
});
|
|
547
638
|
},
|
|
548
639
|
.Str(s) => {
|
|
549
640
|
_write_str_escaped(s, out);
|
|
@@ -551,42 +642,43 @@ _stringify_into :: (fn(value: JsonValue, out: ArrayList(u8)) -> unit)({
|
|
|
551
642
|
.Array(items) => {
|
|
552
643
|
out.push(u8(91)); // '['
|
|
553
644
|
i := usize(0);
|
|
554
|
-
while
|
|
645
|
+
while(i < items.len(), i = (i + usize(1)), {
|
|
555
646
|
cond(
|
|
556
|
-
(i > usize(0)) => {
|
|
647
|
+
(i > usize(0)) => {
|
|
648
|
+
out.push(u8(44));
|
|
649
|
+
},
|
|
557
650
|
true => ()
|
|
558
651
|
);
|
|
559
652
|
recur(items.get(i).unwrap(), out);
|
|
560
|
-
};
|
|
653
|
+
});
|
|
561
654
|
out.push(u8(93)); // ']'
|
|
562
655
|
},
|
|
563
656
|
.Object(keys, values) => {
|
|
564
657
|
out.push(u8(123)); // '{'
|
|
565
658
|
i := usize(0);
|
|
566
|
-
while
|
|
659
|
+
while(i < keys.len(), i = (i + usize(1)), {
|
|
567
660
|
cond(
|
|
568
|
-
(i > usize(0)) => {
|
|
661
|
+
(i > usize(0)) => {
|
|
662
|
+
out.push(u8(44));
|
|
663
|
+
},
|
|
569
664
|
true => ()
|
|
570
665
|
);
|
|
571
666
|
_write_str_escaped(keys.get(i).unwrap(), out);
|
|
572
667
|
out.push(u8(58)); // ':'
|
|
573
668
|
recur(values.get(i).unwrap(), out);
|
|
574
|
-
};
|
|
669
|
+
});
|
|
575
670
|
out.push(u8(125)); // '}'
|
|
576
671
|
}
|
|
577
672
|
);
|
|
578
673
|
});
|
|
579
|
-
|
|
580
674
|
/// Serialize a `JsonValue` to a compact JSON string.
|
|
581
|
-
json_stringify :: (fn(value: JsonValue) -> String)({
|
|
675
|
+
json_stringify :: (fn(value : JsonValue) -> String)({
|
|
582
676
|
out := ArrayList(u8).new();
|
|
583
677
|
_stringify_into(value, out);
|
|
584
678
|
String.from_bytes(out)
|
|
585
679
|
});
|
|
586
|
-
|
|
587
680
|
/// Serialize a `JsonValue` to a pretty-printed JSON string.
|
|
588
|
-
json_stringify_pretty :: (fn(value: JsonValue, _indent: usize) -> String)(
|
|
681
|
+
json_stringify_pretty :: (fn(value : JsonValue, _indent : usize) -> String)(
|
|
589
682
|
json_stringify(value)
|
|
590
683
|
);
|
|
591
|
-
|
|
592
|
-
export json_stringify, json_stringify_pretty;
|
|
684
|
+
export(json_stringify, json_stringify_pretty);
|