All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.overture.interpreter.VDMJ Maven / Gradle / Ivy

There is a newer version: 3.0.2
Show newest version
/*******************************************************************************
 *
 *	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 .
 *
 ******************************************************************************/

package org.overture.interpreter;

import java.io.File;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;

import org.overture.ast.lex.Dialect;
import org.overture.config.Release;
import org.overture.config.Settings;
import org.overture.interpreter.assistant.IInterpreterAssistantFactory;
import org.overture.interpreter.assistant.InterpreterAssistantFactory;
import org.overture.interpreter.debug.RemoteControl;
import org.overture.interpreter.debug.RemoteInterpreter;
import org.overture.interpreter.messages.Console;
import org.overture.interpreter.messages.rtlog.RTLogger;
import org.overture.interpreter.runtime.Interpreter;
import org.overture.interpreter.util.ExitStatus;
import org.overture.parser.config.Properties;

/**
 * The main class of the VDMJ parser/checker/interpreter.
 */

abstract public class VDMJ
{
	protected static boolean warnings = true;
	protected static boolean interpret = false;
	protected static boolean pog = false;
	protected static boolean quiet = false;
	protected static String script = null;
	protected static String outfile = null;
	protected static String logfile = null;

	public static String filecharset = Charset.defaultCharset().name();

	final protected IInterpreterAssistantFactory assistantFactory;// = new TypeCheckerAssistantFactory();

	/**
	 * VDM-only constructor. NOT for use by extensions.
	 */
	public VDMJ()
	{
		this.assistantFactory = new InterpreterAssistantFactory();
	}

	/**
	 * The main method. This validates the arguments, then parses and type checks the files provided (if any), and
	 * finally enters the interpreter if required.
	 * 
	 * @param args
	 *            Arguments passed to the program.
	 */

