mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-17 02:51:25 -05:00
Self-compiler: object literals.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
(function(){
|
||||
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 AccessorNode, AssignNode, CallNode, CommentNode, Expressions, ExtendsNode, IndexNode, LiteralNode, Node, ObjectNode, 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.
|
||||
@@ -341,8 +341,7 @@
|
||||
// A collection of nodes, each one representing an expression.
|
||||
Expressions = (exports.Expressions = inherit(Node, {
|
||||
constructor: function constructor(nodes) {
|
||||
this.expressions = flatten(nodes);
|
||||
this.children = this.expressions;
|
||||
this.children = (this.expressions = flatten(nodes));
|
||||
return this;
|
||||
},
|
||||
// Tack an expression on to the end of this expression list.
|
||||
@@ -451,8 +450,7 @@
|
||||
// JavaScript without translation, eg.: strings, numbers, true, false, null...
|
||||
LiteralNode = (exports.LiteralNode = inherit(Node, {
|
||||
constructor: function constructor(value) {
|
||||
this.value = value;
|
||||
this.children = [value];
|
||||
this.children = [(this.value = value)];
|
||||
return this;
|
||||
},
|
||||
// Break and continue must be treated as statements -- they lose their meaning
|
||||
@@ -471,8 +469,7 @@
|
||||
// Return an expression, or wrap it in a closure and return it.
|
||||
ReturnNode = (exports.ReturnNode = inherit(Node, {
|
||||
constructor: function constructor(expression) {
|
||||
this.expression = expression;
|
||||
this.children = [expression];
|
||||
this.children = [(this.expression = expression)];
|
||||
return this;
|
||||
},
|
||||
compile_node: function compile_node(o) {
|
||||
@@ -489,9 +486,7 @@
|
||||
ValueNode = (exports.ValueNode = inherit(Node, {
|
||||
SOAK: " == undefined ? undefined : ",
|
||||
constructor: function constructor(base, properties) {
|
||||
this.base = base;
|
||||
this.properties = flatten(properties || []);
|
||||
this.children = flatten(this.base, this.properties);
|
||||
this.children = flatten((this.base = base), (this.properties = (properties || [])));
|
||||
return this;
|
||||
},
|
||||
push: function push(prop) {
|
||||
@@ -572,9 +567,7 @@
|
||||
// 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.children = flatten([(this.variable = variable), (this.args = (args || []))]);
|
||||
this.prefix = '';
|
||||
return this;
|
||||
},
|
||||
@@ -648,9 +641,7 @@
|
||||
// After goog.inherits from the Closure Library.
|
||||
ExtendsNode = (exports.ExtendsNode = inherit(Node, {
|
||||
constructor: function constructor(child, parent) {
|
||||
this.child = child;
|
||||
this.parent = parent;
|
||||
this.children = [child, parent];
|
||||
this.children = [(this.child = child), (this.parent = parent)];
|
||||
return this;
|
||||
},
|
||||
// Hooking one constructor into another's prototype chain.
|
||||
@@ -667,8 +658,7 @@
|
||||
// an accessor into the object's prototype.
|
||||
AccessorNode = (exports.AccessorNode = inherit(Node, {
|
||||
constructor: function constructor(name, tag) {
|
||||
this.name = name;
|
||||
this.children = [this.name];
|
||||
this.children = [(this.name = name)];
|
||||
this.prototype = tag === 'prototype';
|
||||
this.soak = tag === 'soak';
|
||||
return this;
|
||||
@@ -701,9 +691,7 @@
|
||||
// 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.children = [(this.from = from), (this.to = to)];
|
||||
this.exclusive = !!exclusive;
|
||||
return this;
|
||||
},
|
||||
@@ -754,4 +742,143 @@
|
||||
return ".slice(" + from + ', ' + to + plus_part + ')';
|
||||
}
|
||||
}));
|
||||
// An object literal.
|
||||
ObjectNode = (exports.ObjectNode = inherit(Node, {
|
||||
constructor: function constructor(props) {
|
||||
this.objects = (this.properties = props || []);
|
||||
return this;
|
||||
},
|
||||
// All the mucking about with commas is to make sure that CommentNodes and
|
||||
// AssignNodes get interleaved correctly, with no trailing commas or
|
||||
// commas affixed to comments. TODO: Extract this and add it to ArrayNode.
|
||||
compile_node: function compile_node(o) {
|
||||
var __a, __b, __c, __d, __e, i, indent, join, last_noncom, non_comments, prop, props;
|
||||
o.indent = this.idt(1);
|
||||
non_comments = (function() {
|
||||
__a = []; __b = this.properties;
|
||||
for (__c = 0; __c < __b.length; __c++) {
|
||||
prop = __b[__c];
|
||||
if (!(prop instanceof CommentNode)) {
|
||||
__a.push(prop);
|
||||
}
|
||||
}
|
||||
return __a;
|
||||
}).call(this);
|
||||
last_noncom = non_comments[non_comments.length - 1];
|
||||
props = (function() {
|
||||
__d = []; __e = this.properties;
|
||||
for (i = 0; i < __e.length; i++) {
|
||||
prop = __e[i];
|
||||
__d.push((function() {
|
||||
join = ",\n";
|
||||
if (prop === last_noncom || prop instanceof CommentNode) {
|
||||
join = "\n";
|
||||
}
|
||||
if (i === non_comments.length - 1) {
|
||||
join = '';
|
||||
}
|
||||
indent = prop instanceof CommentNode ? '' : this.idt(1);
|
||||
return indent + prop.compile(o) + join;
|
||||
}).call(this));
|
||||
}
|
||||
return __d;
|
||||
}).call(this);
|
||||
return '{\n' + props.join('') + '\n' + this.idt() + '}';
|
||||
}
|
||||
}));
|
||||
// Setting the value of a local variable, or the value of an object property.
|
||||
AssignNode = (exports.AssignNode = inherit(Node, {
|
||||
// Keep the identifier regex in sync with the Lexer.
|
||||
IDENTIFIER: /^([a-zA-Z$_](\w|\$)*)/,
|
||||
PROTO_ASSIGN: /^(\S+)\.prototype/,
|
||||
LEADING_DOT: /^\.(prototype\.)?/,
|
||||
constructor: function constructor(variable, value, context) {
|
||||
this.children = [(this.variable = variable), (this.value = value)];
|
||||
this.context = context;
|
||||
return this;
|
||||
},
|
||||
top_sensitive: function top_sensitive() {
|
||||
return true;
|
||||
},
|
||||
is_value: function is_value() {
|
||||
return this.variable instanceof ValueNode;
|
||||
},
|
||||
is_statement: function is_statement() {
|
||||
return this.is_value() && (this.variable.is_array() || this.variable.is_object());
|
||||
},
|
||||
compile_node: function compile_node(o) {
|
||||
var last, match, name, proto, stmt, top, val;
|
||||
top = del(o, 'top');
|
||||
if (this.is_statement()) {
|
||||
return this.compile_pattern_match(o);
|
||||
}
|
||||
if (this.is_value() && this.variable.is_splice()) {
|
||||
return this.compile_splice(o);
|
||||
}
|
||||
stmt = del(o, 'as_statement');
|
||||
name = this.variable.compile(o);
|
||||
last = this.is_value() ? this.variable.last.replace(this.LEADING_DOT, '') : name;
|
||||
match = name.match(this.PROTO_ASSIGN);
|
||||
proto = match && match[1];
|
||||
if (this.value instanceof CodeNode) {
|
||||
if (last.match(this.IDENTIFIER)) {
|
||||
this.value.name = last;
|
||||
}
|
||||
if (proto) {
|
||||
this.value.proto = proto;
|
||||
}
|
||||
}
|
||||
if (this.context === 'object') {
|
||||
return name + ': ' + this.value.compile(o);
|
||||
}
|
||||
if (!(this.is_value() && this.variable.has_properties())) {
|
||||
o.scope.find(name);
|
||||
}
|
||||
val = name + ' = ' + this.value.compile(o);
|
||||
if (stmt) {
|
||||
return this.idt() + val + ';';
|
||||
}
|
||||
if (!top || o.returns) {
|
||||
val = '(' + val + ')';
|
||||
}
|
||||
if (o.returns) {
|
||||
val = this.idt() + 'return ' + val;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
// Implementation of recursive pattern matching, when assigning array or
|
||||
// object literals to a value. Peeks at their properties to assign inner names.
|
||||
// See: http://wiki.ecmascript.org/doku.php?id=harmony:destructuring
|
||||
compile_pattern_match: function compile_pattern_match(o) {
|
||||
var __a, __b, access_class, assigns, i, obj, val, val_var;
|
||||
val_var = o.scope.free_variable();
|
||||
assigns = [this.idt() + val_var + ' = ' + this.value.compile(o) + ';'];
|
||||
o.top = true;
|
||||
o.as_statement = true;
|
||||
__a = this.variable.base.objects;
|
||||
for (i = 0; i < __a.length; i++) {
|
||||
obj = __a[i];
|
||||
if (this.variable.is_object()) {
|
||||
__b = [obj.value, obj.variable.base];
|
||||
obj = __b[0];
|
||||
i = __b[1];
|
||||
}
|
||||
access_class = this.variable.is_array() ? IndexNode : AccessorNode;
|
||||
obj instanceof SplatNode ? (val = new LiteralNode(obj.compile_value(o, val_var, this.variable.base.objects.indexOf(obj)))) : (val = new ValueNode(val_var, [new access_class(new LiteralNode(i))]));
|
||||
assigns.push(new AssignNode(obj, val).compile(o));
|
||||
}
|
||||
return assigns.join("\n");
|
||||
},
|
||||
compile_splice: function compile_splice(o) {
|
||||
var from, name, plus, range, to;
|
||||
name = this.variable.compile(merge(o, {
|
||||
only_first: true
|
||||
}));
|
||||
range = this.variable.properties.last.range;
|
||||
plus = range.exclusive ? '' : ' + 1';
|
||||
from = range.from.compile(o);
|
||||
to = range.to.compile(o) + ' - ' + from + plus;
|
||||
return name + '.splice.apply(' + name + ', [' + from + ', ' + to + '].concat(' + this.value.compile(o) + '))';
|
||||
}
|
||||
}));
|
||||
})();
|
||||
Reference in New Issue
Block a user