aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/rfnoc/nocscript/expression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/rfnoc/nocscript/expression.cpp')
-rw-r--r--host/lib/rfnoc/nocscript/expression.cpp413
1 files changed, 413 insertions, 0 deletions
diff --git a/host/lib/rfnoc/nocscript/expression.cpp b/host/lib/rfnoc/nocscript/expression.cpp
new file mode 100644
index 000000000..38d6e2128
--- /dev/null
+++ b/host/lib/rfnoc/nocscript/expression.cpp
@@ -0,0 +1,413 @@
+//
+// Copyright 2015 Ettus Research LLC
+//
+// 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 "expression.hpp"
+#include "function_table.hpp"
+#include <uhd/utils/cast.hpp>
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <boost/assign.hpp>
+#include <boost/algorithm/string.hpp>
+
+using namespace uhd::rfnoc::nocscript;
+
+std::map<expression::type_t, std::string> expression::type_repr = boost::assign::map_list_of
+ (TYPE_INT, "INT")
+ (TYPE_DOUBLE, "DOUBLE")
+ (TYPE_STRING, "STRING")
+ (TYPE_BOOL, "BOOL")
+ (TYPE_INT_VECTOR, "INT_VECTOR")
+;
+
+/********************************************************************
+ * Literal expressions (constants)
+ *******************************************************************/
+expression_literal::expression_literal(
+ const std::string token_val,
+ expression::type_t type
+) : _bool_val(false)
+ , _int_val(0)
+ , _double_val(0.0)
+ , _val(token_val)
+ , _type(type)
+{
+ switch (_type) {
+ case expression::TYPE_STRING:
+ // Remove the leading and trailing quotes:
+ _val = _val.substr(1, _val.size()-2);
+ break;
+
+ case expression::TYPE_INT:
+ if (_val.substr(0, 2) == "0x") {
+ _int_val = uhd::cast::hexstr_cast<int>(_val);
+ } else {
+ _int_val = boost::lexical_cast<int>(_val);
+ }
+ break;
+
+ case expression::TYPE_DOUBLE:
+ _double_val = boost::lexical_cast<double>(_val);
+ break;
+
+ case expression::TYPE_BOOL:
+ if (boost::to_upper_copy(_val) == "TRUE") {
+ _bool_val = true;
+ } else {
+ // lexical cast to bool is too picky
+ _bool_val = bool(boost::lexical_cast<int>(_val));
+ }
+ break;
+
+ case expression::TYPE_INT_VECTOR:
+ {
+ std::string str_vec = _val.substr(1, _val.size()-2);
+ std::vector<std::string> subtoken_list;
+ boost::split(subtoken_list, str_vec, boost::is_any_of(", "), boost::token_compress_on);
+ BOOST_FOREACH(const std::string &t, subtoken_list) {
+ _int_vector_val.push_back(boost::lexical_cast<int>(t));
+ }
+ break;
+ }
+
+ default:
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
+expression_literal::expression_literal(bool b)
+ : _bool_val(b)
+ , _int_val(0)
+ , _double_val(0.0)
+ , _val("")
+ , _type(expression::TYPE_BOOL)
+{
+ // nop
+}
+
+expression_literal::expression_literal(int i)
+ : _bool_val(false)
+ , _int_val(i)
+ , _double_val(0.0)
+ , _val("")
+ , _type(expression::TYPE_INT)
+{
+ // nop
+}
+
+expression_literal::expression_literal(double d)
+ : _bool_val(false)
+ , _int_val(0)
+ , _double_val(d)
+ , _val("")
+ , _type(expression::TYPE_DOUBLE)
+{
+ // nop
+}
+
+expression_literal::expression_literal(const std::string &s)
+ : _bool_val(false)
+ , _int_val(0)
+ , _double_val(0.0)
+ , _val(s)
+ , _type(expression::TYPE_STRING)
+{
+ // nop
+}
+
+expression_literal::expression_literal(const std::vector<int> v)
+ : _bool_val(false)
+ , _int_val(0)
+ , _double_val(0.0)
+ , _int_vector_val(v)
+ , _val("")
+ , _type(expression::TYPE_INT_VECTOR)
+{
+ // nop
+}
+
+bool expression_literal::to_bool() const
+{
+ switch (_type) {
+ case TYPE_INT:
+ return bool(boost::lexical_cast<int>(_val));
+ case TYPE_STRING:
+ return not _val.empty();
+ case TYPE_DOUBLE:
+ return bool(boost::lexical_cast<double>(_val));
+ case TYPE_BOOL:
+ return _bool_val;
+ case TYPE_INT_VECTOR:
+ return not _int_vector_val.empty();
+ default:
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
+int expression_literal::get_int() const
+{
+ if (_type != TYPE_INT) {
+ throw uhd::type_error("Cannot call get_int() on non-int value.");
+ }
+
+ return _int_val;
+}
+
+double expression_literal::get_double() const
+{
+ if (_type != TYPE_DOUBLE) {
+ throw uhd::type_error("Cannot call get_double() on non-double value.");
+ }
+
+ return _double_val;
+}
+
+std::string expression_literal::get_string() const
+{
+ if (_type != TYPE_STRING) {
+ throw uhd::type_error("Cannot call get_string() on non-string value.");
+ }
+
+ return _val;
+}
+
+bool expression_literal::get_bool() const
+{
+ if (_type != TYPE_BOOL) {
+ throw uhd::type_error("Cannot call get_bool() on non-boolean value.");
+ }
+
+ return _bool_val;
+}
+
+std::vector<int> expression_literal::get_int_vector() const
+{
+ if (_type != TYPE_INT_VECTOR) {
+ throw uhd::type_error("Cannot call get_bool() on non-boolean value.");
+ }
+
+ return _int_vector_val;
+}
+
+std::string expression_literal::repr() const
+{
+ switch (_type) {
+ case TYPE_INT:
+ return boost::lexical_cast<std::string>(_int_val);
+ case TYPE_STRING:
+ return _val;
+ case TYPE_DOUBLE:
+ return boost::lexical_cast<std::string>(_double_val);
+ case TYPE_BOOL:
+ return _bool_val ? "TRUE" : "FALSE";
+ case TYPE_INT_VECTOR:
+ {
+ std::stringstream sstr;
+ sstr << "[";
+ for (size_t i = 0; i < _int_vector_val.size(); i++) {
+ if (i > 0) {
+ sstr << ", ";
+ }
+ sstr << _int_vector_val[i];
+ }
+ sstr << "]";
+ return sstr.str();
+ }
+ default:
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
+bool expression_literal::operator==(const expression_literal &rhs) const
+{
+ if (rhs.infer_type() != _type) {
+ return false;
+ }
+
+ switch (_type) {
+ case TYPE_INT:
+ return get_int() == rhs.get_int();
+ case TYPE_STRING:
+ return get_string() == rhs.get_string();
+ case TYPE_DOUBLE:
+ return get_double() == rhs.get_double();
+ case TYPE_BOOL:
+ return get_bool() == rhs.get_bool();
+ default:
+ UHD_THROW_INVALID_CODE_PATH();
+ }
+}
+
+/********************************************************************
+ * Containers
+ *******************************************************************/
+expression_container::sptr expression_container::make()
+{
+ return sptr(new expression_container);
+}
+
+expression::type_t expression_container::infer_type() const
+{
+ if (_combiner == COMBINE_OR or _combiner == COMBINE_AND) {
+ return TYPE_BOOL;
+ }
+
+ if (_sub_exprs.empty()) {
+ return TYPE_BOOL;
+ }
+
+ return _sub_exprs.back()->infer_type();
+}
+
+void expression_container::add(expression::sptr new_expr)
+{
+ _sub_exprs.push_back(new_expr);
+}
+
+bool expression_container::empty() const
+{
+ return _sub_exprs.empty();
+}
+
+void expression_container::set_combiner_safe(const combiner_type c)
+{
+ if (_combiner == COMBINE_NOTSET) {
+ _combiner = c;
+ return;
+ }
+
+ throw uhd::syntax_error("Attempting to override combiner type");
+}
+
+expression_literal expression_container::eval()
+{
+ if (_sub_exprs.empty()) {
+ return expression_literal(true);
+ }
+
+ expression_literal ret_val;
+ BOOST_FOREACH(const expression::sptr &sub_expr, _sub_exprs) {
+ ret_val = sub_expr->eval();
+ if (_combiner == COMBINE_AND and ret_val.to_bool() == false) {
+ return ret_val;
+ }
+ if (_combiner == COMBINE_OR and ret_val.to_bool() == true) {
+ return ret_val;
+ }
+ // For ALL, we return the last one, so just overwrite it
+ }
+ return ret_val;
+}
+
+/********************************************************************
+ * Functions
+ *******************************************************************/
+std::string expression_function::to_string(const std::string &name, const argtype_list_type &types)
+{
+ std::string s = name;
+ int arg_count = 0;
+ BOOST_FOREACH(const expression::type_t type, types) {
+ if (arg_count == 0) {
+ s += "(";
+ } else {
+ s += ", ";
+ }
+ s += type_repr[type];
+ arg_count++;
+ }
+ s += ")";
+
+ return s;
+}
+
+expression_function::expression_function(
+ const std::string &name,
+ const function_table::sptr func_table
+) : _name(name)
+ , _func_table(func_table)
+{
+ _combiner = COMBINE_ALL;
+ if (not _func_table->function_exists(_name)) {
+ throw uhd::syntax_error(str(
+ boost::format("Unknown function: %s")
+ % _name
+ ));
+ }
+}
+
+void expression_function::add(expression::sptr new_expr)
+{
+ expression_container::add(new_expr);
+ _arg_types.push_back(new_expr->infer_type());
+}
+
+expression::type_t expression_function::infer_type() const
+{
+ return _func_table->get_type(_name, _arg_types);
+}
+
+expression_literal expression_function::eval()
+{
+ return _func_table->eval(_name, _arg_types, _sub_exprs);
+}
+
+
+std::string expression_function::repr() const
+{
+ return to_string(_name, _arg_types);
+}
+
+expression_function::sptr expression_function::make(
+ const std::string &name,
+ const function_table::sptr func_table
+) {
+ return sptr(new expression_function(name, func_table));
+}
+
+/********************************************************************
+ * Variables
+ *******************************************************************/
+expression_variable::expression_variable(
+ const std::string &token_val,
+ type_getter_type type_getter,
+ value_getter_type value_getter
+) : _type_getter(type_getter)
+ , _value_getter(value_getter)
+{
+ // We can assume this is true because otherwise, it's not a valid token:
+ UHD_ASSERT_THROW(not token_val.empty() and token_val[0] == '$');
+
+ _varname = token_val.substr(1);
+}
+
+expression::type_t expression_variable::infer_type() const
+{
+ return _type_getter(_varname);
+}
+
+expression_literal expression_variable::eval()
+{
+ return _value_getter(_varname);
+}
+
+expression_variable::sptr expression_variable::make(
+ const std::string &token_val,
+ type_getter_type type_getter,
+ value_getter_type value_getter
+) {
+ return sptr(new expression_variable(token_val, type_getter, value_getter));
+}
+