// ------------------------------------------------------------
//  Copyright (C) 2002-2003 Michael Zeilfelder
//  e-mail: info@michaelzeilfelder.de
//
//  This program is published under the terms of the GNU
//  General Public License version 2 as published by the Free
//  Software Foundation.
// ------------------------------------------------------------
// Simple Lisp-like Interpreter
// Does not support complete Lisp yet
// TODO: Memory management (currently none, so it leaves lot of
// leakes)
// ------------------------------------------------------------
#ifndef _LISP_H
#define _LISP_H

#include <list>
#include <string>
#include <map>
#include "LispFuncs.h"

class Token
{
public:
    Token(const string str_)        { Set(str_); }
    void Set(const string str_);
    const string& Get()             { return m_str; }
    bool IsNumber()                 { return m_isNumber; }
    double GetNumber();

protected:
    bool CheckForNumber(const string& str_);

private:
    string  m_str;
    bool    m_isNumber;
};

enum ENodeType
{
    NT_NUMBER = 0,
    NT_SYMBOL,
    NT_CELL,
};

class LispNode
{
public:
    LispNode(ENodeType type_) : m_type(type_)   {}

    ENodeType m_type;
};

class LispCell : public LispNode
{
public:
    LispCell( LispNode * first_, LispNode *rest_) : LispNode(NT_CELL)
    {   m_first = first_; m_rest = rest_; }

    LispNode * m_first;
    LispNode * m_rest;
};

class LispNumber : public LispNode
{
public:
    LispNumber( double val_) : LispNode(NT_NUMBER)
    {   m_val = val_; }

    double m_val;
};

class LispSymbol : public LispNode
{
public:
    LispSymbol(const string & string_)  : LispNode(NT_SYMBOL)
    { m_symbol = string_; }

    string m_symbol;
};

class LispDefun
{
    LispNode * m_function;
};

class LispInterpreter
{
public:
    LispInterpreter();
    ~LispInterpreter();

    void Tokenize(const string& str_);
    void Parse();
    void Evaluate();
    void Print();
    void ShowTokens();

    // add a function who's arguments will be evaluted first
    void AddFunction( string name_, LispCallPtr fn_ );
    // add a functions which gets arguments which were not evaluated
    void AddSpecialFunction( string name_, LispCallPtr fn_ );

    //
    // Some useful lisp-like commands (names are historical).
    // This are the commands which should always be used to access the internal
    // lisp structure

    // evaluate expression
    LispNode * Eval(LispNode * expr_);
    // get first list element
    LispNode * Car( LispNode * node_ ) { return node_ ? (node_->m_type == NT_CELL ? ((LispCell*)node_)->m_first : NULL) : NULL ; }
    // get rest of list
    LispNode * Cdr( LispNode * node_ ) { return node_ ? (node_->m_type == NT_CELL ? ((LispCell*)node_)->m_rest : NULL) : NULL; }
    // make a new lisp cell
    LispNode * Cons( LispNode *car_, LispNode *cdr_ ) { return new LispCell( car_, cdr_); }
    // make a new number node
    LispNode * MakeNumber( double val_ )    { return new LispNumber(val_); }
    // make a new symbol
    LispNode * MakeSymbol( const string & str_) { return new LispSymbol(str_); }
    // assign a variable
    void MakeVar( LispSymbol *symbol_, LispNode * node_) { m_vars[symbol_->m_symbol] = node_; }

    // print internal structure as s_expression to cout
    void Print(LispNode * node_);

protected:
    void TokenizeRek(const string& str_);
    LispFunction* FindFunction( string name_);
    LispFunction* FindSpecialFunction( string name_);
    LispNode* Parse(list<Token>::iterator &it_);
    LispNode* ParseRest(list<Token>::iterator &it_);
    LispNode* FindVar(LispSymbol *symbol_);

private:
    list<LispFunction*> m_functions;
    list<LispFunction*> m_specialFunctions;
    list<Token>         m_tokens;
    typedef map<string, LispNode*> varsmap;
    varsmap             m_vars;
    LispNode *          m_content;
    LispNode *          m_tree;
};

#endif // _LISP_H
