summaryrefslogtreecommitdiffstats
path: root/languages/ruby/debugger/rdbparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'languages/ruby/debugger/rdbparser.cpp')
-rw-r--r--languages/ruby/debugger/rdbparser.cpp350
1 files changed, 350 insertions, 0 deletions
diff --git a/languages/ruby/debugger/rdbparser.cpp b/languages/ruby/debugger/rdbparser.cpp
new file mode 100644
index 00000000..7792acc5
--- /dev/null
+++ b/languages/ruby/debugger/rdbparser.cpp
@@ -0,0 +1,350 @@
+// **************************************************************************
+// begin : Tue Aug 17 1999
+// copyright : (C) 1999 by John Birch
+// email : [email protected]
+//
+// Adapted for ruby debugging
+// --------------------------
+// begin : Mon Nov 1 2004
+// copyright : (C) 2004 by Richard Dale
+// email : [email protected]
+// **************************************************************************
+
+// **************************************************************************
+// *
+// 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 2 of the License, or *
+// (at your option) any later version. *
+// *
+// **************************************************************************
+
+#include "rdbparser.h"
+#include "variablewidget.h"
+
+#include <qregexp.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <kdebug.h>
+
+namespace RDBDebugger
+{
+
+
+// **************************************************************************
+
+void RDBParser::parseVariables(LazyFetchItem *parent, char *buf)
+{
+ static const char *unknown = "?";
+
+ QString varName;
+ QCString value;
+ int pos;
+
+ Q_ASSERT(parent);
+ if (buf == 0 || strlen(buf) == 0) {
+ return;
+ }
+
+ if (buf[0] == 0) {
+ buf = (char*)unknown;
+ }
+
+ QRegExp var_re("\\s*([^\\n\\s]+) => ([^\\n]+)");
+ QRegExp ref_re("(#<([^:]|::)+:0x[\\da-f]+)\\s*([^=]*)>?");
+ QRegExp struct_re("#<struct Struct::(\\w+)");
+
+ // Look for 'dataitem => value' pairs. For example:
+ // a => 1
+ // m => #<MyClass:0x30093540 @temp={"z"=>"zed", "p"=>"pee"}, @foobar="hello">
+ //
+ pos = var_re.search(buf);
+ if (pos != -1) {
+ while (pos != -1) {
+ varName = var_re.cap(1);
+ if (ref_re.search(var_re.cap(2)) != -1) {
+ if (var_re.cap(2).contains("=") > 0) {
+ value = (ref_re.cap(1) + ">").latin1();
+ } else {
+ // There are no 'name=value' pairs, as in #<Qt::Color:0x0 #ff0000>
+ value = var_re.cap(2).latin1();
+ }
+ } else if (struct_re.search(var_re.cap(2)) != -1) {
+ value = (QString("#<Struct::") + struct_re.cap(1) + ">").latin1();
+ } else {
+ value = var_re.cap(2).latin1();
+ }
+
+ DataType dataType = determineType((char *) var_re.cap(2).latin1());
+
+ // 'self' variables don't need to be expandable, as their details are
+ // already shown in the current frame. So always make them VALUE_TYPE's.
+ if (varName == "self") {
+ dataType = VALUE_TYPE;
+ }
+
+ setItem(parent, varName, dataType, value);
+
+ pos += var_re.matchedLength();
+ pos = var_re.search(buf, pos);
+ }
+
+ return;
+ }
+}
+
+void RDBParser::parseExpandedVariable(VarItem *parent, char *buf)
+{
+ DataType dataType;
+ int pos;
+ QString varName;
+ QCString value;
+ QRegExp ppref_re("(#<([^:]|::)+:0x[\\da-f]+)([^\\n>]*)(>?)");
+
+ switch (parent->dataType()) {
+ case REFERENCE_TYPE:
+ {
+ // Look for a reference type which has been printed via a 'pp' command, to
+ // expand its sub items on multiple lines. For example:
+ // #<MyClass:0x30093540
+ // @foobar="hello",
+ // @sleeper=#<Thread:0x3008fd18 sleep>,
+ // @temp={"z"=>"zed", "p"=>"pee"}>
+ //
+ QRegExp ppvalue_re("\\s*([^\\n\\s=]+)=([^\\n]+)[,>]");
+
+ pos = ppref_re.search(buf);
+ if (pos != -1) {
+ if (ppref_re.cap(4) != "") {
+ // The value is all on one line, so match against name=value
+ // pairs which can't have commas in their values
+ ppvalue_re = QRegExp("\\s*([^\\s=]+)=([^,>]+)([,>])");
+ }
+
+ pos = ppvalue_re.search(buf, pos);
+
+ while (pos != -1) {
+ varName = ppvalue_re.cap(1);
+
+ if (ppref_re.search(ppvalue_re.cap(2)) != -1) {
+ if (ppvalue_re.cap(2).contains("=") > 0) {
+ value = (ppref_re.cap(1) + ">").latin1();
+ } else {
+ // There are no 'name=value' pairs, as in #<Qt::Color:0x0 #ff0000>
+ value = ppvalue_re.cap(2).latin1();
+ }
+ } else {
+ value = ppvalue_re.cap(2).latin1();
+ }
+
+ dataType = determineType((char *) ppvalue_re.cap(2).latin1());
+ setItem(parent, varName, dataType, value);
+
+ pos += ppvalue_re.matchedLength();
+ pos = ppvalue_re.search(buf, pos);
+ }
+
+ }
+ return;
+ }
+
+ case ARRAY_TYPE:
+ {
+ // Look for a array type which has been printed via a 'pp' command, to
+ // expand its sub items. For example:
+ // [0]="hello"
+ // [1]=#"goodbye"
+ //
+ QRegExp pparray_re("\\s*([^=]+)=([^\\n]+)\\n");
+
+ pos = pparray_re.search(buf);
+
+ while (pos != -1) {
+ varName = pparray_re.cap(1);
+
+ if (ppref_re.search(pparray_re.cap(2)) != -1) {
+ value = (ppref_re.cap(1) + ">").latin1();
+ } else {
+ value = pparray_re.cap(2).latin1();
+ }
+
+ DataType dataType = determineType((char *) pparray_re.cap(2).latin1());
+ setItem(parent, varName, dataType, value);
+
+ pos += pparray_re.matchedLength();
+ pos = pparray_re.search(buf, pos);
+ }
+
+ return;
+ }
+
+ case HASH_TYPE:
+ {
+ // Look for a hash type which has been printed via a 'pp' command, to
+ // expand its sub items. For example:
+ // ["greeting"]="hello"
+ // ["farewell"]="goodbye"
+ //
+ QRegExp pphash_re("\\s*(\\[[^\\]]+\\])=([^\\n]+)\\n");
+ pos = pphash_re.search(buf);
+
+ while (pos != -1) {
+ varName = pphash_re.cap(1);
+ value = pphash_re.cap(2).latin1();
+ DataType dataType = determineType(value.data());
+ setItem(parent, varName, dataType, value);
+
+ pos += pphash_re.matchedLength();
+ pos = pphash_re.search(buf, pos);
+ }
+
+ return;
+ }
+
+ case STRUCT_TYPE:
+ {
+ // Look for a reference type which has been printed via a 'pp' command, to
+ // expand its sub items. For example:
+ // #<Struct::Customer
+ // @foobar="hello",
+ // @sleeper=#<Thread:0x3008fd18 sleep>,
+ // @temp={"z"=>"zed", "p"=>"pee"}>
+ //
+ QRegExp ppstruct_re("(#<Struct::\\w+)\\s([^\\n>]*)(>?)");
+ QRegExp ppvalue_re("\\s*([^\\n\\s=]+)=([^\\n]+)[,>]");
+
+ pos = ppstruct_re.search(buf);
+ if (pos != -1) {
+ if (ppstruct_re.cap(3) != "" && ppvalue_re.search(ppstruct_re.cap(0)) != -1) {
+ // The line ends with a '>', but we have this case now..
+ // If there is only one instance variable, pp puts everything
+ // on a single line:
+ // #<Struct::Customer @foobar="hello">
+ // So search for '@foobar="hello"', to use as the
+ // first name=value pair
+ pos = 0;
+ } else {
+ // Mltiple lines with name=value pairs:
+ // #<Struct::Customer
+ // @foobar="hello",
+ pos = ppvalue_re.search(buf, pos);
+ }
+
+ while (pos != -1) {
+ varName = ppvalue_re.cap(1);
+ value = ppvalue_re.cap(2).latin1();
+ dataType = determineType(value.data());
+ setItem(parent, varName, dataType, value);
+
+ pos += ppvalue_re.matchedLength();
+ pos = ppvalue_re.search(buf, pos);
+ }
+
+ }
+ return;
+ }
+
+ case STRING_TYPE:
+ {
+ // Look for a long String which has been printed via a 'pp' command, to
+ // show it as a sequence of 12 bytes slices in hex. For example:
+ // [0..11]=0x89504e470d0a1a0a0000000d
+ // [12..23]=0x494844520000001600000016
+ //
+ QRegExp ppstring_re("\\s*(\\[[^\\]]+\\])=([^\\n]+)\\n");
+ pos = ppstring_re.search(buf);
+
+ while (pos != -1) {
+ varName = ppstring_re.cap(1);
+ value = ppstring_re.cap(2).latin1();
+ DataType dataType = determineType(value.data());
+ setItem(parent, varName, dataType, value);
+
+ pos += ppstring_re.matchedLength();
+ pos = ppstring_re.search(buf, pos);
+ }
+
+ return;
+ }
+
+ default:
+ Q_ASSERT(false);
+ }
+
+ return;
+}
+
+
+// **************************************************************************
+
+void RDBParser::setItem(LazyFetchItem *parent, const QString &varName,
+ DataType dataType, const QCString &value)
+{
+ VarItem *item = parent->findItem(varName);
+ if (item == 0) {
+ item = new VarItem(parent, varName, dataType);
+ } else {
+ // The dataType of an item can change, so update it
+ item->setDataType(dataType);
+ }
+
+ switch (dataType) {
+ case HASH_TYPE:
+ case ARRAY_TYPE:
+ case REFERENCE_TYPE:
+ case STRUCT_TYPE:
+ case STRING_TYPE:
+ item->setText(VALUE_COLUMN, value);
+ item->setExpandable(true);
+ item->update();
+ break;
+
+ case COLOR_TYPE:
+ case VALUE_TYPE:
+ item->setText(VALUE_COLUMN, value);
+ item->setExpandable(false);
+ break;
+
+ default:
+ break;
+ }
+}
+
+// **************************************************************************
+
+DataType RDBParser::determineType(char *buf)
+{
+ QRegExp array_re("(Array \\(\\d+ element\\(s\\)\\))");
+ QRegExp hash_re("(Hash \\(\\d+ element\\(s\\)\\))");
+ QRegExp string_re("(String \\(length \\d+\\))");
+
+ if (qstrncmp(buf, "#<struct", strlen("#<struct")) == 0) {
+ return STRUCT_TYPE;
+ } else if (qstrncmp(buf, "#<Qt::Color:0x", strlen("#<Qt::Color:0x")) == 0) {
+ return COLOR_TYPE;
+ } else if (qstrncmp(buf, "#<", strlen("#<")) == 0 && strstr(buf, "=") != 0) {
+ // An object instance reference is only expandable and a 'REFERENCE_TYPE'
+ // if it contains an '=' (ie it has at least one '@instance_variable=value').
+ // Otherwise, treat it as a 'VALUE_TYPE'.
+ return REFERENCE_TYPE;
+ } else if (array_re.search(buf) != -1) {
+ return ARRAY_TYPE;
+ } else if (hash_re.search(buf) != -1) {
+ return HASH_TYPE;
+ } else if (string_re.search(buf) != -1) {
+ return STRING_TYPE;
+ } else if (qstrncmp(buf, "nil", strlen("nil")) == 0) {
+// return UNKNOWN_TYPE;
+ return VALUE_TYPE;
+ } else {
+ return VALUE_TYPE;
+ }
+}
+
+
+// **************************************************************************
+// **************************************************************************
+// **************************************************************************
+
+}