Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/coffee-script.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,14 @@ exports.tokens = withPrettyErrors (code, options) ->
# return the AST. You can then compile it by calling `.compile()` on the root,
# or traverse it by using `.traverseChildren()` with a callback.
exports.nodes = withPrettyErrors (source, options) ->
console.log 'uniced', options.uniced
if typeof source is 'string'
iced_transform(parser.parse(lexer.tokenize(source, options)), options)
result = parser.parse lexer.tokenize(source, options)
else
iced_transform(parser.parse(source),options)
result = parser.parse source
if not options.uniced
result = iced_transform result, options
return result

# Compile and execute a string of CoffeeScript (on the server), correctly
# setting `__filename`, `__dirname`, and relative `require()`.
Expand Down
7 changes: 5 additions & 2 deletions src/command.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ SWITCHES = [
['-s', '--stdio', 'listen for and compile scripts over stdio']
['-l', '--literate', 'treat stdio as literate style coffee-script']
['-t', '--tokens', 'print out the tokens that the lexer/rewriter produce']
['-u', '--uniced', 'print out the uniced parse tree that the parser produces']
['-v', '--version', 'display the version number']
['-w', '--watch', 'watch scripts for changes and rerun commands']
['-I', '--runtime [WHICH]', "how to include the iced runtime, one of #{runtime_modes_str}; default is 'node'" ]
Expand Down Expand Up @@ -168,8 +169,9 @@ compileScript = (file, input, base = null) ->
CoffeeScript.emit 'compile', task
if o.tokens
printTokens CoffeeScript.tokens t.input, t.options
else if o.nodes
printLine CoffeeScript.nodes(t.input, t.options).toString().trim()
else if o.nodes or o.uniced
printLine CoffeeScript.nodes(
t.input, t.options, o.uniced).toString().trim()
else if o.run
CoffeeScript.register()
CoffeeScript.run t.input, t.options
Expand Down Expand Up @@ -403,6 +405,7 @@ compileOptions = (filename, base) ->
sourceMap: opts.map
runtime : opts.runtime
runforce : opts.runforce
uniced: opts.uniced
}
if filename
if base
Expand Down
14 changes: 11 additions & 3 deletions src/grammar.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ o = (patternString, action, options) ->

# All runtime functions we need are defined on "yy"
action = action.replace /\bnew /g, '$&yy.'
action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
action = action.replace /\b(?:Block\.wrap|extend|makewait)\b/g, 'yy.$&'

# Returns a function which adds location data to the first parameter passed
# in, and returns the parameter. If the parameter is not a node, it will
Expand Down Expand Up @@ -85,6 +85,7 @@ grammar =

# Block and statements, which make up a line in a body.
Line: [
o 'AwaitAssign'
o 'Expression'
o 'Statement'
]
Expand All @@ -98,8 +99,15 @@ grammar =
]

Await: [
o 'AWAIT Block', -> new Await $2
o 'AWAIT Expression', -> new Await Block.wrap [$2 ]
o 'AWAIT Block', -> makewait false, $2, yylineno
o 'AWAIT Expression', -> makewait true, $2, yylineno
]

# ECMAScript 7-style x = await fn()
AwaitAssign: [
o 'Assignable = AWAIT Expression', -> makewait $1, $4, yylineno
o 'Assignable = TERMINATOR AWAIT Expression', -> makewait $1, $5, yylineno
o 'Assignable = INDENT AWAIT Expression OUTDENT', -> makewait $1, $5, yylineno
]

# All the different types of expressions in our language. The basic unit of
Expand Down
33 changes: 33 additions & 0 deletions src/nodes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2660,6 +2660,36 @@ exports.Await = class Await extends Base
super p, o
@icedNodeFlag = o.foundAwaitFunc = o.foundAwait = true

#### makewait

# The **Await.assign** is used to assign a local variable to value,
# or to set the property of an object -- including within object literals.
exports.makewait = (variable, value, lineno) ->
hasDefer = value.contains isDefer
# if this is a bare await containing a single expression (variable is true)
# then it should be treated as an iced-await if it contains 'defer'.
if variable is true and hasDefer
variable = false
value = Block.wrap [ value ]
# if this is a bare await containing a block, then it is an iced-style await.
if variable is false
result = new Await value
if not hasDefer
result.error 'await block is missing a defer statement'
return result
# if this is an await assignment, then parse it as if it uses defer notation.
# written as: x = await expr
# parses as: await (expr).then(defer x)
# TODO: consider doing this as part of the iced transformation
expr = new Value new Parens value
expr_then = expr.add new Access new Value new Literal "then"
defer_args = if variable is true then [] else [variable]
call = new Call(expr_then, [ new Defer(defer_args, lineno) ])
result = new Await Block.wrap [ call ]
if hasDefer
result.error 'promise-style await must not have a defer statement'
return result

#### IcedRuntime
#
# By default, the iced libraries are require'd via nodejs' require.
Expand Down Expand Up @@ -3606,6 +3636,9 @@ isLiteralThis = (node) ->
(node instanceof Code and node.bound) or
(node instanceof Call and node.isSuper)

isDefer = (node) ->
node instanceof Defer

# Unfold a node's child if soak, then tuck the node under created `If`
unfoldSoak = (o, parent, name) ->
return unless ifn = parent[name].unfoldSoak o
Expand Down