/* * <copyright> * * Copyright (c) 2005-2006 Sven Efftinge and others. * 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: * Sven Efftinge - Initial API and implementation * * </copyright> */ package org.eclipse.gmf.internal.xpand.xtend.ast; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.Stack; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.gmf.internal.xpand.expression.AnalysationIssue; import org.eclipse.gmf.internal.xpand.expression.ExecutionContext; import org.eclipse.gmf.internal.xpand.expression.Variable; import org.eclipse.gmf.internal.xpand.expression.ast.DeclaredParameter; import org.eclipse.gmf.internal.xpand.expression.ast.Expression; import org.eclipse.gmf.internal.xpand.expression.ast.Identifier; import org.eclipse.gmf.internal.xpand.migration.ExpressionAnalyzeTrace; public class ExpressionExtensionStatement extends Extension { private final Expression expression; public ExpressionExtensionStatement(final int start, final int end, final int line, final int startOffset, final int endOffset, final Identifier name, final Identifier returnType, final List<DeclaredParameter> formalParameters, final Expression expression, final boolean cached, final boolean isPrivate) { super(start, end, line, startOffset, endOffset, name, returnType, formalParameters, cached, isPrivate); this.expression = expression; } public Expression getExpression() { return expression; } private final Stack<List<EClassifier>> analyzations = new Stack<List<EClassifier>>(); private final Stack<List<Object>> evaluations = new Stack<List<Object>>(); @Override public Object evaluateInternal(final Object[] parameters, final ExecutionContext ctx) { final List<Object> params = Arrays.asList(parameters); if (!evaluations.contains(params)) { evaluations.push(params); try { return evaluateInternal2(parameters, ctx); } finally { evaluations.pop(); } } else { throw new RuntimeException("Infinite recursion in '" + toString() + "'"); } } protected Object evaluateInternal2(final Object[] parameters, ExecutionContext ctx) { ctx = ctx.cloneWithoutVariables(); ctx = ctx.cloneWithResource(file); final List<String> paramNames = getParameterNames(); for (int i = 0, x = paramNames.size(); i < x; i++) { final String name = paramNames.get(i); ctx = ctx.cloneWithVariable(new Variable(name, parameters[i])); } return expression.evaluate(ctx); } @Override public void analyzeInternal(final ExecutionContext ctx, final Set<AnalysationIssue> issues) { EClassifier expressionType = expression.analyze(ctx, issues); createAnalyzeTrace(ctx, new ExpressionAnalyzeTrace(getReturnTypeIdentifier() != null ? ctx.getTypeForName(getReturnTypeIdentifier().getValue()) : expressionType)); } @Override protected EClassifier internalGetReturnType(final EClassifier[] parameters, final ExecutionContext ctx, final Set<AnalysationIssue> issues) { if (getReturnTypeIdentifier() != null) { return ctx.getTypeForName(getReturnTypeIdentifier().getValue()); } if ((parameters == null) || (parameters.length != getParameterNames().size())) { return null; } final List<EClassifier> params = Arrays.asList(parameters); if (!analyzations.contains(params)) { analyzations.push(params); try { return analyzeInternal(parameters, ctx, issues); } finally { analyzations.pop(); } } else { if (returnType == null) { issues.add(new AnalysationIssue(AnalysationIssue.Type.INTERNAL_ERROR, "Recursive extensions need to have a return type specified!", this)); return null; } return ctx.getTypeForName(returnType.getValue()); } } protected EClassifier analyzeInternal(final EClassifier[] parameters, ExecutionContext ctx, final Set<AnalysationIssue> issues) { ctx = ctx.cloneWithoutVariables(); ctx = ctx.cloneWithResource(file); final List<String> paramNames = getParameterNames(); for (int i = 0, x = paramNames.size(); i < x; i++) { final String name = paramNames.get(i); final EClassifier t = parameters[i]; ctx = ctx.cloneWithVariable(new Variable(name, t)); } return expression.analyze(ctx, issues); } }