swig/Source/Swig/tree.c
William S Fulton 1db04bf322 Improvements to the -debug command line options
The debug command line options that display parse tree nodes
(-debug-module, -debug-top, -debug-symtabs) now display previously hidden
linked list pointers which are useful for debugging parse trees.

Added new command line option -debug-quiet. This suppresses the display
of most linked list pointers and symbol table pointers in the parse tree nodes.

The keys in the parse tree node are now shown in alphabetical order.
2022-03-25 23:34:52 +00:00

426 lines
11 KiB
C

/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* tree.c
*
* This file provides some general purpose functions for manipulating
* parse trees.
* ----------------------------------------------------------------------------- */
#include "swig.h"
#include <stdarg.h>
#include <assert.h>
static int debug_quiet = 0;
/* -----------------------------------------------------------------------------
* Swig_print_quiet()
*
* Set quiet mode when printing a parse tree node
* ----------------------------------------------------------------------------- */
int Swig_print_quiet(int quiet) {
int previous_quiet = debug_quiet;
debug_quiet = quiet;
return previous_quiet;
}
/* -----------------------------------------------------------------------------
* Swig_print_tags()
*
* Dump the tag structure of a parse tree to standard output
* ----------------------------------------------------------------------------- */
void Swig_print_tags(DOH *obj, DOH *root) {
DOH *croot, *newroot;
DOH *cobj;
if (!root)
croot = NewStringEmpty();
else
croot = root;
while (obj) {
Swig_diagnostic(Getfile(obj), Getline(obj), "%s . %s\n", croot, nodeType(obj));
cobj = firstChild(obj);
if (cobj) {
newroot = NewStringf("%s . %s", croot, nodeType(obj));
Swig_print_tags(cobj, newroot);
Delete(newroot);
}
obj = nextSibling(obj);
}
if (!root)
Delete(croot);
}
static int indent_level = 0;
static void print_indent(int l) {
int i;
for (i = 0; i < indent_level; i++) {
fputc(' ', stdout);
}
if (l) {
fputc('|', stdout);
fputc(' ', stdout);
}
}
/* -----------------------------------------------------------------------------
* Swig_print_node(Node *n)
* ----------------------------------------------------------------------------- */
void Swig_print_node(Node *obj) {
Iterator ki;
Node *cobj;
print_indent(0);
if (debug_quiet)
Printf(stdout, "+++ %s ----------------------------------------\n", nodeType(obj));
else
Printf(stdout, "+++ %s - %p ----------------------------------------\n", nodeType(obj), obj);
List *keys = Keys(obj);
SortList(keys, 0);
ki = First(keys);
while (ki.item) {
String *k = ki.item;
DOH *value = Getattr(obj, k);
if (Equal(k, "nodeType") || (*(Char(k)) == '$')) {
/* Do nothing */
} else if (debug_quiet && (Equal(k, "nodeType") || Equal(k, "firstChild") || Equal(k, "lastChild") || Equal(k, "parentNode") || Equal(k, "nextSibling") ||
Equal(k, "previousSibling") || Equal(k, "symtab") || Equal(k, "csymtab") || Equal(k, "sym:symtab") || Equal(k, "sym:nextSibling") ||
Equal(k, "sym:previousSibling") || Equal(k, "csym:nextSibling") || Equal(k, "csym:previousSibling"))) {
/* Do nothing */
} else if (Equal(k, "kwargs") || Equal(k, "parms") || Equal(k, "wrap:parms") || Equal(k, "pattern") || Equal(k, "templateparms") || Equal(k, "throws")) {
print_indent(2);
/* Differentiate parameter lists by displaying within single quotes */
Printf(stdout, "%-12s - \'%s\'\n", k, ParmList_str_defaultargs(value));
} else {
DOH *o;
const char *trunc = "";
print_indent(2);
if (DohIsString(value)) {
o = Str(value);
if (Len(o) > 80) {
trunc = "...";
}
Printf(stdout, "%-12s - \"%(escape)-0.80s%s\"\n", k, o, trunc);
Delete(o);
} else {
Printf(stdout, "%-12s - %p\n", k, value);
}
}
ki = Next(ki);
}
cobj = firstChild(obj);
if (cobj) {
indent_level += 6;
Printf(stdout, "\n");
Swig_print_tree(cobj);
indent_level -= 6;
} else {
print_indent(1);
Printf(stdout, "\n");
}
Delete(keys);
}
/* -----------------------------------------------------------------------------
* Swig_print_tree()
*
* Dump the tree structure of a parse tree to standard output
* ----------------------------------------------------------------------------- */
void Swig_print_tree(DOH *obj) {
while (obj) {
Swig_print_node(obj);
obj = nextSibling(obj);
}
}
/* -----------------------------------------------------------------------------
* appendChild()
*
* Appends a new child to a node
* ----------------------------------------------------------------------------- */
void appendChild(Node *node, Node *chd) {
Node *lc;
if (!chd)
return;
lc = lastChild(node);
if (!lc) {
set_firstChild(node, chd);
} else {
set_nextSibling(lc, chd);
set_previousSibling(chd, lc);
}
while (chd) {
lc = chd;
set_parentNode(chd, node);
chd = nextSibling(chd);
}
set_lastChild(node, lc);
}
/* -----------------------------------------------------------------------------
* prependChild()
*
* Prepends a new child to a node
* ----------------------------------------------------------------------------- */
void prependChild(Node *node, Node *chd) {
Node *fc;
if (!chd)
return;
fc = firstChild(node);
if (fc) {
set_nextSibling(chd, fc);
set_previousSibling(fc, chd);
}
set_firstChild(node, chd);
while (chd) {
set_parentNode(chd, node);
chd = nextSibling(chd);
}
}
void appendSibling(Node *node, Node *chd) {
Node *parent;
Node *lc = node;
while (nextSibling(lc))
lc = nextSibling(lc);
set_nextSibling(lc, chd);
set_previousSibling(chd, lc);
parent = parentNode(node);
if (parent) {
while (chd) {
lc = chd;
set_parentNode(chd, parent);
chd = nextSibling(chd);
}
set_lastChild(parent, lc);
}
}
/* -----------------------------------------------------------------------------
* removeNode()
*
* Removes a node from the parse tree. Detaches it from its parent's child list.
* ----------------------------------------------------------------------------- */
void removeNode(Node *n) {
Node *parent;
Node *prev;
Node *next;
parent = parentNode(n);
if (!parent) return;
prev = previousSibling(n);
next = nextSibling(n);
if (prev) {
set_nextSibling(prev, next);
} else {
if (parent) {
set_firstChild(parent, next);
}
}
if (next) {
set_previousSibling(next, prev);
} else {
if (parent) {
set_lastChild(parent, prev);
}
}
/* Delete attributes */
Delattr(n,"parentNode");
Delattr(n,"nextSibling");
Delattr(n,"previousSibling");
}
/* -----------------------------------------------------------------------------
* copyNode()
*
* Copies a node, but only copies simple attributes (no lists, hashes).
* ----------------------------------------------------------------------------- */
Node *copyNode(Node *n) {
Iterator ki;
Node *c = NewHash();
for (ki = First(n); ki.key; ki = Next(ki)) {
if (DohIsString(ki.item)) {
Setattr(c, ki.key, Copy(ki.item));
}
}
Setfile(c, Getfile(n));
Setline(c, Getline(n));
return c;
}
/* -----------------------------------------------------------------------------
* checkAttribute()
* ----------------------------------------------------------------------------- */
int checkAttribute(Node *n, const_String_or_char_ptr name, const_String_or_char_ptr value) {
String *v = Getattr(n, name);
return v ? Equal(v, value) : 0;
}
/* -----------------------------------------------------------------------------
* Swig_require()
* ns - namespace for the view name for saving any attributes under
* n - node
* ... - list of attribute names of type char*
*
* An attribute is optional if it is prefixed by ?, eg "?value". All
* non-optional attributes are checked for on node n and if any do not exist
* SWIG exits with a fatal error.
*
* If the attribute name is prefixed by * or ?, eg "*value" then a copy of the
* attribute is saved. The saved attributes will be restored on a subsequent
* call to Swig_restore(). All the saved attributes are saved in the view
* namespace (prefixed by ns).
*
* This function can be called more than once with different namespaces.
* ----------------------------------------------------------------------------- */
void Swig_require(const char *ns, Node *n, ...) {
va_list ap;
char *name;
DOH *obj;
va_start(ap, n);
name = va_arg(ap, char *);
while (name) {
int newref = 0;
int opt = 0;
if (*name == '*') {
newref = 1;
name++;
} else if (*name == '?') {
newref = 1;
opt = 1;
name++;
}
obj = Getattr(n, name);
if (!opt && !obj) {
Swig_error(Getfile(n), Getline(n), "Fatal error (Swig_require). Missing attribute '%s' in node '%s'.\n", name, nodeType(n));
Exit(EXIT_FAILURE);
}
if (!obj)
obj = DohNone;
if (newref) {
/* Save a copy of the attribute */
Setattr(n, NewStringf("%s:%s", ns, name), obj);
}
name = va_arg(ap, char *);
}
va_end(ap);
/* Save the view */
{
String *view = Getattr(n, "view");
if (view) {
if (Strcmp(view, ns) != 0) {
Setattr(n, NewStringf("%s:view", ns), view);
Setattr(n, "view", NewString(ns));
}
} else {
Setattr(n, "view", NewString(ns));
}
}
}
/* -----------------------------------------------------------------------------
* Swig_save()
* Same as Swig_require(), but all attribute names are optional and all attributes
* are saved, ie behaves as if all the attribute names were prefixed by ?.
* ----------------------------------------------------------------------------- */
void Swig_save(const char *ns, Node *n, ...) {
va_list ap;
char *name;
DOH *obj;
va_start(ap, n);
name = va_arg(ap, char *);
while (name) {
if (*name == '*') {
name++;
} else if (*name == '?') {
name++;
}
obj = Getattr(n, name);
if (!obj)
obj = DohNone;
/* Save a copy of the attribute */
if (Setattr(n, NewStringf("%s:%s", ns, name), obj)) {
Printf(stderr, "Swig_save('%s','%s'): Warning, attribute '%s' was already saved.\n", ns, nodeType(n), name);
}
name = va_arg(ap, char *);
}
va_end(ap);
/* Save the view */
{
String *view = Getattr(n, "view");
if (view) {
if (Strcmp(view, ns) != 0) {
Setattr(n, NewStringf("%s:view", ns), view);
Setattr(n, "view", NewString(ns));
}
} else {
Setattr(n, "view", NewString(ns));
}
}
}
/* -----------------------------------------------------------------------------
* Swig_restore()
* Restores attributes saved by a previous call to Swig_require() or Swig_save().
* ----------------------------------------------------------------------------- */
void Swig_restore(Node *n) {
String *temp;
int len;
List *l;
String *ns;
Iterator ki;
ns = Getattr(n, "view");
assert(ns);
l = NewList();
temp = NewStringf("%s:", ns);
len = Len(temp);
for (ki = First(n); ki.key; ki = Next(ki)) {
if (Strncmp(temp, ki.key, len) == 0) {
Append(l, ki.key);
}
}
for (ki = First(l); ki.item; ki = Next(ki)) {
DOH *obj = Getattr(n, ki.item);
Setattr(n, Char(ki.item) + len, obj);
Delattr(n, ki.item);
}
Delete(l);
Delete(temp);
}