diff --git a/src/ast.ls b/src/ast.ls index 41b909b8c..9bf81b52a 100644 --- a/src/ast.ls +++ b/src/ast.ls @@ -157,6 +157,7 @@ SourceNode::to-string = (...args) -> that.carp 'inconvertible statement' if @get-jump! fun = Fun [] Block this call = Call! + fun.async = true if o.in-async fun.generator = true if o.in-generator var hasArgs, hasThis @traverse-children !-> @@ -174,6 +175,8 @@ SourceNode::to-string = (...args) -> out = Parens(Chain fun<<<{+wrapper, @void} [call]; true) if o.in-generator out = new Yield 'yieldfrom', out + else if o.in-async + out = new Yield 'await', out out.compile o # Compiles a child node as a block statement. @@ -1151,21 +1154,21 @@ class exports.Yield extends Node children: <[ it ]> - show: -> if @op is 'yieldfrom' then 'from' else '' + show: -> switch @op + | 'yield' => '' + | 'yieldfrom' => 'from' + | 'await' => 'await' + | _ => '' ::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' + )] + if @it then code.push " #{@it.compile o, LEVEL_OP + PREC.unary}" sn(this, "(", ...code, ")") #### Unary operators @@ -1881,7 +1884,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 ]> @@ -1913,7 +1916,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-async = true + code.unshift 'async ' + else if @generator @ctor and @carp "a constructor can't be a generator" o.in-generator = true code.push \* diff --git a/src/grammar.ls b/src/grammar.ls index b875fae73..c1d9efa7e 100644 --- a/src/grammar.ls +++ b/src/grammar.ls @@ -277,11 +277,13 @@ 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) # 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 diff --git a/src/lexer.ls b/src/lexer.ls index cec6e68f1..9957b28f8 100644 --- a/src/lexer.ls +++ b/src/lexer.ls @@ -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' @@ -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' @@ -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 = '<-' @@ -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 + | 'FUNCTION' => token.0 = 'ASYNC' + | 'GENERATOR' => carp 'named generator cannot be async' line prev = token continue @@ -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