WIP visitor transformer
This commit is contained in:
parent
cfce3e4dbb
commit
d4b6714229
15 changed files with 200 additions and 20 deletions
|
@ -17,7 +17,7 @@
|
|||
<dependency>
|
||||
<groupId>nu.zoom.dsl</groupId>
|
||||
<artifactId>parser</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.13.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>info.picocli</groupId>
|
||||
<artifactId>picocli</artifactId>
|
||||
<version>4.7.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -42,6 +47,9 @@
|
|||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-maven-plugin</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<configuration>
|
||||
<visitor>true</visitor>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
grammar Endpoints;
|
||||
|
||||
document : generatorconfig? (compoundType|endpoint)* ;
|
||||
generatorconfig : '{' (configitem)? (',' configitem)* '}';
|
||||
configitem : configkey ':' configvalue ;
|
||||
configkey : IDENTIFIER ;
|
||||
configvalue : (IDENTIFIER|VALUE) ;
|
||||
compoundType : compoundTypeName compoundFields ;
|
||||
compoundTypeName : IDENTIFIER ;
|
||||
compoundFields : '(' compoundField (',' compoundField)* ')' ;
|
||||
compoundField : fieldName ':' fieldType ;
|
||||
fieldName : IDENTIFIER ;
|
||||
fieldType : IDENTIFIER ;
|
||||
compoundTypeName : IDENTIFIER ;
|
||||
compoundField : fieldName ':' fieldType ;
|
||||
compoundFields : '(' compoundField (',' compoundField)* ')' ;
|
||||
compoundType : compoundTypeName compoundFields ;
|
||||
pathSegment : '/' (IDENTIFIER|VALUE) ;
|
||||
endpoint : path '<' (compoundType | IDENTIFIER) ;
|
||||
path : (pathSegment)+ ;
|
||||
endpoint : path '<' (compoundFields | IDENTIFIER) ;
|
||||
pathSegment : '/' (IDENTIFIER|VALUE) ;
|
||||
|
||||
|
||||
fragment DIGIT : [0-9] ;
|
||||
fragment LOWERCASE : [a-z] ;
|
||||
fragment UPPERCASE : [A-Z] ;
|
||||
COMMENT : '/*' (IDENTIFIER|VALUE)* '*/' -> skip ;
|
||||
WS : [ \t\n\r]+ -> skip;
|
||||
IDENTIFIER : (LOWERCASE | UPPERCASE) (LOWERCASE | UPPERCASE | DIGIT)* ;
|
||||
VALUE : ~[ ,{}:()\n\t\r/<>"']+ ;
|
||||
VALUE : ~[ ,{}:()\n\t\r/<>"#';*]+ ;
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package nu.zoom.dsl;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, World!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record CompoundTypeNode(String name, List<FieldNode> fields) {
|
||||
}
|
4
parser/src/main/java/nu/zoom/dsl/ast/ConfigItemNode.java
Normal file
4
parser/src/main/java/nu/zoom/dsl/ast/ConfigItemNode.java
Normal file
|
@ -0,0 +1,4 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
public record ConfigItemNode(String key, String value) {
|
||||
}
|
9
parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java
Normal file
9
parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record DocumentNode(
|
||||
List<ConfigItemNode> configItems,
|
||||
List<CompoundTypeNode> typeDefinitions,
|
||||
List<EndpointNode> endpoints) {
|
||||
}
|
8
parser/src/main/java/nu/zoom/dsl/ast/EndpointNode.java
Normal file
8
parser/src/main/java/nu/zoom/dsl/ast/EndpointNode.java
Normal file
|
@ -0,0 +1,8 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record EndpointNode(
|
||||
PathsNode paths,
|
||||
String inputType) {
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
import nu.zoom.dsl.parser.EndpointsBaseVisitor;
|
||||
import nu.zoom.dsl.parser.EndpointsParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class EndpointsVisitorTransformer extends EndpointsBaseVisitor<EndpointsParser.DocumentContext> {
|
||||
private ArrayList<EndpointNode> endpoints = new ArrayList<>();
|
||||
private ArrayList<ConfigItemNode> config = new ArrayList<>();
|
||||
private ArrayList<CompoundTypeNode> dataTypes = new ArrayList<>();
|
||||
public EndpointsVisitorTransformer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndpointsParser.DocumentContext visitConfigitem(EndpointsParser.ConfigitemContext ctx) {
|
||||
String configKey = ctx.configkey().IDENTIFIER().getText() ;
|
||||
String configValue = getText(ctx.configvalue()) ;
|
||||
this.config.add(new ConfigItemNode(configKey, configValue));
|
||||
return super.visitConfigitem(ctx) ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndpointsParser.DocumentContext visitCompoundType(EndpointsParser.CompoundTypeContext ctx) {
|
||||
return super.visitCompoundType(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EndpointsParser.DocumentContext visitEndpoint(EndpointsParser.EndpointContext ctx) {
|
||||
return super.visitEndpoint(ctx);
|
||||
}
|
||||
|
||||
private String getText(EndpointsParser.ConfigvalueContext ctx) {
|
||||
String identifierText = (ctx.IDENTIFIER() != null) ? ctx.IDENTIFIER().getText() : "" ;
|
||||
String valueText = (ctx.VALUE() != null) ? ctx.VALUE().getText() : "" ;
|
||||
return identifierText + valueText;
|
||||
}
|
||||
}
|
4
parser/src/main/java/nu/zoom/dsl/ast/FieldNode.java
Normal file
4
parser/src/main/java/nu/zoom/dsl/ast/FieldNode.java
Normal file
|
@ -0,0 +1,4 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
public record FieldNode(String name, String type) {
|
||||
}
|
22
parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java
Normal file
22
parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
import nu.zoom.dsl.parser.EndpointsLexer;
|
||||
import nu.zoom.dsl.parser.EndpointsParser;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ParserWrapper {
|
||||
public DocumentNode parse(Path sourcePath) throws IOException {
|
||||
var ins = CharStreams.fromPath(sourcePath, StandardCharsets.UTF_8);
|
||||
EndpointsLexer lexer = new EndpointsLexer(ins);
|
||||
EndpointsParser parser = new EndpointsParser(new CommonTokenStream(lexer));
|
||||
var document= parser.document() ;
|
||||
new EndpointsVisitorTransformer().visit(document);
|
||||
return null ;
|
||||
}
|
||||
}
|
6
parser/src/main/java/nu/zoom/dsl/ast/PathsNode.java
Normal file
6
parser/src/main/java/nu/zoom/dsl/ast/PathsNode.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
package nu.zoom.dsl.ast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record PathsNode(List<String> paths) {
|
||||
}
|
75
parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java
Normal file
75
parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
package nu.zoom.dsl.cli;
|
||||
|
||||
import nu.zoom.dsl.ast.ParserWrapper;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@Command(
|
||||
name = "EndpointsCLI",
|
||||
mixinStandardHelpOptions = true,
|
||||
description = "Generate source code from an endpoints specification file."
|
||||
)
|
||||
public class EndpointsCLI implements Callable<Integer> {
|
||||
@Parameters(index = "0", description = "The source endpoints DSL file.")
|
||||
private Path file;
|
||||
|
||||
@Option(names = {"-t", "--template"}, description = "The template directory. Default is ~/endpoints-templates")
|
||||
private Path templateDir = Paths.get(System.getProperty("user.dir"), "endpoints-templates");
|
||||
|
||||
@Option(names = {"-o", "--output"}, description = "The directory to write the generated code to. Default is ~/endpoints-output")
|
||||
private Path outputDir = Paths.get(System.getProperty("user.dir"), "endpoints-output");
|
||||
|
||||
@Option(names = {"-v", "--verbose"}, description = "Print verbose debug messages.")
|
||||
private Boolean verbose = false;
|
||||
|
||||
public static void main(String[] args) {
|
||||
int exitCode = new CommandLine(new EndpointsCLI()).execute(args);
|
||||
System.exit(exitCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer call() {
|
||||
try {
|
||||
validateTemplateDirectory();
|
||||
validateInputFile();
|
||||
validateOutputDirectory();
|
||||
new ParserWrapper().parse(file);
|
||||
return 0;
|
||||
} catch (Exception e) {
|
||||
System.err.println(e.getMessage());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOutputDirectory() throws IOException {
|
||||
if (Files.notExists(this.outputDir)) {
|
||||
Files.createDirectories(this.outputDir);
|
||||
}
|
||||
if (!Files.isDirectory(this.outputDir)) {
|
||||
throw new IllegalArgumentException("Output directory: '" + this.outputDir + " 'is not a directory.");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTemplateDirectory() throws IOException {
|
||||
if (!Files.isDirectory(this.templateDir)) {
|
||||
throw new IllegalArgumentException("Template directory '" + this.templateDir + "' is not a directory.");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateInputFile() throws IOException {
|
||||
if (Files.notExists(this.file)) {
|
||||
throw new IllegalArgumentException("Input file '" + this.file + "' does not exist.");
|
||||
}
|
||||
if (!Files.isReadable(this.file) || !Files.isRegularFile(this.file)) {
|
||||
throw new IllegalArgumentException("Input file '" + this.file + "' is not a readable file.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package nu.zoom.dsl.parser;
|
||||
|
||||
public class ParserFactory {
|
||||
}
|
10
test01.endpoints
Normal file
10
test01.endpoints
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
config:foo
|
||||
}
|
||||
|
||||
SomeType(
|
||||
foo:bar
|
||||
)
|
||||
|
||||
/some/endpoint < SomeType
|
||||
/some/other/endpoint < SomeOtherType(bar:String)
|
Loading…
Add table
Reference in a new issue