Self-compiler: array slice literals.

This commit is contained in:
Jeremy Ashkenas
2010-02-09 19:30:28 -05:00
parent a451e90374
commit 91a7102f11
5 changed files with 220 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
(function(){
var AccessorNode, CallNode, CommentNode, Expressions, ExtendsNode, IndexNode, LiteralNode, Node, ReturnNode, TAB, TRAILING_WHITESPACE, ThisNode, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement;
var AccessorNode, CallNode, CommentNode, Expressions, ExtendsNode, IndexNode, LiteralNode, Node, RangeNode, ReturnNode, SliceNode, TAB, TRAILING_WHITESPACE, ThisNode, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement;
var __hasProp = Object.prototype.hasOwnProperty;
process.mixin(require('./scope'));
// The abstract base class for all CoffeeScript nodes.
@@ -690,10 +690,68 @@
// A this-reference, using '@'.
ThisNode = (exports.ThisNode = inherit(Node, {
constructor: function constructor(property) {
return this.property = property || null;
this.property = property || null;
return this;
},
compile_node: function compile_node(o) {
return 'this' + (this.property ? '.' + this.property : '');
}
}));
// A range literal. Ranges can be used to extract portions (slices) of arrays,
// or to specify a range for list comprehensions.
RangeNode = (exports.RangeNode = inherit(Node, {
constructor: function constructor(from, to, exclusive) {
this.from = from;
this.to = to;
this.children = [from, to];
this.exclusive = !!exclusive;
return this;
},
compile_variables: function compile_variables(o) {
this.indent = o.indent;
this.from_var = o.scope.free_variable();
this.to_var = o.scope.free_variable();
return this.from_var + ' = ' + this.from.compile(o) + '; ' + this.to_var + ' = ' + this.to.compile(o) + ";\n" + this.idt();
},
compile_node: function compile_node(o) {
var compare, equals, idx, incr, intro, step;
if (!(o.index)) {
return this.compile_array(o);
}
idx = del(o, 'index');
step = del(o, 'step');
equals = this.exclusive ? '' : '=';
intro = '(' + this.from_var + ' <= ' + this.to_var + ' ? ' + idx;
compare = intro + ' <' + equals + ' ' + this.to_var + ' : ' + idx + ' >' + equals + ' ' + this.to_var + ')';
incr = intro + ' += ' + step + ' : ' + idx + ' -= ' + step + ')';
return vars + '; ' + compare + '; ' + incr;
},
// Expand the range into the equivalent array, if it's not being used as
// part of a comprehension, slice, or splice.
// TODO: This generates pretty ugly code ... shrink it.
compile_array: function compile_array(o) {
var arr, body;
body = Expressions.wrap(new LiteralNode('i'));
arr = Expressions.wrap(new ForNode(body, {
source: (new ValueNode(this))
}, 'i'));
return (new ParentheticalNode(new CallNode(new CodeNode([], arr)))).compile(o);
}
}));
// 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)
// is the index of the beginning.
SliceNode = (exports.SliceNode = inherit(Node, {
constructor: function constructor(range) {
this.children = [(this.range = range)];
return this;
},
compile_node: function compile_node(o) {
var from, plus_part, to;
from = this.range.from.compile(o);
to = this.range.to.compile(o);
plus_part = this.range.exclusive ? '' : ' + 1';
return ".slice(" + from + ', ' + to + plus_part + ')';
}
}));
})();