Skip to content

Commit 705ae04

Browse files
committed
Remove FunctionDef in favour of PureFunction
1 parent 49fd29f commit 705ae04

File tree

1 file changed

+7
-103
lines changed

1 file changed

+7
-103
lines changed

src/compiler.rs

Lines changed: 7 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ use crate::bytecode::{Chunk, ConstIdx, Op, Reg};
22
use crate::value::Value;
33
use std::collections::HashMap;
44

5-
/// A function definition (for compile-time evaluation and inlining)
5+
/// A pure function definition (for compile-time evaluation)
66
#[derive(Clone)]
7-
struct FunctionDef {
7+
struct PureFunction {
88
params: Vec<String>,
99
body: Value,
1010
}
1111

1212
/// Registry of pure functions for compile-time evaluation
1313
#[derive(Clone, Default)]
1414
struct PureFunctions {
15-
funcs: HashMap<String, FunctionDef>,
15+
funcs: HashMap<String, PureFunction>,
1616
}
1717

1818
impl PureFunctions {
@@ -23,32 +23,10 @@ impl PureFunctions {
2323
}
2424

2525
fn register(&mut self, name: &str, params: Vec<String>, body: Value) {
26-
self.funcs.insert(name.to_string(), FunctionDef { params, body });
26+
self.funcs.insert(name.to_string(), PureFunction { params, body });
2727
}
2828

29-
fn get(&self, name: &str) -> Option<&FunctionDef> {
30-
self.funcs.get(name)
31-
}
32-
}
33-
34-
/// Registry of ALL function definitions for inlining (regardless of purity)
35-
#[derive(Clone, Default)]
36-
struct InlineCandidates {
37-
funcs: HashMap<String, FunctionDef>,
38-
}
39-
40-
impl InlineCandidates {
41-
fn new() -> Self {
42-
InlineCandidates {
43-
funcs: HashMap::new(),
44-
}
45-
}
46-
47-
fn register(&mut self, name: &str, params: Vec<String>, body: Value) {
48-
self.funcs.insert(name.to_string(), FunctionDef { params, body });
49-
}
50-
51-
fn get(&self, name: &str) -> Option<&FunctionDef> {
29+
fn get(&self, name: &str) -> Option<&PureFunction> {
5230
self.funcs.get(name)
5331
}
5432
}
@@ -58,7 +36,6 @@ pub struct Compiler {
5836
locals: Vec<String>,
5937
scope_depth: usize,
6038
pure_fns: PureFunctions,
61-
inline_candidates: InlineCandidates,
6239
}
6340

6441
/// Check if an expression is pure (no side effects)
@@ -182,56 +159,6 @@ fn substitute(expr: &Value, params: &[String], args: &[Value]) -> Value {
182159
expr.clone()
183160
}
184161

185-
/// Check if expression contains a call to the given function name (recursion check)
186-
fn contains_call_to(expr: &Value, name: &str) -> bool {
187-
if let Some(items) = expr.as_list() {
188-
if !items.is_empty() {
189-
// Check if this is a call to the function
190-
if let Some(first) = items[0].as_symbol() {
191-
if first == name {
192-
return true;
193-
}
194-
}
195-
// Recursively check all sub-expressions
196-
for item in items.iter() {
197-
if contains_call_to(item, name) {
198-
return true;
199-
}
200-
}
201-
}
202-
}
203-
false
204-
}
205-
206-
/// Check if a function body is small enough to inline.
207-
/// We inline if the body is a single expression that is:
208-
/// - A simple call to another function (thin wrapper)
209-
/// - A simple arithmetic/comparison expression
210-
/// - A small if expression
211-
fn is_small_body(body: &Value) -> bool {
212-
if let Some(items) = body.as_list() {
213-
// Body is a list (an expression)
214-
if items.is_empty() {
215-
return true;
216-
}
217-
if let Some(first) = items[0].as_symbol() {
218-
match first {
219-
// Simple operations are always small
220-
"+" | "-" | "*" | "/" | "mod" | "<" | "<=" | ">" | ">=" | "=" | "!=" | "not" => {
221-
return items.len() <= 4; // op + up to 3 args
222-
}
223-
// A call to another function (thin wrapper pattern)
224-
_ => {
225-
// Consider it small if it's just a function call with up to 4 args
226-
return items.len() <= 5;
227-
}
228-
}
229-
}
230-
}
231-
// Non-list values (symbols, literals) are trivially small
232-
true
233-
}
234-
235162
/// Try to fold an operation with constant arguments
236163
fn fold_op(op: &str, args: &[&Value]) -> Option<Value> {
237164
match op {
@@ -436,7 +363,6 @@ impl Compiler {
436363
locals: Vec::new(),
437364
scope_depth: 0,
438365
pure_fns: PureFunctions::new(),
439-
inline_candidates: InlineCandidates::new(),
440366
}
441367
}
442368

@@ -742,7 +668,7 @@ impl Compiler {
742668
.as_symbol()
743669
.ok_or("def expects a symbol as first argument")?;
744670

745-
// Check if we're defining a function: (def name (fn (params) body))
671+
// Check if we're defining a pure function: (def name (fn (params) body))
746672
if let Some(fn_expr) = args[1].as_list() {
747673
if fn_expr.len() >= 3 {
748674
if let Some(fn_sym) = fn_expr[0].as_symbol() {
@@ -764,11 +690,7 @@ impl Compiler {
764690
Value::list(do_list)
765691
};
766692

767-
// Register ALL functions as inline candidates
768-
// (inlining decision made at call site based on size/recursion)
769-
self.inline_candidates.register(name, params.clone(), body.clone());
770-
771-
// Also register pure functions for constant folding
693+
// Check if body is pure (with knowledge of already-registered pure fns)
772694
if is_pure_expr_with_fns(&body, &self.pure_fns) {
773695
self.pure_fns.register(name, params, body);
774696
}
@@ -1046,24 +968,6 @@ impl Compiler {
1046968
self.free_reg(); // free cdr_reg
1047969
return Ok(());
1048970
}
1049-
1050-
// Try inlining small non-recursive functions
1051-
// This eliminates call overhead for thin wrappers like:
1052-
// (def reverse (fn (lst) (reverse-acc lst (list))))
1053-
if let Some(fn_def) = self.inline_candidates.get(op).cloned() {
1054-
// Check: correct number of arguments
1055-
if args.len() == fn_def.params.len() {
1056-
// Check: function is small enough to inline
1057-
if is_small_body(&fn_def.body) {
1058-
// Check: function doesn't call itself (non-recursive)
1059-
if !contains_call_to(&fn_def.body, op) {
1060-
// Inline: substitute parameters with arguments and compile
1061-
let inlined = substitute(&fn_def.body, &fn_def.params, args);
1062-
return self.compile_expr(&inlined, dest, tail_pos);
1063-
}
1064-
}
1065-
}
1066-
}
1067971
}
1068972

1069973
// Check if calling a global symbol (optimization: use CallGlobal/TailCallGlobal)

0 commit comments

Comments
 (0)