lucia_lang/compiler/
codegen.rs

1//! The Code Generator.
2//!
3//! Turn `Vec<Function>` build by analyzer into `Code`.
4
5use std::{convert::TryFrom, vec};
6
7use thiserror::Error;
8
9use crate::utils::Join;
10
11use super::{
12    analyzer::{Function, GlobalNameInfo, UpvalueNameInfo},
13    ast::*,
14    code::{Code, ConstValue, FunctionKind},
15    opcode::{JumpTarget, OpCode},
16    parser::ParserError,
17};
18
19impl TryFrom<BinOp> for OpCode {
20    type Error = SyntaxError;
21
22    fn try_from(value: BinOp) -> Result<Self, Self::Error> {
23        Ok(match value {
24            BinOp::Add => OpCode::Add,
25            BinOp::Sub => OpCode::Sub,
26            BinOp::Mul => OpCode::Mul,
27            BinOp::Div => OpCode::Div,
28            BinOp::Mod => OpCode::Mod,
29            BinOp::Eq => OpCode::Eq,
30            BinOp::Lt => OpCode::Lt,
31            BinOp::Le => OpCode::Le,
32            BinOp::Ne => OpCode::Ne,
33            BinOp::Ge => OpCode::Ge,
34            BinOp::Gt => OpCode::Gt,
35            BinOp::Is => OpCode::Is,
36            _ => return Err(SyntaxError::IllegalAst),
37        })
38    }
39}
40
41/// Generate code.
42pub fn gen_code(func_list: Vec<Function>) -> Result<Code, SyntaxError> {
43    CodeGen { func_list }.gen_code(0)
44}
45
46struct CodeGen {
47    func_list: Vec<Function>,
48}
49
50impl CodeGen {
51    fn get_jump_target(&mut self, func_id: usize) -> JumpTarget {
52        self.func_list[func_id].jump_target_count += 1;
53        JumpTarget(self.func_list[func_id].jump_target_count - 1)
54    }
55
56    fn add_const(&mut self, func_id: usize, value: ConstValue) -> usize {
57        if let Some(index) = self.func_list[func_id]
58            .consts
59            .iter()
60            .position(|x| *x == value)
61        {
62            index
63        } else {
64            self.func_list[func_id].consts.push(value);
65            self.func_list[func_id].consts.len() - 1
66        }
67    }
68
69    fn load(&mut self, func_id: usize, name: &str) -> Result<(), SyntaxError> {
70        let t = if let Some(i) = self.func_list[func_id].local_names.get_index_of(name) {
71            OpCode::LoadLocal(i)
72        } else if let Some(i) = self.func_list[func_id]
73            .global_names
74            .get_index_of(&GlobalNameInfo::from(name.to_owned()))
75        {
76            OpCode::LoadGlobal(i)
77        } else if let Some(i) = self.func_list[func_id]
78            .upvalue_names
79            .get_index_of(&UpvalueNameInfo::from(name.to_owned()))
80        {
81            OpCode::LoadUpvalue(i)
82        } else {
83            return Err(SyntaxError::IllegalAst);
84        };
85        self.func_list[func_id].code.push(t);
86        Ok(())
87    }
88
89    fn store(&mut self, func_id: usize, name: &str) -> Result<(), SyntaxError> {
90        let t = if let Some(i) = self.func_list[func_id].local_names.get_index_of(name) {
91            OpCode::StoreLocal(i)
92        } else if let Some(i) = self.func_list[func_id]
93            .global_names
94            .get_index_of(&GlobalNameInfo::from(name.to_owned()))
95        {
96            OpCode::StoreGlobal(i)
97        } else if let Some(i) = self.func_list[func_id]
98            .upvalue_names
99            .get_index_of(&UpvalueNameInfo::from(name.to_owned()))
100        {
101            OpCode::StoreUpvalue(i)
102        } else {
103            return Err(SyntaxError::IllegalAst);
104        };
105        self.func_list[func_id].code.push(t);
106        Ok(())
107    }
108
109    fn gen_code(&mut self, func_id: usize) -> Result<Code, SyntaxError> {
110        if let Some(variadic) = self.func_list[func_id].variadic.clone() {
111            self.store(func_id, &variadic)?;
112        }
113        for param in self.func_list[func_id].params.clone().into_iter().rev() {
114            self.store(func_id, &param)?;
115        }
116        for stmt in self.func_list[func_id].body.clone().body {
117            self.gen_stmt(func_id, &stmt)?;
118        }
119        if self.func_list[func_id].kind == FunctionKind::Do {
120            self.func_list[func_id].code.push(OpCode::Return);
121        } else if *self.func_list[func_id].code.last().unwrap_or(&OpCode::Pop) != OpCode::Return {
122            let t = self.add_const(func_id, ConstValue::Null);
123            self.func_list[func_id].code.push(OpCode::LoadConst(t));
124            self.func_list[func_id].code.push(OpCode::Return);
125        }
126
127        let mut temp: Vec<usize> = vec![0; self.func_list[func_id].jump_target_count];
128        let mut i = 0;
129        while i < self.func_list[func_id].code.len() {
130            match self.func_list[func_id].code[i] {
131                OpCode::JumpTarget(JumpTarget(index)) => {
132                    temp[index] = i;
133                    self.func_list[func_id].code.remove(i);
134                }
135                _ => i += 1,
136            }
137        }
138        let mut i = 0;
139        while i < self.func_list[func_id].code.len() {
140            match &self.func_list[func_id].code[i] {
141                OpCode::Jump(JumpTarget(v)) => {
142                    self.func_list[func_id].code[i] = OpCode::Jump(JumpTarget(temp[*v]))
143                }
144                OpCode::JumpIfNull(JumpTarget(v)) => {
145                    self.func_list[func_id].code[i] = OpCode::JumpIfNull(JumpTarget(temp[*v]))
146                }
147                OpCode::JumpPopIfFalse(JumpTarget(v)) => {
148                    self.func_list[func_id].code[i] = OpCode::JumpPopIfFalse(JumpTarget(temp[*v]))
149                }
150                OpCode::JumpIfTrueOrPop(JumpTarget(v)) => {
151                    self.func_list[func_id].code[i] = OpCode::JumpIfTrueOrPop(JumpTarget(temp[*v]))
152                }
153                OpCode::JumpIfFalseOrPop(JumpTarget(v)) => {
154                    self.func_list[func_id].code[i] = OpCode::JumpIfFalseOrPop(JumpTarget(temp[*v]))
155                }
156                _ => (),
157            }
158            i += 1;
159        }
160
161        let stack_size = get_stack_size(
162            &self.func_list[func_id].code,
163            0,
164            self.func_list[func_id].params.len()
165                + if self.func_list[func_id].variadic.is_some() {
166                    1
167                } else {
168                    0
169                },
170        );
171        Ok(Code {
172            params: self.func_list[func_id].params.clone(),
173            variadic: self.func_list[func_id].variadic.clone(),
174            kind: self.func_list[func_id].kind,
175            code: self.func_list[func_id].code.clone(),
176            consts: self.func_list[func_id].consts.clone(),
177            local_names: self.func_list[func_id]
178                .local_names
179                .clone()
180                .into_iter()
181                .collect(),
182            global_names: self.func_list[func_id]
183                .global_names
184                .clone()
185                .into_iter()
186                .map(|x| x.name)
187                .collect(),
188            upvalue_names: self.func_list[func_id]
189                .upvalue_names
190                .clone()
191                .into_iter()
192                .map(|x| x.into())
193                .collect(),
194            def_upvalue_count: self.func_list[func_id].def_upvalue_count,
195            stack_size,
196        })
197    }
198
199    fn gen_expr(&mut self, func_id: usize, ast_node: &Expr) -> Result<(), SyntaxError> {
200        match &ast_node.kind {
201            ExprKind::Lit(lit) => {
202                let t = self.add_const(
203                    func_id,
204                    match &lit.value {
205                        LitKind::Null => ConstValue::Null,
206                        LitKind::Bool(v) => ConstValue::Bool(*v),
207                        LitKind::Int(v) => ConstValue::Int(*v),
208                        LitKind::Float(v) => ConstValue::Float(*v),
209                        LitKind::Str(v) => ConstValue::Str(v.clone()),
210                    },
211                );
212                self.func_list[func_id].code.push(OpCode::LoadConst(t));
213            }
214            ExprKind::Ident(ident) => self.load(func_id, &ident.name)?,
215            ExprKind::Function { .. } => return Err(SyntaxError::IllegalAst),
216            ExprKind::FunctionId(i) => {
217                let code = self.gen_code(*i)?;
218                let is_do = code.kind == FunctionKind::Do;
219                let t = self.add_const(func_id, ConstValue::Func(code));
220                self.func_list[func_id].code.push(OpCode::LoadConst(t));
221                if is_do {
222                    self.func_list[func_id].code.push(OpCode::Call(0));
223                }
224            }
225            ExprKind::Table { properties } => {
226                let temp = properties.len();
227                for TableProperty { key, value, .. } in properties {
228                    self.gen_expr(func_id, key)?;
229                    self.gen_expr(func_id, value)?;
230                }
231                self.func_list[func_id].code.push(OpCode::BuildTable(temp));
232            }
233            ExprKind::List { items } => {
234                let temp = items.len();
235                for item in items {
236                    self.gen_expr(func_id, item)?;
237                }
238                self.func_list[func_id].code.push(OpCode::BuildList(temp));
239            }
240            ExprKind::Unary { operator, argument } => {
241                self.gen_expr(func_id, argument)?;
242                self.func_list[func_id].code.push(match operator {
243                    UnOp::Not => OpCode::Not,
244                    UnOp::Neg => OpCode::Neg,
245                });
246            }
247            ExprKind::Binary {
248                operator,
249                left,
250                right,
251            } => match operator {
252                BinOp::And => {
253                    let label = self.get_jump_target(func_id);
254                    self.gen_expr(func_id, left)?;
255                    self.func_list[func_id]
256                        .code
257                        .push(OpCode::JumpIfFalseOrPop(label));
258                    self.gen_expr(func_id, right)?;
259                    self.func_list[func_id].code.push(OpCode::JumpTarget(label));
260                }
261                BinOp::Or => {
262                    let label = self.get_jump_target(func_id);
263                    self.gen_expr(func_id, left)?;
264                    self.func_list[func_id]
265                        .code
266                        .push(OpCode::JumpIfTrueOrPop(label));
267                    self.gen_expr(func_id, right)?;
268                    self.func_list[func_id].code.push(OpCode::JumpTarget(label));
269                }
270                operator => {
271                    self.gen_expr(func_id, left)?;
272                    self.gen_expr(func_id, right)?;
273                    self.func_list[func_id]
274                        .code
275                        .push(OpCode::try_from(*operator)?);
276                }
277            },
278            ExprKind::Member {
279                table,
280                property,
281                kind,
282                safe,
283            } => {
284                self.gen_expr(func_id, table)?;
285                let safe_label = self.get_jump_target(func_id);
286                if *safe {
287                    self.func_list[func_id]
288                        .code
289                        .push(OpCode::JumpIfNull(safe_label));
290                }
291                match kind {
292                    MemberKind::Bracket => {
293                        self.gen_expr(func_id, property)?;
294                        self.func_list[func_id].code.push(OpCode::GetItem);
295                    }
296                    MemberKind::Dot | MemberKind::DoubleColon => {
297                        match &property.kind {
298                            ExprKind::Ident(ident) => {
299                                let t =
300                                    self.add_const(func_id, ConstValue::Str(ident.name.clone()));
301                                self.func_list[func_id].code.push(OpCode::LoadConst(t));
302                            }
303                            _ => return Err(SyntaxError::IllegalAst),
304                        }
305                        self.func_list[func_id].code.push(OpCode::GetAttr);
306                    }
307                }
308                self.func_list[func_id]
309                    .code
310                    .push(OpCode::JumpTarget(safe_label));
311            }
312            ExprKind::MetaMember { table, safe } => {
313                self.gen_expr(func_id, table)?;
314                let safe_label = self.get_jump_target(func_id);
315                if *safe {
316                    self.func_list[func_id]
317                        .code
318                        .push(OpCode::JumpIfNull(safe_label));
319                }
320                self.func_list[func_id].code.push(OpCode::GetMeta);
321                self.func_list[func_id]
322                    .code
323                    .push(OpCode::JumpTarget(safe_label));
324            }
325            ExprKind::Call {
326                callee,
327                arguments,
328                propagating_error,
329            } => {
330                let mut temp: usize = arguments.len();
331                let safe_label = self.get_jump_target(func_id);
332                match callee.kind.clone() {
333                    ExprKind::Member {
334                        table,
335                        property,
336                        kind,
337                        safe,
338                    } => {
339                        self.gen_expr(func_id, &table)?;
340                        if safe {
341                            self.func_list[func_id]
342                                .code
343                                .push(OpCode::JumpIfNull(safe_label));
344                        }
345                        match kind {
346                            MemberKind::Bracket => {
347                                self.gen_expr(func_id, &property)?;
348                                self.func_list[func_id].code.push(OpCode::GetItem);
349                            }
350                            MemberKind::Dot => {
351                                self.func_list[func_id].code.push(OpCode::Copy(1));
352                                match property.kind {
353                                    ExprKind::Ident(ident) => {
354                                        let t =
355                                            self.add_const(func_id, ConstValue::Str(ident.name));
356                                        self.func_list[func_id].code.push(OpCode::LoadConst(t));
357                                    }
358                                    _ => return Err(SyntaxError::IllegalAst),
359                                }
360                                self.func_list[func_id].code.push(OpCode::GetAttr);
361                                self.func_list[func_id].code.push(OpCode::Swap(2));
362                                temp += 1;
363                            }
364                            MemberKind::DoubleColon => {
365                                match property.kind {
366                                    ExprKind::Ident(ident) => {
367                                        let t =
368                                            self.add_const(func_id, ConstValue::Str(ident.name));
369                                        self.func_list[func_id].code.push(OpCode::LoadConst(t));
370                                    }
371                                    _ => return Err(SyntaxError::IllegalAst),
372                                }
373                                self.func_list[func_id].code.push(OpCode::GetAttr);
374                            }
375                        }
376                    }
377                    _ => {
378                        self.gen_expr(func_id, callee)?;
379                    }
380                }
381                for arg in arguments {
382                    self.gen_expr(func_id, arg)?;
383                }
384                self.func_list[func_id].code.push(if *propagating_error {
385                    OpCode::TryCall(temp)
386                } else {
387                    OpCode::Call(temp)
388                });
389                self.func_list[func_id]
390                    .code
391                    .push(OpCode::JumpTarget(safe_label));
392            }
393        }
394        Ok(())
395    }
396
397    fn gen_stmt(&mut self, func_id: usize, ast_node: &Stmt) -> Result<(), SyntaxError> {
398        macro_rules! gen_block {
399            ($block:expr) => {
400                for stmt in &$block.body {
401                    self.gen_stmt(func_id, stmt)?;
402                }
403            };
404        }
405        macro_rules! gen_expr_member_without_get {
406            ($table:expr, $property:expr, $kind:expr, $safe:expr) => {{
407                if *$safe {
408                    return Err(SyntaxError::IllegalAst);
409                }
410                self.gen_expr(func_id, &$table)?;
411                match $kind {
412                    MemberKind::Bracket => self.gen_expr(func_id, &$property)?,
413                    MemberKind::Dot | MemberKind::DoubleColon => match &$property.kind {
414                        ExprKind::Ident(ident) => {
415                            let t = self.add_const(func_id, ConstValue::Str(ident.name.clone()));
416                            self.func_list[func_id].code.push(OpCode::LoadConst(t));
417                        }
418                        _ => return Err(SyntaxError::IllegalAst),
419                    },
420                }
421            }};
422        }
423        macro_rules! assign_left {
424            ($left:expr) => {
425                match &$left.kind {
426                    ExprKind::Ident(ident) => self.store(func_id, &ident.name)?,
427                    ExprKind::Member {
428                        table,
429                        property,
430                        kind,
431                        safe,
432                    } => {
433                        gen_expr_member_without_get!(table, property, kind, safe);
434                        self.func_list[func_id].code.push(match kind {
435                            MemberKind::Bracket => OpCode::SetItem,
436                            MemberKind::Dot | MemberKind::DoubleColon => OpCode::SetAttr,
437                        });
438                    }
439                    ExprKind::MetaMember { table, safe } => {
440                        if *safe {
441                            return Err(SyntaxError::IllegalAst);
442                        }
443                        self.gen_expr(func_id, table)?;
444                        self.func_list[func_id].code.push(OpCode::SetMeta);
445                    }
446                    _ => return Err(SyntaxError::IllegalAst),
447                }
448            };
449        }
450        match &ast_node.kind {
451            StmtKind::If {
452                test,
453                consequent,
454                alternate,
455            } => {
456                /*
457                if (...) <statement> [else <statement>]
458
459                  if (<cond>)                   <cond>
460                                                JUMP_IF_FALSE a
461                    <true_statement>   ===>     <true_statement>
462                  else:                         JUMP b
463                a:                           a:
464                    <false_statement>           <false_statement>
465                b:                           b:
466                */
467                if let Some(alternate) = alternate {
468                    let false_label = self.get_jump_target(func_id);
469                    let end_label = self.get_jump_target(func_id);
470                    self.gen_expr(func_id, test)?;
471                    self.func_list[func_id]
472                        .code
473                        .push(OpCode::JumpPopIfFalse(false_label));
474                    gen_block!(consequent);
475                    self.func_list[func_id].code.push(OpCode::Jump(end_label));
476                    self.func_list[func_id]
477                        .code
478                        .push(OpCode::JumpTarget(false_label));
479                    self.gen_stmt(func_id, alternate)?;
480                    self.func_list[func_id]
481                        .code
482                        .push(OpCode::JumpTarget(end_label));
483                } else {
484                    let end_label = self.get_jump_target(func_id);
485                    self.gen_expr(func_id, test)?;
486                    self.func_list[func_id]
487                        .code
488                        .push(OpCode::JumpPopIfFalse(end_label));
489                    gen_block!(consequent);
490                    self.func_list[func_id]
491                        .code
492                        .push(OpCode::JumpTarget(end_label));
493                }
494            }
495            StmtKind::Loop { body } => {
496                let continue_label = self.get_jump_target(func_id);
497                let break_label = self.get_jump_target(func_id);
498                self.func_list[func_id].continue_stack.push(continue_label);
499                self.func_list[func_id].break_stack.push(break_label);
500
501                self.func_list[func_id]
502                    .code
503                    .push(OpCode::JumpTarget(continue_label));
504                gen_block!(body);
505                self.func_list[func_id]
506                    .code
507                    .push(OpCode::Jump(continue_label));
508                self.func_list[func_id]
509                    .code
510                    .push(OpCode::JumpTarget(break_label));
511
512                self.func_list[func_id].continue_stack.pop();
513                self.func_list[func_id].break_stack.pop();
514            }
515            StmtKind::While { test, body } => {
516                let continue_label = self.get_jump_target(func_id);
517                let break_label = self.get_jump_target(func_id);
518                self.func_list[func_id].continue_stack.push(continue_label);
519                self.func_list[func_id].break_stack.push(break_label);
520
521                self.func_list[func_id]
522                    .code
523                    .push(OpCode::JumpTarget(continue_label));
524                self.gen_expr(func_id, test)?;
525                self.func_list[func_id]
526                    .code
527                    .push(OpCode::JumpPopIfFalse(break_label));
528                gen_block!(body);
529                self.func_list[func_id]
530                    .code
531                    .push(OpCode::Jump(continue_label));
532                self.func_list[func_id]
533                    .code
534                    .push(OpCode::JumpTarget(break_label));
535
536                self.func_list[func_id].continue_stack.pop();
537                self.func_list[func_id].break_stack.pop();
538            }
539            StmtKind::For { left, right, body } => {
540                let continue_label = self.get_jump_target(func_id);
541                let break_label = self.get_jump_target(func_id);
542                self.func_list[func_id].continue_stack.push(continue_label);
543                self.func_list[func_id].break_stack.push(break_label);
544
545                self.gen_expr(func_id, right)?;
546                self.func_list[func_id].code.push(OpCode::Iter);
547                self.func_list[func_id]
548                    .code
549                    .push(OpCode::JumpTarget(continue_label));
550                self.func_list[func_id].code.push(OpCode::Copy(1));
551                self.func_list[func_id].code.push(OpCode::Call(0));
552                self.func_list[func_id]
553                    .code
554                    .push(OpCode::JumpIfNull(break_label));
555                if left.len() == 1 {
556                    self.store(func_id, &left[0].name)?;
557                } else {
558                    for (i, l) in left.iter().enumerate() {
559                        self.func_list[func_id].code.push(OpCode::Copy(1));
560                        let t = self.add_const(func_id, ConstValue::Int(i.try_into().unwrap()));
561                        self.func_list[func_id].code.push(OpCode::LoadConst(t));
562                        self.func_list[func_id].code.push(OpCode::GetItem);
563                        self.store(func_id, &l.name)?;
564                    }
565                    self.func_list[func_id].code.push(OpCode::Pop);
566                }
567                gen_block!(body);
568                self.func_list[func_id]
569                    .code
570                    .push(OpCode::Jump(continue_label));
571                self.func_list[func_id]
572                    .code
573                    .push(OpCode::JumpTarget(break_label));
574                self.func_list[func_id].code.push(OpCode::Pop);
575                self.func_list[func_id].code.push(OpCode::Pop);
576
577                self.func_list[func_id].continue_stack.pop();
578                self.func_list[func_id].break_stack.pop();
579            }
580            StmtKind::Break => {
581                let t = OpCode::Jump(match self.func_list[func_id].break_stack.last() {
582                    Some(v) => *v,
583                    None => return Err(SyntaxError::BreakOutsideLoop),
584                });
585                self.func_list[func_id].code.push(t);
586            }
587            StmtKind::Continue => {
588                let t = OpCode::Jump(match self.func_list[func_id].continue_stack.last() {
589                    Some(v) => *v,
590                    None => return Err(SyntaxError::ContinueOutsideLoop),
591                });
592                self.func_list[func_id].code.push(t);
593            }
594            StmtKind::Return { argument } => {
595                if self.func_list[func_id].kind == FunctionKind::Do {
596                    return Err(SyntaxError::ReturnOutsideFunction);
597                }
598                if let ExprKind::Call {
599                    propagating_error, ..
600                } = argument.kind
601                {
602                    self.gen_expr(func_id, argument)?;
603                    if propagating_error {
604                        self.func_list[func_id].code.push(OpCode::Return);
605                    } else if let OpCode::Call(i) =
606                        self.func_list[func_id].code[self.func_list[func_id].code.len() - 2]
607                    {
608                        let t = self.func_list[func_id].code.len();
609                        self.func_list[func_id].code[t - 2] = OpCode::ReturnCall(i);
610                    }
611                } else {
612                    self.gen_expr(func_id, argument)?;
613                    self.func_list[func_id].code.push(OpCode::Return);
614                }
615            }
616            StmtKind::Throw { argument } => {
617                if self.func_list[func_id].kind == FunctionKind::Do {
618                    return Err(SyntaxError::ThrowOutsideFunction);
619                }
620                self.gen_expr(func_id, argument)?;
621                self.func_list[func_id].code.push(OpCode::Throw);
622            }
623            StmtKind::Global { arguments } => {
624                if self.func_list[func_id].kind == FunctionKind::Do {
625                    return Err(SyntaxError::GlobalOutsideFunction);
626                }
627                for arg in arguments {
628                    self.func_list[func_id].global_names.insert(GlobalNameInfo {
629                        name: arg.name.clone(),
630                        is_writable: true,
631                    });
632                }
633            }
634            StmtKind::Import { path, kind } => {
635                let path_str = path.iter().map(|x| x.name.as_str()).join("::");
636                let t = self.add_const(func_id, ConstValue::Str(path_str));
637                self.func_list[func_id].code.push(OpCode::Import(t));
638                match kind {
639                    ImportKind::Simple(alias) => self.store(func_id, &alias.name)?,
640                    ImportKind::Nested(items) => {
641                        for (name, alias) in items {
642                            let t = self.add_const(func_id, ConstValue::Str(name.name.clone()));
643                            self.func_list[func_id].code.push(OpCode::ImportFrom(t));
644                            self.store(func_id, &alias.name)?;
645                        }
646                        self.func_list[func_id].code.push(OpCode::Pop);
647                    }
648                    ImportKind::Glob => {
649                        self.func_list[func_id].code.push(OpCode::ImportGlob);
650                    }
651                }
652            }
653            StmtKind::Assign { left, right } => {
654                self.gen_expr(func_id, right)?;
655                assign_left!(left);
656            }
657            StmtKind::AssignOp {
658                operator,
659                left,
660                right,
661            } => match &left.kind {
662                ExprKind::Ident(ident) => {
663                    self.gen_expr(func_id, left)?;
664                    self.gen_expr(func_id, right)?;
665                    self.func_list[func_id]
666                        .code
667                        .push(OpCode::try_from(*operator)?);
668                    self.store(func_id, &ident.name)?;
669                }
670                ExprKind::Member {
671                    table,
672                    property,
673                    kind,
674                    safe,
675                } => {
676                    gen_expr_member_without_get!(table, property, kind, safe);
677                    self.func_list[func_id].code.push(OpCode::Copy(2));
678                    self.func_list[func_id].code.push(OpCode::Copy(2));
679                    self.func_list[func_id].code.push(match kind {
680                        MemberKind::Bracket => OpCode::GetItem,
681                        MemberKind::Dot | MemberKind::DoubleColon => OpCode::GetAttr,
682                    });
683                    self.gen_expr(func_id, right)?;
684                    self.func_list[func_id]
685                        .code
686                        .push(OpCode::try_from(*operator)?);
687                    self.func_list[func_id].code.push(OpCode::Swap(3));
688                    self.func_list[func_id].code.push(OpCode::Swap(2));
689                    self.func_list[func_id].code.push(match kind {
690                        MemberKind::Bracket => OpCode::SetItem,
691                        MemberKind::Dot | MemberKind::DoubleColon => OpCode::SetAttr,
692                    });
693                }
694                ExprKind::MetaMember { table, safe } => {
695                    if *safe {
696                        return Err(SyntaxError::IllegalAst);
697                    }
698                    self.gen_expr(func_id, table)?;
699                    self.func_list[func_id].code.push(OpCode::Copy(1));
700                    self.func_list[func_id].code.push(OpCode::GetMeta);
701                    self.func_list[func_id].code.push(OpCode::SetMeta);
702                }
703                _ => return Err(SyntaxError::IllegalAst),
704            },
705            StmtKind::AssignUnpack { left, right } => {
706                self.gen_expr(func_id, right)?;
707                for (i, l) in left.iter().enumerate() {
708                    let t = self.add_const(func_id, ConstValue::Int(i.try_into().unwrap()));
709                    self.func_list[func_id].code.push(OpCode::LoadConst(t));
710                    self.func_list[func_id].code.push(OpCode::GetItem);
711                    assign_left!(l);
712                }
713            }
714            StmtKind::AssignMulti { left, right } => {
715                if left.len() != right.len() {
716                    return Err(SyntaxError::IllegalAst);
717                }
718                for right in right {
719                    self.gen_expr(func_id, right)?;
720                }
721                for left in left.iter().rev() {
722                    assign_left!(left);
723                }
724            }
725            StmtKind::Block(block) => gen_block!(block),
726            StmtKind::Expr(expr) => {
727                self.gen_expr(func_id, expr)?;
728                self.func_list[func_id].code.push(OpCode::Pop);
729            }
730        }
731        Ok(())
732    }
733}
734
735/// Try estimate function stack size.
736fn get_stack_size(code: &Vec<OpCode>, mut offset: usize, init_size: usize) -> usize {
737    let mut stack_size = init_size;
738    let mut t = init_size;
739    while offset < code.len() {
740        match code[offset] {
741            OpCode::Pop => t += 1,
742            OpCode::Copy(_) => t += 1,
743            OpCode::Swap(_) => (),
744            OpCode::LoadLocal(_)
745            | OpCode::LoadGlobal(_)
746            | OpCode::LoadUpvalue(_)
747            | OpCode::LoadConst(_) => t += 1,
748            OpCode::StoreLocal(_) | OpCode::StoreGlobal(_) | OpCode::StoreUpvalue(_) => t -= 1,
749            OpCode::Import(_) => t += 1,
750            OpCode::ImportFrom(_) => t += 1,
751            OpCode::ImportGlob => (),
752            OpCode::BuildTable(i) => t = t - i * 2 + 1,
753            OpCode::BuildList(i) => t = t - i + 1,
754            OpCode::GetAttr | OpCode::GetItem => t -= 1,
755            OpCode::GetMeta => (),
756            OpCode::SetAttr | OpCode::SetItem => t -= 2,
757            OpCode::SetMeta => t -= 1,
758            OpCode::Neg | OpCode::Not => (),
759            OpCode::Add
760            | OpCode::Sub
761            | OpCode::Mul
762            | OpCode::Div
763            | OpCode::Mod
764            | OpCode::Eq
765            | OpCode::Ne
766            | OpCode::Gt
767            | OpCode::Ge
768            | OpCode::Lt
769            | OpCode::Le
770            | OpCode::Is => t -= 1,
771            OpCode::Iter => (),
772            OpCode::Jump(JumpTarget(_)) => (),
773            OpCode::JumpIfNull(JumpTarget(i)) => {
774                stack_size = stack_size.max(get_stack_size(code, i, t));
775            }
776            OpCode::JumpPopIfFalse(JumpTarget(i)) => {
777                t -= 1;
778                stack_size = stack_size.max(get_stack_size(code, i, t));
779            }
780            OpCode::JumpIfTrueOrPop(JumpTarget(i)) | OpCode::JumpIfFalseOrPop(JumpTarget(i)) => {
781                stack_size = stack_size.max(get_stack_size(code, i, t));
782                t -= 1;
783            }
784            OpCode::Call(i) => t = t - i + 1,
785            OpCode::TryCall(i) => t = t - i + 1,
786            OpCode::Return | OpCode::Throw => break,
787            OpCode::ReturnCall(i) => t = t - i + 1,
788            OpCode::JumpTarget(_) => panic!(),
789        }
790        stack_size = stack_size.max(t);
791        offset += 1;
792    }
793    stack_size
794}
795
796/// Kind of SyntaxError.
797#[derive(Error, Debug, Clone, PartialEq)]
798pub enum SyntaxError {
799    #[error("illegal ast")]
800    IllegalAst,
801    #[error("break outside loop")]
802    BreakOutsideLoop,
803    #[error("continue outside loop")]
804    ContinueOutsideLoop,
805    #[error("global outside function")]
806    GlobalOutsideFunction,
807    #[error("return outside function")]
808    ReturnOutsideFunction,
809    #[error("throw outside function")]
810    ThrowOutsideFunction,
811    #[error(transparent)]
812    ParserError(#[from] ParserError),
813}