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: [
o("PARAM", function() {
return new LiteralNode($1);
}), o("Param . . .", function() {
return new SplatNode($1);
}), o("@ PARAM", function() {
return new ParamNode($2, true);
}), o("PARAM . . .", function() {
return new ParamNode($1, false, true);
}), o("@ PARAM . . .", function() {
return new ParamNode($2, true, true);
})
],
Splat: [

View File

@ -1,5 +1,5 @@
(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 ctor = function(){};
ctor.prototype = parent.prototype;
@ -958,7 +958,7 @@
CodeNode.prototype['class'] = 'CodeNode';
CodeNode.prototype.children = ['params', 'body'];
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');
top = del(o, 'top');
o.scope = sharedScope || new Scope(o.scope, this.body, this);
@ -966,37 +966,46 @@
o.indent = this.idt(1);
del(o, 'noWrap');
del(o, 'globals');
i = 0;
splat = undefined;
params = [];
_c = this.params;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
param = _c[_b];
if (param instanceof SplatNode && !(typeof splat !== "undefined" && splat !== null)) {
splat = param;
splat.index = i;
splat.trailings = [];
splat.arglength = this.params.length;
this.body.unshift(splat);
} else if (typeof splat !== "undefined" && splat !== null) {
_b = this.params;
for (i = 0, _c = _b.length; i < _c; i++) {
param = _b[i];
if (typeof splat !== "undefined" && splat !== null) {
if (param.attach) {
param.assign = new AssignNode(new ValueNode(literal('this'), [new AccessorNode(param.name)]));
this.body.expressions.splice(splat.index + 1, 0, param.assign);
}
splat.trailings.push(param);
} 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() {
_e = []; _g = params;
for (_f = 0, _h = _g.length; _f < _h; _f++) {
param = _g[_f];
_e.push(param.compile(o));
_d = []; _f = params;
for (_e = 0, _g = _f.length; _e < _g; _e++) {
param = _f[_e];
_d.push(param.compile(o));
}
return _e;
return _d;
})();
this.body.makeReturn();
_j = params;
for (_i = 0, _k = _j.length; _i < _k; _i++) {
param = _j[_i];
_i = params;
for (_h = 0, _j = _i.length; _h < _j; _h++) {
param = _i[_h];
(o.scope.parameter(param));
}
code = this.body.expressions.length ? ("\n" + (this.body.compileWithDeclarations(o)) + "\n") : '';
@ -1029,6 +1038,24 @@
};
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() {
SplatNode = function(name) {
if (!(name.compile)) {
@ -1045,7 +1072,7 @@
return (typeof (_b = this.index) !== "undefined" && _b !== null) ? this.compileParam(o) : this.name.compile(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);
o.scope.find(name);
end = '';
@ -1058,6 +1085,11 @@
_b = this.trailings;
for (idx = 0, _c = _b.length; idx < _c; idx++) {
trailing = _b[idx];
if (trailing.attach) {
assign = trailing.assign;
trailing = literal(o.scope.freeVariable());
assign.value = trailing;
}
pos = this.trailings.length - 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.
Param: [
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.

View File

@ -871,21 +871,27 @@ exports.CodeNode = class CodeNode extends BaseNode
o.indent = @idt(1)
del o, 'noWrap'
del o, 'globals'
i = 0
splat = undefined
params = []
for param in @params
if param instanceof SplatNode and not splat?
splat = param
splat.index = i
splat.trailings = []
splat.arglength = @params.length
@body.unshift(splat)
else if splat?
splat.trailings.push(param)
for param, i in @params
if splat?
if param.attach
param.assign = new AssignNode new ValueNode literal('this'), [new AccessorNode param.name]
@body.expressions.splice splat.index + 1, 0, param.assign
splat.trailings.push param
else
params.push(param)
i += 1
if param.attach
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)
@body.makeReturn()
(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('')
"\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
# 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"
end = if @trailings.length then ", #len - #{@trailings.length}"
for trailing, idx in @trailings
if trailing.attach
assign = trailing.assign
trailing = literal o.scope.freeVariable()
assign.value = trailing
pos = @trailings.length - idx
o.scope.assign(trailing.compile(o), "arguments[#variadic ? #len - #pos : #{@index + idx}]")
"#name = #{utility('slice')}.call(arguments, #@index#end)"

View File

@ -22,4 +22,11 @@ sumOfArgs = ->
sum += val for val in arguments
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