use crate::ast_emitter::AstEmitter; use crate::emitter::EmitError; use ast::source_atom_set::SourceAtomSetIndex; /// Struct for emitting bytecode for a property where its name is string. /// /// If the property name is a string representing a number, it is considered an /// index. In this case, NamePropertyEmitter falls back internally to /// IndexPropertyEmitter pub struct NamePropertyEmitter<'a, F> where F: Fn(&mut AstEmitter) -> Result<(), EmitError>, { pub state: &'a mut ObjectEmitterState, pub key: SourceAtomSetIndex, pub value: F, } impl<'a, F> NamePropertyEmitter<'a, F> where F: Fn(&mut AstEmitter) -> Result<(), EmitError>, { pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> { // [stack] OBJ match self.to_property_index(emitter, self.key) { Some(value) => { IndexPropertyEmitter { state: self.state, key: value as f64, value: self.value, } .emit(emitter)?; // [stack] OBJ } None => { let name_index = emitter.emit.get_atom_gcthing_index(self.key); (self.value)(emitter)?; // [stack] OBJ VALUE emitter.emit.init_prop(name_index); // [stack] OBJ } } Ok(()) } fn to_property_index( &self, emitter: &mut AstEmitter, index: SourceAtomSetIndex, ) -> Option { let s = emitter.compilation_info.atoms.get(index); s.parse::().ok() } } /// Struct for emitting bytecode for a property where its name is number. pub struct IndexPropertyEmitter<'a, F> where F: Fn(&mut AstEmitter) -> Result<(), EmitError>, { pub state: &'a mut ObjectEmitterState, pub key: f64, pub value: F, } impl<'a, F> IndexPropertyEmitter<'a, F> where F: Fn(&mut AstEmitter) -> Result<(), EmitError>, { pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> { // [stack] OBJ emitter.emit.numeric(self.key); // [stack] OBJ KEY (self.value)(emitter)?; // [stack] OBJ KEY VALUE emitter.emit.init_elem(); // [stack] OBJ Ok(()) } } /// Struct for emitting bytecode for a computed property. pub struct ComputedPropertyEmitter<'a, F1, F2> where F1: Fn(&mut AstEmitter) -> Result<(), EmitError>, F2: Fn(&mut AstEmitter) -> Result<(), EmitError>, { pub state: &'a mut ObjectEmitterState, pub key: F1, pub value: F2, } impl<'a, F1, F2> ComputedPropertyEmitter<'a, F1, F2> where F1: Fn(&mut AstEmitter) -> Result<(), EmitError>, F2: Fn(&mut AstEmitter) -> Result<(), EmitError>, { pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> { // [stack] OBJ (self.key)(emitter)?; // [stack] OBJ KEY (self.value)(emitter)?; // [stack] OBJ KEY VALUE emitter.emit.init_elem(); // [stack] OBJ Ok(()) } } /// No state so far. struct ObjectEmitterStateInternal {} /// Opaque struct that can be created only by ObjectEmitter. /// This guarantees that *PropertyEmitter structs cannot be used outside /// of ObjectEmitter callback. pub struct ObjectEmitterState(ObjectEmitterStateInternal); impl ObjectEmitterState { fn new() -> Self { Self(ObjectEmitterStateInternal {}) } } pub struct ObjectEmitter<'a, PropT, PropF> where PropF: Fn(&mut AstEmitter, &mut ObjectEmitterState, &PropT) -> Result<(), EmitError>, { pub properties: std::slice::Iter<'a, PropT>, pub prop: PropF, } impl<'a, PropT, PropF> ObjectEmitter<'a, PropT, PropF> where PropF: Fn(&mut AstEmitter, &mut ObjectEmitterState, &PropT) -> Result<(), EmitError>, { pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> { // [stack] emitter.emit.new_init(); // [stack] OBJ let mut state = ObjectEmitterState::new(); for prop in self.properties { (self.prop)(emitter, &mut state, prop)?; // [stack] OBJ } Ok(()) } }