Skip to content

Commit 77df584

Browse files
committed
Add Arena struct with thread-local
Add TAG_ARENA NaN-boxing tag to distinguish arena values from Rc Arena values have free clone (just copy bits) and no-op drop Add Value::promote to convert arena values to Rc when escaping scope
1 parent 969771e commit 77df584

File tree

3 files changed

+414
-15
lines changed

3 files changed

+414
-15
lines changed

src/lib.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,31 @@ pub use compiler::Compiler;
1010
pub use eval::{eval, standard_env, Env};
1111
pub use macros::{expand, MacroRegistry};
1212
pub use parser::{parse, parse_all};
13-
pub use value::Value;
13+
pub use value::{clear_arena, set_arena_enabled, Value};
1414
pub use vm::{standard_vm, VM};
1515

1616
/// Convenience function to evaluate a string using the bytecode VM
1717
pub fn run(input: &str) -> Result<Value, String> {
1818
let expr = parse(input)?;
1919
let chunk = Compiler::compile(&expr)?;
2020
let mut vm = standard_vm();
21-
vm.run(chunk)
21+
let result = vm.run(chunk)?;
22+
// Promote result to Rc if needed (escaping arena scope)
23+
let promoted = result.promote();
24+
// Clear arena after each expression
25+
clear_arena();
26+
Ok(promoted)
2227
}
2328

2429
/// Convenience function to evaluate multiple expressions using the bytecode VM
2530
pub fn run_all(input: &str) -> Result<Value, String> {
2631
let exprs = parse_all(input)?;
2732
let chunk = Compiler::compile_all(&exprs)?;
2833
let mut vm = standard_vm();
29-
vm.run(chunk)
34+
let result = vm.run(chunk)?;
35+
// Promote result to Rc if needed (escaping arena scope)
36+
let promoted = result.promote();
37+
// Clear arena after execution
38+
clear_arena();
39+
Ok(promoted)
3040
}

src/main.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use lisp_vm::{expand, parse, parse_all, standard_env, standard_vm, Compiler, MacroRegistry, Value};
1+
use lisp_vm::{clear_arena, expand, parse, parse_all, standard_env, standard_vm, Compiler, MacroRegistry, Value};
22
use std::env;
33
use std::fs;
44
use std::io::{self, BufRead, Write};
@@ -41,8 +41,18 @@ fn run_file(filename: &str) -> Result<Value, String> {
4141
let chunk = Compiler::compile_all(&expanded)?;
4242

4343
// Execute via bytecode VM
44+
// Note: Arena allocations accumulate during execution for maximum performance
45+
// (free clone/drop). The arena is cleared when the program exits.
4446
let mut vm = standard_vm();
45-
vm.run(chunk)
47+
let result = vm.run(chunk)?;
48+
49+
// Promote result if it contains arena values (for returning to caller)
50+
let promoted = result.promote();
51+
52+
// Clear arena after execution (frees all temporary allocations at once)
53+
clear_arena();
54+
55+
Ok(promoted)
4656
}
4757

4858
fn run_repl() {
@@ -88,12 +98,19 @@ fn run_repl() {
8898
// Execute via VM
8999
match vm.run(chunk) {
90100
Ok(result) => {
101+
// Promote result before displaying (escapes arena)
102+
let result = result.promote();
91103
// Don't display nil results (common REPL behavior)
92104
if !result.is_nil() {
93105
println!("{}", result);
94106
}
107+
// Clear arena after each REPL command
108+
clear_arena();
109+
}
110+
Err(e) => {
111+
clear_arena(); // Clear even on error
112+
eprintln!("Error: {}", e);
95113
}
96-
Err(e) => eprintln!("Error: {}", e),
97114
}
98115
}
99116
Err(e) => eprintln!("Compile error: {}", e),

0 commit comments

Comments
 (0)