From 4c882a08e2dba95d393caec0da6fbc977a28a547 Mon Sep 17 00:00:00 2001 From: Kevin Glynn Date: Thu, 20 Jan 2011 12:33:29 +0100 Subject: [PATCH] Convert some switch statements to if-then-else --- .../antlr3/src/cs2j/CSharp/NetMaker.g | 149 +++++++++++++++++- CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g | 2 + 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g index d8037ad..44117ef 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/NetMaker.g @@ -151,6 +151,76 @@ scope SymTab { return (CommonTree)adaptor.DupTree(t); } + protected static readonly string[] ScruTypeStrs = new string[] { "System.Int32", + "System.Int64", + "System.Char", + "System.Enum", + }; + + protected bool typeIsInvalidForScrutinee(TypeRepTemplate sType) { + bool ret = true; + + foreach (string t in ScruTypeStrs) + { + if (sType.IsA(AppEnv.Search(t), AppEnv)) + { + ret = false; + break; + } + } + + return ret; + + } + + // counter to ensure that the catch vars we introduce are unique + protected int dummyScrutVarCtr = 0; + + protected CommonTree convertSectionsToITE(List sections) { + CommonTree ret = null; + if (sections != null && sections.Count > 0) { + ret = dupTree((CommonTree)sections[sections.Count - 1]); + for(int i = sections.Count - 2; i >= 0; i--) { + CommonTree section = dupTree((CommonTree)sections[i]); + // section is either ^(IF ...) or "else ^(IF ....)" we need to insert ret into the IF + if (section.IsNil) { + section.Children[section.Children.Count-1].AddChild(ret); + } + else { + section.AddChild(ret); + } + ret = section; + } + } + return ret; + } + + // In switch sections we want to remove final break statements if we have converted to if-then-else + protected CommonTree stripFinalBreak(CommonTree stats) { + + CommonTree ret = stats; + if (stats.IsNil) { + // A list of statements + // look for an ending of "break [;]" + int len = stats.Children.Count; + int breakPos = len - 1; + if ( len > 1 && stats.Children[len-1].Type == SEMI ) { + breakPos = len -2; + } + if (stats.Children[breakPos].Type != BREAK) { + // not found + breakPos = -1; + } + if (breakPos > 0) { + // delete from break to end + for (int i = len-1; i >= breakPos; i--) { + stats.DeleteChild(i); + } + } + } + return ret; + } + } compilation_unit @@ -1154,8 +1224,31 @@ embedded_statement: switch_statement scope { bool isEnum; + bool convertToIfThenElse; + string scrutVar; + bool isFirstCase; +} +@init { + $switch_statement::isEnum = false; + $switch_statement::convertToIfThenElse = false; + $switch_statement::scrutVar = "WHOOPS"; + $switch_statement::isFirstCase = true; }: - ^('switch' expression { $switch_statement::isEnum = $expression.dotNetType != null && $expression.dotNetType.IsA(AppEnv.Search("System.Enum"), AppEnv); } switch_section*) + ^(s='switch' se=expression sv=magicScrutineeVar[$s.token] + { + if ($expression.dotNetType != null) { + $switch_statement::isEnum = $expression.dotNetType.IsA(AppEnv.Search("System.Enum"), AppEnv); + $switch_statement::convertToIfThenElse = typeIsInvalidForScrutinee($expression.dotNetType); + $switch_statement::scrutVar = $sv.thetext; + } + } + ss+=switch_section*) + -> { $switch_statement::convertToIfThenElse }? + // TODO: down the line, check if scrutinee is already a var and reuse that. + // TYPE{ String } ret ; + ^(TYPE[$s.token, "TYPE"] IDENTIFIER[$s.token,$expression.dotNetType.Java]) $sv ASSIGN[$s.token, "="] { dupTree($se.tree) } SEMI[$s.token, ";"] + { convertSectionsToITE($ss) } + -> ^($s expression $ss*) ; fixed_statement: 'fixed' '(' pointer_type fixed_pointer_declarators ')' embedded_statement ; @@ -1198,12 +1291,49 @@ statement_expression: ; else_statement: 'else' embedded_statement ; -switch_section: - ^(SWITCH_SECTION switch_label+ statement_list) ; -switch_label: - ^(c='case' ce=constant_expression ) -> { $switch_statement::isEnum && $constant_expression.rmId != null}? ^($c IDENTIFIER[$c.token, $constant_expression.rmId]) - -> ^($c $ce) - | 'default'; +switch_section +@init { + bool defaultSection = false; +} +@after{ + $switch_statement::isFirstCase = false; +}: + ^(s=SWITCH_SECTION ({$switch_statement::convertToIfThenElse}? ite_switch_labels | switch_labels) sl=statement_list) + { + + } + -> {$switch_statement::convertToIfThenElse && $switch_statement::isFirstCase && $ite_switch_labels.isDefault}? { stripFinalBreak($sl.tree) } + -> {$switch_statement::convertToIfThenElse && $ite_switch_labels.isDefault}? ELSE[$s.token, "else"] OPEN_BRACE[$s.token, "{"] { stripFinalBreak($sl.tree) } CLOSE_BRACE[$s.token, "}"] + -> {$switch_statement::convertToIfThenElse && $switch_statement::isFirstCase}? ^(IF[$s.token, "if"] ite_switch_labels SEP OPEN_BRACE[$s.token, "{"] { stripFinalBreak($sl.tree) } CLOSE_BRACE[$s.token, "}"]) + -> {$switch_statement::convertToIfThenElse}? ELSE[$s.token, "else"] ^(IF[$s.token, "if"] ite_switch_labels SEP OPEN_BRACE[$s.token, "{"] { stripFinalBreak($sl.tree) } CLOSE_BRACE[$s.token, "}"]) + -> ^($s switch_labels statement_list) + ; + +ite_switch_labels returns [bool isDefault] +@init { + $isDefault = false; +}: + (l1=switch_label { if($l1.isDefault) $isDefault = true; } -> $l1) + (ln=switch_label { if($ln.isDefault) $isDefault = true; } -> ^(LOG_OR[$ln.tree.Token, "||"] { dupTree($ite_switch_labels.tree) } { dupTree($ln.tree) }) )* + ; +switch_labels returns [bool isDefault] +@init { + $isDefault = false; +}: + switch_label+ + ; + +switch_label returns [bool isDefault] +@init { + $isDefault = false; +}: + ^(c='case' ce=constant_expression ) + -> { $switch_statement::convertToIfThenElse }? + // scrutVar.equals(ce) + ^(APPLY[$c.token, "APPLY"] ^(DOT[$c.token, "."] IDENTIFIER[$c.token, $switch_statement::scrutVar] IDENTIFIER[$c.token, "equals"]) ^(ARGS[$c.token, "ARGS"] $ce)) + -> { $switch_statement::isEnum && $constant_expression.rmId != null}? ^($c IDENTIFIER[$c.token, $constant_expression.rmId]) + -> ^($c $ce) + | 'default' { $isDefault = true; }; iteration_statement scope SymTab; @init { @@ -1320,3 +1450,8 @@ literal returns [TypeRepTemplate dotNetType] | NULL { ns = "System.Object"; } ; +magicScrutineeVar [IToken tok] returns [String thetext] +@init { + $thetext = "__dummyScrutVar" + dummyScrutVarCtr++; +}: + -> IDENTIFIER[tok,$thetext]; diff --git a/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g b/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g index d7c5f35..9dbf4ab 100644 --- a/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g +++ b/CSharpTranslator/antlr3/src/cs2j/CSharp/cs.g @@ -59,6 +59,8 @@ tokens { CATCH = 'catch'; FINALLY = 'finally'; THROW = 'throw'; + ELSE = 'else'; + BREAK = 'break'; OPEN_BRACKET='['; CLOSE_BRACKET=']';