The coffee utility. Handles command-line compilation of CoffeeScript
into various forms: saved into .js files or printed to stdout, piped to
-JSLint or recompiled every time the source is
+JavaScript Lint or recompiled every time the source is
saved, printed as a token stream or as the syntax tree, or launch an
interactive REPL. | |
External dependencies. | fs = require 'fs'
path = require 'path'
@@ -20,7 +20,7 @@
['-j', '--join [FILE]', 'concatenate the scripts before compiling']
['-w', '--watch', 'watch scripts for changes, and recompile']
['-p', '--print', 'print the compiled JavaScript to stdout']
- ['-l', '--lint', 'pipe the compiled JavaScript through JSLint']
+ ['-l', '--lint', 'pipe the compiled JavaScript through JavaScript Lint']
['-s', '--stdio', 'listen for and compile scripts over stdio']
['-e', '--eval', 'compile a string from the command line']
['-r', '--require [FILE*]', 'require a library before executing your script']
@@ -49,7 +49,7 @@
opts.literals = sources.splice(1).concat opts.literals
process.ARGV = process.argv = process.argv.slice(0, 2).concat opts.literals
process.argv[0] = 'coffee'
- process.execPath = process.mainModule.filename
+ process.execPath = require.main.filename
compileScripts() |
Asynchronously read in each CoffeeScript in a list of source files and
compile them. If a directory is passed, recursively compile all
'.coffee' extension source files in it and all subdirectories. | compileScripts = ->
diff --git a/documentation/docs/docco.css b/documentation/docs/docco.css
index 20f2753d4b..5aa0a8d73f 100644
--- a/documentation/docs/docco.css
+++ b/documentation/docs/docco.css
@@ -115,7 +115,7 @@ table td {
}
pre, tt, code {
font-size: 12px; line-height: 18px;
- font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
+ font-family: Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
diff --git a/documentation/docs/nodes.html b/documentation/docs/nodes.html
index bd39eb2025..95c160e7e5 100644
--- a/documentation/docs/nodes.html
+++ b/documentation/docs/nodes.html
@@ -285,7 +285,7 @@
code += prop.compile o for prop in props
code |
Unfold a soak into an If : a?.b -> a.b if a? | unfoldSoak: (o) ->
return @unfoldedSoak if @unfoldedSoak?
- result = do =>
+ result = do =>
if ifn = @base.unfoldSoak o
Array::push.apply ifn.body.properties, @properties
return ifn
@@ -460,23 +460,26 @@
parts.push @to if @to isnt @toVar |
When compiled normally, the range returns the contents of the for loop
needed to iterate over the values in the range. Used by comprehensions. | compileNode: (o) ->
@compileVariables o
- return @compileArray(o) unless o.index
- return @compileSimple(o) if @fromNum and @toNum
+ return @compileArray(o) unless o.index
+ return @compileSimple(o) if @fromNum and @toNum
idx = del o, 'index'
step = del o, 'step'
- vars = "#{idx} = #{@from}" + if @to isnt @toVar then ", #{@to}" else ''
+ stepvar = o.scope.freeVariable "step" if step
+ varPart = "#{idx} = #{@from}" + ( if @to isnt @toVar then ", #{@to}" else '' ) + if step then ", #{stepvar} = #{step.compile(o)}" else ''
cond = "#{@fromVar} <= #{@toVar}"
- compare = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
- incr = if step then "#{idx} += #{step.compile(o)}" else "#{cond} ? #{idx}++ : #{idx}--"
- "#{vars}; #{compare}; #{incr}" |
Compile a simple range comprehension, with integers. | compileSimple: (o) ->
+ condPart = "#{cond} ? #{idx} <#{@equals} #{@toVar} : #{idx} >#{@equals} #{@toVar}"
+ stepPart = if step then "#{idx} += #{stepvar}" else "#{cond} ? #{idx}++ : #{idx}--"
+ "#{varPart}; #{condPart}; #{stepPart}" |
Compile a simple range comprehension, with integers. | compileSimple: (o) ->
[from, to] = [+@fromNum, +@toNum]
idx = del o, 'index'
step = del o, 'step'
- step and= "#{idx} += #{step.compile(o)}"
- if from <= to
- "#{idx} = #{from}; #{idx} <#{@equals} #{to}; #{step or "#{idx}++"}"
- else
- "#{idx} = #{from}; #{idx} >#{@equals} #{to}; #{step or "#{idx}--"}" |
When used as a value, expand the range into the equivalent array. | compileArray: (o) ->
+ stepvar = o.scope.freeVariable "step" if step
+ varPart = "#{idx} = #{from}"
+ varPart += ", #{stepvar} = #{step.compile(o)}" if step
+ condPart = if from <= to then "#{idx} <#{@equals} #{to}" else "#{idx} >#{@equals} #{to}"
+ stepPart = "#{idx} += #{stepvar}" if step
+ stepPart = ( if from <= to then "#{idx}++" else "#{idx}--" ) if not step
+ "#{varPart}; #{condPart}; #{stepPart}" |
When used as a value, expand the range into the equivalent array. | compileArray: (o) ->
if @fromNum and @toNum and Math.abs(@fromNum - @toNum) <= 20
range = [+@fromNum..+@toNum]
range.pop() if @exclusive
@@ -595,10 +598,10 @@
if @boundFuncs.length
for bvar in @boundFuncs
bname = bvar.compile o
- @ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this);" |
Merge the properties from a top-level object as prototypal properties
-on the class. | addProperties: (node, name) ->
+ @ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this)" |
Merge the properties from a top-level object as prototypal properties
+on the class. | addProperties: (node, name, o) ->
props = node.base.properties.slice 0
- while assign = props.shift()
+ exprs = while assign = props.shift()
if assign instanceof Assign
base = assign.variable.base
delete assign.context
@@ -611,25 +614,28 @@
if func instanceof Code
assign = @ctor = func
else
- assign = @ctor = new Assign(new Value(new Literal name), func)
+ @externalCtor = o.scope.freeVariable 'class'
+ assign = new Assign new Literal(@externalCtor), func
else
unless assign.variable.this
assign.variable = new Value(new Literal(name), [new Access(base, 'proto')])
if func instanceof Code and func.bound
@boundFuncs.push base
func.bound = no
- assign |
Walk the body of the class, looking for prototype properties to be converted. | walkBody: (name) ->
+ assign
+ compact exprs |
Walk the body of the class, looking for prototype properties to be converted. | walkBody: (name, o) ->
@traverseChildren false, (child) =>
return false if child instanceof Class
if child instanceof Block
for node, i in exps = child.expressions
if node instanceof Value and node.isObject(true)
- exps[i] = @addProperties node, name
+ exps[i] = @addProperties node, name, o
child.expressions = exps = flatten exps |
Make sure that a constructor is defined for the class, and properly
configured. | ensureConstructor: (name) ->
if not @ctor
@ctor = new Code
- @ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent
+ @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent
+ @ctor.body.push new Literal "return #{@externalCtor}.apply(this, arguments)" if @externalCtor
@body.expressions.unshift @ctor
@ctor.ctor = @ctor.name = name
@ctor.klass = null
@@ -641,9 +647,10 @@
lname = new Literal name
@setContext name
- @walkBody name
+ @walkBody name, o
@ensureConstructor name
- @body.expressions.splice 1, 0, new Extends(lname, @parent) if @parent
+ @body.expressions.unshift new Extends lname, @parent if @parent
+ @body.expressions.unshift @ctor unless @ctor instanceof Code
@body.expressions.push lname
@addBoundFunctions o
@@ -1146,50 +1153,51 @@
loop, filtering, stepping, and result saving for array, object, and range
comprehensions. Some of the generated code can be shared in common, and
some cannot. | compileNode: (o) ->
- body = Block.wrap [@body]
- lastJumps = last(body.expressions)?.jumps()
- @returns = no if lastJumps and lastJumps instanceof Return
- source = if @range then @source.base else @source
- scope = o.scope
- name = @name and @name.compile o, LEVEL_LIST
- index = @index and @index.compile o, LEVEL_LIST
+ body = Block.wrap [@body]
+ lastJumps = last(body.expressions)?.jumps()
+ @returns = no if lastJumps and lastJumps instanceof Return
+ source = if @range then @source.base else @source
+ scope = o.scope
+ name = @name and @name.compile o, LEVEL_LIST
+ index = @index and @index.compile o, LEVEL_LIST
scope.find(name, immediate: yes) if name and not @pattern
scope.find(index, immediate: yes) if index
- rvar = scope.freeVariable 'results' if @returns
- ivar = (if @range then name else index) or scope.freeVariable 'i'
- name = ivar if @pattern
- varPart = ''
- guardPart = ''
- defPart = ''
- idt1 = @tab + TAB
+ rvar = scope.freeVariable 'results' if @returns
+ ivar = (if @range then name else index) or scope.freeVariable 'i' |
the _by variable is created twice in Range s if we don't prevent it from being declared here | stepvar = scope.freeVariable "step" if @step and not @range
+ name = ivar if @pattern
+ varPart = ''
+ guardPart = ''
+ defPart = ''
+ idt1 = @tab + TAB
if @range
forPart = source.compile merge(o, {index: ivar, @step})
else
- svar = @source.compile o, LEVEL_LIST
+ svar = @source.compile o, LEVEL_LIST
if (name or @own) and not IDENTIFIER.test svar
- defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
- svar = ref
+ defPart = "#{@tab}#{ref = scope.freeVariable 'ref'} = #{svar};\n"
+ svar = ref
if name and not @pattern
- namePart = "#{name} = #{svar}[#{ivar}]"
+ namePart = "#{name} = #{svar}[#{ivar}]"
unless @object
- lvar = scope.freeVariable 'len'
- stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++"
- forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
+ lvar = scope.freeVariable 'len'
+ forVarPart = "#{ivar} = 0, #{lvar} = #{svar}.length" + if @step then ", #{stepvar} = #{@step.compile(o, LEVEL_OP)}" else ''
+ stepPart = if @step then "#{ivar} += #{stepvar}" else "#{ivar}++"
+ forPart = "#{forVarPart}; #{ivar} < #{lvar}; #{stepPart}"
if @returns
- resultPart = "#{@tab}#{rvar} = [];\n"
- returnResult = "\n#{@tab}return #{rvar};"
- body = Push.wrap rvar, body
+ resultPart = "#{@tab}#{rvar} = [];\n"
+ returnResult = "\n#{@tab}return #{rvar};"
+ body = Push.wrap rvar, body
if @guard
- body = Block.wrap [new If @guard, body]
+ body = Block.wrap [new If @guard, body]
if @pattern
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
- defPart += @pluckDirectCall o, body
- varPart = "\n#{idt1}#{namePart};" if namePart
+ defPart += @pluckDirectCall o, body
+ varPart = "\n#{idt1}#{namePart};" if namePart
if @object
- forPart = "#{ivar} in #{svar}"
- guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
- body = body.compile merge(o, indent: idt1), LEVEL_TOP
- body = '\n' + body + '\n' if body
+ forPart = "#{ivar} in #{svar}"
+ guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" if @own
+ body = body.compile merge(o, indent: idt1), LEVEL_TOP
+ body = '\n' + body + '\n' if body
"""
#{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
"""
@@ -1213,7 +1221,7 @@
args.unshift new Literal 'this'
body.expressions[idx] = new Call base, expr.args
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
- defs |
Switch | |
A JavaScript switch statement. Converts into a returnable expression on-demand. | exports.Switch = class Switch extends Base
+ defs |
Switch | |
A JavaScript switch statement. Converts into a returnable expression on-demand. | exports.Switch = class Switch extends Base
constructor: (@subject, @cases, @otherwise) ->
children: ['subject', 'cases', 'otherwise']
@@ -1244,7 +1252,7 @@
continue if expr instanceof Return or (expr instanceof Literal and expr.jumps() and expr.value isnt 'debugger')
code += idt2 + 'break;\n'
code += idt1 + "default:\n#{ @otherwise.compile o, LEVEL_TOP }\n" if @otherwise and @otherwise.expressions.length
- code + @tab + '}' |
If | |
If/else statements. Acts as an expression by pushing down requested returns
+ code + @tab + '}' |
If | |
If/else statements. Acts as an expression by pushing down requested returns
to the last line of each clause.
Single-expression Ifs are compiled into conditional operators if possible,
@@ -1258,13 +1266,13 @@
children: ['condition', 'body', 'elseBody']
bodyNode: -> @body?.unwrap()
- elseBodyNode: -> @elseBody?.unwrap() |
Rewrite a chain of Ifs to add a default case as the final else. | addElse: (elseBody) ->
+ elseBodyNode: -> @elseBody?.unwrap() |
Rewrite a chain of Ifs to add a default case as the final else. | addElse: (elseBody) ->
if @isChain
@elseBodyNode().addElse elseBody
else
@isChain = elseBody instanceof If
@elseBody = @ensureBlock elseBody
- this |
The If only compiles into a statement if either of its bodies needs
+ this |
The If only compiles into a statement if either of its bodies needs
to be a statement. Otherwise a conditional operator is safe. | isStatement: (o) ->
o?.level is LEVEL_TOP or
@bodyNode().isStatement(o) or @elseBodyNode()?.isStatement(o)
@@ -1280,7 +1288,7 @@
this
ensureBlock: (node) ->
- if node instanceof Block then node else new Block [node] |
Compile the If as a regular if-else statement. Flattened chains
+ if node instanceof Block then node else new Block [node] |
Compile the If as a regular if-else statement. Flattened chains
force inner else bodies into statement form. | compileStatement: (o) ->
child = del o, 'chainChild'
cond = @condition.compile o, LEVEL_PAREN
@@ -1295,7 +1303,7 @@
o.chainChild = yes
@elseBody.unwrap().compile o, LEVEL_TOP
else
- "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}" |
Compile the If as a conditional operator. | compileExpression: (o) ->
+ "{\n#{ @elseBody.compile o, LEVEL_TOP }\n#{@tab}}" |
Compile the If as a conditional operator. | compileExpression: (o) ->
cond = @condition.compile o, LEVEL_COND
body = @bodyNode().compile o, LEVEL_LIST
alt = if @elseBodyNode() then @elseBodyNode().compile(o, LEVEL_LIST) else 'void 0'
@@ -1303,14 +1311,14 @@
if o.level >= LEVEL_COND then "(#{code})" else code
unfoldSoak: ->
- @soak and this |
Faux-Nodes
+ @soak and this |
Faux-Nodes
Faux-nodes are never created by the grammar, but are used during code
-generation to generate other combinations of nodes. | |
Push | |
The Push creates the tree for array.push(value) ,
+generation to generate other combinations of nodes. | |
Push | |
The Push creates the tree for array.push(value) ,
which is helpful for recording the result arrays from comprehensions. | Push =
wrap: (name, exps) ->
return exps if exps.isEmpty() or last(exps.expressions).jumps()
- exps.push new Call new Value(new Literal(name), [new Access new Literal 'push']), [exps.pop()] |
Closure | |
A faux-node used to wrap an expressions body in a closure. | |
Wrap the expressions body, unless it contains a pure statement,
+ exps.push new Call new Value(new Literal(name), [new Access new Literal 'push']), [exps.pop()] |
Closure | |
A faux-node used to wrap an expressions body in a closure. | |
Wrap the expressions body, unless it contains a pure statement,
in which case, no dice. If the body mentions this or arguments ,
then make sure that the closure wrapper preserves the original values. | wrap: (expressions, statement, noReturn) ->
return expressions if expressions.jumps()
@@ -1329,11 +1337,11 @@
node instanceof Literal and node.value is 'arguments' and not node.asKey
literalThis: (node) ->
(node instanceof Literal and node.value is 'this' and not node.asKey) or
- (node instanceof Code and node.bound) |
Unfold a node's child if soak, then tuck the node under created If | unfoldSoak = (o, parent, name) ->
+ (node instanceof Code and node.bound) |
Unfold a node's child if soak, then tuck the node under created If | unfoldSoak = (o, parent, name) ->
return unless ifn = parent[name].unfoldSoak o
parent[name] = ifn.body
ifn.body = new Value parent
- ifn |
Constants | |
Correctly set up a prototype chain for inheritance, including a reference
+ ifn |
Constants | |
Correctly set up a prototype chain for inheritance, including a reference
to the superclass for super() calls, and copies of any static properties. | extends: '''
function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
@@ -1343,26 +1351,26 @@
child.__super__ = parent.prototype;
return child;
}
- ''' |
Create a function bound to the current value of "this". | |
Create a function bound to the current value of "this". | bind: '''
function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
- ''' |
Discover if an item is in an array. | |
Discover if an item is in an array. | indexOf: '''
Array.prototype.indexOf || function(item) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i] === item) return i;
}
return -1;
}
- ''' |
Shortcuts to speed up the lookup time for native functions. | hasProp: 'Object.prototype.hasOwnProperty'
- slice : 'Array.prototype.slice' |
Levels indicates a node's position in the AST. Useful for knowing if
+ ''' |
Shortcuts to speed up the lookup time for native functions. | hasProp: 'Object.prototype.hasOwnProperty'
+ slice : 'Array.prototype.slice' |
Levels indicates a node's position in the AST. Useful for knowing if
parens are necessary or superfluous. | LEVEL_TOP = 1 # ...;
LEVEL_PAREN = 2 # (...)
LEVEL_LIST = 3 # [...]
LEVEL_COND = 4 # ... ? x : y
LEVEL_OP = 5 # !...
-LEVEL_ACCESS = 6 # ...[0] |
Tabs are two spaces for pretty printing. | TAB = ' '
+LEVEL_ACCESS = 6 # ...[0] |
Tabs are two spaces for pretty printing. | TAB = ' '
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/
-SIMPLENUM = /^[+-]?\d+$/ |
Is a literal value a string? | |
Utility Functions | |
Helper for ensuring that utility functions are assigned at the top level. | utility = (name) ->
+SIMPLENUM = /^[+-]?\d+$/ |
Is a literal value a string? | |
Utility Functions | |
Helper for ensuring that utility functions are assigned at the top level. | utility = (name) ->
ref = "__#{name}"
Scope.root.assign ref, UTILITIES[name]
ref
diff --git a/documentation/index.html.erb b/documentation/index.html.erb
index 53a1cb3f5d..e6738f1d27 100644
--- a/documentation/index.html.erb
+++ b/documentation/index.html.erb
@@ -131,7 +131,7 @@
Latest Version:
- 1.1.0
+ 1.1.1
@@ -1020,6 +1020,14 @@ Expressions
Change Log
+
+
+ Bugfix release for classes with external constructor functions, see
+ issue #1182.
+
+
@@ -1312,10 +1312,10 @@
return Animal;
})();
Snake = (function() {
+ __extends(Snake, Animal);
function Snake() {
Snake.__super__.constructor.apply(this, arguments);
}
- __extends(Snake, Animal);
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.__super__.move.call(this, 5);
@@ -1323,10 +1323,10 @@
return Snake;
})();
Horse = (function() {
+ __extends(Horse, Animal);
function Horse() {
Horse.__super__.constructor.apply(this, arguments);
}
- __extends(Horse, Animal);
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.__super__.move.call(this, 45);
@@ -1356,10 +1356,10 @@
return Animal;
})();
Snake = (function() {
+ __extends(Snake, Animal);
function Snake() {
Snake.__super__.constructor.apply(this, arguments);
}
- __extends(Snake, Animal);
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.__super__.move.call(this, 5);
@@ -1367,10 +1367,10 @@
return Snake;
})();
Horse = (function() {
+ __extends(Horse, Animal);
function Horse() {
Horse.__super__.constructor.apply(this, arguments);
}
- __extends(Horse, Animal);
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.__super__.move.call(this, 45);
@@ -1725,16 +1725,16 @@
are preserved in the generated code.
+ load
@@ -1936,6 +1936,14 @@
Change Log
+
+
+ Bugfix release for classes with external constructor functions, see
+ issue #1182.
+
+
|