	@SuppressWarnings("unchecked")
	public static void main(String[] args)
	{
		List filenames = new Vector();
		List pathnames = new Vector();
		List largs = Arrays.asList(args);
		VDMJ controller = null;
		Dialect dialect = Dialect.VDM_SL;
		String remoteName = null;
		Class remoteClass = null;
		String defaultName = null;

		Properties.init(); // Read properties file, if any
		Settings.usingCmdLine = true;

		for (Iterator i = largs.iterator(); i.hasNext();)
		{
			String arg = i.next();

			if (arg.equals("-vdmsl"))
			{
				controller = new VDMSL();
				dialect = Dialect.VDM_SL;
			} else if (arg.equals("-vdmpp"))
			{
				controller = new VDMPP();
				dialect = Dialect.VDM_PP;
			} else if (arg.equals("-vdmrt"))
			{
				controller = new VDMRT();
				dialect = Dialect.VDM_RT;
			} else if (arg.equals("-w"))
			{
				warnings = false;
			} else if (arg.equals("-i"))
			{
				interpret = true;
			} else if (arg.equals("-p"))
			{
				pog = true;
			} else if (arg.equals("-q"))
			{
				quiet = true;
			} else if (arg.equals("-e"))
			{
				Settings.usingCmdLine = false;
				interpret = true;
				pog = false;

				if (i.hasNext())
				{
					script = i.next();
				} else
				{
					usage("-e option requires an expression");
				}
			} else if (arg.equals("-o"))
			{
				if (i.hasNext())
				{
					if (outfile != null)
					{
						usage("Only one -o option allowed");
					}

					outfile = i.next();
				} else
				{
					usage("-o option requires a filename");
				}
			} else if (arg.equals("-c"))
			{
				if (i.hasNext())
				{
					filecharset = validateCharset(i.next());
				} else
				{
					usage("-c option requires a charset name");
				}
			} else if (arg.equals("-t"))
			{
				if (i.hasNext())
				{
					Console.setCharset(validateCharset(i.next()));
				} else
				{
					usage("-t option requires a charset name");
				}
			} else if (arg.equals("-r"))
			{
				if (i.hasNext())
				{
					Settings.release = Release.lookup(i.next());

					if (Settings.release == null)
					{
						usage("-r option must be " + Release.list());
					}
				} else
				{
					usage("-r option requires a VDM release");
				}
			} else if (arg.equals("-pre"))
			{
				Settings.prechecks = false;
			} else if (arg.equals("-post"))
			{
				Settings.postchecks = false;
			} else if (arg.equals("-inv"))
			{
				Settings.invchecks = false;
			} else if (arg.equals("-dtc"))
			{
				// NB. Turn off both when no DTC
				Settings.invchecks = false;
				Settings.dynamictypechecks = false;
			} else if (arg.equals("-measures"))
			{
				Settings.measureChecks = false;
			} else if (arg.equals("-log"))
			{
				if (i.hasNext())
				{
					logfile = i.next();
				} else
				{
					usage("-log option requires a filename");
				}
			} else if (arg.equals("-remote"))
			{
				if (i.hasNext())
				{
					interpret = true;
					remoteName = i.next();
				} else
				{
					usage("-remote option requires a Java classname");
				}
			} else if (arg.equals("-default"))
			{
				if (i.hasNext())
				{
					defaultName = i.next();
				} else
				{
					usage("-default option requires a name");
				}
			} else if (arg.equals("-path"))
			{
				if (i.hasNext())
				{
					File path = new File(i.next());

					if (path.isDirectory())
					{
						pathnames.add(path);
					} else
					{
						usage(path + " is not a directory");
					}
				} else
				{
					usage("-path option requires a directory");
				}
			}else if (arg.equals("-baseDir"))
			{
				if (i.hasNext())
				{
					try
					{
						Settings.baseDir = new File(i.next());
					} catch (IllegalArgumentException e)
					{
						usage(e.getMessage() + ": " + arg);
					}
				} else
				{
					usage("-baseDir option requires a folder name");
				}
			}  else if (arg.startsWith("-"))
			{
				usage("Unknown option " + arg);
			} else
			{
				// It's a file or a directory
				File file = new File(arg);

				if (file.isDirectory())
				{
					for (File subFile : file.listFiles(dialect.getFilter()))
					{
						if (subFile.isFile())
						{
							filenames.add(subFile);
						}
					}
				} else
				{
					if (file.exists())
					{
						filenames.add(file);
					} else
					{
						boolean OK = false;

						for (File path : pathnames)
						{
							File pfile = new File(path, arg);

							if (pfile.exists())
							{
								filenames.add(pfile);
								OK = true;
								break;
							}
						}

						if (!OK)
						{
							usage("Cannot find file " + file);
						}

					}
				}
			}
		}

		if (controller == null)
		{
			usage("You must specify either -vdmsl, -vdmpp or -vdmrt");
		}

		if (logfile != null && !(controller instanceof VDMRT))
		{
			usage("The -log option can only be used with -vdmrt");
		}

		if (remoteName != null)
		{
			try
			{
				Class cls = ClassLoader.getSystemClassLoader().loadClass(remoteName);
				remoteClass = (Class) cls;
			} catch (ClassNotFoundException e)
			{
				usage("Cannot locate " + remoteName + " on the CLASSPATH");
			}
		}

		ExitStatus status = null;

		if (filenames.isEmpty() && (!interpret || remoteClass != null))
		{
			usage("You didn't specify any files");
			status = ExitStatus.EXIT_ERRORS;
		} else
		{
			do
			{
				if (filenames.isEmpty())
				{
					status = controller.interpret(filenames, null);
				} else
				{
					status = controller.parse(filenames);

					if (status == ExitStatus.EXIT_OK)
					{
						status = controller.typeCheck();

						if (status == ExitStatus.EXIT_OK && interpret)
						{
							if (remoteClass == null)
							{
								status = controller.interpret(filenames, defaultName);
							} else
							{
								try
								{
									final RemoteControl remote = remoteClass.newInstance();
									Interpreter i = controller.getInterpreter();

									if (defaultName != null)
									{
										i.setDefaultName(defaultName);
									}

									i.init(null);

									try
									{
										// remote.run(new RemoteInterpreter(i, null));
										final RemoteInterpreter remoteInterpreter = new RemoteInterpreter(i, null);
										Thread remoteThread = new Thread(new Runnable()
										{

											public void run()
											{
												try
												{
													remote.run(remoteInterpreter);
												} catch (Exception e)
												{
													println(e.getMessage());
													// status = ExitStatus.EXIT_ERRORS;
												}
											}
										});
										remoteThread.setName("RemoteControl runner");
										remoteThread.setDaemon(true);
										remoteThread.start();
										remoteInterpreter.processRemoteCalls();
										status = ExitStatus.EXIT_OK;
									} catch (Exception e)
									{
										println(e.getMessage());
										status = ExitStatus.EXIT_ERRORS;
									}
								} catch (InstantiationException e)
								{
									usage("Cannot instantiate " + remoteName);
								} catch (Exception e)
								{
									usage(e.getMessage());
								}
							}
						}
					}
				}
			} while (status == ExitStatus.RELOAD);
		}

		if (interpret)
		{
			infoln("Bye");
		}

		System.exit(status == ExitStatus.EXIT_OK ? 0 : 1);
	}

