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