Skip to content

Commit

Permalink
Support rest/spread placeholder args
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohnson committed Jul 17, 2017
1 parent cd625f1 commit ee2f7a7
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 3 deletions.
5 changes: 4 additions & 1 deletion src/index.lsc
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ Lightscript(babel) ->
//// AST transforms
// Perform basic ast fixups (block bodies, etc)
fixAst(path)

// Transform placeholder expressions first.
transformPlaceholders(path)
if compilerState.opts.placeholderArgs:
transformPlaceholders(path)

// Main LSC transforms
path.traverse({
ForInArrayStatement(path): void ->
// TODO: push the linter conditional down into the transform
Expand Down
25 changes: 23 additions & 2 deletions src/placeholders.lsc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import t from './types'

registerPlaceholder(functions, path, programPath) ->
fnPath = path.getFunctionParent()
if fnPath == programPath || !fnPath.node || !fnPath.node.params:
Expand All @@ -6,6 +8,10 @@ registerPlaceholder(functions, path, programPath) ->
if fnPath.node.params.length:
throw path.buildCodeFrameError("Placeholders cannot be used in functions with arguments.")

if path.parentPath?.node?.type == "SpreadElement":
if path.node?.index?:
throw path.buildCodeFrameError("Cannot use indices with spread placeholders.")

let fnInfo = functions.get(fnPath)
if fnInfo:
fnInfo.placeholders.push(path)
Expand All @@ -17,14 +23,29 @@ liftPlaceholders(fnPath, phPaths) ->
ixPhPaths = phPaths.filter(x -> x.node.index?)
nixPhPaths = phPaths.filter(x-> not x.node.index?)
ixPhPaths.sort((a, b) -> a.node.index - b.node.index)
nixPhPaths.sort((a, b) ->
// SpreadElements are last
if a.parentPath?.node.type == "SpreadElement":
1
elif b.parentPath?.node.type == "SpreadElement":
-1
else:
0
)
sortedPhPaths = ixPhPaths.concat(nixPhPaths)

// Formulate args
args = []
let prevIndex = undefined
let prevIndex = undefined, restArg = undefined
for elem phPath in sortedPhPaths:
{ node } = phPath
if node.index? and node.index == prevIndex:
if phPath.parentPath?.node.type == "SpreadElement":
if not restArg:
now restArg = fnPath.scope.generateUidIdentifier("arg")
args.push(t.restElement(restArg))
phPath.replaceWith(restArg)
elif node.index? and node.index == prevIndex:
// Repeated use of an index = same arg.
phPath.replaceWith(args[args.length - 1])
else:
args.push(fnPath.scope.generateUidIdentifier("arg"))
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/placeholder-args/spread-index-illegal/actual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
->
a = [..._1]
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"throws": "Cannot use indices with spread placeholders."
}
9 changes: 9 additions & 0 deletions test/fixtures/placeholder-args/spread/actual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-> f(_2, _1, _, ..._)

->
a = [..._]
f(_2, _1, _, a)

->
a = [..._]
b = [..._]
10 changes: 10 additions & 0 deletions test/fixtures/placeholder-args/spread/expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(function (_arg, _arg2, _arg3, ..._arg4) {
return f(_arg2, _arg, _arg3, ..._arg4);
});(function (_arg5, _arg6, _arg7, ..._arg8) {
const a = [..._arg8];
return f(_arg6, _arg5, _arg7, a);
});(function (..._arg9) {
const a = [..._arg9];
const b = [..._arg9];
return b;
});

0 comments on commit ee2f7a7

Please sign in to comment.