add more builtins
This commit is contained in:
parent
15b3dbab05
commit
7ed11f78f9
|
|
@ -118,6 +118,7 @@ struct value_t {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct value_int_t : public value_t {
|
struct value_int_t : public value_t {
|
||||||
value_int_t(int64_t v) { val_int = v; }
|
value_int_t(int64_t v) { val_int = v; }
|
||||||
virtual std::string type() const override { return "Integer"; }
|
virtual std::string type() const override { return "Integer"; }
|
||||||
|
|
@ -125,9 +126,11 @@ struct value_int_t : public value_t {
|
||||||
virtual double as_float() const override { return static_cast<double>(val_int); }
|
virtual double as_float() const override { return static_cast<double>(val_int); }
|
||||||
virtual std::string as_string() const override { return std::to_string(val_int); }
|
virtual std::string as_string() const override { return std::to_string(val_int); }
|
||||||
virtual value clone() const override { return std::make_unique<value_int_t>(*this); }
|
virtual value clone() const override { return std::make_unique<value_int_t>(*this); }
|
||||||
|
virtual const func_builtins & get_builtins() const override;
|
||||||
};
|
};
|
||||||
using value_int = std::unique_ptr<value_int_t>;
|
using value_int = std::unique_ptr<value_int_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_float_t : public value_t {
|
struct value_float_t : public value_t {
|
||||||
value_float_t(double v) { val_flt = v; }
|
value_float_t(double v) { val_flt = v; }
|
||||||
virtual std::string type() const override { return "Float"; }
|
virtual std::string type() const override { return "Float"; }
|
||||||
|
|
@ -135,27 +138,32 @@ struct value_float_t : public value_t {
|
||||||
virtual int64_t as_int() const override { return static_cast<int64_t>(val_flt); }
|
virtual int64_t as_int() const override { return static_cast<int64_t>(val_flt); }
|
||||||
virtual std::string as_string() const override { return std::to_string(val_flt); }
|
virtual std::string as_string() const override { return std::to_string(val_flt); }
|
||||||
virtual value clone() const override { return std::make_unique<value_float_t>(*this); }
|
virtual value clone() const override { return std::make_unique<value_float_t>(*this); }
|
||||||
|
virtual const func_builtins & get_builtins() const override;
|
||||||
};
|
};
|
||||||
using value_float = std::unique_ptr<value_float_t>;
|
using value_float = std::unique_ptr<value_float_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_string_t : public value_t {
|
struct value_string_t : public value_t {
|
||||||
value_string_t(const std::string & v) { val_str = v; }
|
value_string_t(const std::string & v) { val_str = v; }
|
||||||
virtual std::string type() const override { return "String"; }
|
virtual std::string type() const override { return "String"; }
|
||||||
virtual std::string as_string() const override { return val_str; }
|
virtual std::string as_string() const override { return val_str; }
|
||||||
virtual value clone() const override { return std::make_unique<value_string_t>(*this); }
|
virtual value clone() const override { return std::make_unique<value_string_t>(*this); }
|
||||||
const func_builtins & get_builtins() const override;
|
virtual const func_builtins & get_builtins() const override;
|
||||||
};
|
};
|
||||||
using value_string = std::unique_ptr<value_string_t>;
|
using value_string = std::unique_ptr<value_string_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_bool_t : public value_t {
|
struct value_bool_t : public value_t {
|
||||||
value_bool_t(bool v) { val_bool = v; }
|
value_bool_t(bool v) { val_bool = v; }
|
||||||
virtual std::string type() const override { return "Boolean"; }
|
virtual std::string type() const override { return "Boolean"; }
|
||||||
virtual bool as_bool() const override { return val_bool; }
|
virtual bool as_bool() const override { return val_bool; }
|
||||||
virtual std::string as_string() const override { return val_bool ? "True" : "False"; }
|
virtual std::string as_string() const override { return val_bool ? "True" : "False"; }
|
||||||
virtual value clone() const override { return std::make_unique<value_bool_t>(*this); }
|
virtual value clone() const override { return std::make_unique<value_bool_t>(*this); }
|
||||||
|
virtual const func_builtins & get_builtins() const override;
|
||||||
};
|
};
|
||||||
using value_bool = std::unique_ptr<value_bool_t>;
|
using value_bool = std::unique_ptr<value_bool_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_array_t : public value_t {
|
struct value_array_t : public value_t {
|
||||||
value_array_t() {
|
value_array_t() {
|
||||||
val_arr = std::make_shared<std::vector<value>>();
|
val_arr = std::make_shared<std::vector<value>>();
|
||||||
|
|
@ -184,9 +192,11 @@ struct value_array_t : public value_t {
|
||||||
tmp->val_arr = this->val_arr;
|
tmp->val_arr = this->val_arr;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
virtual const func_builtins & get_builtins() const override;
|
||||||
};
|
};
|
||||||
using value_array = std::unique_ptr<value_array_t>;
|
using value_array = std::unique_ptr<value_array_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_object_t : public value_t {
|
struct value_object_t : public value_t {
|
||||||
value_object_t() {
|
value_object_t() {
|
||||||
val_obj = std::make_shared<std::map<std::string, value>>();
|
val_obj = std::make_shared<std::map<std::string, value>>();
|
||||||
|
|
@ -208,9 +218,11 @@ struct value_object_t : public value_t {
|
||||||
tmp->val_obj = this->val_obj;
|
tmp->val_obj = this->val_obj;
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
virtual const func_builtins & get_builtins() const override;
|
||||||
};
|
};
|
||||||
using value_object = std::unique_ptr<value_object_t>;
|
using value_object = std::unique_ptr<value_object_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_func_t : public value_t {
|
struct value_func_t : public value_t {
|
||||||
value_func_t(func_handler & func) {
|
value_func_t(func_handler & func) {
|
||||||
val_func = func;
|
val_func = func;
|
||||||
|
|
@ -223,6 +235,7 @@ struct value_func_t : public value_t {
|
||||||
};
|
};
|
||||||
using value_func = std::unique_ptr<value_func_t>;
|
using value_func = std::unique_ptr<value_func_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_null_t : public value_t {
|
struct value_null_t : public value_t {
|
||||||
virtual std::string type() const override { return "Null"; }
|
virtual std::string type() const override { return "Null"; }
|
||||||
virtual bool is_null() const override { return true; }
|
virtual bool is_null() const override { return true; }
|
||||||
|
|
@ -230,6 +243,7 @@ struct value_null_t : public value_t {
|
||||||
};
|
};
|
||||||
using value_null = std::unique_ptr<value_null_t>;
|
using value_null = std::unique_ptr<value_null_t>;
|
||||||
|
|
||||||
|
|
||||||
struct value_undefined_t : public value_t {
|
struct value_undefined_t : public value_t {
|
||||||
virtual std::string type() const override { return "Undefined"; }
|
virtual std::string type() const override { return "Undefined"; }
|
||||||
virtual bool is_undefined() const override { return true; }
|
virtual bool is_undefined() const override { return true; }
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,40 @@
|
||||||
|
|
||||||
namespace jinja {
|
namespace jinja {
|
||||||
|
|
||||||
|
const func_builtins & value_int_t::get_builtins() const {
|
||||||
|
static const func_builtins builtins = {
|
||||||
|
{"abs", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_int>();
|
||||||
|
int64_t val = args.args[0]->as_int();
|
||||||
|
return std::make_unique<value_int_t>(val < 0 ? -val : val);
|
||||||
|
}},
|
||||||
|
{"float", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_int>();
|
||||||
|
double val = static_cast<double>(args.args[0]->as_int());
|
||||||
|
return std::make_unique<value_float_t>(val);
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const func_builtins & value_float_t::get_builtins() const {
|
||||||
|
static const func_builtins builtins = {
|
||||||
|
{"abs", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_float>();
|
||||||
|
double val = args.args[0]->as_float();
|
||||||
|
return std::make_unique<value_float_t>(val < 0.0 ? -val : val);
|
||||||
|
}},
|
||||||
|
{"int", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_float>();
|
||||||
|
int64_t val = static_cast<int64_t>(args.args[0]->as_float());
|
||||||
|
return std::make_unique<value_int_t>(val);
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string string_strip(const std::string & str, bool left, bool right) {
|
static std::string string_strip(const std::string & str, bool left, bool right) {
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
size_t end = str.length();
|
size_t end = str.length();
|
||||||
|
|
@ -132,8 +166,146 @@ const func_builtins & value_string_t::get_builtins() const {
|
||||||
}
|
}
|
||||||
return std::make_unique<value_string_t>(str);
|
return std::make_unique<value_string_t>(str);
|
||||||
}},
|
}},
|
||||||
|
{"int", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_string>();
|
||||||
|
std::string str = args.args[0]->as_string();
|
||||||
|
try {
|
||||||
|
return std::make_unique<value_int_t>(std::stoi(str));
|
||||||
|
} catch (...) {
|
||||||
|
throw std::runtime_error("Cannot convert string '" + str + "' to int");
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{"float", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_string>();
|
||||||
|
std::string str = args.args[0]->as_string();
|
||||||
|
try {
|
||||||
|
return std::make_unique<value_float_t>(std::stod(str));
|
||||||
|
} catch (...) {
|
||||||
|
throw std::runtime_error("Cannot convert string '" + str + "' to float");
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{"string", [](const func_args & args) -> value {
|
||||||
|
// no-op
|
||||||
|
args.ensure_vals<value_string>();
|
||||||
|
return std::make_unique<value_string_t>(args.args[0]->as_string());
|
||||||
|
}},
|
||||||
|
{"indent", [](const func_args & args) -> value {
|
||||||
|
throw std::runtime_error("indent builtin not implemented");
|
||||||
|
}},
|
||||||
|
{"join", [](const func_args & args) -> value {
|
||||||
|
throw std::runtime_error("join builtin not implemented");
|
||||||
|
}},
|
||||||
};
|
};
|
||||||
return builtins;
|
return builtins;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const func_builtins & value_bool_t::get_builtins() const {
|
||||||
|
static const func_builtins builtins = {
|
||||||
|
{"int", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_bool>();
|
||||||
|
bool val = args.args[0]->as_bool();
|
||||||
|
return std::make_unique<value_int_t>(val ? 1 : 0);
|
||||||
|
}},
|
||||||
|
{"float", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_bool>();
|
||||||
|
bool val = args.args[0]->as_bool();
|
||||||
|
return std::make_unique<value_float_t>(val ? 1.0 : 0.0);
|
||||||
|
}},
|
||||||
|
{"string", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_bool>();
|
||||||
|
bool val = args.args[0]->as_bool();
|
||||||
|
return std::make_unique<value_string_t>(val ? "True" : "False");
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const func_builtins & value_array_t::get_builtins() const {
|
||||||
|
static const func_builtins builtins = {
|
||||||
|
{"list", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_array>();
|
||||||
|
const auto & arr = args.args[0]->as_array();
|
||||||
|
auto result = std::make_unique<value_array_t>();
|
||||||
|
for (const auto& v : arr) {
|
||||||
|
result->val_arr->push_back(v->clone());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}},
|
||||||
|
{"first", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_array>();
|
||||||
|
const auto & arr = args.args[0]->as_array();
|
||||||
|
if (arr.empty()) {
|
||||||
|
return std::make_unique<value_undefined_t>();
|
||||||
|
}
|
||||||
|
return arr[0]->clone();
|
||||||
|
}},
|
||||||
|
{"last", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_array>();
|
||||||
|
const auto & arr = args.args[0]->as_array();
|
||||||
|
if (arr.empty()) {
|
||||||
|
return std::make_unique<value_undefined_t>();
|
||||||
|
}
|
||||||
|
return arr[arr.size() - 1]->clone();
|
||||||
|
}},
|
||||||
|
{"length", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_array>();
|
||||||
|
const auto & arr = args.args[0]->as_array();
|
||||||
|
return std::make_unique<value_int_t>(static_cast<int64_t>(arr.size()));
|
||||||
|
}},
|
||||||
|
// TODO: reverse, sort, join, string, unique
|
||||||
|
};
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const func_builtins & value_object_t::get_builtins() const {
|
||||||
|
static const func_builtins builtins = {
|
||||||
|
{"get", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_object, value_string>(); // TODO: add default value
|
||||||
|
const auto & obj = args.args[0]->as_object();
|
||||||
|
std::string key = args.args[1]->as_string();
|
||||||
|
auto it = obj.find(key);
|
||||||
|
if (it != obj.end()) {
|
||||||
|
return it->second->clone();
|
||||||
|
} else {
|
||||||
|
return std::make_unique<value_undefined_t>();
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{"keys", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_object>();
|
||||||
|
const auto & obj = args.args[0]->as_object();
|
||||||
|
auto result = std::make_unique<value_array_t>();
|
||||||
|
for (const auto & pair : obj) {
|
||||||
|
result->val_arr->push_back(std::make_unique<value_string_t>(pair.first));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}},
|
||||||
|
{"values", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_object>();
|
||||||
|
const auto & obj = args.args[0]->as_object();
|
||||||
|
auto result = std::make_unique<value_array_t>();
|
||||||
|
for (const auto & pair : obj) {
|
||||||
|
result->val_arr->push_back(pair.second->clone());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}},
|
||||||
|
{"items", [](const func_args & args) -> value {
|
||||||
|
args.ensure_vals<value_object>();
|
||||||
|
const auto & obj = args.args[0]->as_object();
|
||||||
|
auto result = std::make_unique<value_array_t>();
|
||||||
|
for (const auto & pair : obj) {
|
||||||
|
auto item = std::make_unique<value_array_t>();
|
||||||
|
item->val_arr->push_back(std::make_unique<value_string_t>(pair.first));
|
||||||
|
item->val_arr->push_back(pair.second->clone());
|
||||||
|
result->val_arr->push_back(std::move(item));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace jinja
|
} // namespace jinja
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,17 @@ value binary_expression::execute(context & ctx) {
|
||||||
|
|
||||||
value filter_expression::execute(context & ctx) {
|
value filter_expression::execute(context & ctx) {
|
||||||
value input = operand->execute(ctx);
|
value input = operand->execute(ctx);
|
||||||
// value filter_func = filter->execute(ctx);
|
|
||||||
|
auto try_builtin = [&](const std::string & name) -> value {
|
||||||
|
auto builtins = input->get_builtins();
|
||||||
|
auto it = builtins.find(name);
|
||||||
|
if (it != builtins.end()) {
|
||||||
|
func_args args;
|
||||||
|
args.args.push_back(input->clone());
|
||||||
|
return it->second(args);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
if (is_stmt<identifier>(filter)) {
|
if (is_stmt<identifier>(filter)) {
|
||||||
auto filter_val = dynamic_cast<identifier*>(filter.get())->value;
|
auto filter_val = dynamic_cast<identifier*>(filter.get())->value;
|
||||||
|
|
@ -154,43 +164,42 @@ value filter_expression::execute(context & ctx) {
|
||||||
|
|
||||||
if (is_val<value_array>(input)) {
|
if (is_val<value_array>(input)) {
|
||||||
auto & arr = input->as_array();
|
auto & arr = input->as_array();
|
||||||
if (filter_val == "list") {
|
auto res = try_builtin(filter_val);
|
||||||
return std::make_unique<value_array_t>(input);
|
if (res) {
|
||||||
} else if (filter_val == "first") {
|
return res;
|
||||||
if (arr.empty()) {
|
|
||||||
return std::make_unique<value_undefined_t>();
|
|
||||||
}
|
|
||||||
return arr[0]->clone();
|
|
||||||
} else if (filter_val == "last") {
|
|
||||||
if (arr.empty()) {
|
|
||||||
return std::make_unique<value_undefined_t>();
|
|
||||||
}
|
|
||||||
return arr[arr.size() - 1]->clone();
|
|
||||||
} else if (filter_val == "length") {
|
|
||||||
return std::make_unique<value_int_t>(static_cast<int64_t>(arr.size()));
|
|
||||||
} else {
|
|
||||||
// TODO: reverse, sort, join, string, unique
|
|
||||||
throw std::runtime_error("Unknown filter '" + filter_val + "' for array");
|
|
||||||
}
|
}
|
||||||
|
throw std::runtime_error("Unknown filter '" + filter_val + "' for array");
|
||||||
|
|
||||||
} else if (is_val<value_string>(input)) {
|
} else if (is_val<value_string>(input)) {
|
||||||
auto str = input->as_string();
|
auto str = input->as_string();
|
||||||
auto builtins = input->get_builtins();
|
auto builtins = input->get_builtins();
|
||||||
auto it = builtins.find(filter_val);
|
if (filter_val == "trim") {
|
||||||
if (it != builtins.end()) {
|
filter_val = "strip"; // alias
|
||||||
func_args args;
|
}
|
||||||
args.args.push_back(input->clone());
|
auto res = try_builtin(filter_val);
|
||||||
return it->second(args);
|
if (res) {
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("Unknown filter '" + filter_val + "' for string");
|
throw std::runtime_error("Unknown filter '" + filter_val + "' for string");
|
||||||
|
|
||||||
} else if (is_val<value_int>(input) || is_val<value_float>(input)) {
|
} else if (is_val<value_int>(input) || is_val<value_float>(input)) {
|
||||||
// TODO
|
auto res = try_builtin(filter_val);
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
throw std::runtime_error("Unknown filter '" + filter_val + "' for number");
|
throw std::runtime_error("Unknown filter '" + filter_val + "' for number");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Filters not supported for type " + input->type());
|
throw std::runtime_error("Filters not supported for type " + input->type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (is_stmt<call_expression>(filter)) {
|
||||||
|
// TODO
|
||||||
|
// value filter_func = filter->execute(ctx);
|
||||||
|
throw std::runtime_error("Filter with arguments not implemented");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Invalid filter expression");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue