use mk_val

This commit is contained in:
Xuan Son Nguyen 2025-12-27 22:28:54 +01:00
parent da7bbe5813
commit c08f4ddf01
3 changed files with 57 additions and 57 deletions

View File

@ -28,7 +28,7 @@ bool is_val(const value & ptr) {
return dynamic_cast<const PointeeType*>(ptr.get()) != nullptr; return dynamic_cast<const PointeeType*>(ptr.get()) != nullptr;
} }
template<typename T, typename... Args> template<typename T, typename... Args>
bool mk_val(Args&&... args) { value mk_val(Args&&... args) {
using PointeeType = typename extract_pointee<T>::type; using PointeeType = typename extract_pointee<T>::type;
return std::make_unique<PointeeType>(std::forward<Args>(args)...); return std::make_unique<PointeeType>(std::forward<Args>(args)...);
} }

View File

@ -13,12 +13,12 @@ const func_builtins & value_int_t::get_builtins() const {
{"abs", [](const func_args & args) -> value { {"abs", [](const func_args & args) -> value {
args.ensure_vals<value_int>(); args.ensure_vals<value_int>();
int64_t val = args.args[0]->as_int(); int64_t val = args.args[0]->as_int();
return std::make_unique<value_int_t>(val < 0 ? -val : val); return mk_val<value_int>(val < 0 ? -val : val);
}}, }},
{"float", [](const func_args & args) -> value { {"float", [](const func_args & args) -> value {
args.ensure_vals<value_int>(); args.ensure_vals<value_int>();
double val = static_cast<double>(args.args[0]->as_int()); double val = static_cast<double>(args.args[0]->as_int());
return std::make_unique<value_float_t>(val); return mk_val<value_float>(val);
}}, }},
}; };
return builtins; return builtins;
@ -30,12 +30,12 @@ const func_builtins & value_float_t::get_builtins() const {
{"abs", [](const func_args & args) -> value { {"abs", [](const func_args & args) -> value {
args.ensure_vals<value_float>(); args.ensure_vals<value_float>();
double val = args.args[0]->as_float(); double val = args.args[0]->as_float();
return std::make_unique<value_float_t>(val < 0.0 ? -val : val); return mk_val<value_float>(val < 0.0 ? -val : val);
}}, }},
{"int", [](const func_args & args) -> value { {"int", [](const func_args & args) -> value {
args.ensure_vals<value_float>(); args.ensure_vals<value_float>();
int64_t val = static_cast<int64_t>(args.args[0]->as_float()); int64_t val = static_cast<int64_t>(args.args[0]->as_float());
return std::make_unique<value_int_t>(val); return mk_val<value_int>(val);
}}, }},
}; };
return builtins; return builtins;
@ -74,28 +74,28 @@ const func_builtins & value_string_t::get_builtins() const {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
std::transform(str.begin(), str.end(), str.begin(), ::toupper); std::transform(str.begin(), str.end(), str.begin(), ::toupper);
return std::make_unique<value_string_t>(str); return mk_val<value_string>(str);
}}, }},
{"lower", [](const func_args & args) -> value { {"lower", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
std::transform(str.begin(), str.end(), str.begin(), ::tolower); std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return std::make_unique<value_string_t>(str); return mk_val<value_string>(str);
}}, }},
{"strip", [](const func_args & args) -> value { {"strip", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
return std::make_unique<value_string_t>(string_strip(str, true, true)); return mk_val<value_string>(string_strip(str, true, true));
}}, }},
{"rstrip", [](const func_args & args) -> value { {"rstrip", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
return std::make_unique<value_string_t>(string_strip(str, false, true)); return mk_val<value_string>(string_strip(str, false, true));
}}, }},
{"lstrip", [](const func_args & args) -> value { {"lstrip", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
return std::make_unique<value_string_t>(string_strip(str, true, false)); return mk_val<value_string>(string_strip(str, true, false));
}}, }},
{"title", [](const func_args & args) -> value { {"title", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
@ -111,7 +111,7 @@ const func_builtins & value_string_t::get_builtins() const {
c = ::tolower(static_cast<unsigned char>(c)); c = ::tolower(static_cast<unsigned char>(c));
} }
} }
return std::make_unique<value_string_t>(str); return mk_val<value_string>(str);
}}, }},
{"capitalize", [](const func_args & args) -> value { {"capitalize", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
@ -120,38 +120,38 @@ const func_builtins & value_string_t::get_builtins() const {
str[0] = ::toupper(static_cast<unsigned char>(str[0])); str[0] = ::toupper(static_cast<unsigned char>(str[0]));
std::transform(str.begin() + 1, str.end(), str.begin() + 1, ::tolower); std::transform(str.begin() + 1, str.end(), str.begin() + 1, ::tolower);
} }
return std::make_unique<value_string_t>(str); return mk_val<value_string>(str);
}}, }},
{"length", [](const func_args & args) -> value { {"length", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
return std::make_unique<value_int_t>(str.length()); return mk_val<value_int>(str.length());
}}, }},
{"startswith", [](const func_args & args) -> value { {"startswith", [](const func_args & args) -> value {
args.ensure_vals<value_string, value_string>(); args.ensure_vals<value_string, value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
std::string prefix = args.args[1]->as_string(); std::string prefix = args.args[1]->as_string();
return std::make_unique<value_bool_t>(string_startswith(str, prefix)); return mk_val<value_bool>(string_startswith(str, prefix));
}}, }},
{"endswith", [](const func_args & args) -> value { {"endswith", [](const func_args & args) -> value {
args.ensure_vals<value_string, value_string>(); args.ensure_vals<value_string, value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
std::string suffix = args.args[1]->as_string(); std::string suffix = args.args[1]->as_string();
return std::make_unique<value_bool_t>(string_endswith(str, suffix)); return mk_val<value_bool>(string_endswith(str, suffix));
}}, }},
{"split", [](const func_args & args) -> value { {"split", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
std::string delim = (args.args.size() > 1) ? args.args[1]->as_string() : " "; std::string delim = (args.args.size() > 1) ? args.args[1]->as_string() : " ";
auto result = std::make_unique<value_array_t>(); auto result = mk_val<value_array>();
size_t pos = 0; size_t pos = 0;
std::string token; std::string token;
while ((pos = str.find(delim)) != std::string::npos) { while ((pos = str.find(delim)) != std::string::npos) {
token = str.substr(0, pos); token = str.substr(0, pos);
result->val_arr->push_back(std::make_unique<value_string_t>(token)); result->val_arr->push_back(mk_val<value_string>(token));
str.erase(0, pos + delim.length()); str.erase(0, pos + delim.length());
} }
result->val_arr->push_back(std::make_unique<value_string_t>(str)); result->val_arr->push_back(mk_val<value_string>(str));
return std::move(result); return std::move(result);
}}, }},
{"replace", [](const func_args & args) -> value { {"replace", [](const func_args & args) -> value {
@ -164,13 +164,13 @@ const func_builtins & value_string_t::get_builtins() const {
str.replace(pos, old_str.length(), new_str); str.replace(pos, old_str.length(), new_str);
pos += new_str.length(); pos += new_str.length();
} }
return std::make_unique<value_string_t>(str); return mk_val<value_string>(str);
}}, }},
{"int", [](const func_args & args) -> value { {"int", [](const func_args & args) -> value {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
try { try {
return std::make_unique<value_int_t>(std::stoi(str)); return mk_val<value_int>(std::stoi(str));
} catch (...) { } catch (...) {
throw std::runtime_error("Cannot convert string '" + str + "' to int"); throw std::runtime_error("Cannot convert string '" + str + "' to int");
} }
@ -179,7 +179,7 @@ const func_builtins & value_string_t::get_builtins() const {
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
std::string str = args.args[0]->as_string(); std::string str = args.args[0]->as_string();
try { try {
return std::make_unique<value_float_t>(std::stod(str)); return mk_val<value_float>(std::stod(str));
} catch (...) { } catch (...) {
throw std::runtime_error("Cannot convert string '" + str + "' to float"); throw std::runtime_error("Cannot convert string '" + str + "' to float");
} }
@ -187,7 +187,7 @@ const func_builtins & value_string_t::get_builtins() const {
{"string", [](const func_args & args) -> value { {"string", [](const func_args & args) -> value {
// no-op // no-op
args.ensure_vals<value_string>(); args.ensure_vals<value_string>();
return std::make_unique<value_string_t>(args.args[0]->as_string()); return mk_val<value_string>(args.args[0]->as_string());
}}, }},
{"indent", [](const func_args & args) -> value { {"indent", [](const func_args & args) -> value {
throw std::runtime_error("indent builtin not implemented"); throw std::runtime_error("indent builtin not implemented");
@ -205,17 +205,17 @@ const func_builtins & value_bool_t::get_builtins() const {
{"int", [](const func_args & args) -> value { {"int", [](const func_args & args) -> value {
args.ensure_vals<value_bool>(); args.ensure_vals<value_bool>();
bool val = args.args[0]->as_bool(); bool val = args.args[0]->as_bool();
return std::make_unique<value_int_t>(val ? 1 : 0); return mk_val<value_int>(val ? 1 : 0);
}}, }},
{"float", [](const func_args & args) -> value { {"float", [](const func_args & args) -> value {
args.ensure_vals<value_bool>(); args.ensure_vals<value_bool>();
bool val = args.args[0]->as_bool(); bool val = args.args[0]->as_bool();
return std::make_unique<value_float_t>(val ? 1.0 : 0.0); return mk_val<value_float>(val ? 1.0 : 0.0);
}}, }},
{"string", [](const func_args & args) -> value { {"string", [](const func_args & args) -> value {
args.ensure_vals<value_bool>(); args.ensure_vals<value_bool>();
bool val = args.args[0]->as_bool(); bool val = args.args[0]->as_bool();
return std::make_unique<value_string_t>(val ? "True" : "False"); return mk_val<value_string>(val ? "True" : "False");
}}, }},
}; };
return builtins; return builtins;
@ -227,7 +227,7 @@ const func_builtins & value_array_t::get_builtins() const {
{"list", [](const func_args & args) -> value { {"list", [](const func_args & args) -> value {
args.ensure_vals<value_array>(); args.ensure_vals<value_array>();
const auto & arr = args.args[0]->as_array(); const auto & arr = args.args[0]->as_array();
auto result = std::make_unique<value_array_t>(); auto result = mk_val<value_array>();
for (const auto& v : arr) { for (const auto& v : arr) {
result->val_arr->push_back(v->clone()); result->val_arr->push_back(v->clone());
} }
@ -237,7 +237,7 @@ const func_builtins & value_array_t::get_builtins() const {
args.ensure_vals<value_array>(); args.ensure_vals<value_array>();
const auto & arr = args.args[0]->as_array(); const auto & arr = args.args[0]->as_array();
if (arr.empty()) { if (arr.empty()) {
return std::make_unique<value_undefined_t>(); return mk_val<value_undefined>();
} }
return arr[0]->clone(); return arr[0]->clone();
}}, }},
@ -245,14 +245,14 @@ const func_builtins & value_array_t::get_builtins() const {
args.ensure_vals<value_array>(); args.ensure_vals<value_array>();
const auto & arr = args.args[0]->as_array(); const auto & arr = args.args[0]->as_array();
if (arr.empty()) { if (arr.empty()) {
return std::make_unique<value_undefined_t>(); return mk_val<value_undefined>();
} }
return arr[arr.size() - 1]->clone(); return arr[arr.size() - 1]->clone();
}}, }},
{"length", [](const func_args & args) -> value { {"length", [](const func_args & args) -> value {
args.ensure_vals<value_array>(); args.ensure_vals<value_array>();
const auto & arr = args.args[0]->as_array(); const auto & arr = args.args[0]->as_array();
return std::make_unique<value_int_t>(static_cast<int64_t>(arr.size())); return mk_val<value_int>(static_cast<int64_t>(arr.size()));
}}, }},
// TODO: reverse, sort, join, string, unique // TODO: reverse, sort, join, string, unique
}; };
@ -270,22 +270,22 @@ const func_builtins & value_object_t::get_builtins() const {
if (it != obj.end()) { if (it != obj.end()) {
return it->second->clone(); return it->second->clone();
} else { } else {
return std::make_unique<value_undefined_t>(); return mk_val<value_undefined>();
} }
}}, }},
{"keys", [](const func_args & args) -> value { {"keys", [](const func_args & args) -> value {
args.ensure_vals<value_object>(); args.ensure_vals<value_object>();
const auto & obj = args.args[0]->as_object(); const auto & obj = args.args[0]->as_object();
auto result = std::make_unique<value_array_t>(); auto result = mk_val<value_array>();
for (const auto & pair : obj) { for (const auto & pair : obj) {
result->val_arr->push_back(std::make_unique<value_string_t>(pair.first)); result->val_arr->push_back(mk_val<value_string>(pair.first));
} }
return result; return result;
}}, }},
{"values", [](const func_args & args) -> value { {"values", [](const func_args & args) -> value {
args.ensure_vals<value_object>(); args.ensure_vals<value_object>();
const auto & obj = args.args[0]->as_object(); const auto & obj = args.args[0]->as_object();
auto result = std::make_unique<value_array_t>(); auto result = mk_val<value_array>();
for (const auto & pair : obj) { for (const auto & pair : obj) {
result->val_arr->push_back(pair.second->clone()); result->val_arr->push_back(pair.second->clone());
} }
@ -294,10 +294,10 @@ const func_builtins & value_object_t::get_builtins() const {
{"items", [](const func_args & args) -> value { {"items", [](const func_args & args) -> value {
args.ensure_vals<value_object>(); args.ensure_vals<value_object>();
const auto & obj = args.args[0]->as_object(); const auto & obj = args.args[0]->as_object();
auto result = std::make_unique<value_array_t>(); auto result = mk_val<value_array>();
for (const auto & pair : obj) { for (const auto & pair : obj) {
auto item = std::make_unique<value_array_t>(); auto item = mk_val<value_array>();
item->val_arr->push_back(std::make_unique<value_string_t>(pair.first)); item->val_arr->push_back(mk_val<value_string>(pair.first));
item->val_arr->push_back(pair.second->clone()); item->val_arr->push_back(pair.second->clone());
result->val_arr->push_back(std::move(item)); result->val_arr->push_back(std::move(item));
} }

View File

@ -28,16 +28,16 @@ value binary_expression::execute(context & ctx) {
// Equality operators // Equality operators
value right_val = right->execute(ctx); value right_val = right->execute(ctx);
if (op.value == "==") { if (op.value == "==") {
return std::make_unique<value_bool_t>(left_val == right_val); return mk_val<value_bool>(left_val == right_val);
} else if (op.value == "!=") { } else if (op.value == "!=") {
return std::make_unique<value_bool_t>(left_val != right_val); return mk_val<value_bool>(left_val != right_val);
} }
// Handle undefined and null values // Handle undefined and null values
if (is_val<value_undefined>(left_val) || is_val<value_undefined>(right_val)) { if (is_val<value_undefined>(left_val) || is_val<value_undefined>(right_val)) {
if (is_val<value_undefined>(right_val) && (op.value == "in" || op.value == "not in")) { if (is_val<value_undefined>(right_val) && (op.value == "in" || op.value == "not in")) {
// Special case: `anything in undefined` is `false` and `anything not in undefined` is `true` // Special case: `anything in undefined` is `false` and `anything not in undefined` is `true`
return std::make_unique<value_bool_t>(op.value == "not in"); return mk_val<value_bool>(op.value == "not in");
} }
throw std::runtime_error("Cannot perform operation " + op.value + " on undefined values"); throw std::runtime_error("Cannot perform operation " + op.value + " on undefined values");
} else if (is_val<value_null>(left_val) || is_val<value_null>(right_val)) { } else if (is_val<value_null>(left_val) || is_val<value_null>(right_val)) {
@ -46,7 +46,7 @@ value binary_expression::execute(context & ctx) {
// String concatenation with ~ // String concatenation with ~
if (op.value == "~") { if (op.value == "~") {
return std::make_unique<value_string_t>(left_val->as_string() + right_val->as_string()); return mk_val<value_string>(left_val->as_string() + right_val->as_string());
} }
// Float operations // Float operations
@ -58,28 +58,28 @@ value binary_expression::execute(context & ctx) {
double res = (op.value == "+") ? a + b : (op.value == "-") ? a - b : a * b; double res = (op.value == "+") ? a + b : (op.value == "-") ? a - b : a * b;
bool is_float = is_val<value_float>(left_val) || is_val<value_float>(right_val); bool is_float = is_val<value_float>(left_val) || is_val<value_float>(right_val);
if (is_float) { if (is_float) {
return std::make_unique<value_float_t>(res); return mk_val<value_float>(res);
} else { } else {
return std::make_unique<value_int_t>(static_cast<int64_t>(res)); return mk_val<value_int>(static_cast<int64_t>(res));
} }
} else if (op.value == "/") { } else if (op.value == "/") {
return std::make_unique<value_float_t>(a / b); return mk_val<value_float>(a / b);
} else if (op.value == "%") { } else if (op.value == "%") {
double rem = std::fmod(a, b); double rem = std::fmod(a, b);
bool is_float = is_val<value_float>(left_val) || is_val<value_float>(right_val); bool is_float = is_val<value_float>(left_val) || is_val<value_float>(right_val);
if (is_float) { if (is_float) {
return std::make_unique<value_float_t>(rem); return mk_val<value_float>(rem);
} else { } else {
return std::make_unique<value_int_t>(static_cast<int64_t>(rem)); return mk_val<value_int>(static_cast<int64_t>(rem));
} }
} else if (op.value == "<") { } else if (op.value == "<") {
return std::make_unique<value_bool_t>(a < b); return mk_val<value_bool>(a < b);
} else if (op.value == ">") { } else if (op.value == ">") {
return std::make_unique<value_bool_t>(a > b); return mk_val<value_bool>(a > b);
} else if (op.value == ">=") { } else if (op.value == ">=") {
return std::make_unique<value_bool_t>(a >= b); return mk_val<value_bool>(a >= b);
} else if (op.value == "<=") { } else if (op.value == "<=") {
return std::make_unique<value_bool_t>(a <= b); return mk_val<value_bool>(a <= b);
} }
} }
@ -88,7 +88,7 @@ value binary_expression::execute(context & ctx) {
if (op.value == "+") { if (op.value == "+") {
auto & left_arr = left_val->as_array(); auto & left_arr = left_val->as_array();
auto & right_arr = right_val->as_array(); auto & right_arr = right_val->as_array();
auto result = std::make_unique<value_array_t>(); auto result = mk_val<value_array>();
for (const auto & item : left_arr) { for (const auto & item : left_arr) {
result->val_arr->push_back(item->clone()); result->val_arr->push_back(item->clone());
} }
@ -101,16 +101,16 @@ value binary_expression::execute(context & ctx) {
auto & arr = right_val->as_array(); auto & arr = right_val->as_array();
bool member = std::find_if(arr.begin(), arr.end(), [&](const value& v) { return v == left_val; }) != arr.end(); bool member = std::find_if(arr.begin(), arr.end(), [&](const value& v) { return v == left_val; }) != arr.end();
if (op.value == "in") { if (op.value == "in") {
return std::make_unique<value_bool_t>(member); return mk_val<value_bool>(member);
} else if (op.value == "not in") { } else if (op.value == "not in") {
return std::make_unique<value_bool_t>(!member); return mk_val<value_bool>(!member);
} }
} }
// String concatenation // String concatenation
if (is_val<value_string>(left_val) || is_val<value_string>(right_val)) { if (is_val<value_string>(left_val) || is_val<value_string>(right_val)) {
if (op.value == "+") { if (op.value == "+") {
return std::make_unique<value_string_t>(left_val->as_string() + right_val->as_string()); return mk_val<value_string>(left_val->as_string() + right_val->as_string());
} }
} }
@ -119,9 +119,9 @@ value binary_expression::execute(context & ctx) {
auto left_str = left_val->as_string(); auto left_str = left_val->as_string();
auto right_str = right_val->as_string(); auto right_str = right_val->as_string();
if (op.value == "in") { if (op.value == "in") {
return std::make_unique<value_bool_t>(right_str.find(left_str) != std::string::npos); return mk_val<value_bool>(right_str.find(left_str) != std::string::npos);
} else if (op.value == "not in") { } else if (op.value == "not in") {
return std::make_unique<value_bool_t>(right_str.find(left_str) == std::string::npos); return mk_val<value_bool>(right_str.find(left_str) == std::string::npos);
} }
} }
@ -131,9 +131,9 @@ value binary_expression::execute(context & ctx) {
auto & obj = right_val->as_object(); auto & obj = right_val->as_object();
bool has_key = obj.find(key) != obj.end(); bool has_key = obj.find(key) != obj.end();
if (op.value == "in") { if (op.value == "in") {
return std::make_unique<value_bool_t>(has_key); return mk_val<value_bool>(has_key);
} else if (op.value == "not in") { } else if (op.value == "not in") {
return std::make_unique<value_bool_t>(!has_key); return mk_val<value_bool>(!has_key);
} }
} }