~ubuntu-branches/ubuntu/raring/geany/raring-proposed

« back to all changes in this revision

Viewing changes to tagmanager/python.c

  • Committer: Bazaar Package Importer
  • Author(s): Damián Viano
  • Date: 2008-05-02 11:37:45 UTC
  • mfrom: (1.2.1 upstream) (9 hardy)
  • mto: (3.2.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: james.westby@ubuntu.com-20080502113745-xzp4g6dmovrpoj17
Tags: 0.14-1
New upstream release (Closes: #478126)

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
*   INCLUDE FILES
14
14
*/
15
15
#include "general.h"    /* must always come first */
16
 
 
 
16
#include <glib.h>
17
17
#include <string.h>
18
18
 
19
19
#include "parse.h"
24
24
*   DATA DEFINITIONS
25
25
*/
26
26
typedef enum {
27
 
    K_CLASS, K_FUNCTION, K_METHOD
 
27
    K_CLASS, K_FUNCTION, K_METHOD, K_VARIABLE
28
28
} pythonKind;
29
29
 
30
30
static kindOption PythonKinds [] = {
31
31
    { TRUE, 'c', "class",    "classes" },
32
32
    { TRUE, 'f', "function", "functions" },
33
 
    { TRUE, 'm', "member", "methods" }
 
33
    { TRUE, 'm', "member", "methods" },
 
34
    { TRUE, 'v', "variable", "variables" }
34
35
};
35
36
 
 
37
typedef struct _lastClass {
 
38
        gchar *name;
 
39
        gint indent;
 
40
} lastClass;
 
41
 
36
42
/*
37
43
*   FUNCTION DEFINITIONS
38
44
*/
39
45
 
 
46
static boolean isIdentifierFirstCharacter (int c)
 
47
{
 
48
        return (boolean) (isalpha (c) || c == '_');
 
49
}
 
50
 
 
51
static boolean isIdentifierCharacter (int c)
 
52
{
 
53
        return (boolean) (isalnum (c) || c == '_');
 
54
}
 
55
 
 
56
 
 
57
/* remove all previous classes with more indent than the current one */
 
58
static GList *clean_class_list(GList *list, gint indent)
 
59
{
 
60
        GList *tmp, *tmp2;
 
61
 
 
62
        tmp = g_list_first(list);
 
63
        while (tmp != NULL)
 
64
        {
 
65
                if (((lastClass*)tmp->data)->indent >= indent)
 
66
                {
 
67
                        g_free(((lastClass*)tmp->data)->name);
 
68
                        g_free(tmp->data);
 
69
                        tmp2 = tmp->next;
 
70
 
 
71
                        list = g_list_remove(list, tmp->data);
 
72
                        tmp = tmp2;
 
73
                }
 
74
                else
 
75
                {
 
76
                        tmp = tmp->next;
 
77
                }
 
78
        }
 
79
 
 
80
        return list;
 
81
}
 
82
 
 
83
 
40
84
static void findPythonTags (void)
41
85
{
 
86
    GList *parents = NULL, *tmp; /* list of classes which are around the token */
42
87
    vString *name = vStringNew ();
43
 
    vString *lastClass = vStringNew();
 
88
    gint indent;
44
89
    const unsigned char *line;
45
90
    boolean inMultilineString = FALSE;
 
91
    boolean wasInMultilineString = FALSE;
 
92
        lastClass *lastclass = NULL;
 
93
    boolean inFunction = FALSE;
 
94
    gint fn_indent = 0;
46
95
 
47
96
    while ((line = fileReadLine ()) != NULL)
48
97
    {
49
98
        const unsigned char *cp = line;
50
 
 
 
99
        indent = 0;
51
100
        while (*cp != '\0')
52
101
        {
53
102
            if (*cp=='"' &&
54
103
                strncmp ((const char*) cp, "\"\"\"", (size_t) 3) == 0)
55
104
            {
56
105
                inMultilineString = (boolean) !inMultilineString;
 
106
                if (! inMultilineString)
 
107
                        wasInMultilineString = TRUE;
57
108
                cp += 3;
58
109
            }
59
110
            if (*cp=='\'' &&
60
111
                strncmp ((const char*) cp, "'''", (size_t) 3) == 0)
61
112
            {
62
113
                inMultilineString = (boolean) !inMultilineString;
 
114
                if (! inMultilineString)
 
115
                        wasInMultilineString = TRUE;
63
116
                cp += 3;
64
117
            }
65
 
            if (inMultilineString  ||  isspace ((int) *cp))
 
118
 
 
119
                if (*cp == '\0' || wasInMultilineString)
 
120
                {
 
121
                        wasInMultilineString = FALSE;
 
122
                        break;  /* at end of multiline string */
 
123
                }
 
124
 
 
125
                /* update indent-sensitive things */
 
126
                if (!inMultilineString && !isspace(*cp))
 
127
                {
 
128
                        if (inFunction)
 
129
                        {
 
130
                                if (indent < fn_indent)
 
131
                                        inFunction = FALSE;
 
132
                        }
 
133
                    if (lastclass != NULL)
 
134
                    {
 
135
                                if (indent <= lastclass->indent)
 
136
                                {
 
137
                                        GList *last;
 
138
 
 
139
                                        parents = clean_class_list(parents, indent);
 
140
                                        last = g_list_last(parents);
 
141
                                        if (last != NULL)
 
142
                                                lastclass = last->data;
 
143
                                        else
 
144
                                                lastclass = NULL;
 
145
                                }
 
146
                    }
 
147
                }
 
148
 
 
149
            if (inMultilineString)
66
150
                ++cp;
 
151
                else if (isspace ((int) *cp))
 
152
                {
 
153
                        /* count indentation amount of current line
 
154
                         * the indentation has to be made with tabs only _or_ spaces only, if they are mixed
 
155
                         * the code below gets confused */
 
156
                        if (cp == line)
 
157
                        {
 
158
                                do
 
159
                                {
 
160
                                        indent++;
 
161
                                        cp++;
 
162
                                } while (isspace(*cp));
 
163
                        }
 
164
                        else
 
165
                                cp++;   /* non-indent whitespace */
 
166
                }
67
167
            else if (*cp == '#')
68
168
                break;
69
169
            else if (strncmp ((const char*) cp, "class", (size_t) 5) == 0)
70
170
            {
71
 
                cp += 5;
72
 
                if (isspace ((int) *cp))
73
 
                {
74
 
                    while (isspace ((int) *cp))
75
 
                        ++cp;
76
 
                    while (isalnum ((int) *cp)  ||  *cp == '_')
77
 
                    {
78
 
                        vStringPut (name, (int) *cp);
79
 
                        ++cp;
80
 
                    }
81
 
                    vStringTerminate (name);
82
 
                    makeSimpleTag (name, PythonKinds, K_CLASS);
83
 
                    vStringCopy (lastClass, name);
84
 
                    vStringClear (name);
85
 
                }
 
171
                        cp += 5;
 
172
                        if (isspace ((int) *cp))
 
173
                        {
 
174
                                lastClass *newclass = g_new(lastClass, 1);
 
175
 
 
176
                                while (isspace ((int) *cp))
 
177
                                ++cp;
 
178
                                while (isalnum ((int) *cp)  ||  *cp == '_')
 
179
                                {
 
180
                                vStringPut (name, (int) *cp);
 
181
                                ++cp;
 
182
                                }
 
183
                                vStringTerminate (name);
 
184
 
 
185
                                newclass->name = g_strdup(vStringValue(name));
 
186
                                newclass->indent = indent;
 
187
                                parents = g_list_append(parents, newclass);
 
188
                                if (lastclass == NULL)
 
189
                                        makeSimpleTag (name, PythonKinds, K_CLASS);
 
190
                                else
 
191
                                        makeSimpleScopedTag (name, PythonKinds, K_CLASS,
 
192
                                                PythonKinds[K_CLASS].name, lastclass->name, "public");
 
193
                                vStringClear (name);
 
194
 
 
195
                                lastclass = newclass;
 
196
                                break;  /* ignore rest of line so that lastclass is not reset immediately */
 
197
                        }
86
198
            }
87
199
            else if (strncmp ((const char*) cp, "def", (size_t) 3) == 0)
88
200
            {
97
209
                        ++cp;
98
210
                    }
99
211
                    vStringTerminate (name);
100
 
                    if (!isspace(*line) || vStringLength(lastClass) <= 0)
 
212
                    if (!isspace(*line) || lastclass == NULL || strlen(lastclass->name) <= 0)
101
213
                        makeSimpleTag (name, PythonKinds, K_FUNCTION);
102
214
                    else
103
215
                        makeSimpleScopedTag (name, PythonKinds, K_METHOD,
104
 
                                             PythonKinds[K_CLASS].name,
105
 
                                             vStringValue(lastClass), "public");
 
216
                                             PythonKinds[K_CLASS].name, lastclass->name, "public");
106
217
                    vStringClear (name);
 
218
 
 
219
                    inFunction = TRUE;
 
220
                    fn_indent = indent + 1;
 
221
                    break;      /* ignore rest of line so inFunction is not cancelled immediately */
107
222
                }
108
223
            }
 
224
                else if (!inFunction && *(const char*)cp == '=')
 
225
                {
 
226
                        /* Parse global and class variable names (C.x) from assignment statements.
 
227
                         * Object attributes (obj.x) are ignored.
 
228
                         * Assignment to a tuple 'x, y = 2, 3' not supported.
 
229
                         * TODO: ignore duplicate tags from reassignment statements. */
 
230
                        const guchar *sp, *eq, *start;
 
231
 
 
232
                        eq = cp + 1;
 
233
                        while (*eq)
 
234
                        {
 
235
                                if (*eq == '=')
 
236
                                        goto skipvar;   /* ignore '==' operator and 'x=5,y=6)' function lines */
 
237
                                if (*eq == '(')
 
238
                                        break;  /* allow 'x = func(b=2,y=2,' lines */
 
239
                                eq++;
 
240
                        }
 
241
                        /* go backwards to the start of the line, checking we have valid chars */
 
242
                        start = cp - 1;
 
243
                        while (start >= line && isspace ((int) *start))
 
244
                                --start;
 
245
                        while (start >= line && isIdentifierCharacter ((int) *start))
 
246
                                --start;
 
247
                        if (!isIdentifierFirstCharacter(*(start + 1)))
 
248
                                goto skipvar;
 
249
                        sp = start;
 
250
                        while (sp >= line && isspace ((int) *sp))
 
251
                                --sp;
 
252
                        if ((sp + 1) != line)   /* the line isn't a simple variable assignment */
 
253
                                goto skipvar;
 
254
                        /* the line is valid, parse the variable name */
 
255
                        ++start;
 
256
                        while (isIdentifierCharacter ((int) *start))
 
257
                        {
 
258
                                vStringPut (name, (int) *start);
 
259
                                ++start;
 
260
                        }
 
261
                        vStringTerminate (name);
 
262
 
 
263
                        if (lastclass == NULL)
 
264
                                makeSimpleTag (name, PythonKinds, K_VARIABLE);
 
265
                        else
 
266
                                makeSimpleScopedTag (name, PythonKinds, K_VARIABLE,
 
267
                                        PythonKinds[K_CLASS].name, lastclass->name, "public");  /* class member variables */
 
268
 
 
269
                        vStringClear (name);
 
270
 
 
271
                        skipvar:
 
272
                        ++cp;
 
273
                }
109
274
            else if (*cp != '\0')
110
275
            {
111
276
                do
115
280
        }
116
281
    }
117
282
    vStringDelete (name);
118
 
    vStringDelete (lastClass);
 
283
 
 
284
    /* clear the remaining elements in the list */
 
285
    tmp = g_list_first(parents);
 
286
    while (tmp != NULL)
 
287
    {
 
288
        if (tmp->data)
 
289
        {
 
290
                        g_free(((lastClass*)tmp->data)->name);
 
291
                        g_free(tmp->data);
 
292
        }
 
293
        tmp = tmp->next;
 
294
    }
 
295
    g_list_free(parents);
119
296
}
120
297
 
121
298
extern parserDefinition* PythonParser (void)