First draft of real switch statements for CoffeeScript switch statements.
This commit is contained in:
parent
60f80e2698
commit
d8465ce767
|
@ -497,29 +497,25 @@
|
|||
],
|
||||
Switch: [
|
||||
o("SWITCH Expression INDENT Whens OUTDENT", function() {
|
||||
return $4.switchesOver($2);
|
||||
return new SwitchNode($2, $4);
|
||||
}), o("SWITCH Expression INDENT Whens ELSE Block OUTDENT", function() {
|
||||
return $4.switchesOver($2).addElse($6, true);
|
||||
return new SwitchNode($2, $4, $6);
|
||||
}), o("SWITCH INDENT Whens OUTDENT", function() {
|
||||
return $3;
|
||||
return new SwitchNode(null, $3);
|
||||
}), o("SWITCH INDENT Whens ELSE Block OUTDENT", function() {
|
||||
return $3.addElse($5, true);
|
||||
return new SwitchNode(null, $3, $5);
|
||||
})
|
||||
],
|
||||
Whens: [
|
||||
o("When"), o("Whens When", function() {
|
||||
return $1.addElse($2);
|
||||
return $1.concat($2);
|
||||
})
|
||||
],
|
||||
When: [
|
||||
o("LEADING_WHEN SimpleArgs Block", function() {
|
||||
return new IfNode($2, $3, {
|
||||
statement: true
|
||||
});
|
||||
return [[$2, $3]];
|
||||
}), o("LEADING_WHEN SimpleArgs Block TERMINATOR", function() {
|
||||
return new IfNode($2, $3, {
|
||||
statement: true
|
||||
});
|
||||
return [[$2, $3]];
|
||||
})
|
||||
],
|
||||
IfBlock: [
|
||||
|
|
12
lib/lexer.js
12
lib/lexer.js
|
@ -416,7 +416,7 @@
|
|||
return doc.replace(MULTILINER, "\\n").replace(new RegExp(options.quote, 'g'), "\\" + (options.quote));
|
||||
};
|
||||
Lexer.prototype.tagParameters = function() {
|
||||
var _d, i, tok;
|
||||
var i, tok;
|
||||
if (this.tag() !== ')') {
|
||||
return null;
|
||||
}
|
||||
|
@ -427,11 +427,15 @@
|
|||
if (!tok) {
|
||||
return null;
|
||||
}
|
||||
if ((_d = tok[0]) === 'IDENTIFIER') {
|
||||
switch (tok[0]) {
|
||||
case 'IDENTIFIER':
|
||||
tok[0] = 'PARAM';
|
||||
} else if (_d === ')') {
|
||||
break;
|
||||
case ')':
|
||||
tok[0] = 'PARAM_END';
|
||||
} else if (_d === '(' || _d === 'CALL_START') {
|
||||
break;
|
||||
case '(':
|
||||
case 'CALL_START':
|
||||
return (tok[0] = 'PARAM_START');
|
||||
}
|
||||
}
|
||||
|
|
63
lib/nodes.js
63
lib/nodes.js
|
@ -1,5 +1,5 @@
|
|||
(function() {
|
||||
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, 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 AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, 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;
|
||||
|
@ -1728,6 +1728,67 @@
|
|||
};
|
||||
return ForNode;
|
||||
})();
|
||||
exports.SwitchNode = (function() {
|
||||
SwitchNode = function(_b, _c, _d) {
|
||||
this.otherwise = _d;
|
||||
this.cases = _c;
|
||||
this.subject = _b;
|
||||
SwitchNode.__super__.constructor.call(this);
|
||||
this.tags.subjectless = !this.subject;
|
||||
this.subject || (this.subject = literal('true'));
|
||||
return this;
|
||||
};
|
||||
__extends(SwitchNode, BaseNode);
|
||||
SwitchNode.prototype["class"] = 'SwitchNode';
|
||||
SwitchNode.prototype.children = ['subject', 'cases', 'otherwise'];
|
||||
SwitchNode.prototype.isStatement = function() {
|
||||
return true;
|
||||
};
|
||||
SwitchNode.prototype.makeReturn = function() {
|
||||
var _b, _c, _d, pair;
|
||||
_c = this.cases;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
pair = _c[_b];
|
||||
pair[1].makeReturn();
|
||||
}
|
||||
if (this.otherwise) {
|
||||
this.otherwise.makeReturn();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
SwitchNode.prototype.compileNode = function(o) {
|
||||
var _b, _c, _d, _e, _f, _g, _h, block, code, condition, conditions, exprs, idt, pair;
|
||||
idt = (o.indent = this.idt(1));
|
||||
o.top = true;
|
||||
code = ("" + (this.tab) + "switch (" + (this.subject.compile(o)) + ") {");
|
||||
_c = this.cases;
|
||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||
pair = _c[_b];
|
||||
_e = pair;
|
||||
conditions = _e[0];
|
||||
block = _e[1];
|
||||
exprs = block.expressions;
|
||||
_g = flatten([conditions]);
|
||||
for (_f = 0, _h = _g.length; _f < _h; _f++) {
|
||||
condition = _g[_f];
|
||||
if (this.tags.subjectless) {
|
||||
condition = new OpNode('!!', new ParentheticalNode(condition));
|
||||
}
|
||||
code += ("\n" + (this.tab) + "case " + (condition.compile(o)) + ":");
|
||||
}
|
||||
code += ("\n" + (block.compile(o)));
|
||||
if (!(exprs[exprs.length - 1] instanceof ReturnNode)) {
|
||||
code += ("\n" + (idt) + "break;");
|
||||
}
|
||||
}
|
||||
if (this.otherwise) {
|
||||
code += ("\n" + (this.tab) + "default:\n" + (this.otherwise.compile(o)));
|
||||
}
|
||||
code += ("\n" + (this.tab) + "}");
|
||||
return code;
|
||||
};
|
||||
return SwitchNode;
|
||||
})();
|
||||
exports.IfNode = (function() {
|
||||
IfNode = function(_b, _c, _d) {
|
||||
this.tags = _d;
|
||||
|
|
|
@ -409,25 +409,21 @@ case 177:this.$ = {
|
|||
guard: $$[$0-6+6-1]
|
||||
};
|
||||
break;
|
||||
case 178:this.$ = $$[$0-5+4-1].switchesOver($$[$0-5+2-1]);
|
||||
case 178:this.$ = new SwitchNode($$[$0-5+2-1], $$[$0-5+4-1]);
|
||||
break;
|
||||
case 179:this.$ = $$[$0-7+4-1].switchesOver($$[$0-7+2-1]).addElse($$[$0-7+6-1], true);
|
||||
case 179:this.$ = new SwitchNode($$[$0-7+2-1], $$[$0-7+4-1], $$[$0-7+6-1]);
|
||||
break;
|
||||
case 180:this.$ = $$[$0-4+3-1];
|
||||
case 180:this.$ = new SwitchNode(null, $$[$0-4+3-1]);
|
||||
break;
|
||||
case 181:this.$ = $$[$0-6+3-1].addElse($$[$0-6+5-1], true);
|
||||
case 181:this.$ = new SwitchNode(null, $$[$0-6+3-1], $$[$0-6+5-1]);
|
||||
break;
|
||||
case 182:this.$ = $$[$0-1+1-1];
|
||||
break;
|
||||
case 183:this.$ = $$[$0-2+1-1].addElse($$[$0-2+2-1]);
|
||||
case 183:this.$ = $$[$0-2+1-1].concat($$[$0-2+2-1]);
|
||||
break;
|
||||
case 184:this.$ = new IfNode($$[$0-3+2-1], $$[$0-3+3-1], {
|
||||
statement: true
|
||||
});
|
||||
case 184:this.$ = [[$$[$0-3+2-1], $$[$0-3+3-1]]];
|
||||
break;
|
||||
case 185:this.$ = new IfNode($$[$0-4+2-1], $$[$0-4+3-1], {
|
||||
statement: true
|
||||
});
|
||||
case 185:this.$ = [[$$[$0-4+2-1], $$[$0-4+3-1]]];
|
||||
break;
|
||||
case 186:this.$ = new IfNode($$[$0-3+2-1], $$[$0-3+3-1]);
|
||||
break;
|
||||
|
|
|
@ -485,26 +485,22 @@ grammar =
|
|||
o "IN Expression BY Expression WHEN Expression", -> source: $2, step: $4, guard: $6
|
||||
]
|
||||
|
||||
# The CoffeeScript switch/when/else block replaces the JavaScript
|
||||
# switch/case/default by compiling into an if-else chain.
|
||||
Switch: [
|
||||
o "SWITCH Expression INDENT Whens OUTDENT", -> $4.switchesOver $2
|
||||
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.switchesOver($2).addElse $6, true
|
||||
o "SWITCH INDENT Whens OUTDENT", -> $3
|
||||
o "SWITCH INDENT Whens ELSE Block OUTDENT", -> $3.addElse $5, true
|
||||
o "SWITCH Expression INDENT Whens OUTDENT", -> new SwitchNode $2, $4
|
||||
o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> new SwitchNode $2, $4, $6
|
||||
o "SWITCH INDENT Whens OUTDENT", -> new SwitchNode null, $3
|
||||
o "SWITCH INDENT Whens ELSE Block OUTDENT", -> new SwitchNode null, $3, $5
|
||||
]
|
||||
|
||||
# The inner list of whens is left recursive. At code-generation time, the
|
||||
# IfNode will rewrite them into a proper chain.
|
||||
Whens: [
|
||||
o "When"
|
||||
o "Whens When", -> $1.addElse $2
|
||||
o "Whens When", -> $1.concat $2
|
||||
]
|
||||
|
||||
# An individual **When** clause, with action.
|
||||
When: [
|
||||
o "LEADING_WHEN SimpleArgs Block", -> new IfNode $2, $3, statement: true
|
||||
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> new IfNode $2, $3, statement: true
|
||||
o "LEADING_WHEN SimpleArgs Block", -> [[$2, $3]]
|
||||
o "LEADING_WHEN SimpleArgs Block TERMINATOR", -> [[$2, $3]]
|
||||
]
|
||||
|
||||
# The most basic form of *if* is a condition and an action. The following
|
||||
|
|
|
@ -1422,6 +1422,43 @@ exports.ForNode = class ForNode extends BaseNode
|
|||
vars = if range then name else "#{name}, #{ivar}"
|
||||
"#{sourcePart}for (#{forPart}) {#{guardPart}\n#{varPart}#{body}\n#{@tab}}#{returnResult}"
|
||||
|
||||
#### SwitchNode
|
||||
|
||||
# A JavaScript *switch* statement. Converts into a returnable expression on-demand.
|
||||
exports.SwitchNode = class SwitchNode extends BaseNode
|
||||
|
||||
class: 'SwitchNode'
|
||||
children: ['subject', 'cases', 'otherwise']
|
||||
|
||||
isStatement: -> yes
|
||||
|
||||
constructor: (@subject, @cases, @otherwise) ->
|
||||
super()
|
||||
@tags.subjectless = !@subject
|
||||
@subject or= literal 'true'
|
||||
|
||||
makeReturn: ->
|
||||
pair[1].makeReturn() for pair in @cases
|
||||
@otherwise.makeReturn() if @otherwise
|
||||
this
|
||||
|
||||
compileNode: (o) ->
|
||||
idt = o.indent = @idt 1
|
||||
o.top = yes
|
||||
code = "#{ @tab }switch (#{ @subject.compile o }) {"
|
||||
for pair in @cases
|
||||
[conditions, block] = pair
|
||||
exprs = block.expressions
|
||||
for condition in flatten [conditions]
|
||||
condition = new OpNode '!!', new ParentheticalNode condition if @tags.subjectless
|
||||
code += "\n#{ @tab }case #{ condition.compile o }:"
|
||||
code += "\n#{ block.compile o }"
|
||||
code += "\n#{ idt }break;" unless exprs[exprs.length - 1] instanceof ReturnNode
|
||||
if @otherwise
|
||||
code += "\n#{ @tab }default:\n#{ @otherwise.compile o }"
|
||||
code += "\n#{ @tab }}"
|
||||
code
|
||||
|
||||
#### IfNode
|
||||
|
||||
# *If/else* statements. Our *switch/when* will be compiled into this. Acts as an
|
||||
|
|
Loading…
Reference in New Issue