blob: b52c90f29c54e5d7d5cb9e3bdc6dbf269331c210 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 R.Dvorak and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Radek Dvorak - initial API and implementation
*******************************************************************************/
package org.eclipse.m2m.qvt.oml.debug.core.vm;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.m2m.internal.qvt.oml.QvtMessage;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalAstWalker;
import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation;
import org.eclipse.m2m.internal.qvt.oml.expressions.ObjectExp;
import org.eclipse.m2m.internal.qvt.oml.expressions.ResolveExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.BlockExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ComputeExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ForExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ImperativeIterateExp;
import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.VariableInitExp;
import org.eclipse.ocl.ecore.Variable;
import org.eclipse.ocl.expressions.IterateExp;
import org.eclipse.ocl.expressions.IteratorExp;
import org.eclipse.ocl.expressions.LetExp;
import org.eclipse.ocl.expressions.LoopExp;
import org.eclipse.ocl.utilities.Visitable;
class ASTElementContextEnv extends QvtOperationalEnv {
private final class EnvVariableCollector extends QvtOperationalAstWalker {
private final EObject astContext;
private final List<Variable> varStack;
private final List<Variable> result;
private EnvVariableCollector(EObject astContext) {
// use NOP external node processor, we need to customize the
// visiting protocol
super(
new NodeProcessor() {
public void process(Visitable e, Visitable parent) {
// do nothing
}
});
this.astContext = astContext;
this.varStack = new ArrayList<Variable>();
this.result = new ArrayList<Variable>();
}
List<Variable> getVariables() {
return result;
}
protected void doProcess(Visitable e, Visitable parent) {
if (e == astContext) {
result.addAll(varStack);
}
if (!result.isEmpty()) {
// preserve the env collected so far
return;
}
if (e != null) {
getNodeProcessor().process(e, parent);
e.accept(this);
}
}
@Override
public Object visitVariableInitExp(VariableInitExp variableInitExp) {
Variable var = variableInitExp.getReferredVariable();
varStack.add(var);
Object result = super.visitVariableInitExp(variableInitExp);
// Note: no remove is needed, the scope handling for BlockExp
// will handle that
return result;
}
@Override
public Object visitLetExp(LetExp<EClassifier, EParameter> letExp) {
org.eclipse.ocl.expressions.Variable<EClassifier, EParameter> var = letExp
.getVariable();
varStack.add((Variable) var);
Object result = super.visitLetExp(letExp);
varStack.remove((Variable) var);
return result;
}
@Override
public Object visitObjectExp(ObjectExp objectExp) {
Variable var = objectExp.getReferredObject();
varStack.add((Variable) var);
Object result = super.visitObjectExp(objectExp);
varStack.remove((Variable) var);
return result;
}
@Override
public Object visitResolveExp(ResolveExp resolveExp) {
Variable var = resolveExp.getTarget();
if (var != null) {
varStack.add(var);
}
Object result = super.visitResolveExp(resolveExp);
if (var != null) {
varStack.remove(var);
}
return result;
}
@Override
public Object visitIteratorExp(
IteratorExp<EClassifier, EParameter> callExp) {
addVars(varStack, callExp);
Object result = super.visitIteratorExp(callExp);
removeVars(varStack, callExp);
return result;
}
@Override
public Object visitIterateExp(
IterateExp<EClassifier, EParameter> callExp) {
addVars(varStack, callExp);
Object result = super.visitIterateExp(callExp);
removeVars(varStack, callExp);
return result;
}
@Override
public Object visitForExp(ForExp forExp) {
addVars(varStack, forExp);
Object result = super.visitForExp(forExp);
removeVars(varStack, forExp);
return result;
}
@Override
public Object visitImperativeIterateExp(
ImperativeIterateExp imperativeIterateExp) {
addVars(varStack, imperativeIterateExp);
Object result = super
.visitImperativeIterateExp(imperativeIterateExp);
removeVars(varStack, imperativeIterateExp);
return result;
}
@Override
public Object visitBlockExp(BlockExp blockExp) {
List<Variable> saveVarStack = new ArrayList<Variable>(varStack);
Object result = super.visitBlockExp(blockExp);
varStack.clear();
varStack.addAll(saveVarStack);
return result;
}
@Override
public Object visitComputeExp(ComputeExp computeExp) {
Variable var = computeExp.getReturnedElement();
if (var != null) {
varStack.add(var);
}
Object result = super.visitComputeExp(computeExp);
if (var != null) {
varStack.remove(var);
}
return result;
}
private void removeVars(final List<Variable> varStack,
LoopExp<EClassifier, EParameter> itExp) {
for (org.eclipse.ocl.expressions.Variable<EClassifier, EParameter> iter : itExp
.getIterator()) {
varStack.remove((Variable) iter);
}
}
private void addVars(final List<Variable> varStack,
LoopExp<EClassifier, EParameter> itExp) {
for (org.eclipse.ocl.expressions.Variable<EClassifier, EParameter> iter : itExp
.getIterator()) {
varStack.add((Variable) iter);
}
}
}
private StringBuilder fErrors = new StringBuilder();
ASTElementContextEnv(QvtOperationalEnv parent, EObject astElement) {
super(parent);
initializeContextVariables(astElement);
}
StringBuilder getErrorTxtBuffer() {
return fErrors;
}
@Override
public boolean hasErrors() {
return fErrors.length() > 0;
}
@Override
public QvtMessage reportError(String message, int startOffset, int endOffset) {
// do not propagate fErrors to the root environment
fErrors.append(message).append('\n');
return null;
}
@Override
public QvtMessage reportWarning(String message, int startOffset, int endOffset) {
// not important
return null;
}
private void initializeContextVariables(final EObject astContext) {
EnvVariableCollector varCollector = new EnvVariableCollector(astContext);
EOperation contextOperation = this.getContextOperation();
if(contextOperation instanceof ImperativeOperation) {
varCollector.visitImperativeOperation((ImperativeOperation) contextOperation);
}
List<Variable> variables = varCollector.getVariables();
if (!variables.isEmpty()) {
for (Variable variable : variables) {
String name = variable.getName();
boolean isExplicit = !name.startsWith(QvtOperationalEnv.GENERATED_NAME_SPECIAL_PREFIX);
this.addElement(name, variable, isExplicit);
}
}
}
}