Skip to content
Snippets Groups Projects
Commit 7cc0554b authored by René Schöne's avatar René Schöne
Browse files

Merge branch 'update-preprocessor' into 'master'

update preprocessor

See merge request jastadd/relast2uml!1
parents 08e6ea11 15c75a2b
No related branches found
No related tags found
1 merge request!1update preprocessor
Pipeline #7387 passed
Showing
with 101 additions and 488 deletions
Subproject commit 54af6737685fab0be452f446b70b9842aba89e42 Subproject commit 79d237fda220364ffebf77dc7de0a7b29635e360
...@@ -17,6 +17,8 @@ buildscript { ...@@ -17,6 +17,8 @@ buildscript {
} }
dependencies { dependencies {
implementation project(':relast.preprocessor')
implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.9.6' implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: '0.9.6'
implementation group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.11.2' implementation group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.11.2'
runtime group: 'org.jastadd', name: 'jastadd', version: '2.3.4' runtime group: 'org.jastadd', name: 'jastadd', version: '2.3.4'
......
...@@ -9,68 +9,11 @@ aspect Navigation { ...@@ -9,68 +9,11 @@ aspect Navigation {
eq Relast2Uml.getChild().relast2uml() = this; eq Relast2Uml.getChild().relast2uml() = this;
eq MRelast2Uml.getChild().relast2uml() = getRelast2Uml(); eq MRelast2Uml.getChild().relast2uml() = getRelast2Uml();
// --- containedFile (first equation should be in preprocessor) --- // --- containedFile ---
eq Program.getChild().containedFile() = null;
eq Relast2Uml.getChild().containedFile() = null; eq Relast2Uml.getChild().containedFile() = null;
// --- isTypeDecl (should be in preprocessor) --- // --- containedFileName ---
syn boolean Declaration.isTypeDecl() = false;
eq TypeDecl.isTypeDecl() = true;
// --- asTypeDecl (should be in preprocessor) ---
syn TypeDecl Declaration.asTypeDecl() = null;
eq TypeDecl.asTypeDecl() = this;
// --- isTypeComponent (should be in preprocessor) ---
syn boolean Component.isTypeComponent() = false;
eq TypeComponent.isTypeComponent() = true;
// --- asTypeComponent (should be in preprocessor) ---
syn TypeComponent Component.asTypeComponent() = null;
eq TypeComponent.asTypeComponent() = this;
// --- isNormalComponent (should be in preprocessor) ---
syn boolean Component.isNormalComponent() = false;
eq NormalComponent.isNormalComponent() = true;
// --- asNormalComponent (should be in preprocessor) ---
syn NormalComponent Component.asNormalComponent() = null;
eq NormalComponent.asNormalComponent() = this;
// --- isListComponent (should be in preprocessor) ---
syn boolean Component.isListComponent() = false;
eq ListComponent.isListComponent() = true;
// --- asListComponent (should be in preprocessor) ---
syn ListComponent Component.asListComponent() = null;
eq ListComponent.asListComponent() = this;
// --- isDirectedRelation (should be in preprocessor) ---
syn boolean Relation.isDirectedRelation() = false;
eq DirectedRelation.isDirectedRelation() = true;
// --- asDirectedRelation (should be in preprocessor) ---
syn DirectedRelation Relation.asDirectedRelation() = null;
eq DirectedRelation.asDirectedRelation() = this;
// --- asBidirectionalRelation (should be in preprocessor) ---
syn BidirectionalRelation Relation.asBidirectionalRelation() = null;
eq BidirectionalRelation.asBidirectionalRelation() = this;
// --- isListRole (should be in preprocessor) ---
syn boolean Role.isListRole() = false;
eq ListRole.isListRole() = true;
// --- containedFileName (should replace containedFile in preprocessor) ---
inh String ASTNode.containedFileName();
eq GrammarFile.getChild().containedFileName() = getFileName();
eq Relast2Uml.getChild().containedFileName() = getFileName(); eq Relast2Uml.getChild().containedFileName() = getFileName();
eq Program.getChild().containedFileName() = null; eq Program.getChild().containedFileName() = null;
eq MRelast2Uml.getChild().containedFileName() = null; eq MRelast2Uml.getChild().containedFileName() = null;
// --- allTokenComponents ---
coll java.util.Set<TokenComponent> Program.allTokenComponents() [new java.util.HashSet<>()] root Program;
TokenComponent contributes this
to Program.allTokenComponents()
for program();
} }
...@@ -13,5 +13,8 @@ import org.jastadd.relast2uml.parser.Relast2UmlParser.Terminals; ...@@ -13,5 +13,8 @@ import org.jastadd.relast2uml.parser.Relast2UmlParser.Terminals;
%yylexthrow beaver.Scanner.Exception %yylexthrow beaver.Scanner.Exception
%scanerror Relast2UmlScanner.ScannerError %scanerror Relast2UmlScanner.ScannerError
%x COMMENT
%s DECLARATION
%line %line
%column %column
"folder" { return sym(Terminals.FOLDER); } "folder" { yybegin(DECLARATION); return sym(Terminals.FOLDER); }
package org.jastadd.relast2uml.compiler; package org.jastadd.relast2uml.compiler;
import beaver.Parser; import beaver.Parser;
import org.jastadd.relast2uml.ast.*; import org.jastadd.option.BooleanOption;
import org.jastadd.relast2uml.compiler.options.CommandLine; import org.jastadd.option.ValueOption;
import org.jastadd.relast2uml.compiler.options.FlagOption; import org.jastadd.relast.compiler.AbstractCompiler;
import org.jastadd.relast2uml.compiler.options.Option; import org.jastadd.relast.compiler.CompilerException;
import org.jastadd.relast2uml.compiler.options.StringOption; import org.jastadd.relast2uml.ast.ErrorMessage;
import org.jastadd.relast2uml.ast.GrammarFile;
import org.jastadd.relast2uml.ast.Program;
import org.jastadd.relast2uml.ast.Relast2Uml;
import org.jastadd.relast2uml.parser.Relast2UmlParser; import org.jastadd.relast2uml.parser.Relast2UmlParser;
import org.jastadd.relast2uml.scanner.Relast2UmlScanner; import org.jastadd.relast2uml.scanner.Relast2UmlScanner;
...@@ -13,93 +16,22 @@ import java.io.BufferedReader; ...@@ -13,93 +16,22 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class Compiler { public class Compiler extends AbstractCompiler {
private StringOption optionOutputFile; private ValueOption optionOutputFile;
private StringOption optionInputRelast2Uml; private ValueOption optionInputRelast2Uml;
private FlagOption optionDefaultFolders; private BooleanOption optionDefaultFolders;
private FlagOption optionHelp; private BooleanOption optionHelp;
private FlagOption optionVersion; private BooleanOption optionVersion;
private FlagOption optionVerbose; private BooleanOption optionVerbose;
private ArrayList<Option<?>> options;
private CommandLine commandLine;
public Compiler() { public Compiler() {
options = new ArrayList<>(); super("relast2uml", false);
addOptions();
}
public void run(String[] args) throws CommandLine.CommandLineException, CompilerException {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("mustache.debug", "true");
options = new ArrayList<>();
addOptions();
commandLine = new CommandLine(options);
commandLine.parse(args);
if (optionHelp.isSet()) {
printUsage();
return;
}
if (optionVersion.isSet()) {
System.out.println(readVersion());
return;
}
if (optionVerbose.isSet()) {
try {
run();
} catch (CompilerException e) {
e.printStackTrace();
throw e;
}
} else {
run();
}
}
private void run() throws CompilerException {
printMessage("Running relast2uml " + readVersion());
String output;
if (optionOutputFile.isSet()) {
output = optionOutputFile.getValue();
} else {
output = "uml.md";
System.out.println("No output output file is set. Assuming '" + output + "'.");
}
try {
Files.createDirectories(Paths.get(output).toAbsolutePath().getParent());
} catch (IOException e) {
throw new CompilerException("Error creating output dir " + Paths.get(output).getParent().toAbsolutePath(), e);
}
if (anyRequiredOptionIsUnset()) {
throw new CompilerException("Aborting due to missing values for required options.");
}
if (commandLine.getArguments().isEmpty()) {
throw new CompilerException("No input grammars specified!");
}
Relast2Uml relast2uml = parseProgram();
if (!relast2uml.errors().isEmpty()) {
System.err.println("Errors:");
for (ErrorMessage e : relast2uml.errors()) {
System.err.println(e);
}
System.exit(1);
}
printMessage("Writing output file " + output);
writeToFile(output, relast2uml.generateAspect());
} }
/** /**
...@@ -122,23 +54,12 @@ public class Compiler { ...@@ -122,23 +54,12 @@ public class Compiler {
} }
} }
private boolean anyRequiredOptionIsUnset() {
boolean foundError = false;
for (Option<?> option : options) {
if (option.hasArgument() == Option.HasArgument.YES && !option.isSet()) {
System.err.println("Option '" + option.getName() +
"' (" + option.getDescription() + ") is required but unset!");
foundError = true;
}
}
return foundError;
}
public static void main(String[] args) { public static void main(String[] args) {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("mustache.debug", "true");
try { try {
new Compiler().run(args); new Compiler().run(args);
} catch (CommandLine.CommandLineException | CompilerException e) { } catch (CompilerException e) {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
System.exit(-1); System.exit(-1);
} }
...@@ -158,38 +79,42 @@ public class Compiler { ...@@ -158,38 +79,42 @@ public class Compiler {
} }
} }
private void addOptions() { protected void initOptions() {
optionOutputFile = addOption(new StringOption( optionOutputFile = addOption(
"output", "target file to be generated.", "uml.md").makeOptional()); new ValueOption("output", "target file to be generated.")
optionInputRelast2Uml = addOption(new StringOption( .defaultValue("uml.md")
"inputRelast2Uml", "relast2uml definition file.").makeOptional()); .acceptAnyValue()
optionDefaultFolders = addOption(new FlagOption( .needsValue(false));
"defaultFolders", "Creates a default folder per grammar file.")); optionInputRelast2Uml = addOption(
optionHelp = addOption(new FlagOption( new ValueOption("inputRelast2Uml", "relast2uml definition file.")
"help", "Print usage and exit.")); .needsValue(true));
optionVersion = addOption(new FlagOption( optionDefaultFolders = addOption(
"help", "Print version and exit.")); new BooleanOption("defaultFolders",
optionVerbose = addOption(new FlagOption( "Creates a default folder per grammar file.")
"verbose", "Print more messages while compiling.")); .defaultValue(false));
} optionHelp = addOption(
new BooleanOption("help", "Print usage and exit.")
private <OptionType extends Option<?>> OptionType addOption(OptionType option) { .defaultValue(false));
options.add(option); optionVersion = addOption(
return option; new BooleanOption("help", "Print version and exit.")
.defaultValue(false));
optionVerbose = addOption(
new BooleanOption("verbose", "Print more messages while compiling.")
.defaultValue(false));
} }
private Relast2Uml parseProgram() throws CompilerException { private Relast2Uml parseProgram() throws CompilerException {
Program program = new Program(); Program program = new Program();
Relast2Uml relast2Uml; Relast2Uml relast2Uml;
for (String inputGrammarFileName : commandLine.getArguments()) { for (String inputGrammarFileName : getConfiguration().getFiles()) {
printMessage("Parsing " + inputGrammarFileName); printMessage("Parsing " + inputGrammarFileName);
GrammarFile inputGrammar; GrammarFile inputGrammar;
try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) { try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) {
Relast2UmlScanner scanner = new Relast2UmlScanner(reader); Relast2UmlScanner scanner = new Relast2UmlScanner(reader);
Relast2UmlParser parser = new Relast2UmlParser(); Relast2UmlParser parser = new Relast2UmlParser();
inputGrammar = (GrammarFile) parser.parse(scanner); inputGrammar = (GrammarFile) parser.parse(scanner);
if (optionVerbose.isSet()) { if (optionVerbose.value()) {
inputGrammar.dumpTree(System.out); inputGrammar.dumpTree(System.out);
} }
program.addGrammarFile(inputGrammar); program.addGrammarFile(inputGrammar);
...@@ -199,8 +124,8 @@ public class Compiler { ...@@ -199,8 +124,8 @@ public class Compiler {
} }
} }
if (optionInputRelast2Uml.isSet()) { if (optionInputRelast2Uml.isMatched()) {
String inputRelast2UmlFileName = optionInputRelast2Uml.getValue(); String inputRelast2UmlFileName = optionInputRelast2Uml.value();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputRelast2UmlFileName))) { try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputRelast2UmlFileName))) {
Relast2UmlScanner scanner = new Relast2UmlScanner(reader); Relast2UmlScanner scanner = new Relast2UmlScanner(reader);
Relast2UmlParser parser = new Relast2UmlParser(); Relast2UmlParser parser = new Relast2UmlParser();
...@@ -216,7 +141,7 @@ public class Compiler { ...@@ -216,7 +141,7 @@ public class Compiler {
} }
relast2Uml.setProgram(program); relast2Uml.setProgram(program);
relast2Uml.treeResolveAll(); relast2Uml.treeResolveAll();
if (optionDefaultFolders.isSet()) { if (optionDefaultFolders.value()) {
for (GrammarFile grammarFile : program.getGrammarFileList()) { for (GrammarFile grammarFile : program.getGrammarFileList()) {
relast2Uml.addFolder(grammarFile.defaultFolder()); relast2Uml.addFolder(grammarFile.defaultFolder());
} }
...@@ -224,18 +149,49 @@ public class Compiler { ...@@ -224,18 +149,49 @@ public class Compiler {
return relast2Uml; return relast2Uml;
} }
protected void printUsage() { @Override
System.out.println("Usage: java -jar relast2uml.jar [--option1] [--option2=value] ... <filename1> <filename2> ... "); protected int compile() throws CompilerException {
System.out.println("Options:"); if (optionVersion.value()) {
System.out.print(commandLine.printOptionHelp()); System.out.println(readVersion());
return 0;
}
if (optionHelp.value()) {
getConfiguration().printHelp(System.out);
return 0;
}
printMessage("Running relast2uml " + readVersion());
String output;
if (optionOutputFile.isMatched()) {
output = optionOutputFile.value();
} else {
output = "uml.md";
System.out.println("No output output file is set. Assuming '" + output + "'.");
}
Path parent = Paths.get(optionOutputFile.value()).toAbsolutePath().getParent();
try {
Files.createDirectories(parent);
} catch (IOException e) {
throw new CompilerException("Error creating output dir " + parent, e);
}
if (getConfiguration().getFiles().isEmpty()) {
throw new CompilerException("No input grammars specified!");
} }
public static class CompilerException extends Exception { Relast2Uml relast2uml = parseProgram();
CompilerException(String message) {
super(message); if (!relast2uml.errors().isEmpty()) {
System.err.println("Errors:");
for (ErrorMessage e : relast2uml.errors()) {
System.err.println(e);
} }
CompilerException(String message, Throwable cause) { System.exit(1);
super(message, cause);
} }
printMessage("Writing output file " + output);
writeToFile(output, relast2uml.generateAspect());
return 0;
} }
} }
package org.jastadd.relast2uml.compiler.options;
import java.util.*;
public class CommandLine {
private final Collection<Option<?>> options;
private final Map<String, Option<?>> mapping;
private final List<String> arguments;
public CommandLine(Collection<Option<?>> options) {
this.options = options;
this.mapping = new HashMap<>();
for (Option<?> option : options) {
mapping.put(option.getName(), option);
}
this.arguments = new ArrayList<>();
}
public void parse(String[] args) throws CommandLineException {
int i = 0;
while (i < args.length) {
if (args[i].startsWith(Option.PREFIX)) {
int argumentIndex = args[i].indexOf("=");
String name;
String argument = null;
if (argumentIndex > 0) {
name = args[i].substring(2, argumentIndex);
argument = args[i].substring(argumentIndex + 1);
} else {
name = args[i].substring(2);
}
Option<?> option = mapping.get(name);
if (option == null) {
throw new CommandLineException("Option " + Option.PREFIX + name + " not found");
}
match(option, argument);
} else {
arguments.add(args[i]);
}
i++;
}
}
public void match(Option<?> option, String argument) throws CommandLineException {
try {
switch (option.hasArgument()) {
case NO:
if (argument == null) {
option.match(null);
} else {
throw new CommandLineException("Option " + option + " is not allowed to have an argument");
}
break;
case OPTIONAL:
option.match(argument);
break;
case YES:
if (argument != null) {
option.match(argument);
} else {
throw new CommandLineException("Option " + option + " requires an argument");
}
break;
}
} catch (Option.IllegalMatchException e) {
throw new CommandLineException("Invalid value for option " + option + ": " + e.getMessage());
}
}
public List<String> getArguments() {
return arguments;
}
public String printOptionHelp() {
StringBuilder sb = new StringBuilder();
int longestOption = 0;
for (Option<?> option : options) {
if (longestOption < option.getName().length()) {
longestOption = option.getName().length();
}
}
for (Option<?> option : new TreeSet<>(options)) {
String s = String.format(" %s%-" + (longestOption + 6) + "s %s%n",
Option.PREFIX, option.getName(), option.getDescription());
sb.append(s);
}
return sb.toString();
}
public static class CommandLineException extends Exception {
private static final long serialVersionUID = 1L;
public CommandLineException(String message) {
super(message);
}
}
}
package org.jastadd.relast2uml.compiler.options;
import java.util.Collection;
import java.util.TreeSet;
public class EnumOption extends Option<String> {
private final TreeSet<String> allowedValues;
private final String defaultValue;
private String value;
private boolean isSet;
public EnumOption(String name, String description, Collection<String> allowedValues, String defaultValue) {
super(name, description);
this.allowedValues = new TreeSet<>(allowedValues);
this.defaultValue = defaultValue;
this.value = defaultValue;
this.isSet = false;
}
public boolean addAllowedValue(String allowedValue) {
return allowedValues.add(allowedValue);
}
@Override
public String getValue() {
return value;
}
@Override
public Option.HasArgument hasArgument() {
return Option.HasArgument.OPTIONAL;
}
@Override
public void match(String argument) throws IllegalMatchException {
if (argument == null) {
isSet = true;
value = defaultValue;
} else if (allowedValues.contains(argument)) {
isSet = true;
value = argument;
} else {
throw new IllegalMatchException(argument
+ " is not allowed, allowed values are " + allowedValues);
}
}
@Override
public boolean isSet() {
return isSet;
}
@Override
public String getDescription() {
String allowedValuesStr = allowedValues.toString();
allowedValuesStr = allowedValuesStr.substring(1);
allowedValuesStr = allowedValuesStr.substring(0, allowedValuesStr.length() - 1);
return super.getDescription() + " (allowed values: " + allowedValuesStr + ")";
}
}
package org.jastadd.relast2uml.compiler.options;
public class FlagOption extends Option<Boolean> {
private boolean value;
public FlagOption(String name, String description) {
super(name, description);
value = false;
}
@Override
public Boolean getValue() {
return value;
}
@Override
public Option.HasArgument hasArgument() {
return Option.HasArgument.NO;
}
@Override
public void match(String string) throws IllegalMatchException {
value = true;
}
@Override
public boolean isSet() {
return getValue();
}
}
package org.jastadd.relast2uml.compiler.options;
abstract public class Option<ValueType> implements Comparable<Option<?>> {
public final static String PREFIX = "--";
private final String name;
private final String description;
public Option(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public int compareTo(Option<?> o) {
return name.compareTo(o.name);
}
@Override
public boolean equals(Object other) {
if (other instanceof Option) {
return compareTo((Option<?>) other) == 0;
}
return false;
}
@Override
public String toString() {
return PREFIX + name;
}
abstract public boolean isSet();
abstract public ValueType getValue();
abstract public HasArgument hasArgument();
abstract public void match(String input) throws IllegalMatchException;
public enum HasArgument {
NO,
OPTIONAL,
YES
}
public static class IllegalMatchException extends Exception {
private static final long serialVersionUID = 1L;
public IllegalMatchException(String message) {
super(message);
}
}
}
package org.jastadd.relast2uml.compiler.options;
public class StringOption extends Option<String> {
private HasArgument hasArgument;
private String value;
private boolean isSet;
public StringOption(String name, String description) {
this(name, description, "");
}
public StringOption(String name, String description, String defaultValue) {
super(name, description);
value = defaultValue;
isSet = false;
hasArgument = HasArgument.YES;
}
public StringOption makeOptional() {
hasArgument = HasArgument.OPTIONAL;
return this;
}
@Override
public String getValue() {
return value;
}
@Override
public Option.HasArgument hasArgument() {
return hasArgument;
}
@Override
public void match(String value) {
this.value = value;
isSet = true;
}
@Override
public boolean isSet() {
return isSet;
}
}
package org.jastadd.relast2uml.test; package org.jastadd.relast2uml.test;
import org.jastadd.relast.compiler.CompilerException;
import org.jastadd.relast2uml.compiler.Compiler; import org.jastadd.relast2uml.compiler.Compiler;
import org.jastadd.relast2uml.compiler.options.CommandLine;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.File; import java.io.File;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
...@@ -18,7 +17,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; ...@@ -18,7 +17,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
*/ */
public class CompilerTest { public class CompilerTest {
void transform(String inputGrammar, String inputRelast2Uml, String output) throws CommandLine.CommandLineException, Compiler.CompilerException { @SuppressWarnings("SameParameterValue")
void transform(String inputGrammar, String inputRelast2Uml, String output) throws CompilerException {
System.out.println("Running test in directory '" + Paths.get(".").toAbsolutePath() + "'."); System.out.println("Running test in directory '" + Paths.get(".").toAbsolutePath() + "'.");
assertTrue(Paths.get(inputGrammar).toFile().exists(), "input grammar does not exist"); assertTrue(Paths.get(inputGrammar).toFile().exists(), "input grammar does not exist");
...@@ -43,7 +43,7 @@ public class CompilerTest { ...@@ -43,7 +43,7 @@ public class CompilerTest {
} }
@Test @Test
void transformMinimalExample() throws CommandLine.CommandLineException, Compiler.CompilerException { void transformMinimalExample() throws CompilerException {
transform("src/test/resources/Example.relast", "src/test/resources/Example.relast2uml", "src/test/resources/uml.md"); transform("src/test/resources/Example.relast", "src/test/resources/Example.relast2uml", "src/test/resources/uml.md");
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment