Skip to content

Commit

Permalink
ES7 async await impl with concise syntax
Browse files Browse the repository at this point in the history
see http://wiki.ecmascript.org/doku.php?id=strawman:async_functions

async function: `->>`, `~>>`, `-->>`, `~~>>`, `async (arglist) ->...`, `async function name (arglist)`
await: `await` => `await`; `await all` => `await*` (proposed to translate to `Promise.all`, not final)

backcall does NOT work, but this should be fine because they were invented to create the illusion of async function anyway
  • Loading branch information
summivox committed Dec 27, 2016
1 parent 7a30758 commit c60abe6
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 18 deletions.
32 changes: 19 additions & 13 deletions src/ast.ls
Original file line number Diff line number Diff line change
Expand Up @@ -1151,21 +1151,23 @@ class exports.Yield extends Node

children: <[ it ]>

show: -> if @op is 'yieldfrom' then 'from' else ''
show: -> switch @op
| 'yield' => ''
| 'yieldfrom' => 'from'
| 'await' => 'await'
| 'awaitall' => 'await all'
| _ => ''

::delegate <[ isCallable ]> -> yes

compile-node: (o) ->
code = []

if @op is \yieldfrom
code.push 'yield*'
else
code.push 'yield'

if @it
code.push " #{@it.compile o, LEVEL_OP + PREC.unary}"

code = [(switch @op
| 'yield' => 'yield'
| 'yieldfrom' => 'yield*'
| 'await' => 'await'
| 'awaitall' => 'await*'
)]
if @it then code.push " #{@it.compile o, LEVEL_OP + PREC.unary}"
sn(this, "(", ...code, ")")

#### Unary operators
Expand Down Expand Up @@ -1881,7 +1883,7 @@ class exports.Existence extends Node implements Negatable
#### Fun
# A function definition. This is the only node that creates a `new Scope`.
class exports.Fun extends Node
(@params or [], @body or Block!, @bound and \this$, @curried or false, @hushed = false, @generator = false) ~>
(@params or [], @body or Block!, @bound and \this$, @curried or false, @hushed = false, @generator = false, @async = false) ~>

children: <[ params body ]>

Expand Down Expand Up @@ -1913,7 +1915,11 @@ class exports.Fun extends Node
o.indent += TAB
{body, name, tab} = this
code = [\function]
if @generator
if @async
@ctor and @carp "a constructor can't be async"
o.in-generator = true
code.unshift 'async '
else if @generator
@ctor and @carp "a constructor can't be a generator"
o.in-generator = true
code.push \*
Expand Down
8 changes: 6 additions & 2 deletions src/grammar.ls
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,15 @@ bnf =

# The function literal can be either anonymous with `->`,
o 'PARAM( ArgList OptComma )PARAM -> Block'
, -> Fun $2, $6, /~/.test($5), /--|~~/.test($5), /!/.test($5), /\*/.test($5)
, -> Fun $2, $6, /~/.test($5), /--|~~/.test($5), /!/.test($5), /\*/.test($5), />>/.test($5)
o 'ASYNC PARAM( ArgList OptComma )PARAM -> Block'
, -> Fun $3, $7, /~/.test($6), /--|~~/.test($6), /!/.test($6), false, true
# or named with `function`.
o 'FUNCTION CALL( ArgList OptComma )CALL Block' -> (Fun $3, $6).named $1
o 'GENERATOR CALL( ArgList OptComma )CALL Block'
, -> (Fun $3, $6, false, false, false, true).named $1
, -> (Fun $3, $6, false, false, false, true, false).named $1
o 'ASYNC FUNCTION CALL( ArgList OptComma )CALL Block'
, -> (Fun $4, $7, false, false, false, false, true).named $2

# The full complement of `if` and `unless` expressions
o 'IF Expression Block Else' -> L 1 2 If $2, $3, $1 is 'unless' .add-else $4
Expand Down
14 changes: 11 additions & 3 deletions src/lexer.ls
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ exports <<<
tag = 'LITERAL'
case <[ new do typeof delete ]>
tag = 'UNARY'
case 'yield'
case 'yield' 'await'
tag = 'YIELD'
case 'return' 'throw'
tag = 'HURL'
Expand Down Expand Up @@ -240,6 +240,9 @@ exports <<<
or last.1 is 'import' and 'All'
last.1 += that
return 3
if last.0 is 'yield' and last.1 is 'await'
last.1 += 'all'
return 3
case 'from'
if last.1 is 'yield'
last.1 += 'from'
Expand Down Expand Up @@ -655,7 +658,7 @@ exports <<<
@fset 'for' false
tag = 'THEN'
default
if /^!?(?:--?|~~?)>\*?$/.test val # function arrow
if /^!?(?:--?|~~?)>(?:>|\*)?$/.test val # function arrow
@parameters tag = '->'
else if /^\*?<(?:--?|~~?)!?$/.test val # backcall
@parameters tag = '<-'
Expand Down Expand Up @@ -1030,6 +1033,11 @@ character = if not JSON? then uxxxx else ->
[')PARAM' ')' line, column]
['->' '~>' line, column]
break LOOP
case tag is 'ID' and val is 'async'
next = tokens[i + 1]
switch next.0
| 'PARAM(', 'FUNCTION' => token.0 = 'ASYNC'
| 'GENERATOR' => carp 'named generator cannot be async' line
prev = token
continue

Expand Down Expand Up @@ -1344,7 +1352,7 @@ SYMBOL = //
| \.{1,3} # dot / cascade / splat/placeholder/yada*3
| \^\^ # clone
| \*?<(?:--?|~~?)!? # backcall
| !?(?:--?|~~?)>\*? # function, bound function
| !?(?:--?|~~?)>(?:>|\*)? # function, bound function
| ([-+&|:])\1 # crement / logic / `prototype`
| %% # mod
| & # arguments
Expand Down

0 comments on commit c60abe6

Please sign in to comment.