Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/interpreter/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ impl Environment {
Ok(())
}

pub fn define_native(
&mut self,
name: &'static str,
func: crate::interpreter::value::NativeFunction,
) {
let _ = self.define(
name,
crate::interpreter::value::Value::NativeFunction(name, func),
);
Comment on lines +97 to +100

Copilot AI Mar 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

define_native currently discards the Result from define, so if a native name is already defined (in current or parent scope) registration will silently fail and the function may be missing at runtime. The PR description indicates this should unwrap()/fail fast; consider either (a) returning Result<(), String> from define_native and handling it at call sites, or (b) calling .expect(...) here so duplicate registrations are surfaced immediately.

Suggested change
let _ = self.define(
name,
crate::interpreter::value::Value::NativeFunction(name, func),
);
self.define(
name,
crate::interpreter::value::Value::NativeFunction(name, func),
)
.expect("Native function registration failed: duplicate definition");

Copilot uses AI. Check for mistakes.
}

/// Defines a variable in the current scope without checking parent scopes for shadowing.
/// This is an optimization for when existence in parent scopes has already been checked.
pub fn define_direct(&mut self, name: &str, value: Value) -> Result<(), String> {
Expand Down
20 changes: 7 additions & 13 deletions src/stdlib/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,11 @@ pub fn native_isnothing(args: Vec<Value>) -> Result<Value, RuntimeError> {
}

pub fn register_core(env: &mut Environment) {
let _ = env.define("print", Value::NativeFunction("print", native_print));

let _ = env.define("typeof", Value::NativeFunction("typeof", native_typeof));
let _ = env.define(
"isnothing",
Value::NativeFunction("isnothing", native_isnothing),
);

let _ = env.define("type_of", Value::NativeFunction("type_of", native_typeof));
let _ = env.define(
"is_nothing",
Value::NativeFunction("is_nothing", native_isnothing),
);
env.define_native("print", native_print);

env.define_native("typeof", native_typeof);
env.define_native("isnothing", native_isnothing);

env.define_native("type_of", native_typeof);
env.define_native("is_nothing", native_isnothing);
}
25 changes: 5 additions & 20 deletions src/stdlib/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,26 +512,11 @@ pub fn native_generate_csrf_token(args: Vec<Value>) -> Result<Value, RuntimeErro

/// Register all crypto functions in the environment
pub fn register_crypto(env: &mut Environment) {
let _ = env.define(
"wflhash256",
Value::NativeFunction("wflhash256", native_wflhash256),
);
let _ = env.define(
"wflhash512",
Value::NativeFunction("wflhash512", native_wflhash512),
);
let _ = env.define(
"wflhash256_with_salt",
Value::NativeFunction("wflhash256_with_salt", native_wflhash256_with_salt),
);
let _ = env.define(
"wflmac256",
Value::NativeFunction("wflmac256", native_wflmac256),
);
let _ = env.define(
"generate_csrf_token",
Value::NativeFunction("generate_csrf_token", native_generate_csrf_token),
);
env.define_native("wflhash256", native_wflhash256);
env.define_native("wflhash512", native_wflhash512);
env.define_native("wflhash256_with_salt", native_wflhash256_with_salt);
env.define_native("wflmac256", native_wflmac256);
env.define_native("generate_csrf_token", native_generate_csrf_token);
}

#[cfg(test)]
Expand Down
83 changes: 19 additions & 64 deletions src/stdlib/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,70 +459,25 @@ pub fn native_remove_dir(args: Vec<Value>) -> Result<Value, RuntimeError> {
}

pub fn register_filesystem(env: &mut crate::interpreter::environment::Environment) {
let _ = env.define(
"list_dir",
Value::NativeFunction("list_dir", native_list_dir),
);
let _ = env.define("glob", Value::NativeFunction("glob", native_glob));
let _ = env.define("rglob", Value::NativeFunction("rglob", native_rglob));
let _ = env.define(
"path_join",
Value::NativeFunction("path_join", native_path_join),
);
let _ = env.define(
"path_basename",
Value::NativeFunction("path_basename", native_path_basename),
);
let _ = env.define(
"path_dirname",
Value::NativeFunction("path_dirname", native_path_dirname),
);
let _ = env.define(
"makedirs",
Value::NativeFunction("makedirs", native_makedirs),
);
let _ = env.define(
"file_mtime",
Value::NativeFunction("file_mtime", native_file_mtime),
);
let _ = env.define(
"path_exists",
Value::NativeFunction("path_exists", native_path_exists),
);
let _ = env.define("is_file", Value::NativeFunction("is_file", native_is_file));
let _ = env.define("is_dir", Value::NativeFunction("is_dir", native_is_dir));
let _ = env.define(
"count_lines",
Value::NativeFunction("count_lines", native_count_lines),
);
let _ = env.define(
"path_extension",
Value::NativeFunction("path_extension", native_path_extension),
);
let _ = env.define(
"path_stem",
Value::NativeFunction("path_stem", native_path_stem),
);
let _ = env.define(
"file_size",
Value::NativeFunction("file_size", native_file_size),
);
let _ = env.define(
"copy_file",
Value::NativeFunction("copy_file", native_copy_file),
);
let _ = env.define(
"move_file",
Value::NativeFunction("move_file", native_move_file),
);
let _ = env.define(
"remove_file",
Value::NativeFunction("remove_file", native_remove_file),
);
let _ = env.define(
"remove_dir",
Value::NativeFunction("remove_dir", native_remove_dir),
);
env.define_native("list_dir", native_list_dir);
env.define_native("glob", native_glob);
env.define_native("rglob", native_rglob);
env.define_native("path_join", native_path_join);
env.define_native("path_basename", native_path_basename);
env.define_native("path_dirname", native_path_dirname);
env.define_native("makedirs", native_makedirs);
env.define_native("file_mtime", native_file_mtime);
env.define_native("path_exists", native_path_exists);
env.define_native("is_file", native_is_file);
env.define_native("is_dir", native_is_dir);
env.define_native("count_lines", native_count_lines);
env.define_native("path_extension", native_path_extension);
env.define_native("path_stem", native_path_stem);
env.define_native("file_size", native_file_size);
env.define_native("copy_file", native_copy_file);
env.define_native("move_file", native_move_file);
env.define_native("remove_file", native_remove_file);
env.define_native("remove_dir", native_remove_dir);
}

#[cfg(test)]
Expand Down
15 changes: 3 additions & 12 deletions src/stdlib/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,9 @@ pub fn native_stringify_json_pretty(args: Vec<Value>) -> Result<Value, RuntimeEr

/// Register all JSON functions in the environment
pub fn register_json(env: &mut Environment) {
let _ = env.define(
"parse_json",
Value::NativeFunction("parse_json", native_parse_json),
);
let _ = env.define(
"stringify_json",
Value::NativeFunction("stringify_json", native_stringify_json),
);
let _ = env.define(
"stringify_json_pretty",
Value::NativeFunction("stringify_json_pretty", native_stringify_json_pretty),
);
env.define_native("parse_json", native_parse_json);
env.define_native("stringify_json", native_stringify_json);
env.define_native("stringify_json_pretty", native_stringify_json_pretty);
}

#[cfg(test)]
Expand Down
81 changes: 27 additions & 54 deletions src/stdlib/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,68 +388,41 @@ pub fn native_some(args: Vec<Value>) -> Result<Value, RuntimeError> {
}

pub fn register_list(env: &mut Environment) {
let _ = env.define("length", Value::NativeFunction("length", native_length));
let _ = env.define("push", Value::NativeFunction("push", native_push));
let _ = env.define("pop", Value::NativeFunction("pop", native_pop));
let _ = env.define(
"contains",
Value::NativeFunction("contains", native_contains),
);
let _ = env.define("indexof", Value::NativeFunction("indexof", native_indexof));
let _ = env.define(
"index_of",
Value::NativeFunction("index_of", native_indexof),
);
env.define_native("length", native_length);
env.define_native("push", native_push);
env.define_native("pop", native_pop);
env.define_native("contains", native_contains);
env.define_native("indexof", native_indexof);
env.define_native("index_of", native_indexof);

// Batch 3: Basic List Manipulation
let _ = env.define("shift", Value::NativeFunction("shift", native_shift));
let _ = env.define("unshift", Value::NativeFunction("unshift", native_unshift));
let _ = env.define(
"remove_at",
Value::NativeFunction("remove_at", native_remove_at),
);
let _ = env.define(
"removeat",
Value::NativeFunction("removeat", native_remove_at),
);
let _ = env.define(
"insert_at",
Value::NativeFunction("insert_at", native_insert_at),
);
let _ = env.define(
"insertat",
Value::NativeFunction("insertat", native_insert_at),
);
let _ = env.define("clear", Value::NativeFunction("clear", native_clear));
let _ = env.define("slice", Value::NativeFunction("slice", native_slice));
let _ = env.define("concat", Value::NativeFunction("concat", native_concat));
let _ = env.define(
"includes",
Value::NativeFunction("includes", native_contains),
);
env.define_native("shift", native_shift);
env.define_native("unshift", native_unshift);
env.define_native("remove_at", native_remove_at);
env.define_native("removeat", native_remove_at);
env.define_native("insert_at", native_insert_at);
env.define_native("insertat", native_insert_at);
env.define_native("clear", native_clear);
env.define_native("slice", native_slice);
env.define_native("concat", native_concat);
env.define_native("includes", native_contains);

// Batch 4: List Utilities
let _ = env.define("join", Value::NativeFunction("join", native_join));
let _ = env.define("unique", Value::NativeFunction("unique", native_unique));
let _ = env.define("count", Value::NativeFunction("count", native_count));
let _ = env.define("size", Value::NativeFunction("size", native_length));
let _ = env.define("fill", Value::NativeFunction("fill", native_fill));
env.define_native("join", native_join);
env.define_native("unique", native_unique);
env.define_native("count", native_count);
env.define_native("size", native_length);
env.define_native("fill", native_fill);

// Batch 5: Sort & Reverse
let _ = env.define("sort", Value::NativeFunction("sort", native_sort));
let _ = env.define(
"reverse_list",
Value::NativeFunction("reverse_list", native_reverse_list),
);
env.define_native("sort", native_sort);
env.define_native("reverse_list", native_reverse_list);

// Batch 6: List Search
let _ = env.define("find", Value::NativeFunction("find", native_find));
let _ = env.define(
"find_index",
Value::NativeFunction("find_index", native_indexof),
);
let _ = env.define("every", Value::NativeFunction("every", native_every));
let _ = env.define("some", Value::NativeFunction("some", native_some));
env.define_native("find", native_find);
env.define_native("find_index", native_indexof);
env.define_native("every", native_every);
env.define_native("some", native_some);
}

#[cfg(test)]
Expand Down
24 changes: 12 additions & 12 deletions src/stdlib/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,18 @@ pub fn native_tan(args: Vec<Value>) -> Result<Value, RuntimeError> {
}

pub fn register_math(env: &mut Environment) {
let _ = env.define("abs", Value::NativeFunction("abs", native_abs));
let _ = env.define("round", Value::NativeFunction("round", native_round));
let _ = env.define("floor", Value::NativeFunction("floor", native_floor));
let _ = env.define("ceil", Value::NativeFunction("ceil", native_ceil));
let _ = env.define("clamp", Value::NativeFunction("clamp", native_clamp));
let _ = env.define("min", Value::NativeFunction("min", native_min));
let _ = env.define("max", Value::NativeFunction("max", native_max));
let _ = env.define("power", Value::NativeFunction("power", native_power));
let _ = env.define("sqrt", Value::NativeFunction("sqrt", native_sqrt));
let _ = env.define("sin", Value::NativeFunction("sin", native_sin));
let _ = env.define("cos", Value::NativeFunction("cos", native_cos));
let _ = env.define("tan", Value::NativeFunction("tan", native_tan));
env.define_native("abs", native_abs);
env.define_native("round", native_round);
env.define_native("floor", native_floor);
env.define_native("ceil", native_ceil);
env.define_native("clamp", native_clamp);
env.define_native("min", native_min);
env.define_native("max", native_max);
env.define_native("power", native_power);
env.define_native("sqrt", native_sqrt);
env.define_native("sin", native_sin);
env.define_native("cos", native_cos);
env.define_native("tan", native_tan);
}

#[cfg(test)]
Expand Down
15 changes: 3 additions & 12 deletions src/stdlib/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,9 @@ use std::sync::Arc;

pub fn register(env: &mut Environment) {
// Register new pattern functions that work with our pattern system
let _ = env.define(
"pattern_matches",
Value::NativeFunction("pattern_matches", pattern_matches_native),
);
let _ = env.define(
"pattern_find",
Value::NativeFunction("pattern_find", pattern_find_native),
);
let _ = env.define(
"pattern_find_all",
Value::NativeFunction("pattern_find_all", pattern_find_all_native),
);
env.define_native("pattern_matches", pattern_matches_native);
env.define_native("pattern_find", pattern_find_native);
env.define_native("pattern_find_all", pattern_find_all_native);
// Register pattern_split - this was missing!
// Note: pattern_split is called directly from the interpreter for PatternSplit expressions,
// but we don't register it as a standalone function since it uses special syntax
Expand Down
32 changes: 7 additions & 25 deletions src/stdlib/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,31 +148,13 @@ pub fn native_generate_uuid(args: Vec<Value>) -> Result<Value, RuntimeError> {

/// Register all random functions in the environment
pub fn register_random(env: &mut Environment) {
let _ = env.define("random", Value::NativeFunction("random", native_random));
let _ = env.define(
"random_between",
Value::NativeFunction("random_between", native_random_between),
);
let _ = env.define(
"random_int",
Value::NativeFunction("random_int", native_random_int),
);
let _ = env.define(
"random_boolean",
Value::NativeFunction("random_boolean", native_random_boolean),
);
let _ = env.define(
"random_from",
Value::NativeFunction("random_from", native_random_from),
);
let _ = env.define(
"random_seed",
Value::NativeFunction("random_seed", native_random_seed),
);
let _ = env.define(
"generate_uuid",
Value::NativeFunction("generate_uuid", native_generate_uuid),
);
env.define_native("random", native_random);
env.define_native("random_between", native_random_between);
env.define_native("random_int", native_random_int);
env.define_native("random_boolean", native_random_boolean);
env.define_native("random_from", native_random_from);
env.define_native("random_seed", native_random_seed);
env.define_native("generate_uuid", native_generate_uuid);
}

#[cfg(test)]
Expand Down
Loading
Loading