Commit 9693a8e9 authored by Ferdinand Alexander Mehlan's avatar Ferdinand Alexander Mehlan
Browse files

Generator stuff for complex tag types

parent a6d389d2
Pipeline #62946 passed with stage
in 55 seconds
#
#
# ******************************************************************************
# MontiCAR Modeling Family, www.se-rwth.de
# Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
# All rights reserved.
#
# This project is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3.0 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this project. If not, see <http://www.gnu.org/licenses/>.
# *******************************************************************************
#
image: maven:3-jdk-8
......
......@@ -64,6 +64,19 @@
</properties>
<dependencies>
<dependency>
<groupId>org.jscience</groupId>
<artifactId>jscience</artifactId>
<version>4.3.1</version>
</dependency>
<!-- <dependency>
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency> -->
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
******************************************************************************
MontiCAR Modeling Family, www.se-rwth.de
Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
All rights reserved.
This project is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this project. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************
-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
......
......@@ -26,7 +26,8 @@ grammar TagSchema extends de.monticore.common.Common {
port:"Port" |
portInstance:"PortInstance" |
connector:"Connector" |
connectorInstance:"ConnectorInstance";
connectorInstance:"ConnectorInstance" |
identifier:Name;
ast ScopeIdentifier =
method public String getScopeName() {
......@@ -36,6 +37,7 @@ grammar TagSchema extends de.monticore.common.Common {
if(isPresentPortInstance()) return getPortInstance();
if(isPresentConnector()) return getConnector();
if(isPresentConnectorInstance()) return getConnectorInstance();
if(isPresentIdentifier()) return getIdentifier();
return "undefined";
};
......@@ -62,14 +64,12 @@ grammar TagSchema extends de.monticore.common.Common {
// Reference = Name ":" datatype:Name ("?"|"+"|"*")? ;
// ComplexTagType = "tagtype" Name Scope ComplexTagDef;
ComplexTagType implements TagType = ("private")? "tagtype" Name Scope? complexTag:ComplexTagDef;
token ComplexTagDef = 'i' 's' WSS* Recursion (WSS* ';');
fragment token Recursion = '{' (~('{' | '}' | '"') | String | Recursion)+ '}';
fragment token WSS = (' ' | '\t' | '\r' | '\n');
/* ast ComplexTagType =
method public String getName() {
return "undefined";
};*/
}
\ No newline at end of file
......@@ -29,6 +29,6 @@ import de.monticore.symboltable.Scope;
* @author Michael von Wenckstern
*/
public interface TagSymbolCreator {
void create(ASTTaggingUnit unit, TaggingResolver tagging);
void create(ASTTaggingUnit unit, Scope gs);
}
/**
*
* ******************************************************************************
* MontiCAR Modeling Family, www.se-rwth.de
* Copyright (c) 2017, Software Engineering Group at RWTH Aachen,
* All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* *******************************************************************************
*/
package de.monticore.lang.tagging._symboltable;
import de.monticore.ModelingLanguage;
public interface TagableModelingLanguage extends ModelingLanguage {
default void addTagSymbolCreator(TagSymbolCreator tagSymbolCreator) {
}
}
......@@ -24,22 +24,21 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.monticore.generating.GeneratorEngine;
import de.monticore.generating.GeneratorSetup;
import de.monticore.lang.tagging.helper.UnitKinds;
import de.monticore.lang.tagschema._ast.ASTSimpleTagType;
import de.monticore.lang.tagschema._ast.ASTTagSchemaUnit;
import de.monticore.lang.tagschema._ast.ASTTagType;
import de.monticore.lang.tagschema._ast.ASTValuedTagType;
import de.monticore.lang.tagschema._ast.*;
import de.monticore.lang.tagschema._parser.TagSchemaParser;
import de.monticore.symboltable.ImportStatement;
import de.monticore.types.types._ast.ASTImportStatement;
import de.se_rwth.commons.Joiners;
import de.se_rwth.commons.Splitters;
import de.se_rwth.commons.logging.Log;
import org.jscience.physics.amount.Amount;
/**
* Created by Michael von Wenckstern on 09.06.2016.
......@@ -65,9 +64,11 @@ public class TagSchemaGenerator extends GeneratorEngine {
Map<String, String> symbolScopeMap = new LinkedHashMap<>();
symbolScopeMap.put("Component", "NameScope");
symbolScopeMap.put("ComponentInstance", "NameScope");
symbolScopeMap.put("Port", "NameScope");
symbolScopeMap.put("ExpandedComponentInstance", "NameScope");
symbolScopeMap.put("PortInstance", "NameScope");
symbolScopeMap.put("Connector", "ConnectorScope");
symbolScopeMap.put("ConnectorInstance", "ConnectorScope");
List<String> list = Splitters.DOT.splitToList(tagSchemaLocation);
Path pathTagschema = Paths.get(list.get(0));
......@@ -124,6 +125,77 @@ public class TagSchemaGenerator extends GeneratorEngine {
else if (tagType instanceof ASTValuedTagType) {
generateValuedTagType((ASTValuedTagType) tagType, tagSchemaUnit, packageName, symbolScopeMap);
}
else if (tagType instanceof ASTComplexTagType) {
generateComplexTagType((ASTComplexTagType) tagType, tagSchemaUnit, packageName, symbolScopeMap);
}
}
protected void generateComplexTagType(ASTComplexTagType complexTagType, ASTTagSchemaUnit tagSchemaUnit, String packageName, Map<String,String> symbolScopeMap) {
// extract basic information
String complexTagTypeName = complexTagType.getName();
List<String> scopeIdentifiers = new LinkedList<>();
if (complexTagType.isPresentScope()) {
complexTagType.getScope().getScopeIdentifierList().forEach(s -> scopeIdentifiers.add(s.getScopeName()));
}
// extract variables used in the complex type
Map<String, String> complexVars = new HashMap<>();
String complexTag = complexTagType.getComplexTag();
Matcher m = Pattern.compile("\\$\\{(\\w+):(\\w+)\\}").matcher(complexTag);
String symbolParams = "";
int count = 1;
while (m.find()) {
String name = m.group(1);
String type = m.group(2);
if (!UnitKinds.contains(type) && !type.equals("Boolean") && !type.equals("String") && !type.equals("Number")) {
Log.error(String.format("Unit kind '%s' is not supported. Currently the following types are available: Boolean, String, Number or '%s' ",
type, UnitKinds.available()), complexTagType.get_SourcePositionStart());
return;
}
if (complexVars.containsKey(name)) {
Log.error("Variable name: " + name + " in complex tagType: " + complexTagTypeName + " in tagschema: " + tagSchemaUnit.getName() + " is not unique");
return;
}
complexVars.put(name, type);
if (UnitKinds.contains(type)) {
symbolParams += "Amount.valueOf(m.group(" + count + ")), ";
}
else if (type.equals("Boolean") || type.equals("Number")) {
symbolParams += "m.group(" + count + "), ";
}
else if (type.equals("String")) {
symbolParams += "\"m.group(" + count + ")\", ";
}
count++;
}
if (symbolParams.length() > 0) {
symbolParams = symbolParams.substring(0, symbolParams.length() - 2);
}
// build matching string
String complexMatching = "(\\\\d+(?:\\\\.\\\\d+)?(?:m|n|k|d)?m)\\\\s*x\\\\s*(\\\\d+(?:\\\\.\\\\d+)?(?:m|n|k|d)?m)\\\\s*x\\\\s*(\\\\d+(?:\\\\.\\\\d+)?(?:m|n|k|d)?m)";
// generate creator
List<String> imports = new LinkedList<String>();
for(ASTImportStatement importStatement : tagSchemaUnit.getImportStatementList()) {
String importString = Joiners.DOT.join(importStatement.getImportList());
if(importStatement.isStar()) importString += ".*";
imports.add(importString);
}
String scopeSymbol = complexTagType.getScopeOpt().get().getScopeIdentifierList().get(0).getScopeName();
String nameScopeType = Log.errorIfNull(symbolScopeMap.get(scopeSymbol), String.format("For the scope symbol '%s' is no scope type defined.", scopeSymbol));
generate("templates.de.monticore.lang.tagschema.ComplexTagTypeCreator",
Paths.get(createPackagePath(packageName).toString(), tagSchemaUnit.getName(), complexTagTypeName + "SymbolCreator.java"),
tagSchemaUnit,
packageName, tagSchemaUnit.getName(), complexTagTypeName, imports, scopeSymbol + "Symbol", nameScopeType, complexMatching, complexTag, symbolParams);
// generate symbol
generate("templates.de.monticore.lang.tagschema.ComplexTagType",
Paths.get(createPackagePath(packageName).toString(), tagSchemaUnit.getName(), complexTagType.getName() + "Symbol.java"),
tagSchemaUnit,
packageName, tagSchemaUnit.getName(), complexTagType.getName(), complexVars, true);
}
protected void generateValuedTagType(ASTValuedTagType valuedTagType, ASTTagSchemaUnit tagSchemaUnit, String packageName, Map<String, String> symbolScopeMap) {
......
${tc.signature("packageName", "schemaName", "tagTypeName", "complexVars", "isUnit")}
package ${packageName}.${schemaName};
import de.monticore.lang.tagging._symboltable.TagKind;
import de.monticore.lang.tagging._symboltable.TagSymbol;
import org.jscience.physics.amount.Amount;
import javax.measure.quantity.*;
/**
* Created by ValuedTagType.ftl
*/
public class ${tagTypeName}Symbol extends TagSymbol {
public static final ${tagTypeName}Kind KIND = ${tagTypeName}Kind.INSTANCE;
public ${tagTypeName}Symbol(
<#list complexVars?keys as name>
Amount<?> ${name}<#if (name_has_next)>,</#if>
</#list>
) {
super(KIND,
<#list complexVars?keys as name>
(Amount<${complexVars[name]}>)${name}<#if (name_has_next)>,</#if>
</#list>
);
}
<#list complexVars?keys as name>
<#if complexVars[name] == 'Number' || complexVars[name] == 'String' || complexVars[name] == 'Boolean'>
public ${complexVars[name]} get${name?cap_first}() {
return getValue(${name?index});
}
<#else>
public Amount<${complexVars[name]}> get${name?cap_first}() {
return getValue(${name?index});
}
</#if>
</#list>
@Override
public String toString() {
return String.format("${tagTypeName} = " +
<#list complexVars?keys as name>
"%s"<#if (name_has_next)>+</#if>
</#list>
,
<#list complexVars?keys as name>
get${name?cap_first}()<#if (name_has_next)>,</#if>
</#list>
);
}
public static class ${tagTypeName}Kind extends TagKind {
public static final ${tagTypeName}Kind INSTANCE = new ${tagTypeName}Kind();
protected ${tagTypeName}Kind() {
}
}
}
\ No newline at end of file
${tc.signature("packageName", "schemaName", "tagTypeName", "importSymbols", "scopeSymbol", "nameScopeType",
${tc.signature("packageName", "schemaName", "tagTypeName", "imports", "scopeSymbol", "nameScopeType",
"regexPattern", "commentRegexPattern", "symbolParams")}
package ${packageName}.${schemaName};
......@@ -7,7 +7,10 @@ import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ${importSymbols};
<#list imports as import>
import ${import};
</#list>
import de.monticore.lang.tagging._ast.ASTNameScope;
import de.monticore.lang.tagging._ast.ASTScope;
import de.monticore.lang.tagging._ast.ASTTag;
......@@ -16,6 +19,7 @@ import de.monticore.lang.tagging._symboltable.TagSymbolCreator;
import de.monticore.symboltable.Scope;
import de.se_rwth.commons.Joiners;
import de.se_rwth.commons.logging.Log;
import org.jscience.physics.amount.Amount;
/**
* created by ComplexTagTypeCreator.ftl
......@@ -28,9 +32,9 @@ public class ${tagTypeName}SymbolCreator implements TagSymbolCreator {
*
* the pattern can be tested online at:
* http://www.regexplanet.com/advanced/java/index.html
/*
*/
public static final Pattern pattern = Pattern.compile(
${regexPattern}
"${regexPattern}"
);
public static Scope getGlobalScope(final Scope scope) {
......@@ -42,24 +46,24 @@ public class ${tagTypeName}SymbolCreator implements TagSymbolCreator {
}
public void create(ASTTaggingUnit unit, Scope gs) {
if (unit.getQualifiedNames().stream()
if (unit.getQualifiedNameList().stream()
.map(q -> q.toString())
.filter(n -> n.endsWith("${schemaName}"))
.count() == 0) {
return; // the tagging model is not conform to the ${schemaName} tagging schema
}
final String packageName = Joiners.DOT.join(unit.getPackage());
final String packageName = Joiners.DOT.join(unit.getPackageList());
final String rootCmp = // if-else does not work b/c of final (required by streams)
(unit.getTagBody().getTargetModel().isPresent()) ?
Joiners.DOT.join(packageName, ((ASTNameScope) unit.getTagBody().getTargetModel().get())
(unit.getTagBody().getTargetModelOpt().isPresent()) ?
Joiners.DOT.join(packageName, ((ASTNameScope) unit.getTagBody().getTargetModelOpt().get())
.getQualifiedName().toString()) :
packageName;
for (ASTTag element : unit.getTagBody().getTagList()) {
element.getTagElements().stream()
element.getTagElementList().stream()
.filter(t -> t.getName().equals("${tagTypeName}"))
.filter(t -> !t.getTagValue().isPresent())
.map(t -> matchRegexPattern(t.getTagValue().get()))
.filter(t -> !t.getTagValueOpt().isPresent())
.map(t -> matchRegexPattern(t.getTagValueOpt().get()))
.filter(r -> r != null)
.forEachOrdered(m ->
element.getScopeList().stream()
......@@ -83,8 +87,7 @@ public class ${tagTypeName}SymbolCreator implements TagSymbolCreator {
return matcher;
}
Log.error(String.format("'%s' does not match the specified regex pattern '%s'",
regex,
"${commentRegexPattern}"
"It should fit this; ${commentRegexPattern}"
));
return null;
}
......
......@@ -29,7 +29,7 @@ public class ${schemaName} {
<#list tagTypeNames as tagTypeName>
modelingLanguage.addTagSymbolCreator(new ${tagTypeName}SymbolCreator());
commonModelingLanguage.addResolver(CommonResolvingFilter.create(${tagTypeName}Symbol.KIND));
commonModelingLanguage.addResolvingFilter(CommonResolvingFilter.create(${tagTypeName}Symbol.KIND));
</#list>
}
}
......
......@@ -29,6 +29,7 @@ import java.util.Map;
import de.monticore.generating.GeneratorSetup;
import de.monticore.lang.tagging.generator.TagSchemaGenerator;
import org.junit.Ignore;
import org.junit.Test;
/**
......@@ -125,4 +126,15 @@ public class GeneratorTest {
generator.generate(Paths.get("CompPower"), Paths.get("src/test/resources/nfp/"), symbolScopeMap);
}
@Test
public void testSizeTag() throws Exception {
GeneratorSetup setup = new GeneratorSetup();
setup.setOutputDirectory(getPathFromRelativePath("src/test/resources/generator/").toFile());
setup.setTracing(true);
TagSchemaGenerator generator = new TagSchemaGenerator(setup);
Map<String, String> symbolScopeMap = new LinkedHashMap<>();
symbolScopeMap.put("EMAComponentInstance", "NameScope");
generator.generate(Paths.get("PhysicalTags"), Paths.get("src/test/resources/nfp"), symbolScopeMap);
}
}
/* generated from model null*/
/* generated by template templates.de.monticore.lang.montiarc.tagschema.SimpleTagType*/
package de.monticore.lang.montiarc.tag.drawing.TraceabilityTagSchema;
import de.monticore.lang.montiarc.tagging._symboltable.TagKind;
import de.monticore.lang.montiarc.tagging._symboltable.TagSymbol;
/**
* Created by SimpleTagType.ftl
*/
public class IsTraceableSymbol extends TagSymbol {
public static final IsTraceableKind KIND = IsTraceableKind.INSTANCE;
/**
* is marker symbol so it has no value by itself
*/
public IsTraceableSymbol() {
super(KIND);
}
protected IsTraceableSymbol(IsTraceableKind kind) {
super(kind);
}
@Override
public String toString() {
return "IsTraceable";
}
public static class IsTraceableKind extends TagKind {
public static final IsTraceableKind INSTANCE = new IsTraceableKind();
protected IsTraceableKind() {
}
}
}
\ No newline at end of file
/* generated from model null*/
/* generated by template templates.de.monticore.lang.montiarc.tagschema.SimpleTagTypeCreator*/
package de.monticore.lang.montiarc.tag.drawing.TraceabilityTagSchema;
import java.util.Optional;
import de.monticore.lang.montiarc.montiarc._symboltable.*;
import de.monticore.lang.montiarc.tagging._ast.ASTNameScope;
import de.monticore.lang.montiarc.tagging._ast.ASTScope;
import de.monticore.lang.montiarc.tagging._ast.ASTTag;
import de.monticore.lang.montiarc.tagging._ast.ASTTaggingUnit;
import de.monticore.lang.montiarc.tagging._symboltable.TagSymbolCreator;
import de.monticore.symboltable.Scope;
import de.se_rwth.commons.Joiners;
import de.se_rwth.commons.logging.Log;
/**
* created by SimpleTagTypeCreator.ftl
*/
public class IsTraceableSymbolCreator implements TagSymbolCreator {
public static Scope getGlobalScope(final Scope scope) {
Scope s = scope;
while (s.getEnclosingScope().isPresent()) {
s = s.getEnclosingScope().get();
}
return s;
}
public void create(ASTTaggingUnit unit, Scope gs) {
if (unit.getQualifiedNames().stream()
.map(q -> q.toString())
.filter(n -> n.endsWith("TraceabilityTagSchema"))
.count() == 0) {
return; // the tagging model is not conform to the TraceabilityTagSchema tagging schema
}
final String packageName = Joiners.DOT.join(unit.getPackage());
final String rootCmp = // if-else does not work b/c of final (required by streams)
(unit.getTagBody().getTargetModel().isPresent()) ?
Joiners.DOT.join(packageName, ((ASTNameScope) unit.getTagBody().getTargetModel().get())
.getQualifiedName().toString()) :
packageName;
for (ASTTag element : unit.getTagBody().getTagList()) {
element.getTagElements().stream()
.filter(t -> t.getName().equals("IsTraceable"))
.filter(t -> !t.getTagValue().isPresent()) // only marker tag with no value
.forEachOrdered(t ->
element.getScopeList().stream()
.filter(this::checkScope)
.map(s -> (ASTNameScope) s)
.map(s -> getGlobalScope(gs).<ComponentSymbol>resolveDown(
Joiners.DOT.join(rootCmp, s.getQualifiedName().toString()),
ComponentSymbol.KIND))
.filter(Optional::isPresent)
.map(Optional::get)
.forEachOrdered(s -> s.addTag(new IsTraceableSymbol())));
}
}
protected boolean checkScope(ASTScope scope) {
if (scope.getScopeKind().equals("NameScope")) {
return true;
}
Log.error(String.format("0xT0005 Invalid scope kind: '%s'. IsTraceable expects as scope kind 'NameScope'.",
scope.getScopeKind()), scope.get_SourcePositionStart());
return false;
}
}
\ No newline at end of file
......@@ -29,9 +29,9 @@ public class TraceabilityTagSchema {
CommonModelingLanguage commonModelingLanguage = (CommonModelingLanguage)modelingLanguage;
modelingLanguage.addTagSymbolCreator(new IsTraceableSymbolCreator());
commonModelingLanguage.addResolver(CommonResolvingFilter.create(IsTraceableSymbol.KIND));
commonModelingLanguage.addResolvingFilter(CommonResolvingFilter.create(IsTraceableSymbol.KIND));
modelingLanguage.addTagSymbolCreator(new TraceableSymbolCreator());
commonModelingLanguage.addResolver(CommonResolvingFilter.create(TraceableSymbol.KIND));
commonModelingLanguage.addResolvingFilter(CommonResolvingFilter.create(TraceableSymbol.KIND));
}