Commit 55ed9bd0 authored by Johannes Mey's avatar Johannes Mey
Browse files

initial commit for new version

parent ea4e069e
[submodule "src/main/jastadd/mustache"]
path = src/main/jastadd/mustache
url = ../mustache.git
apply plugin: 'java'
apply plugin: 'jastadd'
apply plugin: 'application'
apply plugin: "idea"
plugins {
id 'java-library'
id 'org.jastadd'
id 'java'
id 'idea'
id 'java-test-fixtures'
id 'com.github.ben-manes.versions' version '0.34.0'
}
sourceCompatibility = 1.8
mainClassName = 'org.jastadd.relast.compiler.RelastSourceToSourceCompiler'
targetCompatibility = 1.8
repositories {
jcenter()
}
buildscript {
repositories.jcenter()
dependencies {
classpath 'org.jastadd:jastaddgradle:1.13.3'
sourceSets {
model {
java {
srcDir "src/gen/java"
}
}
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.0'
testCompile 'org.assertj:assertj-core:3.12.1'
compile 'org.jastadd:jastadd:2.3.4'
runtime 'org.jastadd:jastadd:2.3.4'
compile group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
task modelJar(type: Jar) {
group = "build"
archiveBaseName = 'model'
from sourceSets.model.output
}
sourceSets {
main {
java.srcDir "src/gen/java"
java.srcDir "buildSrc/gen/java"
}
artifacts {
archives modelJar
}
dependencies {
modelImplementation group: 'org.jastadd', name: 'jastadd', version: '2.3.4'
modelImplementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
compileOnly files(modelJar.archiveFile.get())
api group: 'org.jastadd', name: 'jastadd', version: '2.3.4'
api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
implementation group: 'com.github.jknack', name: 'handlebars', version: '4.2.0'
implementation group: 'org.yaml', name: 'snakeyaml', version: '1.27'
// test
testRuntimeClasspath files(modelJar.archiveFile.get())
// test fixtures
testFixturesApi group: 'org.slf4j', name: 'slf4j-jdk14', version: '1.7.30'
testFixturesApi group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.0'
testFixturesApi group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
testFixturesApi group: 'org.assertj', name: 'assertj-core', version: '3.18.0'
testFixturesApi group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.12.0-rc1'
testFixturesApi group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.12.0-rc1'
}
test {
......@@ -41,61 +61,47 @@ test {
maxHeapSize = '1G'
}
jar {
manifest {
attributes "Main-Class": 'org.jastadd.relast.compiler.RelastSourceToSourceCompiler'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
// Input and output files for relast
def relastInputFiles = [
"src/main/jastadd/RelAst.relast",
"src/main/jastadd/mustache/Mustache.relast"
]
def relastOutputFiles = [
"src/gen/jastadd/RelAst.ast",
"src/gen/jastadd/RelAst.jadd",
"src/gen/jastadd/RelAstRefResolver.jadd",
"src/gen/jastadd/RelAstResolverStubs.jrag"
]
task relast(type: JavaExec) {
classpath = files("libs/relast.jar")
group = 'Build'
main = "-jar"
doFirst {
delete "src/gen/jastadd/*.ast"
delete "src/gen/jastadd/RelAst.jadd"
delete "src/gen/jastadd/RelAstRefResolver.jadd"
delete "src/gen/jastadd/RelAstResolverStubs.jrag"
mkdir "src/gen/jastadd/"
delete relastOutputFiles
mkdir "src/gen/jastadd/"
}
args = [
"libs/relast.jar",
"./src/main/jastadd/RelAst.relast",
"--listClass=java.util.ArrayList",
"--jastAddList=JastAddList",
"--useJastAddNames",
"--file",
"--resolverHelper",
"--grammarName=./src/gen/jastadd/RelAst"
]
inputs.files file("../libs/relast.jar"),
file("src/main/jastadd/RelAst.relast")
outputs.files file("./src/gen/jastadd/RelAst.ast"),
file("src/gen/jastadd/RelAst.jadd"),
file("src/gen/jastadd/RelAstRefResolver.jadd"),
file('src/gen/jastadd/RelAstResolverStubs.jrag')
] + relastInputFiles
inputs.files relastInputFiles
outputs.files relastOutputFiles
}
jastadd {
configureModuleBuild()
modules {
//noinspection GroovyAssignabilityCheck
module("RelAst") {
java {
basedir "."
include "src/main/**/*.java"
include "src/gen/**/*.java"
}
module("Preprocessor") {
jastadd {
basedir "."
include "src/main/jastadd/**/*.ast"
include "src/main/jastadd/**/*.jadd"
include "src/main/jastadd/**/*.jrag"
......@@ -105,10 +111,10 @@ jastadd {
}
scanner {
include "src/main/jastadd/scanner/Header.flex", [-4]
include "src/main/jastadd/scanner/Preamble.flex", [-3]
include "src/main/jastadd/scanner/Macros.flex", [-2]
include "src/main/jastadd/scanner/RulesPreamble.flex", [-1]
include "src/main/jastadd/scanner/Header.flex", [-4]
include "src/main/jastadd/scanner/Preamble.flex", [-3]
include "src/main/jastadd/scanner/Macros.flex", [-2]
include "src/main/jastadd/scanner/RulesPreamble.flex", [-1]
include "src/main/jastadd/scanner/Keywords.flex", [0]
include "src/main/jastadd/scanner/Symbols.flex", [1]
include "src/main/jastadd/scanner/RulesPostamble.flex", [2]
......@@ -122,8 +128,8 @@ jastadd {
}
cleanGen.doFirst {
delete "src/gen/java/org"
delete "src/gen-res/BuildInfo.properties"
delete "src/gen"
delete "src/gen-res"
}
preprocessParser.doFirst {
......@@ -132,7 +138,7 @@ jastadd {
}
module = "RelAst"
module = "Preprocessor"
astPackage = 'org.jastadd.relast.ast'
......@@ -149,3 +155,11 @@ jastadd {
}
generateAst.dependsOn relast
clean.dependsOn(cleanGen)
modelJar.dependsOn(generateAst, modelClasses)
modelClasses.dependsOn(generateAst)
compileJava.dependsOn(modelJar)
jar.dependsOn(modelJar)
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
No preview for this file type
pluginManagement {
plugins {
id 'org.jastadd' version '1.13.3'
}
}
Subproject commit c10bed0d03e3fa18b8133ce1de48de7646899615
......@@ -32,56 +32,80 @@ import org.jastadd.option.Option;
import java.io.PrintStream;
import java.util.*;
import java.util.stream.Collectors;
/**
* Tracks JastAdd configuration options.
*
* @author Jesper Öqvist <jesper.oqvist@cs.lth.se>
*/
public class JastAddConfiguration extends org.jastadd.Configuration {
public class PreprocessorConfiguration extends org.jastadd.Configuration {
/**
* Indicates if there were unknown command-line options
*/
final boolean unknownOptions;
private boolean isJastAddCompliant;
public boolean isJastAddCompliant() {
return isJastAddCompliant;
}
private final Map<String, Option<?>> options = new HashMap<>();
private final boolean isJastAddCompliant;
private final ArgumentParser argParser;
/**
* Parse options from an argument list.
*
* @param args Command-line arguments to build configuration from
* @param err output stream to print configuration warnings to
*/
public JastAddConfiguration(String[] args, PrintStream err, boolean isJastAddCompliant, Collection<Option<?>> extraOptions) {
ArgumentParser argParser = new ArgumentParser();
public PreprocessorConfiguration(String[] args, PrintStream err, boolean isJastAddCompliant, Collection<Option<?>> extraOptions) {
argParser = new ArgumentParser();
this.isJastAddCompliant = isJastAddCompliant;
if (isJastAddCompliant) {
Collection<Option<?>> jastAddOptions = allJastAddOptions();
for (Option<?> o : jastAddOptions) {
options.put(o.name(), o);
}
argParser.addOptions(jastAddOptions);
}
// if the JastAdd options are supported, we have to check for duplicates!
Set<String> jastAddOptionNames = jastAddOptions.stream().map(o -> o.name()).collect(Collectors.toSet());
for (Option option : extraOptions) {
if (jastAddOptionNames.contains(option.name())) {
System.err.println("Unable to add option '" + option.name() + "', because there is a JastAdd option with the same name.");
} else {
argParser.addOption(option);
}
// if the JastAdd options are supported, we have to check for duplicates!
for (Option option : extraOptions) {
if (options.containsKey(option.name())) {
System.err.println("Unable to add option '" + option.name() + "', because there is a JastAdd option with the same name.");
} else {
argParser.addOption(option);
options.put(option.name(), option);
}
} else {
argParser.addOptions(extraOptions);
}
unknownOptions = !argParser.parseArgs(args, err);
filenames = argParser.getFilenames();
}
public ArgumentParser getArgParser() {
return argParser;
}
public Optional<Option> getOption(String name) {
return options.containsKey(name) ? Optional.of(options.get(name)) : Optional.empty();
}
public boolean isJastAddCompliant() {
return isJastAddCompliant;
}
/**
* Print help
*
* @param out Output stream to print help to.
*/
@Override
public void printHelp(PrintStream out) {
out.println("This program reads a number of .jrag, .jadd, and .ast files");
out.println("Options:");
argParser.printHelp(out);
out.println();
out.println("Arguments:");
out.println(" Names of abstract grammr (.ast) and aspect (.jrag and .jadd) files.");
}
/**
* @return all files
*/
......
package org.jastadd.relast.compiler;
import org.jastadd.JastAddConfiguration;
import org.jastadd.PreprocessorConfiguration;
import org.jastadd.option.FlagOption;
import org.jastadd.option.Option;
import java.util.ArrayList;
......@@ -8,20 +9,16 @@ import java.util.ArrayList;
public abstract class AbstractCompiler {
private final boolean jastAddCompliant;
protected ArrayList<Option<?>> options;
private final String name;
private JastAddConfiguration configuration;
protected ArrayList<Option<?>> options;
private PreprocessorConfiguration configuration;
public AbstractCompiler(String name, boolean jastaddCompliant) {
this.name = name;
this.jastAddCompliant = jastaddCompliant;
}
public JastAddConfiguration getConfiguration() throws CompilerException {
if (configuration == null) {
throw new CompilerException("Configuration only supported for JastAdd-compliant compilers!");
}
public PreprocessorConfiguration getConfiguration() {
return configuration;
}
......@@ -29,7 +26,12 @@ public abstract class AbstractCompiler {
options = new ArrayList<>();
initOptions();
configuration = new JastAddConfiguration(args, System.err, jastAddCompliant, options);
configuration = new PreprocessorConfiguration(args, System.err, jastAddCompliant, options);
if (configuration.shouldPrintHelp()) {
configuration.printHelp(System.out);
return 0;
}
return compile();
}
......@@ -37,10 +39,13 @@ public abstract class AbstractCompiler {
protected abstract int compile() throws CompilerException;
protected void initOptions() {
// there are no options by default
if (!jastAddCompliant) {
addOption(new FlagOption("version", "print version info"));
addOption(new FlagOption("help", "print command-line usage info"));
}
}
protected <OptionType extends Option<?>> OptionType addOption(OptionType option) {
protected <O extends Option<?>> O addOption(O option) {
options.add(option);
return option;
}
......
package org.jastadd.relast.compiler;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.io.ClassPathTemplateLoader;
import com.github.jknack.handlebars.io.TemplateLoader;
import org.yaml.snakeyaml.Yaml;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Mustache {
public static void javaMustache(String templateFileName, String yamlFileName, String outputFileName) throws IOException {
Object context = new Yaml().load(new FileReader(yamlFileName));
TemplateLoader loader = new ClassPathTemplateLoader();
loader.setSuffix(".mustache"); // the default is ".hbs"
Handlebars handlebars = new Handlebars(loader);
handlebars.prettyPrint(true); // set handlebars to mustache mode (skip some whitespace)
Template template = handlebars.compile(templateFileName);
try (Writer w = new FileWriter(outputFileName)) {
template.apply(context, w);
w.flush();
}
}
}
package org.jastadd.relast.compiler;
import org.jastadd.option.ValueOption;
import org.jastadd.relast.ast.GrammarFile;
import org.jastadd.relast.ast.Program;
import org.jastadd.relast.parser.RelAstParser;
import org.jastadd.relast.scanner.RelAstScanner;
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.Collection;
import java.util.Optional;
public abstract class RelAstProcessor extends AbstractCompiler {
protected ValueOption optionOutputBaseDir;
protected ValueOption optionInputBaseDir;
public RelAstProcessor(String name, boolean jastAddCompliant) {
super(name, jastAddCompliant);
}
protected static boolean isGrammarFile(String fileName) {
String extension = fileName.subSequence(fileName.lastIndexOf('.'), fileName.length()).toString();
return extension.equals(".relast") || extension.equals(".ast");
}
@Override
protected void initOptions() {
optionOutputBaseDir = addOption(new ValueOption("outputBaseDir", "base directory for generated files"));
optionInputBaseDir = addOption(new ValueOption("inputBaseDir", "base directory for input files"));
super.initOptions();
}
@Override
protected int compile() throws CompilerException {
final Path inputBasePath;
if (optionInputBaseDir.isMatched()) {
inputBasePath = Paths.get(optionInputBaseDir.value()).toAbsolutePath();
} else {
inputBasePath = Paths.get(".").toAbsolutePath();
printMessage("No input base dir is set. Assuming current directory '" + inputBasePath.toAbsolutePath().toString() + "'.");
}
if (!inputBasePath.toFile().exists()) {
printMessage("Input path '" + inputBasePath.toAbsolutePath().toString() + "' does not exist. Exiting...");
System.exit(-1);
} else if (!inputBasePath.toFile().isDirectory()) {
printMessage("Input path '" + inputBasePath.toAbsolutePath().toString() + "' is not a directory. Exiting...");
System.exit(-1);
}
final Path outputBasePath;
if (optionOutputBaseDir.isMatched()) {
outputBasePath = Paths.get(optionOutputBaseDir.value()).toAbsolutePath();
} else {
throw new CompilerException("No output base dir is set.");
}
if (outputBasePath.toFile().exists() && !outputBasePath.toFile().isDirectory()) {
printMessage("Output path '" + inputBasePath.toAbsolutePath().toString() + "' exists, but is not a directory. Exiting...");
}
printMessage("Running " + getName());
// gather all files
Collection<Path> inputFiles = new ArrayList<>();
getConfiguration().getFiles().forEach(name -> relativizeFileName(inputBasePath, Paths.get(name)).ifPresent(inputFiles::add));
Program program = parseProgram(inputFiles);
return processGrammar(program, inputBasePath, outputBasePath);
}
protected abstract int processGrammar(Program program, Path inputBasePath, Path outputBasePath) throws CompilerException;
private Optional<Path> relativizeFileName(Path inputBasePath, Path filePath) {
if (filePath.isAbsolute()) {
if (filePath.startsWith(inputBasePath)) {
return Optional.of(filePath.relativize(inputBasePath));
} else {
printMessage("Path '" + filePath + "' is not contained in the base path '" + inputBasePath + "'.");
return Optional.empty();
}
} else {
return Optional.of(inputBasePath.resolve(filePath));
}
}
protected void printMessage(String message) {
System.out.println(message);
}
protected void writeToFile(Path path, String str) throws CompilerException {
//noinspection ResultOfMethodCallIgnored
path.getParent().toFile().mkdirs(); // create directory structure if necessary
try (PrintWriter writer = new PrintWriter(path.toFile())) {
writer.print(str);
} catch (Exception e) {
throw new CompilerException("Could not write to file " + path, e);
}
}
private Program parseProgram(Collection<Path> inputFiles) {
Program program = new Program();
RelAstParser parser = new RelAstParser();
inputFiles.stream().filter(path -> isGrammarFile(path.toString())).forEach(
path -> {
try (BufferedReader reader = Files.newBufferedReader(path)) {
RelAstScanner scanner = new RelAstScanner(reader);
GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner);
inputGrammar.setFileName(path.toString());
program.addGrammarFile(inputGrammar);
inputGrammar.treeResolveAll();
} catch (IOException | beaver.Parser.Exception e) {
printMessage("Could not parse grammar file " + path);
e.printStackTrace();
}
}
);
return program;
}
}
package org.jastadd.relast.compiler;
import beaver.Parser;
import org.jastadd.option.ValueOption;
import org.jastadd.relast.ast.GrammarFile;
import org.jastadd.relast.ast.Program;
import org.jastadd.relast.parser.RelAstParser;
import org.jastadd.relast.scanner.RelAstScanner;
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.Collection;
import java.util.Optional;
public class RelastSourceToSourceCompiler extends AbstractCompiler {
public class RelastSourceToSourceCompiler extends RelAstProcessor {
protected ValueOption optionOutputBaseDir;
protected ValueOption optionInputBaseDir;
public RelastSourceToSourceCompiler(String name, boolean jastAddCompliant) {
super(name, jastAddCompliant);
}
......@@ -42,103 +28,16 @@ public class RelastSourceToSourceCompiler extends AbstractCompiler {
}
@Override
protected void initOptions() {
optionOutputBaseDir = addOption(new ValueOption("outputBaseDir", "base directory for generated files"));
optionInputBaseDir = addOption(new ValueOption("inputBaseDir", "base directory for input files"));
}
@Override
protected int compile() throws CompilerException {
final Path inputBasePath;
if (optionInputBaseDir.isMatched()) {
inputBasePath = Paths.get(optionInputBaseDir.value()).toAbsolutePath();
<