diff --git a/assembly/pom.xml b/assembly/pom.xml index 43bb1e9..ab82935 100644 --- a/assembly/pom.xml +++ b/assembly/pom.xml @@ -17,7 +17,7 @@ nu.zoom.dsl parser - ${parent.version} + ${project.parent.version} diff --git a/parser/pom.xml b/parser/pom.xml index 0c1f9b6..a5d8510 100644 --- a/parser/pom.xml +++ b/parser/pom.xml @@ -18,6 +18,11 @@ antlr4-runtime 4.13.0 + + info.picocli + picocli + 4.7.6 + @@ -42,6 +47,9 @@ org.antlr antlr4-maven-plugin 4.13.1 + + true + diff --git a/parser/src/main/antlr4/nu/zoom/dsl/parser/Endpoints.g4 b/parser/src/main/antlr4/nu/zoom/dsl/parser/Endpoints.g4 index 7fc1d09..6885407 100644 --- a/parser/src/main/antlr4/nu/zoom/dsl/parser/Endpoints.g4 +++ b/parser/src/main/antlr4/nu/zoom/dsl/parser/Endpoints.g4 @@ -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/<>"#';*]+ ; diff --git a/parser/src/main/java/nu/zoom/dsl/Main.java b/parser/src/main/java/nu/zoom/dsl/Main.java deleted file mode 100644 index c57eaa0..0000000 --- a/parser/src/main/java/nu/zoom/dsl/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package nu.zoom.dsl; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} \ No newline at end of file diff --git a/parser/src/main/java/nu/zoom/dsl/ast/CompoundTypeNode.java b/parser/src/main/java/nu/zoom/dsl/ast/CompoundTypeNode.java new file mode 100644 index 0000000..d5218fc --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/CompoundTypeNode.java @@ -0,0 +1,6 @@ +package nu.zoom.dsl.ast; + +import java.util.List; + +public record CompoundTypeNode(String name, List fields) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/ConfigItemNode.java b/parser/src/main/java/nu/zoom/dsl/ast/ConfigItemNode.java new file mode 100644 index 0000000..b18eea6 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/ConfigItemNode.java @@ -0,0 +1,4 @@ +package nu.zoom.dsl.ast; + +public record ConfigItemNode(String key, String value) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java b/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java new file mode 100644 index 0000000..0f29bdd --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/DocumentNode.java @@ -0,0 +1,9 @@ +package nu.zoom.dsl.ast; + +import java.util.List; + +public record DocumentNode( + List configItems, + List typeDefinitions, + List endpoints) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/EndpointNode.java b/parser/src/main/java/nu/zoom/dsl/ast/EndpointNode.java new file mode 100644 index 0000000..c4c771d --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/EndpointNode.java @@ -0,0 +1,8 @@ +package nu.zoom.dsl.ast; + +import java.util.Optional; + +public record EndpointNode( + PathsNode paths, + String inputType) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/EndpointsVisitorTransformer.java b/parser/src/main/java/nu/zoom/dsl/ast/EndpointsVisitorTransformer.java new file mode 100644 index 0000000..db5c1cc --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/EndpointsVisitorTransformer.java @@ -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 { + private ArrayList endpoints = new ArrayList<>(); + private ArrayList config = new ArrayList<>(); + private ArrayList 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; + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/FieldNode.java b/parser/src/main/java/nu/zoom/dsl/ast/FieldNode.java new file mode 100644 index 0000000..bde0328 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/FieldNode.java @@ -0,0 +1,4 @@ +package nu.zoom.dsl.ast; + +public record FieldNode(String name, String type) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java b/parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java new file mode 100644 index 0000000..369d4ff --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/ParserWrapper.java @@ -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 ; + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/ast/PathsNode.java b/parser/src/main/java/nu/zoom/dsl/ast/PathsNode.java new file mode 100644 index 0000000..313a28c --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/ast/PathsNode.java @@ -0,0 +1,6 @@ +package nu.zoom.dsl.ast; + +import java.util.List; + +public record PathsNode(List paths) { +} diff --git a/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java b/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java new file mode 100644 index 0000000..caf3530 --- /dev/null +++ b/parser/src/main/java/nu/zoom/dsl/cli/EndpointsCLI.java @@ -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 { + @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."); + } + } +} diff --git a/parser/src/main/java/nu/zoom/dsl/parser/ParserFactory.java b/parser/src/main/java/nu/zoom/dsl/parser/ParserFactory.java deleted file mode 100644 index 370386c..0000000 --- a/parser/src/main/java/nu/zoom/dsl/parser/ParserFactory.java +++ /dev/null @@ -1,4 +0,0 @@ -package nu.zoom.dsl.parser; - -public class ParserFactory { -} diff --git a/test01.endpoints b/test01.endpoints new file mode 100644 index 0000000..6ba4a95 --- /dev/null +++ b/test01.endpoints @@ -0,0 +1,10 @@ +{ + config:foo +} + +SomeType( + foo:bar +) + +/some/endpoint < SomeType +/some/other/endpoint < SomeOtherType(bar:String) \ No newline at end of file