diff --git a/doc/macroprocessor/macroprocessor.tex b/doc/macroprocessor/macroprocessor.tex index 8f7c4d19..a3b56db7 100644 --- a/doc/macroprocessor/macroprocessor.tex +++ b/doc/macroprocessor/macroprocessor.tex @@ -215,6 +215,7 @@ \item comparison operators: \texttt{< > <= >= == !=} \item concatenation: \texttt{+} \item string length: \texttt{length()} + \item string emptiness: \texttt{isempty()} \item extraction of substrings: if \texttt{s} is a string, then one can write \texttt{s[3]} or \texttt{s[4:6]} \end{itemize} \end{block} @@ -227,7 +228,7 @@ \begin{block}{Operators on tuples} \begin{itemize} \item comparison operators: \texttt{== !=} - \item functions: \texttt{length, empty} + \item functions: \texttt{length, isempty} \item testing membership in tuple: \texttt{in} operator \\ (example: \texttt{"b" in ("a", "b", "c")} returns \texttt{1}) \end{itemize} @@ -243,7 +244,7 @@ \item comparison operators: \texttt{== !=} \item dereferencing: if \texttt{v} is an array, then \texttt{v[2]} is its $2^{\textrm{nd}}$ element \item concatenation: \texttt{+} - \item functions: \texttt{sum, length, empty} + \item functions: \texttt{sum, length, isempty} \item difference \texttt{-}: returns the first operand from which the elements of the second operand have been removed \item Cartesian product of two arrays: \texttt{*} \item Cartesian product of one array \texttt{N} times: \texttt{\^{}N} diff --git a/src/macro/Expressions.cc b/src/macro/Expressions.cc index ed1c6abd..23784ab7 100644 --- a/src/macro/Expressions.cc +++ b/src/macro/Expressions.cc @@ -803,6 +803,8 @@ UnaryOp::eval() return argbt->unary_plus(); case codes::UnaryOp::length: return argbt->length(); + case codes::UnaryOp::isempty: + return argbt->isempty(); case codes::UnaryOp::exp: return argbt->exp(); case codes::UnaryOp::ln: @@ -1133,6 +1135,8 @@ UnaryOp::to_string() const noexcept return "+" + retval; case codes::UnaryOp::length: return "length(" + retval + ")"; + case codes::UnaryOp::isempty: + return "isempty(" + retval + ")"; case codes::UnaryOp::exp: return "exp(" + retval + ")"; case codes::UnaryOp::ln: @@ -1352,6 +1356,9 @@ UnaryOp::print(ostream &output, bool matlab_output) const noexcept case codes::UnaryOp::length: output << "length("; break; + case codes::UnaryOp::isempty: + output << "isempty("; + break; case codes::UnaryOp::exp: output << "exp("; break; diff --git a/src/macro/Expressions.hh b/src/macro/Expressions.hh index 099f6920..9153e112 100644 --- a/src/macro/Expressions.hh +++ b/src/macro/Expressions.hh @@ -148,6 +148,7 @@ namespace macro virtual ArrayPtr set_intersection(const BaseTypePtr &btp) const { throw StackTrace("Operator & does not exist for this type"); } virtual BoolPtr contains(const BaseTypePtr &btp) const { throw StackTrace("Second argument of `in` operator must be an array"); } virtual RealPtr length() const { throw StackTrace("Operator `length` does not exist for this type"); } + virtual BoolPtr isempty() const { throw StackTrace("Operator `isempty` does not exist for this type"); } virtual RealPtr max(const BaseTypePtr &btp) const { throw StackTrace("Operator `max` does not exist for this type"); } virtual RealPtr min(const BaseTypePtr &btp) const { throw StackTrace("Operator `min` does not exist for this type"); } virtual RealPtr mod(const BaseTypePtr &btp) const { throw StackTrace("Operator `mod` does not exist for this type"); } @@ -337,6 +338,7 @@ namespace macro BoolPtr is_greater_equal(const BaseTypePtr &btp) const override; BoolPtr is_equal(const BaseTypePtr &btp) const override; inline RealPtr length() const override { return make_shared(value.size(), env); } + inline BoolPtr isempty() const override { return make_shared(value.empty(), env); } BoolPtr cast_bool() const override; RealPtr cast_real() const override; inline StringPtr cast_string() const override { return make_shared(value, env); } @@ -373,6 +375,7 @@ namespace macro BoolPtr is_equal(const BaseTypePtr &btp) const override; BoolPtr contains(const BaseTypePtr &btp) const override; inline RealPtr length() const override { return make_shared(tup.size(), env); } + inline BoolPtr isempty() const override { return make_shared(empty(), env); } BoolPtr cast_bool() const override; RealPtr cast_real() const override; inline StringPtr cast_string() const override { return make_shared(this->to_string(), env); } @@ -418,6 +421,7 @@ namespace macro ArrayPtr set_intersection(const BaseTypePtr &btp) const override; BoolPtr contains(const BaseTypePtr &btp) const override; inline RealPtr length() const override { return make_shared(arr.size(), env); } + inline BoolPtr isempty() const override { return make_shared(empty(), env); } RealPtr sum() const override; BoolPtr cast_bool() const override; RealPtr cast_real() const override; diff --git a/src/macro/ForwardDeclarationsAndEnums.hh b/src/macro/ForwardDeclarationsAndEnums.hh index a606482c..35112c6b 100644 --- a/src/macro/ForwardDeclarationsAndEnums.hh +++ b/src/macro/ForwardDeclarationsAndEnums.hh @@ -76,6 +76,7 @@ namespace macro unary_minus, unary_plus, length, + isempty, exp, ln, log10, diff --git a/src/macro/Parser.yy b/src/macro/Parser.yy index cb51900f..98e2b38f 100644 --- a/src/macro/Parser.yy +++ b/src/macro/Parser.yy @@ -65,6 +65,8 @@ using namespace macro; %token SQRT CBRT SIGN MAX MIN FLOOR CEIL TRUNC SUM MOD %token ERF ERFC GAMMA LGAMMA ROUND NORMPDF NORMCDF LENGTH +%token ISEMPTY + %token BOOL REAL STRING TUPLE ARRAY %left OR @@ -340,6 +342,8 @@ expr : LPAREN expr RPAREN { $$ = make_shared(codes::UnaryOp::unary_plus, $2, driver.env, @$); } | LENGTH LPAREN expr RPAREN { $$ = make_shared(codes::UnaryOp::length, $3, driver.env, @$); } + | ISEMPTY LPAREN expr RPAREN + { $$ = make_shared(codes::UnaryOp::isempty, $3, driver.env, @$); } | EXP LPAREN expr RPAREN { $$ = make_shared(codes::UnaryOp::exp, $3, driver.env, @$); } | LOG LPAREN expr RPAREN diff --git a/src/macro/Tokenizer.ll b/src/macro/Tokenizer.ll index 756e8d9b..c661d4a1 100644 --- a/src/macro/Tokenizer.ll +++ b/src/macro/Tokenizer.ll @@ -141,6 +141,7 @@ CONT \\\\{SPC}* length { return token::LENGTH; } normpdf { return token::NORMPDF; } normcdf { return token::NORMCDF; } +isempty { return token::ISEMPTY; } bool { return token::BOOL; } real { return token::REAL; }