///|
// An immutable, closed representation of the destructuring subset lowered by
// bytecode. The fields are private and the constructors copy their input
// arrays, so a verified plan cannot be mutated by its lowering caller.
pub struct DestructurePlan {
priv node : DestructurePlanNode
}
///|
priv enum DestructurePlanNode {
BindName(String)
ArrayPattern(Array[DestructurePlan?], DestructurePlan?)
ObjectPattern(Array[DestructurePropertyPlan], DestructurePlan?)
}
///|
pub struct DestructurePropertyPlan {
priv key : String
priv target : DestructurePlan
}
///|
pub fn destructure_plan_bind_name(name : String) -> DestructurePlan {
{ node: BindName(name), }
}
///|
pub fn destructure_plan_array(
elements : Array[DestructurePlan?],
rest : DestructurePlan?,
) -> DestructurePlan {
{ node: ArrayPattern(elements.copy(), rest), }
}
///|
pub fn destructure_plan_property(
key : String,
target : DestructurePlan,
) -> DestructurePropertyPlan {
{ key, target, }
}
///|
pub fn destructure_plan_object(
properties : Array[DestructurePropertyPlan],
rest : DestructurePlan?,
) -> DestructurePlan {
{ node: ObjectPattern(properties.copy(), rest), }
}
///|
// The tree-walker remains the owner of the existing destructuring semantics.
// This adapter materializes the equivalent AST only inside that runtime owner;
// the compiler and VM carry and dispatch the immutable plan above. No source
// pattern is retained or consulted as a second authority.
pub fn Interpreter::eval_destructure_assign_plan(
self : Interpreter,
ctx : ExecContext,
plan : DestructurePlan,
value : Value,
env : Environment,
) -> Value raise Error {
self.eval_destructure_assign(ctx, plan.to_ast(), value, env)
}
///|
fn DestructurePlan::to_ast(self : DestructurePlan) -> @ast.Pattern {
match self.node {
BindName(name) => @ast.Pattern::IdentPat(name)
ArrayPattern(elements, rest) => {
let ast_elements : Array[@ast.Pattern?] = []
for element in elements {
ast_elements.push(
match element {
Some(plan) => Some(plan.to_ast())
None => None
},
)
}
let ast_rest : @ast.Pattern? = match rest {
Some(plan) => Some(plan.to_ast())
None => None
}
@ast.Pattern::ArrayPat(ast_elements, ast_rest)
}
ObjectPattern(properties, rest) => {
let ast_properties : Array[@ast.PropPat] = []
for property in properties {
ast_properties.push({
key: property.key,
key_lex_form: @token.LexForm::LexNormal,
key_loc: @token.Loc::default(),
value: property.target.to_ast(),
default_val: None,
computed_key: None,
})
}
let ast_rest : @ast.Pattern? = match rest {
Some(plan) => Some(plan.to_ast())
None => None
}
@ast.Pattern::ObjectPat(ast_properties, ast_rest)
}
}
}