Skip to main content

qanglang_core/backend/
assembler.rs

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            // Regular case: emit expression and return
937            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); // Pop the condition result
2232
2233                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); // Pop the condition result
2241            }
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        // This is handled inline in visit_when_expression for better control
2264        // over jump patching and stack management
2265        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}