R7RS core: call/cc, raise/guard, multi-arity map, cond =>, do iteration
Phase 1 engine step 4 — R7RS compatibility primitives for the CEK evaluator. call/cc: undelimited continuation capture with separate CallccContinuation type (distinct from delimited shift/reset continuations). Escape semantics — invoking k replaces the current continuation entirely. raise/raise-continuable: proper CEK arg evaluation via raise-eval frame. Non-continuable raise uses raise-guard frame that errors on handler return. host-error primitive for safe unhandled exception fallback. Multi-arity map: (map fn list1 list2 ...) zips multiple lists. Single-list path unchanged for performance. New multi-map frame type. cond =>: arrow clause syntax (cond (test => fn)) calls fn with test value. New cond-arrow frame type. R7RS do: shape-detecting dispatch — (do ((var init step) ...) (test result) body) desugars to named let. Existing (do expr1 expr2) sequential form preserved. integer? primitive, host-error alias. Transpiler fixes: match/case routing, wildcard _ support, nested match arm handling. 2522/2524 OCaml tests pass (2 pre-existing scope failures from transpiler match codegen, not related to these changes). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -100,7 +100,7 @@ let rec value_to_js (v : value) : Js.Unsafe.any =
|
||||
Js.Unsafe.set obj (Js.string k) (value_to_js v)) d;
|
||||
Js.Unsafe.inject obj)
|
||||
(* Callable values: wrap as JS functions with __sx_handle *)
|
||||
| Lambda _ | NativeFn _ | Continuation _ | VmClosure _ ->
|
||||
| Lambda _ | NativeFn _ | Continuation _ | CallccContinuation _ | VmClosure _ ->
|
||||
let handle = alloc_handle v in
|
||||
let inner = Js.wrap_callback (fun args_js ->
|
||||
try
|
||||
|
||||
@@ -218,6 +218,8 @@ let () =
|
||||
match args with [a] -> Bool (is_nil a) | _ -> raise (Eval_error "nil?: 1 arg"));
|
||||
register "number?" (fun args ->
|
||||
match args with [Number _] -> Bool true | [_] -> Bool false | _ -> raise (Eval_error "number?: 1 arg"));
|
||||
register "integer?" (fun args ->
|
||||
match args with [Number f] -> Bool (Float.is_integer f) | [_] -> Bool false | _ -> raise (Eval_error "integer?: 1 arg"));
|
||||
register "string?" (fun args ->
|
||||
match args with [String _] -> Bool true | [_] -> Bool false | _ -> raise (Eval_error "string?: 1 arg"));
|
||||
register "boolean?" (fun args ->
|
||||
@@ -708,6 +710,10 @@ let () =
|
||||
match args with [String msg] -> raise (Eval_error msg)
|
||||
| [a] -> raise (Eval_error (to_string a))
|
||||
| _ -> raise (Eval_error "error: 1 arg"));
|
||||
register "host-error" (fun args ->
|
||||
match args with [String msg] -> raise (Eval_error msg)
|
||||
| [a] -> raise (Eval_error (to_string a))
|
||||
| _ -> raise (Eval_error "host-error: 1 arg"));
|
||||
register "try-catch" (fun args ->
|
||||
match args with
|
||||
| [try_fn; catch_fn] ->
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -50,6 +50,8 @@ let sx_call f args =
|
||||
Thunk (l.l_body, local)
|
||||
| Continuation (k, _) ->
|
||||
k (match args with x :: _ -> x | [] -> Nil)
|
||||
| CallccContinuation _ ->
|
||||
raise (Eval_error "callcc continuations must be invoked through the CEK machine")
|
||||
| _ ->
|
||||
let nargs = List.length args in
|
||||
let args_preview = if nargs = 0 then "" else
|
||||
@@ -103,6 +105,7 @@ let get_val container key =
|
||||
| "update-fn" -> f.cf_extra | "head-name" -> f.cf_extra
|
||||
| "emitted" -> f.cf_extra2 | "effect-list" -> f.cf_extra2
|
||||
| "first-render" -> f.cf_extra2 | "file" -> f.cf_env
|
||||
| "extra" -> f.cf_extra | "extra2" -> f.cf_extra2
|
||||
| _ -> Nil)
|
||||
| Dict d, String k -> dict_get d k
|
||||
| Dict d, Keyword k -> dict_get d k
|
||||
@@ -323,7 +326,20 @@ let continuation_data v = match v with
|
||||
| Continuation (_, None) -> Dict (Hashtbl.create 0)
|
||||
| _ -> raise (Eval_error "not a continuation")
|
||||
|
||||
(* Callcc (undelimited) continuation support *)
|
||||
let callcc_continuation_p v = match v with CallccContinuation _ -> Bool true | _ -> Bool false
|
||||
|
||||
let make_callcc_continuation captured =
|
||||
CallccContinuation (sx_to_list captured)
|
||||
|
||||
let callcc_continuation_data v = match v with
|
||||
| CallccContinuation frames -> List frames
|
||||
| _ -> raise (Eval_error "not a callcc continuation")
|
||||
|
||||
(* Dynamic wind — simplified for OCaml (no async) *)
|
||||
let host_error msg =
|
||||
raise (Eval_error (value_to_str msg))
|
||||
|
||||
let dynamic_wind_call before body after _env =
|
||||
ignore (sx_call before []);
|
||||
let result = sx_call body [] in
|
||||
|
||||
@@ -56,6 +56,7 @@ and value =
|
||||
| Macro of macro
|
||||
| Thunk of value * env
|
||||
| Continuation of (value -> value) * dict option
|
||||
| CallccContinuation of value list (** Undelimited continuation — captured kont frames *)
|
||||
| NativeFn of string * (value list -> value)
|
||||
| Signal of signal
|
||||
| RawHTML of string
|
||||
@@ -336,6 +337,7 @@ let type_of = function
|
||||
| Macro _ -> "macro"
|
||||
| Thunk _ -> "thunk"
|
||||
| Continuation (_, _) -> "continuation"
|
||||
| CallccContinuation _ -> "continuation"
|
||||
| NativeFn _ -> "function"
|
||||
| Signal _ -> "signal"
|
||||
| RawHTML _ -> "raw-html"
|
||||
@@ -358,7 +360,7 @@ let is_signal = function
|
||||
| _ -> false
|
||||
|
||||
let is_callable = function
|
||||
| Lambda _ | NativeFn _ | Continuation (_, _) | VmClosure _ -> true
|
||||
| Lambda _ | NativeFn _ | Continuation (_, _) | CallccContinuation _ | VmClosure _ -> true
|
||||
| _ -> false
|
||||
|
||||
|
||||
@@ -529,6 +531,7 @@ let rec inspect = function
|
||||
Printf.sprintf "<%s(%s)>" tag (String.concat ", " m.m_params)
|
||||
| Thunk _ -> "<thunk>"
|
||||
| Continuation (_, _) -> "<continuation>"
|
||||
| CallccContinuation _ -> "<callcc-continuation>"
|
||||
| NativeFn (name, _) -> Printf.sprintf "<native:%s>" name
|
||||
| Signal _ -> "<signal>"
|
||||
| RawHTML s -> Printf.sprintf "\"<raw-html:%d>\"" (String.length s)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user