mostSpecificFunction =
+ getFuncRel().getMostSpecificFunction(callableFuncs);
+ if (mostSpecificFunction.isPresent()) {
+ type = mostSpecificFunction.get().getType().deepClone();
+ }
+ else {
+ type = createObscureType();
+ }
+ }
+ }
+ getType4Ast().setTypeOfExpression(expr, type);
+ }
+
+ @Override
+ public void traverse(ASTFieldAccessExpression expr) {
+ if (isSeriesOfNames(expr.getExpression())) {
+ // done without visitor
+ fieldAccessCustomTraverse(expr);
+ }
+ else {
+ // traverse as normal
+ expr.getExpression().accept(getTraverser());
+ }
+ }
+
+ /**
+ * custom traverse for ASTFieldAccessExpressions.
+ * Normal traversing would try to calculate types,
+ * however, not every ASTFieldAccessExpression is a field access expression;
+ * E.g., given the expression "a.b.c.d.e", "a.b" could be a package name,
+ * "a.b.c" a name of a typeId, "a.b.c.d" the name of a variable,
+ * and "a.b.c.d.e" the access of field "e" in "a.b.c.d".
+ *
+ * As such, given a series of names a.b.c,
+ * up until the most outer field access expression in the series,
+ * we allow to not find an expression (and thus have no type calculated).
+ */
+ protected void fieldAccessCustomTraverse(ASTFieldAccessExpression expr) {
+ if (isSeriesOfNames(expr)) {
+ if (getTypeDispatcher().isASTFieldAccessExpression(expr.getExpression())) {
+ ASTFieldAccessExpression innerFieldAccessExpr =
+ getTypeDispatcher().asASTFieldAccessExpression(expr.getExpression());
+ fieldAccessCustomTraverse(innerFieldAccessExpr);
+ // if expression or type identifier has been found,
+ // continue to require further results
+ boolean resultsAreOptional =
+ !getType4Ast().hasTypeOfExpression(expr.getExpression()) &&
+ !getType4Ast().hasTypeOfTypeIdentifierForName(expr.getExpression());
+ calculateFieldAccess(innerFieldAccessExpr, resultsAreOptional);
+ }
+ else if (getTypeDispatcher().isASTNameExpression(expr.getExpression())) {
+ ASTNameExpression nameExpr = getTypeDispatcher().asASTNameExpression(expr.getExpression());
+ Optional nameAsExprType =
+ calculateExprQName(nameExpr);
+ Optional nameAsTypeIdType =
+ calculateTypeIdQName(nameExpr);
+ if (nameAsExprType.isPresent()) {
+ getType4Ast().setTypeOfExpression(nameExpr, nameAsExprType.get());
+ }
+ else if (nameAsTypeIdType.isPresent()) {
+ getType4Ast().setTypeOfTypeIdentifierForName(
+ nameExpr,
+ nameAsTypeIdType.get()
+ );
+ }
+ }
+ else {
+ Log.error("0xFD5AC internal error:"
+ + "expected a series of names (a.b.c)",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ }
+ else {
+ Log.error("0xFD5AD internal error:"
+ + "expected a series of names (a.b.c)",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ }
+
+ @Override
+ public void endVisit(ASTFieldAccessExpression expr) {
+ calculateFieldAccess(expr, false);
+ }
+
+ /**
+ * implementation for endVisit.
+ *
+ * @param resultsAreOptional s. {@link #fieldAccessCustomTraverse(ASTFieldAccessExpression)}
+ */
+ protected void calculateFieldAccess(
+ ASTFieldAccessExpression expr, boolean resultsAreOptional) {
+ // after the non-visitor traversal, types have been calculated if they exist
+ Optional exprType;
+ Optional typeId = Optional.empty();
+ // case: expression "." name, e.g., getX().var
+ if (getType4Ast().hasTypeOfExpression(expr.getExpression())) {
+ exprType = calculateExprFieldAccessOrLogError(expr, false);
+ }
+ // case: typeIdentifier "." name, e.g., XClass.staticVar
+ // in Java, if variable exists, typeIdentifier "." name is ignored,
+ // even if variable "." name does not exist
+ else if (getType4Ast().hasTypeOfTypeIdentifierForName(expr.getExpression())) {
+ exprType = calculateTypeIdFieldAccessOrLogError(expr, resultsAreOptional);
+ // case: typeid "." typeid2 ("." name), e.g., C1.CInner.staticVar
+ if (exprType.isEmpty() && resultsAreOptional) {
+ typeId = calculateInnerTypeIdFieldAccess(expr);
+ }
+ }
+ // case: qualifier "." name
+ else {
+ // case: qualifier "." name as Expression
+ exprType = calculateExprQNameOrLogError(expr, resultsAreOptional);
+ // case qualifier "." name as type identifier
+ // this requires an outer field-access (qualifier.name.field),
+ // as the end result has to be an expression
+ if (exprType.isEmpty() && resultsAreOptional) {
+ typeId = calculateTypeIdQName(expr);
+ }
+ }
+
+ // store expression type
+ if (exprType.isPresent()) {
+ getType4Ast().setTypeOfExpression(expr, exprType.get());
+ }
+ else if (!resultsAreOptional) {
+ // error already logged
+ getType4Ast().setTypeOfExpression(expr, SymTypeExpressionFactory.createObscureType());
+ }
+ // store type id
+ if (typeId.isPresent()) {
+ getType4Ast().setTypeOfTypeIdentifierForName(expr, typeId.get());
+ }
+ }
+
+ // The following functions all interpret field access / name expressions
+
+ /**
+ * case: expression "." name,
+ * e.g., getX().var.
+ * will log an error if necessary (resultsAreOptional).
+ */
+ protected Optional calculateExprFieldAccessOrLogError(
+ ASTFieldAccessExpression expr,
+ boolean resultsAreOptional
+ ) {
+ Optional type = calculateExprFieldAccess(expr);
+ if (type.isEmpty() && !resultsAreOptional) {
+ Log.error("0xF737F given expression of type "
+ + getType4Ast().getPartialTypeOfExpr(expr.getExpression()).printFullName()
+ + " unable to derive the type of the access \"."
+ + expr.getName() + "\"",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ return type;
+ }
+
+ /**
+ * calculates a.b with a being an expression,
+ * e.g., getX().var
+ */
+ protected Optional calculateExprFieldAccess(
+ ASTFieldAccessExpression expr) {
+ Set types = new HashSet<>();
+ final String name = expr.getName();
+ if (!getType4Ast().hasTypeOfExpression(expr.getExpression())) {
+ Log.error("0xFD231 internal error:"
+ + "unable to find type identifier for field access",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ else {
+ SymTypeExpression innerAsExprType =
+ getType4Ast().getPartialTypeOfExpr(expr.getExpression());
+ if (getWithinTypeResolver().canResolveIn(innerAsExprType)) {
+ AccessModifier modifier = innerAsExprType.hasTypeInfo() ?
+ getTypeCtxCalc().getAccessModifier(
+ innerAsExprType.getTypeInfo(), expr.getEnclosingScope()
+ ) : AccessModifier.ALL_INCLUSION;
+ Optional variable =
+ getWithinTypeResolver().resolveVariable(innerAsExprType,
+ name,
+ modifier,
+ v -> true
+ );
+ if (variable.isPresent()) {
+ types.add(variable.get());
+ }
+ Collection functions =
+ getWithinTypeResolver().resolveFunctions(
+ innerAsExprType,
+ name,
+ modifier,
+ f -> true
+ );
+ types.addAll(functions);
+ }
+ // extension point
+ else {
+ Log.error("0xFDB3A unexpected field access \""
+ + expr.getName()
+ + "\" for type "
+ + innerAsExprType.printFullName(),
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ }
+ if (types.size() <= 1) {
+ return types.stream().findAny();
+ }
+ else {
+ return Optional.of(SymTypeExpressionFactory.createIntersection(types));
+ }
+ }
+
+ /**
+ * case: typeIdentifier "." name,
+ * e.g., XClass.staticVar.
+ * will log an error if necessary (resultsAreOptional).
+ */
+ protected Optional calculateTypeIdFieldAccessOrLogError(
+ ASTFieldAccessExpression expr,
+ boolean resultsAreOptional
+ ) {
+ Optional type = calculateTypeIdFieldAccess(expr);
+ if (type.isEmpty() && !resultsAreOptional) {
+ Log.error("0xF736F given type identifier of type "
+ + getType4Ast().getPartialTypeOfTypeIdForName(expr.getExpression()).printFullName()
+ + " unable to derive the type of the access \"."
+ + expr.getName() + "\"",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ return type;
+ }
+
+ /**
+ * calculates a.b.c with a.b being a type identifier,
+ * e.g., XClass.staticVar
+ */
+ protected Optional calculateTypeIdFieldAccess(
+ ASTFieldAccessExpression expr) {
+ final String name = expr.getName();
+ Set types = new HashSet<>();
+ if (!getType4Ast().hasTypeOfTypeIdentifierForName(expr.getExpression())) {
+ Log.error("0xFD232 internal error:"
+ + "unable to find type identifier for field access",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ else {
+ SymTypeExpression innerAsTypeIdType =
+ getType4Ast().getPartialTypeOfTypeIdForName(expr.getExpression());
+ if (getWithinTypeResolver().canResolveIn(innerAsTypeIdType)) {
+ AccessModifier modifier = innerAsTypeIdType.hasTypeInfo() ?
+ getTypeCtxCalc().getAccessModifier(
+ innerAsTypeIdType.getTypeInfo(),
+ expr.getEnclosingScope(),
+ true
+ ) : StaticAccessModifier.STATIC;
+ Optional variable =
+ getWithinTypeResolver().resolveVariable(
+ innerAsTypeIdType,
+ name,
+ modifier,
+ v -> true
+ );
+ variable.ifPresent(types::add);
+ Collection functions =
+ getWithinTypeResolver().resolveFunctions(
+ innerAsTypeIdType,
+ name,
+ modifier,
+ f -> true
+ );
+ types.addAll(functions);
+ }
+ // extension point
+ else {
+ Log.error("0xFDE3A unexpected field access \""
+ + expr.getName()
+ + "\" for type "
+ + innerAsTypeIdType.printFullName(),
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ }
+ if (types.size() <= 1) {
+ return types.stream().findAny();
+ }
+ else {
+ return Optional.of(SymTypeExpressionFactory.createIntersection(types));
+ }
+ }
+
+ /**
+ * calculates a.b.c as a type identifier with a.b being a type identifier,
+ * e.g., OuterClass.InnerClass.StaticVariable
+ */
+ protected Optional calculateInnerTypeIdFieldAccess(
+ ASTFieldAccessExpression expr) {
+ final String name = expr.getName();
+ Optional type = Optional.empty();
+ if (!getType4Ast().hasTypeOfTypeIdentifierForName(expr.getExpression())) {
+ Log.error("0xFD233 internal error:"
+ + "unable to find type identifier for field access",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ else {
+ SymTypeExpression innerAsTypeIdType =
+ getType4Ast().getPartialTypeOfTypeIdForName(expr.getExpression());
+ if (getWithinTypeResolver().canResolveIn(innerAsTypeIdType)) {
+ AccessModifier modifier = innerAsTypeIdType.hasTypeInfo() ?
+ getTypeCtxCalc().getAccessModifier(
+ innerAsTypeIdType.getTypeInfo(),
+ expr.getEnclosingScope(),
+ true
+ ) : StaticAccessModifier.STATIC;
+ type = getWithinTypeResolver().resolveType(
+ innerAsTypeIdType,
+ name,
+ getTypeCtxCalc().getAccessModifier(
+ innerAsTypeIdType.getTypeInfo(),
+ expr.getEnclosingScope(),
+ true
+ ),
+ t -> true
+ );
+ }
+ else {
+ Log.error("0xFDE3A unexpected field access \""
+ + expr.getName()
+ + "\" for type "
+ + innerAsTypeIdType.printFullName(),
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ }
+ return type;
+ }
+
+ /**
+ * case: qName "." name,
+ * e.g., package.artifact.staticVar.
+ * will log an error if necessary (resultsAreOptional).
+ */
+ protected Optional calculateExprQNameOrLogError(
+ ASTFieldAccessExpression expr,
+ boolean resultsAreOptional
+ ) {
+ // case qualifier "." name as an expression
+ Optional type = calculateExprQName(expr);
+ if (type.isEmpty() && !resultsAreOptional) {
+ if (isSeriesOfNames(expr)) {
+ Log.error("0xF735F unable to interpret qualified name \""
+ + getExprAsQName(expr).get()
+ + "\" as expression",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ }
+ else {
+ // error already logged
+ }
+ }
+ return type;
+ }
+
+ /**
+ * calculates a.b.c as expression with a.b being a qualifier
+ */
+ protected Optional calculateExprQName(
+ ASTFieldAccessExpression expr) {
+ Optional nameOpt = getExprAsQName(expr);
+ Optional type;
+ if (nameOpt.isPresent()) {
+ type = getNameExpressionTypeCalculator().
+ typeOfNameAsExpr(
+ getAsBasicSymbolsScope(expr.getEnclosingScope()),
+ nameOpt.get()
+ );
+ }
+ else {
+ type = Optional.empty();
+ }
+ return type;
+ }
+
+ /**
+ * calculates "a" as expression
+ */
+ protected Optional calculateExprQName(
+ ASTNameExpression expr) {
+ return getNameExpressionTypeCalculator().typeOfNameAsExpr(
+ getAsBasicSymbolsScope(expr.getEnclosingScope()),
+ expr.getName()
+ );
+ }
+
+ /**
+ * calculates a.b.c as type identifier with a.b being a qualifier.
+ * only evaluates qualified names without type arguments
+ *
+ * s.a. {@link #getExprAsQName(ASTExpression)}
+ */
+ protected Optional calculateTypeIdQName(
+ ASTFieldAccessExpression expr) {
+ Optional nameOpt = getExprAsQName(expr);
+ Optional type;
+ if (nameOpt.isPresent()) {
+ type = getNameExpressionTypeCalculator().
+ typeOfNameAsTypeId(
+ getAsBasicSymbolsScope(expr.getEnclosingScope()),
+ nameOpt.get()
+ );
+ }
+ else {
+ type = Optional.empty();
+ }
+ return type;
+ }
+
+ /**
+ * calculates "a" as type identifier
+ */
+ protected Optional calculateTypeIdQName(
+ ASTNameExpression expr) {
+ return getNameExpressionTypeCalculator().typeOfNameAsTypeId(
+ getAsBasicSymbolsScope(expr.getEnclosingScope()),
+ expr.getName()
+ );
+ }
+
+ // Helper
+
+ /**
+ * For FieldAccessExpression / CallExpression
+ * given expression "." name,
+ * expression may be a (qualified) name for
+ * * a type (for static members)
+ * * a value (global variable / function)
+ * this analyses the expression and returns a qualified name if possible,
+ * which _may_ be of a type / value
+ * Note: Java (Spec v.20 chapter 19: Syntax) does not allow type arguments,
+ * e.g., class C{T t;} C.t = 3.2;
+ */
+ protected Optional getExprAsQName(ASTExpression expr) {
+ if (getTypeDispatcher().isASTNameExpression(expr)) {
+ ASTNameExpression nameExpr = (ASTNameExpression) expr;
+ return Optional.of(nameExpr.getName());
+ }
+ else if (getTypeDispatcher().isASTFieldAccessExpression(expr)) {
+ ASTFieldAccessExpression fieldAccessExpression =
+ (ASTFieldAccessExpression) expr;
+ return getExprAsQName(fieldAccessExpression.getExpression())
+ .map(qualifier ->
+ Names.getQualifiedName(qualifier, fieldAccessExpression.getName())
+ );
+ }
+ else {
+ return Optional.empty();
+ }
+ }
+
+ /**
+ * does the expression have a form like a.b.c.d?
+ */
+ protected boolean isSeriesOfNames(ASTExpression expr) {
+ if (getTypeDispatcher().isASTNameExpression(expr)) {
+ return true;
+ }
+ if (getTypeDispatcher().isASTFieldAccessExpression(expr)) {
+ return isSeriesOfNames(
+ getTypeDispatcher().asASTFieldAccessExpression(expr).getExpression()
+ );
+ }
+ else {
+ return false;
+ }
+ }
+
+ protected SymTypeExpression calculateNumericPrefix(
+ ASTExpression innerExpr, String op) {
+ SymTypeExpression innerType = getType4Ast().getPartialTypeOfExpr(innerExpr);
+ if (innerType.isObscureType()) {
+ return createObscureType();
+ }
+ if (!getTypeRel().isNumericType(innerType)) {
+ Log.error("0xA017D Prefix Operator '" + op
+ + "' not applicable to " + "'" + innerType.print() + "'",
+ innerExpr.get_SourcePositionStart(),
+ innerExpr.get_SourcePositionEnd()
+ );
+ return createObscureType();
+ }
+ // in Java, an evaluation of the actual value
+ // would take place (if possible)
+ return getTypeRel().numericPromotion(innerType);
+ }
+
+ /**
+ * for <=, >=, <, >
+ * calculates the resulting type
+ */
+ protected SymTypeExpression calculateNumericComparison(
+ ASTInfixExpression expr, String op) {
+ SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft());
+ SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight());
+
+ if (left.isObscureType() || right.isObscureType()) {
+ // if any inner obscure then error already logged
+ return createObscureType();
+ }
+ // if the left and the right part of the expression are numerics,
+ // then the whole expression is a boolean
+ else if (getTypeRel().isNumericType(left) && getTypeRel().isNumericType(right)) {
+ return createPrimitive(BasicSymbolsMill.BOOLEAN);
+ }
+ else {
+ // operator not applicable
+ Log.error("0xB0167 Operator '" + op + "' not applicable to "
+ + "'" + left.print() + "', '"
+ + right.print() + "'",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ return createObscureType();
+ }
+ }
+
+ /**
+ * for +, -, *, /, %
+ * + -> String not supported
+ * calculates the resulting type
+ */
+ protected SymTypeExpression calculateArithmeticExpression(
+ ASTInfixExpression expr, String op) {
+ SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft());
+ SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight());
+
+ if (left.isObscureType() || right.isObscureType()) {
+ // if any inner obscure then error already logged
+ return createObscureType();
+ }
+ else if (getTypeRel().isNumericType(left) && getTypeRel().isNumericType(right)) {
+ return getTypeRel().numericPromotion(left, right);
+ }
+ else {
+ // operator not applicable
+ Log.error("0xB0163 Operator '" + op + "' not applicable to " +
+ "'" + left.print() + "', '"
+ + right.print() + "'",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ return createObscureType();
+ }
+ }
+
+ /**
+ * for ==, !=
+ * calculates the resulting type
+ */
+ protected SymTypeExpression calculateEquality(
+ ASTInfixExpression expr, String op) {
+ SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft());
+ SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight());
+
+ if (left.isObscureType() || right.isObscureType()) {
+ // if any inner obscure then error already logged
+ return createObscureType();
+ }
+ else if (left.isPrimitive() || right.isPrimitive()) {
+ // skip unboxing + numeric promotion if applicable
+ if (getTypeRel().isNumericType(left) && getTypeRel().isNumericType(right)) {
+ return SymTypeExpressionFactory.createPrimitive(BasicSymbolsMill.BOOLEAN);
+ }
+ left = getTypeRel().unbox(left);
+ right = getTypeRel().unbox(right);
+ }
+ if (getTypeRel().isCompatible(left, right)
+ || getTypeRel().isCompatible(right, left)) {
+ return SymTypeExpressionFactory.createPrimitive(BasicSymbolsMill.BOOLEAN);
+ }
+ else {
+ Log.error("0xB0166 Operator '" + op + "' not applicable to " +
+ "'" + left.print() + "', '"
+ + right.print() + "'",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ return createObscureType();
+ }
+ }
+
+ /**
+ * for &&, ||
+ * calculates the resulting type
+ */
+ protected SymTypeExpression calculateConditionalBooleanOp(
+ ASTInfixExpression expr, String op) {
+ SymTypeExpression left = getType4Ast().getPartialTypeOfExpr(expr.getLeft());
+ SymTypeExpression right = getType4Ast().getPartialTypeOfExpr(expr.getRight());
+
+ if (left.isObscureType() || right.isObscureType()) {
+ // if any inner obscure then error already logged
+ return createObscureType();
+ }
+ else if (getTypeRel().isBoolean(left) && getTypeRel().isBoolean(right)) {
+ return createPrimitive(BasicSymbolsMill.BOOLEAN);
+ }
+ else {
+ // operator not applicable
+ Log.error("0xB0113 Operator '" + op + "' not applicable to " +
+ "'" + left.print() + "', '"
+ + right.print() + "'",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ return createObscureType();
+ }
+ }
+
+ protected CommonExpressionsTypeDispatcher getTypeDispatcher() {
+ return CommonExpressionsMill.typeDispatcher();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/types3/util/CommonExpressionsLValueRelations.java b/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/types3/util/CommonExpressionsLValueRelations.java
new file mode 100644
index 0000000000..4da91ba67a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/commonexpressions/types3/util/CommonExpressionsLValueRelations.java
@@ -0,0 +1,32 @@
+// (c) https://github.com/MontiCore/monticore
+package de.monticore.expressions.commonexpressions.types3.util;
+
+import de.monticore.expressions.commonexpressions.CommonExpressionsMill;
+import de.monticore.expressions.commonexpressions._util.CommonExpressionsTypeDispatcher;
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.expressions.expressionsbasis.types3.util.ILValueRelations;
+
+public class CommonExpressionsLValueRelations implements ILValueRelations {
+
+ /**
+ * according to Java Spec 20 4.12.3
+ * Note: this is not an "isAssignable"-check,
+ * as the variable might be final (s. OOSymbols) and already assigned to.
+ */
+ @Override
+ public boolean isLValue(ASTExpression expression) {
+ CommonExpressionsTypeDispatcher dispatcher =
+ CommonExpressionsMill.typeDispatcher();
+ boolean result;
+ if (dispatcher.isASTNameExpression(expression)) {
+ result = true;
+ }
+ else if (dispatcher.isASTFieldAccessExpression(expression)) {
+ result = true;
+ }
+ else {
+ result = false;
+ }
+ return result;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_ast/ASTNameExpression.java b/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_ast/ASTNameExpression.java
new file mode 100644
index 0000000000..ee92f95a2e
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/_ast/ASTNameExpression.java
@@ -0,0 +1,19 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.expressionsbasis._ast;
+
+import de.monticore.symboltable.ISymbol;
+
+import java.util.Optional;
+
+public class ASTNameExpression extends ASTNameExpressionTOP {
+
+ protected ISymbol definingSymbol;
+
+ public Optional getDefiningSymbol() {
+ return Optional.ofNullable(this.definingSymbol);
+ }
+
+ public void setDefiningSymbol(ISymbol symbol) {
+ this.definingSymbol = symbol;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/types3/ExpressionBasisTypeVisitor.java b/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/types3/ExpressionBasisTypeVisitor.java
new file mode 100644
index 0000000000..46b388a696
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/expressionsbasis/types3/ExpressionBasisTypeVisitor.java
@@ -0,0 +1,74 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.expressionsbasis.types3;
+
+import de.monticore.expressions.expressionsbasis._ast.ASTLiteralExpression;
+import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression;
+import de.monticore.expressions.expressionsbasis._visitor.ExpressionsBasisVisitor2;
+import de.monticore.symbols.basicsymbols._symboltable.IBasicSymbolsScope;
+import de.monticore.types.check.SymTypeExpression;
+import de.monticore.types.check.SymTypeExpressionFactory;
+import de.monticore.types3.AbstractTypeVisitor;
+import de.monticore.types3.util.NameExpressionTypeCalculator;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Optional;
+
+public class ExpressionBasisTypeVisitor extends AbstractTypeVisitor
+ implements ExpressionsBasisVisitor2 {
+
+ protected NameExpressionTypeCalculator nameExpressionTypeCalculator;
+
+ public ExpressionBasisTypeVisitor() {
+ // default values
+ nameExpressionTypeCalculator = new NameExpressionTypeCalculator();
+ }
+
+ public void setNameExpressionTypeCalculator(
+ NameExpressionTypeCalculator nameExpressionTypeCalculator) {
+ this.nameExpressionTypeCalculator = nameExpressionTypeCalculator;
+ }
+
+ protected NameExpressionTypeCalculator getNameExpressionTypeCalculator() {
+ return nameExpressionTypeCalculator;
+ }
+
+ @Override
+ public void endVisit(ASTNameExpression expr) {
+ Optional wholeResult = calculateNameExpression(expr);
+ if (wholeResult.isPresent()) {
+ getType4Ast().setTypeOfExpression(expr, wholeResult.get());
+ }
+ else {
+ Log.error("0xFD118 could not find symbol for expression \""
+ + expr.getName() + "\"",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ getType4Ast().setTypeOfExpression(expr, SymTypeExpressionFactory.createObscureType());
+ }
+ }
+
+ protected Optional calculateNameExpression(
+ ASTNameExpression expr) {
+ if (expr.getEnclosingScope() == null) {
+ Log.error("0xFD161 internal error: "
+ + "enclosing scope of expression expected",
+ expr.get_SourcePositionStart(),
+ expr.get_SourcePositionEnd()
+ );
+ return Optional.empty();
+ }
+
+ final String name = expr.getName();
+ IBasicSymbolsScope enclosingScope =
+ getAsBasicSymbolsScope(expr.getEnclosingScope());
+ return getNameExpressionTypeCalculator().typeOfNameAsExpr(enclosingScope, name);
+ }
+
+ @Override
+ public void endVisit(ASTLiteralExpression expr) {
+ getType4Ast().setTypeOfExpression(expr,
+ getType4Ast().getPartialTypeOfExpr(expr.getLiteral())
+ );
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/AssignmentExpressionsFullJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/AssignmentExpressionsFullJavaPrinter.java
new file mode 100644
index 0000000000..62db9cae5d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/AssignmentExpressionsFullJavaPrinter.java
@@ -0,0 +1,33 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.assignmentexpressions.AssignmentExpressionsMill;
+import de.monticore.expressions.assignmentexpressions._visitor.AssignmentExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class AssignmentExpressionsFullJavaPrinter extends ExpressionsBasisFullJavaPrinter{
+
+ protected AssignmentExpressionsTraverser traverser;
+
+ @Override
+ public AssignmentExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(AssignmentExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public AssignmentExpressionsFullJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = AssignmentExpressionsMill.traverser();
+
+ AssignmentExpressionsJavaPrinter assignmentExpressions = new AssignmentExpressionsJavaPrinter(printer);
+ traverser.setAssignmentExpressionsHandler(assignmentExpressions);
+ traverser.add4AssignmentExpressions(assignmentExpressions);
+ ExpressionsBasisJavaPrinter basisExpression = new ExpressionsBasisJavaPrinter(printer);
+ traverser.setExpressionsBasisHandler(basisExpression);
+ traverser.add4ExpressionsBasis(basisExpression);
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/AssignmentExpressionsJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/AssignmentExpressionsJavaPrinter.java
new file mode 100644
index 0000000000..778b99328f
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/AssignmentExpressionsJavaPrinter.java
@@ -0,0 +1,19 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.prettyprint.AssignmentExpressionsPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class AssignmentExpressionsJavaPrinter extends AssignmentExpressionsPrettyPrinter {
+
+ public AssignmentExpressionsJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ this.printer = printer;
+ }
+
+ public AssignmentExpressionsJavaPrinter() {
+ super(new IndentPrinter());
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/BitExpressionsFullJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/BitExpressionsFullJavaPrinter.java
new file mode 100644
index 0000000000..ffa20b2754
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/BitExpressionsFullJavaPrinter.java
@@ -0,0 +1,39 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;/* (c) https://github.com/MontiCore/monticore */
+
+import de.monticore.expressions.bitexpressions.BitExpressionsMill;
+import de.monticore.expressions.bitexpressions._visitor.BitExpressionsTraverser;
+import de.monticore.expressions.prettyprint.BitExpressionsPrettyPrinter;
+import de.monticore.expressions.prettyprint.ExpressionsBasisPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class BitExpressionsFullJavaPrinter extends ExpressionsBasisFullJavaPrinter {
+
+ protected BitExpressionsTraverser traverser;
+
+ @Override
+ public BitExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(BitExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public BitExpressionsFullJavaPrinter(IndentPrinter printer) {
+
+ super(printer);
+ this.traverser = BitExpressionsMill.traverser();
+
+ ExpressionsBasisJavaPrinter basisExpression = new ExpressionsBasisJavaPrinter(printer);
+ traverser.setExpressionsBasisHandler(basisExpression);
+ traverser.add4ExpressionsBasis(basisExpression);
+ BitExpressionsJavaPrinter bitExpressions = new BitExpressionsJavaPrinter(printer);
+ traverser.setBitExpressionsHandler(bitExpressions);
+ traverser.add4BitExpressions(bitExpressions);
+
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/BitExpressionsJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/BitExpressionsJavaPrinter.java
new file mode 100644
index 0000000000..8c48d8a8ad
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/BitExpressionsJavaPrinter.java
@@ -0,0 +1,18 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;/* (c) https://github.com/MontiCore/monticore */
+
+import de.monticore.expressions.prettyprint.BitExpressionsPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class BitExpressionsJavaPrinter extends BitExpressionsPrettyPrinter {
+
+ public BitExpressionsJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ }
+
+ public BitExpressionsJavaPrinter() {
+ super(new IndentPrinter());
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/CommonExpressionsFullJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/CommonExpressionsFullJavaPrinter.java
new file mode 100644
index 0000000000..082fe7d606
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/CommonExpressionsFullJavaPrinter.java
@@ -0,0 +1,33 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.commonexpressions.CommonExpressionsMill;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class CommonExpressionsFullJavaPrinter extends ExpressionsBasisFullJavaPrinter {
+
+ protected CommonExpressionsTraverser traverser;
+
+ public CommonExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(CommonExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public CommonExpressionsFullJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = CommonExpressionsMill.traverser();
+
+ LegacyCommonExpressionsJavaPrinter commonExpressions = new LegacyCommonExpressionsJavaPrinter(printer);
+ traverser.setCommonExpressionsHandler(commonExpressions);
+ traverser.add4CommonExpressions(commonExpressions);
+ ExpressionsBasisJavaPrinter basicExpression = new ExpressionsBasisJavaPrinter(printer);
+ traverser.setExpressionsBasisHandler(basicExpression);
+ traverser.add4ExpressionsBasis(basicExpression);
+
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/CommonExpressionsJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/CommonExpressionsJavaPrinter.java
new file mode 100644
index 0000000000..5c79619fac
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/CommonExpressionsJavaPrinter.java
@@ -0,0 +1,43 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression;
+import de.monticore.expressions.commonexpressions._prettyprint.CommonExpressionsPrettyPrinter;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+
+public class CommonExpressionsJavaPrinter extends CommonExpressionsPrettyPrinter {
+
+ public CommonExpressionsJavaPrinter(IndentPrinter printer, boolean printComments) {
+ super(printer, printComments);
+ }
+
+ @Override
+ public void handle(ASTFieldAccessExpression node) {
+ if (this.isPrintComments()) {
+ de.monticore.prettyprint.CommentPrettyPrinter.printPreComments(node, getPrinter());
+ }
+ node.getExpression().accept(getTraverser());
+ getPrinter().stripTrailing();
+ getPrinter().print(".");
+ String name = "get" + node.getName().substring(0, 1).toUpperCase() + node.getName().substring(1) + "()";
+ getPrinter().print(name);
+ if (this.isPrintComments()) {
+ de.monticore.prettyprint.CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+ }
+
+ /**
+ * Apply this overridden handling of FieldAccessExpressions to a FullPrettyPrinter
+ * @param traverser the FullPrettyPrinters traverser
+ * @param indentPrinter the printer to use
+ * @param printComments whether to print comments
+ */
+ public static void applyJavaPrinter(T traverser, IndentPrinter indentPrinter, boolean printComments){
+ CommonExpressionsJavaPrinter commonExpressionsJavaPrinter = new CommonExpressionsJavaPrinter(indentPrinter, printComments);
+ traverser.getCommonExpressionsVisitorList().clear();
+ traverser.add4CommonExpressions(commonExpressionsJavaPrinter);
+ traverser.setCommonExpressionsHandler(commonExpressionsJavaPrinter);
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/ExpressionsBasisFullJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/ExpressionsBasisFullJavaPrinter.java
new file mode 100644
index 0000000000..905ef4b770
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/ExpressionsBasisFullJavaPrinter.java
@@ -0,0 +1,47 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.expressionsbasis.ExpressionsBasisMill;
+import de.monticore.expressions.expressionsbasis._ast.ASTExpressionsBasisNode;
+import de.monticore.expressions.expressionsbasis._visitor.ExpressionsBasisTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class ExpressionsBasisFullJavaPrinter {
+
+ protected ExpressionsBasisTraverser traverser;
+
+ protected IndentPrinter printer;
+
+ public ExpressionsBasisFullJavaPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ this.traverser = ExpressionsBasisMill.traverser();
+
+ ExpressionsBasisJavaPrinter basisExpression = new ExpressionsBasisJavaPrinter(printer);
+ traverser.setExpressionsBasisHandler(basisExpression);
+ traverser.add4ExpressionsBasis(basisExpression);
+ }
+
+ public ExpressionsBasisTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(ExpressionsBasisTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public IndentPrinter getPrinter() {
+ return printer;
+ }
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ public String print(ASTExpressionsBasisNode a) {
+ getPrinter().clearBuffer();
+ a.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/ExpressionsBasisJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/ExpressionsBasisJavaPrinter.java
new file mode 100644
index 0000000000..63c1d1588a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/ExpressionsBasisJavaPrinter.java
@@ -0,0 +1,18 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;/* (c) https://github.com/MontiCore/monticore */
+
+import de.monticore.expressions.prettyprint.ExpressionsBasisPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class ExpressionsBasisJavaPrinter extends ExpressionsBasisPrettyPrinter {
+
+ public ExpressionsBasisJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ }
+
+ public ExpressionsBasisJavaPrinter() {
+ super(new IndentPrinter());
+ }
+
+}
\ No newline at end of file
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/JavaClassExpressionsFullJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/JavaClassExpressionsFullJavaPrinter.java
new file mode 100644
index 0000000000..fb0ce0c493
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/JavaClassExpressionsFullJavaPrinter.java
@@ -0,0 +1,66 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.javaclassexpressions.JavaClassExpressionsMill;
+import de.monticore.expressions.javaclassexpressions._ast.ASTGenericInvocationSuffix;
+import de.monticore.expressions.javaclassexpressions._ast.ASTTypePattern;
+import de.monticore.expressions.javaclassexpressions._visitor.JavaClassExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.statements.mcstatementsbasis._prettyprint.MCStatementsBasisPrettyPrinter;
+import de.monticore.statements.prettyprint.MCVarDeclarationStatementsPrettyPrinter;
+import de.monticore.types.prettyprint.MCBasicTypesPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class JavaClassExpressionsFullJavaPrinter extends CommonExpressionsFullJavaPrinter {
+
+ protected JavaClassExpressionsTraverser traverser;
+
+ @Override
+ public JavaClassExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(JavaClassExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public JavaClassExpressionsFullJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = JavaClassExpressionsMill.traverser();
+
+ LegacyCommonExpressionsJavaPrinter commonExpression = new LegacyCommonExpressionsJavaPrinter(printer);
+ traverser.setCommonExpressionsHandler(commonExpression);
+ traverser.add4CommonExpressions(commonExpression);
+ ExpressionsBasisJavaPrinter expressionBasis = new ExpressionsBasisJavaPrinter(printer);
+ traverser.setExpressionsBasisHandler(expressionBasis);
+ traverser.add4ExpressionsBasis(expressionBasis);
+ JavaClassExpressionsJavaPrinter javaClassExpression = new JavaClassExpressionsJavaPrinter(printer);
+ traverser.setJavaClassExpressionsHandler(javaClassExpression);
+ traverser.add4JavaClassExpressions(javaClassExpression);
+
+ MCBasicTypesPrettyPrinter mcBasicTypes = new MCBasicTypesPrettyPrinter(printer);
+ traverser.setMCBasicTypesHandler(mcBasicTypes);
+ traverser.add4MCBasicTypes(mcBasicTypes);
+
+ MCStatementsBasisPrettyPrinter mcStatementsBasis = new MCStatementsBasisPrettyPrinter(printer, true);
+ traverser.setMCStatementsBasisHandler(mcStatementsBasis);
+ traverser.add4MCStatementsBasis(mcStatementsBasis);
+
+ MCVarDeclarationStatementsPrettyPrinter mcVarDeclarationStatements = new MCVarDeclarationStatementsPrettyPrinter(printer);
+ traverser.setMCVarDeclarationStatementsHandler(mcVarDeclarationStatements);
+ traverser.add4MCVarDeclarationStatements(mcVarDeclarationStatements);
+ }
+
+ public String print(ASTGenericInvocationSuffix node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+ public String print(ASTTypePattern node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/JavaClassExpressionsJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/JavaClassExpressionsJavaPrinter.java
new file mode 100644
index 0000000000..b2abe20aa8
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/JavaClassExpressionsJavaPrinter.java
@@ -0,0 +1,18 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;/* (c) https://github.com/MontiCore/monticore */
+
+import de.monticore.expressions.prettyprint.JavaClassExpressionsPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class JavaClassExpressionsJavaPrinter extends JavaClassExpressionsPrettyPrinter {
+
+ public JavaClassExpressionsJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ }
+
+ public JavaClassExpressionsJavaPrinter() {
+ super(new IndentPrinter());
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LambdaExpressionsFullJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LambdaExpressionsFullJavaPrinter.java
new file mode 100644
index 0000000000..59557979fe
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LambdaExpressionsFullJavaPrinter.java
@@ -0,0 +1,41 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.expressions.lambdaexpressions.LambdaExpressionsMill;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class LambdaExpressionsFullJavaPrinter extends ExpressionsBasisFullJavaPrinter {
+
+ protected LambdaExpressionsTraverser traverser;
+
+ @Override
+ public LambdaExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(LambdaExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public LambdaExpressionsFullJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = LambdaExpressionsMill.traverser();
+
+ ExpressionsBasisJavaPrinter expressionBasis = new ExpressionsBasisJavaPrinter(printer);
+ traverser.setExpressionsBasisHandler(expressionBasis);
+ traverser.add4ExpressionsBasis(expressionBasis);
+ LambdaExpressionsJavaPrinter javaClassExpression = new LambdaExpressionsJavaPrinter(printer);
+ traverser.setLambdaExpressionsHandler(javaClassExpression);
+ traverser.add4LambdaExpressions(javaClassExpression);
+ }
+
+ public String print(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LambdaExpressionsJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LambdaExpressionsJavaPrinter.java
new file mode 100644
index 0000000000..cec2edbda2
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LambdaExpressionsJavaPrinter.java
@@ -0,0 +1,18 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;/* (c) https://github.com/MontiCore/monticore */
+
+import de.monticore.expressions.prettyprint.LambdaExpressionsPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class LambdaExpressionsJavaPrinter extends LambdaExpressionsPrettyPrinter {
+
+ public LambdaExpressionsJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ }
+
+ public LambdaExpressionsJavaPrinter() {
+ super(new IndentPrinter());
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LegacyCommonExpressionsJavaPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LegacyCommonExpressionsJavaPrinter.java
new file mode 100644
index 0000000000..e0217f788b
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/exptojava/LegacyCommonExpressionsJavaPrinter.java
@@ -0,0 +1,53 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.exptojava;
+
+import de.monticore.expressions.commonexpressions._ast.ASTFieldAccessExpression;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser;
+import de.monticore.expressions.prettyprint.CommonExpressionsPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+/**
+ * @deprecated use {@link CommonExpressionsJavaPrinter} instead
+ */
+@Deprecated(forRemoval = true)
+public class LegacyCommonExpressionsJavaPrinter extends CommonExpressionsPrettyPrinter {
+
+ protected CommonExpressionsTraverser traverser;
+
+ protected IndentPrinter printer;
+
+ @Override
+ public CommonExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ @Override
+ public void setTraverser(CommonExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public IndentPrinter getPrinter() {
+ return printer;
+ }
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ public LegacyCommonExpressionsJavaPrinter(IndentPrinter printer) {
+ super(printer);
+ this.printer = printer;
+ }
+
+ public LegacyCommonExpressionsJavaPrinter(){
+ super(new IndentPrinter());
+ }
+
+ @Override //TODO: READD ME
+ public void handle(ASTFieldAccessExpression node) {
+ node.getExpression().accept(getTraverser());
+ String name = "get"+ node.getName().substring(0,1).toUpperCase() + node.getName().substring(1)+"()";
+ getPrinter().print("."+name);
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_symboltable/LambdaExpressionsSTCompleteTypes.java b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_symboltable/LambdaExpressionsSTCompleteTypes.java
new file mode 100644
index 0000000000..95fc2b40eb
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_symboltable/LambdaExpressionsSTCompleteTypes.java
@@ -0,0 +1,39 @@
+// (c) https://github.com/MontiCore/monticore
+package de.monticore.expressions.lambdaexpressions._symboltable;
+
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameter;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsVisitor2;
+import de.monticore.types.check.ISynthesize;
+import de.monticore.types.check.SymTypeExpression;
+import de.monticore.types.check.SymTypeOfNull;
+import de.monticore.types.check.TypeCheckResult;
+import de.monticore.types.mcbasictypes._ast.ASTMCType;
+
+public class LambdaExpressionsSTCompleteTypes implements LambdaExpressionsVisitor2 {
+
+ ISynthesize synthesize;
+
+ public LambdaExpressionsSTCompleteTypes(ISynthesize synthesize) {
+ this.synthesize = synthesize;
+ }
+
+ protected ISynthesize getSynthesize() {
+ return synthesize;
+ }
+
+ @Override
+ public void endVisit(ASTLambdaParameter ast) {
+ if (ast.isPresentMCType()) {
+ ast.getSymbol().setType(createTypeLoader(ast.getMCType()));
+ }
+ }
+
+ protected SymTypeExpression createTypeLoader(ASTMCType ast) {
+ TypeCheckResult typeCheckResult = getSynthesize().synthesizeType(ast);
+ if (typeCheckResult.isPresentResult()) {
+ return typeCheckResult.getResult();
+ }
+ return new SymTypeOfNull();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_symboltable/LambdaExpressionsSTCompleteTypes2.java b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_symboltable/LambdaExpressionsSTCompleteTypes2.java
new file mode 100644
index 0000000000..67c48f100b
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/_symboltable/LambdaExpressionsSTCompleteTypes2.java
@@ -0,0 +1,56 @@
+// (c) https://github.com/MontiCore/monticore
+package de.monticore.expressions.lambdaexpressions._symboltable;
+
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameter;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsVisitor2;
+import de.monticore.types.check.SymTypeExpression;
+import de.monticore.types.mcbasictypes._ast.ASTMCType;
+import de.monticore.types3.Type4Ast;
+import de.monticore.visitor.ITraverser;
+
+public class LambdaExpressionsSTCompleteTypes2 implements LambdaExpressionsVisitor2 {
+
+ // to be moved into the mill after details are discussed
+ @Deprecated
+ private Type4Ast type4Ast = null;
+
+ // the traverser filling the type map
+ // not required, if the map is already filled
+ protected ITraverser typeTraverser;
+
+ protected Type4Ast getTypeMap() {
+ return type4Ast;
+ }
+
+ protected ITraverser getTypeTraverser() {
+ return typeTraverser;
+ }
+
+ // after moving the typemap, the other constructor ought to be used
+ @Deprecated
+ public LambdaExpressionsSTCompleteTypes2(ITraverser typeTraverser, Type4Ast type4Ast) {
+ this(typeTraverser);
+ this.type4Ast = type4Ast;
+ }
+
+ public LambdaExpressionsSTCompleteTypes2(ITraverser typeTraverser) {
+ this.typeTraverser = typeTraverser;
+ }
+
+ @Override
+ public void endVisit(ASTLambdaParameter ast) {
+ if (ast.isPresentMCType()) {
+ ast.getSymbol().setType(calculateType(ast.getMCType()));
+ }
+ }
+
+ // Helper
+
+ protected SymTypeExpression calculateType(ASTMCType mcType) {
+ if (!getTypeMap().hasTypeOfTypeIdentifier(mcType)) {
+ mcType.accept(getTypeTraverser());
+ }
+ return getTypeMap().getTypeOfTypeIdentifier(mcType);
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/types3/LambdaExpressionsTypeVisitor.java b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/types3/LambdaExpressionsTypeVisitor.java
new file mode 100644
index 0000000000..f01c09801a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/lambdaexpressions/types3/LambdaExpressionsTypeVisitor.java
@@ -0,0 +1,56 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.lambdaexpressions.types3;
+
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaExpression;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaExpressionBody;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameter;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsVisitor2;
+import de.monticore.types.check.SymTypeExpression;
+import de.monticore.types.check.SymTypeExpressionFactory;
+import de.monticore.types3.AbstractTypeVisitor;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class LambdaExpressionsTypeVisitor extends AbstractTypeVisitor
+ implements LambdaExpressionsVisitor2 {
+
+ @Override
+ public void endVisit(ASTLambdaExpression exp) {
+ SymTypeExpression returnType = exp.getLambdaBody().getType();
+
+ List parameters = new LinkedList<>();
+ boolean obscureParams = false;
+ for (ASTLambdaParameter parameter : exp.getLambdaParameters().getLambdaParameterList()) {
+ SymTypeExpression paramSymType = calculateTypeOfLambdaParameter(parameter);
+ parameters.add(paramSymType);
+ if (paramSymType.isObscureType()) {
+ obscureParams = true;
+ }
+ }
+
+ if (!returnType.isObscureType() && !obscureParams) {
+ SymTypeExpression wholeResult =
+ SymTypeExpressionFactory.createFunction(returnType, parameters);
+ getType4Ast().setTypeOfExpression(exp, wholeResult);
+ }
+ else {
+ getType4Ast().setTypeOfExpression(exp, SymTypeExpressionFactory.createObscureType());
+ }
+ }
+
+ @Override
+ public void endVisit(ASTLambdaExpressionBody body) {
+ body.setType(getType4Ast().getPartialTypeOfExpr(body.getExpression()));
+ }
+
+ protected SymTypeExpression calculateTypeOfLambdaParameter(ASTLambdaParameter parameter) {
+ if (parameter.isPresentMCType()) {
+ return getType4Ast().getPartialTypeOfTypeId(parameter.getMCType());
+ }
+ Log.error("0xBC373 unable to calculate type of lambda parameter",
+ parameter.get_SourcePositionStart(), parameter.get_SourcePositionEnd());
+ return SymTypeExpressionFactory.createObscureType();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/AssignmentExpressionsFullPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/AssignmentExpressionsFullPrettyPrinter.java
new file mode 100644
index 0000000000..738939afc8
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/AssignmentExpressionsFullPrettyPrinter.java
@@ -0,0 +1,37 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.assignmentexpressions.AssignmentExpressionsMill;
+import de.monticore.expressions.assignmentexpressions._visitor.AssignmentExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+
+
+@Deprecated(forRemoval = true)
+public class AssignmentExpressionsFullPrettyPrinter extends ExpressionsBasisFullPrettyPrinter {
+
+ protected AssignmentExpressionsTraverser traverser;
+
+ public AssignmentExpressionsFullPrettyPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = AssignmentExpressionsMill.traverser();
+
+ AssignmentExpressionsPrettyPrinter assignmentExpressions = new AssignmentExpressionsPrettyPrinter(printer);
+ traverser.setAssignmentExpressionsHandler(assignmentExpressions);
+ traverser.add4AssignmentExpressions(assignmentExpressions);
+ ExpressionsBasisPrettyPrinter basisExpression = new ExpressionsBasisPrettyPrinter(printer);
+ traverser.setExpressionsBasisHandler(basisExpression);
+ traverser.add4ExpressionsBasis(basisExpression);
+ MCBasicsPrettyPrinter basic = new MCBasicsPrettyPrinter(printer);
+ traverser.add4MCBasics(basic);
+ }
+
+
+ public AssignmentExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(AssignmentExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/AssignmentExpressionsPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/AssignmentExpressionsPrettyPrinter.java
new file mode 100644
index 0000000000..36f028904d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/AssignmentExpressionsPrettyPrinter.java
@@ -0,0 +1,131 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.assignmentexpressions._ast.*;
+import de.monticore.expressions.assignmentexpressions._visitor.AssignmentExpressionsHandler;
+import de.monticore.expressions.assignmentexpressions._visitor.AssignmentExpressionsTraverser;
+import de.monticore.expressions.assignmentexpressions._visitor.AssignmentExpressionsVisitor2;
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.prettyprint.CommentPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+import de.se_rwth.commons.logging.Log;
+
+@Deprecated(forRemoval = true)
+public class AssignmentExpressionsPrettyPrinter implements AssignmentExpressionsVisitor2, AssignmentExpressionsHandler {
+
+ protected AssignmentExpressionsTraverser traverser;
+
+ @Override
+ public AssignmentExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ @Override
+ public void setTraverser(AssignmentExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ protected IndentPrinter printer;
+
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ public AssignmentExpressionsPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public void handle(ASTIncSuffixExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print("++");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTDecSuffixExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print("--");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTIncPrefixExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("++");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTDecPrefixExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("--");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTAssignmentExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ // ["="|"+="|"-="|"*="|"/="|"&="|"|="|"^="|">>="|">>>="|"<<="|"%="]
+ switch (node.getOperator()) {
+ case ASTConstantsAssignmentExpressions.EQUALS:
+ getPrinter().print(("="));
+ break;
+ case ASTConstantsAssignmentExpressions.PLUSEQUALS:
+ getPrinter().print(("+="));
+ break;
+ case ASTConstantsAssignmentExpressions.MINUSEQUALS:
+ getPrinter().print(("-="));
+ break;
+ case ASTConstantsAssignmentExpressions.STAREQUALS:
+ getPrinter().print(("*="));
+ break;
+ case ASTConstantsAssignmentExpressions.SLASHEQUALS:
+ getPrinter().print(("/="));
+ break;
+ case ASTConstantsAssignmentExpressions.AND_EQUALS:
+ getPrinter().print(("&="));
+ break;
+ case ASTConstantsAssignmentExpressions.PIPEEQUALS:
+ getPrinter().print(("|="));
+ break;
+ case ASTConstantsAssignmentExpressions.ROOFEQUALS:
+ getPrinter().print(("^="));
+ break;
+ case ASTConstantsAssignmentExpressions.GTGTEQUALS:
+ getPrinter().print((">>="));
+ break;
+ case ASTConstantsAssignmentExpressions.GTGTGTEQUALS:
+ getPrinter().print((">>>="));
+ break;
+ case ASTConstantsAssignmentExpressions.LTLTEQUALS:
+ getPrinter().print(("<<="));
+ break;
+ case ASTConstantsAssignmentExpressions.PERCENTEQUALS:
+ getPrinter().print(("%="));
+ break;
+ default:
+ Log.error("0xA0114 Missing implementation for RegularAssignmentExpression");
+ }
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+
+ public IndentPrinter getPrinter() {
+ return this.printer;
+ }
+
+ public String prettyprint(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/BitExpressionsFullPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/BitExpressionsFullPrettyPrinter.java
new file mode 100644
index 0000000000..29f02ae668
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/BitExpressionsFullPrettyPrinter.java
@@ -0,0 +1,36 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.bitexpressions.BitExpressionsMill;
+import de.monticore.expressions.bitexpressions._visitor.BitExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class BitExpressionsFullPrettyPrinter extends ExpressionsBasisFullPrettyPrinter {
+
+ protected BitExpressionsTraverser traverser;
+
+ public BitExpressionsFullPrettyPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = BitExpressionsMill.traverser();
+
+ ExpressionsBasisPrettyPrinter basisExpression = new ExpressionsBasisPrettyPrinter(printer);
+ traverser.setExpressionsBasisHandler(basisExpression);
+ traverser.add4ExpressionsBasis(basisExpression);
+ MCBasicsPrettyPrinter basics = new MCBasicsPrettyPrinter(printer);
+ traverser.add4MCBasics(basics);
+ BitExpressionsPrettyPrinter bitExpressions = new BitExpressionsPrettyPrinter(printer);
+ traverser.setBitExpressionsHandler(bitExpressions);
+ traverser.add4BitExpressions(bitExpressions);
+ }
+
+ @Override
+ public BitExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(BitExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/BitExpressionsPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/BitExpressionsPrettyPrinter.java
new file mode 100644
index 0000000000..37baf0a176
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/BitExpressionsPrettyPrinter.java
@@ -0,0 +1,89 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.bitexpressions._visitor.BitExpressionsHandler;
+import de.monticore.expressions.bitexpressions._visitor.BitExpressionsTraverser;
+import de.monticore.expressions.bitexpressions._visitor.BitExpressionsVisitor2;
+import de.monticore.prettyprint.CommentPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.expressions.bitexpressions._ast.*;
+
+@Deprecated(forRemoval = true)
+public class BitExpressionsPrettyPrinter implements BitExpressionsVisitor2, BitExpressionsHandler {
+
+ protected BitExpressionsTraverser traverser;
+
+ protected IndentPrinter printer;
+
+ public BitExpressionsPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public BitExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ @Override
+ public void setTraverser(BitExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ @Override
+ public void handle(ASTLeftShiftExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print("<<");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTRightShiftExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(">>");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLogicalRightShiftExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(">>>");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBinaryAndExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print("&");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBinaryXorExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print("^");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBinaryOrOpExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print("|");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ public IndentPrinter getPrinter() {
+ return this.printer;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/CommonExpressionsFullPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/CommonExpressionsFullPrettyPrinter.java
new file mode 100644
index 0000000000..af858fe3ff
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/CommonExpressionsFullPrettyPrinter.java
@@ -0,0 +1,36 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.commonexpressions.CommonExpressionsMill;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class CommonExpressionsFullPrettyPrinter extends ExpressionsBasisFullPrettyPrinter {
+ protected CommonExpressionsTraverser traverser;
+
+ @Override
+ public CommonExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(CommonExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public CommonExpressionsFullPrettyPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = CommonExpressionsMill.traverser();
+
+ CommonExpressionsPrettyPrinter commonExpressions = new CommonExpressionsPrettyPrinter(printer);
+ traverser.setCommonExpressionsHandler(commonExpressions);
+ traverser.add4CommonExpressions(commonExpressions);
+ ExpressionsBasisPrettyPrinter basicExpression = new ExpressionsBasisPrettyPrinter(printer);
+ traverser.setExpressionsBasisHandler(basicExpression);
+ traverser.add4ExpressionsBasis(basicExpression);
+ MCBasicsPrettyPrinter basic = new MCBasicsPrettyPrinter(printer);
+ traverser.add4MCBasics(basic);
+ }
+}
+
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/CommonExpressionsPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/CommonExpressionsPrettyPrinter.java
new file mode 100644
index 0000000000..9836769a3b
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/CommonExpressionsPrettyPrinter.java
@@ -0,0 +1,239 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.commonexpressions._ast.*;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsHandler;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsTraverser;
+import de.monticore.expressions.commonexpressions._visitor.CommonExpressionsVisitor2;
+import de.monticore.expressions.expressionsbasis._ast.ASTArguments;
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.prettyprint.CommentPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class CommonExpressionsPrettyPrinter implements CommonExpressionsVisitor2, CommonExpressionsHandler {
+
+ protected CommonExpressionsTraverser traverser;
+
+ protected IndentPrinter printer;
+
+ @Override
+ public void setTraverser(CommonExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public CommonExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public CommonExpressionsPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public void handle(ASTPlusPrefixExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("+");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTMinusPrefixExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("-");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTFieldAccessExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print("." + node.getName());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTMultExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" * ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTDivideExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" / ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTModuloExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" % ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTPlusExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" + ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTMinusExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" - ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLessEqualExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" <= ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTGreaterEqualExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" >= ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLessThanExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" < ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTGreaterThanExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" > ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBooleanAndOpExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" && ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBooleanOrOpExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" || ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTEqualsExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" == ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTNotEqualsExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLeft().accept(getTraverser());
+ getPrinter().print(" != ");
+ node.getRight().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTConditionalExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getCondition().accept(getTraverser());
+ getPrinter().print(" ? ");
+ node.getTrueExpression().accept(getTraverser());
+ getPrinter().print(" : ");
+ node.getFalseExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBracketExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("(");
+ node.getExpression().accept(getTraverser());
+ getPrinter().print(")");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTBooleanNotExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("~");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLogicalNotExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("!");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTCallExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ node.getArguments().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ public IndentPrinter getPrinter() {
+ return this.printer;
+ }
+
+ public String prettyprint(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+ public String prettyprint(ASTArguments node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/ExpressionsBasisFullPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/ExpressionsBasisFullPrettyPrinter.java
new file mode 100644
index 0000000000..38bf182ca9
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/ExpressionsBasisFullPrettyPrinter.java
@@ -0,0 +1,54 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.expressionsbasis.ExpressionsBasisMill;
+import de.monticore.expressions.expressionsbasis._ast.ASTExpressionsBasisNode;
+import de.monticore.expressions.expressionsbasis._visitor.ExpressionsBasisTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class ExpressionsBasisFullPrettyPrinter {
+ protected ExpressionsBasisTraverser traverser;
+
+ protected IndentPrinter printer;
+
+ public ExpressionsBasisFullPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ this.traverser = ExpressionsBasisMill.traverser();
+
+ ExpressionsBasisPrettyPrinter basisExpression = new ExpressionsBasisPrettyPrinter(printer);
+ traverser.setExpressionsBasisHandler(basisExpression);
+ traverser.add4ExpressionsBasis(basisExpression);
+ MCBasicsPrettyPrinter basics = new MCBasicsPrettyPrinter(printer);
+ traverser.add4MCBasics(basics);
+ }
+
+ public IndentPrinter getPrinter() {
+ return printer;
+ }
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ public ExpressionsBasisTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(ExpressionsBasisTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ /**
+ * This method prettyprints a given node from type grammar.
+ *
+ * @param a A node from type grammar.
+ * @return String representation.
+ */
+ public String prettyprint(ASTExpressionsBasisNode a) {
+ getPrinter().clearBuffer();
+ a.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/ExpressionsBasisPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/ExpressionsBasisPrettyPrinter.java
new file mode 100644
index 0000000000..7475c18646
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/ExpressionsBasisPrettyPrinter.java
@@ -0,0 +1,74 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.expressionsbasis._ast.ASTArguments;
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.expressions.expressionsbasis._ast.ASTLiteralExpression;
+import de.monticore.expressions.expressionsbasis._ast.ASTNameExpression;
+import de.monticore.expressions.expressionsbasis._visitor.ExpressionsBasisHandler;
+import de.monticore.expressions.expressionsbasis._visitor.ExpressionsBasisTraverser;
+import de.monticore.expressions.expressionsbasis._visitor.ExpressionsBasisVisitor2;
+import de.monticore.prettyprint.CommentPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class ExpressionsBasisPrettyPrinter implements ExpressionsBasisVisitor2, ExpressionsBasisHandler {
+
+ protected ExpressionsBasisTraverser traverser;
+
+ @Override
+ public void setTraverser(ExpressionsBasisTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ @Override
+ public ExpressionsBasisTraverser getTraverser() {
+ return traverser;
+ }
+
+ protected IndentPrinter printer;
+
+ public ExpressionsBasisPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ public IndentPrinter getPrinter() {
+ return printer;
+ }
+
+ @Override
+ public void handle(ASTNameExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print(node.getName());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLiteralExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLiteral().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTArguments node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("(");
+ String divider = "";
+ if (!node.isEmptyExpressions()) {
+ for (ASTExpression ast : node.getExpressionList()) {
+ getPrinter().print(divider);
+ ast.accept(getTraverser());
+ divider = ",";
+ }
+ }
+ getPrinter().print(")");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ public String prettyprint(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/JavaClassExpressionsFullPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/JavaClassExpressionsFullPrettyPrinter.java
new file mode 100644
index 0000000000..99194c2a1d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/JavaClassExpressionsFullPrettyPrinter.java
@@ -0,0 +1,45 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.javaclassexpressions.JavaClassExpressionsMill;
+import de.monticore.expressions.javaclassexpressions._ast.ASTGenericInvocationSuffix;
+import de.monticore.expressions.javaclassexpressions._visitor.JavaClassExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class JavaClassExpressionsFullPrettyPrinter extends CommonExpressionsFullPrettyPrinter {
+
+ protected JavaClassExpressionsTraverser traverser;
+
+ @Override
+ public JavaClassExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(JavaClassExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public JavaClassExpressionsFullPrettyPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = JavaClassExpressionsMill.traverser();
+ CommonExpressionsPrettyPrinter commonExpression = new CommonExpressionsPrettyPrinter(printer);
+ traverser.setCommonExpressionsHandler(commonExpression);
+ traverser.add4CommonExpressions(commonExpression);
+ ExpressionsBasisPrettyPrinter expressionBasis = new ExpressionsBasisPrettyPrinter(printer);
+ traverser.setExpressionsBasisHandler(expressionBasis);
+ traverser.add4ExpressionsBasis(expressionBasis);
+ JavaClassExpressionsPrettyPrinter javaClassExpression = new JavaClassExpressionsPrettyPrinter(printer);
+ traverser.setJavaClassExpressionsHandler(javaClassExpression);
+ traverser.add4JavaClassExpressions(javaClassExpression);
+ MCBasicsPrettyPrinter basic = new MCBasicsPrettyPrinter(printer);
+ traverser.add4MCBasics(basic);
+ }
+
+ public String prettyprint(ASTGenericInvocationSuffix node){
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/JavaClassExpressionsPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/JavaClassExpressionsPrettyPrinter.java
new file mode 100644
index 0000000000..2ab40162ea
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/JavaClassExpressionsPrettyPrinter.java
@@ -0,0 +1,250 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.expressions.javaclassexpressions._ast.*;
+import de.monticore.expressions.javaclassexpressions._visitor.JavaClassExpressionsHandler;
+import de.monticore.expressions.javaclassexpressions._visitor.JavaClassExpressionsTraverser;
+import de.monticore.expressions.javaclassexpressions._visitor.JavaClassExpressionsVisitor2;
+import de.monticore.prettyprint.CommentPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+import java.util.List;
+
+@Deprecated(forRemoval = true)
+public class JavaClassExpressionsPrettyPrinter implements JavaClassExpressionsVisitor2, JavaClassExpressionsHandler {
+
+ protected JavaClassExpressionsTraverser traverser;
+
+ @Override
+ public void setTraverser(JavaClassExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ @Override
+ public JavaClassExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ protected IndentPrinter printer;
+
+ public JavaClassExpressionsPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public void visit(ASTPrimarySuperExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("super");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTSuperSuffix node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ if (node.isPresentName()) {
+ getPrinter().print(".");
+ if (!node.getExtTypeArgumentList().isEmpty()) {
+ handleTypeArguments(node.getExtTypeArgumentList());
+ }
+ getPrinter().print(node.getName());
+ if (node.isPresentArguments()) {
+ node.getArguments().accept(getTraverser());
+ }
+ } else {
+ node.getArguments().accept(getTraverser());
+ }
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ protected void handleTypeArguments(List typeArguments){
+ getPrinter().print("<");
+ for (int i = 0; i < typeArguments.size(); i++) {
+ typeArguments.get(i).accept(getTraverser());
+ if (i != typeArguments.size() - 1) {
+ getPrinter().print(",");
+ }
+ }
+ getPrinter().print(">");
+ }
+
+ @Override
+ public void handle(ASTSuperExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print(".super");
+ node.getSuperSuffix().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTClassExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExtReturnType().accept(getTraverser());
+ getPrinter().print(".class");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTTypeCastExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("(");
+ node.getExtType().accept(getTraverser());
+ getPrinter().print(")");
+ node.getExpression().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTGenericInvocationSuffix node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ if (node.isPresentSuperSuffix()) {
+ if (node.isSuper()) {
+ getPrinter().print("super");
+ }
+ node.getSuperSuffix().accept(getTraverser());
+ } else if (node.isPresentName()) {
+ getPrinter().print(node.getName());
+ node.getArguments().accept(getTraverser());
+ } else {
+ if (node.isThis()) {
+ getPrinter().print("this");
+ }
+ node.getArguments().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ }
+
+ @Override
+ public void handle(ASTGenericInvocationExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print(".");
+ handle(node.getPrimaryGenericInvocationExpression());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTPrimaryGenericInvocationExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("<");
+ for (int i = 0; i < node.getExtTypeArgumentList().size(); i++) {
+ node.getExtTypeArgument(i).accept(getTraverser());
+ if (i != node.getExtTypeArgumentList().size() - 1) {
+ getPrinter().print(",");
+ }
+ }
+ getPrinter().print(">");
+ getPrinter().print(" ");
+ node.getGenericInvocationSuffix().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTInstanceofExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print(" instanceof ");
+
+ if (node.isPresentExtType()) {
+ node.getExtType().accept(getTraverser());
+ } else {
+ node.getPattern().accept(getTraverser());
+ }
+
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTThisExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print(".");
+ getPrinter().print("this");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTArrayExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getExpression().accept(getTraverser());
+ getPrinter().print("[");
+ node.getIndexExpression().accept(getTraverser());
+ getPrinter().print("]");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void visit(ASTPrimaryThisExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ getPrinter().print("this");
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTArrayCreator a) {
+ CommentPrettyPrinter.printPreComments(a, getPrinter());
+ a.getExtType().accept(getTraverser());
+ a.getArrayDimensionSpecifier().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(a, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTArrayDimensionByExpression a) {
+ CommentPrettyPrinter.printPreComments(a, getPrinter());
+ for (ASTExpression astExpression : a.getExpressionList()) {
+ getPrinter().print("[");
+ astExpression.accept(getTraverser());
+ getPrinter().print("]");
+ }
+ for (int i = 0; i < a.getDimList().size(); i++) {
+ getPrinter().print("[]");
+ }
+ CommentPrettyPrinter.printPostComments(a, getPrinter());
+ }
+
+
+ @Override
+ public void handle(ASTCreatorExpression a) {
+ CommentPrettyPrinter.printPreComments(a, getPrinter());
+ getPrinter().print(" new ");
+ a.getCreator().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(a, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTTypePattern node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLocalVariableDeclaration().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ public IndentPrinter getPrinter() {
+ return this.printer;
+ }
+
+ public String prettyprint(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+ public String prettyprint(ASTGenericInvocationSuffix node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+ public String prettyprint(ASTSuperSuffix node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/LambdaExpressionsFullPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/LambdaExpressionsFullPrettyPrinter.java
new file mode 100644
index 0000000000..95261d1d09
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/LambdaExpressionsFullPrettyPrinter.java
@@ -0,0 +1,61 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.expressions.lambdaexpressions.LambdaExpressionsMill;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameter;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameters;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsTraverser;
+import de.monticore.prettyprint.IndentPrinter;
+import de.monticore.prettyprint.MCBasicsPrettyPrinter;
+import de.monticore.types.prettyprint.MCBasicTypesPrettyPrinter;
+
+@Deprecated(forRemoval = true)
+public class LambdaExpressionsFullPrettyPrinter extends ExpressionsBasisFullPrettyPrinter {
+
+ protected LambdaExpressionsTraverser traverser;
+
+ @Override
+ public LambdaExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ public void setTraverser(LambdaExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public LambdaExpressionsFullPrettyPrinter(IndentPrinter printer) {
+ super(printer);
+ this.traverser = LambdaExpressionsMill.traverser();
+ ExpressionsBasisPrettyPrinter expressionBasis = new ExpressionsBasisPrettyPrinter(printer);
+ traverser.setExpressionsBasisHandler(expressionBasis);
+ traverser.add4ExpressionsBasis(expressionBasis);
+ MCBasicTypesPrettyPrinter mcBasicTypes = new MCBasicTypesPrettyPrinter(printer);
+ traverser.setMCBasicTypesHandler(mcBasicTypes);
+ traverser.add4MCBasicTypes(mcBasicTypes);
+ LambdaExpressionsPrettyPrinter lambdaExpression = new LambdaExpressionsPrettyPrinter(printer);
+ traverser.setLambdaExpressionsHandler(lambdaExpression);
+ traverser.add4LambdaExpressions(lambdaExpression);
+ MCBasicsPrettyPrinter basic = new MCBasicsPrettyPrinter(printer);
+ traverser.add4MCBasics(basic);
+ }
+
+ public String prettyprint(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+ public String prettyprint(ASTLambdaParameter node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+ public String prettyprint(ASTLambdaParameters node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/LambdaExpressionsPrettyPrinter.java b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/LambdaExpressionsPrettyPrinter.java
new file mode 100644
index 0000000000..2dfd4e7897
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/expressions/prettyprint/LambdaExpressionsPrettyPrinter.java
@@ -0,0 +1,94 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.expressions.prettyprint;
+
+import de.monticore.expressions.expressionsbasis._ast.ASTExpression;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaExpression;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaExpressionBody;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameter;
+import de.monticore.expressions.lambdaexpressions._ast.ASTLambdaParameters;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsHandler;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsTraverser;
+import de.monticore.expressions.lambdaexpressions._visitor.LambdaExpressionsVisitor2;
+import de.monticore.prettyprint.CommentPrettyPrinter;
+import de.monticore.prettyprint.IndentPrinter;
+
+@Deprecated(forRemoval = true)
+public class LambdaExpressionsPrettyPrinter
+ implements LambdaExpressionsVisitor2, LambdaExpressionsHandler {
+
+ protected LambdaExpressionsTraverser traverser;
+
+ @Override
+ public void setTraverser(LambdaExpressionsTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ @Override
+ public LambdaExpressionsTraverser getTraverser() {
+ return traverser;
+ }
+
+ protected IndentPrinter printer;
+
+ public void setPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ public IndentPrinter getPrinter() {
+ return this.printer;
+ }
+
+ public LambdaExpressionsPrettyPrinter(IndentPrinter printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public void handle(ASTLambdaParameter node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ if (node.isPresentMCType()) {
+ node.getMCType().accept(getTraverser());
+ getPrinter().print(" ");
+ }
+ getPrinter().print(node.getName());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLambdaParameters node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ if (node.isPresentParenthesis()) {
+ getPrinter().print("(");
+ }
+ for (int i = 0; i < node.getLambdaParameterList().size(); i++) {
+ node.getLambdaParameterList().get(i).accept(getTraverser());
+ if (i != node.getLambdaParameterList().size() - 1) {
+ getPrinter().print(",");
+ }
+ }
+ if (node.isPresentParenthesis()) {
+ getPrinter().print(")");
+ }
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLambdaExpression node) {
+ CommentPrettyPrinter.printPreComments(node, getPrinter());
+ node.getLambdaParameters().accept(getTraverser());
+ getPrinter().print(" -> ");
+ node.getLambdaBody().accept(getTraverser());
+ CommentPrettyPrinter.printPostComments(node, getPrinter());
+ }
+
+ @Override
+ public void handle(ASTLambdaExpressionBody node) {
+ node.getExpression().accept(getTraverser());
+ }
+
+ public String prettyprint(ASTExpression node) {
+ getPrinter().clearBuffer();
+ node.accept(getTraverser());
+ return getPrinter().getContent();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/ComponentCollector.java b/monticore-grammar/src/main/java/de/monticore/grammar/ComponentCollector.java
new file mode 100644
index 0000000000..bd0fee241f
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/ComponentCollector.java
@@ -0,0 +1,56 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.grammar.GrammarMill;
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._visitor.GrammarTraverser;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+
+import java.util.List;
+
+public class ComponentCollector {
+
+ public static List getAllComponents(ASTGrammarNode node) {
+ CollectRuleComponents cv = new CollectRuleComponents();
+ GrammarTraverser traverser = GrammarMill.traverser();
+ traverser.add4Grammar(cv);
+ node.accept(traverser);
+ return cv.getRuleComponents();
+ }
+
+ protected static class CollectRuleComponents implements GrammarVisitor2 {
+
+ public List ruleComponentList = Lists.newArrayList();
+
+ public List getRuleComponents() {
+ return ruleComponentList;
+ }
+
+ @Override
+ public void visit(ASTNonTerminal node) {
+ ruleComponentList.add(node);
+ }
+
+ @Override
+ public void visit(ASTTerminal node) {
+ ruleComponentList.add(node);
+ }
+
+ @Override
+ public void visit(ASTKeyTerminal node) {
+ ruleComponentList.add(node);
+ }
+
+ @Override
+ public void visit(ASTTokenTerminal node) {
+ ruleComponentList.add(node);
+ }
+
+ @Override
+ public void visit(ASTConstantGroup node) {
+ ruleComponentList.add(node);
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/DirectLeftRecursionDetector.java b/monticore-grammar/src/main/java/de/monticore/grammar/DirectLeftRecursionDetector.java
new file mode 100644
index 0000000000..e2d2fe4009
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/DirectLeftRecursionDetector.java
@@ -0,0 +1,75 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar;
+
+import de.monticore.grammar.grammar._ast.ASTAlt;
+import de.monticore.grammar.grammar._ast.ASTNonTerminal;
+import de.monticore.grammar.grammar._ast.ASTRuleComponent;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Checks if a MC production is a left directly left recursive: e.g. of the form A -> A.*
+ *
+ */
+public class DirectLeftRecursionDetector {
+
+ public boolean isAlternativeLeftRecursive(final ASTAlt productionAlternative,
+ final ASTNonTerminal actualNonTerminal) {
+ final String classProductionName = actualNonTerminal.getName();
+
+ final List nodes = ComponentCollector.getAllComponents(productionAlternative);
+
+ if (nodes.isEmpty()) {
+ return false;
+ }
+
+ if (nodes.get(0) instanceof ASTNonTerminal) {
+ ASTNonTerminal leftmostNonterminal = (ASTNonTerminal) nodes.get(0);
+ if ((leftmostNonterminal == actualNonTerminal)
+ && leftmostNonterminal.getName().equals(classProductionName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isAlternativeLeftRecursive(final ASTAlt productionAlternative,
+ final String classProductionName) {
+ final List nodes = ComponentCollector.getAllComponents(productionAlternative);
+
+ if (nodes.isEmpty()) {
+ return false;
+ }
+
+ if (nodes.get(0) instanceof ASTNonTerminal) {
+ ASTNonTerminal leftmostNonterminal = (ASTNonTerminal) nodes.get(0);
+ if (leftmostNonterminal.getName().equals(classProductionName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isAlternativeLeftRecursive(final ASTAlt productionAlternative,
+ final Collection names) {
+ final List nodes = ComponentCollector.getAllComponents(productionAlternative);
+
+ if (nodes.isEmpty()) {
+ return false;
+ }
+
+ if (nodes.get(0) instanceof ASTNonTerminal) {
+ ASTNonTerminal leftmostNonterminal = (ASTNonTerminal) nodes.get(0);
+ if (names.contains(leftmostNonterminal.getName())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/LexNamer.java b/monticore-grammar/src/main/java/de/monticore/grammar/LexNamer.java
new file mode 100644
index 0000000000..5cb5293f2c
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/LexNamer.java
@@ -0,0 +1,172 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.se_rwth.commons.logging.Log;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Class generates human readable names for Lexersymbols
+ *
+ */
+public class LexNamer {
+
+ protected int constantCounter = 0;
+
+ protected int lexCounter = 0;
+
+ protected Map usedLex = new HashMap();
+
+ protected Map usedConstants = new HashMap();
+
+ protected static Map goodNames = null;
+
+ public static Map getGoodNames() {
+ if (goodNames == null) {
+ goodNames = new HashMap();
+ // Put all common names here, one character only, since all others are
+ // concatanation of these
+ goodNames.put(";", "SEMI");
+ goodNames.put("@", "AT");
+ goodNames.put("#", "HASH");
+ goodNames.put(".", "POINT");
+ goodNames.put(",", "COMMA");
+ goodNames.put("?", "QUESTION");
+ goodNames.put("§", "LEX");
+ goodNames.put("\"", "QUOTE");
+ goodNames.put("'", "APOSTROPHE");
+ goodNames.put("$", "DOLLAR");
+ goodNames.put("~", "TILDE");
+ goodNames.put(">", "GT");
+ goodNames.put("<", "LT");
+ goodNames.put("=", "EQUALS");
+ goodNames.put("+", "PLUS");
+ goodNames.put("-", "MINUS");
+ goodNames.put("*", "STAR");
+ goodNames.put("%", "PERCENT");
+ goodNames.put("/", "SLASH");
+ goodNames.put("&", "AND_");
+ goodNames.put("|", "PIPE");
+ goodNames.put(":", "COLON");
+ goodNames.put("!", "EXCLAMATIONMARK");
+ goodNames.put("^", "ROOF");
+
+ // Don't change the following, unless you change Grammar2Antlr too
+ goodNames.put("(", "LPAREN");
+ goodNames.put(")", "RPAREN");
+ goodNames.put("[", "LBRACK");
+ goodNames.put("]", "RBRACK");
+ goodNames.put("{", "LCURLY");
+ goodNames.put("}", "RCURLY");
+ }
+ return goodNames;
+ }
+
+ /**
+ * Returns a good name for the lex symbol or ""
+ */
+ public static String createGoodName(String x) {
+
+ if (x.matches("[a-zA-Z][a-zA-Z_0-9]*")) {
+ return x.toUpperCase()+Integer.toUnsignedString(x.hashCode());
+ }
+
+ if (x.matches("[^a-zA-Z0-9]+")) {
+ StringBuilder ret = new StringBuilder();
+ for (int i = 0; i < x.length(); i++) {
+
+ String substring = x.substring(i, i + 1);
+ if (getGoodNames().containsKey(substring)) {
+ ret.append(getGoodNames().get(substring));
+ } else {
+ return "";
+ }
+ }
+ return ret.toString();
+ }
+ return "";
+
+ }
+
+ /**
+ * Returns a good name for the lex symbol or ""
+ */
+ public static String createSimpleGoodName(String x) {
+
+ if (x.matches("[a-zA-Z][a-zA-Z_0-9]*")) {
+ return x.toUpperCase();
+ }
+
+ if (x.matches("[^a-zA-Z0-9]+")) {
+ StringBuilder ret = new StringBuilder();
+ for (int i = 0; i < x.length(); i++) {
+
+ String substring = x.substring(i, i + 1);
+ if (getGoodNames().containsKey(substring)) {
+ ret.append(getGoodNames().get(substring));
+ } else {
+ return "";
+ }
+ }
+ return ret.toString();
+ }
+ return "";
+
+ }
+
+ /**
+ * Returns Human-Readable, antlr conformed name for a lexsymbols nice names for common tokens
+ * (change constructor to add tokenes) LEXi where i is number for unknown ones
+ *
+ * @param sym lexer symbol
+ * @return Human-Readable, antlr conformed name for a lexsymbols
+ */
+ public String getLexName(MCGrammarSymbol grammarSymbol, String sym) {
+ if (usedLex.containsKey(sym)) {
+ return usedLex.get(sym);
+ }
+
+ String goodName = createGoodName(sym);
+ if (goodName.isEmpty() || grammarSymbol.getProd(goodName).isPresent()) {
+ goodName = "LEXNAME" + lexCounter++;
+ }
+ usedLex.put(sym, goodName);
+ Log.debug("Using lexer symbol " + goodName + " for symbol '" + sym + "'", "LexNamer");
+ return goodName;
+ }
+
+ public String getConstantName(String sym) {
+ String s = sym.intern();
+
+ if (!usedConstants.containsKey(s)) {
+ String goodName = createSimpleGoodName(s);
+ if (!goodName.isEmpty()) {
+ usedConstants.put(s, goodName);
+ }
+ else {
+ usedConstants.put(s, ("CONSTANT" + constantCounter++).intern());
+ }
+ }
+
+ String name = usedConstants.get(sym.intern());
+ Log.debug("Using lexer constant " + name + " for symbol '" + s + "'", "LexNamer");
+
+ return name;
+ }
+
+ protected String convertKeyword(String key) {
+ key = StringUtils.replace(key, "\\\"", "\"");
+ key = StringUtils.replace(key, "'", "\\'");
+ return key;
+ }
+
+
+ public Set getLexnames() {
+ return usedLex.keySet();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/MCGrammarSymbolTableHelper.java b/monticore-grammar/src/main/java/de/monticore/grammar/MCGrammarSymbolTableHelper.java
new file mode 100644
index 0000000000..f8ca580f46
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/MCGrammarSymbolTableHelper.java
@@ -0,0 +1,314 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._symboltable.*;
+import de.monticore.symboltable.IScopeSpanningSymbol;
+import de.se_rwth.commons.StringTransformations;
+import de.se_rwth.commons.Util;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.google.common.collect.Sets.newLinkedHashSet;
+
+public class MCGrammarSymbolTableHelper {
+
+ public static final String AST_DOT_PACKAGE_SUFFIX_DOT = "._ast.";
+ protected static final Integer STAR = -1;
+
+ public static Optional resolveRule(ASTMCGrammar astNode, String name) {
+ if (astNode.isPresentSymbol()) {
+ return astNode.getSymbol().getProdWithInherited(name);
+ }
+ return Optional.empty();
+ }
+
+ public static Optional resolveRuleInSupersOnly(ASTClassProd astNode, String name) {
+ Optional grammarSymbol = getMCGrammarSymbol(astNode.getEnclosingScope());
+ Stream superGrammars = grammarSymbol
+ .map(symbol -> Util.preOrder(symbol, MCGrammarSymbol::getSuperGrammarSymbols)
+ .stream())
+ .orElse(Stream.empty()).skip(1);
+ return superGrammars.map(superGrammar -> superGrammar.getProd(name))
+ .filter(mcRuleSymbol -> mcRuleSymbol.isPresent())
+ .map(Optional::get)
+ .findFirst();
+ }
+
+ public static Optional getMCGrammarSymbol(IGrammarScope scope) {
+ boolean exist = true;
+ while (exist) {
+ if (scope.isPresentSpanningSymbol() && scope.getSpanningSymbol() instanceof MCGrammarSymbol) {
+ return Optional.of((MCGrammarSymbol) scope.getSpanningSymbol());
+ }
+ if (scope instanceof IGrammarGlobalScope) {
+ exist = false;
+ } else {
+ scope = scope.getEnclosingScope();
+ }
+ }
+ return Optional.empty();
+ }
+
+ public static Optional getEnclosingRule(ASTRuleComponent astNode) {
+ if (astNode.getEnclosingScope().isPresentSpanningSymbol()) {
+ IScopeSpanningSymbol s = astNode.getEnclosingScope().getSpanningSymbol();
+ if (s instanceof ProdSymbol) {
+ return Optional.of((ProdSymbol) s);
+ }
+ }
+ return Optional.empty();
+ }
+
+ public static Optional getEnclosingRule(RuleComponentSymbol prod) {
+ if (prod.getEnclosingScope().isPresentSpanningSymbol() && prod.getEnclosingScope().getSpanningSymbol() instanceof ProdSymbol) {
+ return Optional.of((ProdSymbol) prod.getEnclosingScope().getSpanningSymbol());
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Returns a set of all super grammars of the given grammar (transitively)
+ *
+ * @return
+ */
+ public static Set getAllSuperGrammars(
+ MCGrammarSymbol grammarSymbol) {
+ Set allSuperGrammars = new LinkedHashSet<>();
+ Set tmpList = new LinkedHashSet<>();
+ allSuperGrammars.addAll(grammarSymbol.getSuperGrammarSymbols());
+ boolean modified = false;
+ do {
+ for (MCGrammarSymbol curGrammar : allSuperGrammars) {
+ tmpList.addAll(curGrammar.getSuperGrammarSymbols());
+ }
+ modified = allSuperGrammars.addAll(tmpList);
+ tmpList.clear();
+ } while (modified);
+
+ return ImmutableSet.copyOf(allSuperGrammars);
+ }
+
+ public static String getQualifiedName(ASTProd astNode, ProdSymbol symbol, String prefix,
+ String suffix) {
+ if (symbol.isIsExternal()) {
+ return symbol.getName();
+ } else {
+ Optional grammarSymbol = getMCGrammarSymbol(astNode.getEnclosingScope());
+ String string = (grammarSymbol.isPresent()
+ ? grammarSymbol.get().getFullName().toLowerCase()
+ : "")
+ + AST_DOT_PACKAGE_SUFFIX_DOT + prefix +
+ StringTransformations.capitalize(symbol.getName() + suffix);
+
+ if (string.startsWith(".")) {
+ string = string.substring(1);
+ }
+ return string;
+ }
+ }
+
+
+ public static String getConstantGroupName(ASTConstantGroup ast) {
+ // setAttributeMinMax(a.getIteration(), att);
+ if (ast.isPresentUsageName()) {
+ return ast.getUsageName();
+ }
+ // derive attribute name from constant entry (but only if we have
+ // one entry!)
+ else if (ast.getConstantList().size() == 1) {
+ return ast.getConstantList().get(0).getHumanName();
+ }
+
+ Log.error("0xA2345 The name of the constant group could't be ascertained",
+ ast.get_SourcePositionStart());
+
+ return "";
+ }
+
+ public static Set getAllSuperProds(ProdSymbol prod) {
+ Set supersHandled = new LinkedHashSet<>();
+ List supersToHandle = new ArrayList<>();
+ supersToHandle.addAll(getSuperProds(prod));
+ Set supersNextRound = new LinkedHashSet<>();
+
+ while (!supersToHandle.isEmpty()) {
+ for (ProdSymbol superType : supersToHandle) {
+ if (!supersHandled.contains(superType)) {
+ supersNextRound.addAll(getSuperProds(superType));
+ }
+ supersHandled.add(superType);
+ }
+ supersToHandle.clear();
+ supersToHandle.addAll(supersNextRound);
+ supersNextRound.clear();
+ }
+ return ImmutableSet.copyOf(supersHandled);
+ }
+
+ public static Set getAllSuperInterfaces(ProdSymbol prod) {
+ return getAllSuperProds(prod).stream().filter(p -> p.isIsInterface()).collect(Collectors.toSet());
+ }
+
+ protected final static LoadingCache> superProdCache = CacheBuilder.newBuilder().maximumSize(10000)
+ .build(new CacheLoader>() {
+ @Override
+ public List load(ProdSymbol prod) {
+ List superTypes = prod.getSuperProds().stream().filter(s -> s.isSymbolPresent())
+ .map(s -> s.lazyLoadDelegate()).collect(Collectors.toList());
+ superTypes.addAll(prod.getSuperInterfaceProds().stream().filter(s -> s.isSymbolPresent())
+ .map(s -> s.lazyLoadDelegate()).collect(Collectors.toList()));
+
+ superTypes.addAll(prod.getAstSuperClasses().stream().filter(s -> s.isSymbolPresent())
+ .map(s -> s.lazyLoadDelegate()).collect(Collectors.toList()));
+ superTypes.addAll(prod.getAstSuperInterfaces().stream().filter(s -> s.isSymbolPresent())
+ .map(s -> s.lazyLoadDelegate()).collect(Collectors.toList()));
+ return ImmutableList.copyOf(superTypes);
+ }
+ });
+
+ /**
+ * @param prod
+ * @return
+ */
+ public static List getSuperProds(ProdSymbol prod) {
+ return superProdCache.getUnchecked(prod);
+ }
+
+ public static boolean isSubtype(ProdSymbol subType, ProdSymbol superType) {
+ return isSubtype(subType, superType, newLinkedHashSet(Arrays.asList(subType)));
+ }
+
+ protected static boolean isSubtype(ProdSymbol subType, ProdSymbol superType,
+ Set handledTypes) {
+ if (areSameTypes(subType, superType)) {
+ return true;
+ }
+
+ // Try to find superType in super types of this type
+ final Collection allSuperTypes = getAllSuperProds(subType);
+ if (allSuperTypes.contains(superType)) {
+ return true;
+ }
+
+ // check transitive sub-type relation
+ for (ProdSymbol t : allSuperTypes) {
+ if (handledTypes.add(superType)) {
+ boolean subtypeOf = isSubtype(t, superType, handledTypes);
+ if (subtypeOf) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean areSameTypes(ProdSymbol type1, ProdSymbol type2) {
+ Log.errorIfNull(type1);
+ Log.errorIfNull(type2);
+
+ if (type1 == type2) {
+ return true;
+ }
+
+ return type1.getFullName().equals(type2.getFullName());
+
+ }
+
+ public static boolean isAssignmentCompatibleOrUndecidable(ProdSymbol subType,
+ ProdSymbol superType) {
+ return isAssignmentCompatibleOrUndecidable(subType, superType,
+ newLinkedHashSet(Arrays.asList(subType)));
+ }
+
+ /**
+ * Returns the type of the collection types
that is the sub type
+ * of all other types in this collection. Else, null is returned.
+ *
+ * @param types Collection of types
+ * @return type that is subtype of all other types or null.
+ */
+ public static Optional findLeastType(Collection types) {
+ for (ProdSymbol t1 : types) {
+ boolean isLeastType = true;
+ for (ProdSymbol t2 : types) {
+ if (!isSubtype(t2, t1) && !areSameTypes(t2, t1)) {
+ isLeastType = false;
+ break;
+ }
+ }
+ if (isLeastType) {
+ return Optional.of(t1);
+ }
+ }
+ return Optional.empty();
+ }
+
+ public static boolean isAssignmentCompatibleOrUndecidable(ProdSymbol subType,
+ ProdSymbol superType, Set handledTypes) {
+ // Return true if this type or the other type are both external
+ // TODO GV: check, wenn Java angebunden
+ if (subType.isIsExternal()
+ || superType.isIsExternal()) {
+ return true;
+ }
+
+ // Return true if this type and the other type are the same
+ if (areSameTypes(subType, superType)) {
+ return true;
+ }
+
+ // Try to find superType in supertypes of this type
+ Collection allSuperTypes = getAllSuperProds(subType);
+ if (allSuperTypes.contains(superType)) {
+ return true;
+ }
+
+ // check transitive sub-type relation
+ for (ProdSymbol t : allSuperTypes) {
+ if (handledTypes.add(superType)) {
+ boolean subtypeOf = isAssignmentCompatibleOrUndecidable(t, superType, handledTypes);
+ if (subtypeOf) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ public static Optional getMin(AdditionalAttributeSymbol attrSymbol) {
+ if (!attrSymbol.isPresentAstNode()) {
+ return Optional.empty();
+ }
+ return getMin(attrSymbol.getAstNode());
+ }
+
+ public static Optional getMin(ASTAdditionalAttribute ast) {
+ if (ast.isPresentCard()
+ && ast.getCard().isPresentMin()) {
+ String min = ast.getCard().getMin();
+ try {
+ int x = Integer.parseInt(min);
+ return Optional.of(x);
+ } catch (NumberFormatException ignored) {
+ Log.warn("0xA0141 Failed to parse an integer value of max of ASTAdditionalAttribute "
+ + ast.getName() + " from string " + min);
+ }
+ }
+ return Optional.empty();
+ }
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/Multiplicity.java b/monticore-grammar/src/main/java/de/monticore/grammar/Multiplicity.java
new file mode 100644
index 0000000000..48b6997c34
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/Multiplicity.java
@@ -0,0 +1,222 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar;
+
+import de.monticore.ast.ASTNode;
+import de.monticore.grammar.grammar.GrammarMill;
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._symboltable.IGrammarScope;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._visitor.GrammarTraverser;
+import de.monticore.symboltable.IGlobalScope;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.max;
+
+/**
+ * Denotes the multiplicity of nonterminals in a MC grammar such as '*', '+', or '?'.
+ *
+ */
+public enum Multiplicity {
+
+ /**
+ * No quantifier present
+ */
+ STANDARD,
+ /**
+ * '?' quantifier present
+ */
+ OPTIONAL,
+ /**
+ * '*' or '+' quantifier present
+ */
+ LIST;
+
+ public static Multiplicity determineMultiplicity(ASTAdditionalAttribute attributeInAST) {
+ if (!attributeInAST.isPresentCard()) {
+ return STANDARD;
+ }
+ ASTCard cardinality = attributeInAST.getCard();
+ if (cardinality.getIteration() == ASTConstantsGrammar.STAR
+ || cardinality.getIteration() == ASTConstantsGrammar.PLUS
+ || (cardinality.isPresentMax() && (cardinality.getMax().equals("*") || getMaxCardinality(cardinality) > 1))) {
+ return LIST;
+ } else if (cardinality.getIteration() == ASTConstantsGrammar.QUESTION
+ || (!cardinality.isPresentMin() || getMinCardinality(cardinality) == 0)) {
+ return OPTIONAL;
+ }
+ return STANDARD;
+ }
+
+ protected static int getMaxCardinality(ASTCard cardinality) {
+ return Integer.parseInt(cardinality.getMax());
+ }
+
+ protected static int getMinCardinality(ASTCard cardinality) {
+ return Integer.parseInt(cardinality.getMin());
+ }
+
+ /**
+ * Performs the multiplicity calculation for inherited attributes.
+ *
+ * @param astNode The ast node.
+ * @return The multiplicity of the ast in the defining grammar.
+ */
+ public static Multiplicity determineMultiplicity(ASTRuleComponent astNode) {
+ // multiplicity by inheritance is only relevant for nonterminals and can
+ // cause errors otherwise; cast rootNode to ASTMCGrammar for further use
+ // switch to default behavior without inheritance otherwise
+ if (astNode instanceof ASTConstantGroup) {
+ // constant groups are always standard iteration
+ return STANDARD;
+ }
+ IGrammarScope scope = astNode.getEnclosingScope();
+ while (!(scope instanceof IGlobalScope) ) {
+ if (scope.isPresentSpanningSymbol() && scope.getSpanningSymbol() instanceof MCGrammarSymbol) {
+ return determineMultiplicity(((MCGrammarSymbol) scope.getSpanningSymbol()).getAstNode(), astNode);
+ }
+ scope = scope.getEnclosingScope();
+ }
+ return Multiplicity.STANDARD;
+
+ }
+
+ public static Multiplicity determineMultiplicity(ASTNode astNode) {
+ if (astNode instanceof ASTRuleComponent) {
+ return determineMultiplicity((ASTRuleComponent) astNode);
+ } else if (astNode instanceof ASTAdditionalAttribute) {
+ return determineMultiplicity((ASTAdditionalAttribute) astNode);
+ }
+ return null;
+ }
+
+ public static Multiplicity determineMultiplicity(ASTMCGrammar rootNode, ASTRuleComponent astNode) {
+ MultiplicityVisitor mv = new MultiplicityVisitor(astNode);
+ GrammarTraverser traverser = GrammarMill.traverser();
+ traverser.add4Grammar(mv);
+ rootNode.accept(traverser);
+ List intermediates = mv.getComponents();
+ Multiplicity byAlternative = multiplicityByAlternative(rootNode, astNode, intermediates);
+ Multiplicity byDuplicates = multiplicityByDuplicates(rootNode, astNode, intermediates);
+ Multiplicity byIteration = multiplicityByIteration(rootNode, astNode, intermediates);
+ ArrayList newArrayList = newArrayList(byDuplicates, byIteration, byAlternative);
+ return max(newArrayList);
+ }
+
+ protected static Multiplicity multiplicityByAlternative(ASTMCGrammar rootNode, ASTRuleComponent astNode, List intermediates) {
+ boolean containedInAlternative = false;
+ for (ASTNode intermediate : intermediates) {
+ if (intermediate instanceof ASTClassProd) {
+ containedInAlternative |= ((ASTClassProd) intermediate).getAltList().size() > 1;
+ } else if (intermediate instanceof ASTBlock) {
+ containedInAlternative |= ((ASTBlock) intermediate).getAltList().size() > 1;
+ }
+ }
+ return containedInAlternative ? OPTIONAL : STANDARD;
+ }
+
+ protected static Multiplicity multiplicityByDuplicates(ASTMCGrammar rootNode, ASTRuleComponent astNode, List intermediates) {
+ boolean hasDuplicate = getAllNodesInRelatedRuleComponents(rootNode, astNode, intermediates)
+ .anyMatch(sibling -> areDuplicates(rootNode, astNode, sibling));
+ if (hasDuplicate) {
+ return LIST;
+ } else {
+ return STANDARD;
+ }
+ }
+
+ public static Optional getUsageName(ASTNode ancestor) {
+ if (ancestor instanceof ASTConstantGroup && ((ASTConstantGroup) ancestor).isPresentUsageName()) {
+ return Optional.of(((ASTConstantGroup) ancestor).getUsageName());
+ }
+ if (ancestor instanceof ASTNonTerminal && ((ASTNonTerminal) ancestor).isPresentUsageName()) {
+ return Optional.of(((ASTNonTerminal) ancestor).getUsageName());
+ }
+ if (ancestor instanceof ASTNonTerminalSeparator) {
+ return Optional.of(((ASTNonTerminalSeparator) ancestor).getUsageName());
+ }
+ if (ancestor instanceof ASTITerminal && ((ASTITerminal) ancestor).isPresentUsageName()) {
+ return Optional.of(((ASTITerminal) ancestor).getUsageName());
+ }
+ if (ancestor instanceof ASTAdditionalAttribute && ((ASTAdditionalAttribute) ancestor).isPresentName()) {
+ return Optional.of(((ASTAdditionalAttribute) ancestor).getName());
+ }
+
+ return Optional.empty();
+ }
+
+ protected static boolean areDuplicates(ASTMCGrammar rootNode, ASTRuleComponent firstNode, ASTRuleComponent secondNode) {
+ Optional firstName = Optional.of(firstNode.getName());
+ Optional firstUsageName = getUsageName(firstNode);
+ Optional secondName = Optional.of(secondNode.getName());
+ Optional secondUsageName = getUsageName(secondNode);
+
+ boolean bothUsageNamesAbsent = !firstUsageName.isPresent() && !secondUsageName.isPresent();
+ boolean namesMatch = firstName.equals(secondName);
+ boolean usageNamesMatch = firstUsageName.equals(secondUsageName);
+ return (bothUsageNamesAbsent && namesMatch) || (!bothUsageNamesAbsent && usageNamesMatch);
+ }
+
+ protected static Stream getAllNodesInRelatedRuleComponents(ASTMCGrammar rootNode,
+ ASTRuleComponent astNode,
+ List intermediates) {
+
+ Set ancestorRuleComponents = intermediates.stream()
+ .filter(ASTRuleComponent.class::isInstance)
+ .map(ASTRuleComponent.class::cast)
+ .collect(Collectors.toSet());
+
+ return intermediates.stream()
+ .filter(ASTAlt.class::isInstance)
+ .map(ASTAlt.class::cast)
+ .flatMap(alt -> alt.getComponentList().stream())
+ .filter(ruleComponent -> !ancestorRuleComponents.contains(ruleComponent))
+ .flatMap(ruleComponent -> ComponentCollector.getAllComponents(ruleComponent).stream());
+ }
+
+ public static Multiplicity multiplicityByIteration(ASTMCGrammar rootNode, ASTRuleComponent astNode, List intermediates) {
+ Multiplicity multiplicity = STANDARD;
+ for (ASTNode intermediate :intermediates) {
+ int iteration = getIterationInt(intermediate);
+
+ if (iteration == ASTConstantsGrammar.PLUS || iteration == ASTConstantsGrammar.STAR) {
+ multiplicity = LIST;
+ }
+ if (iteration == ASTConstantsGrammar.QUESTION && multiplicity != LIST) {
+ multiplicity = OPTIONAL;
+ }
+ }
+ return multiplicity;
+ }
+
+ protected static int getIterationInt(ASTNode ancestor) {
+ int iteration = ASTConstantsGrammar.DEFAULT;
+ if (ancestor instanceof ASTBlock) {
+ iteration = ((ASTBlock) ancestor).getIteration();
+ }
+ if (ancestor instanceof ASTNonTerminal) {
+ iteration = ((ASTNonTerminal) ancestor).getIteration();
+ }
+ if (ancestor instanceof ASTTerminal) {
+ iteration = ((ASTTerminal) ancestor).getIteration();
+ }
+ if (ancestor instanceof ASTKeyTerminal) {
+ iteration = ((ASTKeyTerminal) ancestor).getIteration();
+ }
+ if (ancestor instanceof ASTTokenTerminal) {
+ iteration = ((ASTTokenTerminal) ancestor).getIteration();
+ }
+ if (ancestor instanceof ASTConstantGroup) {
+ iteration = ((ASTConstantGroup) ancestor).getIteration();
+ }
+ return iteration;
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/MultiplicityVisitor.java b/monticore-grammar/src/main/java/de/monticore/grammar/MultiplicityVisitor.java
new file mode 100644
index 0000000000..0e263a5244
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/MultiplicityVisitor.java
@@ -0,0 +1,138 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar;
+
+import com.google.common.collect.Lists;
+import de.monticore.ast.ASTNode;
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+
+import java.util.List;
+import java.util.Stack;
+
+public class MultiplicityVisitor implements GrammarVisitor2 {
+
+
+ protected Stack components = new Stack<>();
+ protected List result = Lists.newArrayList();
+
+ protected ASTNode last;
+
+ public MultiplicityVisitor(ASTGrammarNode last) {
+ this.last = last;
+ }
+
+ public List getComponents() {
+ return result;
+ }
+
+
+ @Override
+ public void visit(ASTClassProd node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTClassProd node) {
+ components.pop();
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void visit(ASTAlt node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTAlt node) {
+ components.pop();
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void visit(ASTBlock node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTBlock node) {
+ components.pop();
+ }
+
+ @Override
+ public void visit(ASTNonTerminal node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTNonTerminal node) {
+ components.pop();
+ }
+
+ @Override
+ public void visit(ASTTerminal node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTTerminal node) {
+ components.pop();
+ }
+ @Override
+ public void visit(ASTKeyTerminal node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTKeyTerminal node) {
+ components.pop();
+ }
+
+ @Override
+ public void visit(ASTTokenTerminal node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTTokenTerminal node) {
+ components.pop();
+ }
+
+ @Override
+ public void visit(ASTConstantGroup node) {
+ components.push(node);
+ if (node==last) {
+ result.addAll(components);
+ }
+ }
+
+ @Override
+ public void endVisit(ASTConstantGroup node) {
+ components.pop();
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/PredicatePair.java b/monticore-grammar/src/main/java/de/monticore/grammar/PredicatePair.java
new file mode 100644
index 0000000000..d6ba78c599
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/PredicatePair.java
@@ -0,0 +1,38 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar;
+
+import de.monticore.grammar.grammar._ast.ASTRuleReference;
+
+public class PredicatePair {
+ protected String classname;
+
+ protected ASTRuleReference ruleReference;
+
+ public ASTRuleReference getRuleReference() {
+ return ruleReference;
+ }
+
+ public void setRuleReference(ASTRuleReference ruleReference) {
+ this.ruleReference = ruleReference;
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+
+ public PredicatePair(String classname, ASTRuleReference ruleReference) {
+ this.classname = classname;
+ this.ruleReference = ruleReference;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof PredicatePair) && classname.equals(((PredicatePair) o).classname);
+ }
+
+ @Override
+ public int hashCode() {
+ return classname.hashCode();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/RegExpBuilder.java b/monticore-grammar/src/main/java/de/monticore/grammar/RegExpBuilder.java
new file mode 100644
index 0000000000..196babb855
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/RegExpBuilder.java
@@ -0,0 +1,163 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar;
+
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._visitor.GrammarHandler;
+import de.monticore.grammar.grammar._visitor.GrammarTraverser;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+
+import java.util.Optional;
+
+public class RegExpBuilder implements GrammarVisitor2, GrammarHandler {
+
+ protected StringBuilder b;
+
+ protected MCGrammarSymbol st;
+
+ protected GrammarTraverser traverser;
+
+ @Override
+ public GrammarTraverser getTraverser() {
+ return traverser;
+ }
+
+ @Override
+ public void setTraverser(GrammarTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ public RegExpBuilder(StringBuilder b, MCGrammarSymbol st) {
+ this.b = b;
+ this.st = st;
+ }
+
+ /**
+ * Prints Lexer Rule
+ *
+ * @param a
+ */
+ @Override
+ public void handle(ASTLexProd a) {
+ String del = "";
+ for (ASTLexAlt alt: a.getAltList()) {
+ b.append(del);
+ alt.accept(getTraverser());
+ del = "|";
+ }
+ }
+
+
+ @Override
+ public void handle(ASTLexBlock a) {
+
+ if (a.isNegate()) {
+ b.append("^");
+ }
+
+ b.append("(");
+
+ // Visit all alternatives
+ String del = "";
+ for (ASTLexAlt alt: a.getLexAltList()) {
+ b.append(del);
+ alt.accept(getTraverser());
+ del = "|";
+ }
+
+ // Start of Block with iteration
+ b.append(")");
+ b.append(printIteration(a.getIteration()));
+
+ }
+
+ @Override
+ public void visit(ASTLexCharRange a) {
+
+ b.append("[");
+ if (a.isNegate()) {
+ b.append("^");
+ }
+ b.append(a.getLowerChar());
+ b.append("-");
+ b.append(a.getUpperChar() + "]");
+
+ }
+
+ @Override
+ public void visit(ASTLexChar a) {
+
+ if (a.getChar().startsWith("\\")) {
+ b.append("(");
+ if (a.isNegate()) {
+ b.append("^");
+ }
+ b.append(a.getChar() + ")");
+ }
+ else {
+
+ if ("[".equals(a.getChar()) || "]".equals(a.getChar())) {
+
+ if (a.isNegate()) {
+ b.append("^");
+ }
+ b.append(a.getChar());
+
+ }
+ else {
+ b.append("[");
+ if (a.isNegate()) {
+ b.append("^");
+ }
+ b.append(a.getChar() + "]");
+ }
+ }
+ }
+
+ @Override
+ public void visit(ASTLexString a) {
+
+ for (int i = 0; i < a.getString().length(); i++) {
+
+ String x = a.getString().substring(i, i + 1);
+ if (x.startsWith("\\")) {
+
+ b.append("(" + a.getString().substring(i, i + 2) + ")");
+ i++;
+ }
+ else {
+ if (needsEscapeChar(x)) {
+ x = "\\".concat(x);
+ }
+ b.append("[" + x + "]");
+ }
+ }
+
+ }
+
+ protected boolean needsEscapeChar(String x) {
+ return "^".equals(x);
+ }
+
+ @Override
+ public void visit(ASTLexNonTerminal a) {
+ Optional lexrule = st.getProd(a.getName());
+ b.append(lexrule.isPresent()? lexrule.get().getName():"");
+
+ }
+
+ protected String printIteration(int i) {
+ switch (i) {
+ case ASTConstantsGrammar.PLUS:
+ return "+";
+ case ASTConstantsGrammar.STAR:
+ return "*";
+ case ASTConstantsGrammar.QUESTION:
+ return "?";
+ default:
+ return "";
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ASTRuleAndNTUseSameAttrNameForDiffNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ASTRuleAndNTUseSameAttrNameForDiffNTs.java
new file mode 100644
index 0000000000..0a4549fa18
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ASTRuleAndNTUseSameAttrNameForDiffNTs.java
@@ -0,0 +1,100 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTASTRule;
+import de.monticore.grammar.grammar._cocos.GrammarASTASTRuleCoCo;
+import de.monticore.grammar.grammar._symboltable.AdditionalAttributeSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._symboltable.RuleComponentSymbol;
+import de.monticore.types.mcbasictypes._ast.ASTMCPrimitiveType;
+import de.monticore.types.mcbasictypes._ast.ASTMCType;
+import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ *
+ */
+public class ASTRuleAndNTUseSameAttrNameForDiffNTs implements GrammarASTASTRuleCoCo {
+
+ public static final String ERROR_CODE = "0xA4028";
+
+ public static final String ERROR_MSG_FORMAT = " The AST rule for the nonterminal %s must not use the "
+ + "same attribute name %s as the corresponding production "
+ + "with the type %s is not "
+ + "identical to or a super type of %s.";
+
+ @Override
+ public void check(ASTASTRule a) {
+ ProdSymbol prodSymbol = a.getEnclosingScope().resolveProd(a.getType()).get();
+ for (AdditionalAttributeSymbol attr : prodSymbol.getSpannedScope().getLocalAdditionalAttributeSymbols()) {
+ List rcs = prodSymbol.getSpannedScope().resolveRuleComponentDownMany(attr.getName());
+ if (!rcs.isEmpty()) {
+ RuleComponentSymbol rc = rcs.get(0);
+ if (rc.isIsNonterminal()) {
+ String typeName = attr.getAstNode().getMCType().printType();
+ if (!typeName
+ .endsWith(rc.getReferencedProd().get().getName())) {
+ Optional attrType = a.getEnclosingScope()
+ .resolveProd(typeName);
+ Optional compType = a.getEnclosingScope()
+ .resolveProd(rc.getReferencedProd().get().getName());
+ if (attrType.isPresent() && compType.isPresent()) {
+ if (MCGrammarSymbolTableHelper.isSubtype(compType.get(), attrType.get())
+ || isCorrespondingJavaTypeFromToken(attrType.get(), compType.get())) {
+ continue;
+ } else {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getType(),
+ attr.getName(), typeName,
+ rc.getReferencedProd().get().getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ } else if (rc.isIsTerminal() || rc.isIsLexerNonterminal()) {
+ // Compare to String
+ if (!("String".equals(attr.getType()) || "java.lang.String".equals(attr.getType()))) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getType(),
+ attr.getName(), attr.getType(),
+ rc.getName()),
+ a.get_SourcePositionStart());
+ }
+ } else if (rc.isIsConstant()) {
+ // Compare to boolean
+ ASTMCType attrType = attr.getAstNode().getMCType();
+ if (!((attrType instanceof ASTMCPrimitiveType) || ((ASTMCPrimitiveType) attrType).isBoolean())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getType(),
+ attr.getName(), attr.getType(),
+ rc.getName()),
+ a.get_SourcePositionStart());
+ }
+ } else if (rc.isIsConstantGroup()) {
+ // Compare to int
+ ASTMCType attrType = attr.getAstNode().getMCType();
+ if (!(attrType instanceof ASTMCPrimitiveType) || !((ASTMCPrimitiveType) attrType).isInt()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getType(),
+ attr.getName(), attr.getType(),
+ rc.getName()),
+ a.get_SourcePositionStart());
+ }
+ } else {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getType(),
+ attr.getName(), attr.getType(),
+ rc.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+
+ protected boolean isCorrespondingJavaTypeFromToken(ProdSymbol astRuleType, ProdSymbol compType) {
+ if ("Name".equals(compType.getName())) {
+ return "String".equals(astRuleType.getName());
+ }
+ return false;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTNotExtendInterfaceOrExternalNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTNotExtendInterfaceOrExternalNTs.java
new file mode 100644
index 0000000000..ceeac33389
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTNotExtendInterfaceOrExternalNTs.java
@@ -0,0 +1,45 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTAbstractProd;
+import de.monticore.grammar.grammar._ast.ASTRuleReference;
+import de.monticore.grammar.grammar._cocos.GrammarASTAbstractProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that abstract nonterminals only extends abstract or normal nonterminals..
+ *
+
+ */
+public class AbstractNTNotExtendInterfaceOrExternalNTs implements GrammarASTAbstractProdCoCo {
+
+ public static final String ERROR_CODE = "0xA2107";
+
+ public static final String ERROR_MSG_FORMAT = " The abstract nonterminal %s must not extend the %s nonterminal %s. " +
+ "Abstract nonterminals may only extend abstract or normal nonterminals.";
+
+ @Override
+ public void check(ASTAbstractProd a) {
+ if (!a.getSuperRuleList().isEmpty()) {
+ List superRules = a.getSuperRuleList();
+ for(ASTRuleReference sr : superRules){
+ Optional ruleSymbol = a.getEnclosingScope().resolveProd(sr.getName());
+ if(ruleSymbol.isPresent()){
+ ProdSymbol r = ruleSymbol.get();
+ boolean isInterface = r.isIsInterface();
+ boolean isExternal = r.isIsExternal();
+ if(isInterface || isExternal){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), isInterface? "interface": "external", r.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyExtendOrAstextendNTOrClass.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyExtendOrAstextendNTOrClass.java
new file mode 100644
index 0000000000..96436e6410
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyExtendOrAstextendNTOrClass.java
@@ -0,0 +1,27 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTAbstractProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTAbstractProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that abstract nonterminals do not extend and astextend a type.
+ *
+ */
+public class AbstractNTOnlyExtendOrAstextendNTOrClass implements GrammarASTAbstractProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4030";
+
+ public static final String ERROR_MSG_FORMAT = " The abstract nonterminal %s must not extend and astextend a type.";
+
+ @Override
+ public void check(ASTAbstractProd a) {
+ if (!a.getSuperRuleList().isEmpty() && !a.getASTSuperClassList().isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyExtendsOneNTOrClass.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyExtendsOneNTOrClass.java
new file mode 100644
index 0000000000..5c5e45332b
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyExtendsOneNTOrClass.java
@@ -0,0 +1,32 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTAbstractProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTAbstractProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that abstract nonterminals do not extend more than one nonterminals/class.
+ *
+
+ */
+public class AbstractNTOnlyExtendsOneNTOrClass implements GrammarASTAbstractProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4012";
+
+ public static final String ERROR_MSG_FORMAT = " The abstract nonterminal %s must not %s more than one %s.";
+
+ @Override
+ public void check(ASTAbstractProd a) {
+ if (a.getSuperRuleList().size()>1) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), "extend", "nonterminal"),
+ a.get_SourcePositionStart());
+ }
+ if(a.getASTSuperClassList().size()>1){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), "astextend", "class"),
+ a.get_SourcePositionStart());
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyImplementInterfaceNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyImplementInterfaceNTs.java
new file mode 100644
index 0000000000..1159738e7a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTOnlyImplementInterfaceNTs.java
@@ -0,0 +1,42 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTAbstractProd;
+import de.monticore.grammar.grammar._ast.ASTRuleReference;
+import de.monticore.grammar.grammar._cocos.GrammarASTAbstractProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that abstract nonterminals only implement interface nonterminals.
+ *
+ */
+public class AbstractNTOnlyImplementInterfaceNTs implements GrammarASTAbstractProdCoCo {
+
+ public static final String ERROR_CODE = "0xA2106";
+
+ public static final String ERROR_MSG_FORMAT = " The abstract nonterminal %s must not implement the nonterminal %s. "
+ +
+ "Abstract nonterminals may only implement interface nonterminals.";
+
+ @Override
+ public void check(ASTAbstractProd a) {
+ if (!a.getSuperInterfaceRuleList().isEmpty()) {
+ List interfaces = a.getSuperInterfaceRuleList();
+ for (ASTRuleReference i : interfaces) {
+ Optional ruleSymbol = a.getEnclosingScope().resolveProd(i.getName());
+ if (ruleSymbol.isPresent()) {
+ ProdSymbol r = ruleSymbol.get();
+ if (!r.isIsInterface()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), r.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTWithoutExtensionOnlyInComponentGrammar.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTWithoutExtensionOnlyInComponentGrammar.java
new file mode 100644
index 0000000000..22c4d523a7
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AbstractNTWithoutExtensionOnlyInComponentGrammar.java
@@ -0,0 +1,100 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbolSurrogate;
+import de.se_rwth.commons.StringTransformations;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Checks that abstract nonterminals witheout extending productions only occur in a component grammar.
+ *
+ */
+public class AbstractNTWithoutExtensionOnlyInComponentGrammar implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA0277";
+
+ public static final String ERROR_MSG_FORMAT = " The abstract nonterminal %s must not be used without nonterminals " +
+ "extending it in a grammar not marked as a grammar component.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ if (!a.isComponent()) {
+
+ Collection localProds = grammarSymbol.getProds();
+ List superGrammars = grammarSymbol.getAllSuperGrammars();
+
+ List abstractProds = localProds.stream().
+ filter(ProdSymbol::isIsAbstract).collect(Collectors.toList());
+ List prods = localProds.stream().
+ filter(prodSymbol -> prodSymbol.isClass() || prodSymbol.isIsAbstract()).collect(Collectors.toList());
+
+ for(MCGrammarSymbol symbol: superGrammars){
+ Collection prodSymbols = symbol.getProds();
+ for(ProdSymbol mcProdSymbol : prodSymbols){
+ if (mcProdSymbol.isIsAbstract()) {
+ abstractProds.add(mcProdSymbol);
+ }
+ if (mcProdSymbol.isIsAbstract() || mcProdSymbol.isClass()) {
+ prods.add(mcProdSymbol);
+ }
+
+ }
+ }
+
+ if(!abstractProds.isEmpty()) {
+ List temp = new ArrayList<>(abstractProds);
+ for(ProdSymbol abstractProdSymbol : abstractProds){
+ for(ProdSymbolSurrogate abstractProdExtended : abstractProdSymbol.getSuperProds()){
+ for(int i = abstractProds.size()-1;i>=0;--i){
+ ProdSymbol abstractProd = abstractProds.get(i);
+ if(abstractProdExtended.lazyLoadDelegate().getName().equals(abstractProd.getName())){
+ temp.remove(abstractProdExtended.lazyLoadDelegate());
+ }
+ }
+ }
+ }
+ abstractProds = temp;
+ }
+
+ if(!abstractProds.isEmpty()){
+ for (ProdSymbol prodSymbol : prods) {
+ for (ProdSymbolSurrogate abstractProdImplemented : prodSymbol.getSuperProds()) {
+ for (int i = abstractProds.size() - 1; i >= 0; --i) {
+ ProdSymbol interfaceProd = abstractProds.get(i);
+ if (abstractProdImplemented.getName().equals(interfaceProd.getName())) {
+ abstractProds.remove(i);
+ }
+ }
+ }
+ }
+ }
+
+ for (ProdSymbol prodSymbol: abstractProds) {
+ List checkList = Lists.newArrayList(prodSymbol.getName());
+ prodSymbol.getSuperProds().stream().forEach(i -> checkList.add(i.getName()));
+ for (ProdSymbol prod : prods) {
+ for (String name: checkList) {
+ if (!prod.getSpannedScope().resolveRuleComponentDownMany(StringTransformations.uncapitalize(name)).isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, name), a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AttributeNameLowerCase.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AttributeNameLowerCase.java
new file mode 100644
index 0000000000..db459b38eb
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/AttributeNameLowerCase.java
@@ -0,0 +1,32 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTNonTerminal;
+import de.monticore.grammar.grammar._cocos.GrammarASTNonTerminalCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminal names start lower-case.
+ *
+
+ */
+public class AttributeNameLowerCase implements GrammarASTNonTerminalCoCo {
+
+ public static final String ERROR_CODE = "0xA4005";
+
+ public static final String ERROR_MSG_FORMAT = " The name %s used for the nonterminal %s referenced by the production %s" +
+ " should start with a lower-case letter.";
+
+ @Override
+ public void check(ASTNonTerminal a) {
+ if (a.isPresentUsageName()) {
+ if (!Character.isLowerCase(a.getUsageName().charAt(0))) {
+ String rulename = a.getEnclosingScope().getSpanningSymbol().getName();
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getUsageName(), a.getName(), rulename),
+ a.get_SourcePositionStart());
+ }
+
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ConservativeExtensionCheck.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ConservativeExtensionCheck.java
new file mode 100644
index 0000000000..e18c9e0be4
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ConservativeExtensionCheck.java
@@ -0,0 +1,74 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTGrammarAnnotation;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._symboltable.RuleComponentSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+
+public class ConservativeExtensionCheck implements GrammarASTMCGrammarCoCo {
+
+ // TODO: Multiple kinds of Errors, #2376
+
+ public static final String ERROR_CODE = "0xA2007";
+
+ public static final String ERROR_MSG_FORMAT = " Warning: Production %s does not extend %s in a conservative manner in component %s. This can lead to problems in the AST.";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ MCGrammarSymbol g = node.getSymbol();
+ for (ProdSymbol nt : g.getProds()) {
+ if (!hasNonConservativeAnno(nt.getAstNode().getGrammarAnnotationList())) {
+ //check when you extend a class not conservative directly (Subclass extends Superclass = ...)
+ if (nt.isClass() && !nt.getSuperProds().isEmpty()
+ && !MCGrammarSymbolTableHelper.getAllSuperProds(nt).isEmpty()) {
+ for (ProdSymbol superNt : MCGrammarSymbolTableHelper.getAllSuperProds(nt)) {
+ compareComponents(nt, superNt);
+ }
+ }
+ //checks when you define a Prod with the same Name as a Prod in a Supergrammar
+ if(!g.getSuperGrammarSymbols().isEmpty()){
+ for(MCGrammarSymbol superg : g.getSuperGrammarSymbols()){
+ for(ProdSymbol superNt : superg.getProds()){
+ if(nt.getName().equals(superNt.getName())){
+ compareComponents(nt, superNt);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected void compareComponents(ProdSymbol p, ProdSymbol superp) {
+ for (RuleComponentSymbol comp : superp.getProdComponents()) {
+ List prodComponents = p.getSpannedScope().resolveRuleComponentDownMany(comp.getName());
+ if (prodComponents.isEmpty()) {
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, p.getName(), superp.getFullName(), comp.getName()),
+ p.getSourcePosition());
+ }else if (prodComponents.get(0).isIsTerminal() != comp.isIsTerminal() ||
+ prodComponents.get(0).isIsNonterminal() != comp.isIsNonterminal() ||
+ prodComponents.get(0).isIsList() != comp.isIsList() ||
+ prodComponents.get(0).isIsOptional() != comp.isIsOptional() ||
+ !prodComponents.get(0).getName().equals(comp.getName())) {
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, p.getName(), superp.getFullName(), comp.getName()),
+ p.getSourcePosition());
+ }
+ }
+ }
+
+ protected boolean hasNonConservativeAnno(List grammarAnnotationsList) {
+ for (ASTGrammarAnnotation anno : grammarAnnotationsList) {
+ if (anno.isNonConservative()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DerivedAndManualListName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DerivedAndManualListName.java
new file mode 100644
index 0000000000..6a76049259
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DerivedAndManualListName.java
@@ -0,0 +1,63 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTNonTerminal;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTProdCoCo;
+import de.monticore.grammar.grammar._symboltable.RuleComponentSymbol;
+import de.monticore.grammar.grammar._symboltable.RuleComponentSymbolTOP;
+import de.se_rwth.commons.StringTransformations;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * checks that one NonTerminal does not define a component with the same derived and a manual name at the same time
+ * for example:
+ * A = names:Name* Name*;
+ * is not allowed because both definition are merged into the same attribute but create different method names
+ * form names:Name* e.g. the method name getNameList() is created
+ * but from Name* e.g. the method name getNameList() is created
+ *
+ * this does not fit together and is therefore forbidden
+ */
+public class DerivedAndManualListName implements GrammarASTProdCoCo {
+
+ public static final String ERROR_CODE = "0xA2008";
+
+ public static final String ERROR_MSG_FORMAT = " The production '%s' contains two list nonterminals " +
+ "that result in the attribute name '%s'. " +
+ "But one name is derived from the nonterminal name and one is set manually. This is not allowed.";
+
+ @Override
+ public void check(ASTProd node) {
+ if (node.isPresentSymbol()) {
+ List listComponents = node.getSymbol().getProdComponents().stream()
+ .filter(RuleComponentSymbolTOP::isIsList)
+ .collect(Collectors.toList());
+ for (int i = 0; i < listComponents.size(); i++) {
+ for (int j = i + 1; j < listComponents.size(); j++) {
+ if ((listComponents.get(i).isIsNonterminal() && listComponents.get(j).isIsNonterminal()) ||
+ (listComponents.get(i).isIsLexerNonterminal() && listComponents.get(j).isIsLexerNonterminal())) {
+ ASTNonTerminal nonterminal1 = (ASTNonTerminal) listComponents.get(i).getAstNode();
+ ASTNonTerminal nonterminal2 = (ASTNonTerminal) listComponents.get(j).getAstNode();
+ if (getAttributeName(nonterminal1).equals(getAttributeName(nonterminal2)) &&
+ nonterminal1.isPresentUsageName() != nonterminal2.isPresentUsageName()){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, node.getName(),getAttributeName(nonterminal1)),
+ node.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected String getAttributeName(ASTNonTerminal astNonTerminal) {
+ if (astNonTerminal.isPresentUsageName()) {
+ return astNonTerminal.getUsageName();
+ } else {
+ return StringTransformations.uncapitalize(astNonTerminal.getName()) + "s";
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DuplicatedEnumConstant.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DuplicatedEnumConstant.java
new file mode 100644
index 0000000000..a56a10da4d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DuplicatedEnumConstant.java
@@ -0,0 +1,36 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.monticore.grammar.grammar._ast.ASTConstant;
+import de.monticore.grammar.grammar._ast.ASTEnumProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTEnumProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that every EnumConstant is only used once
+ *
+ */
+public class DuplicatedEnumConstant implements GrammarASTEnumProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4014";
+
+ public static final String ERROR_MSG_FORMAT = " Duplicate enum constant: %s.";
+ public static final String HINT = "\nHint: The constants of enumerations must be unique within an enumeration.";
+
+ @Override
+ public void check(ASTEnumProd a) {
+ List constants = new ArrayList<>();
+ for(ASTConstant c: a.getConstantList()) {
+ if(!constants.contains(c.getName())){
+ constants.add(c.getName());
+ } else {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, c.getName()) + HINT,
+ c.get_SourcePositionStart());
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DuplicatedSymbolDefinitionInProd.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DuplicatedSymbolDefinitionInProd.java
new file mode 100644
index 0000000000..2f8bfb5064
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/DuplicatedSymbolDefinitionInProd.java
@@ -0,0 +1,33 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._ast.ASTSymbolDefinition;
+import de.monticore.grammar.grammar._cocos.GrammarASTProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that Prods have one symbol and one scope keyword at most
+ *
+ */
+public class DuplicatedSymbolDefinitionInProd implements GrammarASTProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4041";
+
+ public static final String ERROR_MSG_FORMAT = " Symbol or scope is mentioned more than once in the declaration '%s'.";
+
+ @Override
+ public void check(ASTProd a) {
+ boolean isScope = false;
+ boolean isSymbol = false;
+ for (ASTSymbolDefinition c : a.getSymbolDefinitionList()) {
+ if ((c.isGenScope() && isScope) || (c.isGenSymbol() && isSymbol)) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()), a.get_SourcePositionStart());
+ }
+ isScope |= c.isGenScope();
+ isSymbol |= c.isGenSymbol();
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ExternalNTNoASTRule.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ExternalNTNoASTRule.java
new file mode 100644
index 0000000000..62b2225afa
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ExternalNTNoASTRule.java
@@ -0,0 +1,25 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTASTRule;
+import de.monticore.grammar.grammar._cocos.GrammarASTASTRuleCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Optional;
+
+public class ExternalNTNoASTRule implements GrammarASTASTRuleCoCo {
+
+ public static final String ERROR_CODE = "0xA4118";
+
+ public static final String ERROR_MSG_FORMAT = " The external production %s must not have a " +
+ "corresponding ASTRule.";
+
+ @Override
+ public void check(ASTASTRule node) {
+ Optional prod = node.getEnclosingScope().resolveProd(node.getType());
+ if(prod.isPresent() && prod.get().isIsExternal()){
+ Log.error(ERROR_CODE+String.format(ERROR_MSG_FORMAT, prod.get().getName()));
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ExternalNTOnlyInComponentGrammar.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ExternalNTOnlyInComponentGrammar.java
new file mode 100644
index 0000000000..930459dc92
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/ExternalNTOnlyInComponentGrammar.java
@@ -0,0 +1,77 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.StringTransformations;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Checks that external nonterminals only occur in a component grammar.
+ *
+
+ */
+public class ExternalNTOnlyInComponentGrammar implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA0276";
+
+ public static final String ERROR_MSG_FORMAT = " The external nonterminal %s must not be used in a grammar not marked " +
+ "as a grammar component.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+
+ if (!a.isComponent()) {
+ List externalProds = grammarSymbol.getProds().stream().
+ filter(ProdSymbol::isIsExternal).collect(Collectors.toList());
+ for(MCGrammarSymbol symbol: grammarSymbol.getAllSuperGrammars()){
+ Collection prodSymbols = symbol.getProds();
+ for(ProdSymbol mcProdSymbol : prodSymbols){
+ if (mcProdSymbol.isIsExternal()) {
+ externalProds.add(mcProdSymbol);
+ }
+ }
+ }
+
+ List prods = grammarSymbol.getProds().stream().
+ filter(prodSymbol -> prodSymbol.isClass() || prodSymbol.isIsAbstract()).collect(Collectors.toList());
+ for(MCGrammarSymbol symbol: grammarSymbol.getAllSuperGrammars()){
+ Collection prodSymbols = symbol.getProds();
+ for(ProdSymbol mcProdSymbol : prodSymbols){
+ if (mcProdSymbol.isIsAbstract() || mcProdSymbol.isClass()) {
+ prods.add(mcProdSymbol);
+ }
+ }
+ }
+
+ if(!externalProds.isEmpty()) {
+ for (ProdSymbol prodSymbol : prods) {
+ for (int i = externalProds.size()-1; i >= 0; i--) {
+ ProdSymbol externalProdSymbol = externalProds.get(i);
+ if (prodSymbol.getName().equals(externalProdSymbol.getName())) {
+ externalProds.remove(i);
+ }
+ }
+ }
+ }
+
+ for (ProdSymbol prodSymbol: externalProds) {
+ for (ProdSymbol prod : prods) {
+ if (!prod.getSpannedScope().resolveRuleComponentMany(StringTransformations.uncapitalize(prodSymbol.getName())).isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, prodSymbol.getName()), a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+
+}
+
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarCoCos.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarCoCos.java
new file mode 100644
index 0000000000..b0e92c01fe
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarCoCos.java
@@ -0,0 +1,113 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar_withconcepts._cocos.Grammar_WithConceptsCoCoChecker;
+
+public class GrammarCoCos {
+ public Grammar_WithConceptsCoCoChecker getCoCoChecker() {
+ Grammar_WithConceptsCoCoChecker checker = new Grammar_WithConceptsCoCoChecker();
+ checker.addCoCo(new OverridingNTsHaveNoSuperRules());
+ checker.addCoCo(new OverridingAbstractNTsHaveNoSuperRules());
+ checker.addCoCo(new OverridingEnumNTs());
+ checker.addCoCo(new OverridingNTs());
+ checker.addCoCo(new OverridingAbstractNTs());
+ checker.addCoCo(new OverridingInterfaceNTs());
+ checker.addCoCo(new DuplicatedEnumConstant());
+ checker.addCoCo(new NTAndASTRuleExtendType());
+ checker.addCoCo(new NoASTRuleForEnumNTs());
+ checker.addCoCo(new NTForASTRuleExists());
+ checker.addCoCo(new MultipleASTRules());
+ checker.addCoCo(new NoASTExtendsForClasses());
+ checker.addCoCo(new LexNTsOnlyUseLexNTs());
+ checker.addCoCo(new UsedLexNTNotDefined());
+ checker.addCoCo(new UsedNTNotDefined());
+ checker.addCoCo(new InterfaceNTWithoutImplementationOnlyInComponentGrammar());
+ checker.addCoCo(new ExternalNTOnlyInComponentGrammar());
+ checker.addCoCo(new AbstractNTWithoutExtensionOnlyInComponentGrammar());
+ checker.addCoCo(new ProdAndExtendedProdUseSameAttrNameForDiffNTs());
+ checker.addCoCo(new GrammarNameUpperCase());
+ checker.addCoCo(new GrammarExtensionOnce());
+ checker.addCoCo(new AbstractNTNotExtendInterfaceOrExternalNTs());
+ checker.addCoCo(new AbstractNTOnlyExtendOrAstextendNTOrClass());
+ checker.addCoCo(new AbstractNTOnlyExtendsOneNTOrClass());
+ checker.addCoCo(new AbstractNTOnlyImplementInterfaceNTs());
+ checker.addCoCo(new AttributeNameLowerCase());
+ checker.addCoCo(new InterfaceNTOnlyExtendInterfaceNTs());
+ checker.addCoCo(new KeywordAlternativeName());
+ checker.addCoCo(new NTNotExtendInterfaceOrExternalNTs());
+ checker.addCoCo(new NTOnlyExtendOrAstextendNTOrClass());
+ checker.addCoCo(new NTOnlyExtendsOneNTOrClass());
+ checker.addCoCo(new NTOnlyImplementInterfaceNTs());
+ checker.addCoCo(new ProdStartsWithCapital());
+ checker.addCoCo(new ProdAndOverriddenProdUseSameAttrNameForDiffNTs());
+ checker.addCoCo(new ProdWithExtensionMustNotBeOverridden());
+ checker.addCoCo(new ASTRuleAndNTUseSameAttrNameForDiffNTs());
+ checker.addCoCo(new OverridingLexNTs());
+ checker.addCoCo(new GrammarInheritanceCycle());
+ checker.addCoCo(new LeftRecursiveRulesInBlock());
+ checker.addCoCo(new DuplicatedSymbolDefinitionInProd());
+ checker.addCoCo(new SubrulesUseInterfaceNTs());
+ checker.addCoCo(new ReferenceSymbolSameAttribute());
+ checker.addCoCo(new ReferenceSymbolNotName());
+ checker.addCoCo(new ReferencedSymbolExists());
+ checker.addCoCo(new ConservativeExtensionCheck());
+ checker.addCoCo(new NoTokenDefined());
+ // checker.addCoCo(new InheritedSymbolProperty());
+ // checker.addCoCo(new InheritedScopeProperty());
+ checker.addCoCo(new SymbolRuleWithoutSymbolRef());
+ checker.addCoCo(new SymbolRuleHasName());
+ checker.addCoCo(new NoNestedGenericsInAdditionalAttributes());
+ checker.addCoCo(new NoMultipleSymbolRule());
+ checker.addCoCo(new SymbolProdOverwrittenBySymbol());
+ checker.addCoCo(new ScopeProdOverwrittenByScope());
+ checker.addCoCo(new UniqueProdNameInGrammar());
+ checker.addCoCo(new ProdExtendsNotExistingProd());
+ checker.addCoCo(new TokenConstantInvalid());
+ checker.addCoCo(new SplitRuleInvalid());
+ checker.addCoCo(new KeyConstantInvalid());
+ checker.addCoCo(new KeywordRuleInvalid());
+ checker.addCoCo(new TerminalCritical());
+ checker.addCoCo(new PackageNameLowerCase());
+ checker.addCoCo(new NoOverridingNTHasAnnotation());
+ checker.addCoCo(new OverridingNTHasNoAnnotation());
+ checker.addCoCo(new ProdWithDoubleAnnos());
+ checker.addCoCo(new ExternalNTNoASTRule());
+ checker.addCoCo(new DerivedAndManualListName());
+ checker.addCoCo(new KeyRuleWithoutName());
+ checker.addCoCo(new SymbolWithManyNames());
+ checker.addCoCo(new OverridingAdditionalAttributes());
+ checker.addCoCo(new NoExtensionOfSymbolThatOnlySpansScope());
+ // checker.addCoCo(new NoNTInheritanceCycle());
+ checker.addCoCo(new LexProdModeNameUpperCase());
+ checker.addCoCo(new NoTokenModeInComponentGrammar());
+ checker.addCoCo(new InheritedModiOverwrite());
+ checker.addCoCo(new NoForbiddenGrammarName());
+ checker.addCoCo(new NoForbiddenProdName());
+ checker.addCoCo(new NoForbiddenProdAndSymbolName());
+ checker.addCoCo(new NoForbiddenProdNameAddon());
+ checker.addCoCo(new NoForbiddenSymbolName());
+ checker.addCoCo(new NoForbiddenSymbolNameAddon());
+ checker.addCoCo(new RuleComponentsCompatible());
+
+ return checker;
+ }
+
+ public Grammar_WithConceptsCoCoChecker getSymbolTableCoCoChecker() {
+ Grammar_WithConceptsCoCoChecker checker = new Grammar_WithConceptsCoCoChecker();
+ checker.addCoCo(new OverridingNTsHaveNoSuperRules());
+ checker.addCoCo(new OverridingAbstractNTsHaveNoSuperRules());
+ checker.addCoCo(new OverridingEnumNTs());
+ checker.addCoCo(new OverridingNTs());
+ checker.addCoCo(new OverridingAbstractNTs());
+ checker.addCoCo(new UsedNTNotDefined());
+ checker.addCoCo(new KeywordAlternativeName());
+ checker.addCoCo(new NTDefinedByAtmostOneProduction());
+ checker.addCoCo(new NTUniqueIgnoreCase());
+ checker.addCoCo(new ReferencedNTNotDefined());
+ checker.addCoCo(new KeywordInvalidName());
+ checker.addCoCo(new LexNTsNotEmpty());
+
+ return checker;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarExtensionOnce.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarExtensionOnce.java
new file mode 100644
index 0000000000..402d7bbaa8
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarExtensionOnce.java
@@ -0,0 +1,31 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.Names;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that a grammar does not extend the same grammar multiple times
+ */
+public class GrammarExtensionOnce implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4150";
+
+ public static final String ERROR_MSG_FORMAT = "A grammar must not extend another grammar multiple times.";
+
+ @Override
+ public void check(ASTMCGrammar gr) {
+ for (int i = 0; i < gr.getSupergrammarList().size() - 1; i++) {
+ for (int j = i + 1; j < gr.getSupergrammarList().size(); j++) {
+ if (Names.getQualifiedName(gr.getSupergrammar(i).getNameList()).equals(
+ Names.getQualifiedName(gr.getSupergrammar(j).getNameList()))) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, gr.getName()),
+ gr.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarInheritanceCycle.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarInheritanceCycle.java
new file mode 100644
index 0000000000..fae90d86be
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarInheritanceCycle.java
@@ -0,0 +1,35 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTGrammarReference;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.Names;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminal names start lower-case.
+ *
+
+ */
+public class GrammarInheritanceCycle implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4023";
+
+ public static final String ERROR_MSG_FORMAT = " The grammar %s introduces an inheritance cycle.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ for(ASTGrammarReference ref : a.getSupergrammarList()) {
+ if (Names.getQualifiedName(ref.getNameList()).equals(
+ Names.getQualifiedName(a.getPackageList()) +"."+ a.getName())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ return;
+ }
+ }
+ }
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarNameUpperCase.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarNameUpperCase.java
new file mode 100644
index 0000000000..5616218a18
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/GrammarNameUpperCase.java
@@ -0,0 +1,28 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminal names start lower-case.
+ *
+
+ */
+public class GrammarNameUpperCase implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4033";
+
+ public static final String ERROR_MSG_FORMAT = " The grammar's name %s should start with an upper-case letter.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ if (!Character.isUpperCase(a.getName().charAt(0))) {
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ }
+
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedModiOverwrite.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedModiOverwrite.java
new file mode 100644
index 0000000000..1af62cec7f
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedModiOverwrite.java
@@ -0,0 +1,43 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTLexProd;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.se_rwth.commons.Joiners;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class InheritedModiOverwrite implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4069";
+ public static final String ERROR_MSG_FORMAT = " The lexical production %s of the grammar %s will inherit the token mode %s as it overwrites the lexical production %s of the grammar %s";
+
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ List superGrammars = node.getSymbol().getAllSuperGrammars();
+ for (MCGrammarSymbol superGrammar : superGrammars) {
+ ASTMCGrammar astNode = superGrammar.getAstNode();
+ String superGrammarName = superGrammar.getName();
+ for (ASTLexProd lexProd : astNode.getLexProdList()) {
+ if (lexProd.isPresentMode()) {
+ String modeString = lexProd.getMode();
+ String prodName = lexProd.getName();
+ List supLexProdList = node.getLexProdList().stream().filter(prod -> prod.getName().equals(prodName)).collect(Collectors.toList());
+ for (ASTLexProd lex : supLexProdList) {
+ if (!lex.isPresentMode()) {
+ //warn the user that he inherits a token mode
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, prodName, grammarName, modeString, prodName, superGrammarName));
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedScopeProperty.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedScopeProperty.java
new file mode 100644
index 0000000000..6fad4d90f1
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedScopeProperty.java
@@ -0,0 +1,35 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Set;
+
+/**
+ * Checks that prods do not inherit their symbols from more than one class
+ */
+public class InheritedScopeProperty implements GrammarASTProdCoCo {
+
+ public static final String ERROR_CODE = "0xA0135";
+
+ public static final String ERROR_MSG_FORMAT = " The rule %s inherits scope properties from more than one class.";
+
+ @Override
+ public void check(ASTProd a) {
+ ProdSymbol s = a.getSymbol();
+ Set superProds = MCGrammarSymbolTableHelper.getAllSuperProds(s);
+ boolean found = s.isIsScopeSpanning();
+ for (ProdSymbol prod : superProds) {
+ if (found && prod.isIsScopeSpanning()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()), a.get_SourcePositionStart());
+ } else if (prod.isIsScopeSpanning()) {
+ found = true;
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedSymbolProperty.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedSymbolProperty.java
new file mode 100644
index 0000000000..c975675cf4
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InheritedSymbolProperty.java
@@ -0,0 +1,39 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Checks that prods do not inherit their symbols from more than one class
+ */
+public class InheritedSymbolProperty implements GrammarASTProdCoCo {
+
+ public static final String ERROR_CODE = "0xA0125";
+
+ public static final String ERROR_MSG_FORMAT = " The rule %s inherits symbols from more than one class.";
+
+ @Override
+ public void check(ASTProd a) {
+ ProdSymbol s = a.getSymbol();
+ Set superProds = MCGrammarSymbolTableHelper.getAllSuperProds(s);
+ Optional found = Optional.empty();
+ for (ProdSymbol prod : superProds) {
+ if (found.isPresent() && prod.isIsSymbolDefinition()) {
+ if (!MCGrammarSymbolTableHelper.getAllSuperProds(found.get()).contains(prod)) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()), a.get_SourcePositionStart());
+ }
+ } else if (prod.isIsSymbolDefinition()) {
+ found = Optional.of(prod);
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InterfaceNTOnlyExtendInterfaceNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InterfaceNTOnlyExtendInterfaceNTs.java
new file mode 100644
index 0000000000..a37924dc55
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InterfaceNTOnlyExtendInterfaceNTs.java
@@ -0,0 +1,46 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTInterfaceProd;
+import de.monticore.grammar.grammar._ast.ASTRuleReference;
+import de.monticore.grammar.grammar._cocos.GrammarASTInterfaceProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only extends abstract or normal nonterminals..
+ *
+ */
+public class InterfaceNTOnlyExtendInterfaceNTs implements GrammarASTInterfaceProdCoCo {
+
+ public static final String ERROR_CODE = "0xA2116";
+
+ public static final String ERROR_MSG_FORMAT = " The interface nonterminal %s must not extend the%s nonterminal %s. "
+ +
+ "Interface nonterminals may only extend interface nonterminals.";
+
+ @Override
+ public void check(ASTInterfaceProd a) {
+ if (!a.getSuperInterfaceRuleList().isEmpty()) {
+ List superRules = a.getSuperInterfaceRuleList();
+ for (ASTRuleReference sr : superRules) {
+ Optional ruleSymbol = a.getEnclosingScope().resolveProd(sr.getName());
+ if (ruleSymbol.isPresent()) {
+ ProdSymbol r = ruleSymbol.get();
+ boolean isAbstract = r.isIsAbstract();
+ boolean isExternal = r.isIsExternal();
+ if (!r.isIsInterface()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(),
+ isAbstract ? " abstract" : isExternal ? " external" : "", r.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InterfaceNTWithoutImplementationOnlyInComponentGrammar.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InterfaceNTWithoutImplementationOnlyInComponentGrammar.java
new file mode 100644
index 0000000000..6c11d6e980
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/InterfaceNTWithoutImplementationOnlyInComponentGrammar.java
@@ -0,0 +1,123 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbolSurrogate;
+import de.monticore.grammar.grammar._symboltable.RuleComponentSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Checks that abstract nonterminals witheout extending productions only occur in a component grammar.
+ */
+public class InterfaceNTWithoutImplementationOnlyInComponentGrammar implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA0278";
+
+ public static final String ERROR_MSG_FORMAT = " The interface nonterminal %s must not be used without nonterminals " +
+ "implementing it in a grammar not marked as a grammar component.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+
+ // if the given grammar is a component grammar we ignore it, since there we allow interfaces without an
+ // implementation
+ if (!a.isComponent()) {
+
+ // we collect all interface productions from the grammar and all its super grammars and save them to the list
+ // interfaceProds
+ List interfaceProds = grammarSymbol.getProds().stream().
+ filter(ProdSymbol::isIsInterface).collect(Collectors.toList());
+ for (MCGrammarSymbol symbol : grammarSymbol.getAllSuperGrammars()) {
+ Collection prodSymbols = symbol.getProds();
+ for (ProdSymbol mcProdSymbol : prodSymbols) {
+ if (mcProdSymbol.isIsInterface()) {
+ interfaceProds.add(mcProdSymbol);
+ }
+ }
+ }
+
+ // for every interface production we get all other interfaces implementing it and save it to map of all interface
+ // productions mapping to all their subinterfaces
+ Map> subSymbols = new HashMap<>();
+ for (ProdSymbol interfaceProd : interfaceProds) {
+ for (ProdSymbol superInterface : interfaceProd.getSuperInterfaceProds()) {
+ if (!subSymbols.containsKey(superInterface.getName())) {
+ subSymbols.put(superInterface.getName(), new ArrayList<>());
+ }
+ subSymbols.get(superInterface.getName()).add(interfaceProd);
+ }
+ }
+
+ // we collect all non-interface productions from the grammar and all its super-grammars and save them to the list
+ // prods
+ List prods = grammarSymbol.getProds().stream().
+ filter(prodSymbol -> prodSymbol.isClass() || prodSymbol.isIsAbstract()).collect(Collectors.toList());
+ for (MCGrammarSymbol symbol : grammarSymbol.getAllSuperGrammars()) {
+ Collection prodSymbols = symbol.getProds();
+ for (ProdSymbol mcProdSymbol : prodSymbols) {
+ if (mcProdSymbol.isIsAbstract() || mcProdSymbol.isClass()) {
+ prods.add(mcProdSymbol);
+ }
+ }
+ }
+
+ // from the list interfaceProds we remove every interface production that does not get used in a non-interface
+ // production
+ if (!interfaceProds.isEmpty()) {
+ List temp = new ArrayList<>();
+ for (ProdSymbol prod : prods) {
+ for (RuleComponentSymbol component : prod.getProdComponents()) {
+ for (ProdSymbol interfaceProd : interfaceProds) {
+ if (component.isPresentReferencedType() && component.getReferencedType().equals(interfaceProd.getName())) {
+ temp.add(interfaceProd);
+ }
+ }
+ }
+ }
+ interfaceProds = temp;
+ }
+
+ // for every remaining interface production we check if it or any subinterface gets implemented anywhere and
+ // otherwise log an error since it gets used in a production without getting implemented
+ for (ProdSymbol interf : interfaceProds) {
+ if (!isImplemented(interf, prods, subSymbols)) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, interf.getName()), a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+
+ protected boolean isImplemented(ProdSymbol interfaceSymbol, List prods, Map> subSymbols) {
+
+ // if a production exists that directly implements the interface return true
+ for (ProdSymbol prod : prods) {
+ for (ProdSymbol implemented : prod.getSuperInterfaceProds()) {
+ if (implemented.getName().equals(interfaceSymbol.getName())) {
+ return true;
+ }
+ }
+ }
+
+ // otherwise get all interfaces that extend this interface and recursively call this method on them. if any of them
+ // return true end the method and return true. otherwise, if none of its subinterface gets implemented, return false
+ if (subSymbols.containsKey(interfaceSymbol.getName())) {
+ for (ProdSymbol subSymbol : subSymbols.get(interfaceSymbol.getName())) {
+ if (isImplemented(subSymbol, prods, subSymbols)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeyConstantInvalid.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeyConstantInvalid.java
new file mode 100644
index 0000000000..b26f0703bf
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeyConstantInvalid.java
@@ -0,0 +1,24 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTKeyConstant;
+import de.monticore.grammar.grammar._cocos.GrammarASTKeyConstantCoCo;
+import de.se_rwth.commons.logging.Log;
+
+public class KeyConstantInvalid implements GrammarASTKeyConstantCoCo {
+
+ public static final String ERROR_CODE = "0xA4091";
+
+ public static final String ERROR_MSG_FORMAT =
+ " The string '%s' for key() must be compatible to 'Name'";
+
+ @Override
+ public void check(ASTKeyConstant a) {
+ for (String s :a.getStringList()) {
+ if (!s.matches("[a-zA-Z_$][a-zA-Z0-9_$]*")) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, s), a.get_SourcePositionStart());
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeyRuleWithoutName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeyRuleWithoutName.java
new file mode 100644
index 0000000000..7f8361d878
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeyRuleWithoutName.java
@@ -0,0 +1,48 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar.GrammarMill;
+import de.monticore.grammar.grammar._ast.ASTGrammarNode;
+import de.monticore.grammar.grammar._ast.ASTKeyConstant;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._visitor.GrammarTraverser;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that a grammar using keyword rules defines the token Name
+ */
+public class KeyRuleWithoutName implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA0142";
+
+ public static final String ERROR_MSG_FORMAT = "Using the keyword rules a grammar must define the token Name.";
+
+ @Override
+ public void check(ASTMCGrammar gr) {
+ MCGrammarSymbol grSymbol = gr.getSymbol();
+ if (!gr.isComponent() && !grSymbol.getProdWithInherited("Name").isPresent()) {
+ if (!gr.getKeywordRuleList().isEmpty() || new FindKeyConstant().getResult(gr)) {
+ Log.error(ERROR_CODE + ERROR_MSG_FORMAT, gr.get_SourcePositionStart());
+ }
+ }
+ }
+
+ protected class FindKeyConstant implements GrammarVisitor2 {
+ protected boolean hasKeyConstant = false;
+
+ public boolean getResult(ASTGrammarNode ast) {
+ GrammarTraverser traverser = GrammarMill.traverser();
+ traverser.add4Grammar(this);
+ ast.accept(traverser);
+ return hasKeyConstant;
+ }
+
+ public void visit(ASTKeyConstant ast) {
+ hasKeyConstant = true;
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordAlternativeName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordAlternativeName.java
new file mode 100644
index 0000000000..d87ab6fe0d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordAlternativeName.java
@@ -0,0 +1,31 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTConstantGroup;
+import de.monticore.grammar.grammar._cocos.GrammarASTConstantGroupCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that alternatives of keywords are named.
+ *
+ */
+public class KeywordAlternativeName implements GrammarASTConstantGroupCoCo {
+
+ public static final String ERROR_CODE = "0xA4019";
+
+ public static final String ERROR_MSG_FORMAT = " The production %s must not use a ConstantGroup with more than one element without naming it.";
+
+ @Override
+ public void check(ASTConstantGroup a) {
+ if (!a.isPresentUsageName()&& a.getConstantList().size() >1) {
+ String rulename = MCGrammarSymbolTableHelper.getEnclosingRule(a).get().getName();
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, rulename),
+ a.get_SourcePositionStart());
+
+ }
+ }
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordInvalidName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordInvalidName.java
new file mode 100644
index 0000000000..ba6b8de860
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordInvalidName.java
@@ -0,0 +1,36 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTConstant;
+import de.monticore.grammar.grammar._ast.ASTConstantGroup;
+import de.monticore.grammar.grammar._cocos.GrammarASTConstantGroupCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that alternatives of keywords are named.
+ *
+
+ */
+public class KeywordInvalidName implements GrammarASTConstantGroupCoCo {
+
+ public static final String ERROR_CODE = "0xA4018";
+
+ public static final String ERROR_MSG_FORMAT = " The production %s must not use the keyword %s without naming it.";
+
+ @Override
+ public void check(ASTConstantGroup a) {
+ if (!a.isPresentUsageName()) {
+ for (ASTConstant c : a.getConstantList()) {
+ if (c.getHumanName().isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT,
+ a.getEnclosingScope().getSpanningSymbol()
+ .getName(),
+ c.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordRuleInvalid.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordRuleInvalid.java
new file mode 100644
index 0000000000..0e110c943e
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/KeywordRuleInvalid.java
@@ -0,0 +1,24 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTKeywordRule;
+import de.monticore.grammar.grammar._cocos.GrammarASTKeywordRuleCoCo;
+import de.se_rwth.commons.logging.Log;
+
+public class KeywordRuleInvalid implements GrammarASTKeywordRuleCoCo {
+
+ public static final String ERROR_CODE = "0xA4093";
+
+ public static final String ERROR_MSG_FORMAT =
+ " The string '%s' must be compatible to 'Name'";
+
+ @Override
+ public void check(ASTKeywordRule a) {
+ for (String s :a.getStringList()) {
+ if (!s.matches("[a-zA-Z_$][a-zA-Z0-9_$]*")) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, s), a.get_SourcePositionStart());
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LeftRecursiveRulesInBlock.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LeftRecursiveRulesInBlock.java
new file mode 100644
index 0000000000..fb3dc65836
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LeftRecursiveRulesInBlock.java
@@ -0,0 +1,47 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.DirectLeftRecursionDetector;
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTAlt;
+import de.monticore.grammar.grammar._ast.ASTBlock;
+import de.monticore.grammar.grammar._ast.ASTClassProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTClassProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Checks that blocks do not contain left recursive rules
+ * If Antlr (Antlr 4.5 throws an exception) can take care of it, the check is
+ * no longer necessary.
+ *
+ */
+public class LeftRecursiveRulesInBlock implements GrammarASTClassProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4056";
+
+ public static final String ERROR_MSG_FORMAT = " The left recursive rule %s is not allowed in blocks, because it is not supported in Antlr. ";
+
+ @Override
+ public void check(ASTClassProd a) {
+ if (!a.getSymbol().isIsDirectLeftRecursive() && !a.getSymbol().isIsIndirectLeftRecursive()) {
+ return;
+ }
+ DirectLeftRecursionDetector detector = new DirectLeftRecursionDetector();
+ ArrayList ruleNames = Lists.newArrayList(a.getName());
+ MCGrammarSymbolTableHelper.getAllSuperProds(a.getSymbol()).forEach(p -> ruleNames.add(p.getName()));
+ for (ASTAlt alt : a.getAltList()) {
+ if (!alt.getComponentList().isEmpty() && alt.getComponentList().get(0) instanceof ASTBlock) {
+ if (detector.isAlternativeLeftRecursive(alt, ruleNames)) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getSymbol().getName()),
+ a.get_SourcePositionStart());
+ return;
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexNTsNotEmpty.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexNTsNotEmpty.java
new file mode 100644
index 0000000000..e9347e7ea5
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexNTsNotEmpty.java
@@ -0,0 +1,64 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTConstantsGrammar;
+import de.monticore.grammar.grammar._ast.ASTLexAlt;
+import de.monticore.grammar.grammar._ast.ASTLexBlock;
+import de.monticore.grammar.grammar._ast.ASTLexChar;
+import de.monticore.grammar.grammar._ast.ASTLexCharRange;
+import de.monticore.grammar.grammar._ast.ASTLexComponent;
+import de.monticore.grammar.grammar._ast.ASTLexNonTerminal;
+import de.monticore.grammar.grammar._ast.ASTLexProd;
+import de.monticore.grammar.grammar._ast.ASTLexSimpleIteration;
+import de.monticore.grammar.grammar._ast.ASTLexString;
+import de.monticore.grammar.grammar._cocos.GrammarASTLexProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that used nonterminals are lexical nonterminals.
+ *
+
+ */
+public class LexNTsNotEmpty implements GrammarASTLexProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4015";
+
+ public static final String ERROR_MSG_FORMAT = " The lexical production %s must not allow the empty token.";
+
+ @Override
+ public void check(ASTLexProd a) {
+ for (ASTLexAlt alt : a.getAltList()) {
+ if (alt.getLexComponentList().isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ return;
+ }
+ else {
+ for (ASTLexComponent rc : alt.getLexComponentList()) {
+ if (rc instanceof ASTLexBlock) {
+ if (((ASTLexBlock) rc).getIteration() == ASTConstantsGrammar.PLUS
+ || ((ASTLexBlock) rc).getIteration() == ASTConstantsGrammar.DEFAULT) {
+ return;
+ }
+ }
+ else if (rc instanceof ASTLexSimpleIteration) {
+ if (((ASTLexSimpleIteration) rc).getIteration() == ASTConstantsGrammar.PLUS
+ || ((ASTLexSimpleIteration) rc).getIteration() == ASTConstantsGrammar.DEFAULT) {
+ return;
+ }
+ }
+ else if (rc instanceof ASTLexNonTerminal
+ || rc instanceof ASTLexString
+ || rc instanceof ASTLexChar
+ || rc instanceof ASTLexCharRange
+ || rc instanceof ASTLexString) {
+ return;
+ }
+ }
+ }
+ }
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexNTsOnlyUseLexNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexNTsOnlyUseLexNTs.java
new file mode 100644
index 0000000000..0334352fa9
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexNTsOnlyUseLexNTs.java
@@ -0,0 +1,41 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.Optional;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTLexNonTerminal;
+import de.monticore.grammar.grammar._cocos.GrammarASTLexNonTerminalCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that used nonterminals are lexical nonterminals.
+ *
+ */
+public class LexNTsOnlyUseLexNTs implements GrammarASTLexNonTerminalCoCo {
+
+ public static final String ERROR_CODE = "0xA4017";
+
+ public static final String ERROR_MSG_FORMAT = " The lexical production %s must not use" +
+ " the nonterminal %s because %s is defined by a production of" +
+ " another type than lexical. Lexical productions may only reference nonterminals" +
+ " defined by lexical productions.";
+
+ @Override
+ public void check(ASTLexNonTerminal a) {
+ Optional grammarSymbol = MCGrammarSymbolTableHelper
+ .getMCGrammarSymbol(a.getEnclosingScope());
+
+ Optional ruleSymbol = MCGrammarSymbolTableHelper.getEnclosingRule(a);
+ String ruleName = ruleSymbol.isPresent() ? ruleSymbol.get().getName() : "";
+ if (grammarSymbol.isPresent()
+ && grammarSymbol.get().getProdWithInherited(a.getName()).isPresent() &&
+ !grammarSymbol.get().getProdWithInherited(a.getName()).get().isIsLexerProd()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, ruleName, a.getName(), a.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexProdModeNameUpperCase.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexProdModeNameUpperCase.java
new file mode 100644
index 0000000000..6d4c99b1ae
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/LexProdModeNameUpperCase.java
@@ -0,0 +1,26 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTLexProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTLexProdCoCo;
+import de.se_rwth.commons.logging.Log;
+import org.apache.commons.lang3.StringUtils;
+
+public class LexProdModeNameUpperCase implements GrammarASTLexProdCoCo {
+ public static final String ERROR_CODE = "0xA4038";
+
+ public static final String ERROR_MSG_FORMAT = " The lexical production %s must use Upper-case mode names.";
+
+ @Override
+ public void check(ASTLexProd node) {
+ if (node.isPresentMode()) {
+ String m = node.getMode();
+ if(!StringUtils.isAllUpperCase(m)){
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, node.getName()),
+ node.get_SourcePositionStart());
+ }
+ }
+ }
+}
+
+
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/MultipleASTRules.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/MultipleASTRules.java
new file mode 100644
index 0000000000..52ffdde98a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/MultipleASTRules.java
@@ -0,0 +1,38 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.monticore.grammar.grammar._ast.ASTASTRule;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that for each rule there exists max. one astrule
+ *
+
+ */
+public class MultipleASTRules implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4020";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist more than one AST" +
+ " rule for the nonterminal %s.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ List nts = new ArrayList<>();
+ for(ASTASTRule rule : a.getASTRuleList()){
+ if (!nts.contains(rule.getType())) {
+ nts.add(rule.getType());
+ } else {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, rule.getType()),
+ rule.get_SourcePositionStart());
+ }
+ }
+
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTAndASTRuleExtendType.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTAndASTRuleExtendType.java
new file mode 100644
index 0000000000..9017610df7
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTAndASTRuleExtendType.java
@@ -0,0 +1,52 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Optional;
+
+/**
+ * Checks that nonterminal names start lower-case.
+ */
+public class NTAndASTRuleExtendType implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4013";
+
+ public static final String ERROR_MSG_FORMAT = " The AST rule for %s must not extend the type " +
+ "%s because the production already extends a type.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ for (ASTASTRule rule : a.getASTRuleList()) {
+ if (!rule.getASTSuperClassList().isEmpty()) {
+ Optional ruleSymbol = grammarSymbol.getProdWithInherited(rule.getType());
+ if (ruleSymbol.isPresent()) {
+ if (ruleSymbol.get().isClass()) {
+ if (ruleSymbol.get().isPresentAstNode()
+ && (!((ASTClassProd) ruleSymbol.get().getAstNode()).getASTSuperClassList().isEmpty()
+ || !((ASTClassProd) ruleSymbol.get().getAstNode()).getSuperRuleList().isEmpty())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, rule.getType(),
+ MCSimpleGenericTypesMill.prettyPrint(rule.getASTSuperClassList().get(0), false).trim()),
+ rule.get_SourcePositionStart());
+ }
+ } else if (ruleSymbol.get().isPresentAstNode()
+ && ruleSymbol.get().getAstNode() instanceof ASTAbstractProd) {
+ ASTAbstractProd prod = (ASTAbstractProd) ruleSymbol.get().getAstNode();
+ if (!prod.getASTSuperClassList().isEmpty() || !prod.getSuperRuleList().isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, rule.getType(),
+ MCSimpleGenericTypesMill.prettyPrint(rule.getASTSuperClassList().get(0), false).trim()),
+ rule.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTDefinedByAtmostOneProduction.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTDefinedByAtmostOneProduction.java
new file mode 100644
index 0000000000..4232d95348
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTDefinedByAtmostOneProduction.java
@@ -0,0 +1,44 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only extends abstract or normal nonterminals.
+ *
+ */
+public class NTDefinedByAtmostOneProduction implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA2025";
+
+ public static final String ERROR_MSG_FORMAT = " The nonterminal %s must not be defined by more than one production.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ List prodnames = new ArrayList<>();
+ List prods = new ArrayList<>();
+ prods.addAll(a.getAbstractProdList());
+ prods.addAll(a.getClassProdList());
+ prods.addAll(a.getEnumProdList());
+ prods.addAll(a.getInterfaceProdList());
+ prods.addAll(a.getLexProdList());
+ prods.addAll(a.getExternalProdList());
+
+ for(ASTProd p: prods){
+ if(prodnames.contains(p.getName())){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, p.getName()),
+ p.get_SourcePositionStart());
+ } else {
+ prodnames.add(p.getName());
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTForASTRuleExists.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTForASTRuleExists.java
new file mode 100644
index 0000000000..ab96a5519b
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTForASTRuleExists.java
@@ -0,0 +1,46 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.Map;
+
+import de.monticore.grammar.grammar._ast.ASTASTRule;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminal names start lower-case.
+ *
+
+ */
+public class NTForASTRuleExists implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4021";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist an AST rule for the nonterminal %s" +
+ " because there exists no production defining %s";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ boolean prodFound = false;
+ for(ASTASTRule astrule : a.getASTRuleList()){
+ if(!grammarSymbol.getProdWithInherited(astrule.getType()).isPresent()){
+ for(Map.Entry entry : grammarSymbol.getProdsWithInherited().entrySet()){
+ ProdSymbol rs = (ProdSymbol) entry.getValue();
+ if (astrule.getType().equals(rs.getName())) {
+ prodFound = true;
+ break ;
+ }
+ }
+ if (!prodFound) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, astrule.getType(), astrule.getType()),
+ astrule.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTNotExtendInterfaceOrExternalNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTNotExtendInterfaceOrExternalNTs.java
new file mode 100644
index 0000000000..e2e5c9022d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTNotExtendInterfaceOrExternalNTs.java
@@ -0,0 +1,47 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTClassProd;
+import de.monticore.grammar.grammar._ast.ASTRuleReference;
+import de.monticore.grammar.grammar._cocos.GrammarASTClassProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only extends abstract or normal nonterminals.
+ *
+
+ */
+public class NTNotExtendInterfaceOrExternalNTs implements GrammarASTClassProdCoCo {
+
+ public static final String ERROR_CODE = "0xA2103";
+
+ public static final String ERROR_MSG_FORMAT = " The nonterminal %s must not extend the %s nonterminal %s. "
+ +
+ "Nonterminals may only extend abstract or normal nonterminals.";
+
+ @Override
+ public void check(ASTClassProd a) {
+ if (!a.getSuperRuleList().isEmpty()) {
+ List superRules = a.getSuperRuleList();
+ for (ASTRuleReference sr : superRules) {
+ Optional ruleSymbol = a.getEnclosingScope().resolveProd(sr.getName());
+ if (ruleSymbol.isPresent()) {
+ ProdSymbol r = ruleSymbol.get();
+ boolean isInterface = r.isIsInterface();
+ boolean isExternal = r.isIsExternal();
+ if (isInterface || isExternal) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(),
+ isInterface ? "interface" : "external", r.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyExtendOrAstextendNTOrClass.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyExtendOrAstextendNTOrClass.java
new file mode 100644
index 0000000000..721b0febf9
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyExtendOrAstextendNTOrClass.java
@@ -0,0 +1,27 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTClassProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTClassProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals do not extend and astextend a type.
+ *
+ */
+public class NTOnlyExtendOrAstextendNTOrClass implements GrammarASTClassProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4029";
+
+ public static final String ERROR_MSG_FORMAT = " The nonterminal %s must not extend and astextend a type.";
+
+ @Override
+ public void check(ASTClassProd a) {
+ if (!a.getSuperRuleList().isEmpty() && !a.getASTSuperClassList().isEmpty()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyExtendsOneNTOrClass.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyExtendsOneNTOrClass.java
new file mode 100644
index 0000000000..097d9babf5
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyExtendsOneNTOrClass.java
@@ -0,0 +1,32 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTClassProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTClassProdCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals do not extend more than one nonterminals/class.
+ *
+
+ */
+public class NTOnlyExtendsOneNTOrClass implements GrammarASTClassProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4011";
+
+ public static final String ERROR_MSG_FORMAT = " The nonterminal %s must not %s more than one %s.";
+
+ @Override
+ public void check(ASTClassProd a) {
+ if (a.getSuperRuleList().size()>1) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), "extend", "nonterminal"),
+ a.get_SourcePositionStart());
+ }
+ if(a.getASTSuperClassList().size()>1){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), "astextend", "class"),
+ a.get_SourcePositionStart());
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyImplementInterfaceNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyImplementInterfaceNTs.java
new file mode 100644
index 0000000000..666f1e7a51
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTOnlyImplementInterfaceNTs.java
@@ -0,0 +1,43 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTClassProd;
+import de.monticore.grammar.grammar._ast.ASTRuleReference;
+import de.monticore.grammar.grammar._cocos.GrammarASTClassProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only implement interface nonterminals.
+ *
+
+ */
+public class NTOnlyImplementInterfaceNTs implements GrammarASTClassProdCoCo {
+
+ public static final String ERROR_CODE = "0xA2102";
+
+ public static final String ERROR_MSG_FORMAT = " The nonterminal %s must not implement the nonterminal %s. "
+ +
+ "Nonterminals may only implement interface nonterminals.";
+
+ @Override
+ public void check(ASTClassProd a) {
+ if (!a.getSuperInterfaceRuleList().isEmpty()) {
+ List interfaces = a.getSuperInterfaceRuleList();
+ for (ASTRuleReference i : interfaces) {
+ Optional ruleSymbol = a.getEnclosingScope().resolveProd(i.getName());
+ if (ruleSymbol.isPresent()) {
+ ProdSymbol r = ruleSymbol.get();
+ if (!r.isIsInterface()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), r.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTUniqueIgnoreCase.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTUniqueIgnoreCase.java
new file mode 100644
index 0000000000..1092d5659d
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NTUniqueIgnoreCase.java
@@ -0,0 +1,47 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals or only overridden by normal nonterminals.
+ *
+
+ */
+public class NTUniqueIgnoreCase implements GrammarASTMCGrammarCoCo {
+
+public static final String ERROR_CODE = "0xA2026";
+
+ public static final String ERROR_MSG_FORMAT = " The nonterminal %s must not be defined by more than one production: nonterminals aren't case-sensitive.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ List prodnames = new ArrayList<>();
+ List prodnamesIgnoreCase = new ArrayList<>();
+ List prods = new ArrayList<>();
+ prods.addAll(a.getAbstractProdList());
+ prods.addAll(a.getClassProdList());
+ prods.addAll(a.getEnumProdList());
+ prods.addAll(a.getInterfaceProdList());
+ prods.addAll(a.getLexProdList());
+ prods.addAll(a.getExternalProdList());
+
+ for(ASTProd p: prods){
+ if(!prodnames.contains(p.getName()) && prodnamesIgnoreCase.contains(p.getName().toLowerCase())){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, p.getName()),
+ a.get_SourcePositionStart());
+ } else {
+ prodnames.add(p.getName());
+ prodnamesIgnoreCase.add(p.getName().toLowerCase());
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoASTExtendsForClasses.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoASTExtendsForClasses.java
new file mode 100644
index 0000000000..66c96016f7
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoASTExtendsForClasses.java
@@ -0,0 +1,72 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTASTRule;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbolSurrogate;
+import de.monticore.types.mcbasictypes._ast.ASTMCType;
+import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType;
+import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill;
+import de.se_rwth.commons.Names;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Map;
+
+/**
+ * Checks that no ast rules exist for enum nonterminals.
+ *
+ */
+public class NoASTExtendsForClasses implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4097";
+
+ public static final String ERROR_MSG_FORMAT = " It is forbidden to extend the rule %s with the external class %s.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ Map allProds = grammarSymbol.getProdsWithInherited();
+
+ for (ProdSymbol classProd : grammarSymbol.getProds()) {
+ for (ProdSymbolSurrogate sClass : classProd.getAstSuperClasses()) {
+ if (!allProds.containsKey(
+ sClass.getName().substring("AST".length()))) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT,
+ classProd.getName(),
+ Names.getSimpleName(sClass.getName()),
+ classProd.getAstNode().get_SourcePositionStart()));
+ }
+ }
+ }
+
+ for (ASTASTRule rule : a.getASTRuleList()) {
+ if (allProds.containsKey(rule.getType())) {
+ ProdSymbol prod = allProds.get(rule.getType());
+ if (prod.isClass()) {
+ for (ASTMCType type : rule.getASTSuperClassList()) {
+ String simpleName = simpleName(type);
+ if (!allProds.containsKey(simpleName.substring("AST".length()))) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT,
+ rule.getType(), simpleName,
+ rule.get_SourcePositionStart()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected static String simpleName(ASTMCType type) {
+ String name;
+ if (type instanceof ASTMCGenericType) {
+ name = ((ASTMCGenericType) type).printWithoutTypeArguments();
+ } else {
+ name = type.printType();
+ }
+ return Names.getSimpleName(name);
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoASTRuleForEnumNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoASTRuleForEnumNTs.java
new file mode 100644
index 0000000000..20444d9bf3
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoASTRuleForEnumNTs.java
@@ -0,0 +1,37 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTASTRule;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that no ast rules exist for enum nonterminals.
+ *
+
+ */
+public class NoASTRuleForEnumNTs implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4032";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist an AST rule for the enum nonterminal %s.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ for (ASTASTRule rule : a.getASTRuleList()) {
+ Optional ruleSymbol = grammarSymbol.getProdWithInherited(rule.getType());
+ if (ruleSymbol.isPresent() && ruleSymbol.get().isIsEnum()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, rule.getType()),
+ rule.get_SourcePositionStart());
+ }
+ }
+
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoExtensionOfSymbolThatOnlySpansScope.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoExtensionOfSymbolThatOnlySpansScope.java
new file mode 100644
index 0000000000..11f74bf24a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoExtensionOfSymbolThatOnlySpansScope.java
@@ -0,0 +1,70 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbolSurrogate;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public class NoExtensionOfSymbolThatOnlySpansScope implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA0810";
+
+ public static final String ERROR_MSG_FORMAT = " The production %s extends the symbol production %s and spans a scope " +
+ "without being a symbol itself.";
+
+ protected boolean hasSymbol;
+ protected boolean hasScope;
+ protected ProdSymbol symbolProd;
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ MCGrammarSymbol symbol = node.getSymbol();
+ Map prodsWithInherited = symbol.getProdsWithInherited();
+ Collection prods = symbol.getProds();
+ for(ProdSymbol prod: prods){
+ hasSymbol = false;
+ hasScope = false;
+ if(prod.isIsScopeSpanning() && !prod.isIsSymbolDefinition()) {
+ checkProd(prod, prodsWithInherited);
+ if (hasSymbol && !hasScope) {
+ logError(prod, symbolProd);
+ }
+ }
+ }
+ }
+
+ protected void checkProd(ProdSymbol prod, Map prodsWithInherited){
+ List superProds = new ArrayList<>(prod.getSuperProds());
+ superProds.addAll(prod.getSuperInterfaceProds());
+ checkProdsAndLogError(superProds, prod, prodsWithInherited);
+ }
+
+ protected void checkProdsAndLogError(List superProds, ProdSymbol prod, Map prodsWithInherited){
+ for(ProdSymbolSurrogate surrogate: superProds){
+ ProdSymbol superProd = prodsWithInherited.get(surrogate.getName());
+ if(superProd.isIsSymbolDefinition()){
+ hasSymbol = true;
+ symbolProd = superProd;
+ }
+ if (superProd.isIsScopeSpanning()) {
+ hasScope = true;
+ }
+ checkProd(superProd, prodsWithInherited);
+ }
+ }
+
+ protected void logError(ProdSymbol original, ProdSymbol superProd){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, original, superProd));
+ }
+
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenGrammarName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenGrammarName.java
new file mode 100644
index 0000000000..f971e17a77
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenGrammarName.java
@@ -0,0 +1,30 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.Collections;
+
+public class NoForbiddenGrammarName implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4036";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist a grammar with the name %s.";
+
+ protected static final List forbiddenNames = Collections.unmodifiableList(Lists.newArrayList("I"));
+
+ @Override
+ public void check (ASTMCGrammar node){
+ String grammarName = node.getName();
+ if(forbiddenNames.contains(grammarName)){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, grammarName));
+ }
+ }
+
+
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdAndSymbolName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdAndSymbolName.java
new file mode 100644
index 0000000000..61a50473db
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdAndSymbolName.java
@@ -0,0 +1,49 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class NoForbiddenProdAndSymbolName implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4122";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist a production with the name %s in the grammar %s if " +
+ "there already exists a symbol with the name %s.";
+
+ public static final String SYMBOL = "Symbol";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ MCGrammarSymbol symbol = node.getSymbol();
+ Collection prods = symbol.getProdsWithInherited().values();
+ List symbolProds = prods.stream().filter(ProdSymbol::isIsSymbolDefinition).collect(Collectors.toList());
+ for(ProdSymbol prod:prods){
+ String prodName = prod.getName();
+ if(prodName.endsWith(SYMBOL)){
+ handle(grammarName, SYMBOL, prodName, symbolProds);
+ }
+ }
+ }
+
+ protected void handle(String grammarName, String addon, String prodName, Collection prods){
+ String prodNameWithoutAddon = prodName.substring(0, prodName.lastIndexOf(addon));
+ List forbidden = prods.stream()
+ .filter(p -> p.getName().equals(prodNameWithoutAddon))
+ .collect(Collectors.toList());
+
+ if(!forbidden.isEmpty()){
+ for(ProdSymbol prod: forbidden){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, prodName, grammarName, prod.getName()));
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdName.java
new file mode 100644
index 0000000000..73747e65ee
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdName.java
@@ -0,0 +1,46 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class NoForbiddenProdName implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4096";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist a production with the name %s in the grammar %s.";
+
+ protected static final List forbiddenNames = Collections.unmodifiableList(Lists.newArrayList("EnclosingScope", "SpannedScope", "Node", "CNode",
+ "Class", "Traverser", "ScopesGenitor", "ScopesGenitorDelegator", "Scope", "ArtifactScope", "GlobalScope",
+ // Antlr
+ "Mode", "Parser", "Lexer", "Options", "Returns"));
+
+ protected static final String NODE = "Node";
+
+ protected static final String CONSTANTS = "Constants";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ MCGrammarSymbol symbol = node.getSymbol();
+ Collection prods = symbol.getProdsWithInherited().values();
+ for(ProdSymbol prod: prods){
+ String prodName = prod.getName();
+ if(forbiddenNames.contains(prodName)){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, prodName, grammarName));
+ }
+ if((grammarName+NODE).equals(prodName) || (CONSTANTS+grammarName).equals(prodName)){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, prodName, grammarName));
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdNameAddon.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdNameAddon.java
new file mode 100644
index 0000000000..414f39c276
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenProdNameAddon.java
@@ -0,0 +1,47 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class NoForbiddenProdNameAddon implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4120";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist a production with the name %s in the grammar %s if there is already a production with the name %s.";
+
+ protected static final String BUILDER = "Builder";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ MCGrammarSymbol symbol = node.getSymbol();
+ Collection prods = symbol.getProdsWithInherited().values();
+ for(ProdSymbol prod:prods){
+ String prodName = prod.getName();
+ if(prodName.endsWith(BUILDER)){
+ handle(grammarName, BUILDER, prodName, prods);
+ }
+ }
+ }
+
+ protected void handle(String grammarName, String addon, String prodName, Collection prods){
+ String prodNameWithoutAddon = prodName.substring(0, prodName.lastIndexOf(addon));
+ List forbidden = prods.stream()
+ .filter(p -> p.getName().equals(prodNameWithoutAddon))
+ .collect(Collectors.toList());
+
+ if(!forbidden.isEmpty()){
+ for(ProdSymbol prod: forbidden){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, prodName, grammarName, prod.getName()));
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenSymbolName.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenSymbolName.java
new file mode 100644
index 0000000000..d8dd1790c7
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenSymbolName.java
@@ -0,0 +1,42 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class NoForbiddenSymbolName implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4099";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist a symbol production with the name %s in the grammar %s.";
+
+ protected static final String SYMBOL = "Symbol";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ MCGrammarSymbol symbol = node.getSymbol();
+ List symbolProds = symbol.getProdsWithInherited().values()
+ .stream()
+ .filter(ProdSymbol::isIsSymbolDefinition)
+ .collect(Collectors.toList());
+ if(grammarName.endsWith(SYMBOL)){
+ String nameWithoutSymbol = grammarName.substring(0,grammarName.lastIndexOf(SYMBOL));
+ List forbidden = symbolProds.stream()
+ .filter(p -> p.getName().equals(nameWithoutSymbol))
+ .collect(Collectors.toList());
+ if(!forbidden.isEmpty()){
+ for(ProdSymbol prod: forbidden){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, prod.getName(), grammarName));
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenSymbolNameAddon.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenSymbolNameAddon.java
new file mode 100644
index 0000000000..44bee40a69
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoForbiddenSymbolNameAddon.java
@@ -0,0 +1,66 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class NoForbiddenSymbolNameAddon implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4121";
+
+ public static final String ERROR_MSG_FORMAT = " There must not exist a symbol production with the name %s in the grammar %s if there is already a symbol production %s.";
+
+ protected static final String MANY = "Many";
+
+ protected static final String DOWN = "Down";
+
+ protected static final String LOCALLY = "Locally";
+
+ protected static final String ADAPTED = "Adapted";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ MCGrammarSymbol symbol = node.getSymbol();
+ List symbolProds = symbol.getProdsWithInherited().values()
+ .stream()
+ .filter(ProdSymbol::isIsSymbolDefinition)
+ .collect(Collectors.toList());
+ for(ProdSymbol prod: symbolProds){
+ String prodName = prod.getName();
+ if(prodName.endsWith(MANY)){
+ handle(grammarName, MANY, prodName, symbolProds);
+ }else if(prodName.endsWith(DOWN)) {
+ handle(grammarName, DOWN, prodName, symbolProds);
+ }else if(prodName.endsWith(LOCALLY)){
+ handle(grammarName, LOCALLY, prodName, symbolProds);
+ }else if(prodName.startsWith(ADAPTED)){
+ handle(grammarName, ADAPTED, prodName, symbolProds);
+ }
+ }
+ }
+
+ protected void handle(String grammarName, String addon, String prodName, List potentialSymbolProds){
+ String prodNameWithoutAddon;
+ if(addon.equals(ADAPTED)){
+ prodNameWithoutAddon = prodName.substring(addon.length());
+ }else{
+ prodNameWithoutAddon = prodName.substring(0, prodName.lastIndexOf(addon));
+ }
+ List forbidden = potentialSymbolProds.stream()
+ .filter(p -> p.getName().equals(prodNameWithoutAddon))
+ .collect(Collectors.toList());
+
+ if(!forbidden.isEmpty()){
+ for(ProdSymbol prod: forbidden){
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, prodName, grammarName, prod.getName()));
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoMultipleSymbolRule.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoMultipleSymbolRule.java
new file mode 100644
index 0000000000..796d38329a
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoMultipleSymbolRule.java
@@ -0,0 +1,33 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTSymbolRule;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks only at most 1 symbolrule exists per nonterminal
+ */
+public class NoMultipleSymbolRule implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4151";
+
+ public static final String ERROR_MSG_FORMAT = " A symbolRule must not exist twice for a single nonterminal. Violation by %s";
+
+ @Override
+ public void check(ASTMCGrammar g) {
+ for (ASTSymbolRule rule : g.getSymbolRuleList()) {
+ int count = 0;
+ for (ASTSymbolRule r2 : g.getSymbolRuleList()) {
+ if (rule.getType().equals(r2.getType())) {
+ count++;
+ }
+ }
+ if (count != 1) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, rule.getType()), rule.get_SourcePositionStart());
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoNTInheritanceCycle.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoNTInheritanceCycle.java
new file mode 100644
index 0000000000..65a3ce8cf2
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoNTInheritanceCycle.java
@@ -0,0 +1,34 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTProdCoCo;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals do not have inheritance cycles.
+ *
+
+ */
+public class NoNTInheritanceCycle implements GrammarASTProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4022";
+
+ public static final String ERROR_MSG_FORMAT = " The production %s introduces an inheritance"
+ + " cycle. Inheritance may not be cyclic.";
+
+ @Override
+ public void check(ASTProd a) {
+ ProdSymbol symbol = a.getSymbol();
+ for (ProdSymbol sr : MCGrammarSymbolTableHelper.getAllSuperProds(symbol)) {
+ if (sr.getFullName().equals(symbol.getFullName())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, symbol.getFullName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoNestedGenericsInAdditionalAttributes.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoNestedGenericsInAdditionalAttributes.java
new file mode 100644
index 0000000000..40d61ab18f
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoNestedGenericsInAdditionalAttributes.java
@@ -0,0 +1,126 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.types.mcbasictypes._ast.ASTMCType;
+import de.monticore.types.mccollectiontypes._ast.ASTMCGenericType;
+import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+
+import static de.monticore.grammar.grammar._ast.ASTConstantsGrammar.*;
+
+/**
+ * CoCo that checks if in a additional attribute of a astrule, symbolrule or scoperule a generic type does not contain a MCCustomTypeArgument
+ * with the *,+,? and min, max notation this can be created in different ways
+ * these cases are covered e.g.:
+ * A>
+ * A*, A+, A?
+ * A min = 0, A max = 5, A max = *
+ * because these cases cannot be handled in the generator so far and will generate the wrong type
+ */
+public class NoNestedGenericsInAdditionalAttributes implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4102";
+
+ public static final String ERROR_MSG_FORMAT = " %srule does not allow the definition of nested generics. " +
+ "Problem in grammar '%s', rule for '%s', with additional attribute: '%s'.";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ String grammarName = node.getName();
+ // astrule
+ for (ASTASTRule astastRule : node.getASTRuleList()) {
+ findMultipleGenericAttributes(astastRule.getAdditionalAttributeList(), "Ast", grammarName, astastRule.getType());
+ }
+ // symbolrule
+ for (ASTSymbolRule astSymbolRule : node.getSymbolRuleList()) {
+ findMultipleGenericAttributes(astSymbolRule.getAdditionalAttributeList(), "Symbol", grammarName, astSymbolRule.getType());
+ }
+ // scoperule
+ if (node.isPresentScopeRule()) {
+ findMultipleGenericAttributes(node.getScopeRule().getAdditionalAttributeList(), "Scope", grammarName, grammarName + "Scope");
+ }
+ }
+
+ protected void findMultipleGenericAttributes(List astAdditionalAttributes, String ruleName,
+ String grammarName, String prodName) {
+ for (ASTAdditionalAttribute astAdditionalAttribute : astAdditionalAttributes) {
+ ASTMCType mcType = astAdditionalAttribute.getMCType();
+
+ if (mcType instanceof ASTMCGenericType) {
+ if (hasNestedGeneric(mcType)) {
+ // for e.g. A>
+ logError(ruleName, grammarName, prodName, astAdditionalAttribute);
+ } else if (astAdditionalAttribute.isPresentCard()) {
+ if (hasGenericIteration(astAdditionalAttribute)) {
+ // for e.g. A*
+ logError(ruleName, grammarName, prodName, astAdditionalAttribute);
+ } else if (hasGenericMaxValue(astAdditionalAttribute)) {
+ // for e.g. A min=0 or A max=2 or A max=*
+ logError(ruleName, grammarName, prodName, astAdditionalAttribute);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * for e.g. A>
+ */
+ protected boolean hasNestedGeneric(ASTMCType mcType){
+ return((ASTMCGenericType) mcType).getMCTypeArgumentList()
+ .stream()
+ .filter(ta -> ta.getMCTypeOpt().isPresent())
+ .anyMatch(ta -> ta.getMCTypeOpt().get() instanceof ASTMCGenericType);
+ }
+
+ /**
+ * for e.g. A*, A+, A?
+ */
+ protected boolean hasGenericIteration(ASTAdditionalAttribute astAdditionalAttribute){
+ return astAdditionalAttribute.getCard().getIteration() == STAR || astAdditionalAttribute.getCard().getIteration() == PLUS ||
+ astAdditionalAttribute.getCard().getIteration() == QUESTION;
+ }
+
+ /**
+ * for e.g. A min=0, A max=2, A max=*
+ */
+ protected boolean hasGenericMaxValue(ASTAdditionalAttribute astAdditionalAttribute){
+ return (astAdditionalAttribute.getCard().isPresentMax() && ("*".equals(astAdditionalAttribute.getCard().getMax()) ||
+ Integer.parseInt(astAdditionalAttribute.getCard().getMax()) > 1) ||
+ (astAdditionalAttribute.getCard().isPresentMin() && Integer.parseInt(astAdditionalAttribute.getCard().getMin()) == 0));
+ }
+
+ protected void logError(String ruleName, String grammarName, String prodName, ASTAdditionalAttribute astAdditionalAttribute) {
+ Log.error(ERROR_CODE + String.format(ERROR_MSG_FORMAT, ruleName, grammarName, prodName,
+ printASTAdditionalAttribute(astAdditionalAttribute)));
+ }
+
+ protected String printASTAdditionalAttribute(ASTAdditionalAttribute astAdditionalAttribute) {
+ String attribute = "";
+ if (astAdditionalAttribute.isPresentName()) {
+ attribute += astAdditionalAttribute.getName() + ":";
+ }
+ attribute += MCSimpleGenericTypesMill.prettyPrint(astAdditionalAttribute.getMCType(), false).trim();
+ if (astAdditionalAttribute.isPresentCard()) {
+ ASTCard card = astAdditionalAttribute.getCard();
+ if (card.getIteration() == STAR) {
+ attribute += "*";
+ } else if (card.getIteration() == PLUS) {
+ attribute += "+";
+ } else if (card.getIteration() == QUESTION) {
+ attribute += "?";
+ }
+ if (card.isPresentMin()) {
+ attribute += " min=" + card.getMin();
+ }
+ if (card.isPresentMax()) {
+ attribute += " max=" + card.getMax();
+ }
+ }
+ return attribute;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoOverridingNTHasAnnotation.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoOverridingNTHasAnnotation.java
new file mode 100644
index 0000000000..f1c5743d1c
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoOverridingNTHasAnnotation.java
@@ -0,0 +1,36 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTClassProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTClassProdCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.Optional;
+
+/**
+ * Checks if nonterminals with an override annotation really overrides a class
+ *
+ */
+public class NoOverridingNTHasAnnotation implements GrammarASTClassProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4094";
+
+ public static final String ERROR_MSG_FORMAT = " The production %s does not override any production.";
+
+ @Override
+ public void check(ASTClassProd a) {
+ if (a.getGrammarAnnotationList().stream().anyMatch(s -> s.isOverride())) {
+ Optional grammarSymbol = MCGrammarSymbolTableHelper
+ .getMCGrammarSymbol(a.getEnclosingScope());
+
+ if (!grammarSymbol.get().getInheritedProd(a.getName()).isPresent()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName()),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoReplaceKeywordRuleOnConstantGroup.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoReplaceKeywordRuleOnConstantGroup.java
new file mode 100644
index 0000000000..7a97e175f2
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoReplaceKeywordRuleOnConstantGroup.java
@@ -0,0 +1,50 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTConstant;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTTerminal;
+import de.monticore.grammar.grammar._cocos.GrammarASTConstantCoCo;
+import de.monticore.grammar.grammar._cocos.GrammarASTTerminalCoCo;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NoReplaceKeywordRuleOnConstantGroup implements GrammarASTConstantCoCo, GrammarVisitor2 {
+
+ /**
+ * Coco that checks whether a constant-rule constant
+ * is replaced wit a replace keword rule.
+ * Due to the generated Antlr parser files not respecting these replaced keywords,
+ * this CoCo ensures that replacekeyword does not target constants.
+ */
+
+ public static final String ERROR_CODE = "0xA4162";
+
+ public static final String ERROR_MSG_FORMAT = " There is a replacekeyword rule targeting a constant-group constant: '%s'. ";
+
+
+ protected List replacedKeywords = new ArrayList<>();
+
+
+ @Override
+ public void visit(ASTMCGrammar node) {
+ // Cache the replaced keywords for this grammar
+ this.replacedKeywords.addAll(node.getSymbol().getReplacedKeywordsWithInherited().keySet());
+ }
+
+ @Override
+ public void endVisit(ASTMCGrammar node) {
+ this.replacedKeywords.clear();
+ }
+
+ @Override
+ public void check(ASTConstant node) {
+ if (this.replacedKeywords.contains(node.getName())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, node.getName()),
+ node.get_SourcePositionStart());
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoReplaceKeywordRuleOnUsageNamedAttribute.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoReplaceKeywordRuleOnUsageNamedAttribute.java
new file mode 100644
index 0000000000..452826644e
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoReplaceKeywordRuleOnUsageNamedAttribute.java
@@ -0,0 +1,51 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTTerminal;
+import de.monticore.grammar.grammar._cocos.GrammarASTTerminalCoCo;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NoReplaceKeywordRuleOnUsageNamedAttribute implements GrammarASTTerminalCoCo, GrammarVisitor2 {
+
+ /**
+ * Coco that checks whether an attributed terminal (terminal with a usage name)
+ * is replaced wit a replace keword rule.
+ * Due to the generated Antlr actions not setting the AST attribute to the replace value,
+ * and in cases with multiple replaced keyword values more distinction would be required,
+ * this CoCo ensures that replacekeyword does not target such an terminal.
+ */
+
+ public static final String ERROR_CODE = "0xA4161";
+
+ public static final String ERROR_MSG_FORMAT = " There is a replacekeyword rule targeting a terminal with present usage-name: '%s'. ";
+
+
+ protected List replacedKeywords = new ArrayList<>();
+
+
+ @Override
+ public void visit(ASTMCGrammar node) {
+ // Cache the replaced keywords for this grammar
+ this.replacedKeywords.addAll(node.getSymbol().getReplacedKeywordsWithInherited().keySet());
+ }
+
+ @Override
+ public void endVisit(ASTMCGrammar node) {
+ this.replacedKeywords.clear();
+ }
+
+ @Override
+ public void check(ASTTerminal node) {
+ if (node.isPresentUsageName()) {
+ if (this.replacedKeywords.contains(node.getName())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, node.getName()),
+ node.get_SourcePositionStart());
+ }
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenDefined.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenDefined.java
new file mode 100644
index 0000000000..371fb650e6
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenDefined.java
@@ -0,0 +1,52 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar.GrammarMill;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._visitor.GrammarTraverser;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class NoTokenDefined implements GrammarASTMCGrammarCoCo {
+
+ /**
+ * Coco that checks whether a token is defined by the grammar or any super grammar.
+ * If not, there will be no lexer generated, so the parser will not compile
+ * This coco ensures that this will not happen
+ */
+
+ public static final String ERROR_CODE = "0xA4101";
+
+ public static final String ERROR_MSG_FORMAT = " There is no production defining a token in Grammar : '%s'. ";
+
+ @Override
+ public void check(ASTMCGrammar node) {
+ if (node.isPresentSymbol() && !node.getSymbol().isIsComponent()) {
+ MCGrammarSymbol symbol = node.getSymbol();
+ List superGrammars = symbol.getAllSuperGrammars().stream()
+ .filter(x -> x.isPresentAstNode())
+ .map(x -> (ASTMCGrammar) x.getAstNode())
+ .collect(Collectors.toList());
+ //check for own and super grammars tokens
+ if (!hasTokenDefinition(node) && superGrammars.stream().noneMatch(this::hasTokenDefinition)) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, node.getName()),
+ node.get_SourcePositionStart());
+ }
+ }
+ }
+
+ protected boolean hasTokenDefinition(ASTMCGrammar node) {
+ //if there is a body check if the body contains tokens
+ GrammarTraverser traverser = GrammarMill.traverser();
+ NoTokenDefinedVisitor visitor = new NoTokenDefinedVisitor();
+ traverser.add4Grammar(visitor);
+ traverser.setGrammarHandler(visitor);
+ node.accept(traverser);
+ return visitor.foundTerminal();
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenDefinedVisitor.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenDefinedVisitor.java
new file mode 100644
index 0000000000..73f8ea614b
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenDefinedVisitor.java
@@ -0,0 +1,56 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.*;
+import de.monticore.grammar.grammar._visitor.GrammarHandler;
+import de.monticore.grammar.grammar._visitor.GrammarTraverser;
+import de.monticore.grammar.grammar._visitor.GrammarVisitor2;
+
+public class NoTokenDefinedVisitor implements GrammarVisitor2, GrammarHandler {
+
+ protected boolean terminalFound = false;
+
+ GrammarTraverser traverser;
+
+ @Override
+ public GrammarTraverser getTraverser() {
+ return traverser;
+ }
+
+ @Override
+ public void setTraverser(GrammarTraverser traverser) {
+ this.traverser = traverser;
+ }
+
+ @Override
+ public void visit(ASTTerminal node) {
+ terminalFound = true;
+ }
+
+ @Override
+ public void visit(ASTConstant node) {
+ terminalFound = true;
+ }
+
+ @Override
+ public void visit(ASTLexProd node) {
+ terminalFound = true;
+ }
+
+ @Override
+ public void handle(ASTAbstractProd node){
+ //do not navigate here
+ //because tokes in abstract prods still lead to the compile error
+ //due to the problem, that nor lexer is generated
+ }
+
+ @Override
+ public void handle(ASTNonTerminalSeparator node) {
+ terminalFound = true;
+ }
+
+ public boolean foundTerminal() {
+ return terminalFound;
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenModeInComponentGrammar.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenModeInComponentGrammar.java
new file mode 100644
index 0000000000..f1039dc16e
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/NoTokenModeInComponentGrammar.java
@@ -0,0 +1,25 @@
+/* (c) https://github.com/MontiCore/monticore */
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTLexProd;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.se_rwth.commons.logging.Log;
+
+public class NoTokenModeInComponentGrammar implements GrammarASTMCGrammarCoCo {
+ public static final String ERROR_CODE = "0xA4068";
+
+ public static final String ERROR_MSG_FORMAT = " The lexical production %s must not define a mode in a Component Grammar.";
+ @Override
+ public void check(ASTMCGrammar node) {
+ if( node.isComponent()){
+ for(ASTLexProd prod : node.getLexProdList()){
+ if (prod.isPresentMode()){
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, prod.getName()),
+ node.get_SourcePositionStart());
+ }
+ }
+
+ }
+ }
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAbstractNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAbstractNTs.java
new file mode 100644
index 0000000000..56d138fc1c
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAbstractNTs.java
@@ -0,0 +1,58 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTEnumProd;
+import de.monticore.grammar.grammar._ast.ASTExternalProd;
+import de.monticore.grammar.grammar._ast.ASTInterfaceProd;
+import de.monticore.grammar.grammar._ast.ASTLexProd;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only extends abstract or normal nonterminals.
+ *
+
+ */
+public class OverridingAbstractNTs implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4008";
+
+ public static final String ERROR_MSG_FORMAT = " The production for the abstract nonterminal %s must not be overridden\n"
+ +
+ "by a production for an %s nonterminal.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ List grammarSymbols = grammarSymbol.getSuperGrammarSymbols();
+
+ for (MCGrammarSymbol s : grammarSymbols) {
+ for (ASTEnumProd p : a.getEnumProdList()) {
+ doCheck(s.getProd(p.getName()), "enum");
+ }
+ for (ASTExternalProd p : a.getExternalProdList()) {
+ doCheck(s.getProd(p.getName()), "external");
+ }
+ for (ASTInterfaceProd p : a.getInterfaceProdList()) {
+ doCheck(s.getProd(p.getName()), "interface");
+ }
+ for (ASTLexProd p : a.getLexProdList()) {
+ doCheck(s.getProd(p.getName()), "lexical");
+ }
+ }
+ }
+
+ protected void doCheck(Optional typeSymbol, String type) {
+ if (typeSymbol.isPresent() && typeSymbol.get().isIsAbstract()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, typeSymbol.get().getName(), type));
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAbstractNTsHaveNoSuperRules.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAbstractNTsHaveNoSuperRules.java
new file mode 100644
index 0000000000..78d430a286
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAbstractNTsHaveNoSuperRules.java
@@ -0,0 +1,52 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.MCGrammarSymbolTableHelper;
+import de.monticore.grammar.grammar._ast.ASTAbstractProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTAbstractProdCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.types.mcsimplegenerictypes.MCSimpleGenericTypesMill;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that overriding abstract nonterminals do not have super rules or classes.
+ *
+ */
+public class OverridingAbstractNTsHaveNoSuperRules implements GrammarASTAbstractProdCoCo {
+
+ public static final String ERROR_CODE = "0xA4002";
+
+ public static final String ERROR_MSG_FORMAT = " The abstract production %s overriding a production of " +
+ "a sub grammar must not extend the production %s.\n" +
+ "Hint: Overriding productions can only implement interfaces.";
+
+ @Override
+ public void check(ASTAbstractProd a) {
+ Optional grammarSymbol = MCGrammarSymbolTableHelper
+ .getMCGrammarSymbol(a.getEnclosingScope());
+ List grammarSymbols = grammarSymbol.get().getSuperGrammarSymbols();
+
+ if (!a.getSuperRuleList().isEmpty() || !a.getASTSuperClassList().isEmpty()) {
+ String extendedType;
+ if (!a.getSuperRuleList().isEmpty()){
+ extendedType = a.getSuperRuleList().get(0).getName();
+ }
+ else{
+ extendedType = MCSimpleGenericTypesMill
+ .prettyPrint(a.getASTSuperClassList().get(0), false).trim();
+ }
+
+ for (MCGrammarSymbol s : grammarSymbols) {
+ if (s.getProd(a.getName()).isPresent()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, a.getName(), extendedType),
+ a.get_SourcePositionStart());
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAdditionalAttributes.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAdditionalAttributes.java
new file mode 100644
index 0000000000..585837effa
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingAdditionalAttributes.java
@@ -0,0 +1,39 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import com.google.common.collect.Lists;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.AdditionalAttributeSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+
+/**
+ * Checks, if additional attributes are declared twice
+ */
+public class OverridingAdditionalAttributes implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4035";
+
+ public static final String ERROR_MSG_FORMAT = " The additional attribute %s is defined twice for the " +
+ "rule %s";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ for (ProdSymbol prodSymbol: a.getSymbol().getSpannedScope().getLocalProdSymbols()) {
+ List attributes = prodSymbol.getSpannedScope().getLocalAdditionalAttributeSymbols();
+ List superAttributes = Lists.newArrayList(attributes);
+ prodSymbol.getSuperProds().forEach(p -> superAttributes.addAll(p.lazyLoadDelegate().getSpannedScope().getLocalAdditionalAttributeSymbols()));
+ for (AdditionalAttributeSymbol ad: attributes) {
+ if (superAttributes.stream().filter(m -> ad.getName().equals(m.getName())
+ && ad.isIsAstAttr()==m.isIsAstAttr()).count()>1) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, ad.getName(), prodSymbol.getName()));
+ }
+ }
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingEnumNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingEnumNTs.java
new file mode 100644
index 0000000000..9ba722dfb3
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingEnumNTs.java
@@ -0,0 +1,46 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only extends abstract or normal nonterminals.
+ *
+ */
+public class OverridingEnumNTs implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4027";
+
+ public static final String ERROR_MSG_FORMAT = " The production for the enum nonterminal %s must not be overridden.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ List prods = new ArrayList<>(a.getClassProdList());
+ prods.addAll(a.getExternalProdList());
+ prods.addAll(a.getLexProdList());
+ prods.addAll(a.getInterfaceProdList());
+ prods.addAll(a.getEnumProdList());
+ prods.addAll(a.getAbstractProdList());
+
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+
+ for (ASTProd p : prods) {
+ Optional typeSymbol = grammarSymbol.getInheritedProd(p.getName());
+ if (typeSymbol.isPresent() && typeSymbol.get().isIsEnum()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, p.getName()));
+ }
+ }
+
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingInterfaceNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingInterfaceNTs.java
new file mode 100644
index 0000000000..c4edf4aa99
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingInterfaceNTs.java
@@ -0,0 +1,49 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._ast.ASTProd;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals only extends abstract or normal nonterminals.
+ *
+
+ */
+public class OverridingInterfaceNTs implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4007";
+
+ public static final String ERROR_MSG_FORMAT = " The production for the interface nonterminal %s must not be overridden.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ List prods = new ArrayList<>(a.getClassProdList());
+ prods.addAll(a.getExternalProdList());
+ prods.addAll(a.getLexProdList());
+ prods.addAll(a.getInterfaceProdList());
+ prods.addAll(a.getEnumProdList());
+ prods.addAll(a.getAbstractProdList());
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ List grammarSymbols = grammarSymbol.getSuperGrammarSymbols();
+
+ for (ASTProd p : prods) {
+ for (MCGrammarSymbol s : grammarSymbols) {
+ Optional typeSymbol = s.getProd(p.getName());
+ if (typeSymbol.isPresent() && typeSymbol.get().isIsInterface()) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, typeSymbol.get().getName()));
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingLexNTs.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingLexNTs.java
new file mode 100644
index 0000000000..e248fe8195
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingLexNTs.java
@@ -0,0 +1,47 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import java.util.List;
+import java.util.Optional;
+
+import de.monticore.grammar.grammar._ast.ASTLexProd;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+/**
+ * Checks that nonterminals or only overridden by normal nonterminals.
+ *
+
+ */
+public class OverridingLexNTs implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4026";
+
+ public static final String ERROR_MSG_FORMAT = " The lexical production %s must not use a different type to "
+ + "store the token than the overridden production.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol grammarSymbol = a.getSymbol();
+ List grammarSymbols = grammarSymbol.getSuperGrammarSymbols();
+
+ for (MCGrammarSymbol s : grammarSymbols) {
+ for (ASTLexProd p : a.getLexProdList()) {
+ doCheck(s.getProdWithInherited(p.getName()), p);
+ }
+ }
+ }
+
+ protected void doCheck(Optional prodSymbol, ASTLexProd lexProd) {
+ if (prodSymbol.isPresent() && prodSymbol.get().isIsLexerProd()
+ && !((ASTLexProd) prodSymbol.get().getAstNode()).getTypeList()
+ .equals(lexProd.getTypeList())) {
+ Log.error(String.format(ERROR_CODE + ERROR_MSG_FORMAT, lexProd.getName()));
+ }
+ }
+
+}
diff --git a/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingNTHasNoAnnotation.java b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingNTHasNoAnnotation.java
new file mode 100644
index 0000000000..0e82df74bf
--- /dev/null
+++ b/monticore-grammar/src/main/java/de/monticore/grammar/cocos/OverridingNTHasNoAnnotation.java
@@ -0,0 +1,44 @@
+/* (c) https://github.com/MontiCore/monticore */
+
+package de.monticore.grammar.cocos;
+
+import de.monticore.grammar.grammar._ast.ASTGrammarAnnotation;
+import de.monticore.grammar.grammar._ast.ASTMCGrammar;
+import de.monticore.grammar.grammar._cocos.GrammarASTMCGrammarCoCo;
+import de.monticore.grammar.grammar._symboltable.MCGrammarSymbol;
+import de.monticore.grammar.grammar._symboltable.ProdSymbol;
+import de.se_rwth.commons.logging.Log;
+
+import java.util.List;
+
+/**
+ * Checks if nonterminals with an override annotation really overrides a class
+ */
+public class OverridingNTHasNoAnnotation implements GrammarASTMCGrammarCoCo {
+
+ public static final String ERROR_CODE = "0xA4098";
+
+ public static final String ERROR_MSG_FORMAT = " Warning: The production %s overrides production %s without annotation.";
+
+ @Override
+ public void check(ASTMCGrammar a) {
+ MCGrammarSymbol gSymbol = a.getSymbol();
+ for (ProdSymbol p : gSymbol.getProds()) {
+ if (!hasOverrideAnno(p.getAstNode().getGrammarAnnotationList()) && gSymbol.getInheritedProd(p.getName()).isPresent()) {
+ String fullName = gSymbol.getInheritedProd(p.getName()).get().getFullName();
+ Log.warn(String.format(ERROR_CODE + ERROR_MSG_FORMAT, p.getName(), fullName),
+ p.getAstNode().get_SourcePositionStart());
+ }
+ }
+ }
+
+ protected boolean hasOverrideAnno(List