我在尝试重构if/else statement
中的switch statement
时遇到问题。使用的语法是Java 8,根据以下语法:
如果是其他声明
syntax IfThenStatement = "if" "(" Expression ")" Statement ;
syntax IfThenElseStatement = "if" "(" Expression ")" StatementNoShortIf "else" Statement ;
syntax IfThenElseStatementNoShortIf = "if" "(" Expression ")" StatementNoShortIf "else" StatementNoShortIf ;
切换声明
syntax SwitchStatement = "switch" "(" Expression ")" SwitchBlock ;
syntax SwitchBlock = "{" SwitchBlockStatementGroup* SwitchLabel* "}" ;
syntax SwitchBlockStatementGroup = SwitchLabels BlockStatements ;
syntax SwitchLabels = SwitchLabel+ ;
syntax SwitchLabel = "case" ConstantExpression ":"
| "default" ":"
;
我使用以下代码执行重构:
CompilationUnit refactorIfElseStatement(CompilationUnit unit) = visit(unit) {
case (IfThenElseStatement) `if (<Identifier idIf>.equals(<StringLiteral stringCompare>)) <StatementNoShortIf stmtIf> else <Statement stmtElse>` =>
(SwitchStatement) `switch (<Identifier idIf>) {<SwitchBlockStatementGroup switchBlock>}`
when switchBlock := generateCaseFromIfElseStatement(stmtElse, idIf)
};
SwitchBlockStatementGroup generateCaseFromIfElseStatement(Statement stmt, Identifier idIf) = visit(stmt){
case (StatementNoShortIf) `<StatementNoShortIf stmt1>` =>
(SwitchBlockStatementGroup) `default: <BlockStatements stmt1>`
case (IfThenElseStatement) `if (idIf.equals(<StringLiteral stringCompare>)) <StatementNoShortIf stmtIf> else <Statement stmtElse>` =>
(SwitchBlockStatementGroup) `case <ConstantExpression stringCompare> : { <BlockStatements stmtIf> }`
};
但是,运行重构代码时,会显示以下错误:
Expected SwitchBlockStatementGroup, but got Statement Advice: |http://tutor.rascal-mpl.org/Errors/Static/UnexpectedType/UnexpectedType.html|
首先,重构很简单,如下面的代码块所示。随后,我打算增加其复杂性,以满足其他情况。
if (string.equals("boo")){
System.out.println("is a boo");
}
else if (string.equals("blah")){
System.out.println("is a blah");
}
else if (string.equals("foo")){
System.out.println("is a foo");
}
else{
System.out.print("is a default");
}
答案 0 :(得分:2)
在Rascal中,访问语句只能用同一个非终端替换非终端。
visit
语句的rank-2多态语义正确地进行类型检查,对于它访问的所有节点,它只能用其他类型替换它在那里找到的类型的值这是匹配类型的子类型SwitchBlockStatementGroup
不是触发错误消息的StatementNoShortIf
的子类型,IfThenElseStatement
和SwitchBlockStatementGroup
所以这意味着必须修复代码以跳过类型安全和语法安全箍。选项:
Statement
和一个Expression
),通常由明确的消歧构造支持(如优先级>
并遵循限制!>>
)。此外,我们避免使用syntax A = B
之类的使用链规则(注入),以避免必须记住其他类型并避免编写过于特定的模式。Statement
级别并重写您的模式,将Statement
替换为另一个Statement
。在这种情况下,这意味着匹配左侧的周围if-then-else并在右侧重建它,并用右括号围绕SwitchBlockStatementGroup
以使其成为声明等。 答案 1 :(得分:2)
我使用(在顶层)访问者+基于Rascal的switch-case语句(不使用其他访问者表达式)的递归函数来修复问题。请注意,此代码仍然是实验性的,我只使用一些测试用例进行了测试。
CompilationUnit refactorToSwitchString(CompilationUnit unit) = top-down-break visit(unit) {
case (Statement)`if(<Identifier id>.equals(<StringLiteral lit>)) {<Statement stmt1> } else <Statement stmt2>` =>
(Statement)`switch(<Identifier id>) { case <StringLiteral lit> : { <Statement stmt1> } <SwitchBlockStatementGroup* stmt3> }`
when stmt3 := buildSwitchGroups(stmt2, id)
};
SwitchBlockStatementGroups buildSwitchGroups(stmt, id) {
switch(stmt) {
case (Statement)`if(<Identifier id>.equals(<StringLiteral lit>)) { <Statement stmt1> } else <Statement stmt2>` : {
stmt3 = buildSwitchGroups(stmt2, id) ;
return (SwitchBlockStatementGroups)`case <StringLiteral lit> : { <Statement stmt1> break; } <SwitchBlockStatementGroup* stmt3>`;
}
case (Statement)`if(<Identifier id>.equals(<StringLiteral lit>)) <Statement stmt1>` : {
return (SwitchBlockStatementGroups) `case <StringLiteral lit> : { <Statement stmt1> break;`;
}
case (Statement)`<Statement stmt>` : {
return (SwitchBlockStatementGroups)`default : <Statement stmt>` ;
}
};
我不得不稍微改变语法,引入如下定义:
syntax SwitchBlock = "{" SwitchBlockStatementGroups SwitchLabel* "}" ;
syntax SwitchBlockStatementGroups = SwitchBlockStatementGroup* ;
虽然我不确定这种变化是否真的有必要。