/*____________________________________________________________________________
session, it is the interpreter by itself
time sharing paradigm require that many interpreter work at the same time
____________________________________________________________________________*/

#pragma once
#ifndef _FART
#define _FART

#include <stdio.h>
#include <stdlib.h>

#include "word.h"
#include "node.hpp"
#include "memory.hpp"
#include "stack.hpp"

/*____________________________________________________________________________
class
____________________________________________________________________________*/

class session{
    int _mode;
    memory * _memory;
    stack _accum,
          _return;
public:
    //constructor
    session(memory *);
    //mutator
    word accumPop();
    void accumPush(word w);
    void process(word ins);
    void parse(const char *);
    //debug
    void accumPrint();
};

/*____________________________________________________________________________
methode
____________________________________________________________________________*/


session::session(memory * mem)
{
    _mode = execMode;
    _memory = mem;
}

word session::accumPop()
{
    word data = _accum.top();
    node * cell = _accum.pop();
    _memory->free(cell);
    return data;
}

void session::accumPush(word w)
{
    _accum.push(_memory->alloc(),w);
}

void session::accumPrint()
{
    for (int i=0;i<_accum.size();i++)
        printf("%lld \n", _accum.at(i));
}

void session::process(const word ins)
{
    //temporary register
    word a,
         b;
    //opcode execute
    switch(ins)
    {
    /*mode change*/
    case NUM:
        _mode = pushNumMode;
        break;
    case EXEC:
        _mode = execMode;
        break;
    case TXT:
        _mode = pushTxtMode;
        break;
    /*stack operation*/
    case POP:
        accumPop();
        break;
    case DUPE:
        a = accumPop();
        accumPush(a);
        accumPush(a);
        break;
    case SWAP:
        a = accumPop();
        b = accumPop();
        accumPush(a);
        accumPush(b);
        break;
    /*alu*/
    case AND:
        a = accumPop();
        b = accumPop();
        accumPush(a&b);
        break;
    case OR:
        a = accumPop();
        b = accumPop();
        accumPush(a|b);
        break;
    case NOT:
        a = accumPop();
        accumPush(!a);
        break;
    case XOR:
        a = accumPop();
        b = accumPop();
        accumPush(a^b);
        break;
    case ADD:
        a = accumPop();
        b = accumPop();
        accumPush(a+b);
        break;
    case SUB:
        a = accumPop();
        b = accumPop();
        accumPush(a-b);
        break;
    case SHIFTL:
        a = accumPop();
        b = accumPop();
        accumPush(b<<a);
        break;
    case SHIFTR:
        a = accumPop();
        b = accumPop();
        accumPush(b>>a);
        break;
    }
}

void session::parse(const char * wordtxt)
{
    word tmp;
    switch(_mode)
    {
    case pushNumMode:
        tmp = atoll(wordtxt);
        if(tmp==0)
            _mode = execMode;
        else
            accumPush(tmp);
        break;
    case pushTxtMode:
        break;
    case execMode:
        process(txt2word(wordtxt));
        break;
    default:
        printf("\n    error\n");
        break;
    }
}

#endif
