@@ -2,17 +2,17 @@ use crate::bytecode::{Chunk, ConstIdx, Op, Reg};
22use crate :: value:: Value ;
33use 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 ) ]
1414struct PureFunctions {
15- funcs : HashMap < String , FunctionDef > ,
15+ funcs : HashMap < String , PureFunction > ,
1616}
1717
1818impl 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
236163fn 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