mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-04-11 03:00:13 -04:00
CoffeeScript-in-CoffeeScript is compiling function calls
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
(function(){
|
(function(){
|
||||||
var CommentNode, Expressions, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ValueNode, compact, del, dup, flatten, inherit, merge, statement;
|
var CallNode, CommentNode, Expressions, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement;
|
||||||
var __hasProp = Object.prototype.hasOwnProperty;
|
var __hasProp = Object.prototype.hasOwnProperty;
|
||||||
process.mixin(require('./scope'));
|
process.mixin(require('./scope'));
|
||||||
// The abstract base class for all CoffeeScript nodes.
|
// The abstract base class for all CoffeeScript nodes.
|
||||||
@@ -270,6 +270,21 @@
|
|||||||
}).call(this);
|
}).call(this);
|
||||||
return dest;
|
return dest;
|
||||||
};
|
};
|
||||||
|
// Do any of the elements in the list pass a truth test?
|
||||||
|
any = function any(list, test) {
|
||||||
|
var __a, __b, __c, item, result;
|
||||||
|
result = (function() {
|
||||||
|
__a = []; __b = list;
|
||||||
|
for (__c = 0; __c < __b.length; __c++) {
|
||||||
|
item = __b[__c];
|
||||||
|
if (test(item)) {
|
||||||
|
__a.push(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return __a;
|
||||||
|
}).call(this);
|
||||||
|
return !!result.length;
|
||||||
|
};
|
||||||
// Delete a key from an object, returning the value.
|
// Delete a key from an object, returning the value.
|
||||||
del = function del(obj, key) {
|
del = function del(obj, key) {
|
||||||
var val;
|
var val;
|
||||||
@@ -612,4 +627,79 @@
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
statement(CommentNode);
|
statement(CommentNode);
|
||||||
|
// Node for a function invocation. Takes care of converting super() calls into
|
||||||
|
// calls against the prototype's function of the same name.
|
||||||
|
CallNode = (exports.CallNode = inherit(Node, {
|
||||||
|
constructor: function constructor(variable, args) {
|
||||||
|
this.variable = variable;
|
||||||
|
this.args = args || [];
|
||||||
|
this.children = flatten([this.variable, this.args]);
|
||||||
|
this.prefix = '';
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
new_instance: function new_instance() {
|
||||||
|
this.prefix = 'new ';
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
push: function push(arg) {
|
||||||
|
this.args.push(arg);
|
||||||
|
return this.children.push(arg);
|
||||||
|
},
|
||||||
|
// Compile a vanilla function call.
|
||||||
|
compile_node: function compile_node(o) {
|
||||||
|
var __a, __b, __c, arg, args;
|
||||||
|
if (any(this.args, function(a) {
|
||||||
|
return a instanceof SplatNode;
|
||||||
|
})) {
|
||||||
|
return this.compile_splat(o);
|
||||||
|
}
|
||||||
|
args = ((function() {
|
||||||
|
__a = []; __b = this.args;
|
||||||
|
for (__c = 0; __c < __b.length; __c++) {
|
||||||
|
arg = __b[__c];
|
||||||
|
__a.push(arg.compile(o));
|
||||||
|
}
|
||||||
|
return __a;
|
||||||
|
}).call(this)).join(', ');
|
||||||
|
if (this.variable === 'super') {
|
||||||
|
return this.compile_super(args, o);
|
||||||
|
}
|
||||||
|
return this.prefix + this.variable.compile(o) + '(' + args + ')';
|
||||||
|
},
|
||||||
|
// Compile a call against the superclass's implementation of the current function.
|
||||||
|
compile_super: function compile_super(args, o) {
|
||||||
|
var arg_part, meth, methname;
|
||||||
|
methname = o.scope.method.name;
|
||||||
|
arg_part = args.length ? ', ' + args : '';
|
||||||
|
meth = o.scope.method.proto ? o.scope.method.proto + '.__superClass__.' + methname : methname + '.__superClass__.constructor';
|
||||||
|
return meth + '.call(this' + arg_part + ')';
|
||||||
|
},
|
||||||
|
// Compile a function call being passed variable arguments.
|
||||||
|
compile_splat: function compile_splat(o) {
|
||||||
|
var __a, __b, arg, args, code, i, meth, obj;
|
||||||
|
meth = this.variable.compile(o);
|
||||||
|
obj = this.variable.source || 'this';
|
||||||
|
args = (function() {
|
||||||
|
__a = []; __b = this.args;
|
||||||
|
for (i = 0; i < __b.length; i++) {
|
||||||
|
arg = __b[i];
|
||||||
|
__a.push((function() {
|
||||||
|
code = arg.compile(o);
|
||||||
|
code = arg instanceof SplatNode ? code : '[' + code + ']';
|
||||||
|
return i === 0 ? code : '.concat(' + code + ')';
|
||||||
|
}).call(this));
|
||||||
|
}
|
||||||
|
return __a;
|
||||||
|
}).call(this);
|
||||||
|
return this.prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')';
|
||||||
|
},
|
||||||
|
// If the code generation wished to use the result of a function call
|
||||||
|
// in multiple places, ensure that the function is only ever called once.
|
||||||
|
compile_reference: function compile_reference(o) {
|
||||||
|
var call, reference;
|
||||||
|
reference = o.scope.free_variable();
|
||||||
|
call = new ParentheticalNode(new AssignNode(reference, this));
|
||||||
|
return [call, reference];
|
||||||
|
}
|
||||||
|
}));
|
||||||
})();
|
})();
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
],
|
],
|
||||||
// Assignment within an object literal (can be quoted).
|
// Assignment within an object literal (can be quoted).
|
||||||
AssignObj: [o("IDENTIFIER ASSIGN Expression", function() {
|
AssignObj: [o("IDENTIFIER ASSIGN Expression", function() {
|
||||||
return new AssignNode(new ValueNode(yytext), $3, 'object');
|
return new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object');
|
||||||
}), o("STRING ASSIGN Expression", function() {
|
}), o("STRING ASSIGN Expression", function() {
|
||||||
return new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object');
|
return new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object');
|
||||||
}), o("NUMBER ASSIGN Expression", function() {
|
}), o("NUMBER ASSIGN Expression", function() {
|
||||||
@@ -189,7 +189,7 @@
|
|||||||
],
|
],
|
||||||
// A Parameter (or ParamSplat) in a function definition.
|
// A Parameter (or ParamSplat) in a function definition.
|
||||||
Param: [o("PARAM", function() {
|
Param: [o("PARAM", function() {
|
||||||
return yytext;
|
return new LiteralNode(yytext);
|
||||||
}), o("PARAM . . .", function() {
|
}), o("PARAM . . .", function() {
|
||||||
return new SplatNode(yytext);
|
return new SplatNode(yytext);
|
||||||
})
|
})
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
],
|
],
|
||||||
// Expressions that can be treated as values.
|
// Expressions that can be treated as values.
|
||||||
Value: [o("IDENTIFIER", function() {
|
Value: [o("IDENTIFIER", function() {
|
||||||
return new ValueNode(yytext);
|
return new ValueNode(new LiteralNode(yytext));
|
||||||
}), o("Literal", function() {
|
}), o("Literal", function() {
|
||||||
return new ValueNode($1);
|
return new ValueNode($1);
|
||||||
}), o("Array", function() {
|
}), o("Array", function() {
|
||||||
@@ -220,11 +220,11 @@
|
|||||||
],
|
],
|
||||||
// Accessing into an object or array, through dot or index notation.
|
// Accessing into an object or array, through dot or index notation.
|
||||||
Accessor: [o("PROPERTY_ACCESS IDENTIFIER", function() {
|
Accessor: [o("PROPERTY_ACCESS IDENTIFIER", function() {
|
||||||
return new AccessorNode(yytext);
|
return new AccessorNode(new LiteralNode(yytext));
|
||||||
}), o("PROTOTYPE_ACCESS IDENTIFIER", function() {
|
}), o("PROTOTYPE_ACCESS IDENTIFIER", function() {
|
||||||
return new AccessorNode(yytext, 'prototype');
|
return new AccessorNode(new LiteralNode(yytext), 'prototype');
|
||||||
}), o("SOAK_ACCESS IDENTIFIER", function() {
|
}), o("SOAK_ACCESS IDENTIFIER", function() {
|
||||||
return new AccessorNode(yytext, 'soak');
|
return new AccessorNode(new LiteralNode(yytext), 'soak');
|
||||||
}), o("Index"), o("Slice", function() {
|
}), o("Index"), o("Slice", function() {
|
||||||
return new SliceNode($1);
|
return new SliceNode($1);
|
||||||
})
|
})
|
||||||
@@ -308,7 +308,7 @@
|
|||||||
ArgList: [o("", function() {
|
ArgList: [o("", function() {
|
||||||
return [];
|
return [];
|
||||||
}), o("Expression", function() {
|
}), o("Expression", function() {
|
||||||
return val;
|
return [$1];
|
||||||
}), o("INDENT Expression", function() {
|
}), o("INDENT Expression", function() {
|
||||||
return [$2];
|
return [$2];
|
||||||
}), o("ArgList , Expression", function() {
|
}), o("ArgList , Expression", function() {
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ merge: (src, dest) ->
|
|||||||
dest[key]: val for key, val of src
|
dest[key]: val for key, val of src
|
||||||
dest
|
dest
|
||||||
|
|
||||||
|
# Do any of the elements in the list pass a truth test?
|
||||||
|
any: (list, test) ->
|
||||||
|
result: true for item in list when test(item)
|
||||||
|
!!result.length
|
||||||
|
|
||||||
# Delete a key from an object, returning the value.
|
# Delete a key from an object, returning the value.
|
||||||
del: (obj, key) ->
|
del: (obj, key) ->
|
||||||
val: obj[key]
|
val: obj[key]
|
||||||
@@ -354,7 +359,60 @@ CommentNode: exports.CommentNode: inherit Node, {
|
|||||||
statement CommentNode
|
statement CommentNode
|
||||||
|
|
||||||
|
|
||||||
|
# Node for a function invocation. Takes care of converting super() calls into
|
||||||
|
# calls against the prototype's function of the same name.
|
||||||
|
CallNode: exports.CallNode: inherit Node, {
|
||||||
|
|
||||||
|
constructor: (variable, args) ->
|
||||||
|
@variable: variable
|
||||||
|
@args: args or []
|
||||||
|
@children: flatten([@variable, @args])
|
||||||
|
@prefix: ''
|
||||||
|
this
|
||||||
|
|
||||||
|
new_instance: ->
|
||||||
|
@prefix: 'new '
|
||||||
|
this
|
||||||
|
|
||||||
|
push: (arg) ->
|
||||||
|
@args.push(arg)
|
||||||
|
@children.push(arg)
|
||||||
|
|
||||||
|
# Compile a vanilla function call.
|
||||||
|
compile_node: (o) ->
|
||||||
|
return @compile_splat(o) if any @args, (a) -> a instanceof SplatNode
|
||||||
|
args: (arg.compile(o) for arg in @args).join(', ')
|
||||||
|
return @compile_super(args, o) if @variable is 'super'
|
||||||
|
@prefix + @variable.compile(o) + '(' + args + ')'
|
||||||
|
|
||||||
|
# Compile a call against the superclass's implementation of the current function.
|
||||||
|
compile_super: (args, o) ->
|
||||||
|
methname: o.scope.method.name
|
||||||
|
arg_part: if args.length then ', ' + args else ''
|
||||||
|
meth: if o.scope.method.proto
|
||||||
|
o.scope.method.proto + '.__superClass__.' + methname
|
||||||
|
else
|
||||||
|
methname + '.__superClass__.constructor'
|
||||||
|
meth + '.call(this' + arg_part + ')'
|
||||||
|
|
||||||
|
# Compile a function call being passed variable arguments.
|
||||||
|
compile_splat: (o) ->
|
||||||
|
meth: @variable.compile o
|
||||||
|
obj: @variable.source or 'this'
|
||||||
|
args: for arg, i in @args
|
||||||
|
code: arg.compile o
|
||||||
|
code: if arg instanceof SplatNode then code else '[' + code + ']'
|
||||||
|
if i is 0 then code else '.concat(' + code + ')'
|
||||||
|
@prefix + meth + '.apply(' + obj + ', ' + args.join('') + ')'
|
||||||
|
|
||||||
|
# If the code generation wished to use the result of a function call
|
||||||
|
# in multiple places, ensure that the function is only ever called once.
|
||||||
|
compile_reference: (o) ->
|
||||||
|
reference: o.scope.free_variable()
|
||||||
|
call: new ParentheticalNode(new AssignNode(reference, this))
|
||||||
|
[call, reference]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ grammar: {
|
|||||||
|
|
||||||
# Assignment within an object literal (can be quoted).
|
# Assignment within an object literal (can be quoted).
|
||||||
AssignObj: [
|
AssignObj: [
|
||||||
o "IDENTIFIER ASSIGN Expression", -> new AssignNode(new ValueNode(yytext), $3, 'object')
|
o "IDENTIFIER ASSIGN Expression", -> new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object')
|
||||||
o "STRING ASSIGN Expression", -> new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object')
|
o "STRING ASSIGN Expression", -> new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object')
|
||||||
o "NUMBER ASSIGN Expression", -> new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object')
|
o "NUMBER ASSIGN Expression", -> new AssignNode(new ValueNode(new LiteralNode(yytext)), $3, 'object')
|
||||||
o "Comment"
|
o "Comment"
|
||||||
@@ -213,7 +213,7 @@ grammar: {
|
|||||||
|
|
||||||
# A Parameter (or ParamSplat) in a function definition.
|
# A Parameter (or ParamSplat) in a function definition.
|
||||||
Param: [
|
Param: [
|
||||||
o "PARAM", -> yytext
|
o "PARAM", -> new LiteralNode(yytext)
|
||||||
o "PARAM . . .", -> new SplatNode(yytext)
|
o "PARAM . . .", -> new SplatNode(yytext)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ grammar: {
|
|||||||
|
|
||||||
# Expressions that can be treated as values.
|
# Expressions that can be treated as values.
|
||||||
Value: [
|
Value: [
|
||||||
o "IDENTIFIER", -> new ValueNode(yytext)
|
o "IDENTIFIER", -> new ValueNode(new LiteralNode(yytext))
|
||||||
o "Literal", -> new ValueNode($1)
|
o "Literal", -> new ValueNode($1)
|
||||||
o "Array", -> new ValueNode($1)
|
o "Array", -> new ValueNode($1)
|
||||||
o "Object", -> new ValueNode($1)
|
o "Object", -> new ValueNode($1)
|
||||||
@@ -236,9 +236,9 @@ grammar: {
|
|||||||
|
|
||||||
# Accessing into an object or array, through dot or index notation.
|
# Accessing into an object or array, through dot or index notation.
|
||||||
Accessor: [
|
Accessor: [
|
||||||
o "PROPERTY_ACCESS IDENTIFIER", -> new AccessorNode(yytext)
|
o "PROPERTY_ACCESS IDENTIFIER", -> new AccessorNode(new LiteralNode(yytext))
|
||||||
o "PROTOTYPE_ACCESS IDENTIFIER", -> new AccessorNode(yytext, 'prototype')
|
o "PROTOTYPE_ACCESS IDENTIFIER", -> new AccessorNode(new LiteralNode(yytext), 'prototype')
|
||||||
o "SOAK_ACCESS IDENTIFIER", -> new AccessorNode(yytext, 'soak')
|
o "SOAK_ACCESS IDENTIFIER", -> new AccessorNode(new LiteralNode(yytext), 'soak')
|
||||||
o "Index"
|
o "Index"
|
||||||
o "Slice", -> new SliceNode($1)
|
o "Slice", -> new SliceNode($1)
|
||||||
]
|
]
|
||||||
@@ -311,7 +311,7 @@ grammar: {
|
|||||||
# A list of arguments to a method call, or as the contents of an array.
|
# A list of arguments to a method call, or as the contents of an array.
|
||||||
ArgList: [
|
ArgList: [
|
||||||
o "", -> []
|
o "", -> []
|
||||||
o "Expression", -> val
|
o "Expression", -> [$1]
|
||||||
o "INDENT Expression", -> [$2]
|
o "INDENT Expression", -> [$2]
|
||||||
o "ArgList , Expression", -> $1.push $3
|
o "ArgList , Expression", -> $1.push $3
|
||||||
o "ArgList TERMINATOR Expression", -> $1.push $3
|
o "ArgList TERMINATOR Expression", -> $1.push $3
|
||||||
|
|||||||
Reference in New Issue
Block a user