假设我有以下简单语法(查询 DSL):
grammar TestGrammar;
term : textTerm ;
textTerm : 'Text' '(' T_VALUE '=' STRING+ ')' ;
T_VALUE : 'value' ;
STRING : '"' .+? '"' ;
WS : [ \t\r\n]+ -> skip ;
然后在某个时候我决定需要更改文本术语格式,例如:
Text(value = "123") -> MyText(val = "123")
我应该如何迁移用户使用以前版本的语法生成的现有数据?
假设
让我们通过引入 token 来简化语法TEXT
for 'Text'
string.
grammar TestGrammar;
WS : [ \t\r\n]+ -> channel(HIDDEN); // preserve the whitespaces characters!
T_VALUE : 'value';
STRING : '"' .+? '"';
TEXT : 'Text';
term
: textTerm;
textTerm
: TEXT '(' T_VALUE '=' STRING+ ')';
Solution
现在我们将利用 ANTLRv4 工具构建的 AST 监听器。这使我们能够遍历 AST 并执行令牌替换TokenStreamRewriter
已经提到过的类卢卡斯·切斯涅夫斯基在评论中。
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStreamRewriter;
public class MigrationTask extends TestGrammarBaseListener {
private TokenStreamRewriter rewriter;
public MigrationTask(CommonTokenStream stream) {
this.rewriter = new TokenStreamRewriter(stream);
}
@Override
public void enterTextTerm(TestGrammarParser.TextTermContext ctx) {
rewriter.replace(ctx.TEXT().getSymbol(), "MyText");
rewriter.replace(ctx.T_VALUE().getSymbol(), "val");
}
public String getMigrationResult() {
return rewriter.getText();
}
}
因此,每当我们在 AST 遍历过程中遇到标记时,我们都会用其替换标记来替换给定标记。
Usage
现在我们可以执行MigrationTask
给定的ParseTree
并检索迁移结果:
(...)
CommonTokenStream tokens = new CommonTokenStream(lexer);
TestGrammarParser parser = new TestGrammarParser(tokens);
ParseTree tree = parser.term();
ParseTreeWalker walker = new ParseTreeWalker();
MigrationTask migrationTask = new MigrationTask(tokens);
walker.walk(migrationTask, tree);
String result = migrationTask.getMigrationResult(); // Here we retrive migration result !
(...)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)