Skip to content

Commit d26d6e7

Browse files
feat: list_fns + fn_source full source + fn_arity introspection improvements
- list_fns() added as ergonomic alias for list_defined_fns() - fn_source(name) now emits full formatted source via formatter::format_program instead of just "fn name(params) { ... }"; enables self-inspection loops where OMC programs can read their own function implementations - fn_arity(name) already worked; no change - get_scope_vars() already worked; no change 1132/1132 tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d513f65 commit d26d6e7

1 file changed

Lines changed: 16 additions & 8 deletions

File tree

omnimcode-core/src/interpreter.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,7 +2416,7 @@ impl Interpreter {
24162416
| "to_string" | "to_str" | "string" | "len" | "type_of" | "error"
24172417
| "defined_functions" | "call"
24182418
// Introspection builtins
2419-
| "list_defined_fns" | "fn_arity" | "fn_source" | "get_scope_vars"
2419+
| "list_defined_fns" | "list_fns" | "fn_arity" | "fn_source" | "get_scope_vars"
24202420
// Python-idiom builtins (forgiving aliases for users new to OMC)
24212421
| "range" | "getenv" | "to_hex" | "from_hex"
24222422
| "parse_int" | "parse_float"
@@ -5126,8 +5126,8 @@ impl Interpreter {
51265126
names.into_iter().map(Value::String).collect(),
51275127
)))
51285128
}
5129-
// list_defined_fns() — alias for defined_functions; returns sorted array of user fn names
5130-
"list_defined_fns" => {
5129+
// list_defined_fns() / list_fns() — returns sorted array of user fn names
5130+
"list_defined_fns" | "list_fns" => {
51315131
let mut names: Vec<String> = self.functions.keys()
51325132
.filter(|n| !n.starts_with("__lambda_") && !n.starts_with("__rt_lambda_"))
51335133
.cloned()
@@ -5153,7 +5153,7 @@ impl Interpreter {
51535153
Ok(Value::Null)
51545154
}
51555155
}
5156-
// fn_source(name) → string — reconstructed signature of a user-defined function
5156+
// fn_source(name) → string — full formatted source of a user-defined function
51575157
"fn_source" => {
51585158
if args.is_empty() {
51595159
return Err("fn_source requires (fn_name)".to_string());
@@ -5163,9 +5163,17 @@ impl Interpreter {
51635163
Value::String(s) => s.clone(),
51645164
_ => return Err("fn_source: argument must be a string".to_string()),
51655165
};
5166-
if let Some((params, _body)) = self.functions.get(&fn_name) {
5167-
let param_str = params.join(", ");
5168-
Ok(Value::String(format!("fn {}({}) {{ ... }}", fn_name, param_str)))
5166+
if let Some((params, body)) = self.functions.get(&fn_name) {
5167+
let stmt = Statement::FunctionDef {
5168+
name: fn_name.clone(),
5169+
params: params.clone(),
5170+
param_types: params.iter().map(|_| None).collect(),
5171+
body: body.clone(),
5172+
return_type: None,
5173+
pragmas: vec![],
5174+
};
5175+
let src = crate::formatter::format_program(&[stmt]);
5176+
Ok(Value::String(src.trim_end_matches('\n').to_string()))
51695177
} else {
51705178
Ok(Value::Null)
51715179
}
@@ -14843,7 +14851,7 @@ pub(crate) const HEAL_BUILTIN_NAMES: &[&str] = &[
1484314851
"to_int", "int", "to_float", "float",
1484414852
"to_string", "string", "len", "type_of", "error",
1484514853
"defined_functions", "call",
14846-
"list_defined_fns", "fn_arity", "fn_source", "get_scope_vars",
14854+
"list_defined_fns", "list_fns", "fn_arity", "fn_source", "get_scope_vars",
1484714855
"test_record_failure", "test_failure_count",
1484814856
"test_get_failures", "test_clear_failures",
1484914857
"test_set_current", "test_get_current",

0 commit comments

Comments
 (0)