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 {
}
dependencies {
implementation project(':relast.preprocessor')
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'
runtime group: 'org.jastadd', name: 'jastadd', version: '2.3.4'
......
......@@ -9,68 +9,11 @@ aspect Navigation {
eq Relast2Uml.getChild().relast2uml() = this;
eq MRelast2Uml.getChild().relast2uml() = getRelast2Uml();
// --- containedFile (first equation should be in preprocessor) ---
eq Program.getChild().containedFile() = null;
// --- containedFile ---
eq Relast2Uml.getChild().containedFile() = null;
// --- isTypeDecl (should be in preprocessor) ---
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();
// --- containedFileName ---
eq Relast2Uml.getChild().containedFileName() = getFileName();
eq Program.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;
%yylexthrow beaver.Scanner.Exception
%scanerror Relast2UmlScanner.ScannerError
%x COMMENT
%s DECLARATION
%line
%column
"folder" { return sym(Terminals.FOLDER); }
"folder" { yybegin(DECLARATION); return sym(Terminals.FOLDER); }
package org.jastadd.relast2uml.compiler;
import beaver.Parser;
import org.jastadd.relast2uml.ast.*;
import org.jastadd.relast2uml.compiler.options.CommandLine;
import org.jastadd.relast2uml.compiler.options.FlagOption;
import org.jastadd.relast2uml.compiler.options.Option;
import org.jastadd.relast2uml.compiler.options.StringOption;
import org.jastadd.option.BooleanOption;
import org.jastadd.option.ValueOption;
import org.jastadd.relast.compiler.AbstractCompiler;
import org.jastadd.relast.compiler.CompilerException;
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.scanner.Relast2UmlScanner;
......@@ -13,93 +16,22 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
public class Compiler {
public class Compiler extends AbstractCompiler {
private StringOption optionOutputFile;
private StringOption optionInputRelast2Uml;
private FlagOption optionDefaultFolders;
private FlagOption optionHelp;
private FlagOption optionVersion;
private FlagOption optionVerbose;
private ArrayList<Option<?>> options;
private CommandLine commandLine;
private ValueOption optionOutputFile;
private ValueOption optionInputRelast2Uml;
private BooleanOption optionDefaultFolders;
private BooleanOption optionHelp;
private BooleanOption optionVersion;
private BooleanOption optionVerbose;
public Compiler() {
options = new ArrayList<>();
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());
super("relast2uml", false);
}
/**
......@@ -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) {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("mustache.debug", "true");
try {
new Compiler().run(args);
} catch (CommandLine.CommandLineException | CompilerException e) {
} catch (CompilerException e) {
System.err.println(e.getMessage());
System.exit(-1);
}
......@@ -158,38 +79,42 @@ public class Compiler {
}
}
private void addOptions() {
optionOutputFile = addOption(new StringOption(
"output", "target file to be generated.", "uml.md").makeOptional());
optionInputRelast2Uml = addOption(new StringOption(
"inputRelast2Uml", "relast2uml definition file.").makeOptional());
optionDefaultFolders = addOption(new FlagOption(
"defaultFolders", "Creates a default folder per grammar file."));
optionHelp = addOption(new FlagOption(
"help", "Print usage and exit."));
optionVersion = addOption(new FlagOption(
"help", "Print version and exit."));
optionVerbose = addOption(new FlagOption(
"verbose", "Print more messages while compiling."));
}
private <OptionType extends Option<?>> OptionType addOption(OptionType option) {
options.add(option);
return option;
protected void initOptions() {
optionOutputFile = addOption(
new ValueOption("output", "target file to be generated.")
.defaultValue("uml.md")
.acceptAnyValue()
.needsValue(false));
optionInputRelast2Uml = addOption(
new ValueOption("inputRelast2Uml", "relast2uml definition file.")
.needsValue(true));
optionDefaultFolders = addOption(
new BooleanOption("defaultFolders",
"Creates a default folder per grammar file.")
.defaultValue(false));
optionHelp = addOption(
new BooleanOption("help", "Print usage and exit.")
.defaultValue(false));
optionVersion = addOption(
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 {
Program program = new Program();
Relast2Uml relast2Uml;
for (String inputGrammarFileName : commandLine.getArguments()) {
for (String inputGrammarFileName : getConfiguration().getFiles()) {
printMessage("Parsing " + inputGrammarFileName);
GrammarFile inputGrammar;
try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputGrammarFileName))) {
Relast2UmlScanner scanner = new Relast2UmlScanner(reader);
Relast2UmlParser parser = new Relast2UmlParser();
inputGrammar = (GrammarFile) parser.parse(scanner);
if (optionVerbose.isSet()) {
if (optionVerbose.value()) {
inputGrammar.dumpTree(System.out);
}
program.addGrammarFile(inputGrammar);
......@@ -199,8 +124,8 @@ public class Compiler {
}
}
if (optionInputRelast2Uml.isSet()) {
String inputRelast2UmlFileName = optionInputRelast2Uml.getValue();
if (optionInputRelast2Uml.isMatched()) {
String inputRelast2UmlFileName = optionInputRelast2Uml.value();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(inputRelast2UmlFileName))) {
Relast2UmlScanner scanner = new Relast2UmlScanner(reader);
Relast2UmlParser parser = new Relast2UmlParser();
......@@ -216,7 +141,7 @@ public class Compiler {
}
relast2Uml.setProgram(program);
relast2Uml.treeResolveAll();
if (optionDefaultFolders.isSet()) {
if (optionDefaultFolders.value()) {
for (GrammarFile grammarFile : program.getGrammarFileList()) {
relast2Uml.addFolder(grammarFile.defaultFolder());
}
......@@ -224,18 +149,49 @@ public class Compiler {
return relast2Uml;
}
protected void printUsage() {
System.out.println("Usage: java -jar relast2uml.jar [--option1] [--option2=value] ... <filename1> <filename2> ... ");
System.out.println("Options:");
System.out.print(commandLine.printOptionHelp());
@Override
protected int compile() throws CompilerException {
if (optionVersion.value()) {
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 {
CompilerException(String message) {
super(message);
Relast2Uml relast2uml = parseProgram();
if (!relast2uml.errors().isEmpty()) {
System.err.println("Errors:");
for (ErrorMessage e : relast2uml.errors()) {
System.err.println(e);
}
CompilerException(String message, Throwable cause) {
super(message, cause);
System.exit(1);
}
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;
import org.jastadd.relast.compiler.CompilerException;
import org.jastadd.relast2uml.compiler.Compiler;
import org.jastadd.relast2uml.compiler.options.CommandLine;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.nio.file.Paths;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
......@@ -18,7 +17,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
*/
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() + "'.");
assertTrue(Paths.get(inputGrammar).toFile().exists(), "input grammar does not exist");
......@@ -43,7 +43,7 @@ public class CompilerTest {
}
@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");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment