You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1413 lines
30 KiB

/*
* EEZ Modular Firmware
* Copyright (C) 2021-present, Envox d.o.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <math.h>
#include <chrono>
#include <string>
#include <iostream>
#include <sstream>
// https://howardhinnant.github.io/date/date.html
#include <eez/libs/date.h>
#include <eez/gui/gui.h>
#include <eez/flow/flow.h>
#include <eez/flow/operations.h>
namespace eez {
namespace flow {
using namespace gui;
Value op_add(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
if (a.isAnyStringType() || b.isAnyStringType()) {
Value value1 = a.toString(0x84eafaa8);
Value value2 = b.toString(0xd273cab6);
auto res = Value::concatenateString(value1, value2);
char str1[128];
res.toText(str1, sizeof(str1));
return res;
}
if (a.isDouble() || b.isDouble()) {
return Value(a.toDouble() + b.toDouble(), VALUE_TYPE_DOUBLE);
}
if (a.isFloat() || b.isFloat()) {
return Value(a.toFloat() + b.toFloat(), VALUE_TYPE_FLOAT);
}
if (a.isInt64() || b.isInt64()) {
return Value(a.toInt64() + b.toInt64(), VALUE_TYPE_INT64);
}
if (a.isInt32OrLess() && b.isInt32OrLess()) {
return Value((int)(a.int32Value + b.int32Value), VALUE_TYPE_INT32);
}
return Value();
}
Value op_sub(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
if (a.isDouble() || b.isDouble()) {
return Value(a.toDouble() - b.toDouble(), VALUE_TYPE_DOUBLE);
}
if (a.isFloat() || b.isFloat()) {
return Value(a.toFloat() - b.toFloat(), VALUE_TYPE_FLOAT);
}
if (a.isInt64() || b.isInt64()) {
return Value(a.toInt64() - b.toInt64(), VALUE_TYPE_INT64);
}
if (a.isInt32OrLess() && b.isInt32OrLess()) {
return Value((int)(a.int32Value - b.int32Value), VALUE_TYPE_INT32);
}
return Value();
}
Value op_mul(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
if (a.isDouble() || b.isDouble()) {
return Value(a.toDouble() * b.toDouble(), VALUE_TYPE_DOUBLE);
}
if (a.isFloat() || b.isFloat()) {
return Value(a.toFloat() * b.toFloat(), VALUE_TYPE_FLOAT);
}
if (a.isInt64() || b.isInt64()) {
return Value(a.toInt64() * b.toInt64(), VALUE_TYPE_INT64);
}
if (a.isInt32OrLess() && b.isInt32OrLess()) {
return Value((int)(a.int32Value * b.int32Value), VALUE_TYPE_INT32);
}
return Value();
}
Value op_div(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
if (a.isDouble() || b.isDouble()) {
return Value(a.toDouble() / b.toDouble(), VALUE_TYPE_DOUBLE);
}
if (a.isFloat() || b.isFloat()) {
return Value(a.toFloat() / b.toFloat(), VALUE_TYPE_FLOAT);
}
if (a.isInt64() || b.isInt64()) {
return Value(1.0 * a.toInt64() / b.toInt64(), VALUE_TYPE_DOUBLE);
}
if (a.isInt32OrLess() && b.isInt32OrLess()) {
return Value(1.0 * a.int32Value / b.int32Value, VALUE_TYPE_DOUBLE);
}
return Value();
}
Value op_mod(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
return Value(a.toDouble() - floor(a.toDouble() / b.toDouble()) * b.toDouble(), VALUE_TYPE_DOUBLE);
}
Value op_left_shift(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
return Value((int)(a.toInt32() << b.toInt32()), VALUE_TYPE_INT32);
}
Value op_right_shift(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
return Value((int)(a.toInt32() >> b.toInt32()), VALUE_TYPE_INT32);
}
Value op_binary_and(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
return Value((int)(a.toBool() & b.toBool()), VALUE_TYPE_INT32);
}
Value op_binary_or(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
return Value((int)(a.toBool() | b.toBool()), VALUE_TYPE_INT32);
}
Value op_binary_xor(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
return Value((int)(a.toBool() ^ b.toBool()), VALUE_TYPE_INT32);
}
bool is_equal(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
auto aIsUndefinedOrNull = a.getType() == VALUE_TYPE_UNDEFINED || a.getType() == VALUE_TYPE_NULL;
auto bIsUndefinedOrNull = b.getType() == VALUE_TYPE_UNDEFINED || b.getType() == VALUE_TYPE_NULL;
if (aIsUndefinedOrNull) {
return bIsUndefinedOrNull;
} else if (bIsUndefinedOrNull) {
return false;
}
if (a.isAnyStringType() && b.isAnyStringType()) {
const char *aStr = a.getString();
const char *bStr = b.getString();
if (!aStr && !aStr) {
return true;
}
if (!aStr || !bStr) {
return false;
}
return strcmp(aStr, bStr) == 0;
}
return a.toDouble() == b.toDouble();
}
bool is_less(const Value& a1, const Value& b1) {
auto a = a1.getValue();
auto b = b1.getValue();
if (a.isAnyStringType() && b.isAnyStringType()) {
const char *aStr = a.getString();
const char *bStr = b.getString();
if (!aStr || !bStr) {
return false;
}
return strcmp(aStr, bStr) < 0;
}
return a.toDouble() < b.toDouble();
}
Value op_eq(const Value& a1, const Value& b1) {
return Value(is_equal(a1, b1), VALUE_TYPE_BOOLEAN);
}
Value op_neq(const Value& a1, const Value& b1) {
return Value(!is_equal(a1, b1), VALUE_TYPE_BOOLEAN);
}
Value op_less(const Value& a1, const Value& b1) {
return Value(is_less(a1, b1), VALUE_TYPE_BOOLEAN);
}
Value op_great(const Value& a1, const Value& b1) {
return Value(!is_less(a1, b1) && !is_equal(a1, b1), VALUE_TYPE_BOOLEAN);
}
Value op_less_eq(const Value& a1, const Value& b1) {
return Value(is_less(a1, b1) || is_equal(a1, b1), VALUE_TYPE_BOOLEAN);
}
Value op_great_eq(const Value& a1, const Value& b1) {
return Value(!is_less(a1, b1), VALUE_TYPE_BOOLEAN);
}
bool do_OPERATION_TYPE_ADD(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_add(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_SUB(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_sub(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_MUL(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_mul(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_DIV(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_div(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_MOD(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_mod(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_LEFT_SHIFT(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_left_shift(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_RIGHT_SHIFT(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_right_shift(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_BINARY_AND(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_binary_and(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_BINARY_OR(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_binary_or(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_BINARY_XOR(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
auto result = op_binary_xor(a, b);
if (result.getType() == VALUE_TYPE_UNDEFINED) {
return false;
}
if (!stack.push(result)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_EQUAL(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
if (!stack.push(op_eq(a, b))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_NOT_EQUAL(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
if (!stack.push(op_neq(a, b))) {
return false;
}
return true;}
bool do_OPERATION_TYPE_LESS(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
if (!stack.push(op_less(a, b))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_GREATER(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
if (!stack.push(op_great(a, b))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_LESS_OR_EQUAL(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
if (!stack.push(op_less_eq(a, b))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_GREATER_OR_EQUAL(EvalStack &stack) {
auto b = stack.pop();
auto a = stack.pop();
if (!stack.push(op_great_eq(a, b))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_LOGICAL_AND(EvalStack &stack) {
auto b = stack.pop().getValue();
auto a = stack.pop().getValue();
if (!stack.push(Value(a.toBool() && b.toBool(), VALUE_TYPE_BOOLEAN))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_LOGICAL_OR(EvalStack &stack) {
auto b = stack.pop().getValue();
auto a = stack.pop().getValue();
if (!stack.push(Value(a.toBool() || b.toBool(), VALUE_TYPE_BOOLEAN))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_UNARY_PLUS(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(a.getDouble(), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(a.toFloat(), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value((int64_t)a.getInt64(), VALUE_TYPE_INT64))) {
return false;
}
return true;
}
if (a.isInt32()) {
if (!stack.push(Value((int)a.getInt32(), VALUE_TYPE_INT32))) {
return false;
}
return true;
}
if (a.isInt16()) {
if (!stack.push(Value((int16_t)a.getInt16(), VALUE_TYPE_INT16))) {
return false;
}
return true;
}
if (a.isInt8()) {
if (!stack.push(Value((int8_t)a.getInt8(), VALUE_TYPE_INT8))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_UNARY_MINUS(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(-a.getDouble(), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(-a.toFloat(), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value((int64_t)-a.getInt64(), VALUE_TYPE_INT64))) {
return false;
}
return true;
}
if (a.isInt32()) {
if (!stack.push(Value((int)-a.getInt32(), VALUE_TYPE_INT32))) {
return false;
}
return true;
}
if (a.isInt16()) {
if (!stack.push(Value((int16_t)-a.getInt16(), VALUE_TYPE_INT16))) {
return false;
}
return true;
}
if (a.isInt8()) {
if (!stack.push(Value((int8_t)-a.getInt8(), VALUE_TYPE_INT8))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_BINARY_ONE_COMPLEMENT(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isInt64()) {
if (!stack.push(Value(~a.uint64Value, VALUE_TYPE_UINT64))) {
return false;
}
return true;
}
if (a.isInt32()) {
if (!stack.push(Value(~a.uint32Value, VALUE_TYPE_UINT32))) {
return false;
}
return true;
}
if (a.isInt16()) {
if (!stack.push(Value(~a.uint16Value, VALUE_TYPE_UINT16))) {
return false;
}
return true;
}
if (a.isInt8()) {
if (!stack.push(Value(~a.uint8Value, VALUE_TYPE_UINT8))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_NOT(EvalStack &stack) {
auto aValue = stack.pop();
int err;
auto a = aValue.toBool(&err);
if (err != 0) {
return false;
}
if (!stack.push(Value(!a, VALUE_TYPE_BOOLEAN))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_CONDITIONAL(EvalStack &stack) {
auto alternate = stack.pop();
auto consequent = stack.pop();
auto conditionValue = stack.pop();
int err;
auto condition = conditionValue.toBool(&err);
if (err != 0) {
return false;
}
if (!stack.push(condition ? consequent : alternate)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_SYSTEM_GET_TICK(EvalStack &stack) {
if (!stack.push(Value(millis(), VALUE_TYPE_UINT32))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_INDEX(EvalStack &stack) {
if (!stack.iterators) {
return false;
}
auto a = stack.pop();
int err;
auto iteratorIndex = a.toInt32(&err);
if (err != 0) {
return false;
}
using eez::gui::MAX_ITERATORS;
iteratorIndex = iteratorIndex;
if (iteratorIndex < 0 || iteratorIndex >= (int)MAX_ITERATORS) {
return false;
}
if (!stack.push(stack.iterators[iteratorIndex])) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_IS_PAGE_ACTIVE(EvalStack &stack) {
bool isActive = false;
auto pageIndex = getPageIndex(stack.flowState);
if (pageIndex >= 0) {
int16_t pageId = (int16_t)(pageIndex + 1);
if (stack.flowState->assets == g_externalAssets) {
pageId = -pageId;
}
for (int16_t appContextId = 0; ; appContextId++) {
auto appContext = getAppContextFromId(appContextId);
if (!appContext) {
break;
}
if (appContext->isPageOnStack(pageId)) {
isActive = true;
break;
}
}
}
if (!stack.push(Value(isActive, VALUE_TYPE_BOOLEAN))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_PAGE_TIMELINE_POSITION(EvalStack &stack) {
if (!stack.push(Value(stack.flowState->timelinePosition, VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_MAKE_ARRAY_VALUE(EvalStack &stack) {
auto arrayTypeValue = stack.pop();
auto arraySizeValue = stack.pop();
int arrayType = arrayTypeValue.getInt();
int arraySize = arraySizeValue.getInt();
auto arrayValue = Value::makeArrayRef(arraySize, arrayType, 0x837260d4);
auto array = arrayValue.getArray();
for (int i = 0; i < arraySize; i++) {
array->values[i] = stack.pop().getValue();
}
if (!stack.push(arrayValue)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_LANGUAGES(EvalStack &stack) {
auto languages = stack.flowState->assets->languages;
auto arrayValue = Value::makeArrayRef(languages.count, VALUE_TYPE_STRING, 0xff4787fc);
auto array = arrayValue.getArray();
for (uint32_t i = 0; i < languages.count; i++) {
array->values[i] = Value((const char *)(languages[i]->languageID));
}
if (!stack.push(arrayValue)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_TRANSLATE(EvalStack &stack) {
auto textResourceIndexValue = stack.pop();
int textResourceIndex = textResourceIndexValue.getInt();
int languageIndex = g_selectedLanguage;
auto languages = stack.flowState->assets->languages;
if (languageIndex >= 0 && languageIndex < (int)languages.count) {
auto translations = languages[languageIndex]->translations;
if (textResourceIndex >= 0 && textResourceIndex < (int)translations.count) {
if (!stack.push(translations[textResourceIndex])) {
return false;
}
return true;
}
}
if (!stack.push("")) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_PARSE_INTEGER(EvalStack &stack) {
auto str = stack.pop();
int err;
auto value = str.toInt32(&err);
if (err) {
return false;
}
if (!stack.push(Value((int)value, VALUE_TYPE_INT32))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_PARSE_FLOAT(EvalStack &stack) {
auto str = stack.pop();
int err;
auto value = str.toFloat(&err);
if (err) {
return false;
}
if (!stack.push(Value(value, VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_FLOW_PARSE_DOUBLE(EvalStack &stack) {
auto str = stack.pop();
int err;
auto value = str.toDouble(&err);
if (err) {
return false;
}
if (!stack.push(Value(value, VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_DATE_NOW(EvalStack &stack) {
using namespace std::chrono;
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
if (!stack.push(Value((double)ms.count(), VALUE_TYPE_DATE))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_DATE_TO_STRING(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.getType() != VALUE_TYPE_DATE) {
return false;
}
using namespace std;
using namespace std::chrono;
using namespace date;
auto tp = system_clock::time_point(milliseconds((long long)a.getDouble()));
stringstream out;
out << tp << endl;
if (!stack.push(Value::makeStringRef(out.str().c_str(), -1, 0xbe440ec8))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_DATE_FROM_STRING(EvalStack &stack) {
auto a = stack.pop().getValue();
Value dateStrValue = a.toString(0x99cb1a93);
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{dateStrValue.getString()};
system_clock::time_point tp;
in >> date::parse("%Y-%m-%d %T", tp);
milliseconds ms = duration_cast<milliseconds>(tp.time_since_epoch());
if (!stack.push(Value((double)ms.count(), VALUE_TYPE_DATE))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_MATH_SIN(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(sin(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(sinf(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value(sin(a.toInt64()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt32OrLess()) {
if (!stack.push(Value(sinf(a.int32Value), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_COS(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(cos(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(cosf(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value(cos(a.toInt64()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt32OrLess()) {
if (!stack.push(Value(cosf(a.int32Value), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_LOG(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(log(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(logf(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value(log(a.toInt64()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt32OrLess()) {
if (!stack.push(Value(logf(a.int32Value), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_LOG10(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(log10(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(log10f(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value(log10(a.toInt64()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt32OrLess()) {
if (!stack.push(Value(log10f(a.int32Value), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_ABS(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(abs(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(abs(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt64()) {
if (!stack.push(Value((int64_t)abs(a.getInt64()), VALUE_TYPE_INT64))) {
return false;
}
return true;
}
if (a.isInt32()) {
if (!stack.push(Value((int)abs(a.getInt32()), VALUE_TYPE_INT32))) {
return false;
}
return true;
}
if (a.isInt16()) {
if (!stack.push(Value(abs(a.getInt16()), VALUE_TYPE_INT16))) {
return false;
}
return true;
}
if (a.isInt8()) {
if (!stack.push(Value(abs(a.getInt8()), VALUE_TYPE_INT8))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_FLOOR(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(floor(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(floorf(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_CEIL(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.isDouble()) {
if (!stack.push(Value(ceil(a.getDouble()), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(ceilf(a.toFloat()), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
return false;
}
float roundN(float value, unsigned int numDigits) {
float pow_10 = pow(10.0f, numDigits);
return round(value * pow_10) / pow_10;
}
double roundN(double value, unsigned int numDigits) {
float pow_10 = pow(10.0f, numDigits);
return round(value * pow_10) / pow_10;
}
bool do_OPERATION_TYPE_MATH_ROUND(EvalStack &stack) {
auto numArgs = stack.pop().getInt();
auto a = stack.pop().getValue();
unsigned int numDigits;
if (numArgs > 1) {
auto b = stack.pop().getValue();
numDigits = b.toInt32();
} else {
numDigits = 0;
}
if (a.isDouble()) {
if (!stack.push(Value(roundN(a.getDouble(), numDigits), VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
if (a.isFloat()) {
if (!stack.push(Value(roundN(a.toFloat(), numDigits), VALUE_TYPE_FLOAT))) {
return false;
}
return true;
}
if (a.isInt32OrLess()) {
if (!stack.push(a)) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_MATH_MIN(EvalStack &stack) {
auto numArgs = stack.pop().getInt();
double minValue = INFINITY;
for (int i = 0; i < numArgs; i++) {
auto value = stack.pop().getValue().toDouble();
if (value < minValue) {
minValue = value;
}
}
if (!stack.push(Value(minValue, VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_MATH_MAX(EvalStack &stack) {
auto numArgs = stack.pop().getInt();
double maxValue = -INFINITY;
for (int i = 0; i < numArgs; i++) {
auto value = stack.pop().getValue().toDouble();
if (value > maxValue) {
maxValue = value;
}
}
if (!stack.push(Value(maxValue, VALUE_TYPE_DOUBLE))) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_STRING_FIND(EvalStack &stack) {
auto b = stack.pop().getValue();
auto a = stack.pop().getValue();
Value aStr = a.toString(0xf616bf4d);
Value bStr = b.toString(0x81229133);
if (!aStr.getString() || !bStr.getString()) {
if (!stack.push(Value(-1, VALUE_TYPE_INT32))) {
return false;
}
} else {
const char *pos = strstr(aStr.getString(), bStr.getString());
if (!pos) {
if (!stack.push(Value((int)(pos - aStr.getString()), VALUE_TYPE_INT32))) {
return false;
}
} else {
if (!stack.push(Value(-1, VALUE_TYPE_INT32))) {
return false;
}
}
}
return true;
}
bool do_OPERATION_TYPE_STRING_PAD_START(EvalStack &stack) {
auto a = stack.pop().getValue();
auto b = stack.pop().getValue();
auto c = stack.pop().getValue();
auto str = a.toString(0xcf6aabe6);
if (!str.getString()) {
return false;
}
int strLen = strlen(str.getString());
int err;
int targetLength = b.toInt32(&err);
if (err) {
return false;
}
if (targetLength < strLen) {
targetLength = strLen;
}
auto padStr = c.toString(0x81353bd7);
if (!padStr.getString()) {
return false;
}
int padStrLen = strlen(padStr.getString());
Value resultValue = eez::gui::Value::makeStringRef("", targetLength, 0xf43b14dd);
if (resultValue.type == VALUE_TYPE_NULL) {
return false;
}
char *resultStr = (char *)resultValue.getString();
auto n = targetLength - strLen;
stringCopy(resultStr + (targetLength - strLen), strLen + 1, str.getString());
for (int i = 0; i < n; i++) {
resultStr[i] = padStr.getString()[i % padStrLen];
}
if (!stack.push(resultValue)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_STRING_SPLIT(EvalStack &stack) {
auto strValue = stack.pop().getValue();
auto delimValue = stack.pop().getValue();
auto str = strValue.getString();
if (!str) {
return false;
}
auto delim = delimValue.getString();
if (!delim) {
return false;
}
auto strLen = strlen(str);
char *strCopy = (char *)eez::alloc(strLen + 1, 0xea9d0bc0);
stringCopy(strCopy, strLen + 1, str);
// get num parts
size_t arraySize = 0;
char *token = strtok(strCopy, delim);
while (token != NULL) {
arraySize++;
token = strtok(NULL, delim);
}
eez::free(strCopy);
strCopy = (char *)eez::alloc(strLen + 1, 0xea9d0bc1);
stringCopy(strCopy, strLen + 1, str);
// make array
auto arrayValue = Value::makeArrayRef(arraySize, VALUE_TYPE_STRING, 0xe82675d4);
auto array = arrayValue.getArray();
int i = 0;
token = strtok(strCopy, delim);
while (token != NULL) {
array->values[i++] = Value::makeStringRef(token, -1, 0x45209ec0);
token = strtok(NULL, delim);
}
eez::free(strCopy);
if (!stack.push(arrayValue)) {
return false;
}
return true;
}
bool do_OPERATION_TYPE_ARRAY_LENGTH(EvalStack &stack) {
auto a = stack.pop().getValue();
if (a.getType() == VALUE_TYPE_ARRAY || a.getType() == VALUE_TYPE_ARRAY_REF) {
auto array = a.getArray();
if (!stack.push(Value(array->arraySize, VALUE_TYPE_UINT32))) {
return false;
}
return true;
}
return false;
}
bool do_OPERATION_TYPE_ARRAY_SLICE(EvalStack &stack) {
// TODO
return false;
}
EvalOperation g_evalOperations[] = {
do_OPERATION_TYPE_ADD,
do_OPERATION_TYPE_SUB,
do_OPERATION_TYPE_MUL,
do_OPERATION_TYPE_DIV,
do_OPERATION_TYPE_MOD,
do_OPERATION_TYPE_LEFT_SHIFT,
do_OPERATION_TYPE_RIGHT_SHIFT,
do_OPERATION_TYPE_BINARY_AND,
do_OPERATION_TYPE_BINARY_OR,
do_OPERATION_TYPE_BINARY_XOR,
do_OPERATION_TYPE_EQUAL,
do_OPERATION_TYPE_NOT_EQUAL,
do_OPERATION_TYPE_LESS,
do_OPERATION_TYPE_GREATER,
do_OPERATION_TYPE_LESS_OR_EQUAL,
do_OPERATION_TYPE_GREATER_OR_EQUAL,
do_OPERATION_TYPE_LOGICAL_AND,
do_OPERATION_TYPE_LOGICAL_OR,
do_OPERATION_TYPE_UNARY_PLUS,
do_OPERATION_TYPE_UNARY_MINUS,
do_OPERATION_TYPE_BINARY_ONE_COMPLEMENT,
do_OPERATION_TYPE_NOT,
do_OPERATION_TYPE_CONDITIONAL,
do_OPERATION_TYPE_SYSTEM_GET_TICK,
do_OPERATION_TYPE_FLOW_INDEX,
do_OPERATION_TYPE_FLOW_IS_PAGE_ACTIVE,
do_OPERATION_TYPE_FLOW_PAGE_TIMELINE_POSITION,
do_OPERATION_TYPE_FLOW_MAKE_ARRAY_VALUE,
do_OPERATION_TYPE_FLOW_MAKE_ARRAY_VALUE,
do_OPERATION_TYPE_FLOW_LANGUAGES,
do_OPERATION_TYPE_FLOW_TRANSLATE,
do_OPERATION_TYPE_FLOW_PARSE_INTEGER,
do_OPERATION_TYPE_FLOW_PARSE_FLOAT,
do_OPERATION_TYPE_FLOW_PARSE_DOUBLE,
do_OPERATION_TYPE_DATE_NOW,
do_OPERATION_TYPE_DATE_TO_STRING,
do_OPERATION_TYPE_DATE_FROM_STRING,
do_OPERATION_TYPE_MATH_SIN,
do_OPERATION_TYPE_MATH_COS,
do_OPERATION_TYPE_MATH_LOG,
do_OPERATION_TYPE_MATH_LOG10,
do_OPERATION_TYPE_MATH_ABS,
do_OPERATION_TYPE_MATH_FLOOR,
do_OPERATION_TYPE_MATH_CEIL,
do_OPERATION_TYPE_MATH_ROUND,
do_OPERATION_TYPE_MATH_MIN,
do_OPERATION_TYPE_MATH_MAX,
do_OPERATION_TYPE_STRING_FIND,
do_OPERATION_TYPE_STRING_PAD_START,
do_OPERATION_TYPE_STRING_SPLIT,
do_OPERATION_TYPE_ARRAY_LENGTH,
do_OPERATION_TYPE_ARRAY_SLICE
};
} // namespace flow
} // namespace eez