@scriptc/runtime 0.0.15 → 0.0.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scriptc/runtime",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "scriptc native runtime — C sources, compiled into every scriptc binary",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://scriptc.dev",
@@ -154,13 +154,12 @@ ScrBytes *scr_crypto_random_bytes(double n) {
154
154
  /* ── process.stdout/stderr.write(buf) ──────────────────────────────────── */
155
155
 
156
156
  bool scr_process_stdout_write_bytes(const ScrBytes *b) {
157
- fwrite(b->data, 1, b->len * scr_bytes_elem_size(b->elem), stdout);
157
+ scr_stdio_write(1, b->data, b->len * scr_bytes_elem_size(b->elem));
158
158
  return true;
159
159
  }
160
160
 
161
161
  bool scr_process_stderr_write_bytes(const ScrBytes *b) {
162
- fflush(stdout); /* merged 2>&1 output keeps source order (scr_lib.c) */
163
- fwrite(b->data, 1, b->len * scr_bytes_elem_size(b->elem), stderr);
162
+ scr_stdio_write(2, b->data, b->len * scr_bytes_elem_size(b->elem));
164
163
  return true;
165
164
  }
166
165
 
package/src/scr_console.c CHANGED
@@ -83,8 +83,11 @@ void scr_init(void) {
83
83
  _setmode(_fileno(stderr), _O_BINARY);
84
84
  _setmode(_fileno(stdin), _O_BINARY);
85
85
  #endif
86
- /* Full buffering matches Node writing to a pipe (the differential harness
87
- * never runs either side on a TTY) and makes output-heavy programs fast. */
86
+ /* A private formatting buffer coalesces the several stdio calls needed to
87
+ * render one console line. Every JavaScript-visible stdout write flushes
88
+ * before returning, so this buffer is never observable as delayed output:
89
+ * Node hands each console.log/process.stdout.write chunk to its backing
90
+ * stream immediately. */
88
91
  static char outbuf[1 << 16];
89
92
  setvbuf(stdout, outbuf, _IOFBF, sizeof outbuf);
90
93
  /* atexit is LIFO; registration order makes exit run: library cleanup
@@ -131,18 +134,36 @@ static void scr_console_write(FILE *out, size_t n, const ScrLogArg *args) {
131
134
  }
132
135
  }
133
136
  fputc('\n', out);
137
+ /* Console methods submit one formatted chunk to their backing stream.
138
+ * Keep the C buffer only as a formatter coalescing detail: a caller
139
+ * observing a live child must see this line before the next JS turn. */
140
+ fflush(out);
134
141
  }
135
142
 
136
143
  void scr_console_log(size_t n, const ScrLogArg *args) {
137
144
  scr_console_write(stdout, n, args);
138
145
  }
139
146
 
140
- /* console.error and console.warn. stderr is UNBUFFERED (C's default; Node
141
- * writes stderr synchronously too), and stdout FLUSHES first so a merged
142
- * redirection (2>&1) sees writes in source order despite stdout's full
143
- * buffering Node's piped stdout/stderr preserve write order the same
144
- * way. */
147
+ /* console.error and console.warn. Flush stdout first so runtime-internal
148
+ * output that is still being assembled cannot cross this stderr line under
149
+ * a merged redirection (2>&1); JavaScript-visible stdout writes have already
150
+ * flushed themselves. */
145
151
  void scr_console_error(size_t n, const ScrLogArg *args) {
146
152
  fflush(stdout);
147
153
  scr_console_write(stderr, n, args);
148
154
  }
155
+
156
+ /* One JavaScript-visible raw write. Node's global console and process stream
157
+ * methods hand each chunk to the backing stream when called; they do not
158
+ * retain stdout until a later stderr write, a 64 KiB threshold, or process
159
+ * exit. The runtime remains synchronous internally, so its backpressure
160
+ * surface is still constantly true, but the bytes are observable promptly.
161
+ *
162
+ * stderr flushes any runtime-internal stdout fragment first to preserve the
163
+ * existing merged-fd ordering convention. */
164
+ void scr_stdio_write(int fd, const void *data, size_t len) {
165
+ FILE *out = fd == 2 ? stderr : stdout;
166
+ if (fd == 2) fflush(stdout);
167
+ if (len > 0) fwrite(data, 1, len, out);
168
+ fflush(out);
169
+ }
@@ -307,8 +307,8 @@ int scr_exit_code_hint_get(void) { return scr_exit_code_hint; }
307
307
 
308
308
  void scr_exc_print_uncaught(void) {
309
309
  scr_exit_code_note(1);
310
- /* Pre-throw stdout must land before the stderr line when both share a
311
- * terminal; stdout is fully buffered (scr_init). */
310
+ /* Settle any runtime-internal stdout fragment before the stderr line when
311
+ * both share an fd. JavaScript-visible writes already flush themselves. */
312
312
  fflush(stdout);
313
313
  fputs("Uncaught ", stderr);
314
314
  switch (scr_exc_kind) {
package/src/scr_island.c CHANGED
@@ -2682,7 +2682,7 @@ static JSValue isl_host_write(JSContext *ctx, JSValueConst this_val, int argc,
2682
2682
  size_t len;
2683
2683
  const char *s = JS_ToCStringLen(ctx, &len, argv[1]);
2684
2684
  if (!s) return JS_EXCEPTION;
2685
- fwrite(s, 1, len, fd == 2 ? stderr : stdout);
2685
+ scr_stdio_write(fd, s, len);
2686
2686
  JS_FreeCString(ctx, s);
2687
2687
  return JS_TRUE;
2688
2688
  }
package/src/scr_lib.c CHANGED
@@ -584,21 +584,18 @@ ScrStr *scr_process_cwd(void) {
584
584
  return scr_str_new(buf, strlen(buf));
585
585
  }
586
586
 
587
- /* The raw byte writes. stdout goes through the SAME stdio stream and
588
- * buffer console.log uses (scr_init's setvbuf), so interleaved writes
589
- * keep source order; stderr is unbuffered, like Node's, and FLUSHES
590
- * stdout first (the console.error convention) so merged 2>&1 output
591
- * keeps source order despite stdout's full buffering. The boolean is
592
- * Node's backpressure signal — a synchronous fwrite has no backpressure,
593
- * so it is constantly true. */
587
+ /* The raw byte writes use the SAME stdio stream as console, and each call
588
+ * flushes before returning so live consumers see Node's source order without
589
+ * an observable C buffering delay. The boolean is Node's backpressure signal
590
+ * this synchronous runtime has no queued backpressure, so it is constantly
591
+ * true. */
594
592
  bool scr_process_stdout_write(const ScrStr *data) {
595
- fwrite(data->data, 1, data->len, stdout);
593
+ scr_stdio_write(1, data->data, data->len);
596
594
  return true;
597
595
  }
598
596
 
599
597
  bool scr_process_stderr_write(const ScrStr *data) {
600
- fflush(stdout);
601
- fwrite(data->data, 1, data->len, stderr);
598
+ scr_stdio_write(2, data->data, data->len);
602
599
  return true;
603
600
  }
604
601
 
@@ -606,7 +603,7 @@ bool scr_process_stderr_write(const ScrStr *data) {
606
603
  * WritableStream-typed value — the prefixStream idiom): the value is the
607
604
  * stream's fd (1 or 2, minted by the process.stdout/stderr reads), and
608
605
  * the write dispatches onto the exact stdout/stderr paths above so
609
- * buffering and ordering stay identical. */
606
+ * prompt submission and ordering stay identical. */
610
607
  bool scr_proc_stream_write(double fd, const ScrStr *data) {
611
608
  return (int)fd == 2 ? scr_process_stderr_write(data) : scr_process_stdout_write(data);
612
609
  }
@@ -235,9 +235,10 @@ void scr_rl_question(double id, const ScrStr *query, ScrClosure *cb /*moves*/,
235
235
  scr_throw_error_msg(SCR_ERR_ERROR, "readline was closed", 19);
236
236
  return;
237
237
  }
238
- /* The prompt writes to stdout under pipes too (Node's question does);
239
- * same stream and buffer as console.log, so ordering holds. */
240
- fwrite(query->data, 1, query->len, stdout);
238
+ /* The prompt writes to stdout under pipes too (Node's question does), and
239
+ * must be visible before input arrives even though it has no trailing
240
+ * newline. */
241
+ scr_stdio_write(1, query->data, query->len);
241
242
  if (rl->dead) {
242
243
  /* Created after stdin ended: pinned against Node — the prompt still
243
244
  * writes, but the DESTROYED stream delivers nothing and 'close'
package/src/scr_runtime.h CHANGED
@@ -35,8 +35,9 @@ char *strcasestr(const char *hay, const char *needle);
35
35
 
36
36
  /* ── process ──────────────────────────────────────────────────────────── */
37
37
 
38
- /* Called once at the top of main: stdout buffering to match piped Node,
39
- * flush-at-exit, RC audit registration (when built with -DSCR_RC_AUDIT). */
38
+ /* Called once at the top of main: private stdout formatter buffer,
39
+ * flush-at-exit, RC audit registration (when built with -DSCR_RC_AUDIT).
40
+ * JavaScript-visible writes flush before returning. */
40
41
  void scr_init(void);
41
42
 
42
43
  /* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ──────
@@ -1840,10 +1841,13 @@ int scr_lib_arg_count(void);
1840
1841
  const char *scr_lib_arg(int i);
1841
1842
  ScrStr *scr_process_platform(void); /* +1 interned ("darwin", "linux", ...) */
1842
1843
  ScrStr *scr_process_cwd(void); /* +1 fresh (getcwd) */
1843
- /* process.stdout/.stderr .write the raw byte writes (no newline, no
1844
- * formatting; data borrowed). stdout shares console.log's stream+buffer
1845
- * (ordering preserved); stderr is unbuffered like Node's. Constantly true
1846
- * (Node's backpressure boolean never fires on synchronous writes). */
1844
+ /* Submit one raw chunk to fd 1/2 and flush it before returning. Used by all
1845
+ * JavaScript-visible console/process/readline/island output paths so the
1846
+ * internal stdio formatting buffer never delays live output. */
1847
+ void scr_stdio_write(int fd, const void *data, size_t len);
1848
+ /* process.stdout/.stderr .write — raw bytes (no newline or formatting; data
1849
+ * borrowed), promptly visible and ordered with console output. Constantly
1850
+ * true (the synchronous runtime never queues backpressure). */
1847
1851
  bool scr_process_stdout_write(const ScrStr *data);
1848
1852
  bool scr_process_stderr_write(const ScrStr *data);
1849
1853
  /* The first-class WritableStream write: fd is the stream value itself
@@ -5835,11 +5839,11 @@ typedef struct {
5835
5839
  } v;
5836
5840
  } ScrLogArg;
5837
5841
 
5838
- /* Space-joined args + '\n', single buffered write. Borrows string args. */
5842
+ /* Space-joined args + '\n', submitted before return. Borrows string args. */
5839
5843
  void scr_console_log(size_t n, const ScrLogArg *args);
5840
5844
  /* The stderr twin (console.error AND console.warn — one stream in Node):
5841
- * identical formatting, unbuffered stderr, stdout flushed first so merged
5842
- * (2>&1) output keeps source order. */
5845
+ * identical formatting, with stdout settled first so merged (2>&1) output
5846
+ * keeps source order. */
5843
5847
  void scr_console_error(size_t n, const ScrLogArg *args);
5844
5848
 
5845
5849
  #endif /* SCR_RUNTIME_H */
package/src/scr_web.c CHANGED
@@ -1739,7 +1739,7 @@ static JSValue web_host_write(JSContext *ctx, JSValueConst this_val, int argc,
1739
1739
  size_t len;
1740
1740
  const char *s = JS_ToCStringLen(ctx, &len, argv[1]);
1741
1741
  if (!s) return JS_EXCEPTION;
1742
- fwrite(s, 1, len, fd == 2 ? stderr : stdout);
1742
+ scr_stdio_write(fd, s, len);
1743
1743
  JS_FreeCString(ctx, s);
1744
1744
  return JS_UNDEFINED;
1745
1745
  }