@shd101wyy/yo 0.0.26 → 0.0.28

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 (63) hide show
  1. package/README.md +7 -6
  2. package/out/cjs/index.cjs +568 -563
  3. package/out/cjs/yo-cli.cjs +686 -556
  4. package/out/esm/index.mjs +509 -504
  5. package/out/types/src/build-runner.d.ts +22 -0
  6. package/out/types/src/cache.d.ts +3 -0
  7. package/out/types/src/codegen/async/state-machine.d.ts +1 -1
  8. package/out/types/src/codegen/codegen-c.d.ts +3 -0
  9. package/out/types/src/codegen/exprs/await.d.ts +1 -0
  10. package/out/types/src/codegen/exprs/return.d.ts +1 -0
  11. package/out/types/src/codegen/exprs/while.d.ts +1 -1
  12. package/out/types/src/codegen/functions/context.d.ts +6 -18
  13. package/out/types/src/codegen/functions/declarations.d.ts +10 -2
  14. package/out/types/src/codegen/index.d.ts +4 -0
  15. package/out/types/src/codegen/utils/index.d.ts +3 -0
  16. package/out/types/src/evaluator/async/await-analysis.d.ts +1 -0
  17. package/out/types/src/evaluator/builtins/build.d.ts +135 -0
  18. package/out/types/src/evaluator/context.d.ts +1 -0
  19. package/out/types/src/expr.d.ts +18 -0
  20. package/out/types/src/fetch-command.d.ts +6 -0
  21. package/out/types/src/fetch.d.ts +10 -0
  22. package/out/types/src/function-value.d.ts +1 -0
  23. package/out/types/src/init.d.ts +5 -0
  24. package/out/types/src/install-command.d.ts +6 -0
  25. package/out/types/src/lock-file.d.ts +16 -0
  26. package/out/types/src/module-manager.d.ts +3 -1
  27. package/out/types/src/pkg-config.d.ts +11 -0
  28. package/out/types/src/target.d.ts +28 -0
  29. package/out/types/src/tests/build-system.test.d.ts +1 -0
  30. package/out/types/src/types/creators.d.ts +2 -1
  31. package/out/types/src/types/definitions.d.ts +2 -1
  32. package/out/types/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +1 -1
  34. package/std/build.yo +287 -0
  35. package/std/crypto/random.yo +27 -15
  36. package/std/encoding/base64.yo +24 -49
  37. package/std/encoding/hex.yo +25 -22
  38. package/std/encoding/json.yo +25 -3
  39. package/std/encoding/utf16.yo +6 -5
  40. package/std/fs/dir.yo +107 -104
  41. package/std/fs/file.yo +122 -158
  42. package/std/fs/metadata.yo +23 -22
  43. package/std/fs/temp.yo +42 -48
  44. package/std/fs/walker.yo +48 -55
  45. package/std/net/addr.yo +8 -7
  46. package/std/net/dns.yo +27 -33
  47. package/std/net/errors.yo +13 -8
  48. package/std/net/tcp.yo +92 -113
  49. package/std/net/udp.yo +50 -54
  50. package/std/os/env.yo +5 -5
  51. package/std/os/signal.yo +21 -16
  52. package/std/path.yo +2 -2
  53. package/std/prelude.yo +23 -2
  54. package/std/process.yo +23 -43
  55. package/std/sys/clock.yo +1 -1
  56. package/std/sys/constants.yo +3 -3
  57. package/std/sys/errors.yo +45 -33
  58. package/std/sys/mmap.yo +2 -2
  59. package/std/sys/signals.yo +4 -4
  60. package/std/sys/socket.yo +25 -25
  61. package/std/sys/sysinfo.yo +4 -4
  62. package/std/url/url.yo +19 -32
  63. package/out/types/src/codegen/effects/effect-state-machine.d.ts +0 -34
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shd101wyy/yo",
3
3
  "displayName": "Yo",
4
- "version": "0.0.26",
4
+ "version": "0.0.28",
5
5
  "main": "./out/cjs/index.cjs",
