summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus-emitter/src/object_emitter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/jsparagus-emitter/src/object_emitter.rs')
-rw-r--r--third_party/rust/jsparagus-emitter/src/object_emitter.rs162
1 files changed, 162 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-emitter/src/object_emitter.rs b/third_party/rust/jsparagus-emitter/src/object_emitter.rs
new file mode 100644
index 0000000000..9f77382aa4
--- /dev/null
+++ b/third_party/rust/jsparagus-emitter/src/object_emitter.rs
@@ -0,0 +1,162 @@
+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(())
+ }
+}