Skip to main content

compiler/
compiler.rs

1use object::builtins::BuiltIns;
2use serde::Serialize;
3use std::collections::HashMap;
4use std::rc::Rc;
5
6use object::Object;
7use parser::ast::{
8    BlockStatement, Expression, Literal, MethodDefinition, MethodKind, Node, Statement,
9};
10use parser::lexer::token::Span;
11use parser::lexer::token::TokenKind;
12use parser::validation::validate_program;
13
14use crate::op_code::Opcode::*;
15use crate::op_code::{make_instructions, Instructions, Opcode};
16use crate::symbol_table::{Symbol, SymbolScope, SymbolTable};
17
18struct CompilationScope {
19    instructions: Instructions,
20    last_instruction: EmittedInstruction,
21    previous_instruction: EmittedInstruction,
22    debug_info: DebugInfo,
23}
24
25pub struct Compiler {
26    pub constants: Vec<Rc<Object>>,
27    pub symbol_table: SymbolTable,
28    function_debug_info: HashMap<usize, DebugInfo>,
29    scopes: Vec<CompilationScope>,
30    scope_index: usize,
31    callable_kinds: Vec<CallableKind>,
32}
33
34#[derive(Debug, PartialEq)]
35pub struct Bytecode {
36    pub instructions: Instructions,
37    pub constants: Vec<Rc<Object>>,
38    pub debug_info: DebugInfo,
39    pub function_debug_info: HashMap<usize, DebugInfo>,
40}
41
42#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
43#[serde(rename_all = "camelCase")]
44pub struct PcSpan {
45    pub pc: usize,
46    pub span: Span,
47}
48
49#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
50#[serde(rename_all = "camelCase")]
51pub struct DebugInfo {
52    pub pc_spans: Vec<PcSpan>,
53}
54
55#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
56#[serde(tag = "type", rename_all = "camelCase")]
57pub enum InstructionScope {
58    Main,
59    Function { constant_index: usize },
60}
61
62#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
63#[serde(rename_all = "camelCase")]
64pub struct InstructionLineMapping {
65    pub line: usize,
66    pub pc: usize,
67    pub scope: InstructionScope,
68}
69
70#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
71#[serde(rename_all = "camelCase")]
72pub struct BytecodeDebugView {
73    pub detail: String,
74    pub main_debug_info: DebugInfo,
75    pub function_debug_info: HashMap<usize, DebugInfo>,
76    pub instruction_lines: Vec<InstructionLineMapping>,
77}
78
79struct ScopedInstructions {
80    instructions: Instructions,
81    debug_info: DebugInfo,
82}
83
84impl Bytecode {
85    pub fn string(&self) -> String {
86        self.debug_view().detail
87    }
88
89    pub fn debug_view(&self) -> BytecodeDebugView {
90        let mut builder = BytecodeDisplayBuilder::new();
91
92        builder.write_line("Instructions:");
93        for line in self.instructions.string().lines() {
94            builder
95                .write_instruction_line(line, InstructionScope::Main, |line| format!("{line}\n"));
96        }
97
98        builder.write_line("");
99        builder.write_line("Constants:");
100
101        if self.constants.is_empty() {
102            builder.write_line("(none)");
103        } else {
104            for (index, constant) in self.constants.iter().enumerate() {
105                match constant.as_ref() {
106                    Object::CompiledFunction(function) => {
107                        let name = if function.name.is_empty() {
108                            "<anonymous>"
109                        } else {
110                            function.name.as_str()
111                        };
112                        builder.write_line(&format!(
113                            "{index:04} CompiledFunction(name={name}, num_locals={}, num_parameters={})",
114                            function.num_locals,
115                            function.num_parameters
116                        ));
117                        builder.write_line("     Instructions:");
118
119                        let instructions = Instructions {
120                            data: function.instructions.clone(),
121                        };
122                        let scope = InstructionScope::Function {
123                            constant_index: index,
124                        };
125                        for line in instructions.string().lines() {
126                            builder.write_instruction_line(line, scope.clone(), |line| {
127                                format!("       {line}\n")
128                            });
129                        }
130                    }
131                    value => builder.write_line(&format!("{index:04} {value}")),
132                }
133            }
134        }
135
136        BytecodeDebugView {
137            detail: builder.output,
138            main_debug_info: self.debug_info.clone(),
139            function_debug_info: self.function_debug_info.clone(),
140            instruction_lines: builder.instruction_lines,
141        }
142    }
143}
144
145struct BytecodeDisplayBuilder {
146    output: String,
147    line: usize,
148    instruction_lines: Vec<InstructionLineMapping>,
149}
150
151impl BytecodeDisplayBuilder {
152    fn new() -> Self {
153        Self {
154            output: String::new(),
155            line: 0,
156            instruction_lines: vec![],
157        }
158    }
159
160    fn write_line(&mut self, line: &str) {
161        self.output.push_str(line);
162        self.output.push('\n');
163        self.line += 1;
164    }
165
166    fn write_instruction_line(
167        &mut self,
168        raw_line: &str,
169        scope: InstructionScope,
170        format_line: impl FnOnce(&str) -> String,
171    ) {
172        if let Some(pc) = parse_instruction_pc(raw_line) {
173            self.instruction_lines.push(InstructionLineMapping {
174                line: self.line,
175                pc,
176                scope,
177            });
178        }
179
180        self.output.push_str(&format_line(raw_line));
181        self.line += 1;
182    }
183}
184
185fn parse_instruction_pc(line: &str) -> Option<usize> {
186    let trimmed = line.trim_start();
187    if trimmed.len() < 4 {
188        return None;
189    }
190
191    let pc_part = &trimmed[..4];
192    if !pc_part.chars().all(|c| c.is_ascii_digit()) {
193        return None;
194    }
195
196    pc_part.parse().ok()
197}
198
199impl DebugInfo {
200    pub fn add_pc_span(&mut self, pc: usize, span: &Span) {
201        if self
202            .pc_spans
203            .last()
204            .map(|last| last.span == *span)
205            .unwrap_or(false)
206        {
207            return;
208        }
209
210        self.pc_spans.push(PcSpan {
211            pc,
212            span: span.clone(),
213        });
214    }
215
216    pub fn span_for_pc(&self, pc: usize) -> Option<&Span> {
217        self.pc_spans
218            .iter()
219            .rev()
220            .find(|pc_span| pc_span.pc <= pc)
221            .map(|pc_span| &pc_span.span)
222    }
223
224    fn truncate_from_pc(&mut self, pc: usize) {
225        self.pc_spans.retain(|pc_span| pc_span.pc < pc);
226    }
227}
228
229#[derive(Clone)]
230pub struct EmittedInstruction {
231    pub opcode: Opcode,
232    pub position: usize,
233}
234
235type CompileError = String;
236
237#[derive(Clone, Copy, Debug, Eq, PartialEq)]
238enum CallableKind {
239    Function,
240    Method,
241    Constructor,
242}
243
244impl Compiler {
245    pub fn new() -> Compiler {
246        let main_scope = CompilationScope {
247            instructions: Instructions {
248                data: vec![],
249            },
250            last_instruction: EmittedInstruction {
251                opcode: OpNull,
252                position: 0,
253            },
254            previous_instruction: EmittedInstruction {
255                opcode: OpNull,
256                position: 0,
257            },
258            debug_info: DebugInfo::default(),
259        };
260
261        let mut symbol_table = SymbolTable::new();
262        for (key, value) in BuiltIns.iter().enumerate() {
263            symbol_table.define_builtin(key, value.name.to_string());
264        }
265
266        return Compiler {
267            constants: vec![],
268            symbol_table,
269            function_debug_info: HashMap::new(),
270            scopes: vec![main_scope],
271            scope_index: 0,
272            callable_kinds: vec![],
273        };
274    }
275
276    pub fn new_with_state(symbol_table: SymbolTable, constants: Vec<Rc<Object>>) -> Compiler {
277        let mut compiler = Compiler::new();
278        compiler.constants = constants;
279        compiler.symbol_table = symbol_table;
280        return compiler;
281    }
282
283    pub fn compile(&mut self, node: &Node) -> Result<Bytecode, CompileError> {
284        match node {
285            Node::Program(p) => {
286                let mut predefined_names = self.symbol_table.visible_names();
287                predefined_names.extend(BuiltIns.iter().map(|builtin| builtin.name.to_string()));
288                let predefined_names = predefined_names
289                    .iter()
290                    .map(String::as_str)
291                    .collect::<Vec<_>>();
292                validate_program(p, &predefined_names).map_err(|error| error.message)?;
293                for stmt in &p.body {
294                    self.compile_stmt(stmt)?;
295                }
296            }
297            Node::Statement(s) => {
298                self.compile_stmt(s)?;
299            }
300            Node::Expression(e) => {
301                self.compile_expr(e)?;
302            }
303        }
304
305        return Ok(self.bytecode());
306    }
307
308    fn compile_stmt(&mut self, s: &Statement) -> Result<(), CompileError> {
309        match s {
310            Statement::Let(let_statement) => {
311                let symbol = self
312                    .symbol_table
313                    .define(let_statement.identifier.kind.to_string());
314                self.compile_expr(&let_statement.expr)?;
315                if symbol.scope == SymbolScope::Global {
316                    self.emit_with_span(
317                        Opcode::OpSetGlobal,
318                        &vec![symbol.index],
319                        &let_statement.span,
320                    );
321                } else {
322                    self.emit_with_span(
323                        Opcode::OpSetLocal,
324                        &vec![symbol.index],
325                        &let_statement.span,
326                    );
327                }
328                return Ok(());
329            }
330            Statement::Return(r) => {
331                if self.callable_kinds.last() == Some(&CallableKind::Constructor) {
332                    return Err("constructor cannot return a value".to_string());
333                }
334                self.compile_expr(&r.argument)?;
335                self.emit_with_span(Opcode::OpReturnValue, &vec![], &r.span);
336                return Ok(());
337            }
338            Statement::Expr(e) => {
339                self.compile_expr(e)?;
340                self.emit_with_span(OpPop, &vec![], e.span());
341                return Ok(());
342            }
343            Statement::Class(class) => {
344                let symbol = self.symbol_table.define(class.name.name.clone());
345                let class_name = self.add_constant(Object::String(class.name.name.clone()));
346                self.emit_with_span(OpClass, &vec![class_name], &class.span);
347
348                for method in &class.methods {
349                    self.compile_method(&class.name.name, method)?;
350                    let method_name = self.add_constant(Object::String(method.name.name.clone()));
351                    let kind = match method.kind {
352                        MethodKind::Method => 0,
353                        MethodKind::Constructor => 1,
354                    };
355                    self.emit_with_span(OpMethod, &vec![method_name, kind], &method.span);
356                }
357
358                self.emit_with_span(OpSetGlobal, &vec![symbol.index], &class.span);
359                self.emit_with_span(OpNull, &vec![], &class.span);
360                self.emit_with_span(OpPop, &vec![], &class.span);
361                Ok(())
362            }
363            Statement::SetProperty(statement) => {
364                self.compile_expr(&statement.object)?;
365                self.compile_expr(&statement.value)?;
366                let property = self.add_constant(Object::String(statement.property.name.clone()));
367                self.emit_with_span(OpSetProperty, &vec![property], &statement.span);
368                self.emit_with_span(OpNull, &vec![], &statement.span);
369                self.emit_with_span(OpPop, &vec![], &statement.span);
370                Ok(())
371            }
372        }
373    }
374
375    fn compile_expr(&mut self, e: &Expression) -> Result<(), CompileError> {
376        match e {
377            Expression::IDENTIFIER(identifier) => {
378                let symbol = self.symbol_table.resolve(identifier.name.clone());
379                match symbol {
380                    Some(symbol) => {
381                        self.load_symbol(&symbol, &identifier.span);
382                    }
383                    None => {
384                        return Err(format!("Undefined variable '{}'", identifier.name));
385                    }
386                }
387            }
388            Expression::LITERAL(l) => match l {
389                Literal::Integer(i) => {
390                    let int = Object::Integer(i.raw);
391                    let operands = vec![self.add_constant(int)];
392                    self.emit_with_span(OpConst, &operands, &i.span);
393                }
394                Literal::Boolean(i) => {
395                    if i.raw {
396                        self.emit_with_span(OpTrue, &vec![], &i.span);
397                    } else {
398                        self.emit_with_span(OpFalse, &vec![], &i.span);
399                    }
400                }
401                Literal::String(s) => {
402                    let string_object = Object::String(s.raw.clone());
403                    let operands = vec![self.add_constant(string_object)];
404                    self.emit_with_span(OpConst, &operands, &s.span);
405                }
406                Literal::Array(array) => {
407                    for element in array.elements.iter() {
408                        self.compile_expr(element)?;
409                    }
410                    self.emit_with_span(OpArray, &vec![array.elements.len()], &array.span);
411                }
412                Literal::Hash(hash) => {
413                    for (key, value) in hash.elements.iter() {
414                        self.compile_expr(&key)?;
415                        self.compile_expr(&value)?;
416                    }
417                    self.emit_with_span(OpHash, &vec![hash.elements.len() * 2], &hash.span);
418                }
419            },
420            Expression::PREFIX(prefix) => {
421                self.compile_expr(&prefix.operand)?;
422                match prefix.op.kind {
423                    TokenKind::MINUS => {
424                        self.emit_with_span(OpMinus, &vec![], &prefix.span);
425                    }
426                    TokenKind::BANG => {
427                        self.emit_with_span(OpBang, &vec![], &prefix.span);
428                    }
429                    _ => {
430                        return Err(format!("unexpected prefix op: {}", prefix.op));
431                    }
432                }
433            }
434            Expression::INFIX(infix) => {
435                if infix.op.kind == TokenKind::LT {
436                    self.compile_expr(&infix.right)?;
437                    self.compile_expr(&infix.left)?;
438                    self.emit_with_span(Opcode::OpGreaterThan, &vec![], &infix.span);
439                    return Ok(());
440                }
441                self.compile_expr(&infix.left)?;
442                self.compile_expr(&infix.right)?;
443                match infix.op.kind {
444                    TokenKind::PLUS => {
445                        self.emit_with_span(OpAdd, &vec![], &infix.span);
446                    }
447                    TokenKind::MINUS => {
448                        self.emit_with_span(OpSub, &vec![], &infix.span);
449                    }
450                    TokenKind::ASTERISK => {
451                        self.emit_with_span(OpMul, &vec![], &infix.span);
452                    }
453                    TokenKind::SLASH => {
454                        self.emit_with_span(OpDiv, &vec![], &infix.span);
455                    }
456                    TokenKind::GT => {
457                        self.emit_with_span(Opcode::OpGreaterThan, &vec![], &infix.span);
458                    }
459                    TokenKind::EQ => {
460                        self.emit_with_span(Opcode::OpEqual, &vec![], &infix.span);
461                    }
462                    TokenKind::NotEq => {
463                        self.emit_with_span(Opcode::OpNotEqual, &vec![], &infix.span);
464                    }
465                    _ => {
466                        return Err(format!("unexpected infix op: {}", infix.op));
467                    }
468                }
469            }
470            Expression::IF(if_node) => {
471                self.compile_expr(&if_node.condition)?;
472                let jump_not_truthy =
473                    self.emit_with_span(OpJumpNotTruthy, &vec![9527], &if_node.span);
474                self.compile_block_statement(&if_node.consequent)?;
475                if self.last_instruction_is(OpPop) {
476                    self.remove_last_pop();
477                }
478
479                let jump_pos = self.emit_with_span(OpJump, &vec![9527], &if_node.span);
480
481                let after_consequence_location = self.current_instruction().data.len();
482                self.change_operand(jump_not_truthy, after_consequence_location);
483
484                if if_node.alternate.is_none() {
485                    self.emit_with_span(OpNull, &vec![], &if_node.span);
486                } else {
487                    self.compile_block_statement(&if_node.clone().alternate.unwrap())?;
488                    if self.last_instruction_is(OpPop) {
489                        self.remove_last_pop();
490                    }
491                }
492                let after_alternative_location = self.current_instruction().data.len();
493                self.change_operand(jump_pos, after_alternative_location);
494            }
495            Expression::Index(index) => {
496                self.compile_expr(&index.object)?;
497                self.compile_expr(&index.index)?;
498                self.emit_with_span(OpIndex, &vec![], &index.span);
499            }
500            Expression::FUNCTION(f) => {
501                let function_span = f.span.clone();
502                self.enter_scope();
503                self.callable_kinds.push(CallableKind::Function);
504                for param in f.params.iter() {
505                    self.symbol_table.define(param.name.clone());
506                }
507                self.compile_block_statement(&f.body)?;
508                if self.last_instruction_is(OpPop) {
509                    self.replace_last_pop_with_return();
510                }
511                if !(self.last_instruction_is(OpReturnValue)) {
512                    self.emit_with_span(OpReturn, &vec![], &function_span);
513                }
514                let num_locals = self.symbol_table.num_definitions;
515                let free_symbols = self.symbol_table.free_symbols.clone();
516                let scoped_instructions = self.leave_scope();
517                self.callable_kinds.pop();
518                for x in free_symbols.clone() {
519                    self.load_symbol(&x, &function_span);
520                }
521
522                let compiled_function = Rc::from(object::CompiledFunction {
523                    name: f.name.clone(),
524                    instructions: scoped_instructions.instructions.data,
525                    num_locals,
526                    num_parameters: f.params.len(),
527                });
528
529                let constant_index = self.add_constant(Object::CompiledFunction(compiled_function));
530                self.function_debug_info_mut()
531                    .insert(constant_index, scoped_instructions.debug_info);
532                let operands = vec![constant_index, free_symbols.len()];
533                self.emit_with_span(OpClosure, &operands, &function_span);
534            }
535            Expression::FunctionCall(fc) => {
536                self.compile_expr(&fc.callee)?;
537                for arg in fc.arguments.iter() {
538                    self.compile_expr(arg)?;
539                }
540                self.emit_with_span(OpCall, &vec![fc.arguments.len()], &fc.span);
541            }
542            Expression::This(this) => {
543                let symbol = self
544                    .symbol_table
545                    .resolve("this".to_string())
546                    .ok_or_else(|| "this is only available inside a method".to_string())?;
547                self.load_symbol(&symbol, &this.span);
548            }
549            Expression::Property(property) => {
550                self.compile_expr(&property.object)?;
551                let name = self.add_constant(Object::String(property.property.name.clone()));
552                self.emit_with_span(OpGetProperty, &vec![name], &property.span);
553            }
554            Expression::New(new_expression) => {
555                let symbol = self
556                    .symbol_table
557                    .resolve(new_expression.callee.name.clone())
558                    .ok_or_else(|| {
559                        format!("Undefined variable '{}'", new_expression.callee.name)
560                    })?;
561                self.load_symbol(&symbol, &new_expression.callee.span);
562                for argument in &new_expression.arguments {
563                    self.compile_expr(argument)?;
564                }
565                self.emit_with_span(
566                    OpNew,
567                    &vec![new_expression.arguments.len()],
568                    &new_expression.span,
569                );
570            }
571        }
572
573        return Ok(());
574    }
575
576    fn load_symbol(&mut self, symbol: &Rc<Symbol>, span: &Span) {
577        match symbol.scope {
578            SymbolScope::Global => {
579                self.emit_with_span(OpGetGlobal, &vec![symbol.index], span);
580            }
581            SymbolScope::LOCAL => {
582                self.emit_with_span(OpGetLocal, &vec![symbol.index], span);
583            }
584            SymbolScope::Builtin => {
585                self.emit_with_span(OpGetBuiltin, &vec![symbol.index], span);
586            }
587            SymbolScope::Free => {
588                self.emit_with_span(OpGetFree, &vec![symbol.index], span);
589            }
590            SymbolScope::Function => {
591                self.emit_with_span(OpCurrentClosure, &vec![], span);
592            }
593        }
594    }
595
596    pub fn bytecode(&self) -> Bytecode {
597        return Bytecode {
598            instructions: self.current_instruction().clone(),
599            constants: self.constants.clone(),
600            debug_info: self.current_debug_info().clone(),
601            function_debug_info: self.function_debug_info.clone(),
602        };
603    }
604
605    pub fn add_constant(&mut self, obj: Object) -> usize {
606        self.constants.push(Rc::new(obj));
607        return self.constants.len() - 1;
608    }
609
610    pub fn emit(&mut self, op: Opcode, operands: &Vec<usize>) -> usize {
611        let ins = make_instructions(op, operands);
612        let pos = self.add_instructions(&ins);
613        self.set_last_instruction(op, pos);
614
615        return pos;
616    }
617
618    pub fn emit_with_span(&mut self, op: Opcode, operands: &Vec<usize>, span: &Span) -> usize {
619        let pos = self.emit(op, operands);
620        self.add_pc_span(pos, span);
621        pos
622    }
623
624    fn compile_block_statement(
625        &mut self,
626        block_statement: &BlockStatement,
627    ) -> Result<(), CompileError> {
628        for stmt in &block_statement.body {
629            self.compile_stmt(stmt)?;
630        }
631        Ok(())
632    }
633
634    fn compile_method(
635        &mut self,
636        class_name: &str,
637        method: &MethodDefinition,
638    ) -> Result<(), CompileError> {
639        let method_span = method.span.clone();
640        self.enter_scope();
641        let callable_kind = match method.kind {
642            MethodKind::Method => CallableKind::Method,
643            MethodKind::Constructor => CallableKind::Constructor,
644        };
645        self.callable_kinds.push(callable_kind);
646
647        self.symbol_table.define("this".to_string());
648        for parameter in &method.params {
649            self.symbol_table.define(parameter.name.clone());
650        }
651        self.compile_block_statement(&method.body)?;
652
653        match method.kind {
654            MethodKind::Constructor => {
655                self.emit_with_span(OpGetLocal, &vec![0], &method_span);
656                self.emit_with_span(OpReturnValue, &vec![], &method_span);
657            }
658            MethodKind::Method => {
659                if self.last_instruction_is(OpPop) {
660                    self.replace_last_pop_with_return();
661                }
662                if !self.last_instruction_is(OpReturnValue) {
663                    self.emit_with_span(OpReturn, &vec![], &method_span);
664                }
665            }
666        }
667
668        let num_locals = self.symbol_table.num_definitions;
669        let free_symbols = self.symbol_table.free_symbols.clone();
670        let scoped_instructions = self.leave_scope();
671        self.callable_kinds.pop();
672        for symbol in &free_symbols {
673            self.load_symbol(symbol, &method_span);
674        }
675
676        let compiled_function = Rc::new(object::CompiledFunction {
677            name: format!("{}.{}", class_name, method.name.name),
678            instructions: scoped_instructions.instructions.data,
679            num_locals,
680            num_parameters: method.params.len() + 1,
681        });
682        let constant_index = self.add_constant(Object::CompiledFunction(compiled_function));
683        self.function_debug_info_mut()
684            .insert(constant_index, scoped_instructions.debug_info);
685        self.emit_with_span(OpClosure, &vec![constant_index, free_symbols.len()], &method_span);
686        Ok(())
687    }
688
689    pub fn add_instructions(&mut self, ins: &Instructions) -> usize {
690        let pos = self.current_instruction().data.len();
691        let updated_ins = self.scopes[self.scope_index]
692            .instructions
693            .merge_instructions(ins);
694        self.scopes[self.scope_index].instructions = updated_ins;
695        return pos;
696    }
697
698    fn set_last_instruction(&mut self, op: Opcode, pos: usize) {
699        let previous_instruction = self.scopes[self.scope_index].last_instruction.clone();
700        let last_instruction = EmittedInstruction {
701            opcode: op,
702            position: pos,
703        };
704        self.scopes[self.scope_index].last_instruction = last_instruction;
705        self.scopes[self.scope_index].previous_instruction = previous_instruction;
706    }
707
708    fn last_instruction_is(&self, op: Opcode) -> bool {
709        if self.current_instruction().data.len() == 0 {
710            return false;
711        }
712        return self.scopes[self.scope_index].last_instruction.opcode == op;
713    }
714
715    fn remove_last_pop(&mut self) {
716        let last = self.scopes[self.scope_index].last_instruction.clone();
717        let previous = self.scopes[self.scope_index].previous_instruction.clone();
718
719        let old = self.current_instruction().data.clone();
720        let new = old[..last.position].to_vec();
721
722        self.scopes[self.scope_index].instructions.data = new;
723        self.scopes[self.scope_index]
724            .debug_info
725            .truncate_from_pc(last.position);
726        self.scopes[self.scope_index].last_instruction = previous;
727    }
728
729    fn replace_instruction(&mut self, pos: usize, new_instruction: &Instructions) {
730        let ins = &mut self.scopes[self.scope_index].instructions;
731        for i in 0..new_instruction.data.len() {
732            ins.data[pos + i] = new_instruction.data[i];
733        }
734    }
735
736    fn replace_last_pop_with_return(&mut self) {
737        let last_pos = self.scopes[self.scope_index].last_instruction.position;
738        self.replace_instruction(last_pos, &make_instructions(OpReturnValue, &vec![]));
739        self.scopes[self.scope_index].last_instruction.opcode = OpReturnValue;
740    }
741
742    fn change_operand(&mut self, pos: usize, operand: usize) {
743        let op = Opcode::from_repr(self.current_instruction().data[pos])
744            .expect("compiler emitted an unknown opcode");
745        let ins = make_instructions(op, &vec![operand]);
746        self.replace_instruction(pos, &ins);
747    }
748
749    fn current_instruction(&self) -> &Instructions {
750        return &self.scopes[self.scope_index].instructions;
751    }
752
753    fn current_debug_info(&self) -> &DebugInfo {
754        return &self.scopes[self.scope_index].debug_info;
755    }
756
757    fn function_debug_info_mut(&mut self) -> &mut HashMap<usize, DebugInfo> {
758        return &mut self.function_debug_info;
759    }
760
761    fn add_pc_span(&mut self, pc: usize, span: &Span) {
762        self.scopes[self.scope_index]
763            .debug_info
764            .add_pc_span(pc, span);
765    }
766
767    fn enter_scope(&mut self) {
768        let scope = CompilationScope {
769            instructions: Instructions {
770                data: vec![],
771            },
772            last_instruction: EmittedInstruction {
773                opcode: OpNull,
774                position: 0,
775            },
776            previous_instruction: EmittedInstruction {
777                opcode: OpNull,
778                position: 0,
779            },
780            debug_info: DebugInfo::default(),
781        };
782        self.scopes.push(scope);
783        self.scope_index += 1;
784        self.symbol_table = SymbolTable::new_enclosed_symbol_table(self.symbol_table.clone());
785    }
786
787    fn leave_scope(&mut self) -> ScopedInstructions {
788        let instructions = self.current_instruction().clone();
789        let debug_info = self.current_debug_info().clone();
790        self.scopes.pop();
791        self.scope_index -= 1;
792        let s = self.symbol_table.outer.as_ref().unwrap().as_ref().clone();
793        self.symbol_table = s;
794        return ScopedInstructions {
795            instructions,
796            debug_info,
797        };
798    }
799}