@scriptc/runtime 0.0.4 → 0.0.5

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/src/scr_regex.c CHANGED
@@ -37,8 +37,7 @@
37
37
  #include "libregexp.h"
38
38
 
39
39
  static void scr_regex_oom(void) {
40
- fputs("scriptc: out of memory\n", stderr);
41
- abort();
40
+ scr_trap("scriptc: out of memory\n");
42
41
  }
43
42
 
44
43
  /* ── libregexp host hooks ─────────────────────────────────────────────
@@ -102,7 +101,7 @@ static void scr_note_compiled(ScrRegex *re) {
102
101
  scr_compiled = realloc(scr_compiled, scr_compiled_cap * sizeof *scr_compiled);
103
102
  if (!scr_compiled) scr_regex_oom();
104
103
  }
105
- if (scr_compiled_len == 0) atexit(scr_regex_free_bytecodes);
104
+ if (scr_compiled_len == 0) scr_atexit(scr_regex_free_bytecodes);
106
105
  scr_compiled[scr_compiled_len++] = re;
107
106
  }
108
107
 
@@ -119,9 +118,8 @@ static int scr_lre_flags(const ScrStr *flags) {
119
118
  case 'u': mask |= LRE_FLAG_UNICODE; break;
120
119
  case 'y': mask |= LRE_FLAG_STICKY; break;
121
120
  default:
122
- fprintf(stderr, "scriptc: internal error: unexpected regex flag '%c'\n",
123
- flags->data[i]);
124
- abort();
121
+ scr_trap_fmt("scriptc: internal error: unexpected regex flag '%c'\n",
122
+ flags->data[i]);
125
123
  }
126
124
  }
127
125
  return mask;
@@ -197,9 +195,8 @@ static uint8_t *scr_regex_bc(ScrRegex *re) {
197
195
  * tsc's parser has already caught plain syntax errors, so this is
198
196
  * rare). */
199
197
  fflush(stdout);
200
- fprintf(stderr, "scriptc: SyntaxError: Invalid regular expression: /%s/%s: %s\n",
201
- re->source->data, re->flags->data, error_msg);
202
- abort();
198
+ scr_trap_fmt("scriptc: SyntaxError: Invalid regular expression: /%s/%s: %s\n",
199
+ re->source->data, re->flags->data, error_msg);
203
200
  }
204
201
  re->bc = bc;
205
202
  scr_note_compiled(re);
@@ -315,8 +312,7 @@ static int scr_exec(uint8_t **capture, const uint8_t *bc, const uint16_t *u,
315
312
  int rc = lre_exec(capture, bc, (const uint8_t *)u, index, len, 1, lre_opaque());
316
313
  if (rc < 0) {
317
314
  fflush(stdout);
318
- fputs("scriptc: regular expression execution failed\n", stderr);
319
- abort();
315
+ scr_trap("scriptc: regular expression execution failed\n");
320
316
  }
321
317
  return rc;
322
318
  }
@@ -351,11 +347,9 @@ bool scr_regex_test(ScrRegex *re, ScrStr *s) {
351
347
  * iteration this slice does not model (the frontend rejects the sites
352
348
  * it can see; values that flow through variables land here). */
353
349
  fflush(stdout);
354
- fprintf(stderr,
355
- "scriptc: test() on a regex with the 'g' or 'y' flag is not "
356
- "supported (stateful lastIndex); drop the flag, or use "
357
- "replace/replaceAll/split\n");
358
- abort();
350
+ scr_trap("scriptc: test() on a regex with the 'g' or 'y' flag is not "
351
+ "supported (stateful lastIndex); drop the flag, or use "
352
+ "replace/replaceAll/split\n");
359
353
  }
360
354
  int len;
361
355
  uint16_t *u = scr_to_utf16(s, &len);
