// ---------------------------------------------------------------------------
// - Interp.hpp                                                              -
// - aleph engine - interpreter class definition                             -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - 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.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2003 amaury darsch                                   -
// ---------------------------------------------------------------------------

#ifndef  ALEPH_INTERP_HPP
#define  ALEPH_INTERP_HPP

#ifndef  ALEPH_STRVEC_HPP
#include "Strvec.hpp"
#endif

#ifndef  ALEPH_TERMINAL_HPP
#include "Terminal.hpp"
#endif

#ifndef  ALEPH_GLOBALSET_HPP
#include "Globalset.hpp"
#endif

#ifndef  ALEPH_STACK_HPP
#include "Stack.hpp"
#endif

#ifndef  ALEPH_RESOLVER_HPP
#include "Resolver.hpp"
#endif

#ifndef  ALEPH_RUNNABLE_HPP
#include "Runnable.hpp"
#endif

namespace aleph {

  /// The Interp class is the main aleph interpreter engine. The interpreter
  /// operates on three streams, the standard input, the standard output and
  /// the standard error stream. By default, the interpreter install a 
  /// terminal object, unless the three streams are specified at construction.
  /// The interpreter holds a series of registers. For each basic types,
  /// like integer, real, character and boolean, the interpreter has 256 
  /// local thread registers. The operations associated with the registers
  /// are type dependant. For integer and real, these are mostly arithmetic 
  /// operations. For boolean, these are logical operations. The interpreter 
  /// has a top level (or global) nameset. The global nameset is shared 
  /// between all interpreters and is referenced as '...'. On top of this, 
  /// the interpreter provides a 'compile' method which takes a form and 
  /// generates a new one. The sole purpose of the compile method is to
  /// perform static checking and generate a new form ready for execution.
  /// @author amaury darsch

  class Interp : public Runnable {
  private:
    /// the standard input stream
    mutable Input* p_is;
    /// the standard output stream
    mutable Output* p_os;
    /// the standard error stream
    mutable Output* p_es;
    /// the assert flag
    bool d_assert;
    /// the cloned interpreter flag
    bool d_cloned;
    /// the posted object
    Object* p_posted;
    /// the interpreter global nameset
    Globalset* p_gset;
    /// the execution stack
    Stack* p_stk;
    /// the vector arguments
    Vector* p_argv;
    /// the runnable form
    Object* p_rform;
    /// the vector of shared libraries
    Vector* p_shlib;
    /// the vector of namesets
    Vector* p_vnset;

  protected:
    /// the default terminal
    Terminal* p_term;
    /// the path resolver
    Resolver* p_rslv;
    /// the next flag
    bool d_next;

  public:
    /// create a default interpreter
    Interp (void);

    /// create a new interpreter
    /// @param is the standard input stream
    /// @param os the standard output stream
    /// @param es the standard error stream
    Interp (Input* is, Output* os, Output* es);

    /// copy constructor for this interpreter
    /// @param that the interpreter to copy
    Interp (const Interp& that);

    /// destroy this interpreter
    ~Interp (void);

    /// @return the class name
    String repr (void) const;

    /// make this interpreter a shared object
    void mksho (void);

    /// post an object in this interpreter
    void post (Object* object);

    /// clone this interpreter
    Interp* clone (void);

    /// clone this interpreter and set the runnable form
    /// @param form the runnable form to set
    Interp* clone (Object* form);

    /// evaluate the runnable form
    Object* run (void);

    /// evaluate a form in a thread by cloning this interpreter
    /// @param form the form to evaluate
    Object* launch (Object* form);

    /// evaluate a form in a daemon thread by cloning this interpreter
    /// @param form the form to evaluate
    Object* daemon (Object* form);

    /// @return the interpreter input stream
    Input* getis (void) const;

    /// @return the interpreter output stream
    Output* getos (void) const;

    /// @return the interpreter error stream
    Output* getes (void) const;

    /// @return the interpreter stack
    Stack* getstk (void) const;

    /// @return the interpreter global nameset
    Nameset* getgset (void) const;

    /// set the interpreter arguments
    /// @param args the arguments to set
    void setargs (const Strvec& args);

    /// @return the interpreter arguments
    Strvec getargs (void) const;

    /// add a path to the resolver
    /// @param path the path to add
    void addpath (const String& path);

    /// set the resolver with a list of path
    /// @param path the path to set
    void setpath (const Strvec& path);

    /// set the assert flag
    /// @param flag the flag to set
    void setassert (const bool flag);

    /// @return the assert flag
    bool getassert (void) const;

    // create a new reserved name in the global nameset
    /// @param name the reserved name
    /// @param object the object to bind
    void mkrsv (const String& name, Object* object);

    /// create a new nameset in reference to a parent one
    /// @param name the nameset name to create
    /// @param parent the parent nameset
    Nameset* mknset (const String& name, Nameset* parent);

    /// open a new dynamic library by name
    /// @param name the library name
    /// @param argv the vector arguments
    Object* library (const String& name, Vector* argv);
 
    /// set the next flag
    /// @param flag the flag to set
    void setnext (const bool flag);

    /// @return the next flag
    bool getnext (void) const;

    /// break the runnable in a nameset with an object
    /// @param nset   the nameset to loop
    /// @param object the object to break on
    bool bpt (Nameset* nset, Object* object);

    /// loop in the context of a nameset
    /// @param nset the nameset context
    bool loop (Nameset* nset);

    /// run the read-eval loop with a file
    /// @param fname the file name to read
    void load (const String& fname);

    /// run the read-eval loop on the standard streams
    /// @return false if something bad happen
    bool loop (void);

    /// run the read-eval loop with a file
    /// @param fname the file name to read
    /// @return false if something bad happen
    bool loop (const String& fname);

    /// compile from an input stream to an output stream
    /// @param the file to compile
    /// @param os the output stream to write
    void compile (const String& name, Output& os);
    
    /// evaluate an object in this interpreter
    /// @param object the object to evaluate
    Object* eval (Object* object);

    /// evaluate an interpreter method by quark
    /// @param robj  the current runnable
    /// @param nset  the current nameset    
    /// @param quark the quark to evaluate
    Object* eval (Runnable* robj, Nameset* nset, const long quark);

    /// apply this interpreter with a set of arguments and a quark
    /// @param robj  the current runnable
    /// @param nset  the current nameset    
    /// @param quark the quark to apply these arguments
    /// @param argv  the arguments to apply
    Object* apply (Runnable* robj, Nameset* nset, const long quark,
		   Vector* argv);

  private:
    // make the assignment operator private
    Interp& operator = (const Interp&);
  };
}

#endif