	private static void usage(String msg)
	{
		System.err.println("Overture: " + msg + "\n");
		System.err.println("Usage: Overture <-vdmsl | -vdmpp | -vdmrt> [] []");
		System.err.println("-vdmsl: parse files as VDM-SL");
		System.err.println("-vdmpp: parse files as VDM++");
		System.err.println("-vdmrt: parse files as VDM-RT");
		System.err.println("-path: search path for files");
		System.err.println("-r : VDM language release");
		System.err.println("-w: suppress warning messages");
		System.err.println("-q: suppress information messages");
		System.err.println("-i: run the interpreter if successfully type checked");
		System.err.println("-p: generate proof obligations and stop");
		System.err.println("-e : evaluate  and stop");
		System.err.println("-c : select a file charset");
		System.err.println("-t : select a console charset");
		System.err.println("-o : saved type checked specification");
		System.err.println("-default : set the default module/class");
		System.err.println("-pre: disable precondition checks");
		System.err.println("-post: disable postcondition checks");
		System.err.println("-inv: disable type/state invariant checks");
		System.err.println("-dtc: disable all dynamic type checking");
		System.err.println("-measures: disable recursive measure checking");
		System.err.println("-log: enable real-time event logging");
		System.err.println("-remote : enable remote control");

		System.exit(1);
	}

	/**
	 * Parse the list of files passed. The value returned is the number of syntax errors encountered.
	 * 
	 * @param files
	 *            The files to parse.
	 * @return The number of syntax errors.
	 */

	public abstract ExitStatus parse(List files);

	/**
	 * Type check the files previously parsed by {@link #parse(List)}. The value returned is the number of type checking
	 * errors.
	 * 
	 * @return The number of type check errors.
	 */

	public abstract ExitStatus typeCheck();

	/**
	 * Generate an interpreter from the classes parsed.
	 * 
	 * @return An initialized interpreter.
	 * @throws Exception
	 */

	public abstract Interpreter getInterpreter() throws Exception;

	/**
	 * Interpret the type checked specification. The number returned is the number of runtime errors not caught by the
	 * interpreter (usually zero or one).
	 * 
	 * @param filenames
	 *            The filenames currently loaded.
	 * @param defaultName
	 *            The default module or class (or null).
	 * @return The exit status of the interpreter.
	 */

	abstract protected ExitStatus interpret(List filenames,
			String defaultName);

	/**
	 * Dump log files
	 */
	protected void dumpLogs()
	{
		if (logfile != null)
		{
			RTLogger.dump(true);
			infoln("RT events dumped to " + logfile);
		}
	}

	public void setWarnings(boolean w)
	{
		warnings = w;
	}

	public void setQuiet(boolean q)
	{
		quiet = q;
	}

	public void setCharset(String charset)
	{
		filecharset = charset;
		Console.setCharset(charset);
	}

	protected static void info(String m)
	{
		if (!quiet)
		{
			print(m);
		}
	}

	protected static void infoln(String m)
	{
		if (!quiet)
		{
			println(m);
		}
	}

	protected static void print(String m)
	{
		Console.out.print(m);
		Console.out.flush();
	}

	protected static void println(String m)
	{
		Console.out.println(m);
	}

	protected String plural(int n, String s, String pl)
	{
		return n + " " + (n != 1 ? s + pl : s);
	}

	private static String validateCharset(String cs)
	{
		if (!Charset.isSupported(cs))
		{
			println("Charset " + cs + " is not supported\n");
			println("Available charsets:");
			println("Default = " + Charset.defaultCharset());
			Map available = Charset.availableCharsets();

			for (Entry entry : available.entrySet())
			{
				println(entry.getKey() + " "
						+ available.get(entry.getValue()).aliases());
			}

			println("");
			usage("Charset " + cs + " is not supported");
		}

		return cs;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy