needs testing

This commit is contained in:
Johan Maasing 2025-05-04 09:41:16 +02:00
parent e0922d5639
commit 46da5c5019
16 changed files with 406 additions and 36 deletions

View file

@ -14,7 +14,7 @@
package nu.zoom.dsl.cli;
import nu.zoom.dsl.ast.DocumentNode;
import nu.zoom.dsl.ast.ParserWrapper;
import nu.zoom.dsl.run.*;
import nu.zoom.dsl.freemarker.Generator;
import picocli.CommandLine;
import picocli.CommandLine.Command;
@ -24,8 +24,8 @@ 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.List;
import java.util.Optional;
import java.util.concurrent.Callable;
@Command(
@ -34,20 +34,16 @@ import java.util.concurrent.Callable;
description = "Generate source code from an endpoints specification file."
)
public class EndpointsCLI implements Callable<Integer> {
public enum ParserType {
Endpoints,
States
}
@SuppressWarnings("unused")
@Parameters(index = "0", description = "The source endpoints DSL file.")
private Path file;
@SuppressWarnings("CanBeFinal")
@Option(names = {"-t", "--template"}, defaultValue = "endpoints-template", description = "The template directory. Default is ${DEFAULT-VALUE}")
@Option(names = {"-t", "--template"}, defaultValue = Runner.DEFAULT_TEMPLATE_DIRECTORY_NAME, description = "The template directory. Default is ${DEFAULT-VALUE}")
private Path templateDir ;
@SuppressWarnings("CanBeFinal")
@Option(names = {"-o", "--output"}, defaultValue = "endpoints-output", description = "The directory to write the generated code to. Default is ${DEFAULT-VALUE}")
@Option(names = {"-o", "--output"}, defaultValue = Runner.DEFAULT_OUTPUT_DIRECTORY_NAME, description = "The directory to write the generated code to. Default is ${DEFAULT-VALUE}")
private Path outputDir ;
@SuppressWarnings("unused")
@ -55,7 +51,7 @@ public class EndpointsCLI implements Callable<Integer> {
private Boolean verbose = false;
@Option(names = {"-p", "--parser"}, description = "Force use of a specific parser instead of determining from filename. Valid values: ${COMPLETION-CANDIDATES}.")
private ParserType parser = null;
private Runner.ParserType parser = null;
public static void main(String[] args) {
int exitCode = new CommandLine(new EndpointsCLI()).execute(args);
@ -65,32 +61,14 @@ public class EndpointsCLI implements Callable<Integer> {
@Override
public Integer call() {
try {
validateTemplateDirectory();
validateInputFile();
validateOutputDirectory();
verbose("Parsing: " + file.toAbsolutePath());
if (parser == null) {
if (file.getFileName().toString().endsWith(".states")) {
parser = ParserType.States;
}
}
final DocumentNode rootNode ;
if (parser == ParserType.States) {
verbose("using state grammar.") ;
rootNode = ParserWrapper.parseStates(file);
} else {
verbose("using endpoints grammar.") ;
rootNode = ParserWrapper.parseEndpoints(file);
}
verbose("AST: " + rootNode);
verbose("Generating from templates in: " + templateDir.toAbsolutePath());
Generator generator = new Generator(templateDir, rootNode, outputDir);
List<Path> generatedPaths = generator.generate();
if (generatedPaths.isEmpty()) {
System.out.println("No generated paths found.");
} else {
generatedPaths.forEach(p -> verbose("Generated: " + p.toAbsolutePath()));
}
final Logger logger = this.verbose ? new StdoutLogger() : new NullLogger() ;
Runner.run(
this.file,
Optional.of(this.templateDir),
Optional.of(this.outputDir),
parser == null ? Optional.empty() : Optional.of(parser),
logger
);
return 0;
} catch (Exception e) {
System.err.println(e.getMessage());

View file

@ -0,0 +1,15 @@
package nu.zoom.dsl.run;
public abstract class EndgenException extends Exception {
public EndgenException(String message, Throwable cause) {
super(message, cause);
}
public EndgenException(Throwable cause) {
super(cause);
}
public EndgenException(String message) {
super(message);
}
}

View file

@ -0,0 +1,15 @@
package nu.zoom.dsl.run;
public class GeneratorException extends EndgenException {
public GeneratorException(String message) {
super(message);
}
public GeneratorException(String message, Throwable cause) {
super(message, cause);
}
public GeneratorException(Throwable cause) {
super(cause);
}
}

View file

@ -0,0 +1,5 @@
package nu.zoom.dsl.run;
public interface Logger {
void println(String message);
}

View file

@ -0,0 +1,8 @@
package nu.zoom.dsl.run;
public class NullLogger implements Logger {
@Override
public void println(String message) {
}
}

View file

@ -0,0 +1,15 @@
package nu.zoom.dsl.run;
public class ParserException extends EndgenException {
public ParserException(String message) {
super(message);
}
public ParserException(String message, Throwable cause) {
super(message, cause);
}
public ParserException(Throwable cause) {
super(cause);
}
}

View file

@ -11,8 +11,11 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nu.zoom.dsl.ast;
package nu.zoom.dsl.run;
import nu.zoom.dsl.ast.DocumentNode;
import nu.zoom.dsl.ast.EndpointsVisitorTransformer;
import nu.zoom.dsl.ast.StatesVisitorTransformer;
import nu.zoom.dsl.parser.*;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;

View file

@ -0,0 +1,96 @@
package nu.zoom.dsl.run;
import freemarker.template.TemplateException;
import nu.zoom.dsl.ast.DocumentNode;
import nu.zoom.dsl.freemarker.Generator;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
public final class Runner {
public static final String DEFAULT_TEMPLATE_DIRECTORY_NAME = "endpoints-template";
public static final String DEFAULT_OUTPUT_DIRECTORY_NAME = "endpoints-output";
public static void run(
Path dsl,
Optional<Path> templates,
Optional<Path> output,
Optional<ParserType> maybeParser,
Logger logger
) throws ValidationException, IOException, GeneratorException {
Path templatesDir = templates.orElse(Paths.get(DEFAULT_TEMPLATE_DIRECTORY_NAME));
Path outputDir = output.orElse(Paths.get(DEFAULT_OUTPUT_DIRECTORY_NAME));
validateOutputDirectory(outputDir);
validateTemplateDirectory(templatesDir);
validateInputFile(dsl);
logger.println("Parsing: " + dsl.toAbsolutePath());
final ParserType parser =
maybeParser.orElseGet(
() -> {
if (dsl.getFileName().toString().endsWith(".states")) {
return ParserType.States;
} else {
return ParserType.Endpoints;
}
}
);
final DocumentNode rootNode;
if (parser == ParserType.States) {
logger.println("using state grammar.");
rootNode = ParserWrapper.parseStates(dsl);
} else {
logger.println("using endpoints grammar.");
rootNode = ParserWrapper.parseEndpoints(dsl);
}
logger.println("AST: " + rootNode);
logger.println("Generating from templates in: " + templatesDir.toAbsolutePath());
Generator generator = new Generator(templatesDir, rootNode, outputDir);
List<Path> generatedPaths = null;
try {
generatedPaths = generator.generate();
} catch (TemplateException e) {
throw new GeneratorException(e);
}
if (generatedPaths.isEmpty()) {
System.out.println("No generated paths found.");
} else {
generatedPaths.forEach(p -> logger.println("Generated: " + p.toAbsolutePath()));
}
}
private static void validateOutputDirectory(Path outputDir) throws IOException, ValidationException {
if (Files.notExists(outputDir)) {
Files.createDirectories(outputDir);
}
if (!Files.isDirectory(outputDir)) {
throw new ValidationException("Output directory: '" + outputDir + " 'is not a directory.");
}
}
private static void validateTemplateDirectory(Path templateDir) throws ValidationException {
if (!Files.isDirectory(templateDir)) {
throw new ValidationException("Template directory '" + templateDir + "' is not a directory.");
}
}
private static void validateInputFile(Path file) throws ValidationException {
if (Files.notExists(file)) {
throw new ValidationException("Input file '" + file + "' does not exist.");
}
if (!Files.isReadable(file) || !Files.isRegularFile(file)) {
throw new ValidationException("Input file '" + file + "' is not a readable file.");
}
}
public enum ParserType {
Endpoints,
States
}
}

View file

@ -0,0 +1,9 @@
package nu.zoom.dsl.run;
public class StdoutLogger implements Logger {
@Override
public void println(String message) {
System.out.println(message);
}
}

View file

@ -0,0 +1,15 @@
package nu.zoom.dsl.run;
public class ValidationException extends EndgenException {
public ValidationException(String message) {
super(message);
}
public ValidationException(String message, Throwable cause) {
super(message, cause);
}
public ValidationException(Throwable cause) {
super(cause);
}
}