/*
 * Copyright (c) 2002-2006 Samit Basu
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef __Interpreter_h__
#define __Interpreter_h__

#include "Tree.hpp"
#include "Context.hpp"
#include "FunctionDef.hpp"
#include "Array.hpp"
#include <stack>
#include <string>
#include <vector>
#include <QStringList>
#include <QObject>
#include <QMutex>
#include <QWaitCondition>
#include <QThread>

using namespace std;

class InterpreterContinueException : public exception {};
class InterpreterBreakException : public exception {};
class InterpreterReturnException : public exception {};
class InterpreterRetallException : public exception {};
class InterpreterQuitException : public exception {};
class InterpreterKillException : public exception {};

class stackentry {
public:
  string cname;
  string detail;
  int tokid;
  int number;
  int steptrap;
  int stepcurrentline;
    
  // A number of -1 corresponds to a temporary breakpoint 
  stackentry(string cntxt, string detail, int id, 
	     int num = 0, int strp = 0, int stcl = 0);
  stackentry();
  ~stackentry();
};

class Interpreter;
class UserClass;

typedef Array (*BinaryFunc)(Array, Array, Interpreter*);
typedef Array (*UnaryFunc)(Array, Interpreter*);

/**
 * This is the class that implements the interpreter - it generally
 * operates on abstract syntax trees (ASTs).
 */
class Interpreter : public QThread {
  Q_OBJECT

  /******************************************
   *  Class Members for the Interpreter     *
   ******************************************/

  /**
   * Members related to "end" references.
   */
  ArrayReference endRef;
  int endTotal;
  int endCount;

  /**
   * Debugger related values
   */
  int steptrap;
  int stepcurrentline;
  int tracetrap;
  int tracecurrentline;
  string stepname;

