Allow comments, unnamed type declarations for request / response bodies

This commit is contained in:
Johan Maasing 2025-04-07 19:41:13 +02:00
parent a98ef3cebd
commit 2a46a92630
5 changed files with 54 additions and 46 deletions

View file

@ -1,24 +1,32 @@
grammar Endpoints; grammar Endpoints;
document : generatorconfig? (compoundType|endpoint)* ; document : generatorconfig? (namedTypeDeclaration|endpoint)* ;
generatorconfig : '{' (configitem)? (',' configitem)* '}'; generatorconfig : '{' (configitem)? (',' configitem)* '}';
configitem : configkey ':' configvalue ; configitem : configkey ':' configvalue ;
configkey : IDENTIFIER ; configkey : IDENTIFIER ;
configvalue : (IDENTIFIER|VALUE) ; configvalue : (IDENTIFIER|VALUE) ;
compoundType : compoundTypeName compoundFields ; namedTypeDeclaration : typeName typeDeclaration ;
compoundTypeName : IDENTIFIER ; typeName : IDENTIFIER ;
compoundFields : '(' compoundField (',' compoundField)* ')' ; typeDeclaration : typeName? '(' typeField (',' typeField)* ')' ;
compoundField : fieldName ':' fieldType ; typeField : fieldName ':' fieldType ;
fieldName : IDENTIFIER ; fieldName : IDENTIFIER ;
fieldType : IDENTIFIER ; fieldType : IDENTIFIER ;
endpoint : path '=<' (compoundType | IDENTIFIER) ; requestBody : REQUEST_PREFIX (namedTypeDeclaration | typeDeclaration | IDENTIFIER) ;
responseBody : RESPONSE_PREFIX (namedTypeDeclaration | typeDeclaration | IDENTIFIER) ;
endpoint : path requestBody responseBody?;
path : (pathSegment)+ ; path : (pathSegment)+ ;
pathSegment : '/' (IDENTIFIER|VALUE) ; pathSegment : SLASH (IDENTIFIER|VALUE) ;
fragment DIGIT : [0-9] ; fragment DIGIT : [0-9] ;
fragment LOWERCASE : [a-z] ; fragment LOWERCASE : [a-z] ;
fragment UPPERCASE : [A-Z] ; fragment UPPERCASE : [A-Z] ;
fragment GENERICS : '['|']'|'<'|'>' ; fragment GENERICS : '['|']'|'<'|'>' ;
fragment COMMENT_BEGIN : '/*' ;
fragment COMMENT_END : '*/' ;
WS : [ \t\n\r]+ -> skip; WS : [ \t\n\r]+ -> skip;
COMMENT : COMMENT_BEGIN ~[/]* COMMENT_END -> skip;
REQUEST_PREFIX : '<-' ;
RESPONSE_PREFIX : '->' ;
SLASH : '/' ;
IDENTIFIER : (LOWERCASE | UPPERCASE) (LOWERCASE | UPPERCASE | DIGIT | GENERICS)* ; IDENTIFIER : (LOWERCASE | UPPERCASE) (LOWERCASE | UPPERCASE | DIGIT | GENERICS)* ;
VALUE : ~[ ,{}:()/="#';*]+ ; VALUE : ~[ ,{}:()/="#';*\n\r\t]+ ;

View file

@ -1,6 +0,0 @@
package nu.zoom.dsl.ast;
import java.util.List;
public record CompoundTypeNode(String name, List<FieldNode> fields) {
}

View file

@ -4,6 +4,6 @@ import java.util.List;
public record DocumentNode( public record DocumentNode(
List<ConfigItemNode> configItems, List<ConfigItemNode> configItems,
List<CompoundTypeNode> typeDefinitions, List<TypeNode> typeDefinitions,
List<EndpointNode> endpoints) { List<EndpointNode> endpoints) {
} }

View file

@ -6,11 +6,12 @@ import org.antlr.v4.runtime.tree.TerminalNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
public class EndpointsVisitorTransformer extends EndpointsBaseVisitor<EndpointsParser.DocumentContext> { public class EndpointsVisitorTransformer extends EndpointsBaseVisitor<EndpointsParser.DocumentContext> {
private final ArrayList<EndpointNode> endpoints = new ArrayList<>(); private final ArrayList<EndpointNode> endpoints = new ArrayList<>();
private final ArrayList<ConfigItemNode> config = new ArrayList<>(); private final ArrayList<ConfigItemNode> config = new ArrayList<>();
private final ArrayList<CompoundTypeNode> dataTypes = new ArrayList<>(); private final ArrayList<TypeNode> dataTypes = new ArrayList<>();
public EndpointsVisitorTransformer() { public EndpointsVisitorTransformer() {
} }
@ -23,7 +24,7 @@ public class EndpointsVisitorTransformer extends EndpointsBaseVisitor<EndpointsP
return List.copyOf(config); return List.copyOf(config);
} }
public List<CompoundTypeNode> getDataTypes() { public List<TypeNode> getDataTypes() {
return List.copyOf(dataTypes); return List.copyOf(dataTypes);
} }
@ -35,12 +36,6 @@ public class EndpointsVisitorTransformer extends EndpointsBaseVisitor<EndpointsP
return super.visitConfigitem(ctx); return super.visitConfigitem(ctx);
} }
@Override
public EndpointsParser.DocumentContext visitCompoundType(EndpointsParser.CompoundTypeContext ctx) {
this.dataTypes.add(extractCompoundTypeNode(ctx));
return super.visitCompoundType(ctx);
}
@Override @Override
public EndpointsParser.DocumentContext visitEndpoint(EndpointsParser.EndpointContext ctx) { public EndpointsParser.DocumentContext visitEndpoint(EndpointsParser.EndpointContext ctx) {
List<String> segments = ctx List<String> segments = ctx
@ -50,26 +45,30 @@ public class EndpointsVisitorTransformer extends EndpointsBaseVisitor<EndpointsP
.map( .map(
segment -> getText(segment.IDENTIFIER(), segment.VALUE()) segment -> getText(segment.IDENTIFIER(), segment.VALUE())
).toList(); ).toList();
TerminalNode typeReference = ctx.IDENTIFIER(); EndpointsParser.RequestBodyContext requestBodyContext = ctx.requestBody() ;
TerminalNode typeReference = requestBodyContext.IDENTIFIER() ;
extractEndpoint(ctx, typeReference, segments);
return super.visitEndpoint(ctx);
}
private void extractEndpoint(EndpointsParser.EndpointContext ctx, TerminalNode typeReference, List<String> segments) {
if (typeReference != null) { if (typeReference != null) {
var endpoint = new EndpointNode(new PathsNode(segments), typeReference.getText()); var endpoint = new EndpointNode(new PathsNode(segments), typeReference.getText());
this.endpoints.add(endpoint); this.endpoints.add(endpoint);
} else { } else {
var compoundTypeNode = extractCompoundTypeNode(ctx.compoundType()); var compoundTypeNode = extractCompoundTypeNode(ctx.requestBody().namedTypeDeclaration());
var endpoint = new EndpointNode(new PathsNode(segments), compoundTypeNode.name()); var endpoint = new EndpointNode(new PathsNode(segments), compoundTypeNode.name().orElseThrow());
//this.dataTypes.add(compoundTypeNode);
this.endpoints.add(endpoint); this.endpoints.add(endpoint);
} }
return super.visitEndpoint(ctx);
} }
private CompoundTypeNode extractCompoundTypeNode(EndpointsParser.CompoundTypeContext ctx) { private TypeNode extractCompoundTypeNode(EndpointsParser.NamedTypeDeclarationContext ctx) {
String typeName = ctx.compoundTypeName().getText(); String typeName = ctx.typeName().getText();
List<FieldNode> fields = extractTypeFields(ctx.compoundFields().compoundField()); List<FieldNode> fields = extractTypeFields(ctx.typeDeclaration().typeField());
return new CompoundTypeNode(typeName, fields); return new TypeNode(Optional.of(typeName), fields);
} }
private List<FieldNode> extractTypeFields(List<EndpointsParser.CompoundFieldContext> compoundFieldContexts) { private List<FieldNode> extractTypeFields(List<EndpointsParser.TypeFieldContext> compoundFieldContexts) {
return compoundFieldContexts.stream().map( return compoundFieldContexts.stream().map(
ctx -> new FieldNode( ctx -> new FieldNode(
ctx.fieldName().getText(), ctx.fieldName().getText(),

View file

@ -0,0 +1,7 @@
package nu.zoom.dsl.ast;
import java.util.List;
import java.util.Optional;
public record TypeNode(Optional<String> name, List<FieldNode> fields) {
}