Grammar for states and transitions

This commit is contained in:
Johan Maasing 2025-04-19 07:08:06 +02:00
parent 8050d35811
commit a546d257f3
5 changed files with 88 additions and 20 deletions

View file

@ -1,14 +0,0 @@
package nu.zoom.dsl.ast;
import java.util.List;
import java.util.Map;
public interface ParseTreeTransformer {
List<EndpointNode> getEndpoints();
Map<String,String> getConfig();
List<TypeNode> getDataTypes();
}

View file

@ -2,8 +2,10 @@ package nu.zoom.dsl.ast;
import nu.zoom.dsl.parser.StatesBaseVisitor;
import nu.zoom.dsl.parser.StatesParser;
import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.*;
import java.util.stream.Stream;
public class StatesVisitorTransformer extends StatesBaseVisitor<StatesParser.DocumentContext> {
private final HashMap<String,String> config = new HashMap<>();
@ -29,9 +31,30 @@ public class StatesVisitorTransformer extends StatesBaseVisitor<StatesParser.Doc
return super.visitState(ctx);
}
@Override
public StatesParser.DocumentContext visitMessage(StatesParser.MessageContext ctx) {
String messageName = ctx.typeName().IDENTIFIER().getText() ;
List<FieldNode> fields = extractFields(ctx.typeDeclaration()) ;
this.messageTypes.add(new TypeNode(messageName, fields));
return super.visitMessage(ctx);
}
@Override
public StatesParser.DocumentContext visitConfigitem(StatesParser.ConfigitemContext ctx) {
String configKey = ctx.configkey().IDENTIFIER().getText();
String configValue = getText(ctx.configvalue().IDENTIFIER(), ctx.configvalue().VALUE());
this.config.put(configKey, configValue);
return super.visitConfigitem(ctx);
}
public Set<StateNode> getStates() {
// TODO: Calculate state nodes from this.transitions
return Set.of();
HashSet<StateNode> states = new HashSet<>();
this.transitions.forEach((state,v)->{
HashSet<TransitionNode> transitionNodes = new HashSet<>();
v.forEach((to, message) -> transitionNodes.add(new TransitionNode(message, to)));
states.add(new StateNode(state, "", transitionNodes)) ;
}) ;
return states ;
}
public Map<String,String> getConfig() {
@ -40,10 +63,28 @@ public class StatesVisitorTransformer extends StatesBaseVisitor<StatesParser.Doc
public Set<TypeNode> getTypes() {
// TODO calculate data types from NodeTypes and MessageTypes with duplicate check.
return Set.of() ;
HashMap<String, TypeNode> typeNodes = new HashMap<>();
this.nodeTypes.forEach(typeNode -> {
if (typeNodes.containsKey(typeNode.name())) {
throw new RuntimeException("Duplicate type name: " + typeNode.name());
} else {
typeNodes.put(typeNode.name(), typeNode);
}
}) ;
this.messageTypes.forEach(typeNode -> {
if (typeNodes.containsKey(typeNode.name())) {
throw new RuntimeException("Duplicate type name: " + typeNode.name());
} else {
typeNodes.put(typeNode.name(), typeNode);
}
}) ;
return Set.of(typeNodes.values().toArray(new TypeNode[0])) ;
}
private List<FieldNode> extractFields(StatesParser.TypeDeclarationContext declaration) {
if (declaration == null) {
return Collections.emptyList();
}
return declaration
.typeField()
.stream()
@ -53,4 +94,13 @@ public class StatesVisitorTransformer extends StatesBaseVisitor<StatesParser.Doc
)
.toList();
}
// Concatenate the text from two terminal nodes. Useful for contexts that are either an identifier or a value,
// and you just want the text from whichever is not null.
private String getText(TerminalNode identifier, TerminalNode value) {
return
((identifier != null) ? identifier.getText() : "") +
((value != null) ? value.getText() : "");
}
}

View file

@ -26,7 +26,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
@Command(
@ -35,7 +34,7 @@ import java.util.concurrent.Callable;
description = "Generate source code from an endpoints specification file."
)
public class EndpointsCLI implements Callable<Integer> {
public static enum ParserType {
public enum ParserType {
Endpoints,
States
}
@ -71,7 +70,7 @@ public class EndpointsCLI implements Callable<Integer> {
validateOutputDirectory();
verbose("Parsing: " + file.toAbsolutePath());
if (parser == null) {
if (file.getFileName().endsWith(".states")) {
if (file.getFileName().toString().endsWith(".states")) {
parser = ParserType.States;
}
}