writeonce/runtime/src/builtin.h
shoney.arickathil d24c705860 feat: iterations 19 + 17 — Float/Bytes scalars (.wob v5), library kind + internal/
- Float full stack: literals (fraction/exponent; `0..10` still a range), f64
  opcodes 34-41, @table column, WAL bit-exact replay, json fractions in and
  shortest-round-trip out. IEEE-quiet — FDIV never traps where DIV does.
- Bytes: a wo_str with its own class id, so alloc/free/copy are shared but no
  Text builtin accepts one; len/at/slice/eq/concat, base64 both ways, json
  boundary as base64; TEXT_COPY preserves the kind.
- No implicit Int/Float mixing (WO-E201 in the typechecker, not the emitter,
  which picks the opcode from one side and would misread the other).
- One IEEE deviation: float_cmp total order (NaN last, -0.0 == +0.0) for
  indexes and order-by, keys canonicalized to match. `?Float` nil is a
  reserved quiet NaN — the zero word is +0.0, WO_NIL_SCALAR's bits are -2.0.
- Renderer prefers fixed over exponential in 1e-6..1e21: pure shortest makes
  a price of 900.0 read `9e+02`. One renderer for interp/json/float_to_text.
- Fixed en route: lexer double-counted the leading digit; is_scalar_shaped
  took Float/Bytes as Int-shaped; Bytes ownership needed a shared heap-scalar
  predicate or temps never dropped; order-by bit-compared negatives backwards.
- Iteration 17: `kind = "library"` (absent = program; bad value = WO-E109),
  entry-less check mode retiring the `--emit` workaround, Go's `internal/` as
  WO-E108 at the consumer's `use`. Driver-only; VM/.wob/GC untouched.
- Framework reorg: internal/{parse,serve}.wo; http/form.wo split out to keep
  media_type/form_values public (parse.wo had grown public surface).
- Docs: link audit (97 -> 88 broken, conflict markers resolved, 2 duplicate
  stories removed), 00-code-review verified 26/27, iterations re-sequenced.
- Also carries the pre-staged pub(read)/using/#if work from the index.
- Gates: corpus 103/0, test_wal 156/0, web-app 26/0, oop-accept ALL MET.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 19:24:15 +02:00

56 lines
2.9 KiB
C

/* builtin.h — runtime services bytecode can't express (spec §3/§5):
* now/print/print_int/words plus the container bridge to cont.c. One
* dispatcher: takes the VM, the current frame's registers, and the
* instruction; 0 = ok, else a WO_T_* trap code with *msg set. */
#ifndef WO_BUILTIN_H
#define WO_BUILTIN_H
#include "vm.h"
/* Not a trap code: the stop flag (SIGTERM/SIGINT, armed by `env.stopping`)
* was set when a BLOCKING call was interrupted, so the call does not restart
* the syscall — it hands this back and the VM ends the program with it. A
* service parked in `accept` otherwise never observes the flag and only
* `kill -9` ends it. Negative so it cannot collide with a WO_T_* code, and
* deliberately NOT catchable: `try` must not be able to swallow a stop. */
#define WO_SYS_STOPPED (-2)
/* arc T4: the builtin parked the calling fiber against the shard's I/O
* plane (fb->park_* filled); the interpreter schedules another fiber. */
#define WO_SYS_PARKED (-3)
/* the stop flag, readable by the I/O plane's wait loop (park.c) */
int wo_sys_stop_pending(void);
int wo_builtin(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
/* The systems stdlib's OS half (runtime/src/sysio.c): same contract as
* wo_builtin above — 0 on success, a WO_T_* code with *msg set on failure.
* wo_builtin dispatches every id at or above WO_B_SYS_FIRST here. */
int wo_builtin_sys(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
/* json.encode / json.decode (runtime/src/json.c), same contract again. */
int wo_builtin_json(wo_vm *vm, uint64_t *R, uint32_t ins, const char **msg);
/* iteration 19: render a Float as text, SHORTEST form that reparses to the
* same bits, into `out` (cap must be >= WO_FLOAT_TEXT_CAP); returns the
* length. One renderer for three callers — WO_B_FLOAT_TO_TEXT, string
* interpolation, and json.encode — because three spellings of the same
* number is how a round-trip test starts passing while the product lies.
*
* The rendering always carries a '.' or an exponent, so a Float never prints
* as `1` where an Int would: the two numeric worlds stay visibly distinct,
* and `1.0` reparses to exactly the same bits as `1`. Non-finite values
* render `nan` / `inf` / `-inf`; json.encode does NOT use those (JSON has no
* such literals) and emits `null` instead, which it decides for itself. */
#define WO_FLOAT_TEXT_CAP 32u
size_t wo_float_text(double d, char *out, size_t cap);
/* iteration 19: decode base64 into a fresh Bytes. Two callers — the
* `base64_decode` builtin and json.decode's Bytes boundary — and they must
* agree byte for byte, so there is one implementation.
* 0 = ok (*out is the Bytes word), -1 = malformed input, -2 = OOM.
* Malformed is a return code rather than a trap because both callers treat
* bad base64 as expected input from the network. */
int wo_base64_to_bytes(wo_rt *rt, const char *p, uint32_t len, uint64_t *out);
#endif /* WO_BUILTIN_H */