首页 > 解决方案 > 如何在我的 antlr4 语法中实现将写入域但不耦合域服务的方法?

问题描述

我已经为我的域生成了一个 DSL。我已经实现了我的DSL的所有读取访问方法,现在我正在考虑如何解决写入方法。也许有人可以给我一个很好的建议。

为了能够实现和测试我的 DSL,我选择使用一个接口来处理所有数据访问。在我的测试中,我可以模拟和填充这些数据集合,稍后当我将 DSL 集成到一些域服务中时,这些集合将填充真实数据。对于阅读访问,这很好用。但是我怎样才能解决写访问。我当前的实现没有与可以写入数据的服务耦合。所以我想我可以收集所有的写作对象,我的 dsl 的调用者将检索这个集合并进行写作。如何用我的语法返回这样的集合,目前我只返回真或假。也许有更好的方法,但我不想在我的 DSL 实现中包含编写服务。

这是我的语法的一部分, setCommand 和 setIfCommand 尚未正确实现

grammar EXPRESS;

prog: expr+ EOF;
expr:
             statement                          #StatementExpr
             |NOT expr                          #NotExpr
             | expr AND expr                 #AndExpr
             | expr (OR | XOR) expr        #OrExpr
             | function                           #FunctionExpr
             | LPAREN expr RPAREN       #ParenExpr
             | writeCommand                 #WriteExpr
 ;

writeCommand: setCommand | setIfCommand;
statement: ID '=' getCommand  NEWLINE         #Assign;
setCommand: 'set' LPAREN variable = variableType '|' value = parameter RPAREN;
setIfCommand: 'setIf' LPAREN variableType '|' expr '?' p1 = parameter ':' p2 = parameter RPAREN;

这是我的访客的一部分

@Override
public Value visitSetCommand(FELParser.SetCommandContext ctx) {
    //'set' LPAREN variable = variableType '|' value = parameter RPAREN SEMI;
    Value variable = this.visit(ctx.variableType());
    Value newValue = this.visit(ctx.parameter());
    memory.put(variable.asString(), newValue);
    return Value.TRUE;
}

@Override
public Value visitSetIfCommand(FELParser.SetIfCommandContext ctx) {
    //'setIf' LPAREN variableType '|' expr '?' p1 = parameter ':' p2 = 
   parameter RPAREN SEMI;
    Value variable = this.visit(ctx.variableType());
    Value expression = this.visit(ctx.expr());
    Value trueValue = this.visit(ctx.p1);
    Value falseValue = this.visit(ctx.p2);

    if (expression.asBoolean()){
        memory.put(variable.asString(), new Value(trueValue));
    }
    else{
        memory.put(variable.asString(), new Value(falseValue));
    }
    return Value.TRUE;
}

这里有一个测试用例

 @Test
public void whenSetCommand_ThenTrueAndValueInBuffer() {
    String expression = "set(buffer, foo|bar)  isSet(buffer,foo)";

    ParseTree tree = getParseTree(expression);
    Mockito.when(data.getFieldValues()).thenReturn(fieldValues);

    Value answer = new FELCustomVisitor(data).visit(tree);
    assertThat(answer.asBoolean()).isTrue();
}

   public void beforeEach(){
    data = initPDIXDataMock();
    Mockito.when(data.getFieldValues()).thenReturn(new HashMap<>());
    Mockito.when(data.getFormAttachments()).thenReturn(new HashMap<>());
    Mockito.when(data.getInstanceAttachments()).thenReturn(new HashMap<>());
    Mockito.when(data.getMandatorAttachments()).thenReturn(new HashMap<>());
    Mockito.when(data.getFormAttributes()).thenReturn(new HashMap<>());
    Mockito.when(data.getInstanceAttributes()).thenReturn(new HashMap<>());
    Mockito.when(data.getMandatorAttributes()).thenReturn(new HashMap<>());
}

一个想法是将它添加到返回对象中,在我的例子中是值。在那里,我可以添加需要由我的 DSL 的调用服务处理的方法列表。这是我的价值对象

public class Value {
public static final Value TRUE = new Value(true);
public static final Value FALSE = new Value(false);
public static final Value NULL = new Value(null);

private final Object value;

public Value(Object value) {
    this.value = value;
}

public Boolean asBoolean() {
    return (Boolean) this.value;
}
public String asString(){
    return (String) this.value;
}
public double asDouble(){
    return Double.parseDouble(asString());
}


@Override
public String toString() {
    return String.format("Value{type: %s, value: %s}",
            this.value == null ? "null" : this.value.getClass().getSimpleName(), this.value);
}

public PDIXAttribute asAttribute() {
    return (PDIXAttribute) this.value;
}

public PDIXAttachments asAttachment() {
    return (PDIXAttachments) this.value;
}

标签: javaantlr4

解决方案


推荐阅读