plotnik_compiler/compile/
compiler.rs1use std::cell::RefCell;
4
5use indexmap::IndexMap;
6use plotnik_core::{Interner, NodeFieldId, NodeTypeId, Symbol};
7
8use crate::analyze::symbol_table::SymbolTable;
9use crate::analyze::type_check::{DefId, TypeContext};
10use crate::bytecode::{InstructionIR, Label, ReturnIR, TrampolineIR};
11use crate::emit::StringTableBuilder;
12use crate::parser::Expr;
13use plotnik_bytecode::Nav;
14
15use super::capture::CaptureEffects;
16use super::dce::remove_unreachable;
17use super::epsilon_elim::eliminate_epsilons;
18use super::error::{CompileError, CompileResult};
19use super::scope::StructScope;
20use super::verify::debug_verify_ir_fingerprint;
21
22pub struct CompileCtx<'a> {
27 pub interner: &'a Interner,
28 pub type_ctx: &'a TypeContext,
29 pub symbol_table: &'a SymbolTable,
30 pub strings: &'a RefCell<StringTableBuilder>,
31 pub node_types: Option<&'a IndexMap<Symbol, NodeTypeId>>,
32 pub node_fields: Option<&'a IndexMap<Symbol, NodeFieldId>>,
33}
34
35pub struct Compiler<'a> {
37 pub(super) ctx: &'a CompileCtx<'a>,
38 pub(super) instructions: Vec<InstructionIR>,
39 pub(crate) next_label_id: u32,
40 pub(super) def_entries: IndexMap<DefId, Label>,
41 pub(super) scope_stack: Vec<StructScope>,
44}
45
46impl<'a> Compiler<'a> {
47 pub fn new(ctx: &'a CompileCtx<'a>) -> Self {
49 Self {
50 ctx,
51 instructions: Vec::new(),
52 next_label_id: 0,
53 def_entries: IndexMap::new(),
54 scope_stack: Vec::new(),
55 }
56 }
57
58 pub fn compile(ctx: &'a CompileCtx<'a>) -> Result<CompileResult, CompileError> {
60 let mut compiler = Compiler::new(ctx);
61
62 let preamble_entry = compiler.emit_preamble();
65
66 for (def_id, _) in ctx.type_ctx.iter_def_types() {
68 let label = compiler.fresh_label();
69 compiler.def_entries.insert(def_id, label);
70 }
71
72 for (def_id, _) in ctx.type_ctx.iter_def_types() {
74 compiler.compile_def(def_id)?;
75 }
76
77 let mut result = CompileResult {
78 instructions: compiler.instructions,
79 def_entries: compiler.def_entries,
80 preamble_entry,
81 };
82
83 eliminate_epsilons(&mut result, ctx);
85
86 remove_unreachable(&mut result);
88
89 Ok(result)
90 }
91
92 fn emit_preamble(&mut self) -> Label {
97 let return_label = self.fresh_label();
99 self.instructions.push(ReturnIR::new(return_label).into());
100
101 let endobj_label = self.emit_endobj_step(return_label);
103
104 let trampoline_label = self.fresh_label();
105 self.instructions
106 .push(TrampolineIR::new(trampoline_label, endobj_label).into());
107
108 self.emit_obj_step(trampoline_label)
109 }
110
111 pub(super) fn fresh_label(&mut self) -> Label {
113 let l = Label(self.next_label_id);
114 self.next_label_id += 1;
115 l
116 }
117
118 fn compile_def(&mut self, def_id: DefId) -> Result<(), CompileError> {
120 let name_sym = self.ctx.type_ctx.def_name_sym(def_id);
121 let name = self.ctx.interner.resolve(name_sym);
122
123 let Some(body) = self.ctx.symbol_table.get(name) else {
124 return Err(CompileError::DefinitionNotFound(name.to_string()));
125 };
126
127 let entry_label = self.def_entries[&def_id];
128
129 let return_label = self.fresh_label();
133 self.instructions.push(ReturnIR::new(return_label).into());
134
135 let body_nav = Some(Nav::StayExact);
140
141 let body_entry = if let Some(type_id) = self.ctx.type_ctx.get_def_type(def_id) {
145 self.with_scope(type_id, |this| {
146 this.compile_expr_with_nav(body, return_label, body_nav)
147 })
148 } else {
149 self.compile_expr_with_nav(body, return_label, body_nav)
150 };
151
152 if body_entry != entry_label {
154 self.emit_epsilon(entry_label, vec![body_entry]);
155 }
156
157 debug_verify_ir_fingerprint(
159 &self.instructions,
160 entry_label,
161 &self.def_entries,
162 name,
163 self.ctx,
164 );
165
166 Ok(())
167 }
168
169 pub(super) fn compile_expr_with_nav(
171 &mut self,
172 expr: &Expr,
173 exit: Label,
174 nav_override: Option<Nav>,
175 ) -> Label {
176 self.compile_expr_inner(expr, exit, nav_override, CaptureEffects::default())
177 }
178
179 pub(super) fn compile_expr_inner(
187 &mut self,
188 expr: &Expr,
189 exit: Label,
190 nav_override: Option<Nav>,
191 capture: CaptureEffects,
192 ) -> Label {
193 match expr {
194 Expr::NamedNode(n) => self.compile_named_node_inner(n, exit, nav_override, capture),
196 Expr::AnonymousNode(n) => {
197 self.compile_anonymous_node_inner(n, exit, nav_override, capture)
198 }
199 Expr::SeqExpr(s) => self.compile_seq_inner(s, exit, nav_override, capture),
201 Expr::AltExpr(a) => self.compile_alt_inner(a, exit, nav_override, capture),
203 Expr::CapturedExpr(c) => self.compile_captured_inner(c, exit, nav_override, capture),
205 Expr::QuantifiedExpr(q) => {
206 self.compile_quantified_inner(q, exit, nav_override, capture)
207 }
208 Expr::FieldExpr(f) => self.compile_field_inner(f, exit, nav_override, capture),
209 Expr::Ref(r) => self.compile_ref_inner(r, exit, nav_override, None, capture),
211 }
212 }
213}