Kaydet (Commit) 023a60cd authored tarafından Nick Treleaven's avatar Nick Treleaven

Parse Python global variables and class variables from assignment

statements; assignment to a tuple literal ('x, y =') not supported.


git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@1773 ea778897-0a13-0410-b9d1-a72fbfd435f5
üst 2397dc3b
2007-08-07 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/symbols.c, tagmanager/python.c:
Parse Python global variables and class variables from assignment
statements; assignment to a tuple literal ('x, y =') not supported.
2007-08-05 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* geany.glade, src/geany.h, src/interface.c, src/keyfile.c,
......
......@@ -572,6 +572,7 @@ static void init_tag_list(gint idx)
&(tv_iters.tag_class), _("Classes"), "classviewer-class",
&(tv_iters.tag_member), _("Methods"), "classviewer-member",
&(tv_iters.tag_function), _("Functions"), "classviewer-method",
&(tv_iters.tag_variable), _("Variables"), "classviewer-var",
NULL);
//&(tv_iters.tag_macro), _("Mixin"),
//&(tv_iters.tag_variable), _("Variables"),
......
......@@ -24,13 +24,14 @@
* DATA DEFINITIONS
*/
typedef enum {
K_CLASS, K_FUNCTION, K_METHOD
K_CLASS, K_FUNCTION, K_METHOD, K_VARIABLE
} pythonKind;
static kindOption PythonKinds [] = {
{ TRUE, 'c', "class", "classes" },
{ TRUE, 'f', "function", "functions" },
{ TRUE, 'm', "member", "methods" }
{ TRUE, 'm', "member", "methods" },
{ TRUE, 'v', "variable", "variables" }
};
typedef struct _lastClass {
......@@ -42,6 +43,16 @@ typedef struct _lastClass {
* FUNCTION DEFINITIONS
*/
static boolean isIdentifierFirstCharacter (int c)
{
return (boolean) (isalpha (c) || c == '_');
}
static boolean isIdentifierCharacter (int c)
{
return (boolean) (isalnum (c) || c == '_');
}
// remove all previous classes with more indent than the current one
static GList *clean_class_list(GList *list, gint indent)
......@@ -77,6 +88,9 @@ static void findPythonTags (void)
gint indent;
const unsigned char *line;
boolean inMultilineString = FALSE;
lastClass *lastclass = NULL;
boolean inFunction = FALSE;
gint fn_indent = 0;
while ((line = fileReadLine ()) != NULL)
{
......@@ -97,15 +111,50 @@ static void findPythonTags (void)
cp += 3;
}
if (*cp == '\0')
break; // at end of multiline string
// update indent-sensitive things
if (!inMultilineString && !isspace(*cp))
{
if (inFunction)
{
if (indent < fn_indent)
inFunction = FALSE;
}
if (lastclass != NULL)
{
if (indent <= lastclass->indent)
{
GList *last;
parents = clean_class_list(parents, indent);
last = g_list_last(parents);
if (last != NULL)
lastclass = last->data;
else
lastclass = NULL;
}
}
}
if (inMultilineString)
++cp;
else if (isspace ((int) *cp))
{
cp++;
// count indentation amount of current line
// the indentation has to be made with tabs only _or_ spaces only, if they are mixed
// the code below gets confused
indent++;
if (cp == line)
{
do
{
indent++;
cp++;
} while (isspace(*cp));
}
else
cp++; // non-indent whitespace
}
else if (*cp == '#')
break;
......@@ -114,12 +163,8 @@ static void findPythonTags (void)
cp += 5;
if (isspace ((int) *cp))
{
GList *last = g_list_last(parents);
lastClass *lastclass = NULL;
lastClass *newclass = g_new(lastClass, 1);
if (last != NULL) lastclass = last->data;
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
......@@ -129,13 +174,14 @@ static void findPythonTags (void)
}
vStringTerminate (name);
parents = clean_class_list(parents, indent);
newclass->name = g_strdup(vStringValue(name));
newclass->indent = indent;
parents = g_list_append(parents, newclass);
makeSimpleTag (name, PythonKinds, K_CLASS);
vStringClear (name);
lastclass = newclass;
break; // ignore rest of line so that lastclass is not reset immediately
}
}
else if (strncmp ((const char*) cp, "def", (size_t) 3) == 0)
......@@ -143,13 +189,6 @@ static void findPythonTags (void)
cp += 3;
if (isspace ((int) *cp))
{
GList *last;
lastClass *lastclass = NULL;
parents = clean_class_list(parents, indent);
last = g_list_last(parents);
if (last != NULL) lastclass = last->data;
while (isspace ((int) *cp))
++cp;
while (isalnum ((int) *cp) || *cp == '_')
......@@ -164,8 +203,62 @@ static void findPythonTags (void)
makeSimpleScopedTag (name, PythonKinds, K_METHOD,
PythonKinds[K_CLASS].name, lastclass->name, "public");
vStringClear (name);
inFunction = TRUE;
fn_indent = indent + 1;
break; // ignore rest of line so inFunction is not cancelled immediately
}
}
else if (!inFunction && *(const char*)cp == '=')
{
/* Parse global and class variable names (C.x) from assignment statements.
* Object attributes (obj.x) are ignored.
* Assignment to a tuple 'x, y = 2, 3' not supported.
* TODO: ignore duplicate tags from reassignment statements. */
const guchar *sp, *eq, *start;
eq = cp + 1;
while (*eq)
{
if (*eq == '=')
goto skipvar; // ignore '==' operator and 'x=5,y=6)' function lines
if (*eq == '(')
break; // allow 'x = func(b=2,y=2,' lines
eq++;
}
// go backwards to the start of the line, checking we have valid chars
start = cp - 1;
while (start >= line && isspace ((int) *start))
--start;
while (start >= line && isIdentifierCharacter ((int) *start))
--start;
if (!isIdentifierFirstCharacter(*(start + 1)))
goto skipvar;
sp = start;
while (sp >= line && isspace ((int) *sp))
--sp;
if ((sp + 1) != line) // the line isn't a simple variable assignment
goto skipvar;
// the line is valid, parse the variable name
++start;
while (isIdentifierCharacter ((int) *start))
{
vStringPut (name, (int) *start);
++start;
}
vStringTerminate (name);
if (lastclass == NULL)
makeSimpleTag (name, PythonKinds, K_VARIABLE);
else
makeSimpleScopedTag (name, PythonKinds, K_VARIABLE,
PythonKinds[K_CLASS].name, lastclass->name, "public"); // class member variables
vStringClear (name);
skipvar:
++cp;
}
else if (*cp != '\0')
{
do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment