1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

implementing the inline javascript in the documentation page in text/coffeescript, switching from the closure compiler to the yui compressor for building the browser version -- the closure compiler had a bug for our input -- fixable by hand but not worth the tiny savings

This commit is contained in:
Jeremy Ashkenas 2010-02-24 20:41:56 -05:00
parent c1427d6558
commit c14869f008
8 changed files with 154 additions and 688 deletions

View file

@ -2,7 +2,7 @@ require 'erb'
require 'fileutils' require 'fileutils'
require 'rake/testtask' require 'rake/testtask'
require 'rubygems' require 'rubygems'
require 'closure-compiler' require 'yui/compressor'
desc "Build the documentation page" desc "Build the documentation page"
task :doc do task :doc do
@ -25,7 +25,7 @@ desc "Build the single concatenated and minified script for the browser"
task :browser do task :browser do
sources = %w(rewriter.js lexer.js parser.js scope.js nodes.js coffee-script.js) sources = %w(rewriter.js lexer.js parser.js scope.js nodes.js coffee-script.js)
code = sources.map {|s| File.read('lib/' + s) }.join('') code = sources.map {|s| File.read('lib/' + s) }.join('')
code = Closure::Compiler.new.compile(code) code = YUI::JavaScriptCompressor.new.compress(code)
File.open('extras/coffee-script.js', 'w+') {|f| f.write(code) } File.open('extras/coffee-script.js', 'w+') {|f| f.write(code) }
end end

View file