  /**
   * Tracks the number of errors that have occured (used by the documentation
   * compiler helpgen)
   */
  int errorCount;
  /**
   * The context that the intepreter operates in.
   */
  Context* context;
  /**
   * The debug depth.  Each time the command line interface is invoked
   * via a keyboard command, the debug depth is increased.
   */
  int depth;  
  /**
   * The print limit (how many elements get printed before output 
   * stops).
   */
  int printLimit;
  /**
   * The last error that occured.
   */
  string lasterr;
  /**
   * autostop storage flag
   */
  bool autostop;
  /**
   * jit control flag
   */
  bool jitcontrol;
  /**
   * When this flag is active, autostop does nothing.
   */
  bool InCLI;
  /**
   * This mutex protects the command buffer.
   */
  QMutex mutex;
  /**
   * The command buffer
   */
  vector<string> cmd_buffer;
  /**
   * A buffer of return values from graphics calls
   */
  vector<ArrayVector> gfx_buffer;
  /**
   * A flag to indicate that the gfx call failed
   */
  bool gfxErrorOccured;
  /**
   * The corresponding exception.
   */
  string gfxError;
  /**
   * A synchronization variable to wait on when the command buffer is empty
   */
  QWaitCondition bufferNotEmpty;
  /**
   * A synchronization variable to wait on when the gfx buffer is empty
   */
  QWaitCondition gfxBufferNotEmpty;
  /**
   * This is the equivalent of an "instruction pointer".  It stores the
   * function name and some detailed information on our location.
   */
  string ip_funcname;
  string ip_detailname;
  int ip_context;
  /**
   * For technical reasons, the interpreter stores a mirror of the call stack
   * in this member.
   */
  vector<stackentry> cstack;
  /**
   * A list of breakpoints
   */
  vector<stackentry> bpStack;
  /**
   * True if the interpreter is in single-step mode
   */
  bool inStepMode;
  /**
   * The effective location of the next breakpoint (if single stepping)
   */
  stackentry stepTrap;
  /**
   * The class records (store information about each user defined class)
   */
  SymbolTable<UserClass> classTable;
  /**
   * Set this flag to true to stop overloading of methods
   */
  bool stopoverload;
  /**
   * The base path - contains all of the directories for FreeMat-shipped code
   */
  QStringList m_basePath;
  /**
   * The user path - contains all of the directories for user defined FreeMat code
   */
  QStringList m_userPath;
  /**
   * The width of the output in characters
   */
  int m_ncols;
  /**
   * This flag controls the greeting
   */
  bool m_skipflag;
  /**
   * Our thread ID
   */
  int m_threadID;
  /**
   * The thread function we are executing
   */
  FunctionDef *m_threadFunc;
  /**
   * The arguments to the thread function we are executing
   */
  ArrayVector m_threadFuncArgs;
  /**
   * The number of return arguments expected
   */
  int m_threadNargout;
  /**
   * The return value of the thread function
   */
  ArrayVector m_threadFuncRets;
  /**
   * The error state of the thread function (true if an exception
   * occured).
   */
  bool m_threadErrorState;
  /**
   * Interrupt the current thread at the next opportunity
   */
  bool m_interrupt;
   /**
   * Kill the thread at the next opportunity
   */
  bool m_kill;
  /**
   * The current state of diary output
   */
  bool m_diaryState;
  /**
   * The filename for the diary
   */
  string m_diaryFilename;
  /**
   * The capture string
   */
  string m_capture;
  /**
   * The capture state
   */
  bool m_captureState;
  /**
   * The quiet level
   */
  int m_quietlevel;
  /******************************************
   *  Public Methods for the Interpreter    *
   ******************************************/
public:
  /**
   * Construct a Interpreter object with the given context to operate
   * in.
   */
  Interpreter(Context* aContext);
  /**
   * Destruct the Interpreter object.
   */
  ~Interpreter();
  /**
   * Set the thread ID to the given number...
   */
  inline void setThreadID(int threadID) {m_threadID = threadID;}
  /**
   * Return the thread ID
   */
  inline int getThreadID() const {return m_threadID;}
  /**
   * Set the thread function and the arguments
   */
  inline void setThreadFunc(FunctionDef *threadFunc, 
			    int nargout,
			    ArrayVector threadFuncArgs) { 
    m_threadFunc = threadFunc;  
    m_threadFuncArgs = threadFuncArgs; 
    m_threadNargout = nargout;
    m_threadErrorState = false;
  }
  /**
   * Manipulate the quiet level
   */
  inline int getQuietLevel() {return m_quietlevel;}
  inline void setQuietLevel(int t) {m_quietlevel = t;}
  /**
   * Manipulate the diary state
   */
  inline bool getDiaryState() {return m_diaryState;}
  inline void setDiaryState(bool t) {m_diaryState = t;}
  inline void setDiaryFilename(string name) {m_diaryFilename = name;}
  void diaryMessage(string msg);
  /**
   * Manipulate the capture state
   */
  inline void clearCaptureString() {m_capture = "";}
  inline void setCaptureState(bool t) {m_captureState = t;}
  inline string getCaptureString() {return m_capture;}
  /**
   * Get the result of the thread function evaluation
   */
  inline ArrayVector getThreadFuncReturn() {return m_threadFuncRets;}
  /**
   * Get the error state - is true if the thread function throws
   * an exception.
   */
  inline bool getLastErrorState() {return m_threadErrorState;}
  /**
   * Activate the interrupt for the thread - so that it stops.
   */
  inline void setInterrupt() {m_interrupt = true;}
   /**
   * Activate the kill for the thread - so that it dies.
   */
  inline void setKill() {m_kill = true;}
  /**
   * Run a command-line-interface interface from this thread.
   */
  void doCLI();
  /**
   * Queue a command for execution
   */
  void ExecuteLine(string txt);
  /**
   * Retrieve data about the current location of the instruction pointer
   */
  string getMFileName();
  string getInstructionPointerFileName();
  /**
   * The Base Path is the one that contains .m files in the current app bundle
   */
  void setBasePath(QStringList);
  /**
   * The User Path is the one that the user can tinker with.
   */
  void setUserPath(QStringList);
  /**
   * Get the current path set for the interface. (user path - legacy interface)
   */
  string getPath();
  /**
   * Get the current path set for the interface (base path + user path)
   */
  string getTotalPath();
  /**
   * Set the path for the interface. (user path - legacy interface)
   */
  void setPath(string);
  /**
   * Force a rescan of the current path to look for 
   * new function files.
   */
  void rescanPath();
  /**
   * Return the width of the current "terminal" in
   * characters.
   */
  int getTerminalWidth();
  /**
   * Set the width of the current "terminal" in characters
   */
  void setTerminalWidth(int ncols);
  /**
   * Output the following text message.
   */
  void outputMessage(string msg);
  void outputMessage(const char* format,...);
  /**
   * Output the following error message.
   */
  void errorMessage(string msg);
  /**
   * Output the following warning message.
   */
  void warningMessage(string msg);
  /**
   * Start the interpreter running.
   */
  void run();
  /**
   * Get/Set the overload stop flag
   */
  bool getStopOverload();
  void setStopOverload(bool flag);
  /**
   * Retrieve the version string for the interpreter
   */
  static string getVersionString();
  /**
   * Retrieve the number of errors that occured.  The
   * side effect is that the error count is set to zero.
   */
  int getErrorCount();
  /**
   * True if we are currently in the method of a class
   */
  bool inMethodCall(string classname);
  /**
   * Get the context for the interface.
   */
  inline Context* getContext() {return context;}
  /**
   * Refresh the breakpoints in the code.  Call this after updating
   * code for functions, or breakpoints will not work.
   */
  void refreshBreakpoints();
  /**
   * Add a new breakpoint
   */
  MFunctionDef* lookupFullPath(string name);
  void addBreakpoint(stackentry bp);
  void addBreakpoint(string name, int line) ;
  /**
   * Activate a breakpoint in the code.  If the line number for the
   * breakpoint is negative, the breakpoint is set as a step trap.  
   * If the line number is positive, and the enable flag is set 
   * then a breakpoint is set.  If the enable flag is false then
   * the breakpoint is cleared.
   */
  void setBreakpoint(stackentry bp, bool enableFlag);
  /**
   * List all breakpoints
   */
  void listBreakpoints();
  /**
   * Delete a breakpoint from the persistent list
   */
  void deleteBreakpoint(int number);
  /**
   * Generate a stacktrace
   */
  void stackTrace(bool includeCurrent);
  /**
   * Returns true if a userclass with the given name is defined
   */
  bool isUserClassDefined(string classname);
  /**
   * Lookup a user class.
   */
  UserClass lookupUserClass(string classname);
  /**
   * Register a new user class.
   */
  void registerUserClass(string classname, UserClass cdata);
  /**
   * Clear the registered class table
   */
  void clearUserClasses();
  /**
   * Push a function name and detail onto the debug stack
   */
  void pushDebug(string fname, string detail);
  /**
   * Pop the debug stack
   */
  void popDebug();
  /**
   * Step the given number of lines
   */
  void dbstepStatement(const tree &t);
  void dbtraceStatement(const tree &t);
  /**
   * Set the autostop flag - this flag determines what happens when
   * an exception occurs
   */
  inline bool AutoStop() {return autostop;}
  inline void AutoStop(bool a) {autostop = a;}
  /**
   * Set the JITControl flag
   */
  inline bool JITControl() {return jitcontrol;}
  inline void JITControl(bool a) {jitcontrol = a;}
  /**
   * Set the print limit (number of element printed prior to truncation).
   */
  void setPrintLimit(int);
  /**
   * Get the print limit (number of element printed prior to truncation).
   */
  int getPrintLimit();
  /**
   * The workhorse routine - "evaluate" the contents of a string
   * and execute it.  The flag indicates whether or not exceptions
   * are propogated or printed.
   */
  void evaluateString(string line, bool propogateExceptions = false);
  /**
   * Get the last error that occurred.
   */
  string getLastErrorString();
  /**
   * Set the text for the last error.
   */
  void setLastErrorString(string txt);
  /**
   * Set to false to turn off the greeting.
   */
  void setGreetingFlag(bool skip);
  /**
   * Register the result of a gfx call
   */
  void RegisterGfxResults(ArrayVector m);
  /**
   * Register an error that occurs with a gfx call
   */
  void RegisterGfxError(string msg);
  /**
   * Simplified interface for function lookup.
   */
  bool lookupFunction(string funcName, FuncPtr& val);
   /**
   * Prompt the user for input, and return the answer.
   */
  string getLine(string prompt);
  /**
   * Go to sleep for the specified number of milliseconds
   */
  void sleepMilliseconds(unsigned long msecs);
  /**
   * Executes a sequence of statements, trapping exceptions
   * as necessary.  The AST looks like
   *   <ignored>
   *      |
   *    statement->statement->statement
   * If an exception occurs, it is caught and rethrown.  The
   * lasterr string is also set to the contents of the exception.
   *
   */
  void block(const tree &t);
  /**
   * Start a command line interface.  Statements are retrieved
   * from the console, and executed sequentially until a "return"
   * statement is executed or the user presses 'CTRL-D'.
   */
  void evalCLI();

