1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "script_expression.h"
16#include "script_function.h"
17#include "script_interpreter.h"
18#include "script_utils.h"
19
20using namespace std;
21
22namespace Uscript {
23UScriptExpression::UScriptExpression(ExpressionType expressType) : expressType_(expressType) {}
24UScriptExpression::~UScriptExpression() {}
25
26UScriptExpression* AssignExpression::CreateExpression(const std::string identifier, UScriptExpression *expression)
27{
28    return new AssignExpression(identifier, expression);
29}
30void AssignExpression::AddIdentifier(const std::string &identifier)
31{
32    multipleIdentifiers_.push_back(identifier);
33}
34
35UScriptExpression* AssignExpression::AddIdentifier(UScriptExpression *expression, const std::string identifier)
36{
37    auto assign = reinterpret_cast<AssignExpression*>(expression);
38    if (assign != nullptr) {
39        assign->AddIdentifier(identifier);
40    }
41    return assign;
42}
43
44// binary operator
45UScriptExpression* BinaryExpression::CreateExpression(ExpressionAction action,
46    UScriptExpression *left,
47    UScriptExpression *right)
48{
49    return new BinaryExpression(action, left, right);
50}
51UScriptExpression* FunctionCallExpression::CreateExpression(const std::string identifier, ScriptParams *params)
52{
53    return new FunctionCallExpression(identifier, params);
54}
55UScriptValuePtr UScriptExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
56{
57    return std::make_shared<UScriptValue>(UScriptValue::VALUE_TYPE_ERROR);
58}
59UScriptValuePtr IntegerExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
60{
61    return std::make_shared<IntegerValue>(this->value_);
62}
63UScriptValuePtr FloatExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
64{
65    return std::make_shared<FloatValue>(this->value_);
66}
67UScriptValuePtr StringExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
68{
69    return std::make_shared<StringValue>(this->value_);
70}
71UScriptValuePtr IdentifierExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
72{
73    INTERPRETER_LOGI(inter, local, "Execute statements identifier %s ", identifier_.c_str());
74    UScriptValuePtr variable = inter.FindVariable(local, identifier_);
75    INTERPRETER_LOGI(inter, local, "IdentifierExpression::Execute '%s = %s ' ", identifier_.c_str(),
76        UScriptValue::ScriptToString(variable).c_str());
77    if (variable != nullptr) {
78        return variable;
79    }
80    return std::make_shared<UScriptValue>(UScriptValue::VALUE_TYPE_ERROR);
81}
82
83int32_t IdentifierExpression::GetIdentifierName(UScriptExpression *expression, std::string &name)
84{
85    if (expression == nullptr) {
86        return USCRIPT_INVALID_PARAM;
87    }
88    if (expression->GetExpressType() != EXPRESSION_TYPE_IDENTIFIER) {
89        return USCRIPT_INVALID_PARAM;
90    } else {
91        auto identifier = reinterpret_cast<IdentifierExpression*>(expression);
92        if (identifier != nullptr) {
93            name = identifier->GetIdentifier();
94            return USCRIPT_SUCCESS;
95        }
96    }
97    return USCRIPT_INVALID_PARAM;
98}
99UScriptValuePtr AssignExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
100{
101    UScriptValuePtr result = expression_->Execute(inter, local);
102    INTERPRETER_LOGI(inter, local, "AssignExpression::Execute update local var '%s = %s ' ", identifier_.c_str(),
103        UScriptValue::ScriptToString(result).c_str());
104    if (result->GetValueType() == UScriptValue::VALUE_TYPE_ERROR) {
105        return result;
106    }
107    UScriptValuePtr var = inter.FindVariable(local, identifier_);
108    if (var != nullptr) {
109        inter.UpdateVariable(local, identifier_, result);
110        return result;
111    }
112
113    std::vector<std::string> identifiers;
114    identifiers.push_back(identifier_);
115    identifiers.insert(identifiers.begin() + 1, multipleIdentifiers_.begin(), multipleIdentifiers_.end());
116    size_t index = 0;
117    local->UpdateVariables(inter, result, identifiers, index);
118    return result;
119}
120
121UScriptValuePtr BinaryExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
122{
123    static std::vector<std::string> opStr = {
124        "", "add", "sub", "mul", "div", ">", ">=", "<", "<=", "==", "!=", "&&", "||"
125    };
126    UScriptValuePtr left;
127    UScriptValuePtr right;
128
129    INTERPRETER_LOGI(inter, local, "BinaryExpression::Execute ");
130    if (left_ != nullptr) {
131        left = left_->Execute(inter, local);
132    }
133
134    if (action_ == OR_OPERATOR && left != nullptr && left->IsTrue()) {
135        INTERPRETER_LOGE(inter, local, "BinaryExpression::Execute left:%s %s",
136            UScriptValue::ScriptToString(left).c_str(), opStr[action_].c_str());
137        return std::make_shared<IntegerValue>(1);
138    }
139    if (right_ != nullptr) {
140        right = right_->Execute(inter, local);
141    }
142    if (left != nullptr && right != nullptr) {
143        UScriptValuePtr value = left->Computer(action_, right);
144        INTERPRETER_LOGI(inter, local, "BinaryExpression::Execute left:%s %s right:%s result:%s",
145            UScriptValue::ScriptToString(left).c_str(), opStr[action_].c_str(),
146            UScriptValue::ScriptToString(right).c_str(), UScriptValue::ScriptToString(value).c_str());
147        return value;
148    }
149    return std::make_shared<ErrorValue>(USCRIPT_ERROR_INTERPRET);
150}
151
152UScriptValuePtr FunctionCallExpression::Execute(ScriptInterpreter &inter, UScriptContextPtr local)
153{
154    UScriptValuePtr v;
155    INTERPRETER_LOGD(inter, local, "FunctionCallExpression::Execute %s ", functionName_.c_str());
156
157    if (inter.IsNativeFunction(functionName_)) {
158        return inter.ExecuteNativeFunc(local, functionName_, params_);
159    }
160    return inter.ExecuteFunction(local, functionName_, params_);
161}
162
163BinaryExpression::~BinaryExpression()
164{
165    delete left_;
166    delete right_;
167}
168AssignExpression::~AssignExpression()
169{
170    delete this->expression_;
171}
172FunctionCallExpression::~FunctionCallExpression()
173{
174    delete params_;
175}
176} // namespace Uscript
177