6
6
  "module": "./out/esm/index.mjs",
7
7
  "types": "./out/types/src/index.d.ts",
package/std/build.yo ADDED
@@ -0,0 +1,287 @@
1
+ // Build System Module
2
+ //
3
+ // Provides the declarative build API for Yo projects.
4
+ // All functions are compile-time only — they register build artifacts
5
+ // and steps that the build runner uses to orchestrate compilation.
6
+ //
7
+ // Usage in build.yo:
8
+ // build :: import "std/build";
9
+ // build.project({ name: "my-app", root: "./src/lib.yo" });
10
+ // exe :: build.executable({ name: "my-app", root: "./src/main.yo" });
11
+ // install :: build.step("install", "Build all artifacts");
12
+ // install.depend_on(exe);
13
+
14
+ // ── Optimization levels ──────────────────────────────────────────────
15
+
16
+ Optimize :: enum(
17
+ Debug,
18
+ ReleaseSafe,
19
+ ReleaseFast,
20
+ ReleaseSmall
21
+ );
22
+ export Optimize;
23
+
24
+ // ── Memory allocators ────────────────────────────────────────────────
25
+
26
+ Allocator :: enum(
27
+ Mimalloc,
28
+ Libc
29
+ );
30
+ export Allocator;
31
+
32
+ // ── Sanitizers ───────────────────────────────────────────────────────
33
+
34
+ Sanitize :: enum(
35
+ None,
36
+ Address,
37
+ Leak
38
+ );
39
+ export Sanitize;
40
+
41
+ // ── Step kinds ───────────────────────────────────────────────────────
42
+
43
+ StepKind :: enum(
44
+ Executable,
45
+ StaticLibrary,
46
+ SharedLibrary,
47
+ SystemLibrary,
48
+ TestSuite,
49
+ Run,
50
+ Custom
51
+ );
52
+ export StepKind;
53
+
54
+ // ── Target utilities ─────────────────────────────────────────────────
55
+
56
+ target_host :: __yo_build_target_host();
57
+ export target_host;
58
+
59
+ // ── Config struct types ──────────────────────────────────────────────
60
+ // Struct types with defaults, like Zig's options structs.
61
+ // Usage: build.executable({ name: "app", root: "./src/main.yo" })
62
+ // Unspecified fields get their default values.
63
+
64
+ Project :: struct(
65
+ name : comptime_string,
66
+ (root : comptime_string) ?= "./src/lib.yo"
67
+ );
68
+ export Project;
69
+
70
+ Executable :: struct(
71
+ name : comptime_string,
72
+ root : comptime_string,
73
+ (target : comptime_string) ?= __yo_build_target_host(),
74
+ (optimize : Optimize) ?= Optimize.Debug,
75
+ (allocator : Allocator) ?= Allocator.Mimalloc,
76
+ (sanitize : Sanitize) ?= Sanitize.None
77
+ );
78
+ export Executable;
79
+
80
+ StaticLibrary :: struct(
81
+ name : comptime_string,
82
+ root : comptime_string,
83
+ (target : comptime_string) ?= __yo_build_target_host(),
84
+ (optimize : Optimize) ?= Optimize.Debug
85
+ );
86
+ export StaticLibrary;
87
+
88
+ SharedLibrary :: struct(
89
+ name : comptime_string,
90
+ root : comptime_string,
91
+ (target : comptime_string) ?= __yo_build_target_host(),
92
+ (optimize : Optimize) ?= Optimize.Debug
93
+ );
94
+ export SharedLibrary;
95
+
96
+ TestSuite :: struct(
97
+ name : comptime_string,
98
+ root : comptime_string,
99
+ (target : comptime_string) ?= __yo_build_target_host()
100
+ );
101
+ export TestSuite;
102
+
103
+ // ── Step type ────────────────────────────────────────────────────────
104
+ // Returned by all build functions. Used to wire dependencies between steps.
105
+
106
+ Step :: struct(
107
+ name : comptime_string,
108
+ kind : StepKind
109
+ );
110
+ export Step;
111
+
112
+ // ── Step methods ─────────────────────────────────────────────────────
113
+ // Methods on Step for Zig-like API: step.depend_on(other), exe.link(lib).
114
+
115
+ impl(Step,
116
+ depend_on : (fn(comptime(self) : Self, comptime(dep) : Step) -> comptime(unit))({
117
+ __yo_build_step_depend_on(self.name, dep.name, dep.kind);
118
+ }),
119
+ link : (fn(comptime(self) : Self, comptime(library) : Step) -> comptime(unit))({
120
+ __yo_build_link(self.name, library.name);
121
+ })
122
+ );
123
+
124
+ // ── Build option config types ────────────────────────────────────────
125
+ // Like Zig's b.option(), declare user-configurable options.
126
+ // CLI usage: yo build -Dname=value
127
+
128
+ BuildOption :: struct(
129
+ name : comptime_string,
130
+ description : comptime_string,
131
+ (default : comptime_string) ?= ""
132
+ );
133
+ export BuildOption;
134
+
135
+ // ── Dependency config types ──────────────────────────────────────────
136
+
137
+ GitDependency :: struct(
138
+ name : comptime_string,
139
+ url : comptime_string,
140
+ (ref : comptime_string) ?= "HEAD",
141
+ (path : comptime_string) ?= ""
142
+ );
143
+ export GitDependency;
144
+
145
+ PathDependency :: struct(
146
+ name : comptime_string,
147
+ path : comptime_string
148
+ );
149
+ export PathDependency;
150
+
151
+ SystemLibrary :: struct(
152
+ name : comptime_string,
153
+ pkg_config : comptime_string,
154
+ (fallback_include : comptime_string) ?= "",
155
+ (fallback_lib : comptime_string) ?= "",
156
+ (fallback_link : comptime_string) ?= ""
157
+ );
158
+ export SystemLibrary;
159
+
160
+ // ── Dependency handle ────────────────────────────────────────────────
161
+ // Returned by build.dependency() and build.path_dependency().
162
+ // Provides access to artifacts defined in the dependency's build.yo.
163
+
164
+ Dependency :: struct(
165
+ name : comptime_string
166
+ );
167
+ export Dependency;
168
+
169
+ impl(Dependency,
170
+ // Access a named artifact from the dependency's build.yo.
171
+ // Returns a Step that can be linked to the consumer's artifacts.
172
+ artifact : (fn(comptime(self) : Self, comptime(artifact_name) : comptime_string) -> comptime(Step))({
173
+ __yo_build_dep_artifact(self.name, artifact_name);
174
+ Step(name: artifact_name, kind: StepKind.StaticLibrary)
175
+ })
176
+ );
177
+
178
+ // ── Build functions ──────────────────────────────────────────────────
179
+ // All registration functions return a Step value, allowing steps to be
180
+ // wired together as dependencies via step.depend_on(dep).
181
+
182
+ // Register project metadata.
183
+ project :: (fn(comptime(config) : Project) -> comptime(unit)) {
184
+ __yo_build_project(config.name, config.root);
185
+ };
186
+ export project;
187
+
188
+ // Register an executable artifact. Returns a Step for dependency wiring.
189
+ executable :: (fn(comptime(config) : Executable) -> comptime(Step)) {
190
+ opt_str :: match(config.optimize,
191
+ .Debug => "debug",
192
+ .ReleaseSafe => "release-safe",
193
+ .ReleaseFast => "release-fast",
194
+ .ReleaseSmall => "release-small"
195
+ );
196
+ alloc_str :: match(config.allocator,
197
+ .Mimalloc => "mimalloc",
198
+ .Libc => "libc"
199
+ );
200
+ san_str :: match(config.sanitize,
201
+ .None => "none",
202
+ .Address => "address",
203
+ .Leak => "leak"
204
+ );
205
+ __yo_build_executable(config.name, config.root, config.target, opt_str, alloc_str, san_str);
206
+ Step(name: config.name, kind: StepKind.Executable)
207
+ };
208
+ export executable;
209
+
210
+ // Register a static library artifact. Returns a Step for dependency wiring.
211
+ static_library :: (fn(comptime(config) : StaticLibrary) -> comptime(Step)) {
212
+ opt_str :: match(config.optimize,
213
+ .Debug => "debug",
214
+ .ReleaseSafe => "release-safe",
215
+ .ReleaseFast => "release-fast",
216
+ .ReleaseSmall => "release-small"
217
+ );
218
+ __yo_build_static_library(config.name, config.root, config.target, opt_str);
219
+ Step(name: config.name, kind: StepKind.StaticLibrary)
220
+ };
221
+ export static_library;
222
+
223
+ // Register a shared/dynamic library artifact. Returns a Step for dependency wiring.
224
+ shared_library :: (fn(comptime(config) : SharedLibrary) -> comptime(Step)) {
225
+ opt_str :: match(config.optimize,
226
+ .Debug => "debug",
227
+ .ReleaseSafe => "release-safe",
228
+ .ReleaseFast => "release-fast",
229
+ .ReleaseSmall => "release-small"
230
+ );
231
+ __yo_build_shared_library(config.name, config.root, config.target, opt_str);
232
+ Step(name: config.name, kind: StepKind.SharedLibrary)
233
+ };
234
+ export shared_library;
235
+
236
+ // Register a test suite. Returns a Step for dependency wiring.
237
+ test :: (fn(comptime(config) : TestSuite) -> comptime(Step)) {
238
+ __yo_build_test(config.name, config.root, config.target);
239
+ Step(name: config.name, kind: StepKind.TestSuite)
240
+ };
241
+ export test;
242
+
243
+ // Create a run step (compile + execute an artifact). Returns a Step.
244
+ run :: (fn(comptime(artifact) : Step) -> comptime(Step)) {
245
+ __yo_build_run(artifact.name);
246
+ Step(name: artifact.name, kind: StepKind.Run)
247
+ };
248
+ export run;
249
+
250
+ // Register a named build step. Use step.depend_on(dep) to add dependencies.
251
+ step :: (fn(
252
+ comptime(name) : comptime_string,
253
+ comptime(description) : comptime_string
254
+ ) -> comptime(Step)) {
255
+ __yo_build_step(name, description);
256
+ Step(name: name, kind: StepKind.Custom)
257
+ };
258
+ export step;
259
+
260
+ // Register a git-hosted dependency. Returns a Dependency handle for accessing artifacts.
261
+ dependency :: (fn(comptime(config) : GitDependency) -> comptime(Dependency)) {
262
+ __yo_build_dependency(config.name, config.url, config.ref, config.path);
263
+ Dependency(name: config.name)
264
+ };
265
+ export dependency;
266
+
267
+ // Register a local path dependency. Returns a Dependency handle for accessing artifacts.
268
+ path_dependency :: (fn(comptime(config) : PathDependency) -> comptime(Dependency)) {
269
+ __yo_build_path_dependency(config.name, config.path);
270
+ Dependency(name: config.name)
271
+ };
272
+ export path_dependency;
273
+
274
+ // Register a system C library discovered via pkg-config. Returns a Step for linking.
275
+ system_library :: (fn(comptime(config) : SystemLibrary) -> comptime(Step)) {
276
+ __yo_build_system_library(config.name, config.pkg_config, config.fallback_include, config.fallback_lib, config.fallback_link);
277
+ Step(name: config.name, kind: StepKind.SystemLibrary)
278
+ };
279
+ export system_library;
280
+
281
+ // Declare a user-configurable build option.
282
+ // Returns the option value (from CLI -Dname=value, or the default).
283
+ // Usage: strip :: build.option({ name: "strip", description: "Strip debug symbols", default: "false" });
284
+ option :: (fn(comptime(config) : BuildOption) -> comptime(str))(
285
+ __yo_build_option(config.name, config.description, config.default)
286
+ );
287
+ export option;
@@ -15,6 +15,8 @@
15
15
  open import "../string";