  bool isBPSet(QString fname, int lineNumber);
  bool isInstructionPointer(QString fname, int lineNumber);
  void toggleBP(QString fname, int lineNumber);

  /******************************************
   *  Signals for the Interpreter           *
   ******************************************/
signals:
  /**
   * Send a string of text to a terminal somewhere
   */
  void outputRawText(string);
  /**
   * Flush the I/O buffers
   */ 
  void Flush();
  /**
   * User has changed the current working directory
   */
  void CWDChanged();
  /**
   * Change the prompt
   */
  void SetPrompt(string);
  /**
   * Dispatch a graphics call
   */
  void doGraphicsCall(Interpreter*, FuncPtr, ArrayVector, int);
  /**
   * All done.
   */
  void QuitSignal();
  /**
   * Something went wrong...
   */
  void CrashedSignal();
  /**
   * Refresh the breakpoints 
   */
  void RefreshBPLists();
  /**
   * Show the current active line
   */
  void ShowActiveLine();
  /**
   * Enable repainting
   */
  void EnableRepaint();
  /**
   * Disable repainting
   */
  void DisableRepaint();

  /******************************************
   *  Private Methods for the Interpreter   *
   ******************************************/
private:
  /**
   * Execute a function that accesses the graphics subsystem.  All such
   * accesses must be made through the main thread.  So the interpreter
   * sends a signal out that a graphics call needs to be made, and then
   * waits for the result.
   */
  ArrayVector doGraphicsFunction(FuncPtr f, ArrayVector m, int narg_out);
  /**
   * Collect information about keyword usage and the relevant 
   * expressions from a function call
   */
  void collectKeywords(const tree &q, ArrayVector &keyvals,
		       treeVector &keyexpr, stringVector &keywords);
  /**
   * Sort keywords into a proper call order.
   */
  int* sortKeywords(ArrayVector &m, stringVector &keywords,
		    stringVector arguments, ArrayVector keyvals);
  /**
   * For values passed by reference, update the caller's variables.
   */
  void handlePassByReference(const tree &q, stringVector arguments,
			     ArrayVector m,stringVector keywords,
			     treeVector keyexpr, int* argTypeMap);
  /**
   * Create a variable in the correct scope, and return a reference to it
   */
  ArrayReference createVariable(string name);
  /**
   * Perform a binary operator with the given name
   */
  Array DoBinaryOperator(const tree &t, BinaryFunc fnc, string fname);
  /**
   * Perform a unary operator with the given name
   */
  Array DoUnaryOperator(const tree &t, UnaryFunc fnc, string fname);
  /**
   * Handle the construction of a function pointer
   */
  Array FunctionPointer(const tree &args);
  /**
   * Dispatch a function pointer
   */
  ArrayVector FunctionPointerDispatch(Array r, const tree &args, int narg_out);
  /**
   * Set the context of the interpreter.  This is an integer that indicates
   * where in the source file we are.
   */
  inline void SetContext(int id);
  /**
   * Clear the context stacks.
   */
  void clearStacks();
  /**
   * Convert a matrix definition of the form: [expr1,expr2;expr3;expr4] into
   * a vector of row definitions.  The first row is the vector [expr1,expr2], and
   * the second is the vector [expr3,expr4].  The AST input should look like:
   *  []
   *   |
   *   ;-> ; -> ... -> NULL
   *   |   |
   *   |   rowDef
   *   rowDef
   */
  Array matrixDefinition(const tree &t);
  /**
   * Convert a cell defintion of the form: {expr1,expr2;expr3;expr4} into
   * a vector of row definitions.  The first row is the vector {expr1,expr2}, and
   * the second is the vector {expr3,expr4}.  The AST input should look like:
   *  {}
   *   |
   *   ;-> ; -> ... -> NULL
   *   |   |
   *   |   rowDef
   *   rowDef
   */
  Array cellDefinition(const tree &t);
  /**
   * Evaluate the expression pointed to by the AST t into a variable.
   */
  Array expression(const tree &t);

