Skip to content

Commit

Permalink
Hoist array binding and rest ref declarations. Fixes #1139. Fixes #1312
Browse files Browse the repository at this point in the history
  • Loading branch information
STRd6 committed Jul 9, 2024
1 parent 122fb4c commit 93fe16d
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 6 deletions.
18 changes: 16 additions & 2 deletions source/parser/lib.civet
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,8 @@ function processAssignments(statements): void {
lhs.children.splice(0, 0, "(")
tail.push(")")

refsToDeclare := new Set<ASTRef>

// Walk from right to left to handle splices
i = len - 1
while i >= 0
Expand Down Expand Up @@ -916,6 +918,9 @@ function processAssignments(statements): void {
break
else if lhs.type is like "ObjectBindingPattern", "ArrayBindingPattern"
processBindingPatternLHS(lhs, tail)
// Extract temp refs that need to be declared from lhs
gatherRecursiveAll(lhs, .type is "Ref").forEach refsToDeclare@add

// NOTE: currently not processing any non-binding pattern ObjectExpression or ArrayExpressions
// This might not be correct in all situations, esp BindingPatterns nested inside ObjectExpressions
i--
Expand All @@ -937,18 +942,27 @@ function processAssignments(statements): void {

if newMemberExp !== lhs
if newMemberExp.usesRef
exp.hoistDec = {
exp.hoistDec =
type: "Declaration"
children: ["let ", optionalChainRef]
names: []
}

replaceNode $2, newMemberExp
newMemberExp.parent = exp
$2 = newMemberExp

i--

// Add any additional binding refs that need to be declared to our hoisted declarations
if refsToDeclare.size
if exp.hoistDec
exp.hoistDec.children.push [...refsToDeclare].map [",", &]
else
exp.hoistDec =
type: "Declaration"
children: ["let ", [...refsToDeclare].map (r, i) => i ? [",", r] : r]
names: []

// Gather all identifier names from the lhs array
exp.names = $1.flatMap(([, l]) => l.names or [])

Expand Down
40 changes: 36 additions & 4 deletions test/assignment.civet
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,38 @@ describe "assignment", ->
[a, ...b] = d, [c] = b.splice(-1)
"""

testCase """
array destructuring with anon rest element
---
[a, ..., c] = d
---
let ref;[a, ...ref] = d, [c] = ref.splice(-1)
"""

testCase """
array destructure into @rest
---
[, ...@rest] = c
---
let rest;[, ...rest] = c, this.rest = rest
"""

testCase """
destructure into @ bindings
---
[@a, b] = c
---
let a;[a, b] = c, this.a = a
"""

testCase """
complex destructure
---
{a: [@b, ..., @c], x: { y: [@a, @d, ..., @e] } } = x
---
let b,ref,a1,d,ref1;({a: [b, ...ref], x: { y: [a1, d, ...ref1] } } = x), [c] = ref.splice(-1), [e] = ref1.splice(-1), this.b = b, this.c = c, this.a = a1, this.d = d, this.e = e
"""

testCase """
object destructuring
---
Expand Down Expand Up @@ -219,23 +251,23 @@ describe "assignment", ->
---
[a, ..., b] = d
---
[a, ...ref] = d, [b] = ref.splice(-1)
let ref;[a, ...ref] = d, [b] = ref.splice(-1)
"""

testCase """
non-end rest element with post rest trailing comma
---
[a, ..., b,] = d
---
[a, ...ref] = d, [b,] = ref.splice(-2)
let ref;[a, ...ref] = d, [b,] = ref.splice(-2)
"""

testCase """
non-end rest element with post rest elisions
---
[a, ..., b,,,] = d
---
[a, ...ref] = d, [b,,,] = ref.splice(-4)
let ref;[a, ...ref] = d, [b,,,] = ref.splice(-4)
"""

testCase """
Expand All @@ -251,7 +283,7 @@ describe "assignment", ->
---
{ x, y: [b, ...@c, d] } = e
---
({ x, y: [b, ...c] } = e), [d] = c.splice(-1), this.c = c
let c;({ x, y: [b, ...c] } = e), [d] = c.splice(-1), this.c = c
"""

testCase """
Expand Down

0 comments on commit 93fe16d

Please sign in to comment.