From a6aae172e3e1dac98b68ea6896be67c5a1feaab3 Mon Sep 17 00:00:00 2001 From: Asger Gitz-Johansen Date: Mon, 12 Sep 2022 20:50:03 +0200 Subject: [PATCH] feat: add support for delayable clock types --- CMakeLists.txt | 1 + include/clock.h | 42 +++++++++++++++++++++++++ include/symbol_table.h | 10 +++--- src/clock.cpp | 63 +++++++++++++++++++++++++++++++++++++ src/drivers/z3_driver.cpp | 2 ++ src/operations/add.cpp | 15 +++++++++ src/operations/boolean.cpp | 30 ++++++++++++++++++ src/operations/divide.cpp | 25 +++++++++++++++ src/operations/modulo.cpp | 9 ++++++ src/operations/multiply.cpp | 15 +++++++++ src/operations/pow.cpp | 15 +++++++++ src/operations/subtract.cpp | 15 +++++++++ src/parser/lex/footer.l | 9 ++++++ src/parser/lex/lexer.l | 1 + src/parser/lex/skeleton.l | 1 + src/parser/lex/tokens.l | 3 +- src/parser/yacc/exp.y | 1 + src/parser/yacc/tokens.y | 1 + src/symbol_table.cpp | 11 ++++++- 19 files changed, 263 insertions(+), 6 deletions(-) create mode 100644 include/clock.h create mode 100644 src/clock.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f32e5f..09a617c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ add_library(${PROJECT_NAME} SHARED src/drivers/interpreter.cpp src/drivers/compiler.cpp + src/clock.cpp src/symbol_table.cpp src/operations/add.cpp src/operations/subtract.cpp diff --git a/include/clock.h b/include/clock.h new file mode 100644 index 0000000..efe7763 --- /dev/null +++ b/include/clock.h @@ -0,0 +1,42 @@ +/* MIT License + * + * Copyright (c) 2022 Asger Gitz-Johansen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef EXPR_CLOCK_H +#define EXPR_CLOCK_H +#include + +namespace expr { + struct clock_t { + unsigned int time_units = 0; + void reset(); + void delay(unsigned int delta); + auto operator+=(const unsigned int& delta) -> clock_t&; + auto operator==(const clock_t& o) const -> bool; + auto operator!=(const clock_t& o) const -> bool; + }; + + auto operator"" _ms(unsigned long long val) -> clock_t; + auto operator<<(std::ostream& o, const clock_t& c) -> std::ostream&; + auto stoclk(const char* str) -> clock_t; +} + +#endif //EXPR_CLOCK_H diff --git a/include/symbol_table.h b/include/symbol_table.h index 1806c49..c022d51 100644 --- a/include/symbol_table.h +++ b/include/symbol_table.h @@ -31,9 +31,10 @@ #include #include #include +#include "clock.h" namespace expr { - using underlying_symbol_value_t = std::variant; + using underlying_symbol_value_t = std::variant; struct symbol_value_t : public underlying_symbol_value_t { symbol_value_t() = default; @@ -76,11 +77,12 @@ namespace expr { auto is_overlapping(const symbol_table_t& other) -> bool; auto is_overlapping_and_not_idempotent(const symbol_table_t& other) -> bool; auto is_completely_overlapping(const symbol_table_t& other) -> bool; + void delay(unsigned int time_units); }; - symbol_table_t operator+(const symbol_table_t &a, const symbol_table_t &b); - std::ostream &operator<<(std::ostream &os, const symbol_value_t &v); - std::ostream &operator<<(std::ostream &os, const symbol_table_t &m); + auto operator+(const symbol_table_t &a, const symbol_table_t &b) -> symbol_table_t; + auto operator<<(std::ostream &os, const symbol_value_t &v) -> std::ostream&; + auto operator<<(std::ostream &os, const symbol_table_t &m) -> std::ostream&; enum class operator_type_t { minus, plus, star, slash, percent, hat, diff --git a/src/clock.cpp b/src/clock.cpp new file mode 100644 index 0000000..8a59974 --- /dev/null +++ b/src/clock.cpp @@ -0,0 +1,63 @@ +/* MIT License + * + * Copyright (c) 2022 Asger Gitz-Johansen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "clock.h" +#include + +namespace expr { + void clock_t::reset() { + time_units = 0; + } + void clock_t::delay(unsigned int delta) { + time_units += delta; + } + auto clock_t::operator+=(const unsigned int& delta) -> clock_t& { + delay(delta); + return *this; + } + auto clock_t::operator==(const clock_t& o) const -> bool { + return time_units == o.time_units; + } + auto clock_t::operator!=(const clock_t& o) const -> bool { + return !(*this == o); + } + + auto operator"" _ms(unsigned long long val) -> clock_t { + clock_t v{}; v.time_units = val; + return v; + } + + auto operator<<(std::ostream& o, const clock_t& c) -> std::ostream& { + return o << c.time_units; + } + + auto stoclk(const char* str) -> clock_t { + std::string s{str}; + auto loc = s.find( "_ms", 0 ); + if(loc == std::string::npos) + throw std::invalid_argument("not a clock_t value "+s); + auto i = std::stoi(s.substr(0, loc)); + clock_t c{}; + c.time_units = i; + return c; + } +} diff --git a/src/drivers/z3_driver.cpp b/src/drivers/z3_driver.cpp index 9d300bf..4c9c732 100644 --- a/src/drivers/z3_driver.cpp +++ b/src/drivers/z3_driver.cpp @@ -98,6 +98,7 @@ namespace expr { [this](const float& f) { return c.real_val(std::to_string(f).c_str()); }, [this](const bool& b) { return c.bool_val(b); }, [this](const std::string& sv) { return c.string_val(sv); }, + [this](const expr::clock_t& v){ return c.int_val(v.time_units); }, [](auto&& x){ throw std::logic_error("unable to convert symbol value to z3::expr"); } ), static_cast(val)); } @@ -109,6 +110,7 @@ namespace expr { [this, &ref](const float& _) { return c.real_const(ref.ident.c_str()); }, [this, &ref](const bool& _) { return c.bool_const(ref.ident.c_str()); }, [this, &ref](const std::string& _) { return c.string_const(ref.ident.c_str()); }, + [this, &ref](const expr::clock_t& _){ return c.int_const(ref.ident.c_str()); }, [](auto&& x){ throw std::logic_error("unable to convert symbol reference to z3::expr"); } ), static_cast(it->second)); } diff --git a/src/operations/add.cpp b/src/operations/add.cpp index b116c8e..24230b0 100644 --- a/src/operations/add.cpp +++ b/src/operations/add.cpp @@ -47,6 +47,21 @@ template<> auto t_add(const float& x, const float& y) { template<> auto t_add(const std::string& x, const std::string& y) { return x + y; } +template<> auto t_add(const expr::clock_t& x, const expr::clock_t& y) { + return expr::clock_t{x.time_units + y.time_units}; +} +template<> auto t_add(const expr::clock_t& x, const int& y) { + return expr::clock_t{x.time_units + y}; +} +template<> auto t_add(const int& x, const expr::clock_t& y) { + return (int)(x + y.time_units); +} +template<> auto t_add(const expr::clock_t& x, const float& y) { + return expr::clock_t{x.time_units + (int)y}; +} +template<> auto t_add(const float& x, const expr::clock_t& y) { + return x + y.time_units; +} symbol_value_t add(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/operations/boolean.cpp b/src/operations/boolean.cpp index 068821a..45b948f 100644 --- a/src/operations/boolean.cpp +++ b/src/operations/boolean.cpp @@ -127,37 +127,67 @@ auto t_implies(const bool& a, const bool& b) { auto t_gt(const int& a, const int& b) {return a > b;} auto t_gt(const int& a, const float& b) {return a > b;} +auto t_gt(const int& a, const expr::clock_t& b) {return a > b.time_units;} auto t_gt(const float& a, const int& b) {return a > b;} auto t_gt(const float& a, const float& b) {return a > b;} +auto t_gt(const float& a, const expr::clock_t& b) {return a > b.time_units;} +auto t_gt(const expr::clock_t& a, const expr::clock_t& b) {return a.time_units > b.time_units;} +auto t_gt(const expr::clock_t& a, const int& b) {return a.time_units > b;} +auto t_gt(const expr::clock_t& a, const float& b) {return a.time_units > b;} auto t_ge(const int& a, const int& b) {return a >= b;} auto t_ge(const int& a, const float& b) {return a >= b;} +auto t_ge(const int& a, const expr::clock_t& b) {return a >= b.time_units;} auto t_ge(const float& a, const int& b) {return a >= b;} auto t_ge(const float& a, const float& b) {return a >= b;} +auto t_ge(const float& a, const expr::clock_t& b) {return a >= b.time_units;} +auto t_ge(const expr::clock_t& a, const expr::clock_t& b) {return a.time_units >= b.time_units;} +auto t_ge(const expr::clock_t& a, const int& b) {return a.time_units >= b;} +auto t_ge(const expr::clock_t& a, const float& b) {return a.time_units >= b;} auto t_ee(const bool& a, const bool& b) {return a == b;} auto t_ee(const int& a, const int& b) {return a == b;} auto t_ee(const int& a, const float& b) {return a == b;} +auto t_ee(const int& a, const expr::clock_t& b) {return a == b.time_units;} auto t_ee(const float& a, const int& b) {return a == b;} auto t_ee(const float& a, const float& b) {return a == b;} +auto t_ee(const float& a, const expr::clock_t& b) {return a == b.time_units;} +auto t_ee(const expr::clock_t& a, const expr::clock_t& b) {return a.time_units == b.time_units;} +auto t_ee(const expr::clock_t& a, const int& b) {return a.time_units == b;} +auto t_ee(const expr::clock_t& a, const float& b) {return a.time_units == b;} auto t_ee(const std::string& a, const std::string& b) {return a == b;} auto t_ne(const bool& a, const bool& b) {return a != b;} auto t_ne(const int& a, const int& b) {return a != b;} auto t_ne(const int& a, const float& b) {return a != b;} +auto t_ne(const int& a, const expr::clock_t& b) {return a != b.time_units;} auto t_ne(const float& a, const int& b) {return a != b;} auto t_ne(const float& a, const float& b) {return a != b;} +auto t_ne(const float& a, const expr::clock_t& b) {return a != b.time_units;} +auto t_ne(const expr::clock_t& a, const expr::clock_t& b) {return a.time_units != b.time_units;} +auto t_ne(const expr::clock_t& a, const int& b) {return a.time_units != b;} +auto t_ne(const expr::clock_t& a, const float& b) {return a.time_units != b;} auto t_ne(const std::string& a, const std::string& b) {return a != b;} auto t_lt(const int& a, const int& b) {return a < b;} auto t_lt(const int& a, const float& b) {return a < b;} +auto t_lt(const int& a, const expr::clock_t& b) {return a < b.time_units;} auto t_lt(const float& a, const int& b) {return a < b;} auto t_lt(const float& a, const float& b) {return a < b;} +auto t_lt(const float& a, const expr::clock_t& b) {return a < b.time_units;} +auto t_lt(const expr::clock_t& a, const expr::clock_t& b) {return a.time_units < b.time_units;} +auto t_lt(const expr::clock_t& a, const int& b) {return a.time_units < b;} +auto t_lt(const expr::clock_t& a, const float& b) {return a.time_units < b;} auto t_le(const int& a, const int& b) {return a <= b;} auto t_le(const int& a, const float& b) {return a <= b;} +auto t_le(const int& a, const expr::clock_t& b) {return a <= b.time_units;} auto t_le(const float& a, const int& b) {return a <= b;} auto t_le(const float& a, const float& b) {return a <= b;} +auto t_le(const float& a, const expr::clock_t& b) {return a <= b.time_units;} +auto t_le(const expr::clock_t& a, const expr::clock_t& b) {return a.time_units <= b.time_units;} +auto t_le(const expr::clock_t& a, const int& b) {return a.time_units <= b;} +auto t_le(const expr::clock_t& a, const float& b) {return a.time_units <= b;} symbol_value_t and_(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/operations/divide.cpp b/src/operations/divide.cpp index 398380c..c5077b1 100644 --- a/src/operations/divide.cpp +++ b/src/operations/divide.cpp @@ -52,6 +52,31 @@ template<> auto t_divide(const float& x, const float& y) { throw std::domain_error("Cannot divide with zero or INT_MIN / -1"); return x / y; } +template<> auto t_divide(const expr::clock_t& x, const expr::clock_t& y) { + if(y.time_units == 0) + throw std::domain_error("Cannot divide with zero or INT_MIN / -1"); + return expr::clock_t{x.time_units / y.time_units}; +} +template<> auto t_divide(const int& x, const expr::clock_t& y) { + if(y.time_units == 0) + throw std::domain_error("Cannot divide with zero or INT_MIN / -1"); + return (int)(x / y.time_units); +} +template<> auto t_divide(const expr::clock_t& x, const int& y) { + if(y == 0) + throw std::domain_error("Cannot divide with zero or INT_MIN / -1"); + return expr::clock_t{x.time_units / y}; +} +template<> auto t_divide(const float& x, const expr::clock_t& y) { + if(y.time_units == 0) + throw std::domain_error("Cannot divide with zero or INT_MIN / -1"); + return x / y.time_units; +} +template<> auto t_divide(const expr::clock_t& x, const float& y) { + if(y == 0.0f) + throw std::domain_error("Cannot divide with zero or INT_MIN / -1"); + return x.time_units / y; +} symbol_value_t divide(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/operations/modulo.cpp b/src/operations/modulo.cpp index 5e74f27..8c94d14 100644 --- a/src/operations/modulo.cpp +++ b/src/operations/modulo.cpp @@ -35,6 +35,15 @@ auto t_modulo(const T1&, const T2&) { template<> auto t_modulo(const int& x, const int& y) { return x % y; } +template<> auto t_modulo(const expr::clock_t& x, const int& y) { + return (int)(x.time_units % y); +} +template<> auto t_modulo(const expr::clock_t& x, const expr::clock_t& y) { + return expr::clock_t{x.time_units % y.time_units}; +} +template<> auto t_modulo(const int& x, const expr::clock_t& y) { + return expr::clock_t{x % y.time_units}; +} symbol_value_t modulo(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/operations/multiply.cpp b/src/operations/multiply.cpp index 9e26ac2..481ce89 100644 --- a/src/operations/multiply.cpp +++ b/src/operations/multiply.cpp @@ -44,6 +44,21 @@ template<> auto t_multiply(const int& x, const float& y) { template<> auto t_multiply(const float& x, const float& y) { return x * y; } +template<> auto t_multiply(const expr::clock_t& x, const expr::clock_t& y) { + return expr::clock_t{x.time_units * y.time_units}; +} +template<> auto t_multiply(const expr::clock_t& x, const float& y) { + return x.time_units * y; +} +template<> auto t_multiply(const expr::clock_t& x, const int& y) { + return expr::clock_t{x.time_units * y}; +} +template<> auto t_multiply(const int& x, const expr::clock_t& y) { + return (int)(x * y.time_units); +} +template<> auto t_multiply(const float& x, const expr::clock_t& y) { + return x * y.time_units; +} symbol_value_t multiply(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/operations/pow.cpp b/src/operations/pow.cpp index 4eba177..3745097 100644 --- a/src/operations/pow.cpp +++ b/src/operations/pow.cpp @@ -45,6 +45,21 @@ template<> auto t_pow(const int& x, const float& y) { template<> auto t_pow(const float& x, const float& y) { return static_cast(pow(x,y)); } +template<> auto t_pow(const expr::clock_t& x, const expr::clock_t& y) { + return expr::clock_t{static_cast(pow(x.time_units, y.time_units))}; +} +template<> auto t_pow(const expr::clock_t& x, const float& y) { + return static_cast(pow(x.time_units, y)); +} +template<> auto t_pow(const expr::clock_t& x, const int& y) { + return expr::clock_t{static_cast(pow(x.time_units, y))}; +} +template<> auto t_pow(const int& x, const expr::clock_t& y) { + return static_cast(pow(x, y.time_units)); +} +template<> auto t_pow(const float& x, const expr::clock_t& y) { + return static_cast(pow(x, y.time_units)); +} symbol_value_t pow(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/operations/subtract.cpp b/src/operations/subtract.cpp index 5636197..1b8ad19 100644 --- a/src/operations/subtract.cpp +++ b/src/operations/subtract.cpp @@ -44,6 +44,21 @@ template<> auto t_subtract(const int& x, const float& y) { template<> auto t_subtract(const float& x, const float& y) { return x - y; } +template<> auto t_subtract(const expr::clock_t& x, const expr::clock_t& y) { + return expr::clock_t{x.time_units - y.time_units}; +} +template<> auto t_subtract(const expr::clock_t& x, const int& y) { + return expr::clock_t{x.time_units - y}; +} +template<> auto t_subtract(const int& x, const expr::clock_t& y) { + return (int)(x - y.time_units); +} +template<> auto t_subtract(const expr::clock_t& x, const float& y) { + return expr::clock_t{x.time_units - (int)y}; +} +template<> auto t_subtract(const float& x, const expr::clock_t& y) { + return x - y.time_units; +} symbol_value_t subtract(const symbol_value_t& a, const symbol_value_t& b) { symbol_value_t res{}; diff --git a/src/parser/lex/footer.l b/src/parser/lex/footer.l index 9596e26..15fc56a 100644 --- a/src/parser/lex/footer.l +++ b/src/parser/lex/footer.l @@ -27,3 +27,12 @@ PARSER_NS ::parser::symbol_type make_BOOL(std::string s, const PARSER_NS ::parse std::istringstream(s) >> std::boolalpha >> b; return PARSER_NS ::parser::make_BOOL(b, loc); } + +PARSER_NS ::parser::symbol_type make_CLOCK(const std::string &s, const PARSER_NS ::parser::location_type& loc) { + try { + auto c = expr::stoclk(s.c_str()); + return PARSER_NS ::parser::make_CLOCK(c, loc); + } catch(std::out_of_range& e) { + throw PARSER_NS ::parser::syntax_error (loc, "clock value is out of range: " + s); + } +} diff --git a/src/parser/lex/lexer.l b/src/parser/lex/lexer.l index a677f84..1d9745f 100644 --- a/src/parser/lex/lexer.l +++ b/src/parser/lex/lexer.l @@ -31,6 +31,7 @@ m4_changequote() {int} return make_NUMBER(yytext, loc); {flt} return make_FLOAT(yytext, loc); {str} return make_STRING(yytext, loc); +{clk} return make_CLOCK(yytext, loc); {bool} return make_BOOL(yytext, loc); {id} return PARSER_NS ::parser::make_IDENTIFIER (yytext, loc); . { throw PARSER_NS ::parser::syntax_error(loc, "invalid character: " + std::string(yytext)); } diff --git a/src/parser/lex/skeleton.l b/src/parser/lex/skeleton.l index 14b4e86..d87ed6b 100644 --- a/src/parser/lex/skeleton.l +++ b/src/parser/lex/skeleton.l @@ -79,4 +79,5 @@ m4_changequote() PARSER_NS ::parser::symbol_type make_FLOAT(const std::string &s, const PARSER_NS ::parser::location_type& loc); PARSER_NS ::parser::symbol_type make_STRING(const std::string &s, const PARSER_NS ::parser::location_type& loc); PARSER_NS ::parser::symbol_type make_BOOL(std::string s, const PARSER_NS ::parser::location_type& loc); + PARSER_NS ::parser::symbol_type make_CLOCK(const std::string& s, const PARSER_NS ::parser::location_type& loc); %} diff --git a/src/parser/lex/tokens.l b/src/parser/lex/tokens.l index 9d82e44..3a9d836 100644 --- a/src/parser/lex/tokens.l +++ b/src/parser/lex/tokens.l @@ -5,9 +5,10 @@ m4_changequote() %} id [a-z_A-Z]([.ðđ€\(\)a-zA-Z_0-9]*[a-zA-Z_0-9]+)? int [0-9]+[Ll]? +clk [0-9]+(_ms) flt [0-9]+[.][0-9]+[fd]? bool [Ff]alse|[Tt]rue str \"(\\.|[^\\"])*\" blank [ \t\r] accmod [Pp](ublic|rivate|rotected) -type int|long|float|double|string|bool|var|auto +type int|long|float|double|string|bool|clock|timer|var|auto diff --git a/src/parser/yacc/exp.y b/src/parser/yacc/exp.y index 44c22b1..6c02761 100644 --- a/src/parser/yacc/exp.y +++ b/src/parser/yacc/exp.y @@ -38,4 +38,5 @@ lit: | "string" { $$ = LIT_CTOR ($1); } | "bool" { $$ = LIT_CTOR ($1); } | "identifier" { $$ = IDENT_CTOR ($1); } +| "clk" { $$ = LIT_CTOR ($1); } ; diff --git a/src/parser/yacc/tokens.y b/src/parser/yacc/tokens.y index cbed3f4..96845a4 100644 --- a/src/parser/yacc/tokens.y +++ b/src/parser/yacc/tokens.y @@ -33,6 +33,7 @@ m4_changequote() %token NUMBER "number" %token FLOAT "float" %token BOOL "bool" +%token CLOCK "clk" %token STRING "string" %printer { yyo << $$; } <*>; diff --git a/src/symbol_table.cpp b/src/symbol_table.cpp index ba1036e..0ebdf54 100644 --- a/src/symbol_table.cpp +++ b/src/symbol_table.cpp @@ -62,6 +62,13 @@ namespace expr { return std::any_of(other.begin(), other.end(), comparator); } + void symbol_table_t::delay(unsigned int time_units) { + for(auto& e : *this) + std::visit(ya::overload( + [&time_units](clock_t& v){ v.delay(time_units); }, + [](auto&&){}), e.second); + } + symbol_table_t operator+(const symbol_table_t &a, const symbol_table_t &b) { symbol_table_t r{}; r += a; @@ -73,6 +80,7 @@ namespace expr { std::visit(ya::overload{ [&os](const bool &b) { os << std::boolalpha << b << " " << typeid(b).name(); }, [&os](const std::string &s) { os << "\"" << s << "\" s"; }, + [&os](const expr::clock_t &s) { os << "\"" << s << "\" c"; }, [&os](auto &&v) { os << v << " " << typeid(v).name(); }}, static_cast(v)); return os; @@ -159,7 +167,8 @@ auto std::hash::operator()(const expr::symbol_value_t& v) [&result](const int& v){result = std::hash{}(v);}, [&result](const float& v){result = std::hash{}(v);}, [&result](const bool& v){result = std::hash{}(v);}, - [&result](const std::string& v){result = std::hash{}(v);} + [&result](const std::string& v){result = std::hash{}(v);}, + [&result](const expr::clock_t& c){result = std::hash{}(c.time_units);} ), static_cast(v)); return result; }