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 {
|
||||
value_int_t(int64_t v) { val_int = v; }
|
||||
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 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 const func_builtins & get_builtins() const override;
|
||||
};
|
||||
using value_int = std::unique_ptr<value_int_t>;
|
||||
|
||||
|
||||
struct value_float_t : public value_t {
|
||||
value_float_t(double v) { val_flt = v; }
|
||||
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 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 const func_builtins & get_builtins() const override;
|
||||
};
|
||||
using value_float = std::unique_ptr<value_float_t>;
|
||||
|
||||
|
||||
struct value_string_t : public value_t {
|
||||
value_string_t(const std::string & v) { val_str = v; }
|
||||
virtual std::string type() const override { return "String"; }
|
||||
virtual std::string as_string() const override { return val_str; }
|
||||
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>;
|
||||
|
||||
|
||||
struct value_bool_t : public value_t {
|
||||
value_bool_t(bool v) { val_bool = v; }
|
||||
virtual std::string type() const override { return "Boolean"; }
|
||||
virtual bool as_bool() const override { return val_bool; }
|
||||
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 const func_builtins & get_builtins() const override;
|
||||
};
|
||||
using value_bool = std::unique_ptr<value_bool_t>;
|
||||
|
||||
|
||||
struct value_array_t : public value_t {
|
||||
value_array_t() {
|
||||
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;
|
||||
return tmp;
|
||||
}
|
||||
virtual const func_builtins & get_builtins() const override;
|
||||
};
|
||||
using value_array = std::unique_ptr<value_array_t>;
|
||||
|
||||
|
||||
struct value_object_t : public value_t {
|
||||
value_object_t() {
|
||||
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;
|
||||
return tmp;
|
||||
}
|
||||
virtual const func_builtins & get_builtins() const override;
|
||||
};
|
||||
using value_object = std::unique_ptr<value_object_t>;
|
||||
|
||||
|
||||
struct value_func_t : public value_t {
|
||||
value_func_t(func_handler & func) {
|
||||
val_func = func;
|
||||
|
|
@ -223,6 +235,7 @@ struct value_func_t : public value_t {
|
|||
};
|
||||
using value_func = std::unique_ptr<value_func_t>;
|
||||
|
||||
|
||||
struct value_null_t : public value_t {
|
||||
virtual std::string type() const override { return "Null"; }
|
||||
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>;
|
||||
|
||||
|
||||
struct value_undefined_t : public value_t {
|
||||
virtual std::string type() const override { return "Undefined"; }
|
||||
virtual bool is_undefined() const override { return true; }
|
||||
|
|
|
|||
|
|
@ -8,6 +8,40 @@
|
|||
|
||||
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) {
|
||||
size_t start = 0;
|
||||
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);
|
||||
}},
|
||||
{"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;
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -142,7 +142,17 @@ value binary_expression::execute(context & ctx) {
|
|||
|
||||
value filter_expression::execute(context & 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)) {
|
||||
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)) {
|
||||
auto & arr = input->as_array();
|
||||
if (filter_val == "list") {
|
||||
return std::make_unique<value_array_t>(input);
|
||||
} else if (filter_val == "first") {
|
||||
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");
|
||||
auto res = try_builtin(filter_val);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
throw std::runtime_error("Unknown filter '" + filter_val + "' for array");
|
||||
|
||||
} else if (is_val<value_string>(input)) {
|
||||
auto str = input->as_string();
|
||||
auto builtins = input->get_builtins();
|
||||
auto it = builtins.find(filter_val);
|
||||
if (it != builtins.end()) {
|
||||
func_args args;
|
||||
args.args.push_back(input->clone());
|
||||
return it->second(args);
|
||||
if (filter_val == "trim") {
|
||||
filter_val = "strip"; // alias
|
||||
}
|
||||
auto res = try_builtin(filter_val);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
throw std::runtime_error("Unknown filter '" + filter_val + "' for string");
|
||||
|
||||
} 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");
|
||||
|
||||
} else {
|
||||
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