goscript_codegen/
codegen.rs

1use std::collections::HashMap;
2use std::convert::TryFrom;
3use std::rc::Rc;
4
5use super::branch::*;
6use super::emit::*;
7use super::interface::IfaceMapping;
8use super::package::PkgUtil;
9use super::types::{TypeCache, TypeLookup};
10
11use goscript_vm::gc::GcoVec;
12use goscript_vm::instruction::*;
13use goscript_vm::metadata::*;
14use goscript_vm::objects::EntIndex;
15use goscript_vm::value::*;
16use goscript_vm::zero_val;
17
18use goscript_parser::ast::*;
19use goscript_parser::objects::Objects as AstObjects;
20use goscript_parser::objects::*;
21use goscript_parser::position::Pos;
22use goscript_parser::token::Token;
23use goscript_parser::visitor::{walk_decl, walk_expr, walk_stmt, ExprVisitor, StmtVisitor};
24use goscript_types::{
25    identical, Builtin, OperandMode, PackageKey as TCPackageKey, TCObjects, TypeInfo,
26    TypeKey as TCTypeKey,
27};
28
29macro_rules! current_func_mut {
30    ($owner:ident) => {
31        &mut $owner.objects.functions[*$owner.func_stack.last().unwrap()]
32    };
33}
34
35macro_rules! current_func {
36    ($owner:ident) => {
37        &$owner.objects.functions[*$owner.func_stack.last().unwrap()]
38    };
39}
40
41macro_rules! current_func_emitter {
42    ($owner:ident) => {
43        Emitter::new(current_func_mut!($owner))
44    };
45}
46
47/// CodeGen implements the code generation logic.
48pub struct CodeGen<'a> {
49    objects: &'a mut VMObjects,
50    ast_objs: &'a AstObjects,
51    tc_objs: &'a TCObjects,
52    dummy_gcv: &'a mut GcoVec,
53    tlookup: TypeLookup<'a>,
54    iface_mapping: &'a mut IfaceMapping,
55    pkg_util: PkgUtil<'a>,
56    branch: BranchHelper,
57    pkg_key: PackageKey,
58    func_stack: Vec<FunctionKey>,
59    func_t_stack: Vec<TCTypeKey>, // for casting return values to interfaces
60    blank_ident: IdentKey,
61}
62
63impl<'a> CodeGen<'a> {
64    pub fn new(
65        vmo: &'a mut VMObjects,
66        asto: &'a AstObjects,
67        tco: &'a TCObjects,
68        dummy_gcv: &'a mut GcoVec,
69        ti: &'a TypeInfo,
70        type_cache: &'a mut TypeCache,
71        mapping: &'a mut IfaceMapping,
72        pkg_indices: &'a HashMap<TCPackageKey, OpIndex>,
73        pkgs: &'a Vec<PackageKey>,
74        pkg: PackageKey,
75        bk: IdentKey,
76    ) -> CodeGen<'a> {
77        CodeGen {
78            objects: vmo,
79            ast_objs: asto,
80            tc_objs: tco,
81            dummy_gcv: dummy_gcv,
82            tlookup: TypeLookup::new(tco, ti, type_cache),
83            iface_mapping: mapping,
84            pkg_util: PkgUtil::new(asto, tco, pkg_indices, pkgs, pkg),
85            branch: BranchHelper::new(),
86            pkg_key: pkg,
87            func_stack: Vec::new(),
88            func_t_stack: Vec::new(),
89            blank_ident: bk,
90        }
91    }
92
93    pub fn pkg_util(&mut self) -> &mut PkgUtil<'a> {
94        &mut self.pkg_util
95    }
96
97    fn resolve_any_ident(&mut self, ident: &IdentKey, expr: Option<&Expr>) -> EntIndex {
98        let id = &self.ast_objs.idents[*ident];
99        match id.entity_key() {
100            None => match expr.map_or(&OperandMode::Value, |x| self.tlookup.get_expr_mode(x)) {
101                OperandMode::TypeExpr => {
102                    let lookup = &self.tlookup;
103                    let tctype = lookup.underlying_tc(lookup.get_use_tc_type(*ident));
104                    let meta = lookup.basic_type_from_tc(tctype, self.objects);
105                    EntIndex::BuiltInType(meta)
106                }
107                OperandMode::Value => match &*id.name {
108                    "true" => EntIndex::BuiltInVal(Opcode::PUSH_TRUE),
109                    "false" => EntIndex::BuiltInVal(Opcode::PUSH_FALSE),
110                    "nil" => EntIndex::BuiltInVal(Opcode::PUSH_NIL),
111                    _ => unreachable!(),
112                },
113                _ => unreachable!(),
114            },
115            Some(_) => self.resolve_var_ident(ident),
116        }
117    }
118
119    fn resolve_var_ident(&mut self, ident: &IdentKey) -> EntIndex {
120        let entity_key = &self.ast_objs.idents[*ident].entity_key().unwrap();
121        // 1. try local first
122        if let Some(index) = current_func!(self).entity_index(&entity_key).map(|x| *x) {
123            return index;
124        }
125        // 2. try upvalue
126        let upvalue = self
127            .func_stack
128            .clone()
129            .iter()
130            .skip(1) // skip package constructor
131            .rev()
132            .skip(1) // skip itself
133            .find_map(|ifunc| {
134                let f = &mut self.objects.functions[*ifunc];
135                let index = f.entity_index(&entity_key).map(|x| *x);
136                if let Some(ind) = index {
137                    let desc = ValueDesc::new(
138                        *ifunc,
139                        ind.into(),
140                        self.tlookup.get_use_value_type(*ident),
141                        true,
142                    );
143                    Some(desc)
144                } else {
145                    None
146                }
147            });
148        if let Some(uv) = upvalue {
149            let func = current_func_mut!(self);
150            let index = func.try_add_upvalue(&entity_key, uv);
151            return index;
152        }
153        // 3. must be package member
154        EntIndex::PackageMember(self.pkg_key, *ident)
155    }
156
157    fn add_local_or_resolve_ident(
158        &mut self,
159        ikey: &IdentKey,
160        is_def: bool,
161    ) -> (EntIndex, Option<TCTypeKey>, usize) {
162        let ident = &self.ast_objs.idents[*ikey];
163        let pos = ident.pos;
164        if ident.is_blank() {
165            return (EntIndex::Blank, None, pos);
166        }
167        if is_def {
168            let meta = self
169                .tlookup
170                .gen_def_type_meta(*ikey, self.objects, self.dummy_gcv);
171            let zero_val = zero_val!(meta, self.objects, self.dummy_gcv);
172            let func = current_func_mut!(self);
173            let ident_key = ident.entity.clone().into_key();
174            let index = func.add_local(ident_key);
175            func.add_local_zero(zero_val);
176            if func.is_ctor() {
177                let pkg_key = func.package;
178                let pkg = &mut self.objects.packages[pkg_key];
179                pkg.add_var_mapping(ident.name.clone(), index.into());
180            }
181            let t = self.tlookup.get_def_tc_type(*ikey);
182            (index, Some(t), pos)
183        } else {
184            let index = self.resolve_var_ident(ikey);
185            let t = self.tlookup.get_use_tc_type(*ikey);
186            (index, Some(t), pos)
187        }
188    }
189
190    fn gen_def_var(&mut self, vs: &ValueSpec) {
191        let lhs = vs
192            .names
193            .iter()
194            .map(|n| -> (LeftHandSide, Option<TCTypeKey>, usize) {
195                let (index, t, pos) = self.add_local_or_resolve_ident(n, true);
196                (LeftHandSide::Primitive(index), t, pos)
197            })
198            .collect::<Vec<(LeftHandSide, Option<TCTypeKey>, usize)>>();
199        let rhs = if vs.values.is_empty() {
200            RightHandSide::Nothing
201        } else {
202            RightHandSide::Values(&vs.values)
203        };
204        self.gen_assign_def_var(&lhs, &vs.typ, &rhs);
205    }
206
207    fn gen_def_const(&mut self, names: &Vec<IdentKey>, values: &Vec<Expr>) {
208        assert!(names.len() == values.len());
209        for i in 0..names.len() {
210            let ident = self.ast_objs.idents[names[i]].clone();
211            let val = self.tlookup.get_const_value(values[i].id());
212            self.current_func_add_const_def(&ident, val);
213        }
214    }
215
216    /// entrance for all assign related stmts
217    /// var x
218    /// x := 0
219    /// x += 1
220    /// x++
221    /// for x := range xxx
222    /// recv clause of select stmt
223    fn gen_assign(
224        &mut self,
225        token: &Token,
226        lhs_exprs: &Vec<&Expr>,
227        rhs: RightHandSide,
228    ) -> Option<usize> {
229        let lhs = lhs_exprs
230            .iter()
231            .map(|expr| {
232                match expr {
233                    Expr::Ident(ident) => {
234                        // cannot only determined by token, because it could be a mixture
235                        let mut is_def = *token == Token::DEFINE;
236                        if is_def {
237                            let entity = &self.ast_objs.idents[*ident].entity_key();
238                            is_def = entity.is_some()
239                                && current_func!(self)
240                                    .entity_index(entity.as_ref().unwrap())
241                                    .is_none();
242                        }
243                        let (idx, t, p) = self.add_local_or_resolve_ident(ident, is_def);
244                        (LeftHandSide::Primitive(idx), t, p)
245                    }
246                    Expr::Index(ind_expr) => {
247                        let obj = &ind_expr.as_ref().expr;
248                        self.visit_expr(obj);
249                        let obj_typ = self.tlookup.get_expr_value_type(obj);
250                        let ind = &ind_expr.as_ref().index;
251                        let pos = ind_expr.as_ref().l_brack;
252
253                        let mut index_const = None;
254                        let mut index_typ = None;
255                        if let Some(const_val) = self.tlookup.get_tc_const_value(ind.id()) {
256                            let (ival, _) = const_val.to_int().int_as_i64();
257                            if let Ok(i) = OpIndex::try_from(ival) {
258                                index_const = Some(i);
259                            }
260                        }
261                        if index_const.is_none() {
262                            self.visit_expr(ind);
263                            index_typ = Some(self.tlookup.get_expr_value_type(ind));
264                        }
265                        (
266                            LeftHandSide::IndexSelExpr(IndexSelInfo::new(
267                                0,
268                                index_const,
269                                obj_typ,
270                                index_typ,
271                                IndexSelType::Indexing,
272                            )), // the true index will be calculated later
273                            Some(self.tlookup.get_expr_tc_type(expr)),
274                            pos,
275                        )
276                    }
277                    Expr::Selector(sexpr) => {
278                        let pos = self.ast_objs.idents[sexpr.sel].pos;
279                        match self.tlookup.try_get_pkg_key(&sexpr.expr) {
280                            Some(key) => {
281                                let pkg = self.pkg_util.get_vm_pkg(key);
282                                //let t = self.tlookup.get_use_value_type(sexpr.sel);
283                                (
284                                    // the true index will be calculated later
285                                    LeftHandSide::Primitive(EntIndex::PackageMember(
286                                        pkg, sexpr.sel,
287                                    )),
288                                    Some(self.tlookup.get_expr_tc_type(expr)),
289                                    pos,
290                                )
291                            }
292                            None => {
293                                let t = self.tlookup.get_meta_by_node_id(
294                                    sexpr.expr.id(),
295                                    self.objects,
296                                    self.dummy_gcv,
297                                );
298                                let name = &self.ast_objs.idents[sexpr.sel].name;
299                                let i = t.field_index(name, &self.objects.metas);
300
301                                self.visit_expr(&sexpr.expr);
302                                let obj_typ = self.tlookup.get_expr_value_type(&sexpr.expr);
303                                (
304                                    // the true index will be calculated later
305                                    LeftHandSide::IndexSelExpr(IndexSelInfo::new(
306                                        0,
307                                        Some(i),
308                                        obj_typ,
309                                        None,
310                                        IndexSelType::StructField,
311                                    )),
312                                    Some(self.tlookup.get_expr_tc_type(expr)),
313                                    pos,
314                                )
315                            }
316                        }
317                    }
318                    Expr::Star(sexpr) => {
319                        self.visit_expr(&sexpr.expr);
320                        (
321                            LeftHandSide::Deref(0), // the true index will be calculated later
322                            Some(self.tlookup.get_expr_tc_type(expr)),
323                            sexpr.star,
324                        )
325                    }
326                    _ => unreachable!(),
327                }
328            })
329            .collect::<Vec<(LeftHandSide, Option<TCTypeKey>, usize)>>();
330
331        match rhs {
332            RightHandSide::Nothing => {
333                let code = match token {
334                    Token::INC => Opcode::ADD,
335                    Token::DEC => Opcode::SUB,
336                    _ => unreachable!(),
337                };
338                let typ = self.tlookup.get_expr_value_type(&lhs_exprs[0]);
339                self.gen_op_assign(&lhs[0].0, (code, None), None, typ, lhs[0].2);
340                None
341            }
342            RightHandSide::Values(rhs_exprs) => {
343                let simple_op = match token {
344                    Token::ADD_ASSIGN => Some(Opcode::ADD),         // +=
345                    Token::SUB_ASSIGN => Some(Opcode::SUB),         // -=
346                    Token::MUL_ASSIGN => Some(Opcode::MUL),         // *=
347                    Token::QUO_ASSIGN => Some(Opcode::QUO),         // /=
348                    Token::REM_ASSIGN => Some(Opcode::REM),         // %=
349                    Token::AND_ASSIGN => Some(Opcode::AND),         // &=
350                    Token::OR_ASSIGN => Some(Opcode::OR),           // |=
351                    Token::XOR_ASSIGN => Some(Opcode::XOR),         // ^=
352                    Token::SHL_ASSIGN => Some(Opcode::SHL),         // <<=
353                    Token::SHR_ASSIGN => Some(Opcode::SHR),         // >>=
354                    Token::AND_NOT_ASSIGN => Some(Opcode::AND_NOT), // &^=
355                    Token::ASSIGN | Token::DEFINE => None,
356                    _ => unreachable!(),
357                };
358                if let Some(code) = simple_op {
359                    assert_eq!(lhs_exprs.len(), 1);
360                    assert_eq!(rhs_exprs.len(), 1);
361                    let ltyp = self.tlookup.get_expr_value_type(&lhs_exprs[0]);
362                    let rtyp = match code {
363                        Opcode::SHL | Opcode::SHR => {
364                            Some(self.tlookup.get_expr_value_type(&rhs_exprs[0]))
365                        }
366                        _ => None,
367                    };
368                    self.gen_op_assign(
369                        &lhs[0].0,
370                        (code, rtyp),
371                        Some(&rhs_exprs[0]),
372                        ltyp,
373                        lhs[0].2,
374                    );
375                    None
376                } else {
377                    self.gen_assign_def_var(&lhs, &None, &rhs)
378                }
379            }
380            _ => self.gen_assign_def_var(&lhs, &None, &rhs),
381        }
382    }
383
384    fn gen_assign_def_var(
385        &mut self,
386        lhs: &Vec<(LeftHandSide, Option<TCTypeKey>, usize)>,
387        typ: &Option<Expr>,
388        rhs: &RightHandSide,
389    ) -> Option<usize> {
390        let mut range_marker = None;
391        // handle the right hand side
392        let types = match rhs {
393            RightHandSide::Nothing => {
394                // define without values
395                let (val, t) = self.get_type_default(&typ.as_ref().unwrap());
396                let mut types = Vec::with_capacity(lhs.len());
397                for (_, _, pos) in lhs.iter() {
398                    let mut emitter = current_func_emitter!(self);
399                    let i = emitter.add_const(None, val.clone());
400                    emitter.emit_load(i, None, self.tlookup.value_type_from_tc(t), Some(*pos));
401                    types.push(t);
402                }
403                types
404            }
405            RightHandSide::Values(values) => {
406                let val0 = &values[0];
407                let val0_mode = self.tlookup.get_expr_mode(val0);
408                if values.len() == 1
409                    && (val0_mode == &OperandMode::CommaOk || val0_mode == &OperandMode::MapIndex)
410                {
411                    let comma_ok = lhs.len() == 2;
412                    match val0 {
413                        Expr::TypeAssert(tae) => {
414                            self.visit_expr(&tae.expr);
415                            let t = self.tlookup.get_expr_tc_type(tae.typ.as_ref().unwrap());
416                            let meta = self.tlookup.meta_from_tc(t, self.objects, self.dummy_gcv);
417                            let func = current_func_mut!(self);
418                            let index = func.add_const(None, GosValue::Metadata(meta));
419                            func.emit_code_with_flag_imm(
420                                Opcode::TYPE_ASSERT,
421                                comma_ok,
422                                index.into(),
423                                Some(tae.l_paren),
424                            );
425                        }
426                        Expr::Index(ie) => {
427                            self.gen_map_index(&ie.expr, &ie.index, comma_ok);
428                        }
429                        Expr::Unary(recv_expr) => {
430                            assert_eq!(recv_expr.op, Token::ARROW);
431                            self.visit_expr(&recv_expr.expr);
432                            let t = self.tlookup.get_expr_value_type(&recv_expr.expr);
433                            assert_eq!(t, ValueType::Channel);
434                            let comma_ok_flag = comma_ok.then(|| ValueType::FlagA);
435                            current_func_mut!(self).emit_code_with_type2(
436                                Opcode::RECV,
437                                t,
438                                comma_ok_flag,
439                                Some(recv_expr.op_pos),
440                            );
441                        }
442                        _ => {
443                            dbg!(val0, val0_mode);
444                            unreachable!()
445                        }
446                    }
447                    if comma_ok {
448                        self.tlookup.get_tuple_tc_types(val0)
449                    } else {
450                        vec![self.tlookup.get_expr_tc_type(val0)]
451                    }
452                } else if values.len() == lhs.len() {
453                    // define or assign with values
454                    let mut types = Vec::with_capacity(values.len());
455                    for val in values.iter() {
456                        self.visit_expr(val);
457                        let rhs_type = self.tlookup.get_expr_tc_type(val);
458                        types.push(rhs_type);
459                    }
460                    types
461                } else if values.len() == 1 {
462                    let expr = val0;
463                    // define or assign with function call on the right
464                    if let Expr::Call(_) = expr {
465                        self.visit_expr(expr);
466                    } else {
467                        unreachable!()
468                    }
469                    self.tlookup.get_tuple_tc_types(expr)
470                } else {
471                    unreachable!();
472                }
473            }
474            RightHandSide::Range(r) => {
475                // the range statement
476                self.visit_expr(r);
477                let tkv = self.tlookup.get_range_tc_types(r);
478                let types = [
479                    Some(self.tlookup.value_type_from_tc(tkv[0])),
480                    Some(self.tlookup.value_type_from_tc(tkv[1])),
481                    Some(self.tlookup.value_type_from_tc(tkv[2])),
482                ];
483                let pos = Some(r.pos(&self.ast_objs));
484                //current_func_emitter!(self).emit_push_imm(ValueType::Int, -1, pos);
485                let func = current_func_mut!(self);
486                func.emit_inst(Opcode::RANGE_INIT, types, None, pos);
487                range_marker = Some(func.next_code_index());
488                // the block_end address to be set
489                func.emit_inst(Opcode::RANGE, types, None, pos);
490                tkv[1..].to_vec()
491            }
492            RightHandSide::SelectRecv(rhs) => {
493                let comma_ok =
494                    lhs.len() == 2 && self.tlookup.get_expr_mode(rhs) == &OperandMode::CommaOk;
495                if comma_ok {
496                    self.tlookup.get_tuple_tc_types(rhs)
497                } else {
498                    vec![self.tlookup.get_expr_tc_type(rhs)]
499                }
500            }
501        };
502
503        // now the values should be on stack, generate code to set them to the lhs
504        let total_lhs_stack_space = lhs.iter().fold(0, |acc, (x, _, _)| match x {
505            LeftHandSide::Primitive(_) => acc,
506            LeftHandSide::IndexSelExpr(info) => acc + info.stack_space(),
507            LeftHandSide::Deref(_) => acc + 1,
508        });
509        // only when in select stmt, lhs in stack is on top of the rhs
510        let lhs_on_stack_top = if let RightHandSide::SelectRecv(_) = rhs {
511            true
512        } else {
513            false
514        };
515
516        assert_eq!(lhs.len(), types.len());
517        let total_val = types.len() as OpIndex;
518        let total_stack_space = (total_lhs_stack_space + total_val) as OpIndex;
519        let mut current_indexing_deref_index = -if lhs_on_stack_top {
520            total_lhs_stack_space
521        } else {
522            total_stack_space
523        };
524        for (i, (l, _, p)) in lhs.iter().enumerate() {
525            let rhs_index = i as OpIndex
526                - if lhs_on_stack_top {
527                    total_stack_space
528                } else {
529                    total_val
530                };
531            let typ = self.try_cast_to_iface(lhs[i].1, Some(types[i]), rhs_index, *p);
532            let pos = Some(*p);
533            match l {
534                LeftHandSide::Primitive(_) => {
535                    current_func_emitter!(self).emit_store(l, rhs_index, None, None, typ, pos);
536                }
537                LeftHandSide::IndexSelExpr(info) => {
538                    current_func_emitter!(self).emit_store(
539                        &LeftHandSide::IndexSelExpr(info.with_index(current_indexing_deref_index)),
540                        rhs_index,
541                        None,
542                        None,
543                        typ,
544                        pos,
545                    );
546                    // the lhs of IndexSelExpr takes two spots
547                    current_indexing_deref_index += 2;
548                }
549                LeftHandSide::Deref(_) => {
550                    current_func_emitter!(self).emit_store(
551                        &LeftHandSide::Deref(current_indexing_deref_index),
552                        rhs_index,
553                        None,
554                        None,
555                        typ,
556                        pos,
557                    );
558                    current_indexing_deref_index += 1;
559                }
560            }
561        }
562
563        // pop rhs
564        let mut total_pop = types.iter().count() as OpIndex;
565        // pop lhs
566        for (i, _, _) in lhs.iter().rev() {
567            match i {
568                LeftHandSide::Primitive(_) => {}
569                LeftHandSide::IndexSelExpr(info) => {
570                    if let Some(_t) = info.t2 {
571                        total_pop += 1;
572                    }
573                    total_pop += 1;
574                }
575                LeftHandSide::Deref(_) => total_pop += 1,
576            }
577        }
578        let pos = Some(lhs[0].2);
579        current_func_emitter!(self).emit_pop(total_pop, pos);
580        range_marker
581    }
582
583    fn gen_op_assign(
584        &mut self,
585        left: &LeftHandSide,
586        op: (Opcode, Option<ValueType>),
587        right: Option<&Expr>,
588        typ: ValueType,
589        p: usize,
590    ) {
591        let pos = Some(p);
592        if let Some(e) = right {
593            self.visit_expr(e);
594        } else {
595            // it's inc/dec
596            current_func_emitter!(self).emit_push_imm(typ, 1, pos);
597        }
598        match left {
599            LeftHandSide::Primitive(_) => {
600                // why no magic number?
601                // local index is resolved in gen_assign
602                let mut emitter = current_func_emitter!(self);
603                let fkey = self.func_stack.last().unwrap();
604                emitter.emit_store(
605                    left,
606                    -1,
607                    Some(op),
608                    Some((self.pkg_util.pairs_mut(), *fkey)),
609                    typ,
610                    pos,
611                );
612                emitter.emit_pop(1, pos);
613            }
614            LeftHandSide::IndexSelExpr(info) => {
615                // stack looks like this(bottom to top) :
616                //  [... target, index, value] or [... target, value]
617                current_func_emitter!(self).emit_store(
618                    &LeftHandSide::IndexSelExpr(info.with_index(-info.stack_space() - 1)),
619                    -1,
620                    Some(op),
621                    None,
622                    typ,
623                    pos,
624                );
625                let mut total_pop = 2;
626                if let Some(_) = info.t2 {
627                    total_pop += 1;
628                }
629                current_func_emitter!(self).emit_pop(total_pop, pos);
630            }
631            LeftHandSide::Deref(_) => {
632                // why -2?  stack looks like this(bottom to top) :
633                //  [... target, value]
634                let mut emitter = current_func_emitter!(self);
635                emitter.emit_store(&LeftHandSide::Deref(-2), -1, Some(op), None, typ, pos);
636                emitter.emit_pop(2, pos);
637            }
638        }
639    }
640
641    fn gen_switch_body(&mut self, body: &BlockStmt, tag_type: ValueType) {
642        let mut helper = SwitchHelper::new();
643        let mut has_default = false;
644        for (i, stmt) in body.list.iter().enumerate() {
645            helper.add_case_clause();
646            let cc = SwitchHelper::to_case_clause(stmt);
647            match &cc.list {
648                Some(l) => {
649                    for c in l.iter() {
650                        let pos = Some(stmt.pos(&self.ast_objs));
651                        self.visit_expr(c);
652                        let func = current_func_mut!(self);
653                        helper.tags.add_case(i, func.next_code_index());
654                        func.emit_code_with_type(Opcode::SWITCH, tag_type, pos);
655                    }
656                }
657                None => has_default = true,
658            }
659        }
660        if has_default {
661            let func = current_func_mut!(self);
662            helper.tags.add_default(func.next_code_index());
663            func.emit_code(Opcode::JUMP, None);
664        }
665
666        for (i, stmt) in body.list.iter().enumerate() {
667            let cc = SwitchHelper::to_case_clause(stmt);
668            let func = current_func_mut!(self);
669            let default = cc.list.is_none();
670            if default {
671                helper.tags.patch_default(func, func.next_code_index());
672            } else {
673                helper.tags.patch_case(func, i, func.next_code_index());
674            }
675            for s in cc.body.iter() {
676                self.visit_stmt(s);
677            }
678            if !SwitchHelper::has_fall_through(stmt) {
679                let func = current_func_mut!(self);
680                if default {
681                    helper.ends.add_default(func.next_code_index());
682                } else {
683                    helper.ends.add_case(i, func.next_code_index());
684                }
685                func.emit_code(Opcode::JUMP, None);
686            }
687        }
688        let end = current_func!(self).next_code_index();
689        helper.patch_ends(current_func_mut!(self), end);
690
691        // pop the tag
692        current_func_emitter!(self).emit_pop(1, None);
693    }
694
695    fn gen_func_def(
696        &mut self,
697        tc_type: TCTypeKey, // GosMetadata,
698        fkey: FuncTypeKey,
699        recv: Option<FieldList>,
700        body: &BlockStmt,
701    ) -> FunctionKey {
702        let typ = &self.ast_objs.ftypes[fkey];
703        let fmeta = self
704            .tlookup
705            .meta_from_tc(tc_type, &mut self.objects, self.dummy_gcv);
706        let f = GosValue::new_function(
707            self.pkg_key,
708            fmeta,
709            self.objects,
710            self.dummy_gcv,
711            FuncFlag::Default,
712        );
713        let fkey = *f.as_function();
714        let mut emitter = Emitter::new(&mut self.objects.functions[fkey]);
715        if let Some(fl) = &typ.results {
716            emitter.add_params(&fl, self.ast_objs);
717        }
718        match recv {
719            Some(recv) => {
720                let mut fields = recv;
721                fields.list.append(&mut typ.params.list.clone());
722                emitter.add_params(&fields, self.ast_objs)
723            }
724            None => emitter.add_params(&typ.params, self.ast_objs),
725        };
726        self.func_stack.push(fkey);
727        self.func_t_stack.push(tc_type);
728        // process function body
729        self.visit_stmt_block(body);
730        // it will not be executed if it's redundant
731        Emitter::new(&mut self.objects.functions[fkey]).emit_return(None, Some(body.r_brace));
732
733        self.func_stack.pop();
734        self.func_t_stack.pop();
735        fkey
736    }
737
738    fn gen_call(&mut self, func_expr: &Expr, params: &Vec<Expr>, ellipsis: bool, style: CallStyle) {
739        let pos = Some(func_expr.pos(&self.ast_objs));
740        match *self.tlookup.get_expr_mode(func_expr) {
741            // built in function
742            OperandMode::Builtin(builtin) => {
743                let opcode = match builtin {
744                    Builtin::New => Opcode::NEW,
745                    Builtin::Make => Opcode::MAKE,
746                    Builtin::Len => Opcode::LEN,
747                    Builtin::Cap => Opcode::CAP,
748                    Builtin::Append => Opcode::APPEND,
749                    Builtin::Close => Opcode::CLOSE,
750                    Builtin::Panic => Opcode::PANIC,
751                    Builtin::Recover => Opcode::RECOVER,
752                    Builtin::Assert => Opcode::ASSERT,
753                    Builtin::Ffi => Opcode::FFI,
754                    _ => unimplemented!(),
755                };
756                for e in params.iter() {
757                    self.visit_expr(e);
758                }
759                // some of the built in funcs are not recorded
760                if let Some(t) = self.tlookup.try_get_expr_tc_type(func_expr) {
761                    self.try_cast_params_to_iface(t, params, ellipsis);
762                    if opcode == Opcode::FFI {
763                        // FFI needs the signature of the call
764                        let meta = self.tlookup.meta_from_tc(t, self.objects, self.dummy_gcv);
765                        let mut emitter = current_func_emitter!(self);
766                        let i = emitter.add_const(None, GosValue::Metadata(meta));
767                        emitter.emit_load(i, None, ValueType::Metadata, pos);
768                    }
769                }
770                let (param0t, param_last_t) = if params.len() > 0 {
771                    (
772                        Some(self.tlookup.get_expr_value_type(&params[0])),
773                        Some(self.tlookup.get_expr_value_type(params.last().unwrap())),
774                    )
775                } else {
776                    (None, None)
777                };
778                let bf = self.tc_objs.universe().builtins()[&builtin];
779                let param_count = params.len() as OpIndex;
780                let (t_variadic, count) = if bf.variadic {
781                    if ellipsis {
782                        (None, Some(0)) // do not pack params if there is ellipsis
783                    } else {
784                        (param_last_t, Some(bf.arg_count as OpIndex - param_count))
785                    }
786                } else {
787                    (None, Some(param_count as OpIndex))
788                };
789                let func = current_func_mut!(self);
790                func.emit_inst(opcode, [param0t, t_variadic, None], count, pos);
791            }
792            // conversion
793            // from the specs:
794            /*
795            A non-constant value x can be converted to type T in any of these cases:
796                x is assignable to T.
797                ignoring struct tags (see below), x's type and T have identical underlying types.
798                ignoring struct tags (see below), x's type and T are pointer types that are not defined types, and their pointer base types have identical underlying types.
799                x's type and T are both integer or floating point types.
800                x's type and T are both complex types.
801                x is an integer or a slice of bytes or runes and T is a string type.
802                x is a string and T is a slice of bytes or runes.
803            A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
804                x's type is identical to T.
805                x's type V and T have identical underlying types and at least one of V or T is not a defined type.
806                T is an interface type and x implements T.
807                x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a defined type.
808                x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
809                x is an untyped constant representable by a value of type T.
810            */
811            OperandMode::TypeExpr => {
812                assert!(params.len() == 1);
813                self.visit_expr(&params[0]);
814                let tct0 = self.tlookup.get_expr_tc_type(func_expr);
815                let utct0 = self.tlookup.underlying_tc(tct0);
816                let t0 = self.tlookup.value_type_from_tc(utct0);
817                let tct1 = self.tlookup.get_expr_tc_type(&params[0]);
818                let utct1 = self.tlookup.underlying_tc(tct1);
819                let t1 = self.tlookup.value_type_from_tc(utct1);
820                // just ignore conversion if it's nil or types are identical
821                if t1 != ValueType::Nil && !identical(utct0, utct1, self.tc_objs) {
822                    let iface_index = match t0 {
823                        ValueType::Interface => {
824                            if t1 != ValueType::Nil {
825                                self.iface_mapping.get_index(
826                                    &(tct0, Some(tct1)),
827                                    &mut self.tlookup,
828                                    self.objects,
829                                    self.dummy_gcv,
830                                )
831                            } else {
832                                0
833                            }
834                        }
835                        _ => 0,
836                    };
837                    // get the type of slice element if we are converting to or from a slice
838                    let tct2 = if t0 == ValueType::Slice {
839                        Some(utct0)
840                    } else if t1 == ValueType::Slice {
841                        Some(utct1)
842                    } else {
843                        None
844                    };
845                    let t2 = tct2.map(|x| {
846                        self.tlookup.value_type_from_tc(
847                            self.tc_objs.types[x].try_as_slice().unwrap().elem(),
848                        )
849                    });
850                    current_func_emitter!(self).emit_cast(t0, t1, t2, -1, iface_index, pos);
851                }
852            }
853            // normal goscript function
854            _ => {
855                self.visit_expr(func_expr);
856                current_func_emitter!(self).emit_pre_call(pos);
857                let _ = params.iter().map(|e| self.visit_expr(e)).count();
858                let t = self.tlookup.get_expr_tc_type(func_expr);
859                self.try_cast_params_to_iface(t, params, ellipsis);
860
861                // do not pack params if there is ellipsis
862                let ftc = self
863                    .tlookup
864                    .underlying_tc(self.tlookup.get_expr_tc_type(func_expr));
865                let func_detail = self.tc_objs.types[ftc].try_as_signature().unwrap();
866                let variadic = func_detail.variadic();
867                let pack = variadic && !ellipsis;
868                current_func_emitter!(self).emit_call(style, pack, pos);
869            }
870        }
871    }
872
873    fn gen_map_index(&mut self, expr: &Expr, index: &Expr, comma_ok: bool) {
874        let t0 = self.tlookup.get_expr_value_type(expr);
875        let t1 = self.tlookup.get_expr_value_type(index);
876        self.visit_expr(expr);
877        let pos = Some(expr.pos(&self.ast_objs));
878        if let Some(const_val) = self.tlookup.get_tc_const_value(index.id()) {
879            let (ival, _) = const_val.to_int().int_as_i64();
880            if let Ok(i) = OpIndex::try_from(ival) {
881                current_func_emitter!(self).emit_load_index_imm(i, t0, comma_ok, pos);
882                return;
883            }
884        }
885        self.visit_expr(index);
886        current_func_emitter!(self).emit_load_index(t0, t1, comma_ok, pos);
887    }
888
889    fn try_cast_to_iface(
890        &mut self,
891        lhs: Option<TCTypeKey>,
892        rhs: Option<TCTypeKey>,
893        rhs_index: OpIndex,
894        pos: usize,
895    ) -> ValueType {
896        let mut ret_type = None;
897        if let Some(t0) = lhs {
898            if self.tlookup.underlying_value_type_from_tc(t0) == ValueType::Interface {
899                let (cast, typ) = match rhs {
900                    Some(t1) => {
901                        let vt1 = self.tlookup.underlying_value_type_from_tc(t1);
902                        (vt1 != ValueType::Interface && vt1 != ValueType::Nil, vt1)
903                    }
904                    None => (true, ValueType::Slice), // it must be a variadic parameter
905                };
906                if cast {
907                    let index = self.iface_mapping.get_index(
908                        &(t0, rhs),
909                        &mut self.tlookup,
910                        self.objects,
911                        self.dummy_gcv,
912                    );
913                    current_func_emitter!(self).emit_cast(
914                        ValueType::Interface,
915                        typ,
916                        None,
917                        rhs_index,
918                        index,
919                        Some(pos),
920                    );
921                    ret_type = Some(ValueType::Interface);
922                }
923            }
924        }
925        ret_type.unwrap_or(self.tlookup.value_type_from_tc(rhs.unwrap()))
926    }
927
928    fn try_cast_params_to_iface(&mut self, func: TCTypeKey, params: &Vec<Expr>, ellipsis: bool) {
929        let (sig_params, variadic) = self.tlookup.get_sig_params_tc_types(func);
930        let non_variadic_params = variadic.map_or(sig_params.len(), |_| sig_params.len() - 1);
931        for (i, v) in sig_params[..non_variadic_params].iter().enumerate() {
932            let rhs_index = i as OpIndex - params.len() as OpIndex;
933            let rhs = if i == params.len() - 1 && ellipsis {
934                None
935            } else {
936                Some(self.tlookup.get_expr_tc_type(&params[i]))
937            };
938            let pos = params[i].pos(&self.ast_objs);
939            self.try_cast_to_iface(Some(*v), rhs, rhs_index, pos);
940        }
941        if !ellipsis {
942            if let Some((_, t)) = variadic {
943                if self.tlookup.underlying_value_type_from_tc(t) == ValueType::Interface {
944                    for (i, p) in params.iter().enumerate().skip(non_variadic_params) {
945                        let rhs_index = i as OpIndex - params.len() as OpIndex;
946                        let rhs = self.tlookup.get_expr_tc_type(p);
947                        let pos = p.pos(&self.ast_objs);
948                        self.try_cast_to_iface(Some(t), Some(rhs), rhs_index, pos);
949                    }
950                }
951            }
952        }
953    }
954
955    fn get_type_default(&mut self, expr: &Expr) -> (GosValue, TCTypeKey) {
956        let t = self.tlookup.get_expr_tc_type(expr);
957        let meta = self.tlookup.meta_from_tc(t, self.objects, self.dummy_gcv);
958        let zero_val = zero_val!(meta, self.objects, self.dummy_gcv);
959        (zero_val, t)
960    }
961
962    fn visit_composite_expr(&mut self, expr: &Expr, tctype: TCTypeKey) {
963        match expr {
964            Expr::CompositeLit(clit) => self.gen_composite_literal(clit, tctype),
965            _ => self.visit_expr(expr),
966        }
967        let t = self.tlookup.get_expr_tc_type(expr);
968        self.try_cast_to_iface(Some(tctype), Some(t), -1, expr.pos(self.ast_objs));
969    }
970
971    fn gen_composite_literal(&mut self, clit: &CompositeLit, tctype: TCTypeKey) {
972        let meta = self
973            .tlookup
974            .meta_from_tc(tctype, &mut self.objects, self.dummy_gcv);
975        let pos = Some(clit.l_brace);
976        let typ = &self.tc_objs.types[tctype].underlying_val(&self.tc_objs);
977        let (mkey, mc) = meta.get_underlying(&self.objects.metas).unwrap_non_ptr();
978        let mtype = &self.objects.metas[mkey].clone();
979        match mtype {
980            MetadataType::SliceOrArray(_, _) => {
981                let elem = match mc {
982                    MetaCategory::Default => typ.try_as_slice().unwrap().elem(),
983                    MetaCategory::Array => typ.try_as_array().unwrap().elem(),
984                    _ => unreachable!(),
985                };
986                for expr in clit.elts.iter().rev() {
987                    match expr {
988                        Expr::KeyValue(kv) => {
989                            self.visit_composite_expr(&kv.val, elem);
990                            // the key is a constant
991                            self.visit_expr(&kv.key);
992                        }
993                        _ => {
994                            self.visit_composite_expr(expr, elem);
995                            // -1 as a placeholder for when the index is missing
996                            current_func_emitter!(self).emit_push_imm(ValueType::Int, -1, None);
997                        }
998                    };
999                }
1000            }
1001            MetadataType::Map(_, _) => {
1002                let map_type = typ.try_as_map().unwrap();
1003                for expr in clit.elts.iter() {
1004                    match expr {
1005                        Expr::KeyValue(kv) => {
1006                            self.visit_composite_expr(&kv.val, map_type.elem());
1007                            self.visit_composite_expr(&kv.key, map_type.key());
1008                        }
1009                        _ => unreachable!(),
1010                    }
1011                }
1012            }
1013            MetadataType::Struct(f, _) => {
1014                let struct_type = typ.try_as_struct().unwrap();
1015                for (i, expr) in clit.elts.iter().enumerate() {
1016                    let field_type = self.tc_objs.lobjs[struct_type.fields()[i]].typ().unwrap();
1017                    let index = match expr {
1018                        Expr::KeyValue(kv) => {
1019                            self.visit_composite_expr(&kv.val, field_type);
1020                            let ident = kv.key.try_as_ident().unwrap();
1021                            f.mapping[&self.ast_objs.idents[*ident].name]
1022                        }
1023                        _ => {
1024                            self.visit_composite_expr(expr, field_type);
1025                            i as OpIndex
1026                        }
1027                    };
1028                    current_func_emitter!(self).emit_push_imm(ValueType::Uint, index, pos);
1029                }
1030            }
1031            _ => {
1032                dbg!(&mtype);
1033                unreachable!()
1034            }
1035        }
1036        current_func_emitter!(self).emit_push_imm(
1037            ValueType::Int32,
1038            clit.elts.len() as OpIndex,
1039            pos,
1040        );
1041
1042        let mut emitter = current_func_emitter!(self);
1043        let i = emitter.add_const(None, GosValue::Metadata(meta));
1044        emitter.emit_literal(ValueType::Metadata, i.into(), pos);
1045    }
1046
1047    fn gen_type_meta(&mut self, typ: &Expr) {
1048        let m = self
1049            .tlookup
1050            .get_meta_by_node_id(typ.id(), self.objects, self.dummy_gcv);
1051        let mut emitter = current_func_emitter!(self);
1052        let i = emitter.add_const(None, GosValue::Metadata(m));
1053        let pos = Some(typ.pos(&self.ast_objs));
1054        emitter.emit_load(i, None, ValueType::Metadata, pos);
1055    }
1056
1057    fn gen_const(&mut self, node: NodeId, pos: Option<Pos>) {
1058        let val = self.tlookup.get_const_value(node);
1059        let mut emitter = current_func_emitter!(self);
1060        let t = val.get_type();
1061        let i = emitter.add_const(None, val);
1062        emitter.emit_load(i, None, t, pos);
1063    }
1064
1065    fn current_func_add_const_def(&mut self, ident: &Ident, cst: GosValue) -> EntIndex {
1066        let func = current_func_mut!(self);
1067        let entity = ident.entity.clone().into_key().unwrap();
1068        let index = func.add_const(Some(entity), cst.clone());
1069        if func.is_ctor() {
1070            let pkg_key = func.package;
1071            drop(func);
1072            let pkg = &mut self.objects.packages[pkg_key];
1073            pkg.add_member(ident.name.clone(), cst);
1074        }
1075        index
1076    }
1077
1078    fn add_pkg_var_member(&mut self, pkey: PackageKey, vars: &Vec<Rc<ValueSpec>>) {
1079        for v in vars.iter() {
1080            for n in v.names.iter() {
1081                let ident = &self.ast_objs.idents[*n];
1082                let meta = self
1083                    .tlookup
1084                    .gen_def_type_meta(*n, self.objects, self.dummy_gcv);
1085                let val = zero_val!(meta, self.objects, self.dummy_gcv);
1086                self.objects.packages[pkey].add_member(ident.name.clone(), val);
1087            }
1088        }
1089    }
1090
1091    pub fn gen_with_files(&mut self, files: &Vec<File>, tcpkg: TCPackageKey, index: OpIndex) {
1092        let pkey = self.pkg_key;
1093        let fmeta = self.objects.metadata.default_sig;
1094        let f =
1095            GosValue::new_function(pkey, fmeta, self.objects, self.dummy_gcv, FuncFlag::PkgCtor);
1096        let fkey = *f.as_function();
1097        // the 0th member is the constructor
1098        self.objects.packages[pkey].add_member(
1099            String::new(),
1100            GosValue::new_closure(fkey, &self.objects.functions),
1101        );
1102        self.pkg_key = pkey;
1103        self.func_stack.push(fkey);
1104
1105        let vars = self
1106            .pkg_util
1107            .sort_var_decls(files, self.tlookup.type_info());
1108        self.add_pkg_var_member(pkey, &vars);
1109
1110        self.pkg_util.gen_imports(tcpkg, current_func_mut!(self));
1111
1112        for f in files.iter() {
1113            for d in f.decls.iter() {
1114                self.visit_decl(d)
1115            }
1116        }
1117        for v in vars.iter() {
1118            self.gen_def_var(v);
1119        }
1120
1121        let mut emitter = Emitter::new(&mut self.objects.functions[fkey]);
1122        emitter.emit_return(Some(index), None);
1123        self.func_stack.pop();
1124    }
1125}
1126
1127impl<'a> ExprVisitor for CodeGen<'a> {
1128    type Result = ();
1129
1130    fn visit_expr(&mut self, expr: &Expr) {
1131        if let Some(mode) = self.tlookup.try_get_expr_mode(expr) {
1132            if let OperandMode::Constant(_) = mode {
1133                self.gen_const(expr.id(), Some(expr.pos(&self.ast_objs)));
1134                return;
1135            }
1136        }
1137        walk_expr(self, expr);
1138    }
1139
1140    fn visit_expr_ident(&mut self, expr: &Expr, ident: &IdentKey) {
1141        let index = self.resolve_any_ident(ident, Some(expr));
1142        let t = self.tlookup.get_use_value_type(*ident);
1143        let fkey = self.func_stack.last().unwrap();
1144        let p = Some(self.ast_objs.idents[*ident].pos);
1145        current_func_emitter!(self).emit_load(
1146            index,
1147            Some((self.pkg_util.pairs_mut(), *fkey)),
1148            t,
1149            p,
1150        );
1151    }
1152
1153    fn visit_expr_ellipsis(&mut self, _: &Expr, _els: &Option<Expr>) {
1154        unreachable!();
1155    }
1156
1157    fn visit_expr_basic_lit(&mut self, this: &Expr, blit: &BasicLit) {
1158        self.gen_const(this.id(), Some(blit.pos));
1159    }
1160
1161    /// Add function as a const and then generate a closure of it
1162    fn visit_expr_func_lit(&mut self, this: &Expr, flit: &FuncLit) {
1163        let tc_type = self.tlookup.get_node_tc_type(this.id());
1164        let fkey = self.gen_func_def(tc_type, flit.typ, None, &flit.body);
1165        let mut emitter = current_func_emitter!(self);
1166        let i = emitter.add_const(None, GosValue::Function(fkey));
1167        let pos = Some(flit.body.l_brace);
1168        emitter.emit_literal(ValueType::Function, i.into(), pos);
1169    }
1170
1171    fn visit_expr_composit_lit(&mut self, _: &Expr, clit: &CompositeLit) {
1172        let tctype = self.tlookup.get_expr_tc_type(clit.typ.as_ref().unwrap());
1173        self.gen_composite_literal(clit, tctype);
1174    }
1175
1176    fn visit_expr_paren(&mut self, _: &Expr, expr: &Expr) {
1177        self.visit_expr(expr)
1178    }
1179
1180    fn visit_expr_selector(&mut self, this: &Expr, expr: &Expr, ident: &IdentKey) {
1181        let pos = Some(expr.pos(&self.ast_objs));
1182        if let Some(key) = self.tlookup.try_get_pkg_key(expr) {
1183            let pkg = self.pkg_util.get_vm_pkg(key);
1184            let t = self.tlookup.get_use_value_type(*ident);
1185            let fkey = self.func_stack.last().unwrap();
1186            current_func_emitter!(self).emit_load(
1187                EntIndex::PackageMember(pkg, *ident),
1188                Some((self.pkg_util.pairs_mut(), *fkey)),
1189                t,
1190                pos,
1191            );
1192            return;
1193        }
1194
1195        let (t0, t1) = self.tlookup.get_selection_value_types(this.id());
1196        let meta = self
1197            .tlookup
1198            .get_meta_by_node_id(expr.id(), self.objects, self.dummy_gcv);
1199        let name = &self.ast_objs.idents[*ident].name;
1200        if t1 == ValueType::Closure {
1201            if meta
1202                .get_underlying(&self.objects.metas)
1203                .get_value_type(&self.objects.metas)
1204                == ValueType::Interface
1205            {
1206                let i = meta.iface_method_index(name, &self.objects.metas);
1207                self.visit_expr(expr);
1208                current_func_mut!(self).emit_code_with_type_imm(
1209                    Opcode::BIND_INTERFACE_METHOD,
1210                    meta.get_value_type(&self.objects.metas),
1211                    i,
1212                    pos,
1213                );
1214            } else {
1215                let i = meta.method_index(name, &self.objects.metas);
1216                let method = meta.get_method(i, &self.objects.metas);
1217                if method.borrow().pointer_recv {
1218                    // desugar
1219                    self.visit_expr_unary(this, expr, &Token::AND);
1220                } else {
1221                    self.visit_expr(expr);
1222                }
1223                let func = current_func_mut!(self);
1224                // todo: fix this!!!
1225                let mi = func.add_const(None, GosValue::Function(method.borrow().func.unwrap()));
1226                func.emit_code_with_type_imm(Opcode::BIND_METHOD, t0, mi.into(), pos);
1227            }
1228        } else {
1229            self.visit_expr(expr);
1230            let i = meta.field_index(name, &self.objects.metas);
1231            current_func_emitter!(self).emit_load_struct_field(i, t0, pos);
1232        }
1233    }
1234
1235    fn visit_expr_index(&mut self, _: &Expr, expr: &Expr, index: &Expr) {
1236        self.gen_map_index(expr, index, false);
1237    }
1238
1239    fn visit_expr_slice(
1240        &mut self,
1241        _: &Expr,
1242        expr: &Expr,
1243        low: &Option<Expr>,
1244        high: &Option<Expr>,
1245        max: &Option<Expr>,
1246    ) -> Self::Result {
1247        self.visit_expr(expr);
1248        let t = self.tlookup.get_expr_value_type(expr);
1249        let pos = Some(expr.pos(&self.ast_objs));
1250        match low {
1251            None => current_func_emitter!(self).emit_push_imm(ValueType::Int, 0, pos),
1252            Some(e) => self.visit_expr(e),
1253        }
1254        match high {
1255            None => current_func_emitter!(self).emit_push_imm(ValueType::Int, -1, pos),
1256            Some(e) => self.visit_expr(e),
1257        }
1258        match max {
1259            None => current_func_mut!(self).emit_code_with_type(Opcode::SLICE, t, pos),
1260            Some(e) => {
1261                self.visit_expr(e);
1262                current_func_mut!(self).emit_code_with_type(Opcode::SLICE_FULL, t, pos);
1263            }
1264        }
1265    }
1266
1267    fn visit_expr_type_assert(&mut self, _: &Expr, _expr: &Expr, _typ: &Option<Expr>) {
1268        unimplemented!();
1269    }
1270
1271    fn visit_expr_call(&mut self, _: &Expr, func_expr: &Expr, params: &Vec<Expr>, ellipsis: bool) {
1272        self.gen_call(func_expr, params, ellipsis, CallStyle::Default);
1273    }
1274
1275    fn visit_expr_star(&mut self, _: &Expr, expr: &Expr) {
1276        let pos = Some(expr.pos(&self.ast_objs));
1277        match self.tlookup.get_expr_mode(expr) {
1278            OperandMode::TypeExpr => {
1279                let m = self
1280                    .tlookup
1281                    .meta_from_tc(
1282                        self.tlookup.get_expr_tc_type(expr),
1283                        self.objects,
1284                        self.dummy_gcv,
1285                    )
1286                    .ptr_to();
1287                let mut emitter = current_func_emitter!(self);
1288                let index = emitter.add_const(None, GosValue::Metadata(m));
1289                emitter.emit_load(index, None, ValueType::Metadata, pos);
1290            }
1291            _ => {
1292                self.visit_expr(expr);
1293                let t = self.tlookup.get_expr_value_type(expr);
1294                current_func_mut!(self).emit_code_with_type(Opcode::DEREF, t, pos);
1295            }
1296        }
1297    }
1298
1299    fn visit_expr_unary(&mut self, this: &Expr, expr: &Expr, op: &Token) {
1300        let pos = Some(expr.pos(&self.ast_objs));
1301        if op == &Token::AND {
1302            match expr {
1303                Expr::Ident(ikey) => {
1304                    let index = self.resolve_any_ident(ikey, None);
1305                    match index {
1306                        EntIndex::LocalVar(i) => {
1307                            let meta = self.tlookup.get_meta_by_node_id(
1308                                expr.id(),
1309                                self.objects,
1310                                self.dummy_gcv,
1311                            );
1312                            let t = meta.get_value_type(&self.objects.metas);
1313                            let ut = meta
1314                                .get_underlying(&self.objects.metas)
1315                                .get_value_type(&self.objects.metas);
1316                            if ut == ValueType::Struct
1317                                || ut == ValueType::Array
1318                                || ut == ValueType::Slice
1319                                || ut == ValueType::Map
1320                            {
1321                                let func = current_func_mut!(self);
1322                                func.emit_inst(
1323                                    Opcode::REF_LOCAL,
1324                                    [Some(t), None, None],
1325                                    Some(i),
1326                                    pos,
1327                                );
1328                            } else {
1329                                let ident = &self.ast_objs.idents[*ikey];
1330                                let entity_key = ident.entity_key().unwrap();
1331                                let func = current_func_mut!(self);
1332                                let ind = *func.entity_index(&entity_key).unwrap();
1333                                let desc = ValueDesc::new(
1334                                    *self.func_stack.last().unwrap(),
1335                                    ind.into(),
1336                                    t,
1337                                    false,
1338                                );
1339                                let index = func.try_add_upvalue(&entity_key, desc);
1340                                func.emit_inst(
1341                                    Opcode::REF_UPVALUE,
1342                                    [Some(t), None, None],
1343                                    Some(index.into()),
1344                                    pos,
1345                                );
1346                            }
1347                        }
1348                        EntIndex::UpValue(i) => {
1349                            let t = self.tlookup.get_expr_value_type(expr);
1350                            let func = current_func_mut!(self);
1351                            func.emit_inst(
1352                                Opcode::REF_UPVALUE,
1353                                [Some(t), None, None],
1354                                Some(i),
1355                                pos,
1356                            );
1357                        }
1358                        EntIndex::PackageMember(pkg, ident) => {
1359                            let func = current_func_mut!(self);
1360                            func.emit_inst(
1361                                Opcode::REF_PKG_MEMBER,
1362                                [None, None, None],
1363                                Some(0),
1364                                pos,
1365                            );
1366                            func.emit_raw_inst(key_to_u64(self.pkg_key), pos);
1367                            let fkey = self.func_stack.last().unwrap();
1368                            let i = current_func!(self).next_code_index() - 2;
1369                            self.pkg_util.add_pair(pkg, ident, *fkey, i, false);
1370                        }
1371                        _ => unreachable!(),
1372                    }
1373                }
1374                Expr::Index(iexpr) => {
1375                    let t0 = self.tlookup.get_expr_value_type(&iexpr.expr);
1376                    let t1 = self.tlookup.get_expr_value_type(&iexpr.index);
1377                    self.visit_expr(&iexpr.expr);
1378                    self.visit_expr(&iexpr.index);
1379                    let pos = Some(iexpr.index.pos(&self.ast_objs));
1380                    current_func_mut!(self).emit_inst(
1381                        Opcode::REF_SLICE_MEMBER,
1382                        [Some(t0), Some(t1), None],
1383                        None,
1384                        pos,
1385                    );
1386                }
1387                Expr::Selector(sexpr) => match self.tlookup.try_get_pkg_key(&sexpr.expr) {
1388                    Some(key) => {
1389                        let pkey = self.pkg_util.get_vm_pkg(key);
1390                        let func = current_func_mut!(self);
1391                        func.emit_inst(Opcode::REF_PKG_MEMBER, [None, None, None], Some(0), pos);
1392                        func.emit_raw_inst(key_to_u64(pkey), pos);
1393                        let fkey = self.func_stack.last().unwrap();
1394                        let i = current_func!(self).next_code_index() - 2;
1395                        self.pkg_util.add_pair(pkey, sexpr.sel, *fkey, i, false);
1396                    }
1397                    None => {
1398                        self.visit_expr(&sexpr.expr);
1399                        let t0 = self.tlookup.get_meta_by_node_id(
1400                            sexpr.expr.id(),
1401                            &mut self.objects,
1402                            self.dummy_gcv,
1403                        );
1404                        let name = &self.ast_objs.idents[sexpr.sel].name;
1405                        let i = t0.field_index(name, &self.objects.metas);
1406                        current_func_mut!(self).emit_code_with_type_imm(
1407                            Opcode::REF_STRUCT_FIELD,
1408                            t0.get_value_type(&self.objects.metas),
1409                            i,
1410                            pos,
1411                        );
1412                    }
1413                },
1414                Expr::CompositeLit(clit) => {
1415                    self.visit_expr_composit_lit(this, clit);
1416                    let typ = self.tlookup.get_expr_value_type(expr);
1417                    current_func_mut!(self).emit_inst(
1418                        Opcode::REF_LOCAL,
1419                        [Some(typ), None, None],
1420                        Some(-1),
1421                        pos,
1422                    );
1423                }
1424                _ => {
1425                    dbg!(&expr);
1426                    unimplemented!()
1427                }
1428            }
1429            return;
1430        }
1431
1432        self.visit_expr(expr);
1433        let code = match op {
1434            Token::ADD => Opcode::UNARY_ADD,
1435            Token::SUB => Opcode::UNARY_SUB,
1436            Token::XOR => Opcode::UNARY_XOR,
1437            Token::NOT => Opcode::NOT,
1438            Token::ARROW => Opcode::RECV,
1439            _ => {
1440                dbg!(op);
1441                unreachable!()
1442            }
1443        };
1444        let t = self.tlookup.get_expr_value_type(expr);
1445        current_func_mut!(self).emit_code_with_type(code, t, pos);
1446    }
1447
1448    fn visit_expr_binary(&mut self, _: &Expr, left: &Expr, op: &Token, right: &Expr) {
1449        self.visit_expr(left);
1450        let t = self.tlookup.get_expr_value_type(left);
1451        let code = match op {
1452            Token::ADD => Opcode::ADD,
1453            Token::SUB => Opcode::SUB,
1454            Token::MUL => Opcode::MUL,
1455            Token::QUO => Opcode::QUO,
1456            Token::REM => Opcode::REM,
1457            Token::AND => Opcode::AND,
1458            Token::OR => Opcode::OR,
1459            Token::XOR => Opcode::XOR,
1460            Token::SHL => Opcode::SHL,
1461            Token::SHR => Opcode::SHR,
1462            Token::AND_NOT => Opcode::AND_NOT,
1463            Token::LAND => Opcode::PUSH_FALSE,
1464            Token::LOR => Opcode::PUSH_TRUE,
1465            Token::NOT => Opcode::NOT,
1466            Token::EQL => Opcode::EQL,
1467            Token::LSS => Opcode::LSS,
1468            Token::GTR => Opcode::GTR,
1469            Token::NEQ => Opcode::NEQ,
1470            Token::LEQ => Opcode::LEQ,
1471            Token::GEQ => Opcode::GEQ,
1472            _ => unreachable!(),
1473        };
1474        let pos = Some(left.pos(&self.ast_objs));
1475        // handles short circuit
1476        let mark_code = match op {
1477            Token::LAND => {
1478                let func = current_func_mut!(self);
1479                func.emit_code(Opcode::JUMP_IF_NOT, pos);
1480                Some((func.next_code_index(), code))
1481            }
1482            Token::LOR => {
1483                let func = current_func_mut!(self);
1484                func.emit_code(Opcode::JUMP_IF, pos);
1485                Some((func.next_code_index(), code))
1486            }
1487            _ => None,
1488        };
1489        self.visit_expr(right);
1490
1491        if let Some((i, c)) = mark_code {
1492            let func = current_func_mut!(self);
1493            func.emit_code_with_imm(Opcode::JUMP, 1, pos);
1494            func.emit_code_with_type(c, t, pos);
1495            let diff = func.next_code_index() - i - 1;
1496            func.instruction_mut(i - 1).set_imm(diff as OpIndex);
1497        } else {
1498            let t1 = if code == Opcode::SHL || code == Opcode::SHR {
1499                Some(self.tlookup.get_expr_value_type(right))
1500            } else {
1501                None
1502            };
1503            current_func_mut!(self).emit_code_with_type2(code, t, t1, pos);
1504        }
1505    }
1506
1507    fn visit_expr_key_value(&mut self, e: &Expr, _key: &Expr, _val: &Expr) {
1508        dbg!(e);
1509        unimplemented!();
1510    }
1511
1512    fn visit_expr_array_type(&mut self, this: &Expr, _: &Option<Expr>, _: &Expr) {
1513        self.gen_type_meta(this)
1514    }
1515
1516    fn visit_expr_struct_type(&mut self, this: &Expr, _s: &StructType) {
1517        self.gen_type_meta(this)
1518    }
1519
1520    fn visit_expr_func_type(&mut self, this: &Expr, _s: &FuncTypeKey) {
1521        self.gen_type_meta(this)
1522    }
1523
1524    fn visit_expr_interface_type(&mut self, this: &Expr, _s: &InterfaceType) {
1525        self.gen_type_meta(this)
1526    }
1527
1528    fn visit_map_type(&mut self, this: &Expr, _: &Expr, _: &Expr, _map: &Expr) {
1529        self.gen_type_meta(this)
1530    }
1531
1532    fn visit_chan_type(&mut self, this: &Expr, _chan: &Expr, _dir: &ChanDir) {
1533        self.gen_type_meta(this)
1534    }
1535
1536    fn visit_bad_expr(&mut self, _: &Expr, _e: &BadExpr) {
1537        unreachable!();
1538    }
1539}
1540
1541impl<'a> StmtVisitor for CodeGen<'a> {
1542    type Result = ();
1543
1544    fn visit_stmt(&mut self, stmt: &Stmt) {
1545        walk_stmt(self, stmt)
1546    }
1547
1548    fn visit_decl(&mut self, decl: &Decl) {
1549        walk_decl(self, decl)
1550    }
1551
1552    fn visit_stmt_decl_gen(&mut self, gdecl: &GenDecl) {
1553        for s in gdecl.specs.iter() {
1554            let spec = &self.ast_objs.specs[*s];
1555            match spec {
1556                Spec::Import(_) => {
1557                    //handled elsewhere
1558                }
1559                Spec::Type(ts) => {
1560                    let ident = self.ast_objs.idents[ts.name].clone();
1561                    let m = self
1562                        .tlookup
1563                        .gen_def_type_meta(ts.name, self.objects, self.dummy_gcv);
1564                    self.current_func_add_const_def(&ident, GosValue::Metadata(m));
1565                }
1566                Spec::Value(vs) => match &gdecl.token {
1567                    Token::VAR => {
1568                        // package level vars are handled elsewhere due to ordering
1569                        if !current_func!(self).is_ctor() {
1570                            self.gen_def_var(vs);
1571                        }
1572                    }
1573                    Token::CONST => self.gen_def_const(&vs.names, &vs.values),
1574                    _ => unreachable!(),
1575                },
1576            }
1577        }
1578    }
1579
1580    fn visit_stmt_decl_func(&mut self, fdecl: &FuncDeclKey) -> Self::Result {
1581        let decl = &self.ast_objs.fdecls[*fdecl];
1582        if decl.body.is_none() {
1583            unimplemented!()
1584        }
1585        let tc_type = self.tlookup.get_def_tc_type(decl.name);
1586        let stmt = decl.body.as_ref().unwrap();
1587        let fkey = self.gen_func_def(tc_type, decl.typ, decl.recv.clone(), stmt);
1588        let cls = GosValue::new_closure(fkey, &self.objects.functions);
1589        // this is a struct method
1590        if let Some(self_ident) = &decl.recv {
1591            let field = &self.ast_objs.fields[self_ident.list[0]];
1592            let name = &self.ast_objs.idents[decl.name].name;
1593            let meta =
1594                self.tlookup
1595                    .get_meta_by_node_id(field.typ.id(), self.objects, self.dummy_gcv);
1596            meta.set_method_code(name, fkey, &mut self.objects.metas);
1597        } else {
1598            let ident = &self.ast_objs.idents[decl.name];
1599            let pkg = &mut self.objects.packages[self.pkg_key];
1600            pkg.add_member(ident.name.clone(), cls);
1601        }
1602    }
1603
1604    fn visit_stmt_labeled(&mut self, lstmt: &LabeledStmtKey) {
1605        let stmt = &self.ast_objs.l_stmts[*lstmt];
1606        let offset = current_func!(self).code().len();
1607        let entity = self.ast_objs.idents[stmt.label].entity_key().unwrap();
1608        let is_breakable = match &stmt.stmt {
1609            Stmt::For(_) | Stmt::Range(_) | Stmt::Select(_) | Stmt::Switch(_) => true,
1610            _ => false,
1611        };
1612        self.branch.add_label(entity, offset, is_breakable);
1613        self.visit_stmt(&stmt.stmt);
1614    }
1615
1616    fn visit_stmt_send(&mut self, sstmt: &SendStmt) {
1617        self.visit_expr(&sstmt.chan);
1618        self.visit_expr(&sstmt.val);
1619        let t = self.tlookup.get_expr_value_type(&sstmt.val);
1620        current_func_mut!(self).emit_code_with_type(Opcode::SEND, t, Some(sstmt.arrow));
1621    }
1622
1623    fn visit_stmt_incdec(&mut self, idcstmt: &IncDecStmt) {
1624        self.gen_assign(&idcstmt.token, &vec![&idcstmt.expr], RightHandSide::Nothing);
1625    }
1626
1627    fn visit_stmt_assign(&mut self, astmt: &AssignStmtKey) {
1628        let stmt = &self.ast_objs.a_stmts[*astmt];
1629        self.gen_assign(
1630            &stmt.token,
1631            &stmt.lhs.iter().map(|x| x).collect(),
1632            RightHandSide::Values(&stmt.rhs),
1633        );
1634    }
1635
1636    fn visit_stmt_go(&mut self, gostmt: &GoStmt) {
1637        match &gostmt.call {
1638            Expr::Call(call) => {
1639                self.gen_call(
1640                    &call.func,
1641                    &call.args,
1642                    call.ellipsis.is_some(),
1643                    CallStyle::Async,
1644                );
1645            }
1646            _ => unreachable!(),
1647        }
1648    }
1649
1650    fn visit_stmt_defer(&mut self, dstmt: &DeferStmt) {
1651        current_func_mut!(self).flag = FuncFlag::HasDefer;
1652        match &dstmt.call {
1653            Expr::Call(call) => {
1654                self.gen_call(
1655                    &call.func,
1656                    &call.args,
1657                    call.ellipsis.is_some(),
1658                    CallStyle::Defer,
1659                );
1660            }
1661            _ => unreachable!(),
1662        }
1663    }
1664
1665    fn visit_stmt_return(&mut self, rstmt: &ReturnStmt) {
1666        let pos = Some(rstmt.ret);
1667        let types = self
1668            .tlookup
1669            .get_sig_returns_tc_types(*self.func_t_stack.last().unwrap());
1670        for (i, expr) in rstmt.results.iter().enumerate() {
1671            self.visit_expr(expr);
1672            let tc_type = self.tlookup.get_expr_tc_type(expr);
1673            let t =
1674                self.try_cast_to_iface(Some(types[i]), Some(tc_type), -1, expr.pos(&self.ast_objs));
1675            let mut emitter = current_func_emitter!(self);
1676            emitter.emit_store(
1677                &LeftHandSide::Primitive(EntIndex::LocalVar(i as OpIndex)),
1678                -1,
1679                None,
1680                None,
1681                t,
1682                pos,
1683            );
1684            emitter.emit_pop(1, pos);
1685        }
1686        current_func_emitter!(self).emit_return(None, pos);
1687    }
1688
1689    fn visit_stmt_branch(&mut self, bstmt: &BranchStmt) {
1690        match bstmt.token {
1691            Token::BREAK | Token::CONTINUE => {
1692                let entity = bstmt
1693                    .label
1694                    .map(|x| self.ast_objs.idents[x].entity_key().unwrap());
1695                self.branch.add_point(
1696                    current_func_mut!(self),
1697                    bstmt.token.clone(),
1698                    entity,
1699                    bstmt.token_pos,
1700                );
1701            }
1702            Token::GOTO => {
1703                let func = current_func_mut!(self);
1704                let label = bstmt.label.unwrap();
1705                let entity = self.ast_objs.idents[label].entity_key().unwrap();
1706                self.branch.go_to(func, &entity, bstmt.token_pos);
1707            }
1708            Token::FALLTHROUGH => {
1709                // handled in gen_switch_body
1710            }
1711            _ => unreachable!(),
1712        }
1713    }
1714
1715    fn visit_stmt_block(&mut self, bstmt: &BlockStmt) {
1716        for stmt in bstmt.list.iter() {
1717            self.visit_stmt(stmt);
1718        }
1719    }
1720
1721    fn visit_stmt_if(&mut self, ifstmt: &IfStmt) {
1722        if let Some(init) = &ifstmt.init {
1723            self.visit_stmt(init);
1724        }
1725        self.visit_expr(&ifstmt.cond);
1726        let func = current_func_mut!(self);
1727        func.emit_code(Opcode::JUMP_IF_NOT, Some(ifstmt.if_pos));
1728        let top_marker = func.next_code_index();
1729
1730        drop(func);
1731        self.visit_stmt_block(&ifstmt.body);
1732        let marker_if_arm_end = if ifstmt.els.is_some() {
1733            let func = current_func_mut!(self);
1734            // imm to be set later
1735            func.emit_code(Opcode::JUMP, Some(ifstmt.if_pos));
1736            Some(func.next_code_index())
1737        } else {
1738            None
1739        };
1740
1741        // set the correct else jump target
1742        let func = current_func_mut!(self);
1743        let offset = func.offset(top_marker);
1744        func.instruction_mut(top_marker - 1).set_imm(offset);
1745
1746        if let Some(els) = &ifstmt.els {
1747            self.visit_stmt(els);
1748            // set the correct if_arm_end jump target
1749            let func = current_func_mut!(self);
1750            let marker = marker_if_arm_end.unwrap();
1751            let offset = func.offset(marker);
1752            func.instruction_mut(marker - 1).set_imm(offset);
1753        }
1754    }
1755
1756    fn visit_stmt_case(&mut self, _cclause: &CaseClause) {
1757        unreachable!(); // handled at upper level of the tree
1758    }
1759
1760    fn visit_stmt_switch(&mut self, sstmt: &SwitchStmt) {
1761        self.branch.enter_block();
1762
1763        if let Some(init) = &sstmt.init {
1764            self.visit_stmt(init);
1765        }
1766        let tag_type = match &sstmt.tag {
1767            Some(e) => {
1768                self.visit_expr(e);
1769                self.tlookup.get_expr_value_type(e)
1770            }
1771            None => {
1772                current_func_mut!(self).emit_code(Opcode::PUSH_TRUE, None);
1773                ValueType::Bool
1774            }
1775        };
1776
1777        self.gen_switch_body(&*sstmt.body, tag_type);
1778
1779        self.branch.leave_block(current_func_mut!(self), None);
1780    }
1781
1782    fn visit_stmt_type_switch(&mut self, tstmt: &TypeSwitchStmt) {
1783        if let Some(init) = &tstmt.init {
1784            self.visit_stmt(init);
1785        }
1786
1787        let (ident_expr, assert) = match &tstmt.assign {
1788            Stmt::Assign(ass_key) => {
1789                let ass = &self.ast_objs.a_stmts[*ass_key];
1790                (Some(&ass.lhs[0]), &ass.rhs[0])
1791            }
1792            Stmt::Expr(e) => (None, &**e),
1793            _ => unreachable!(),
1794        };
1795        let (v, pos) = match assert {
1796            Expr::TypeAssert(ta) => (&ta.expr, Some(ta.l_paren)),
1797            _ => unreachable!(),
1798        };
1799
1800        if let Some(iexpr) = ident_expr {
1801            let ident = &self.ast_objs.idents[*iexpr.try_as_ident().unwrap()];
1802            let ident_key = ident.entity.clone().into_key();
1803            let func = current_func_mut!(self);
1804            let index = func.add_local(ident_key);
1805            func.add_local_zero(GosValue::new_nil());
1806            self.visit_expr(v);
1807            let func = current_func_mut!(self);
1808            func.emit_code_with_flag_imm(Opcode::TYPE, true, index.into(), pos);
1809        } else {
1810            self.visit_expr(v);
1811            current_func_mut!(self).emit_code(Opcode::TYPE, pos);
1812        }
1813
1814        self.gen_switch_body(&*tstmt.body, ValueType::Metadata);
1815    }
1816
1817    fn visit_stmt_comm(&mut self, _cclause: &CommClause) {
1818        unimplemented!();
1819    }
1820
1821    fn visit_stmt_select(&mut self, sstmt: &SelectStmt) {
1822        /*
1823        Execution of a "select" statement proceeds in several steps:
1824
1825        1. For all the cases in the statement, the channel operands of receive operations
1826        and the channel and right-hand-side expressions of send statements are evaluated
1827        exactly once, in source order, upon entering the "select" statement. The result
1828        is a set of channels to receive from or send to, and the corresponding values to
1829        send. Any side effects in that evaluation will occur irrespective of which (if any)
1830        communication operation is selected to proceed. Expressions on the left-hand side
1831        of a RecvStmt with a short variable declaration or assignment are not yet evaluated.
1832        2. If one or more of the communications can proceed, a single one that can proceed
1833        is chosen via a uniform pseudo-random selection. Otherwise, if there is a default
1834        case, that case is chosen. If there is no default case, the "select" statement
1835        blocks until at least one of the communications can proceed.
1836        3. Unless the selected case is the default case, the respective communication operation
1837        is executed.
1838        4. If the selected case is a RecvStmt with a short variable declaration or an assignment,
1839        the left-hand side expressions are evaluated and the received value (or values)
1840        are assigned.
1841        5. The statement list of the selected case is executed.
1842
1843        Since communication on nil channels can never proceed, a select with only nil
1844        channels and no default case blocks forever.
1845        */
1846        self.branch.enter_block();
1847
1848        let mut helper = SelectHelper::new();
1849        let comms: Vec<&CommClause> = sstmt
1850            .body
1851            .list
1852            .iter()
1853            .map(|s| SelectHelper::to_comm_clause(s))
1854            .collect();
1855        for c in comms.iter() {
1856            let (typ, pos) = match &c.comm {
1857                Some(comm) => match comm {
1858                    Stmt::Send(send_stmt) => {
1859                        self.visit_expr(&send_stmt.chan);
1860                        self.visit_expr(&send_stmt.val);
1861                        let t = self.tlookup.get_expr_value_type(&send_stmt.val);
1862                        (CommType::Send(t), send_stmt.arrow)
1863                    }
1864                    Stmt::Assign(ass_key) => {
1865                        let ass = &self.ast_objs.a_stmts[*ass_key];
1866                        let (e, pos) = SelectHelper::unwrap_recv(&ass.rhs[0]);
1867                        self.visit_expr(e);
1868                        let t = match &ass.lhs.len() {
1869                            1 => CommType::Recv(&ass),
1870                            2 => CommType::RecvCommaOk(&ass),
1871                            _ => unreachable!(),
1872                        };
1873                        (t, pos)
1874                    }
1875                    Stmt::Expr(expr_stmt) => {
1876                        let (e, pos) = SelectHelper::unwrap_recv(expr_stmt);
1877                        self.visit_expr(e);
1878                        (CommType::RecvNoLhs, pos)
1879                    }
1880                    _ => unreachable!(),
1881                },
1882                None => (CommType::Default, c.colon),
1883            };
1884            helper.add_comm(typ, pos);
1885        }
1886
1887        helper.emit_select(current_func_mut!(self));
1888
1889        let last_index = comms.len() - 1;
1890        for (i, c) in comms.iter().enumerate() {
1891            let begin = current_func!(self).next_code_index();
1892
1893            match helper.comm_type(i) {
1894                CommType::Recv(ass) | CommType::RecvCommaOk(ass) => {
1895                    self.gen_assign(
1896                        &ass.token,
1897                        &ass.lhs.iter().map(|x| x).collect(),
1898                        RightHandSide::SelectRecv(&ass.rhs[0]),
1899                    );
1900                }
1901                _ => {}
1902            }
1903
1904            for stmt in c.body.iter() {
1905                self.visit_stmt(stmt);
1906            }
1907            let func = current_func_mut!(self);
1908            let mut end = func.next_code_index();
1909            // the last block doesn't jump
1910            if i < last_index {
1911                func.emit_code(Opcode::JUMP, None);
1912            } else {
1913                end -= 1;
1914            }
1915
1916            helper.set_block_begin_end(i, begin, end);
1917        }
1918
1919        helper.patch_select(current_func_mut!(self));
1920
1921        self.branch.leave_block(current_func_mut!(self), None);
1922    }
1923
1924    fn visit_stmt_for(&mut self, fstmt: &ForStmt) {
1925        self.branch.enter_block();
1926
1927        if let Some(init) = &fstmt.init {
1928            self.visit_stmt(init);
1929        }
1930        let top_marker = current_func!(self).next_code_index();
1931        let out_marker = if let Some(cond) = &fstmt.cond {
1932            self.visit_expr(&cond);
1933            let func = current_func_mut!(self);
1934            func.emit_code(Opcode::JUMP_IF_NOT, Some(fstmt.for_pos));
1935            Some(func.next_code_index())
1936        } else {
1937            None
1938        };
1939        self.visit_stmt_block(&fstmt.body);
1940        let continue_marker = if let Some(post) = &fstmt.post {
1941            // "continue" jumps to post statements
1942            let m = current_func!(self).next_code_index();
1943            self.visit_stmt(post);
1944            m
1945        } else {
1946            // "continue" jumps to top directly if no post statements
1947            top_marker
1948        };
1949
1950        // jump to the top
1951        let func = current_func_mut!(self);
1952        let offset = -func.offset(top_marker) - 1;
1953        func.emit_code_with_imm(Opcode::JUMP, offset, Some(fstmt.for_pos));
1954
1955        // set the correct else jump out target
1956        if let Some(m) = out_marker {
1957            let func = current_func_mut!(self);
1958            let offset = func.offset(m);
1959            func.instruction_mut(m - 1).set_imm(offset);
1960        }
1961
1962        self.branch
1963            .leave_block(current_func_mut!(self), Some(continue_marker));
1964    }
1965
1966    fn visit_stmt_range(&mut self, rstmt: &RangeStmt) {
1967        self.branch.enter_block();
1968
1969        let blank = Expr::Ident(self.blank_ident);
1970        let lhs = vec![
1971            rstmt.key.as_ref().unwrap_or(&blank),
1972            rstmt.val.as_ref().unwrap_or(&blank),
1973        ];
1974        let marker = self
1975            .gen_assign(&rstmt.token, &lhs, RightHandSide::Range(&rstmt.expr))
1976            .unwrap();
1977
1978        self.visit_stmt_block(&rstmt.body);
1979        // jump to the top
1980        let func = current_func_mut!(self);
1981        let offset = -func.offset(marker) - 1;
1982        // tell Opcode::RANGE where to jump after it's done
1983        let end_offset = func.offset(marker);
1984        func.instruction_mut(marker).set_imm(end_offset);
1985        func.emit_code_with_imm(Opcode::JUMP, offset, Some(rstmt.token_pos));
1986
1987        self.branch
1988            .leave_block(current_func_mut!(self), Some(marker));
1989    }
1990
1991    fn visit_empty_stmt(&mut self, _e: &EmptyStmt) {}
1992
1993    fn visit_bad_stmt(&mut self, _b: &BadStmt) {
1994        unreachable!();
1995    }
1996
1997    fn visit_bad_decl(&mut self, _b: &BadDecl) {
1998        unreachable!();
1999    }
2000}