@@ -379,11 +373,9 @@ ScrArr *scr_regex_match(ScrStr *s, ScrRegex *re) {
379
373
  uint8_t *bc = scr_regex_bc(re);
380
374
  if (lre_get_flags(bc) & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {
381
375
  fflush(stdout);
382
- fprintf(stderr,
383
- "scriptc: match() on a regex with the 'g' or 'y' flag is not "
384
- "supported (an every-match array is a different shape); drop the "
385
- "flag, or use replace/replaceAll/split\n");
386
- abort();
376
+ scr_trap("scriptc: match() on a regex with the 'g' or 'y' flag is not "
377
+ "supported (an every-match array is a different shape); drop the "
378
+ "flag, or use replace/replaceAll/split\n");
387
379
  }
388
380
  int len;
389
381
  uint16_t *u = scr_to_utf16(s, &len);
@@ -803,7 +795,7 @@ static bool scr_assert_regex_hits(ScrRegex *re, ScrStr *s) {
803
795
  static ScrStr *scr_assert_regex_render(ScrRegex *re) {
804
796
  size_t cap = re->source->len + re->flags->len + 2;
805
797
  char *buf = malloc(cap);
806
- if (!buf) abort();
798
+ if (!buf) scr_trap("scriptc: out of memory\n");
807
799
  size_t n = 0;
808
800
  buf[n++] = '/';
809
801
  memcpy(buf + n, re->source->data, re->source->len);
@@ -831,7 +823,7 @@ static void scr_assert_regex_input_fail(bool negated, ScrRegex *re, ScrStr *inpu
831
823
  const char *mid = ". Input:\n\n";
832
824
  size_t cap = strlen(head) + rre->len + strlen(mid) + insp->len + 1;
833
825
  char *buf = malloc(cap);
834
- if (!buf) abort();
826
+ if (!buf) scr_trap("scriptc: out of memory\n");
835
827
  size_t n = 0;
836
828
  memcpy(buf + n, head, strlen(head));
837
829
  n += strlen(head);
@@ -924,8 +916,7 @@ ScrRegex *scr_regex_new(ScrStr *pattern, ScrStr *flags) {
924
916
  }
925
917
  ScrRegex *re = calloc(1, sizeof *re);
926
918
  if (!re) {
927
- fputs("scriptc: out of memory\n", stderr);
928
- abort();
919
+ scr_trap("scriptc: out of memory\n");
929
920
  }
930
921
  re->rc = 1;
931
922
  re->source = pattern->len > 0 ? scr_str_retain(pattern) : scr_str_new("(?:)", 4);
package/src/scr_runtime.h CHANGED
@@ -39,6 +39,81 @@ char *strcasestr(const char *hay, const char *needle);
39
39
  * flush-at-exit, RC audit registration (when built with -DSCR_RC_AUDIT). */
40
40
  void scr_init(void);
41
41
 
42
+ /* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ──────
43
+ * Every unrecoverable runtime trap — OOM, semantic range traps, internal-
44
+ * invariant failures — funnels through this pair instead of open-coded
45
+ * fputs/fprintf + abort. Executable builds expand to exactly the historical
46
+ * behavior (the message's bytes on stderr, then abort — the default lane
47
+ * must not change by a byte). Library builds (-DSCR_LIB) route the message to
48
+ * the host-registered panic sink and abort only as the last resort: before
49
+ * registration, or if the sink returns (the ruled host-contract violation —
50
+ * a conforming sink longjmps to a host frame BELOW the entry, never back
51
+ * into library frames). Messages keep their trailing newline in both lanes so
52
+ * the funnel is a pure indirection over identical bytes. */
53
+ _Noreturn void scr_trap(const char *msg);
54
+ _Noreturn void scr_trap_fmt(const char *fmt, ...);
55
+
56
+ /* ── library mode (scr_library.c, linked only into library artifacts) ─────
57
+ * A library artifact has no main, no event loop, no signal handlers, no
58
+ * atexit registrations, and never touches host stdio modes or buffering:
59
+ * initialization runs inside the profile-named init entry (re-runnable
60
+ * deterministically), traps route to the sink above, and buffer-class
61
+ * results live in a library-owned result arena. Everything here compiles only
62
+ * under -DSCR_LIB; executable builds never contain it. */
63
+ #ifdef SCR_LIB
64
+ typedef struct ScrStr ScrStr; /* full definitions below (C11 repeat) */
65
+ typedef struct ScrBytes ScrBytes;
66
+ /* The host's panic sink: msg is UTF-8, valid only for the duration of the
67
+ * call; address is the trap site's return address (0 when the toolchain
68
+ * cannot supply one); ctx is the registration's opaque pointer. The sink
69
+ * must not call back into any library entry and must not unwind or longjmp
70
+ * back into library frames. */
71
+ typedef void (*ScrLibSinkFn)(void *ctx, const uint8_t *msg, size_t msg_len,
72
+ uint64_t address);
73
+ void scr_library_set_sink(ScrLibSinkFn fn, void *ctx); /* latest wins */
74
+
75
+ /* Entry prologue: aborts deterministically when the library is poisoned (a
76
+ * trap already fired — no profile entry may run again; recovery is process
77
+ * restart). reset_arena additionally drops the result arena (the
78
+ * auto-reset posture, and the reset/collect entries' shared body). */
79
+ void scr_library_entry(bool reset_arena);
80
+ void scr_library_arena_reset(void);
81
+ /* The mode-provided collect entry's body: arena reset + a full cycle
82
+ * collection (snapshot-invariant by construction — collection frees only
83
+ * unreachable cycles). */
84
+ void scr_library_collect(void);
85
+
86
+ /* Full session reset, called by the generated init entry AFTER the program
87
+ * TU released and zeroed its globals: pending-exception clear, arena
88
+ * reset, the reset registry's drains (the units' repointed atexit halves),
89
+ * the library's interned process values, a cycle collection, and — under
90
+ * SCR_RC_AUDIT — the zero-live-heap assertion (a failure is a trap through
91
+ * the sink, never _Exit). */
92
+ void scr_library_reset(void);
93
+ /* Where a unit would atexit() a lazy teardown, library builds register it
94
+ * here instead (called on every scr_library_reset, registered once). */
95
+ void scr_library_register_reset(void (*fn)(void));
96
+ /* An escaped exception at an entry boundary: renders the same "Uncaught
97
+ * ..." text the executable epilogue prints, releases the payload, and
98
+ * routes the text through the trap funnel. No-op when nothing is pending.
99
+ * Defined in scr_exception.c (it owns the cell). */
100
+ void scr_library_check_exc(void);
101
+
102
+ /* Marshalling helpers the generated wrappers call (both emissions share
103
+ * these bodies, which is how the two lanes stay identical by
104
+ * construction). Inbound is borrowed-and-copied; outbound values MOVE into
105
+ * the result arena and stay valid until the next arena reset. String
106
+ * results are NUL-terminated after *out_len bytes (ScrStr's layout). */
107
+ ScrStr *scr_library_str_in(const uint8_t *p, size_t len); /* +1 */
108
+ ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len); /* +1, u8 */
109
+ void scr_library_str_out(ScrStr *s, const uint8_t **out, size_t *out_len);
110
+ void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len);
111
+
112
+ #define scr_atexit(fn) scr_library_register_reset(fn)
113
+ #else
114
+ #define scr_atexit(fn) atexit(fn)
115
+ #endif /* SCR_LIB */
116
+
42
117
  /* ── cycle collection (scr_cycle.c) ───────────────────────────────────
43
118
  * Reference counting alone cannot free cycles, so every object that can
44
119
  * participate in one — capture boxes, heap closures, unions, promises, and
package/src/scr_string.c CHANGED
@@ -15,8 +15,7 @@ long scr_str_live_count(void) { return scr_live_strings; }
15
15
  #endif
16
16
 
17
17
  static void scr_oom(void) {
18
- fputs("scriptc: out of memory\n", stderr);
19
- abort();
18
+ scr_trap("scriptc: out of memory\n");
20
19
  }
21
20
 
22
21
  /* ── UTF-16 index cache ───────────────────────────────────────────────
@@ -519,8 +518,7 @@ ScrStr *scr_str_slice(ScrStr *s, double start, double end) {
519
518
  ScrStr *scr_str_repeat(ScrStr *s, double count) {
520
519
  double n = scr_to_integer_or_infinity(count);
521
520
  if (n < 0 || (isinf(n) && n > 0)) {
522
- fputs("scriptc: RangeError: Invalid count value\n", stderr);
523
- abort();
521
+ scr_trap("scriptc: RangeError: Invalid count value\n");
524
522
  }
525
523
  if (n == 0 || s->len == 0) return scr_str_empty();
526
524
  /* n is a finite non-negative integer here. Reject sizes malloc could not
package/src/scr_symbol.c CHANGED
@@ -44,8 +44,7 @@ void scr_sym_release_v(void *p) { scr_sym_release(p); }
44
44
  ScrSym *scr_sym_new(ScrStr *desc) {
45
45
  ScrSym *s = malloc(sizeof(ScrSym));
46
46
  if (!s) {
47
- fputs("scriptc: out of memory\n", stderr);
48
- abort();
47
+ scr_trap("scriptc: out of memory\n");
49
48
  }
50
49
  s->rc = 1;
51
50
  s->desc = desc ? scr_str_retain(desc) : NULL;
@@ -75,7 +74,7 @@ ScrSym *scr_sym_for(ScrStr *key) {
75
74
  /* First request for this key: a fresh symbol whose description IS the
76
75
  * key (the spec's Symbol.for behavior), chained into the registry with
77
76
  * the registry's own reference. */
78
- if (!g_sym_registry) atexit(scr_sym_registry_cleanup);
77
+ if (!g_sym_registry) scr_atexit(scr_sym_registry_cleanup);
79
78
  ScrSym *s = scr_sym_new(key);
80
79
  s->reg_key = scr_str_retain(key);
81
80
  s->reg_next = g_sym_registry;
package/src/scr_url.c CHANGED
@@ -69,8 +69,7 @@ static void ub_init(UrlBuf *b) {
69
69
  b->len = 0;
70
70
  b->data = malloc(b->cap);
71
71
  if (!b->data) {
72
- fputs("scriptc: out of memory\n", stderr);
73
- abort();
72
+ scr_trap("scriptc: out of memory\n");
74
73
  }
75
74
  }
76
75
 
@@ -79,8 +78,7 @@ static void ub_append(UrlBuf *b, const char *bytes, size_t n) {
79
78
  while (b->len + n > b->cap) b->cap *= 2;
80
79
  char *grown = realloc(b->data, b->cap);
81
80
  if (!grown) {
82
- fputs("scriptc: out of memory\n", stderr);
83
- abort();
81
+ scr_trap("scriptc: out of memory\n");
84
82
  }
85
83
  b->data = grown;
86
84
  }
@@ -182,8 +180,7 @@ static ScrStr *parse_rooted_path(const char *raw, size_t len, bool special) {
182
180
  size_t seg_starts_cap = 8, seg_count = 0;
183
181
  size_t *seg_starts = malloc(seg_starts_cap * sizeof(size_t));
184
182
  if (!seg_starts) {
185
- fputs("scriptc: out of memory\n", stderr);
186
- abort();
183
+ scr_trap("scriptc: out of memory\n");
187
184
  }
188
185
  size_t i = 0;
189
186
  /* One leading separator opens the first segment (rooted). */
@@ -206,7 +203,7 @@ static ScrStr *parse_rooted_path(const char *raw, size_t len, bool special) {
206
203
  if (seg_count == seg_starts_cap) {
207
204
  seg_starts_cap *= 2;
208
205
  seg_starts = realloc(seg_starts, seg_starts_cap * sizeof(size_t));
209
- if (!seg_starts) abort();
206
+ if (!seg_starts) scr_trap("scriptc: out of memory\n");
210
207
  }
211
208
  seg_starts[seg_count++] = out.len;
212
209
  }
@@ -215,7 +212,7 @@ static ScrStr *parse_rooted_path(const char *raw, size_t len, bool special) {
215
212
  if (seg_count == seg_starts_cap) {
216
213
  seg_starts_cap *= 2;
217
214
  seg_starts = realloc(seg_starts, seg_starts_cap * sizeof(size_t));
218
- if (!seg_starts) abort();
215
+ if (!seg_starts) scr_trap("scriptc: out of memory\n");
219
216
  }
220
217
  seg_starts[seg_count++] = out.len;
221
218
  }
@@ -224,8 +221,7 @@ static ScrStr *parse_rooted_path(const char *raw, size_t len, bool special) {
224
221
  seg_starts_cap *= 2;
225
222
  seg_starts = realloc(seg_starts, seg_starts_cap * sizeof(size_t));
226
223
  if (!seg_starts) {
227
- fputs("scriptc: out of memory\n", stderr);
228
- abort();
224
+ scr_trap("scriptc: out of memory\n");
229
225
  }
230
226
  }
231
227
  seg_starts[seg_count++] = out.len;
@@ -355,8 +351,7 @@ ScrUrl *scr_url_new(ScrStr *input) {
355
351
  while (e > b && (unsigned char)raw[e - 1] <= 0x20) e--;
356
352
  char *buf = malloc(e - b + 1);
357
353
  if (!buf) {
358
- fputs("scriptc: out of memory\n", stderr);
359
- abort();
354
+ scr_trap("scriptc: out of memory\n");
360
355
  }
361
356
  size_t len = 0;
362
357
  for (size_t i = b; i < e; i++) {
@@ -526,8 +521,7 @@ ScrUrl *scr_url_new(ScrStr *input) {
526
521
 
527
522
  ScrUrl *u = malloc(sizeof(ScrUrl));
528
523
  if (!u) {
529
- fputs("scriptc: out of memory\n", stderr);
530
- abort();
524
+ scr_trap("scriptc: out of memory\n");
531
525
  }
532
526
  u->rc = 1;
533
527
  u->scheme = scheme_str;
@@ -738,8 +732,7 @@ ScrStr *scr_url_str_to_path(ScrStr *input) {
738
732
  static ScrUrl *scr_url_new_file(ScrStr *host, ScrStr *encoded_path) {
739
733
  ScrUrl *u = malloc(sizeof(ScrUrl));
740
734
  if (!u) {
741
- fputs("scriptc: out of memory\n", stderr);
742
- abort();
735
+ scr_trap("scriptc: out of memory\n");
743
736
  }
744
737
  u->rc = 1;
745
738
  u->scheme = scr_str_new("file", 4);
@@ -26,8 +26,7 @@ static void ub_init(UrlBuf *b) {
26
26
  b->len = 0;
27
27
  b->data = malloc(b->cap);
28
28
  if (!b->data) {
29
- fputs("scriptc: out of memory\n", stderr);
30
- abort();
29
+ scr_trap("scriptc: out of memory\n");
31
30
  }
32
31
  }
33
32
 
@@ -36,8 +35,7 @@ static void ub_append(UrlBuf *b, const char *bytes, size_t n) {
36
35
  while (b->len + n > b->cap) b->cap *= 2;
37
36
  char *grown = realloc(b->data, b->cap);
38
37
  if (!grown) {
39
- fputs("scriptc: out of memory\n", stderr);
40
- abort();
38
+ scr_trap("scriptc: out of memory\n");
41
39
  }
42
40
  b->data = grown;
43
41
  }
@@ -94,8 +92,7 @@ struct ScrSearchParams {
94
92
  static ScrSearchParams *sp_alloc(void) {
95
93
  ScrSearchParams *sp = malloc(sizeof(ScrSearchParams));
96
94
  if (!sp) {
97
- fputs("scriptc: out of memory\n", stderr);
98
- abort();
95
+ scr_trap("scriptc: out of memory\n");
99
96
  }
100
97
  sp->rc = 1;
101
98
  sp->len = 0;
@@ -103,8 +100,7 @@ static ScrSearchParams *sp_alloc(void) {
103
100
  sp->names = malloc(sp->cap * sizeof(ScrStr *));
104
101
  sp->vals = malloc(sp->cap * sizeof(ScrStr *));
105
102
  if (!sp->names || !sp->vals) {
106
- fputs("scriptc: out of memory\n", stderr);
107
- abort();
103
+ scr_trap("scriptc: out of memory\n");
108
104
  }
109
105
  sp->owner = NULL;
110
106
  return sp;
@@ -142,8 +138,7 @@ static void sp_push(ScrSearchParams *sp, ScrStr *name, ScrStr *value) {
142
138
  ScrStr **gn = realloc(sp->names, sp->cap * sizeof(ScrStr *));
143
139
  ScrStr **gv = realloc(sp->vals, sp->cap * sizeof(ScrStr *));
144
140
  if (!gn || !gv) {
145
- fputs("scriptc: out of memory\n", stderr);
146
- abort();
141
+ scr_trap("scriptc: out of memory\n");
147
142
  }
148
143
  sp->names = gn;
149
144
  sp->vals = gv;
@@ -161,8 +156,7 @@ static ScrStr *sp_scrub_utf8(const char *in_c, size_t n) {
161
156
  const unsigned char *in = (const unsigned char *)in_c;
162
157
  char *out = malloc(n * 3 + 1);
163
158
  if (!out) {
164
- fputs("scriptc: out of memory\n", stderr);
165
- abort();
159
+ scr_trap("scriptc: out of memory\n");
166
160
  }
167
161
  size_t o = 0;
168
162
  uint32_t cp = 0;
package/src/scr_zlib.c CHANGED
@@ -18,8 +18,7 @@
18
18
  #include <zlib.h>
19
19
 
20
20
  static void scr_zlib_oom(void) {
21
- fputs("scriptc: out of memory\n", stderr);
22
- abort();
21
+ scr_trap("scriptc: out of memory\n");
23
22
  }
24
23
 
25
24
  ScrBytes *scr_zlib_deflate(const ScrBytes *data) {