summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus-emitter/src/array_emitter.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /third_party/rust/jsparagus-emitter/src/array_emitter.rs
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/jsparagus-emitter/src/array_emitter.rs')
-rw-r--r--third_party/rust/jsparagus-emitter/src/array_emitter.rs176
1 files changed, 176 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-emitter/src/array_emitter.rs b/third_party/rust/jsparagus-emitter/src/array_emitter.rs
new file mode 100644
index 0000000000..b44137182e
--- /dev/null
+++ b/third_party/rust/jsparagus-emitter/src/array_emitter.rs
@@ -0,0 +1,176 @@
+use crate::ast_emitter::AstEmitter;
+use crate::emitter::EmitError;
+
+/// Struct for emitting bytecode for an array element.
+pub struct ArrayElementEmitter<'a, F>
+where
+ F: Fn(&mut AstEmitter) -> Result<(), EmitError>,
+{
+ pub state: &'a mut ArrayEmitterState,
+ pub elem: F,
+}
+
+impl<'a, F> ArrayElementEmitter<'a, F>
+where
+ F: Fn(&mut AstEmitter) -> Result<(), EmitError>,
+{
+ pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
+ // [stack] ARRAY INDEX?
+
+ (self.elem)(emitter)?;
+ // [stack] ARRAY INDEX? ELEM
+
+ match &mut self.state.0 {
+ ArrayEmitterStateInternal::BeforeSpread { ref mut index } => {
+ emitter.emit.init_elem_array(*index);
+ // [stack] ARRAY
+
+ *index += 1;
+ }
+ ArrayEmitterStateInternal::AfterSpread => {
+ emitter.emit.init_elem_inc();
+ // [stack] ARRAY INDEX+1
+ }
+ }
+
+ // [stack] ARRAY INDEX?
+
+ Ok(())
+ }
+}
+
+/// Struct for emitting bytecode for an array element with hole.
+pub struct ArrayElisionEmitter<'a> {
+ pub state: &'a mut ArrayEmitterState,
+}
+
+impl<'a> ArrayElisionEmitter<'a> {
+ pub fn emit(self, emitter: &mut AstEmitter) {
+ // [stack] ARRAY INDEX?
+
+ emitter.emit.hole();
+ // [stack] ARRAY INDEX? HOLE
+
+ match &mut self.state.0 {
+ ArrayEmitterStateInternal::BeforeSpread { ref mut index } => {
+ emitter.emit.init_elem_array(*index);
+ // [stack] ARRAY
+
+ *index += 1;
+ }
+ ArrayEmitterStateInternal::AfterSpread => {
+ emitter.emit.init_elem_inc();
+ // [stack] ARRAY INDEX+1
+ }
+ }
+
+ // [stack] ARRAY INDEX?
+ }
+}
+
+/// Struct for emitting bytecode for an array element with spread.
+pub struct ArraySpreadEmitter<'a, F>
+where
+ F: Fn(&mut AstEmitter) -> Result<(), EmitError>,
+{
+ pub state: &'a mut ArrayEmitterState,
+ pub elem: F,
+}
+
+impl<'a, F> ArraySpreadEmitter<'a, F>
+where
+ F: Fn(&mut AstEmitter) -> Result<(), EmitError>,
+{
+ pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
+ // [stack] ARRAY INDEX?
+
+ match self.state.0 {
+ ArrayEmitterStateInternal::BeforeSpread { index } => {
+ emitter.emit.numeric(index as f64);
+ }
+ _ => {}
+ }
+ self.state.0 = ArrayEmitterStateInternal::AfterSpread;
+
+ // [stack] ARRAY INDEX
+
+ Err(EmitError::NotImplemented("TODO: spread element"))
+ }
+}
+
+enum ArrayEmitterStateInternal {
+ BeforeSpread { index: u32 },
+ AfterSpread,
+}
+
+/// Opaque struct that can be created only by ArrayEmitter.
+/// This guarantees that Array*Emitter structs cannot be used outside
+/// of ArrayEmitter callback.
+pub struct ArrayEmitterState(ArrayEmitterStateInternal);
+
+impl ArrayEmitterState {
+ fn new() -> Self {
+ Self(ArrayEmitterStateInternal::BeforeSpread { index: 0 })
+ }
+}
+
+pub enum ArrayElementKind {
+ Normal,
+ Elision,
+ Spread,
+}
+
+/// Struct for emitting bytecode for an array expression.
+pub struct ArrayEmitter<'a, ElemT, ElemKindF, ElemF>
+where
+ ElemKindF: Fn(&ElemT) -> ArrayElementKind,
+ ElemF: Fn(&mut AstEmitter, &mut ArrayEmitterState, &'a ElemT) -> Result<(), EmitError>,
+{
+ pub elements: std::slice::Iter<'a, ElemT>,
+ pub elem_kind: ElemKindF,
+ pub elem: ElemF,
+}
+
+impl<'a, ElemT, ElemKindF, ElemF> ArrayEmitter<'a, ElemT, ElemKindF, ElemF>
+where
+ ElemKindF: Fn(&ElemT) -> ArrayElementKind,
+ ElemF: Fn(&mut AstEmitter, &mut ArrayEmitterState, &'a ElemT) -> Result<(), EmitError>,
+{
+ pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
+ // [stack]
+
+ // Initialize the array to its minimum possible length.
+ let min_length = self
+ .elements
+ .clone()
+ .map(|e| match (self.elem_kind)(e) {
+ ArrayElementKind::Normal => 1,
+ ArrayElementKind::Elision => 1,
+ ArrayElementKind::Spread => 0,
+ })
+ .sum::<u32>();
+
+ emitter.emit.new_array(min_length);
+ // [stack] ARRAY
+
+ let mut state = ArrayEmitterState::new();
+ for element in self.elements {
+ (self.elem)(emitter, &mut state, element)?;
+ // [stack] ARRAY INDEX?
+ }
+
+ match state.0 {
+ ArrayEmitterStateInternal::AfterSpread => {
+ // [stack] ARRAY INDEX
+
+ emitter.emit.pop();
+ // [stack] ARRAY
+ }
+ _ => {}
+ }
+
+ // [stack] ARRAY
+
+ Ok(())
+ }
+}