-
-
Notifications
You must be signed in to change notification settings - Fork 632
Expand file tree
/
Copy pathmodule.rs
More file actions
131 lines (112 loc) · 4.11 KB
/
module.rs
File metadata and controls
131 lines (112 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::cell::RefCell;
use boa_ast::scope::Scope;
use boa_gc::{Finalize, GcRefCell, Trace};
use crate::{JsResult, JsString, JsValue, error::PanicError, module::Module};
/// Type of accessor used to access an indirect binding.
#[derive(Debug, Clone)]
enum BindingAccessor {
Identifier(JsString),
Index(u32),
}
/// An indirect reference to a binding inside an environment.
#[derive(Clone, Debug, Trace, Finalize)]
struct IndirectBinding {
module: Module,
#[unsafe_ignore_trace]
accessor: RefCell<BindingAccessor>,
}
/// The type of binding a [`ModuleEnvironment`] can contain.
#[derive(Clone, Debug, Trace, Finalize)]
enum BindingType {
Direct(Option<JsValue>),
Indirect(IndirectBinding),
}
/// A [**Module Environment Record**][spec].
///
/// Module environments allow referencing bindings inside other environments, in addition
/// to the usual declarative environment functionality.
///
///
/// [spec]: https://tc39.es/ecma262/#sec-module-environment-records
#[derive(Debug, Trace, Finalize)]
pub(crate) struct ModuleEnvironment {
bindings: GcRefCell<Vec<BindingType>>,
// Safety: Nothing in CompileTimeEnvironment needs tracing.
#[unsafe_ignore_trace]
compile: Scope,
}
impl ModuleEnvironment {
/// Creates a new `LexicalEnvironment`.
pub(crate) fn new(bindings: u32, compile: Scope) -> Self {
Self {
bindings: GcRefCell::new(vec![BindingType::Direct(None); bindings as usize]),
compile,
}
}
/// Gets the compile time environment of this module environment.
pub(crate) const fn compile(&self) -> &Scope {
&self.compile
}
/// Get the binding value from the environment by it's index.
///
/// # Panics
///
/// Panics if the binding value is out of range or not initialized.
#[track_caller]
pub(crate) fn get(&self, index: u32) -> Option<JsValue> {
let bindings = self.bindings.borrow();
match &bindings[index as usize] {
BindingType::Direct(v) => v.clone(),
BindingType::Indirect(IndirectBinding { module, accessor }) => {
let env = module.environment()?;
match &*accessor.clone().borrow() {
BindingAccessor::Identifier(name) => {
let index = env
.kind()
.as_module()
.expect("must be module environment")
.compile()
.get_binding(name)
.expect("linking must ensure the binding exists");
let value = env.get(index.binding_index())?;
*accessor.borrow_mut() = BindingAccessor::Index(index.binding_index());
Some(value)
}
BindingAccessor::Index(index) => env.get(*index),
}
}
}
}
/// Sets the binding value from the environment by index.
///
/// # Errors
///
/// Returns a `TypeError` if the binding is an indirect reference to another environment.
#[track_caller]
pub(crate) fn set(&self, index: u32, value: JsValue) -> JsResult<()> {
let mut bindings = self.bindings.borrow_mut();
match &mut bindings[index as usize] {
BindingType::Direct(v) => {
*v = Some(value);
Ok(())
}
BindingType::Indirect(_) => Err(PanicError::new(
"cannot modify indirect references to other environments",
)
.into()),
}
}
/// Creates an indirect binding reference to another environment binding.
///
/// # Panics
///
/// Panics if the binding value is out of range.
#[track_caller]
pub(crate) fn set_indirect(&self, index: u32, target_module: Module, target_binding: JsString) {
let mut bindings = self.bindings.borrow_mut();
bindings[index as usize] = BindingType::Indirect(IndirectBinding {
module: target_module,
accessor: RefCell::new(BindingAccessor::Identifier(target_binding)),
});
}
}