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

Split project into base and example.

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 1532 additions and 0 deletions
build
src/gen-res/
src/gen/
out/
*.class
apply plugin: 'jastadd'
apply plugin: 'application'
sourceCompatibility = 1.8
mainClassName = 'org.jastadd.ros2rag.compiler.Compiler'
repositories {
jcenter()
}
buildscript {
repositories.jcenter()
dependencies {
classpath 'org.jastadd:jastaddgradle:1.13.3'
}
}
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 "com.fasterxml.jackson.core:jackson-core:${jackson_version}"
compile "com.fasterxml.jackson.core:jackson-databind:${jackson_version}"
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'
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.10.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.10.0'
}
sourceSets {
main {
java.srcDir "src/gen/java"
java.srcDir "buildSrc/gen/java"
}
}
test {
useJUnitPlatform()
maxHeapSize = '1G'
}
jar {
manifest {
attributes "Main-Class": 'org.jastadd.ros2rag.compiler.Compiler'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
jastadd {
configureModuleBuild()
modules {
//noinspection GroovyAssignabilityCheck
module("RelAst") {
java {
basedir "."
include "src/main/**/*.java"
include "src/gen/**/*.java"
}
jastadd {
basedir "src/main/jastadd/"
include "**/*.ast"
include "**/*.jadd"
include "**/*.jrag"
}
scanner {
include "src/main/jastadd/RelAst.flex"
}
parser {
include "src/main/jastadd/Preamble.parser"
include "src/main/jastadd/RelAst.parser"
}
}
}
cleanGen.doFirst {
delete "src/gen/java/org"
delete "src/gen-res/BuildInfo.properties"
}
preprocessParser.doFirst {
args += ["--no-beaver-symbol"]
}
module = "RelAst"
astPackage = 'org.jastadd.ros2rag.ast'
parser.name = 'RelAstParser'
genDir = 'src/gen/java'
buildInfoDir = 'src/gen-res'
scanner.genDir = "src/gen/java/org/jastadd/ros2rag/scanner"
parser.genDir = "src/gen/java/org/jastadd/ros2rag/parser"
jastaddOptions = ["--lineColumnNumbers", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all"]
}
import java.util.*;
aspect TypeAnalysis {
public abstract TypeUse Component.getTypeUse();
//--- lookupType ---
syn TypeDecl TypeUse.decl() = lookupType(getID());
inh TypeDecl TypeUse.lookupType(String name);
inh TypeDecl TypeDecl.lookupType(String name);
eq Program.getChild().lookupType(String name) {
for (TypeDecl td : getTypeDecls()) {
if (td.getID().equals(name)) {
return td;
}
}
return null;
}
//--- isAlreadyDeclared ---
syn boolean TypeDecl.isAlreadyDeclared() = lookupType(getID()) != this;
}
aspect ComponentAnalysis {
//--- isTargetOfDirectedRelation ---
inh boolean Component.isTargetOfDirectedRelation();
eq Relation.getRight().isTargetOfDirectedRelation() = getDirection() instanceof RightDirection;
eq Program.getChild().isTargetOfDirectedRelation() = false;
//--- name ---
syn String Component.name() = getID();
//--- enclosingTypeDecl ---
inh TypeDecl Component.enclosingTypeDecl();
eq TypeDecl.getChild().enclosingTypeDecl() = this;
eq Program.getChild().enclosingTypeDecl() = null;
//--- otherSide ---
inh RelationComponent RelationComponent.opposite();
eq Relation.getLeft().opposite() = getRight();
eq Relation.getRight().opposite() = getLeft();
eq Program.getChild().opposite() = null;
//--- ofTypeDecl ---
syn TypeDecl RelationComponent.ofTypeDecl() = opposite().getTypeUse().decl();
//--- isAlreadyDeclared ---
/**
* Check, if role with the same name is already declared on the same nonterminal
*/
syn boolean RelationComponent.isAlreadyDeclared()
= !isTargetOfDirectedRelation() /* if unnamed in relation, there is no role name, so no error */
&& getTypeUse().decl() != null /* nonterminal type of role is defined */
&& findComponent(getTypeUse().decl(), name()) != this; /* there is another role defined previously with the same name */
//--- findComponent ---
/** Search for either a component on the RHS of the given type with the given name,
* or a relation part for the given type and a role with the given name */
inh Component Component.findComponent(TypeDecl td, String name);
eq Program.getChild().findComponent(TypeDecl td, String name)
= findComponentSyn(td, name);
syn Component Program.findComponentSyn(TypeDecl td, String name) {
for (Component c: td.getComponents()) {
if (c.name().equals(name)) {
return c;
}
}
for (Relation r : getRelations()) {
if (r.getLeft().matches(td, name))
return r.getLeft();
if (r.getRight().matches(td, name))
return r.getRight();
}
return null;
}
//--- isInvalidRedefinition ---
/**
* Check, if a component with the same name is already declared in some supertype
*/
syn boolean Component.isInvalidRedefinition() = invalidRedefinition() != null;
/**
* Check, if a component with the same name is already declared in some supertype, and return it, if any
*/
syn Component Component.invalidRedefinition() = null;
eq TokenComponent.invalidRedefinition() = invalidRedefinitionOn(enclosingTypeDecl());
eq RelationComponent.invalidRedefinition() = invalidRedefinitionOn(getTypeUse().decl());
syn Component Component.invalidRedefinitionOn(TypeDecl td) {
if (td == null) return null;
while (td.hasSuper() && td.getSuper().decl() != null) {
td = td.getSuper().decl();
// find a matching component on the RHS of the (current) super type
Component c = findComponent(td, getID());
if (c != null && !this.isEqual(c)) return c;
}
return null;
}
//--- isEqual ---
syn boolean Component.isEqual(Component c) = this.getClass() == c.getClass() && getTypeUse().isEqual(c.getTypeUse());
/**
* TokenComponents may be specialized by NTATokenComponents and vice versa
*/
eq TokenComponent.isEqual(Component c) = (c instanceof TokenComponent) && getTypeUse().isEqual(c.getTypeUse());
syn boolean TypeUse.isEqual(TypeUse u);
eq SimpleTypeUse.isEqual(TypeUse u) = u instanceof SimpleTypeUse && getID().equals(u.getID());
eq ParameterizedTypeUse.isEqual(TypeUse u) {
if (!getID().equals(u.getID())) return false;
if (!(u instanceof ParameterizedTypeUse)) return false;
ParameterizedTypeUse pu = (ParameterizedTypeUse) u;
if (getNumTypeUse() != pu.getNumTypeUse()) return false;
for (int i = 0; i < getNumTypeUse(); i++) {
if (!getTypeUse(i).isEqual(pu.getTypeUse(i))) return false;
}
return true;
}
//--- matches ---
/**
* @return true, if the component has both type and role, its type matches the given typeDecl and its name matches the given name
*/
syn boolean RelationComponent.matches(TypeDecl td, String name)
= !isTargetOfDirectedRelation() && getTypeUse().decl() == td && name().equals(name);
//--- relationComponents ---
coll Set<RelationComponent> TypeDecl.relationComponents()
[new HashSet<RelationComponent>()]
root Program;
RelationComponent contributes this
when !isTargetOfDirectedRelation() && getTypeUse().decl() != null
to TypeDecl.relationComponents()
for getTypeUse().decl();
//--- relationComponentsTransitive ---
syn Collection<RelationComponent> TypeDecl.relationComponentsTransitive() {
Collection<RelationComponent> list = new ArrayList<>();
if (hasSuper() && getSuper().decl() != null) {
list.addAll(getSuper().decl().relationComponentsTransitive());
}
list.addAll(relationComponents());
return list;
}
//--- oneRelationComponents ---
syn Set<OneRelationComponent> TypeDecl.oneRelationComponents() {
Set<OneRelationComponent> set = new HashSet<>();
for (RelationComponent rc: relationComponents()) {
if (rc instanceof OneRelationComponent) {
set.add((OneRelationComponent) rc);
}
}
return set;
}
//--- needUnresolvedClass ---
syn boolean TypeDecl.needUnresolvedClass() {
// a TypeDecl needs an unresolved class, if it can appear in a relation
// TODO
return true;
}
//--- isList ---
syn boolean Component.isList() = false;
eq ListComponent.isList() = true;
eq NTAListComponent.isList() = true;
eq ManyRelationComponent.isList() = true;
//--- isOpt ---
syn boolean Component.isOpt() = false;
eq OptComponent.isOpt() = true;
eq NTAOptComponent.isOpt() = true;
eq OptionalRelationComponent.isOpt() = true;
//--- isNullable ---
syn boolean Component.isNullable() = false;
eq TokenComponent.isNullable() = !"float double int short long char byte boolean".contains(getTypeUse().getID());
}
aspect InstanceSupplier {
//--- program ---
inh Program TypeDecl.program();
eq Program.getTypeDecl(int i).program() = this;
//--- subTypeDecls ---
syn Collection<TypeDecl> TypeDecl.subTypeDecls() {
Collection<TypeDecl> subDecls = new ArrayList();
for (TypeDecl decl : program().getTypeDeclList()) {
if (decl.hasSuper() && decl.getSuper().getID().equals(getID())) {
subDecls.add(decl);
}
}
return subDecls;
}
//--- instantiableSubType ---
syn TypeDecl TypeDecl.instantiableSubType() {
if (getAbstract() == false) {
return this;
} else {
for (TypeDecl sub : subTypeDecls()) {
if (sub.getAbstract() == false) {
return sub;
} else {
TypeDecl subInstance = sub.instantiableSubType();
if (subInstance != null) {
return subInstance;
}
}
}
}
return null;
}
}
aspect Constructors {
//--- componentsTransitive ---
syn Collection<Component> TypeDecl.componentsTransitive() {
ArrayList<Component> list = new ArrayList<>();
if (hasSuper() && getSuper().decl() != null) {
list.addAll(getSuper().decl().componentsTransitive());
}
for (Component c: getComponents()) {
if (c.inConstructor()) {
list.add(c);
}
}
return list;
}
//--- needsConstructor ---
syn boolean TypeDecl.needsConstructor() = !componentsTransitive().isEmpty() && !relationComponentsTransitive().isEmpty();
//--- inConstructor ---
/**
* @return true, if the component should be added to the constructor (i.e., is not an NTA)
*/
syn boolean Component.inConstructor() = true;
eq NTAComponent.inConstructor() = false;
eq NTAOptComponent.inConstructor() = false;
eq NTAListComponent.inConstructor() = false;
eq NTATokenComponent.inConstructor() = false;
}
aspect Utils {
//--- toString ---
public String SimpleTypeUse.toString() {
return getID();
}
public String ParameterizedTypeUse.toString() {
StringBuilder sb = new StringBuilder();
sb.append(getID()).append("<");
boolean first = true;
for (TypeUse u: getTypeUses()) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(u.toString());
}
sb.append(">");
return sb.toString();
}
public String TypeDecl.toString() {
return getID();
}
}
aspect DumpTree {
private static final String ASTNode.DUMP_TREE_INDENT = " ";
public String ASTNode.dumpTree() {
java.io.ByteArrayOutputStream bytes = new java.io.ByteArrayOutputStream();
dumpTree(new java.io.PrintStream(bytes));
return bytes.toString();
}
public void ASTNode.dumpTree(java.io.PrintStream out) {
dumpTree(out, "");
out.flush();
}
public void ASTNode.dumpTree(java.io.PrintStream out, String indent) {
out.print(indent + getClass().getSimpleName());
out.print(getTokens());
String extra = extraDumpInfo();
if (!extra.isEmpty()) {
out.print(" " + extra);
}
out.println();
String childIndent = indent + DUMP_TREE_INDENT;
for (ASTNode child : astChildren()) {
if (child == null) {
out.println(childIndent + "null");
} else {
child.dumpTree(out, childIndent);
}
}
}
public String ASTNode.extraDumpInfo() { return ""; }
public String ASTNode.getTokens() {
java.util.TreeSet<java.lang.reflect.Method> methods = new java.util.TreeSet<>(Comparator.comparing(java.lang.reflect.Method::getName));
methods.addAll(java.util.Arrays.asList(getClass().getMethods()));
StringBuilder result = new StringBuilder();
for (java.lang.reflect.Method method : methods) {
ASTNodeAnnotation.Token token = method.getAnnotation(ASTNodeAnnotation.Token.class);
if (token != null) {
try {
result.append(String.format(" %s=\"%s\"", token.name(), method.invoke(this)));
} catch (IllegalAccessException ignored) {
} catch (java.lang.reflect.InvocationTargetException ignored) {
}
}
}
return result.toString();
}
}
import java.util.Set;
import java.util.TreeSet;
import java.util.LinkedList;
aspect Errors {
coll Set<ErrorMessage> Program.errors()
[new TreeSet<ErrorMessage>()]
root Program;
TypeUse contributes error("Type '" + getID() + "' not found")
when decl() == null && !isToken()
to Program.errors();
TypeDecl contributes error("Type '" + getID() + "' is already declared")
when isAlreadyDeclared()
to Program.errors();
RelationComponent contributes error("Role '" + name()
+ "' is already declared for type '" + getTypeUse().decl() + "'")
when isAlreadyDeclared()
to Program.errors();
RelationComponent contributes error("Role '" + name()
+ "' is an invalid redefinition for type '" + getTypeUse().decl() + "', conflicts with supertype '"
+ invalidRedefinition().enclosingTypeDecl() + "'")
when isInvalidRedefinition()
to Program.errors();
TokenComponent contributes error("Token '" + name()
+ "' is an invalid redefinition for type '" + enclosingTypeDecl() + "', conflicts with supertype '"
+ invalidRedefinition().enclosingTypeDecl() + "'")
when isInvalidRedefinition()
to Program.errors();
RelationComponent contributes
error("Role name missing for type '" + getTypeUse().decl() + "'")
when !isTargetOfDirectedRelation() && name().isEmpty()
to Program.errors();
RelationComponent contributes
error("The target of a directed relation cannot have a role name")
when isTargetOfDirectedRelation() && !getID().isEmpty()
to Program.errors();
RelationComponent contributes
error("The target of a directed relation may only have multiplicity 1")
when isTargetOfDirectedRelation() && !multiplicityOne()
to Program.errors();
}
aspect HelpAttributes {
inh Program ASTNode.program();
eq Program.getChild().program() = this;
inh boolean TypeUse.isToken();
eq Program.getChild().isToken() = false;
eq TokenComponent.getTypeUse().isToken() = true;
syn boolean RelationComponent.multiplicityOne() = false;
eq OneRelationComponent.multiplicityOne() = true;
syn boolean RelationComponent.multiplicityOpt() = false;
eq OptionalRelationComponent.multiplicityOpt() = true;
syn boolean RelationComponent.multiplicityMany() = false;
eq ManyRelationComponent.multiplicityMany() = true;
inh ContainedInFile Component.enclosingFileContainer();
eq TypeDecl.getComponent().enclosingFileContainer() = this;
eq Relation.getChild().enclosingFileContainer() = this;
inh ContainedInFile TypeUse.enclosingFileContainer();
eq SimpleTypeComponent.getTypeUse().enclosingFileContainer() = enclosingFileContainer();
eq TokenComponent.getTypeUse().enclosingFileContainer() = enclosingFileContainer();
eq TypeDecl.getSuper().enclosingFileContainer() = this;
syn String ASTNode.containedFile() = "Unknown";
eq Component.containedFile() = enclosingFileContainer() == null ? "Unknown2" : enclosingFileContainer().containedFile();
eq TypeUse.containedFile() = enclosingFileContainer() == null ? "Unknown3" : enclosingFileContainer().containedFile();
eq TypeDecl.containedFile() = getFileName();
eq Relation.containedFile() = getFileName();
}
aspect ErrorMessage {
public class ErrorMessage implements Comparable<ErrorMessage> {
private final ASTNode node;
private final String filename;
private final int line;
private final int col;
private final String message;
public ErrorMessage(ASTNode node, String message) {
this.node = node;
this.filename = node.containedFile();
this.line = node.getStartLine();
this.col = node.getStartColumn();
this.message = message;
}
public ASTNode getNode() {
return node;
}
public int getLine() {
return line;
}
public int getCol() {
return col;
}
public String getMessage() {
return message;
}
public String toString() {
return filename + " Line " + line + ", column " + col + ": " + message;
}
@Override
public int compareTo(ErrorMessage err) {
int n = filename.compareTo(err.filename);
if (n != 0) {
return n;
}
n = line - err.line;
if (n != 0) {
return n;
}
n = col-err.col;
if (n != 0) {
return n;
}
return message.compareTo(err.message);
}
}
protected ErrorMessage ASTNode.error(String message) {
return new ErrorMessage(this, message);
}
}
%header {:
package org.jastadd.ros2rag.parser;
import org.jastadd.ros2rag.ast.*;
:};
%goal goal;
Program ::= TypeDecl* Relation*;
abstract ContainedInFile ::= <FileName> ;
TypeDecl : ContainedInFile ::= <ID> <Abstract:boolean> [Super:TypeUse] Component*;
abstract Component ::= <ID>;
abstract SimpleTypeComponent : Component ::= TypeUse:SimpleTypeUse;
NormalComponent : SimpleTypeComponent;
ListComponent : SimpleTypeComponent;
OptComponent : SimpleTypeComponent;
NTAComponent : SimpleTypeComponent;
NTAOptComponent : SimpleTypeComponent;
NTAListComponent : SimpleTypeComponent;
TokenComponent : Component ::= TypeUse;
NTATokenComponent : TokenComponent ::= TypeUse;
abstract TypeUse ::= <ID>;
SimpleTypeUse : TypeUse;
ParameterizedTypeUse : TypeUse ::= TypeUse*;
Relation : ContainedInFile ::= Left:RelationComponent Direction Right:RelationComponent;
abstract RelationComponent : SimpleTypeComponent;
OneRelationComponent : RelationComponent;
OptionalRelationComponent : RelationComponent;
ManyRelationComponent : RelationComponent;
abstract Direction;
RightDirection : Direction;
LeftDirection : Direction;
Bidirectional : Direction;
package org.jastadd.ros2rag.scanner;
import org.jastadd.ros2rag.parser.RelAstParser.Terminals;
%%
%public
%final
%class RelAstScanner
%extends beaver.Scanner
%type beaver.Symbol
%function nextToken
%yylexthrow beaver.Scanner.Exception
%scanerror RelAstScanner.ScannerError
%line
%column
%{
private StringBuilder stringLitSb = new StringBuilder();
private beaver.Symbol sym(short id) {
return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), yytext());
}
private beaver.Symbol sym(short id, String text) {
return new beaver.Symbol(id, yyline + 1, yycolumn + 1, yylength(), text);
}
public static class ScannerError extends Error {
public ScannerError(String message) {
super(message);
}
}
%}
WhiteSpace = [ ] | \t | \f | \n | \r | \r\n
TraditionalComment = [/][*][^*]*[*]+([^*/][^*]*[*]+)*[/]
EndOfLineComment = "//" [^\n\r]*
Comment = {TraditionalComment} | {EndOfLineComment}
ID = [a-zA-Z$_][a-zA-Z0-9$_]*
%%
{WhiteSpace} { /* ignore */ }
{Comment} { /* ignore */ }
"abstract" { return sym(Terminals.ABSTRACT); }
"rel" { return sym(Terminals.RELATION); }
";" { return sym(Terminals.SCOL); }
":" { return sym(Terminals.COL); }
"::=" { return sym(Terminals.ASSIGN); }
"*" { return sym(Terminals.STAR); }
"." { return sym(Terminals.DOT); }
"," { return sym(Terminals.COMMA); }
"<" { return sym(Terminals.LT); }
">" { return sym(Terminals.GT); }
"[" { return sym(Terminals.LBRACKET); }
"]" { return sym(Terminals.RBRACKET); }
"/" { return sym(Terminals.SLASH); }
"?" { return sym(Terminals.QUESTION_MARK); }
"->" { return sym(Terminals.RIGHT); }
"<-" { return sym(Terminals.LEFT); }
"<->" { return sym(Terminals.BIDIRECTIONAL); }
// ID
{ID} { return sym(Terminals.ID); }
<<EOF>> { return sym(Terminals.EOF); }
[^] { throw new ScannerError((yyline+1) +"," + (yycolumn+1) + ": Illegal character <"+yytext()+">"); }
Program goal =
/* empty */ {: return new Program(); :}
| type_decl.t goal.p {: p.getTypeDeclList().insertChild(t, 0); return p; :}
| relation.r goal.p {: p.getRelationList().insertChild(r, 0); return p; :}
;
TypeDecl type_decl =
ID type_decl_super.s components_opt.c SCOL
{:
TypeDecl result = new TypeDecl();
result.setID(ID);
result.setAbstract(false);
result.setSuperOpt(s);
result.setComponentList(c);
return result;
:}
| ABSTRACT ID type_decl_super.s components_opt.c SCOL
{:
TypeDecl result = new TypeDecl();
result.setID(ID);
result.setAbstract(true);
result.setSuperOpt(s);
result.setComponentList(c);
return result;
:}
;
Opt type_decl_super =
/* empty */ {: return new Opt(); :}
| COL s_type_use.u {: return new Opt(u); :}
;
SimpleTypeUse s_type_use =
ID {: return new SimpleTypeUse(ID); :}
;
ArrayList inner_type_use
= ID
| inner_type_use DOT ID
;
TypeUse type_use =
parameterized_type_use.p {: return p; :}
| inner_type_use.p {: return new SimpleTypeUse((String)p.stream().map( x -> ((Symbol)x).value.toString()).collect(java.util.stream.Collectors.joining("."))); :}
;
ParameterizedTypeUse parameterized_type_use =
inner_type_use.i LT type_use_list.l GT {: return new ParameterizedTypeUse((String)i.stream().map( x -> ((Symbol)x).value.toString()).collect(java.util.stream.Collectors.joining(".")), l); :}
;
List type_use_list =
type_use.u {: return new List().add(u); :}
| type_use_list.l COMMA type_use.u {: return l.add(u); :}
;
List components_opt =
/* empty */ {: return new List(); :}
| ASSIGN components.l {: return l; :}
;
List components =
/* empty */ {: return new List(); :}
| components.l component.c {: return l.add(c); :}
;
Component component =
ID COL s_type_use.u {: return new NormalComponent(ID, u); :}
| s_type_use.u {: return new NormalComponent(u.getID(), u); :}
// List
| ID COL s_type_use.u STAR {: return new ListComponent(ID, u); :}
| s_type_use.u STAR {: return new ListComponent(u.getID(), u); :}
// Opt
| LBRACKET ID COL s_type_use.u RBRACKET {: return new OptComponent(ID, u); :}
| LBRACKET s_type_use.u RBRACKET {: return new OptComponent(u.getID(), u); :}
// NTA list
| SLASH ID COL s_type_use.u STAR SLASH {: return new NTAListComponent(ID, u); :}
| SLASH s_type_use.u STAR SLASH {: return new NTAListComponent(u.getID(), u); :}
// NTA opt
| SLASH LBRACKET ID COL s_type_use.u RBRACKET SLASH {: return new NTAOptComponent(ID, u); :}
| SLASH LBRACKET s_type_use.u RBRACKET SLASH {: return new NTAOptComponent(u.getID(), u); :}
// NTA
| SLASH ID COL s_type_use.u SLASH {: return new NTAComponent(ID, u); :}
| SLASH s_type_use.u SLASH {: return new NTAComponent(u.getID(), u); :}
// NTA Token (same as NTA)
| SLASH LT ID COL s_type_use.u GT SLASH {: return new NTATokenComponent(ID, u); :}
| SLASH LT ID GT SLASH {: return new NTATokenComponent(ID, new SimpleTypeUse("String")); :}
// Token
| LT ID COL type_use.u GT {: return new TokenComponent(ID, u); :}
| LT ID GT {: return new TokenComponent(ID, new SimpleTypeUse("String")); :}
;
Relation relation =
RELATION relation_comp.l direction relation_comp.r SCOL
{:
Relation result = new Relation();
if (direction instanceof LeftDirection) {
result.setLeft(r);
result.setDirection(new RightDirection());
result.setRight(l);
} else {
result.setLeft(l);
result.setDirection(direction);
result.setRight(r);
}
return result;
:}
;
RelationComponent relation_comp =
// One
s_type_use.u DOT ID {: return new OneRelationComponent(ID, u); :}
| s_type_use.u {: return new OneRelationComponent("", u); :}
// Optional
| s_type_use.u DOT ID QUESTION_MARK {: return new OptionalRelationComponent(ID, u); :}
| s_type_use.u QUESTION_MARK {: return new OptionalRelationComponent("", u); :}
// Many
| s_type_use.u DOT ID STAR {: return new ManyRelationComponent(ID, u); :}
| s_type_use.u STAR {: return new ManyRelationComponent("", u); :}
;
Direction direction =
RIGHT {: return new RightDirection(); :}
| LEFT {: return new LeftDirection(); :}
| BIDIRECTIONAL {: return new Bidirectional(); :}
;
Ros2Rag ::= MappingDefinition* SyncDefinition* Program; //MqttRoot ;
abstract SyncDefinition ::= <AlwaysApply:Boolean> ;
abstract TokenWritingSyncDefinition : SyncDefinition ::= TargetType:SimpleTypeUse <TargetChild> ;
UpdateDefinition : TokenWritingSyncDefinition ::= <SourceAttribute> [MappingDefinitionUse] ;
ReadFromMqttDefinition : TokenWritingSyncDefinition ::= [MappingDefinitionUse] ;
WriteToMqttDefinition : SyncDefinition ::= SourceType:SimpleTypeUse <SourceChild> [MappingDefinitionUse] ;
MappingDefinition ::= <ID> From:SimpleTypeUse To:SimpleTypeUse <Content> ;
MappingDefinitionUse ::= <ID> ;
aspect BackendAbstractGrammar {
public static String ASTNode.listInterface = "java.util.List";
public static String ASTNode.listClass = "java.util.ArrayList";
public static String ASTNode.jastAddListType = "List";
public static String ASTNode.jastAddOptType = "Opt";
public String Program.generateAbstractGrammar() {
StringBuilder sb = new StringBuilder();
generateAbstractGrammar(sb);
return sb.toString();
}
public void Program.generateAbstractGrammar(StringBuilder sb) {
for (TypeDecl td: getTypeDecls()) {
td.generateAbstractGrammar(sb);
}
}
public void TypeDecl.generateAbstractGrammar(StringBuilder sb) {
if (getAbstract()) {
sb.append("abstract ");
}
sb.append(getID());
if (hasSuper()) {
sb.append(" : " + getSuper());
}
if (getNumComponent() > 0 || relationComponents().size() > 0) {
sb.append(" ::=");
}
for (Component c: getComponents()) {
sb.append(" ");
sb.append(c.generateAbstractGrammar());
}
sb.append(";\n");
}
public String Component.generateAbstractGrammar() {
if (getID().equals(getTypeUse().toString())) {
return getTypeUse().toString();
} else {
return getID() + ":" + getTypeUse();
}
}
public String ListComponent.generateAbstractGrammar() {
return super.generateAbstractGrammar() + "*";
}
public String OptComponent.generateAbstractGrammar() {
return "[" + super.generateAbstractGrammar() + "]";
}
public String NTAComponent.generateAbstractGrammar() {
return "/" + super.generateAbstractGrammar() + "/";
}
public String NTAListComponent.generateAbstractGrammar() {
return "/" + super.generateAbstractGrammar() + "*/";
}
public String NTAOptComponent.generateAbstractGrammar() {
return "/[" + super.generateAbstractGrammar() + "]/";
}
public String TokenComponent.generateAbstractGrammar() {
return "<" + getID() + ":" + getTypeUse() + ">";
}
public String NTATokenComponent.generateAbstractGrammar() {
return "/<" + getID() + ":" + getTypeUse() + ">/";
}
public String Relation.generateAbstractGrammar() {
return "rel "
+ getLeft().generateAbstractGrammar() + " "
+ getDirection().generateAbstractGrammar() + " "
+ getRight().generateAbstractGrammar();
}
public String RelationComponent.generateAbstractGrammar() {
if (getID().isEmpty()) {
return getTypeUse().toString();
} else {
return getTypeUse() + "." + getID();
}
}
public String OptionalRelationComponent.generateAbstractGrammar() {
return super.generateAbstractGrammar() + "?";
}
public String ManyRelationComponent.generateAbstractGrammar() {
return super.generateAbstractGrammar() + "*";
}
abstract public String Direction.generateAbstractGrammar();
public String RightDirection.generateAbstractGrammar() {
return "->";
}
public String LeftDirection.generateAbstractGrammar() {
return "<-";
}
public String Bidirectional.generateAbstractGrammar() {
return "<->";
}
}
aspect Aspect {
public static final String ASTNode.aspectIndent = " ";
public String Program.generateAspect() {
StringBuilder sb = new StringBuilder();
generateAspect(sb);
return sb.toString();
}
@Deprecated
public void Program.generateAspect(StringBuilder sb) {
sb.append("aspect ROS2RAG {\n");
// TODO generate getters and setters for ROS2RAG terminals (and attributes?)
sb.append("}\n");
}
public String Ros2Rag.generateAspect() {
StringBuilder sb = new StringBuilder();
generateAspect(sb);
return sb.toString();
}
// from "[always] read Joint.CurrentPosition using PoseToPosition;" generate method connectTo
// Joint j;
// j.getCurrentPosition().connectTo("/robot/joint2/pos");
public void Ros2Rag.generateAspect(StringBuilder sb) {
sb.append("aspect ROS2RAG {\n");
for (SyncDefinition def : getSyncDefinitionList()) {
def.generateAspect(sb);
}
sb.append("}\n");
}
abstract void SyncDefinition.generateAspect(StringBuilder sb);
@Override
void UpdateDefinition.generateAspect(StringBuilder sb) {
// TODO
}
// will be "addConnectionJoint_CurrentPosition" in example
/* // see discussion in codimd (InstanceLocation), why this won't work here
Position.connectTo(String topic) {
mqttUpdater().addConnectionJoint_CurrentPosition(this, topic);
}
MqttUpdater.addConnectionJoint_CurrentPosition(Position target, String topic) {
// either
topicActionMap.put(topic, new Action(JOINT_CURRENTPOSITION, target));
// or
topicForJoint_CurrentPosition.put(topic, target);
}
*/
@Override
void ReadFromMqttDefinition.generateAspect(StringBuilder sb) {
sb.append("public void ").append("type").append(".connectTo(String topic) {\n")
.append(aspectIndent).append("mqttUpdater().addConnection")
.append(getTargetType().getID()).append("_")
.append(getTargetChild())
.append("(this, topic);\n")
.append("}\n");
}
@Override
void WriteToMqttDefinition.generateAspect(StringBuilder sb) {
// TODO
}
}
package org.jastadd.ros2rag.compiler;
import beaver.Parser;
import org.jastadd.ros2rag.ast.ErrorMessage;
import org.jastadd.ros2rag.ast.Program;
import org.jastadd.ros2rag.ast.Relation;
import org.jastadd.ros2rag.ast.TypeDecl;
import org.jastadd.ros2rag.compiler.options.CommandLine;
import org.jastadd.ros2rag.compiler.options.CommandLine.CommandLineException;
import org.jastadd.ros2rag.compiler.options.Option;
import org.jastadd.ros2rag.compiler.options.StringOption;
import org.jastadd.ros2rag.parser.RelAstParser;
import org.jastadd.ros2rag.scanner.RelAstScanner;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Compiler {
private StringOption optionOutputDir;
private ArrayList<Option<?>> options;
private CommandLine commandLine;
public Compiler(String[] args) throws CommandLineException {
options = new ArrayList<>();
addOptions();
commandLine = new CommandLine(options);
commandLine.parse(args);
String outputDir = "gen"; // should not be used, but otherwise there is a compiler warning
if (optionOutputDir.isSet()) {
outputDir = optionOutputDir.getValue();
} else {
System.out.println("No output grammar name is set. Assuming output dir '" + outputDir + "'.");
}
printMessage("Running ROS2RAG Preprocessor");
if (commandLine.getArguments().size() < 1) {
error("specify at least one input file");
}
List<String> filenames = commandLine.getArguments();
Program p = parseProgram(filenames);
if (!p.errors().isEmpty()) {
System.err.println("Errors:");
for (ErrorMessage e : p.errors()) {
System.err.println(e);
}
System.exit(1);
} else {
writeToFile(outputDir + "/Grammar.ast", p.generateAbstractGrammar());
writeToFile(outputDir + "/ROS2RAG.jadd", p.generateAspect());
}
}
public static void main(String[] args) {
try {
new Compiler(args);
} catch (CommandLineException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
private void printMessage(String message) {
System.out.println(message);
}
private void writeToFile(String filename, String str) {
try {
PrintWriter writer = new PrintWriter(filename);
writer.print(str);
writer.close();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
private void addOptions() {
optionOutputDir = addOption(new StringOption("outputDir", "target directory for the generated files."));
}
private <OptionType extends Option<?>> OptionType addOption(OptionType option) {
options.add(option);
return option;
}
private Program parseProgram(List<String> fileNames) {
Program program = new Program();
for (String fileName : fileNames) {
FileReader reader = null;
try {
reader = new FileReader(fileName);
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
System.exit(1);
}
parse(program, reader, fileName);
}
return program;
}
private void parse(Program program, Reader reader, String file) {
RelAstScanner scanner = new RelAstScanner(reader);
RelAstParser parser = new RelAstParser();
try {
Program newProgram = (Program) parser.parse(scanner);
for (TypeDecl typeDecl : newProgram.getTypeDeclList()) {
typeDecl.setFileName(file);
program.addTypeDecl(typeDecl);
}
for (Relation relation : newProgram.getRelationList()) {
relation.setFileName(file);
program.addRelation(relation);
}
} catch (IOException e) {
error(e.getMessage());
} catch (Parser.Exception e) {
System.err.println("Parse error in file " + file);
System.err.println(e.getMessage());
System.exit(1);
}
}
protected void error(String message) {
System.err.println("Error: " + message);
System.err.println();
System.err.println("Usage: java -jar ros2rag.jar [--option1] [--option2=value] ... <filename1> <filename2> ... ");
System.err.println("Options:");
System.err.print(commandLine.printOptionHelp());
System.exit(1);
}
}
package org.jastadd.ros2rag.compiler;
import beaver.Parser;
import org.jastadd.ros2rag.ast.*;
import org.jastadd.ros2rag.parser.RelAstParser;
import org.jastadd.ros2rag.scanner.RelAstScanner;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Testing Ros2Rag without parser.
*
* @author rschoene - Initial contribution
*/
public class SimpleMain {
public static void main(String[] args) {
/*
// as soon as the cache of isInSafetyZone is invalidated, update the value of Robot.ShouldUseLowSpeed with its value
[always] update Robot.ShouldUseLowSpeed with isInSafetyZone() using transformation();
// when a (new?) value for ShouldUseLowSpeed is set, send it over via mqtt
[always] write Robot.ShouldUseLowSpeed;
// when an update of pose is read via mqtt, then update current position
[always] read Joint.CurrentPosition using PoseToPosition;
// PBPose is a datatype defined in protobuf
PoseToPosition: map PBPose to Position using
pose.position.x += sqrt(.5 * size.x)
MAP round(2)
x = x / 100
IGNORE_IF_SAME
;
--- using generated methods ---
Joint j;
j.getCurrentPosition().connectTo("/robot/joint2/pos");
RobotArm r;
// this should not be required
r.getShouldUseLowSpeed().addObserver(j.getCurrentPosition());
r.getShouldUseLowSpeed().connectTo("/robot/config/speed");
*/
Ros2Rag model = new Ros2Rag();
Program program = parseProgram(Paths.get("src", "test", "resources", "MinimalExample.relast"));
model.setProgram(program);
MappingDefinition mappingDefinition = new MappingDefinition();
mappingDefinition.setID("PoseToPosition");
mappingDefinition.setFrom(new SimpleTypeUse("PBPose"));
mappingDefinition.setTo(new SimpleTypeUse("Position"));
mappingDefinition.setContent(" pose.position.x += sqrt(.5 * size.x)\n" +
" MAP round(2)\n" +
" x = x / 100\n" +
" IGNORE_IF_SAME\n" +
" ;");
model.addMappingDefinition(mappingDefinition);
ReadFromMqttDefinition readFromMqttDefinition = new ReadFromMqttDefinition();
readFromMqttDefinition.setAlwaysApply(false);
readFromMqttDefinition.setTargetType(new SimpleTypeUse("Joint"));
readFromMqttDefinition.setTargetChild("CurrentPosition");
readFromMqttDefinition.setMappingDefinitionUse(new MappingDefinitionUse("PoseToPosition"));
model.addSyncDefinition(readFromMqttDefinition);
System.out.println(model.generateAspect());
}
private static Program parseProgram(Path path) {
try (BufferedReader reader = Files.newBufferedReader(path)) {
RelAstScanner scanner = new RelAstScanner(reader);
RelAstParser parser = new RelAstParser();
return (Program) parser.parse(scanner);
} catch (IOException | Parser.Exception e) {
e.printStackTrace();
}
return null;
}
}
package org.jastadd.ros2rag.compiler;
import java.util.*;
import java.util.function.Predicate;
import static java.util.stream.Collectors.toList;
public class Utils {
public static <T> List<T> filterToList(Collection<T> collection, Predicate<T> predicate) {
return collection.stream().filter(predicate).collect(toList());
}
public static <T> Set<T> asSet(T... t) {
return new HashSet<T>(Arrays.asList(t));
}
}
package org.jastadd.ros2rag.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.ros2rag.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.ros2rag.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.ros2rag.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.ros2rag.compiler.options;
public class StringOption extends Option<String> {
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;
}
@Override
public String getValue() {
return value;
}
@Override
public Option.HasArgument hasArgument() {
return Option.HasArgument.YES;
}
@Override
public void match(String value) {
this.value = value;
isSet = true;
}
@Override
public boolean isSet() {
return isSet;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment