package org.overture.interpreter.traces; import java.util.List; import java.util.Vector; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.QuestionAnswerAdaptor; import org.overture.ast.definitions.PDefinition; import org.overture.ast.definitions.traces.AApplyExpressionTraceCoreDefinition; import org.overture.ast.definitions.traces.ABracketedExpressionTraceCoreDefinition; import org.overture.ast.definitions.traces.AConcurrentExpressionTraceCoreDefinition; import org.overture.ast.definitions.traces.AInstanceTraceDefinition; import org.overture.ast.definitions.traces.ALetBeStBindingTraceDefinition; import org.overture.ast.definitions.traces.ALetDefBindingTraceDefinition; import org.overture.ast.definitions.traces.ARepeatTraceDefinition; import org.overture.ast.definitions.traces.ATraceDefinitionTerm; import org.overture.ast.definitions.traces.PTraceCoreDefinition; import org.overture.ast.definitions.traces.PTraceDefinition; import org.overture.ast.expressions.PExp; import org.overture.ast.factory.AstFactory; import org.overture.ast.lex.LexIdentifierToken; import org.overture.ast.node.INode; import org.overture.ast.patterns.PMultipleBind; import org.overture.ast.patterns.PPattern; import org.overture.ast.statements.ACallObjectStm; import org.overture.ast.statements.ACallStm; import org.overture.ast.statements.PStm; import org.overture.config.Settings; import org.overture.interpreter.assistant.IInterpreterAssistantFactory; import org.overture.interpreter.runtime.Context; import org.overture.interpreter.runtime.ContextException; import org.overture.interpreter.runtime.ValueException; import org.overture.interpreter.runtime.VdmRuntime; import org.overture.interpreter.values.NameValuePair; import org.overture.interpreter.values.NameValuePairList; import org.overture.interpreter.values.ObjectValue; import org.overture.interpreter.values.Quantifier; import org.overture.interpreter.values.QuantifierList; import org.overture.interpreter.values.Value; import org.overture.interpreter.values.ValueList; import org.overture.parser.lex.LexException; import org.overture.parser.lex.LexTokenReader; import org.overture.parser.syntax.ExpressionReader; import org.overture.parser.syntax.ParserException; /** * This method expands the trace of a core element in the tree. * * @author pvj */ public class TraceExpander extends QuestionAnswerAdaptor<Context, TraceNode> { protected IInterpreterAssistantFactory af; public TraceExpander(IInterpreterAssistantFactory af) { this.af = af; } @Override public TraceNode caseAApplyExpressionTraceCoreDefinition( AApplyExpressionTraceCoreDefinition core, Context ctxt) throws AnalysisException { // return AApplyExpressionTraceCoreDefinitionAssistantInterpreter.expand(core, ctxt); List<PExp> newargs = new Vector<PExp>(); List<PExp> args = null; if (core.getCallStatement() instanceof ACallStm) { ACallStm stmt = (ACallStm) core.getCallStatement(); args = stmt.getArgs(); } else { ACallObjectStm stmt = (ACallObjectStm) core.getCallStatement(); args = stmt.getArgs(); } for (PExp arg : args) { Value v = null; try { v = arg.apply(VdmRuntime.getExpressionEvaluator(), ctxt).deref(); } catch (AnalysisException e1) { e1.printStackTrace(); } if (v instanceof ObjectValue) { newargs.add(arg.clone()); } else { String value = v.toString(); // If the value includes mk_R() expressions, we may not be able to resolve the type, // either because the type R is not explicit (like mk_M`R) or because the type may // have been exported from its module as a "struct" and so mk_R(x) is not legal. // Note that a RecordValue's toString does not explicitly expand the module name. // So we exclude anything with mk_R expressions too... if (!value.matches("mk_token\\(.*\\)") && value.matches(".*mk_\\w+\\(.*")) { newargs.add(arg.clone()); // Give up! } else { LexTokenReader ltr = new LexTokenReader(value, Settings.dialect, arg.getLocation()); ExpressionReader er = new ExpressionReader(ltr); er.setCurrentModule(core.getCurrentModule()); try { newargs.add(er.readExpression()); } catch (ParserException e) { newargs.add(arg.clone()); // Give up! } catch (LexException e) { newargs.add(arg.clone()); // Give up! } } } } PStm newStatement = null; if (core.getCallStatement() instanceof ACallStm) { ACallStm stmt = (ACallStm) core.getCallStatement(); newStatement = AstFactory.newACallStm(stmt.getName().clone(), newargs); } else { ACallObjectStm stmt = (ACallObjectStm) core.getCallStatement(); ACallObjectStm newCallStatement; if (stmt.getClassname() != null) { newCallStatement = AstFactory.newACallObjectStm(stmt.getDesignator().clone(), stmt.getClassname().clone(), newargs); } else { newCallStatement = AstFactory.newACallObjectStm(stmt.getDesignator().clone(), (LexIdentifierToken) stmt.getFieldname().clone(), newargs); } if(stmt.getField() != null) { newCallStatement.setField(stmt.getField().clone()); } newStatement = newCallStatement; } return new StatementTraceNode(newStatement); } @Override public TraceNode caseABracketedExpressionTraceCoreDefinition( ABracketedExpressionTraceCoreDefinition core, Context ctxt) throws AnalysisException { // return ABracketedExpressionTraceCoreDefinitionAssitantInterpreter.expand(core, ctxt); SequenceTraceNode node = new SequenceTraceNode(); for (ATraceDefinitionTerm term : core.getTerms()) { // node.nodes.add(ATraceDefinitionTermAssistantInterpreter.expand(term, ctxt)); node.nodes.add(term.apply(THIS, ctxt)); } return node; } @Override public TraceNode caseAConcurrentExpressionTraceCoreDefinition( AConcurrentExpressionTraceCoreDefinition core, Context ctxt) throws AnalysisException { // return AConcurrentExpressionTraceCoreDefinitionAssistantInterpreter.expand(core, ctxt); ConcurrentTraceNode node = new ConcurrentTraceNode(); for (PTraceDefinition term : core.getDefs()) { // node.nodes.add(PTraceDefinitionAssistantInterpreter.expand(term, ctxt)); node.nodes.add(term.apply(THIS, ctxt)); } return node; } @Override public TraceNode caseATraceDefinitionTerm(ATraceDefinitionTerm node, Context question) throws AnalysisException { AlternativeTraceNode newNode = new AlternativeTraceNode(); for (PTraceDefinition term : node.getList()) { newNode.alternatives.add(term.apply(THIS, question)); // newNode.alternatives.add(PTraceDefinitionAssistantInterpreter.expand(term, ctxt)); } return newNode; } @Override public TraceNode defaultPTraceCoreDefinition(PTraceCoreDefinition node, Context question) throws AnalysisException { assert false : "Should not happen"; return null; } @Override public TraceNode createNewReturnValue(INode node, Context question) throws AnalysisException { // TODO Auto-generated method stub return null; } @Override public TraceNode createNewReturnValue(Object node, Context question) throws AnalysisException { // TODO Auto-generated method stub return null; } @Override public TraceNode caseAInstanceTraceDefinition( AInstanceTraceDefinition term, Context ctxt) throws AnalysisException { assert false : "this one is not in Nicks tree"; return null; } @Override public TraceNode caseALetBeStBindingTraceDefinition( ALetBeStBindingTraceDefinition term, Context ctxt) throws AnalysisException { // return ALetBeStBindingTraceDefinitionAssistantInterpreter.expand(term, ctxt); AlternativeTraceNode node = new AlternativeTraceNode(); try { QuantifierList quantifiers = new QuantifierList(); for (PMultipleBind mb : term.getDef().getBindings()) { ValueList bvals = af.createPMultipleBindAssistant().getBindValues(mb, ctxt, true); // NB permuted for (PPattern p : mb.getPlist()) { Quantifier q = new Quantifier(p, bvals); quantifiers.add(q); } } quantifiers.init(ctxt, true); if (quantifiers.finished()) // No entries at all { node.alternatives.add(new StatementTraceNode(AstFactory.newASkipStm(term.getLocation()))); return node; } while (quantifiers.hasNext()) { Context evalContext = new Context(af, term.getLocation(), "TRACE", 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 && (term.getStexp() == null || term.getStexp().apply(VdmRuntime.getExpressionEvaluator(), evalContext).boolValue(ctxt))) { TraceNode exp = term.getBody().apply(THIS, evalContext); exp.addVariables(new TraceVariableList(evalContext, af.createPDefinitionAssistant().getDefinitions(term.getDef()))); node.alternatives.add(exp); } } } catch (AnalysisException e) { if (e instanceof ValueException) { throw new ContextException((ValueException) e, term.getLocation()); } } return node; } @Override public TraceNode caseALetDefBindingTraceDefinition( ALetDefBindingTraceDefinition term, Context ctxt) throws AnalysisException { // return ALetDefBindingTraceDefinitionAssistantInterpreter.expand(term, ctxt); Context evalContext = new Context(af, term.getLocation(), "TRACE", ctxt); for (PDefinition d : term.getLocalDefs()) { evalContext.putList(af.createPDefinitionAssistant().getNamedValues(d, evalContext)); } TraceNode node = term.getBody().apply(THIS, evalContext); node.addVariables(new TraceVariableList(evalContext, term.getLocalDefs())); return node; } @Override public TraceNode caseARepeatTraceDefinition(ARepeatTraceDefinition term, Context ctxt) throws AnalysisException { TraceNode body = term.getCore().apply(af.getTraceExpander(),ctxt); //expand(term.getCore(), ctxt); if (term.getFrom() == 1 && term.getTo() == 1) { return body; } else { return new RepeatTraceNode(body, term.getFrom(), term.getTo()); } } // public TraceNode expand(PTraceCoreDefinition core, Context ctxt) // { // try // { // return core.apply(af.getTraceExpander(), ctxt); // } catch (AnalysisException e) // { // return null; // } // } }