/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#pragma once

class UserFunction : public Function
{
    virtual Value Execute(int arity, Value* arg);

protected:
    Context* Address;

public:
    UserFunction(const char* nam, Context* s) :
        Function(nam) { Address = s; }
};

class ObjectFunction : public UserFunction
{
    virtual Value Execute(int arity, Value* arg);

public:
    ObjectFunction(const char* nam, Context* s) :
        UserFunction(nam, s) {}
};

class ExternFunction : public UserFunction
{
    char* cmd;
    char* file;

    int compiled;
    int Compile(void);
    virtual Value Execute(int arity, Value* arg);

public:
    void SetCommand(const char* c, const char* f);
    ExternFunction(const char* name, Context* s);
    ~ExternFunction();
};

class OpPop : public Step
{
    virtual void Print(void) { printf("pop\n"); }
    virtual Step* Execute(void);
};


class OpStore : public Step
{
    virtual Step* Execute(void);

protected:
    int Count;
    char* Name;
    virtual void Print(void) { printf("store %s [%d]\n", Name ? Name : "(null)", Count); }

public:
    OpStore(const char* nam, int n = 0)
    {
        Name = strcache(nam);
        Count = n;
    }
    ~OpStore() { strfree(Name); }
};


class OpPush : public OpStore
{
    int type;

    virtual Step* Execute(void);
    virtual void Print(void) { printf("push %s\n", Name ? Name : "(null)"); }

public:
    OpPush(const char* nam, int t) :
        OpStore(nam) { type = t; }
};

class OpParam : public OpStore
{
    virtual Step* Execute(void);
    virtual void Print(void) { printf("param %s\n", Name ? Name : "(null)"); }

public:
    OpParam(const char* nam) :
        OpStore(nam) {}
};

class OpCall : public OpStore
{
    int Arity;
    virtual Step* Execute(void);
    virtual void Print(void) { printf("call %s %d\n", Name ? Name : "(null)", Arity); }

public:
    OpCall(const char* nam, int arity) :
        OpStore(nam) { Arity = arity; }
};

class OpGoto : public Step
{
    Step* Branch;
    virtual void Print(void) { printf("goto\n"); }

public:
    OpGoto() { Branch = nullptr; }
    virtual Step* Execute(void);
    void SetBranch(Step* b) { Branch = b; }
    virtual int Ready(void) { return Branch != nullptr; }
};

class OpTest : public OpGoto
{
    virtual void Print(void) { printf("test\n"); }
    virtual Step* Execute(void);

public:
    bool Pass(Value&);
};

class OpReturn : public Step
{
    virtual void Print(void) { printf("return\n"); }
    virtual Step* Execute(void);
};
