diff --git a/lib/coffee-script.js b/lib/coffee-script.js index 0d5486ef..a1fe3476 100755 --- a/lib/coffee-script.js +++ b/lib/coffee-script.js @@ -1,7 +1,8 @@ (function() { - var Lexer, RESERVED, compile, fs, lexer, parser, path, _ref; + var Lexer, RESERVED, compile, fs, lexer, parser, path, vm, _ref; fs = require('fs'); path = require('path'); + vm = require('vm'); _ref = require('./lexer'), Lexer = _ref.Lexer, RESERVED = _ref.RESERVED; parser = require('./parser').parser; if (require.extensions) { @@ -64,11 +65,30 @@ } }; exports.eval = function(code, options) { - global.__filename = module.filename = process.argv[1] = options.filename; - global.__dirname = path.dirname(__filename); - global.require = require; - global.module = module; - return (0, eval)(compile(code, options)); + var g, js, sandbox; + if (options == null) { + options = {}; + } + sandbox = options.sandbox; + if (!sandbox) { + sandbox = { + require: require, + module: { + exports: {} + }, + global: {} + }; + for (g in global) { + sandbox[g] = global[g]; + } + sandbox.global.global = sandbox.global; + sandbox.global.root = sandbox.global; + sandbox.global.GLOBAL = sandbox.global; + } + sandbox.__filename = options.filename || 'eval'; + sandbox.__dirname = path.dirname(sandbox.__filename); + js = compile("_=(" + (code.trim()) + ")", options); + return vm.runInNewContext(js, sandbox, sandbox.__filename); }; lexer = new Lexer; parser.lexer = { diff --git a/lib/repl.js b/lib/repl.js index 865cf91e..c7bc51c3 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -15,27 +15,44 @@ return stdout.write((err.stack || err.toString()) + '\n\n'); }; backlog = ''; - run = function(buffer) { - var code, val; - code = backlog += '\n' + buffer.toString(); - if (code[code.length - 1] === '\\') { - return backlog = backlog.slice(0, backlog.length - 1); + run = (function() { + var g, sandbox; + sandbox = { + require: require, + module: { + exports: {} + }, + global: {} + }; + for (g in global) { + sandbox[g] = global[g]; } - backlog = ''; - try { - val = CoffeeScript.eval(code, { - bare: true, - globals: true, - filename: 'repl' - }); - if (val !== void 0) { - process.stdout.write(inspect(val, false, 2, enableColours) + '\n'); + sandbox.global.global = sandbox.global; + sandbox.global.root = sandbox.global; + sandbox.global.GLOBAL = sandbox.global; + return function(buffer) { + var code, val; + code = backlog += '\n' + buffer.toString(); + if (code[code.length - 1] === '\\') { + return backlog = backlog.slice(0, backlog.length - 1); } - } catch (err) { - error(err); - } - return repl.prompt(); - }; + backlog = ''; + try { + val = CoffeeScript.eval(code, { + sandbox: sandbox, + bare: true, + globals: true, + filename: 'repl' + }); + if (val !== void 0) { + process.stdout.write(inspect(val, false, 2, enableColours) + '\n'); + } + } catch (err) { + error(err); + } + return repl.prompt(); + }; + })(); ACCESSOR = /\s*([\w\.]+)(?:\.(\w*))$/; SIMPLEVAR = /\s*(\w*)$/i; autocomplete = function(text) { diff --git a/src/coffee-script.coffee b/src/coffee-script.coffee index a2357faf..c63a1cc7 100755 --- a/src/coffee-script.coffee +++ b/src/coffee-script.coffee @@ -8,6 +8,7 @@ fs = require 'fs' path = require 'path' +vm = require 'vm' {Lexer,RESERVED} = require './lexer' {parser} = require './parser' @@ -77,12 +78,21 @@ exports.run = (code, options) -> # Compile and evaluate a string of CoffeeScript (in a Node.js-like environment). # The CoffeeScript REPL uses this to run the input. -exports.eval = (code, options) -> - global.__filename = module.filename = process.argv[1] = options.filename - global.__dirname = path.dirname __filename - global.require = require - global.module = module - (0;eval) compile code, options +exports.eval = (code, options = {}) -> + sandbox = options.sandbox + unless sandbox + sandbox = + require: require + module : { exports: {} } + global : {} + sandbox[g] = global[g] for g of global + sandbox.global.global = sandbox.global + sandbox.global.root = sandbox.global + sandbox.global.GLOBAL = sandbox.global + sandbox.__filename = options.filename || 'eval' + sandbox.__dirname = path.dirname sandbox.__filename + js = compile "_=(#{code.trim()})", options + vm.runInNewContext js, sandbox, sandbox.__filename # Instantiate a Lexer for our use here. lexer = new Lexer diff --git a/src/repl.coffee b/src/repl.coffee index 59b2f4ce..6731fa60 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -31,18 +31,32 @@ backlog = '' # The main REPL function. **run** is called every time a line of code is entered. # Attempt to evaluate the command. If there's an exception, print it out instead # of exiting. -run = (buffer) -> - code = backlog += '\n' + buffer.toString() - if code[code.length - 1] is '\\' - return backlog = backlog[0...backlog.length - 1] - backlog = '' - try - val = CoffeeScript.eval code, bare: on, globals: on, filename: 'repl' - unless val is undefined - process.stdout.write inspect(val, no, 2, enableColours) + '\n' - catch err - error err - repl.prompt() +run = do -> + sandbox = + require: require + module : { exports: {} } + global : {} + sandbox[g] = global[g] for g of global + sandbox.global.global = sandbox.global + sandbox.global.root = sandbox.global + sandbox.global.GLOBAL = sandbox.global + (buffer) -> + code = backlog += '\n' + buffer.toString() + if code[code.length - 1] is '\\' + return backlog = backlog[0...backlog.length - 1] + backlog = '' + try + val = CoffeeScript.eval code, { + sandbox, + bare: on, + globals: on, + filename: 'repl' + } + unless val is undefined + process.stdout.write inspect(val, no, 2, enableColours) + '\n' + catch err + error err + repl.prompt() ## Autocompletion