blob: 46552a44fe1411447679b24eccc758984ef6ea72 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 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.generator.fsm.base;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.etrice.core.fsm.fSM.AbstractInterfaceItem;
import org.eclipse.etrice.core.fsm.fSM.DetailCode;
import org.eclipse.etrice.core.fsm.fSM.ModelComponent;
import org.eclipse.etrice.core.fsm.naming.FSMNameProvider;
/**
* @author Henrik Rentz-Reichert
*
*/
public class FSMDetailCodeTranslator {
public static class Position {
public int pos = 0;
}
protected IFSMTranslationProvider provider;
protected EObject container;
protected boolean doTranslate;
private boolean isPrepared = false;
private FSMNameProvider fsmNameProvider = new FSMNameProvider();
protected HashMap<String, AbstractInterfaceItem> name2item = new HashMap<String, AbstractInterfaceItem>();
public FSMDetailCodeTranslator(ModelComponent container, IFSMTranslationProvider provider, boolean doTranslate) {
this((EObject)container, provider, doTranslate);
}
protected FSMDetailCodeTranslator(EObject container, IFSMTranslationProvider provider, boolean doTranslate) {
this.provider = provider;
this.container = container;
this.doTranslate = doTranslate;
}
protected void prepare() {
provider.setContainerClass(container);
if (container instanceof ModelComponent) {
ModelComponent mc = (ModelComponent) container;
List<AbstractInterfaceItem> items = mc.getAllAbstractInterfaceItems();
for (AbstractInterfaceItem item : items) {
name2item.put(item.getName(), item);
}
}
}
/**
* @param code a {@link DetailCode} to translate
* @return the translated code as string
*/
public String translateDetailCode(DetailCode code) {
if (code==null)
return "";
// concatenate lines
StringBuilder text = new StringBuilder();
for (String line : code.getLines()) {
text.append(line+"\n");
}
String result = text.substring(0, Math.max(0, text.length()-1));
if (!doTranslate)
return result;
if (provider.translateMembers())
result = translateText(result);
if (provider.translateTags())
result = translateTags(result, code);
return result;
}
public String translateText(String text) {
if (!isPrepared) {
isPrepared = true;
prepare();
}
StringBuilder result = new StringBuilder();
Position curr = new Position();
int last = 0;
while (curr.pos<text.length()) {
proceedToToken(text, curr);
last = appendParsed(text, curr, last, result);
String token = getToken(text, curr);
if (token.isEmpty()) {
if (curr.pos<text.length() && !isTokenChar(text.charAt(curr.pos)))
++curr.pos;
last = appendParsed(text, curr, last, result);
}
else {
String translated = translateToken(text, curr, last, token);
if (translated!=null) {
last = curr.pos;
result.append(translated);
}
else
last = appendParsed(text, curr, last, result);
}
}
return result.toString();
}
protected String translateTags(String text, DetailCode code) {
StringBuilder result = new StringBuilder();
int last = 0;
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)
break;
String tag = text.substring(last, next);
result.append(provider.translateTag(tag, code));
last = next+IFSMTranslationProvider.TAG_END.length();
next = text.indexOf(IFSMTranslationProvider.TAG_START, last);
}
result.append(text.substring(last));
return result.toString();
}
protected String translateToken(String text, Position curr, int last, String token) {
String translated = null;
AbstractInterfaceItem item = name2item.get(token);
if (item!=null) {
int start = curr.pos;
String index = getArrayIndex(text, curr);
if (index==null)
curr.pos = start;
EObject msg = getMessage(text, curr, item, true);
if (msg!=null) {
ArrayList<String> args = getArgs(text, curr);
if (args!=null) {
if (argsMatching(msg, args)) {
// recursively apply this algorithm to each argument
for (int i=0; i<args.size(); ++i) {
String transArg = translateText(args.remove(i));
args.add(i, transArg);
}
String orig = text.substring(last, curr.pos);
translated = provider.getInterfaceItemMessageText(item, msg, args, index, orig);
}
}
}
else {
curr.pos = start;
translated = translateInterfaceItemToken(item, text, curr, last, token);
}
}
return translated;
}
protected String translateInterfaceItemToken(AbstractInterfaceItem item, String text, Position curr, int last, String token) {
return null;
}
protected EObject getMessage(String text, Position curr, AbstractInterfaceItem item, boolean outgoing) {
proceedToToken(text, curr);
if (curr.pos>=text.length() || text.charAt(curr.pos)!='.')
return null;
++curr.pos;
proceedToToken(text, curr);
String token = getToken(text, curr);
List<EObject> messages = outgoing? item.getAllOutgoingAbstractMessages() : item.getAllIncomingAbstractMessages();
for (EObject message : messages) {
if (fsmNameProvider.getMessageName(message).equals(token))
return message;
}
return null;
}
protected String getArrayIndex(String text, Position curr) {
proceedToToken(text, curr);
if (curr.pos>=text.length() || text.charAt(curr.pos)!='[')
return null;
++curr.pos;
String token = getIndex(text, curr);
if (curr.pos>=text.length() || text.charAt(curr.pos)!=']')
return null;
++curr.pos;
return translateText(token);
}
/**
* @param text
* @param result
* @return
*/
protected int appendParsed(String text, Position curr, int last,
StringBuilder result) {
String str = text.substring(last, curr.pos);
result.append(str);
return curr.pos;
}
protected void proceedToToken(String text, Position curr) {
proceedToToken(text, curr, true);
}
protected void proceedToToken(String text, Position curr, boolean skipString) {
boolean stop = false;
while (curr.pos<text.length() && !stop) {
if (text.charAt(curr.pos)=='"') {
if (skipString)
skipString(text, curr);
else
stop = true;
}
else if (text.charAt(curr.pos)=='/') {
if (curr.pos+1<text.length()) {
if (text.charAt(curr.pos+1)=='/') {
skipSingleComment(text, curr);
}
else if (text.charAt(curr.pos+1)=='*') {
skipMultiComment(text, curr);
}
else
stop = true;
}
else
stop = true;
}
else if (Character.isWhitespace(text.charAt(curr.pos))) {
skipWhiteSpace(text, curr);
}
else
stop = true;
}
}
protected ArrayList<String> getArgs(String text, Position curr) {
proceedToToken(text, curr);
if (curr.pos>=text.length() || text.charAt(curr.pos)!='(')
return null;
++curr.pos;
ArrayList<String> result = new ArrayList<String>();
boolean stop = false;
do {
proceedToToken(text, curr, false);
if (curr.pos<text.length() && text.charAt(curr.pos)!=')') {
String arg = getParam(text, curr);
result.add(arg);
proceedToToken(text, curr);
}
if (curr.pos<text.length() && text.charAt(curr.pos)==',')
++curr.pos;
else
stop = true;
}
while (!stop);
if (curr.pos>=text.length() || text.charAt(curr.pos)!=')')
return null;
++curr.pos;
return result;
}
protected String getToken(String text, Position curr) {
int begin = curr.pos;
while (curr.pos<text.length() && isTokenChar(text.charAt(curr.pos)))
++curr.pos;
String token = text.substring(begin, curr.pos);
return token;
}
protected String getParam(String text, Position curr) {
int begin = curr.pos;
int parenthesisLevel = 0;
while (curr.pos<text.length()) {
if (text.charAt(curr.pos)=='(')
++parenthesisLevel;
else if (text.charAt(curr.pos)==')') {
if (parenthesisLevel==0)
break;
else
--parenthesisLevel;
}
else if (parenthesisLevel==0) {
if (text.charAt(curr.pos)==',')
break;
}
++curr.pos;
}
String token = text.substring(begin, curr.pos).trim();
return token;
}
protected String getIndex(String text, Position curr) {
int begin = curr.pos;
int parenthesisLevel = 0;
while (curr.pos<text.length()) {
if (text.charAt(curr.pos)=='[')
++parenthesisLevel;
else if (text.charAt(curr.pos)==']') {
if (parenthesisLevel==0)
break;
else
--parenthesisLevel;
}
++curr.pos;
}
String token = text.substring(begin, curr.pos).trim();
return token;
}
protected void skipWhiteSpace(String text, Position curr) {
while (curr.pos<text.length() && Character.isWhitespace(text.charAt(curr.pos)))
++curr.pos;
}
protected void skipMultiComment(String text, Position curr) {
curr.pos += 2;
while (curr.pos<text.length()-1 && text.charAt(curr.pos++)!='*')
if (text.charAt(curr.pos)=='/')
break;
if (curr.pos<text.length())
++curr.pos;
}
protected void skipSingleComment(String text, Position curr) {
while (curr.pos<text.length() && text.charAt(curr.pos)!='\n')
++curr.pos;
if (curr.pos<text.length())
++curr.pos;
}
protected void skipString(String text, Position curr) {
while (++curr.pos<text.length() && text.charAt(curr.pos)!='"')
if (text.charAt(curr.pos)=='\\')
++curr.pos;
if (curr.pos<text.length())
++curr.pos;
}
protected boolean argsMatching(EObject msg, ArrayList<String> args) {
return true;
}
protected boolean isTokenChar(char c) {
return Character.isDigit(c) || Character.isLetter(c) || c=='_';
}
}