blob: cd0795076e676a3fc1509857eefaed6c86f6132b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005-2014 Obeo
*
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.sirius.query.legacy.gen.template.expressions;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.sirius.query.legacy.ecore.factories.FactoryException;
import org.eclipse.sirius.query.legacy.gen.AcceleoGenMessages;
import org.eclipse.sirius.query.legacy.gen.template.Template;
import org.eclipse.sirius.query.legacy.gen.template.TemplateConstants;
import org.eclipse.sirius.query.legacy.gen.template.TemplateElement;
import org.eclipse.sirius.query.legacy.gen.template.TemplateSyntaxException;
import org.eclipse.sirius.query.legacy.gen.template.eval.ENode;
import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeCastException;
import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeException;
import org.eclipse.sirius.query.legacy.gen.template.eval.LaunchManager;
import org.eclipse.sirius.query.legacy.gen.template.eval.merge.MergeTools;
import org.eclipse.sirius.query.legacy.gen.template.scripts.IScript;
import org.eclipse.sirius.query.legacy.gen.template.statements.TemplateFeatureStatement;
import org.eclipse.sirius.query.legacy.gen.template.statements.TemplateForStatement;
import org.eclipse.sirius.query.legacy.tools.strings.Int2;
import org.eclipse.sirius.query.legacy.tools.strings.TextSearch;
/**
* This is a sequence of variable call expression (TemplateCallExpression).
* <p>
* For example, "a.b.c(d,e).f" is a sequence with four variables call
* expressions : "a", "b", "c(d,e)", and "f".
*
*
*/
public class TemplateCallSetExpression extends TemplateExpression {
/**
* Variables call expressions.
*/
protected List calls = new ArrayList();
/**
* Constructor.
*
* @param script
* is the script
*/
public TemplateCallSetExpression(IScript script) {
super(script);
}
/**
* Adds a call expression.
*
* @param call
* is the new call
*/
public void addCall(TemplateCallExpression call) {
if (calls.size() > 0) {
TemplateCallExpression last = (TemplateCallExpression) calls.get(calls.size() - 1);
last.setNextCall(call);
}
calls.add(call);
call.setParent(this);
}
/**
* Gets the first call of the set, or null is the set is empty.
*
* @return the first call of the set, or null
*/
public TemplateCallExpression getFirst() {
if (calls.size() > 0) {
return (TemplateCallExpression) calls.get(0);
} else {
return null;
}
}
/**
* Gets an iterator for the calls.
*
* @return an iterator for the calls
*/
public Iterator iterator() {
return calls.iterator();
}
/**
* Indicates if this set is a predefined link.
* <p>
* Samples:
* <li>i()</li>
* <li>args(?)</li>
* <li>startUserCode</li>
* <li>endUserCode</li>
*
* @return true if this set is a predefined link
*/
public boolean isPredefined() {
boolean predefined = false;
if (this.calls.size() > 0) {
TemplateCallExpression call = (TemplateCallExpression) calls.get(0);
if (call.link.equals(TemplateConstants.LINK_NAME_INDEX) && call.arguments.size() == 0 && "".equals(call.getPrefix())) {
return true;
} else if (call.link.equals(TemplateConstants.LINK_NAME_ARGS) && call.arguments.size() == 1 && "".equals(call.getPrefix())) {
predefined = true;
} else if (call.link.equals(TemplateConstants.USER_BEGIN_NAME) && call.arguments.size() == 0) {
if (parent instanceof TemplateFeatureStatement) {
predefined = true;
}
} else if (call.link.equals(TemplateConstants.USER_END_NAME) && call.arguments.size() == 0) {
if (parent instanceof TemplateFeatureStatement) {
predefined = true;
}
}
}
return predefined;
}
/* (non-Javadoc) */
@Override
public ENode evaluate(ENode current, IScript script, LaunchManager mode) throws ENodeException, FactoryException {
script.contextPush(IScript.CURRENT_NODE, current);
try {
Iterator calls = this.calls.iterator();
if (calls.hasNext()) {
TemplateCallExpression call = (TemplateCallExpression) calls.next();
// Predefined links
boolean predefined = false;
if (call.link.equals(TemplateConstants.LINK_NAME_INDEX) && call.arguments.size() == 0 && "".equals(call.getPrefix())) {
Integer index = (Integer) script.contextPeek(IScript.WHILE_INDEX);
if (index == null) {
index = new Integer(0);
}
current = new ENode(index.intValue(), current);
predefined = true;
} else if (call.link.equals(TemplateConstants.LINK_NAME_ARGS) && call.arguments.size() == 1 && "".equals(call.getPrefix())) {
ENode[] templateArgs = (ENode[]) script.contextPeek(IScript.TEMPLATE_ARGS);
if (templateArgs == null) {
templateArgs = new ENode[] {};
}
ENode index = ((TemplateExpression) call.arguments.get(0)).evaluate(current, script, mode);
try {
int i = index.getInt();
if (i < templateArgs.length) {
current = templateArgs[i];
predefined = true;
} else {
throw new ENodeException(
AcceleoGenMessages.getString("TemplateCallSetExpression.UnresolvedArgument", new Object[] { Integer.toString(i), }), call.getPos(), script, current, true); //$NON-NLS-1$
}
} catch (ENodeCastException e) {
throw new ENodeException(AcceleoGenMessages.getString("TemplateCallSetExpression.InvalidArgument"), call.getPos(), script, current, true); //$NON-NLS-1$
}
} else if (call.link.equals(TemplateConstants.USER_BEGIN_NAME) && call.arguments.size() == 0) {
current = new ENode(MergeTools.DEFAULT_USER_BEGIN, current);
predefined = true;
} else if (call.link.equals(TemplateConstants.USER_END_NAME) && call.arguments.size() == 0) {
current = new ENode(MergeTools.DEFAULT_USER_END, current);
predefined = true;
}
if (predefined) {
if (calls.hasNext()) {
call = (TemplateCallExpression) calls.next();
} else {
return current;
}
}
// Dynamic links
ENode first = call.evaluate(current, script, mode);
current = first;
while (calls.hasNext()) {
call = (TemplateCallExpression) calls.next();
current = call.evaluate(current, script, mode);
}
// Put linked object
if (!predefined) {
if (current.isString() && first.isEObject() && !first.isContainment()) {
try {
ENode node = new ENode("", first); //$NON-NLS-1$
if (node.getTextModelMapping() != null) {
node.getTextModelMapping().linkBegin(first.getEObject());
}
node.append(current);
if (node.getTextModelMapping() != null) {
node.getTextModelMapping().linkEnd();
}
current = node;
} catch (ENodeCastException e) {
// Never catch
}
}
if (first.isOptional()) {
current.setOptional(true);
}
}
}
return current;
} finally {
script.contextPop(IScript.CURRENT_NODE);
}
}
/* (non-Javadoc) */
@Override
public String toString() {
StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$
Iterator calls = this.calls.iterator();
while (calls.hasNext()) {
TemplateCallExpression call = (TemplateCallExpression) calls.next();
buffer.append(call.toString());
if (calls.hasNext()) {
buffer.append(TemplateConstants.CALL_SEP);
}
}
return buffer.toString();
}
/* (non-Javadoc) */
public static TemplateExpression fromString(String buffer, Int2 limits, IScript script) throws TemplateSyntaxException {
Int2 trim = TextSearch.getDefaultSearch().trim(buffer, limits.b(), limits.e());
if (trim.b() == -1) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.MissingElement"), script, limits); //$NON-NLS-1$
} else {
limits = trim;
}
Int2[] positions = TextSearch.getDefaultSearch().splitPositionsIn(buffer, limits.b(), limits.e(), new String[] { TemplateConstants.CALL_SEP }, false, TemplateConstants.SPEC,
TemplateConstants.INHIBS_EXPRESSION);
TemplateCallSetExpression expression = new TemplateCallSetExpression(script);
expression.setPos(limits);
for (Int2 pos : positions) {
expression.addCall((TemplateCallExpression) TemplateCallExpression.fromString(buffer, pos, script));
}
return expression;
}
/**
* Gets the root resolver for this link : EClassifier for the block
* container like "for" and "script".
*
* @param defaultRoot
* is the default container for the current template
* @param gen
* is the script
* @return the root resolver for this link
*/
public Object getRootResolver(Object defaultRoot, IScript gen) {
TemplateElement parent = getParent();
TemplateElement current = this;
boolean inForBlock = false;
while (parent != null) {
if (parent instanceof Template && parent.getParent() instanceof TemplateForStatement) {
inForBlock = true;
} else if (parent instanceof TemplateForStatement) {
if (inForBlock) {
TemplateExpression forCondition = ((TemplateForStatement) parent).getCondition();
List testElements = forCondition.getAllElements(TemplateCallSetExpression.class);
if (testElements.size() > 0) {
TemplateCallSetExpression firstCallSet = (TemplateCallSetExpression) testElements.get(0);
if (firstCallSet != null) {
Object resolvedType = firstCallSet.getRootResolver(defaultRoot, gen);
Iterator calls = firstCallSet.iterator();
while (resolvedType != null && calls.hasNext()) {
TemplateCallExpression call = (TemplateCallExpression) calls.next();
resolvedType = gen.resolveType(resolvedType, call, 0);
}
return resolvedType;
}
}
}
} else if (parent instanceof TemplateCallExpression && ((TemplateCallExpression) parent).filter == current && parent.getParent() instanceof TemplateCallSetExpression) {
TemplateCallSetExpression callSet = (TemplateCallSetExpression) parent.getParent();
Object resolvedType = callSet.getRootResolver(defaultRoot, gen);
Iterator calls = callSet.iterator();
while (resolvedType != null && calls.hasNext()) {
TemplateCallExpression call = (TemplateCallExpression) calls.next();
resolvedType = gen.resolveType(resolvedType, call, 0);
if (call == parent) {
break;
}
}
return resolvedType;
}
current = parent;
parent = parent.getParent();
}
return defaultRoot;
}
}