blob: 2e6e994354120338ab7403e4a235b827ce5eb3bb [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.TemplateConstants;
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.ENodeIterator;
import org.eclipse.sirius.query.legacy.gen.template.eval.ENodeList;
import org.eclipse.sirius.query.legacy.gen.template.eval.LaunchManager;
import org.eclipse.sirius.query.legacy.gen.template.scripts.IScript;
import org.eclipse.sirius.query.legacy.tools.strings.Int2;
import org.eclipse.sirius.query.legacy.tools.strings.TextSearch;
/**
* This is a variable call expression for the generation tool. It is a kind of
* expression. A variable call can be a link of the model or a java service.
* Between the brackets after a java service name, there is a list of arguments.
* Each argument is an expression. The argument list is a sequence of entries,
* each separated from the next by a comma. Syntactically, a service call
* expression is an open parenthesis followed by one or more expressions
* followed by a close parenthesis. The remaining expressions are all evaluated
* and their values are the arguments to the service.
*
*
*/
public class TemplateCallExpression extends TemplateExpression {
/**
* The called link that is a template, a link of the model or a java service
* name.
*/
protected String link;
/**
* The prefix to filter a template, a link of the model or a java service.
*/
protected String prefix;
/**
* Between the parenthesis after a java service name or a template name,
* there is a list of arguments. Each argument is an expression. The
* remaining expressions are all evaluated and their values are the
* arguments to the service.
*/
protected List arguments = new ArrayList();
/**
* Between the brackets after a java service name or a template name, there
* is a filter.
*/
protected TemplateExpression filter = null;
/**
* It's the next variable call expression for the current statement.
*/
protected TemplateCallExpression nextCall = null;
/**
* Constructor.
*
* @param link
* is a link of the model or a java service name
* @param script
* is the script
*/
public TemplateCallExpression(String link, IScript script) {
super(script);
if (link != null) {
final int iDot = link.indexOf(TemplateConstants.LINK_PREFIX_SEPARATOR);
if (iDot > -1) {
this.prefix = link.substring(0, iDot).trim();
this.link = link.substring(iDot + TemplateConstants.LINK_PREFIX_SEPARATOR.length()).trim();
} else {
this.prefix = ""; //$NON-NLS-1$
this.link = link.trim();
}
} else {
this.prefix = ""; //$NON-NLS-1$
this.link = ""; //$NON-NLS-1$
}
}
/**
* @return the called link
*/
public String getLink() {
return link;
}
/**
* @return the prefix
*/
public String getPrefix() {
return prefix;
}
/**
* @return the next variable call expression for the current statement
*/
public TemplateCallExpression getNextCall() {
return nextCall;
}
/**
* @param next
* is the next variable call expression for the current statement
*/
public void setNextCall(TemplateCallExpression nextCall) {
this.nextCall = nextCall;
}
/**
* @return the arguments
*/
public List getArguments() {
return arguments;
}
/**
* @return the filter
*/
public TemplateExpression getFilter() {
return filter;
}
/**
* @param filter
* is the filter
*/
public void setFilter(TemplateExpression filter) {
this.filter = filter;
this.filter.setParent(this);
}
/**
* Adds an argument expression for the service.
*
* @param expression
* is the new argument
*/
public void addArgument(TemplateExpression expression) {
arguments.add(expression);
expression.setParent(this);
}
/**
* Counts the arguments.
*
* @return the number of arguments
*/
public int countArguments() {
return arguments.size();
}
/**
* Gets the first argument.
*
* @return the first argument
*/
public TemplateExpression getFirstArgument() {
if (arguments.size() > 0) {
return (TemplateExpression) arguments.get(0);
} else {
return null;
}
}
/**
* Now, the next evaluation will be ignored.
*/
public void ignoreNextEval() {
ignoreNextEval = true;
}
private boolean ignoreNextEval = false;
/* (non-Javadoc) */
@Override
public ENode evaluate(ENode current, IScript script, LaunchManager mode) throws ENodeException, FactoryException {
ENode result = evaluateSub(current, script, mode);
if (filter != null) {
result = select(result);
}
return result;
}
private ENode evaluateSub(ENode current, IScript script, LaunchManager mode) throws ENodeException, FactoryException {
// Ignore?
if (ignoreNextEval) {
ignoreNextEval = false;
return current;
} else {
ENode argCurrent = (ENode) script.contextPeek(IScript.CURRENT_NODE);
if (argCurrent == null) {
argCurrent = current;
}
if (link.length() == 0) {
if (arguments.size() == 1) {
final TemplateExpression arg = (TemplateExpression) arguments.get(0);
return arg.evaluate(argCurrent, script, mode);
} else if (arguments.size() > 1) {
final ENodeList result = new ENodeList();
final Iterator arguments = this.arguments.iterator();
while (arguments.hasNext()) {
final TemplateExpression arg = (TemplateExpression) arguments.next();
final ENode argEval = arg.evaluate(argCurrent, script, mode);
result.add(argEval);
}
return new ENode(result, current);
} else {
return new ENode(ENode.EMPTY, current);
}
} else {
// Arguments
final List argList = new ArrayList();
final Iterator arguments = this.arguments.iterator();
while (arguments.hasNext()) {
final TemplateExpression arg = (TemplateExpression) arguments.next();
final ENode argEval = arg.evaluate(argCurrent, script, mode);
argList.add(argEval);
}
// Call the script or the service
final ENode[] args = (ENode[]) argList.toArray(new ENode[argList.size()]);
// Specific strategy
ENode result = null;
final IScript[] specifics = script.goToSpecifics();
if (specifics != null && specifics.length > 0) {
ENodeException.disableRuntimeMarkersFor(this);
try {
for (int i = 0; result == null && i < specifics.length; i++) {
final IScript specific = specifics[i];
try {
result = specific.eGet(this, current, args, mode, false);
} catch (final ENodeException e) {
// result = null;
}
}
} finally {
ENodeException.enableRuntimeMarkersFor(this);
}
}
if (result == null) {
result = script.eGet(this, current, args, mode, true);
}
if (result == null) {
throw new ENodeException(AcceleoGenMessages.getString("TemplateCallExpression.UnresolvedCall", new Object[] { getLink(), }), pos, script, current, true); //$NON-NLS-1$
}
return result;
}
}
}
private ENode select(ENode current) throws FactoryException {
// ASSERT filter != null
if (current.isList()) {
final ENodeList res = new ENodeList();
try {
final ENodeList list = current.getList();
final ENodeIterator it = list.iterator();
while (it.hasNext()) {
res.add(select(it.next()));
}
} catch (final ENodeCastException e) {
// Never catch
}
return new ENode(res, current);
} else {
script.contextPush(IScript.CURRENT_NODE, current);
script.contextPush(IScript.TEMPLATE_NODE, current);
try {
final ENode result = filter.evaluate(current, script, LaunchManager.create("run", true)); //$NON-NLS-1$
final Object boolValue = result.getAdapterValue(boolean.class);
if (boolValue instanceof Boolean && ((Boolean) boolValue).booleanValue()) {
return current;
} else {
return new ENode(ENode.EMPTY, current);
}
} catch (final ENodeException e) {
return new ENode(ENode.EMPTY, current);
} catch (final ENodeCastException e) {
return new ENode(ENode.EMPTY, current);
} finally {
script.contextPop(IScript.CURRENT_NODE);
script.contextPop(IScript.TEMPLATE_NODE);
}
}
}
/* (non-Javadoc) */
@Override
public String toString() {
final StringBuffer buffer = new StringBuffer();
if (prefix != null && prefix.length() > 0) {
buffer.append(prefix);
buffer.append(TemplateConstants.LINK_PREFIX_SEPARATOR);
}
buffer.append(link);
if (this.arguments.size() > 0) {
buffer.append(TemplateConstants.PARENTH[0]);
final Iterator arguments = this.arguments.iterator();
while (arguments.hasNext()) {
final TemplateExpression argument = (TemplateExpression) arguments.next();
buffer.append(argument.toString());
if (arguments.hasNext()) {
buffer.append(TemplateConstants.ARG_SEP);
}
}
buffer.append(TemplateConstants.PARENTH[1]);
}
if (this.filter != null) {
buffer.append(TemplateConstants.BRACKETS[0]);
buffer.append(this.filter.toString());
buffer.append(TemplateConstants.BRACKETS[1]);
}
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;
}
TemplateExpression filter = null;
Int2 begin = TextSearch.getDefaultSearch().indexIn(buffer, TemplateConstants.BRACKETS[0], limits.b(), limits.e(), TemplateConstants.SPEC,
new String[][] { TemplateConstants.LITERAL, TemplateConstants.PARENTH });
if (begin.b() > -1) {
final Int2 end = TextSearch.getDefaultSearch().blockIndexEndIn(buffer, TemplateConstants.BRACKETS[0], TemplateConstants.BRACKETS[1], begin.b(), limits.e(), false, TemplateConstants.SPEC,
TemplateConstants.INHIBS_EXPRESSION);
if (end.b() == -1) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.MissingCloseBracket"), script, begin.b()); //$NON-NLS-1$
}
if (buffer.substring(end.e(), limits.e()).trim().length() > 0) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.InvalidSequence"), script, end.e()); //$NON-NLS-1$
}
final Int2 pos = new Int2(begin.e(), end.b());
filter = TemplateExpression.fromString(buffer, pos, script);
filter.setPos(pos);
limits = new Int2(limits.b(), begin.b());
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;
}
}
TemplateCallExpression expression;
begin = TextSearch.getDefaultSearch().indexIn(buffer, TemplateConstants.PARENTH[0], limits.b(), limits.e(), TemplateConstants.SPEC, new String[][] { TemplateConstants.LITERAL });
if (begin.b() > -1) {
final Int2 end = TextSearch.getDefaultSearch().blockIndexEndIn(buffer, TemplateConstants.PARENTH[0], TemplateConstants.PARENTH[1], begin.b(), limits.e(), false, TemplateConstants.SPEC,
TemplateConstants.INHIBS_EXPRESSION);
if (end.b() == -1) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.MissingCloseParenthesis"), script, begin.b()); //$NON-NLS-1$
}
if (buffer.substring(end.e(), limits.e()).trim().length() > 0) {
throw new TemplateSyntaxException(AcceleoGenMessages.getString("TemplateSyntaxError.InvalidSequence"), script, end.e()); //$NON-NLS-1$
}
final Int2[] positions = TextSearch.getDefaultSearch().splitPositionsIn(buffer, begin.e(), end.b(), new String[] { TemplateConstants.ARG_SEP }, false, TemplateConstants.SPEC,
TemplateConstants.INHIBS_EXPRESSION);
expression = new TemplateCallExpression(buffer.substring(limits.b(), begin.b()), script);
expression.setPos(new Int2(limits.b(), begin.b()));
for (final Int2 pos : positions) {
expression.addArgument(TemplateExpression.fromString(buffer, pos, script));
}
} else {
expression = new TemplateCallExpression(buffer.substring(limits.b(), limits.e()), script);
expression.setPos(new Int2(limits.b(), limits.e()));
}
expression.setPos(limits);
if (filter != null) {
expression.setFilter(filter);
}
return expression;
}
}