blob: 35bfe06f07e9305221aa865c27bc9424ec8da88c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004-2008 Peter Pasztor, Akos Horvath, Gergely Varro, Istvan Rath and Daniel Varro
* 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:
* Peter Pasztor, Akos Horvath, Gergely Varro, Istvan Rath - initial API and implementation
*******************************************************************************/
package org.eclipse.viatra2.gtasm.interpreter.impl.rules;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Hashtable;
import org.eclipse.emf.common.util.EList;
import org.eclipse.viatra2.errors.VPMRuntimeException;
import org.eclipse.viatra2.gtasm.interpreter.exception.ASMInterpreterErrorStrings;
import org.eclipse.viatra2.gtasm.interpreter.exception.ViatraTransformationException;
import org.eclipse.viatra2.gtasm.interpreter.executionEnvironment.IExecutionEnvironment;
import org.eclipse.viatra2.gtasm.interpreter.impl.executionEnvironment.CallRuleExecutionEnvironment;
import org.eclipse.viatra2.gtasm.interpreter.impl.machine.ASMInterpreterException;
import org.eclipse.viatra2.gtasm.interpreter.term.rules.JavaNativeValue;
import org.eclipse.viatra2.gtasm.interpreter.term.rules.TermEvaluator;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.compoundRules.IterateRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.core.RuntimeAnnotation;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.Rule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.SymbolicRuleParameter;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.definitions.Variable;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.DirectionKind;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.LogLevel;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.enums.ValueKind;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.ASMRuleInvocation;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.CallRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.FailRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.LogRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.PrintLnRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.PrintRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.simpleRules.SkipRule;
import org.eclipse.viatra2.gtasmmodel.gtasm.metamodel.asm.terms.VariableReference;
import org.eclipse.viatra2.interpreters.IProgressReport;
public class BasicRuleInterpreter extends RuleInterpreter {
private static BasicRuleInterpreter _instance = new BasicRuleInterpreter();
private BasicRuleInterpreter()
{
}
public static BasicRuleInterpreter getInstance() {
return _instance;
}
@Override
public Boolean interpretRule(IExecutionEnvironment executionEnvironment, ASMRuleInvocation ruleToBeInterpreted, IProgressReport pr)
throws ViatraTransformationException
{
if(ruleToBeInterpreted instanceof SkipRule)
{
return Boolean.TRUE;
}
else if(ruleToBeInterpreted instanceof FailRule)
{
return Boolean.FALSE;
}
else if(ruleToBeInterpreted instanceof PrintLnRule)
{
//codeout.codeOut(""+org.eclipse.viatra2.gtasm.interpreter.executionEnvironment.getTermEvaluator().evaluate(org.eclipse.viatra2.gtasm.interpreter.executionEnvironment,((PrintLnRule)ruleToBeInterpreted).getOut())+"\n");
PrintLnRule r = (PrintLnRule)ruleToBeInterpreted;
String s = ""+TermEvaluator.getInstance().evaluate(executionEnvironment,r.getOut())+System.getProperty("line.separator");
try
{
if (r.getBuffer()!=null)
{
// buffer is specified
Writer w = (Writer) ((JavaNativeValue)TermEvaluator.getInstance().evaluate(executionEnvironment,r.getBuffer())).getValue();
w.write(s);
//w.flush();
}
else
{
// print to default output
codeout.codeOut(s);
}
}
catch (VPMRuntimeException e) {
String[] context = {e.getMessage()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.CODEOUT_ERROR
,context
,r);
} catch (IOException e) {
String[] context = {e.getMessage()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.CODEOUT_ERROR
,context
,r);
}
return Boolean.TRUE;
}
else if(ruleToBeInterpreted instanceof PrintRule)
{
PrintRule r = (PrintRule)ruleToBeInterpreted;
String s = ""+TermEvaluator.getInstance().evaluate(executionEnvironment,r.getOut());
try
{
if (r.getBuffer()!=null)
{
// buffer is specified
Object obj = TermEvaluator.getInstance().evaluate(executionEnvironment,r.getBuffer());
if(obj instanceof JavaNativeValue)
{
Object jNativeValueObj = ((JavaNativeValue)obj).getValue();
if(jNativeValueObj instanceof Writer)
{
Writer w = (Writer) jNativeValueObj;
w.write(s);
}
else
{
String[] context = {jNativeValueObj.toString()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.PRINTRULE_NOBUFFER
,context
,r);
}
}
else
{
String[] context = {obj.toString()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.PRINTRULE_NOBUFFER
,context
,r);
}
}
else
{
// print to default output
codeout.codeOut(s);
}
}
catch (VPMRuntimeException e) {
String[] context = {e.getMessage()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.CODEOUT_ERROR
,context
,r);
} catch (IOException e) {
String[] context = {e.getMessage()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.CODEOUT_ERROR
,context
,r);
}
return Boolean.TRUE;
}
else if(ruleToBeInterpreted instanceof CallRule)
{
// Needs new, clean execution environment
CallRule callRule = (CallRule)ruleToBeInterpreted;
Rule calledASMRule = callRule.getRule();
EList<SymbolicRuleParameter> symParams = calledASMRule.getSymParameters();
CallRuleExecutionEnvironment callRuleExecutionEnvironment=
new CallRuleExecutionEnvironment(executionEnvironment.getFramework(),
calledASMRule);
Hashtable<Variable, Object> symVarBindings=new Hashtable<Variable, Object>();
Hashtable<Variable, Variable> outVarBindings=new Hashtable<Variable, Variable>();
// Variable vector to check for any inout or out parameters that reference the same variable
ArrayList<Variable> outandInoutVariables=new ArrayList<Variable>();
// Binding the symbolic variables. Need to evaluate them before running the actual rule.
for (int i=0;i<callRule.getActualParameters().size();i++)
{
// Bind the symbolic variables
Object evaluatedValue =TermEvaluator.getInstance().
evaluate(executionEnvironment,
callRule.getActualParameters().get(i));
SymbolicRuleParameter symbolicRuleParameter = symParams.get(i);
Variable symbolicVariable = symbolicRuleParameter.getVariable();
//if it is an OutPut variable it means then an undef must be passed rather than its actual value
if(symbolicRuleParameter.getDirection().equals(DirectionKind.OUT_LITERAL))
{
symVarBindings.put(symbolicVariable , ValueKind.UNDEF_LITERAL);
}
else
{symVarBindings.put(symbolicVariable, evaluatedValue);}
// If not an IN parameter, it must be a variable
if(!symbolicRuleParameter.getDirection().equals(DirectionKind.IN_LITERAL))
{
if(callRule.getActualParameters().get(i) instanceof VariableReference)
{
Variable actualVariable = ((VariableReference)callRule.getActualParameters().get(i)).getVariable();
outVarBindings.put(symbolicVariable,actualVariable)
;
// If it contains the variable, there is an error, since it has already been referenced as an inout or out variable
if(outandInoutVariables.contains(actualVariable))
{
String[] context = {actualVariable.getName(),symbolicRuleParameter.getDirection().toString()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.ASMRULE_PARAM_OUT_INOUT_MULTIPLE_REF
,context
,callRule);
// ,callRule.getRule());
// e.addNewStackElement(callRule);
}
else
outandInoutVariables.add(((VariableReference)callRule.getActualParameters().get(i)).getVariable());
}
else
{
String[] context = {symbolicVariable.getName(),symbolicRuleParameter.getDirection().toString(),callRule.getRule().getName()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.ASMRULE_PARAM_IN_INOUT_NOT_VARREF
,context
,callRule);
}
}
else if(ValueKind.UNDEF_LITERAL.equals(evaluatedValue)) // All in parameters must be bound! (inout parameters must be variables)
{
String[] context = {symbolicRuleParameter.getName(),callRule.getRule().getName()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.ASMRULE_PARAM_IN_NOT_BOUND
,context
,callRule);
}
}
boolean isNative = false;
//Checks for the "native" annotation
for (Object annot : calledASMRule.getRuntimeAnnotations()) {
if ("@native".equals(((RuntimeAnnotation) annot).getAnnotationName().toLowerCase())) {
isNative = true; break;
}
}
Boolean result=Boolean.FALSE;
callRuleExecutionEnvironment.onBegin(symVarBindings);
if(isNative) //Native ASM Rule
{
result = NativeASMRuleInterpreter.getInstance().executeNativeASMRule(callRuleExecutionEnvironment, symVarBindings, callRule);
}
else
{//Normal ASM rule
try {
result= RuleInterpreter.getInstance().interpretRule(callRuleExecutionEnvironment,calledASMRule.getBody(), pr);
} catch (ViatraTransformationException e) {
//throw e.addNewStackElement(((CallRule)ruleToBeInterpreted).getRule());
throw e.addNewStackElement(callRule.getRule()).addNewStackElement(callRule);
}
// If the rule failed, we have to restore the previous state. -> we don't have to write the values of the
// variables back to the current execution environment
if(result)
{
symVarBindings=(Hashtable<Variable, Object>)callRuleExecutionEnvironment.onTerminate();
// Getting the values back from the execution environment. Only for parameters with OUT or INOUT directions.
for (int i=0;i<callRule.getActualParameters().size();i++) {
if(!(symParams.get(i)).getDirection().equals(DirectionKind.IN_LITERAL))
{
Variable _sym=(symParams.get(i)).getVariable();
outVarBindings.put(_sym,((VariableReference)callRule.getActualParameters().get(i)).getVariable());
}
}
}
// Putting the changed variables back to the original environment
for (Object symbolicVariableOut : outVarBindings.keySet()) {
try {
executionEnvironment.setVariableValue(outVarBindings.get(symbolicVariableOut), symVarBindings.get(symbolicVariableOut));
} catch (ViatraTransformationException e) {
String[] context = {((Variable)symbolicVariableOut).getName(),callRule.getRule().getName(),e.getMessage()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.SET_VAR_VALUE_AFTER_ASMRULE_CALL
,context
,callRule);
}
}
}
return result;
}
else if(ruleToBeInterpreted instanceof IterateRule)
{
while(RuleInterpreter.getInstance().interpretRule(executionEnvironment, ((IterateRule)ruleToBeInterpreted).getBody(),pr));
return Boolean.TRUE;
}
else if(ruleToBeInterpreted instanceof LogRule)
{
String msg = ""+(TermEvaluator.getInstance().evaluate(executionEnvironment,((LogRule)ruleToBeInterpreted).getOut()));
switch(((LogRule)ruleToBeInterpreted).getLevel().getValue())
{
case LogLevel.INFO:
log.info(msg);
break;
case LogLevel.DEBUG:
log.debug(msg);
break;
case LogLevel.WARNING:
log.warning(msg);
break;
case LogLevel.ERROR:
log.error(msg);
break;
case LogLevel.FATAL:
log.fatal(msg);
break;
default:
log.fatal(msg);
break;
}
return Boolean.TRUE;
}
String[] context = {ruleToBeInterpreted.getName()};
throw new ASMInterpreterException(ASMInterpreterErrorStrings.RULE_UNIMPL
,context
,ruleToBeInterpreted);
//return Boolean.FALSE;
}
}