Source code
Revision control
Copy as Markdown
Other Tools
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<u32> {
let s = emitter.compilation_info.atoms.get(index);
s.parse::<u32>().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(())
}
}