  ArrayVector handleReindexing(const tree &t, const ArrayVector &p);
  
  /**
   * Evaluate the expression into a variable-array
   */
  void multiexpr(const tree &t, ArrayVector& m, int lhsCount = 1);

  /**
   * Evaluate a unit colon expression.  The AST input should look like:
   *   :
   *   |
   *   expr1->expr2
   *
   * The output is the expression expr1:expr2, which is the vector
   * [expr1,expr1+1,expr1+2,...,expr1+n], where n is the largest 
   * integer such that expr1+n <= expr2.
   */
  Array unitColon(const tree &t);
  /**
   * Evaluate a double colon expression.  The AST input should look like:
   *   :
   *   |
   *   :->expr3
   *   |
   *   expr1->expr2
   * The output is the expression expr1:expr2:expr3, which is the
   * vector [expr1,expr1+expr2,expr1+2*expr2,...,expr1+n*expr2], where
   * n is the largest integer such that expr1+n*expr2 <= expr3.
   */
  Array doubleColon(const tree &t);
  /**
   * Decode references to ":" inside variable dereferences.
   */
  Array AllColonReference(Array v, int index, int count);
  /**
   * Handle statements that are simply expressions
   */
  void expressionStatement(const tree &t, bool printIt);
  /**
   * The RHS expression is used to represent an rvalue in an
   * assignment statement (or an implicit assignment such as 
   * -->2+3).  The form of the AST depends on the head.  If the
   * head identifier is a function name, then the form of the
   * AST is:
   *    ident
   *     |
   *     ()
   *     |
   *     expr1->expr2->...
   * On the other hand, if the identifier represents a variable
   * (variables are checked for first, incidentally), then the AST
   * looks like:
   *    ident
   *     |
   *     ()->{}->.
   *     |   |   |
   *     |   |   field

   *     |   expr3->...
   *     expr1->expr2->...
   * Throws an Exception 
   *    - if the identifier cannot be matched to
   *      either a variable or function.  
   *    - 
   */
  ArrayVector rhsExpression(const tree &t, int lhsCount = 1);