@ -923,52 +923,44 @@ coffee --print app/scripts/*.coffee > concatenation.js</pre>
</div> </div>
<script type="text/javascript" src="lib/rewriter.js"></script> <script src="extras/coffee-script.js"></script>
<script type="text/javascript" src="lib/lexer.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="lib/parser.js"></script>
<script type="text/javascript" src="lib/scope.js"></script>
<script type="text/javascript" src="lib/nodes.js"></script>
<script type="text/javascript" src="lib/coffee-script.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/coffeescript">
<script type="text/javascript"> window.repl_compile: ->
window.repl_compile = function() { source: $('#repl_source').val()
var source = $('#repl_source').val(); window.compiled_js: ''
window.compiled_js = ''; try
try { window.compiled_js: CoffeeScript.compile source, {no_wrap: true}
window.compiled_js = CoffeeScript.compile(source, {no_wrap: true}); catch error then alert error
} catch(error) { $('#repl_results').html window.compiled_js
alert(error);
}
$('#repl_results').html(window.compiled_js);
};
window.repl_run = function() {
try {
eval(window.compiled_js);
} catch(error) {
alert(error);
}
};
var nav = $('.navigation'); window.repl_run: ->
var currentNav = null; try
var closeMenus = function() { eval window.compiled_js
if (currentNav) currentNav.removeClass('active'); catch error then alert error
currentNav = null;
}; nav: $('.navigation')
nav.click(function(e) { current_nav: null
if (e.target.tagName.toLowerCase() == 'a') return;
if (this !== (currentNav && currentNav[0])) { close_menus: ->
closeMenus(); current_nav.removeClass 'active' if current_nav
currentNav = $(this); current_nav: null
currentNav.addClass('active');
} nav.click (e) ->
return false; return if e.target.tagName.toLowerCase() is 'a'
}); if this isnt (current_nav and current_nav[0])
$(document.body).click(function() { close_menus();
closeMenus(); current_nav: $(this)
}); current_nav.addClass 'active'
false
$(document.body).click -> close_menus()
</script>
<script>
CoffeeScript.activate();
</script> </script>
</body> </body>

File diff suppressed because one or more lines are too long

View file

@ -1803,52 +1803,44 @@ task(<span class="String"><span class="String">'</span>test<span class="String">
</div> </div>
<script type="text/javascript" src="lib/rewriter.js"></script> <script src="extras/coffee-script.js"></script>
<script type="text/javascript" src="lib/lexer.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="lib/parser.js"></script>
<script type="text/javascript" src="lib/scope.js"></script>
<script type="text/javascript" src="lib/nodes.js"></script>
<script type="text/javascript" src="lib/coffee-script.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/coffeescript">
<script type="text/javascript"> window.repl_compile: ->
window.repl_compile = function() { source: $('#repl_source').val()
var source = $('#repl_source').val(); window.compiled_js: ''
window.compiled_js = ''; try
try { window.compiled_js: CoffeeScript.compile source, {no_wrap: true}
window.compiled_js = CoffeeScript.compile(source, {no_wrap: true}); catch error then alert error
} catch(error) { $('#repl_results').html window.compiled_js
alert(error);
}
$('#repl_results').html(window.compiled_js);
};
window.repl_run = function() {
try {
eval(window.compiled_js);
} catch(error) {
alert(error);
}
};
var nav = $('.navigation'); window.repl_run: ->
var currentNav = null; try
var closeMenus = function() { eval window.compiled_js
if (currentNav) currentNav.removeClass('active'); catch error then alert error
currentNav = null;
}; nav: $('.navigation')
nav.click(function(e) { current_nav: null
if (e.target.tagName.toLowerCase() == 'a') return;
if (this !== (currentNav && currentNav[0])) { close_menus: ->
closeMenus(); current_nav.removeClass 'active' if current_nav
currentNav = $(this); current_nav: null
currentNav.addClass('active');
} nav.click (e) ->
return false; return if e.target.tagName.toLowerCase() is 'a'
}); if this isnt (current_nav and current_nav[0])
$(document.body).click(function() { close_menus();
closeMenus(); current_nav: $(this)
}); current_nav.addClass 'active'
false
$(document.body).click -> close_menus()
</script>
<script>
CoffeeScript.activate();
</script> </script>
</body> </body>

View file

@ -87,7 +87,7 @@
} else if (o.lint) { } else if (o.lint) {
return lint(js); return lint(js);
} else if (o.print || o.eval) { } else if (o.print || o.eval) {
return puts(js); return print(js);
} else { } else {
return write_js(source, js); return write_js(source, js);
} }

View file

@ -1,5 +1,5 @@
(function(){ (function(){
var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, Node, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, inherit, merge, statement; var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, ValueNode, WhileNode, compact, del, flatten, inherit, merge, statement;
var __hasProp = Object.prototype.hasOwnProperty; var __hasProp = Object.prototype.hasOwnProperty;
(typeof process !== "undefined" && process !== null) ? process.mixin(require('scope')) : (this.exports = this); (typeof process !== "undefined" && process !== null) ? process.mixin(require('scope')) : (this.exports = this);
// Some helper functions // Some helper functions
@ -90,12 +90,12 @@
// generated code should be wrapped up in a closure. An options hash is passed // generated code should be wrapped up in a closure. An options hash is passed
// and cloned throughout, containing messages from higher in the AST, // and cloned throughout, containing messages from higher in the AST,
// information about the current scope, and indentation level. // information about the current scope, and indentation level.
Node = (exports.Node = function Node() { }); BaseNode = (exports.BaseNode = function BaseNode() { });
// This is extremely important -- we convert JS statements into expressions // This is extremely important -- we convert JS statements into expressions
// by wrapping them in a closure, only if it's possible, and we're not at // by wrapping them in a closure, only if it's possible, and we're not at
// the top level of a block (which would be unnecessary), and we haven't // the top level of a block (which would be unnecessary), and we haven't
// already been asked to return the result. // already been asked to return the result.
Node.prototype.compile = function compile(o) { BaseNode.prototype.compile = function compile(o) {
var closure, top; var closure, top;
this.options = merge(o || {}); this.options = merge(o || {});
this.indent = o.indent; this.indent = o.indent;
@ -110,21 +110,21 @@
}; };
// Statements converted into expressions share scope with their parent // Statements converted into expressions share scope with their parent
// closure, to preserve JavaScript-style lexical scope. // closure, to preserve JavaScript-style lexical scope.
Node.prototype.compile_closure = function compile_closure(o) { BaseNode.prototype.compile_closure = function compile_closure(o) {
this.indent = o.indent; this.indent = o.indent;
o.shared_scope = o.scope; o.shared_scope = o.scope;
return ClosureNode.wrap(this).compile(o); return ClosureNode.wrap(this).compile(o);
}; };
// If the code generation wishes to use the result of a complex expression // If the code generation wishes to use the result of a complex expression
// in multiple places, ensure that the expression is only ever evaluated once. // in multiple places, ensure that the expression is only ever evaluated once.
Node.prototype.compile_reference = function compile_reference(o) { BaseNode.prototype.compile_reference = function compile_reference(o) {
var compiled, reference; var compiled, reference;
reference = new LiteralNode(o.scope.free_variable()); reference = new LiteralNode(o.scope.free_variable());
compiled = new AssignNode(reference, this); compiled = new AssignNode(reference, this);
return [compiled, reference]; return [compiled, reference];
}; };
// Quick short method for the current indentation level, plus tabbing in. // Quick short method for the current indentation level, plus tabbing in.
Node.prototype.idt = function idt(tabs) { BaseNode.prototype.idt = function idt(tabs) {
var _a, _b, _c, _d, i, idt; var _a, _b, _c, _d, i, idt;
idt = (this.indent || ''); idt = (this.indent || '');
_c = 0; _d = (tabs || 0); _c = 0; _d = (tabs || 0);
@ -134,7 +134,7 @@
return idt; return idt;
}; };
// Does this node, or any of its children, contain a node of a certain kind? // Does this node, or any of its children, contain a node of a certain kind?
Node.prototype.contains = function contains(block) { BaseNode.prototype.contains = function contains(block) {
var _a, _b, node; var _a, _b, node;
_a = this.children; _a = this.children;
for (_b = 0; _b < _a.length; _b++) { for (_b = 0; _b < _a.length; _b++) {
@ -142,14 +142,14 @@
if (block(node)) { if (block(node)) {
return true; return true;
} }
if (node instanceof Node && node.contains(block)) { if (node instanceof BaseNode && node.contains(block)) {
return true; return true;
} }
} }
return false; return false;
}; };
// toString representation of the node, for inspecting the parse tree. // toString representation of the node, for inspecting the parse tree.
Node.prototype.toString = function toString(idt) { BaseNode.prototype.toString = function toString(idt) {
var _a, _b, _c, child; var _a, _b, _c, child;
idt = idt || ''; idt = idt || '';
return '\n' + idt + this.type + (function() { return '\n' + idt + this.type + (function() {
@ -162,24 +162,24 @@
}).call(this).join(''); }).call(this).join('');
}; };
// Default implementations of the common node methods. // Default implementations of the common node methods.
Node.prototype.unwrap = function unwrap() { BaseNode.prototype.unwrap = function unwrap() {
return this; return this;
}; };
Node.prototype.children = []; BaseNode.prototype.children = [];
Node.prototype.is_statement = function is_statement() { BaseNode.prototype.is_statement = function is_statement() {
return false; return false;
}; };
Node.prototype.is_statement_only = function is_statement_only() { BaseNode.prototype.is_statement_only = function is_statement_only() {
return false; return false;
}; };
Node.prototype.top_sensitive = function top_sensitive() { BaseNode.prototype.top_sensitive = function top_sensitive() {
return false; return false;
}; };
Node.prototype.operation_sensitive = function operation_sensitive() { BaseNode.prototype.operation_sensitive = function operation_sensitive() {
return false; return false;
}; };
// A collection of nodes, each one representing an expression. // A collection of nodes, each one representing an expression.
Expressions = (exports.Expressions = inherit(Node, { Expressions = (exports.Expressions = inherit(BaseNode, {
type: 'Expressions', type: 'Expressions',
constructor: function constructor(nodes) { constructor: function constructor(nodes) {
this.children = (this.expressions = compact(flatten(nodes || []))); this.children = (this.expressions = compact(flatten(nodes || [])));
@ -212,7 +212,7 @@
}, },
compile: function compile(o) { compile: function compile(o) {
o = o || {}; o = o || {};
return o.scope ? Node.prototype.compile.call(this, o) : this.compile_root(o); return o.scope ? BaseNode.prototype.compile.call(this, o) : this.compile_root(o);
}, },
// Compile each expression in the Expressions body. // Compile each expression in the Expressions body.
compile_node: function compile_node(o) { compile_node: function compile_node(o) {
@ -287,7 +287,7 @@
statement(Expressions); statement(Expressions);
// Literals are static values that can be passed through directly into // Literals are static values that can be passed through directly into
// JavaScript without translation, eg.: strings, numbers, true, false, null... // JavaScript without translation, eg.: strings, numbers, true, false, null...
LiteralNode = (exports.LiteralNode = inherit(Node, { LiteralNode = (exports.LiteralNode = inherit(BaseNode, {
type: 'Literal', type: 'Literal',
constructor: function constructor(value) { constructor: function constructor(value) {
this.value = value; this.value = value;
@ -310,7 +310,7 @@
})); }));
LiteralNode.prototype.is_statement_only = LiteralNode.prototype.is_statement; LiteralNode.prototype.is_statement_only = LiteralNode.prototype.is_statement;
// Return an expression, or wrap it in a closure and return it. // Return an expression, or wrap it in a closure and return it.
ReturnNode = (exports.ReturnNode = inherit(Node, { ReturnNode = (exports.ReturnNode = inherit(BaseNode, {
type: 'Return', type: 'Return',
constructor: function constructor(expression) { constructor: function constructor(expression) {
this.children = [(this.expression = expression)]; this.children = [(this.expression = expression)];
@ -327,7 +327,7 @@
})); }));
statement(ReturnNode, true); statement(ReturnNode, true);
// A value, indexed or dotted into, or vanilla. // A value, indexed or dotted into, or vanilla.
ValueNode = (exports.ValueNode = inherit(Node, { ValueNode = (exports.ValueNode = inherit(BaseNode, {
type: 'Value', type: 'Value',
SOAK: " == undefined ? undefined : ", SOAK: " == undefined ? undefined : ",
constructor: function constructor(base, properties) { constructor: function constructor(base, properties) {
@ -399,7 +399,7 @@
})); }));
// Pass through CoffeeScript comments into JavaScript comments at the // Pass through CoffeeScript comments into JavaScript comments at the
// same position. // same position.
CommentNode = (exports.CommentNode = inherit(Node, { CommentNode = (exports.CommentNode = inherit(BaseNode, {
type: 'Comment', type: 'Comment',
constructor: function constructor(lines) { constructor: function constructor(lines) {
this.lines = lines; this.lines = lines;
@ -412,7 +412,7 @@
statement(CommentNode); statement(CommentNode);
// Node for a function invocation. Takes care of converting super() calls into // Node for a function invocation. Takes care of converting super() calls into
// calls against the prototype's function of the same name. // calls against the prototype's function of the same name.
CallNode = (exports.CallNode = inherit(Node, { CallNode = (exports.CallNode = inherit(BaseNode, {
type: 'Call', type: 'Call',
constructor: function constructor(variable, args) { constructor: function constructor(variable, args) {
this.children = flatten([(this.variable = variable), (this.args = (args || []))]); this.children = flatten([(this.variable = variable), (this.args = (args || []))]);
@ -477,7 +477,7 @@
})); }));
// Node to extend an object's prototype with an ancestor object. // Node to extend an object's prototype with an ancestor object.
// After goog.inherits from the Closure Library. // After goog.inherits from the Closure Library.
ExtendsNode = (exports.ExtendsNode = inherit(Node, { ExtendsNode = (exports.ExtendsNode = inherit(BaseNode, {
type: 'Extends', type: 'Extends',
constructor: function constructor(child, parent) { constructor: function constructor(child, parent) {
this.children = [(this.child = child), (this.parent = parent)]; this.children = [(this.child = child), (this.parent = parent)];
@ -506,7 +506,7 @@
statement(ExtendsNode); statement(ExtendsNode);
// A dotted accessor into a part of a value, or the :: shorthand for // A dotted accessor into a part of a value, or the :: shorthand for
// an accessor into the object's prototype. // an accessor into the object's prototype.
AccessorNode = (exports.AccessorNode = inherit(Node, { AccessorNode = (exports.AccessorNode = inherit(BaseNode, {
type: 'Accessor', type: 'Accessor',
constructor: function constructor(name, tag) { constructor: function constructor(name, tag) {
this.children = [(this.name = name)]; this.children = [(this.name = name)];
@ -519,7 +519,7 @@
} }
})); }));
// An indexed accessor into a part of an array or object. // An indexed accessor into a part of an array or object.
IndexNode = (exports.IndexNode = inherit(Node, { IndexNode = (exports.IndexNode = inherit(BaseNode, {
type: 'Index', type: 'Index',
constructor: function constructor(index, tag) { constructor: function constructor(index, tag) {
this.children = [(this.index = index)]; this.children = [(this.index = index)];
@ -532,7 +532,7 @@
})); }));
// A range literal. Ranges can be used to extract portions (slices) of arrays, // A range literal. Ranges can be used to extract portions (slices) of arrays,
// or to specify a range for list comprehensions. // or to specify a range for list comprehensions.
RangeNode = (exports.RangeNode = inherit(Node, { RangeNode = (exports.RangeNode = inherit(BaseNode, {
type: 'Range', type: 'Range',
constructor: function constructor(from, to, exclusive) { constructor: function constructor(from, to, exclusive) {
this.children = [(this.from = from), (this.to = to)]; this.children = [(this.from = from), (this.to = to)];
@ -577,7 +577,7 @@
// An array slice literal. Unlike JavaScript's Array#slice, the second parameter // An array slice literal. Unlike JavaScript's Array#slice, the second parameter
// specifies the index of the end of the slice (just like the first parameter) // specifies the index of the end of the slice (just like the first parameter)
// is the index of the beginning. // is the index of the beginning.
SliceNode = (exports.SliceNode = inherit(Node, { SliceNode = (exports.SliceNode = inherit(BaseNode, {
type: 'Slice', type: 'Slice',
constructor: function constructor(range) { constructor: function constructor(range) {
this.children = [(this.range = range)]; this.children = [(this.range = range)];
@ -592,7 +592,7 @@
} }
})); }));
// An object literal. // An object literal.
ObjectNode = (exports.ObjectNode = inherit(Node, { ObjectNode = (exports.ObjectNode = inherit(BaseNode, {
type: 'Object', type: 'Object',
constructor: function constructor(props) { constructor: function constructor(props) {
this.children = (this.objects = (this.properties = props || [])); this.children = (this.objects = (this.properties = props || []));
@ -639,7 +639,7 @@
} }
})); }));
// An array literal. // An array literal.
ArrayNode = (exports.ArrayNode = inherit(Node, { ArrayNode = (exports.ArrayNode = inherit(BaseNode, {
type: 'Array', type: 'Array',
constructor: function constructor(objects) { constructor: function constructor(objects) {
this.children = (this.objects = objects || []); this.children = (this.objects = objects || []);
@ -694,7 +694,7 @@
} }
}); });
// Setting the value of a local variable, or the value of an object property. // Setting the value of a local variable, or the value of an object property.
AssignNode = (exports.AssignNode = inherit(Node, { AssignNode = (exports.AssignNode = inherit(BaseNode, {
type: 'Assign', type: 'Assign',
PROTO_ASSIGN: /^(\S+)\.prototype/, PROTO_ASSIGN: /^(\S+)\.prototype/,
LEADING_DOT: /^\.(prototype\.)?/, LEADING_DOT: /^\.(prototype\.)?/,
@ -798,7 +798,7 @@
})); }));
// A function definition. The only node that creates a new Scope. // A function definition. The only node that creates a new Scope.
// A CodeNode does not have any children -- they're within the new scope. // A CodeNode does not have any children -- they're within the new scope.
CodeNode = (exports.CodeNode = inherit(Node, { CodeNode = (exports.CodeNode = inherit(BaseNode, {
type: 'Code', type: 'Code',
constructor: function constructor(params, body, tag) { constructor: function constructor(params, body, tag) {
this.params = params; this.params = params;
@ -865,7 +865,7 @@
})); }));
// A splat, either as a parameter to a function, an argument to a call, // A splat, either as a parameter to a function, an argument to a call,
// or in a destructuring assignment. // or in a destructuring assignment.
SplatNode = (exports.SplatNode = inherit(Node, { SplatNode = (exports.SplatNode = inherit(BaseNode, {
type: 'Splat', type: 'Splat',
constructor: function constructor(name) { constructor: function constructor(name) {
if (!(name.compile)) { if (!(name.compile)) {
@ -890,7 +890,7 @@
})); }));
// A while loop, the only sort of low-level loop exposed by CoffeeScript. From // A while loop, the only sort of low-level loop exposed by CoffeeScript. From
// it, all other loops can be manufactured. // it, all other loops can be manufactured.
WhileNode = (exports.WhileNode = inherit(Node, { WhileNode = (exports.WhileNode = inherit(BaseNode, {
type: 'While', type: 'While',
constructor: function constructor(condition, opts) { constructor: function constructor(condition, opts) {
this.children = [(this.condition = condition)]; this.children = [(this.condition = condition)];
@ -933,7 +933,7 @@
statement(WhileNode); statement(WhileNode);
// Simple Arithmetic and logical operations. Performs some conversion from // Simple Arithmetic and logical operations. Performs some conversion from
// CoffeeScript operations into their JavaScript equivalents. // CoffeeScript operations into their JavaScript equivalents.
OpNode = (exports.OpNode = inherit(Node, { OpNode = (exports.OpNode = inherit(BaseNode, {
type: 'Op', type: 'Op',
CONVERSIONS: { CONVERSIONS: {
'==': '===', '==': '===',
@ -1019,7 +1019,7 @@
} }
})); }));
// A try/catch/finally block. // A try/catch/finally block.
TryNode = (exports.TryNode = inherit(Node, { TryNode = (exports.TryNode = inherit(BaseNode, {
type: 'Try', type: 'Try',
constructor: function constructor(attempt, error, recovery, ensure) { constructor: function constructor(attempt, error, recovery, ensure) {
this.children = compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]); this.children = compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]);
@ -1040,7 +1040,7 @@
})); }));
statement(TryNode); statement(TryNode);
// Throw an exception. // Throw an exception.
ThrowNode = (exports.ThrowNode = inherit(Node, { ThrowNode = (exports.ThrowNode = inherit(BaseNode, {
type: 'Throw', type: 'Throw',
constructor: function constructor(expression) { constructor: function constructor(expression) {
this.children = [(this.expression = expression)]; this.children = [(this.expression = expression)];
@ -1052,7 +1052,7 @@
})); }));
statement(ThrowNode, true); statement(ThrowNode, true);
// Check an expression for existence (meaning not null or undefined). // Check an expression for existence (meaning not null or undefined).
ExistenceNode = (exports.ExistenceNode = inherit(Node, { ExistenceNode = (exports.ExistenceNode = inherit(BaseNode, {
type: 'Existence', type: 'Existence',
constructor: function constructor(expression) { constructor: function constructor(expression) {
this.children = [(this.expression = expression)]; this.children = [(this.expression = expression)];
@ -1075,7 +1075,7 @@
return '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)'; return '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)';
}; };
// An extra set of parentheses, specified explicitly in the source. // An extra set of parentheses, specified explicitly in the source.
ParentheticalNode = (exports.ParentheticalNode = inherit(Node, { ParentheticalNode = (exports.ParentheticalNode = inherit(BaseNode, {
type: 'Paren', type: 'Paren',
constructor: function constructor(expression) { constructor: function constructor(expression) {
this.children = [(this.expression = expression)]; this.children = [(this.expression = expression)];
@ -1101,7 +1101,7 @@
// into a for loop. Also acts as an expression, able to return the result // into a for loop. Also acts as an expression, able to return the result
// of the comprehenion. Unlike Python array comprehensions, it's able to pass // of the comprehenion. Unlike Python array comprehensions, it's able to pass
// the current index of the loop as a second parameter. // the current index of the loop as a second parameter.
ForNode = (exports.ForNode = inherit(Node, { ForNode = (exports.ForNode = inherit(BaseNode, {
type: 'For', type: 'For',
constructor: function constructor(body, source, name, index) { constructor: function constructor(body, source, name, index) {
var _a; var _a;
@ -1199,7 +1199,7 @@
// expression by pushing down requested returns to the expression bodies. // expression by pushing down requested returns to the expression bodies.
// Single-expression IfNodes are compiled into ternary operators if possible, // Single-expression IfNodes are compiled into ternary operators if possible,
// because ternaries are first-class returnable assignable expressions. // because ternaries are first-class returnable assignable expressions.
IfNode = (exports.IfNode = inherit(Node, { IfNode = (exports.IfNode = inherit(BaseNode, {
type: 'If', type: 'If',
constructor: function constructor(condition, body, else_body, tags) { constructor: function constructor(condition, body, else_body, tags) {
this.condition = condition; this.condition = condition;

View file

@ -77,7 +77,7 @@ compile_script: (source, code) ->
js: coffee.compile code, compile_options() js: coffee.compile code, compile_options()
if o.run then eval js if o.run then eval js
else if o.lint then lint js else if o.lint then lint js
else if o.print or o.eval then puts js else if o.print or o.eval then print js
else write_js source, js else write_js source, js
catch err catch err
if o.watch then puts err.message else throw err if o.watch then puts err.message else throw err

View file

@ -54,13 +54,13 @@ statement: (klass, only) ->
# generated code should be wrapped up in a closure. An options hash is passed # generated code should be wrapped up in a closure. An options hash is passed
# and cloned throughout, containing messages from higher in the AST, # and cloned throughout, containing messages from higher in the AST,
# information about the current scope, and indentation level. # information about the current scope, and indentation level.
Node: exports.Node: -> BaseNode: exports.BaseNode: ->
# This is extremely important -- we convert JS statements into expressions # This is extremely important -- we convert JS statements into expressions
# by wrapping them in a closure, only if it's possible, and we're not at # by wrapping them in a closure, only if it's possible, and we're not at
# the top level of a block (which would be unnecessary), and we haven't # the top level of a block (which would be unnecessary), and we haven't
# already been asked to return the result. # already been asked to return the result.
Node::compile: (o) -> BaseNode::compile: (o) ->
@options: merge o or {} @options: merge o or {}
@indent: o.indent @indent: o.indent
del @options, 'operation' unless @operation_sensitive() del @options, 'operation' unless @operation_sensitive()
@ -72,46 +72,46 @@ Node::compile: (o) ->
# Statements converted into expressions share scope with their parent # Statements converted into expressions share scope with their parent
# closure, to preserve JavaScript-style lexical scope. # closure, to preserve JavaScript-style lexical scope.
Node::compile_closure: (o) -> BaseNode::compile_closure: (o) ->
@indent: o.indent @indent: o.indent
o.shared_scope: o.scope o.shared_scope: o.scope
ClosureNode.wrap(this).compile(o) ClosureNode.wrap(this).compile(o)
# If the code generation wishes to use the result of a complex expression # If the code generation wishes to use the result of a complex expression
# in multiple places, ensure that the expression is only ever evaluated once. # in multiple places, ensure that the expression is only ever evaluated once.
Node::compile_reference: (o) -> BaseNode::compile_reference: (o) ->
reference: new LiteralNode(o.scope.free_variable()) reference: new LiteralNode(o.scope.free_variable())
compiled: new AssignNode(reference, this) compiled: new AssignNode(reference, this)
[compiled, reference] [compiled, reference]
# Quick short method for the current indentation level, plus tabbing in. # Quick short method for the current indentation level, plus tabbing in.
Node::idt: (tabs) -> BaseNode::idt: (tabs) ->
idt: (@indent || '') idt: (@indent || '')
idt += TAB for i in [0...(tabs or 0)] idt += TAB for i in [0...(tabs or 0)]
idt idt
# Does this node, or any of its children, contain a node of a certain kind? # Does this node, or any of its children, contain a node of a certain kind?
Node::contains: (block) -> BaseNode::contains: (block) ->
for node in @children for node in @children
return true if block(node) return true if block(node)
return true if node instanceof Node and node.contains block return true if node instanceof BaseNode and node.contains block
false false
# toString representation of the node, for inspecting the parse tree. # toString representation of the node, for inspecting the parse tree.
Node::toString: (idt) -> BaseNode::toString: (idt) ->
idt ||= '' idt ||= ''
'\n' + idt + @type + (child.toString(idt + TAB) for child in @children).join('') '\n' + idt + @type + (child.toString(idt + TAB) for child in @children).join('')
# Default implementations of the common node methods. # Default implementations of the common node methods.
Node::unwrap: -> this BaseNode::unwrap: -> this
Node::children: [] BaseNode::children: []
Node::is_statement: -> false BaseNode::is_statement: -> false
Node::is_statement_only: -> false BaseNode::is_statement_only: -> false
Node::top_sensitive: -> false BaseNode::top_sensitive: -> false
Node::operation_sensitive: -> false BaseNode::operation_sensitive: -> false
# A collection of nodes, each one representing an expression. # A collection of nodes, each one representing an expression.
Expressions: exports.Expressions: inherit Node, { Expressions: exports.Expressions: inherit BaseNode, {
type: 'Expressions' type: 'Expressions'
constructor: (nodes) -> constructor: (nodes) ->
@ -144,7 +144,7 @@ Expressions: exports.Expressions: inherit Node, {
compile: (o) -> compile: (o) ->
o ||= {} o ||= {}
if o.scope then Node::compile.call(this, o) else @compile_root(o) if o.scope then BaseNode::compile.call(this, o) else @compile_root(o)
# Compile each expression in the Expressions body. # Compile each expression in the Expressions body.
compile_node: (o) -> compile_node: (o) ->
@ -192,7 +192,7 @@ statement Expressions
# Literals are static values that can be passed through directly into # Literals are static values that can be passed through directly into
# JavaScript without translation, eg.: strings, numbers, true, false, null... # JavaScript without translation, eg.: strings, numbers, true, false, null...
LiteralNode: exports.LiteralNode: inherit Node, { LiteralNode: exports.LiteralNode: inherit BaseNode, {
type: 'Literal' type: 'Literal'
constructor: (value) -> constructor: (value) ->
@ -217,7 +217,7 @@ LiteralNode: exports.LiteralNode: inherit Node, {
LiteralNode::is_statement_only: LiteralNode::is_statement LiteralNode::is_statement_only: LiteralNode::is_statement
# Return an expression, or wrap it in a closure and return it. # Return an expression, or wrap it in a closure and return it.
ReturnNode: exports.ReturnNode: inherit Node, { ReturnNode: exports.ReturnNode: inherit BaseNode, {
type: 'Return' type: 'Return'
constructor: (expression) -> constructor: (expression) ->
@ -233,7 +233,7 @@ ReturnNode: exports.ReturnNode: inherit Node, {
statement ReturnNode, true statement ReturnNode, true
# A value, indexed or dotted into, or vanilla. # A value, indexed or dotted into, or vanilla.
ValueNode: exports.ValueNode: inherit Node, { ValueNode: exports.ValueNode: inherit BaseNode, {
type: 'Value' type: 'Value'
SOAK: " == undefined ? undefined : " SOAK: " == undefined ? undefined : "
@ -302,7 +302,7 @@ ValueNode: exports.ValueNode: inherit Node, {
# Pass through CoffeeScript comments into JavaScript comments at the # Pass through CoffeeScript comments into JavaScript comments at the
# same position. # same position.
CommentNode: exports.CommentNode: inherit Node, { CommentNode: exports.CommentNode: inherit BaseNode, {
type: 'Comment' type: 'Comment'
constructor: (lines) -> constructor: (lines) ->
@ -318,7 +318,7 @@ statement CommentNode
# Node for a function invocation. Takes care of converting super() calls into # Node for a function invocation. Takes care of converting super() calls into
# calls against the prototype's function of the same name. # calls against the prototype's function of the same name.
CallNode: exports.CallNode: inherit Node, { CallNode: exports.CallNode: inherit BaseNode, {
type: 'Call' type: 'Call'
constructor: (variable, args) -> constructor: (variable, args) ->
@ -366,7 +366,7 @@ CallNode: exports.CallNode: inherit Node, {
# Node to extend an object's prototype with an ancestor object. # Node to extend an object's prototype with an ancestor object.
# After goog.inherits from the Closure Library. # After goog.inherits from the Closure Library.
ExtendsNode: exports.ExtendsNode: inherit Node, { ExtendsNode: exports.ExtendsNode: inherit BaseNode, {
type: 'Extends' type: 'Extends'
constructor: (child, parent) -> constructor: (child, parent) ->
@ -399,7 +399,7 @@ statement ExtendsNode
# A dotted accessor into a part of a value, or the :: shorthand for # A dotted accessor into a part of a value, or the :: shorthand for
# an accessor into the object's prototype. # an accessor into the object's prototype.
AccessorNode: exports.AccessorNode: inherit Node, { AccessorNode: exports.AccessorNode: inherit BaseNode, {
type: 'Accessor' type: 'Accessor'
constructor: (name, tag) -> constructor: (name, tag) ->
@ -414,7 +414,7 @@ AccessorNode: exports.AccessorNode: inherit Node, {
} }
# An indexed accessor into a part of an array or object. # An indexed accessor into a part of an array or object.
IndexNode: exports.IndexNode: inherit Node, { IndexNode: exports.IndexNode: inherit BaseNode, {
type: 'Index' type: 'Index'
constructor: (index, tag) -> constructor: (index, tag) ->
@ -429,7 +429,7 @@ IndexNode: exports.IndexNode: inherit Node, {
# A range literal. Ranges can be used to extract portions (slices) of arrays, # A range literal. Ranges can be used to extract portions (slices) of arrays,
# or to specify a range for list comprehensions. # or to specify a range for list comprehensions.
RangeNode: exports.RangeNode: inherit Node, { RangeNode: exports.RangeNode: inherit BaseNode, {
type: 'Range' type: 'Range'
constructor: (from, to, exclusive) -> constructor: (from, to, exclusive) ->
@ -469,7 +469,7 @@ RangeNode: exports.RangeNode: inherit Node, {
# An array slice literal. Unlike JavaScript's Array#slice, the second parameter # An array slice literal. Unlike JavaScript's Array#slice, the second parameter
# specifies the index of the end of the slice (just like the first parameter) # specifies the index of the end of the slice (just like the first parameter)
# is the index of the beginning. # is the index of the beginning.
SliceNode: exports.SliceNode: inherit Node, { SliceNode: exports.SliceNode: inherit BaseNode, {
type: 'Slice' type: 'Slice'
constructor: (range) -> constructor: (range) ->
@ -485,7 +485,7 @@ SliceNode: exports.SliceNode: inherit Node, {
} }
# An object literal. # An object literal.
ObjectNode: exports.ObjectNode: inherit Node, { ObjectNode: exports.ObjectNode: inherit BaseNode, {
type: 'Object' type: 'Object'
constructor: (props) -> constructor: (props) ->
@ -512,7 +512,7 @@ ObjectNode: exports.ObjectNode: inherit Node, {
} }
# An array literal. # An array literal.
ArrayNode: exports.ArrayNode: inherit Node, { ArrayNode: exports.ArrayNode: inherit BaseNode, {
type: 'Array' type: 'Array'
constructor: (objects) -> constructor: (objects) ->
@ -559,7 +559,7 @@ ClosureNode: exports.ClosureNode: {
} }
# Setting the value of a local variable, or the value of an object property. # Setting the value of a local variable, or the value of an object property.
AssignNode: exports.AssignNode: inherit Node, { AssignNode: exports.AssignNode: inherit BaseNode, {
type: 'Assign' type: 'Assign'
PROTO_ASSIGN: /^(\S+)\.prototype/ PROTO_ASSIGN: /^(\S+)\.prototype/
@ -632,7 +632,7 @@ AssignNode: exports.AssignNode: inherit Node, {
# A function definition. The only node that creates a new Scope. # A function definition. The only node that creates a new Scope.
# A CodeNode does not have any children -- they're within the new scope. # A CodeNode does not have any children -- they're within the new scope.
CodeNode: exports.CodeNode: inherit Node, { CodeNode: exports.CodeNode: inherit BaseNode, {
type: 'Code' type: 'Code'
constructor: (params, body, tag) -> constructor: (params, body, tag) ->
@ -676,7 +676,7 @@ CodeNode: exports.CodeNode: inherit Node, {
# A splat, either as a parameter to a function, an argument to a call, # A splat, either as a parameter to a function, an argument to a call,
# or in a destructuring assignment. # or in a destructuring assignment.
SplatNode: exports.SplatNode: inherit Node, { SplatNode: exports.SplatNode: inherit BaseNode, {
type: 'Splat' type: 'Splat'
constructor: (name) -> constructor: (name) ->
@ -699,7 +699,7 @@ SplatNode: exports.SplatNode: inherit Node, {
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From # A while loop, the only sort of low-level loop exposed by CoffeeScript. From
# it, all other loops can be manufactured. # it, all other loops can be manufactured.
WhileNode: exports.WhileNode: inherit Node, { WhileNode: exports.WhileNode: inherit BaseNode, {
type: 'While' type: 'While'
constructor: (condition, opts) -> constructor: (condition, opts) ->
@ -737,7 +737,7 @@ statement WhileNode
# Simple Arithmetic and logical operations. Performs some conversion from # Simple Arithmetic and logical operations. Performs some conversion from
# CoffeeScript operations into their JavaScript equivalents. # CoffeeScript operations into their JavaScript equivalents.
OpNode: exports.OpNode: inherit Node, { OpNode: exports.OpNode: inherit BaseNode, {
type: 'Op' type: 'Op'
CONVERSIONS: { CONVERSIONS: {
@ -801,7 +801,7 @@ OpNode: exports.OpNode: inherit Node, {
} }
# A try/catch/finally block. # A try/catch/finally block.
TryNode: exports.TryNode: inherit Node, { TryNode: exports.TryNode: inherit BaseNode, {
type: 'Try' type: 'Try'
constructor: (attempt, error, recovery, ensure) -> constructor: (attempt, error, recovery, ensure) ->
@ -822,7 +822,7 @@ TryNode: exports.TryNode: inherit Node, {
statement TryNode statement TryNode
# Throw an exception. # Throw an exception.
ThrowNode: exports.ThrowNode: inherit Node, { ThrowNode: exports.ThrowNode: inherit BaseNode, {
type: 'Throw' type: 'Throw'
constructor: (expression) -> constructor: (expression) ->
@ -837,7 +837,7 @@ ThrowNode: exports.ThrowNode: inherit Node, {
statement ThrowNode, true statement ThrowNode, true
# Check an expression for existence (meaning not null or undefined). # Check an expression for existence (meaning not null or undefined).
ExistenceNode: exports.ExistenceNode: inherit Node, { ExistenceNode: exports.ExistenceNode: inherit BaseNode, {
type: 'Existence' type: 'Existence'
constructor: (expression) -> constructor: (expression) ->
@ -856,7 +856,7 @@ ExistenceNode.compile_test: (o, variable) ->
'(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)' '(typeof ' + first.compile(o) + ' !== "undefined" && ' + second.compile(o) + ' !== null)'
# An extra set of parentheses, specified explicitly in the source. # An extra set of parentheses, specified explicitly in the source.
ParentheticalNode: exports.ParentheticalNode: inherit Node, { ParentheticalNode: exports.ParentheticalNode: inherit BaseNode, {
type: 'Paren' type: 'Paren'
constructor: (expression) -> constructor: (expression) ->
@ -879,7 +879,7 @@ ParentheticalNode: exports.ParentheticalNode: inherit Node, {
# into a for loop. Also acts as an expression, able to return the result # into a for loop. Also acts as an expression, able to return the result
# of the comprehenion. Unlike Python array comprehensions, it's able to pass # of the comprehenion. Unlike Python array comprehensions, it's able to pass
# the current index of the loop as a second parameter. # the current index of the loop as a second parameter.
ForNode: exports.ForNode: inherit Node, { ForNode: exports.ForNode: inherit BaseNode, {
type: 'For' type: 'For'
constructor: (body, source, name, index) -> constructor: (body, source, name, index) ->
@ -949,7 +949,7 @@ statement ForNode
# expression by pushing down requested returns to the expression bodies. # expression by pushing down requested returns to the expression bodies.
# Single-expression IfNodes are compiled into ternary operators if possible, # Single-expression IfNodes are compiled into ternary operators if possible,
# because ternaries are first-class returnable assignable expressions. # because ternaries are first-class returnable assignable expressions.
IfNode: exports.IfNode: inherit Node, { IfNode: exports.IfNode: inherit BaseNode, {
type: 'If' type: 'If'
constructor: (condition, body, else_body, tags) -> constructor: (condition, body, else_body, tags) ->