From 9f8710b631868ba7b8080d9c4c1d0e783be497a2 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Wed, 24 Feb 2010 18:18:29 -0500 Subject: [PATCH] adding compilation over stdin/stdout. Use --stdio or -s, and pipe away. --- lib/command_line.js | 47 +++++++++++++++++++++++++++++------------ lib/nodes.js | 2 +- src/command_line.coffee | 33 +++++++++++++++++++---------- src/nodes.coffee | 2 +- 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/lib/command_line.js b/lib/command_line.js index 61e7ffbb..fe23e186 100644 --- a/lib/command_line.js +++ b/lib/command_line.js @@ -1,11 +1,11 @@ (function(){ - var BANNER, SWITCHES, coffee, compile_script, compile_scripts, fs, lint, option_parser, options, optparse, parse_options, path, sources, usage, version, watch_scripts, write_js; + var BANNER, SWITCHES, coffee, compile_options, compile_script, compile_scripts, compile_stdio, fs, lint, option_parser, options, optparse, parse_options, path, sources, usage, version, watch_scripts, write_js; fs = require('fs'); path = require('path'); coffee = require('coffee-script'); optparse = require('optparse'); BANNER = "coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee"; - SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-e', '--eval', 'compile a string from the command line'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']]; + SWITCHES = [['-i', '--interactive', 'run an interactive CoffeeScript REPL'], ['-r', '--run', 'compile and run a CoffeeScript'], ['-o', '--output [DIR]', 'set the directory for compiled JavaScript'], ['-w', '--watch', 'watch scripts for changes, and recompile'], ['-p', '--print', 'print the compiled JavaScript to stdout'], ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'], ['-s', '--stdio', 'listen for and compile scripts over stdio'], ['-e', '--eval', 'compile a string from the command line'], ['-t', '--tokens', 'print the tokens that the lexer produces'], ['-tr', '--tree', 'print the parse tree that Jison produces'], ['-n', '--no-wrap', 'compile without the top-level function wrapper'], ['-v', '--version', 'display CoffeeScript version'], ['-h', '--help', 'display this help message']]; options = {}; sources = []; option_parser = null; @@ -22,6 +22,9 @@ if (options.interactive) { return require('repl'); } + if (options.stdio) { + return compile_stdio(); + } if (options.eval) { return compile_script('unknown', sources[0]); } @@ -70,36 +73,46 @@ // Compile a single source script, containing the given code, according to the // requested options. Both compile_scripts and watch_scripts share this method. compile_script = function compile_script(source, code) { - var js, o, opts; - opts = options; - o = opts['no-wrap'] ? { - no_wrap: true - } : {}; + var js; try { - if (opts.tokens) { + if (options.tokens) { return coffee.print_tokens(coffee.tokenize(code)); - } else if (opts.tree) { + } else if (options.tree) { return puts(coffee.tree(code).toString()); } else { - js = coffee.compile(code, o); - if (opts.run) { + js = coffee.compile(code, compile_options()); + if (options.run) { return eval(js); - } else if (opts.lint) { + } else if (options.lint) { return lint(js); - } else if (opts.print || opts.eval) { + } else if (options.print || options.eval) { return puts(js); } else { return write_js(source, js); } } } catch (err) { - if (opts.watch) { + if (options.watch) { return puts(err.message); } else { throw err; } } }; + // Listen for and compile scripts over stdio. + compile_stdio = function compile_stdio() { + var code; + code = ''; + process.stdio.open(); + process.stdio.addListener('data', function(string) { + if (string) { + return code += string; + } + }); + return process.stdio.addListener('close', function() { + return process.stdio.write(coffee.compile(code, compile_options())); + }); + }; // Watch a list of source CoffeeScript files, recompiling them every time the // files are updated. watch_scripts = function watch_scripts() { @@ -155,4 +168,10 @@ options = option_parser.parse(process.ARGV); return sources = options.arguments.slice(2, options.arguments.length); }; + // The options to pass to the CoffeeScript compiler. + compile_options = function compile_options() { + return options['no-wrap'] ? { + no_wrap: true + } : {}; + }; })(); \ No newline at end of file diff --git a/lib/nodes.js b/lib/nodes.js index f9050655..0b405b65 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -233,7 +233,7 @@ o.scope = new Scope(null, this, null); code = o.globals ? this.compile_node(o) : this.compile_with_declarations(o); code = code.replace(TRAILING_WHITESPACE, ''); - return o.no_wrap ? code : "(function(){\n" + code + "\n})();"; + return o.no_wrap ? code : "(function(){\n" + code + "\n})();\n"; }, // Compile the expressions body, with declarations of all inner variables // pushed up to the top. diff --git a/src/command_line.coffee b/src/command_line.coffee index 1977d984..5a1ca774 100644 --- a/src/command_line.coffee +++ b/src/command_line.coffee @@ -17,6 +17,7 @@ SWITCHES: [ ['-w', '--watch', 'watch scripts for changes, and recompile'] ['-p', '--print', 'print the compiled JavaScript to stdout'] ['-l', '--lint', 'pipe the compiled JavaScript through JSLint'] + ['-s', '--stdio', 'listen for and compile scripts over stdio'] ['-e', '--eval', 'compile a string from the command line'] ['-t', '--tokens', 'print the tokens that the lexer produces'] ['-tr','--tree', 'print the parse tree that Jison produces'] @@ -35,6 +36,7 @@ exports.run: -> return usage() if options.help return version() if options.version return require 'repl' if options.interactive + return compile_stdio() if options.stdio return compile_script 'unknown', sources[0] if options.eval return usage() unless sources.length separator: sources.indexOf '--' @@ -64,23 +66,29 @@ compile_scripts: -> fs.readFile source, (err, code) -> compile_script(source, code) compile(source) for source in sources - # Compile a single source script, containing the given code, according to the # requested options. Both compile_scripts and watch_scripts share this method. compile_script: (source, code) -> - opts: options - o: if opts['no-wrap'] then {no_wrap: true} else {} try - if opts.tokens then coffee.print_tokens coffee.tokenize code - else if opts.tree then puts coffee.tree(code).toString() + if options.tokens then coffee.print_tokens coffee.tokenize code + else if options.tree then puts coffee.tree(code).toString() else - js: coffee.compile code, o - if opts.run then eval js - else if opts.lint then lint js - else if opts.print or opts.eval then puts js - else write_js source, js + js: coffee.compile code, compile_options() + if options.run then eval js + else if options.lint then lint js + else if options.print or options.eval then puts js + else write_js source, js catch err - if opts.watch then puts err.message else throw err + if options.watch then puts err.message else throw err + +# Listen for and compile scripts over stdio. +compile_stdio: -> + code: '' + process.stdio.open() + process.stdio.addListener 'data', (string) -> + code += string if string + process.stdio.addListener 'close', -> + process.stdio.write coffee.compile code, compile_options() # Watch a list of source CoffeeScript files, recompiling them every time the # files are updated. @@ -114,3 +122,6 @@ parse_options: -> options: option_parser.parse(process.ARGV) sources: options.arguments[2...options.arguments.length] +# The options to pass to the CoffeeScript compiler. +compile_options: -> + if options['no-wrap'] then {no_wrap: true} else {} diff --git a/src/nodes.coffee b/src/nodes.coffee index e50bacd5..f4a64ec0 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -156,7 +156,7 @@ Expressions: exports.Expressions: inherit Node, { o.scope: new Scope(null, this, null) code: if o.globals then @compile_node(o) else @compile_with_declarations(o) code: code.replace(TRAILING_WHITESPACE, '') - if o.no_wrap then code else "(function(){\n"+code+"\n})();" + if o.no_wrap then code else "(function(){\n"+code+"\n})();\n" # Compile the expressions body, with declarations of all inner variables # pushed up to the top.