diff --git a/src/ExprNode.cc b/src/ExprNode.cc index 91ca9360e34af3f6e2a602ffaac0654375b4cc3e..c88c36be39b3b16772a7074038c305c43a9aa8f3 100644 --- a/src/ExprNode.cc +++ b/src/ExprNode.cc @@ -8927,3 +8927,11 @@ ExprNode::matchLinearCombinationOfEndogenousWithConstant() const } return { endo_terms, intercept }; } + +string +ExprNode::toString() const +{ + ostringstream ss; + writeJsonOutput(ss, {}, {}); + return ss.str(); +} diff --git a/src/ExprNode.hh b/src/ExprNode.hh index c4b20990cb2c1088c073dd0273c9ba6908815ade..a2ffa392ddfdd81f7a769b9de195752ea2374774 100644 --- a/src/ExprNode.hh +++ b/src/ExprNode.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2007-2021 Dynare Team + * Copyright © 2007-2022 Dynare Team * * This file is part of Dynare. * @@ -341,6 +341,9 @@ public: //! Writes output of node in JSON syntax virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, bool isdynamic = true) const = 0; + // Returns a string representation of the expression, used by the GDB pretty printer + string toString() const; + //! Writes the Abstract Syntax Tree in JSON virtual void writeJsonAST(ostream &output) const = 0; diff --git a/src/Makefile.am b/src/Makefile.am index bf8c8272bc14f0074fac9e5a19730543315aa2d2..43dc2b2bd7b1bdb2e2255d43f21a67221340d6ab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,6 +62,7 @@ ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = \ Doxyfile \ + dynare-preprocessor-gdb.py \ $(BUILT_SOURCES) # The -I. is for <FlexLexer.h> diff --git a/src/dynare-preprocessor-gdb.py b/src/dynare-preprocessor-gdb.py new file mode 100644 index 0000000000000000000000000000000000000000..4c74e6ed38884b327afcd0a0d5825c6570acb6a2 --- /dev/null +++ b/src/dynare-preprocessor-gdb.py @@ -0,0 +1,52 @@ +# GDB pretty-printer for ExprNode class hierarchy + +# Copyright © 2022 Dynare Team +# +# This file is part of Dynare. +# +# Dynare 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. +# +# Dynare 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 Dynare. If not, see <https://www.gnu.org/licenses/>. + +class ExprNodePrinter: + '''Pretty-prints an ExprNode value''' + def __init__(self, val): + self.val = val + + def to_string(self): + # Call the toString() method on the pointer. + # We must use the raw pretty-printer for the pointer itself, otherwise + # we enter an infinite loop. + # We retrieve a C string, because with C++ strings the gdb pretty-printer + # insists on keeping the quotes around it. + r = gdb.parse_and_eval("((ExprNode *) " + self.val.format_string(raw = True) + ")->toString().c_str()") + typestr = "(" + str(self.val.type) + ") "; + # Add dynamic type information between brackets, if different from static type + if str(self.val.type) != str(self.val.dynamic_type): + typestr += "[" + str(self.val.dynamic_type) + "] " + return typestr + r.string() + +class ExprNodePrinterControl(gdb.printing.PrettyPrinter): + '''Determines whether a value can be pretty printed with ExprNodePrinter. To be directly registered within the GDB API.''' + def __init__(self): + # The name below will appear in “info pretty-printer”, and can be used with “enable/disable pretty-printer” + super().__init__('ExprNode') + + def __call__(self, val): + # Check if the value is a subtype of ExprNode *. + # Doing a dynamic_cast on a non-pointer type triggers an exception, so we first check + # whethe it’s a pointer (after resolving for typedefs, such as “expr_t”). + if val.type.strip_typedefs().code == gdb.TYPE_CODE_PTR and val.dynamic_cast(gdb.lookup_type('ExprNode').pointer()) != 0: + return ExprNodePrinter(val) + +# Register the pretty printer +gdb.pretty_printers.append(ExprNodePrinterControl())