16
16
  { snprintf } :: import "../libc/stdio";
17
17
  { hex_encode } :: import "../encoding/hex";
18
+ { Error, AnyError, Exception } :: import "../error";
19
+ { ToString } :: import "../fmt";
18
20
 
19
21
  // ============================================================================
20
22
  // Error type
@@ -25,6 +27,17 @@ CryptoError :: enum(
25
27
  Other(msg: String)
26
28
  );
27
29
 
30
+ impl(CryptoError, ToString(
31
+ to_string : (self ->
32
+ match(self,
33
+ .Unavailable => `crypto: platform random unavailable`,
34
+ .Other(msg) => `crypto error: ${msg}`
35
+ )
36
+ )
37
+ ));
38
+
39
+ impl(CryptoError, Error());
40
+
28
41
  export CryptoError;
29
42
 
30
43
  // ============================================================================
@@ -41,26 +54,25 @@ extern "Yo",
41
54
  // Fill a buffer with cryptographically secure random bytes.
42
55
  // ============================================================================
43
56
 
44
- random_bytes :: (fn(buf: *(u8), size: usize) -> Result(unit, CryptoError))(
57
+ random_bytes :: (fn(buf: *(u8), size: usize, using(exn : Exception)) -> unit)(
45
58
  cond(
46
- (platform == Platform.Darwin) => {
59
+ (platform == Platform.Macos) => {
47
60
  __yo_arc4random_buf(buf, size);
48
- .Ok(())
49
61
  },
50
- (platform == Platform.Win32) => {
62
+ (platform == Platform.Windows) => {
51
63
  r := __yo_bcrypt_gen_random(buf, u32(size));
52
64
  cond(
53
- (r == i32(0)) => .Ok(()),
54
- true => .Err(.Unavailable)
55
- )
65
+ (r == i32(0)) => (),
66
+ true => { exn.throw(dyn CryptoError.Unavailable); }
67
+ );
56
68
  },
57
69
  true => {
58
70
  // Linux: getrandom syscall
59
71
  ret := __yo_getrandom(buf, size, u32(0));
60
72
  cond(
61
- (ret < isize(0)) => .Err(.Unavailable),
62
- true => .Ok(())
63
- )
73
+ (ret < isize(0)) => { exn.throw(dyn CryptoError.Unavailable); },
74
+ true => ()
75
+ );
64
76
  }
65
77
  )
66
78
  );
@@ -71,7 +83,7 @@ export random_bytes;
71
83
  // Typed helpers
72
84
  // ============================================================================
73
85
 
74
- random_u32 :: (fn() -> u32)({
86
+ random_u32 :: (fn(using(exn : Exception)) -> u32)({
75
87
  buf := Array(u8, usize(4)).fill(u8(0));
76
88
  buf_ptr := &(buf(usize(0)));
77
89
  random_bytes(buf_ptr, usize(4));
@@ -81,18 +93,18 @@ random_u32 :: (fn() -> u32)({
81
93
  (u32(buf(usize(3))) << u32(24)))
82
94
  });
83
95
 
84
- random_u64 :: (fn() -> u64)({
96
+ random_u64 :: (fn(using(exn : Exception)) -> u64)({
85
97
  lo := u64(random_u32());
86
98
  hi := u64(random_u32());
87
99
  (lo | (hi << u64(32)))
88
100
  });
89
101
 
90
- random_f64 :: (fn() -> f64)(
102
+ random_f64 :: (fn(using(exn : Exception)) -> f64)(
91
103
  (f64(random_u64()) / f64(18446744073709551615.0))
92
104
  );
93
105
 
94
106
  // Return a random integer in the half-open range [min, max).
95
- random_range :: (fn(min: i64, max: i64) -> i64)({
107
+ random_range :: (fn(min: i64, max: i64, using(exn : Exception)) -> i64)({
96
108
  span := (max - min);
97
109
  cond(
98
110
  (span <= i64(0)) => min,
@@ -110,7 +122,7 @@ export random_u32, random_u64, random_f64, random_range;
110
122
  // ============================================================================
111
123
 
112
124
  // Generate a random UUID v4 string: "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
113
- uuid_v4 :: (fn() -> String)({
125
+ uuid_v4 :: (fn(using(exn : Exception)) -> String)({
114
126
  bytes := ArrayList(u8).with_capacity(usize(16));
115
127
  buf := Array(u8, usize(16)).fill(u8(0));
116
128
  buf_ptr := &(buf(usize(0)));
@@ -11,6 +11,7 @@
11
11
  open import "../string";
12
12
  { ArrayList } :: import "../collections/array_list";
13
13
  { EncodingError } :: import "./hex";
14
+ { Error, AnyError, Exception } :: import "../error";
14
15
 
15
16
  // ============================================================================
16
17
  // Standard alphabet
@@ -73,81 +74,55 @@ export base64_encode, base64_encode_url;
73
74
  // Decoding
74
75
  // ============================================================================
75
76
 
76
- _decode_char :: (fn(c: u8, alpha: str) -> Result(u8, EncodingError))({
77
+ _decode_char :: (fn(c: u8, alpha: str, using(exn : Exception)) -> u8)({
77
78
  i := usize(0);
78
79
  while (i < usize(64)), (i = (i + usize(1))), {
79
80
  cond(
80
- (alpha.bytes(i) == c) => { return .Ok(u8(i)); },
81
+ (alpha.bytes(i) == c) => { return u8(i); },
81
82
  true => ()
82
83
  );
83
84
  };
84
- .Err(.InvalidChar(c))
85
+ exn.throw(dyn EncodingError.InvalidChar(c))
85
86
  });
86
87
 
87
- _decode_with :: (fn(s: str, alpha: str) -> Result(ArrayList(u8), EncodingError))({
88
+ _decode_with :: (fn(s: str, alpha: str, using(exn : Exception)) -> ArrayList(u8))({
88
89
  // Strip trailing padding
89
90
  len := s.len();
90
91
  while ((len > usize(0)) && (s.bytes((len - usize(1))) == _PAD)), (len = (len - usize(1))), ();
91
92
  out := ArrayList(u8).with_capacity(((len * usize(3)) / usize(4)));
92
93
  i := usize(0);
93
94
  while (i < len), (i = (i + usize(4))), {
94
- c0_r := _decode_char(s.bytes(i), alpha);
95
- c1_r := cond(
95
+ c0 := _decode_char(s.bytes(i), alpha);
96
+ c1 := cond(
96
97
  ((i + usize(1)) < len) => _decode_char(s.bytes((i + usize(1))), alpha),
97
- true => Result(u8, EncodingError).Ok(u8(0))
98
+ true => u8(0)
98
99
  );
99
- c2_r := cond(
100
- ((i + usize(2)) < len) => _decode_char(s.bytes((i + usize(2))), alpha),
101
- true => Result(u8, EncodingError).Ok(u8(0))
102
- );
103
- c3_r := cond(
104
- ((i + usize(3)) < len) => _decode_char(s.bytes((i + usize(3))), alpha),
105
- true => Result(u8, EncodingError).Ok(u8(0))
106
- );
107
- match(c0_r,
108
- .Err(e) => { return .Err(e); },
109
- .Ok(c0) => {
110
- match(c1_r,
111
- .Err(e) => { return .Err(e); },
112
- .Ok(c1) => {
113
- out.push(((c0 << u8(2)) | (c1 >> u8(4))));
114
- cond(
115
- ((i + usize(2)) < len) => {
116
- match(c2_r,
117
- .Err(e) => { return .Err(e); },
118
- .Ok(c2) => {
119
- out.push((((c1 & u8(15)) << u8(4)) | (c2 >> u8(2))));
120
- cond(
121
- ((i + usize(3)) < len) => {
122
- match(c3_r,
123
- .Err(e) => { return .Err(e); },
124
- .Ok(c3) => {
125
- out.push((((c2 & u8(3)) << u8(6)) | c3));
126
- }
127
- );
128
- },
129
- true => ()
130
- );
131
- }
132
- );
133
- },
134
- true => ()
135
- );
136
- }
100
+ out.push(((c0 << u8(2)) | (c1 >> u8(4))));
101
+ cond(
102
+ ((i + usize(2)) < len) => {
103
+ c2 := _decode_char(s.bytes((i + usize(2))), alpha);
104
+ out.push((((c1 & u8(15)) << u8(4)) | (c2 >> u8(2))));
105
+ cond(
106
+ ((i + usize(3)) < len) => {
107
+ c3 := _decode_char(s.bytes((i + usize(3))), alpha);
108
+ out.push((((c2 & u8(3)) << u8(6)) | c3));
109
+ },
110
+ true => ()
137
111
  );
138
- }
112
+ },
113
+ true => ()
139
114
  );
140
115
  };
141
- .Ok(out)
116
+ out
142
117
  });
143
118
 
144
119
  // Decode standard base64.
145
- base64_decode :: (fn(s: str) -> Result(ArrayList(u8), EncodingError))(
120
+ base64_decode :: (fn(s: str, using(exn : Exception)) -> ArrayList(u8))(
146
121
  _decode_with(s, _STD_ALPHA)
147
122
  );
148
123
 
149
124
  // Decode URL-safe base64.
150
- base64_decode_url :: (fn(s: str) -> Result(ArrayList(u8), EncodingError))(
125
+ base64_decode_url :: (fn(s: str, using(exn : Exception)) -> ArrayList(u8))(
151
126
  _decode_with(s, _URL_ALPHA)
152
127
  );
153
128
 
@@ -6,10 +6,12 @@
6
6
  // { hex_encode, hex_decode } :: import "std/encoding/hex";
7
7
  //
8
8
  // s := hex_encode(data); // "deadbeef"
9
- // b := hex_decode("deadbeef").unwrap();
9
+ // b := hex_decode("deadbeef");
10
10
 
11
11
  open import "../string";
12
12
  { ArrayList } :: import "../collections/array_list";
13
+ { Error, AnyError, Exception } :: import "../error";
14
+ { ToString } :: import "../fmt";
13
15
 
14
16
  // ============================================================================
15
17
  // Error type
@@ -20,6 +22,17 @@ EncodingError :: enum(
20
22
  OddLength
21
23
  );
22
24
 
25
+ impl(EncodingError, ToString(
26
+ to_string : (self ->
27
+ match(self,
28
+ .InvalidChar(ch) => `encoding error: invalid character ${ch}`,
29
+ .OddLength => `encoding error: odd length`
30
+ )
31
+ )
32
+ ));
33
+
34
+ impl(EncodingError, Error());
35
+
23
36
  export EncodingError;
24
37
 
25
38
  // ============================================================================
@@ -52,41 +65,31 @@ export hex_encode;
52
65
  // Decoding
53
66
  // ============================================================================
54
67
 
55
- _hex_nibble :: (fn(c: u8) -> Result(u8, EncodingError))(
68
+ _hex_nibble :: (fn(c: u8, using(exn : Exception)) -> u8)(
56
69
  cond(
57
- ((c >= u8(48)) && (c <= u8(57))) => .Ok((c - u8(48))), // '0'-'9'
58
- ((c >= u8(97)) && (c <= u8(102))) => .Ok(((c - u8(97)) + u8(10))), // 'a'-'f'
59
- ((c >= u8(65)) && (c <= u8(70))) => .Ok(((c - u8(65)) + u8(10))), // 'A'-'F'
60
- true => .Err(.InvalidChar(c))
70
+ ((c >= u8(48)) && (c <= u8(57))) => (c - u8(48)), // '0'-'9'
71
+ ((c >= u8(97)) && (c <= u8(102))) => ((c - u8(97)) + u8(10)), // 'a'-'f'
72
+ ((c >= u8(65)) && (c <= u8(70))) => ((c - u8(65)) + u8(10)), // 'A'-'F'
73
+ true => exn.throw(dyn EncodingError.InvalidChar(c))
61
74
  )
62
75
  );
63
76
 
64
77
  // Decode a hexadecimal string into bytes.
65
- hex_decode :: (fn(s: str) -> Result(ArrayList(u8), EncodingError))({
78
+ hex_decode :: (fn(s: str, using(exn : Exception)) -> ArrayList(u8))({
66
79
  cond(
67
80
  (((s.len() % usize(2)) != usize(0))) => {
68
- return .Err(.OddLength);
81
+ exn.throw(dyn EncodingError.OddLength);
69
82
  },
70
83
  true => ()
71
84
  );
72
85
  out := ArrayList(u8).with_capacity((s.len() / usize(2)));
73
86
  i := usize(0);
74
87
  while (i < s.len()), (i = (i + usize(2))), {
75
- hi_r := _hex_nibble(s.bytes(i));
76
- lo_r := _hex_nibble(s.bytes((i + usize(1))));
77
- match(hi_r,
78
- .Err(e) => { return .Err(e); },
79
- .Ok(hi) => {
80
- match(lo_r,
81
- .Err(e) => { return .Err(e); },
82
- .Ok(lo) => {
83
- out.push(((hi << u8(4)) | lo));
84
- }
85
- );
86
- }
87
- );
88
+ hi := _hex_nibble(s.bytes(i));
89
+ lo := _hex_nibble(s.bytes((i + usize(1))));
90
+ out.push(((hi << u8(4)) | lo));
88
91
  };
89
- .Ok(out)
92
+ out
90
93
  });
91
94
 
92
95
  export hex_decode;
@@ -4,13 +4,17 @@
4
4
  //
5
5
  // Example:
6
6
  // { json_parse, json_stringify, JsonValue } :: import "std/encoding/json";
7
+ // { Exception } :: import "std/error";
7
8
  //
8
- // v := json_parse(`{"x": 1}`).unwrap();
9
+ // given(exn) := Exception(throw : ((err) -> { escape (); }));
10
+ // v := json_parse(`{"x": 1}`);
9
11
  // println(json_stringify(v));
10
12
 
11
13
  open import "../string";
12
14
  { ArrayList } :: import "../collections/array_list";
13
15
  { snprintf } :: import "../libc/stdio";
16
+ { Error, AnyError, Exception } :: import "../error";
17
+ { ToString } :: import "../fmt";
14
18
 
15
19
  // ============================================================================
16
20
  // JsonError
@@ -25,6 +29,21 @@ JsonError :: enum(
25
29
  Other(msg: String)
26
30
  );
27
31
 
32
+ impl(JsonError, ToString(
33
+ to_string : (self ->
34
+ match(self,
35
+ .UnexpectedChar(ch, pos) => `unexpected character at position ${pos}`,
36
+ .UnexpectedEnd => `unexpected end of input`,
37
+ .InvalidNumber => `invalid number`,
38
+ .InvalidEscape => `invalid escape sequence`,
39
+ .InvalidUnicode => `invalid unicode`,
40
+ .Other(msg) => `JSON error: ${msg}`
41
+ )
42
+ )
43
+ ));
44
+
45
+ impl(JsonError, Error());
46
+
28
47
  export JsonError;
29
48
 
30
49
  // ============================================================================
@@ -449,9 +468,12 @@ _parse_value :: (fn(p: _Parser) -> Result(JsonValue, JsonError))({
449
468
  // Public API
450
469
  // ============================================================================
451
470
 
452
- json_parse :: (fn(s: str) -> Result(JsonValue, JsonError))({
471
+ json_parse :: (fn(s: str, using(exn : Exception)) -> JsonValue)({
453
472
  p := _Parser.new(s);
454
- _parse_value(p)
473
+ match(_parse_value(p),
474
+ .Ok(v) => v,
475
+ .Err(e) => exn.throw(dyn e)
476
+ )
455
477
  });
456
478
 
457
479
  export json_parse;