1use std::sync::Arc;
2
3use crate::{
4 AstNodeArena, ErrorReporter, FunctionHandle, FunctionObject, HeapAllocator, NodeId,
5 QangCompilerError, QangPipelineError, SourceLocation, SourceMap, Value,
6 backend::{
7 chunk::{Chunk, OpCode},
8 module_resolver::ModuleResolver,
9 },
10 frontend::{
11 ast_node_arena::TypedNodeRef,
12 node_visitor::{NodeVisitor, VisitorContext},
13 semantic_validator::FunctionKind,
14 symbol_resolver::{SymbolKind, SymbolTable},
15 },
16 nodes::*,
17};
18
19pub const FRAME_MAX: usize = 256;
20pub const STACK_MAX: usize = FRAME_MAX * 256;
21
22#[derive(Debug, Clone, PartialEq)]
23pub struct QangProgram {
24 function: FunctionHandle,
25 modules: ModuleResolver,
26}
27
28impl QangProgram {
29 pub fn new(handle: FunctionHandle, modules: ModuleResolver) -> Self {
30 Self {
31 function: handle,
32 modules,
33 }
34 }
35
36 pub fn get_handle(&self) -> FunctionHandle {
37 self.function
38 }
39
40 pub fn into_modules(self) -> ModuleResolver {
41 self.modules
42 }
43}
44
45#[derive(Debug, Clone, PartialEq, Default)]
46struct LoopContext {
47 continue_jumps: Vec<usize>,
48 break_jumps: Vec<usize>,
49 node_id: NodeId,
50}
51
52#[derive(Debug, Clone)]
53struct Local {
54 name: crate::StringHandle,
55 depth: Option<usize>,
56 is_captured: bool,
57}
58
59impl Local {
60 fn new(name: crate::StringHandle) -> Self {
61 Self {
62 name,
63 depth: None,
64 is_captured: false,
65 }
66 }
67}
68
69#[derive(Debug, Clone, Copy)]
70struct Upvalue {
71 index: u8,
72 is_local: bool,
73}
74
75#[derive(Debug, Clone)]
76struct State {
77 kind: FunctionKind,
78 locals: Vec<Local>,
79 local_count: usize,
80 scope_depth: usize,
81 upvalues: Vec<Upvalue>,
82 enclosing: Option<Box<State>>,
83 has_superclass: bool,
84 blank_handle: crate::StringHandle,
85 this_handle: crate::StringHandle,
86 source_map: Arc<SourceMap>,
87}
88
89impl State {
90 fn new(
91 blank_handle: crate::StringHandle,
92 this_handle: crate::StringHandle,
93 source_map: Arc<SourceMap>,
94 ) -> Self {
95 let mut locals = Vec::with_capacity(u8::MAX as usize);
96 locals.push(Local::new(blank_handle));
97 Self {
98 kind: FunctionKind::Script,
99 locals,
100 local_count: 1,
101 scope_depth: 0,
102 upvalues: Vec::with_capacity(u8::MAX as usize),
103 enclosing: None,
104 has_superclass: false,
105 blank_handle,
106 this_handle,
107 source_map,
108 }
109 }
110
111 fn push(&mut self, has_superclass: bool, kind: FunctionKind) -> &mut Self {
112 let mut locals = Vec::with_capacity(u8::MAX as usize);
113 let is_method = matches!(kind, FunctionKind::Method | FunctionKind::Initializer);
114 if is_method {
115 let mut this_local = Local::new(self.this_handle);
116 this_local.depth = Some(0);
117 locals.push(this_local);
118 } else {
119 locals.push(Local::new(self.blank_handle));
120 }
121 let previous = std::mem::replace(
122 self,
123 Self {
124 kind,
125 locals,
126 local_count: 1,
127 scope_depth: 0,
128 upvalues: Vec::with_capacity(u8::MAX as usize),
129 enclosing: None,
130 has_superclass,
131 blank_handle: self.blank_handle,
132 this_handle: self.this_handle,
133 source_map: self.source_map.clone(),
134 },
135 );
136
137 self.enclosing = Some(Box::new(previous));
138 self
139 }
140
141 fn pop(&mut self) -> Option<Self> {
142 if let Some(mut previous) = self.enclosing.take() {
143 std::mem::swap(&mut *previous, self);
144 Some(*previous)
145 } else {
146 None
147 }
148 }
149
150 fn resolve_local_variable(
151 &self,
152 handle: crate::StringHandle,
153 span: SourceSpan,
154 ) -> Result<Option<usize>, QangCompilerError> {
155 for i in (0..self.local_count).rev() {
156 if let Some(local) = self.locals.get(i)
157 && local.name == handle
158 {
159 if local.depth.is_none() {
160 return Err(QangCompilerError::new_assembler_error(
161 "Cannot read local variable during its initialization.".to_string(),
162 span,
163 self.source_map.clone(),
164 ));
165 }
166 return Ok(Some(i));
167 }
168 }
169
170 Ok(None)
171 }
172
173 fn resolve_upvalue(
174 &mut self,
175 handle: crate::StringHandle,
176 span: SourceSpan,
177 ) -> Result<Option<usize>, QangCompilerError> {
178 if let Some(enclosing) = self.enclosing.as_mut() {
179 if let Some(local_index) = enclosing.resolve_local_variable(handle, span)? {
180 if let Some(local) = enclosing.locals.get_mut(local_index) {
181 local.is_captured = true;
182 }
183 return self.add_upvalue(local_index, true, span).map(Some);
184 }
185
186 if let Some(upvalue_index) = enclosing.resolve_upvalue(handle, span)? {
187 return self.add_upvalue(upvalue_index, false, span).map(Some);
188 }
189 }
190
191 Ok(None)
192 }
193
194 fn add_upvalue(
195 &mut self,
196 index: usize,
197 is_local: bool,
198 span: SourceSpan,
199 ) -> Result<usize, QangCompilerError> {
200 let upvalue_count = self.upvalues.len();
201
202 for i in 0..upvalue_count {
203 let upvalue = self.upvalues[i];
204 if upvalue.index == index as u8 && upvalue.is_local == is_local {
205 return Ok(i);
206 }
207 }
208
209 if upvalue_count == u8::MAX as usize {
210 return Err(QangCompilerError::new_assembler_error(
211 "Can only close over up to 256 variables.".to_string(),
212 span,
213 self.source_map.clone(),
214 ));
215 }
216
217 self.upvalues.push(Upvalue {
218 index: index as u8,
219 is_local,
220 });
221
222 Ok(upvalue_count)
223 }
224
225 fn is_in_class_method(&self) -> bool {
226 if matches!(self.kind, FunctionKind::Method | FunctionKind::Initializer) {
227 return true;
228 }
229
230 if let Some(ref enclosing) = self.enclosing {
231 return enclosing.is_in_class_method();
232 }
233
234 false
235 }
236
237 fn has_superclass_in_scope(&self) -> bool {
238 if matches!(self.kind, FunctionKind::Method | FunctionKind::Initializer) {
239 return self.has_superclass;
240 }
241
242 if let Some(ref enclosing) = self.enclosing {
243 return enclosing.has_superclass_in_scope();
244 }
245
246 false
247 }
248}
249
250pub struct Assembler<'a> {
251 source_map: Arc<SourceMap>,
252 allocator: &'a mut HeapAllocator,
253 current_function_id: Option<NodeId>,
254 current_function: FunctionObject,
255 loop_contexts: Vec<LoopContext>,
256 compiler_state: State,
257 symbol_table: &'a SymbolTable,
258}
259
260impl<'a> Assembler<'a> {
261 pub fn new(
262 source_map: Arc<SourceMap>,
263 allocator: &'a mut HeapAllocator,
264 symbol_table: &'a SymbolTable,
265 ) -> Self {
266 let handle = allocator.strings.intern("");
267 let blank_handle = allocator.strings.intern("");
268 let this_handle = allocator.strings.intern("this");
269 Self {
270 source_map: source_map.clone(),
271 allocator,
272 current_function: FunctionObject::new(handle, 0),
273 current_function_id: None,
274 loop_contexts: Vec::new(),
275 compiler_state: State::new(blank_handle, this_handle, source_map),
276 symbol_table,
277 }
278 }
279
280 pub fn assemble(
281 mut self,
282 program: NodeId,
283 nodes: &mut AstNodeArena,
284 errors: &mut ErrorReporter,
285 ) -> Result<FunctionObject, QangPipelineError> {
286 let mut ctx = VisitorContext::new(nodes, errors);
287
288 let program_node = ctx.nodes.get_program_node(program);
289
290 self.visit_module(program_node, &mut ctx)
291 .map_err(|err| QangPipelineError::new(vec![err]))?;
292
293 self.emit_opcode(OpCode::Nil, SourceSpan::default());
294 self.emit_opcode(OpCode::ModuleReturn, SourceSpan::default());
295
296 Ok(self.current_function)
297 }
298
299 fn current_chunk_mut(&mut self) -> &mut Chunk {
300 &mut self.current_function.chunk
301 }
302
303 fn emit_opcode(&mut self, opcode: OpCode, span: SourceSpan) {
304 let line = self.source_map.get_line_number(span.start);
305 let col = self.source_map.get_column_number(span.start);
306 self.current_chunk_mut()
307 .write_opcode(opcode, SourceLocation::new(line, col));
308 }
309
310 fn emit_byte(&mut self, byte: u8, span: SourceSpan) {
311 let line = self.source_map.get_line_number(span.start);
312 let col = self.source_map.get_column_number(span.start);
313 self.current_chunk_mut()
314 .write(byte, SourceLocation::new(line, col));
315 }
316
317 fn emit_jump(&mut self, opcode: OpCode, span: SourceSpan) -> usize {
318 self.emit_opcode(opcode, span);
319 self.emit_byte(0xff, span);
320 self.emit_byte(0xff, span);
321 self.current_chunk_mut().code.len() - 2
322 }
323
324 fn patch_jump(&mut self, offset: usize, span: SourceSpan) -> Result<(), QangCompilerError> {
325 let jump = self.current_chunk_mut().code.len() - offset - 2;
326
327 if jump > u16::MAX as usize {
328 return Err(QangCompilerError::new_assembler_error(
329 "Too much code to jump over.".to_string(),
330 span,
331 self.source_map.clone(),
332 ));
333 }
334
335 self.current_chunk_mut().code[offset] = ((jump >> 8) & 0xff) as u8;
336 self.current_chunk_mut().code[offset + 1] = (jump & 0xff) as u8;
337
338 Ok(())
339 }
340
341 fn emit_loop(&mut self, loop_start: usize, span: SourceSpan) -> Result<(), QangCompilerError> {
342 self.emit_opcode(OpCode::Loop, span);
343 let offset = self.current_chunk_mut().code.len() - loop_start + 2;
344 if offset > u16::MAX as usize {
345 return Err(QangCompilerError::new_assembler_error(
346 "Loop body too large.".to_string(),
347 span,
348 self.source_map.clone(),
349 ));
350 }
351
352 self.emit_byte((offset >> 8 & 0xff) as u8, span);
353 self.emit_byte((offset & 0xff) as u8, span);
354
355 Ok(())
356 }
357
358 fn emit_opcode_and_byte(&mut self, opcode: OpCode, byte: u8, span: SourceSpan) {
359 self.emit_opcode(opcode, span);
360 self.emit_byte(byte, span);
361 }
362
363 fn emit_constant(&mut self, value: Value, span: SourceSpan) -> Result<(), QangCompilerError> {
364 let index = self.current_chunk_mut().add_constant(value);
365
366 if index <= u8::MAX as usize {
367 self.emit_opcode_and_byte(OpCode::Constant, index as u8, span);
368 } else if index <= u16::MAX as usize {
369 self.emit_opcode(OpCode::Constant16, span);
370 self.emit_byte((index >> 8) as u8, span);
371 self.emit_byte((index & 0xff) as u8, span);
372 } else {
373 return Err(QangCompilerError::new_assembler_error(
374 "Too many constants in function".to_string(),
375 span,
376 self.source_map.clone(),
377 ));
378 }
379
380 Ok(())
381 }
382
383 fn emit_constant_opcode(
384 &mut self,
385 opcode_8: OpCode,
386 opcode_16: OpCode,
387 value: Value,
388 span: SourceSpan,
389 ) -> Result<(), QangCompilerError> {
390 let index = self.current_chunk_mut().add_constant(value);
391
392 if index <= u8::MAX as usize {
393 self.emit_opcode_and_byte(opcode_8, index as u8, span);
394 } else if index <= u16::MAX as usize {
395 self.emit_opcode(opcode_16, span);
396 self.emit_byte((index >> 8) as u8, span);
397 self.emit_byte((index & 0xff) as u8, span);
398 } else {
399 return Err(QangCompilerError::new_assembler_error(
400 "Too many constants in function (max 65536)".to_string(),
401 span,
402 self.source_map.clone(),
403 ));
404 }
405
406 Ok(())
407 }
408
409 fn begin_scope(&mut self) {
410 self.compiler_state.scope_depth += 1;
411 }
412
413 fn end_scope(&mut self, span: SourceSpan) {
414 let current = &mut self.compiler_state;
415 current.scope_depth -= 1;
416
417 let mut instructions = Vec::new();
418
419 for i in (0..current.local_count).rev() {
420 if let Some(local) = current.locals.get(i) {
421 if let Some(depth) = local.depth {
422 if depth > current.scope_depth {
423 let instruction = if local.is_captured {
424 OpCode::CloseUpvalue
425 } else {
426 OpCode::Pop
427 };
428 instructions.push(instruction);
429 } else {
430 break;
431 }
432 } else {
433 break;
434 }
435 } else {
436 break;
437 }
438 }
439
440 current.local_count -= instructions.len();
441
442 for instruction in instructions {
443 self.emit_opcode(instruction, span);
444 }
445 }
446
447 fn add_local(
448 &mut self,
449 handle: crate::StringHandle,
450 span: SourceSpan,
451 ) -> Result<(), QangCompilerError> {
452 let current = &mut self.compiler_state;
453 if current.local_count >= STACK_MAX {
454 Err(QangCompilerError::new_assembler_error(
455 "Too many local variables in scope.".to_string(),
456 span,
457 self.source_map.clone(),
458 ))
459 } else {
460 let local = Local::new(handle);
461 if current.local_count < current.locals.len() {
462 current.locals[current.local_count] = local;
463 } else {
464 current.locals.push(local);
465 }
466 current.local_count += 1;
467 Ok(())
468 }
469 }
470
471 fn declare_variable(
472 &mut self,
473 handle: crate::StringHandle,
474 span: SourceSpan,
475 ) -> Result<(), QangCompilerError> {
476 let current = &self.compiler_state;
477 if current.scope_depth == 0 {
478 return Ok(());
479 }
480 for i in (0..current.local_count).rev() {
481 if let Some(local) = current.locals.get(i) {
482 if local
483 .depth
484 .map(|local_depth| local_depth < current.scope_depth)
485 .unwrap_or(false)
486 {
487 break;
488 }
489
490 if local.name == handle {
491 return Err(QangCompilerError::new_assembler_error(
492 "Already a variable with this name in this scope.".to_string(),
493 span,
494 self.source_map.clone(),
495 ));
496 }
497 }
498 }
499
500 self.add_local(handle, span)?;
501 Ok(())
502 }
503
504 fn define_variable(
505 &mut self,
506 handle: Option<crate::StringHandle>,
507 span: SourceSpan,
508 ) -> Result<(), QangCompilerError> {
509 if self.compiler_state.scope_depth > 0 {
510 self.mark_initialized();
511 return Ok(());
512 }
513 let handle = handle.expect("Expected an object handle when defining global variables.");
514
515 self.emit_constant_opcode(
516 OpCode::DefineGlobal,
517 OpCode::DefineGlobal16,
518 Value::string(handle),
519 span,
520 )?;
521
522 Ok(())
523 }
524
525 fn mark_initialized(&mut self) {
526 let current = &mut self.compiler_state;
527 if current.scope_depth == 0 {
528 return;
529 }
530 if current.local_count > 0
531 && let Some(local) = current.locals.get_mut(current.local_count - 1)
532 {
533 local.depth = Some(current.scope_depth)
534 }
535 }
536
537 fn parse_variable(
538 &mut self,
539 identifier: crate::StringHandle,
540 span: SourceSpan,
541 ) -> Result<bool, QangCompilerError> {
542 self.declare_variable(identifier, span)?;
543
544 if self.compiler_state.scope_depth > 0 {
545 Ok(true)
546 } else {
547 Ok(false)
548 }
549 }
550
551 fn handle_variable(
552 &mut self,
553 handle: crate::StringHandle,
554 span: SourceSpan,
555 is_assignment: bool,
556 ) -> Result<(), QangCompilerError> {
557 let (index, get_op, set_op) = {
558 if let Some(index) = self.resolve_local_variable(handle, span)? {
559 (index as u8, OpCode::GetLocal, OpCode::SetLocal)
560 } else if let Some(index) = self.resolve_upvalue(handle, span)? {
561 (index as u8, OpCode::GetUpvalue, OpCode::SetUpvalue)
562 } else {
563 let index = self.current_chunk_mut().add_constant(Value::string(handle));
564 if index <= u8::MAX as usize {
565 (index as u8, OpCode::GetGlobal, OpCode::SetGlobal)
566 } else {
567 return self.emit_global_variable_access(handle, is_assignment, span);
568 }
569 }
570 };
571
572 let op = if is_assignment { set_op } else { get_op };
573 self.emit_opcode_and_byte(op, index, span);
574
575 Ok(())
576 }
577
578 fn resolve_upvalue(
579 &mut self,
580 name: crate::StringHandle,
581 span: SourceSpan,
582 ) -> Result<Option<usize>, QangCompilerError> {
583 self.compiler_state.resolve_upvalue(name, span)
584 }
585
586 fn resolve_local_variable(
587 &self,
588 handle: crate::StringHandle,
589 span: SourceSpan,
590 ) -> Result<Option<usize>, QangCompilerError> {
591 self.compiler_state.resolve_local_variable(handle, span)
592 }
593
594 fn emit_return(&mut self, span: SourceSpan) {
595 let is_init = matches!(self.compiler_state.kind, FunctionKind::Initializer);
596 if is_init {
597 self.emit_opcode_and_byte(OpCode::GetLocal, 0, span);
598 } else {
599 self.emit_opcode(OpCode::Nil, span);
600 }
601 self.emit_opcode(OpCode::Return, span);
602 }
603
604 fn emit_variable_access(
605 &mut self,
606 node_id: NodeId,
607 span: SourceSpan,
608 is_assignment: bool,
609 ctx: &VisitorContext,
610 ) -> Result<(), QangCompilerError> {
611 let variable_name = match ctx.nodes.get_node(node_id) {
612 AstNode::Identifier(identifier) => identifier.name,
613 AstNode::SuperExpr(_) => self.allocator.strings.intern("super"),
614 _ => {
615 return Err(QangCompilerError::new_assembler_error(
616 format!(
617 "Unexpected node type for variable access: {:?}",
618 ctx.nodes.get_node(node_id),
619 ),
620 span,
621 self.source_map.clone(),
622 ));
623 }
624 };
625
626 self.handle_variable(variable_name, span, is_assignment)
627 }
628
629 fn emit_global_variable_access(
630 &mut self,
631 handle: crate::StringHandle,
632 is_assignment: bool,
633 span: SourceSpan,
634 ) -> Result<(), QangCompilerError> {
635 if is_assignment {
636 self.emit_constant_opcode(
637 OpCode::SetGlobal,
638 OpCode::SetGlobal16,
639 Value::string(handle),
640 span,
641 )
642 } else {
643 self.emit_constant_opcode(
644 OpCode::GetGlobal,
645 OpCode::GetGlobal16,
646 Value::string(handle),
647 span,
648 )
649 }
650 }
651
652 fn compile_function(
653 &mut self,
654 func_node_id: NodeId,
655 func_expr: FunctionExprNode,
656 ctx: &mut VisitorContext,
657 ) -> Result<(), QangCompilerError> {
658 self.compile_function_with_superclass(
659 func_node_id,
660 func_expr,
661 ctx,
662 false,
663 FunctionKind::Function,
664 )
665 }
666
667 fn compile_function_with_superclass(
668 &mut self,
669 func_node_id: NodeId,
670 func_expr: FunctionExprNode,
671 ctx: &mut VisitorContext,
672 has_superclass: bool,
673 func_kind: FunctionKind,
674 ) -> Result<(), QangCompilerError> {
675 let func_arity = ctx.nodes.array.size(func_expr.parameters);
676
677 let identifier = ctx.nodes.get_identifier_node(func_expr.name).node;
678 let function = FunctionObject::new(identifier.name, func_arity);
679
680 let old_function = std::mem::replace(&mut self.current_function, function);
681
682 let old_loop_contexts = std::mem::take(&mut self.loop_contexts);
683
684 let old_func_id = self.current_function_id;
685 self.current_function_id = Some(func_node_id);
686
687 self.compiler_state.push(has_superclass, func_kind);
688 self.begin_scope();
689
690 let param_count = ctx.nodes.array.size(func_expr.parameters);
691 for i in 0..param_count {
692 if let Some(param_id) = ctx.nodes.array.get_node_id_at(func_expr.parameters, i) {
693 let param = ctx.nodes.get_identifier_node(param_id);
694 let is_local = self.parse_variable(param.node.name, param.node.span)?;
695 self.define_variable(
696 if is_local {
697 None
698 } else {
699 Some(param.node.name)
700 },
701 param.node.span,
702 )?;
703 }
704 }
705
706 let body_node = ctx.nodes.get_block_stmt_node(func_expr.body);
707 self.visit_block_statement(body_node, ctx)?;
708
709 self.emit_return(func_expr.span);
710
711 let old_state = self
712 .compiler_state
713 .pop()
714 .expect("Function state should exist");
715
716 let mut compiled_function = std::mem::replace(&mut self.current_function, old_function);
717 compiled_function.upvalue_count = old_state.upvalues.len();
718
719 self.loop_contexts = old_loop_contexts;
720
721 self.current_function_id = old_func_id;
722
723 let function_handle = self.allocator.allocate_function(compiled_function);
724 self.emit_constant_opcode(
725 OpCode::Closure,
726 OpCode::Closure16,
727 Value::function(function_handle),
728 func_expr.span,
729 )?;
730
731 for upvalue in &old_state.upvalues {
732 let is_local_byte = if upvalue.is_local { 1 } else { 0 };
733 self.emit_byte(is_local_byte, func_expr.span);
734 self.emit_byte(upvalue.index, func_expr.span);
735 }
736
737 Ok(())
738 }
739
740 fn emit_compound_assignment_op(
741 &mut self,
742 operator: AssignmentOperator,
743 span: SourceSpan,
744 ) -> Result<(), QangCompilerError> {
745 let opcode = match operator {
746 AssignmentOperator::Assign => unreachable!(),
747 AssignmentOperator::AddAssign => OpCode::Add,
748 AssignmentOperator::SubtractAssign => OpCode::Subtract,
749 AssignmentOperator::MultiplyAssign => OpCode::Multiply,
750 AssignmentOperator::DivideAssign => OpCode::Divide,
751 AssignmentOperator::ModuloAssign => OpCode::Modulo,
752 };
753
754 self.emit_opcode(opcode, span);
755 Ok(())
756 }
757
758 fn handle_map_expression(
759 &mut self,
760 callee: TypedNodeRef<ExprNode>,
761 map_expr: MapExprNode,
762 map_node_id: NodeId,
763 ctx: &mut VisitorContext,
764 ) -> Result<(), QangCompilerError> {
765 self.compile_map_expression(map_node_id, map_expr, ctx)?;
766
767 self.visit_expression(callee, ctx)?;
768
769 self.emit_opcode_and_byte(OpCode::Call, 1, map_expr.span);
770 Ok(())
771 }
772
773 fn compile_map_expression(
774 &mut self,
775 map_node_id: NodeId,
776 map_expr: MapExprNode,
777 ctx: &mut VisitorContext,
778 ) -> Result<(), QangCompilerError> {
779 let map_name_handle = self.allocator.strings.intern("<map>");
780 let func_arity = 1;
781
782 let function = FunctionObject::new(map_name_handle, func_arity);
783
784 let old_function = std::mem::replace(&mut self.current_function, function);
785
786 let old_loop_contexts = std::mem::take(&mut self.loop_contexts);
787
788 let old_func_id = self.current_function_id;
789 self.current_function_id = Some(map_node_id);
790
791 self.compiler_state.push(false, FunctionKind::Function);
792 self.begin_scope();
793
794 let param_identifier = ctx.nodes.get_identifier_node(map_expr.parameter);
795 let param_handle = param_identifier.node.name;
796 let is_local = self.parse_variable(param_handle, param_identifier.node.span)?;
797 self.define_variable(
798 if is_local { None } else { Some(param_handle) },
799 param_identifier.node.span,
800 )?;
801
802 let return_node = ReturnStmtNode {
803 value: Some(map_expr.body),
804 span: map_expr.span,
805 };
806 self.visit_return_statement(TypedNodeRef::new(map_expr.body, return_node), ctx)?;
807
808 self.end_scope(map_expr.span);
809 let old_state = self
810 .compiler_state
811 .pop()
812 .expect("Map expression state should exist");
813
814 let mut compiled_function = std::mem::replace(&mut self.current_function, old_function);
815 compiled_function.upvalue_count = old_state.upvalues.len();
816
817 self.loop_contexts = old_loop_contexts;
818
819 self.current_function_id = old_func_id;
820
821 let function_handle = self.allocator.allocate_function(compiled_function);
822 self.emit_constant_opcode(
823 OpCode::Closure,
824 OpCode::Closure16,
825 Value::function(function_handle),
826 map_expr.span,
827 )?;
828
829 for upvalue in &old_state.upvalues {
830 let is_local_byte = if upvalue.is_local { 1 } else { 0 };
831 self.emit_byte(is_local_byte, map_expr.span);
832 self.emit_byte(upvalue.index, map_expr.span);
833 }
834
835 Ok(())
836 }
837
838 fn is_safe_for_tail_call(&self, call_expr: &CallExprNode, ctx: &VisitorContext) -> bool {
839 let callee = ctx.nodes.get_expr_node(call_expr.callee);
840 if let ExprNode::Primary(PrimaryNode::Identifier(_ident_node)) = callee.node {
841 if let Some(symbol_info) = self.symbol_table.resolve(call_expr.callee) {
842 return matches!(symbol_info.kind, SymbolKind::Function);
843 }
844 }
845
846 false
847 }
848}
849
850impl<'a> NodeVisitor for Assembler<'a> {
851 type Error = QangCompilerError;
852
853 fn visit_module(
854 &mut self,
855 program: TypedNodeRef<Module>,
856 ctx: &mut VisitorContext,
857 ) -> Result<(), Self::Error> {
858 let length = ctx.nodes.array.size(program.node.decls);
859
860 for i in 0..length {
861 if let Some(node_id) = ctx.nodes.array.get_node_id_at(program.node.decls, i) {
862 let decl_node = ctx.nodes.get_decl_node(node_id);
863
864 match decl_node.node {
865 DeclNode::Function(func_decl) => self.visit_function_declaration(
866 TypedNodeRef::new(decl_node.id, func_decl),
867 ctx,
868 )?,
869 DeclNode::Class(class_decl) => {
870 self.visit_class_declaration(
871 TypedNodeRef::new(decl_node.id, class_decl),
872 ctx,
873 )?;
874 }
875 _ => {}
876 }
877 }
878 }
879
880 for i in 0..length {
881 if let Some(node_id) = ctx.nodes.array.get_node_id_at(program.node.decls, i) {
882 let decl_node = ctx.nodes.get_decl_node(node_id);
883
884 if !matches!(decl_node.node, DeclNode::Function(_) | DeclNode::Class(_)) {
885 self.visit_declaration(decl_node, ctx)?;
886 }
887 }
888 }
889
890 Ok(())
891 }
892
893 fn visit_return_statement(
894 &mut self,
895 return_stmt: TypedNodeRef<ReturnStmtNode>,
896 ctx: &mut VisitorContext,
897 ) -> Result<(), Self::Error> {
898 if let Some(expr) = return_stmt.node.value {
899 let expr_node = ctx.nodes.get_expr_node(expr);
900
901 if let ExprNode::Call(call_expr) = expr_node.node {
902 let call_operation = ctx.nodes.get_call_operation_node(call_expr.operation);
903
904 if let CallOperationNode::Call(args) = call_operation.node {
905 if self.is_safe_for_tail_call(&call_expr, ctx) {
906 let arg_length = ctx.nodes.array.size(args.args);
907
908 if arg_length > u8::MAX as usize {
909 return Err(QangCompilerError::new_assembler_error(
910 "Functions may only take up to 256 arguments.".to_string(),
911 call_expr.span,
912 self.source_map.clone(),
913 ));
914 }
915
916 let callee = ctx.nodes.get_expr_node(call_expr.callee);
917 self.visit_expression(callee, ctx)?;
918
919 for i in 0..arg_length {
920 if let Some(arg_id) = ctx.nodes.array.get_node_id_at(args.args, i) {
921 let arg = ctx.nodes.get_expr_node(arg_id);
922 self.visit_expression(arg, ctx)?;
923 }
924 }
925
926 self.emit_opcode_and_byte(
927 OpCode::TailCall,
928 arg_length as u8,
929 call_expr.span,
930 );
931 return Ok(());
932 }
933 }
934 }
935
936 self.visit_expression(expr_node, ctx)?;
938 } else {
939 let is_init = matches!(self.compiler_state.kind, FunctionKind::Initializer);
940
941 if is_init {
942 self.emit_opcode_and_byte(OpCode::GetLocal, 0, return_stmt.node.span);
943 } else {
944 self.emit_opcode(OpCode::Nil, return_stmt.node.span);
945 }
946 }
947
948 self.emit_opcode(OpCode::Return, return_stmt.node.span);
949 Ok(())
950 }
951
952 fn visit_number_literal(
953 &mut self,
954 number: TypedNodeRef<NumberLiteralNode>,
955 _ctx: &mut VisitorContext,
956 ) -> Result<(), Self::Error> {
957 self.emit_constant(number.node.value.into(), number.node.span)
958 }
959
960 fn visit_string_literal(
961 &mut self,
962 string: TypedNodeRef<StringLiteralNode>,
963 _ctx: &mut VisitorContext,
964 ) -> Result<(), Self::Error> {
965 self.emit_constant(Value::string(string.node.value), string.node.span)
966 }
967
968 fn visit_boolean_literal(
969 &mut self,
970 boolean: TypedNodeRef<BooleanLiteralNode>,
971 _ctx: &mut VisitorContext,
972 ) -> Result<(), Self::Error> {
973 self.emit_opcode(boolean.node.value.into(), boolean.node.span);
974 Ok(())
975 }
976
977 fn visit_nil_literal(
978 &mut self,
979 nil: TypedNodeRef<NilLiteralNode>,
980 _ctx: &mut VisitorContext,
981 ) -> Result<(), Self::Error> {
982 self.emit_opcode(OpCode::Nil, nil.node.span);
983 Ok(())
984 }
985
986 fn visit_this_expression(
987 &mut self,
988 this_expr: TypedNodeRef<ThisExprNode>,
989 _ctx: &mut VisitorContext,
990 ) -> Result<(), Self::Error> {
991 if !self.compiler_state.is_in_class_method() {
992 return Err(QangCompilerError::new_assembler_error(
993 "Cannot use 'this' outside of a class method.".to_string(),
994 this_expr.node.span,
995 self.source_map.clone(),
996 ));
997 }
998
999 if matches!(
1000 self.compiler_state.kind,
1001 FunctionKind::Method | FunctionKind::Initializer
1002 ) {
1003 self.emit_opcode_and_byte(OpCode::GetLocal, 0, this_expr.node.span);
1004 } else {
1005 let this_handle = self.compiler_state.this_handle;
1006 self.handle_variable(this_handle, this_expr.node.span, false)?;
1007 }
1008 Ok(())
1009 }
1010
1011 fn visit_super_expression(
1012 &mut self,
1013 super_expr: TypedNodeRef<SuperExprNode>,
1014 ctx: &mut VisitorContext,
1015 ) -> Result<(), Self::Error> {
1016 if !self.compiler_state.is_in_class_method() {
1017 return Err(QangCompilerError::new_assembler_error(
1018 "Cannot use 'super' outside of a class method.".to_string(),
1019 super_expr.node.span,
1020 self.source_map.clone(),
1021 ));
1022 }
1023
1024 if !self.compiler_state.has_superclass_in_scope() {
1025 return Err(QangCompilerError::new_assembler_error(
1026 "Can't use 'super' in a class with no superclass.".to_string(),
1027 super_expr.node.span,
1028 self.source_map.clone(),
1029 ));
1030 }
1031
1032 if matches!(
1033 self.compiler_state.kind,
1034 FunctionKind::Method | FunctionKind::Initializer
1035 ) {
1036 self.emit_opcode_and_byte(OpCode::GetLocal, 0, super_expr.node.span);
1037 } else {
1038 let this_handle = self.compiler_state.this_handle;
1039 self.handle_variable(this_handle, super_expr.node.span, false)?;
1040 }
1041
1042 self.emit_variable_access(super_expr.id, super_expr.node.span, false, ctx)?;
1043
1044 let method_identifier = ctx.nodes.get_identifier_node(super_expr.node.method);
1045 self.emit_constant_opcode(
1046 OpCode::GetSuper,
1047 OpCode::GetSuper16,
1048 Value::string(method_identifier.node.name),
1049 super_expr.node.span,
1050 )?;
1051
1052 Ok(())
1053 }
1054
1055 fn visit_comparison_expression(
1056 &mut self,
1057 comparison: TypedNodeRef<ComparisonExprNode>,
1058 ctx: &mut VisitorContext,
1059 ) -> Result<(), Self::Error> {
1060 let left = ctx.nodes.get_expr_node(comparison.node.left);
1061 self.visit_expression(left, ctx)?;
1062 let right = ctx.nodes.get_expr_node(comparison.node.right);
1063 self.visit_expression(right, ctx)?;
1064 self.emit_opcode(comparison.node.operator.into(), comparison.node.span);
1065 Ok(())
1066 }
1067
1068 fn visit_equality_expression(
1069 &mut self,
1070 equality: TypedNodeRef<EqualityExprNode>,
1071 ctx: &mut VisitorContext,
1072 ) -> Result<(), Self::Error> {
1073 let left = ctx.nodes.get_expr_node(equality.node.left);
1074 self.visit_expression(left, ctx)?;
1075 let right = ctx.nodes.get_expr_node(equality.node.right);
1076 self.visit_expression(right, ctx)?;
1077 self.emit_opcode(equality.node.operator.into(), equality.node.span);
1078
1079 if let EqualityOperator::NotEqual = equality.node.operator {
1080 self.emit_opcode(OpCode::Not, equality.node.span);
1081 }
1082 Ok(())
1083 }
1084
1085 fn visit_term_expression(
1086 &mut self,
1087 term: TypedNodeRef<TermExprNode>,
1088 ctx: &mut VisitorContext,
1089 ) -> Result<(), Self::Error> {
1090 let left = ctx.nodes.get_expr_node(term.node.left);
1091 self.visit_expression(left, ctx)?;
1092 let right = ctx.nodes.get_expr_node(term.node.right);
1093 self.visit_expression(right, ctx)?;
1094 self.emit_opcode(term.node.operator.into(), term.node.span);
1095 Ok(())
1096 }
1097
1098 fn visit_factor_expression(
1099 &mut self,
1100 factor: TypedNodeRef<FactorExprNode>,
1101 ctx: &mut VisitorContext,
1102 ) -> Result<(), Self::Error> {
1103 let left = ctx.nodes.get_expr_node(factor.node.left);
1104 self.visit_expression(left, ctx)?;
1105 let right = ctx.nodes.get_expr_node(factor.node.right);
1106 self.visit_expression(right, ctx)?;
1107 self.emit_opcode(factor.node.operator.into(), factor.node.span);
1108 Ok(())
1109 }
1110
1111 fn visit_unary_expression(
1112 &mut self,
1113 unary: TypedNodeRef<UnaryExprNode>,
1114 ctx: &mut VisitorContext,
1115 ) -> Result<(), Self::Error> {
1116 let operand = ctx.nodes.get_expr_node(unary.node.operand);
1117 self.visit_expression(operand, ctx)?;
1118 self.emit_opcode(unary.node.operator.into(), unary.node.span);
1119 Ok(())
1120 }
1121
1122 fn visit_assignment_expression(
1123 &mut self,
1124 assignment: TypedNodeRef<AssignmentExprNode>,
1125 ctx: &mut VisitorContext,
1126 ) -> Result<(), Self::Error> {
1127 let assignment_target = ctx.nodes.get_assignment_target_node(assignment.node.target);
1128 let value = ctx.nodes.get_expr_node(assignment.node.value);
1129
1130 match assignment.node.operator {
1131 AssignmentOperator::Assign => match assignment_target.node {
1132 AssignmentTargetNode::Identifier(identifier) => {
1133 self.visit_expression(value, ctx)?;
1134 self.emit_variable_access(assignment_target.id, identifier.span, true, ctx)?;
1135 }
1136 AssignmentTargetNode::Property(property) => {
1137 self.visit_expression(ctx.nodes.get_expr_node(property.object), ctx)?;
1138 self.visit_expression(value, ctx)?;
1139 let identifier_handle =
1140 ctx.nodes.get_identifier_node(property.property).node.name;
1141 self.emit_constant_opcode(
1142 OpCode::SetProperty,
1143 OpCode::SetProperty16,
1144 Value::string(identifier_handle),
1145 property.span,
1146 )?;
1147 }
1148 AssignmentTargetNode::Index(index) => {
1149 let array = ctx.nodes.get_expr_node(index.object);
1150 self.visit_expression(array, ctx)?;
1151 let index_expr = ctx.nodes.get_expr_node(index.index);
1152 self.visit_expression(index_expr, ctx)?;
1153 self.visit_expression(value, ctx)?;
1154 self.emit_opcode(OpCode::SetArrayIndex, index.span);
1155 }
1156 },
1157 _ => match assignment_target.node {
1158 AssignmentTargetNode::Identifier(identifier) => {
1159 self.emit_variable_access(assignment_target.id, identifier.span, false, ctx)?;
1160 self.visit_expression(value, ctx)?;
1161 self.emit_compound_assignment_op(
1162 assignment.node.operator,
1163 assignment.node.span,
1164 )?;
1165 self.emit_variable_access(assignment_target.id, identifier.span, true, ctx)?;
1166 }
1167 AssignmentTargetNode::Property(property) => {
1168 let property_object = ctx.nodes.get_expr_node(property.object);
1169 self.visit_expression(property_object, ctx)?;
1170 self.visit_expression(property_object, ctx)?;
1171 let identifier_handle =
1172 ctx.nodes.get_identifier_node(property.property).node.name;
1173 self.emit_constant_opcode(
1174 OpCode::GetProperty,
1175 OpCode::GetProperty16,
1176 Value::string(identifier_handle),
1177 property.span,
1178 )?;
1179
1180 self.visit_expression(value, ctx)?;
1181 self.emit_compound_assignment_op(
1182 assignment.node.operator,
1183 assignment.node.span,
1184 )?;
1185
1186 self.emit_constant_opcode(
1187 OpCode::SetProperty,
1188 OpCode::SetProperty16,
1189 Value::string(identifier_handle),
1190 property.span,
1191 )?;
1192 }
1193 AssignmentTargetNode::Index(index_node) => {
1194 let array = ctx.nodes.get_expr_node(index_node.object);
1195 let index = ctx.nodes.get_expr_node(index_node.index);
1196
1197 self.visit_expression(array, ctx)?;
1198 self.visit_expression(index, ctx)?;
1199
1200 self.visit_expression(array, ctx)?;
1201 self.visit_expression(index, ctx)?;
1202
1203 self.emit_opcode(OpCode::GetArrayIndex, index.node.span());
1204
1205 self.visit_expression(value, ctx)?;
1206
1207 self.emit_compound_assignment_op(
1208 assignment.node.operator,
1209 assignment.node.span,
1210 )?;
1211
1212 self.emit_opcode(OpCode::SetArrayIndex, index_node.span);
1213 }
1214 },
1215 }
1216
1217 Ok(())
1218 }
1219
1220 fn visit_expression_statement(
1221 &mut self,
1222 expr_stmt: TypedNodeRef<ExprStmtNode>,
1223 ctx: &mut VisitorContext,
1224 ) -> Result<(), Self::Error> {
1225 let expr_node = ctx.nodes.get_expr_node(expr_stmt.node.expr);
1226 self.visit_expression(expr_node, ctx)?;
1227 self.emit_opcode(OpCode::Pop, expr_stmt.node.span);
1228 Ok(())
1229 }
1230
1231 fn visit_variable_declaration(
1232 &mut self,
1233 var_decl: TypedNodeRef<VariableDeclNode>,
1234 ctx: &mut VisitorContext,
1235 ) -> Result<(), Self::Error> {
1236 let identifier = ctx.nodes.get_identifier_node(var_decl.node.target);
1237
1238 let is_local = self.parse_variable(identifier.node.name, identifier.node.span)?;
1239
1240 if let Some(expr) = var_decl
1241 .node
1242 .initializer
1243 .map(|id| ctx.nodes.get_expr_node(id))
1244 {
1245 self.visit_expression(expr, ctx)?;
1246 } else {
1247 self.emit_opcode(OpCode::Nil, var_decl.node.span);
1248 }
1249
1250 if is_local {
1251 self.define_variable(None, var_decl.node.span)?;
1252 } else {
1253 self.define_variable(Some(identifier.node.name), var_decl.node.span)?;
1254 }
1255
1256 Ok(())
1257 }
1258
1259 fn visit_import_module_declaration(
1260 &mut self,
1261 import_decl: TypedNodeRef<ImportModuleDeclNode>,
1262 ctx: &mut VisitorContext,
1263 ) -> Result<(), Self::Error> {
1264 let identifier = ctx.nodes.get_identifier_node(import_decl.node.name);
1265
1266 let is_local = self.parse_variable(identifier.node.name, identifier.node.span)?;
1267
1268 self.emit_constant_opcode(
1269 OpCode::Module,
1270 OpCode::Module16,
1271 Value::string(import_decl.node.path),
1272 import_decl.node.span,
1273 )?;
1274
1275 if is_local {
1276 self.define_variable(None, import_decl.node.span)?;
1277 } else {
1278 self.define_variable(Some(identifier.node.name), import_decl.node.span)?;
1279 }
1280
1281 Ok(())
1282 }
1283
1284 fn visit_identifier(
1285 &mut self,
1286 identifier: TypedNodeRef<IdentifierNode>,
1287 ctx: &mut VisitorContext,
1288 ) -> Result<(), Self::Error> {
1289 self.emit_variable_access(identifier.id, identifier.node.span, false, ctx)
1290 }
1291
1292 fn visit_if_statement(
1293 &mut self,
1294 if_stmt: TypedNodeRef<IfStmtNode>,
1295 ctx: &mut VisitorContext,
1296 ) -> Result<(), Self::Error> {
1297 let condition = ctx.nodes.get_expr_node(if_stmt.node.condition);
1298 self.visit_expression(condition, ctx)?;
1299
1300 let then_stmt = ctx.nodes.get_stmt_node(if_stmt.node.then_branch);
1301 let then_jump = self.emit_jump(OpCode::JumpIfFalse, then_stmt.node.span());
1302 self.emit_opcode(OpCode::Pop, then_stmt.node.span());
1303 self.visit_statement(then_stmt, ctx)?;
1304
1305 let else_jump = self.emit_jump(OpCode::Jump, if_stmt.node.span);
1306 self.patch_jump(then_jump, if_stmt.node.span)?;
1307 self.emit_opcode(OpCode::Pop, if_stmt.node.span);
1308
1309 if let Some(else_branch) = if_stmt.node.else_branch {
1310 let else_branch = ctx.nodes.get_stmt_node(else_branch);
1311 self.visit_statement(else_branch, ctx)?;
1312 }
1313 self.patch_jump(else_jump, if_stmt.node.span)?;
1314
1315 Ok(())
1316 }
1317
1318 fn visit_ternary_expression(
1319 &mut self,
1320 ternary: TypedNodeRef<TernaryExprNode>,
1321 ctx: &mut VisitorContext,
1322 ) -> Result<(), Self::Error> {
1323 let condition = ctx.nodes.get_expr_node(ternary.node.condition);
1324 self.visit_expression(condition, ctx)?;
1325
1326 let then_jump = self.emit_jump(OpCode::JumpIfFalse, ternary.node.span);
1327 self.emit_opcode(OpCode::Pop, ternary.node.span);
1328
1329 let then_expr = ctx.nodes.get_expr_node(ternary.node.then_expr);
1330 self.visit_expression(then_expr, ctx)?;
1331
1332 let else_jump = self.emit_jump(OpCode::Jump, ternary.node.span);
1333 self.patch_jump(then_jump, ternary.node.span)?;
1334 self.emit_opcode(OpCode::Pop, ternary.node.span);
1335
1336 let else_expr = ctx.nodes.get_expr_node(ternary.node.else_expr);
1337 self.visit_expression(else_expr, ctx)?;
1338
1339 self.patch_jump(else_jump, ternary.node.span)?;
1340
1341 Ok(())
1342 }
1343
1344 fn visit_logical_or_expression(
1345 &mut self,
1346 logical_or: TypedNodeRef<LogicalOrExprNode>,
1347 ctx: &mut VisitorContext,
1348 ) -> Result<(), Self::Error> {
1349 let left = ctx.nodes.get_expr_node(logical_or.node.left);
1350 let right = ctx.nodes.get_expr_node(logical_or.node.right);
1351 self.visit_expression(left, ctx)?;
1352
1353 let else_jump = self.emit_jump(OpCode::JumpIfFalse, logical_or.node.span);
1354 let end_jump = self.emit_jump(OpCode::Jump, logical_or.node.span);
1355
1356 self.patch_jump(else_jump, logical_or.node.span)?;
1357 self.emit_opcode(OpCode::Pop, logical_or.node.span);
1358
1359 self.visit_expression(right, ctx)?;
1360 self.patch_jump(end_jump, logical_or.node.span)?;
1361
1362 Ok(())
1363 }
1364
1365 fn visit_logical_and_expression(
1366 &mut self,
1367 logical_and: TypedNodeRef<LogicalAndExprNode>,
1368 ctx: &mut VisitorContext,
1369 ) -> Result<(), Self::Error> {
1370 let left = ctx.nodes.get_expr_node(logical_and.node.left);
1371 let right = ctx.nodes.get_expr_node(logical_and.node.right);
1372 self.visit_expression(left, ctx)?;
1373
1374 let end_jump = self.emit_jump(OpCode::JumpIfFalse, logical_and.node.span);
1375 self.emit_opcode(OpCode::Pop, logical_and.node.span);
1376
1377 self.visit_expression(right, ctx)?;
1378 self.patch_jump(end_jump, logical_and.node.span)?;
1379
1380 Ok(())
1381 }
1382
1383 fn visit_while_statement(
1384 &mut self,
1385 while_stmt: TypedNodeRef<WhileStmtNode>,
1386 ctx: &mut VisitorContext,
1387 ) -> Result<(), Self::Error> {
1388 let mut loop_context = LoopContext {
1389 continue_jumps: Vec::new(),
1390 break_jumps: Vec::new(),
1391 node_id: while_stmt.id,
1392 };
1393 self.loop_contexts.push(loop_context);
1394
1395 let loop_start = self.current_chunk_mut().code.len();
1396 let condition = ctx.nodes.get_expr_node(while_stmt.node.condition);
1397 self.visit_expression(condition, ctx)?;
1398
1399 let body = ctx.nodes.get_stmt_node(while_stmt.node.body);
1400 let exit_jump = self.emit_jump(OpCode::JumpIfFalse, body.node.span());
1401 self.emit_opcode(OpCode::Pop, body.node.span());
1402 self.visit_statement(body, ctx)?;
1403
1404 loop_context = self.loop_contexts.pop().expect("Loop context should exist");
1405
1406 for continue_position in loop_context.continue_jumps {
1407 let jump_distance = continue_position - loop_start + 3;
1408
1409 if jump_distance > u16::MAX as usize {
1410 return Err(QangCompilerError::new_assembler_error(
1411 "Continue jump too large.".to_string(),
1412 while_stmt.node.span,
1413 self.source_map.clone(),
1414 ));
1415 }
1416
1417 let chunk = self.current_chunk_mut();
1418 chunk.code.insert(continue_position, OpCode::Loop as u8);
1419 chunk
1420 .code
1421 .insert(continue_position + 1, ((jump_distance >> 8) & 0xff) as u8);
1422 chunk
1423 .code
1424 .insert(continue_position + 2, (jump_distance & 0xff) as u8);
1425 }
1426
1427 self.emit_loop(loop_start, body.node.span())?;
1428
1429 self.patch_jump(exit_jump, body.node.span())?;
1430 self.emit_opcode(OpCode::Pop, while_stmt.node.span);
1431
1432 for break_jump in loop_context.break_jumps {
1433 self.patch_jump(break_jump, while_stmt.node.span)?;
1434 }
1435
1436 Ok(())
1437 }
1438
1439 fn visit_for_statement(
1440 &mut self,
1441 for_stmt: TypedNodeRef<ForStmtNode>,
1442 ctx: &mut VisitorContext,
1443 ) -> Result<(), Self::Error> {
1444 self.begin_scope();
1445
1446 if let Some(initializer_id) = for_stmt.node.initializer {
1447 let initializer = ctx.nodes.get_for_initializer_node(initializer_id);
1448 match initializer.node {
1449 ForInitializerNode::VarDecl(var_decl) => {
1450 self.visit_variable_declaration(
1451 TypedNodeRef::new(initializer.id, var_decl),
1452 ctx,
1453 )?;
1454 }
1455 ForInitializerNode::Expr(expr) => {
1456 self.visit_expression(TypedNodeRef::new(initializer.id, expr), ctx)?;
1457 self.emit_opcode(OpCode::Pop, expr.span());
1458 }
1459 }
1460 }
1461
1462 let mut loop_start = self.current_chunk_mut().code.len();
1463 let mut exit_jump: Option<usize> = None;
1464 let increment_start: Option<usize>;
1465
1466 let loop_context = LoopContext {
1467 continue_jumps: Vec::new(),
1468 break_jumps: Vec::new(),
1469 node_id: for_stmt.id,
1470 };
1471 self.loop_contexts.push(loop_context);
1472
1473 if let Some(condition_id) = for_stmt.node.condition {
1474 let condition = ctx.nodes.get_expr_node(condition_id);
1475 let condition_jump = self.emit_jump(OpCode::Jump, condition.node.span());
1476 loop_start = self.current_chunk_mut().code.len();
1477
1478 let body = ctx.nodes.get_stmt_node(for_stmt.node.body);
1479 self.visit_statement(body, ctx)?;
1480
1481 increment_start = Some(self.current_chunk_mut().code.len());
1482
1483 if let Some(afterthought_id) = for_stmt.node.afterthought {
1484 let afterthought = ctx.nodes.get_expr_node(afterthought_id);
1485 self.visit_expression(afterthought, ctx)?;
1486 self.emit_opcode(OpCode::Pop, afterthought.node.span());
1487 }
1488
1489 self.patch_jump(condition_jump, condition.node.span())?;
1490 self.visit_expression(condition, ctx)?;
1491 exit_jump = Some(self.emit_jump(OpCode::JumpIfFalse, condition.node.span()));
1492 self.emit_opcode(OpCode::Pop, condition.node.span());
1493 self.emit_loop(loop_start, body.node.span())?;
1494 } else {
1495 let body = ctx.nodes.get_stmt_node(for_stmt.node.body);
1496 self.visit_statement(body, ctx)?;
1497
1498 increment_start = Some(self.current_chunk_mut().code.len());
1499
1500 if let Some(afterthought_id) = for_stmt.node.afterthought {
1501 let afterthought = ctx.nodes.get_expr_node(afterthought_id);
1502 self.visit_expression(afterthought, ctx)?;
1503 self.emit_opcode(OpCode::Pop, afterthought.node.span());
1504 }
1505
1506 self.emit_loop(loop_start, body.node.span())?;
1507 }
1508
1509 let loop_context = self.loop_contexts.pop().expect("Loop context should exist");
1510
1511 let continue_target = increment_start.unwrap_or(loop_start);
1512 for continue_jump in loop_context.continue_jumps {
1513 if continue_target > continue_jump {
1514 let jump_distance = continue_target - continue_jump - 3;
1515 if jump_distance > u16::MAX as usize {
1516 return Err(QangCompilerError::new_assembler_error(
1517 "Continue jump too large.".to_string(),
1518 for_stmt.node.span,
1519 self.source_map.clone(),
1520 ));
1521 }
1522 let chunk = self.current_chunk_mut();
1523 chunk.code[continue_jump + 1] = ((jump_distance >> 8) & 0xff) as u8;
1524 chunk.code[continue_jump + 2] = (jump_distance & 0xff) as u8;
1525 } else {
1526 let jump_distance = continue_jump - continue_target + 2;
1527 if jump_distance > u16::MAX as usize {
1528 return Err(QangCompilerError::new_assembler_error(
1529 "Continue jump too large.".to_string(),
1530 for_stmt.node.span,
1531 self.source_map.clone(),
1532 ));
1533 }
1534 let chunk = self.current_chunk_mut();
1535 chunk.code[continue_jump] = OpCode::Loop as u8;
1536 chunk.code[continue_jump + 1] = ((jump_distance >> 8) & 0xff) as u8;
1537 chunk.code[continue_jump + 2] = (jump_distance & 0xff) as u8;
1538 }
1539 }
1540
1541 if let Some(exit_jump) = exit_jump {
1542 self.patch_jump(exit_jump, for_stmt.node.span)?;
1543 self.emit_opcode(OpCode::Pop, for_stmt.node.span);
1544 }
1545
1546 for break_jump in loop_context.break_jumps {
1547 self.patch_jump(break_jump, for_stmt.node.span)?;
1548 }
1549
1550 self.end_scope(for_stmt.node.span);
1551
1552 Ok(())
1553 }
1554
1555 fn visit_function_declaration(
1556 &mut self,
1557 func_decl: TypedNodeRef<FunctionDeclNode>,
1558 ctx: &mut VisitorContext,
1559 ) -> Result<(), Self::Error> {
1560 let func_expr = ctx.nodes.get_func_expr_node(func_decl.node.function);
1561
1562 let identifier = ctx.nodes.get_identifier_node(func_expr.node.name);
1563 let is_local = self.parse_variable(identifier.node.name, identifier.node.span)?;
1564
1565 self.compile_function(func_decl.node.function, func_expr.node, ctx)?;
1566
1567 self.define_variable(
1568 if is_local {
1569 None
1570 } else {
1571 Some(identifier.node.name)
1572 },
1573 func_decl.node.span,
1574 )?;
1575
1576 Ok(())
1577 }
1578
1579 fn visit_break_statement(
1580 &mut self,
1581 break_stmt: TypedNodeRef<BreakStmtNode>,
1582 _ctx: &mut VisitorContext,
1583 ) -> Result<(), Self::Error> {
1584 if self.loop_contexts.is_empty() {
1585 return Err(QangCompilerError::new_assembler_error(
1586 "'break' can only be used inside loops.".to_string(),
1587 break_stmt.node.span,
1588 self.source_map.clone(),
1589 ));
1590 }
1591
1592 let jump = self.emit_jump(OpCode::Jump, break_stmt.node.span);
1593
1594 if let Some(loop_context) = self.loop_contexts.last_mut() {
1595 loop_context.break_jumps.push(jump);
1596 }
1597
1598 Ok(())
1599 }
1600
1601 fn visit_continue_statement(
1602 &mut self,
1603 continue_stmt: TypedNodeRef<ContinueStmtNode>,
1604 _ctx: &mut VisitorContext,
1605 ) -> Result<(), Self::Error> {
1606 if self.loop_contexts.is_empty() {
1607 return Err(QangCompilerError::new_assembler_error(
1608 "'continue' can only be used inside loops.".to_string(),
1609 continue_stmt.node.span,
1610 self.source_map.clone(),
1611 ));
1612 }
1613
1614 let continue_position = self.current_chunk_mut().code.len();
1615
1616 if let Some(loop_context) = self.loop_contexts.last_mut() {
1617 loop_context.continue_jumps.push(continue_position);
1618 }
1619
1620 Ok(())
1621 }
1622
1623 fn visit_block_statement(
1624 &mut self,
1625 block_stmt: TypedNodeRef<BlockStmtNode>,
1626 ctx: &mut VisitorContext,
1627 ) -> Result<(), Self::Error> {
1628 self.begin_scope();
1629
1630 let length = ctx.nodes.array.size(block_stmt.node.decls);
1631
1632 for i in 0..length {
1633 if let Some(node_id) = ctx.nodes.array.get_node_id_at(block_stmt.node.decls, i) {
1634 let decl = ctx.nodes.get_decl_node(node_id);
1635 self.visit_declaration(decl, ctx)?;
1636 }
1637 }
1638
1639 self.end_scope(block_stmt.node.span);
1640
1641 Ok(())
1642 }
1643
1644 fn visit_lambda_declaration(
1645 &mut self,
1646 lambda_decl: TypedNodeRef<LambdaDeclNode>,
1647 ctx: &mut VisitorContext,
1648 ) -> Result<(), Self::Error> {
1649 let identifier = ctx.nodes.get_identifier_node(lambda_decl.node.name);
1650 let lambda_expr = ctx.nodes.get_lambda_expr_node(lambda_decl.node.lambda);
1651
1652 let is_local = self.parse_variable(identifier.node.name, identifier.node.span)?;
1653
1654 self.visit_lambda_expression(lambda_expr, ctx)?;
1655
1656 self.define_variable(
1657 if is_local {
1658 None
1659 } else {
1660 Some(identifier.node.name)
1661 },
1662 lambda_decl.node.span,
1663 )?;
1664
1665 Ok(())
1666 }
1667
1668 fn visit_lambda_expression(
1669 &mut self,
1670 lambda_expr: TypedNodeRef<LambdaExprNode>,
1671 ctx: &mut VisitorContext,
1672 ) -> Result<(), Self::Error> {
1673 let lambda_name_handle = self.allocator.strings.intern("<anonymous>");
1674 let func_arity = ctx.nodes.array.size(lambda_expr.node.parameters);
1675
1676 let function = FunctionObject::new(lambda_name_handle, func_arity);
1677
1678 let old_function = std::mem::replace(&mut self.current_function, function);
1679
1680 let old_loop_contexts = std::mem::take(&mut self.loop_contexts);
1681
1682 let old_function_id = self.current_function_id;
1683 self.current_function_id = Some(lambda_expr.id);
1684
1685 self.compiler_state.push(false, FunctionKind::Function);
1686 self.begin_scope();
1687
1688 let param_count = ctx.nodes.array.size(lambda_expr.node.parameters);
1689 for i in 0..param_count {
1690 if let Some(param_id) = ctx
1691 .nodes
1692 .array
1693 .get_node_id_at(lambda_expr.node.parameters, i)
1694 {
1695 let param = ctx.nodes.get_identifier_node(param_id);
1696 let is_local = self.parse_variable(param.node.name, param.node.span)?;
1697 self.define_variable(
1698 if is_local {
1699 None
1700 } else {
1701 Some(param.node.name)
1702 },
1703 param.node.span,
1704 )?;
1705 }
1706 }
1707
1708 let lambda_body = ctx.nodes.get_lambda_body_node(lambda_expr.node.body);
1709 match lambda_body.node {
1710 LambdaBodyNode::Block(body) => {
1711 self.visit_block_statement(TypedNodeRef::new(lambda_body.id, body), ctx)?;
1712 self.emit_return(lambda_expr.node.span);
1713 }
1714 LambdaBodyNode::Expr(_) => {
1715 let return_node = ReturnStmtNode {
1716 value: Some(lambda_body.id),
1717 span: lambda_body.node.span(),
1718 };
1719 self.visit_return_statement(TypedNodeRef::new(lambda_body.id, return_node), ctx)?;
1720 }
1721 }
1722
1723 self.end_scope(lambda_expr.node.span);
1724 let old_state = self
1725 .compiler_state
1726 .pop()
1727 .expect("Lambda state should exist");
1728
1729 let mut compiled_function = std::mem::replace(&mut self.current_function, old_function);
1730 compiled_function.upvalue_count = old_state.upvalues.len();
1731
1732 self.loop_contexts = old_loop_contexts;
1733
1734 self.current_function_id = old_function_id;
1735
1736 let function_handle = self.allocator.allocate_function(compiled_function);
1737 self.emit_constant_opcode(
1738 OpCode::Closure,
1739 OpCode::Closure16,
1740 Value::function(function_handle),
1741 lambda_expr.node.span,
1742 )?;
1743
1744 for upvalue in &old_state.upvalues {
1745 let is_local_byte = if upvalue.is_local { 1 } else { 0 };
1746 self.emit_byte(is_local_byte, lambda_expr.node.span);
1747 self.emit_byte(upvalue.index, lambda_expr.node.span);
1748 }
1749
1750 Ok(())
1751 }
1752
1753 fn visit_call_expression(
1754 &mut self,
1755 call: TypedNodeRef<CallExprNode>,
1756 ctx: &mut VisitorContext,
1757 ) -> Result<(), Self::Error> {
1758 let callee = ctx.nodes.get_expr_node(call.node.callee);
1759 let call_operation = ctx.nodes.get_call_operation_node(call.node.operation);
1760
1761 match call_operation.node {
1762 CallOperationNode::Call(args) => {
1763 let arg_length = ctx.nodes.array.size(args.args);
1764 if arg_length > u8::MAX as usize {
1765 return Err(QangCompilerError::new_assembler_error(
1766 "Functions may only take up to 256 arguments.".to_string(),
1767 call.node.span,
1768 self.source_map.clone(),
1769 ));
1770 }
1771
1772 if let ExprNode::Primary(PrimaryNode::Super(super_expr)) = callee.node {
1773 if !matches!(
1774 self.compiler_state.kind,
1775 FunctionKind::Method | FunctionKind::Initializer
1776 ) {
1777 return Err(QangCompilerError::new_assembler_error(
1778 "Cannot use 'super' outside of a class method.".to_string(),
1779 super_expr.span,
1780 self.source_map.clone(),
1781 ));
1782 }
1783
1784 self.emit_opcode_and_byte(OpCode::GetLocal, 0, super_expr.span);
1785
1786 for i in 0..arg_length {
1787 if let Some(node_id) = ctx.nodes.array.get_node_id_at(args.args, i) {
1788 let expr = ctx.nodes.get_expr_node(node_id);
1789 self.visit_expression(expr, ctx)?;
1790 } else {
1791 self.emit_opcode(OpCode::Nil, call.node.span);
1792 }
1793 }
1794
1795 self.emit_variable_access(callee.id, super_expr.span, false, ctx)?;
1796
1797 let method = ctx.nodes.get_identifier_node(super_expr.method);
1798 self.emit_constant_opcode(
1799 OpCode::SuperInvoke,
1800 OpCode::SuperInvoke16,
1801 Value::string(method.node.name),
1802 call.node.span,
1803 )?;
1804 self.emit_byte(arg_length as u8, call.node.span);
1805
1806 return Ok(());
1807 }
1808
1809 if let ExprNode::Call(property_call) = callee.node
1810 && let CallOperationNode::Property(method_name) = ctx
1811 .nodes
1812 .get_call_operation_node(property_call.operation)
1813 .node
1814 {
1815 let expr = ctx.nodes.get_expr_node(property_call.callee);
1816 self.visit_expression(expr, ctx)?;
1817
1818 let method_handle = ctx
1819 .nodes
1820 .get_identifier_node(method_name.identifier)
1821 .node
1822 .name;
1823
1824 for i in 0..arg_length {
1825 if let Some(node_id) = ctx.nodes.array.get_node_id_at(args.args, i) {
1826 let expr = ctx.nodes.get_expr_node(node_id);
1827 self.visit_expression(expr, ctx)?;
1828 } else {
1829 self.emit_opcode(OpCode::Nil, call.node.span);
1830 }
1831 }
1832
1833 self.emit_constant_opcode(
1834 OpCode::Invoke,
1835 OpCode::Invoke16,
1836 Value::string(method_handle),
1837 call.node.span,
1838 )?;
1839 self.emit_byte(arg_length as u8, call.node.span);
1840
1841 return Ok(());
1842 }
1843
1844 self.visit_expression(callee, ctx)?;
1845
1846 for i in 0..arg_length {
1847 if let Some(node_id) = ctx.nodes.array.get_node_id_at(args.args, i) {
1848 let expr = ctx.nodes.get_expr_node(node_id);
1849 self.visit_expression(expr, ctx)?;
1850 } else {
1851 self.emit_opcode(OpCode::Nil, call.node.span);
1852 }
1853 }
1854
1855 self.emit_opcode_and_byte(OpCode::Call, arg_length as u8, call.node.span);
1856 Ok(())
1857 }
1858 CallOperationNode::Property(identifier) => {
1859 self.visit_expression(callee, ctx)?;
1860 let identifier_handle = ctx
1861 .nodes
1862 .get_identifier_node(identifier.identifier)
1863 .node
1864 .name;
1865 self.emit_constant_opcode(
1866 OpCode::GetProperty,
1867 OpCode::GetProperty16,
1868 Value::string(identifier_handle),
1869 call.node.span,
1870 )?;
1871 Ok(())
1872 }
1873 CallOperationNode::Index(expr) => {
1874 self.visit_expression(callee, ctx)?;
1875 let expr = ctx.nodes.get_expr_node(expr.index);
1876 self.visit_expression(expr, ctx)?;
1877 self.emit_opcode(OpCode::GetArrayIndex, call.node.span);
1878 Ok(())
1879 }
1880 CallOperationNode::OptionalProperty(identifier) => {
1881 self.visit_expression(callee, ctx)?;
1882 let identifier_handle = ctx
1883 .nodes
1884 .get_identifier_node(identifier.identifier)
1885 .node
1886 .name;
1887 self.emit_constant_opcode(
1888 OpCode::GetOptionalProperty,
1889 OpCode::GetOptionalProperty16,
1890 Value::string(identifier_handle),
1891 call.node.span,
1892 )?;
1893 Ok(())
1894 }
1895 CallOperationNode::Map(map_expr) => {
1896 self.handle_map_expression(callee, map_expr, call_operation.id, ctx)
1897 }
1898 CallOperationNode::OptionalMap(map_expr) => {
1899 self.visit_expression(callee, ctx)?;
1900 let nil_jump = self.emit_jump(OpCode::JumpIfNil, map_expr.span);
1901 self.emit_opcode(OpCode::Pop, map_expr.span);
1902 self.handle_map_expression(
1903 callee,
1904 MapExprNode {
1905 body: map_expr.body,
1906 parameter: map_expr.parameter,
1907 span: map_expr.span,
1908 },
1909 call_operation.id,
1910 ctx,
1911 )?;
1912 self.patch_jump(nil_jump, map_expr.span)?;
1913 Ok(())
1914 }
1915 }
1916 }
1917
1918 fn visit_pipe_expression(
1919 &mut self,
1920 pipe: TypedNodeRef<PipeExprNode>,
1921 ctx: &mut VisitorContext,
1922 ) -> Result<(), Self::Error> {
1923 let left = ctx.nodes.get_expr_node(pipe.node.left);
1924 let right = ctx.nodes.get_expr_node(pipe.node.right);
1925 let call_handle = self.allocator.strings.intern("call");
1926
1927 match right.node {
1928 ExprNode::Call(call_expr) => {
1929 match ctx.nodes.get_call_operation_node(call_expr.operation).node {
1930 CallOperationNode::Call(arguments) => {
1931 if let ExprNode::Call(inner_call) =
1932 ctx.nodes.get_expr_node(call_expr.callee).node
1933 && let CallOperationNode::Property(method_name) =
1934 ctx.nodes.get_call_operation_node(inner_call.operation).node
1935 && ctx
1936 .nodes
1937 .get_identifier_node(method_name.identifier)
1938 .node
1939 .name
1940 == call_handle
1941 {
1942 self.visit_expression(ctx.nodes.get_expr_node(call_expr.callee), ctx)?;
1943 self.visit_expression(left, ctx)?;
1944 let method_handle = ctx
1945 .nodes
1946 .get_identifier_node(method_name.identifier)
1947 .node
1948 .name;
1949 self.emit_constant_opcode(
1950 OpCode::Invoke,
1951 OpCode::Invoke16,
1952 Value::string(method_handle),
1953 pipe.node.span,
1954 )?;
1955 self.emit_byte(1, pipe.node.span);
1956 return Ok(());
1957 }
1958
1959 self.visit_expression(ctx.nodes.get_expr_node(call_expr.callee), ctx)?;
1960
1961 self.visit_expression(left, ctx)?;
1962
1963 let arg_length = ctx.nodes.array.size(arguments.args);
1964 for i in 0..arg_length {
1965 if let Some(node_id) = ctx.nodes.array.get_node_id_at(arguments.args, i)
1966 {
1967 let expr = ctx.nodes.get_expr_node(node_id);
1968 self.visit_expression(expr, ctx)?;
1969 } else {
1970 self.emit_opcode(OpCode::Nil, pipe.node.span);
1971 }
1972 }
1973
1974 let total_args = 1 + arg_length;
1975 if total_args > u8::MAX as usize {
1976 return Err(QangCompilerError::new_assembler_error(
1977 "Functions may only take up to 256 arguments.".to_string(),
1978 pipe.node.span,
1979 self.source_map.clone(),
1980 ));
1981 }
1982
1983 self.emit_opcode_and_byte(OpCode::Call, total_args as u8, pipe.node.span);
1984 }
1985 CallOperationNode::Property(method_name) => {
1986 self.visit_expression(ctx.nodes.get_expr_node(call_expr.callee), ctx)?;
1987 self.visit_expression(left, ctx)?;
1988 let method_handle = ctx
1989 .nodes
1990 .get_identifier_node(method_name.identifier)
1991 .node
1992 .name;
1993 self.emit_constant_opcode(
1994 OpCode::Invoke,
1995 OpCode::Invoke16,
1996 Value::string(method_handle),
1997 pipe.node.span,
1998 )?;
1999 self.emit_byte(1, pipe.node.span);
2000 }
2001 _ => {
2002 return Err(QangCompilerError::new_assembler_error(
2003 "Pipe expression with non-call operation not supported.".to_string(),
2004 call_expr.span,
2005 self.source_map.clone(),
2006 ));
2007 }
2008 }
2009 }
2010 _ => {
2011 self.visit_expression(right, ctx)?;
2012 self.visit_expression(left, ctx)?;
2013 self.emit_opcode_and_byte(OpCode::Call, 1, pipe.node.span);
2014 }
2015 }
2016
2017 Ok(())
2018 }
2019
2020 fn visit_class_declaration(
2021 &mut self,
2022 class_decl: TypedNodeRef<ClassDeclNode>,
2023 ctx: &mut VisitorContext,
2024 ) -> Result<(), Self::Error> {
2025 let name = ctx.nodes.get_identifier_node(class_decl.node.name);
2026 let superclass = class_decl
2027 .node
2028 .superclass
2029 .map(|superclass| ctx.nodes.get_identifier_node(superclass));
2030
2031 let class_handle = name.node.name;
2032 self.emit_constant_opcode(
2033 OpCode::Class,
2034 OpCode::Class16,
2035 Value::string(class_handle),
2036 name.node.span,
2037 )?;
2038
2039 let is_local = self.parse_variable(class_handle, name.node.span)?;
2040 self.define_variable(
2041 if is_local { None } else { Some(class_handle) },
2042 name.node.span,
2043 )?;
2044
2045 self.handle_variable(class_handle, name.node.span, false)?;
2046
2047 if let Some(superclass) = superclass {
2048 if class_handle == superclass.node.name {
2049 return Err(QangCompilerError::new_assembler_error(
2050 "A class cannot inherit from itself.".to_string(),
2051 superclass.node.span,
2052 self.source_map.clone(),
2053 ));
2054 }
2055
2056 self.begin_scope();
2057
2058 self.handle_variable(class_handle, name.node.span, false)?;
2059
2060 self.handle_variable(superclass.node.name, superclass.node.span, false)?;
2061
2062 let super_handle = self.allocator.strings.intern("super");
2063 self.add_local(super_handle, class_decl.node.span)?;
2064 self.define_variable(None, class_decl.node.span)?;
2065
2066 self.handle_variable(super_handle, superclass.node.span, true)?;
2067
2068 self.emit_opcode(OpCode::Inherit, superclass.node.span);
2069 }
2070
2071 let length = ctx.nodes.array.size(class_decl.node.members);
2072 for i in 0..length {
2073 if let Some(node_id) = ctx.nodes.array.get_node_id_at(class_decl.node.members, i) {
2074 let member = ctx.nodes.get_class_member_node(node_id);
2075
2076 match member.node {
2077 ClassMemberNode::Method(function) => {
2078 let method_name = ctx.nodes.get_identifier_node(function.name);
2079 let init_name = self.allocator.strings.intern("init");
2080 let is_initializer = method_name.node.name == init_name;
2081 let func_kind = if is_initializer {
2082 FunctionKind::Initializer
2083 } else {
2084 FunctionKind::Method
2085 };
2086
2087 let has_superclass = class_decl.node.superclass.is_some();
2088 self.compile_function_with_superclass(
2089 node_id,
2090 function,
2091 ctx,
2092 has_superclass,
2093 func_kind,
2094 )?;
2095
2096 self.emit_constant_opcode(
2097 OpCode::Method,
2098 OpCode::Method16,
2099 Value::string(method_name.node.name),
2100 function.span,
2101 )?;
2102 }
2103 ClassMemberNode::Field(field) => {
2104 let field_name = ctx.nodes.get_identifier_node(field.name);
2105
2106 if let Some(init_id) = field.initializer {
2107 let initializer = ctx.nodes.get_expr_node(init_id);
2108 self.visit_expression(initializer, ctx)?;
2109 } else {
2110 self.emit_opcode(OpCode::Nil, field.span);
2111 }
2112
2113 self.emit_constant_opcode(
2114 OpCode::InitField,
2115 OpCode::InitField16,
2116 Value::string(field_name.node.name),
2117 field_name.node.span,
2118 )?;
2119 }
2120 }
2121 }
2122 }
2123
2124 self.emit_opcode(OpCode::Pop, class_decl.node.span);
2125
2126 if class_decl.node.superclass.is_some() {
2127 self.end_scope(class_decl.node.span);
2128 }
2129
2130 Ok(())
2131 }
2132
2133 fn visit_array_literal(
2134 &mut self,
2135 array: TypedNodeRef<ArrayLiteralExprNode>,
2136 ctx: &mut VisitorContext,
2137 ) -> Result<(), Self::Error> {
2138 let length = ctx.nodes.array.size(array.node.elements);
2139
2140 if length > u8::MAX.into() {
2141 return Err(QangCompilerError::new_assembler_error(
2142 "An array literal cannot be initialized with more than 256 elements.".to_string(),
2143 array.node.span,
2144 self.source_map.clone(),
2145 ));
2146 }
2147
2148 for i in (0..length).rev() {
2149 if let Some(node_id) = ctx.nodes.array.get_node_id_at(array.node.elements, i) {
2150 let expr = ctx.nodes.get_expr_node(node_id);
2151 self.visit_expression(expr, ctx)?;
2152 }
2153 }
2154
2155 self.emit_opcode_and_byte(OpCode::ArrayLiteral, length as u8, array.node.span);
2156
2157 Ok(())
2158 }
2159
2160 fn visit_object_literal(
2161 &mut self,
2162 object: TypedNodeRef<ObjectLiteralExprNode>,
2163 ctx: &mut VisitorContext,
2164 ) -> Result<(), Self::Error> {
2165 let length = ctx.nodes.array.size(object.node.entries);
2166
2167 if length > u8::MAX.into() {
2168 return Err(QangCompilerError::new_assembler_error(
2169 "An object literal cannot be initialized with more than 256 entries.".to_string(),
2170 object.node.span,
2171 self.source_map.clone(),
2172 ));
2173 }
2174
2175 for i in 0..length {
2176 if let Some(node_id) = ctx.nodes.array.get_node_id_at(object.node.entries, i) {
2177 let entry = ctx.nodes.get_obj_entry_node(node_id);
2178 self.visit_object_entry(entry, ctx)?;
2179 }
2180 }
2181
2182 self.emit_opcode_and_byte(OpCode::ObjectLiteral, length as u8, object.node.span);
2183 Ok(())
2184 }
2185
2186 fn visit_object_entry(
2187 &mut self,
2188 entry: TypedNodeRef<ObjectEntryNode>,
2189 ctx: &mut VisitorContext,
2190 ) -> Result<(), Self::Error> {
2191 let identifier_node = ctx.nodes.get_identifier_node(entry.node.key).node;
2192 let identifier_handle = identifier_node.name;
2193 self.emit_constant(Value::string(identifier_handle), identifier_node.span)?;
2194 let value = ctx.nodes.get_expr_node(entry.node.value);
2195 self.visit_expression(value, ctx)?;
2196 Ok(())
2197 }
2198
2199 fn visit_when_expression(
2200 &mut self,
2201 when_expr: TypedNodeRef<WhenExprNode>,
2202 ctx: &mut VisitorContext,
2203 ) -> Result<(), Self::Error> {
2204 let match_value_expr = when_expr.node.value;
2205
2206 let mut end_jumps = Vec::new();
2207
2208 let branch_count = ctx.nodes.array.size(when_expr.node.branches);
2209 for i in 0..branch_count {
2210 if let Some(branch_id) = ctx.nodes.array.get_node_id_at(when_expr.node.branches, i) {
2211 let branch = ctx.nodes.get_when_branch_node(branch_id);
2212
2213 if let Some(value_id) = match_value_expr {
2214 let value = ctx.nodes.get_expr_node(value_id);
2215 self.visit_expression(value, ctx)?;
2216
2217 let condition = ctx.nodes.get_expr_node(branch.node.condition);
2218 self.visit_expression(condition, ctx)?;
2219
2220 if branch.node.is_type_check {
2221 self.emit_opcode(OpCode::Is, branch.node.span);
2222 } else {
2223 self.emit_opcode(OpCode::Equal, branch.node.span);
2224 }
2225 } else {
2226 let condition = ctx.nodes.get_expr_node(branch.node.condition);
2227 self.visit_expression(condition, ctx)?;
2228 }
2229
2230 let false_jump = self.emit_jump(OpCode::JumpIfFalse, branch.node.span);
2231 self.emit_opcode(OpCode::Pop, branch.node.span); let body = ctx.nodes.get_expr_node(branch.node.body);
2234 self.visit_expression(body, ctx)?;
2235
2236 let end_jump = self.emit_jump(OpCode::Jump, branch.node.span);
2237 end_jumps.push(end_jump);
2238
2239 self.patch_jump(false_jump, branch.node.span)?;
2240 self.emit_opcode(OpCode::Pop, branch.node.span); }
2242 }
2243
2244 if let Some(else_branch_id) = when_expr.node.else_branch {
2245 let else_branch = ctx.nodes.get_expr_node(else_branch_id);
2246 self.visit_expression(else_branch, ctx)?;
2247 } else {
2248 self.emit_opcode(OpCode::Nil, when_expr.node.span);
2249 }
2250
2251 for jump in end_jumps {
2252 self.patch_jump(jump, when_expr.node.span)?;
2253 }
2254
2255 Ok(())
2256 }
2257
2258 fn visit_when_branch(
2259 &mut self,
2260 branch: TypedNodeRef<WhenBranchNode>,
2261 ctx: &mut VisitorContext,
2262 ) -> Result<(), Self::Error> {
2263 self.visit_expression(ctx.nodes.get_expr_node(branch.node.condition), ctx)?;
2266 self.visit_expression(ctx.nodes.get_expr_node(branch.node.body), ctx)
2267 }
2268}