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