~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/ruby/debugger/rdbparser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2006-05-23 18:39:42 UTC
  • Revision ID: james.westby@ubuntu.com-20060523183942-hucifbvh68k2bwz7
Tags: upstream-3.3.2
Import upstream version 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// **************************************************************************
 
2
//    begin                : Tue Aug 17 1999
 
3
//    copyright            : (C) 1999 by John Birch
 
4
//    email                : jbb@kdevelop.org
 
5
//      
 
6
//                          Adapted for ruby debugging
 
7
//                          --------------------------
 
8
//    begin                : Mon Nov 1 2004
 
9
//    copyright            : (C) 2004 by Richard Dale
 
10
//    email                : Richard_Dale@tipitina.demon.co.uk
 
11
// **************************************************************************
 
12
 
 
13
// **************************************************************************
 
14
//                                                                          *
 
15
//    This program is free software; you can redistribute it and/or modify  *
 
16
//    it under the terms of the GNU General Public License as published by  *
 
17
//    the Free Software Foundation; either version 2 of the License, or     *
 
18
//    (at your option) any later version.                                   *
 
19
//                                                                          *
 
20
// **************************************************************************
 
21
 
 
22
#include "rdbparser.h"
 
23
#include "variablewidget.h"
 
24
 
 
25
#include <qregexp.h>
 
26
 
 
27
#include <ctype.h>
 
28
#include <stdlib.h>
 
29
#include <kdebug.h>
 
30
 
 
31
namespace RDBDebugger
 
