@fraczak/k 6.3.3 → 6.4.0
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/DOCS/CODECS.md +258 -0
- package/DOCS/DICTIONARY.md +1172 -0
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +51 -46
- package/DOCS/KIR_V1.md +221 -0
- package/DOCS/KVM_EXECUTION_MODEL.md +56 -19
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +2 -1
- package/DOCS/PROFILING_AND_TRACING.md +196 -0
- package/DOCS/REPL.md +61 -4
- package/DOCS/WEB_REPL_REQUIREMENTS.md +135 -0
- package/DOCS/dependency-graph.md +144 -0
- package/Examples/arithmetics.k +51 -48
- package/Examples/bnat.k +1 -1
- package/Examples/buda.k +44 -0
- package/Examples/ieee.k +300 -8671
- package/Examples/poly.k +67 -0
- package/README.md +68 -19
- package/augmentation.mjs +9 -7
- package/backend-api.mjs +11 -2
- package/backends/arm64/README.md +104 -0
- package/backends/arm64/bin/k-arm64-compile.mjs +101 -0
- package/backends/arm64/bin/k-arm64-run.mjs +58 -0
- package/backends/arm64/bin/k-arm64.mjs +88 -0
- package/backends/arm64/scripts/run-tests.mjs +41 -0
- package/backends/arm64/src/arm64.mjs +229 -0
- package/backends/arm64/src/cli.mjs +155 -0
- package/backends/arm64/src/kvm2arm64.mjs +906 -0
- package/backends/arm64/src/runtime.c +728 -0
- package/backends/arm64/tests/integration.sh +112 -0
- package/backends/arm64/tests/test-arm64.mjs +240 -0
- package/backends/llvm/README.md +135 -0
- package/backends/llvm/bin/k-llvm-build.mjs +71 -0
- package/backends/llvm/bin/k-llvm-compile.mjs +68 -0
- package/backends/llvm/bin/k-llvm-jit.mjs +160 -0
- package/backends/llvm/bin/k-llvm-run.mjs +90 -0
- package/backends/llvm/runtime/krt.c +1508 -0
- package/backends/llvm/runtime/krt.h +109 -0
- package/backends/llvm/scripts/conformance.mjs +76 -0
- package/backends/llvm/scripts/run-tests.mjs +28 -0
- package/backends/llvm/src/executable.mjs +562 -0
- package/backends/llvm/src/kvm2llvm.mjs +998 -0
- package/backends/llvm/src/llvm.mjs +1092 -0
- package/backends/llvm/tests/composition-driver.c +22 -0
- package/backends/llvm/tests/identity-driver.c +27 -0
- package/backends/llvm/tests/integration.sh +153 -0
- package/backends/llvm/tests/perf-support.mjs +735 -0
- package/backends/llvm/tests/product-driver.c +23 -0
- package/backends/llvm/tests/projection-driver.c +19 -0
- package/backends/llvm/tests/relation-driver.c +29 -0
- package/backends/llvm/tests/test-llvm.mjs +240 -0
- package/backends/llvm/tests/union-driver.c +31 -0
- package/backends/llvm/tests/variant-driver.c +19 -0
- package/backends/llvm/tests/variant-projection-driver.c +21 -0
- package/backends/wasm/DOCS/USE-WEB-ASSEMBLY.md +233 -0
- package/backends/wasm/README.md +97 -0
- package/backends/wasm/TECHNICAL-DEBT.md +60 -0
- package/backends/wasm/bin/k-wasm-compile.mjs +50 -0
- package/backends/wasm/bin/k-wasm-run.mjs +140 -0
- package/backends/wasm/bin/k-wasm.mjs +49 -0
- package/backends/wasm/demo_ieee.mjs +319 -0
- package/backends/wasm/runtime.wat +102 -0
- package/backends/wasm/scripts/run-tests.mjs +41 -0
- package/backends/wasm/src/cli.mjs +133 -0
- package/backends/wasm/src/kvm2wasm.mjs +661 -0
- package/backends/wasm/src/wasm.mjs +1010 -0
- package/backends/wasm/tests/integration.sh +182 -0
- package/backends/wasm/tests/perf-support.mjs +336 -0
- package/backends/wasm/tests/test-wasm.mjs +617 -0
- package/browser/repl-browser.mjs +1584 -0
- package/browser/shims/assert.mjs +19 -0
- package/browser/shims/buffer.mjs +224 -0
- package/browser/shims/crypto.mjs +103 -0
- package/browser/shims/fs.mjs +159 -0
- package/browser/shims/os.mjs +17 -0
- package/browser/shims/path.mjs +54 -0
- package/browser/shims/process.mjs +44 -0
- package/browser/shims/readline.mjs +11 -0
- package/browser/shims/url.mjs +12 -0
- package/browser/vfs-data.mjs +19 -0
- package/codecs/README.md +3 -0
- package/codecs/runtime/show-value.mjs +2 -2
- package/conformance/helper-reuse/case.json +8 -0
- package/conformance/helper-reuse/expected.kv +1 -0
- package/conformance/helper-reuse/input.kv +1 -0
- package/conformance/helper-reuse/program.k +2 -0
- package/conformance/identity/case.json +8 -0
- package/conformance/identity/expected.kv +1 -0
- package/conformance/identity/input.kv +1 -0
- package/conformance/identity/program.k +1 -0
- package/conformance/product-projection/case.json +8 -0
- package/conformance/product-projection/expected.kv +1 -0
- package/conformance/product-projection/input.kv +1 -0
- package/conformance/product-projection/program.k +1 -0
- package/conformance/run.mjs +149 -0
- package/conformance/variant-construction/case.json +8 -0
- package/conformance/variant-construction/expected.kv +1 -0
- package/conformance/variant-construction/input.kv +1 -0
- package/conformance/variant-construction/program.k +1 -0
- package/harness/adapters/arm64.mjs +105 -0
- package/harness/adapters/kvm.mjs +144 -0
- package/harness/adapters/llvm.mjs +118 -0
- package/harness/adapters/native.mjs +77 -0
- package/harness/adapters/wasm.mjs +169 -0
- package/harness/backend.mjs +95 -0
- package/harness/cli.mjs +130 -0
- package/harness/format.mjs +95 -0
- package/harness/index.mjs +25 -0
- package/harness/persistent.mjs +121 -0
- package/harness/registry.mjs +44 -0
- package/harness/suite.mjs +257 -0
- package/harness/suites/poly.mjs +156 -0
- package/harness/trace.mjs +50 -0
- package/harness/util.mjs +92 -0
- package/intrinsics.mjs +41 -0
- package/kir.mjs +399 -0
- package/kvm.mjs +585 -81
- package/objects/README.md +37 -3
- package/objects/compile.mjs +15 -22
- package/objects/inspect.mjs +96 -0
- package/objects/validate.mjs +415 -0
- package/package.json +51 -19
- package/repl-codecs.mjs +105 -6
- package/repl.mjs +335 -49
- package/run.mjs +2 -7
- package/scripts/benchmark.mjs +406 -22
- package/scripts/build-repl-html.mjs +1784 -0
- package/scripts/perf-ieee.mjs +586 -0
- package/scripts/perf-int.mjs +531 -0
- package/scripts/perf-poly.mjs +945 -0
- package/scripts/render-benchmark.mjs +12 -8
- package/scripts/run-tests.mjs +6 -0
- package/tests/integration.sh +19 -2
- package/tests/test-arithmetics.mjs +54 -0
- package/tests/test-ieee-arithmetic.mjs +4 -0
- package/tests/test-kir.mjs +85 -0
- package/tests/test-kvm-polymorphic.mjs +278 -0
- package/tests/test-kvm.mjs +25 -6
- package/tests/test-poly.mjs +129 -0
- package/tests/test-repl-html.mjs +303 -0
- package/tests/test-repl.mjs +144 -1
- package/tests/test-validate-object.mjs +40 -0
- package/a.klib +0 -1
- package/a.kvm +0 -142676
- package/a.wasm +0 -0
- package/benchmark-results.html +0 -532
- package/benchmark-results.json +0 -480
- package/k-vscode/.vscode/launch.json +0 -14
- package/k-vscode/README.md +0 -75
- package/k-vscode/extension.js +0 -273
- package/k-vscode/language-configuration.json +0 -42
- package/k-vscode/package.json +0 -79
- package/k-vscode/snippets/k.json +0 -92
- package/k-vscode/syntaxes/k.tmLanguage.json +0 -599
- package/k-vscode/test/background-ranges.test.js +0 -50
- package/k-vscode/themes/k-contrast-color-theme.json +0 -104
- package/scripts/git-hooks/pre-commit +0 -10
|
@@ -0,0 +1,1508 @@
|
|
|
1
|
+
#include "krt.h"
|
|
2
|
+
|
|
3
|
+
#include <stddef.h>
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
#include <string.h>
|
|
6
|
+
|
|
7
|
+
enum {
|
|
8
|
+
K_ARENA_BLOCK_SIZE = 262144
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
typedef enum {
|
|
12
|
+
K_VALUE_UNIT,
|
|
13
|
+
K_VALUE_PRODUCT,
|
|
14
|
+
K_VALUE_VARIANT
|
|
15
|
+
} k_value_kind;
|
|
16
|
+
|
|
17
|
+
typedef struct {
|
|
18
|
+
char *label;
|
|
19
|
+
size_t label_length;
|
|
20
|
+
k_value *value;
|
|
21
|
+
} k_field;
|
|
22
|
+
|
|
23
|
+
typedef struct k_arena_block {
|
|
24
|
+
struct k_arena_block *next;
|
|
25
|
+
size_t used;
|
|
26
|
+
size_t capacity;
|
|
27
|
+
unsigned char data[];
|
|
28
|
+
} k_arena_block;
|
|
29
|
+
|
|
30
|
+
struct k_value {
|
|
31
|
+
k_value_kind kind;
|
|
32
|
+
k_rt *rt;
|
|
33
|
+
union {
|
|
34
|
+
struct {
|
|
35
|
+
size_t count;
|
|
36
|
+
size_t capacity;
|
|
37
|
+
k_field *fields;
|
|
38
|
+
} product;
|
|
39
|
+
struct {
|
|
40
|
+
char *tag;
|
|
41
|
+
size_t tag_length;
|
|
42
|
+
k_value *payload;
|
|
43
|
+
} variant;
|
|
44
|
+
} as;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
struct k_rt {
|
|
48
|
+
k_arena_block *blocks;
|
|
49
|
+
k_value *unit_cache;
|
|
50
|
+
k_value *bit0_cache;
|
|
51
|
+
k_value *bit1_cache;
|
|
52
|
+
int has_reusable_blocks;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
static size_t align_size(size_t size) {
|
|
56
|
+
size_t alignment = sizeof(max_align_t);
|
|
57
|
+
return (size + alignment - 1) & ~(alignment - 1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static k_arena_block *reuse_arena_block(k_rt *rt, size_t size) {
|
|
61
|
+
if (rt == NULL || !rt->has_reusable_blocks) return NULL;
|
|
62
|
+
k_arena_block **link = rt == NULL || rt->blocks == NULL ? NULL : &rt->blocks->next;
|
|
63
|
+
int saw_reusable = 0;
|
|
64
|
+
while (link != NULL && *link != NULL) {
|
|
65
|
+
k_arena_block *block = *link;
|
|
66
|
+
if (block->used == 0) {
|
|
67
|
+
saw_reusable = 1;
|
|
68
|
+
if (block->capacity >= size) {
|
|
69
|
+
*link = block->next;
|
|
70
|
+
block->next = rt->blocks;
|
|
71
|
+
rt->blocks = block;
|
|
72
|
+
return block;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
link = &block->next;
|
|
76
|
+
}
|
|
77
|
+
rt->has_reusable_blocks = saw_reusable;
|
|
78
|
+
return NULL;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static void *rt_alloc(k_rt *rt, size_t size) {
|
|
82
|
+
if (rt == NULL) return NULL;
|
|
83
|
+
size = align_size(size == 0 ? 1 : size);
|
|
84
|
+
k_arena_block *block = rt->blocks;
|
|
85
|
+
if (block == NULL || block->capacity - block->used < size) {
|
|
86
|
+
block = reuse_arena_block(rt, size);
|
|
87
|
+
if (block == NULL) {
|
|
88
|
+
size_t capacity = size > K_ARENA_BLOCK_SIZE ? size : K_ARENA_BLOCK_SIZE;
|
|
89
|
+
block = malloc(sizeof(k_arena_block) + capacity);
|
|
90
|
+
if (block == NULL) abort();
|
|
91
|
+
block->next = rt->blocks;
|
|
92
|
+
block->used = 0;
|
|
93
|
+
block->capacity = capacity;
|
|
94
|
+
rt->blocks = block;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
void *ptr = block->data + block->used;
|
|
98
|
+
block->used += size;
|
|
99
|
+
return ptr;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void *k_rt_alloc(k_rt *rt, size_t size) {
|
|
103
|
+
return rt_alloc(rt, size);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static void *rt_zalloc(k_rt *rt, size_t count, size_t size) {
|
|
107
|
+
if (count != 0 && size > ((size_t)-1) / count) abort();
|
|
108
|
+
size_t bytes = count * size;
|
|
109
|
+
void *ptr = rt_alloc(rt, bytes);
|
|
110
|
+
if (ptr == NULL) return NULL;
|
|
111
|
+
memset(ptr, 0, bytes);
|
|
112
|
+
return ptr;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static char *rt_memdup_text(k_rt *rt, const char *text, size_t length) {
|
|
116
|
+
char *copy = rt_alloc(rt, length + 1);
|
|
117
|
+
if (copy == NULL) abort();
|
|
118
|
+
if (length > 0) memcpy(copy, text, length);
|
|
119
|
+
copy[length] = 0;
|
|
120
|
+
return copy;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static char *heap_memdup_text(const char *text, size_t length) {
|
|
124
|
+
char *copy = malloc(length + 1);
|
|
125
|
+
if (copy == NULL) abort();
|
|
126
|
+
if (length > 0) memcpy(copy, text, length);
|
|
127
|
+
copy[length] = 0;
|
|
128
|
+
return copy;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static int bytes_equal(const char *a, size_t a_length, const char *b, size_t b_length) {
|
|
132
|
+
if (a_length != b_length) return 0;
|
|
133
|
+
if (a == b) return 1;
|
|
134
|
+
return a_length == 0 || memcmp(a, b, a_length) == 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static int is_empty_product(k_value *value);
|
|
138
|
+
|
|
139
|
+
static int numeric_label_index(const char *label, size_t label_length, size_t *out) {
|
|
140
|
+
if (label == NULL || label_length == 0) return 0;
|
|
141
|
+
size_t value = 0;
|
|
142
|
+
for (size_t i = 0; i < label_length; i++) {
|
|
143
|
+
unsigned char ch = (unsigned char)label[i];
|
|
144
|
+
if (ch < '0' || ch > '9') return 0;
|
|
145
|
+
size_t digit = (size_t)(ch - '0');
|
|
146
|
+
if (value > (((size_t)-1) - digit) / 10) return 0;
|
|
147
|
+
value = value * 10 + digit;
|
|
148
|
+
}
|
|
149
|
+
*out = value;
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static k_value *alloc_value(k_rt *rt, k_value_kind kind) {
|
|
154
|
+
if (rt == NULL) return NULL;
|
|
155
|
+
k_value *value = rt_alloc(rt, sizeof(k_value));
|
|
156
|
+
if (value == NULL) abort();
|
|
157
|
+
value->kind = kind;
|
|
158
|
+
value->rt = rt;
|
|
159
|
+
return value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static k_value *alloc_product_value(k_rt *rt, size_t count) {
|
|
163
|
+
if (rt == NULL) return NULL;
|
|
164
|
+
size_t header_size = align_size(sizeof(k_value));
|
|
165
|
+
if (count != 0 && sizeof(k_field) > (((size_t)-1) - header_size) / count) abort();
|
|
166
|
+
size_t fields_size = count * sizeof(k_field);
|
|
167
|
+
unsigned char *memory = rt_alloc(rt, header_size + fields_size);
|
|
168
|
+
if (memory == NULL) abort();
|
|
169
|
+
k_value *product = (k_value *)memory;
|
|
170
|
+
product->kind = K_VALUE_PRODUCT;
|
|
171
|
+
product->rt = rt;
|
|
172
|
+
product->as.product.count = 0;
|
|
173
|
+
product->as.product.capacity = count;
|
|
174
|
+
product->as.product.fields = count == 0 ? NULL : (k_field *)(memory + header_size);
|
|
175
|
+
if (fields_size > 0) memset(product->as.product.fields, 0, fields_size);
|
|
176
|
+
return product;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
k_rt *k_rt_new(void) {
|
|
180
|
+
return calloc(1, sizeof(k_rt));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
void k_rt_reset(k_rt *rt) {
|
|
184
|
+
if (rt == NULL) return;
|
|
185
|
+
int has_next = rt->blocks != NULL && rt->blocks->next != NULL;
|
|
186
|
+
for (k_arena_block *block = rt->blocks; block != NULL; block = block->next) {
|
|
187
|
+
block->used = 0;
|
|
188
|
+
}
|
|
189
|
+
rt->unit_cache = NULL;
|
|
190
|
+
rt->bit0_cache = NULL;
|
|
191
|
+
rt->bit1_cache = NULL;
|
|
192
|
+
rt->has_reusable_blocks = has_next;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
k_rt_checkpoint k_rt_mark(k_rt *rt) {
|
|
196
|
+
k_rt_checkpoint mark = {0, 0};
|
|
197
|
+
if (rt == NULL || rt->blocks == NULL) return mark;
|
|
198
|
+
mark.block = rt->blocks;
|
|
199
|
+
mark.used = rt->blocks->used;
|
|
200
|
+
return mark;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
void k_rt_rewind(k_rt *rt, k_rt_checkpoint mark) {
|
|
204
|
+
if (rt == NULL) return;
|
|
205
|
+
if (mark.block == NULL) {
|
|
206
|
+
k_rt_reset(rt);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
int has_reusable = 0;
|
|
210
|
+
for (k_arena_block *block = rt->blocks; block != NULL; block = block->next) {
|
|
211
|
+
if (block == (k_arena_block *)mark.block) {
|
|
212
|
+
block->used = mark.used;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
block->used = 0;
|
|
216
|
+
has_reusable = 1;
|
|
217
|
+
}
|
|
218
|
+
rt->unit_cache = NULL;
|
|
219
|
+
rt->bit0_cache = NULL;
|
|
220
|
+
rt->bit1_cache = NULL;
|
|
221
|
+
rt->has_reusable_blocks = has_reusable;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
void k_rt_free(k_rt *rt) {
|
|
225
|
+
if (rt == NULL) return;
|
|
226
|
+
k_arena_block *block = rt->blocks;
|
|
227
|
+
while (block != NULL) {
|
|
228
|
+
k_arena_block *next = block->next;
|
|
229
|
+
free(block);
|
|
230
|
+
block = next;
|
|
231
|
+
}
|
|
232
|
+
free(rt);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
k_value *k_unit(k_rt *rt) {
|
|
236
|
+
if (rt == NULL) return NULL;
|
|
237
|
+
if (rt->unit_cache != NULL) return rt->unit_cache;
|
|
238
|
+
k_value *unit = alloc_product_value(rt, 0);
|
|
239
|
+
if (unit == NULL) return NULL;
|
|
240
|
+
rt->unit_cache = unit;
|
|
241
|
+
return unit;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static k_value *k_bit(k_rt *rt, int bit) {
|
|
245
|
+
if (rt == NULL) return NULL;
|
|
246
|
+
k_value **cache = bit ? &rt->bit1_cache : &rt->bit0_cache;
|
|
247
|
+
if (*cache != NULL) return *cache;
|
|
248
|
+
k_value *variant = alloc_value(rt, K_VALUE_VARIANT);
|
|
249
|
+
if (variant == NULL) return NULL;
|
|
250
|
+
variant->as.variant.tag = bit ? "1" : "0";
|
|
251
|
+
variant->as.variant.tag_length = 1;
|
|
252
|
+
variant->as.variant.payload = k_unit(rt);
|
|
253
|
+
*cache = variant;
|
|
254
|
+
return variant;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
k_value *k_bit0(k_rt *rt) {
|
|
258
|
+
return k_bit(rt, 0);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
k_value *k_bit1(k_rt *rt) {
|
|
262
|
+
return k_bit(rt, 1);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
k_value *k_product(k_rt *rt, size_t count) {
|
|
266
|
+
return alloc_product_value(rt, count);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
k_value *k_product_get_n(k_value *product, const char *label, size_t label_length) {
|
|
270
|
+
if (product == NULL || product->kind != K_VALUE_PRODUCT || label == NULL) return NULL;
|
|
271
|
+
size_t index = 0;
|
|
272
|
+
if (numeric_label_index(label, label_length, &index) && index < product->as.product.count) {
|
|
273
|
+
k_field *field = &product->as.product.fields[index];
|
|
274
|
+
if (bytes_equal(field->label, field->label_length, label, label_length)) return field->value;
|
|
275
|
+
}
|
|
276
|
+
for (size_t i = 0; i < product->as.product.count; i++) {
|
|
277
|
+
if (bytes_equal(product->as.product.fields[i].label, product->as.product.fields[i].label_length, label, label_length)) {
|
|
278
|
+
return product->as.product.fields[i].value;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return NULL;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
void k_product_set_at(k_value *product, size_t index, const char *label, size_t label_length, k_value *value) {
|
|
285
|
+
if (product == NULL || product->kind != K_VALUE_PRODUCT || label == NULL || index >= product->as.product.capacity) return;
|
|
286
|
+
k_field *field = &product->as.product.fields[index];
|
|
287
|
+
field->label = (char *)label;
|
|
288
|
+
field->label_length = label_length;
|
|
289
|
+
field->value = value;
|
|
290
|
+
if (index >= product->as.product.count) product->as.product.count = index + 1;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
k_value *k_product_get_at(k_value *product, size_t index) {
|
|
294
|
+
if (product == NULL || product->kind != K_VALUE_PRODUCT || index >= product->as.product.count) return NULL;
|
|
295
|
+
return product->as.product.fields[index].value;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
static void k_product_set_internal(k_value *product, const char *label, size_t label_length, k_value *value, int borrow_label) {
|
|
299
|
+
if (product == NULL || product->kind != K_VALUE_PRODUCT || label == NULL) return;
|
|
300
|
+
size_t numeric_index = 0;
|
|
301
|
+
if (numeric_label_index(label, label_length, &numeric_index) &&
|
|
302
|
+
numeric_index < product->as.product.capacity &&
|
|
303
|
+
numeric_index <= product->as.product.count) {
|
|
304
|
+
k_field *field = &product->as.product.fields[numeric_index];
|
|
305
|
+
if (numeric_index == product->as.product.count) {
|
|
306
|
+
field->label = borrow_label ? (char *)label : rt_memdup_text(product->rt, label, label_length);
|
|
307
|
+
field->label_length = label_length;
|
|
308
|
+
field->value = value;
|
|
309
|
+
product->as.product.count++;
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (bytes_equal(field->label, field->label_length, label, label_length)) {
|
|
313
|
+
field->value = value;
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
for (size_t i = 0; i < product->as.product.count; i++) {
|
|
319
|
+
if (bytes_equal(product->as.product.fields[i].label, product->as.product.fields[i].label_length, label, label_length)) {
|
|
320
|
+
product->as.product.fields[i].value = value;
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (product->as.product.count == product->as.product.capacity) {
|
|
326
|
+
size_t capacity = product->as.product.capacity == 0 ? 1 : product->as.product.capacity * 2;
|
|
327
|
+
k_field *fields = rt_zalloc(product->rt, capacity, sizeof(k_field));
|
|
328
|
+
if (fields == NULL) abort();
|
|
329
|
+
if (product->as.product.count > 0) {
|
|
330
|
+
memcpy(fields, product->as.product.fields, product->as.product.count * sizeof(k_field));
|
|
331
|
+
}
|
|
332
|
+
product->as.product.fields = fields;
|
|
333
|
+
product->as.product.capacity = capacity;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
size_t index = product->as.product.count++;
|
|
337
|
+
product->as.product.fields[index].label = borrow_label ? (char *)label : rt_memdup_text(product->rt, label, label_length);
|
|
338
|
+
product->as.product.fields[index].label_length = label_length;
|
|
339
|
+
product->as.product.fields[index].value = value;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
void k_product_set_n(k_value *product, const char *label, size_t label_length, k_value *value) {
|
|
343
|
+
k_product_set_internal(product, label, label_length, value, 0);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
void k_product_set_borrowed_n(k_value *product, const char *label, size_t label_length, k_value *value) {
|
|
347
|
+
k_product_set_internal(product, label, label_length, value, 1);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
void k_product_set(k_value *product, const char *label, k_value *value) {
|
|
351
|
+
if (label == NULL) return;
|
|
352
|
+
k_product_set_n(product, label, strlen(label), value);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
k_value *k_product_get(k_value *product, const char *label) {
|
|
356
|
+
if (label == NULL) return NULL;
|
|
357
|
+
return k_product_get_n(product, label, strlen(label));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
static k_value *k_variant_internal(k_rt *rt, const char *tag, size_t tag_length, k_value *payload, int borrow_tag) {
|
|
361
|
+
if (tag == NULL) return NULL;
|
|
362
|
+
if (rt != NULL && tag_length == 1 && is_empty_product(payload) && (tag[0] == '0' || tag[0] == '1')) {
|
|
363
|
+
return tag[0] == '0' ? k_bit0(rt) : k_bit1(rt);
|
|
364
|
+
}
|
|
365
|
+
k_value *variant = alloc_value(rt, K_VALUE_VARIANT);
|
|
366
|
+
if (variant == NULL) return NULL;
|
|
367
|
+
variant->as.variant.tag = borrow_tag ? (char *)tag : rt_memdup_text(rt, tag, tag_length);
|
|
368
|
+
variant->as.variant.tag_length = tag_length;
|
|
369
|
+
variant->as.variant.payload = payload;
|
|
370
|
+
return variant;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
k_value *k_variant_n(k_rt *rt, const char *tag, size_t tag_length, k_value *payload) {
|
|
374
|
+
return k_variant_internal(rt, tag, tag_length, payload, 0);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
k_value *k_variant_borrowed_n(k_rt *rt, const char *tag, size_t tag_length, k_value *payload) {
|
|
378
|
+
return k_variant_internal(rt, tag, tag_length, payload, 1);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
k_value *k_variant_borrowed_direct_n(k_rt *rt, const char *tag, size_t tag_length, k_value *payload) {
|
|
382
|
+
if (tag == NULL) return NULL;
|
|
383
|
+
k_value *variant = alloc_value(rt, K_VALUE_VARIANT);
|
|
384
|
+
if (variant == NULL) return NULL;
|
|
385
|
+
variant->as.variant.tag = (char *)tag;
|
|
386
|
+
variant->as.variant.tag_length = tag_length;
|
|
387
|
+
variant->as.variant.payload = payload;
|
|
388
|
+
return variant;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
k_value *k_variant_unit_borrowed_n(k_rt *rt, const char *tag, size_t tag_length) {
|
|
392
|
+
if (tag == NULL) return NULL;
|
|
393
|
+
if (rt != NULL && tag_length == 1 && (tag[0] == '0' || tag[0] == '1')) {
|
|
394
|
+
return tag[0] == '0' ? k_bit0(rt) : k_bit1(rt);
|
|
395
|
+
}
|
|
396
|
+
k_value *variant = alloc_value(rt, K_VALUE_VARIANT);
|
|
397
|
+
if (variant == NULL) return NULL;
|
|
398
|
+
variant->as.variant.tag = (char *)tag;
|
|
399
|
+
variant->as.variant.tag_length = tag_length;
|
|
400
|
+
variant->as.variant.payload = k_unit(rt);
|
|
401
|
+
return variant;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
k_value *k_variant(k_rt *rt, const char *tag, k_value *payload) {
|
|
405
|
+
if (tag == NULL) return NULL;
|
|
406
|
+
return k_variant_n(rt, tag, strlen(tag), payload);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const char *k_variant_tag(k_value *value) {
|
|
410
|
+
if (value == NULL || value->kind != K_VALUE_VARIANT) return NULL;
|
|
411
|
+
return value->as.variant.tag;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
size_t k_variant_tag_length(k_value *value) {
|
|
415
|
+
if (value == NULL || value->kind != K_VALUE_VARIANT) return 0;
|
|
416
|
+
return value->as.variant.tag_length;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
int k_variant_tag_matches(k_value *value, const char *tag, size_t tag_length) {
|
|
420
|
+
if (value == NULL || value->kind != K_VALUE_VARIANT || tag == NULL) return 0;
|
|
421
|
+
return bytes_equal(value->as.variant.tag, value->as.variant.tag_length, tag, tag_length);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
k_value *k_variant_payload(k_value *value) {
|
|
425
|
+
if (value == NULL || value->kind != K_VALUE_VARIANT) return NULL;
|
|
426
|
+
return value->as.variant.payload;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
int k_equal(k_value *a, k_value *b) {
|
|
430
|
+
if (a == b) return 1;
|
|
431
|
+
if (a == NULL || b == NULL) return 0;
|
|
432
|
+
if (a->kind != b->kind) return 0;
|
|
433
|
+
|
|
434
|
+
if (a->kind == K_VALUE_UNIT) return 1;
|
|
435
|
+
|
|
436
|
+
if (a->kind == K_VALUE_VARIANT) {
|
|
437
|
+
return bytes_equal(a->as.variant.tag, a->as.variant.tag_length, b->as.variant.tag, b->as.variant.tag_length) &&
|
|
438
|
+
k_equal(a->as.variant.payload, b->as.variant.payload);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (a->kind == K_VALUE_PRODUCT) {
|
|
442
|
+
if (a->as.product.count != b->as.product.count) return 0;
|
|
443
|
+
for (size_t i = 0; i < a->as.product.count; i++) {
|
|
444
|
+
k_value *b_field = k_product_get_n(b, a->as.product.fields[i].label, a->as.product.fields[i].label_length);
|
|
445
|
+
if (!k_equal(a->as.product.fields[i].value, b_field)) return 0;
|
|
446
|
+
}
|
|
447
|
+
return 1;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return 0;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
static int is_empty_product(k_value *value) {
|
|
454
|
+
return value != NULL &&
|
|
455
|
+
value->kind == K_VALUE_PRODUCT &&
|
|
456
|
+
value->as.product.count == 0;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
static void print_json_string_n(FILE *out, const char *text, size_t length) {
|
|
460
|
+
fputc('"', out);
|
|
461
|
+
for (size_t i = 0; i < length; i++) {
|
|
462
|
+
unsigned char ch = (unsigned char)text[i];
|
|
463
|
+
switch (ch) {
|
|
464
|
+
case '"':
|
|
465
|
+
fputs("\\\"", out);
|
|
466
|
+
break;
|
|
467
|
+
case '\\':
|
|
468
|
+
fputs("\\\\", out);
|
|
469
|
+
break;
|
|
470
|
+
case '\b':
|
|
471
|
+
fputs("\\b", out);
|
|
472
|
+
break;
|
|
473
|
+
case '\f':
|
|
474
|
+
fputs("\\f", out);
|
|
475
|
+
break;
|
|
476
|
+
case '\n':
|
|
477
|
+
fputs("\\n", out);
|
|
478
|
+
break;
|
|
479
|
+
case '\r':
|
|
480
|
+
fputs("\\r", out);
|
|
481
|
+
break;
|
|
482
|
+
case '\t':
|
|
483
|
+
fputs("\\t", out);
|
|
484
|
+
break;
|
|
485
|
+
default:
|
|
486
|
+
if (ch < 0x20) {
|
|
487
|
+
fprintf(out, "\\u%04x", ch);
|
|
488
|
+
} else {
|
|
489
|
+
fputc(ch, out);
|
|
490
|
+
}
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
fputc('"', out);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
static void print_json_string(FILE *out, const char *text) {
|
|
498
|
+
print_json_string_n(out, text, strlen(text));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
void k_print_json(FILE *out, k_value *value) {
|
|
502
|
+
if (value == NULL) {
|
|
503
|
+
fputs("null", out);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (value->kind == K_VALUE_UNIT) {
|
|
508
|
+
fputs("{}", out);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (value->kind == K_VALUE_PRODUCT) {
|
|
513
|
+
fputc('{', out);
|
|
514
|
+
for (size_t i = 0; i < value->as.product.count; i++) {
|
|
515
|
+
if (i > 0) fputc(',', out);
|
|
516
|
+
print_json_string_n(out, value->as.product.fields[i].label, value->as.product.fields[i].label_length);
|
|
517
|
+
fputc(':', out);
|
|
518
|
+
k_print_json(out, value->as.product.fields[i].value);
|
|
519
|
+
}
|
|
520
|
+
fputc('}', out);
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (value->kind == K_VALUE_VARIANT) {
|
|
525
|
+
if (is_empty_product(value->as.variant.payload)) {
|
|
526
|
+
print_json_string_n(out, value->as.variant.tag, value->as.variant.tag_length);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
fputc('{', out);
|
|
530
|
+
print_json_string_n(out, value->as.variant.tag, value->as.variant.tag_length);
|
|
531
|
+
fputc(':', out);
|
|
532
|
+
k_print_json(out, value->as.variant.payload);
|
|
533
|
+
fputc('}', out);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
typedef struct {
|
|
538
|
+
const unsigned char *bytes;
|
|
539
|
+
size_t length;
|
|
540
|
+
size_t byte_offset;
|
|
541
|
+
int bit_offset;
|
|
542
|
+
int ok;
|
|
543
|
+
} bit_reader;
|
|
544
|
+
|
|
545
|
+
typedef struct {
|
|
546
|
+
unsigned char *bytes;
|
|
547
|
+
size_t length;
|
|
548
|
+
size_t capacity;
|
|
549
|
+
unsigned char current;
|
|
550
|
+
int bit_count;
|
|
551
|
+
int ok;
|
|
552
|
+
} bit_writer;
|
|
553
|
+
|
|
554
|
+
#define K_PATTERN_EDGE(label, target) {label, sizeof(label) - 1, target}
|
|
555
|
+
|
|
556
|
+
static k_pattern_edge core_edges_0[] = {K_PATTERN_EDGE("cons", 1), K_PATTERN_EDGE("nil", 3)};
|
|
557
|
+
static k_pattern_edge core_edges_1[] = {K_PATTERN_EDGE("car", 2), K_PATTERN_EDGE("cdr", 0)};
|
|
558
|
+
static k_pattern_edge core_edges_2[] = {K_PATTERN_EDGE("any", 3), K_PATTERN_EDGE("closed-product", 4), K_PATTERN_EDGE("closed-union", 4), K_PATTERN_EDGE("open-product", 4), K_PATTERN_EDGE("open-union", 4)};
|
|
559
|
+
static k_pattern_edge core_edges_4[] = {K_PATTERN_EDGE("cons", 5), K_PATTERN_EDGE("nil", 3)};
|
|
560
|
+
static k_pattern_edge core_edges_5[] = {K_PATTERN_EDGE("car", 6), K_PATTERN_EDGE("cdr", 4)};
|
|
561
|
+
static k_pattern_edge core_edges_6[] = {K_PATTERN_EDGE("label", 7), K_PATTERN_EDGE("target", 25)};
|
|
562
|
+
static k_pattern_edge core_edges_7[] = {K_PATTERN_EDGE("cons", 8), K_PATTERN_EDGE("nil", 3)};
|
|
563
|
+
static k_pattern_edge core_edges_8[] = {K_PATTERN_EDGE("car", 9), K_PATTERN_EDGE("cdr", 7)};
|
|
564
|
+
static k_pattern_edge core_edges_9[] = {K_PATTERN_EDGE("ascii", 10), K_PATTERN_EDGE("bmp_common", 12), K_PATTERN_EDGE("bmp_private_use", 17), K_PATTERN_EDGE("plane0", 20), K_PATTERN_EDGE("supplementary_plane1", 21), K_PATTERN_EDGE("supplementary_planes2_16", 22)};
|
|
565
|
+
static k_pattern_edge core_edges_10[] = {K_PATTERN_EDGE("0", 11), K_PATTERN_EDGE("1", 11), K_PATTERN_EDGE("2", 11), K_PATTERN_EDGE("3", 11), K_PATTERN_EDGE("4", 11), K_PATTERN_EDGE("5", 11), K_PATTERN_EDGE("6", 11)};
|
|
566
|
+
static k_pattern_edge core_edges_11[] = {K_PATTERN_EDGE("0", 3), K_PATTERN_EDGE("1", 3)};
|
|
567
|
+
static k_pattern_edge core_edges_12[] = {K_PATTERN_EDGE("hi", 13), K_PATTERN_EDGE("lo", 16)};
|
|
568
|
+
static k_pattern_edge core_edges_13[] = {K_PATTERN_EDGE("h08_0F", 14), K_PATTERN_EDGE("h10_7F", 10), K_PATTERN_EDGE("h80_CF", 10), K_PATTERN_EDGE("hD0_D7", 14), K_PATTERN_EDGE("hF9", 3), K_PATTERN_EDGE("hFA_FB", 15), K_PATTERN_EDGE("hFC_FD", 15), K_PATTERN_EDGE("hFE_FF", 15)};
|
|
569
|
+
static k_pattern_edge core_edges_14[] = {K_PATTERN_EDGE("0", 11), K_PATTERN_EDGE("1", 11), K_PATTERN_EDGE("2", 11)};
|
|
570
|
+
static k_pattern_edge core_edges_15[] = {K_PATTERN_EDGE("0", 11)};
|
|
571
|
+
static k_pattern_edge core_edges_16[] = {K_PATTERN_EDGE("0", 11), K_PATTERN_EDGE("1", 11), K_PATTERN_EDGE("2", 11), K_PATTERN_EDGE("3", 11), K_PATTERN_EDGE("4", 11), K_PATTERN_EDGE("5", 11), K_PATTERN_EDGE("6", 11), K_PATTERN_EDGE("7", 11)};
|
|
572
|
+
static k_pattern_edge core_edges_17[] = {K_PATTERN_EDGE("hi", 18), K_PATTERN_EDGE("lo", 16)};
|
|
573
|
+
static k_pattern_edge core_edges_18[] = {K_PATTERN_EDGE("hE0_EF", 19), K_PATTERN_EDGE("hF0_F7", 14), K_PATTERN_EDGE("hF8", 3)};
|
|
574
|
+
static k_pattern_edge core_edges_19[] = {K_PATTERN_EDGE("0", 11), K_PATTERN_EDGE("1", 11), K_PATTERN_EDGE("2", 11), K_PATTERN_EDGE("3", 11)};
|
|
575
|
+
static k_pattern_edge core_edges_20[] = {K_PATTERN_EDGE("0", 11), K_PATTERN_EDGE("1", 11), K_PATTERN_EDGE("10", 11), K_PATTERN_EDGE("2", 11), K_PATTERN_EDGE("3", 11), K_PATTERN_EDGE("4", 11), K_PATTERN_EDGE("5", 11), K_PATTERN_EDGE("6", 11), K_PATTERN_EDGE("7", 11), K_PATTERN_EDGE("8", 11), K_PATTERN_EDGE("9", 11)};
|
|
576
|
+
static k_pattern_edge core_edges_21[] = {K_PATTERN_EDGE("lo", 16), K_PATTERN_EDGE("mid", 16)};
|
|
577
|
+
static k_pattern_edge core_edges_22[] = {K_PATTERN_EDGE("lo", 16), K_PATTERN_EDGE("mid", 16), K_PATTERN_EDGE("plane", 23)};
|
|
578
|
+
static k_pattern_edge core_edges_23[] = {K_PATTERN_EDGE("p02_03", 15), K_PATTERN_EDGE("p04_07", 24), K_PATTERN_EDGE("p08_0F", 14), K_PATTERN_EDGE("p10", 3)};
|
|
579
|
+
static k_pattern_edge core_edges_24[] = {K_PATTERN_EDGE("0", 11), K_PATTERN_EDGE("1", 11)};
|
|
580
|
+
static k_pattern_edge core_edges_25[] = {K_PATTERN_EDGE("0", 25), K_PATTERN_EDGE("1", 25), K_PATTERN_EDGE("_", 3)};
|
|
581
|
+
|
|
582
|
+
static k_pattern_node core_nodes[] = {
|
|
583
|
+
{KP_CLOSED_UNION, 2, core_edges_0},
|
|
584
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_1},
|
|
585
|
+
{KP_CLOSED_UNION, 5, core_edges_2},
|
|
586
|
+
{KP_CLOSED_PRODUCT, 0, NULL},
|
|
587
|
+
{KP_CLOSED_UNION, 2, core_edges_4},
|
|
588
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_5},
|
|
589
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_6},
|
|
590
|
+
{KP_CLOSED_UNION, 2, core_edges_7},
|
|
591
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_8},
|
|
592
|
+
{KP_CLOSED_UNION, 6, core_edges_9},
|
|
593
|
+
{KP_CLOSED_PRODUCT, 7, core_edges_10},
|
|
594
|
+
{KP_CLOSED_UNION, 2, core_edges_11},
|
|
595
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_12},
|
|
596
|
+
{KP_CLOSED_UNION, 8, core_edges_13},
|
|
597
|
+
{KP_CLOSED_PRODUCT, 3, core_edges_14},
|
|
598
|
+
{KP_CLOSED_PRODUCT, 1, core_edges_15},
|
|
599
|
+
{KP_CLOSED_PRODUCT, 8, core_edges_16},
|
|
600
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_17},
|
|
601
|
+
{KP_CLOSED_UNION, 3, core_edges_18},
|
|
602
|
+
{KP_CLOSED_PRODUCT, 4, core_edges_19},
|
|
603
|
+
{KP_CLOSED_PRODUCT, 11, core_edges_20},
|
|
604
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_21},
|
|
605
|
+
{KP_CLOSED_PRODUCT, 3, core_edges_22},
|
|
606
|
+
{KP_CLOSED_UNION, 4, core_edges_23},
|
|
607
|
+
{KP_CLOSED_PRODUCT, 2, core_edges_24},
|
|
608
|
+
{KP_CLOSED_UNION, 3, core_edges_25}
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
static k_pattern core_pattern = {26, core_nodes};
|
|
612
|
+
|
|
613
|
+
static int choice_width(size_t cardinality) {
|
|
614
|
+
if (cardinality <= 1) return 0;
|
|
615
|
+
size_t choices = cardinality - 1;
|
|
616
|
+
int width = 0;
|
|
617
|
+
while (choices > 0) {
|
|
618
|
+
width++;
|
|
619
|
+
choices >>= 1;
|
|
620
|
+
}
|
|
621
|
+
return width;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
static int br_read_bit(bit_reader *reader) {
|
|
625
|
+
if (!reader->ok || reader->byte_offset >= reader->length) {
|
|
626
|
+
reader->ok = 0;
|
|
627
|
+
return 0;
|
|
628
|
+
}
|
|
629
|
+
int bit = (reader->bytes[reader->byte_offset] >> (7 - reader->bit_offset)) & 1;
|
|
630
|
+
reader->bit_offset++;
|
|
631
|
+
if (reader->bit_offset == 8) {
|
|
632
|
+
reader->byte_offset++;
|
|
633
|
+
reader->bit_offset = 0;
|
|
634
|
+
}
|
|
635
|
+
return bit;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
static unsigned br_read_bits(bit_reader *reader, int width) {
|
|
639
|
+
unsigned value = 0;
|
|
640
|
+
for (int i = 0; i < width; i++) {
|
|
641
|
+
value = (value << 1) | (unsigned)br_read_bit(reader);
|
|
642
|
+
}
|
|
643
|
+
return value;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
static int br_zero_padding(bit_reader *reader) {
|
|
647
|
+
while (reader->byte_offset < reader->length) {
|
|
648
|
+
if (br_read_bit(reader) != 0) return 0;
|
|
649
|
+
}
|
|
650
|
+
return reader->ok;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
static void bw_write_bit(bit_writer *writer, int bit) {
|
|
654
|
+
if (!writer->ok) return;
|
|
655
|
+
writer->current = (unsigned char)((writer->current << 1) | (bit ? 1 : 0));
|
|
656
|
+
writer->bit_count++;
|
|
657
|
+
if (writer->bit_count != 8) return;
|
|
658
|
+
if (writer->length == writer->capacity) {
|
|
659
|
+
size_t capacity = writer->capacity == 0 ? 64 : writer->capacity * 2;
|
|
660
|
+
unsigned char *bytes = realloc(writer->bytes, capacity);
|
|
661
|
+
if (bytes == NULL) {
|
|
662
|
+
writer->ok = 0;
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
writer->bytes = bytes;
|
|
666
|
+
writer->capacity = capacity;
|
|
667
|
+
}
|
|
668
|
+
writer->bytes[writer->length++] = writer->current;
|
|
669
|
+
writer->current = 0;
|
|
670
|
+
writer->bit_count = 0;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
static void bw_write_bits(bit_writer *writer, unsigned value, int width) {
|
|
674
|
+
for (int i = width - 1; i >= 0; i--) {
|
|
675
|
+
bw_write_bit(writer, (value >> i) & 1);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
static void bw_flush(bit_writer *writer) {
|
|
680
|
+
if (writer->ok && writer->bit_count > 0) {
|
|
681
|
+
while (writer->ok && writer->bit_count != 0) bw_write_bit(writer, 0);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
static k_value *decode_node(bit_reader *reader, k_pattern *pattern, size_t node_id, k_rt *rt) {
|
|
686
|
+
if (!reader->ok || node_id >= pattern->node_count) {
|
|
687
|
+
reader->ok = 0;
|
|
688
|
+
return NULL;
|
|
689
|
+
}
|
|
690
|
+
k_pattern_node *node = &pattern->nodes[node_id];
|
|
691
|
+
if (node->kind == KP_ANY) {
|
|
692
|
+
reader->ok = 0;
|
|
693
|
+
return NULL;
|
|
694
|
+
}
|
|
695
|
+
if (node->kind == KP_OPEN_PRODUCT || node->kind == KP_CLOSED_PRODUCT) {
|
|
696
|
+
k_value *product = k_product(rt, node->edge_count);
|
|
697
|
+
if (product == NULL) {
|
|
698
|
+
reader->ok = 0;
|
|
699
|
+
return NULL;
|
|
700
|
+
}
|
|
701
|
+
for (size_t i = 0; i < node->edge_count; i++) {
|
|
702
|
+
k_value *child = decode_node(reader, pattern, node->edges[i].target, rt);
|
|
703
|
+
if (!reader->ok) return NULL;
|
|
704
|
+
k_product_set_at(product, i, node->edges[i].label, node->edges[i].label_length, child);
|
|
705
|
+
}
|
|
706
|
+
return product;
|
|
707
|
+
}
|
|
708
|
+
if (node->kind == KP_OPEN_UNION || node->kind == KP_CLOSED_UNION) {
|
|
709
|
+
if (node->edge_count == 0) {
|
|
710
|
+
reader->ok = 0;
|
|
711
|
+
return NULL;
|
|
712
|
+
}
|
|
713
|
+
unsigned ordinal = br_read_bits(reader, choice_width(node->edge_count));
|
|
714
|
+
if (!reader->ok || ordinal >= node->edge_count) {
|
|
715
|
+
reader->ok = 0;
|
|
716
|
+
return NULL;
|
|
717
|
+
}
|
|
718
|
+
k_pattern_edge *edge = &node->edges[ordinal];
|
|
719
|
+
k_value *payload = decode_node(reader, pattern, edge->target, rt);
|
|
720
|
+
if (!reader->ok) return NULL;
|
|
721
|
+
return k_variant_borrowed_n(rt, edge->label, edge->label_length, payload);
|
|
722
|
+
}
|
|
723
|
+
reader->ok = 0;
|
|
724
|
+
return NULL;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
static int tag_is(k_value *value, const char *tag) {
|
|
728
|
+
const char *actual = k_variant_tag(value);
|
|
729
|
+
return actual != NULL && strcmp(actual, tag) == 0;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
static unsigned bits_to_integer(k_value *value) {
|
|
733
|
+
unsigned place = 1;
|
|
734
|
+
unsigned result = 0;
|
|
735
|
+
k_value *cursor = value;
|
|
736
|
+
for (;;) {
|
|
737
|
+
const char *tag = k_variant_tag(cursor);
|
|
738
|
+
if (tag == NULL) return 0;
|
|
739
|
+
if (strcmp(tag, "_") == 0) return result;
|
|
740
|
+
if (strcmp(tag, "1") == 0) result += place;
|
|
741
|
+
if (strcmp(tag, "0") != 0 && strcmp(tag, "1") != 0) return 0;
|
|
742
|
+
place <<= 1;
|
|
743
|
+
cursor = k_variant_payload(cursor);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
static unsigned bits_product_to_integer(k_value *value, int max_bit) {
|
|
748
|
+
unsigned result = 0;
|
|
749
|
+
char label[16];
|
|
750
|
+
for (int i = max_bit; i >= 0; i--) {
|
|
751
|
+
snprintf(label, sizeof(label), "%d", i);
|
|
752
|
+
k_value *bit = k_product_get(value, label);
|
|
753
|
+
result = (result << 1) | (tag_is(bit, "1") ? 1U : 0U);
|
|
754
|
+
}
|
|
755
|
+
return result;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
static k_value *unit_value(k_rt *rt);
|
|
759
|
+
|
|
760
|
+
static k_value *bits_product(k_rt *rt, int max_bit, unsigned value) {
|
|
761
|
+
k_value *bits = k_product(rt, (size_t)max_bit + 1);
|
|
762
|
+
char label[16];
|
|
763
|
+
for (int bit = 0; bit <= max_bit; bit++) {
|
|
764
|
+
snprintf(label, sizeof(label), "%d", bit);
|
|
765
|
+
k_product_set(bits, label, k_variant(rt, ((value >> bit) & 1U) ? "1" : "0", unit_value(rt)));
|
|
766
|
+
}
|
|
767
|
+
return bits;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
static int decode_bmp_common_hi(k_value *value, unsigned *out) {
|
|
771
|
+
const char *tag = k_variant_tag(value);
|
|
772
|
+
if (tag == NULL) return 0;
|
|
773
|
+
if (strcmp(tag, "h08_0F") == 0) {
|
|
774
|
+
*out = 0x08U + bits_product_to_integer(k_variant_payload(value), 2);
|
|
775
|
+
return 1;
|
|
776
|
+
}
|
|
777
|
+
if (strcmp(tag, "h10_7F") == 0) {
|
|
778
|
+
*out = 0x10U + bits_product_to_integer(k_variant_payload(value), 6);
|
|
779
|
+
return 1;
|
|
780
|
+
}
|
|
781
|
+
if (strcmp(tag, "h80_CF") == 0) {
|
|
782
|
+
*out = 0x80U + bits_product_to_integer(k_variant_payload(value), 6);
|
|
783
|
+
return 1;
|
|
784
|
+
}
|
|
785
|
+
if (strcmp(tag, "hD0_D7") == 0) {
|
|
786
|
+
*out = 0xd0U + bits_product_to_integer(k_variant_payload(value), 2);
|
|
787
|
+
return 1;
|
|
788
|
+
}
|
|
789
|
+
if (strcmp(tag, "hF9") == 0) {
|
|
790
|
+
*out = 0xf9U;
|
|
791
|
+
return 1;
|
|
792
|
+
}
|
|
793
|
+
if (strcmp(tag, "hFA_FB") == 0) {
|
|
794
|
+
*out = 0xfaU + bits_product_to_integer(k_variant_payload(value), 0);
|
|
795
|
+
return 1;
|
|
796
|
+
}
|
|
797
|
+
if (strcmp(tag, "hFC_FD") == 0) {
|
|
798
|
+
*out = 0xfcU + bits_product_to_integer(k_variant_payload(value), 0);
|
|
799
|
+
return 1;
|
|
800
|
+
}
|
|
801
|
+
if (strcmp(tag, "hFE_FF") == 0) {
|
|
802
|
+
*out = 0xfeU + bits_product_to_integer(k_variant_payload(value), 0);
|
|
803
|
+
return 1;
|
|
804
|
+
}
|
|
805
|
+
return 0;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
static int decode_bmp_private_hi(k_value *value, unsigned *out) {
|
|
809
|
+
const char *tag = k_variant_tag(value);
|
|
810
|
+
if (tag == NULL) return 0;
|
|
811
|
+
if (strcmp(tag, "hE0_EF") == 0) {
|
|
812
|
+
*out = 0xe0U + bits_product_to_integer(k_variant_payload(value), 3);
|
|
813
|
+
return 1;
|
|
814
|
+
}
|
|
815
|
+
if (strcmp(tag, "hF0_F7") == 0) {
|
|
816
|
+
*out = 0xf0U + bits_product_to_integer(k_variant_payload(value), 2);
|
|
817
|
+
return 1;
|
|
818
|
+
}
|
|
819
|
+
if (strcmp(tag, "hF8") == 0) {
|
|
820
|
+
*out = 0xf8U;
|
|
821
|
+
return 1;
|
|
822
|
+
}
|
|
823
|
+
return 0;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
static int decode_plane_2_to_16(k_value *value, unsigned *out) {
|
|
827
|
+
const char *tag = k_variant_tag(value);
|
|
828
|
+
if (tag == NULL) return 0;
|
|
829
|
+
if (strcmp(tag, "p02_03") == 0) {
|
|
830
|
+
*out = 2U + bits_product_to_integer(k_variant_payload(value), 0);
|
|
831
|
+
return 1;
|
|
832
|
+
}
|
|
833
|
+
if (strcmp(tag, "p04_07") == 0) {
|
|
834
|
+
*out = 4U + bits_product_to_integer(k_variant_payload(value), 1);
|
|
835
|
+
return 1;
|
|
836
|
+
}
|
|
837
|
+
if (strcmp(tag, "p08_0F") == 0) {
|
|
838
|
+
*out = 8U + bits_product_to_integer(k_variant_payload(value), 2);
|
|
839
|
+
return 1;
|
|
840
|
+
}
|
|
841
|
+
if (strcmp(tag, "p10") == 0) {
|
|
842
|
+
*out = 16U;
|
|
843
|
+
return 1;
|
|
844
|
+
}
|
|
845
|
+
return 0;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
static int unicode_value_to_codepoint(k_value *value, unsigned *out) {
|
|
849
|
+
const char *tag = k_variant_tag(value);
|
|
850
|
+
if (tag == NULL) return 0;
|
|
851
|
+
k_value *payload = k_variant_payload(value);
|
|
852
|
+
if (strcmp(tag, "ascii") == 0) {
|
|
853
|
+
*out = bits_product_to_integer(payload, 6);
|
|
854
|
+
return 1;
|
|
855
|
+
}
|
|
856
|
+
if (strcmp(tag, "plane0") == 0) {
|
|
857
|
+
*out = bits_product_to_integer(payload, 10);
|
|
858
|
+
return 1;
|
|
859
|
+
}
|
|
860
|
+
if (strcmp(tag, "bmp_common") == 0) {
|
|
861
|
+
unsigned hi = 0;
|
|
862
|
+
k_value *product = payload;
|
|
863
|
+
if (!decode_bmp_common_hi(k_product_get(product, "hi"), &hi)) return 0;
|
|
864
|
+
*out = (hi << 8) | bits_product_to_integer(k_product_get(product, "lo"), 7);
|
|
865
|
+
return 1;
|
|
866
|
+
}
|
|
867
|
+
if (strcmp(tag, "bmp_private_use") == 0) {
|
|
868
|
+
unsigned hi = 0;
|
|
869
|
+
k_value *product = payload;
|
|
870
|
+
if (!decode_bmp_private_hi(k_product_get(product, "hi"), &hi)) return 0;
|
|
871
|
+
*out = (hi << 8) | bits_product_to_integer(k_product_get(product, "lo"), 7);
|
|
872
|
+
return 1;
|
|
873
|
+
}
|
|
874
|
+
if (strcmp(tag, "supplementary_plane1") == 0) {
|
|
875
|
+
k_value *product = payload;
|
|
876
|
+
*out = 0x10000U |
|
|
877
|
+
(bits_product_to_integer(k_product_get(product, "mid"), 7) << 8) |
|
|
878
|
+
bits_product_to_integer(k_product_get(product, "lo"), 7);
|
|
879
|
+
return 1;
|
|
880
|
+
}
|
|
881
|
+
if (strcmp(tag, "supplementary_planes2_16") == 0) {
|
|
882
|
+
unsigned plane = 0;
|
|
883
|
+
k_value *product = payload;
|
|
884
|
+
if (!decode_plane_2_to_16(k_product_get(product, "plane"), &plane)) return 0;
|
|
885
|
+
*out = (plane << 16) |
|
|
886
|
+
(bits_product_to_integer(k_product_get(product, "mid"), 7) << 8) |
|
|
887
|
+
bits_product_to_integer(k_product_get(product, "lo"), 7);
|
|
888
|
+
return 1;
|
|
889
|
+
}
|
|
890
|
+
return 0;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
static int utf8_append(char **text, size_t *length, size_t *capacity, unsigned cp) {
|
|
894
|
+
if (cp > 0x10ffffU || (cp >= 0xd800U && cp <= 0xdfffU)) return 0;
|
|
895
|
+
size_t needed = cp <= 0x7fU ? 1 : cp <= 0x7ffU ? 2 : cp <= 0xffffU ? 3 : 4;
|
|
896
|
+
if (*length + needed + 1 > *capacity) {
|
|
897
|
+
while (*length + needed + 1 > *capacity) *capacity *= 2;
|
|
898
|
+
char *grown = realloc(*text, *capacity);
|
|
899
|
+
if (grown == NULL) abort();
|
|
900
|
+
*text = grown;
|
|
901
|
+
}
|
|
902
|
+
unsigned char *out = (unsigned char *)(*text + *length);
|
|
903
|
+
if (cp <= 0x7fU) {
|
|
904
|
+
out[0] = (unsigned char)cp;
|
|
905
|
+
} else if (cp <= 0x7ffU) {
|
|
906
|
+
out[0] = (unsigned char)(0xc0U | (cp >> 6));
|
|
907
|
+
out[1] = (unsigned char)(0x80U | (cp & 0x3fU));
|
|
908
|
+
} else if (cp <= 0xffffU) {
|
|
909
|
+
out[0] = (unsigned char)(0xe0U | (cp >> 12));
|
|
910
|
+
out[1] = (unsigned char)(0x80U | ((cp >> 6) & 0x3fU));
|
|
911
|
+
out[2] = (unsigned char)(0x80U | (cp & 0x3fU));
|
|
912
|
+
} else {
|
|
913
|
+
out[0] = (unsigned char)(0xf0U | (cp >> 18));
|
|
914
|
+
out[1] = (unsigned char)(0x80U | ((cp >> 12) & 0x3fU));
|
|
915
|
+
out[2] = (unsigned char)(0x80U | ((cp >> 6) & 0x3fU));
|
|
916
|
+
out[3] = (unsigned char)(0x80U | (cp & 0x3fU));
|
|
917
|
+
}
|
|
918
|
+
*length += needed;
|
|
919
|
+
(*text)[*length] = 0;
|
|
920
|
+
return 1;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
static char *string_value_to_utf8(k_value *value, size_t *out_length) {
|
|
924
|
+
size_t capacity = 16;
|
|
925
|
+
size_t length = 0;
|
|
926
|
+
char *text = malloc(capacity);
|
|
927
|
+
if (text == NULL) abort();
|
|
928
|
+
text[0] = 0;
|
|
929
|
+
k_value *cursor = value;
|
|
930
|
+
for (;;) {
|
|
931
|
+
const char *tag = k_variant_tag(cursor);
|
|
932
|
+
if (tag == NULL) {
|
|
933
|
+
free(text);
|
|
934
|
+
return NULL;
|
|
935
|
+
}
|
|
936
|
+
if (strcmp(tag, "nil") == 0) {
|
|
937
|
+
text[length] = 0;
|
|
938
|
+
*out_length = length;
|
|
939
|
+
return text;
|
|
940
|
+
}
|
|
941
|
+
if (strcmp(tag, "cons") != 0) {
|
|
942
|
+
free(text);
|
|
943
|
+
return NULL;
|
|
944
|
+
}
|
|
945
|
+
k_value *pair = k_variant_payload(cursor);
|
|
946
|
+
k_value *car = k_product_get(pair, "car");
|
|
947
|
+
unsigned cp = 0;
|
|
948
|
+
if (!unicode_value_to_codepoint(car, &cp) || !utf8_append(&text, &length, &capacity, cp)) {
|
|
949
|
+
free(text);
|
|
950
|
+
return NULL;
|
|
951
|
+
}
|
|
952
|
+
cursor = k_product_get(pair, "cdr");
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
static k_value *list_tail(k_value *list) {
|
|
957
|
+
k_value *payload = k_variant_payload(list);
|
|
958
|
+
return payload == NULL ? NULL : k_product_get(payload, "cdr");
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
static k_value *list_head(k_value *list) {
|
|
962
|
+
k_value *payload = k_variant_payload(list);
|
|
963
|
+
return payload == NULL ? NULL : k_product_get(payload, "car");
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
static size_t list_length(k_value *list) {
|
|
967
|
+
size_t count = 0;
|
|
968
|
+
k_value *cursor = list;
|
|
969
|
+
while (tag_is(cursor, "cons")) {
|
|
970
|
+
count++;
|
|
971
|
+
cursor = list_tail(cursor);
|
|
972
|
+
}
|
|
973
|
+
return tag_is(cursor, "nil") ? count : 0;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
static int node_kind_from_tag(const char *tag) {
|
|
977
|
+
if (strcmp(tag, "any") == 0) return KP_ANY;
|
|
978
|
+
if (strcmp(tag, "open-product") == 0) return KP_OPEN_PRODUCT;
|
|
979
|
+
if (strcmp(tag, "open-union") == 0) return KP_OPEN_UNION;
|
|
980
|
+
if (strcmp(tag, "closed-product") == 0) return KP_CLOSED_PRODUCT;
|
|
981
|
+
if (strcmp(tag, "closed-union") == 0) return KP_CLOSED_UNION;
|
|
982
|
+
return -1;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
static k_pattern *pattern_from_k_value(k_value *value) {
|
|
986
|
+
size_t node_count = list_length(value);
|
|
987
|
+
if (node_count == 0 && !tag_is(value, "nil")) return NULL;
|
|
988
|
+
k_pattern *pattern = calloc(1, sizeof(k_pattern));
|
|
989
|
+
if (pattern == NULL) abort();
|
|
990
|
+
pattern->node_count = node_count;
|
|
991
|
+
pattern->nodes = calloc(node_count, sizeof(k_pattern_node));
|
|
992
|
+
if (node_count > 0 && pattern->nodes == NULL) abort();
|
|
993
|
+
k_value *cursor = value;
|
|
994
|
+
for (size_t node_index = 0; node_index < node_count; node_index++) {
|
|
995
|
+
k_value *node_value = list_head(cursor);
|
|
996
|
+
const char *node_tag = k_variant_tag(node_value);
|
|
997
|
+
int kind = node_tag == NULL ? -1 : node_kind_from_tag(node_tag);
|
|
998
|
+
if (kind < 0) return NULL;
|
|
999
|
+
pattern->nodes[node_index].kind = kind;
|
|
1000
|
+
k_value *edges_list = k_variant_payload(node_value);
|
|
1001
|
+
if (kind == KP_ANY) {
|
|
1002
|
+
pattern->nodes[node_index].edge_count = 0;
|
|
1003
|
+
pattern->nodes[node_index].edges = NULL;
|
|
1004
|
+
} else {
|
|
1005
|
+
size_t edge_count = list_length(edges_list);
|
|
1006
|
+
pattern->nodes[node_index].edge_count = edge_count;
|
|
1007
|
+
pattern->nodes[node_index].edges = calloc(edge_count, sizeof(k_pattern_edge));
|
|
1008
|
+
if (edge_count > 0 && pattern->nodes[node_index].edges == NULL) abort();
|
|
1009
|
+
k_value *edge_cursor = edges_list;
|
|
1010
|
+
for (size_t edge_index = 0; edge_index < edge_count; edge_index++) {
|
|
1011
|
+
k_value *edge = list_head(edge_cursor);
|
|
1012
|
+
size_t label_length = 0;
|
|
1013
|
+
char *label = string_value_to_utf8(k_product_get(edge, "label"), &label_length);
|
|
1014
|
+
if (label == NULL) return NULL;
|
|
1015
|
+
pattern->nodes[node_index].edges[edge_index].label = label;
|
|
1016
|
+
pattern->nodes[node_index].edges[edge_index].label_length = label_length;
|
|
1017
|
+
pattern->nodes[node_index].edges[edge_index].target = bits_to_integer(k_product_get(edge, "target"));
|
|
1018
|
+
edge_cursor = list_tail(edge_cursor);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
cursor = list_tail(cursor);
|
|
1022
|
+
}
|
|
1023
|
+
return pattern;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
static void free_pattern(k_pattern *pattern) {
|
|
1027
|
+
if (pattern == NULL || pattern == &core_pattern) return;
|
|
1028
|
+
for (size_t i = 0; i < pattern->node_count; i++) {
|
|
1029
|
+
for (size_t j = 0; j < pattern->nodes[i].edge_count; j++) {
|
|
1030
|
+
free((void *)pattern->nodes[i].edges[j].label);
|
|
1031
|
+
}
|
|
1032
|
+
free(pattern->nodes[i].edges);
|
|
1033
|
+
}
|
|
1034
|
+
free(pattern->nodes);
|
|
1035
|
+
free(pattern);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
static unsigned char *read_all(FILE *in, size_t *out_length) {
|
|
1039
|
+
size_t capacity = 4096;
|
|
1040
|
+
size_t length = 0;
|
|
1041
|
+
unsigned char *bytes = malloc(capacity);
|
|
1042
|
+
if (bytes == NULL) abort();
|
|
1043
|
+
for (;;) {
|
|
1044
|
+
if (length == capacity) {
|
|
1045
|
+
capacity *= 2;
|
|
1046
|
+
unsigned char *grown = realloc(bytes, capacity);
|
|
1047
|
+
if (grown == NULL) abort();
|
|
1048
|
+
bytes = grown;
|
|
1049
|
+
}
|
|
1050
|
+
size_t n = fread(bytes + length, 1, capacity - length, in);
|
|
1051
|
+
length += n;
|
|
1052
|
+
if (n == 0) break;
|
|
1053
|
+
}
|
|
1054
|
+
if (ferror(in)) {
|
|
1055
|
+
free(bytes);
|
|
1056
|
+
return NULL;
|
|
1057
|
+
}
|
|
1058
|
+
*out_length = length;
|
|
1059
|
+
return bytes;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
k_wire_input k_decode_wire_envelope(const unsigned char *bytes, size_t length, k_rt *rt) {
|
|
1063
|
+
k_wire_input result = {NULL, NULL};
|
|
1064
|
+
if (bytes == NULL) return result;
|
|
1065
|
+
|
|
1066
|
+
bit_reader reader = {bytes, length, 0, 0, 1};
|
|
1067
|
+
k_rt *pattern_rt = k_rt_new();
|
|
1068
|
+
k_value *pattern_value = decode_node(&reader, &core_pattern, 0, pattern_rt);
|
|
1069
|
+
k_pattern *pattern = reader.ok ? pattern_from_k_value(pattern_value) : NULL;
|
|
1070
|
+
k_value *value = pattern == NULL ? NULL : decode_node(&reader, pattern, 0, rt);
|
|
1071
|
+
int ok = reader.ok && br_zero_padding(&reader);
|
|
1072
|
+
k_rt_free(pattern_rt);
|
|
1073
|
+
if (!ok) {
|
|
1074
|
+
free_pattern(pattern);
|
|
1075
|
+
return result;
|
|
1076
|
+
}
|
|
1077
|
+
result.value = value;
|
|
1078
|
+
result.pattern = pattern;
|
|
1079
|
+
return result;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
k_wire_input k_read_wire_envelope(FILE *in, k_rt *rt) {
|
|
1083
|
+
k_wire_input result = {NULL, NULL};
|
|
1084
|
+
size_t length = 0;
|
|
1085
|
+
unsigned char *bytes = read_all(in, &length);
|
|
1086
|
+
if (bytes == NULL) return result;
|
|
1087
|
+
result = k_decode_wire_envelope(bytes, length, rt);
|
|
1088
|
+
free(bytes);
|
|
1089
|
+
return result;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
void k_wire_input_free(k_wire_input input) {
|
|
1093
|
+
free_pattern(input.pattern);
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
k_value *k_read_wire(FILE *in, k_rt *rt) {
|
|
1097
|
+
k_wire_input input = k_read_wire_envelope(in, rt);
|
|
1098
|
+
k_value *value = input.value;
|
|
1099
|
+
k_wire_input_free(input);
|
|
1100
|
+
return value;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
int k_pattern_equal(k_pattern *a, k_pattern *b) {
|
|
1104
|
+
if (a == b) return 1;
|
|
1105
|
+
if (a == NULL || b == NULL) return 0;
|
|
1106
|
+
if (a->node_count != b->node_count) return 0;
|
|
1107
|
+
for (size_t i = 0; i < a->node_count; i++) {
|
|
1108
|
+
k_pattern_node *left = &a->nodes[i];
|
|
1109
|
+
k_pattern_node *right = &b->nodes[i];
|
|
1110
|
+
if (left->kind != right->kind || left->edge_count != right->edge_count) return 0;
|
|
1111
|
+
for (size_t j = 0; j < left->edge_count; j++) {
|
|
1112
|
+
if (left->edges[j].target != right->edges[j].target) return 0;
|
|
1113
|
+
if (!bytes_equal(left->edges[j].label, left->edges[j].label_length, right->edges[j].label, right->edges[j].label_length)) return 0;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
return 1;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
static int wire_prefix_matches(const unsigned char *bytes, size_t length, const k_wire_prefix *prefix) {
|
|
1120
|
+
if (bytes == NULL || prefix == NULL || !prefix->ok || length < prefix->length) return 0;
|
|
1121
|
+
if (prefix->length > 0 && memcmp(bytes, prefix->bytes, prefix->length) != 0) return 0;
|
|
1122
|
+
if (prefix->bit_count == 0) return 1;
|
|
1123
|
+
if (length == prefix->length) return 0;
|
|
1124
|
+
unsigned char mask = (unsigned char)(0xffU << (8 - prefix->bit_count));
|
|
1125
|
+
unsigned char expected = (unsigned char)(prefix->current << (8 - prefix->bit_count));
|
|
1126
|
+
return (bytes[prefix->length] & mask) == expected;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
k_value *k_decode_wire_value_with_prefix(const unsigned char *bytes, size_t length, k_wire_prefix *prefix, k_pattern *pattern, k_rt *rt) {
|
|
1130
|
+
if (!wire_prefix_matches(bytes, length, prefix)) return NULL;
|
|
1131
|
+
bit_reader reader = {bytes, length, prefix->length, prefix->bit_count, 1};
|
|
1132
|
+
k_value *value = decode_node(&reader, pattern, 0, rt);
|
|
1133
|
+
if (!reader.ok || !br_zero_padding(&reader)) return NULL;
|
|
1134
|
+
return value;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
static void encode_node(bit_writer *writer, k_pattern *pattern, size_t node_id, k_value *value) {
|
|
1138
|
+
if (!writer->ok || node_id >= pattern->node_count) {
|
|
1139
|
+
writer->ok = 0;
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
k_pattern_node *node = &pattern->nodes[node_id];
|
|
1143
|
+
if (node->kind == KP_ANY) {
|
|
1144
|
+
writer->ok = 0;
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
if (node->kind == KP_OPEN_PRODUCT || node->kind == KP_CLOSED_PRODUCT) {
|
|
1148
|
+
if (value == NULL || value->kind != K_VALUE_PRODUCT) {
|
|
1149
|
+
writer->ok = 0;
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
for (size_t i = 0; i < node->edge_count; i++) {
|
|
1153
|
+
k_value *child = NULL;
|
|
1154
|
+
if (i < value->as.product.count &&
|
|
1155
|
+
bytes_equal(value->as.product.fields[i].label, value->as.product.fields[i].label_length, node->edges[i].label, node->edges[i].label_length)) {
|
|
1156
|
+
child = value->as.product.fields[i].value;
|
|
1157
|
+
} else {
|
|
1158
|
+
child = k_product_get_n(value, node->edges[i].label, node->edges[i].label_length);
|
|
1159
|
+
}
|
|
1160
|
+
encode_node(writer, pattern, node->edges[i].target, child);
|
|
1161
|
+
}
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
if (node->kind == KP_OPEN_UNION || node->kind == KP_CLOSED_UNION) {
|
|
1165
|
+
const char *tag = k_variant_tag(value);
|
|
1166
|
+
size_t tag_length = k_variant_tag_length(value);
|
|
1167
|
+
if (tag == NULL) {
|
|
1168
|
+
writer->ok = 0;
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
size_t ordinal = node->edge_count;
|
|
1172
|
+
for (size_t i = 0; i < node->edge_count; i++) {
|
|
1173
|
+
if (bytes_equal(node->edges[i].label, node->edges[i].label_length, tag, tag_length)) {
|
|
1174
|
+
ordinal = i;
|
|
1175
|
+
break;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
if (ordinal == node->edge_count) {
|
|
1179
|
+
writer->ok = 0;
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
bw_write_bits(writer, (unsigned)ordinal, choice_width(node->edge_count));
|
|
1183
|
+
encode_node(writer, pattern, node->edges[ordinal].target, k_variant_payload(value));
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
static int compare_fields(const void *a, const void *b) {
|
|
1188
|
+
const k_field *fa = (const k_field *)a;
|
|
1189
|
+
const k_field *fb = (const k_field *)b;
|
|
1190
|
+
size_t min_length = fa->label_length < fb->label_length ? fa->label_length : fb->label_length;
|
|
1191
|
+
int cmp = min_length == 0 ? 0 : memcmp(fa->label, fb->label, min_length);
|
|
1192
|
+
if (cmp != 0) return cmp;
|
|
1193
|
+
if (fa->label_length < fb->label_length) return -1;
|
|
1194
|
+
if (fa->label_length > fb->label_length) return 1;
|
|
1195
|
+
return 0;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
static size_t derive_pattern_node(k_pattern *pattern, k_value *value) {
|
|
1199
|
+
size_t node_id = pattern->node_count++;
|
|
1200
|
+
pattern->nodes = realloc(pattern->nodes, pattern->node_count * sizeof(k_pattern_node));
|
|
1201
|
+
if (pattern->nodes == NULL) abort();
|
|
1202
|
+
pattern->nodes[node_id].edge_count = 0;
|
|
1203
|
+
pattern->nodes[node_id].edges = NULL;
|
|
1204
|
+
if (value->kind == K_VALUE_PRODUCT || value->kind == K_VALUE_UNIT) {
|
|
1205
|
+
pattern->nodes[node_id].kind = KP_CLOSED_PRODUCT;
|
|
1206
|
+
if (value->kind == K_VALUE_UNIT) return node_id;
|
|
1207
|
+
size_t count = value->as.product.count;
|
|
1208
|
+
k_field *fields = malloc(count * sizeof(k_field));
|
|
1209
|
+
if (count > 0 && fields == NULL) abort();
|
|
1210
|
+
memcpy(fields, value->as.product.fields, count * sizeof(k_field));
|
|
1211
|
+
qsort(fields, count, sizeof(k_field), compare_fields);
|
|
1212
|
+
pattern->nodes[node_id].edge_count = count;
|
|
1213
|
+
pattern->nodes[node_id].edges = calloc(count, sizeof(k_pattern_edge));
|
|
1214
|
+
if (count > 0 && pattern->nodes[node_id].edges == NULL) abort();
|
|
1215
|
+
for (size_t i = 0; i < count; i++) {
|
|
1216
|
+
pattern->nodes[node_id].edges[i].label = heap_memdup_text(fields[i].label, fields[i].label_length);
|
|
1217
|
+
pattern->nodes[node_id].edges[i].label_length = fields[i].label_length;
|
|
1218
|
+
pattern->nodes[node_id].edges[i].target = derive_pattern_node(pattern, fields[i].value);
|
|
1219
|
+
}
|
|
1220
|
+
free(fields);
|
|
1221
|
+
return node_id;
|
|
1222
|
+
}
|
|
1223
|
+
pattern->nodes[node_id].kind = KP_OPEN_UNION;
|
|
1224
|
+
pattern->nodes[node_id].edge_count = 1;
|
|
1225
|
+
pattern->nodes[node_id].edges = calloc(1, sizeof(k_pattern_edge));
|
|
1226
|
+
if (pattern->nodes[node_id].edges == NULL) abort();
|
|
1227
|
+
pattern->nodes[node_id].edges[0].label = heap_memdup_text(value->as.variant.tag, value->as.variant.tag_length);
|
|
1228
|
+
pattern->nodes[node_id].edges[0].label_length = value->as.variant.tag_length;
|
|
1229
|
+
pattern->nodes[node_id].edges[0].target = derive_pattern_node(pattern, value->as.variant.payload);
|
|
1230
|
+
return node_id;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
static k_pattern *derive_pattern(k_value *value) {
|
|
1234
|
+
k_pattern *pattern = calloc(1, sizeof(k_pattern));
|
|
1235
|
+
if (pattern == NULL) abort();
|
|
1236
|
+
derive_pattern_node(pattern, value);
|
|
1237
|
+
return pattern;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
static k_value *unit_value(k_rt *rt) {
|
|
1241
|
+
return k_product(rt, 0);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
static k_value *integer_to_bits(k_rt *rt, unsigned value) {
|
|
1245
|
+
k_value *result = k_variant(rt, "_", unit_value(rt));
|
|
1246
|
+
if (value == 0) return result;
|
|
1247
|
+
|
|
1248
|
+
unsigned bits[sizeof(unsigned) * 8];
|
|
1249
|
+
size_t count = 0;
|
|
1250
|
+
while (value > 0) {
|
|
1251
|
+
bits[count++] = value & 1U;
|
|
1252
|
+
value >>= 1;
|
|
1253
|
+
}
|
|
1254
|
+
while (count > 0) {
|
|
1255
|
+
unsigned bit = bits[--count];
|
|
1256
|
+
result = k_variant(rt, bit ? "1" : "0", result);
|
|
1257
|
+
}
|
|
1258
|
+
return result;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
static k_value *encode_bmp_common_hi(k_rt *rt, unsigned hi) {
|
|
1262
|
+
if (hi >= 0x08U && hi <= 0x0fU) return k_variant(rt, "h08_0F", bits_product(rt, 2, hi - 0x08U));
|
|
1263
|
+
if (hi >= 0x10U && hi <= 0x7fU) return k_variant(rt, "h10_7F", bits_product(rt, 6, hi - 0x10U));
|
|
1264
|
+
if (hi >= 0x80U && hi <= 0xcfU) return k_variant(rt, "h80_CF", bits_product(rt, 6, hi - 0x80U));
|
|
1265
|
+
if (hi >= 0xd0U && hi <= 0xd7U) return k_variant(rt, "hD0_D7", bits_product(rt, 2, hi - 0xd0U));
|
|
1266
|
+
if (hi == 0xf9U) return k_variant(rt, "hF9", unit_value(rt));
|
|
1267
|
+
if (hi >= 0xfaU && hi <= 0xfbU) return k_variant(rt, "hFA_FB", bits_product(rt, 0, hi - 0xfaU));
|
|
1268
|
+
if (hi >= 0xfcU && hi <= 0xfdU) return k_variant(rt, "hFC_FD", bits_product(rt, 0, hi - 0xfcU));
|
|
1269
|
+
if (hi >= 0xfeU && hi <= 0xffU) return k_variant(rt, "hFE_FF", bits_product(rt, 0, hi - 0xfeU));
|
|
1270
|
+
return NULL;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
static k_value *encode_bmp_private_hi(k_rt *rt, unsigned hi) {
|
|
1274
|
+
if (hi >= 0xe0U && hi <= 0xefU) return k_variant(rt, "hE0_EF", bits_product(rt, 3, hi - 0xe0U));
|
|
1275
|
+
if (hi >= 0xf0U && hi <= 0xf7U) return k_variant(rt, "hF0_F7", bits_product(rt, 2, hi - 0xf0U));
|
|
1276
|
+
if (hi == 0xf8U) return k_variant(rt, "hF8", unit_value(rt));
|
|
1277
|
+
return NULL;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
static k_value *encode_plane_2_to_16(k_rt *rt, unsigned plane) {
|
|
1281
|
+
if (plane >= 2U && plane <= 3U) return k_variant(rt, "p02_03", bits_product(rt, 0, plane - 2U));
|
|
1282
|
+
if (plane >= 4U && plane <= 7U) return k_variant(rt, "p04_07", bits_product(rt, 1, plane - 4U));
|
|
1283
|
+
if (plane >= 8U && plane <= 15U) return k_variant(rt, "p08_0F", bits_product(rt, 2, plane - 8U));
|
|
1284
|
+
if (plane == 16U) return k_variant(rt, "p10", unit_value(rt));
|
|
1285
|
+
return NULL;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
static k_value *codepoint_to_unicode_value(k_rt *rt, unsigned cp) {
|
|
1289
|
+
if (cp > 0x10ffffU || (cp >= 0xd800U && cp <= 0xdfffU)) return NULL;
|
|
1290
|
+
if (cp <= 0x7fU) return k_variant(rt, "ascii", bits_product(rt, 6, cp));
|
|
1291
|
+
if (cp <= 0x7ffU) return k_variant(rt, "plane0", bits_product(rt, 10, cp));
|
|
1292
|
+
if (cp <= 0xffffU) {
|
|
1293
|
+
unsigned hi = (cp >> 8) & 0xffU;
|
|
1294
|
+
unsigned lo = cp & 0xffU;
|
|
1295
|
+
k_value *product = k_product(rt, 2);
|
|
1296
|
+
if (hi >= 0xe0U && hi <= 0xf8U) {
|
|
1297
|
+
k_product_set(product, "hi", encode_bmp_private_hi(rt, hi));
|
|
1298
|
+
k_product_set(product, "lo", bits_product(rt, 7, lo));
|
|
1299
|
+
return k_variant(rt, "bmp_private_use", product);
|
|
1300
|
+
}
|
|
1301
|
+
k_product_set(product, "hi", encode_bmp_common_hi(rt, hi));
|
|
1302
|
+
k_product_set(product, "lo", bits_product(rt, 7, lo));
|
|
1303
|
+
return k_variant(rt, "bmp_common", product);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
unsigned mid = (cp >> 8) & 0xffU;
|
|
1307
|
+
unsigned lo = cp & 0xffU;
|
|
1308
|
+
k_value *product = k_product(rt, cp <= 0x1ffffU ? 2 : 3);
|
|
1309
|
+
if (cp <= 0x1ffffU) {
|
|
1310
|
+
k_product_set(product, "mid", bits_product(rt, 7, mid));
|
|
1311
|
+
k_product_set(product, "lo", bits_product(rt, 7, lo));
|
|
1312
|
+
return k_variant(rt, "supplementary_plane1", product);
|
|
1313
|
+
}
|
|
1314
|
+
k_product_set(product, "plane", encode_plane_2_to_16(rt, cp >> 16));
|
|
1315
|
+
k_product_set(product, "mid", bits_product(rt, 7, mid));
|
|
1316
|
+
k_product_set(product, "lo", bits_product(rt, 7, lo));
|
|
1317
|
+
return k_variant(rt, "supplementary_planes2_16", product);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
static int utf8_next_codepoint(const unsigned char **cursor, const unsigned char *end, unsigned *out) {
|
|
1321
|
+
const unsigned char *p = *cursor;
|
|
1322
|
+
if (p >= end) return 0;
|
|
1323
|
+
if (*p <= 0x7fU) {
|
|
1324
|
+
*out = *p;
|
|
1325
|
+
*cursor = p + 1;
|
|
1326
|
+
return 1;
|
|
1327
|
+
}
|
|
1328
|
+
if ((*p & 0xe0U) == 0xc0U) {
|
|
1329
|
+
if (p + 2 > end) return 0;
|
|
1330
|
+
if ((p[1] & 0xc0U) != 0x80U) return 0;
|
|
1331
|
+
unsigned cp = ((unsigned)(p[0] & 0x1fU) << 6) | (unsigned)(p[1] & 0x3fU);
|
|
1332
|
+
if (cp < 0x80U) return 0;
|
|
1333
|
+
*out = cp;
|
|
1334
|
+
*cursor = p + 2;
|
|
1335
|
+
return 1;
|
|
1336
|
+
}
|
|
1337
|
+
if ((*p & 0xf0U) == 0xe0U) {
|
|
1338
|
+
if (p + 3 > end) return 0;
|
|
1339
|
+
if ((p[1] & 0xc0U) != 0x80U || (p[2] & 0xc0U) != 0x80U) return 0;
|
|
1340
|
+
unsigned cp = ((unsigned)(p[0] & 0x0fU) << 12) |
|
|
1341
|
+
((unsigned)(p[1] & 0x3fU) << 6) |
|
|
1342
|
+
(unsigned)(p[2] & 0x3fU);
|
|
1343
|
+
if (cp < 0x800U || (cp >= 0xd800U && cp <= 0xdfffU)) return 0;
|
|
1344
|
+
*out = cp;
|
|
1345
|
+
*cursor = p + 3;
|
|
1346
|
+
return 1;
|
|
1347
|
+
}
|
|
1348
|
+
if ((*p & 0xf8U) == 0xf0U) {
|
|
1349
|
+
if (p + 4 > end) return 0;
|
|
1350
|
+
if ((p[1] & 0xc0U) != 0x80U || (p[2] & 0xc0U) != 0x80U || (p[3] & 0xc0U) != 0x80U) return 0;
|
|
1351
|
+
unsigned cp = ((unsigned)(p[0] & 0x07U) << 18) |
|
|
1352
|
+
((unsigned)(p[1] & 0x3fU) << 12) |
|
|
1353
|
+
((unsigned)(p[2] & 0x3fU) << 6) |
|
|
1354
|
+
(unsigned)(p[3] & 0x3fU);
|
|
1355
|
+
if (cp < 0x10000U || cp > 0x10ffffU) return 0;
|
|
1356
|
+
*out = cp;
|
|
1357
|
+
*cursor = p + 4;
|
|
1358
|
+
return 1;
|
|
1359
|
+
}
|
|
1360
|
+
return 0;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
static k_value *utf8_string_value_n(k_rt *rt, const char *text, size_t text_length) {
|
|
1364
|
+
k_value *result = k_variant(rt, "nil", unit_value(rt));
|
|
1365
|
+
const unsigned char *cursor = (const unsigned char *)text;
|
|
1366
|
+
const unsigned char *end = cursor + text_length;
|
|
1367
|
+
unsigned *codepoints = NULL;
|
|
1368
|
+
size_t count = 0;
|
|
1369
|
+
while (cursor < end) {
|
|
1370
|
+
unsigned cp = 0;
|
|
1371
|
+
if (!utf8_next_codepoint(&cursor, end, &cp)) {
|
|
1372
|
+
free(codepoints);
|
|
1373
|
+
return NULL;
|
|
1374
|
+
}
|
|
1375
|
+
unsigned *grown = realloc(codepoints, (count + 1) * sizeof(unsigned));
|
|
1376
|
+
if (grown == NULL) abort();
|
|
1377
|
+
codepoints = grown;
|
|
1378
|
+
codepoints[count++] = cp;
|
|
1379
|
+
}
|
|
1380
|
+
for (size_t i = count; i > 0; i--) {
|
|
1381
|
+
k_value *unicode = codepoint_to_unicode_value(rt, codepoints[i - 1]);
|
|
1382
|
+
if (unicode == NULL) {
|
|
1383
|
+
free(codepoints);
|
|
1384
|
+
return NULL;
|
|
1385
|
+
}
|
|
1386
|
+
k_value *pair = k_product(rt, 2);
|
|
1387
|
+
k_product_set(pair, "car", unicode);
|
|
1388
|
+
k_product_set(pair, "cdr", result);
|
|
1389
|
+
result = k_variant(rt, "cons", pair);
|
|
1390
|
+
}
|
|
1391
|
+
free(codepoints);
|
|
1392
|
+
return result;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
static k_value *utf8_string_value(k_rt *rt, const char *text) {
|
|
1396
|
+
return utf8_string_value_n(rt, text, strlen(text));
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
static k_value *edge_to_k(k_rt *rt, k_pattern_edge *edge) {
|
|
1400
|
+
k_value *product = k_product(rt, 2);
|
|
1401
|
+
k_product_set(product, "label", utf8_string_value_n(rt, edge->label, edge->label_length));
|
|
1402
|
+
k_product_set(product, "target", integer_to_bits(rt, (unsigned)edge->target));
|
|
1403
|
+
return product;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
static k_value *list_to_k(k_rt *rt, k_value **items, size_t count) {
|
|
1407
|
+
k_value *result = k_variant(rt, "nil", unit_value(rt));
|
|
1408
|
+
for (size_t i = count; i > 0; i--) {
|
|
1409
|
+
k_value *pair = k_product(rt, 2);
|
|
1410
|
+
k_product_set(pair, "car", items[i - 1]);
|
|
1411
|
+
k_product_set(pair, "cdr", result);
|
|
1412
|
+
result = k_variant(rt, "cons", pair);
|
|
1413
|
+
}
|
|
1414
|
+
return result;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
static const char *pattern_kind_tag(int kind) {
|
|
1418
|
+
switch (kind) {
|
|
1419
|
+
case KP_ANY: return "any";
|
|
1420
|
+
case KP_OPEN_PRODUCT: return "open-product";
|
|
1421
|
+
case KP_OPEN_UNION: return "open-union";
|
|
1422
|
+
case KP_CLOSED_PRODUCT: return "closed-product";
|
|
1423
|
+
case KP_CLOSED_UNION: return "closed-union";
|
|
1424
|
+
default: return NULL;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
static k_value *pattern_to_k_value(k_rt *rt, k_pattern *pattern) {
|
|
1429
|
+
k_value **nodes = calloc(pattern->node_count, sizeof(k_value *));
|
|
1430
|
+
if (pattern->node_count > 0 && nodes == NULL) abort();
|
|
1431
|
+
for (size_t i = 0; i < pattern->node_count; i++) {
|
|
1432
|
+
k_pattern_node *node = &pattern->nodes[i];
|
|
1433
|
+
k_value **edges = calloc(node->edge_count, sizeof(k_value *));
|
|
1434
|
+
if (node->edge_count > 0 && edges == NULL) abort();
|
|
1435
|
+
for (size_t j = 0; j < node->edge_count; j++) edges[j] = edge_to_k(rt, &node->edges[j]);
|
|
1436
|
+
k_value *edge_list = list_to_k(rt, edges, node->edge_count);
|
|
1437
|
+
free(edges);
|
|
1438
|
+
const char *tag = pattern_kind_tag(node->kind);
|
|
1439
|
+
nodes[i] = k_variant(rt, tag, node->kind == KP_ANY ? unit_value(rt) : edge_list);
|
|
1440
|
+
}
|
|
1441
|
+
k_value *result = list_to_k(rt, nodes, pattern->node_count);
|
|
1442
|
+
free(nodes);
|
|
1443
|
+
return result;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
k_wire_prefix k_wire_prefix_for_pattern(k_pattern *pattern) {
|
|
1447
|
+
k_wire_prefix prefix = {NULL, 0, 0, 0, 0};
|
|
1448
|
+
k_rt *pattern_rt = k_rt_new();
|
|
1449
|
+
k_value *pattern_value = pattern_to_k_value(pattern_rt, pattern);
|
|
1450
|
+
bit_writer writer = {NULL, 0, 0, 0, 0, 1};
|
|
1451
|
+
encode_node(&writer, &core_pattern, 0, pattern_value);
|
|
1452
|
+
k_rt_free(pattern_rt);
|
|
1453
|
+
if (!writer.ok) {
|
|
1454
|
+
free(writer.bytes);
|
|
1455
|
+
return prefix;
|
|
1456
|
+
}
|
|
1457
|
+
prefix.bytes = writer.bytes;
|
|
1458
|
+
prefix.length = writer.length;
|
|
1459
|
+
prefix.current = writer.current;
|
|
1460
|
+
prefix.bit_count = writer.bit_count;
|
|
1461
|
+
prefix.ok = 1;
|
|
1462
|
+
return prefix;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
void k_wire_prefix_free(k_wire_prefix prefix) {
|
|
1466
|
+
free(prefix.bytes);
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
unsigned char *k_encode_wire_as_with_prefix(k_wire_prefix *prefix, k_pattern *pattern, k_value *value, size_t *out_length) {
|
|
1470
|
+
if (out_length != NULL) *out_length = 0;
|
|
1471
|
+
if (prefix == NULL || !prefix->ok) return NULL;
|
|
1472
|
+
size_t capacity = prefix->length + 64;
|
|
1473
|
+
if (capacity < prefix->length) return NULL;
|
|
1474
|
+
unsigned char *bytes = malloc(capacity == 0 ? 1 : capacity);
|
|
1475
|
+
if (bytes == NULL) abort();
|
|
1476
|
+
if (prefix->length > 0) memcpy(bytes, prefix->bytes, prefix->length);
|
|
1477
|
+
bit_writer writer = {bytes, prefix->length, capacity, prefix->current, prefix->bit_count, 1};
|
|
1478
|
+
encode_node(&writer, pattern, 0, value);
|
|
1479
|
+
bw_flush(&writer);
|
|
1480
|
+
if (!writer.ok) {
|
|
1481
|
+
free(writer.bytes);
|
|
1482
|
+
return NULL;
|
|
1483
|
+
}
|
|
1484
|
+
if (out_length != NULL) *out_length = writer.length;
|
|
1485
|
+
return writer.bytes;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
unsigned char *k_encode_wire_as(k_pattern *pattern, k_value *value, size_t *out_length) {
|
|
1489
|
+
k_wire_prefix prefix = k_wire_prefix_for_pattern(pattern);
|
|
1490
|
+
unsigned char *bytes = k_encode_wire_as_with_prefix(&prefix, pattern, value, out_length);
|
|
1491
|
+
k_wire_prefix_free(prefix);
|
|
1492
|
+
return bytes;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
int k_write_wire_as(FILE *out, k_pattern *pattern, k_value *value) {
|
|
1496
|
+
size_t length = 0;
|
|
1497
|
+
unsigned char *bytes = k_encode_wire_as(pattern, value, &length);
|
|
1498
|
+
int ok = bytes != NULL && fwrite(bytes, 1, length, out) == length;
|
|
1499
|
+
free(bytes);
|
|
1500
|
+
return ok;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
int k_write_wire(FILE *out, k_value *value) {
|
|
1504
|
+
k_pattern *pattern = derive_pattern(value);
|
|
1505
|
+
int ok = k_write_wire_as(out, pattern, value);
|
|
1506
|
+
free_pattern(pattern);
|
|
1507
|
+
return ok;
|
|
1508
|
+
}
|