/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef Forth_DEFINED
#define Forth_DEFINED

#include "SkTypes.h"

class ForthOutput {
public:
    virtual void show(const char output[]) = 0;
};

union FloatIntDual {
    int32_t fInt;
    float   fFloat;
};

static inline int32_t f2i_bits(float x) {
    FloatIntDual d;
    d.fFloat = x;
    return d.fInt;
}

static inline float i2f_bits(int32_t x) {
    FloatIntDual d;
    d.fInt = x;
    return d.fFloat;
}

class ForthEngine {
public:
    ForthEngine(ForthOutput*);
    ~ForthEngine();

    int         depth() const { return fStackStop - fStackCurr; }
    void        clearStack() { fStackCurr = fStackStop; }

    void        push(intptr_t value);
    intptr_t    top() const { return this->peek(0); }
    intptr_t    peek(size_t index) const;
    void        setTop(intptr_t value);
    intptr_t    pop();

    void        fpush(float value) { this->push(f2i_bits(value)); }
    float       fpeek(size_t i) const { return i2f_bits(this->fpeek(i)); }
    float       ftop() const { return i2f_bits(this->top()); }
    void        fsetTop(float value) { this->setTop(f2i_bits(value)); }
    float       fpop() { return i2f_bits(this->pop()); }

    void sendOutput(const char text[]);

private:
    ForthOutput* fOutput;
    intptr_t*   fStackBase;
    intptr_t*   fStackCurr;
    intptr_t*   fStackStop;

    void signal_error(const char msg[]) const {
        SkDebugf("ForthEngine error: %s\n", msg);
    }
};

struct ForthCallBlock {
    const intptr_t* in_data;
    size_t          in_count;
    intptr_t*       out_data;
    size_t          out_count;
    size_t          out_depth;
};

class ForthWord {
public:
    virtual ~ForthWord() {}
    virtual void exec(ForthEngine*) = 0;

    // todo: return error state of the engine
    void call(ForthCallBlock*);
};

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


    void addWord(const char name[], ForthWord*);

    void parse(const char code[]);

    ForthWord* findWord(const char name[]);

    void run(ForthOutput* = NULL);

private:
    class Impl;
    Impl* fImpl;
};

#endif