32
{
 
33
 
 
34
 
 
35
// **************************************************************************
 
36
 
 
37
void RDBParser::parseVariables(LazyFetchItem *parent, char *buf)
 
38
{
 
39
    static const char *unknown = "?";
 
40
        
 
41
        QString         varName;
 
42
        QCString        value;
 
43
        int                     pos;
 
44
 
 
45
    Q_ASSERT(parent);
 
46
    if (buf == 0 || strlen(buf) == 0) {
 
47
        return;
 
48
        }
 
49
 
 
50
    if (buf[0] == 0) {
 
51
        buf = (char*)unknown;
 
52
        }
 
53
                
 
54
        QRegExp var_re("\\s*([^\\n\\s]+) => ([^\\n]+)");
 
55
        QRegExp ref_re("(#<([^:]|::)+:0x[\\da-f]+)\\s*([^=]*)>?");
 
56
        QRegExp struct_re("#<struct Struct::(\\w+)");
 
57
        
 
58
        // Look for 'dataitem => value' pairs. For example:
 
59
        //      a => 1
 
60
        //      m => #<MyClass:0x30093540 @temp={"z"=>"zed", "p"=>"pee"}, @foobar="hello">
 
61
        //
 
62
        pos = var_re.search(buf);       
 
63
        if (pos != -1) {
 
64
                while (pos != -1) {
 
65
                        varName = var_re.cap(1);
 
66
                        if (ref_re.search(var_re.cap(2)) != -1) {
 
67
                                if (var_re.cap(2).contains("=") > 0) {
 
68
                                        value = (ref_re.cap(1) + ">").latin1();
 
69
                                } else {
 
70
                                        // There are no 'name=value' pairs, as in #<Qt::Color:0x0 #ff0000>
 
71
                                        value = var_re.cap(2).latin1();
 
72
                                }
 
73
                        } else if (struct_re.search(var_re.cap(2)) != -1) {
 
74
                                value = (QString("#<Struct::") + struct_re.cap(1) + ">").latin1();
 
75
                        } else {
 
76
                                value = var_re.cap(2).latin1();
 
77
                        }
 
78
                        
 
79
                DataType dataType = determineType((char *) var_re.cap(2).latin1());
 
80
                        
 
81
                        // 'self' variables don't need to be expandable, as their details are
 
82
                        // already shown in the current frame. So always make them VALUE_TYPE's.
 
83
                        if (varName == "self") {
 
84
                                dataType = VALUE_TYPE;
 
85
                        }
 
86
                        
 
87
                        setItem(parent, varName, dataType, value);
 
88
                        
 
89
                        pos  += var_re.matchedLength();
 
90
                        pos = var_re.search(buf, pos);
 
91
                }
 
92
 
 
93
                return;
 
94
        }
 
95
}
 
96
 
 
97
void RDBParser::parseExpandedVariable(VarItem *parent, char *buf)
 
98
{
 
99
        DataType        dataType;
 
100
        int                     pos;
 
101
        QString         varName;
 
102
        QCString        value;
 
103
        QRegExp         ppref_re("(#<([^:]|::)+:0x[\\da-f]+)([^\\n>]*)(>?)");
 
104
    
 
105
        switch (parent->dataType()) {
 
106
    case REFERENCE_TYPE:
 
107
        {
 
108
                // Look for a reference type which has been printed via a 'pp' command, to
 
109
                // expand its sub items on multiple lines. For example:
 
110
                //     #<MyClass:0x30093540
 
111
                //              @foobar="hello",
 
112
                //              @sleeper=#<Thread:0x3008fd18 sleep>,
 
113
                //              @temp={"z"=>"zed", "p"=>"pee"}>
 
114
                //
 
115
                QRegExp ppvalue_re("\\s*([^\\n\\s=]+)=([^\\n]+)[,>]");
 
116
 
 
117
                pos = ppref_re.search(buf);
 
118
                if (pos != -1) {
 
119
                        if (ppref_re.cap(4) != "") {
 
120
                                // The value is all on one line, so match against name=value 
 
121
                                // pairs which can't have commas in their values
 
122
                                ppvalue_re = QRegExp("\\s*([^\\s=]+)=([^,>]+)([,>])");
 
123
                        }
 
124
 
 
125
                        pos = ppvalue_re.search(buf, pos);
 
126
                                        
 
127
                        while (pos != -1) {
 
128
                                varName = ppvalue_re.cap(1);
 
129
                                
 
130
                                if (ppref_re.search(ppvalue_re.cap(2)) != -1) {
 
131
                                        if (ppvalue_re.cap(2).contains("=") > 0) {
 
132
                                                value = (ppref_re.cap(1) + ">").latin1();
 
133
                                        } else {
 
134
                                                // There are no 'name=value' pairs, as in #<Qt::Color:0x0 #ff0000>
 
135
                                                value = ppvalue_re.cap(2).latin1();
 
136
                                        }
 
137
                                } else {
 
138
                                        value = ppvalue_re.cap(2).latin1();
 
139
                                }
 
140
                                
 
141
                                dataType = determineType((char *) ppvalue_re.cap(2).latin1());
 
142
                                setItem(parent, varName, dataType, value);
 
143
                                
 
144
                                pos += ppvalue_re.matchedLength();
 
145
                                pos = ppvalue_re.search(buf, pos);
 
146
                        }
 
147
                        
 
148
                }
 
149
                return;
 
150
        }
 
151
        
 
152
    case ARRAY_TYPE:
 
153
        {
 
154
                // Look for a array type which has been printed via a 'pp' command, to
 
155
                // expand its sub items. For example:
 
156
                //              [0]="hello"
 
157
                //              [1]=#"goodbye"
 
158
                //
 
159
                QRegExp pparray_re("\\s*([^=]+)=([^\\n]+)\\n");
 
160
                
 
161
                pos = pparray_re.search(buf);
 
162
                        
 
163
                while (pos != -1) {
 
164
                        varName = pparray_re.cap(1);
 
165
                        
 
166
                        if (ppref_re.search(pparray_re.cap(2)) != -1) {
 
167
                                value = (ppref_re.cap(1) + ">").latin1();
 
168
                        } else {
 
169
                                value = pparray_re.cap(2).latin1();
 
170
                        }
 
171
                                
 
172
                        DataType dataType = determineType((char *) pparray_re.cap(2).latin1());
 
173
                        setItem(parent, varName, dataType, value);
 
174
                                
 
175
                        pos += pparray_re.matchedLength();
 
176
                        pos = pparray_re.search(buf, pos);
 
177
                }
 
178
                                        
 
179
                return;
 
180
        }
 
181
        
 
182
    case HASH_TYPE:
 
183
        {
 
184
                // Look for a hash type which has been printed via a 'pp' command, to
 
185
                // expand its sub items. For example:
 
186
                //              ["greeting"]="hello"
 
187
                //              ["farewell"]="goodbye"
 
188
                //
 
189
                QRegExp pphash_re("\\s*(\\[[^\\]]+\\])=([^\\n]+)\\n");
 
190
                pos = pphash_re.search(buf);
 
191
                
 
192
                while (pos != -1) {
 
193
                        varName = pphash_re.cap(1);
 
194
                        value = pphash_re.cap(2).latin1();
 
195
                DataType dataType = determineType(value.data());
 
196
                        setItem(parent, varName, dataType, value);
 
197
                        
 
198
                        pos += pphash_re.matchedLength();
 
199
                        pos = pphash_re.search(buf, pos);
 
200
                }
 
201
                
 
202
                return;
 
203
        }
 
204
        
 
205
    case STRUCT_TYPE:
 
206
        {
 
207
                // Look for a reference type which has been printed via a 'pp' command, to
 
208
                // expand its sub items. For example:
 
209
                //     #<Struct::Customer
 
210
                //              @foobar="hello",
 
211
                //              @sleeper=#<Thread:0x3008fd18 sleep>,
 
212
                //              @temp={"z"=>"zed", "p"=>"pee"}>
 
213
                //
 
214
                QRegExp ppstruct_re("(#<Struct::\\w+)\\s([^\\n>]*)(>?)");
 
215
                QRegExp ppvalue_re("\\s*([^\\n\\s=]+)=([^\\n]+)[,>]");
 
216
        
 
217
                pos = ppstruct_re.search(buf);
 
218
                if (pos != -1) {
 
219
                        if (ppstruct_re.cap(3) != "" && ppvalue_re.search(ppstruct_re.cap(0)) != -1) {
 
220
                                // The line ends with a '>', but we have this case now..
 
221
                                // If there is only one instance variable, pp puts everything
 
222
                                // on a single line:
 
223
                                //     #<Struct::Customer @foobar="hello">
 
224
                                // So search for '@foobar="hello"', to use as the
 
225
                                // first name=value pair
 
226
                                pos = 0;
 
227
                        } else {
 
228
                                // Mltiple lines with name=value pairs:
 
229
                                //     #<Struct::Customer
 
230
                                //              @foobar="hello",
 
231
                                pos = ppvalue_re.search(buf, pos);
 
232
                        }
 
233
                                        
 
234
                        while (pos != -1) {
 
235
                                varName = ppvalue_re.cap(1);
 
236
                                value = ppvalue_re.cap(2).latin1();
 
237
                                dataType = determineType(value.data());
 
238
                                setItem(parent, varName, dataType, value);
 
239
                                
 
240
                                pos += ppvalue_re.matchedLength();
 
241
                                pos = ppvalue_re.search(buf, pos);
 
242
                        }
 
243
                        
 
244
                }
 
245
                return;
 
246
        }
 
247
                        
 
248
    case STRING_TYPE:
 
249
        {
 
250
                // Look for a long String which has been printed via a 'pp' command, to
 
251
                // show it as a sequence of 12 bytes slices in hex. For example:
 
252
                //              [0..11]=0x89504e470d0a1a0a0000000d
 
253
                //              [12..23]=0x494844520000001600000016
 
254
                //
 
255
                QRegExp ppstring_re("\\s*(\\[[^\\]]+\\])=([^\\n]+)\\n");
 
256
                pos = ppstring_re.search(buf);
 
257
                
 
258
                while (pos != -1) {
 
259
                        varName = ppstring_re.cap(1);
 
260
                        value = ppstring_re.cap(2).latin1();
 
261
                DataType dataType = determineType(value.data());
 
262
                        setItem(parent, varName, dataType, value);
 
263
                        
 
264
                        pos += ppstring_re.matchedLength();
 
265
                        pos = ppstring_re.search(buf, pos);
 
266
                }
 
267
                
 
268
                return;
 
269
        }
 
270
                
 
271
        default:
 
272
                Q_ASSERT(false);
 
273
        }
 
274
        
 
275
        return;
 
276
}
 
277
 
 
278
 
 
279
// **************************************************************************
 
280
 
 
281
void RDBParser::setItem(LazyFetchItem *parent, const QString &varName,
 
282
                        DataType dataType, const QCString &value)
 
283
{
 
284
        VarItem *item = parent->findItem(varName);
 
285
    if (item == 0) {
 
286
        item = new VarItem(parent, varName, dataType);
 
287
    } else {
 
288
                // The dataType of an item can change, so update it
 
289
                item->setDataType(dataType);
 
290
        }
 
291
 
 
292
    switch (dataType) {
 
293
    case HASH_TYPE:
 
294
    case ARRAY_TYPE:
 
295
    case REFERENCE_TYPE:
 
296
    case STRUCT_TYPE:
 
297
    case STRING_TYPE:
 
298
        item->setText(VALUE_COLUMN, value);
 
299
                item->setExpandable(true);
 
300
        item->update();
 
301
        break;
 
302
 
 
303
    case COLOR_TYPE:
 
304
    case VALUE_TYPE:
 
305
        item->setText(VALUE_COLUMN, value);
 
306
                item->setExpandable(false);
 
307
        break;
 
308
 
 
309
    default:
 
310
        break;
 
311
    }
 
312
}
 
313
 
 
314
// **************************************************************************
 
315
 
 
316
DataType RDBParser::determineType(char *buf)
 
317
{
 
318
        QRegExp array_re("(Array \\(\\d+ element\\(s\\)\\))");
 
319
        QRegExp hash_re("(Hash \\(\\d+ element\\(s\\)\\))");
 
320
        QRegExp string_re("(String \\(length \\d+\\))");
 
321
        
 
322
        if (qstrncmp(buf, "#<struct", strlen("#<struct")) == 0) {
 
323
                return STRUCT_TYPE;
 
324
        } else if (qstrncmp(buf, "#<Qt::Color:0x", strlen("#<Qt::Color:0x")) == 0) {
 
325
                return COLOR_TYPE;
 
326
        } else if (qstrncmp(buf, "#<", strlen("#<")) == 0 && strstr(buf, "=") != 0) {
 
327
                // An object instance reference is only expandable and a 'REFERENCE_TYPE'
 
328
                // if it contains an '=' (ie it has at least one '@instance_variable=value').
 
329
                // Otherwise, treat it as a 'VALUE_TYPE'.
 
330
                return REFERENCE_TYPE;
 
331
        } else if (array_re.search(buf) != -1) {
 
332
                return ARRAY_TYPE;
 
333
        } else if (hash_re.search(buf) != -1) {
 
334
                return HASH_TYPE;
 
335
        } else if (string_re.search(buf) != -1) {
 
336
                return STRING_TYPE;
 
337
        } else if (qstrncmp(buf, "nil", strlen("nil")) == 0) {
 
338
//              return UNKNOWN_TYPE;
 
339
                return VALUE_TYPE;
 
340
        } else {
 
341
                return VALUE_TYPE;
 
342
        }
 
343
}
 
344
 
 
345
 
 
346
// **************************************************************************
 
347
// **************************************************************************
 
348
// **************************************************************************
 
349
 
 
350
}