зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1643632 - Use BaseScopeData. r=yulia
Differential Revision: https://phabricator.services.mozilla.com/D78475
This commit is contained in:
Родитель
654c97a626
Коммит
2c4cbe5c6f
|
@ -30,7 +30,7 @@ rev = "57a07e89e9ac92756b60b67c4a6ee06975b86288"
|
|||
[source."https://github.com/mozilla-spidermonkey/jsparagus"]
|
||||
git = "https://github.com/mozilla-spidermonkey/jsparagus"
|
||||
replace-with = "vendored-sources"
|
||||
rev = "a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
rev = "bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
|
||||
[source."https://github.com/kvark/spirv_cross"]
|
||||
branch = "wgpu3"
|
||||
|
|
|
@ -2373,7 +2373,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"jsparagus-ast",
|
||||
"jsparagus-emitter",
|
||||
|
@ -2387,7 +2387,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"indexmap",
|
||||
|
@ -2398,7 +2398,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus-emitter"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"byteorder",
|
||||
|
@ -2411,7 +2411,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus-generated-parser"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"jsparagus-ast",
|
||||
|
@ -2421,12 +2421,12 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus-json-log"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
|
||||
[[package]]
|
||||
name = "jsparagus-parser"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"jsparagus-ast",
|
||||
|
@ -2437,7 +2437,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus-scope"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"jsparagus-ast",
|
||||
|
@ -2447,7 +2447,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "jsparagus-stencil"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=a62ca363140935fdd77549b6e17bb9d79f76af75#a62ca363140935fdd77549b6e17bb9d79f76af75"
|
||||
source = "git+https://github.com/mozilla-spidermonkey/jsparagus?rev=bc612163f379fa9978571981e860ec34b6ad59bd#bc612163f379fa9978571981e860ec34b6ad59bd"
|
||||
dependencies = [
|
||||
"jsparagus-ast",
|
||||
]
|
||||
|
|
|
@ -12,12 +12,12 @@ log = "0.4"
|
|||
# Disable regex feature for code size.
|
||||
env_logger = {version = "0.6", default-features = false}
|
||||
# For non-jsparagus developers.
|
||||
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "a62ca363140935fdd77549b6e17bb9d79f76af75" }
|
||||
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "bc612163f379fa9978571981e860ec34b6ad59bd" }
|
||||
# For local development, replace above with
|
||||
# jsparagus = { path = "{path to jsparagus}" }
|
||||
|
||||
[build-dependencies]
|
||||
# For non-jsparagus developers.
|
||||
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "a62ca363140935fdd77549b6e17bb9d79f76af75" }
|
||||
jsparagus = { git = "https://github.com/mozilla-spidermonkey/jsparagus", rev = "bc612163f379fa9978571981e860ec34b6ad59bd" }
|
||||
# For local development, replace above with
|
||||
# jsparagus = { path = "{path to jsparagus}" }
|
||||
|
|
|
@ -142,7 +142,7 @@ impl From<ScopeData> for SmooshScopeData {
|
|||
match data {
|
||||
ScopeData::Global(data) => Self {
|
||||
kind: SmooshScopeDataKind::Global,
|
||||
bindings: CVec::from(data.bindings.into_iter().map(|x| x.into()).collect()),
|
||||
bindings: CVec::from(data.base.bindings.into_iter().map(|x| x.into()).collect()),
|
||||
let_start: data.let_start,
|
||||
const_start: data.const_start,
|
||||
enclosing: 0,
|
||||
|
@ -150,7 +150,7 @@ impl From<ScopeData> for SmooshScopeData {
|
|||
},
|
||||
ScopeData::Lexical(data) => Self {
|
||||
kind: SmooshScopeDataKind::Lexical,
|
||||
bindings: CVec::from(data.bindings.into_iter().map(|x| x.into()).collect()),
|
||||
bindings: CVec::from(data.base.bindings.into_iter().map(|x| x.into()).collect()),
|
||||
let_start: 0,
|
||||
const_start: data.const_start,
|
||||
enclosing: data.enclosing.into(),
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"ccbba839b0e9d3f2ea0106439920ed41476a7ca186a8e80584bb936775f1e91f","ast.json":"8bee02b419d90de0203ba7378aedecd5c94a447128b11231970119c9ecfecb77","generate_ast.py":"0c24431d9c07af42d7d17739c2e21465964151562437cfca093ceddde898bc93","src/arena.rs":"03ef07c963556160a6f1a85fd901833d7322f8a5f265c20d3e3543432dd2a96d","src/associated_data.rs":"028b7d2b370e75da153b50d86d9ff809e871d81a7fd3266e2d3727ce2bcc178d","src/dump_generated.rs":"a1368d31a8e3d286f230058e4a007ce7cd94240f2e59c0cc31c8a56756b1c1b3","src/json.rs":"ccc437c27f3fdaabb3d92b28eeb6bdee083bdf8014639ce09e7204a6529661a9","src/lib.rs":"b35553bedec9f6d88cc5194592f857dc13669559cbc8b206048c35299c4f86be","src/source_atom_set.rs":"1e6fb4be166c9fe4cf63ae6475f1abb12cb3dfa268250328a60f483a09e1481c","src/source_location.rs":"3832440ecec6de726262837072810410bddb45c075288386509511c153f6afd9","src/source_location_accessor_generated.rs":"4a016e4860a2b6b9b7637dff10c634255f6c1942231eb75224261679944fa169","src/source_slice_list.rs":"c82413b3081e091a3c4ce5d2c3624e54ecbeb0bb9952f10d373d10faf589955a","src/type_id_generated.rs":"c70cbdc0f84c2fd7e84fa6ef1614be22f63e52ffcbf2f93714c189dce3dad557","src/types_generated.rs":"965e0619315156b9fd918f26f6317aa98970b535a7df7442f163b23ee5eaf641","src/visit_generated.rs":"d09510127771be0c3a20c95ed48a4e4d387144e6cb08b02783a81739539111ed"},"package":null}
|
||||
{"files":{"Cargo.toml":"ccbba839b0e9d3f2ea0106439920ed41476a7ca186a8e80584bb936775f1e91f","ast.json":"8bee02b419d90de0203ba7378aedecd5c94a447128b11231970119c9ecfecb77","generate_ast.py":"0c24431d9c07af42d7d17739c2e21465964151562437cfca093ceddde898bc93","src/arena.rs":"03ef07c963556160a6f1a85fd901833d7322f8a5f265c20d3e3543432dd2a96d","src/associated_data.rs":"aad369f45eca0506632d3c6aa2f487debb81d0dbc5a73eda46ee97478d51eaf3","src/dump_generated.rs":"a1368d31a8e3d286f230058e4a007ce7cd94240f2e59c0cc31c8a56756b1c1b3","src/json.rs":"ccc437c27f3fdaabb3d92b28eeb6bdee083bdf8014639ce09e7204a6529661a9","src/lib.rs":"b35553bedec9f6d88cc5194592f857dc13669559cbc8b206048c35299c4f86be","src/source_atom_set.rs":"1e6fb4be166c9fe4cf63ae6475f1abb12cb3dfa268250328a60f483a09e1481c","src/source_location.rs":"3832440ecec6de726262837072810410bddb45c075288386509511c153f6afd9","src/source_location_accessor_generated.rs":"4a016e4860a2b6b9b7637dff10c634255f6c1942231eb75224261679944fa169","src/source_slice_list.rs":"c82413b3081e091a3c4ce5d2c3624e54ecbeb0bb9952f10d373d10faf589955a","src/type_id_generated.rs":"c70cbdc0f84c2fd7e84fa6ef1614be22f63e52ffcbf2f93714c189dce3dad557","src/types_generated.rs":"965e0619315156b9fd918f26f6317aa98970b535a7df7442f163b23ee5eaf641","src/visit_generated.rs":"d09510127771be0c3a20c95ed48a4e4d387144e6cb08b02783a81739539111ed"},"package":null}
|
|
@ -4,13 +4,13 @@ use crate::SourceLocation;
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||
pub struct Key {
|
||||
struct Key {
|
||||
type_id: NodeTypeId,
|
||||
loc: SourceLocation,
|
||||
}
|
||||
|
||||
impl Key {
|
||||
pub fn new<NodeT>(node: &NodeT) -> Self
|
||||
fn new<NodeT>(node: &NodeT) -> Self
|
||||
where
|
||||
NodeT: SourceLocationAccessor + NodeTypeIdAccessor,
|
||||
{
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"00c740f44b5681e3277e519d2e143e6edfbff186ca31a07ddce2eb46b803ddd7","src/array_emitter.rs":"bbc6528321f1d11d7c86c4f2bfdcfc9dced8f0b8b1c30c9f0a5355f300d196b6","src/ast_emitter.rs":"75ffb4b14483ac450b6e8c868a1b589a0d2a181ec59970ccc6c1146461f5862c","src/block_emitter.rs":"2aad01fd24b4165fe11d0f05949690d6a4010aa52d59203c0b7a923001cb540c","src/compilation_info.rs":"593509d0699213e07336d38279dbaa5fbcdff5969be8a357d4e9858e59091b46","src/control_structures.rs":"5d7ec0cc3234cba80d27d2f298eb39cefa135a6d0cb66247ebdd0711269867aa","src/dis.rs":"4a335d813fa965482ca0f20a7b9295a55ce7625b577d42bd8b33b156b81c6306","src/emitter.rs":"33598c3b3b29a8d226fdf58284707c7428cf0103732e052469e4c1513d961ba9","src/emitter_scope.rs":"0908a6a1587dc2eeb63115c483c4b126e214cd0a2bb390b399f5083ba7c48218","src/expression_emitter.rs":"f8e02785dffb179bbe9fe58e45bbfccc08adc3ad0a071a0073bed0feedc8ed9a","src/function_declaration_emitter.rs":"919fa60d230d0be59bd7872ffe0179adb923e70012160088ed6975952a13e1af","src/lib.rs":"31bf61e0527907e45d58d3a554825bf060e55d2d8c711627a41e03f82e8c2999","src/object_emitter.rs":"998423b3d6ef8797fadef6763803627df72fde292b1b34d6a41b2e66a331a181","src/reference_op_emitter.rs":"f3641a7c94f648b146d2e93321a9a1968a5bcedcccdd325c834d4a62eddbb173","src/script_emitter.rs":"44a6be5ecdcde3c32d78d100a205d38be2591c7c2cc109967579af7393e09fe8"},"package":null}
|
||||
{"files":{"Cargo.toml":"00c740f44b5681e3277e519d2e143e6edfbff186ca31a07ddce2eb46b803ddd7","src/array_emitter.rs":"bbc6528321f1d11d7c86c4f2bfdcfc9dced8f0b8b1c30c9f0a5355f300d196b6","src/ast_emitter.rs":"f781c84197ca49e784733532c8d7155b884299ec3f941fa12e24ea668f0dc057","src/block_emitter.rs":"78965260d87a66c5324d6f3bdfea0f1938f8037f70adde148dbb2db599d1b2c0","src/compilation_info.rs":"8c8abbf777f03c6c9fc8dbf903c4f9f65304f96bc17f04a0868b3dd22cb1d113","src/control_structures.rs":"bdb186e98c14fa4e769b23b3dee4376683e6c6530af0856d55c055aff4398b84","src/dis.rs":"4a335d813fa965482ca0f20a7b9295a55ce7625b577d42bd8b33b156b81c6306","src/emitter.rs":"134f9f38f7f1adecfc43d230e602b7a87a89757af0fc1f6939bf181775ce4164","src/emitter_scope.rs":"07a904b6973bd2dbc1f9395022c15f11f6befc9b0fb4f2f251ccfc3f09aff380","src/expression_emitter.rs":"f8e02785dffb179bbe9fe58e45bbfccc08adc3ad0a071a0073bed0feedc8ed9a","src/function_declaration_emitter.rs":"74610fae178ed14c99e3dd7de01dc611718203adf0a85c7fa5209d27f1520379","src/lib.rs":"7d5c1d2f6fa25a2c18dd08c8361b30e1ceeb207c91542b3cd19f7cd2ab4ef131","src/object_emitter.rs":"998423b3d6ef8797fadef6763803627df72fde292b1b34d6a41b2e66a331a181","src/reference_op_emitter.rs":"4ead96ef4424e3937c3f73e22b4e103f97cee522b9926345caeddcf4643ff843","src/script_emitter.rs":"44a6be5ecdcde3c32d78d100a205d38be2591c7c2cc109967579af7393e09fe8"},"package":null}
|
|
@ -8,7 +8,10 @@ use crate::compilation_info::CompilationInfo;
|
|||
use crate::emitter::{EmitError, EmitOptions, InstructionWriter};
|
||||
use crate::emitter_scope::{EmitterScopeStack, NameLocation};
|
||||
use crate::expression_emitter::*;
|
||||
use crate::function_declaration_emitter::{FunctionDeclarationEmitter, LazyFunctionEmitter};
|
||||
use crate::function_declaration_emitter::{
|
||||
AnnexBFunctionDeclarationEmitter, LazyFunctionEmitter, LexicalFunctionDeclarationEmitter,
|
||||
TopLevelFunctionDeclarationEmitter,
|
||||
};
|
||||
use crate::object_emitter::*;
|
||||
use crate::reference_op_emitter::{
|
||||
AssignmentEmitter, CallEmitter, DeclarationEmitter, ElemReferenceEmitter, GetElemEmitter,
|
||||
|
@ -18,7 +21,6 @@ use crate::reference_op_emitter::{
|
|||
use crate::script_emitter::ScriptEmitter;
|
||||
use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSetIndex};
|
||||
use ast::types::*;
|
||||
use std::collections::HashSet;
|
||||
use stencil::opcode::Opcode;
|
||||
use stencil::regexp::RegExpItem;
|
||||
use stencil::result::EmitResult;
|
||||
|
@ -59,10 +61,6 @@ pub struct AstEmitter<'alloc, 'opt> {
|
|||
pub options: &'opt EmitOptions,
|
||||
pub compilation_info: &'opt mut CompilationInfo<'alloc>,
|
||||
pub control_stack: ControlStructureStack,
|
||||
|
||||
/// Holds the offset of top-level function declarations, to check if the
|
||||
/// given function function declaration is top-level.
|
||||
top_level_function_offsets: HashSet<usize>,
|
||||
}
|
||||
|
||||
impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
||||
|
@ -76,7 +74,6 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
|||
options,
|
||||
compilation_info,
|
||||
control_stack: ControlStructureStack::new(),
|
||||
top_level_function_offsets: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +83,7 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
|||
|
||||
fn emit_script(mut self, ast: &Script) -> Result<ScriptStencil, EmitError> {
|
||||
let scope_data_map = &self.compilation_info.scope_data_map;
|
||||
let function_map = &self.compilation_info.function_map;
|
||||
let function_declarations = &self.compilation_info.function_declarations;
|
||||
|
||||
let scope_index = scope_data_map.get_global_index();
|
||||
let scope_data = scope_data_map.get_global_at(scope_index);
|
||||
|
@ -94,13 +91,13 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
|||
let top_level_functions: Vec<&Function> = scope_data
|
||||
.functions
|
||||
.iter()
|
||||
.map(|key| *function_map.get(key).expect("function should exist"))
|
||||
.map(|key| {
|
||||
*function_declarations
|
||||
.get(key)
|
||||
.expect("function should exist")
|
||||
})
|
||||
.collect();
|
||||
|
||||
for fun in &top_level_functions {
|
||||
self.note_top_level_function(fun);
|
||||
}
|
||||
|
||||
ScriptEmitter {
|
||||
top_level_functions: top_level_functions.iter(),
|
||||
top_level_function: |emitter, fun| emitter.emit_top_level_function_declaration(fun),
|
||||
|
@ -120,12 +117,43 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
|||
.expect("FunctionStencil should be created");
|
||||
let fun_index = LazyFunctionEmitter { stencil_index }.emit(self);
|
||||
|
||||
FunctionDeclarationEmitter { fun: fun_index }.emit(self);
|
||||
TopLevelFunctionDeclarationEmitter { fun_index }.emit(self);
|
||||
|
||||
Err(EmitError::NotImplemented(
|
||||
"TODO: closed over bindings for function",
|
||||
"TODO: Populate FunctionStencil fields",
|
||||
))
|
||||
}
|
||||
|
||||
fn emit_non_top_level_function_declaration(&mut self, fun: &Function) -> Result<(), EmitError> {
|
||||
let stencil_index = *self
|
||||
.compilation_info
|
||||
.function_stencil_indices
|
||||
.get(fun)
|
||||
.expect("FunctionStencil should be created");
|
||||
|
||||
let is_annex_b = self
|
||||
.compilation_info
|
||||
.function_declaration_properties
|
||||
.is_annex_b(stencil_index);
|
||||
|
||||
let fun_index = LazyFunctionEmitter { stencil_index }.emit(self);
|
||||
|
||||
let name = self
|
||||
.compilation_info
|
||||
.functions
|
||||
.get(stencil_index)
|
||||
.name()
|
||||
.expect("Function declaration should have name");
|
||||
|
||||
if is_annex_b {
|
||||
AnnexBFunctionDeclarationEmitter { fun_index, name }.emit(self)?;
|
||||
} else {
|
||||
LexicalFunctionDeclarationEmitter { fun_index, name }.emit(self)?;
|
||||
}
|
||||
|
||||
Err(EmitError::NotImplemented(
|
||||
"TODO: Populate FunctionStencil fields",
|
||||
))
|
||||
//Ok(())
|
||||
}
|
||||
|
||||
fn emit_statement(&mut self, ast: &Statement) -> Result<(), EmitError> {
|
||||
|
@ -134,8 +162,26 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
|||
return Err(EmitError::NotImplemented("TODO: ClassDeclaration"));
|
||||
}
|
||||
Statement::BlockStatement { block, .. } => {
|
||||
let scope_data_map = &self.compilation_info.scope_data_map;
|
||||
let function_declarations = &self.compilation_info.function_declarations;
|
||||
|
||||
let scope_index = scope_data_map.get_index(block);
|
||||
let scope_data = scope_data_map.get_lexical_at(scope_index);
|
||||
|
||||
let functions: Vec<&Function> = scope_data
|
||||
.functions
|
||||
.iter()
|
||||
.map(|key| {
|
||||
*function_declarations
|
||||
.get(key)
|
||||
.expect("function should exist")
|
||||
})
|
||||
.collect();
|
||||
|
||||
BlockEmitter {
|
||||
scope_index: self.compilation_info.scope_data_map.get_index(block),
|
||||
functions: functions.iter(),
|
||||
function: |emitter, fun| emitter.emit_non_top_level_function_declaration(fun),
|
||||
statements: block.statements.iter(),
|
||||
statement: |emitter, statement| emitter.emit_statement(statement),
|
||||
}
|
||||
|
@ -255,26 +301,12 @@ impl<'alloc, 'opt> AstEmitter<'alloc, 'opt> {
|
|||
Statement::WithStatement { .. } => {
|
||||
return Err(EmitError::NotImplemented("TODO: WithStatement"));
|
||||
}
|
||||
Statement::FunctionDeclaration(fun) => {
|
||||
if !self.is_top_level_function(fun) {
|
||||
return Err(EmitError::NotImplemented(
|
||||
"TODO: non-top-level FunctionDeclaration",
|
||||
));
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(_) => {}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn note_top_level_function(&mut self, fun: &Function) {
|
||||
self.top_level_function_offsets.insert(fun.loc.start);
|
||||
}
|
||||
|
||||
fn is_top_level_function(&self, fun: &Function) -> bool {
|
||||
self.top_level_function_offsets.contains(&fun.loc.start)
|
||||
}
|
||||
|
||||
fn emit_variable_declaration_statement(
|
||||
&mut self,
|
||||
ast: &VariableDeclaration,
|
||||
|
|
|
@ -2,17 +2,21 @@ use crate::ast_emitter::AstEmitter;
|
|||
use crate::emitter::EmitError;
|
||||
use stencil::scope::ScopeIndex;
|
||||
|
||||
pub struct BlockEmitter<'a, StmtT, StmtF>
|
||||
pub struct BlockEmitter<'a, FuncT, FuncF, StmtT, StmtF>
|
||||
where
|
||||
FuncF: Fn(&mut AstEmitter, &FuncT) -> Result<(), EmitError>,
|
||||
StmtF: Fn(&mut AstEmitter, &StmtT) -> Result<(), EmitError>,
|
||||
{
|
||||
pub scope_index: ScopeIndex,
|
||||
pub functions: std::slice::Iter<'a, FuncT>,
|
||||
pub function: FuncF,
|
||||
pub statements: std::slice::Iter<'a, StmtT>,
|
||||
pub statement: StmtF,
|
||||
}
|
||||
|
||||
impl<'a, StmtT, StmtF> BlockEmitter<'a, StmtT, StmtF>
|
||||
impl<'a, FuncT, FuncF, StmtT, StmtF> BlockEmitter<'a, FuncT, FuncF, StmtT, StmtF>
|
||||
where
|
||||
FuncF: Fn(&mut AstEmitter, &FuncT) -> Result<(), EmitError>,
|
||||
StmtF: Fn(&mut AstEmitter, &StmtT) -> Result<(), EmitError>,
|
||||
{
|
||||
pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
|
||||
|
@ -22,6 +26,10 @@ where
|
|||
self.scope_index,
|
||||
);
|
||||
|
||||
for fun in self.functions {
|
||||
(self.function)(emitter, fun)?;
|
||||
}
|
||||
|
||||
for statement in self.statements {
|
||||
(self.statement)(emitter, statement)?;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ use ast::associated_data::AssociatedData;
|
|||
use ast::source_atom_set::SourceAtomSet;
|
||||
use ast::source_slice_list::SourceSliceList;
|
||||
use ast::types::Function;
|
||||
use scope::data::FunctionDeclarationPropertyMap;
|
||||
use std::collections::HashMap;
|
||||
use stencil::function::{FunctionStencilIndex, FunctionStencilList};
|
||||
use stencil::scope::ScopeDataMap;
|
||||
|
||||
|
@ -9,8 +11,9 @@ pub struct CompilationInfo<'alloc> {
|
|||
pub atoms: SourceAtomSet<'alloc>,
|
||||
pub slices: SourceSliceList<'alloc>,
|
||||
pub scope_data_map: ScopeDataMap,
|
||||
pub function_map: AssociatedData<&'alloc Function<'alloc>>,
|
||||
pub function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
|
||||
pub function_stencil_indices: AssociatedData<FunctionStencilIndex>,
|
||||
pub function_declaration_properties: FunctionDeclarationPropertyMap,
|
||||
pub functions: FunctionStencilList,
|
||||
}
|
||||
|
||||
|
@ -19,16 +22,18 @@ impl<'alloc> CompilationInfo<'alloc> {
|
|||
atoms: SourceAtomSet<'alloc>,
|
||||
slices: SourceSliceList<'alloc>,
|
||||
scope_data_map: ScopeDataMap,
|
||||
function_map: AssociatedData<&'alloc Function<'alloc>>,
|
||||
function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
|
||||
function_stencil_indices: AssociatedData<FunctionStencilIndex>,
|
||||
function_declaration_properties: FunctionDeclarationPropertyMap,
|
||||
functions: FunctionStencilList,
|
||||
) -> Self {
|
||||
Self {
|
||||
atoms,
|
||||
slices,
|
||||
scope_data_map,
|
||||
function_map,
|
||||
function_declarations,
|
||||
function_stencil_indices,
|
||||
function_declaration_properties,
|
||||
functions,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ast_emitter::AstEmitter;
|
||||
use crate::emitter::EmitError;
|
||||
use crate::emitter::InstructionWriter;
|
||||
use crate::emitter_scope::EmitterScopeDepth;
|
||||
use crate::emitter_scope::{EmitterScope, EmitterScopeDepth};
|
||||
use ast::source_atom_set::SourceAtomSetIndex;
|
||||
use stencil::bytecode_offset::{BytecodeOffset, BytecodeOffsetDiff};
|
||||
|
||||
|
@ -674,31 +674,35 @@ where
|
|||
};
|
||||
|
||||
// Step 2: find the current emitter scope
|
||||
let current_scope_index = emitter.scope_stack.current_depth();
|
||||
let mut parent_scope_note_index = emitter.scope_stack.get_current_scope_note_index();
|
||||
|
||||
// Step 3: iterate over scopes that have been entered since the enclosing scope,
|
||||
// add a scope note hole for each one as we exit
|
||||
// Step 3: iterate over scopes that have been entered since the
|
||||
// enclosing scope, add a scope note hole for each one as we exit
|
||||
let mut holes = Vec::new();
|
||||
let scope_indicies = emitter
|
||||
for item in emitter
|
||||
.scope_stack
|
||||
.scope_note_indices_from_to(&enclosing_emitter_scope_depth, ¤t_scope_index);
|
||||
let mut parent_scope_note_index = emitter
|
||||
.scope_stack
|
||||
.get_scope_note_index_for(current_scope_index);
|
||||
for maybe_scope_note_index in scope_indicies.iter().rev() {
|
||||
let scope_note_index = emitter
|
||||
.emit
|
||||
.enter_scope_hole(maybe_scope_note_index, parent_scope_note_index);
|
||||
holes.push(scope_note_index);
|
||||
parent_scope_note_index = Some(scope_note_index);
|
||||
.walk_up_to_including(enclosing_emitter_scope_depth)
|
||||
{
|
||||
// We're entering `item.outer` as a scope hole of `item.inner`.
|
||||
|
||||
let hole_scope_note_index = match item.inner {
|
||||
EmitterScope::Global(_) => panic!("global shouldn't be enclosed by other scope"),
|
||||
EmitterScope::Lexical(scope) => emitter.emit.enter_scope_hole_from_lexical(
|
||||
&item.outer.scope_note_index(),
|
||||
parent_scope_note_index,
|
||||
scope.has_environment_object(),
|
||||
),
|
||||
};
|
||||
holes.push(hole_scope_note_index);
|
||||
parent_scope_note_index = Some(hole_scope_note_index);
|
||||
}
|
||||
|
||||
// Step 4: perform the jump
|
||||
self.registered_jump.emit(emitter);
|
||||
|
||||
// Step 5: close each scope hole after the jump
|
||||
for scope_note_hole_index in holes.iter() {
|
||||
emitter.emit.leave_scope_hole(*scope_note_hole_index);
|
||||
for hole_scope_note_index in holes.iter() {
|
||||
emitter.emit.leave_scope_hole(*hole_scope_note_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1204,9 +1204,9 @@ impl InstructionWriter {
|
|||
self.write_g_c_thing_index(name_index);
|
||||
}
|
||||
|
||||
pub fn push_lexical_env(&mut self, lexical_scope_index: u32) {
|
||||
pub fn push_lexical_env(&mut self, lexical_scope_index: GCThingIndex) {
|
||||
self.emit_op(Opcode::PushLexicalEnv);
|
||||
self.write_u32(lexical_scope_index);
|
||||
self.write_g_c_thing_index(lexical_scope_index);
|
||||
}
|
||||
|
||||
pub fn pop_lexical_env(&mut self) {
|
||||
|
@ -1225,14 +1225,14 @@ impl InstructionWriter {
|
|||
self.emit_op(Opcode::FreshenLexicalEnv);
|
||||
}
|
||||
|
||||
pub fn push_var_env(&mut self, scope_index: u32) {
|
||||
pub fn push_var_env(&mut self, scope_index: GCThingIndex) {
|
||||
self.emit_op(Opcode::PushVarEnv);
|
||||
self.write_u32(scope_index);
|
||||
self.write_g_c_thing_index(scope_index);
|
||||
}
|
||||
|
||||
pub fn enter_with(&mut self, static_with_index: u32) {
|
||||
pub fn enter_with(&mut self, static_with_index: GCThingIndex) {
|
||||
self.emit_op(Opcode::EnterWith);
|
||||
self.write_u32(static_with_index);
|
||||
self.write_g_c_thing_index(static_with_index);
|
||||
}
|
||||
|
||||
pub fn leave_with(&mut self) {
|
||||
|
@ -1394,6 +1394,7 @@ impl InstructionWriter {
|
|||
scope_index: ScopeIndex,
|
||||
parent_scope_note_index: Option<ScopeNoteIndex>,
|
||||
next_frame_slot: FrameSlot,
|
||||
needs_environment_object: bool,
|
||||
) -> ScopeNoteIndex {
|
||||
self.update_max_frame_slots(next_frame_slot);
|
||||
|
||||
|
@ -1402,27 +1403,46 @@ impl InstructionWriter {
|
|||
let note_index =
|
||||
self.scope_notes
|
||||
.enter_scope(gcthing_index, offset, parent_scope_note_index);
|
||||
|
||||
if needs_environment_object {
|
||||
self.push_lexical_env(gcthing_index);
|
||||
}
|
||||
|
||||
note_index
|
||||
}
|
||||
|
||||
pub fn leave_lexical_scope(&mut self, index: ScopeNoteIndex) {
|
||||
self.debug_leave_lexical_env();
|
||||
pub fn leave_lexical_scope(&mut self, index: ScopeNoteIndex, needs_environment_object: bool) {
|
||||
self.emit_leave_lexical_scope(needs_environment_object);
|
||||
let offset = self.bytecode_offset();
|
||||
self.scope_notes.leave_scope(index, offset);
|
||||
}
|
||||
|
||||
pub fn enter_scope_hole(
|
||||
fn emit_leave_lexical_scope(&mut self, needs_environment_object: bool) {
|
||||
if needs_environment_object {
|
||||
self.pop_lexical_env();
|
||||
} else {
|
||||
self.debug_leave_lexical_env();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter_scope_hole_from_lexical(
|
||||
&mut self,
|
||||
maybe_scope_note_index: &Option<ScopeNoteIndex>,
|
||||
maybe_hole_scope_note_index: &Option<ScopeNoteIndex>,
|
||||
parent_scope_note_index: Option<ScopeNoteIndex>,
|
||||
needs_environment_object: bool,
|
||||
) -> ScopeNoteIndex {
|
||||
self.emit_leave_lexical_scope(needs_environment_object);
|
||||
self.enter_scope_hole(maybe_hole_scope_note_index, parent_scope_note_index)
|
||||
}
|
||||
|
||||
fn enter_scope_hole(
|
||||
&mut self,
|
||||
maybe_hole_scope_note_index: &Option<ScopeNoteIndex>,
|
||||
parent_scope_note_index: Option<ScopeNoteIndex>,
|
||||
) -> ScopeNoteIndex {
|
||||
// TODO: the bytecode sequence before leaving scope (entering hole) depends on the kind
|
||||
// of scope (and also controls). This is currently only debug_leave_lexical_env because
|
||||
// there's only simple lexical scope.
|
||||
self.debug_leave_lexical_env();
|
||||
let offset = self.bytecode_offset();
|
||||
|
||||
let gcthing_index = match maybe_scope_note_index {
|
||||
let gcthing_index = match maybe_hole_scope_note_index {
|
||||
Some(index) => self.scope_notes.get_scope_hole_gcthing_index(index),
|
||||
None => self
|
||||
.body_scope_index
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
use crate::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;
|
||||
|
@ -20,6 +22,7 @@ pub enum NameLocation {
|
|||
Dynamic,
|
||||
Global(BindingKind),
|
||||
FrameSlot(FrameSlot, BindingKind),
|
||||
EnvironmentCoord(EnvironmentHops, EnvironmentSlot, BindingKind),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
|
@ -27,12 +30,26 @@ pub struct EmitterScopeDepth {
|
|||
index: usize,
|
||||
}
|
||||
|
||||
impl EmitterScopeDepth {
|
||||
fn has_parent(&self) -> bool {
|
||||
self.index > 0
|
||||
}
|
||||
|
||||
fn parent(&self) -> Self {
|
||||
debug_assert!(self.has_parent());
|
||||
|
||||
Self {
|
||||
index: self.index - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- EmitterScope types
|
||||
//
|
||||
// These types are the variants of enum EmitterScope.
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GlobalEmitterScope {
|
||||
pub struct GlobalEmitterScope {
|
||||
cache: HashMap<SourceAtomSetIndex, NameLocation>,
|
||||
}
|
||||
|
||||
|
@ -59,28 +76,59 @@ impl GlobalEmitterScope {
|
|||
fn scope_note_index(&self) -> Option<ScopeNoteIndex> {
|
||||
None
|
||||
}
|
||||
|
||||
fn has_environment_object(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
struct LexicalEnvironmentObject {}
|
||||
impl LexicalEnvironmentObject {
|
||||
fn first_free_slot() -> u32 {
|
||||
// FIXME: This is the value of
|
||||
// `JSSLOT_FREE(&LexicalEnvironmentObject::class_)`
|
||||
// in SpiderMonkey
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LexicalEmitterScope {
|
||||
cache: HashMap<SourceAtomSetIndex, NameLocation>,
|
||||
next_frame_slot: FrameSlot,
|
||||
needs_environment_object: bool,
|
||||
scope_note_index: Option<ScopeNoteIndex>,
|
||||
}
|
||||
|
||||
impl LexicalEmitterScope {
|
||||
pub fn new(data: &LexicalScopeData, first_frame_slot: FrameSlot) -> Self {
|
||||
let is_all_bindings_closed_over = data.base.is_all_bindings_closed_over();
|
||||
let mut needs_environment_object = false;
|
||||
|
||||
let mut cache = HashMap::new();
|
||||
let mut slot = first_frame_slot;
|
||||
let mut frame_slot = first_frame_slot;
|
||||
let mut env_slot = EnvironmentSlot::new(LexicalEnvironmentObject::first_free_slot());
|
||||
for item in data.iter() {
|
||||
// FIXME: support environment (item.is_closed_over()).
|
||||
cache.insert(item.name(), NameLocation::FrameSlot(slot, item.kind()));
|
||||
slot.next();
|
||||
if is_all_bindings_closed_over || item.is_closed_over() {
|
||||
cache.insert(
|
||||
item.name(),
|
||||
NameLocation::EnvironmentCoord(EnvironmentHops::new(0), env_slot, item.kind()),
|
||||
);
|
||||
env_slot.next();
|
||||
needs_environment_object = true;
|
||||
} else {
|
||||
cache.insert(
|
||||
item.name(),
|
||||
NameLocation::FrameSlot(frame_slot, item.kind()),
|
||||
);
|
||||
frame_slot.next();
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
cache,
|
||||
next_frame_slot: slot,
|
||||
next_frame_slot: frame_slot,
|
||||
needs_environment_object,
|
||||
scope_note_index: None,
|
||||
}
|
||||
}
|
||||
|
@ -99,11 +147,15 @@ impl LexicalEmitterScope {
|
|||
fn scope_note_index(&self) -> Option<ScopeNoteIndex> {
|
||||
self.scope_note_index
|
||||
}
|
||||
|
||||
pub fn has_environment_object(&self) -> bool {
|
||||
self.needs_environment_object
|
||||
}
|
||||
}
|
||||
|
||||
/// The information about a scope needed for emitting bytecode.
|
||||
#[derive(Debug)]
|
||||
enum EmitterScope {
|
||||
pub enum EmitterScope {
|
||||
Global(GlobalEmitterScope),
|
||||
Lexical(LexicalEmitterScope),
|
||||
}
|
||||
|
@ -129,6 +181,13 @@ impl EmitterScope {
|
|||
EmitterScope::Lexical(scope) => scope.scope_note_index(),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_environment_object(&self) -> bool {
|
||||
match self {
|
||||
EmitterScope::Global(scope) => scope.has_environment_object(),
|
||||
EmitterScope::Lexical(scope) => scope.has_environment_object(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Stack that tracks the current scope chain while emitting bytecode.
|
||||
|
@ -176,7 +235,7 @@ impl EmitterScopeStack {
|
|||
// Enter global scope here, before emitting any name ops below.
|
||||
emit.enter_global_scope(scope_index);
|
||||
|
||||
if scope_data.bindings.len() > 0 {
|
||||
if scope_data.base.bindings.len() > 0 {
|
||||
emit.check_global_or_eval_decl();
|
||||
}
|
||||
|
||||
|
@ -247,14 +306,18 @@ impl EmitterScopeStack {
|
|||
) {
|
||||
let mut scope_data = scope_data_map.get_lexical_at_mut(scope_index);
|
||||
|
||||
let first_frame_slot = self.innermost().next_frame_slot();
|
||||
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;
|
||||
|
||||
let mut 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);
|
||||
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);
|
||||
|
@ -273,6 +336,7 @@ impl EmitterScopeStack {
|
|||
lexical_scope
|
||||
.scope_note_index
|
||||
.expect("scope note index should be populated"),
|
||||
lexical_scope.needs_environment_object,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -283,43 +347,88 @@ impl EmitterScopeStack {
|
|||
///
|
||||
/// [1]: https://tc39.es/ecma262/#sec-resolvebinding
|
||||
pub fn lookup_name(&mut self, name: SourceAtomSetIndex) -> NameLocation {
|
||||
let mut hops = EnvironmentHops::new(0);
|
||||
|
||||
for scope in self.scope_stack.iter().rev() {
|
||||
if let Some(loc) = scope.lookup_name(name) {
|
||||
// FIXME: handle hops in aliased var.
|
||||
return loc;
|
||||
return match loc {
|
||||
NameLocation::EnvironmentCoord(orig_hops, slot, kind) => {
|
||||
debug_assert!(u8::from(orig_hops) == 0u8);
|
||||
NameLocation::EnvironmentCoord(hops, slot, kind)
|
||||
}
|
||||
_ => loc,
|
||||
};
|
||||
}
|
||||
if scope.has_environment_object() {
|
||||
hops.next();
|
||||
}
|
||||
}
|
||||
|
||||
NameLocation::Dynamic
|
||||
}
|
||||
|
||||
pub fn current_depth(&mut self) -> EmitterScopeDepth {
|
||||
pub fn current_depth(&self) -> EmitterScopeDepth {
|
||||
EmitterScopeDepth {
|
||||
index: self.scope_stack.len() - 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scope_note_indices_from_to(
|
||||
&self,
|
||||
from: &EmitterScopeDepth,
|
||||
to: &EmitterScopeDepth,
|
||||
) -> Vec<Option<ScopeNoteIndex>> {
|
||||
let mut indices = Vec::new();
|
||||
for scope in self
|
||||
.scope_stack
|
||||
.iter()
|
||||
.skip(from.index)
|
||||
.take(to.index - from.index)
|
||||
{
|
||||
indices.push(scope.scope_note_index());
|
||||
}
|
||||
indices
|
||||
/// Walk the scope stack up to and including `to` depth.
|
||||
/// See EmitterScopeWalker for the details.
|
||||
pub fn walk_up_to_including<'a>(&'a self, to: EmitterScopeDepth) -> EmitterScopeWalker<'a> {
|
||||
EmitterScopeWalker::new(self, to)
|
||||
}
|
||||
|
||||
pub fn get_scope_note_index_for(&self, index: EmitterScopeDepth) -> Option<ScopeNoteIndex> {
|
||||
pub fn get_current_scope_note_index(&self) -> Option<ScopeNoteIndex> {
|
||||
self.innermost().scope_note_index()
|
||||
}
|
||||
|
||||
fn get<'a>(&'a self, index: EmitterScopeDepth) -> &'a EmitterScope {
|
||||
self.scope_stack
|
||||
.get(index.index)
|
||||
.expect("scope should exist")
|
||||
.scope_note_index()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 }`.
|
||||
pub struct 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();
|
||||
|
||||
Self { stack, to, current }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EmitterScopeWalkItem<'a> {
|
||||
pub outer: &'a EmitterScope,
|
||||
pub inner: &'a EmitterScope,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for EmitterScopeWalker<'a> {
|
||||
type Item = EmitterScopeWalkItem<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<EmitterScopeWalkItem<'a>> {
|
||||
if self.current == self.to {
|
||||
return None;
|
||||
}
|
||||
|
||||
let outer_index = self.current.parent();
|
||||
let inner_index = self.current;
|
||||
self.current = outer_index;
|
||||
|
||||
Some(EmitterScopeWalkItem {
|
||||
inner: self.stack.get(inner_index),
|
||||
outer: self.stack.get(outer_index),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::ast_emitter::AstEmitter;
|
||||
use crate::emitter::EmitError;
|
||||
use crate::reference_op_emitter::{AssignmentEmitter, DeclarationEmitter, NameReferenceEmitter};
|
||||
use ast::source_atom_set::SourceAtomSetIndex;
|
||||
use stencil::function::FunctionStencilIndex;
|
||||
use stencil::gcthings::GCThingIndex;
|
||||
|
||||
|
@ -12,13 +15,53 @@ impl LazyFunctionEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FunctionDeclarationEmitter {
|
||||
pub fun: GCThingIndex,
|
||||
pub struct TopLevelFunctionDeclarationEmitter {
|
||||
pub fun_index: GCThingIndex,
|
||||
}
|
||||
|
||||
impl FunctionDeclarationEmitter {
|
||||
impl TopLevelFunctionDeclarationEmitter {
|
||||
pub fn emit(self, emitter: &mut AstEmitter) {
|
||||
emitter.emit.lambda(self.fun);
|
||||
emitter.emit.lambda(self.fun_index);
|
||||
emitter.emit.def_fun();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LexicalFunctionDeclarationEmitter {
|
||||
pub name: SourceAtomSetIndex,
|
||||
pub fun_index: GCThingIndex,
|
||||
}
|
||||
|
||||
impl LexicalFunctionDeclarationEmitter {
|
||||
pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
|
||||
DeclarationEmitter {
|
||||
lhs: |emitter| {
|
||||
Ok(NameReferenceEmitter { name: self.name }.emit_for_declaration(emitter))
|
||||
},
|
||||
rhs: |emitter| {
|
||||
emitter.emit.lambda(self.fun_index);
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
.emit(emitter)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnnexBFunctionDeclarationEmitter {
|
||||
pub name: SourceAtomSetIndex,
|
||||
pub fun_index: GCThingIndex,
|
||||
}
|
||||
|
||||
impl AnnexBFunctionDeclarationEmitter {
|
||||
pub fn emit(self, emitter: &mut AstEmitter) -> Result<(), EmitError> {
|
||||
AssignmentEmitter {
|
||||
lhs: |emitter| {
|
||||
Ok(NameReferenceEmitter { name: self.name }.emit_for_assignment(emitter))
|
||||
},
|
||||
rhs: |emitter| {
|
||||
emitter.emit.lambda(self.fun_index);
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
.emit(emitter)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,16 +34,18 @@ pub fn emit<'alloc>(
|
|||
) -> Result<EmitResult<'alloc>, EmitError> {
|
||||
let ScopePassResult {
|
||||
scope_data_map,
|
||||
function_map,
|
||||
function_declarations,
|
||||
function_stencil_indices,
|
||||
function_declaration_properties,
|
||||
functions,
|
||||
} = scope::generate_scope_data(ast);
|
||||
let compilation_info = CompilationInfo::new(
|
||||
atoms,
|
||||
slices,
|
||||
scope_data_map,
|
||||
function_map,
|
||||
function_declarations,
|
||||
function_stencil_indices,
|
||||
function_declaration_properties,
|
||||
functions,
|
||||
);
|
||||
ast_emitter::emit_program(ast, options, compilation_info)
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::ast_emitter::AstEmitter;
|
|||
use crate::emitter::EmitError;
|
||||
use crate::emitter_scope::NameLocation;
|
||||
use ast::source_atom_set::SourceAtomSetIndex;
|
||||
use stencil::env_coord::{EnvironmentHops, EnvironmentSlot};
|
||||
use stencil::frame_slot::FrameSlot;
|
||||
use stencil::gcthings::GCThingIndex;
|
||||
use stencil::scope::BindingKind;
|
||||
|
@ -12,6 +13,8 @@ enum AssignmentReferenceKind {
|
|||
GlobalLexical(GCThingIndex),
|
||||
FrameSlotLexical(FrameSlot),
|
||||
FrameSlotNonLexical(FrameSlot),
|
||||
EnvironmentCoordLexical(EnvironmentHops, EnvironmentSlot),
|
||||
EnvironmentCoordNonLexical(EnvironmentHops, EnvironmentSlot),
|
||||
Dynamic(GCThingIndex),
|
||||
#[allow(dead_code)]
|
||||
Prop(GCThingIndex),
|
||||
|
@ -37,6 +40,8 @@ impl AssignmentReference {
|
|||
AssignmentReferenceKind::GlobalLexical(_) => 1,
|
||||
AssignmentReferenceKind::FrameSlotLexical(_) => 0,
|
||||
AssignmentReferenceKind::FrameSlotNonLexical(_) => 0,
|
||||
AssignmentReferenceKind::EnvironmentCoordLexical(_, _) => 0,
|
||||
AssignmentReferenceKind::EnvironmentCoordNonLexical(_, _) => 0,
|
||||
AssignmentReferenceKind::Dynamic(_) => 1,
|
||||
AssignmentReferenceKind::Prop(_) => 1,
|
||||
AssignmentReferenceKind::Elem => 2,
|
||||
|
@ -49,6 +54,7 @@ enum DeclarationReferenceKind {
|
|||
GlobalVar(GCThingIndex),
|
||||
GlobalLexical(GCThingIndex),
|
||||
FrameSlot(FrameSlot),
|
||||
EnvironmentCoord(EnvironmentHops, EnvironmentSlot),
|
||||
}
|
||||
|
||||
// See DeclarationReferenceEmitter.
|
||||
|
@ -76,7 +82,7 @@ enum ValueIsOnStack {
|
|||
Yes,
|
||||
}
|
||||
|
||||
fn check_temporary_dead_zone(
|
||||
fn check_frame_temporary_dead_zone(
|
||||
emitter: &mut AstEmitter,
|
||||
slot: FrameSlot,
|
||||
is_on_stack: ValueIsOnStack,
|
||||
|
@ -102,6 +108,33 @@ fn check_temporary_dead_zone(
|
|||
// [stack] VAL?
|
||||
}
|
||||
|
||||
fn check_env_temporary_dead_zone(
|
||||
emitter: &mut AstEmitter,
|
||||
hops: EnvironmentHops,
|
||||
slot: EnvironmentSlot,
|
||||
is_on_stack: ValueIsOnStack,
|
||||
) {
|
||||
// FIXME: Use cache to avoid emitting check_lexical twice or more.
|
||||
// FIXME: Support aliased lexical.
|
||||
|
||||
// [stack] VAL?
|
||||
|
||||
if is_on_stack == ValueIsOnStack::No {
|
||||
emitter.emit.get_aliased_var(hops.into(), slot.into());
|
||||
// [stack] VAL
|
||||
}
|
||||
|
||||
emitter.emit.check_aliased_lexical(hops.into(), slot.into());
|
||||
// [stack] VAL
|
||||
|
||||
if is_on_stack == ValueIsOnStack::No {
|
||||
emitter.emit.pop();
|
||||
// [stack]
|
||||
}
|
||||
|
||||
// [stack] VAL?
|
||||
}
|
||||
|
||||
// See *ReferenceEmitter.
|
||||
// This uses struct to hide the details from the consumer.
|
||||
#[derive(Debug)]
|
||||
|
@ -140,7 +173,15 @@ impl GetNameEmitter {
|
|||
// [stack] VAL
|
||||
|
||||
if kind == BindingKind::Let || kind == BindingKind::Const {
|
||||
check_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
|
||||
check_frame_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
|
||||
// [stack] VAL
|
||||
}
|
||||
}
|
||||
NameLocation::EnvironmentCoord(hops, slot, kind) => {
|
||||
emitter.emit.get_aliased_var(hops.into(), slot.into());
|
||||
|
||||
if kind == BindingKind::Let || kind == BindingKind::Const {
|
||||
check_env_temporary_dead_zone(emitter, hops, slot, ValueIsOnStack::Yes);
|
||||
// [stack] VAL
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +358,19 @@ impl NameReferenceEmitter {
|
|||
// [stack] CALLEE
|
||||
|
||||
if kind == BindingKind::Let || kind == BindingKind::Const {
|
||||
check_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
|
||||
check_frame_temporary_dead_zone(emitter, slot, ValueIsOnStack::Yes);
|
||||
// [stack] CALLEE
|
||||
}
|
||||
|
||||
emitter.emit.undefined();
|
||||
// [stack] CALLEE THIS
|
||||
}
|
||||
NameLocation::EnvironmentCoord(hops, slot, kind) => {
|
||||
emitter.emit.get_aliased_var(hops.into(), slot.into());
|
||||
// [stack] CALLEE
|
||||
|
||||
if kind == BindingKind::Let || kind == BindingKind::Const {
|
||||
check_env_temporary_dead_zone(emitter, hops, slot, ValueIsOnStack::Yes);
|
||||
// [stack] CALLEE
|
||||
}
|
||||
|
||||
|
@ -361,6 +414,17 @@ impl NameReferenceEmitter {
|
|||
AssignmentReference::new(AssignmentReferenceKind::FrameSlotNonLexical(slot))
|
||||
}
|
||||
}
|
||||
NameLocation::EnvironmentCoord(hops, slot, kind) => {
|
||||
if kind == BindingKind::Let || kind == BindingKind::Const {
|
||||
AssignmentReference::new(AssignmentReferenceKind::EnvironmentCoordLexical(
|
||||
hops, slot,
|
||||
))
|
||||
} else {
|
||||
AssignmentReference::new(AssignmentReferenceKind::EnvironmentCoordNonLexical(
|
||||
hops, slot,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -387,6 +451,10 @@ impl NameReferenceEmitter {
|
|||
NameLocation::FrameSlot(slot, _kind) => {
|
||||
DeclarationReference::new(DeclarationReferenceKind::FrameSlot(slot))
|
||||
}
|
||||
NameLocation::EnvironmentCoord(hops, slot, _kind) => {
|
||||
// FIXME: does this happen????
|
||||
DeclarationReference::new(DeclarationReferenceKind::EnvironmentCoord(hops, slot))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -636,7 +704,7 @@ where
|
|||
AssignmentReferenceKind::FrameSlotLexical(slot) => {
|
||||
// [stack] VAL
|
||||
|
||||
check_temporary_dead_zone(emitter, slot, ValueIsOnStack::No);
|
||||
check_frame_temporary_dead_zone(emitter, slot, ValueIsOnStack::No);
|
||||
// [stack] VAL
|
||||
|
||||
emitter.emit.set_local(slot.into());
|
||||
|
@ -648,6 +716,21 @@ where
|
|||
emitter.emit.set_local(slot.into());
|
||||
// [stack] VAL
|
||||
}
|
||||
AssignmentReferenceKind::EnvironmentCoordLexical(hops, slot) => {
|
||||
// [stack] VAL
|
||||
|
||||
check_env_temporary_dead_zone(emitter, hops, slot, ValueIsOnStack::No);
|
||||
// [stack] VAL
|
||||
|
||||
emitter.emit.set_aliased_var(hops.into(), slot.into());
|
||||
// [stack] VAL
|
||||
}
|
||||
AssignmentReferenceKind::EnvironmentCoordNonLexical(hops, slot) => {
|
||||
// [stack] VAL
|
||||
|
||||
emitter.emit.set_aliased_var(hops.into(), slot.into());
|
||||
// [stack] VAL
|
||||
}
|
||||
AssignmentReferenceKind::Prop(key_index) => {
|
||||
// [stack] OBJ VAL
|
||||
|
||||
|
@ -708,6 +791,12 @@ where
|
|||
emitter.emit.init_lexical(slot.into());
|
||||
// [stack] VAL
|
||||
}
|
||||
DeclarationReferenceKind::EnvironmentCoord(hops, slot) => {
|
||||
// [stack] VAL
|
||||
|
||||
emitter.emit.init_aliased_lexical(hops.into(), slot.into());
|
||||
// [stack] VAL
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"553be3c198fe555913bbeb7473b24e0e1fff12e48890a2e399b311df8a97c814","src/ast_builder.rs":"8b10743ebbc3390d1158cb44ff5c87fbb653d62521f3e1274565d0061eebe095","src/context_stack.rs":"29331d03cd4c8ee9283cb426ebe893b7ba6ad6d8a69016399c4d92a81cb1363b","src/declaration_kind.rs":"fdfda2fe408cce1c637d17fee0813160619450472c6de9befc36ebeed892cc3c","src/early_error_checker.rs":"150a106a8f0901b72ae40581f0c12f785983514cbc9042404ed6cf4315693d60","src/early_errors.rs":"8674454af7ac5efe51eb6a8e2abe088aad5560e0a0bd88a3eae66c90f1527149","src/error.rs":"507e4dd9c66720f3da2db135c3024392d8aaac5ccdb90c7f7463ccb2eff7efa8","src/lib.rs":"a40b11e1dda1afcccef5fc86a2030c326d38feb31e24596e602930dcad28f1ec","src/parser_tables_generated.rs":"2dc9609189992d135583ad0a7ca3b1b261bf3cc86d4ae73df1ce3f822bef54de","src/stack_value_generated.rs":"d8696a671368e2565d589922e3a46d20667ed3e17e29953e69b970470e9639ee","src/token.rs":"479f4cb97d2e6bc654a70634f3809817cc73eaf749c845643beb3556b9ead383","src/traits/mod.rs":"bcc2fa63444ba4c763dc996f410a6871f2cdc3bde54e1924ca8cc25cba92674a"},"package":null}
|
||||
{"files":{"Cargo.toml":"553be3c198fe555913bbeb7473b24e0e1fff12e48890a2e399b311df8a97c814","src/ast_builder.rs":"8b10743ebbc3390d1158cb44ff5c87fbb653d62521f3e1274565d0061eebe095","src/context_stack.rs":"29331d03cd4c8ee9283cb426ebe893b7ba6ad6d8a69016399c4d92a81cb1363b","src/declaration_kind.rs":"fdfda2fe408cce1c637d17fee0813160619450472c6de9befc36ebeed892cc3c","src/early_error_checker.rs":"150a106a8f0901b72ae40581f0c12f785983514cbc9042404ed6cf4315693d60","src/early_errors.rs":"8674454af7ac5efe51eb6a8e2abe088aad5560e0a0bd88a3eae66c90f1527149","src/error.rs":"507e4dd9c66720f3da2db135c3024392d8aaac5ccdb90c7f7463ccb2eff7efa8","src/lib.rs":"a40b11e1dda1afcccef5fc86a2030c326d38feb31e24596e602930dcad28f1ec","src/parser_tables_generated.rs":"f929ecaa8e8ffdbac8a0ae5ebb96b115f72b21116890952e04af75cca5a37718","src/stack_value_generated.rs":"d8696a671368e2565d589922e3a46d20667ed3e17e29953e69b970470e9639ee","src/token.rs":"479f4cb97d2e6bc654a70634f3809817cc73eaf749c845643beb3556b9ead383","src/traits/mod.rs":"bcc2fa63444ba4c763dc996f410a6871f2cdc3bde54e1924ca8cc25cba92674a"},"package":null}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"500dc18629fd32dd7019a7967535d6fc53bf94dc7e6c305be46f4040d47cac9e","src/builder.rs":"a6c3a2192f8b55901fd41e80913fcc9f498f0b08d4097133821596803ebdce9b","src/free_name_tracker.rs":"94df3881bd8f5b0e67e2723cc3a2848461d7145dabb001f359fe124e54ed23bc","src/lib.rs":"9ac4537eb4423a48ddeb41bd0cfdcf04e3d4dcb1db1e53f49df5313dcd1fddf4","src/pass.rs":"dcd77a5de29a63ca8460846883681132325eb7c0ee97b8e9994599ac874fd355"},"package":null}
|
||||
{"files":{"Cargo.toml":"500dc18629fd32dd7019a7967535d6fc53bf94dc7e6c305be46f4040d47cac9e","src/builder.rs":"09e6c547da4098920aaf067d0fc97e00a41500afc52c4dbff4c96eb650b9ac55","src/data.rs":"baebda52ab0d962a0fc13c5db3dcd1173b701e55f248da466da6bcaf0890784e","src/free_name_tracker.rs":"94df3881bd8f5b0e67e2723cc3a2848461d7145dabb001f359fe124e54ed23bc","src/lib.rs":"16b1fe6659f977a547df15922b2864b81c4d452ad198409db4374e88c6df68bc","src/pass.rs":"121a2a63dfec1ad8658587de3932859428c6a04e175e5e6c3d0a8938e411e931"},"package":null}
|
|
@ -33,13 +33,15 @@
|
|||
//!
|
||||
//! [1]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
|
||||
|
||||
use crate::data::FunctionDeclarationPropertyMap;
|
||||
use crate::free_name_tracker::FreeNameTracker;
|
||||
use ast::associated_data::{AssociatedData, Key as AssociatedDataKey};
|
||||
use ast::associated_data::AssociatedData;
|
||||
use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSetIndex};
|
||||
use ast::source_location_accessor::SourceLocationAccessor;
|
||||
use ast::type_id::NodeTypeIdAccessor;
|
||||
use indexmap::set::IndexSet;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::hash_map::Keys;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use stencil::function::{
|
||||
FunctionFlags, FunctionStencil, FunctionStencilIndex, FunctionStencilList, FunctionSyntaxKind,
|
||||
SourceExtent,
|
||||
|
@ -318,6 +320,109 @@ enum ScopeKind {
|
|||
BlockStatementList,
|
||||
}
|
||||
|
||||
/// Index into BaseScopeData.bindings.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct BindingIndex {
|
||||
index: usize,
|
||||
}
|
||||
impl BindingIndex {
|
||||
fn new(index: usize) -> Self {
|
||||
Self { index }
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Self {
|
||||
Self {
|
||||
index: self.index + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BindingIndex> for usize {
|
||||
fn from(index: BindingIndex) -> usize {
|
||||
index.index
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PossiblyAnnexBFunction {
|
||||
name: SourceAtomSetIndex,
|
||||
owner_scope_index: ScopeIndex,
|
||||
binding_index: BindingIndex,
|
||||
stencil_index: FunctionStencilIndex,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PossiblyAnnexBFunctionList {
|
||||
functions: HashMap<SourceAtomSetIndex, Vec<PossiblyAnnexBFunction>>,
|
||||
}
|
||||
|
||||
impl PossiblyAnnexBFunctionList {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
functions: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn push(
|
||||
&mut self,
|
||||
name: SourceAtomSetIndex,
|
||||
owner_scope_index: ScopeIndex,
|
||||
binding_index: BindingIndex,
|
||||
stencil_index: FunctionStencilIndex,
|
||||
) {
|
||||
if let Some(functions) = self.functions.get_mut(&name) {
|
||||
functions.push(PossiblyAnnexBFunction {
|
||||
name,
|
||||
owner_scope_index,
|
||||
binding_index,
|
||||
stencil_index,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let mut functions = Vec::with_capacity(1);
|
||||
functions.push(PossiblyAnnexBFunction {
|
||||
name,
|
||||
owner_scope_index,
|
||||
binding_index,
|
||||
stencil_index,
|
||||
});
|
||||
self.functions.insert(name, functions);
|
||||
}
|
||||
|
||||
fn remove_if_exists(&mut self, name: SourceAtomSetIndex) {
|
||||
self.functions.remove(&name);
|
||||
}
|
||||
|
||||
fn mark_annex_b(
|
||||
&self,
|
||||
scopes: &mut ScopeDataList,
|
||||
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
|
||||
) {
|
||||
for functions in &mut self.functions.values() {
|
||||
for fun in functions {
|
||||
let scope = scopes.get_mut(fun.owner_scope_index);
|
||||
match scope {
|
||||
ScopeData::Lexical(data) => {
|
||||
data.mark_annex_b_function(fun.name, fun.binding_index.into());
|
||||
}
|
||||
_ => panic!("unexpected scope pointed by Annex B function"),
|
||||
}
|
||||
|
||||
function_declaration_properties.mark_annex_b(fun.stencil_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn names(&self) -> Keys<SourceAtomSetIndex, Vec<PossiblyAnnexBFunction>> {
|
||||
self.functions.keys()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.functions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Variables declared/used in GlobalDeclarationInstantiation.
|
||||
#[derive(Debug)]
|
||||
struct GlobalScopeBuilder {
|
||||
|
@ -325,7 +430,7 @@ struct GlobalScopeBuilder {
|
|||
/// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
|
||||
///
|
||||
/// Step 8. Let functionsToInitialize be a new empty List.
|
||||
functions_to_initialize: Vec<AssociatedDataKey>,
|
||||
functions_to_initialize: Vec<FunctionStencilIndex>,
|
||||
|
||||
/// Step 9. Let declaredFunctionNames be a new empty List.
|
||||
declared_function_names: IndexSet<SourceAtomSetIndex>,
|
||||
|
@ -402,10 +507,7 @@ impl GlobalScopeBuilder {
|
|||
self.const_names.push(name);
|
||||
}
|
||||
|
||||
fn declare_function<T>(&mut self, name: SourceAtomSetIndex, fun: &T)
|
||||
where
|
||||
T: SourceLocationAccessor + NodeTypeIdAccessor,
|
||||
{
|
||||
fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: FunctionStencilIndex) {
|
||||
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
|
||||
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
|
||||
//
|
||||
|
@ -439,8 +541,7 @@ impl GlobalScopeBuilder {
|
|||
|
||||
// Step 10.a.iv.4. Insert d as the first element of
|
||||
// functionsToInitialize.
|
||||
self.functions_to_initialize
|
||||
.push(AssociatedDataKey::new(fun));
|
||||
self.functions_to_initialize.push(fun_index);
|
||||
}
|
||||
|
||||
fn remove_function_names_from_var_names(&mut self) {
|
||||
|
@ -456,7 +557,117 @@ impl GlobalScopeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn into_scope_data(self) -> ScopeData {
|
||||
fn perform_annex_b(
|
||||
&mut self,
|
||||
scopes: &mut ScopeDataList,
|
||||
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
|
||||
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
|
||||
) {
|
||||
// Annex B
|
||||
// Changes to GlobalDeclarationInstantiation
|
||||
// https://tc39.es/ecma262/#sec-web-compat-globaldeclarationinstantiation
|
||||
//
|
||||
// Step 1. Let strict be IsStrict of script.
|
||||
//
|
||||
// FIXME: Once directives are supported, reflect it here.
|
||||
let strict = false;
|
||||
|
||||
// Step 2. If strict is false, then
|
||||
if strict {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2.a. Let declaredFunctionOrVarNames be a new empty List.
|
||||
// Step 2.b. Append to declaredFunctionOrVarNames the elements of
|
||||
// declaredFunctionNames.
|
||||
// Step 2.c. Append to declaredFunctionOrVarNames the elements of
|
||||
// declaredVarNames.
|
||||
//
|
||||
// NOTE: Use `self.declared_var_names` to avoid duplication against
|
||||
// `declaredVarNames`.
|
||||
// And duplication against `declaredFunctionNames` will be
|
||||
// removed in `remove_function_names_from_var_names`.
|
||||
|
||||
// Step 2.d. For each FunctionDeclaration f that is directly contained
|
||||
// in the StatementList of a Block, CaseClause, or
|
||||
// DefaultClause Contained within script, do
|
||||
//
|
||||
// NOTE: `possibly_annex_b_functions` contains all of them.
|
||||
|
||||
// Step 2.d.i. Let F be StringValue of the BindingIdentifier of f.
|
||||
// Step 2.d.ii. If replacing the FunctionDeclaration f with a
|
||||
// VariableStatement that has F as a BindingIdentifier
|
||||
// would not produce any Early Errors for script, then
|
||||
//
|
||||
// NOTE: Early Errors happen if any of top-level lexical has
|
||||
// the same name. Filter out those functions here.
|
||||
for n in &self.let_names {
|
||||
possibly_annex_b_functions.remove_if_exists(*n);
|
||||
}
|
||||
for n in &self.const_names {
|
||||
possibly_annex_b_functions.remove_if_exists(*n);
|
||||
}
|
||||
|
||||
// Step 2.d.ii.1. If env.HasLexicalDeclaration(F) is false, then
|
||||
// Step 2.d.ii.1.a. Let fnDefinable be ? env.CanDeclareGlobalVar(F).
|
||||
// Step 2.d.ii.1.b. If fnDefinable is true, then
|
||||
//
|
||||
// FIXME: Are these steps performed by any implementation?
|
||||
// https://github.com/tc39/ecma262/issues/2019
|
||||
|
||||
// Step 2.d.ii.1.b.i. NOTE: A var binding for F is only instantiated
|
||||
// here if it is neither a VarDeclaredName nor
|
||||
// the name of another FunctionDeclaration.
|
||||
// Step 2.d.ii.1.b.ii. If declaredFunctionOrVarNames does not
|
||||
// contain F, then
|
||||
// Step 2.d.ii.1.b.ii.1. Perform
|
||||
// ?env.CreateGlobalVarBinding(F, false).
|
||||
// Step 2.d.ii.1.b.ii.2. Append F to declaredFunctionOrVarNames.
|
||||
for n in possibly_annex_b_functions.names() {
|
||||
self.declared_var_names.insert(*n);
|
||||
}
|
||||
|
||||
// Step 2.d.ii.1.b.iii. When the FunctionDeclaration f is evaluated,
|
||||
// perform the following steps in place of the
|
||||
// FunctionDeclaration Evaluation algorithm
|
||||
// provided in
|
||||
// https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation :
|
||||
// Step 2.d.ii.1.b.iii.1. Let genv be the running execution
|
||||
// context's VariableEnvironment.
|
||||
// Step 2.d.ii.1.b.iii.2. Let benv be the running execution
|
||||
// context's LexicalEnvironment.
|
||||
// Step 2.d.ii.1.b.iii.3. Let fobj be
|
||||
// ! benv.GetBindingValue(F, false).
|
||||
// Step 2.d.ii.1.b.iii.4. Perform
|
||||
// ? genv.SetMutableBinding(F, fobj, false).
|
||||
// Step 2.d.ii.1.b.iii.5. Return NormalCompletion(empty).
|
||||
possibly_annex_b_functions.mark_annex_b(scopes, function_declaration_properties);
|
||||
}
|
||||
|
||||
fn into_scope_data(
|
||||
mut self,
|
||||
scopes: &mut ScopeDataList,
|
||||
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
|
||||
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
|
||||
) -> ScopeData {
|
||||
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
|
||||
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
|
||||
//
|
||||
// NOTE: Steps are reordered to match the order of binding in runtime.
|
||||
|
||||
// Step 13. NOTE: Annex B adds additional steps at this point.
|
||||
//
|
||||
// NOTE: Reordered here to reflect the change to
|
||||
// self.declared_var_names.
|
||||
self.perform_annex_b(
|
||||
scopes,
|
||||
function_declaration_properties,
|
||||
possibly_annex_b_functions,
|
||||
);
|
||||
|
||||
// Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
|
||||
self.remove_function_names_from_var_names();
|
||||
|
||||
let mut data = GlobalScopeData::new(
|
||||
self.declared_var_names.len() + self.declared_function_names.len(),
|
||||
self.let_names.len(),
|
||||
|
@ -464,16 +675,13 @@ impl GlobalScopeBuilder {
|
|||
self.functions_to_initialize,
|
||||
);
|
||||
|
||||
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
|
||||
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
|
||||
//
|
||||
// NOTE: Steps are reordered to match the order of binding in runtime.
|
||||
//
|
||||
// Step 18. For each String vn in declaredVarNames, in list order, do
|
||||
for n in &self.declared_var_names {
|
||||
// 18.a. Perform ? envRec.CreateGlobalVarBinding(vn, false).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over))
|
||||
}
|
||||
|
||||
// Step 17. For each Parse Node f in functionsToInitialize, do
|
||||
|
@ -483,10 +691,9 @@ impl GlobalScopeBuilder {
|
|||
// argument env.
|
||||
// Step 17.c. Perform
|
||||
// ? envRec.CreateGlobalFunctionBinding(fn, fo, false).
|
||||
//
|
||||
// FIXME: for Annex B functions, use `new`.
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new_top_level_function(*n, is_closed_over));
|
||||
}
|
||||
|
||||
|
@ -498,19 +705,29 @@ impl GlobalScopeBuilder {
|
|||
// Step 16.b.ii. Else,
|
||||
// Step 16.b.ii.1. Perform ? envRec.CreateMutableBinding(dn, false).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over))
|
||||
}
|
||||
for n in &self.const_names {
|
||||
// Step 16.b.i. If IsConstantDeclaration of d is true, then
|
||||
// Step 16.b.i.1. Perform ? envRec.CreateImmutableBinding(dn, true).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over))
|
||||
}
|
||||
|
||||
ScopeData::Global(data)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FunctionNameAndStencilIndex {
|
||||
name: SourceAtomSetIndex,
|
||||
stencil: FunctionStencilIndex,
|
||||
}
|
||||
|
||||
/// Variables declared/used in BlockDeclarationInstantiation
|
||||
#[derive(Debug)]
|
||||
struct BlockScopeBuilder {
|
||||
|
@ -519,7 +736,6 @@ struct BlockScopeBuilder {
|
|||
///
|
||||
/// Step 3. Let declarations be the LexicallyScopedDeclarations of code.
|
||||
let_names: Vec<SourceAtomSetIndex>,
|
||||
fun_names: Vec<SourceAtomSetIndex>,
|
||||
const_names: Vec<SourceAtomSetIndex>,
|
||||
|
||||
/// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
|
||||
|
@ -528,9 +744,7 @@ struct BlockScopeBuilder {
|
|||
/// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration, an
|
||||
/// AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
|
||||
/// then
|
||||
///
|
||||
/// FIXME: Support Annex B.
|
||||
functions: Vec<AssociatedDataKey>,
|
||||
functions: Vec<FunctionNameAndStencilIndex>,
|
||||
|
||||
/// Scope associated to this builder.
|
||||
scope_index: ScopeIndex,
|
||||
|
@ -541,7 +755,6 @@ impl BlockScopeBuilder {
|
|||
fn new(scope_index: ScopeIndex) -> Self {
|
||||
Self {
|
||||
let_names: Vec::new(),
|
||||
fun_names: Vec::new(),
|
||||
const_names: Vec::new(),
|
||||
functions: Vec::new(),
|
||||
scope_index,
|
||||
|
@ -565,34 +778,31 @@ impl BlockScopeBuilder {
|
|||
self.const_names.push(name);
|
||||
}
|
||||
|
||||
fn declare_function<T>(&mut self, name: SourceAtomSetIndex, fun: &T)
|
||||
where
|
||||
T: SourceLocationAccessor + NodeTypeIdAccessor,
|
||||
{
|
||||
fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: FunctionStencilIndex) {
|
||||
// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
|
||||
// https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
|
||||
//
|
||||
// Step 3. Let declarations be the LexicallyScopedDeclarations of code.
|
||||
|
||||
self.fun_names.push(name);
|
||||
|
||||
// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
|
||||
// https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
|
||||
//
|
||||
// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration, an
|
||||
// AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
|
||||
// then
|
||||
self.functions.push(AssociatedDataKey::new(fun));
|
||||
self.functions.push(FunctionNameAndStencilIndex {
|
||||
name,
|
||||
stencil: fun_index,
|
||||
});
|
||||
}
|
||||
|
||||
fn into_scope_data(self, enclosing: ScopeIndex) -> ScopeData {
|
||||
// FIXME: Before this, perform Annex B for functions.
|
||||
|
||||
fn into_scope_data(
|
||||
self,
|
||||
enclosing: ScopeIndex,
|
||||
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
|
||||
) -> ScopeData {
|
||||
let mut data = LexicalScopeData::new_block(
|
||||
self.let_names.len() + self.fun_names.len(),
|
||||
self.let_names.len() + self.functions.len(),
|
||||
self.const_names.len(),
|
||||
enclosing,
|
||||
self.functions,
|
||||
self.functions.iter().map(|n| n.stencil).collect(),
|
||||
);
|
||||
|
||||
// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
|
||||
|
@ -608,9 +818,11 @@ impl BlockScopeBuilder {
|
|||
// Step 4.a.ii. Else,
|
||||
// Step 4.a.ii.1. Perform ! envRec.CreateMutableBinding(dn, false).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over));
|
||||
}
|
||||
for n in &self.fun_names {
|
||||
for n in &self.functions {
|
||||
// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration,
|
||||
// an AsyncFunctionDeclaration,
|
||||
// or an AsyncGeneratorDeclaration, then
|
||||
|
@ -618,14 +830,21 @@ impl BlockScopeBuilder {
|
|||
// Step 4.b.ii. Let fo be InstantiateFunctionObject of d with
|
||||
// argument env.
|
||||
// Step 4.b.iii. Perform envRec.InitializeBinding(fn, fo).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(&n.name);
|
||||
let binding_index = BindingIndex::new(data.base.bindings.len());
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(n.name, is_closed_over));
|
||||
|
||||
possibly_annex_b_functions.push(n.name, self.scope_index, binding_index, n.stencil);
|
||||
}
|
||||
for n in &self.const_names {
|
||||
// Step 4.a.i. If IsConstantDeclaration of d is true, then
|
||||
// Step 4.a.i.1. Perform ! envRec.CreateImmutableBinding(dn, true).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over));
|
||||
}
|
||||
|
||||
ScopeData::Lexical(data)
|
||||
|
@ -679,7 +898,9 @@ impl FunctionExpressionScopeBuilder {
|
|||
// Step 4. Let name be StringValue of BindingIdentifier .
|
||||
// Step 5. Perform envRec.CreateImmutableBinding(name, false).
|
||||
let is_closed_over = self.name_tracker.is_closed_over_def(name);
|
||||
data.bindings.push(BindingName::new(*name, is_closed_over));
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*name, is_closed_over));
|
||||
|
||||
ScopeData::Lexical(data)
|
||||
}
|
||||
|
@ -976,10 +1197,84 @@ impl FunctionParametersScopeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
fn perform_annex_b(
|
||||
&mut self,
|
||||
scopes: &mut ScopeDataList,
|
||||
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
|
||||
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
|
||||
body_scope_builder: &mut FunctionBodyScopeBuilder,
|
||||
) {
|
||||
// Annex B
|
||||
// Changes to FunctionDeclarationInstantiation
|
||||
// https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
|
||||
//
|
||||
// Step 1. If strict is false, then
|
||||
//
|
||||
// FIXME: Once directives are supported, reflect it here.
|
||||
let strict = false;
|
||||
if strict {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 1.a. For each FunctionDeclaration f that is directly contained
|
||||
// in the StatementList of a Block, CaseClause, or
|
||||
// DefaultClause, do
|
||||
//
|
||||
// NOTE: `possibly_annex_b_functions` contains all of them.
|
||||
|
||||
// Step 1.a.i. Let F be StringValue of the BindingIdentifier of f.
|
||||
// Step 1.a.ii. If replacing the FunctionDeclaration f with a
|
||||
// VariableStatement that has F as a BindingIdentifier
|
||||
// would not produce any Early Errors for func and F is
|
||||
// not an element of parameterNames, then
|
||||
//
|
||||
// NOTE: Early Errors happen if any of top-level lexical has
|
||||
// the same name. Filter out those functions here.
|
||||
for n in &body_scope_builder.let_names {
|
||||
possibly_annex_b_functions.remove_if_exists(*n);
|
||||
}
|
||||
for n in &body_scope_builder.const_names {
|
||||
possibly_annex_b_functions.remove_if_exists(*n);
|
||||
}
|
||||
|
||||
// Step 1.a.ii.1. NOTE: A var binding for F is only instantiated here
|
||||
// if it is neither a VarDeclaredName, the name of a
|
||||
// formal parameter, or another FunctionDeclaration.
|
||||
//
|
||||
// NOTE: The binding is merged into the list of other var names.
|
||||
|
||||
// Step 1.a.ii.2. If initializedBindings does not contain F and F is
|
||||
// not "arguments", then
|
||||
possibly_annex_b_functions.remove_if_exists(CommonSourceAtomSetIndices::arguments());
|
||||
|
||||
// Step 1.a.ii.2.a. Perform ! varEnv.CreateMutableBinding(F, false).
|
||||
// Step 1.a.ii.2.b. Perform varEnv.InitializeBinding(F, undefined).
|
||||
// Step 1.a.ii.2.c. Append F to instantiatedVarNames.
|
||||
for n in possibly_annex_b_functions.names() {
|
||||
body_scope_builder.var_names.insert(*n);
|
||||
}
|
||||
|
||||
// Step 1.a.ii.3. When the FunctionDeclaration f is evaluated, perform
|
||||
// the following steps in place of the
|
||||
// FunctionDeclaration Evaluation algorithm provided in
|
||||
// https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation
|
||||
// Step 1.a.ii.3.a. Let fenv be the running execution context's
|
||||
// VariableEnvironment.
|
||||
// Step 1.a.ii.3.b. Let benv be the running execution context's
|
||||
// LexicalEnvironment.
|
||||
// Step 1.a.ii.3.c. Let fobj be ! benv.GetBindingValue(F, false).
|
||||
// Step 1.a.ii.3.d. Perform ! fenv.SetMutableBinding(F, fobj, false).
|
||||
// Step 1.a.ii.3.e. Return NormalCompletion(empty).
|
||||
possibly_annex_b_functions.mark_annex_b(scopes, function_declaration_properties);
|
||||
}
|
||||
|
||||
fn into_scope_data_set(
|
||||
self,
|
||||
mut self,
|
||||
scopes: &mut ScopeDataList,
|
||||
function_declaration_properties: &mut FunctionDeclarationPropertyMap,
|
||||
possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
|
||||
enclosing: ScopeIndex,
|
||||
body_scope_builder: FunctionBodyScopeBuilder,
|
||||
mut body_scope_builder: FunctionBodyScopeBuilder,
|
||||
) -> FunctionScopeDataSet {
|
||||
// FunctionDeclarationInstantiation ( func, argumentsList )
|
||||
// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
|
||||
|
@ -1037,6 +1332,17 @@ impl FunctionParametersScopeBuilder {
|
|||
// Step 20.f. Set the LexicalEnvironment of calleeContext to env.
|
||||
}
|
||||
|
||||
// Step 29. NOTE: Annex B adds additional steps at this point.
|
||||
//
|
||||
// NOTE: Reordered here to reflect the change to
|
||||
// body_scope_builder.var_names.
|
||||
self.perform_annex_b(
|
||||
scopes,
|
||||
function_declaration_properties,
|
||||
possibly_annex_b_functions,
|
||||
&mut body_scope_builder,
|
||||
);
|
||||
|
||||
let has_extra_body_var_scope = self.has_parameter_expressions;
|
||||
let function_var_names_count = if has_extra_body_var_scope {
|
||||
0
|
||||
|
@ -1052,6 +1358,9 @@ impl FunctionParametersScopeBuilder {
|
|||
enclosing,
|
||||
);
|
||||
|
||||
// FunctionDeclarationInstantiation ( func, argumentsList )
|
||||
// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
|
||||
//
|
||||
// Step 21. For each String paramName in parameterNames, do
|
||||
// Step 21.a. Let alreadyDeclared be envRec.HasBinding(paramName).
|
||||
// Step 21.b. NOTE: Early errors ensure that duplicate parameter names
|
||||
|
@ -1071,10 +1380,11 @@ impl FunctionParametersScopeBuilder {
|
|||
|| (!has_extra_body_var_scope
|
||||
&& body_scope_builder.name_tracker.is_closed_over_def(n));
|
||||
function_scope_data
|
||||
.base
|
||||
.bindings
|
||||
.push(Some(BindingName::new(*n, is_closed_over)))
|
||||
}
|
||||
None => function_scope_data.bindings.push(None),
|
||||
None => function_scope_data.base.bindings.push(None),
|
||||
}
|
||||
}
|
||||
for n in &self.non_positional_parameter_names {
|
||||
|
@ -1082,6 +1392,7 @@ impl FunctionParametersScopeBuilder {
|
|||
|| (!has_extra_body_var_scope
|
||||
&& body_scope_builder.name_tracker.is_closed_over_def(n));
|
||||
function_scope_data
|
||||
.base
|
||||
.bindings
|
||||
.push(Some(BindingName::new(*n, is_closed_over)))
|
||||
}
|
||||
|
@ -1144,6 +1455,7 @@ impl FunctionParametersScopeBuilder {
|
|||
// ! envRec.CreateMutableBinding(n, false).
|
||||
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
|
||||
function_scope_data
|
||||
.base
|
||||
.bindings
|
||||
.push(Some(BindingName::new(*n, is_closed_over)));
|
||||
|
||||
|
@ -1185,7 +1497,9 @@ impl FunctionParametersScopeBuilder {
|
|||
// Step 28.f.i.2. Perform
|
||||
// ! varEnvRec.CreateMutableBinding(n, false).
|
||||
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over));
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over));
|
||||
|
||||
// Step 28.f.i.3. If n is not an element of parameterBindings or if
|
||||
// n is an element of functionNames, let
|
||||
|
@ -1204,9 +1518,6 @@ impl FunctionParametersScopeBuilder {
|
|||
ScopeData::Var(data)
|
||||
};
|
||||
|
||||
// Step 29. NOTE: Annex B.3.3.1 adds additional steps at this point.
|
||||
// FIXME
|
||||
|
||||
// Step 30. If strict is false, then
|
||||
// Step 30.a. Let lexEnv be NewDeclarativeEnvironment(varEnv).
|
||||
// Step 30.b. NOTE: Non-strict functions use a separate lexical
|
||||
|
@ -1246,14 +1557,18 @@ impl FunctionParametersScopeBuilder {
|
|||
// Step 35.b.ii.1. Perform
|
||||
// ! lexEnvRec.CreateMutableBinding(dn, false).
|
||||
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over))
|
||||
}
|
||||
for n in &body_scope_builder.const_names {
|
||||
// Step 35.b.i. If IsConstantDeclaration of d is true, then
|
||||
// Step 35.b.i.1. Perform
|
||||
// ! lexEnvRec.CreateImmutableBinding(dn, true).
|
||||
let is_closed_over = body_scope_builder.name_tracker.is_closed_over_def(n);
|
||||
data.bindings.push(BindingName::new(*n, is_closed_over))
|
||||
data.base
|
||||
.bindings
|
||||
.push(BindingName::new(*n, is_closed_over))
|
||||
}
|
||||
|
||||
ScopeData::Lexical(data)
|
||||
|
@ -1286,7 +1601,7 @@ struct FunctionBodyScopeBuilder {
|
|||
const_names: Vec<SourceAtomSetIndex>,
|
||||
|
||||
/// Step 13. Let functionsToInitialize be a new empty List.
|
||||
functions_to_initialize: Vec<AssociatedDataKey>,
|
||||
functions_to_initialize: Vec<FunctionStencilIndex>,
|
||||
|
||||
/// Step 18. Else if hasParameterExpressions is false, then
|
||||
/// Step 18.a. If "arguments" is an element of functionNames or
|
||||
|
@ -1352,10 +1667,7 @@ impl FunctionBodyScopeBuilder {
|
|||
self.check_lexical_or_function_name(name);
|
||||
}
|
||||
|
||||
fn declare_function<T>(&mut self, name: SourceAtomSetIndex, fun: &T)
|
||||
where
|
||||
T: SourceLocationAccessor + NodeTypeIdAccessor,
|
||||
{
|
||||
fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: FunctionStencilIndex) {
|
||||
// FunctionDeclarationInstantiation ( func, argumentsList )
|
||||
// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
|
||||
//
|
||||
|
@ -1382,8 +1694,7 @@ impl FunctionBodyScopeBuilder {
|
|||
|
||||
// Step 14.a.iii.3. Insert d as the first element of
|
||||
// functionsToInitialize.
|
||||
self.functions_to_initialize
|
||||
.push(AssociatedDataKey::new(fun));
|
||||
self.functions_to_initialize.push(fun_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1696,7 +2007,7 @@ impl FunctionStencilBuilder {
|
|||
///
|
||||
/// This creates `FunctionStencil` for the function, and adds it to
|
||||
/// enclosing function if exists.
|
||||
fn enter<T>(&mut self, fun: &T, syntax_kind: FunctionSyntaxKind)
|
||||
fn enter<T>(&mut self, fun: &T, syntax_kind: FunctionSyntaxKind) -> FunctionStencilIndex
|
||||
where
|
||||
T: SourceLocationAccessor + NodeTypeIdAccessor,
|
||||
{
|
||||
|
@ -1731,6 +2042,8 @@ impl FunctionStencilBuilder {
|
|||
}
|
||||
|
||||
self.function_stack.push(index);
|
||||
|
||||
index
|
||||
}
|
||||
|
||||
/// Leave a function, setting its source location.
|
||||
|
@ -1834,6 +2147,10 @@ pub struct ScopeDataMapBuilder {
|
|||
non_global: AssociatedData<ScopeIndex>,
|
||||
|
||||
function_stencil_builder: FunctionStencilBuilder,
|
||||
|
||||
function_declaration_properties: FunctionDeclarationPropertyMap,
|
||||
|
||||
possibly_annex_b_functions: PossiblyAnnexBFunctionList,
|
||||
}
|
||||
|
||||
impl ScopeDataMapBuilder {
|
||||
|
@ -1845,6 +2162,8 @@ impl ScopeDataMapBuilder {
|
|||
global: None,
|
||||
non_global: AssociatedData::new(),
|
||||
function_stencil_builder: FunctionStencilBuilder::new(),
|
||||
function_declaration_properties: FunctionDeclarationPropertyMap::new(),
|
||||
possibly_annex_b_functions: PossiblyAnnexBFunctionList::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1885,7 +2204,7 @@ impl ScopeDataMapBuilder {
|
|||
}
|
||||
|
||||
pub fn after_script(&mut self) {
|
||||
let mut builder = self.builder_stack.pop_global();
|
||||
let builder = self.builder_stack.pop_global();
|
||||
|
||||
// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
|
||||
// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
|
||||
|
@ -1893,16 +2212,14 @@ impl ScopeDataMapBuilder {
|
|||
// Steps 3-6.
|
||||
// (done in runtime)
|
||||
|
||||
// Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
|
||||
builder.remove_function_names_from_var_names();
|
||||
|
||||
// Step 14. NOTE: Annex B.3.3.2 adds additional steps at this point.
|
||||
//
|
||||
// FIXME: Implement
|
||||
|
||||
// Steps 15-18.
|
||||
self.scopes
|
||||
.populate(builder.scope_index, builder.into_scope_data());
|
||||
// Steps 12-18.
|
||||
let scope_index = builder.scope_index;
|
||||
let scope = builder.into_scope_data(
|
||||
&mut self.scopes,
|
||||
&mut self.function_declaration_properties,
|
||||
&mut self.possibly_annex_b_functions,
|
||||
);
|
||||
self.scopes.populate(scope_index, scope);
|
||||
}
|
||||
|
||||
pub fn before_block_statement<T>(&mut self, block: &T)
|
||||
|
@ -1946,8 +2263,10 @@ impl ScopeDataMapBuilder {
|
|||
//
|
||||
// Step 3. Perform
|
||||
// BlockDeclarationInstantiation(StatementList, blockEnv).
|
||||
self.scopes
|
||||
.populate(builder.scope_index, builder.into_scope_data(enclosing));
|
||||
self.scopes.populate(
|
||||
builder.scope_index,
|
||||
builder.into_scope_data(enclosing, &mut self.possibly_annex_b_functions),
|
||||
);
|
||||
|
||||
// Step 6. Set the running execution context's LexicalEnvironment to
|
||||
// oldEnv.
|
||||
|
@ -2014,22 +2333,27 @@ impl ScopeDataMapBuilder {
|
|||
fun: &T,
|
||||
is_generator: bool,
|
||||
is_async: bool,
|
||||
) where
|
||||
) -> FunctionStencilIndex
|
||||
where
|
||||
T: SourceLocationAccessor + NodeTypeIdAccessor,
|
||||
{
|
||||
let fun_index = self.function_stencil_builder.enter(
|
||||
fun,
|
||||
FunctionSyntaxKind::function_declaration(is_generator, is_async),
|
||||
);
|
||||
|
||||
match self.builder_stack.innermost_lexical() {
|
||||
ScopeBuilder::Global(ref mut builder) => builder.declare_function(name, fun),
|
||||
ScopeBuilder::Block(ref mut builder) => builder.declare_function(name, fun),
|
||||
ScopeBuilder::FunctionBody(ref mut builder) => builder.declare_function(name, fun),
|
||||
ScopeBuilder::Global(ref mut builder) => builder.declare_function(name, fun_index),
|
||||
ScopeBuilder::Block(ref mut builder) => builder.declare_function(name, fun_index),
|
||||
ScopeBuilder::FunctionBody(ref mut builder) => {
|
||||
builder.declare_function(name, fun_index)
|
||||
}
|
||||
_ => panic!("unexpected lexical for FunctionDeclaration"),
|
||||
}
|
||||
|
||||
self.scope_kind_stack.push(ScopeKind::FunctionName);
|
||||
|
||||
self.function_stencil_builder.enter(
|
||||
fun,
|
||||
FunctionSyntaxKind::function_declaration(is_generator, is_async),
|
||||
);
|
||||
fun_index
|
||||
}
|
||||
|
||||
pub fn after_function_declaration<T>(&mut self, fun: &T)
|
||||
|
@ -2247,8 +2571,15 @@ impl ScopeDataMapBuilder {
|
|||
//
|
||||
// Step 1. Perform ? FunctionDeclarationInstantiation(functionObject,
|
||||
// argumentsList).
|
||||
let scope_data_set =
|
||||
parameter_scope_builder.into_scope_data_set(enclosing, body_scope_builder);
|
||||
let scope_data_set = parameter_scope_builder.into_scope_data_set(
|
||||
&mut self.scopes,
|
||||
&mut self.function_declaration_properties,
|
||||
&mut self.possibly_annex_b_functions,
|
||||
enclosing,
|
||||
body_scope_builder,
|
||||
);
|
||||
|
||||
self.possibly_annex_b_functions.clear();
|
||||
|
||||
self.scopes
|
||||
.populate(function_scope_index, scope_data_set.function);
|
||||
|
@ -2262,6 +2593,7 @@ impl ScopeDataMapBuilder {
|
|||
pub struct ScopeDataMapAndFunctionStencilList {
|
||||
pub scope_data_map: ScopeDataMap,
|
||||
pub function_stencil_indices: AssociatedData<FunctionStencilIndex>,
|
||||
pub function_declaration_properties: FunctionDeclarationPropertyMap,
|
||||
pub functions: FunctionStencilList,
|
||||
}
|
||||
|
||||
|
@ -2274,6 +2606,7 @@ impl From<ScopeDataMapBuilder> for ScopeDataMapAndFunctionStencilList {
|
|||
builder.non_global,
|
||||
),
|
||||
function_stencil_indices: builder.function_stencil_builder.function_stencil_indices,
|
||||
function_declaration_properties: builder.function_declaration_properties,
|
||||
functions: builder.function_stencil_builder.functions,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
//! Data generated by scope analysis, and consumed only by emitter
|
||||
|
||||
use std::collections::HashMap;
|
||||
use stencil::function::FunctionStencilIndex;
|
||||
|
||||
/// Data associated to a function.
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionProperty {
|
||||
is_annex_b: bool,
|
||||
}
|
||||
|
||||
impl FunctionProperty {
|
||||
fn is_annex_b_default() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
is_annex_b: Self::is_annex_b_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_annex_b(&mut self) {
|
||||
self.is_annex_b = true;
|
||||
}
|
||||
|
||||
pub fn is_annex_b(&self) -> bool {
|
||||
self.is_annex_b
|
||||
}
|
||||
}
|
||||
|
||||
/// Map from function to associated data.
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionDeclarationPropertyMap {
|
||||
/// This map is populated lazily, only for functions with non-default
|
||||
/// property.
|
||||
props: HashMap<FunctionStencilIndex, FunctionProperty>,
|
||||
}
|
||||
|
||||
impl FunctionDeclarationPropertyMap {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
props: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark_annex_b(&mut self, index: FunctionStencilIndex) {
|
||||
if !self.props.contains_key(&index) {
|
||||
self.props.insert(index, FunctionProperty::new());
|
||||
}
|
||||
|
||||
self.props
|
||||
.get_mut(&index)
|
||||
.expect("Should exist")
|
||||
.mark_annex_b();
|
||||
}
|
||||
|
||||
pub fn is_annex_b(&self, index: FunctionStencilIndex) -> bool {
|
||||
if !self.props.contains_key(&index) {
|
||||
return FunctionProperty::is_annex_b_default();
|
||||
}
|
||||
|
||||
self.props.get(&index).expect("Should exist").is_annex_b()
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
//! describing each scope, binding, and function in the AST.
|
||||
|
||||
mod builder;
|
||||
pub mod data;
|
||||
pub mod free_name_tracker;
|
||||
mod pass;
|
||||
|
||||
|
|
|
@ -8,17 +8,20 @@
|
|||
//! no AST is built. So we try to keep AST use separate from the analysis code.
|
||||
|
||||
use crate::builder::{ScopeDataMapAndFunctionStencilList, ScopeDataMapBuilder};
|
||||
use crate::data::FunctionDeclarationPropertyMap;
|
||||
use ast::arena;
|
||||
use ast::associated_data::AssociatedData;
|
||||
use ast::{types::*, visit::Pass};
|
||||
use std::collections::HashMap;
|
||||
use stencil::function::{FunctionStencilIndex, FunctionStencilList};
|
||||
use stencil::scope::ScopeDataMap;
|
||||
|
||||
/// The result of scope analysis.
|
||||
pub struct ScopePassResult<'alloc> {
|
||||
pub scope_data_map: ScopeDataMap,
|
||||
pub function_map: AssociatedData<&'alloc Function<'alloc>>,
|
||||
pub function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
|
||||
pub function_stencil_indices: AssociatedData<FunctionStencilIndex>,
|
||||
pub function_declaration_properties: FunctionDeclarationPropertyMap,
|
||||
pub functions: FunctionStencilList,
|
||||
}
|
||||
|
||||
|
@ -30,14 +33,14 @@ pub struct ScopePassResult<'alloc> {
|
|||
#[derive(Debug)]
|
||||
pub struct ScopePass<'alloc> {
|
||||
builder: ScopeDataMapBuilder,
|
||||
function_map: AssociatedData<&'alloc Function<'alloc>>,
|
||||
function_declarations: HashMap<FunctionStencilIndex, &'alloc Function<'alloc>>,
|
||||
}
|
||||
|
||||
impl<'alloc> ScopePass<'alloc> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
builder: ScopeDataMapBuilder::new(),
|
||||
function_map: AssociatedData::new(),
|
||||
function_declarations: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,12 +50,14 @@ impl<'alloc> From<ScopePass<'alloc>> for ScopePassResult<'alloc> {
|
|||
let ScopeDataMapAndFunctionStencilList {
|
||||
scope_data_map,
|
||||
function_stencil_indices,
|
||||
function_declaration_properties,
|
||||
functions,
|
||||
} = pass.builder.into();
|
||||
ScopePassResult {
|
||||
scope_data_map,
|
||||
function_map: pass.function_map,
|
||||
function_declarations: pass.function_declarations,
|
||||
function_stencil_indices,
|
||||
function_declaration_properties,
|
||||
functions,
|
||||
}
|
||||
}
|
||||
|
@ -121,9 +126,10 @@ impl<'alloc> Pass<'alloc> for ScopePass<'alloc> {
|
|||
} else {
|
||||
panic!("FunctionDeclaration should have name");
|
||||
};
|
||||
self.builder
|
||||
.before_function_declaration(name, ast, ast.is_generator, ast.is_async);
|
||||
self.function_map.insert(ast, ast);
|
||||
let fun_index =
|
||||
self.builder
|
||||
.before_function_declaration(name, ast, ast.is_generator, ast.is_async);
|
||||
self.function_declarations.insert(fun_index, ast);
|
||||
}
|
||||
|
||||
fn leave_enum_statement_variant_function_declaration(&mut self, ast: &'alloc Function<'alloc>) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"Cargo.toml":"f5439990185662ab31de12c07ef0c842438e3207bdfecc4fa6a9e4d4bea8a0d3","src/bytecode_offset.rs":"2aa7ba8c3cfbbd832092e65b599ab1c5a28d784ccc65d9e351bba656421b9a69","src/copy/AsyncFunctionResolveKind.h":"3851ecbb4728257595dd6e900749d1d8e02558574c00424a7ff0e3ca007fa6ec","src/copy/BytecodeFormatFlags.h":"7dc2932321cf7cf874cd92b6d8076ebd4139492730f3ee5a3b6ed7fc57a0c685","src/copy/CheckIsObjectKind.h":"8f0e112396d966c9221a743d353f62671e04cdace7dd49a59898d94ba0f621b7","src/copy/FunctionFlags.h":"4376653f70711d916bc36c2096165f0be9a50c487b9d471821da1cad80daa3a3","src/copy/FunctionPrefixKind.h":"f540a5c646a519b2d61aa27e4be865e08a31438def00ad5ba4ba2982ad1f2275","src/copy/GeneratorAndAsyncKind.h":"301668ce705970a51abfa94f89fd5db29ef5f129525110860e9e9bf7586ef187","src/copy/GeneratorResumeKind.h":"9e3cd9dc9c7f50937c6c45d73ec092dbfd92c4b56818ae6d1504bcd77078d0a6","src/copy/Opcodes.h":"72e0faa4eb0ed4e59ee2205d0ed6734fc4e7383552545d605eef2201e69d4c99","src/copy/SourceNotes.h":"1e467f4e63d6f40a428e257fecd210bd14664516adf75a45cb17ab02ccd65fd8","src/copy/StencilEnums.h":"e5a1db4af868fd65591ed97594f7aa9a4cde79194da0cabd62b34e950b3b10b4","src/copy/Symbol.h":"f68b32e1b7add89931a1fa82a6888ebf6d875d03b05872469de426844532bf33","src/copy/ThrowMsgKind.h":"da805756961d81a2b50aeb391a02fd59a0aa39a9e3eb6aae21b423b15875ab30","src/frame_slot.rs":"b20c81d67c572f20d06d493b211cd3eaa0432a8294541583643b82df3af2f813","src/function.rs":"e0e5e1db70b5d22139aab7c01411eada2c28381b9b6298fa0e507462d0869851","src/gcthings.rs":"6237c13fae9a5cfc67037c6fedf489747db67c38952aad95c322a6b7944211b7","src/lib.rs":"731842a46c397bee8dd06543dab435e8f7465a15e51301de5bca9bc67faa7d36","src/opcode.rs":"b9ebb9f03cebbc731b27cddb5799e34f4af12854a1e89aa459e153e0f087bbeb","src/opcode_info.rs":"a27c6d5602f5ecdcc882a0167614bc7a7754d958124941b4c1c0cdc2b0a894f1","src/regexp.rs":"7436cf545b990bec7dcc51ff28d67deaca9d4ce894468fdad0dd44b25c571cf2","src/result.rs":"0244b908bca220114e05291cca64c5e78edd48af2f0982d9587b4eaed5980eaa","src/scope.rs":"71f5acf81a54a92d8ec9ec1531808a92a3a93c81e09af1a6cd27a1fd23f38a30","src/scope_notes.rs":"9947ba5aba3097321c76adcb5648a478e4a67e088fdc1e01511e51c4ad41a9f3","src/script.rs":"a150a209be11380ecb7a4a36c21c3693961625293882c0563a2294a211a82b99"},"package":null}
|
||||
{"files":{"Cargo.toml":"f5439990185662ab31de12c07ef0c842438e3207bdfecc4fa6a9e4d4bea8a0d3","src/bytecode_offset.rs":"2aa7ba8c3cfbbd832092e65b599ab1c5a28d784ccc65d9e351bba656421b9a69","src/copy/AsyncFunctionResolveKind.h":"3851ecbb4728257595dd6e900749d1d8e02558574c00424a7ff0e3ca007fa6ec","src/copy/BytecodeFormatFlags.h":"7dc2932321cf7cf874cd92b6d8076ebd4139492730f3ee5a3b6ed7fc57a0c685","src/copy/CheckIsObjectKind.h":"8f0e112396d966c9221a743d353f62671e04cdace7dd49a59898d94ba0f621b7","src/copy/FunctionFlags.h":"4376653f70711d916bc36c2096165f0be9a50c487b9d471821da1cad80daa3a3","src/copy/FunctionPrefixKind.h":"f540a5c646a519b2d61aa27e4be865e08a31438def00ad5ba4ba2982ad1f2275","src/copy/GeneratorAndAsyncKind.h":"301668ce705970a51abfa94f89fd5db29ef5f129525110860e9e9bf7586ef187","src/copy/GeneratorResumeKind.h":"9e3cd9dc9c7f50937c6c45d73ec092dbfd92c4b56818ae6d1504bcd77078d0a6","src/copy/Opcodes.h":"72e0faa4eb0ed4e59ee2205d0ed6734fc4e7383552545d605eef2201e69d4c99","src/copy/SourceNotes.h":"1e467f4e63d6f40a428e257fecd210bd14664516adf75a45cb17ab02ccd65fd8","src/copy/StencilEnums.h":"e5a1db4af868fd65591ed97594f7aa9a4cde79194da0cabd62b34e950b3b10b4","src/copy/Symbol.h":"f68b32e1b7add89931a1fa82a6888ebf6d875d03b05872469de426844532bf33","src/copy/ThrowMsgKind.h":"da805756961d81a2b50aeb391a02fd59a0aa39a9e3eb6aae21b423b15875ab30","src/env_coord.rs":"0be36a1bd307f5586affe0f3046d8b2ab2f5382b41b7b7bfb364b97d16a7c410","src/frame_slot.rs":"b20c81d67c572f20d06d493b211cd3eaa0432a8294541583643b82df3af2f813","src/function.rs":"5547de3c00ea1f8b90845da635a05c10d7a32fce941fcb421a91267feb4998d3","src/gcthings.rs":"6237c13fae9a5cfc67037c6fedf489747db67c38952aad95c322a6b7944211b7","src/lib.rs":"b003e085344277d2987ef492dc513048e8ec83217850a22ba7ca06ac01bc9b5c","src/opcode.rs":"b9ebb9f03cebbc731b27cddb5799e34f4af12854a1e89aa459e153e0f087bbeb","src/opcode_info.rs":"a27c6d5602f5ecdcc882a0167614bc7a7754d958124941b4c1c0cdc2b0a894f1","src/regexp.rs":"7436cf545b990bec7dcc51ff28d67deaca9d4ce894468fdad0dd44b25c571cf2","src/result.rs":"0244b908bca220114e05291cca64c5e78edd48af2f0982d9587b4eaed5980eaa","src/scope.rs":"7727839d8175171ce097a41e1288498b6d7f6b0fda9037f6cf34655baf4bc562","src/scope_notes.rs":"9947ba5aba3097321c76adcb5648a478e4a67e088fdc1e01511e51c4ad41a9f3","src/script.rs":"a150a209be11380ecb7a4a36c21c3693961625293882c0563a2294a211a82b99"},"package":null}
|
|
@ -0,0 +1,50 @@
|
|||
//! (EnvironmentSlot,EnvironmentHops) pair represent the reference to a slot in
|
||||
//! an environment object in the environment chain.
|
||||
//!
|
||||
//! See the SMDOC comment in m-c/js/src/vm/EnvironmentObject.h for the details
|
||||
//! about environment object and environment chain.
|
||||
|
||||
/// Slot in the environmentslot object.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub struct EnvironmentSlot {
|
||||
slot: u32,
|
||||
}
|
||||
|
||||
impl EnvironmentSlot {
|
||||
pub fn new(slot: u32) -> Self {
|
||||
Self { slot }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
self.slot += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EnvironmentSlot> for u32 {
|
||||
fn from(slot: EnvironmentSlot) -> u32 {
|
||||
slot.slot
|
||||
}
|
||||
}
|
||||
|
||||
/// The number of environment objects to skip (hop) on the environment chain in
|
||||
/// order to find the associated environment object.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub struct EnvironmentHops {
|
||||
hops: u8,
|
||||
}
|
||||
|
||||
impl EnvironmentHops {
|
||||
pub fn new(hops: u8) -> Self {
|
||||
Self { hops }
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
self.hops += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EnvironmentHops> for u8 {
|
||||
fn from(hops: EnvironmentHops) -> u8 {
|
||||
hops.hops
|
||||
}
|
||||
}
|
|
@ -320,6 +320,10 @@ impl FunctionStencil {
|
|||
self.name = Some(name);
|
||||
}
|
||||
|
||||
pub fn name<'a>(&'a self) -> &'a Option<SourceAtomSetIndex> {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn set_has_rest(&mut self) {
|
||||
self.lazy_script_mut().set_has_rest();
|
||||
}
|
||||
|
@ -346,7 +350,7 @@ impl FunctionStencil {
|
|||
}
|
||||
|
||||
/// Index into FunctionStencilList.items.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct FunctionStencilIndex {
|
||||
index: usize,
|
||||
}
|
||||
|
@ -380,6 +384,10 @@ impl FunctionStencilList {
|
|||
FunctionStencilIndex::new(index)
|
||||
}
|
||||
|
||||
pub fn get<'a>(&'a self, index: FunctionStencilIndex) -> &'a FunctionStencil {
|
||||
&self.items[usize::from(index)]
|
||||
}
|
||||
|
||||
pub fn get_mut<'a>(&'a mut self, index: FunctionStencilIndex) -> &'a mut FunctionStencil {
|
||||
&mut self.items[usize::from(index)]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
pub mod bytecode_offset;
|
||||
pub mod env_coord;
|
||||
pub mod frame_slot;
|
||||
pub mod function;
|
||||
pub mod gcthings;
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
//! Each scope contains a list of bindings (`BindingName`).
|
||||
|
||||
use crate::frame_slot::FrameSlot;
|
||||
use ast::associated_data::{AssociatedData, Key as AssociatedDataKey};
|
||||
use crate::function::FunctionStencilIndex;
|
||||
use ast::associated_data::AssociatedData;
|
||||
use ast::source_atom_set::SourceAtomSetIndex;
|
||||
use ast::source_location_accessor::SourceLocationAccessor;
|
||||
use ast::type_id::NodeTypeIdAccessor;
|
||||
|
@ -71,30 +72,102 @@ impl<'a> BindingIterItem<'a> {
|
|||
self.name.is_top_level_function
|
||||
}
|
||||
|
||||
pub fn is_closed_over(&self) -> bool {
|
||||
self.name.is_closed_over
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> BindingKind {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
/// Accessor for is_closed_over for both BindingName/Option<BindingName>.
|
||||
pub trait MaybeBindingName {
|
||||
fn is_closed_over(&self) -> bool;
|
||||
}
|
||||
impl MaybeBindingName for BindingName {
|
||||
fn is_closed_over(&self) -> bool {
|
||||
self.is_closed_over
|
||||
}
|
||||
}
|
||||
impl MaybeBindingName for Option<BindingName> {
|
||||
fn is_closed_over(&self) -> bool {
|
||||
match self {
|
||||
Some(b) => b.is_closed_over,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BaseScopeData<BindingItemT>
|
||||
where
|
||||
BindingItemT: MaybeBindingName,
|
||||
{
|
||||
/// Corresponds to `*Scope::Data.{length, trailingNames}.`
|
||||
/// The layout is defined by *ScopeData structs below, that has
|
||||
/// this struct.
|
||||
pub bindings: Vec<BindingItemT>,
|
||||
pub has_eval: bool,
|
||||
pub has_with: bool,
|
||||
}
|
||||
|
||||
impl<BindingItemT> BaseScopeData<BindingItemT>
|
||||
where
|
||||
BindingItemT: MaybeBindingName,
|
||||
{
|
||||
pub fn new(bindings_count: usize) -> Self {
|
||||
Self {
|
||||
bindings: Vec::with_capacity(bindings_count),
|
||||
has_eval: false,
|
||||
has_with: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_all_bindings_closed_over(&self) -> bool {
|
||||
// `with` and direct `eval` can dynamically access any binding in this
|
||||
// scope.
|
||||
self.has_eval || self.has_with
|
||||
}
|
||||
|
||||
/// Returns true if this scope needs to be allocated on heap as
|
||||
/// EnvironmentObject.
|
||||
pub fn needs_environment_object(&self) -> bool {
|
||||
// `with` and direct `eval` can dynamically access bindings in this
|
||||
// scope.
|
||||
if self.is_all_bindings_closed_over() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If a binding in this scope is closed over by inner function,
|
||||
// it can be accessed when this frame isn't on the stack.
|
||||
for binding in &self.bindings {
|
||||
if binding.is_closed_over() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Bindings created in global environment.
|
||||
///
|
||||
/// Maps to js::GlobalScope::Data in m-c/js/src/vm/Scope.h.
|
||||
#[derive(Debug)]
|
||||
pub struct GlobalScopeData {
|
||||
/// Bindings are sorted by kind:
|
||||
///
|
||||
/// * `base.bindings[0..let_start]` - `var`s
|
||||
/// * `base.bindings[let_start..const_start]` - `let`s
|
||||
/// * `base.bindings[const_start..]` - `const`s
|
||||
pub base: BaseScopeData<BindingName>,
|
||||
|
||||
pub let_start: usize,
|
||||
pub const_start: usize,
|
||||
|
||||
/// Corresponds to `GlobalScope::Data.{length, trailingNames}.`
|
||||
///
|
||||
/// Bindings are sorted by kind:
|
||||
///
|
||||
/// * `bindings[0..let_start]` - `var`s
|
||||
/// * `bindings[let_start..const_start]` - `let`s
|
||||
/// * `bindings[const_start..]` - `const`s
|
||||
pub bindings: Vec<BindingName>,
|
||||
|
||||
/// The global functions in this script.
|
||||
pub functions: Vec<AssociatedDataKey>,
|
||||
pub functions: Vec<FunctionStencilIndex>,
|
||||
}
|
||||
|
||||
impl GlobalScopeData {
|
||||
|
@ -102,14 +175,14 @@ impl GlobalScopeData {
|
|||
var_count: usize,
|
||||
let_count: usize,
|
||||
const_count: usize,
|
||||
functions: Vec<AssociatedDataKey>,
|
||||
functions: Vec<FunctionStencilIndex>,
|
||||
) -> Self {
|
||||
let capacity = var_count + let_count + const_count;
|
||||
|
||||
Self {
|
||||
base: BaseScopeData::new(capacity),
|
||||
let_start: var_count,
|
||||
const_start: var_count + let_count,
|
||||
bindings: Vec::with_capacity(capacity),
|
||||
functions,
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +209,7 @@ impl<'a> Iterator for GlobalBindingIter<'a> {
|
|||
type Item = BindingIterItem<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<BindingIterItem<'a>> {
|
||||
if self.i == self.data.bindings.len() {
|
||||
if self.i == self.data.base.bindings.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -148,7 +221,7 @@ impl<'a> Iterator for GlobalBindingIter<'a> {
|
|||
BindingKind::Const
|
||||
};
|
||||
|
||||
let name = &self.data.bindings[self.i];
|
||||
let name = &self.data.base.bindings[self.i];
|
||||
|
||||
self.i += 1;
|
||||
|
||||
|
@ -163,8 +236,8 @@ impl<'a> Iterator for GlobalBindingIter<'a> {
|
|||
/// in m-c/js/src/frontend/Stencil.h
|
||||
#[derive(Debug)]
|
||||
pub struct VarScopeData {
|
||||
/// Corresponds to VarScope::Data.{length, trailingNames}.
|
||||
pub bindings: Vec<BindingName>,
|
||||
/// All bindings are `var`.
|
||||
pub base: BaseScopeData<BindingName>,
|
||||
|
||||
/// The first frame slot of this scope.
|
||||
///
|
||||
|
@ -186,7 +259,7 @@ impl VarScopeData {
|
|||
let capacity = var_count;
|
||||
|
||||
Self {
|
||||
bindings: Vec::with_capacity(capacity),
|
||||
base: BaseScopeData::new(capacity),
|
||||
// Set to the correct value in EmitterScopeStack::enter_lexical.
|
||||
first_frame_slot: FrameSlot::new(0),
|
||||
enclosing,
|
||||
|
@ -201,10 +274,13 @@ impl VarScopeData {
|
|||
/// in m-c/js/src/frontend/Stencil.h
|
||||
#[derive(Debug)]
|
||||
pub struct LexicalScopeData {
|
||||
pub const_start: usize,
|
||||
/// Bindings are sorted by kind:
|
||||
///
|
||||
/// * `base.bindings[0..const_start]` - `let`s
|
||||
/// * `base.bindings[const_start..]` - `const`s
|
||||
pub base: BaseScopeData<BindingName>,
|
||||
|
||||
/// Corresponds to LexicalScope::Data.{length, trailingNames}.
|
||||
pub bindings: Vec<BindingName>,
|
||||
pub const_start: usize,
|
||||
|
||||
/// The first frame slot of this scope.
|
||||
///
|
||||
|
@ -221,7 +297,7 @@ pub struct LexicalScopeData {
|
|||
pub enclosing: ScopeIndex,
|
||||
|
||||
/// Functions in this scope.
|
||||
pub functions: Vec<AssociatedDataKey>,
|
||||
pub functions: Vec<FunctionStencilIndex>,
|
||||
}
|
||||
|
||||
impl LexicalScopeData {
|
||||
|
@ -229,13 +305,13 @@ impl LexicalScopeData {
|
|||
let_count: usize,
|
||||
const_count: usize,
|
||||
enclosing: ScopeIndex,
|
||||
functions: Vec<AssociatedDataKey>,
|
||||
functions: Vec<FunctionStencilIndex>,
|
||||
) -> Self {
|
||||
let capacity = let_count + const_count;
|
||||
|
||||
Self {
|
||||
base: BaseScopeData::new(capacity),
|
||||
const_start: let_count,
|
||||
bindings: Vec::with_capacity(capacity),
|
||||
// Set to the correct value in EmitterScopeStack::enter_lexical.
|
||||
first_frame_slot: FrameSlot::new(0),
|
||||
enclosing,
|
||||
|
@ -247,7 +323,7 @@ impl LexicalScopeData {
|
|||
let_count: usize,
|
||||
const_count: usize,
|
||||
enclosing: ScopeIndex,
|
||||
functions: Vec<AssociatedDataKey>,
|
||||
functions: Vec<FunctionStencilIndex>,
|
||||
) -> Self {
|
||||
Self::new(let_count, const_count, enclosing, functions)
|
||||
}
|
||||
|
@ -267,6 +343,49 @@ impl LexicalScopeData {
|
|||
pub fn iter<'a>(&'a self) -> LexicalBindingIter<'a> {
|
||||
LexicalBindingIter::new(self)
|
||||
}
|
||||
|
||||
/// Mark a `name` binding originally at `original_binding_index`
|
||||
/// Annex B function.
|
||||
///
|
||||
/// The binding at `original_binding_index` can be different thing
|
||||
/// if any binding before it is already removed.
|
||||
pub fn mark_annex_b_function(
|
||||
&mut self,
|
||||
name: SourceAtomSetIndex,
|
||||
original_binding_index: usize,
|
||||
) {
|
||||
let binding_index = self.find_binding(name, original_binding_index);
|
||||
|
||||
// Lexical function becomes mutable binding.
|
||||
debug_assert!(binding_index < self.const_start);
|
||||
|
||||
self.const_start -= 1;
|
||||
self.base.bindings.remove(binding_index);
|
||||
}
|
||||
|
||||
/// Find the binding `name`, originally stored at `original_binding_index`.
|
||||
/// If the binding at `original_binding_index` isn't `name`, look for
|
||||
/// `name`.
|
||||
/// Panics if the binding with given `name` doesn't exist.
|
||||
fn find_binding(&self, name: SourceAtomSetIndex, original_binding_index: usize) -> usize {
|
||||
if original_binding_index < self.base.bindings.len() {
|
||||
let binding = &self.base.bindings[original_binding_index];
|
||||
if binding.name == name {
|
||||
return original_binding_index;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Search from `original_binding_index` to 0,
|
||||
// instead of iterating all items.
|
||||
|
||||
for (i, binding) in self.base.bindings.iter().enumerate() {
|
||||
if binding.name == name {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
panic!("The binding should exist");
|
||||
}
|
||||
}
|
||||
|
||||
/// Corresponds to the iteration part of js::BindingIter
|
||||
|
@ -286,7 +405,7 @@ impl<'a> Iterator for LexicalBindingIter<'a> {
|
|||
type Item = BindingIterItem<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<BindingIterItem<'a>> {
|
||||
if self.i == self.data.bindings.len() {
|
||||
if self.i == self.data.base.bindings.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -296,7 +415,7 @@ impl<'a> Iterator for LexicalBindingIter<'a> {
|
|||
BindingKind::Const
|
||||
};
|
||||
|
||||
let name = &self.data.bindings[self.i];
|
||||
let name = &self.data.base.bindings[self.i];
|
||||
|
||||
self.i += 1;
|
||||
|
||||
|
@ -311,15 +430,26 @@ impl<'a> Iterator for LexicalBindingIter<'a> {
|
|||
/// in m-c/js/src/frontend/Stencil.h
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionScopeData {
|
||||
has_parameter_exprs: bool,
|
||||
non_positional_formal_start: usize,
|
||||
var_start: usize,
|
||||
|
||||
/// Corresponds to FunctionScope::Data.{length, trailingNames}.
|
||||
/// Bindings are sorted by kind:
|
||||
///
|
||||
/// * `base.bindings[0..non_positional_formal_start]` -
|
||||
/// positional foparameters:
|
||||
/// - single binding parameter with/without default
|
||||
/// - single binding rest parameter
|
||||
/// * `base.bindings[non_positional_formal_start..var_start]` -
|
||||
/// non positional parameters:
|
||||
/// - destructuring parameter
|
||||
/// - destructuring rest parameter
|
||||
/// * `base.bindings[var_start..]` - `var`s
|
||||
///
|
||||
/// Given positional parameters range can have null slot for destructuring,
|
||||
/// this is Vec of Option<BindingName>, instead of BindingName like others.
|
||||
pub bindings: Vec<Option<BindingName>>,
|
||||
/// use Vec of Option<BindingName>, instead of BindingName like others.
|
||||
pub base: BaseScopeData<Option<BindingName>>,
|
||||
|
||||
has_parameter_exprs: bool,
|
||||
|
||||
non_positional_formal_start: usize,
|
||||
var_start: usize,
|
||||
|
||||
/// The first frame slot of this scope.
|
||||
///
|
||||
|
@ -347,10 +477,10 @@ impl FunctionScopeData {
|
|||
let capacity = positional_parameter_count + non_positional_formal_start + var_count;
|
||||
|
||||
Self {
|
||||
base: BaseScopeData::new(capacity),
|
||||
has_parameter_exprs,
|
||||
non_positional_formal_start: positional_parameter_count,
|
||||
var_start: positional_parameter_count + non_positional_formal_start,
|
||||
bindings: Vec::with_capacity(capacity),
|
||||
// Set to the correct value in EmitterScopeStack::enter_function.
|
||||
first_frame_slot: FrameSlot::new(0),
|
||||
enclosing,
|
||||
|
@ -439,7 +569,7 @@ impl ScopeDataList {
|
|||
.expect("Should be populated")
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, index: ScopeIndex) -> &mut ScopeData {
|
||||
pub fn get_mut(&mut self, index: ScopeIndex) -> &mut ScopeData {
|
||||
self.scopes[usize::from(index)]
|
||||
.as_mut()
|
||||
.expect("Should be populated")
|
||||
|
@ -500,6 +630,13 @@ impl ScopeDataMap {
|
|||
.clone()
|
||||
}
|
||||
|
||||
pub fn get_lexical_at(&self, index: ScopeIndex) -> &LexicalScopeData {
|
||||
match self.scopes.get(index) {
|
||||
ScopeData::Lexical(scope) => scope,
|
||||
_ => panic!("Unexpected scope data for lexical"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_lexical_at_mut(&mut self, index: ScopeIndex) -> &mut LexicalScopeData {
|
||||
match self.scopes.get_mut(index) {
|
||||
ScopeData::Lexical(scope) => scope,
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -546,7 +546,7 @@ def generate_emit_methods(out_f, opcodes, types):
|
|||
assert len(params) == 1
|
||||
assert params[0][0] == 'u32'
|
||||
params[0] = ('GCThingIndex', params[0][1])
|
||||
elif 'JOF_OBJECT' in opcode.format_:
|
||||
elif 'JOF_OBJECT' in opcode.format_ or 'JOF_SCOPE' in opcode.format_:
|
||||
assert len(params) == 1
|
||||
assert params[0][0] == 'u32'
|
||||
params[0] = ('GCThingIndex', params[0][1])
|
||||
|
|
Загрузка…
Ссылка в новой задаче