/*******************************************************************************
*
* Copyright (C) 2008 Fujitsu Services Ltd.
*
* Author: Nick Battle
*
* This file is part of VDMJ.
*
* VDMJ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VDMJ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VDMJ. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package org.overture.interpreter.runtime;
import java.io.File;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.ANamedTraceDefinition;
import org.overture.ast.definitions.ATypeDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.expressions.PExp;
import org.overture.ast.factory.AstFactory;
import org.overture.ast.lex.Dialect;
import org.overture.ast.lex.LexIdentifierToken;
import org.overture.ast.lex.LexLocation;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.lex.LexToken;
import org.overture.ast.lex.VDMToken;
import org.overture.ast.modules.AModuleModules;
import org.overture.ast.statements.PStm;
import org.overture.ast.types.PType;
import org.overture.ast.util.modules.ModuleList;
import org.overture.interpreter.assistant.IInterpreterAssistantFactory;
import org.overture.interpreter.assistant.InterpreterAssistantFactory;
import org.overture.interpreter.debug.DBGPReader;
import org.overture.interpreter.messages.Console;
import org.overture.interpreter.scheduler.BasicSchedulableThread;
import org.overture.interpreter.scheduler.CTMainThread;
import org.overture.interpreter.scheduler.InitThread;
import org.overture.interpreter.scheduler.MainThread;
import org.overture.interpreter.traces.CallSequence;
import org.overture.interpreter.util.ModuleListInterpreter;
import org.overture.interpreter.values.CPUValue;
import org.overture.interpreter.values.Value;
import org.overture.parser.lex.LexTokenReader;
import org.overture.parser.messages.VDMErrorsException;
import org.overture.parser.syntax.ExpressionReader;
import org.overture.parser.syntax.ParserException;
import org.overture.pog.pub.IProofObligationList;
import org.overture.typechecker.Environment;
import org.overture.typechecker.ModuleEnvironment;
/**
* The VDM-SL module interpreter.
*/
public class ModuleInterpreter extends Interpreter
{
/** A list of module definitions in the specification. */
public final ModuleListInterpreter modules;
/** The module starting execution. */
public AModuleModules defaultModule;
/**
* Create an Interpreter from the list of modules passed.
*
* @param modules
* @throws Exception
*/
public ModuleInterpreter(ModuleList modules) throws Exception
{
this(new InterpreterAssistantFactory(), modules);
}
/**
* Create an Interpreter from the list of modules passed.
*
* @param assistantFactory
* @param modules
* @throws Exception
*/
public ModuleInterpreter(IInterpreterAssistantFactory assistantFactory,
ModuleList modules) throws Exception
{
super(assistantFactory);
this.modules = new ModuleListInterpreter(modules);
if (modules.isEmpty())
{
setDefaultName(null);
} else
{
setDefaultName(modules.get(0).getName().getName());
}
}
@Override
public PStm findStatement(File file, int lineno)
{
return assistantFactory.createAModuleModulesAssistant().findStatement(modules, file, lineno);
}
@Override
public PExp findExpression(File file, int lineno)
{
return assistantFactory.createAModuleModulesAssistant().findExpression(modules, file, lineno);
}
/**
* Set the default module to the name given.
*
* @param mname
* The name of the new default module.
* @throws Exception
* The module name is not known.
*/
@Override
public void setDefaultName(String mname) throws Exception
{
if (mname == null)
{
defaultModule = AstFactory.newAModuleModules();
} else
{
for (AModuleModules m : modules)
{
if (m.getName().getName().equals(mname))
{
defaultModule = m;
return;
}
}
throw new Exception("Module " + mname + " not loaded");
}
}
/**
* @return The current default module name.
*/
@Override
public String getDefaultName()
{
return defaultModule.getName().getName();
}
/**
* @return The current default module's file name.
*/
@Override
public File getDefaultFile()
{
return defaultModule.getName().getLocation().getFile();
}
@Override
public Set<File> getSourceFiles()
{
return modules.getSourceFiles();
}
/**
* @return The state context for the current default module.
*/
public Context getStateContext()
{
return assistantFactory.createAModuleModulesAssistant().getStateContext(defaultModule);
}
@Override
public Environment getGlobalEnvironment()
{
return new ModuleEnvironment(assistantFactory, defaultModule);
}
/**
* @return The list of loaded modules.
*/
public ModuleList getModules()
{
return modules;
}
@Override
public void init(DBGPReader dbgp)
{
VdmRuntime.initialize();
InitThread iniThread = new InitThread(Thread.currentThread());
BasicSchedulableThread.setInitialThread(iniThread);
scheduler.init();
CPUValue.init(scheduler, assistantFactory);
initialContext = assistantFactory.createModuleListAssistant().initialize(modules, dbgp);
}
@Override
public void traceInit(DBGPReader dbgp)
{
scheduler.reset();
initialContext = assistantFactory.createModuleListAssistant().initialize(modules, dbgp);
}
@Override
protected PExp parseExpression(String line, String module) throws Exception
{
LexTokenReader ltr = new LexTokenReader(line, Dialect.VDM_SL, Console.charset);
ExpressionReader reader = new ExpressionReader(ltr);
reader.setCurrentModule(getDefaultName());
PExp ast = reader.readExpression();
LexToken end = ltr.getLast();
if (!end.is(VDMToken.EOF))
{
throw new ParserException(2330, "Tokens found after expression at " + end, new LexLocation(), 0);
}
return ast;
}
/**
* Parse the line passed, type check it and evaluate it as an expression in the initial module context (with default
* module's state).
*
* @param line
* A VDM expression.
* @return The value of the expression.
* @throws Exception
* Parser, type checking or runtime errors.
*/
@Override
public Value execute(String line, DBGPReader dbgp) throws Exception
{
PExp expr = parseExpression(line, getDefaultName());
Environment env = getGlobalEnvironment();
typeCheck(expr, env);
Context mainContext = new StateContext(assistantFactory, defaultModule.getName().getLocation(), "module scope", null, assistantFactory.createAModuleModulesAssistant().getStateContext(defaultModule));
mainContext.putAll(initialContext);
mainContext.setThreadState(dbgp, null);
clearBreakpointHits();
// scheduler.reset();
InitThread iniThread = new InitThread(Thread.currentThread());
BasicSchedulableThread.setInitialThread(iniThread);
MainThread main = new MainThread(expr, mainContext);
main.start();
scheduler.start(main);
return main.getResult(); // Can throw ContextException
}
/**
* Parse the line passed, and evaluate it as an expression in the context passed.
*
* @param line
* A VDM expression.
* @param ctxt
* The context in which to evaluate the expression.
* @return The value of the expression.
* @throws Exception
* Parser or runtime errors.
*/
@Override
public Value evaluate(String line, Context ctxt) throws Exception
{
PExp expr = parseExpression(line, getDefaultName());
Environment env = new ModuleEnvironment(assistantFactory, defaultModule);
try
{
typeCheck(expr, env);
} catch (VDMErrorsException e)
{
// We don't care... we just needed to type check it.
}
ctxt.threadState.init();
try
{
return expr.apply(VdmRuntime.getExpressionEvaluator(), ctxt);
} catch (Exception e)
{
throw e;
}
}
@Override
public AModuleModules findModule(String module)
{
LexIdentifierToken name = new LexIdentifierToken(module, false, null);
return modules.findModule(name);
}
@Override
protected ANamedTraceDefinition findTraceDefinition(LexNameToken name)
{
return modules.findTraceDefinition(name);
}
// /**
// * Find a Statement in the given file that starts on the given line.
// * If there are none, return null.
// *
// * @param file The file name to search.
// * @param lineno The line number in the file.
// * @return A Statement starting on the line, or null.
// */
//
// @Override
// public PStm findStatement(File file, int lineno)
// {
// return modules.findStatement(file, lineno);
// }
// /**
// * Find an Expression in the given file that starts on the given line.
// * If there are none, return null.
// *
// * @param file The file name to search.
// * @param lineno The line number in the file.
// * @return An Expression starting on the line, or null.
// */
//
// @Override
// public PExp findExpression(File file, int lineno)
// {
// return modules.findExpression(file, lineno);
// }
@Override
public IProofObligationList getProofObligations() throws AnalysisException
{
return assistantFactory.createModuleListAssistant().getProofObligations(modules);
}
@Override
public Context getInitialTraceContext(ANamedTraceDefinition tracedef,
boolean debug) throws ValueException
{
Context mainContext = new StateContext(assistantFactory, defaultModule.getName().getLocation(), "module scope", initialContext, assistantFactory.createAModuleModulesAssistant().getStateContext(defaultModule));
mainContext.putAll(initialContext);
mainContext.setThreadState(mainContext.threadState.dbgp, CPUValue.vCPU);
return mainContext;
}
@Override
public List<Object> runOneTrace(ANamedTraceDefinition tracedef,
CallSequence test, boolean debug)
{
List<Object> list = new Vector<Object>();
Context ctxt = null;
try
{
ctxt = getInitialTraceContext(tracedef, debug);
} catch (ValueException e)
{
list.add(e.getMessage());
return list;
}
clearBreakpointHits();
// scheduler.reset();
CTMainThread main = new CTMainThread(test, ctxt, debug);
main.start();
scheduler.start(main);
return main.getList();
}
@Override
public PType findType(String typename)
{
for (AModuleModules module : modules)
{
for (PDefinition def : module.getDefs())
{
if (def instanceof ATypeDefinition)
{
if (def.getName().equals(typename))
{
return def.getType();
}
}
}
}
return null;
}
}