diff options
Diffstat (limited to 'third_party/rust/jsparagus-emitter/src/lib.rs')
-rw-r--r-- | third_party/rust/jsparagus-emitter/src/lib.rs | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-emitter/src/lib.rs b/third_party/rust/jsparagus-emitter/src/lib.rs new file mode 100644 index 0000000000..e4b5d49bc1 --- /dev/null +++ b/third_party/rust/jsparagus-emitter/src/lib.rs @@ -0,0 +1,177 @@ +mod array_emitter; +mod ast_emitter; +mod block_emitter; +mod compilation_info; +mod control_structures; +mod dis; +mod emitter; +mod emitter_scope; +mod expression_emitter; +mod function_declaration_emitter; +mod object_emitter; +mod reference_op_emitter; +mod script_emitter; + +extern crate jsparagus_ast as ast; +extern crate jsparagus_scope as scope; +extern crate jsparagus_stencil as stencil; + +pub use crate::emitter::{EmitError, EmitOptions}; +pub use dis::dis; + +use crate::compilation_info::CompilationInfo; + +use ast::source_atom_set::SourceAtomSet; +use ast::source_slice_list::SourceSliceList; +use scope::{ScopeBuildError, ScopePassResult}; +use stencil::result::EmitResult; + +pub fn emit<'alloc>( + ast: &'alloc ast::types::Program<'alloc>, + options: &EmitOptions, + atoms: SourceAtomSet<'alloc>, + slices: SourceSliceList<'alloc>, +) -> Result<EmitResult<'alloc>, EmitError> { + let ScopePassResult { + scope_data_map, + function_declarations, + function_stencil_indices, + function_declaration_properties, + scripts, + error, + } = scope::generate_scope_data(ast); + + // Error case for scope analysis will be removed once all syntax is + // supported. Use field instead of Result type here for simplicity. + match error { + Some(ScopeBuildError::NotImplemented(s)) => { + return Err(EmitError::NotImplemented(s)); + } + None => {} + } + + let compilation_info = CompilationInfo::new( + atoms, + slices, + scope_data_map, + function_declarations, + function_stencil_indices, + function_declaration_properties, + scripts, + ); + ast_emitter::emit_program(ast, options, compilation_info) +} + +#[cfg(test)] +mod tests { + extern crate jsparagus_parser as parser; + + use super::{emit, EmitOptions}; + use crate::dis::*; + use ast::source_atom_set::SourceAtomSet; + use ast::source_slice_list::SourceSliceList; + use bumpalo::Bump; + use parser::{parse_script, ParseOptions}; + use std::cell::RefCell; + use std::convert::TryInto; + use std::rc::Rc; + use stencil::opcode::*; + use stencil::script::SourceExtent; + + fn bytecode(source: &str) -> Vec<u8> { + let alloc = &Bump::new(); + let parse_options = ParseOptions::new(); + let atoms = Rc::new(RefCell::new(SourceAtomSet::new())); + let slices = Rc::new(RefCell::new(SourceSliceList::new())); + let source_len = source.len(); + let parse_result = + parse_script(alloc, source, &parse_options, atoms.clone(), slices.clone()) + .expect("Failed to parse"); + // println!("{:?}", parse_result); + + let extent = SourceExtent::top_level_script(source_len.try_into().unwrap(), 1, 0); + let emit_options = EmitOptions::new(extent); + + let result = emit( + alloc.alloc(ast::types::Program::Script(parse_result.unbox())), + &emit_options, + atoms.replace(SourceAtomSet::new_uninitialized()), + slices.replace(SourceSliceList::new()), + ) + .expect("Should work!"); + + let script_data_index: usize = result.scripts[0] + .immutable_script_data + .expect("Top level script should have ImmutableScriptData") + .into(); + let script_data = &result.script_data_list[script_data_index]; + let bytecode = &script_data.bytecode; + + println!("{}", dis(&bytecode)); + bytecode.to_vec() + } + + #[test] + fn it_works() { + assert_eq!( + bytecode("2 + 2"), + vec![ + Opcode::Int8 as u8, + 2, + Opcode::Int8 as u8, + 2, + Opcode::Add as u8, + Opcode::SetRval as u8, + Opcode::RetRval as u8, + ] + ) + } + + #[test] + fn dis_call() { + assert_eq!( + bytecode("dis()"), + vec![ + Opcode::GetGName as u8, + 1, + 0, + 0, + 0, + Opcode::Undefined as u8, + Opcode::Call as u8, + 0, + 0, + Opcode::SetRval as u8, + Opcode::RetRval as u8, + ] + ) + } + + #[test] + fn literals() { + assert_eq!( + bytecode("true"), + vec![ + Opcode::True as u8, + Opcode::SetRval as u8, + Opcode::RetRval as u8, + ] + ); + assert_eq!( + bytecode("false"), + vec![ + Opcode::False as u8, + Opcode::SetRval as u8, + Opcode::RetRval as u8, + ] + ); + //assert_eq!( + // bytecode("'hello world'"), + // vec![ + // Opcode::String as u8, 0, 0, 0, 0, + // Opcode::SetRval as u8, + // Opcode::RetRval as u8, + // ] + //); + } +} |