xbintsc 0.1.3 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -13
- package/dist/src/ast/common.d.ts +33 -0
- package/dist/src/ast/common.js +7 -0
- package/dist/src/ast/common.js.map +1 -0
- package/dist/src/ast/declarations.d.ts +110 -0
- package/dist/src/ast/declarations.js +5 -0
- package/dist/src/ast/declarations.js.map +1 -0
- package/dist/src/ast/expressions.d.ts +219 -0
- package/dist/src/ast/expressions.js +6 -0
- package/dist/src/ast/expressions.js.map +1 -0
- package/dist/src/ast/kinds.d.ts +160 -0
- package/dist/src/ast/kinds.js +171 -0
- package/dist/src/ast/kinds.js.map +1 -0
- package/dist/src/ast/modules.d.ts +61 -0
- package/dist/src/ast/modules.js +5 -0
- package/dist/src/ast/modules.js.map +1 -0
- package/dist/src/ast/nodes.d.ts +11 -839
- package/dist/src/ast/nodes.js +11 -237
- package/dist/src/ast/nodes.js.map +1 -1
- package/dist/src/ast/operators.d.ts +71 -0
- package/dist/src/ast/operators.js +77 -0
- package/dist/src/ast/operators.js.map +1 -0
- package/dist/src/ast/statements.d.ts +120 -0
- package/dist/src/ast/statements.js +5 -0
- package/dist/src/ast/statements.js.map +1 -0
- package/dist/src/ast/types.d.ts +123 -0
- package/dist/src/ast/types.js +6 -0
- package/dist/src/ast/types.js.map +1 -0
- package/dist/src/codegen/generator/calls.d.ts +22 -0
- package/dist/src/codegen/generator/calls.js +301 -0
- package/dist/src/codegen/generator/calls.js.map +1 -0
- package/dist/src/codegen/generator/context.d.ts +45 -0
- package/dist/src/codegen/generator/context.js +128 -0
- package/dist/src/codegen/generator/context.js.map +1 -0
- package/dist/src/codegen/generator/expressions.d.ts +22 -0
- package/dist/src/codegen/generator/expressions.js +383 -0
- package/dist/src/codegen/generator/expressions.js.map +1 -0
- package/dist/src/codegen/generator/generator.d.ts +22 -0
- package/dist/src/codegen/generator/generator.js +21 -0
- package/dist/src/codegen/generator/generator.js.map +1 -0
- package/dist/src/codegen/generator/module.d.ts +15 -0
- package/dist/src/codegen/generator/module.js +114 -0
- package/dist/src/codegen/generator/module.js.map +1 -0
- package/dist/src/codegen/generator/state.d.ts +40 -0
- package/dist/src/codegen/generator/state.js +84 -0
- package/dist/src/codegen/generator/state.js.map +1 -0
- package/dist/src/codegen/generator/statements.d.ts +22 -0
- package/dist/src/codegen/generator/statements.js +425 -0
- package/dist/src/codegen/generator/statements.js.map +1 -0
- package/dist/src/codegen/generator/tables.d.ts +19 -0
- package/dist/src/codegen/generator/tables.js +153 -0
- package/dist/src/codegen/generator/tables.js.map +1 -0
- package/dist/src/codegen/llvm.d.ts +4 -13
- package/dist/src/codegen/llvm.js +4 -1159
- package/dist/src/codegen/llvm.js.map +1 -1
- package/dist/src/driver/compiler.js +13 -4
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/lexer/char.d.ts +78 -0
- package/dist/src/lexer/char.js +106 -0
- package/dist/src/lexer/char.js.map +1 -0
- package/dist/src/lexer/scanner.js +1 -98
- package/dist/src/lexer/scanner.js.map +1 -1
- package/dist/src/parser/context.d.ts +58 -0
- package/dist/src/parser/context.js +174 -0
- package/dist/src/parser/context.js.map +1 -0
- package/dist/src/parser/declarations.d.ts +26 -0
- package/dist/src/parser/declarations.js +461 -0
- package/dist/src/parser/declarations.js.map +1 -0
- package/dist/src/parser/expressions.d.ts +27 -0
- package/dist/src/parser/expressions.js +437 -0
- package/dist/src/parser/expressions.js.map +1 -0
- package/dist/src/parser/helpers.d.ts +7 -0
- package/dist/src/parser/helpers.js +36 -0
- package/dist/src/parser/helpers.js.map +1 -0
- package/dist/src/parser/literals.d.ts +16 -0
- package/dist/src/parser/literals.js +193 -0
- package/dist/src/parser/literals.js.map +1 -0
- package/dist/src/parser/modules.d.ts +12 -0
- package/dist/src/parser/modules.js +175 -0
- package/dist/src/parser/modules.js.map +1 -0
- package/dist/src/parser/operators.d.ts +12 -0
- package/dist/src/parser/operators.js +172 -0
- package/dist/src/parser/operators.js.map +1 -0
- package/dist/src/parser/parser.d.ts +17 -122
- package/dist/src/parser/parser.js +18 -2307
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/parser/speculation.d.ts +6 -0
- package/dist/src/parser/speculation.js +10 -0
- package/dist/src/parser/speculation.js.map +1 -0
- package/dist/src/parser/statements.d.ts +28 -0
- package/dist/src/parser/statements.js +402 -0
- package/dist/src/parser/statements.js.map +1 -0
- package/dist/src/parser/types.d.ts +21 -0
- package/dist/src/parser/types.js +338 -0
- package/dist/src/parser/types.js.map +1 -0
- package/dist/tests/e2e/compile.test.js +122 -2
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +9 -1
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/rt.h +32 -0
- package/runtime/rt_internal.h +106 -0
- package/runtime/xt_alloc.c +38 -0
- package/runtime/xt_builtins.c +192 -0
- package/runtime/xt_containers.c +225 -0
- package/runtime/xt_io.c +133 -0
- package/runtime/xt_stdlib.c +502 -0
- package/runtime/xt_values.c +291 -0
- package/scripts/build-runtime.mjs +8 -1
- package/src/ast/common.ts +210 -0
- package/src/ast/declarations.ts +130 -0
- package/src/ast/expressions.ts +275 -0
- package/src/ast/kinds.ts +176 -0
- package/src/ast/modules.ts +73 -0
- package/src/ast/nodes.ts +11 -1101
- package/src/ast/operators.ts +76 -0
- package/src/ast/statements.ts +148 -0
- package/src/ast/types.ts +173 -0
- package/src/codegen/generator/calls.ts +355 -0
- package/src/codegen/generator/context.ts +156 -0
- package/src/codegen/generator/expressions.ts +431 -0
- package/src/codegen/generator/generator.ts +35 -0
- package/src/codegen/generator/module.ts +139 -0
- package/src/codegen/generator/state.ts +126 -0
- package/src/codegen/generator/statements.ts +474 -0
- package/src/codegen/generator/tables.ts +171 -0
- package/src/codegen/llvm.ts +4 -1305
- package/src/driver/compiler.ts +17 -5
- package/src/lexer/char.ts +116 -0
- package/src/lexer/scanner.ts +9 -109
- package/src/parser/context.ts +196 -0
- package/src/parser/declarations.ts +502 -0
- package/src/parser/expressions.ts +465 -0
- package/src/parser/helpers.ts +42 -0
- package/src/parser/literals.ts +207 -0
- package/src/parser/modules.ts +194 -0
- package/src/parser/operators.ts +181 -0
- package/src/parser/parser.ts +35 -2369
- package/src/parser/speculation.ts +9 -0
- package/src/parser/statements.ts +457 -0
- package/src/parser/types.ts +365 -0
- package/runtime/xt_runtime.c +0 -682
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — private internal header.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the runtime translation units:
|
|
5
|
+
* xt_alloc.c heap arena + allocation kinds
|
|
6
|
+
* xt_values.c constructors, strings, conversions, arithmetic, comparison
|
|
7
|
+
* xt_containers.c objects, arrays, generic member access, boxes
|
|
8
|
+
* xt_stdlib.c Array/String methods and Math
|
|
9
|
+
* xt_builtins.c Object methods, globals and closures
|
|
10
|
+
* xt_io.c exceptions (try/catch) and console output
|
|
11
|
+
*
|
|
12
|
+
* This header declares the internal object layouts and the small set of
|
|
13
|
+
* helpers that cross translation-unit boundaries. Nothing here is part of the
|
|
14
|
+
* public ABI in `rt.h`; generated code only sees the `xt_*` prototypes there.
|
|
15
|
+
*
|
|
16
|
+
* Design notes
|
|
17
|
+
* ------------
|
|
18
|
+
* * Values are 64-bit NaN-boxed words (`xt_value`). Numbers travel unboxed;
|
|
19
|
+
* everything else is a tagged pointer into an allocation arena.
|
|
20
|
+
* * The allocator is a bump arena. It never frees, which keeps the generated
|
|
21
|
+
* code free of write barriers and makes the first implementation small and
|
|
22
|
+
* predictable. Replacing it with a precise/conservative collector is an
|
|
23
|
+
* isolated change behind `xt_alloc` plus root registration.
|
|
24
|
+
* * Strings are UTF-8. JavaScript measures string length in UTF-16 code
|
|
25
|
+
* units; `xt_string_length` currently reports code points (see README).
|
|
26
|
+
* * Objects use a small linear property list. Fine for the language subset
|
|
27
|
+
* xbintsc targets today; swap for a hash map when the profile demands it.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
#ifndef XT_RT_INTERNAL_H
|
|
31
|
+
#define XT_RT_INTERNAL_H
|
|
32
|
+
|
|
33
|
+
#include "rt.h"
|
|
34
|
+
|
|
35
|
+
#include <stddef.h>
|
|
36
|
+
#include <stdint.h>
|
|
37
|
+
|
|
38
|
+
/* Allocation kinds recorded in `xt_header.kind`. */
|
|
39
|
+
#define XT_OBJECT_KIND_STRING 1
|
|
40
|
+
#define XT_OBJECT_KIND_OBJECT 2
|
|
41
|
+
#define XT_OBJECT_KIND_ARRAY 3
|
|
42
|
+
#define XT_OBJECT_KIND_FUNCTION 4
|
|
43
|
+
|
|
44
|
+
/* Common header for every heap object. */
|
|
45
|
+
typedef struct xt_header {
|
|
46
|
+
uint8_t kind;
|
|
47
|
+
uint8_t flags;
|
|
48
|
+
uint16_t reserved;
|
|
49
|
+
uint32_t size;
|
|
50
|
+
struct xt_header *gc_next;
|
|
51
|
+
} xt_header;
|
|
52
|
+
|
|
53
|
+
typedef struct {
|
|
54
|
+
xt_header header;
|
|
55
|
+
uint32_t length;
|
|
56
|
+
uint32_t capacity;
|
|
57
|
+
char *data;
|
|
58
|
+
} xt_string;
|
|
59
|
+
|
|
60
|
+
typedef struct {
|
|
61
|
+
xt_string *key;
|
|
62
|
+
xt_value value;
|
|
63
|
+
} xt_property;
|
|
64
|
+
|
|
65
|
+
typedef struct {
|
|
66
|
+
xt_header header;
|
|
67
|
+
uint32_t count;
|
|
68
|
+
uint32_t capacity;
|
|
69
|
+
xt_property *properties;
|
|
70
|
+
} xt_object;
|
|
71
|
+
|
|
72
|
+
typedef struct {
|
|
73
|
+
xt_header header;
|
|
74
|
+
uint32_t length;
|
|
75
|
+
uint32_t capacity;
|
|
76
|
+
xt_value *items;
|
|
77
|
+
} xt_array;
|
|
78
|
+
|
|
79
|
+
typedef struct {
|
|
80
|
+
xt_header header;
|
|
81
|
+
xt_code_fn code;
|
|
82
|
+
xt_value *environment;
|
|
83
|
+
int32_t environment_count;
|
|
84
|
+
int32_t arity;
|
|
85
|
+
xt_string *name;
|
|
86
|
+
xt_object *properties;
|
|
87
|
+
} xt_function;
|
|
88
|
+
|
|
89
|
+
/* Allocation (xt_alloc.c). */
|
|
90
|
+
void *xt_alloc(size_t size, int kind);
|
|
91
|
+
|
|
92
|
+
/* Value / string helpers shared across translation units (xt_values.c). */
|
|
93
|
+
xt_string *xt_string_alloc(size_t length);
|
|
94
|
+
xt_string *xt_as_string(xt_value value);
|
|
95
|
+
int32_t xt_string_length(xt_string *s);
|
|
96
|
+
int xt_string_equals(xt_string *a, xt_string *b);
|
|
97
|
+
int32_t xt_to_int32(xt_value v);
|
|
98
|
+
|
|
99
|
+
/* Container helper (xt_containers.c). */
|
|
100
|
+
void xt_array_reserve(xt_array *array, uint32_t needed);
|
|
101
|
+
|
|
102
|
+
/* Standard-library helpers (xt_stdlib.c). */
|
|
103
|
+
xt_array *xt_as_array(xt_value value);
|
|
104
|
+
xt_value xt_arg_at(int32_t argc, xt_value *argv, int32_t index);
|
|
105
|
+
|
|
106
|
+
#endif /* XT_RT_INTERNAL_H */
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — heap allocation.
|
|
3
|
+
*
|
|
4
|
+
* A bump-style arena shared by every object kind. Allocations are never
|
|
5
|
+
* reclaimed; the design keeps replacing this with a real collector isolated
|
|
6
|
+
* behind `xt_alloc` (see rt_internal.h).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "rt_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
#include <stdlib.h>
|
|
13
|
+
|
|
14
|
+
/* ------------------------------------------------------------------------- */
|
|
15
|
+
/* Allocation */
|
|
16
|
+
/* ------------------------------------------------------------------------- */
|
|
17
|
+
|
|
18
|
+
static size_t g_heap_bytes = 0;
|
|
19
|
+
static size_t g_heap_allocations = 0;
|
|
20
|
+
static xt_header *g_heap_head = NULL;
|
|
21
|
+
|
|
22
|
+
void *xt_alloc(size_t size, int kind) {
|
|
23
|
+
xt_header *header = (xt_header *)calloc(1, size);
|
|
24
|
+
if (!header) {
|
|
25
|
+
fprintf(stderr, "xbintsc: out of memory allocating %zu bytes\n", size);
|
|
26
|
+
abort();
|
|
27
|
+
}
|
|
28
|
+
header->kind = (uint8_t)kind;
|
|
29
|
+
header->size = (uint32_t)size;
|
|
30
|
+
header->gc_next = g_heap_head;
|
|
31
|
+
g_heap_head = header;
|
|
32
|
+
g_heap_bytes += size;
|
|
33
|
+
g_heap_allocations++;
|
|
34
|
+
return header;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
size_t xt_heap_bytes(void) { return g_heap_bytes; }
|
|
38
|
+
size_t xt_heap_allocations(void) { return g_heap_allocations; }
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — builtins.
|
|
3
|
+
*
|
|
4
|
+
* `Object.*` statics and the free functions (`parseInt`, `isNaN`, `in`, ...),
|
|
5
|
+
* along with the closure representation and calling convention.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include "rt_internal.h"
|
|
9
|
+
|
|
10
|
+
#include <math.h>
|
|
11
|
+
#include <stdlib.h>
|
|
12
|
+
#include <string.h>
|
|
13
|
+
|
|
14
|
+
/* ------------------------------------------------------------------------- */
|
|
15
|
+
/* Object methods and global functions */
|
|
16
|
+
/* ------------------------------------------------------------------------- */
|
|
17
|
+
|
|
18
|
+
xt_value xt_object_values(xt_value value) {
|
|
19
|
+
xt_value result = xt_array_new(0, NULL);
|
|
20
|
+
if (!XT_IS_OBJECT(value)) return result;
|
|
21
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
22
|
+
for (uint32_t i = 0; i < obj->count; i++) xt_array_push(result, obj->properties[i].value);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
xt_value xt_object_entries(xt_value value) {
|
|
27
|
+
xt_value result = xt_array_new(0, NULL);
|
|
28
|
+
if (!XT_IS_OBJECT(value)) return result;
|
|
29
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
30
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
31
|
+
xt_value pair = xt_array_new(0, NULL);
|
|
32
|
+
xt_array_push(pair, XT_FROM_PTR(XT_TAG_STRING, obj->properties[i].key));
|
|
33
|
+
xt_array_push(pair, obj->properties[i].value);
|
|
34
|
+
xt_array_push(result, pair);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
xt_value xt_object_assign(int32_t argc, xt_value *argv) {
|
|
40
|
+
if (argc <= 0) return xt_undefined();
|
|
41
|
+
xt_value target = argv[0];
|
|
42
|
+
if (!XT_IS_OBJECT(target)) return target;
|
|
43
|
+
for (int32_t i = 1; i < argc; i++) {
|
|
44
|
+
if (!XT_IS_OBJECT(argv[i])) continue;
|
|
45
|
+
xt_object *source = (xt_object *)XT_GET_PTR(argv[i]);
|
|
46
|
+
for (uint32_t j = 0; j < source->count; j++) {
|
|
47
|
+
xt_object_set(target, XT_FROM_PTR(XT_TAG_STRING, source->properties[j].key), source->properties[j].value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return target;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Copy every own enumerable property of `source` onto `target` (`{...source}`). */
|
|
54
|
+
xt_value xt_object_spread(xt_value target, xt_value source) {
|
|
55
|
+
xt_value args[2];
|
|
56
|
+
args[0] = target;
|
|
57
|
+
args[1] = source;
|
|
58
|
+
return xt_object_assign(2, args);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
xt_value xt_parse_int(int32_t argc, xt_value *argv) {
|
|
62
|
+
xt_string *s = xt_as_string(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
63
|
+
int32_t radix = argc >= 2 ? xt_to_int32(argv[1]) : 0;
|
|
64
|
+
char *end = NULL;
|
|
65
|
+
long value = strtol(s->data, &end, radix);
|
|
66
|
+
if (end == s->data) return xt_number(NAN);
|
|
67
|
+
return xt_number((double)value);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
xt_value xt_parse_float(int32_t argc, xt_value *argv) {
|
|
71
|
+
xt_string *s = xt_as_string(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
72
|
+
char *end = NULL;
|
|
73
|
+
double value = strtod(s->data, &end);
|
|
74
|
+
if (end == s->data) return xt_number(NAN);
|
|
75
|
+
return xt_number(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
xt_value xt_is_nan(int32_t argc, xt_value *argv) {
|
|
79
|
+
double value = xt_to_number(xt_arg_at(argc, argv, 0));
|
|
80
|
+
return xt_bool(value != value);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
xt_value xt_is_finite(int32_t argc, xt_value *argv) {
|
|
84
|
+
double value = xt_to_number(xt_arg_at(argc, argv, 0));
|
|
85
|
+
return xt_bool(!isnan(value) && !isinf(value));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
xt_value xt_number_ctor(int32_t argc, xt_value *argv) {
|
|
89
|
+
if (argc == 0) return xt_number(0);
|
|
90
|
+
return xt_number(xt_to_number(argv[0]));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
xt_value xt_string_ctor(int32_t argc, xt_value *argv) {
|
|
94
|
+
if (argc == 0) return xt_string_from_cstr("");
|
|
95
|
+
return xt_to_string(argv[0]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
xt_value xt_boolean_ctor(int32_t argc, xt_value *argv) {
|
|
99
|
+
if (argc == 0) return XT_FALSE;
|
|
100
|
+
return xt_bool(xt_truthy(argv[0]));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
xt_value xt_in(xt_value key, xt_value value) {
|
|
104
|
+
if (XT_IS_OBJECT(value)) return xt_object_has(value, key);
|
|
105
|
+
if (XT_IS_ARRAY(value)) {
|
|
106
|
+
int32_t index = xt_to_int32(key);
|
|
107
|
+
return xt_bool(index >= 0 && (uint32_t)index < xt_as_array(value)->length);
|
|
108
|
+
}
|
|
109
|
+
if (XT_IS_STRING(value)) {
|
|
110
|
+
xt_string *s = xt_as_string(value);
|
|
111
|
+
xt_string *k = xt_as_string(xt_to_string(key));
|
|
112
|
+
if (k->length == 6 && memcmp(k->data, "length", 6) == 0) return XT_TRUE;
|
|
113
|
+
int32_t index = xt_to_int32(key);
|
|
114
|
+
return xt_bool(index >= 0 && (uint32_t)index < s->length);
|
|
115
|
+
}
|
|
116
|
+
return XT_FALSE;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
xt_value xt_delete(xt_value value, xt_value key) {
|
|
120
|
+
if (XT_IS_OBJECT(value)) {
|
|
121
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
122
|
+
xt_string *k = xt_as_string(xt_to_string(key));
|
|
123
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
124
|
+
if (xt_string_equals(obj->properties[i].key, k)) {
|
|
125
|
+
for (uint32_t j = i + 1; j < obj->count; j++) obj->properties[j - 1] = obj->properties[j];
|
|
126
|
+
obj->count--;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return XT_TRUE;
|
|
131
|
+
}
|
|
132
|
+
if (XT_IS_ARRAY(value)) {
|
|
133
|
+
xt_array_set(value, key, XT_UNDEFINED);
|
|
134
|
+
return XT_TRUE;
|
|
135
|
+
}
|
|
136
|
+
return XT_TRUE;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
xt_value xt_rest_args(int32_t argc, xt_value *argv, int32_t start) {
|
|
140
|
+
if (start < 0) start = 0;
|
|
141
|
+
int32_t count = argc - start;
|
|
142
|
+
if (count < 0) count = 0;
|
|
143
|
+
return xt_array_new(count, argv ? argv + start : NULL);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
/* ------------------------------------------------------------------------- */
|
|
148
|
+
/* Functions */
|
|
149
|
+
/* ------------------------------------------------------------------------- */
|
|
150
|
+
|
|
151
|
+
xt_value xt_arg(int32_t argc, xt_value *argv, int32_t index) {
|
|
152
|
+
if (index < 0 || index >= argc) return XT_UNDEFINED;
|
|
153
|
+
return argv[index];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
xt_value xt_closure_new(void *fn, int32_t env_count, xt_value *env) {
|
|
157
|
+
xt_function *function = (xt_function *)xt_alloc(sizeof(xt_function), XT_OBJECT_KIND_FUNCTION);
|
|
158
|
+
function->code = (xt_code_fn)fn;
|
|
159
|
+
function->environment_count = env_count;
|
|
160
|
+
function->arity = -1;
|
|
161
|
+
function->properties = NULL;
|
|
162
|
+
function->environment = NULL;
|
|
163
|
+
if (env_count > 0) {
|
|
164
|
+
function->environment = (xt_value *)malloc(sizeof(xt_value) * (size_t)env_count);
|
|
165
|
+
for (int32_t i = 0; i < env_count; i++) function->environment[i] = env[i];
|
|
166
|
+
}
|
|
167
|
+
return XT_FROM_PTR(XT_TAG_FUNCTION, function);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
xt_value xt_closure_call(xt_value value, int32_t argc, xt_value *argv) {
|
|
171
|
+
if (!XT_IS_FUNCTION(value)) {
|
|
172
|
+
xt_throw(xt_string_from_cstr("TypeError: value is not a function"));
|
|
173
|
+
return XT_UNDEFINED;
|
|
174
|
+
}
|
|
175
|
+
xt_function *function = (xt_function *)XT_GET_PTR(value);
|
|
176
|
+
/* The closure value itself is threaded through as `env` so the callee can
|
|
177
|
+
* read its captures with xt_closure_env(env, i). */
|
|
178
|
+
return function->code(value, argc, argv);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
xt_value xt_closure_env(xt_value value, int32_t index) {
|
|
182
|
+
if (!XT_IS_FUNCTION(value)) return XT_UNDEFINED;
|
|
183
|
+
xt_function *function = (xt_function *)XT_GET_PTR(value);
|
|
184
|
+
if (index < 0 || index >= function->environment_count) return XT_UNDEFINED;
|
|
185
|
+
return function->environment[index];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
int32_t xt_closure_arity(xt_value value) {
|
|
189
|
+
if (!XT_IS_FUNCTION(value)) return -1;
|
|
190
|
+
return ((xt_function *)XT_GET_PTR(value))->arity;
|
|
191
|
+
}
|
|
192
|
+
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — containers.
|
|
3
|
+
*
|
|
4
|
+
* Objects (linear property lists) and arrays (dynamic vectors), plus the
|
|
5
|
+
* generic `xt_get`/`xt_set` member access used by the codegen and the boxing
|
|
6
|
+
* helpers used for captured `let` bindings.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "rt_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
#include <stdlib.h>
|
|
13
|
+
#include <string.h>
|
|
14
|
+
|
|
15
|
+
/* ------------------------------------------------------------------------- */
|
|
16
|
+
/* Objects */
|
|
17
|
+
/* ------------------------------------------------------------------------- */
|
|
18
|
+
|
|
19
|
+
static void xt_object_reserve(xt_object *obj, uint32_t needed) {
|
|
20
|
+
if (needed <= obj->capacity) return;
|
|
21
|
+
uint32_t capacity = obj->capacity ? obj->capacity * 2 : 8;
|
|
22
|
+
while (capacity < needed) capacity *= 2;
|
|
23
|
+
obj->properties = (xt_property *)realloc(obj->properties, sizeof(xt_property) * capacity);
|
|
24
|
+
if (!obj->properties) {
|
|
25
|
+
fprintf(stderr, "xbintsc: out of memory growing object\n");
|
|
26
|
+
abort();
|
|
27
|
+
}
|
|
28
|
+
obj->capacity = capacity;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
xt_value xt_object_new(void) {
|
|
32
|
+
xt_object *obj = (xt_object *)xt_alloc(sizeof(xt_object), XT_OBJECT_KIND_OBJECT);
|
|
33
|
+
obj->count = 0;
|
|
34
|
+
obj->capacity = 0;
|
|
35
|
+
obj->properties = NULL;
|
|
36
|
+
return XT_FROM_PTR(XT_TAG_OBJECT, obj);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static xt_property *xt_object_find(xt_object *obj, xt_string *key) {
|
|
40
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
41
|
+
if (xt_string_equals(obj->properties[i].key, key)) return &obj->properties[i];
|
|
42
|
+
}
|
|
43
|
+
return NULL;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
xt_value xt_object_get(xt_value value, xt_value key) {
|
|
47
|
+
if (!XT_IS_OBJECT(value)) return XT_UNDEFINED;
|
|
48
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
49
|
+
xt_value keyString = xt_to_string(key);
|
|
50
|
+
xt_property *prop = xt_object_find(obj, xt_as_string(keyString));
|
|
51
|
+
return prop ? prop->value : XT_UNDEFINED;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
xt_value xt_object_set(xt_value value, xt_value key, xt_value newValue) {
|
|
55
|
+
if (!XT_IS_OBJECT(value)) return newValue;
|
|
56
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
57
|
+
xt_value keyString = xt_to_string(key);
|
|
58
|
+
xt_property *prop = xt_object_find(obj, xt_as_string(keyString));
|
|
59
|
+
if (prop) {
|
|
60
|
+
prop->value = newValue;
|
|
61
|
+
return newValue;
|
|
62
|
+
}
|
|
63
|
+
xt_object_reserve(obj, obj->count + 1);
|
|
64
|
+
obj->properties[obj->count].key = xt_as_string(keyString);
|
|
65
|
+
obj->properties[obj->count].value = newValue;
|
|
66
|
+
obj->count++;
|
|
67
|
+
return newValue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
xt_value xt_object_has(xt_value value, xt_value key) {
|
|
71
|
+
if (!XT_IS_OBJECT(value)) return XT_FALSE;
|
|
72
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
73
|
+
xt_value keyString = xt_to_string(key);
|
|
74
|
+
return xt_bool(xt_object_find(obj, xt_as_string(keyString)) != NULL);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
xt_value xt_object_keys(xt_value value) {
|
|
78
|
+
xt_value result = xt_array_new(0, NULL);
|
|
79
|
+
if (XT_IS_OBJECT(value)) {
|
|
80
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
81
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
82
|
+
xt_array_push(result, XT_FROM_PTR(XT_TAG_STRING, obj->properties[i].key));
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
if (XT_IS_ARRAY(value)) {
|
|
87
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
88
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
89
|
+
char buffer[32];
|
|
90
|
+
snprintf(buffer, sizeof(buffer), "%u", i);
|
|
91
|
+
xt_array_push(result, xt_string_from_cstr(buffer));
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
if (XT_IS_STRING(value)) {
|
|
96
|
+
xt_string *s = xt_as_string(value);
|
|
97
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
98
|
+
char buffer[32];
|
|
99
|
+
snprintf(buffer, sizeof(buffer), "%u", i);
|
|
100
|
+
xt_array_push(result, xt_string_from_cstr(buffer));
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* Convenience used by codegen for `obj.prop`. */
|
|
108
|
+
xt_value xt_object_get_cstr(xt_value value, const char *key) {
|
|
109
|
+
xt_value k = xt_string_from_cstr(key);
|
|
110
|
+
return xt_object_get(value, k);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* ------------------------------------------------------------------------- */
|
|
114
|
+
/* Arrays */
|
|
115
|
+
/* ------------------------------------------------------------------------- */
|
|
116
|
+
|
|
117
|
+
void xt_array_reserve(xt_array *array, uint32_t needed) {
|
|
118
|
+
if (needed <= array->capacity) return;
|
|
119
|
+
uint32_t capacity = array->capacity ? array->capacity * 2 : 8;
|
|
120
|
+
while (capacity < needed) capacity *= 2;
|
|
121
|
+
array->items = (xt_value *)realloc(array->items, sizeof(xt_value) * capacity);
|
|
122
|
+
if (!array->items) {
|
|
123
|
+
fprintf(stderr, "xbintsc: out of memory growing array\n");
|
|
124
|
+
abort();
|
|
125
|
+
}
|
|
126
|
+
for (uint32_t i = array->capacity; i < capacity; i++) array->items[i] = XT_UNDEFINED;
|
|
127
|
+
array->capacity = capacity;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
xt_value xt_array_new(int32_t count, xt_value *items) {
|
|
131
|
+
xt_array *array = (xt_array *)xt_alloc(sizeof(xt_array), XT_OBJECT_KIND_ARRAY);
|
|
132
|
+
array->length = 0;
|
|
133
|
+
array->capacity = 0;
|
|
134
|
+
array->items = NULL;
|
|
135
|
+
if (count > 0) {
|
|
136
|
+
xt_array_reserve(array, (uint32_t)count);
|
|
137
|
+
for (int32_t i = 0; i < count; i++) array->items[i] = items[i];
|
|
138
|
+
array->length = (uint32_t)count;
|
|
139
|
+
}
|
|
140
|
+
return XT_FROM_PTR(XT_TAG_ARRAY, array);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
xt_value xt_array_get(xt_value value, xt_value index) {
|
|
144
|
+
if (!XT_IS_ARRAY(value)) return XT_UNDEFINED;
|
|
145
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
146
|
+
int32_t i = xt_to_int32(index);
|
|
147
|
+
if (i < 0 || (uint32_t)i >= array->length) return XT_UNDEFINED;
|
|
148
|
+
return array->items[i];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
xt_value xt_array_set(xt_value value, xt_value index, xt_value newValue) {
|
|
152
|
+
if (!XT_IS_ARRAY(value)) return newValue;
|
|
153
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
154
|
+
int32_t i = xt_to_int32(index);
|
|
155
|
+
if (i < 0) return newValue;
|
|
156
|
+
xt_array_reserve(array, (uint32_t)i + 1);
|
|
157
|
+
for (uint32_t j = array->length; j < (uint32_t)i; j++) array->items[j] = XT_UNDEFINED;
|
|
158
|
+
array->items[i] = newValue;
|
|
159
|
+
if ((uint32_t)i >= array->length) array->length = (uint32_t)i + 1;
|
|
160
|
+
return newValue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
xt_value xt_array_push(xt_value value, xt_value newValue) {
|
|
164
|
+
if (!XT_IS_ARRAY(value)) return xt_number(0);
|
|
165
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
166
|
+
xt_array_reserve(array, array->length + 1);
|
|
167
|
+
array->items[array->length++] = newValue;
|
|
168
|
+
return xt_number((double)array->length);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
xt_value xt_array_length(xt_value value) {
|
|
172
|
+
if (XT_IS_ARRAY(value)) return xt_number((double)((xt_array *)XT_GET_PTR(value))->length);
|
|
173
|
+
if (XT_IS_STRING(value)) return xt_number((double)xt_string_length(xt_as_string(value)));
|
|
174
|
+
return XT_UNDEFINED;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
xt_value xt_array_spread(xt_value target, xt_value source) {
|
|
178
|
+
if (!XT_IS_ARRAY(target) || !XT_IS_ARRAY(source)) return target;
|
|
179
|
+
xt_array *dst = (xt_array *)XT_GET_PTR(target);
|
|
180
|
+
xt_array *src = (xt_array *)XT_GET_PTR(source);
|
|
181
|
+
xt_array_reserve(dst, dst->length + src->length);
|
|
182
|
+
for (uint32_t i = 0; i < src->length; i++) dst->items[dst->length++] = src->items[i];
|
|
183
|
+
return target;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
/* ------------------------------------------------------------------------- */
|
|
188
|
+
/* Generic member access */
|
|
189
|
+
/* ------------------------------------------------------------------------- */
|
|
190
|
+
|
|
191
|
+
xt_value xt_get(xt_value target, xt_value key) {
|
|
192
|
+
if (XT_IS_ARRAY(target)) return xt_array_get(target, key);
|
|
193
|
+
if (XT_IS_OBJECT(target)) return xt_object_get(target, key);
|
|
194
|
+
if (XT_IS_STRING(target)) {
|
|
195
|
+
/* Property access on a string: `.length` and numeric indexing. */
|
|
196
|
+
xt_string *s = xt_as_string(target);
|
|
197
|
+
if (XT_IS_STRING(key)) {
|
|
198
|
+
xt_string *k = xt_as_string(key);
|
|
199
|
+
if (k->length == 6 && memcmp(k->data, "length", 6) == 0) return xt_number((double)s->length);
|
|
200
|
+
}
|
|
201
|
+
int32_t index = xt_to_int32(key);
|
|
202
|
+
if (index >= 0 && (uint32_t)index < s->length) return xt_string_new(s->data + index, 1);
|
|
203
|
+
return XT_UNDEFINED;
|
|
204
|
+
}
|
|
205
|
+
return XT_UNDEFINED;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
xt_value xt_set(xt_value target, xt_value key, xt_value value) {
|
|
209
|
+
if (XT_IS_ARRAY(target)) return xt_array_set(target, key, value);
|
|
210
|
+
if (XT_IS_OBJECT(target)) return xt_object_set(target, key, value);
|
|
211
|
+
return value;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* ------------------------------------------------------------------------- */
|
|
215
|
+
/* Boxes */
|
|
216
|
+
/* ------------------------------------------------------------------------- */
|
|
217
|
+
|
|
218
|
+
xt_value xt_box_new(xt_value value) { return xt_array_new(1, &value); }
|
|
219
|
+
|
|
220
|
+
xt_value xt_box_get(xt_value box) { return xt_array_get(box, xt_number(0)); }
|
|
221
|
+
|
|
222
|
+
xt_value xt_box_set(xt_value box, xt_value value) { return xt_array_set(box, xt_number(0), value); }
|
|
223
|
+
|
|
224
|
+
xt_value xt_is_nullish(xt_value value) { return xt_bool(value == XT_UNDEFINED || value == XT_NULL); }
|
|
225
|
+
|
package/runtime/xt_io.c
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc runtime — exceptions and output.
|
|
3
|
+
*
|
|
4
|
+
* `try`/`catch` is a stack of setjmp frames; `xt_throw` longjmps into the
|
|
5
|
+
* innermost frame when one is active and otherwise prints + exits. Also holds
|
|
6
|
+
* `print`/`console` output and the Node-like value inspector.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "rt_internal.h"
|
|
10
|
+
|
|
11
|
+
#include <setjmp.h>
|
|
12
|
+
#include <stdio.h>
|
|
13
|
+
#include <stdlib.h>
|
|
14
|
+
#include <string.h>
|
|
15
|
+
|
|
16
|
+
/* ------------------------------------------------------------------------- */
|
|
17
|
+
/* Exceptions and output */
|
|
18
|
+
/* ------------------------------------------------------------------------- */
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* `try`/`catch` is implemented with a stack of setjmp frames. The compiler
|
|
22
|
+
* allocates a frame with `xt_try_enter`, calls `_setjmp` on it, and pops it
|
|
23
|
+
* with `xt_try_leave`. `xt_throw` longjmps into the innermost frame when one
|
|
24
|
+
* is active, and only prints + exits when the exception is uncaught.
|
|
25
|
+
*/
|
|
26
|
+
typedef struct xt_try_frame {
|
|
27
|
+
jmp_buf buf;
|
|
28
|
+
struct xt_try_frame *prev;
|
|
29
|
+
xt_value exception;
|
|
30
|
+
} xt_try_frame;
|
|
31
|
+
|
|
32
|
+
static xt_try_frame *g_try_top = NULL;
|
|
33
|
+
|
|
34
|
+
void *xt_try_enter(void) {
|
|
35
|
+
xt_try_frame *frame = (xt_try_frame *)calloc(1, sizeof(xt_try_frame));
|
|
36
|
+
if (!frame) abort();
|
|
37
|
+
frame->prev = g_try_top;
|
|
38
|
+
frame->exception = XT_UNDEFINED;
|
|
39
|
+
g_try_top = frame;
|
|
40
|
+
return (void *)frame;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
xt_value xt_try_exception(void *framePtr) {
|
|
44
|
+
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
45
|
+
return frame ? frame->exception : XT_UNDEFINED;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
void xt_try_leave(void *framePtr) {
|
|
49
|
+
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
50
|
+
if (frame && g_try_top == frame) g_try_top = frame->prev;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
void xt_throw(xt_value v) {
|
|
54
|
+
if (g_try_top) {
|
|
55
|
+
g_try_top->exception = v;
|
|
56
|
+
_longjmp(g_try_top->buf, 1);
|
|
57
|
+
}
|
|
58
|
+
xt_value message = xt_to_string(v);
|
|
59
|
+
xt_string *s = xt_as_string(message);
|
|
60
|
+
fprintf(stderr, "Uncaught %s\n", s->data);
|
|
61
|
+
exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static void xt_print_value(xt_value v, FILE *out) {
|
|
65
|
+
if (XT_IS_STRING(v)) {
|
|
66
|
+
xt_string *s = xt_as_string(v);
|
|
67
|
+
fwrite(s->data, 1, s->length, out);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
xt_value text = xt_to_string(v);
|
|
71
|
+
xt_string *s = xt_as_string(text);
|
|
72
|
+
fwrite(s->data, 1, s->length, out);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void xt_print(xt_value v) { xt_print_value(v, stdout); }
|
|
76
|
+
void xt_println(xt_value v) {
|
|
77
|
+
xt_print_value(v, stdout);
|
|
78
|
+
fputc('\n', stdout);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* console.log applies a Node-like inspection format: strings unquoted at the
|
|
83
|
+
* top level, arrays as `[ a, b ]` and objects as `{ key: value }`.
|
|
84
|
+
*/
|
|
85
|
+
static void xt_inspect(xt_value v, FILE *out) {
|
|
86
|
+
if (XT_IS_ARRAY(v)) {
|
|
87
|
+
xt_array *array = (xt_array *)XT_GET_PTR(v);
|
|
88
|
+
fputc('[', out);
|
|
89
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
90
|
+
if (i > 0) fputs(", ", out);
|
|
91
|
+
else fputc(' ', out);
|
|
92
|
+
xt_inspect(array->items[i], out);
|
|
93
|
+
}
|
|
94
|
+
if (array->length > 0) fputc(' ', out);
|
|
95
|
+
fputc(']', out);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (XT_IS_OBJECT(v)) {
|
|
99
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(v);
|
|
100
|
+
fputc('{', out);
|
|
101
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
102
|
+
if (i > 0) fputs(", ", out);
|
|
103
|
+
else fputc(' ', out);
|
|
104
|
+
fwrite(obj->properties[i].key->data, 1, obj->properties[i].key->length, out);
|
|
105
|
+
fputs(": ", out);
|
|
106
|
+
xt_inspect(obj->properties[i].value, out);
|
|
107
|
+
}
|
|
108
|
+
if (obj->count > 0) fputc(' ', out);
|
|
109
|
+
fputc('}', out);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
xt_print_value(v, out);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
void xt_console_log(int32_t argc, xt_value *argv) {
|
|
116
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
117
|
+
if (i > 0) fputc(' ', stdout);
|
|
118
|
+
xt_inspect(argv[i], stdout);
|
|
119
|
+
}
|
|
120
|
+
fputc('\n', stdout);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static void xt_console_write(int32_t argc, xt_value *argv, FILE *out) {
|
|
124
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
125
|
+
if (i > 0) fputc(' ', out);
|
|
126
|
+
xt_inspect(argv[i], out);
|
|
127
|
+
}
|
|
128
|
+
fputc('\n', out);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
void xt_console_info(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stdout); }
|
|
132
|
+
void xt_console_warn(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
|
|
133
|
+
void xt_console_error(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
|