Merge semantics: eval rules, capabilities, modules, geography pages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 16:14:14 +00:00
9 changed files with 523 additions and 3 deletions

View File

@@ -198,6 +198,40 @@ let setup_env () =
| _ -> Nil
) nodes path
| _ -> Nil);
(* use — module declaration, no-op at eval time, metadata for static analysis *)
bind "use" (fun _args -> Nil);
(* Capability-based evaluation contexts *)
let cap_stack : string list ref = ref [] in
bind "with-capabilities" (fun args -> match args with
| [List caps; body] ->
let cap_set = List.filter_map (fun v -> match v with
| Symbol s | String s -> Some s | _ -> None) caps in
let prev = !cap_stack in
cap_stack := cap_set;
(* body can be a lambda (call it) or an expression (eval it) *)
let result = try
match body with
| Lambda _ -> Sx_ref.cek_call body Nil
| _ -> body
with exn -> cap_stack := prev; raise exn in
cap_stack := prev;
result
| _ -> Nil);
bind "current-capabilities" (fun _args ->
if !cap_stack = [] then Nil
else List (List.map (fun s -> String s) !cap_stack));
bind "has-capability?" (fun args -> match args with
| [String cap] ->
if !cap_stack = [] then Bool true (* no restriction *)
else Bool (List.mem cap !cap_stack)
| _ -> Bool true);
bind "require-capability!" (fun args -> match args with
| [String cap] ->
if !cap_stack = [] then Nil (* no restriction *)
else if List.mem cap !cap_stack then Nil
else raise (Eval_error (Printf.sprintf
"Capability '%s' not available. Current: %s" cap (String.concat ", " !cap_stack)))
| _ -> Nil);
bind "trim" (fun args -> match args with
| [String s] -> String (String.trim s) | _ -> String "");
bind "split" (fun args -> match args with
@@ -222,7 +256,10 @@ let setup_env () =
(* Load harness *)
(try load_sx_file e (Filename.concat spec_dir "harness.sx")
with exn -> Printf.eprintf "[mcp] Warning: harness.sx load failed: %s\n%!" (Printexc.to_string exn));
Printf.eprintf "[mcp] SX tree-tools + harness loaded\n%!";
(* Load eval-rules *)
(try load_sx_file e (Filename.concat spec_dir "eval-rules.sx")
with exn -> Printf.eprintf "[mcp] Warning: eval-rules.sx load failed: %s\n%!" (Printexc.to_string exn));
Printf.eprintf "[mcp] SX tree-tools + harness + eval-rules loaded\n%!";
env := e
(* ------------------------------------------------------------------ *)
@@ -1290,6 +1327,13 @@ let rec handle_tool name args =
) items
with _ -> ()
) all_sx_files;
(* Find use declarations *)
let use_decls = call_sx "find-use-declarations" [tree] in
let declared_modules = match use_decls with
| List items | ListRef { contents = items } ->
List.filter_map (fun v -> match v with String s -> Some s | _ -> None) items
| _ -> []
in
(* Format output *)
let lines = List.map (fun sym ->
if Hashtbl.mem file_defines sym then
@@ -1304,8 +1348,11 @@ let rec handle_tool name args =
| Some n -> Printf.sprintf "Dependencies of %s in %s" n file
| None -> Printf.sprintf "Dependencies of %s" file
in
text_result (Printf.sprintf "%s\n%d symbols referenced:\n%s"
header (List.length sym_names) (String.concat "\n" lines))
let use_str = if declared_modules = [] then "" else
Printf.sprintf "\n\nDeclared modules (use):\n %s" (String.concat ", " declared_modules)
in
text_result (Printf.sprintf "%s\n%d symbols referenced:\n%s%s"
header (List.length sym_names) (String.concat "\n" lines) use_str)
| "sx_build_manifest" ->
let target = (try args |> member "target" |> to_string with _ -> "js") in
@@ -1367,6 +1414,53 @@ let rec handle_tool name args =
ignore (Unix.close_process_in ic);
text_result (Buffer.contents buf))
| "sx_explain" ->
let form_name = args |> member "name" |> to_string in
let e = !env in
let result = try
let find_fn = env_get e "find-rule" in
Sx_ref.cek_call find_fn (List [String form_name])
with _ -> Nil in
(match result with
| Dict d ->
let get_str k = match Hashtbl.find_opt d k with
| Some (String s) -> s | Some v -> value_to_string v | None -> "" in
let effects = match Hashtbl.find_opt d "effects" with
| Some (List items) -> String.concat ", " (List.map value_to_string items)
| Some Nil -> "none" | _ -> "none" in
let examples = match Hashtbl.find_opt d "examples" with
| Some (String s) -> " " ^ s
| Some (List items) ->
String.concat "\n" (List.map (fun ex -> " " ^ value_to_string ex) items)
| _ -> " (none)" in
text_result (Printf.sprintf "%s\n Category: %s\n Pattern: %s\n Effects: %s\n\n%s\n\nExamples:\n%s"
(get_str "name") (get_str "category") (get_str "pattern") effects
(get_str "rule") examples)
| _ ->
(* Try listing by category *)
let cats_fn = try env_get e "rules-by-category" with _ -> Nil in
let cat_results = try Sx_ref.cek_call cats_fn (List [String form_name]) with _ -> Nil in
(match cat_results with
| List items when items <> [] ->
let lines = List.map (fun rule ->
match rule with
| Dict rd ->
let name = match Hashtbl.find_opt rd "name" with Some (String s) -> s | _ -> "?" in
let pattern = match Hashtbl.find_opt rd "pattern" with Some (String s) -> s | _ -> "" in
Printf.sprintf " %-16s %s" name pattern
| _ -> " " ^ value_to_string rule
) items in
text_result (Printf.sprintf "Category: %s (%d rules)\n\n%s"
form_name (List.length items) (String.concat "\n" lines))
| _ ->
(* List all categories *)
let all_cats = try Sx_ref.cek_call (env_get e "rule-categories") Nil with _ -> Nil in
let cat_str = match all_cats with
| List items -> String.concat ", " (List.filter_map (fun v ->
match v with String s -> Some s | _ -> None) items)
| _ -> "?" in
error_result (Printf.sprintf "No rule found for '%s'. Categories: %s" form_name cat_str)))
| _ -> error_result ("Unknown tool: " ^ name)
and write_edit file result =
@@ -1439,6 +1533,8 @@ let tool_definitions = `List [
[("expr", `Assoc [("type", `String "string"); ("description", `String "SX expression to trace")]);
("file", `Assoc [("type", `String "string"); ("description", `String "Optional .sx file to load for definitions")]);
("max_steps", `Assoc [("type", `String "integer"); ("description", `String "Max CEK steps to show (default: 200)")])] ["expr"];
tool "sx_explain" "Explain SX evaluation rules. Pass a form name (if, let, map, ...) or category (literal, special-form, higher-order, ...)."
[("name", `Assoc [("type", `String "string"); ("description", `String "Form name or category to explain")])] ["name"];
tool "sx_deps" "Dependency analysis for a component or file. Shows all referenced symbols and where they're defined."
[file_prop;
("name", `Assoc [("type", `String "string"); ("description", `String "Specific define/defcomp/defisland to analyze")]);