diff --git a/src/index.lsc b/src/index.lsc index 0e2ee60..9b6cc19 100644 --- a/src/index.lsc +++ b/src/index.lsc @@ -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 diff --git a/src/placeholders.lsc b/src/placeholders.lsc index 7bbf71b..5e55634 100644 --- a/src/placeholders.lsc +++ b/src/placeholders.lsc @@ -1,3 +1,5 @@ +import t from './types' + registerPlaceholder(functions, path, programPath) -> fnPath = path.getFunctionParent() if fnPath == programPath || !fnPath.node || !fnPath.node.params: @@ -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) @@ -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")) diff --git a/test/fixtures/placeholder-args/spread-index-illegal/actual.js b/test/fixtures/placeholder-args/spread-index-illegal/actual.js new file mode 100644 index 0000000..7308d77 --- /dev/null +++ b/test/fixtures/placeholder-args/spread-index-illegal/actual.js @@ -0,0 +1,2 @@ +-> + a = [..._1] diff --git a/test/fixtures/placeholder-args/spread-index-illegal/options.json b/test/fixtures/placeholder-args/spread-index-illegal/options.json new file mode 100644 index 0000000..ceb23ab --- /dev/null +++ b/test/fixtures/placeholder-args/spread-index-illegal/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Cannot use indices with spread placeholders." +} diff --git a/test/fixtures/placeholder-args/spread/actual.js b/test/fixtures/placeholder-args/spread/actual.js new file mode 100644 index 0000000..9e753e4 --- /dev/null +++ b/test/fixtures/placeholder-args/spread/actual.js @@ -0,0 +1,9 @@ +-> f(_2, _1, _, ..._) + +-> + a = [..._] + f(_2, _1, _, a) + +-> + a = [..._] + b = [..._] diff --git a/test/fixtures/placeholder-args/spread/expected.js b/test/fixtures/placeholder-args/spread/expected.js new file mode 100644 index 0000000..3390009 --- /dev/null +++ b/test/fixtures/placeholder-args/spread/expected.js @@ -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; +}); \ No newline at end of file