/*

 * Copyright (c) 2021 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 * http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

#ifndef USCRIPT_EXPRESSION_H

#define USCRIPT_EXPRESSION_H



#include <memory>

#include "script_context.h"



namespace Uscript {

class UScriptExpression;

using UScriptExpressionPtr = std::shared_ptr<UScriptExpression>;



class ScriptParams;

class ScriptFunction;



class UScriptExpression {

public:

    enum ExpressionType {

        EXPRESSION_TYPE_INTERGER,

        EXPRESSION_TYPE_FLOAT,

        EXPRESSION_TYPE_STRING,

        EXPRESSION_TYPE_IDENTIFIER,

        EXPRESSION_TYPE_BINARY,

        EXPRESSION_TYPE_ASSIGN,

        EXPRESSION_TYPE_INV,

        EXPRESSION_TYPE_FUNC,

        EXPRESSION_TYPE_INVALID,

    };

    enum ExpressionAction {

        ADD_OPERATOR = 1,

        SUB_OPERATOR,

        MUL_OPERATOR,

        DIV_OPERATOR,

        GT_OPERATOR,

        GE_OPERATOR,

        LT_OPERATOR,

        LE_OPERATOR,

        EQ_OPERATOR,

        NE_OPERATOR,

        AND_OPERATOR,

        OR_OPERATOR

    };



public:

    explicit UScriptExpression(ExpressionType expressType);

    virtual ~UScriptExpression();



    virtual UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local);

    static UScriptExpression* CreateExpression(ExpressionType expressType)

    {

        return new UScriptExpression(expressType);

    }

    ExpressionType GetExpressType()

    {

        return expressType_;

    }



private:

    ExpressionType expressType_;

};



class IntegerExpression : public UScriptExpression {

public:

    explicit IntegerExpression(int v) : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_INTERGER)

    {

        value_ = v;

    }



    ~IntegerExpression() override {}



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    static UScriptExpression* CreateExpression(int value)

    {

        return new IntegerExpression(value);

    }

private:

    int value_;

};



class FloatExpression : public UScriptExpression {

public:

    explicit FloatExpression(float v) : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_FLOAT)

    {

        value_ = v;

    }



    ~FloatExpression() override {}



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    static UScriptExpression* CreateExpression(float value)

    {

        return new FloatExpression(value);

    }



private:

    float value_;

};



class StringExpression : public UScriptExpression {

public:

    explicit StringExpression(const std::string str) : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_STRING),

        value_(str) {}



    ~StringExpression() override {}



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    static UScriptExpression* CreateExpression(const std::string value)

    {

        return new StringExpression(value);

    }

private:

    std::string value_;

};



class IdentifierExpression : public UScriptExpression {

public:

    explicit IdentifierExpression(const std::string str)

        : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_IDENTIFIER), identifier_(str) {}



    ~IdentifierExpression() override {}



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    static UScriptExpression* CreateExpression(const std::string value)

    {

        return new IdentifierExpression(value);

    }



    const std::string GetIdentifier()

    {

        return identifier_;

    }



    static int32_t GetIdentifierName(UScriptExpression *expression, std::string &name);

private:

    std::string identifier_;

};



class BinaryExpression : public UScriptExpression {

public:

    BinaryExpression(ExpressionAction action, UScriptExpression *left, UScriptExpression *right)

        : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_BINARY), action_(action), left_(left), right_(right) {}



    ~BinaryExpression() override;



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    static UScriptExpression* CreateExpression(ExpressionAction action, UScriptExpression *left,

        UScriptExpression *right);

private:

    UScriptExpression::ExpressionAction action_;

    UScriptExpression* left_ = nullptr;

    UScriptExpression* right_ = nullptr;

};



class AssignExpression : public UScriptExpression {

public:

    AssignExpression(const std::string identifier, UScriptExpression *expression)

        : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_ASSIGN), identifier_(identifier),

        expression_(expression) {}



    ~AssignExpression() override;



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    void AddIdentifier(const std::string &identifier);



    static UScriptExpression* CreateExpression(const std::string identifier, UScriptExpression *expression);

    static UScriptExpression* AddIdentifier(UScriptExpression *expression, const std::string identifier);

private:

    std::string identifier_;

    std::vector<std::string> multipleIdentifiers_; // 最大支持4个参数a,b,v = 1

    UScriptExpression* expression_ = nullptr;

};



class FunctionCallExpression : public UScriptExpression {

public:

    FunctionCallExpression(const std::string identifier, ScriptParams *params)

        : UScriptExpression(UScriptExpression::EXPRESSION_TYPE_FUNC), functionName_(identifier), params_(params) {}



    ~FunctionCallExpression() override;



    UScriptValuePtr Execute(ScriptInterpreter &inter, UScriptContextPtr local) override;



    static UScriptExpression* CreateExpression(const std::string identifier, ScriptParams *params);

private:

    std::string functionName_;

    ScriptParams* params_ = nullptr;

};

} // namespace Uscript

#endif // _HS_EXPRESSION_H