Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Synchronized the python parser with the geany tagmanager, including t…

…he following geany commits:

r3788: nestlevel.c and some other stuff
r3804: Parse Python import statements to get symbol completion for the imported module names.
r3809: Parse Python calltips.
r3831: Fix grouping functions/classes under a nested function.

Many thanks to the geany devs!
  • Loading branch information...
commit 431e41bbdb1d73cf3207496f4b422c060b26c1c7 1 parent ca63130
@elias-pschernig elias-pschernig authored
Showing with 247 additions and 72 deletions.
  1. +80 −0 nestlevel.c
  2. +54 −0 nestlevel.h
  3. +108 −69 python.c
  4. +3 −1 source.mak
  5. +2 −2 testing.mak
View
80 nestlevel.c
@@ -0,0 +1,80 @@
+/*
+* $Id: nestlevel.c 3788 2009-05-12 15:55:13Z ntrel $
+*
+* Copyright (c) 1999-2002, Darren Hiebert
+* Copyright 2009 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* Defines external interface to scope nesting levels for tags.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include "main.h"
+#include "nestlevel.h"
+#include "debug.h"
+#include "routines.h"
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+extern NestingLevels *nestingLevelsNew(void)
+{
+ NestingLevels *nls = xCalloc (1, NestingLevels);
+ return nls;
+}
+
+extern void nestingLevelsFree(NestingLevels *nls)
+{
+ int i;
+ for (i = 0; i < nls->allocated; i++)
+ vStringDelete(nls->levels[i].name);
+ if (nls->levels) eFree(nls->levels);
+ eFree(nls);
+}
+
+extern void nestingLevelsPush(NestingLevels *nls,
+ const vString *name, int type)
+{
+ NestingLevel *nl = NULL;
+
+ if (nls->n >= nls->allocated)
+ {
+ nls->allocated++;
+ nls->levels = xRealloc(nls->levels,
+ nls->allocated, NestingLevel);
+ nls->levels[nls->n].name = vStringNew();
+ }
+ nl = &nls->levels[nls->n];
+ nls->n++;
+
+ vStringCopy(nl->name, name);
+ nl->type = type;
+}
+
+extern void nestingLevelsPop(NestingLevels *nls)
+{
+ const NestingLevel *nl = nestingLevelsGetCurrent(nls);
+
+ Assert (nl != NULL);
+ vStringClear(nl->name);
+ nls->n--;
+}
+
+extern NestingLevel *nestingLevelsGetCurrent(NestingLevels *nls)
+{
+ Assert (nls != NULL);
+
+ if (nls->n < 1)
+ return NULL;
+
+ return &nls->levels[nls->n - 1];
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
View
54 nestlevel.h
@@ -0,0 +1,54 @@
+/*
+* $Id: nestlevel.h 3788 2009-05-12 15:55:13Z ntrel $
+*
+* Copyright (c) 1999-2002, Darren Hiebert
+* Copyright 2009 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* Defines external interface to scope nesting levels for tags.
+*/
+#ifndef _NESTLEVEL_H
+#define _NESTLEVEL_H
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include "vstring.h"
+
+/*
+* DATA DECLARATIONS
+*/
+typedef struct NestingLevel NestingLevel;
+typedef struct NestingLevels NestingLevels;
+
+struct NestingLevel
+{
+ int indentation;
+ vString *name;
+ int type;
+};
+
+struct NestingLevels
+{
+ NestingLevel *levels;
+ int n; /* number of levels in use */
+ int allocated;
+};
+
+/*
+* FUNCTION PROTOTYPES
+*/
+extern NestingLevels *nestingLevelsNew(void);
+extern void nestingLevelsFree(NestingLevels *nls);
+extern void nestingLevelsPush(NestingLevels *nls,
+ const vString *name, int type);
+extern void nestingLevelsPop(NestingLevels *nls);
+extern NestingLevel *nestingLevelsGetCurrent(NestingLevels *nls);
+
+#endif /* _NESTLEVEL_H */
+
+/* vi:set tabstop=4 shiftwidth=4: */
View
177 python.c
@@ -19,38 +19,23 @@
#include "entry.h"
#include "options.h"
#include "read.h"
-#include "routines.h"
+#include "main.h"
#include "vstring.h"
+#include "nestlevel.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
- K_CLASS, K_FUNCTION, K_MEMBER, K_VARIABLE
+ K_CLASS, K_FUNCTION, K_MEMBER, K_VARIABLE, K_IMPORT
} pythonKind;
static kindOption PythonKinds[] = {
{TRUE, 'c', "class", "classes"},
{TRUE, 'f', "function", "functions"},
{TRUE, 'm', "member", "class members"},
- {TRUE, 'v', "variable", "variables"}
-};
-
-typedef struct NestingLevel NestingLevel;
-typedef struct NestingLevels NestingLevels;
-
-struct NestingLevel
-{
- int indentation;
- vString *name;
- boolean is_class;
-};
-
-struct NestingLevels
-{
- NestingLevel *levels;
- int n;
- int allocated;
+ {TRUE, 'v', "variable", "variables"},
+ {TRUE, 'i', "namespace", "imports"}
};
static char const * const singletriple = "'''";
@@ -76,13 +61,14 @@ static boolean isIdentifierCharacter (int c)
* extract all relevant information and create a tag.
*/
static void makeFunctionTag (vString *const function,
- vString *const parent, int is_class_parent)
+ vString *const parent, int is_class_parent, const char *arglist)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (function));
-
+
tag.kindName = "function";
tag.kind = 'f';
+ //tag.extensionFields.arglist = arglist;
if (vStringLength (parent) > 0)
{
@@ -263,11 +249,82 @@ static void parseClass (const char *cp, vString *const class,
vStringDelete (inheritance);
}
+static void parseImports (const char *cp)
+{
+ const char *pos;
+ vString *name, *name_next;
+
+ cp = skipEverything (cp);
+
+ if ((pos = strstr (cp, "import")) == NULL)
+ return;
+
+ cp = pos + 6;
+
+ /* continue only if there is some space between the keyword and the identifier */
+ if (! isspace (*cp))
+ return;
+
+ cp++;
+ cp = skipSpace (cp);
+
+ name = vStringNew ();
+ name_next = vStringNew ();
+
+ cp = skipEverything (cp);
+ while (*cp)
+ {
+ cp = parseIdentifier (cp, name);
+
+ cp = skipEverything (cp);
+ /* we parse the next possible import statement as well to be able to ignore 'foo' in
+ * 'import foo as bar' */
+ parseIdentifier (cp, name_next);
+
+ /* take the current tag only if the next one is not "as" */
+ if (strcmp (vStringValue (name_next), "as") != 0 &&
+ strcmp (vStringValue (name), "as") != 0)
+ {
+ makeSimpleTag (name, PythonKinds, K_IMPORT);
+ }
+ }
+ vStringDelete (name);
+ vStringDelete (name_next);
+}
+
+/* modified from get.c getArglistFromStr().
+ * warning: terminates rest of string past arglist!
+ * note: does not ignore brackets inside strings! */
+static char *parseArglist(const char *buf)
+{
+ char *start, *end;
+ int level;
+ if (NULL == buf)
+ return NULL;
+ if (NULL == (start = strchr(buf, '(')))
+ return NULL;
+ for (level = 1, end = start + 1; level > 0; ++end)
+ {
+ if ('\0' == *end)
+ break;
+ else if ('(' == *end)
+ ++ level;
+ else if (')' == *end)
+ -- level;
+ }
+ *end = '\0';
+ return strdup(start);
+}
+
static void parseFunction (const char *cp, vString *const def,
vString *const parent, int is_class_parent)
{
+ char *arglist;
+
cp = parseIdentifier (cp, def);
- makeFunctionTag (def, parent, is_class_parent);
+ arglist = parseArglist (cp);
+ makeFunctionTag (def, parent, is_class_parent, arglist);
+ eFree (arglist);
}
/* Get the combined name of a nested symbol. Classes are separated with ".",
@@ -295,13 +352,16 @@ static boolean constructParentString(NestingLevels *nls, int indent,
break;
if (prev)
{
- if (prev->is_class)
+ vStringCatS(result, "."); /* make Geany symbol list grouping work properly */
+/*
+ if (prev->type == K_CLASS)
vStringCatS(result, ".");
else
vStringCatS(result, "/");
+*/
}
vStringCat(result, nl->name);
- is_class = nl->is_class;
+ is_class = (nl->type == K_CLASS);
prev = nl;
}
return is_class;
@@ -331,27 +391,8 @@ static void checkParent(NestingLevels *nls, int indent, vString *parent)
}
}
-static NestingLevels *newNestingLevels(void)
-{
- NestingLevels *nls = xCalloc (1, NestingLevels);
- return nls;
-}
-
-static void freeNestingLevels(NestingLevels *nls)
-{
- int i;
- for (i = 0; i < nls->allocated; i++)
- vStringDelete(nls->levels[i].name);
- if (nls->levels) eFree(nls->levels);
- eFree(nls);
-}
-
-/* TODO: This is totally out of place in python.c, but strlist.h is not usable.
- * Maybe should just move these three functions to a separate file, even if no
- * other parser uses them.
- */
static void addNestingLevel(NestingLevels *nls, int indentation,
- vString *name, boolean is_class)
+ const vString *name, boolean is_class)
{
int i;
NestingLevel *nl = NULL;
@@ -363,20 +404,16 @@ static void addNestingLevel(NestingLevels *nls, int indentation,
}
if (i == nls->n)
{
- if (i >= nls->allocated)
- {
- nls->allocated++;
- nls->levels = xRealloc(nls->levels,
- nls->allocated, NestingLevel);
- nls->levels[i].name = vStringNew();
- }
+ nestingLevelsPush(nls, name, 0);
nl = nls->levels + i;
}
- nls->n = i + 1;
-
- vStringCopy(nl->name, name);
+ else
+ { /* reuse existing slot */
+ nls->n = i + 1;
+ vStringCopy(nl->name, name);
+ }
nl->indentation = indentation;
- nl->is_class = is_class;
+ nl->type = is_class ? K_CLASS : !K_CLASS;
}
/* Return a pointer to the start of the next triple string, or NULL. Store
@@ -467,18 +504,18 @@ static const char *findVariable(const char *line)
}
/* Skip type declaration that optionally follows a cdef/cpdef */
-static const char *skipTypeDecl (const char *cp, boolean *is_class)
-{
+static const char *skipTypeDecl (const char *cp, boolean *is_class)
+{
const char *lastStart = cp, *ptr = cp;
int loopCount = 0;
ptr = skipSpace(cp);
- if (!strncmp("extern", ptr, 6)) {
- ptr += 6;
- ptr = skipSpace(ptr);
+ if (!strncmp("extern", ptr, 6)) {
+ ptr += 6;
+ ptr = skipSpace(ptr);
if (!strncmp("from", ptr, 4)) { return NULL; }
}
if (!strncmp("class", ptr, 5)) {
- ptr += 5 ;
+ ptr += 5 ;
*is_class = TRUE;
ptr = skipSpace(ptr);
return ptr;
@@ -489,7 +526,7 @@ static const char *skipTypeDecl (const char *cp, boolean *is_class)
if (!*ptr || *ptr == '=') return NULL;
if (*ptr == '(') {
return lastStart; /* if we stopped on a '(' we are done */
- }
+ }
ptr = skipSpace(ptr);
lastStart = ptr;
while (*lastStart == '*') lastStart++; /* cdef int *identifier */
@@ -503,7 +540,7 @@ static void findPythonTags (void)
vString *const name = vStringNew ();
vString *const parent = vStringNew();
- NestingLevels *const nesting_levels = newNestingLevels();
+ NestingLevels *const nesting_levels = nestingLevelsNew();
const char *line;
int line_skip = 0;
@@ -540,7 +577,7 @@ static void findPythonTags (void)
cp = skipSpace (cp);
indent = cp - line;
line_skip = 0;
-
+
checkParent(nesting_levels, indent, parent);
/* Deal with multiline string ending. */
@@ -549,7 +586,7 @@ static void findPythonTags (void)
find_triple_end(cp, &longStringLiteral);
continue;
}
-
+
/* Deal with multiline string start. */
longstring = find_triple_start(cp, &longStringLiteral);
if (longstring)
@@ -578,7 +615,7 @@ static void findPythonTags (void)
is_class = TRUE;
}
else if (!strncmp (keyword, "cdef ", 5))
- {
+ {
cp = skipSpace(keyword + 4);
candidate = skipTypeDecl (cp, &is_class);
if (candidate)
@@ -589,7 +626,7 @@ static void findPythonTags (void)
}
else if (!strncmp (keyword, "cpdef ", 6))
- {
+ {
cp = skipSpace(keyword + 5);
candidate = skipTypeDecl (cp, &is_class);
if (candidate)
@@ -636,12 +673,14 @@ static void findPythonTags (void)
makeVariableTag (name, parent);
}
+ /* Find and parse imports */
+ parseImports(line);
}
/* Clean up all memory we allocated. */
vStringDelete (parent);
vStringDelete (name);
vStringDelete (continuation);
- freeNestingLevels (nesting_levels);
+ nestingLevelsFree (nesting_levels);
}
extern parserDefinition *PythonParser (void)
View
4 source.mak
@@ -5,7 +5,7 @@
HEADERS = \
args.h ctags.h debug.h entry.h general.h get.h keyword.h \
main.h options.h parse.h parsers.h read.h routines.h sort.h \
- strlist.h vstring.h
+ strlist.h vstring.h nestlevel.h
SOURCES = \
args.c \
@@ -33,6 +33,7 @@ SOURCES = \
main.c \
make.c \
matlab.c \
+ nestlevel.c \
options.c \
parse.c \
pascal.c \
@@ -94,6 +95,7 @@ OBJECTS = \
main.$(OBJEXT) \
make.$(OBJEXT) \
matlab.$(OBJEXT) \
+ nestlevel.$(OBJEXT) \
options.$(OBJEXT) \
parse.$(OBJEXT) \
pascal.$(OBJEXT) \
View
4 testing.mak
@@ -5,8 +5,8 @@
# Development makefile for Exuberant Ctags, used to build releases.
# Requires GNU make.
-CTAGS_TEST = ctags
-CTAGS_REF = ctags.ref
+CTAGS_TEST = ./ctags
+CTAGS_REF = ./ctags.ref
TEST_OPTIONS = -nu --c-kinds=+lpx
DIFF_OPTIONS = -U 0 -I '^!_TAG'
Please sign in to comment.
Something went wrong with that request. Please try again.