SX spec introspection: the spec examines itself via sx-parse
spec-introspect.sx: pure SX functions that read, parse, and analyze spec files. No Python. The spec IS data — a macro transforms it into explorer UI components. - spec-explore: reads spec file via IO, parses with sx-parse, extracts sections/defines/effects/params, produces explorer data dict - spec-form-name/kind/effects/params/source: individual extractors - spec-group-sections: groups defines into sections - spec-compute-stats: aggregate effect/define counts OCaml kernel fixes: - nth handles strings (character indexing for parser) - ident-start?, ident-char?, char-numeric?, parse-number: platform primitives needed by spec/parser.sx when loaded at runtime - _find_spec_file: searches spec/, web/, shared/sx/ref/ for spec files 83/84 Playwright tests pass. The 1 failure is client-side re-rendering of the spec explorer (the client evaluates defpage content which calls find-spec — unavailable on the client). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -353,6 +353,38 @@ let make_server_env () =
|
||||
(try env_get env name with _ -> Nil)
|
||||
| _ -> Nil);
|
||||
|
||||
(* Character classification — platform primitives for spec/parser.sx *)
|
||||
bind "ident-start?" (fun args ->
|
||||
match args with
|
||||
| [String s] when String.length s = 1 ->
|
||||
let c = s.[0] in
|
||||
Bool (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c = '_' || c = '~'
|
||||
|| c = '!' || c = '?' || c = '+' || c = '-' || c = '*' || c = '/'
|
||||
|| c = '=' || c = '<' || c = '>' || c = '&' || c = '|' || c = '%'
|
||||
|| c = '^' || c = '$' || c = '#')
|
||||
| _ -> Bool false);
|
||||
bind "ident-char?" (fun args ->
|
||||
match args with
|
||||
| [String s] when String.length s = 1 ->
|
||||
let c = s.[0] in
|
||||
Bool (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c = '_' || c = '~'
|
||||
|| c = '!' || c = '?' || c = '+' || c = '-' || c = '*' || c = '/'
|
||||
|| c = '=' || c = '<' || c = '>' || c = '&' || c = '|' || c = '%'
|
||||
|| c = '^' || c = '$' || c = '#'
|
||||
|| c >= '0' && c <= '9' || c = '.' || c = ':')
|
||||
| _ -> Bool false);
|
||||
bind "char-numeric?" (fun args ->
|
||||
match args with
|
||||
| [String s] when String.length s = 1 ->
|
||||
Bool (s.[0] >= '0' && s.[0] <= '9')
|
||||
| _ -> Bool false);
|
||||
bind "parse-number" (fun args ->
|
||||
match args with
|
||||
| [String s] ->
|
||||
(try Number (float_of_string s)
|
||||
with _ -> Nil)
|
||||
| _ -> Nil);
|
||||
|
||||
bind "escape-string" (fun args ->
|
||||
match args with
|
||||
| [String s] ->
|
||||
|
||||
@@ -328,7 +328,11 @@ let () =
|
||||
match args with
|
||||
| [List l; Number n] | [ListRef { contents = l }; Number n] ->
|
||||
(try List.nth l (int_of_float n) with _ -> Nil)
|
||||
| _ -> raise (Eval_error "nth: list and number"));
|
||||
| [String s; Number n] ->
|
||||
let i = int_of_float n in
|
||||
if i >= 0 && i < String.length s then String (String.make 1 s.[i])
|
||||
else Nil
|
||||
| _ -> raise (Eval_error "nth: list/string and number"));
|
||||
register "cons" (fun args ->
|
||||
match args with
|
||||
| [x; List l] | [x; ListRef { contents = l }] -> List (x :: l)
|
||||
|
||||
Reference in New Issue
Block a user