diff --git a/lib/coffeescript/repl.js b/lib/coffeescript/repl.js index f027e54853..6b561527c2 100644 --- a/lib/coffeescript/repl.js +++ b/lib/coffeescript/repl.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 2.0.0-beta3 (function() { - var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, updateSyntaxError, vm; + var CoffeeScript, addHistory, addMultilineHandler, fs, getCommandId, merge, nodeREPL, path, replDefaults, runInContext, sawSIGINT, updateSyntaxError, vm; fs = require('fs'); @@ -14,6 +14,8 @@ ({merge, updateSyntaxError} = require('./helpers')); + sawSIGINT = false; + replDefaults = { prompt: 'coffee> ', historyFile: (function() { @@ -24,12 +26,12 @@ } })(), historyMaxInputSize: 10240, - eval: function(input, context, filename, cb) { - var Assign, Block, Literal, Value, ast, err, js, referencedVars, token, tokens; + eval: async function(input, context, filename, cb) { + var Assign, Block, Call, Code, Literal, Value, ast, err, isAsync, js, referencedVars, result, token, tokens; input = input.replace(/\uFF00/g, '\n'); input = input.replace(/^\(([\s\S]*)\n\)$/m, '$1'); input = input.replace(/^\s*try\s*{([\s\S]*)}\s*catch.*$/m, '$1'); - ({Block, Assign, Value, Literal} = require('./nodes')); + ({Block, Assign, Value, Literal, Call, Code} = require('./nodes')); try { tokens = CoffeeScript.tokens(input); referencedVars = (function() { @@ -45,12 +47,25 @@ })(); ast = CoffeeScript.nodes(tokens); ast = new Block([new Assign(new Value(new Literal('__')), ast, '=')]); + ast = new Code([], ast); + isAsync = ast.isAsync; + ast = new Block([new Call(ast)]); js = ast.compile({ bare: true, locals: Object.keys(context), - referencedVars + referencedVars, + sharedScope: true }); - return cb(null, runInContext(js, context, filename)); + result = runInContext(js, context, filename); + if (isAsync) { + result = (await result); + if (!sawSIGINT) { + cb(null, result); + } + return sawSIGINT = false; + } else { + return cb(null, result); + } } catch (error) { err = error; updateSyntaxError(err, input); @@ -150,6 +165,9 @@ return lastLine = code; } }); + repl.on('SIGINT', function() { + return sawSIGINT = true; + }); repl.on('exit', function() { return fs.closeSync(fd); }); diff --git a/src/repl.coffee b/src/repl.coffee index aa89f617fe..7ac2cc1ac3 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -5,6 +5,8 @@ nodeREPL = require 'repl' CoffeeScript = require './' {merge, updateSyntaxError} = require './helpers' +sawSIGINT = no + replDefaults = prompt: 'coffee> ', historyFile: do -> @@ -22,23 +24,31 @@ replDefaults = input = input.replace /^\s*try\s*{([\s\S]*)}\s*catch.*$/m, '$1' # Require AST nodes to do some AST manipulation. - {Block, Assign, Value, Literal} = require './nodes' + {Block, Assign, Value, Literal, Call, Code} = require './nodes' try # Tokenize the clean input. tokens = CoffeeScript.tokens input # Collect referenced variable names just like in `CoffeeScript.compile`. - referencedVars = ( - token[1] for token in tokens when token[0] is 'IDENTIFIER' - ) + referencedVars = (token[1] for token in tokens when token[0] is 'IDENTIFIER') # Generate the AST of the tokens. ast = CoffeeScript.nodes tokens - # Add assignment to `_` variable to force the input to be an expression. - ast = new Block [ - new Assign (new Value new Literal '__'), ast, '=' - ] - js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars} - cb null, runInContext js, context, filename + # Add assignment to `__` variable to force the input to be an expression. + ast = new Block [new Assign (new Value new Literal '__'), ast, '='] + # Wrap the expression in a closure to support top-level `await` + ast = new Code [], ast + isAsync = ast.isAsync + # Invoke the wrapping closure + ast = new Block [new Call ast] + js = ast.compile {bare: yes, locals: Object.keys(context), referencedVars, sharedScope: yes} + result = runInContext js, context, filename + # Await an async result, if necessary + if isAsync + result = await result + cb null, result unless sawSIGINT + sawSIGINT = false + else + cb null, result catch err # AST's `compile` does not add source code information to syntax errors. updateSyntaxError err, input @@ -131,6 +141,8 @@ addHistory = (repl, filename, maxSize) -> fs.writeSync fd, "#{code}\n" lastLine = code + # XXX: The SIGINT event from REPLServer is undocumented, so this is a bit fragile + repl.on 'SIGINT', -> sawSIGINT = yes repl.on 'exit', -> fs.closeSync fd # Add a command to show the history stack