@@ -158,14 +158,14 @@ public class JavaScriptCompiler {
158158
159159 case . ctor( let constructor) :
160160 let defaultValues = defaultValuesPerSubroutine. removeLast ( )
161- let parameters = convertParameters ( constructor. parameters)
161+ let parameters = try convertParameters ( constructor. parameters)
162162 let head = emit (
163163 BeginClassConstructor ( parameters: parameters) , withInputs: defaultValues)
164164
165165 try enterNewScope {
166166 var parameters = head. innerOutputs
167167 map ( " this " , to: parameters. removeFirst ( ) )
168- mapParameters ( constructor. parameters, to: parameters)
168+ try mapParameters ( constructor. parameters, to: parameters)
169169 for statement in constructor. body {
170170 try compileStatement ( statement)
171171 }
@@ -175,7 +175,7 @@ public class JavaScriptCompiler {
175175
176176 case . method( let method) :
177177 let defaultValues = defaultValuesPerSubroutine. removeLast ( )
178- let parameters = convertParameters ( method. parameters)
178+ let parameters = try convertParameters ( method. parameters)
179179 let head : Instruction
180180
181181 guard let key = method. key. body else {
@@ -202,7 +202,7 @@ public class JavaScriptCompiler {
202202 try enterNewScope {
203203 var parameters = head. innerOutputs
204204 map ( " this " , to: parameters. removeFirst ( ) )
205- mapParameters ( method. parameters, to: parameters)
205+ try mapParameters ( method. parameters, to: parameters)
206206 for statement in method. body {
207207 try compileStatement ( statement)
208208 }
@@ -442,7 +442,7 @@ public class JavaScriptCompiler {
442442
443443 case . functionDeclaration( let functionDeclaration) :
444444 let defaultValues = try compileDefaultValues ( for: functionDeclaration. parameters)
445- let parameters = convertParameters ( functionDeclaration. parameters)
445+ let parameters = try convertParameters ( functionDeclaration. parameters)
446446 let functionBegin : Operation
447447 let functionEnd : Operation
448448 switch functionDeclaration. type {
@@ -471,7 +471,7 @@ public class JavaScriptCompiler {
471471 // here we may overwrite an existing variable mapping.
472472 mapOrRemap ( functionDeclaration. name, to: instr. output)
473473 try enterNewScope {
474- mapParameters ( functionDeclaration. parameters, to: instr. innerOutputs)
474+ try mapParameters ( functionDeclaration. parameters, to: instr. innerOutputs)
475475 for statement in functionDeclaration. body {
476476 try compileStatement ( statement)
477477 }
@@ -1230,7 +1230,7 @@ public class JavaScriptCompiler {
12301230 }
12311231 case . method( let method) :
12321232 let defaultValues = methodDefaultValues. removeLast ( )
1233- let parameters = convertParameters ( method. parameters)
1233+ let parameters = try convertParameters ( method. parameters)
12341234 let head : Instruction
12351235
12361236 guard let key = method. key. body else {
@@ -1256,7 +1256,7 @@ public class JavaScriptCompiler {
12561256 try enterNewScope {
12571257 var parameters = head. innerOutputs
12581258 map ( " this " , to: parameters. removeFirst ( ) )
1259- mapParameters ( method. parameters, to: parameters)
1259+ try mapParameters ( method. parameters, to: parameters)
12601260 for statement in method. body {
12611261 try compileStatement ( statement)
12621262 }
@@ -1361,7 +1361,7 @@ public class JavaScriptCompiler {
13611361
13621362 case . functionExpression( let functionExpression) :
13631363 let defaultValues = try compileDefaultValues ( for: functionExpression. parameters)
1364- let parameters = convertParameters ( functionExpression. parameters)
1364+ let parameters = try convertParameters ( functionExpression. parameters)
13651365 let functionBegin : Operation
13661366 let functionEnd : Operation
13671367 let name = functionExpression. name. isEmpty ? nil : functionExpression. name
@@ -1385,7 +1385,7 @@ public class JavaScriptCompiler {
13851385
13861386 let instr = emit ( functionBegin, withInputs: defaultValues)
13871387 try enterNewScope {
1388- mapParameters ( functionExpression. parameters, to: instr. innerOutputs)
1388+ try mapParameters ( functionExpression. parameters, to: instr. innerOutputs)
13891389 for statement in functionExpression. body {
13901390 try compileStatement ( statement)
13911391 }
@@ -1396,7 +1396,7 @@ public class JavaScriptCompiler {
13961396
13971397 case . arrowFunctionExpression( let arrowFunction) :
13981398 let defaultValues = try compileDefaultValues ( for: arrowFunction. parameters)
1399- let parameters = convertParameters ( arrowFunction. parameters)
1399+ let parameters = try convertParameters ( arrowFunction. parameters)
14001400 let functionBegin : Operation
14011401 let functionEnd : Operation
14021402 switch arrowFunction. type {
@@ -1413,7 +1413,7 @@ public class JavaScriptCompiler {
14131413
14141414 let instr = emit ( functionBegin, withInputs: defaultValues)
14151415 try enterNewScope {
1416- mapParameters ( arrowFunction. parameters, to: instr. innerOutputs)
1416+ try mapParameters ( arrowFunction. parameters, to: instr. innerOutputs)
14171417 guard let body = arrowFunction. body else {
14181418 throw CompilerError . invalidNodeError ( " missing body in arrow function " )
14191419 }
@@ -1785,10 +1785,66 @@ public class JavaScriptCompiler {
17851785
17861786 private func mapParameters(
17871787 _ parameters: Compiler_Protobuf_Parameters , to variables: ArraySlice < Variable >
1788- ) {
1789- assert ( parameters. parameters. count == variables. count)
1790- for (param, v) in zip ( parameters. parameters, variables) {
1791- map ( param. name, to: v)
1788+ ) throws {
1789+ var iter = variables. makeIterator ( )
1790+ for param in parameters. parameters {
1791+ switch param. id {
1792+ case . objectPattern( let obj) :
1793+ // e.g. function foo({a, b}) {}
1794+ try mapDestructuringPattern ( obj, iterator: & iter)
1795+ case . arrayPattern( let arr) :
1796+ // e.g. function bar([x, y]) {}
1797+ try mapDestructuringPattern ( arr, iterator: & iter)
1798+ case . name( let name) :
1799+ map ( name, to: iter. next ( ) !)
1800+ case nil :
1801+ break
1802+ }
1803+ }
1804+ }
1805+
1806+ private func mapDestructuringTarget< Iter: IteratorProtocol > (
1807+ _ target: Compiler_Protobuf_LValue , iterator: inout Iter
1808+ ) throws where Iter. Element == Variable {
1809+ switch target. value {
1810+ case . destructuringPattern( let dp) :
1811+ switch dp. pattern {
1812+ case . objectPattern( let obj) :
1813+ try mapDestructuringPattern ( obj, iterator: & iterator)
1814+ case . arrayPattern( let arr) :
1815+ try mapDestructuringPattern ( arr, iterator: & iterator)
1816+ case nil :
1817+ throw CompilerError . invalidASTError (
1818+ " Invalid destructuring assignment target in parameter " )
1819+ }
1820+ case . identifier( let id) :
1821+ map ( id. name, to: iterator. next ( ) !)
1822+ default :
1823+ throw CompilerError . invalidASTError (
1824+ " Invalid destructuring assignment target in parameter " )
1825+ }
1826+ }
1827+
1828+ private func mapDestructuringPattern< Iter: IteratorProtocol > (
1829+ _ pattern: Compiler_Protobuf_ObjectPattern , iterator: inout Iter
1830+ ) throws where Iter. Element == Variable {
1831+ for prop in pattern. properties {
1832+ try mapDestructuringTarget ( prop. target, iterator: & iterator)
1833+ }
1834+ if pattern. hasRestTarget {
1835+ try mapDestructuringTarget ( pattern. restTarget, iterator: & iterator)
1836+ }
1837+ }
1838+
1839+ private func mapDestructuringPattern< Iter: IteratorProtocol > (
1840+ _ pattern: Compiler_Protobuf_ArrayPattern , iterator: inout Iter
1841+ ) throws where Iter. Element == Variable {
1842+ for elem in pattern. elements {
1843+ guard elem. hasTarget else { continue }
1844+ try mapDestructuringTarget ( elem. target, iterator: & iterator)
1845+ }
1846+ if pattern. hasRestTarget {
1847+ try mapDestructuringTarget ( pattern. restTarget, iterator: & iterator)
17921848 }
17931849 }
17941850
@@ -1804,14 +1860,116 @@ public class JavaScriptCompiler {
18041860 return defaultValues
18051861 }
18061862
1807- private func convertParameters( _ parameters: Compiler_Protobuf_Parameters ) -> Parameters {
1863+ private func convertParameterDestructuringPattern(
1864+ _ pattern: Compiler_Protobuf_DestructuringPattern
1865+ ) throws -> DestructuringPattern {
1866+ switch pattern. pattern {
1867+ case . objectPattern( let objProto) :
1868+ var properties = [ DestructuringPattern . ObjectProperty] ( )
1869+ for prop in objProto. properties {
1870+ let key : DestructuringPattern . ObjectProperty . Key
1871+ if case . name( let s) = prop. key. body {
1872+ key = . string( s)
1873+ } else if case . index( let i) = prop. key. body {
1874+ // e.g. function foo({1: a}) {}
1875+ key = . string( String ( i) )
1876+ } else {
1877+ throw CompilerError . invalidASTError (
1878+ " Computed keys not supported in parameter destructuring " )
1879+ }
1880+
1881+ let target : DestructuringPattern . Target
1882+ switch prop. target. value {
1883+ case . destructuringPattern( let dp) :
1884+ target = . pattern( try convertParameterDestructuringPattern ( dp) )
1885+ case . identifier:
1886+ target = . flatBinding
1887+ default :
1888+ throw CompilerError . invalidASTError (
1889+ " Invalid destructuring assignment target in parameter " )
1890+ }
1891+
1892+ assert (
1893+ !prop. hasDefaultValue,
1894+ " Default values in parameter destructuring are not yet supported " )
1895+ properties. append (
1896+ DestructuringPattern . ObjectProperty (
1897+ key: key, target: target, hasDefaultValue: false ) )
1898+ }
1899+ // FuzzIL operations only need to know if a rest target exists, not its string name.
1900+ // The string name mapping (e.g. "myRestParams" -> v3) is handled separately by `mapDestructuringPattern`.
1901+ return . object(
1902+ DestructuringPattern . ObjectPattern (
1903+ properties: properties, hasRestElement: objProto. hasRestTarget) )
1904+
1905+ case . arrayPattern( let arrProto) :
1906+ var elements = [ DestructuringPattern . ArrayElement] ( )
1907+ for elem in arrProto. elements {
1908+ guard elem. hasTarget else {
1909+ elements. append (
1910+ DestructuringPattern . ArrayElement ( target: nil , hasDefaultValue: false ) )
1911+ continue
1912+ }
1913+ let target : DestructuringPattern . Target
1914+ switch elem. target. value {
1915+ case . destructuringPattern( let dp) :
1916+ target = . pattern( try convertParameterDestructuringPattern ( dp) )
1917+ case . identifier:
1918+ target = . flatBinding
1919+ default :
1920+ throw CompilerError . invalidASTError (
1921+ " Invalid destructuring assignment target in parameter " )
1922+ }
1923+ assert (
1924+ !elem. hasDefaultValue,
1925+ " Default values in parameter destructuring are not yet supported " )
1926+ elements. append (
1927+ DestructuringPattern . ArrayElement (
1928+ target: target, hasDefaultValue: false ) )
1929+ }
1930+ let restTarget : DestructuringPattern . Target ?
1931+ if arrProto. hasRestTarget {
1932+ switch arrProto. restTarget. value {
1933+ case . destructuringPattern( let dp) :
1934+ restTarget = . pattern( try convertParameterDestructuringPattern ( dp) )
1935+ default :
1936+ restTarget = . flatBinding
1937+ }
1938+ } else {
1939+ restTarget = nil
1940+ }
1941+ return . array(
1942+ DestructuringPattern . ArrayPattern ( elements: elements, restTarget: restTarget) )
1943+
1944+ case nil :
1945+ throw CompilerError . invalidASTError ( " Missing pattern " )
1946+ }
1947+ }
1948+
1949+ private func convertParameters( _ parameters: Compiler_Protobuf_Parameters ) throws -> Parameters
1950+ {
18081951 let defaultParameterIndices = parameters. parameters. enumerated ( )
18091952 . filter { $0. element. hasDefaultValue }
18101953 . map { $0. offset }
18111954
1955+ var destructuringParameters = [ Int: DestructuringPattern] ( )
1956+ for (i, param) in parameters. parameters. enumerated ( ) {
1957+ switch param. id {
1958+ case . objectPattern( let obj) :
1959+ let dp = Compiler_Protobuf_DestructuringPattern . with { $0. objectPattern = obj }
1960+ destructuringParameters [ i] = try convertParameterDestructuringPattern ( dp)
1961+ case . arrayPattern( let arr) :
1962+ let dp = Compiler_Protobuf_DestructuringPattern . with { $0. arrayPattern = arr }
1963+ destructuringParameters [ i] = try convertParameterDestructuringPattern ( dp)
1964+ default :
1965+ break
1966+ }
1967+ }
1968+
18121969 return Parameters (
18131970 count: parameters. parameters. count, hasRestParameter: parameters. hasRestElement_p,
1814- defaultParameterIndices: defaultParameterIndices)
1971+ defaultParameterIndices: defaultParameterIndices,
1972+ destructuringParameters: destructuringParameters)
18151973 }
18161974
18171975 /// Convenience accessor for the currently active scope.
@@ -1978,6 +2136,9 @@ public class JavaScriptCompiler {
19782136
19792137 var hasDefaultValue = false
19802138 if propProto. hasDefaultValue {
2139+ // TODO(rherouart): we should not emit FuzzIL Code unless default is called, otherwise
2140+ // `let {a = default_with_side_effect()} = foo;`
2141+ // may behave differently in original and re-lifted code otherwise.
19812142 let defaultVar = try compileExpression ( propProto. defaultValue)
19822143 hasDefaultValue = true
19832144 inputs. append ( defaultVar)
0 commit comments