| /******************************************************************************* |
| * 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;
|
| }
|
| }
|