  void assign(ArrayReference r, const tree &s, Array &data);

  void multiassign(ArrayReference r, const tree &s, ArrayVector& m);

  void deref(Array &r, const tree &s);

  Array rhs(const tree &t);
  /**
   * Look up an identifier as a potential function name, using a
   * rescan if the identifier is not found on the first pass.
   */
  bool lookupFunction(string funcName, FuncPtr& val, 
		      ArrayVector& args, bool disableOverload = false);
  /**
   * Special case the single assignment statement 'A = B' for speed.
   */
  void assignment(const tree &var, bool printIt, Array &b);
  /**
   * Try to figure out how many outputs there should be to a multifunction
   * call.  In particular, logic is used to figure out what to do about
   * undefined variables.
   */
  int countLeftHandSides(const tree &t);
  /**
   * Evaluate a function and return the results of the function as
   * an ArrayVector.  For scripts, the body of the function is
   * evaluated directly.  Otherwise, the function evaluates itself
   * (using the FunctionDef::evaluateFunction member function).  The
   * arguments to the function are unpacked from the AST ast follows
   *   ident
   *    |
   *    ()
   *    |
   *    expr1->expr2->...
   * The outputOptional flag allows the function to not assign an 
   * output.
   * Throws an exception if 
   *    - something other than a parenthesis pair "()" follows the 
   *      identifier.  
   *    - if too many arguments are passed to the function.
   *    - too many outputs are requested from the function.
   */
  void functionExpression(const tree &t, int narg_out, bool outputOptional, ArrayVector &output);
  /**
   * A multifunction call is an expression of the sort
   * [expr1,expr2,...,exprn] = func(args).  The AST is
   *    multiCall
   *       |
   *       []->functionExpression_AST
   *       |
   *       ;->NULL
   *       |
   *       rowDefs
   * When calculating the number of left hand sides for the
   * multifunction, single variables without subindexing expressions
   * are counted as a single left hand side.  Thus, an expression
   * such as [A{1:3},B] = func(args) counts for four left hand
   * sides, regardless of the contents of B.
   * If the printIt flag is set, each of the outputs is to be
   * written to the console.
   * Throws an exception if the AST is malformed (i.e., the '[]' is
   * missing, or there are multiple rows in the left hand side.).
   */
  void multiFunctionCall(const tree &t, bool printIt);
  /**
   * A special function call is an expression of the form
   * >> func arg1 arg2 arg3
   * which is represented in an AST is
   *     scall
   *       |
   *       fname->arg
   */
  void specialFunctionCall(const tree &t, bool printIt);
  /**
   * Handles an if statement, corresponding to an if, a number
   * of elseif blocks and an optional else statement.  The AST looks
   * like
   *     cstat->elseIfBlock->elseCode
   *      |        |
   *      |       cstat->cstat->cstat
   *     expr->codeBlock
   * where each of the elseIf blocks are tested sequentially until
   * one of them succeeds.
   */
  void ifStatement(const tree &t);
  /**
   * Handle a switch statement.  The switch statement tests
   * an expression against a number of case blocks.  If a 
   * case block matches, the code in the case block is 
   * executed, and the switch statement quits.  If none of the
   * case blocks match, the otherwise code is executed. The 
   * AST looks like
   *     expr->caseBlock->otherwiseCode
   *              |
   *             testCase->testCase->...->NULL
   * Where testCase is the AST passed to testCaseStatement. For
   * a switch statement, the switch value must be either a 
   * scalar value or a string.  The test values in each case
   * statement can either be the same type, or a cell array.
   * If it is a cell array, then the switch value is compared
   * with each entry in the case expression.
   * Throws an Exception if the switch expression is not
   * either a scalar or a string.
   */
  void switchStatement(const tree &t);
  /**
   * Implements the for control statement.  The AST looks like
   *     ident->codeBlock
   *       |
   *      expr
   * The identifier used as the control variable in the for 
   * statement.  The variable defined by the identifier takes
   * on each of the values in the expression.  For each such
   * assignment, the code in the codeBlock is executed.
   */
  void forStatement(const tree &t);
  /**
   * Implements the while control statement.  The AST looks like
   *     expr->codeBlock
   * The test expression is evaluated until it fails, and for each
   * successful expression, the codeBlock is executed.
   */
  void whileStatement(const tree &t);
  /**
   * Implements the try statement.  The AST looks like
   *     block->catchBlock
   * The code in block is executed.  If an exception occurs, then
   * the code in catchBlock is executed.
   */
  void tryStatement(const tree &t);
  /**
   * Implements the global statement (really a global declaration).
   * The AST looks like:
   *    ident
   *     |
   *    ident
   *     |
   *    etc.
   * Each identifier is added to the global variable list of
   * the current context.
   */
  void globalStatement(const tree &t);
  /**
   * Implements the persistent statement (really a persistent declaration).
   * The AST looks like:
   *    ident
   *     |
   *    ident
   *     |
   *    etc.
   * Each identifier is added to the persistent variable list of
   * the current context.
   */
  void persistentStatement(const tree &t);
  /**
   * This somewhat strange test is used by the switch statement.
   * If x is a scalar, and we are a scalar, this is an equality
   * test.  If x is a string and we are a string, this is a
   * strcmp test.  If x is a scalar and we are a cell-array, this
   * test is applied on an element-by-element basis, looking for
   * any matches.  If x is a string and we are a cell-array, then
   * this is applied on an element-by-element basis also.
   * The AST for this looks like:
   *     FM_CASE
   *       |
   *      expr->codeBlock
   * The expression is compared to x using Array::testForCaseMatch.
   * If a match is found, then the codeBlock is executed.  The result of
   * the test is returned.  Throws an exception if the AST is
   * malformed.
   */
  bool testCaseStatement(const tree &t, Array x);
  /**
   * Execute the statement described by the AST - the printIt flag
   * determines if the result of the statement should be printed to
   * the console.  The form of the AST required depends on the
   * type of statement being executed.  The various statement types
   * handled are as follows:
   *   =          Assignment of expression to LHS
   *   | 
   *  LHS->expr
   *
   *  multicall   Multifunction call
   *   |
   *  multicallBody
   *
   *  FM_FOR      For statement
   *   |
   *  forBody
   *
   *  FM_WHILE    While statement
   *   |
   *  whileBody
   *
   *  FM_IF       If statement
   *   |
   *  ifBody
   *
   *  FM_BREAK    Break statement - change the state of the interpreter to
   *              FM_STATE_BREAK
   *  
   *  FM_CONTINUE Continue statement - change the state of the interpreter
   *              to FM_STATE_CONTINUE
   *
   *  FM_RETURN   Return statement - change the state to FM_STATE_RETURN
   *
   *  FM_SWITCH   Switch statement
   *   |
   *  switchBody
   *
   *  FM_TRY      Try statement
   *   |
   *  tryBody  
   *
   *  FM_KEYBOARD Enter another CLI session
   *
   *  FM_GLOBAL   A global declaration
   *   |
   *  globalBody
   *
   *  FM_PERSISTENT A persistent declaration
   *   |
   *  persistentBody
   *
   *  rhs         A function call being evaluated as a statement
   *   |
   *  funcName
   *
   *  expr        An expression being evaluated as a statement
   *
   * The function call is trapped before the expression to handle
   * the special variable "ans".
   * Throws an Exception if the statement type is not recognized.
   */
  void processBreakpoints(const tree &t);
  void statementType(const tree &t, bool printIt);
  /**
   * The statement method simply screens out the need for the
   * printIt flag.  It also retrieves the statement context
   * for use in error reporting.  The AST looks like:
   *   qstatement          A quiet statement (printIt -> false)
   *      |
   *    context (optional)
   *      |
   *  statementBody
   *
   *   rstatement          A normal statement (printIt -> true)
   *      |
   *    context (optional)
   *      |
   *  statementBody
   * The context data is supplied by the parse (indicates the
   * line number and filename if necessary).
   */
  void statement(const tree &t);
  /**
   * Handles the logistics of shortcut evaluation
   */
  Array ShortCutOr(const tree &t);
  Array ShortCutAnd(const tree &t);
  /**
   * Display an array - added so user classes divert to "display" function
   */
  void displayArray(Array b);
  /**
   * Mangle a function name to get the private version (if it exists)
   */
  string getPrivateMangledName(string fname);
  string getLocalMangledName(string fname);
  /**
   * Convert variables into indexes, calls "subsindex" for user classes.
   */
  Array subsindex(const Array &m);
  void subsindex(ArrayVector& m);
  /**
   * Enter a debug cycle
   */
  void doDebugCycle();
  /**
   * Send a greeting to the user.
   */
  void sendGreeting();
  /**
   * Scan the given directory for .m, .p, classes, etc.  If tempfunc
   * is true, then these functions are marked as temporary (so changing
   * the working directory flushes them).
   */
  void scanDirectory(string scdir, bool tempfunc, string prefixo);
  /**
   * Add the specified .m file to the current context
   */
  void procFileM(string fname, string fullname, bool tempfunc);
  /**
   * Add the specified .p file to the current context
   */
  void procFileP(string fname, string fullname, bool tempfunc);
  /**
   * Add the specified .mex file to the current context
   */
  void procFileMex(string fname, string fullname, bool tempfunc);

  friend Array IndexExpressionToStruct(Interpreter*, const tree&, Array);
  friend ArrayVector ClassRHSExpression(Array, const tree&, Interpreter*);
  friend ArrayVector PCodeFunction(int, const ArrayVector&, Interpreter*);
  friend class MFunctionDef;
  friend class ImportedFunctionDef;
  friend class AnonymousFunctionDef;
};

void sigInterrupt(int arg);
string TrimFilename(string);
QString TildeExpand(string);
#endif


syntax highlighted by Code2HTML, v. 0.9.1