diff options
author | Henrik Rentz-Reichert | 2018-07-06 17:19:51 +0000 |
---|---|---|
committer | Henrik Rentz-Reichert | 2018-07-06 17:22:00 +0000 |
commit | 0509ac03bea494b08a92251e68e9efc92e415a20 (patch) | |
tree | d070ca8800c829827df8aff75c1b773fe1115908 /plugins/org.eclipse.etrice.dctools | |
parent | c2dfdeabf15d7e367bcd92731e6ac8651ffb9cac (diff) | |
parent | bed42b94fbf934db15e792b247ee747f0c37ebf4 (diff) | |
download | org.eclipse.etrice-0509ac03bea494b08a92251e68e9efc92e415a20.tar.gz org.eclipse.etrice-0509ac03bea494b08a92251e68e9efc92e415a20.tar.xz org.eclipse.etrice-0509ac03bea494b08a92251e68e9efc92e415a20.zip |
Merge remote-tracking branch 'newfsmgen_finalize'
Conflicts:
plugins/org.eclipse.etrice.ui.behavior.fsm/META-INF/MANIFEST.MF
plugins/org.eclipse.etrice.ui.behavior/META-INF/MANIFEST.MF
Change-Id: Icc81a851cdcdb35081b8eaa3d5b025c1f850de54
Diffstat (limited to 'plugins/org.eclipse.etrice.dctools')
13 files changed, 1083 insertions, 0 deletions
diff --git a/plugins/org.eclipse.etrice.dctools/.classpath b/plugins/org.eclipse.etrice.dctools/.classpath new file mode 100644 index 000000000..428337e56 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="xtend-gen"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/plugins/org.eclipse.etrice.dctools/.gitignore b/plugins/org.eclipse.etrice.dctools/.gitignore new file mode 100644 index 000000000..1a7726dc2 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/.gitignore @@ -0,0 +1,4 @@ +bin +*._trace +*.smap +*.xtendbin diff --git a/plugins/org.eclipse.etrice.dctools/.project b/plugins/org.eclipse.etrice.dctools/.project new file mode 100644 index 000000000..af0ef944b --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/.project @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>org.eclipse.etrice.dctools</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.xtext.ui.shared.xtextBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.ManifestBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.pde.SchemaBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.pde.PluginNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.xtext.ui.shared.xtextNature</nature> + </natures> +</projectDescription> diff --git a/plugins/org.eclipse.etrice.dctools/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.etrice.dctools/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF b/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF new file mode 100644 index 000000000..9a9f24843 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/META-INF/MANIFEST.MF @@ -0,0 +1,23 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Detail Code Tools +Bundle-SymbolicName: org.eclipse.etrice.dctools +Bundle-Version: 1.1.3.qualifier +Bundle-Vendor: Eclipse eTrice +Automatic-Module-Name: org.eclipse.etrice.dctools +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: com.google.guava, + org.eclipse.emf.ecore, + org.eclipse.jface.text, + org.eclipse.xtext.xbase.lib, + org.eclipse.xtend.lib, + org.eclipse.xtend.lib.macro, + org.eclipse.xtext.ui, + org.eclipse.etrice.core.fsm, + org.eclipse.etrice.core.room, + org.eclipse.etrice.dctools.fsm;visibility:=reexport, + org.eclipse.etrice.generator.fsm, + org.eclipse.etrice.core.genmodel.fsm +Export-Package: org.eclipse.etrice.dctools, + org.eclipse.etrice.dctools.ast + diff --git a/plugins/org.eclipse.etrice.dctools/build.properties b/plugins/org.eclipse.etrice.dctools/build.properties new file mode 100644 index 000000000..d8e2f0e92 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/build.properties @@ -0,0 +1,5 @@ +source.. = src/,\ + xtend-gen/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/GenModelAccess.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/GenModelAccess.xtend new file mode 100644 index 000000000..340b069b8 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/GenModelAccess.xtend @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools + +import java.util.Map +import org.eclipse.etrice.core.RoomStandaloneSetup +import org.eclipse.etrice.core.fsm.fSM.ModelComponent +import org.eclipse.etrice.core.genmodel.fsm.ExtendedFsmGenBuilder +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer + +class GenModelAccess { + + Map<ModelComponent, GraphContainer> cache = newHashMap + + def public GraphContainer get(ModelComponent mc) { + if(!cache.containsKey(mc)) { + val injector = new RoomStandaloneSetup().createInjector + val builder = new ExtendedFsmGenBuilder(injector); + val gc = builder.createTransformedModel(mc) + builder.withCommonData(gc) + cache.put(mc, gc) + } + + return cache.get(mc) + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend new file mode 100644 index 000000000..d703ea1ff --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCLinker.xtend @@ -0,0 +1,278 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools.ast + +import java.util.Deque +import java.util.LinkedList +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.etrice.core.fsm.fSM.StateGraphItem +import org.eclipse.etrice.core.room.ActorClass +import org.eclipse.etrice.core.room.Attribute +import org.eclipse.etrice.core.room.DataClass +import org.eclipse.etrice.core.room.EnumerationType +import org.eclipse.etrice.core.room.InterfaceItem +import org.eclipse.etrice.core.room.MessageData +import org.eclipse.etrice.core.room.Operation +import org.eclipse.etrice.core.room.Port +import org.eclipse.etrice.core.room.PortClass +import org.eclipse.etrice.core.room.RoomClass +import org.eclipse.etrice.core.room.SAP +import org.eclipse.etrice.core.room.VarDecl +import org.eclipse.etrice.core.room.util.RoomHelpers +import org.eclipse.etrice.dctools.fsm.ast.CandidateMap +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstArrayAccessNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstFeatureCallNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstIdentifierNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstOperationCallNode +import org.eclipse.etrice.dctools.fsm.ast.util.IDCAstNodeVisitor + +import static org.eclipse.etrice.core.fsm.fSM.FSMPackage.Literals.* + +import static extension org.eclipse.xtext.EcoreUtil2.* +import org.eclipse.etrice.core.fsm.fSM.DetailCode + +class DCLinker implements IDCAstNodeVisitor { + + enum FeatureType { + SCALAR, + ARRAY, + OPERATION + } + + EObject owner + EReference reference + MessageData transitionData + + protected val extension RoomHelpers roomHelpers = new RoomHelpers + + val Deque<EObject> contexts = new LinkedList + + new(DetailCode dc) { + this(dc.eContainer, dc.eContainingFeature as EReference) + } + + new(EObject owner, EReference reference) { + this(owner, reference, null) + } + + new(DetailCode dc, MessageData transitionData) { + this(dc.eContainer, dc.eContainingFeature as EReference, transitionData) + } + + new(EObject owner, EReference reference, MessageData transitionData) { + this.owner = owner + this.reference = reference + this.transitionData = transitionData + } + + override visitBegin(DCAstNode node) { + switch node { + DCAstFeatureCallNode: { + // a feature call always starts in the global context + contexts.push(owner) + } + DCAstIdentifierNode case node.parent instanceof DCAstFeatureCallNode: link(node) + DCAstArrayAccessNode: link(node) + DCAstOperationCallNode: link(node) + } + + return true + } + + override visitEnd(DCAstNode node) { + switch node { + DCAstFeatureCallNode: contexts.pop + } + } + + protected def dispatch void link(DCAstIdentifierNode node) { + node.doLink(FeatureType.SCALAR, node.id) + } + + protected def dispatch void link(DCAstArrayAccessNode node) { + node.doLink(FeatureType.ARRAY, node.id) + } + + protected def dispatch void link(DCAstOperationCallNode node) { + node.doLink(FeatureType.OPERATION, node.id) + } + + protected def void doLink(DCAstNode node, FeatureType ft, String name) { + val candidates = getCandidates(ft) + node.linkedObject = candidates.get(name) + node.linkedData = candidates + replaceContext(node.linkedObject) + } + + protected def replaceContext(EObject obj) { + contexts.pop + contexts.push(obj?.contextOf) + } + + protected def dispatch getContextOf(EObject obj) { + null + } + + protected def dispatch getContextOf(Port port) { + port + } + + protected def dispatch getContextOf(Attribute att) { + att.type.type + } + + protected def dispatch getContextOf(VarDecl vd) { + vd.refType.type + } + + protected def dispatch getContextOf(MessageData md) { + md?.refType?.type + } + + protected def dispatch getContextOf(Operation op) { + op?.returnType?.type + } + + //http://git.eclipse.org/c/etrice/org.eclipse.etrice.git/tree/tests/org.eclipse.etrice.generator.common.tests/models/EnumTest.room?h=newfsmgen_finalize&id=79aa00b074c61bde5173d4859ce2b52e50b52dec#n117 + + protected def getCandidates(FeatureType type) { + val candidates = new CandidateMap + + if (contexts.peek===owner) { + // this is the top level + topLevelCandidates(candidates, type) + } + else { + val current = contexts.peek + switch current { + DataClass: { + current.getCandidates(type, candidates) + } + + InterfaceItem: { + current.getCandidates(candidates) + } + + Attribute case current.type?.type instanceof DataClass: { + val dc = current.type.type as DataClass + dc.getCandidates(type, candidates) + } + MessageData case current.refType?.type instanceof DataClass: { + val dc = current.refType.type as DataClass + dc.getCandidates(type, candidates) + } + EnumerationType: { + // from descriptions, have to be resolved + var enumType = current + if (current.eIsProxy) { + val resolved = EcoreUtil.resolve(current, owner) + if (resolved instanceof EnumerationType) + enumType = resolved + } + enumType.literals.forEach[candidates.put(it.name, it)] + } + } + } + + return candidates + } + + protected def void topLevelCandidates(CandidateMap candidates, FeatureType type) { + // operation arguments + owner.getContainerOfType(Operation)?.arguments?.forEach[candidates.put(it.name, it)] + + // TODO: compare with org.eclipse.etrice.expressions.detailcode.DetailExpressionProvider.initialFsmExpression(EObject, ActorClass, List<ExpressionFeature>) + if (!reference.name.contains('userCode')) { + val roomClass = owner.getContainerOfType(RoomClass) + switch roomClass { + ActorClass: { + if (transitionData!==null) { + candidates.put("transitionData", transitionData) + } + if (type==FeatureType.SCALAR) { + roomClass.allAttributes.forEach[candidates.put(it.name, it)] + } + if (type==FeatureType.ARRAY) { + roomClass.allAttributes.filter[size>1].forEach[candidates.put(it.name, it)] + } + if (type==FeatureType.OPERATION) { + roomClass.latestOperations.forEach[candidates.put(it.name, it)] + } + roomClass.allInterfaceItems.forEach[ + switch it { + Port case type==FeatureType.SCALAR: candidates.put(it.name, it) + Port case type==FeatureType.ARRAY && it.replicated: candidates.put(it.name, it) + SAP case type==FeatureType.SCALAR: candidates.put(it.name, it) + } + ] + } + + DataClass: { + roomClass.getCandidates(type, candidates) + } + + case owner.getContainerOfType(PortClass)!==null: { + val portClass = owner.getContainerOfType(PortClass) + // TODO inheritance + portClass.operations.forEach[candidates.put(it.name, it)] + portClass.attributes.forEach[candidates.put(it.name, it)] + } + } + } + } + + protected def void getCandidates(DataClass dataClass, FeatureType type, CandidateMap candidates) { + if (type==FeatureType.SCALAR) { + dataClass.allAttributes.forEach[candidates.put(it.name, it)] + } + if (type==FeatureType.ARRAY) { + dataClass.allAttributes.filter[size>1].forEach[candidates.put(it.name, it)] + } + if (type==FeatureType.OPERATION) { + dataClass.latestOperations.forEach[candidates.put(it.name, it)] + } + } + + protected def void getCandidates(InterfaceItem ifItem, CandidateMap candidates) { + // operations + ifItem.protocol.getAllOperations(!ifItem.conjugated).forEach[candidates.put(it.name, it)] + + // messages + switch reference { + case CP_BRANCH_TRANSITION__CONDITION, + case GUARDED_TRANSITION__GUARD, + case GUARD__GUARD: { + val pc = ifItem.protocol + switch pc?.commType { + case DATA_DRIVEN: + if (!ifItem.conjugated) pc.allIncomingMessages.forEach[candidates.put(it.name, it)] + case EVENT_DRIVEN: { /* no async message calls */} + case SYNCHRONOUS: {} + } + } + case owner.getContainerOfType(StateGraphItem)!==null: { + val pc = ifItem.protocol + switch pc?.commType { + case EVENT_DRIVEN: + pc.getAllMessages(ifItem.conjugated).forEach[candidates.put(it.name, it)] + case DATA_DRIVEN: + pc.allIncomingMessages.forEach[candidates.put(it.name, it)] + case SYNCHRONOUS: {} + } + } + } + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCTranslator.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCTranslator.xtend new file mode 100644 index 000000000..7c72cd54b --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCTranslator.xtend @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2018 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools.ast + +import org.eclipse.etrice.generator.fsm.generic.IDetailCodeTranslator +import org.eclipse.etrice.core.fsm.fSM.DetailCode +import org.eclipse.etrice.dctools.ast.internal.DCTranslatorVisitor +import org.eclipse.etrice.core.room.util.RoomHelpers +import org.eclipse.etrice.generator.fsm.base.IFSMTranslationProvider +import org.eclipse.etrice.dctools.fsm.ast.DCLanguage +import org.eclipse.etrice.dctools.fsm.ast.DCParser +import org.eclipse.etrice.core.room.MessageData + +class DCTranslator implements IDetailCodeTranslator { + + DCLanguage language + ITranslationProvider translationProvider + + val extension RoomHelpers roomHelpers = new RoomHelpers + + new(DCLanguage language, ITranslationProvider translationProvider) { + this.language = language + this.translationProvider = translationProvider + } + + override getTranslatedCode(DetailCode dc) { + return getTranslatedCode(dc, null) + } + + def getTranslatedCode(DetailCode dc, MessageData transitionData) { + var code = dc.detailCode + + // before the actual parsing is done we translate tags + if (translationProvider.translateTags) { + code = translateTags(code, dc) + } + + // parse + val parser = new DCParser(language) + val ast = parser.parse(code) + + // link + val linker = new DCLinker(dc, transitionData) + ast.visit(linker) + + // translate + val visitor = new DCTranslatorVisitor(translationProvider) + ast.visit(visitor) + + return visitor.translatedCode + } + + def translateTags(String text, DetailCode dc) { + val result = new StringBuilder + + var int last = 0 + var int next = text.indexOf(IFSMTranslationProvider.TAG_START, last) + while (next >= 0) { + result.append(text.substring(last, next)) + last = next + IFSMTranslationProvider.TAG_START.length() + next = text.indexOf(IFSMTranslationProvider.TAG_END, last) + if (next >= 0) { + val String tag = text.substring(last, next) + result.append(translationProvider.translateTag(tag, dc)) + last = next + IFSMTranslationProvider.TAG_END.length() + next = text.indexOf(IFSMTranslationProvider.TAG_START, last) + } + } + result.append(text.substring(last)) + + return result.toString + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCUtil.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCUtil.xtend new file mode 100644 index 000000000..e2f580939 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/DCUtil.xtend @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools.ast + +import com.google.inject.Inject +import java.util.List +import org.eclipse.emf.ecore.EObject +import org.eclipse.etrice.core.converter.RoomValueConverterService +import org.eclipse.etrice.core.fsm.fSM.DetailCode +import org.eclipse.etrice.core.fsm.fSM.TransitionBase +import org.eclipse.etrice.core.genmodel.fsm.FsmGenExtensions +import org.eclipse.etrice.core.room.ActorClass +import org.eclipse.etrice.core.room.MessageData +import org.eclipse.etrice.core.room.RoomClass +import org.eclipse.etrice.dctools.GenModelAccess +import org.eclipse.etrice.dctools.ast.internal.DCProposalConfig +import org.eclipse.etrice.dctools.fsm.ast.CandidateMap +import org.eclipse.etrice.dctools.fsm.ast.DCLanguage +import org.eclipse.etrice.dctools.fsm.ast.DCNodeAtOffset +import org.eclipse.etrice.dctools.fsm.ast.DCParser +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstIdentifierNode +import org.eclipse.jface.text.contentassist.ICompletionProposal +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.nodemodel.ILeafNode +import org.eclipse.xtext.nodemodel.INode + +class DCUtil { + + @Accessors + static class FindResult { + val EObject object + val int begin + val int length + } + + @Inject RoomValueConverterService converterService + @Inject DCProposalConfig proposalConfig + + val genModelAccess = new GenModelAccess + DCLanguage language = DCLanguage.C_LANGUAGE + + new() { + } + + def setLanguage(DCLanguage language) { + this.language = language + } + + def FindResult findAtOffset(ILeafNode textNode, int offset) { + val ast = textNode.parseAndLink + val astNode = DCNodeAtOffset.find(ast, offset - textNode.delimiterAdjustedOffset) + if (astNode instanceof DCAstIdentifierNode) { + val object = getLinkedObject(astNode) + if (object !==null) { + return new FindResult(object, astNode.begin + converterService.CC_StringConverter.delim.length, astNode.end-astNode.begin) + } + } + return null + } + + def getDelimiterAdjustedOffset(INode astNode) { + astNode.offset + converterService.CC_StringConverter.delim.length + } + + def parseAndLink(INode astNode) { + val text = converterService.CC_StringConverter.stripDelim(astNode.getText()); + val parser = new DCParser(language) + val ast = parser.parse(text) + + if (astNode.parent.semanticElement instanceof DetailCode) { + val dc = astNode.parent.semanticElement as DetailCode + + var DCLinker linker = null; + + // lets check whether we have a transition and determine common data + val transition = EcoreUtil2.getContainerOfType(dc, TransitionBase) + if (transition!==null) { + val roomClass = EcoreUtil2.getContainerOfType(dc, RoomClass) + if (roomClass instanceof ActorClass) { + val gc = genModelAccess.get(roomClass) + val link = FsmGenExtensions.getLinkFor(gc, transition) + if (link!==null) { + linker = new DCLinker(dc, link.commonData as MessageData) + } + } + } + + // if we have no common data we use a plain linker + if (linker===null) { + linker = new DCLinker(dc) + } + + ast.visit(linker) + + return ast + } + else { + return null + } + } + + def List<ICompletionProposal> getProposals(INode textNode, int offset) { + val ast = textNode.parseAndLink + // note: we subtract 1 to get the token to the left of the caret + val astNode = DCNodeAtOffset.find(ast, offset - textNode.delimiterAdjustedOffset - 1) + if (astNode instanceof DCAstIdentifierNode) { + val candidates = astNode.candidates + if (candidates!==null) { + val begin = astNode.begin + converterService.CC_StringConverter.delim.length + val end = offset - textNode.offset + val prefix = textNode.text.substring(begin, end) + val matches = candidates.getMatches(prefix) + return matches.entrySet.map[match | proposalConfig.doCreateProposal(prefix, match.key, match.value, offset)].toList + } + } + + newArrayList + } + + static def EObject getLinkedObject(DCAstIdentifierNode astNode) { + if (astNode.linkedObject!==null) { + astNode.linkedObject + } + else if (astNode.parent!==null) { + astNode.parent.linkedObject + } + } + + static def CandidateMap getCandidates(DCAstIdentifierNode astNode) { + if (astNode.linkedData instanceof CandidateMap) { + astNode.linkedData as CandidateMap + } + else if (astNode.parent!==null && astNode.parent.linkedData instanceof CandidateMap) { + astNode.parent.linkedData as CandidateMap + } + } +} diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/ITranslationProvider.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/ITranslationProvider.xtend new file mode 100644 index 000000000..2bb57091d --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/ITranslationProvider.xtend @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools.ast + +import org.eclipse.etrice.core.room.InterfaceItem +import org.eclipse.etrice.core.fsm.fSM.AbstractInterfaceItem +import org.eclipse.etrice.core.room.Attribute +import org.eclipse.etrice.core.room.Message +import org.eclipse.etrice.core.room.Operation +import org.eclipse.etrice.core.room.PortOperation +import org.eclipse.etrice.core.room.EnumLiteral +import org.eclipse.etrice.dctools.fsm.ast.IFSMTranslationProvider + +/** + * This interface is used by the detail code translator to replace + * common constructs in detail level code with a target language specific + * piece of code. + * <p> + * The constructs that are replaced are + * <ul> + * <li>attributes</li> + * <li>operations</li> + * <li>port.message</li> + * <li>tags of the form <code><|tag|></code></li> + * </ul> + * </p> + * @see DCTranslator + * @author Henrik Rentz-Reichert + */ +interface ITranslationProvider extends IFSMTranslationProvider{ + + /** + * yield text to read an attribute (array index may be null). Is called whenever <i>attribute</i> + * or <i>attribute</i>[<i>index</i>] or is + * found in the detail code + * @param att the actor class attribute + * @param instance a pointer to the instance object + * @param index the index (should be null for scalars, !=null for arrays) + * @param orig the original text + * @return the translation + */ + def String getAttributeGetter(Attribute att, String instance, String index, String orig) + + /** + * yield text to write an attribute (array index may be null). Is called whenever <i>attribute</i>.set(<i>value</i>) + * or <i>attribute</i>[<i>index</i>].set(<i>value</i>) is + * found in the detail code + * @param att the actor class attribute + * @param instance a pointer to the instance object + * @param index the index (should be null for scalars, !=null for arrays) + * @param value to assign to the attribute + * @param orig the original text + * @return the translation + */ + def String getAttributeSetter(Attribute att, String instance, String index, String value, String orig) + + /** + * yield text for operation call. Is called whenever <i>operation</i>(<i>args</i>) + * is found in the detail code + * @param op operation to call + * @param instance a pointer to the defining class instance + * @param args the arguments to pass + * @param orig the original text + * @return the translation + */ + def String getOperationText(Operation op, String instance, String args, String orig) + + /** + * yields a sequence that reads data from a <b>data driven</b> port. + * Is called whenever <i>port</i>.<i>msg</i> or <i>port</i>[<i>index</i>].<i>msg</i> + * is found in the detail code + * @param item the interface item + * @param msg the message to read + * @param orig the original text + * @return the translation + */ + def String getInterfaceItemMessageValue(InterfaceItem item, Message msg, String orig) + + /** + * @return true if translations are provided for enumerations + */ + def boolean translateEnums() + + /** + * yields a replacement for <enumtype>.<literal> + * @param literal the enumeration literal to be translated + * @return the translated enumeration literal + */ + def String getEnumText(EnumLiteral literal) + + /** + * yields a call to an operation of an interface item + * @param item the interface item + * @param op the port class operation + * @param instance a pointer to the defining class instance + * @param args the argument list + * @param orig the original test + * @return the translation + */ + def String getInterfaceItemOperationText(AbstractInterfaceItem item, PortOperation op, String instance, String args, String orig) + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCProposalConfig.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCProposalConfig.xtend new file mode 100644 index 000000000..8f28887cd --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCProposalConfig.xtend @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools.ast.internal + +import com.google.inject.Singleton +import com.google.inject.Inject +import org.eclipse.jface.viewers.ILabelProvider +import org.eclipse.etrice.core.room.util.RoomHelpers +import org.eclipse.emf.ecore.EObject +import org.eclipse.jface.viewers.StyledString +import org.eclipse.swt.graphics.Image +import org.eclipse.xtext.ui.editor.contentassist.ConfigurableCompletionProposal +import org.eclipse.xtext.ui.editor.contentassist.PrefixMatcher +import org.eclipse.jface.text.contentassist.ICompletionProposal +import org.eclipse.swt.graphics.Point +import org.eclipse.etrice.core.room.Operation +import org.eclipse.etrice.core.room.Message +import org.eclipse.etrice.core.room.Attribute +import org.eclipse.etrice.core.room.InterfaceItem +import org.eclipse.etrice.core.room.Port + +@Singleton +class DCProposalConfig { + + @Inject + protected ILabelProvider labelProvider + + @Inject + protected RoomHelpers roomHelpers + + @Inject + protected PrefixMatcher prefixMatcher + + def ICompletionProposal doCreateProposal(String prefix, String proposal, EObject object, int globalOffset) { + new ConfigurableCompletionProposal(proposal, globalOffset - prefix.length, prefix.length, proposal.length, object.image, object.displayString, null, null) => [ + matcher = prefixMatcher + autoInsertable = false + // TODO adjust length to existing text + replaceContextLength = proposal.length + ] + } + + def Pair<String, Point> getPostfixReplacement(EObject object) { + val brackets = switch object { + Operation, + Message: + #['(', ')'] + + Attribute case object.size>0, + Port case object.multiplicity>0: + #['[', ']'] + } + + if (brackets===null) { + return "" -> null + } + + val replacement = switch object { + Operation: + object.arguments.map[name].join(', ') + + Message case object.data !== null: + object.data.refType.type.name + + Attribute, // fall through + InterfaceItem: + '0' + + default: + '' + } + + replacement.wrap(brackets.head, brackets.last) + } + + private def Pair<String, Point> wrap(String text, String left, String right) { + val selection = if (!text.empty) new Point(1, text.length) + left + text + right -> selection + } + + private def StyledString getDisplayString(EObject object) { + + } + + private def Image getImage(EObject object) { + + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend new file mode 100644 index 000000000..c307273d1 --- /dev/null +++ b/plugins/org.eclipse.etrice.dctools/src/org/eclipse/etrice/dctools/ast/internal/DCTranslatorVisitor.xtend @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2011 protos software gmbh (http://www.protos.de). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * CONTRIBUTORS: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.dctools.ast.internal + +import org.eclipse.etrice.core.room.Attribute +import org.eclipse.etrice.core.room.InterfaceItem +import org.eclipse.etrice.core.room.Message +import org.eclipse.etrice.core.room.Operation +import org.eclipse.etrice.dctools.ast.ITranslationProvider +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstArrayAccessNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstBracketNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstBracketNode.BracketType +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstIdentifierNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstOperationCallNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstOtherNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstPeriodNode +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstWhitespaceNode +import org.eclipse.etrice.dctools.fsm.ast.util.DCAstPrinter +import org.eclipse.etrice.dctools.fsm.ast.util.IDCAstNodeVisitor +import org.eclipse.etrice.dctools.fsm.ast.nodes.DCAstFeatureCallNode +import org.eclipse.etrice.core.room.Port +import org.eclipse.etrice.core.room.VarDecl + +class DCTranslatorVisitor implements IDCAstNodeVisitor { + + ITranslationProvider translationProvider + + val sb = new StringBuilder + var currentSB = sb + + new(ITranslationProvider translationProvider) { + this.translationProvider = translationProvider + } + + def String getTranslatedCode() { + sb.toString + } + + + override visitBegin(DCAstNode node) { + + if (node instanceof DCAstBracketNode) { + if (node.shouldCollectArguments) { + currentSB = new StringBuilder + node.linkedData = currentSB + } + else { + currentSB.append(node.left) + } + } + else { + if (!node.skipOutput) { + switch node { + DCAstIdentifierNode: currentSB.append(node.id) + DCAstPeriodNode: currentSB.append(".") + DCAstWhitespaceNode: currentSB.append(node.text) + DCAstOtherNode: currentSB.append(node.text) + } + } + } + + return true + } + + override visitEnd(DCAstNode node) { + switch node { + DCAstBracketNode: { + if (node.linkedData!==null) { + // leave the nested StringBuilder and switch to the enclosing (or top) one + currentSB = node.enclosingSB + } + else if (node.closed) { + currentSB.append(node.right) + } + } + + DCAstFeatureCallNode case node.canTranslate: node.translate + } + } + + private def canTranslate(DCAstFeatureCallNode node) { + // if all even children are linked then we can translate the whole + for (var i=0; i<node.children.size; i=i+2) { + if (node.c(i).linkedObject===null) { + return false + } + } + + // make sure the last child is not a period + val lastNode = node.children.last + if (lastNode instanceof DCAstPeriodNode) { + return false + } + + return true + } + + private def translate(DCAstFeatureCallNode node) { + val lastNode = node.children.last + var linkedObject = lastNode.linkedObject + + // TODO: handle getter for data driven ports: port.message - i.e. no () after message + + if (lastNode instanceof DCAstOperationCallNode) { + if (linkedObject instanceof Message) { + handleSendMessage(lastNode, linkedObject) + return + } + } + + node.handleCallChain + } + + def handleCallChain(DCAstFeatureCallNode node) { + var String instance = null + for (var i=0; i<node.children.size; i=i+2) { + val childNode = node.c(i) + val linkedObject = childNode.linkedObject + switch linkedObject { + Attribute: { + val index = if (childNode instanceof DCAstArrayAccessNode) { + (childNode.bracketNode.linkedData as StringBuilder).toString + } + instance = translationProvider.getAttributeGetter(linkedObject, instance, index, childNode.originalText) + } + + VarDecl: { + instance = linkedObject.name + } + + Operation: { + val args = if (childNode instanceof DCAstOperationCallNode) { + (childNode.bracketNode.linkedData as StringBuilder).toString + } + instance = translationProvider.getOperationText(linkedObject, instance, args, childNode.originalText) + } + } + } + currentSB.append(instance) + } + + private def handleSendMessage(DCAstOperationCallNode msgNode, Message msg) { + val args = (msgNode.bracketNode.linkedData as StringBuilder).toString + // look back to interface item + val ifItemNode = msgNode.parent.c(0) + val ifItem = ifItemNode.linkedObject as InterfaceItem + + val translated = + if (ifItemNode instanceof DCAstIdentifierNode) { + // accessed as scalar (means broadcast for replicated port) + val inst = ifItemNode.id + translationProvider.getInterfaceItemMessageText(ifItem, msg, inst, args, null, msgNode.originalText) + } + else if (ifItemNode instanceof DCAstArrayAccessNode) { + // accessed as array + val inst = ifItemNode.id + val index = (ifItemNode.bracketNode.linkedData as StringBuilder).toString + translationProvider.getInterfaceItemMessageText(ifItem, msg, inst, args, index, msgNode.originalText) + } + else { + // TODO: assert(false) + "internal translator error" + } + currentSB.append(translated) + } + + private def skipOutput(DCAstNode node) { + val surroundingContext = node.getEnclosingBracketOrFeatureCall + + // check whether we are inside a bracket without a feature call + if (surroundingContext instanceof DCAstBracketNode) { + return false + } + + if (surroundingContext instanceof DCAstFeatureCallNode) { + return surroundingContext.canTranslate + } + + return false + } + + private def getEnclosingBracketOrFeatureCall(DCAstNode node) { + var parent = node.parent + while (parent!==null) { + if (parent instanceof DCAstFeatureCallNode || parent instanceof DCAstBracketNode) { + return parent + } + parent = parent.parent + } + + return null + } + + private def getOriginalText(DCAstNode node) { + val printer = new DCAstPrinter + node.visit(printer) + return printer.text + } + + private def getEnclosingSB(DCAstBracketNode node) { + var parent = node.parent + while (parent!==null) { + if (parent instanceof DCAstBracketNode && parent.linkedData instanceof StringBuilder) { + return parent.linkedData as StringBuilder + } + parent = parent.parent + } + + // return top level + return sb + } + + private def shouldCollectArguments(DCAstBracketNode node) { + val linkedObject = node.parent.linkedObject + + if (node.type==BracketType.CURLY) { + false + } + else if (linkedObject instanceof Operation) { + true + } + else if (linkedObject instanceof Message) { + true + } + else if (linkedObject instanceof Attribute) { + true + } + else if (linkedObject instanceof Port) { + true + } + else { + false + } + } +}
\ No newline at end of file |