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}