Implement @-prefixed parameters.

This commit is contained in:
Timothy Jones
2010-07-28 17:54:36 +12:00
parent 5399b989c0
commit c9421cbfcd
6 changed files with 297 additions and 218 deletions

View File

@@ -139,8 +139,12 @@
Param: [ Param: [
o("PARAM", function() { o("PARAM", function() {
return new LiteralNode($1); return new LiteralNode($1);
}), o("Param . . .", function() { }), o("@ PARAM", function() {
return new SplatNode($1); return new ParamNode($2, true);
}), o("PARAM . . .", function() {
return new ParamNode($1, false, true);
}), o("@ PARAM . . .", function() {
return new ParamNode($2, true, true);
}) })
], ],
Splat: [ Splat: [

View File

@@ -1,5 +1,5 @@
(function() { (function() {
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, DOUBLE_PARENS, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, ends, flatten, helpers, include, indexOf, literal, merge, starts, utility; var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, DOUBLE_PARENS, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, ends, flatten, helpers, include, indexOf, literal, merge, starts, utility;
var __extends = function(child, parent) { var __extends = function(child, parent) {
var ctor = function(){}; var ctor = function(){};
ctor.prototype = parent.prototype; ctor.prototype = parent.prototype;
@@ -958,7 +958,7 @@
CodeNode.prototype['class'] = 'CodeNode'; CodeNode.prototype['class'] = 'CodeNode';
CodeNode.prototype.children = ['params', 'body']; CodeNode.prototype.children = ['params', 'body'];
CodeNode.prototype.compileNode = function(o) { CodeNode.prototype.compileNode = function(o) {
var _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, code, func, i, param, params, sharedScope, splat, top; var _b, _c, _d, _e, _f, _g, _h, _i, _j, code, func, i, name, param, params, sharedScope, splat, top;
sharedScope = del(o, 'sharedScope'); sharedScope = del(o, 'sharedScope');
top = del(o, 'top'); top = del(o, 'top');
o.scope = sharedScope || new Scope(o.scope, this.body, this); o.scope = sharedScope || new Scope(o.scope, this.body, this);
@@ -966,37 +966,46 @@
o.indent = this.idt(1); o.indent = this.idt(1);
del(o, 'noWrap'); del(o, 'noWrap');
del(o, 'globals'); del(o, 'globals');
i = 0;
splat = undefined; splat = undefined;
params = []; params = [];
_c = this.params; _b = this.params;
for (_b = 0, _d = _c.length; _b < _d; _b++) { for (i = 0, _c = _b.length; i < _c; i++) {
param = _c[_b]; param = _b[i];
if (param instanceof SplatNode && !(typeof splat !== "undefined" && splat !== null)) { if (typeof splat !== "undefined" && splat !== null) {
splat = param; if (param.attach) {
splat.index = i; param.assign = new AssignNode(new ValueNode(literal('this'), [new AccessorNode(param.name)]));
splat.trailings = []; this.body.expressions.splice(splat.index + 1, 0, param.assign);
splat.arglength = this.params.length; }
this.body.unshift(splat);
} else if (typeof splat !== "undefined" && splat !== null) {
splat.trailings.push(param); splat.trailings.push(param);
} else { } else {
params.push(param); if (param.attach) {
name = param.name;
param = literal(o.scope.freeVariable());
this.body.unshift(new AssignNode(new ValueNode(literal('this'), [new AccessorNode(name)]), param));
}
if (param.splat) {
splat = new SplatNode(param.name);
splat.index = i;
splat.trailings = [];
splat.arglength = this.params.length;
this.body.unshift(splat);
} else {
params.push(param);
}
} }
i += 1;
} }
params = (function() { params = (function() {
_e = []; _g = params; _d = []; _f = params;
for (_f = 0, _h = _g.length; _f < _h; _f++) { for (_e = 0, _g = _f.length; _e < _g; _e++) {
param = _g[_f]; param = _f[_e];
_e.push(param.compile(o)); _d.push(param.compile(o));
} }
return _e; return _d;
})(); })();
this.body.makeReturn(); this.body.makeReturn();
_j = params; _i = params;
for (_i = 0, _k = _j.length; _i < _k; _i++) { for (_h = 0, _j = _i.length; _h < _j; _h++) {
param = _j[_i]; param = _i[_h];
(o.scope.parameter(param)); (o.scope.parameter(param));
} }
code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : ''; code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : '';
@@ -1029,6 +1038,24 @@
}; };
return CodeNode; return CodeNode;
})(); })();
exports.ParamNode = (function() {
ParamNode = function(name, attach, splat) {
this.name = literal(name);
this.attach = attach;
this.splat = splat;
return this;
};
__extends(ParamNode, BaseNode);
ParamNode.prototype['class'] = 'ParamNode';
ParamNode.prototype.children = ['name'];
ParamNode.prototype.compileNode = function(o) {
return this.name.compile(o);
};
ParamNode.prototype.toString = function(idt) {
return this.type === 'this' ? (literal("@" + name)).toString(idt) : this.name.toString(idt);
};
return ParamNode;
})();
exports.SplatNode = (function() { exports.SplatNode = (function() {
SplatNode = function(name) { SplatNode = function(name) {
if (!(name.compile)) { if (!(name.compile)) {
@@ -1045,7 +1072,7 @@
return (typeof (_b = this.index) !== "undefined" && _b !== null) ? this.compileParam(o) : this.name.compile(o); return (typeof (_b = this.index) !== "undefined" && _b !== null) ? this.compileParam(o) : this.name.compile(o);
}; };
SplatNode.prototype.compileParam = function(o) { SplatNode.prototype.compileParam = function(o) {
var _b, _c, end, idx, len, name, pos, trailing, variadic; var _b, _c, assign, end, idx, len, name, pos, trailing, variadic;
name = this.name.compile(o); name = this.name.compile(o);
o.scope.find(name); o.scope.find(name);
end = ''; end = '';
@@ -1058,6 +1085,11 @@
_b = this.trailings; _b = this.trailings;
for (idx = 0, _c = _b.length; idx < _c; idx++) { for (idx = 0, _c = _b.length; idx < _c; idx++) {
trailing = _b[idx]; trailing = _b[idx];
if (trailing.attach) {
assign = trailing.assign;
trailing = literal(o.scope.freeVariable());
assign.value = trailing;
}
pos = this.trailings.length - idx; pos = this.trailings.length - idx;
o.scope.assign(trailing.compile(o), ("arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]")); o.scope.assign(trailing.compile(o), ("arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]"));
} }

File diff suppressed because one or more lines are too long

View File

@@ -203,7 +203,9 @@ grammar =
# that hoovers up the remaining arguments. # that hoovers up the remaining arguments.
Param: [ Param: [
o "PARAM", -> new LiteralNode $1 o "PARAM", -> new LiteralNode $1
o "Param . . .", -> new SplatNode $1 o "@ PARAM", -> new ParamNode $2, true
o "PARAM . . .", -> new ParamNode $1, false, true
o "@ PARAM . . .", -> new ParamNode $2, true, true
] ]
# A splat that occurs outside of a parameter list. # A splat that occurs outside of a parameter list.

View File

@@ -871,21 +871,27 @@ exports.CodeNode = class CodeNode extends BaseNode
o.indent = @idt(1) o.indent = @idt(1)
del o, 'noWrap' del o, 'noWrap'
del o, 'globals' del o, 'globals'
i = 0
splat = undefined splat = undefined
params = [] params = []
for param in @params for param, i in @params
if param instanceof SplatNode and not splat? if splat?
splat = param if param.attach
splat.index = i param.assign = new AssignNode new ValueNode literal('this'), [new AccessorNode param.name]
splat.trailings = [] @body.expressions.splice splat.index + 1, 0, param.assign
splat.arglength = @params.length splat.trailings.push param
@body.unshift(splat)
else if splat?
splat.trailings.push(param)
else else
params.push(param) if param.attach
i += 1 name = param.name
param = literal o.scope.freeVariable()
@body.unshift new AssignNode new ValueNode(literal('this'), [new AccessorNode name]), param
if param.splat
splat = new SplatNode param.name
splat.index = i
splat.trailings = []
splat.arglength = @params.length
@body.unshift(splat)
else
params.push(param)
params = (param.compile(o) for param in params) params = (param.compile(o) for param in params)
@body.makeReturn() @body.makeReturn()
(o.scope.parameter(param)) for param in params (o.scope.parameter(param)) for param in params
@@ -906,6 +912,26 @@ exports.CodeNode = class CodeNode extends BaseNode
children = (child.toString(idt + TAB) for child in @collectChildren()).join('') children = (child.toString(idt + TAB) for child in @collectChildren()).join('')
"\n#idt#children" "\n#idt#children"
#### ParamNode
# A parameter in a function definition. Special parameters have a particular
# type - either 'this', meaning it assigns straight to the current context, or
# 'splat', where it gathers up a block of the parameters into an array.
exports.ParamNode = class ParamNode extends BaseNode
class: 'ParamNode'
children: ['name']
constructor: (name, attach, splat) ->
@name = literal name
@attach = attach
@splat = splat
compileNode: (o) -> @name.compile o
toString: (idt) ->
if @type is 'this' then (literal "@#name").toString idt else @name.toString idt
#### SplatNode #### SplatNode
# 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,
@@ -935,6 +961,10 @@ exports.SplatNode = class SplatNode extends BaseNode
o.scope.assign variadic, "#len >= #@arglength" o.scope.assign variadic, "#len >= #@arglength"
end = if @trailings.length then ", #len - #{@trailings.length}" end = if @trailings.length then ", #len - #{@trailings.length}"
for trailing, idx in @trailings for trailing, idx in @trailings
if trailing.attach
assign = trailing.assign
trailing = literal o.scope.freeVariable()
assign.value = trailing
pos = @trailings.length - idx pos = @trailings.length - idx
o.scope.assign(trailing.compile(o), "arguments[#variadic ? #len - #pos : #{@index + idx}]") o.scope.assign(trailing.compile(o), "arguments[#variadic ? #len - #pos : #{@index + idx}]")
"#name = #{utility('slice')}.call(arguments, #@index#end)" "#name = #{utility('slice')}.call(arguments, #@index#end)"

View File

@@ -22,4 +22,11 @@ sumOfArgs = ->
sum += val for val in arguments sum += val for val in arguments
sum sum
ok sumOfArgs(1, 2, 3, 4, 5) is 15 ok sumOfArgs(1, 2, 3, 4, 5) is 15
((@arg) ->).call context = {}, 1
ok context.arg is 1
((splat..., @arg) ->).call context, 1, 2, 3
ok context.arg is 3