Skip to content
Snippets Groups Projects
Commit 15c75a2b authored by Johannes Mey's avatar Johannes Mey Committed by René Schöne
Browse files

update preprocessor

parent 08e6ea11
No related branches found
No related tags found
No related merge requests found
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;
}
public static class CompilerException extends Exception {
CompilerException(String message) {
super(message);
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 + "'.");
}
CompilerException(String message, Throwable cause) {
super(message, cause);
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!");
}
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());
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