//! Code for tracking scopes and looking up names as the emitter traverses //! the program. //! //! EmitterScopes exist only while the bytecode emitter is working. //! Longer-lived scope information is stored in `ScopeDataMap`.
usecrate::emitter::InstructionWriter; use ast::source_atom_set::SourceAtomSetIndex; use std::collections::HashMap; use std::iter::Iterator; use stencil::env_coord::{EnvironmentHops, EnvironmentSlot}; use stencil::frame_slot::FrameSlot; use stencil::scope::{BindingKind, GlobalScopeData, LexicalScopeData, ScopeDataMap, ScopeIndex}; use stencil::scope_notes::ScopeNoteIndex;
/// Result of looking up a name. /// /// Corresponds to js::frontend::NameLocation in /// m-c/js/src/frontend/NameAnalysisTypes.h #[derive(Debug, Clone)] pubenum NameLocation {
Dynamic,
Global(BindingKind),
FrameSlot(FrameSlot, BindingKind),
EnvironmentCoord(EnvironmentHops, EnvironmentSlot, BindingKind),
}
struct LexicalEnvironmentObject {} impl LexicalEnvironmentObject { fn first_free_slot() -> u32 { // FIXME: This is the value of // `JSSLOT_FREE(&LexicalEnvironmentObject::class_)` // in SpiderMonkey 2
}
}
/// The information about a scope needed for emitting bytecode. #[derive(Debug)] pubenum EmitterScope {
Global(GlobalEmitterScope),
Lexical(LexicalEmitterScope),
}
/// Stack that tracks the current scope chain while emitting bytecode. /// /// Bytecode is emitted by traversing the structure of the program. During this /// process there's always a "current position". This stack represents the /// scope chain at the current position. It is updated when we enter or leave /// any node that has its own scope. /// /// Unlike the C++ impl, this uses an explicit stack struct, since Rust cannot /// store a reference to a stack-allocated object in another object that has a /// longer lifetime. pubstruct EmitterScopeStack {
scope_stack: Vec<EmitterScope>,
}
/// The current innermost scope. fn innermost(&self) -> &EmitterScope { self.scope_stack
.last()
.expect("There should be at least one scope")
}
/// Enter the global scope. Call this once at the beginning of a top-level /// script. /// /// This emits bytecode that implements parts of [ScriptEvaluation][1] and /// [GlobalDeclarationInstantiation][2]. /// /// [1]: https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation /// [2]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation pubfn enter_global(
&mutself,
emit: &mut InstructionWriter,
scope_data_map: &ScopeDataMap,
top_level_function_count: u32,
) { let scope_index = scope_data_map.get_global_index(); let scope_data = scope_data_map.get_global_at(scope_index);
// The outermost scope should be the first item in the GC things list. // Enter global scope here, before emitting any name ops below.
emit.enter_global_scope(scope_index);
if scope_data.base.bindings.len() > 0 {
emit.global_or_eval_decl_instantiation(top_level_function_count);
}
emit.switch_to_main();
let scope = EmitterScope::Global(GlobalEmitterScope::new(scope_data)); self.scope_stack.push(scope);
}
/// Leave the global scope. Call this once at the end of a top-level /// script. pubfn leave_global(&mutself, emit: &InstructionWriter) { matchself.scope_stack.pop() {
Some(EmitterScope::Global(_)) => {}
_ => panic!("unmatching scope"),
}
emit.leave_global_scope();
}
/// Emit bytecode to mark some local lexical variables as uninitialized. fn dead_zone_frame_slot_range(
&self,
emit: &mut InstructionWriter,
slot_start: FrameSlot,
slot_end: FrameSlot,
) { if slot_start == slot_end { return;
}
/// Enter a lexical scope. /// /// A new LexicalEmitterScope based on scope_data_map is pushed to the /// scope stack. Bytecode is emitted to mark the new lexical bindings as /// uninitialized. pubfn enter_lexical(
&mutself,
emit: &mut InstructionWriter,
scope_data_map: &mut ScopeDataMap,
scope_index: ScopeIndex,
) { letmut scope_data = scope_data_map.get_lexical_at_mut(scope_index);
let parent_scope_note_index = self.innermost().scope_note_index();
let first_frame_slot = self.innermost().next_frame_slot();
scope_data.first_frame_slot = first_frame_slot; letmut lexical_scope = LexicalEmitterScope::new(scope_data, first_frame_slot); let next_frame_slot = lexical_scope.next_frame_slot; let index = emit.enter_lexical_scope(
scope_index,
parent_scope_note_index,
next_frame_slot,
lexical_scope.needs_environment_object,
);
lexical_scope.scope_note_index = Some(index);
let scope = EmitterScope::Lexical(lexical_scope); self.scope_stack.push(scope);
/// Leave a lexical scope. pubfn leave_lexical(&mutself, emit: &mut InstructionWriter) { let lexical_scope = matchself.scope_stack.pop() {
Some(EmitterScope::Lexical(scope)) => scope,
_ => panic!("unmatching scope"),
};
emit.leave_lexical_scope(
lexical_scope
.scope_note_index
.expect("scope note index should be populated"),
lexical_scope.needs_environment_object,
);
}
/// Resolve a name by searching the current scope chain. /// /// Implements the parts of [ResolveBinding][1] that can be done at /// emit time. /// /// [1]: https://tc39.es/ecma262/#sec-resolvebinding pubfn lookup_name(&mutself, name: SourceAtomSetIndex) -> NameLocation { letmut hops = EnvironmentHops::new(0);
/// Just like lookup_name, but only in var scope. pubfn lookup_name_in_var(&mutself, name: SourceAtomSetIndex) -> NameLocation { letmut hops = EnvironmentHops::new(0);
/// Walk the scope stack up to and including `to` depth. /// See EmitterScopeWalker for the details. pubfn walk_up_to_including<'a>(&'a self, to: EmitterScopeDepth) -> EmitterScopeWalker<'a> {
EmitterScopeWalker::new(self, to)
}
/// Walk the scope stack up to `to`, and yields EmitterScopeWalkItem for /// each scope. /// /// The first item is `{ outer: parent-of-innermost, inner: innermost }`, and /// the last item is `{ outer: to, inner: child-of-to }`. pubstruct EmitterScopeWalker<'a> {
stack: &'a EmitterScopeStack,
to: EmitterScopeDepth,
current: EmitterScopeDepth,
}
impl<'a> EmitterScopeWalker<'a> { fn new(stack: &'a EmitterScopeStack, to: EmitterScopeDepth) -> Self { let current = stack.current_depth();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.