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, Eq, PartialEq, Serialize)]
51#[serde(rename_all = "camelCase")]
52pub struct BindingDebugInfo {
53 pub name: String,
54 pub slot: usize,
55}
56
57#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
58#[serde(rename_all = "camelCase")]
59pub struct DebugInfo {
60 pub pc_spans: Vec<PcSpan>,
61 pub local_bindings: Vec<BindingDebugInfo>,
64 pub free_names: Vec<String>,
66}
67
68#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
69#[serde(tag = "type", rename_all = "camelCase")]
70pub enum InstructionScope {
71 Main,
72 Function { constant_index: usize },
73}
74
75#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
76#[serde(rename_all = "camelCase")]
77pub struct InstructionLineMapping {
78 pub line: usize,
79 pub pc: usize,
80 pub scope: InstructionScope,
81}
82
83#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
84#[serde(rename_all = "camelCase")]
85pub struct BytecodeDebugView {
86 pub detail: String,
87 pub main_debug_info: DebugInfo,
88 pub function_debug_info: HashMap<usize, DebugInfo>,
89 pub instruction_lines: Vec<InstructionLineMapping>,
90}
91
92struct ScopedInstructions {
93 instructions: Instructions,
94 debug_info: DebugInfo,
95}
96
97impl Bytecode {
98 pub fn string(&self) -> String {
99 self.debug_view().detail
100 }
101
102 pub fn debug_view(&self) -> BytecodeDebugView {
103 let mut builder = BytecodeDisplayBuilder::new();
104
105 builder.write_line("Instructions:");
106 for line in self.instructions.string().lines() {
107 builder
108 .write_instruction_line(line, InstructionScope::Main, |line| format!("{line}\n"));
109 }
110
111 builder.write_line("");
112 builder.write_line("Constants:");
113
114 if self.constants.is_empty() {
115 builder.write_line("(none)");
116 } else {
117 for (index, constant) in self.constants.iter().enumerate() {
118 match constant.as_ref() {
119 Object::CompiledFunction(function) => {
120 let name = if function.name.is_empty() {
121 "<anonymous>"
122 } else {
123 function.name.as_str()
124 };
125 builder.write_line(&format!(
126 "{index:04} CompiledFunction(name={name}, num_locals={}, num_parameters={})",
127 function.num_locals,
128 function.num_parameters
129 ));
130 builder.write_line(" Instructions:");
131
132 let instructions = Instructions {
133 data: function.instructions.clone(),
134 };
135 let scope = InstructionScope::Function {
136 constant_index: index,
137 };
138 for line in instructions.string().lines() {
139 builder.write_instruction_line(line, scope.clone(), |line| {
140 format!(" {line}\n")
141 });
142 }
143 }
144 value => builder.write_line(&format!("{index:04} {value}")),
145 }
146 }
147 }
148
149 BytecodeDebugView {
150 detail: builder.output,
151 main_debug_info: self.debug_info.clone(),
152 function_debug_info: self.function_debug_info.clone(),
153 instruction_lines: builder.instruction_lines,
154 }
155 }
156}
157
158struct BytecodeDisplayBuilder {
159 output: String,
160 line: usize,
161 instruction_lines: Vec<InstructionLineMapping>,
162}
163
164impl BytecodeDisplayBuilder {
165 fn new() -> Self {
166 Self {
167 output: String::new(),
168 line: 0,
169 instruction_lines: vec![],
170 }
171 }
172
173 fn write_line(&mut self, line: &str) {
174 self.output.push_str(line);
175 self.output.push('\n');
176 self.line += 1;
177 }
178
179 fn write_instruction_line(
180 &mut self,
181 raw_line: &str,
182 scope: InstructionScope,
183 format_line: impl FnOnce(&str) -> String,
184 ) {
185 if let Some(pc) = parse_instruction_pc(raw_line) {
186 self.instruction_lines.push(InstructionLineMapping {
187 line: self.line,
188 pc,
189 scope,
190 });
191 }
192
193 self.output.push_str(&format_line(raw_line));
194 self.line += 1;
195 }
196}
197
198fn split_trailing_debuggers(body: &[Statement]) -> (&[Statement], &[Statement]) {
201 let split = body
202 .iter()
203 .rposition(|statement| !matches!(statement, Statement::Debugger(_)))
204 .map_or(0, |index| index + 1);
205 body.split_at(split)
206}
207
208fn statement_contributes_value(statement: &Statement) -> bool {
212 matches!(statement, Statement::Expr(_))
213}
214
215fn parse_instruction_pc(line: &str) -> Option<usize> {
216 let trimmed = line.trim_start();
217 if trimmed.len() < 4 {
218 return None;
219 }
220
221 let pc_part = &trimmed[..4];
222 if !pc_part.chars().all(|c| c.is_ascii_digit()) {
223 return None;
224 }
225
226 pc_part.parse().ok()
227}
228
229impl DebugInfo {
230 pub fn add_pc_span(&mut self, pc: usize, span: &Span) {
231 if self
232 .pc_spans
233 .last()
234 .map(|last| last.span == *span)
235 .unwrap_or(false)
236 {
237 return;
238 }
239
240 self.pc_spans.push(PcSpan {
241 pc,
242 span: span.clone(),
243 });
244 }
245
246 pub fn span_for_pc(&self, pc: usize) -> Option<&Span> {
247 self.pc_spans
248 .iter()
249 .rev()
250 .find(|pc_span| pc_span.pc <= pc)
251 .map(|pc_span| &pc_span.span)
252 }
253
254 fn truncate_from_pc(&mut self, pc: usize) {
255 self.pc_spans.retain(|pc_span| pc_span.pc < pc);
256 }
257}
258
259#[derive(Clone)]
260pub struct EmittedInstruction {
261 pub opcode: Opcode,
262 pub position: usize,
263}
264
265type CompileError = String;
266
267fn ensure_count(count: usize, max: usize, what: &str) -> Result<(), CompileError> {
276 if count > max {
277 return Err(format!("too many {}: {} exceeds the maximum of {}", what, count, max));
278 }
279 return Ok(());
280}
281
282fn ensure_u8_count(count: usize, what: &str) -> Result<(), CompileError> {
284 return ensure_count(count, u8::MAX as usize, what);
285}
286
287fn ensure_u16_count(count: usize, what: &str) -> Result<(), CompileError> {
288 return ensure_count(count, u16::MAX as usize, what);
289}
290
291fn ensure_u8_index(index: usize, what: &str) -> Result<(), CompileError> {
295 return ensure_count(index + 1, u8::MAX as usize + 1, what);
296}
297
298fn ensure_u16_index(index: usize, what: &str) -> Result<(), CompileError> {
299 return ensure_count(index + 1, u16::MAX as usize + 1, what);
300}
301
302#[derive(Clone, Copy, Debug, Eq, PartialEq)]
303enum CallableKind {
304 Function,
305 Method,
306 Constructor,
307}
308
309impl Default for Compiler {
310 fn default() -> Self {
311 Self::new()
312 }
313}
314
315impl Compiler {
316 pub fn new() -> Compiler {
317 let main_scope = CompilationScope {
318 instructions: Instructions {
319 data: vec![],
320 },
321 last_instruction: EmittedInstruction {
322 opcode: OpNull,
323 position: 0,
324 },
325 previous_instruction: EmittedInstruction {
326 opcode: OpNull,
327 position: 0,
328 },
329 debug_info: DebugInfo::default(),
330 };
331
332 let mut symbol_table = SymbolTable::new();
333 for (key, value) in BuiltIns.iter().enumerate() {
334 symbol_table.define_builtin(key, value.name.to_string());
335 }
336
337 return Compiler {
338 constants: vec![],
339 symbol_table,
340 function_debug_info: HashMap::new(),
341 scopes: vec![main_scope],
342 scope_index: 0,
343 callable_kinds: vec![],
344 };
345 }
346
347 pub fn new_with_state(symbol_table: SymbolTable, constants: Vec<Rc<Object>>) -> Compiler {
348 let mut compiler = Compiler::new();
349 compiler.constants = constants;
350 compiler.symbol_table = symbol_table;
351 return compiler;
352 }
353
354 pub fn compile(&mut self, node: &Node) -> Result<Bytecode, CompileError> {
355 match node {
356 Node::Program(p) => {
357 let mut predefined_names = self.symbol_table.visible_names();
358 predefined_names.extend(BuiltIns.iter().map(|builtin| builtin.name.to_string()));
359 let predefined_names = predefined_names
360 .iter()
361 .map(String::as_str)
362 .collect::<Vec<_>>();
363 validate_program(p, &predefined_names).map_err(|error| error.message)?;
364 for stmt in &p.body {
365 self.compile_stmt(stmt)?;
366 }
367 }
368 Node::Statement(s) => {
369 self.compile_stmt(s)?;
370 }
371 Node::Expression(e) => {
372 self.compile_expr(e)?;
373 }
374 }
375
376 return Ok(self.bytecode());
377 }
378
379 fn compile_stmt(&mut self, s: &Statement) -> Result<(), CompileError> {
380 match s {
381 Statement::Let(let_statement) => {
382 self.compile_expr(&let_statement.expr)?;
386 let symbol = self.define_symbol(let_statement.identifier.name.clone())?;
387 if symbol.scope == SymbolScope::Global {
388 self.emit_with_span(Opcode::OpSetGlobal, &[symbol.index], &let_statement.span);
389 } else {
390 self.emit_with_span(Opcode::OpSetLocal, &[symbol.index], &let_statement.span);
391 }
392 return Ok(());
393 }
394 Statement::Return(r) => {
395 if self.callable_kinds.last() == Some(&CallableKind::Constructor) {
396 return Err("constructor cannot return a value".to_string());
397 }
398 self.compile_expr(&r.argument)?;
399 self.emit_with_span(Opcode::OpReturnValue, &[], &r.span);
400 return Ok(());
401 }
402 Statement::Expr(e) => {
403 self.compile_expr(e)?;
404 self.emit_with_span(OpPop, &[], e.span());
405 return Ok(());
406 }
407 Statement::Class(class) => {
408 let symbol = self.define_symbol(class.name.name.clone())?;
409 let class_name = self.try_add_constant(Object::String(class.name.name.clone()))?;
410 self.emit_with_span(OpClass, &[class_name], &class.span);
411
412 for method in &class.methods {
413 self.compile_method(&class.name.name, method)?;
414 let method_name =
415 self.try_add_constant(Object::String(method.name.name.clone()))?;
416 let kind = match method.kind {
417 MethodKind::Method => 0,
418 MethodKind::Constructor => 1,
419 };
420 self.emit_with_span(OpMethod, &[method_name, kind], &method.span);
421 }
422
423 self.emit_with_span(OpSetGlobal, &[symbol.index], &class.span);
424 self.emit_with_span(OpNull, &[], &class.span);
425 self.emit_with_span(OpPop, &[], &class.span);
426 Ok(())
427 }
428 Statement::SetProperty(statement) => {
429 self.compile_expr(&statement.object)?;
430 self.compile_expr(&statement.value)?;
431 let property =
432 self.try_add_constant(Object::String(statement.property.name.clone()))?;
433 self.emit_with_span(OpSetProperty, &[property], &statement.span);
434 self.emit_with_span(OpNull, &[], &statement.span);
435 self.emit_with_span(OpPop, &[], &statement.span);
436 Ok(())
437 }
438 Statement::Debugger(statement) => {
439 self.emit_with_span(OpDebugger, &[], &statement.span);
440 Ok(())
441 }
442 }
443 }
444
445 fn compile_expr(&mut self, e: &Expression) -> Result<(), CompileError> {
446 match e {
447 Expression::IDENTIFIER(identifier) => {
448 let symbol = self.symbol_table.resolve(identifier.name.clone());
449 match symbol {
450 Some(symbol) => {
451 self.load_symbol(&symbol, &identifier.span)?;
452 }
453 None => {
454 return Err(format!("Undefined variable '{}'", identifier.name));
455 }
456 }
457 }
458 Expression::LITERAL(l) => match l {
459 Literal::Integer(i) => {
460 let int = Object::Integer(i.raw);
461 let operands = vec![self.try_add_constant(int)?];
462 self.emit_with_span(OpConst, &operands, &i.span);
463 }
464 Literal::Boolean(i) => {
465 if i.raw {
466 self.emit_with_span(OpTrue, &[], &i.span);
467 } else {
468 self.emit_with_span(OpFalse, &[], &i.span);
469 }
470 }
471 Literal::String(s) => {
472 let string_object = Object::String(s.raw.clone());
473 let operands = vec![self.try_add_constant(string_object)?];
474 self.emit_with_span(OpConst, &operands, &s.span);
475 }
476 Literal::Array(array) => {
477 for element in array.elements.iter() {
478 self.compile_expr(element)?;
479 }
480 ensure_u16_count(array.elements.len(), "array elements")?;
481 self.emit_with_span(OpArray, &[array.elements.len()], &array.span);
482 }
483 Literal::Hash(hash) => {
484 for (key, value) in hash.elements.iter() {
485 self.compile_expr(key)?;
486 self.compile_expr(value)?;
487 }
488 ensure_count(hash.elements.len(), u16::MAX as usize / 2, "hash pairs")?;
493 self.emit_with_span(OpHash, &[hash.elements.len() * 2], &hash.span);
494 }
495 },
496 Expression::PREFIX(prefix) => {
497 self.compile_expr(&prefix.operand)?;
498 match prefix.op.kind {
499 TokenKind::MINUS => {
500 self.emit_with_span(OpMinus, &[], &prefix.span);
501 }
502 TokenKind::BANG => {
503 self.emit_with_span(OpBang, &[], &prefix.span);
504 }
505 _ => {
506 return Err(format!("unexpected prefix op: {}", prefix.op));
507 }
508 }
509 }
510 Expression::INFIX(infix) => {
511 self.compile_expr(&infix.left)?;
512 self.compile_expr(&infix.right)?;
513 match infix.op.kind {
514 TokenKind::PLUS => {
515 self.emit_with_span(OpAdd, &[], &infix.span);
516 }
517 TokenKind::MINUS => {
518 self.emit_with_span(OpSub, &[], &infix.span);
519 }
520 TokenKind::ASTERISK => {
521 self.emit_with_span(OpMul, &[], &infix.span);
522 }
523 TokenKind::SLASH => {
524 self.emit_with_span(OpDiv, &[], &infix.span);
525 }
526 TokenKind::GT => {
527 self.emit_with_span(Opcode::OpGreaterThan, &[], &infix.span);
528 }
529 TokenKind::LT => {
530 self.emit_with_span(Opcode::OpLessThan, &[], &infix.span);
531 }
532 TokenKind::EQ => {
533 self.emit_with_span(Opcode::OpEqual, &[], &infix.span);
534 }
535 TokenKind::NotEq => {
536 self.emit_with_span(Opcode::OpNotEqual, &[], &infix.span);
537 }
538 _ => {
539 return Err(format!("unexpected infix op: {}", infix.op));
540 }
541 }
542 }
543 Expression::IF(if_node) => {
544 self.compile_expr(&if_node.condition)?;
545 let jump_not_truthy = self.emit_with_span(OpJumpNotTruthy, &[9527], &if_node.span);
546 self.compile_block_statement_as_value(&if_node.consequent)?;
547
548 let jump_pos = self.emit_with_span(OpJump, &[9527], &if_node.span);
549
550 let after_consequence_location = self.current_instruction().data.len();
551 self.change_operand(jump_not_truthy, after_consequence_location)?;
552
553 if let Some(alternate) = &if_node.alternate {
554 self.compile_block_statement_as_value(alternate)?;
555 } else {
556 self.emit_with_span(OpNull, &[], &if_node.span);
557 }
558 let after_alternative_location = self.current_instruction().data.len();
559 self.change_operand(jump_pos, after_alternative_location)?;
560 }
561 Expression::Index(index) => {
562 self.compile_expr(&index.object)?;
563 self.compile_expr(&index.index)?;
564 self.emit_with_span(OpIndex, &[], &index.span);
565 }
566 Expression::FUNCTION(f) => {
567 let function_span = f.span.clone();
568 self.enter_scope();
569 self.callable_kinds.push(CallableKind::Function);
570 if !f.name.is_empty() {
571 self.symbol_table.define_function_name(f.name.clone());
572 }
573 for param in f.params.iter() {
574 self.define_symbol(param.identifier.name.clone())?;
575 }
576 self.compile_function_body(&f.body, &function_span)?;
577 let num_locals = self.symbol_table.num_definitions;
578 let free_symbols = self.symbol_table.free_symbols.clone();
579 let scoped_instructions = self.leave_scope();
580 self.callable_kinds.pop();
581 ensure_u8_count(free_symbols.len(), "free variables")?;
586 for x in free_symbols.clone() {
587 self.load_symbol(&x, &function_span)?;
588 }
589
590 let compiled_function = Rc::from(object::CompiledFunction {
591 name: f.name.clone(),
592 instructions: scoped_instructions.instructions.data,
593 num_locals,
594 num_parameters: f.params.len(),
595 });
596
597 let constant_index =
598 self.try_add_constant(Object::CompiledFunction(compiled_function))?;
599 self.function_debug_info_mut()
600 .insert(constant_index, scoped_instructions.debug_info);
601 let operands = vec![constant_index, free_symbols.len()];
602 self.emit_with_span(OpClosure, &operands, &function_span);
603 }
604 Expression::FunctionCall(fc) => {
605 self.compile_expr(&fc.callee)?;
606 for arg in fc.arguments.iter() {
607 self.compile_expr(arg)?;
608 }
609 ensure_u8_count(fc.arguments.len(), "call arguments")?;
610 self.emit_with_span(OpCall, &[fc.arguments.len()], &fc.span);
611 }
612 Expression::This(this) => {
613 let symbol = self
614 .symbol_table
615 .resolve("this".to_string())
616 .ok_or_else(|| "this is only available inside a method".to_string())?;
617 self.load_symbol(&symbol, &this.span)?;
618 }
619 Expression::Property(property) => {
620 self.compile_expr(&property.object)?;
621 let name = self.try_add_constant(Object::String(property.property.name.clone()))?;
622 self.emit_with_span(OpGetProperty, &[name], &property.span);
623 }
624 Expression::New(new_expression) => {
625 let symbol = self
626 .symbol_table
627 .resolve(new_expression.callee.name.clone())
628 .ok_or_else(|| {
629 format!("Undefined variable '{}'", new_expression.callee.name)
630 })?;
631 self.load_symbol(&symbol, &new_expression.callee.span)?;
632 for argument in &new_expression.arguments {
633 self.compile_expr(argument)?;
634 }
635 ensure_u8_count(new_expression.arguments.len(), "constructor arguments")?;
636 self.emit_with_span(OpNew, &[new_expression.arguments.len()], &new_expression.span);
637 }
638 }
639
640 return Ok(());
641 }
642
643 fn load_symbol(&mut self, symbol: &Rc<Symbol>, span: &Span) -> Result<(), CompileError> {
647 match symbol.scope {
648 SymbolScope::Global => {
649 self.emit_with_span(OpGetGlobal, &[symbol.index], span);
650 }
651 SymbolScope::LOCAL => {
652 self.emit_with_span(OpGetLocal, &[symbol.index], span);
653 }
654 SymbolScope::Builtin => {
655 self.emit_with_span(OpGetBuiltin, &[symbol.index], span);
656 }
657 SymbolScope::Free => {
658 ensure_u8_count(symbol.index + 1, "free variables")?;
664 self.emit_with_span(OpGetFree, &[symbol.index], span);
665 }
666 SymbolScope::Function => {
667 self.emit_with_span(OpCurrentClosure, &[], span);
668 }
669 }
670 return Ok(());
671 }
672
673 pub fn bytecode(&self) -> Bytecode {
674 return Bytecode {
675 instructions: self.current_instruction().clone(),
676 constants: self.constants.clone(),
677 debug_info: self.current_debug_info().clone(),
678 function_debug_info: self.function_debug_info.clone(),
679 };
680 }
681
682 fn define_symbol(&mut self, name: String) -> Result<Rc<Symbol>, CompileError> {
683 let symbol = self.symbol_table.define(name);
684 match symbol.scope {
685 SymbolScope::LOCAL => ensure_u8_index(symbol.index, "locals")?,
686 SymbolScope::Global => ensure_u16_index(symbol.index, "globals")?,
687 SymbolScope::Builtin | SymbolScope::Free | SymbolScope::Function => {}
691 }
692 Ok(symbol)
693 }
694
695 pub fn global_bindings(&self) -> Vec<BindingDebugInfo> {
698 self.symbol_table
699 .global_definitions()
700 .iter()
701 .map(|symbol| BindingDebugInfo {
702 name: symbol.name.clone(),
703 slot: symbol.index,
704 })
705 .collect()
706 }
707
708 pub fn add_constant(&mut self, obj: Object) -> usize {
712 self.constants.push(Rc::new(obj));
713 return self.constants.len() - 1;
714 }
715
716 pub fn try_add_constant(&mut self, obj: Object) -> Result<usize, CompileError> {
717 ensure_u16_index(self.constants.len(), "constants")?;
718 return Ok(self.add_constant(obj));
719 }
720
721 pub fn emit(&mut self, op: Opcode, operands: &[usize]) -> usize {
722 let ins = make_instructions(op, operands);
723 let pos = self.add_instructions(&ins);
724 self.set_last_instruction(op, pos);
725
726 return pos;
727 }
728
729 pub fn emit_with_span(&mut self, op: Opcode, operands: &[usize], span: &Span) -> usize {
730 let pos = self.emit(op, operands);
731 self.add_pc_span(pos, span);
732 pos
733 }
734
735 fn compile_block_statement(
736 &mut self,
737 block_statement: &BlockStatement,
738 ) -> Result<(), CompileError> {
739 for stmt in &block_statement.body {
740 self.compile_stmt(stmt)?;
741 }
742 Ok(())
743 }
744
745 fn compile_block_statement_as_value(
746 &mut self,
747 block_statement: &BlockStatement,
748 ) -> Result<(), CompileError> {
749 let (leading, trailing_debuggers) = split_trailing_debuggers(&block_statement.body);
753 let has_value = leading.last().is_some_and(statement_contributes_value);
754 for stmt in leading {
755 self.compile_stmt(stmt)?;
756 }
757 if has_value {
760 debug_assert!(self.last_instruction_is(OpPop));
761 self.remove_last_pop();
762 }
763 for stmt in trailing_debuggers {
764 self.compile_stmt(stmt)?;
765 }
766 if !has_value {
767 self.emit_with_span(OpNull, &[], &block_statement.span);
768 }
769 Ok(())
770 }
771
772 fn compile_function_body(
777 &mut self,
778 body: &BlockStatement,
779 span: &Span,
780 ) -> Result<(), CompileError> {
781 let (leading, trailing_debuggers) = split_trailing_debuggers(&body.body);
782 if trailing_debuggers.is_empty() {
783 self.compile_block_statement(body)?;
784 if self.last_instruction_is(OpPop) {
785 self.replace_last_pop_with_return();
786 }
787 if !(self.last_instruction_is(OpReturnValue)) {
788 self.emit_with_span(OpReturn, &[], span);
789 }
790 return Ok(());
791 }
792
793 let produced_value = leading.last().is_some_and(statement_contributes_value);
794 for stmt in leading {
795 self.compile_stmt(stmt)?;
796 }
797 if produced_value {
798 debug_assert!(self.last_instruction_is(OpPop));
799 self.remove_last_pop();
800 }
801 for stmt in trailing_debuggers {
802 self.compile_stmt(stmt)?;
803 }
804 if produced_value {
805 self.emit_with_span(OpReturnValue, &[], span);
806 } else {
807 self.emit_with_span(OpReturn, &[], span);
808 }
809 Ok(())
810 }
811
812 fn compile_method(
813 &mut self,
814 class_name: &str,
815 method: &MethodDefinition,
816 ) -> Result<(), CompileError> {
817 let method_span = method.span.clone();
818 self.enter_scope();
819 let callable_kind = match method.kind {
820 MethodKind::Method => CallableKind::Method,
821 MethodKind::Constructor => CallableKind::Constructor,
822 };
823 self.callable_kinds.push(callable_kind);
824
825 self.define_symbol("this".to_string())?;
826 for parameter in &method.params {
827 self.define_symbol(parameter.identifier.name.clone())?;
828 }
829
830 match method.kind {
831 MethodKind::Constructor => {
832 self.compile_block_statement(&method.body)?;
835 self.emit_with_span(OpGetLocal, &[0], &method_span);
836 self.emit_with_span(OpReturnValue, &[], &method_span);
837 }
838 MethodKind::Method => {
839 self.compile_function_body(&method.body, &method_span)?;
840 }
841 }
842
843 let num_locals = self.symbol_table.num_definitions;
844 let free_symbols = self.symbol_table.free_symbols.clone();
845 let scoped_instructions = self.leave_scope();
846 self.callable_kinds.pop();
847 ensure_u8_count(free_symbols.len(), "free variables")?;
848 for symbol in &free_symbols {
849 self.load_symbol(symbol, &method_span)?;
850 }
851
852 let compiled_function = Rc::new(object::CompiledFunction {
853 name: format!("{}.{}", class_name, method.name.name),
854 instructions: scoped_instructions.instructions.data,
855 num_locals,
856 num_parameters: method.params.len() + 1,
857 });
858 let constant_index = self.try_add_constant(Object::CompiledFunction(compiled_function))?;
859 self.function_debug_info_mut()
860 .insert(constant_index, scoped_instructions.debug_info);
861 self.emit_with_span(OpClosure, &[constant_index, free_symbols.len()], &method_span);
862 Ok(())
863 }
864
865 pub fn add_instructions(&mut self, ins: &Instructions) -> usize {
866 let pos = self.current_instruction().data.len();
867 let updated_ins = self.scopes[self.scope_index]
868 .instructions
869 .merge_instructions(ins);
870 self.scopes[self.scope_index].instructions = updated_ins;
871 return pos;
872 }
873
874 fn set_last_instruction(&mut self, op: Opcode, pos: usize) {
875 let previous_instruction = self.scopes[self.scope_index].last_instruction.clone();
876 let last_instruction = EmittedInstruction {
877 opcode: op,
878 position: pos,
879 };
880 self.scopes[self.scope_index].last_instruction = last_instruction;
881 self.scopes[self.scope_index].previous_instruction = previous_instruction;
882 }
883
884 fn last_instruction_is(&self, op: Opcode) -> bool {
885 if self.current_instruction().data.is_empty() {
886 return false;
887 }
888 return self.scopes[self.scope_index].last_instruction.opcode == op;
889 }
890
891 fn remove_last_pop(&mut self) {
892 let last = self.scopes[self.scope_index].last_instruction.clone();
893 let previous = self.scopes[self.scope_index].previous_instruction.clone();
894
895 let old = self.current_instruction().data.clone();
896 let new = old[..last.position].to_vec();
897
898 self.scopes[self.scope_index].instructions.data = new;
899 self.scopes[self.scope_index]
900 .debug_info
901 .truncate_from_pc(last.position);
902 self.scopes[self.scope_index].last_instruction = previous;
903 }
904
905 fn replace_instruction(&mut self, pos: usize, new_instruction: &Instructions) {
906 let ins = &mut self.scopes[self.scope_index].instructions;
907 for i in 0..new_instruction.data.len() {
908 ins.data[pos + i] = new_instruction.data[i];
909 }
910 }
911
912 fn replace_last_pop_with_return(&mut self) {
913 let last_pos = self.scopes[self.scope_index].last_instruction.position;
914 self.replace_instruction(last_pos, &make_instructions(OpReturnValue, &[]));
915 self.scopes[self.scope_index].last_instruction.opcode = OpReturnValue;
916 }
917
918 fn change_operand(&mut self, pos: usize, operand: usize) -> Result<(), CompileError> {
919 if operand > u16::MAX as usize {
922 return Err(format!(
923 "compiled code too large: jump target at byte {} is outside the {}-byte range of a jump operand",
924 operand,
925 u16::MAX
926 ));
927 }
928 let op = Opcode::from_repr(self.current_instruction().data[pos])
929 .expect("compiler emitted an unknown opcode");
930 let ins = make_instructions(op, &[operand]);
931 self.replace_instruction(pos, &ins);
932 Ok(())
933 }
934
935 fn current_instruction(&self) -> &Instructions {
936 return &self.scopes[self.scope_index].instructions;
937 }
938
939 fn current_debug_info(&self) -> &DebugInfo {
940 return &self.scopes[self.scope_index].debug_info;
941 }
942
943 fn function_debug_info_mut(&mut self) -> &mut HashMap<usize, DebugInfo> {
944 return &mut self.function_debug_info;
945 }
946
947 fn add_pc_span(&mut self, pc: usize, span: &Span) {
948 self.scopes[self.scope_index]
949 .debug_info
950 .add_pc_span(pc, span);
951 }
952
953 fn enter_scope(&mut self) {
954 let scope = CompilationScope {
955 instructions: Instructions {
956 data: vec![],
957 },
958 last_instruction: EmittedInstruction {
959 opcode: OpNull,
960 position: 0,
961 },
962 previous_instruction: EmittedInstruction {
963 opcode: OpNull,
964 position: 0,
965 },
966 debug_info: DebugInfo::default(),
967 };
968 self.scopes.push(scope);
969 self.scope_index += 1;
970 self.symbol_table = SymbolTable::new_enclosed_symbol_table(self.symbol_table.clone());
971 }
972
973 fn leave_scope(&mut self) -> ScopedInstructions {
974 let instructions = self.current_instruction().clone();
975 let mut debug_info = self.current_debug_info().clone();
976 debug_info.local_bindings = self
979 .symbol_table
980 .definitions
981 .iter()
982 .map(|symbol| BindingDebugInfo {
983 name: symbol.name.clone(),
984 slot: symbol.index,
985 })
986 .collect();
987 debug_info.free_names = self
988 .symbol_table
989 .free_symbols
990 .iter()
991 .map(|symbol| symbol.name.clone())
992 .collect();
993 self.scopes.pop();
994 self.scope_index -= 1;
995 let s = self.symbol_table.outer.as_ref().unwrap().as_ref().clone();
996 self.symbol_table = s;
997 return ScopedInstructions {
998 instructions,
999 debug_info,
1000 };
1001 }
1002}