package org.overture.interpreter.eval; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.intf.IQuestionAnswer; import org.overture.ast.assistant.pattern.PTypeList; import org.overture.ast.definitions.AExplicitFunctionDefinition; import org.overture.ast.definitions.AImplicitFunctionDefinition; import org.overture.ast.definitions.AMultiBindListDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.expressions.AApplyExp; import org.overture.ast.expressions.ACaseAlternative; import org.overture.ast.expressions.ACasesExp; import org.overture.ast.expressions.ADefExp; import org.overture.ast.expressions.AElseIfExp; import org.overture.ast.expressions.AExists1Exp; import org.overture.ast.expressions.AExistsExp; import org.overture.ast.expressions.AFieldExp; import org.overture.ast.expressions.AFieldNumberExp; import org.overture.ast.expressions.AForAllExp; import org.overture.ast.expressions.AFuncInstatiationExp; import org.overture.ast.expressions.AHistoryExp; import org.overture.ast.expressions.AIfExp; import org.overture.ast.expressions.AIotaExp; import org.overture.ast.expressions.AIsExp; import org.overture.ast.expressions.AIsOfBaseClassExp; import org.overture.ast.expressions.AIsOfClassExp; import org.overture.ast.expressions.ALambdaExp; import org.overture.ast.expressions.ALetBeStExp; import org.overture.ast.expressions.ALetDefExp; import org.overture.ast.expressions.AMapCompMapExp; import org.overture.ast.expressions.AMapEnumMapExp; import org.overture.ast.expressions.AMapletExp; import org.overture.ast.expressions.AMkBasicExp; import org.overture.ast.expressions.AMkTypeExp; import org.overture.ast.expressions.AMuExp; import org.overture.ast.expressions.ANarrowExp; import org.overture.ast.expressions.ANewExp; import org.overture.ast.expressions.ANilExp; import org.overture.ast.expressions.ANotYetSpecifiedExp; import org.overture.ast.expressions.APostOpExp; import org.overture.ast.expressions.APreExp; import org.overture.ast.expressions.APreOpExp; import org.overture.ast.expressions.ARecordModifier; import org.overture.ast.expressions.ASameBaseClassExp; import org.overture.ast.expressions.ASameClassExp; import org.overture.ast.expressions.ASelfExp; import org.overture.ast.expressions.ASeqCompSeqExp; import org.overture.ast.expressions.ASeqEnumSeqExp; import org.overture.ast.expressions.ASetCompSetExp; import org.overture.ast.expressions.ASetEnumSetExp; import org.overture.ast.expressions.ASetRangeSetExp; import org.overture.ast.expressions.AStateInitExp; import org.overture.ast.expressions.ASubclassResponsibilityExp; import org.overture.ast.expressions.ASubseqExp; import org.overture.ast.expressions.AThreadIdExp; import org.overture.ast.expressions.ATimeExp; import org.overture.ast.expressions.ATupleExp; import org.overture.ast.expressions.AUndefinedExp; import org.overture.ast.expressions.AVariableExp; import org.overture.ast.expressions.PExp; import org.overture.ast.intf.lex.ILexLocation; import org.overture.ast.intf.lex.ILexNameToken; import org.overture.ast.lex.Dialect; import org.overture.ast.lex.LexNameToken; import org.overture.ast.node.INode; import org.overture.ast.patterns.AIdentifierPattern; import org.overture.ast.patterns.PMultipleBind; import org.overture.ast.patterns.PPattern; import org.overture.ast.statements.AErrorCase; import org.overture.ast.types.AFieldField; import org.overture.ast.types.AFunctionType; import org.overture.ast.types.ATokenBasicType; import org.overture.ast.types.PType; import org.overture.config.Settings; import org.overture.interpreter.assistant.IInterpreterAssistantFactory; import org.overture.interpreter.debug.BreakpointManager; import org.overture.interpreter.runtime.ClassContext; import org.overture.interpreter.runtime.Context; import org.overture.interpreter.runtime.ContextException; import org.overture.interpreter.runtime.ObjectContext; import org.overture.interpreter.runtime.PatternMatchException; import org.overture.interpreter.runtime.ValueException; import org.overture.interpreter.runtime.VdmRuntime; import org.overture.interpreter.runtime.VdmRuntimeError; import org.overture.interpreter.scheduler.SharedStateListner; import org.overture.interpreter.scheduler.SystemClock; import org.overture.interpreter.values.BooleanValue; import org.overture.interpreter.values.CompFunctionValue; import org.overture.interpreter.values.FieldMap; import org.overture.interpreter.values.FunctionValue; import org.overture.interpreter.values.IntegerValue; import org.overture.interpreter.values.IterFunctionValue; import org.overture.interpreter.values.MapValue; import org.overture.interpreter.values.NameValuePair; import org.overture.interpreter.values.NameValuePairList; import org.overture.interpreter.values.NaturalValue; import org.overture.interpreter.values.NilValue; import org.overture.interpreter.values.ObjectValue; import org.overture.interpreter.values.OperationValue; import org.overture.interpreter.values.Quantifier; import org.overture.interpreter.values.QuantifierList; import org.overture.interpreter.values.RecordValue; import org.overture.interpreter.values.SeqValue; import org.overture.interpreter.values.SetValue; import org.overture.interpreter.values.TokenValue; import org.overture.interpreter.values.TupleValue; import org.overture.interpreter.values.UndefinedValue; import org.overture.interpreter.values.Value; import org.overture.interpreter.values.ValueList; import org.overture.interpreter.values.ValueMap; import org.overture.interpreter.values.ValueSet; import org.overture.interpreter.values.VoidValue; import org.overture.typechecker.assistant.pattern.PatternListTC; public class ExpressionEvaluator extends BinaryExpressionEvaluator { @Override public Value caseAApplyExp(AApplyExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); node.getLocation().setHits(node.getLocation().getHits() / 1); // This is counted below when root is evaluated try { Value object = node.getRoot().apply(VdmRuntime.getExpressionEvaluator(), ctxt).deref(); if (object instanceof FunctionValue) { ValueList argvals = new ValueList(); for (PExp arg : node.getArgs()) { argvals.add(arg.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } FunctionValue fv = object.functionValue(ctxt); return fv.eval(node.getLocation(), argvals, ctxt); } else if (object instanceof OperationValue) { ValueList argvals = new ValueList(); for (PExp arg : node.getArgs()) { argvals.add(arg.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } OperationValue ov = object.operationValue(ctxt); return ov.eval(node.getLocation(), argvals, ctxt); } else if (object instanceof SeqValue) { Value arg = node.getArgs().get(0).apply(VdmRuntime.getExpressionEvaluator(), ctxt); SeqValue sv = (SeqValue) object; return sv.get(arg, ctxt); } else if (object instanceof MapValue) { Value arg = node.getArgs().get(0).apply(VdmRuntime.getExpressionEvaluator(), ctxt); MapValue mv = (MapValue) object; return mv.lookup(arg, ctxt); } else { return VdmRuntimeError.abort(node.getLocation(), 4003, "Value " + object + " cannot be applied", ctxt); } } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } /* * Unary expressions are in the base class */ /* * Binary expressions are in the base class */ @Override public Value caseACasesExp(ACasesExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); Value val = node.getExpression().apply(VdmRuntime.getExpressionEvaluator(), ctxt); for (ACaseAlternative c : node.getCases()) { Value rv = eval(c, val, ctxt); if (rv != null) { return rv; } } if (node.getOthers() != null) { return node.getOthers().apply(VdmRuntime.getExpressionEvaluator(), ctxt); } return VdmRuntimeError.abort(node.getLocation(), 4004, "No cases apply for " + val, ctxt); } @Override public Value caseADefExp(ADefExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "def expression", ctxt); for (PDefinition d : node.getLocalDefs()) { evalContext.putList(ctxt.assistantFactory.createPDefinitionAssistant().getNamedValues(d, evalContext)); } return node.getExpression().apply(VdmRuntime.getExpressionEvaluator(), evalContext); } /** * Utility method for ACaseAlternative * * @param node * @param val * @param ctxt * @return * @throws AnalysisException */ public Value eval(ACaseAlternative node, Value val, Context ctxt) throws AnalysisException { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "case alternative", ctxt); try { evalContext.putList(ctxt.assistantFactory.createPPatternAssistant().getNamedValues(node.getPattern(), val, ctxt)); return node.getResult().apply(VdmRuntime.getExpressionEvaluator(), evalContext); } catch (PatternMatchException e) { // Silently fail (CasesExpression will try the others) } return null; } @Override public Value caseAElseIfExp(AElseIfExp node, Context ctxt) throws AnalysisException { return evalElseIf(node, node.getLocation(), node.getElseIf(), node.getThen(), ctxt); } @Override public Value caseAExists1Exp(AExists1Exp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueList allValues = null; boolean alreadyFound = false; try { allValues = ctxt.assistantFactory.createPBindAssistant().getBindValues(node.getBind(), ctxt, false); } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } for (Value val : allValues) { try { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "exists1", ctxt); evalContext.putList(ctxt.assistantFactory.createPPatternAssistant().getNamedValues(node.getBind().getPattern(), val, ctxt)); if (node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt)) { if (alreadyFound) { return new BooleanValue(false); } alreadyFound = true; } } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } catch (PatternMatchException e) { // Ignore pattern mismatches } } return new BooleanValue(alreadyFound); } @Override public Value caseAExistsExp(AExistsExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { QuantifierList quantifiers = new QuantifierList(); for (PMultipleBind mb : node.getBindList()) { ValueList bvals = ctxt.assistantFactory.createPMultipleBindAssistant().getBindValues(mb, ctxt, false); for (PPattern p : mb.getPlist()) { Quantifier q = new Quantifier(p, bvals); quantifiers.add(q); } } quantifiers.init(ctxt, true); while (quantifiers.hasNext()) { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "exists", ctxt); NameValuePairList nvpl = quantifiers.next(); boolean matches = true; for (NameValuePair nvp : nvpl) { Value v = evalContext.get(nvp.name); if (v == null) { evalContext.put(nvp.name, nvp.value); } else { if (!v.equals(nvp.value)) { matches = false; break; // This quantifier set does not match } } } if (matches && node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt)) { return new BooleanValue(true); } } } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } return new BooleanValue(false); } @Override public Value caseAFieldExp(AFieldExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); node.getField().getLocation().hit(); try { return ctxt.assistantFactory.createAFieldExpAssistant().evaluate(node, ctxt); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAFieldNumberExp(AFieldNumberExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); node.getField().getLocation().hit(); try { ValueList fields = node.getTuple().apply(VdmRuntime.getExpressionEvaluator(), ctxt).tupleValue(ctxt); Value r = fields.get((int) node.getField().getValue() - 1); if (r == null) { VdmRuntimeError.abort(node.getLocation(), 4007, "No such field in tuple: #" + node.getField(), ctxt); } return r; } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAForAllExp(AForAllExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { QuantifierList quantifiers = new QuantifierList(); for (PMultipleBind mb : node.getBindList()) { ValueList bvals = ctxt.assistantFactory.createPMultipleBindAssistant().getBindValues(mb, ctxt, false); for (PPattern p : mb.getPlist()) { Quantifier q = new Quantifier(p, bvals); quantifiers.add(q); } } quantifiers.init(ctxt, false); while (quantifiers.hasNext()) { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "forall", ctxt); NameValuePairList nvpl = quantifiers.next(); boolean matches = true; for (NameValuePair nvp : nvpl) { Value v = evalContext.get(nvp.name); if (v == null) { evalContext.put(nvp.name, nvp.value); } else { if (!v.equals(nvp.value)) { matches = false; break; // This quantifier set does not match } } } if (matches && !node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt)) { return new BooleanValue(false); } } } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } return new BooleanValue(true); } @Override public Value caseAFuncInstatiationExp(AFuncInstatiationExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { FunctionValue fv = node.getFunction().apply(VdmRuntime.getExpressionEvaluator(), ctxt).functionValue(ctxt); if (!fv.uninstantiated) { VdmRuntimeError.abort(node.getLocation(), 3034, "Function is already instantiated: " + fv.name, ctxt); } PTypeList fixed = new PTypeList(); for (PType ptype : node.getActualTypes()) { if (ptype.toString().indexOf('@') >= 0) // Ought to have isPolymorphic? { // Resolve any @T types referred to in the type parameters IQuestionAnswer<Context, PType> instantiator = ctxt.assistantFactory.getAllConcreteTypeInstantiator(); fixed.add(ptype.apply(instantiator, ctxt)); } else { fixed.add(ptype); } } FunctionValue rv = null; if (node.getExpdef() == null) { rv = getPolymorphicValue(ctxt.assistantFactory, node.getImpdef(), fixed); } else { rv = ctxt.assistantFactory.createAExplicitFunctionDefinitionAssistant().getPolymorphicValue(ctxt.assistantFactory, node.getExpdef(), fixed); } rv.setSelf(fv.self); rv.uninstantiated = false; return rv; } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAHistoryExp(AHistoryExp node, Context ctxt) throws AnalysisException { try { // TODO Not very efficient to do this every time. But we can't // save the list because the same HistoryExpression is called from // different object instance contexts, and each instance has its // own operation history counters... ValueList operations = new ValueList(); if (ctxt instanceof ObjectContext) { ObjectValue self = ((ObjectContext) ctxt).self; for (ILexNameToken opname : node.getOpnames()) { operations.addAll(self.getOverloads(opname)); } } else if (ctxt instanceof ClassContext) { ClassContext cctxt = (ClassContext) ctxt; Context statics = cctxt.assistantFactory.createSClassDefinitionAssistant().getStatics(cctxt.classdef); for (ILexNameToken opname : node.getOpnames()) { for (ILexNameToken sname : statics.keySet()) { if (opname.matches(sname)) { operations.add(ctxt.check(sname)); } } } } if (operations.isEmpty()) { VdmRuntimeError.abort(node.getLocation(), 4011, "Illegal history operator: " + node.getHop().toString(), ctxt); } int result = 0; for (Value v : operations) { OperationValue ov = v.operationValue(ctxt); switch (node.getHop().getType()) { case ACT: result += ov.getHashAct(); break; case FIN: result += ov.getHashFin(); break; case REQ: result += ov.getHashReq(); break; case ACTIVE: result += ov.getHashAct() - ov.getHashFin(); break; case WAITING: result += ov.getHashReq() - ov.getHashAct(); break; default: VdmRuntimeError.abort(node.getLocation(), 4011, "Illegal history operator: " + node.getHop(), ctxt); } } node.getLocation().hit(); return new NaturalValue(result); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } catch (ContextException e) { throw e; } catch (Exception e) { return VdmRuntimeError.abort(node.getLocation(), 4065, e.getMessage(), ctxt); } } @Override public Value caseAIsExp(AIsExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); Value v = node.getTest().apply(VdmRuntime.getExpressionEvaluator(), ctxt); try { if (node.getTypeName() != null) { if (node.getTypedef() != null) { if (ctxt.assistantFactory.createPDefinitionAssistant().isTypeDefinition(node.getTypedef())) { // NB. we skip the DTC enabled check here v.convertValueTo(ctxt.assistantFactory.createPDefinitionAssistant().getType(node.getTypedef()), ctxt); return new BooleanValue(true); } } else if (v.isType(RecordValue.class)) { RecordValue rv = v.recordValue(ctxt); return new BooleanValue(rv.type.getName().equals(node.getTypeName())); } } else { // NB. we skip the DTC enabled check here v.convertValueTo(node.getBasicType(), ctxt); return new BooleanValue(true); } } catch (ContextException ex) { if (ex.number != 4060) // Type invariant violation { throw ex; // Otherwise return false } } catch (ValueException ex) { // return false... } return new BooleanValue(false); } @Override public Value caseAIfExp(AIfExp node, Context ctxt) throws AnalysisException { return evalIf(node, node.getLocation(), node.getTest(), node.getThen(), node.getElseList(), node.getElse(), ctxt); } /** * Utility method to evaluate both if expressions and statements * * @param node * @param ifLocation * @param testExp * @param thenNode * @param elseIfNodeList * @param elseNode * @param ctxt * @return * @throws AnalysisException */ protected Value evalIf(INode node, ILexLocation ifLocation, PExp testExp, INode thenNode, List<? extends INode> elseIfNodeList, INode elseNode, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(ifLocation, ctxt); try { if (testExp.apply(VdmRuntime.getStatementEvaluator(), ctxt).boolValue(ctxt)) { return thenNode.apply(VdmRuntime.getStatementEvaluator(), ctxt); } else { for (INode elseif : elseIfNodeList) { Value r = elseif.apply(VdmRuntime.getStatementEvaluator(), ctxt); if (r != null) { return r; } } if (elseNode != null) { return elseNode.apply(VdmRuntime.getStatementEvaluator(), ctxt); } return new VoidValue(); } } catch (ValueException e) { return VdmRuntimeError.abort(ifLocation, e); } } /** * Utility method to evaluate elseif nodes * * @param node * @param location * @param test * @param then * @param ctxt * @return * @throws AnalysisException */ protected Value evalElseIf(INode node, ILexLocation location, PExp test, INode then, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(location, ctxt); try { return test.apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt) ? then.apply(THIS, ctxt) : null; } catch (ValueException e) { return VdmRuntimeError.abort(location, e); } } @Override public Value caseAIotaExp(AIotaExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueList allValues = null; Value result = null; try { allValues = ctxt.assistantFactory.createPBindAssistant().getBindValues(node.getBind(), ctxt, false); } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } for (Value val : allValues) { try { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "iota", ctxt); evalContext.putList(ctxt.assistantFactory.createPPatternAssistant().getNamedValues(node.getBind().getPattern(), val, ctxt)); if (node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt)) { if (result != null && !result.equals(val)) { VdmRuntimeError.abort(node.getLocation(), 4013, "Iota selects more than one result", ctxt); } result = val; } } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } catch (PatternMatchException e) { // Ignore pattern mismatches } } if (result != null) { return result; } return VdmRuntimeError.abort(node.getLocation(), 4014, "Iota does not select a result", ctxt); } @Override public Value caseALambdaExp(ALambdaExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); // Free variables are everything currently visible from this // context (but without the context chain). Context free = ctxt.getVisibleVariables(); PatternListTC list = ctxt.assistantFactory.createPatternList(); list.addAll(node.getParamPatterns()); return new FunctionValue(node.getLocation(), "lambda", (AFunctionType) node.getType(), list, node.getExpression(), free); } @Override public Value caseALetBeStExp(ALetBeStExp node, Context ctxt) throws AnalysisException { return evalLetBeSt(node, node.getLocation(), node.getDef(), node.getSuchThat(), node.getValue(), 4015, "expression", ctxt); } public Value evalLetBeSt(INode node, ILexLocation nodeLocation, AMultiBindListDefinition binding, PExp suchThat, INode body, int errorCode, String type, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(nodeLocation, ctxt); try { QuantifierList quantifiers = new QuantifierList(); for (PMultipleBind mb : binding.getBindings()) { ValueList bvals = ctxt.assistantFactory.createPMultipleBindAssistant().getBindValues(mb, ctxt, false); for (PPattern p : mb.getPlist()) { Quantifier q = new Quantifier(p, bvals); quantifiers.add(q); } } quantifiers.init(ctxt, true); while (quantifiers.hasNext()) { Context evalContext = new Context(ctxt.assistantFactory, nodeLocation, "let be st " + type, ctxt); NameValuePairList nvpl = quantifiers.next(); boolean matches = true; for (NameValuePair nvp : nvpl) { Value v = evalContext.get(nvp.name); if (v == null) { evalContext.put(nvp.name, nvp.value); } else { if (!v.equals(nvp.value)) { matches = false; break; // This quantifier set does not match } } } if (matches && (suchThat == null || suchThat.apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt))) { return body.apply(VdmRuntime.getExpressionEvaluator(), evalContext); } } } catch (ValueException e) { VdmRuntimeError.abort(nodeLocation, e); } return VdmRuntimeError.abort(nodeLocation, errorCode, "Let be st found no applicable bindings", ctxt); } @Override public Value caseALetDefExp(ALetDefExp node, Context ctxt) throws AnalysisException { return evalLet(node, node.getLocation(), node.getLocalDefs(), node.getExpression(), "expression", ctxt); } public Value evalLet(INode node, ILexLocation nodeLocation, LinkedList<PDefinition> localDefs, INode body, String type, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(nodeLocation, ctxt); Context evalContext = new Context(ctxt.assistantFactory, nodeLocation, "let " + type, ctxt); LexNameToken sname = new LexNameToken(nodeLocation.getModule(), "self", nodeLocation); ObjectValue self = (ObjectValue) ctxt.check(sname); for (PDefinition d : localDefs) { NameValuePairList values = ctxt.assistantFactory.createPDefinitionAssistant().getNamedValues(d, evalContext); if (self != null && d instanceof AExplicitFunctionDefinition) { for (NameValuePair nvp : values) { if (nvp.value instanceof FunctionValue) { FunctionValue fv = (FunctionValue) nvp.value; fv.setSelf(self); } } } evalContext.putList(values); } return body.apply(VdmRuntime.getExpressionEvaluator(), evalContext); } /* * Map */ @Override public Value caseAMapCompMapExp(AMapCompMapExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueMap map = new ValueMap(); try { QuantifierList quantifiers = new QuantifierList(); for (PMultipleBind mb : node.getBindings()) { ValueList bvals = ctxt.assistantFactory.createPMultipleBindAssistant().getBindValues(mb, ctxt, false); for (PPattern p : mb.getPlist()) { Quantifier q = new Quantifier(p, bvals); quantifiers.add(q); } } quantifiers.init(ctxt, false); while (quantifiers.hasNext()) { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "map comprehension", ctxt); NameValuePairList nvpl = quantifiers.next(); boolean matches = true; for (NameValuePair nvp : nvpl) { Value v = evalContext.get(nvp.name); if (v == null) { evalContext.put(nvp.name, nvp.value); } else { if (!v.equals(nvp.value)) { matches = false; break; // This quantifier set does not match } } } if (matches && (node.getPredicate() == null || node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt))) { Value dom = node.getFirst().getLeft().apply(VdmRuntime.getExpressionEvaluator(), evalContext); Value rng = node.getFirst().getRight().apply(VdmRuntime.getExpressionEvaluator(), evalContext); node.getFirst().getLocation().hit(); Value old = map.put(dom, rng); if (old != null && !old.equals(rng)) { VdmRuntimeError.abort(node.getLocation(), 4016, "Duplicate map keys have different values: " + dom, ctxt); } } } } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } return new MapValue(map); } @Override public Value caseAMapEnumMapExp(AMapEnumMapExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueMap map = new ValueMap(); for (AMapletExp e : node.getMembers()) { Value l = e.getLeft().apply(VdmRuntime.getExpressionEvaluator(), ctxt); Value r = e.getRight().apply(VdmRuntime.getExpressionEvaluator(), ctxt); e.getLocation().hit(); Value old = map.put(l, r); if (old != null && !old.equals(r)) { VdmRuntimeError.abort(node.getLocation(), 4017, "Duplicate map keys have different values: " + l, ctxt); } } return new MapValue(map); } /* * Map end */ @Override public Value caseAMapletExp(AMapletExp node, Context ctxt) throws AnalysisException { // Not used return null; } @Override public Value caseAMkBasicExp(AMkBasicExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); Value v = node.getArg().apply(VdmRuntime.getExpressionEvaluator(), ctxt); if (node.getType() instanceof ATokenBasicType) { return new TokenValue(v); } else { try { v = v.convertTo(node.getType(), ctxt); } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), 4022, "mk_ type argument is not " + node.getType(), ctxt); } } return v; } @Override public Value caseAMkTypeExp(AMkTypeExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueList argvals = new ValueList(); for (PExp e : node.getArgs()) { argvals.add(e.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } try { return new RecordValue(node.getRecordType(), argvals, ctxt); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAMuExp(AMuExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { RecordValue r = node.getRecord().apply(VdmRuntime.getExpressionEvaluator(), ctxt).recordValue(ctxt); FieldMap fields = new FieldMap(r.fieldmap); for (ARecordModifier rm : node.getModifiers()) { AFieldField f = ctxt.assistantFactory.createARecordInvariantTypeAssistant().findField(r.type, rm.getTag().getName()); if (f == null) { VdmRuntimeError.abort(node.getLocation(), 4023, "Mu type conflict? No field tag " + rm.getTag().getName(), ctxt); } else { fields.add(rm.getTag().getName(), rm.getValue().apply(VdmRuntime.getExpressionEvaluator(), ctxt), !f.getEqualityAbstraction()); } } return new RecordValue(r.type, fields, ctxt); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseANarrowExp(ANarrowExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); Value v = node.getTest().apply(VdmRuntime.getExpressionEvaluator(), ctxt); try { if (node.getTypeName() != null) { if (ctxt.assistantFactory.createPDefinitionAssistant().isTypeDefinition(node.getTypedef())) { // NB. we skip the DTC enabled check here v = v.convertValueTo(ctxt.assistantFactory.createPDefinitionAssistant().getType(node.getTypedef()), ctxt); } else if (v.isType(RecordValue.class)) { v = v.recordValue(ctxt); } } else { // NB. we skip the DTC enabled check here v = v.convertValueTo(node.getBasicType(), ctxt); } } catch (ValueException ex) { VdmRuntimeError.abort(node.getLocation(), ex); } return v; } @Override public Value caseANewExp(ANewExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); node.getClassName().getLocation().hit(); try { ValueList argvals = new ValueList(); for (PExp arg : node.getArgs()) { argvals.add(arg.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } ObjectValue objval = ctxt.assistantFactory.createSClassDefinitionAssistant().newInstance(node.getClassdef(), node.getCtorDefinition(), argvals, ctxt); if (objval.invlistener != null) { // Check the initial values of the object's fields objval.invlistener.doInvariantChecks = true; objval.invlistener.changedValue(node.getLocation(), objval, ctxt); } return objval; } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseANilExp(ANilExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); return new NilValue(); } @Override public Value caseANotYetSpecifiedExp(ANotYetSpecifiedExp node, Context ctxt) throws AnalysisException { return evalANotYetSpecified(node, node.getLocation(), 4024, "expression", ctxt); } protected Value evalANotYetSpecified(INode node, ILexLocation location, int abortNumber, String type, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(location, ctxt); return VdmRuntimeError.abort(location, abortNumber, "'not yet specified' " + type + " reached", ctxt); } @Override public Value caseAPostOpExp(APostOpExp node, Context ctxt) throws AnalysisException { // No break check here, as we want to start in the expression // The postcondition function arguments are the function args, the // result, the old/new state (if any). These all exist in ctxt. // We find the Sigma record and expand its contents to give additional // values in ctxt for each field. Ditto with Sigma~. try { if (node.getState() != null) { RecordValue sigma = ctxt.lookup(node.getState().getName()).recordValue(ctxt); for (AFieldField field : node.getState().getFields()) { ctxt.put(field.getTagname(), sigma.fieldmap.get(field.getTag())); } RecordValue oldsigma = ctxt.lookup(node.getState().getName().getOldName()).recordValue(ctxt); for (AFieldField field : node.getState().getFields()) { ctxt.put(field.getTagname().getOldName(), oldsigma.fieldmap.get(field.getTag())); } } else if (ctxt instanceof ObjectContext) { ObjectContext octxt = (ObjectContext) ctxt; ILexNameToken selfname = node.getOpname().getSelfName(); ILexNameToken oldselfname = selfname.getOldName(); ObjectValue self = octxt.lookup(selfname).objectValue(ctxt); ValueMap oldvalues = octxt.lookup(oldselfname).mapValue(ctxt); // If the opname was defined in a superclass of "self", we have // to discover the subobject to populate its state variables. ObjectValue subself = ctxt.assistantFactory.createAPostOpExpAssistant().findObject(node, node.getOpname().getModule(), self); if (self.superobjects.size() == 0) { subself = self; } if (subself == null) { VdmRuntimeError.abort(node.getLocation(), 4026, "Cannot create post_op environment", ctxt); } // Create an object context using the "self" passed in, rather // than the self that we're being called from, assuming they // are different. if (subself != octxt.self) { ObjectContext selfctxt = new ObjectContext(ctxt.assistantFactory, ctxt.location, "postcondition's object", ctxt, subself); selfctxt.putAll(ctxt); // To add "RESULT" and args. ctxt = selfctxt; } ctxt.assistantFactory.createAPostOpExpAssistant().populate(node, ctxt, subself.type.getName().getName(), oldvalues); // To // add // old // "~" // values } else if (ctxt instanceof ClassContext) { ILexNameToken selfname = node.getOpname().getSelfName(); ILexNameToken oldselfname = selfname.getOldName(); ValueMap oldvalues = ctxt.lookup(oldselfname).mapValue(ctxt); ctxt.assistantFactory.createAPostOpExpAssistant().populate(node, ctxt, node.getOpname().getModule(), oldvalues); } // If there are errs clauses, and there is a precondition defined, then // we evaluate that as well as the postcondition. boolean result = (node.getErrors().isEmpty() || node.getPreexpression() == null || node.getPreexpression().apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt)) && node.getPostexpression().apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt); node.setErrorLocation(node.getLocation());// FIXME not good if (node.getErrors() != null) { for (AErrorCase err : node.getErrors()) { boolean left = err.getLeft().apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt); boolean right = err.getRight().apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt); if (left && !right) { node.setErrorLocation(err.getLeft().getLocation());// FIXME not good } result = result || left && right; } } return new BooleanValue(result); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAPreExp(APreExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); Value fv = node.getFunction().apply(VdmRuntime.getExpressionEvaluator(), ctxt); if (fv instanceof FunctionValue) { FunctionValue tfv = (FunctionValue) fv; while (true) { if (tfv instanceof CompFunctionValue) { tfv = ((CompFunctionValue) tfv).ff1; continue; } if (tfv instanceof IterFunctionValue) { tfv = ((IterFunctionValue) tfv).function; continue; } break; } FunctionValue pref = tfv.precondition; if (pref == null) { return new BooleanValue(true); } if (pref.type.getParameters().size() <= node.getArgs().size()) { try { ValueList argvals = new ValueList(); Iterator<PExp> aiter = node.getArgs().iterator(); for (@SuppressWarnings("unused") PType t : pref.type.getParameters()) { argvals.add(aiter.next().apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } return pref.eval(node.getLocation(), argvals, ctxt); } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } } // else true, below. } return new BooleanValue(true); } @Override public Value caseAPreOpExp(APreOpExp node, Context ctxt) throws AnalysisException { try { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); // The precondition function arguments are the function args, // plus the state (if any). These all exist in ctxt. We find the // Sigma record and expand its contents to give additional // values in ctxt for each field. if (node.getState() != null) { try { RecordValue sigma = ctxt.lookup(node.getState().getName()).recordValue(ctxt); for (AFieldField field : node.getState().getFields()) { ctxt.put(field.getTagname(), sigma.fieldmap.get(field.getTag())); } } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } } else if (ctxt instanceof ObjectContext) { ObjectContext octxt = (ObjectContext) ctxt; ILexNameToken selfname = node.getOpname().getSelfName(); ObjectValue self = octxt.lookup(selfname).objectValue(ctxt); // Create an object context using the "self" passed in, rather // than the self that we're being called from. ObjectContext selfctxt = new ObjectContext(ctxt.assistantFactory, ctxt.location, "precondition's object", ctxt, self); selfctxt.putAll(ctxt); // To add "RESULT" and args. ctxt = selfctxt; } boolean result = node.getExpression().apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt); if (node.getErrors() != null) { for (AErrorCase err : node.getErrors()) { result = result || err.getLeft().apply(VdmRuntime.getExpressionEvaluator(), ctxt).boolValue(ctxt); } } return new BooleanValue(result); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseASameBaseClassExp(ASameBaseClassExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { Value l = node.getLeft().apply(VdmRuntime.getExpressionEvaluator(), ctxt); Value r = node.getRight().apply(VdmRuntime.getExpressionEvaluator(), ctxt); if (!l.isType(ObjectValue.class) || !r.isType(ObjectValue.class)) { return new BooleanValue(false); } ObjectValue lv = l.objectValue(ctxt); ObjectValue rv = r.objectValue(ctxt); PTypeList lbases = lv.getBaseTypes(); PTypeList rbases = rv.getBaseTypes(); for (PType ltype : lbases) { if (rbases.contains(ltype)) { return new BooleanValue(true); } } return new BooleanValue(false); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseASameClassExp(ASameClassExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { Value l = node.getLeft().apply(VdmRuntime.getExpressionEvaluator(), ctxt); Value r = node.getRight().apply(VdmRuntime.getExpressionEvaluator(), ctxt); if (!l.isType(ObjectValue.class) || !r.isType(ObjectValue.class)) { return new BooleanValue(false); } ObjectValue lv = l.objectValue(ctxt); ObjectValue rv = r.objectValue(ctxt); return new BooleanValue(lv.type.equals(rv.type)); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } /* * Seq */ @Override public Value caseASeqCompSeqExp(ASeqCompSeqExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); if (node.getSetBind() != null) { return evalSetBind(node, ctxt); } else { return evalSeqBind(node, ctxt); } } private Value evalSeqBind(ASeqCompSeqExp node, Context ctxt) throws AnalysisException { ValueList allValues = ctxt.assistantFactory.createPBindAssistant().getBindValues(node.getSeqBind(), ctxt, false); ValueList seq = new ValueList(); // Bind variable values for (Value val: allValues) { try { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "seq comprehension", ctxt); NameValuePairList nvpl = ctxt.assistantFactory.createPPatternAssistant().getNamedValues(node.getSeqBind().getPattern(), val, ctxt); evalContext.putList(nvpl); if (node.getPredicate() == null || node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt)) { Value out = node.getFirst().apply(VdmRuntime.getExpressionEvaluator(), evalContext); seq.add(out); } } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } catch (PatternMatchException e) { // Ignore mismatches } } return new SeqValue(seq); } private Value evalSetBind(ASeqCompSeqExp node, Context ctxt) throws AnalysisException { ValueList allValues = ctxt.assistantFactory.createPBindAssistant().getBindValues(node.getSetBind(), ctxt, false); ValueSet seq = new ValueSet(); // Bind variable values ValueMap map = new ValueMap(); // Map bind values to output values for (Value val : allValues) { try { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "seq comprehension", ctxt); NameValuePairList nvpl = ctxt.assistantFactory.createPPatternAssistant().getNamedValues(node.getSetBind().getPattern(), val, ctxt); Value sortOn = nvpl.get(0).value; if (map.get(sortOn) == null) { if (nvpl.size() != 1 || !sortOn.isNumeric()) { VdmRuntimeError.abort(node.getLocation(), 4029, "Sequence comprehension bindings must be one numeric value", ctxt); } evalContext.putList(nvpl); if (node.getPredicate() == null || node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt)) { Value out = node.getFirst().apply(VdmRuntime.getExpressionEvaluator(), evalContext); seq.add(sortOn); map.put(sortOn, out); } } } catch (ValueException e) { VdmRuntimeError.abort(node.getLocation(), e); } catch (PatternMatchException e) { // Ignore mismatches } } Collections.sort(seq); // Using compareTo ValueList sorted = new ValueList(); for (Value bv : seq) { sorted.add(map.get(bv)); } return new SeqValue(sorted); } @Override public Value caseASeqEnumSeqExp(ASeqEnumSeqExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueList values = new ValueList(); for (PExp e : node.getMembers()) { values.add(e.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } return new SeqValue(values); } /* * seq end */ /* * (non-Javadoc) Set start * @see * org.overture.ast.analysis.QuestionAnswerAdaptor#caseAStateInitExp(org.overture.ast.expressions.AStateInitExp, * java.lang.Object) */ @Override public Value caseASetEnumSetExp(ASetEnumSetExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueSet values = new ValueSet(); for (PExp e : node.getMembers()) { values.add(e.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } return new SetValue(values); } @Override public Value caseASetCompSetExp(ASetCompSetExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueSet set = new ValueSet(); try { QuantifierList quantifiers = new QuantifierList(); for (PMultipleBind mb : node.getBindings()) { ValueList bvals = ctxt.assistantFactory.createPMultipleBindAssistant().getBindValues(mb, ctxt, false); for (PPattern p : mb.getPlist()) { Quantifier q = new Quantifier(p, bvals); quantifiers.add(q); } } quantifiers.init(ctxt, false); while (quantifiers.hasNext()) { Context evalContext = new Context(ctxt.assistantFactory, node.getLocation(), "set comprehension", ctxt); NameValuePairList nvpl = quantifiers.next(); boolean matches = true; for (NameValuePair nvp : nvpl) { Value v = evalContext.get(nvp.name); if (v == null) { evalContext.put(nvp.name, nvp.value); } else { if (!v.equals(nvp.value)) { matches = false; break; // This quantifier set does not match } } } if (matches && (node.getPredicate() == null || node.getPredicate().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt))) { set.add(node.getFirst().apply(VdmRuntime.getExpressionEvaluator(), evalContext)); } } } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } return new SetValue(set); } @Override public Value caseASetRangeSetExp(ASetRangeSetExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { long from = (long) Math.ceil(node.getFirst().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt)); long to = (long) Math.floor(node.getLast().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt)); ValueSet set = new ValueSet(); for (long i = from; i <= to; i++) { set.addNoCheck(new IntegerValue(i)); } return new SetValue(set); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAStateInitExp(AStateInitExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { FunctionValue invariant = VdmRuntime.getNodeState(node.getState()).invfunc; // Note, the function just checks whether the argument passed would // violate the state invariant (if any). It doesn't initialize the // state itself. This is done in State.initialize(). if (invariant != null) { AIdentifierPattern argp = (AIdentifierPattern) node.getState().getInitPattern(); RecordValue rv = (RecordValue) ctxt.lookup(argp.getName()); return invariant.eval(node.getLocation(), rv, ctxt); } return new BooleanValue(true); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseASubclassResponsibilityExp( ASubclassResponsibilityExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); return VdmRuntimeError.abort(node.getLocation(), 4032, "'is subclass responsibility' expression reached", ctxt); } @Override public Value caseASubseqExp(ASubseqExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); try { ValueList list = node.getSeq().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt); double fr = node.getFrom().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt); double tr = node.getTo().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt); int fi = (int) Math.ceil(fr); int ti = (int) Math.floor(tr); if (fi < 1) { fi = 1; } if (ti > list.size()) { ti = list.size(); } ValueList result = new ValueList(); if (fi <= ti) { result.addAll(list.subList(fi - 1, ti)); } return new SeqValue(result); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAThreadIdExp(AThreadIdExp node, Context ctxt) throws AnalysisException { try { node.getLocation().hit(); return new NaturalValue(ctxt.threadState.threadId); } catch (Exception e) { return VdmRuntimeError.abort(node.getLocation(), 4065, e.getMessage(), ctxt); } } @Override public Value caseATimeExp(ATimeExp node, Context ctxt) throws AnalysisException { node.getLocation().hit(); try { return new NaturalValue(SystemClock.getWallTime()); } catch (Exception e) { return VdmRuntimeError.abort(node.getLocation(), 4145, "Time: " + e.getMessage(), ctxt); } } @Override public Value caseATupleExp(ATupleExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); ValueList argvals = new ValueList(); for (PExp arg : node.getArgs()) { argvals.add(arg.apply(VdmRuntime.getExpressionEvaluator(), ctxt)); } return new TupleValue(argvals); } @Override public Value caseAUndefinedExp(AUndefinedExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); return new UndefinedValue(); } @Override public Value caseAVariableExp(AVariableExp node, Context ctxt) throws AnalysisException { // Experimental hood added for DESTECS if (Settings.dialect == Dialect.VDM_RT) { SharedStateListner.beforeVariableReadDuration(node); } BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); return ctxt.lookup(node.getName()); } @Override public Value caseASelfExp(ASelfExp node, Context ctxt) throws AnalysisException { node.getLocation().hit(); return ctxt.lookup(node.getName()); } @Override public Value caseAIsOfBaseClassExp(AIsOfBaseClassExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); node.getBaseClass().getLocation().hit(); try { Value v = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).deref(); if (!(v instanceof ObjectValue)) { return new BooleanValue(false); } ObjectValue ov = v.objectValue(ctxt); return new BooleanValue(search(node, ov)); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } @Override public Value caseAIsOfClassExp(AIsOfClassExp node, Context ctxt) throws AnalysisException { BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt); node.getClassName().getLocation().hit(); try { Value v = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).deref(); if (!(v instanceof ObjectValue)) { return new BooleanValue(false); } ObjectValue ov = v.objectValue(ctxt); return new BooleanValue(isOfClass(ov, node.getClassName().getName())); } catch (ValueException e) { return VdmRuntimeError.abort(node.getLocation(), e); } } public FunctionValue getPolymorphicValue(IInterpreterAssistantFactory af, AImplicitFunctionDefinition impdef, PTypeList actualTypes) { Map<List<PType>, FunctionValue> polyfuncs = VdmRuntime.getNodeState(impdef).polyfuncs; if (polyfuncs == null) { polyfuncs = new HashMap<List<PType>, FunctionValue>(); } else { // We always return the same function value for a polymorph // with a given set of types. This is so that the one function // value can record measure counts for recursive polymorphic // functions. FunctionValue rv = polyfuncs.get(actualTypes); if (rv != null) { return rv; } } FunctionValue prefv = null; FunctionValue postfv = null; if (impdef.getPredef() != null) { prefv = af.createAExplicitFunctionDefinitionAssistant().getPolymorphicValue(af, impdef.getPredef(), actualTypes); } else { prefv = null; } if (impdef.getPostdef() != null) { postfv = af.createAExplicitFunctionDefinitionAssistant().getPolymorphicValue(af, impdef.getPostdef(), actualTypes); } else { postfv = null; } FunctionValue rv = new FunctionValue(af, impdef, actualTypes, prefv, postfv, null); polyfuncs.put(actualTypes, rv); return rv; } public boolean search(AIsOfBaseClassExp node, ObjectValue from) { if (from.type.getName().getName().equals(node.getBaseClass().getName()) && from.superobjects.isEmpty()) { return true; } for (ObjectValue svalue : from.superobjects) { if (search(node, svalue)) { return true; } } return false; } public boolean isOfClass(ObjectValue obj, String name) { if (obj.type.getName().getName().equals(name)) { return true; } else { for (ObjectValue objval : obj.superobjects) { if (isOfClass(objval, name)) { return true; } } } return false; } }