From dd93e1e51c8cc7ba827a04927dfa98fbe1f1b12a Mon Sep 17 00:00:00 2001 From: Jose Ricardo Ziviani Date: Wed, 22 May 2019 00:56:34 -0300 Subject: [PATCH] Add size expression for containers and strings {% print size("test") %} {% print size(vector) %} {% for i in range(0, size(vec), 1) %} {= vec[i] =} {% endfor %} Signed-off-by: Jose Ricardo Ziviani --- include/context.h | 4 ++++ include/object.h | 35 +++++++++++++++++++++++++---------- src/compiler.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- src/context.cpp | 14 ++++++++++---- 4 files changed, 82 insertions(+), 15 deletions(-) diff --git a/include/context.h b/include/context.h index d240947..c247fd5 100644 --- a/include/context.h +++ b/include/context.h @@ -97,6 +97,10 @@ namespace amps inline object context::stack_top() const { + if (stack_.empty()) { + return std::nullopt; + } + return stack_.look_back(); } diff --git a/include/object.h b/include/object.h index 65899f1..dd49143 100644 --- a/include/object.h +++ b/include/object.h @@ -17,6 +17,7 @@ namespace amps NUMBER, STRING, BOOL, + OBJECT, }; inline std::ostream& operator<<(std::ostream &os, const vobject_types &obj) @@ -33,6 +34,10 @@ namespace amps case vobject_types::STRING: os << "string"; break; + + case vobject_types::OBJECT: + os << "object"; + break; } return os; @@ -41,6 +46,7 @@ namespace amps class vobject { var_t data_; + vobject_types ftype_; public: vobject() @@ -49,6 +55,20 @@ namespace amps vobject(var_t value) : data_(value) + { + if (std::holds_alternative(data_)) { + ftype_ = vobject_types::STRING; + } + else if (std::holds_alternative(data_)) { + ftype_ = vobject_types::NUMBER; + } + else { + ftype_ = vobject_types::BOOL; + } + } + + vobject(var_t value, vobject_types forced_type) : + data_(value), ftype_(forced_type) { } @@ -59,9 +79,9 @@ namespace amps vobject &operator=(const vobject &) = default; vobject &operator=(vobject &&) = default; + vobject_types get_type() const; bool get_bool_or(bool alt) const; number_t get_number_or(number_t alt) const; - vobject_types get_type() const; std::string get_string_or(const std::string &alt) const; std::string to_string() const; }; @@ -98,15 +118,7 @@ namespace amps inline vobject_types vobject::get_type() const { - if (std::holds_alternative(data_)) { - return vobject_types::BOOL; - } - else if (std::holds_alternative(data_)) { - return vobject_types::NUMBER; - } - else { - return vobject_types::STRING; - } + return ftype_; } inline std::string vobject::to_string() const @@ -120,6 +132,9 @@ namespace amps case vobject_types::STRING: return get_string_or(""); + + case vobject_types::OBJECT: + return get_string_or(""); } return ""; diff --git a/src/compiler.cpp b/src/compiler.cpp index b3e4b79..fab7953 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -776,6 +776,48 @@ namespace amps context_.stack_push(object_t(false)); return true; } + else if (it.match(token_types::SIZE)) { + if (it.match(token_types::LEFT_PAREN)) { + if (!parse_expression(it)) { + return false; + } + + if (context_.stack_empty()) { + return false; + } + + vobject_types tp = context_.stack_top_type(); + if (tp == vobject_types::STRING) { + std::string data = context_.stack_pop_string_or(""); + context_.stack_push(object_t(data.size())); + } + else if (tp == vobject_types::NUMBER) { + number_t data = context_.stack_pop_number_or(0); + context_.stack_push(object_t(sizeof(data))); + } + else if (tp == vobject_types::BOOL) { + context_.stack_pop(); + context_.stack_push(object_t(number_t(1))); + } + else if (tp == vobject_types::OBJECT) { + std::string data = context_.stack_pop_string_or(""); + context_.stack_push(object_t(context_.environment_get_size(data))); + } + + if (!it.match(token_types::RIGHT_PAREN)) { + error_.critical("size expects a closing ')'. Line: ", + it.range().line); + return false; + } + + return true; + } + else { + error_.critical("size expects an opening '('", ". Line: ", + it.range().line); + return false; + } + } else if (it.match(token_types::IDENTIFIER)) { string id = it.look_back().value().value_or(""); if (!context_.environment_is_key_defined(id)) { @@ -814,7 +856,7 @@ namespace amps } else { context_.stack_pop(); - context_.stack_push(object_t(std::string(""))); + context_.stack_push(object_t(std::string(""))); } if (!it.match(token_types::RIGHT_BRACKET)) { diff --git a/src/context.cpp b/src/context.cpp index fe3eb3c..b902a6a 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -15,14 +15,15 @@ namespace amps using T = std::decay_t; if constexpr (std::is_same_v || - std::is_same_v) { + std::is_same_v || + std::is_same_v) { stack_push(object_t(var)); } // object exists but it's not a simple number or string // evaluate it to true to represent that it's valid else { - stack_push(object_t(true)); + stack_push(object_t(key, vobject_types::OBJECT)); } return true; @@ -43,7 +44,7 @@ namespace amps // make sure we're not accessing out of bounds item if (index >= var.size()) { - stack_push(object_t(std::string(""))); + stack_push(object_t(std::string(""))); return false; } else { @@ -58,6 +59,11 @@ namespace amps bool context::stack_push_from_environment(const std::string &key, const std::string &user_key) { + if (key.size() == 0 || user_key.size() == 0) { + stack_push(object_t(std::string(""))); + return false; + } + // simply push the value of environment_[key] onto the stack // this method handles map and map // values, so the key of that map is also required @@ -69,7 +75,7 @@ namespace amps // make sure that the key exists if (var.find(user_key) == var.end()) { - stack_push(object_t(std::string(""))); + stack_push(object_t(std::string(""))); return false; } else {