Rust编写的JavaScript引擎,该项目是一个试验性质的项目。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

109 lines
4.4 KiB

use super::*;
use crate::{syntax::ast::Const, syntax::ast::Node, value::RcBigInt, value::RcString};
#[derive(Debug, Default)]
/// The compiler struct holds all the instructions.
pub struct Compiler {
/// Vector of instructions
pub(super) instructions: Vec<Instruction>,
/// The pool stores constant data that can be indexed with the opcodes and pushed on the stack
pub(super) pool: Vec<Value>,
}
impl Compiler {
/// Add a new instruction.
pub fn add_instruction(&mut self, instr: Instruction) {
self.instructions.push(instr);
}
/// This specilaized method puts the string value in the pool then adds an instructions which points to the correct index
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());
}
/// This specilaized method puts the BigInt value in the pool then adds an instructions which points to the correct index
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!(),
}
}
}