1#[cfg(test)]
2mod gc_test;
3#[cfg(test)]
4mod report_test;
5#[cfg(test)]
6mod runner_test;
7#[cfg(test)]
8mod value_test;
9#[cfg(test)]
10mod vm_test;
11
12pub mod frame;
13pub mod header;
14pub mod heap;
15pub mod list;
16pub mod malloc;
17pub mod report;
18pub mod runner;
19#[path = "gc_runtime.rs"]
22pub mod runtime;
23pub mod value;
24pub mod vm;
25
26pub use frame::Frame;
27pub use header::{GcId, GcObjectHeader, GcObjectType, GcPhase, RefCountHeader, RefCountId};
28pub use heap::{GcHeap, GcRef};
29pub use malloc::{MallocState, DEFAULT_GC_THRESHOLD, MALLOC_OVERHEAD};
30pub use report::{
31 EdgeRelation, FinalFate, FreeCycleStats, GcCollectionReport, GcObjectSummary, GcPhaseStats,
32 GcStatsBundle, GlobalRoot, HashKeyKind, HeapSnapshot, ObjectDecision, RestorationWitness,
33 ScanStats, TrialDecision, TrialDeletionStats, ValueKindCounts, VisitedEdge,
34};
35pub use runner::{compile_source, run_bytecode};
36pub use runtime::{GcObject, GcRuntime, MarkFunc};
37pub use value::{
38 export_object, import_object, try_export_object, value_to_string, GcClosure, Value, ValueKind,
39};
40pub use vm::{GcRuntimeError, GcVM, DEFAULT_INSTRUCTION_BUDGET};
41
42use compiler::compiler::{Bytecode, Compiler};
43use object::Object;
44use parser::ast::Node;
45use parser::lexer::token::Span;
46use serde::Serialize;
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
49#[serde(rename_all = "lowercase")]
50pub enum GcRunStage {
51 Parse,
52 Compile,
53 Runtime,
54}
55
56#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
57#[serde(rename_all = "camelCase")]
58pub struct GcRunSuccess {
59 pub result: String,
60 pub report: GcCollectionReport,
61}
62
63#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
64#[serde(rename_all = "camelCase")]
65pub struct GcRunError {
66 pub stage: GcRunStage,
67 pub message: String,
68 pub span: Option<Span>,
69}
70
71pub fn compile(program: &Node) -> Result<Bytecode, String> {
73 let mut compiler = Compiler::new();
74 compiler.compile(program)
75}
76
77pub fn eval(program: &Node) -> Result<Object, String> {
79 let bytecode = compile(program)?;
80 let mut vm = GcVM::new(bytecode);
81 vm.run_with_budget(usize::MAX)
82 .map_err(|error| error.message)?;
83 vm.try_export_last_result()
84}
85
86pub fn eval_source(source: &str) -> Result<Object, String> {
88 let program = parser::parse(source).map_err(|errors| errors[0].clone())?;
89 eval(&program)
90}
91
92pub fn run_source_with_report(
94 source: &str,
95 instruction_budget: usize,
96) -> Result<GcRunSuccess, GcRunError> {
97 let program = parser::parse(source).map_err(|errors| GcRunError {
98 stage: GcRunStage::Parse,
99 message: errors
100 .first()
101 .cloned()
102 .unwrap_or_else(|| "unknown parse error".to_string()),
103 span: None,
104 })?;
105 let mut compiler = Compiler::new();
106 let bytecode = compiler.compile(&program).map_err(|message| GcRunError {
107 stage: GcRunStage::Compile,
108 message,
109 span: None,
110 })?;
111 let global_names = compiler.symbol_table.global_symbols();
112 let mut vm = GcVM::new(bytecode);
113 vm.set_global_names(global_names);
114 vm.heap_mut().set_gc_threshold(usize::MAX);
115 vm.run_with_budget(instruction_budget)
116 .map_err(|error| GcRunError {
117 stage: GcRunStage::Runtime,
118 message: error.message,
119 span: error.span,
120 })?;
121 let result = vm.last_result_string();
122 let report = vm.collect_garbage();
123 Ok(GcRunSuccess {
124 result,
125 report,
126 })
127}