Boa 0.11.0

Boa is a Javascript lexer, parser and Just-in-Time compiler written in Rust. Currently, it has support for some of the language.
Documentation
use super::*;
use crate::{syntax::ast::Const, syntax::ast::Node, value::RcBigInt, value::RcString};

#[derive(Debug, Default)]
pub struct Compiler {
    pub(super) instructions: Vec<Instruction>,
    pub(super) pool: Vec<Value>,
}

impl Compiler {
    // Add a new instruction.
    pub fn add_instruction(&mut self, instr: Instruction) {
        self.instructions.push(instr);
    }

    pub fn add_string_instruction<S>(&mut self, string: S)
    where
        S: Into<RcString>,
    {
        let index = self.pool.len();
        self.add_instruction(Instruction::String(index));
        self.pool.push(string.into().into());
    }

    pub fn add_bigint_instruction<B>(&mut self, bigint: B)
    where
        B: Into<RcBigInt>,
    {
        let index = self.pool.len();
        self.add_instruction(Instruction::BigInt(index));
        self.pool.push(bigint.into().into());
    }
}

pub(crate) trait CodeGen {
    fn compile(&self, compiler: &mut Compiler);
}

impl CodeGen for Node {
    fn compile(&self, compiler: &mut Compiler) {
        let _timer = BoaProfiler::global().start_event(&format!("Node ({})", &self), "codeGen");
        match *self {
            Node::Const(Const::Undefined) => compiler.add_instruction(Instruction::Undefined),
            Node::Const(Const::Null) => compiler.add_instruction(Instruction::Null),
            Node::Const(Const::Bool(true)) => compiler.add_instruction(Instruction::True),
            Node::Const(Const::Bool(false)) => compiler.add_instruction(Instruction::False),
            Node::Const(Const::Num(num)) => compiler.add_instruction(Instruction::Rational(num)),
            Node::Const(Const::Int(num)) => match num {
                0 => compiler.add_instruction(Instruction::Zero),
                1 => compiler.add_instruction(Instruction::One),
                _ => compiler.add_instruction(Instruction::Int32(num)),
            },
            Node::Const(Const::String(ref string)) => {
                compiler.add_string_instruction(string.clone())
            }
            Node::Const(Const::BigInt(ref bigint)) => {
                compiler.add_bigint_instruction(bigint.clone())
            }
            Node::BinOp(ref op) => op.compile(compiler),
            Node::UnaryOp(ref op) => op.compile(compiler),
            Node::VarDeclList(ref list) => {
                for var_decl in list.as_ref() {
                    let name = var_decl.name();
                    let index = compiler.pool.len();
                    compiler.add_instruction(Instruction::DefVar(index));
                    compiler.pool.push(name.into());

                    if let Some(v) = var_decl.init() {
                        v.compile(compiler);
                        compiler.add_instruction(Instruction::InitLexical(index))
                    };
                }
            }
            Node::LetDeclList(ref list) => {
                for let_decl in list.as_ref() {
                    let name = let_decl.name();
                    let index = compiler.pool.len();
                    compiler.add_instruction(Instruction::DefLet(index));
                    compiler.pool.push(name.into());

                    // If name has a value we can init here too
                    if let Some(v) = let_decl.init() {
                        v.compile(compiler);
                        compiler.add_instruction(Instruction::InitLexical(index))
                    };
                }
            }
            Node::ConstDeclList(ref list) => {
                for const_decl in list.as_ref() {
                    let name = const_decl.name();
                    let index = compiler.pool.len();
                    compiler.add_instruction(Instruction::DefConst(index));
                    compiler.pool.push(name.into());

                    if let Some(v) = const_decl.init() {
                        v.compile(compiler);
                        compiler.add_instruction(Instruction::InitLexical(index))
                    };
                }
            }
            _ => unimplemented!(),
        }
    }
}