Created
April 26, 2010 05:40
-
-
Save timbertson/379009 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/grammar.coffee b/src/grammar.coffee | |
index 0a8d950..219911d 100644 | |
--- a/src/grammar.coffee | |
+++ b/src/grammar.coffee | |
@@ -457,8 +457,8 @@ grammar: { | |
# 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.rewrite_condition $2 | |
- o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.rewrite_condition($2).add_else $6, true | |
+ o "SWITCH Expression INDENT Whens OUTDENT", -> $4.unwrap().switches_over $2 | |
+ o "SWITCH Expression INDENT Whens ELSE Block OUTDENT", -> $4.switches_over($2).add_else $6, true | |
] | |
# The inner list of whens is left recursive. At code-generation time, the | |
diff --git a/src/nodes.coffee b/src/nodes.coffee | |
index 5d73d81..995af42 100644 | |
--- a/src/nodes.coffee | |
+++ b/src/nodes.coffee | |
@@ -1152,63 +1152,74 @@ exports.IfNode: class IfNode extends BaseNode | |
constructor: (condition, body, else_body, tags) -> | |
@condition: condition | |
- @body: body and body.unwrap() | |
- @else_body: else_body and else_body.unwrap() | |
- @children: compact flatten [@condition, @body, @else_body] | |
+ @body: body | |
+ @else_body: else_body | |
+ @populate_children() | |
@tags: tags or {} | |
@multiple: true if @condition instanceof Array | |
@condition: new OpNode('!', new ParentheticalNode(@condition)) if @tags.invert | |
+ populate_children: -> | |
+ @children: compact flatten [@condition, @body, @else_body] | |
+ | |
# Add a new *else* clause to this **IfNode**, or push it down to the bottom | |
# of the chain recursively. | |
push: (else_body) -> | |
- eb: else_body.unwrap() | |
- if @else_body then @else_body.push(eb) else @else_body: eb | |
+ else_expressions: else_body | |
+ if not (else_expressions instanceof Expressions) | |
+ else_expressions: new Expressions([else_expressions]) | |
+ if @else_body then @else_body_node().push(else_body) else @else_body: else_expressions | |
this | |
+ body_node: -> @body?.unwrap() | |
+ else_body_node: -> @else_body?.unwrap() | |
+ | |
force_statement: -> | |
@tags.statement: true | |
this | |
# Tag a chain of **IfNodes** with their object(s) to switch on for equality | |
# tests. `rewrite_switch` will perform the actual change at compile time. | |
- rewrite_condition: (expression) -> | |
- @switcher: expression | |
+ switches_over: (expression) -> | |
+ @switch_subject: expression | |
this | |
# Rewrite a chain of **IfNodes** with their switch condition for equality. | |
# Ensure that the switch expression isn't evaluated more than once. | |
rewrite_switch: (o) -> | |
- assigner: @switcher | |
- if not (@switcher.unwrap() instanceof LiteralNode) | |
+ assigner: @switch_subject | |
+ if not (@switch_subject.unwrap() instanceof LiteralNode) | |
variable: literal(o.scope.free_variable()) | |
- assigner: new AssignNode(variable, @switcher) | |
- @switcher: variable | |
+ assigner: new AssignNode(variable, @switch_subject) | |
+ @children.push(assigner) | |
+ @switch_subject: variable | |
@condition: if @multiple | |
for cond, i in @condition | |
- new OpNode('==', (if i is 0 then assigner else @switcher), cond) | |
+ new OpNode('==', (if i is 0 then assigner else @switch_subject), cond) | |
else | |
new OpNode('==', assigner, @condition) | |
- @else_body.rewrite_condition(@switcher) if @is_chain() | |
+ @else_body_node().switches_over(@switch_subject) if @is_chain() | |
+ # prevent this rewrite from happening again | |
+ @switch_subject: undefined | |
this | |
# Rewrite a chain of **IfNodes** to add a default case as the final *else*. | |
add_else: (exprs, statement) -> | |
if @is_chain() | |
- @else_body.add_else exprs, statement | |
+ @else_body_node().add_else exprs, statement | |
else | |
- exprs: exprs.unwrap() unless statement | |
- @children.push @else_body: exprs | |
+ @else_body: exprs | |
+ @populate_children() | |
this | |
# If the `else_body` is an **IfNode** itself, then we've got an *if-else* chain. | |
is_chain: -> | |
- @chain: or @else_body and @else_body instanceof IfNode | |
+ @chain: or @else_body and @else_body_node() instanceof IfNode | |
# The **IfNode** only compiles into a statement if either of its bodies needs | |
# to be a statement. Otherwise a ternary is safe. | |
is_statement: -> | |
- @statement: or !!(@comment or @tags.statement or @body.is_statement() or (@else_body and @else_body.is_statement())) | |
+ @statement: or !!(@comment or @tags.statement or @body_node().is_statement() or (@else_body and @else_body_node().is_statement())) | |
compile_condition: (o) -> | |
(cond.compile(o) for cond in flatten([@condition])).join(' || ') | |
@@ -1217,14 +1228,14 @@ exports.IfNode: class IfNode extends BaseNode | |
if @is_statement() then @compile_statement(o) else @compile_ternary(o) | |
make_return: -> | |
- @body: and @body.make_return() | |
- @else_body: and @else_body.make_return() | |
+ @body: and @body_node().make_return() | |
+ @else_body: and @else_body_node().make_return() | |
this | |
# Compile the **IfNode** as a regular *if-else* statement. Flattened chains | |
# force inner *else* bodies into statement form. | |
compile_statement: (o) -> | |
- @rewrite_switch(o) if @switcher | |
+ @rewrite_switch(o) if @switch_subject | |
child: del o, 'chain_child' | |
cond_o: merge o | |
o.indent: @idt 1 | |
@@ -1232,19 +1243,19 @@ exports.IfNode: class IfNode extends BaseNode | |
if_dent: if child then '' else @idt() | |
com_dent: if child then @idt() else '' | |
prefix: if @comment then "${ @comment.compile(cond_o) }\n$com_dent" else '' | |
- body: Expressions.wrap([@body]).compile(o) | |
+ body: @body.compile(o) | |
if_part: "$prefix${if_dent}if (${ @compile_condition(cond_o) }) {\n$body\n$@tab}" | |
return if_part unless @else_body | |
else_part: if @is_chain() | |
- ' else ' + @else_body.compile(merge(o, {indent: @idt(), chain_child: true})) | |
+ ' else ' + @else_body_node().compile(merge(o, {indent: @idt(), chain_child: true})) | |
else | |
- " else {\n${ Expressions.wrap([@else_body]).compile(o) }\n$@tab}" | |
+ " else {\n${ @else_body.compile(o) }\n$@tab}" | |
"$if_part$else_part" | |
# Compile the IfNode as a ternary operator. | |
compile_ternary: (o) -> | |
- if_part: @condition.compile(o) + ' ? ' + @body.compile(o) | |
- else_part: if @else_body then @else_body.compile(o) else 'null' | |
+ if_part: @condition.compile(o) + ' ? ' + @body_node().compile(o) | |
+ else_part: if @else_body then @else_body_node().compile(o) else 'null' | |
"$if_part : $else_part" | |
# Faux-Nodes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment