How to implement methods which wil write to the domain but not couple domain services in my antlr4 grammar?

Viewed 34

I have generated a DSL for my domain. I have implemented all the read access methods of my DSL, now I am thinking about how to solve the writing methods. Maybe someone can give me a good advice.

To be able to implement and test my DSL, I have choosen to use an interface with which all the data access will be handled. In my tests I can mock and fill these data collections, later when I integrate the DSL into some domain services, these collections will be filled with real data. For reading acces this works good. But how can I solve the writing access. My current implementation is not coupled with services which can write data. So I thought I can collect all the writing objects and the caller of my dsl will retrieve this collection and will do the writing stuff. How can I return such a collection with my grammar, currently I am returning only true or false. Maybe there is a better approach, but I do not want to include writing services in my DSL implementation.

Here is part of my grammar, the setCommand and setIfCommand is not yet correctly implemented

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;

Here the part of my visitor

@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;
}

And here a testcase

 @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<>());
}

One idea is to add this to the return object, in my case Value. There I could add a list of methods which need to be processed by the calling service of my DSL. here is my value object

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;
}
0 Answers
Related