ctags.rb 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -0
- data/Rakefile +23 -0
- data/ctags.rb.gemspec +23 -0
- data/ext/.gitignore +3 -0
- data/ext/extconf.rb +15 -0
- data/ext/vendor/exuberant-ctags/.gitignore +6 -0
- data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
- data/ext/vendor/exuberant-ctags/COPYING +340 -0
- data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
- data/ext/vendor/exuberant-ctags/FAQ +371 -0
- data/ext/vendor/exuberant-ctags/INSTALL +215 -0
- data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
- data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
- data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
- data/ext/vendor/exuberant-ctags/NEWS +871 -0
- data/ext/vendor/exuberant-ctags/README +73 -0
- data/ext/vendor/exuberant-ctags/ant.c +42 -0
- data/ext/vendor/exuberant-ctags/argproc.c +505 -0
- data/ext/vendor/exuberant-ctags/args.c +274 -0
- data/ext/vendor/exuberant-ctags/args.h +63 -0
- data/ext/vendor/exuberant-ctags/asm.c +387 -0
- data/ext/vendor/exuberant-ctags/asp.c +328 -0
- data/ext/vendor/exuberant-ctags/awk.c +81 -0
- data/ext/vendor/exuberant-ctags/basic.c +203 -0
- data/ext/vendor/exuberant-ctags/beta.c +321 -0
- data/ext/vendor/exuberant-ctags/c.c +2932 -0
- data/ext/vendor/exuberant-ctags/cobol.c +50 -0
- data/ext/vendor/exuberant-ctags/config.h.in +277 -0
- data/ext/vendor/exuberant-ctags/configure +7704 -0
- data/ext/vendor/exuberant-ctags/configure.ac +532 -0
- data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
- data/ext/vendor/exuberant-ctags/ctags.h +28 -0
- data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
- data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
- data/ext/vendor/exuberant-ctags/debug.c +113 -0
- data/ext/vendor/exuberant-ctags/debug.h +70 -0
- data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
- data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
- data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
- data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
- data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
- data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
- data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
- data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
- data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
- data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
- data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
- data/ext/vendor/exuberant-ctags/entry.c +847 -0
- data/ext/vendor/exuberant-ctags/entry.h +103 -0
- data/ext/vendor/exuberant-ctags/erlang.c +189 -0
- data/ext/vendor/exuberant-ctags/flex.c +2243 -0
- data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
- data/ext/vendor/exuberant-ctags/general.h +127 -0
- data/ext/vendor/exuberant-ctags/get.c +669 -0
- data/ext/vendor/exuberant-ctags/get.h +50 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
- data/ext/vendor/exuberant-ctags/html.c +49 -0
- data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
- data/ext/vendor/exuberant-ctags/keyword.c +258 -0
- data/ext/vendor/exuberant-ctags/keyword.h +34 -0
- data/ext/vendor/exuberant-ctags/lisp.c +139 -0
- data/ext/vendor/exuberant-ctags/lregex.c +704 -0
- data/ext/vendor/exuberant-ctags/lua.c +133 -0
- data/ext/vendor/exuberant-ctags/mac.c +273 -0
- data/ext/vendor/exuberant-ctags/magic.diff +21 -0
- data/ext/vendor/exuberant-ctags/main.c +584 -0
- data/ext/vendor/exuberant-ctags/main.h +32 -0
- data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
- data/ext/vendor/exuberant-ctags/make.c +217 -0
- data/ext/vendor/exuberant-ctags/matlab.c +44 -0
- data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
- data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
- data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
- data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
- data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
- data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
- data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
- data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
- data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
- data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
- data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
- data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.h +155 -0
- data/ext/vendor/exuberant-ctags/parse.c +677 -0
- data/ext/vendor/exuberant-ctags/parse.h +129 -0
- data/ext/vendor/exuberant-ctags/parsers.h +63 -0
- data/ext/vendor/exuberant-ctags/pascal.c +267 -0
- data/ext/vendor/exuberant-ctags/perl.c +382 -0
- data/ext/vendor/exuberant-ctags/php.c +237 -0
- data/ext/vendor/exuberant-ctags/python.c +771 -0
- data/ext/vendor/exuberant-ctags/qdos.c +106 -0
- data/ext/vendor/exuberant-ctags/read.c +569 -0
- data/ext/vendor/exuberant-ctags/read.h +116 -0
- data/ext/vendor/exuberant-ctags/readtags.c +959 -0
- data/ext/vendor/exuberant-ctags/readtags.h +252 -0
- data/ext/vendor/exuberant-ctags/rexx.c +39 -0
- data/ext/vendor/exuberant-ctags/routines.c +891 -0
- data/ext/vendor/exuberant-ctags/routines.h +134 -0
- data/ext/vendor/exuberant-ctags/ruby.c +408 -0
- data/ext/vendor/exuberant-ctags/scheme.c +111 -0
- data/ext/vendor/exuberant-ctags/sh.c +115 -0
- data/ext/vendor/exuberant-ctags/slang.c +41 -0
- data/ext/vendor/exuberant-ctags/sml.c +212 -0
- data/ext/vendor/exuberant-ctags/sort.c +230 -0
- data/ext/vendor/exuberant-ctags/sort.h +32 -0
- data/ext/vendor/exuberant-ctags/source.mak +122 -0
- data/ext/vendor/exuberant-ctags/sql.c +2112 -0
- data/ext/vendor/exuberant-ctags/strlist.c +281 -0
- data/ext/vendor/exuberant-ctags/strlist.h +54 -0
- data/ext/vendor/exuberant-ctags/tcl.c +116 -0
- data/ext/vendor/exuberant-ctags/tex.c +524 -0
- data/ext/vendor/exuberant-ctags/verilog.c +340 -0
- data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
- data/ext/vendor/exuberant-ctags/vim.c +636 -0
- data/ext/vendor/exuberant-ctags/vstring.c +232 -0
- data/ext/vendor/exuberant-ctags/vstring.h +85 -0
- data/ext/vendor/exuberant-ctags/yacc.c +40 -0
- data/lib/ctags/exuberant.rb +45 -0
- data/lib/ctags/version.rb +3 -0
- data/lib/ctags.rb +6 -0
- data/test/test_ctags.rb +24 -0
- metadata +233 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* $Id: routines.h 536 2007-06-02 06:09:00Z elliotth $
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2002, Darren Hiebert
|
|
5
|
+
*
|
|
6
|
+
* This source code is released for free distribution under the terms of the
|
|
7
|
+
* GNU General Public License.
|
|
8
|
+
*
|
|
9
|
+
* External interface to routines.c
|
|
10
|
+
*/
|
|
11
|
+
#ifndef _ROUTINES_H
|
|
12
|
+
#define _ROUTINES_H
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* INCLUDE FILES
|
|
16
|
+
*/
|
|
17
|
+
#include "general.h" /* must always come first */
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
* MACROS
|
|
21
|
+
*/
|
|
22
|
+
#define xMalloc(n,Type) (Type *)eMalloc((size_t)(n) * sizeof (Type))
|
|
23
|
+
#define xCalloc(n,Type) (Type *)eCalloc((size_t)(n), sizeof (Type))
|
|
24
|
+
#define xRealloc(p,n,Type) (Type *)eRealloc((p), (n) * sizeof (Type))
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* Portability macros
|
|
28
|
+
*/
|
|
29
|
+
#ifndef PATH_SEPARATOR
|
|
30
|
+
# if defined (MSDOS_STYLE_PATH)
|
|
31
|
+
# define PATH_SEPARATOR '\\'
|
|
32
|
+
# elif defined (QDOS)
|
|
33
|
+
# define PATH_SEPARATOR '_'
|
|
34
|
+
# else
|
|
35
|
+
# define PATH_SEPARATOR '/'
|
|
36
|
+
# endif
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
#if defined (MSDOS_STYLE_PATH) && defined (UNIX_PATH_SEPARATOR)
|
|
40
|
+
# define OUTPUT_PATH_SEPARATOR '/'
|
|
41
|
+
#else
|
|
42
|
+
# define OUTPUT_PATH_SEPARATOR PATH_SEPARATOR
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* DATA DECLARATIONS
|
|
47
|
+
*/
|
|
48
|
+
#if defined (MSDOS_STYLE_PATH) || defined (VMS)
|
|
49
|
+
extern const char *const PathDelimiters;
|
|
50
|
+
#endif
|
|
51
|
+
extern char *CurrentDirectory;
|
|
52
|
+
typedef int errorSelection;
|
|
53
|
+
enum eErrorTypes { FATAL = 1, WARNING = 2, PERROR = 4 };
|
|
54
|
+
|
|
55
|
+
typedef struct {
|
|
56
|
+
/* Name of file for which status is valid */
|
|
57
|
+
char* name;
|
|
58
|
+
|
|
59
|
+
/* Does file exist? If not, members below do not contain valid data. */
|
|
60
|
+
boolean exists;
|
|
61
|
+
|
|
62
|
+
/* is file path a symbolic link to another file? */
|
|
63
|
+
boolean isSymbolicLink;
|
|
64
|
+
|
|
65
|
+
/* Is file (pointed to) a directory? */
|
|
66
|
+
boolean isDirectory;
|
|
67
|
+
|
|
68
|
+
/* Is file (pointed to) a normal file? */
|
|
69
|
+
boolean isNormalFile;
|
|
70
|
+
|
|
71
|
+
/* Is file (pointed to) executable? */
|
|
72
|
+
boolean isExecutable;
|
|
73
|
+
|
|
74
|
+
/* Is file (pointed to) setuid? */
|
|
75
|
+
boolean isSetuid;
|
|
76
|
+
|
|
77
|
+
/* Size of file (pointed to) */
|
|
78
|
+
unsigned long size;
|
|
79
|
+
} fileStatus;
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* FUNCTION PROTOTYPES
|
|
83
|
+
*/
|
|
84
|
+
extern void freeRoutineResources (void);
|
|
85
|
+
extern void setExecutableName (const char *const path);
|
|
86
|
+
extern const char *getExecutableName (void);
|
|
87
|
+
extern const char *getExecutablePath (void);
|
|
88
|
+
extern void error (const errorSelection selection, const char *const format, ...) __printf__ (2, 3);
|
|
89
|
+
|
|
90
|
+
/* Memory allocation functions */
|
|
91
|
+
#ifdef NEED_PROTO_MALLOC
|
|
92
|
+
extern void *malloc (size_t);
|
|
93
|
+
extern void *realloc (void *ptr, size_t);
|
|
94
|
+
#endif
|
|
95
|
+
extern void *eMalloc (const size_t size);
|
|
96
|
+
extern void *eCalloc (const size_t count, const size_t size);
|
|
97
|
+
extern void *eRealloc (void *const ptr, const size_t size);
|
|
98
|
+
extern void eFree (void *const ptr);
|
|
99
|
+
|
|
100
|
+
/* String manipulation functions */
|
|
101
|
+
extern int struppercmp (const char *s1, const char *s2);
|
|
102
|
+
extern int strnuppercmp (const char *s1, const char *s2, size_t n);
|
|
103
|
+
#ifndef HAVE_STRSTR
|
|
104
|
+
extern char* strstr (const char *str, const char *substr);
|
|
105
|
+
#endif
|
|
106
|
+
extern char* eStrdup (const char* str);
|
|
107
|
+
extern void toLowerString (char* str);
|
|
108
|
+
extern void toUpperString (char* str);
|
|
109
|
+
extern char* newLowerString (const char* str);
|
|
110
|
+
extern char* newUpperString (const char* str);
|
|
111
|
+
|
|
112
|
+
/* File system functions */
|
|
113
|
+
extern void setCurrentDirectory (void);
|
|
114
|
+
extern fileStatus *eStat (const char *const fileName);
|
|
115
|
+
extern void eStatFree (fileStatus *status);
|
|
116
|
+
extern boolean doesFileExist (const char *const fileName);
|
|
117
|
+
extern boolean isRecursiveLink (const char* const dirName);
|
|
118
|
+
extern boolean isSameFile (const char *const name1, const char *const name2);
|
|
119
|
+
#if defined(NEED_PROTO_FGETPOS)
|
|
120
|
+
extern int fgetpos (FILE *stream, fpos_t *pos);
|
|
121
|
+
extern int fsetpos (FILE *stream, fpos_t *pos);
|
|
122
|
+
#endif
|
|
123
|
+
extern const char *baseFilename (const char *const filePath);
|
|
124
|
+
extern const char *fileExtension (const char *const fileName);
|
|
125
|
+
extern boolean isAbsolutePath (const char *const path);
|
|
126
|
+
extern vString *combinePathAndFile (const char *const path, const char *const file);
|
|
127
|
+
extern char* absoluteFilename (const char *file);
|
|
128
|
+
extern char* absoluteDirname (char *file);
|
|
129
|
+
extern char* relativeFilename (const char *file, const char *dir);
|
|
130
|
+
extern FILE *tempFile (const char *const mode, char **const pName);
|
|
131
|
+
|
|
132
|
+
#endif /* _ROUTINES_H */
|
|
133
|
+
|
|
134
|
+
/* vi:set tabstop=4 shiftwidth=4: */
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* $Id: ruby.c 571 2007-06-24 23:32:14Z elliotth $
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2000-2001, Thaddeus Covert <sahuagin@mediaone.net>
|
|
5
|
+
* Copyright (c) 2002 Matthias Veit <matthias_veit@yahoo.de>
|
|
6
|
+
* Copyright (c) 2004 Elliott Hughes <enh@acm.org>
|
|
7
|
+
*
|
|
8
|
+
* This source code is released for free distribution under the terms of the
|
|
9
|
+
* GNU General Public License.
|
|
10
|
+
*
|
|
11
|
+
* This module contains functions for generating tags for Ruby language
|
|
12
|
+
* files.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* INCLUDE FILES
|
|
17
|
+
*/
|
|
18
|
+
#include "general.h" /* must always come first */
|
|
19
|
+
|
|
20
|
+
#include <string.h>
|
|
21
|
+
|
|
22
|
+
#include "entry.h"
|
|
23
|
+
#include "parse.h"
|
|
24
|
+
#include "read.h"
|
|
25
|
+
#include "vstring.h"
|
|
26
|
+
|
|
27
|
+
/*
|
|
28
|
+
* DATA DECLARATIONS
|
|
29
|
+
*/
|
|
30
|
+
typedef enum {
|
|
31
|
+
K_UNDEFINED = -1, K_CLASS, K_METHOD, K_MODULE, K_SINGLETON
|
|
32
|
+
} rubyKind;
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* DATA DEFINITIONS
|
|
36
|
+
*/
|
|
37
|
+
static kindOption RubyKinds [] = {
|
|
38
|
+
{ TRUE, 'c', "class", "classes" },
|
|
39
|
+
{ TRUE, 'f', "method", "methods" },
|
|
40
|
+
{ TRUE, 'm', "module", "modules" },
|
|
41
|
+
{ TRUE, 'F', "singleton method", "singleton methods" }
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
static stringList* nesting = 0;
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* FUNCTION DEFINITIONS
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/*
|
|
51
|
+
* Returns a string describing the scope in 'list'.
|
|
52
|
+
* We record the current scope as a list of entered scopes.
|
|
53
|
+
* Scopes corresponding to 'if' statements and the like are
|
|
54
|
+
* represented by empty strings. Scopes corresponding to
|
|
55
|
+
* modules and classes are represented by the name of the
|
|
56
|
+
* module or class.
|
|
57
|
+
*/
|
|
58
|
+
static vString* stringListToScope (const stringList* list)
|
|
59
|
+
{
|
|
60
|
+
unsigned int i;
|
|
61
|
+
unsigned int chunks_output = 0;
|
|
62
|
+
vString* result = vStringNew ();
|
|
63
|
+
const unsigned int max = stringListCount (list);
|
|
64
|
+
for (i = 0; i < max; ++i)
|
|
65
|
+
{
|
|
66
|
+
vString* chunk = stringListItem (list, i);
|
|
67
|
+
if (vStringLength (chunk) > 0)
|
|
68
|
+
{
|
|
69
|
+
vStringCatS (result, (chunks_output++ > 0) ? "." : "");
|
|
70
|
+
vStringCatS (result, vStringValue (chunk));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* Attempts to advance 's' past 'literal'.
|
|
78
|
+
* Returns TRUE if it did, FALSE (and leaves 's' where
|
|
79
|
+
* it was) otherwise.
|
|
80
|
+
*/
|
|
81
|
+
static boolean canMatch (const unsigned char** s, const char* literal)
|
|
82
|
+
{
|
|
83
|
+
const int literal_length = strlen (literal);
|
|
84
|
+
const unsigned char next_char = *(*s + literal_length);
|
|
85
|
+
if (strncmp ((const char*) *s, literal, literal_length) != 0)
|
|
86
|
+
{
|
|
87
|
+
return FALSE;
|
|
88
|
+
}
|
|
89
|
+
/* Additionally check that we're at the end of a token. */
|
|
90
|
+
if ( ! (next_char == 0 || isspace (next_char) || next_char == '('))
|
|
91
|
+
{
|
|
92
|
+
return FALSE;
|
|
93
|
+
}
|
|
94
|
+
*s += literal_length;
|
|
95
|
+
return TRUE;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* Attempts to advance 'cp' past a Ruby operator method name. Returns
|
|
100
|
+
* TRUE if successful (and copies the name into 'name'), FALSE otherwise.
|
|
101
|
+
*/
|
|
102
|
+
static boolean parseRubyOperator (vString* name, const unsigned char** cp)
|
|
103
|
+
{
|
|
104
|
+
static const char* RUBY_OPERATORS[] = {
|
|
105
|
+
"[]", "[]=",
|
|
106
|
+
"**",
|
|
107
|
+
"!", "~", "+@", "-@",
|
|
108
|
+
"*", "/", "%",
|
|
109
|
+
"+", "-",
|
|
110
|
+
">>", "<<",
|
|
111
|
+
"&",
|
|
112
|
+
"^", "|",
|
|
113
|
+
"<=", "<", ">", ">=",
|
|
114
|
+
"<=>", "==", "===", "!=", "=~", "!~",
|
|
115
|
+
"`",
|
|
116
|
+
0
|
|
117
|
+
};
|
|
118
|
+
int i;
|
|
119
|
+
for (i = 0; RUBY_OPERATORS[i] != 0; ++i)
|
|
120
|
+
{
|
|
121
|
+
if (canMatch (cp, RUBY_OPERATORS[i]))
|
|
122
|
+
{
|
|
123
|
+
vStringCatS (name, RUBY_OPERATORS[i]);
|
|
124
|
+
return TRUE;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return FALSE;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/*
|
|
131
|
+
* Emits a tag for the given 'name' of kind 'kind' at the current nesting.
|
|
132
|
+
*/
|
|
133
|
+
static void emitRubyTag (vString* name, rubyKind kind)
|
|
134
|
+
{
|
|
135
|
+
tagEntryInfo tag;
|
|
136
|
+
vString* scope;
|
|
137
|
+
|
|
138
|
+
vStringTerminate (name);
|
|
139
|
+
scope = stringListToScope (nesting);
|
|
140
|
+
|
|
141
|
+
initTagEntry (&tag, vStringValue (name));
|
|
142
|
+
if (vStringLength (scope) > 0) {
|
|
143
|
+
tag.extensionFields.scope [0] = "class";
|
|
144
|
+
tag.extensionFields.scope [1] = vStringValue (scope);
|
|
145
|
+
}
|
|
146
|
+
tag.kindName = RubyKinds [kind].name;
|
|
147
|
+
tag.kind = RubyKinds [kind].letter;
|
|
148
|
+
makeTagEntry (&tag);
|
|
149
|
+
|
|
150
|
+
stringListAdd (nesting, vStringNewCopy (name));
|
|
151
|
+
|
|
152
|
+
vStringClear (name);
|
|
153
|
+
vStringDelete (scope);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Tests whether 'ch' is a character in 'list'. */
|
|
157
|
+
static boolean charIsIn (char ch, const char* list)
|
|
158
|
+
{
|
|
159
|
+
return (strchr (list, ch) != 0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Advances 'cp' over leading whitespace. */
|
|
163
|
+
static void skipWhitespace (const unsigned char** cp)
|
|
164
|
+
{
|
|
165
|
+
while (isspace (**cp))
|
|
166
|
+
{
|
|
167
|
+
++*cp;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/*
|
|
172
|
+
* Copies the characters forming an identifier from *cp into
|
|
173
|
+
* name, leaving *cp pointing to the character after the identifier.
|
|
174
|
+
*/
|
|
175
|
+
static rubyKind parseIdentifier (
|
|
176
|
+
const unsigned char** cp, vString* name, rubyKind kind)
|
|
177
|
+
{
|
|
178
|
+
/* Method names are slightly different to class and variable names.
|
|
179
|
+
* A method name may optionally end with a question mark, exclamation
|
|
180
|
+
* point or equals sign. These are all part of the name.
|
|
181
|
+
* A method name may also contain a period if it's a singleton method.
|
|
182
|
+
*/
|
|
183
|
+
const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_";
|
|
184
|
+
|
|
185
|
+
skipWhitespace (cp);
|
|
186
|
+
|
|
187
|
+
/* Check for an anonymous (singleton) class such as "class << HTTP". */
|
|
188
|
+
if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<')
|
|
189
|
+
{
|
|
190
|
+
return K_UNDEFINED;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* Check for operators such as "def []=(key, val)". */
|
|
194
|
+
if (kind == K_METHOD || kind == K_SINGLETON)
|
|
195
|
+
{
|
|
196
|
+
if (parseRubyOperator (name, cp))
|
|
197
|
+
{
|
|
198
|
+
return kind;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Copy the identifier into 'name'. */
|
|
203
|
+
while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok)))
|
|
204
|
+
{
|
|
205
|
+
char last_char = **cp;
|
|
206
|
+
|
|
207
|
+
vStringPut (name, last_char);
|
|
208
|
+
++*cp;
|
|
209
|
+
|
|
210
|
+
if (kind == K_METHOD)
|
|
211
|
+
{
|
|
212
|
+
/* Recognize singleton methods. */
|
|
213
|
+
if (last_char == '.')
|
|
214
|
+
{
|
|
215
|
+
vStringTerminate (name);
|
|
216
|
+
vStringClear (name);
|
|
217
|
+
return parseIdentifier (cp, name, K_SINGLETON);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Recognize characters which mark the end of a method name. */
|
|
221
|
+
if (charIsIn (last_char, "?!="))
|
|
222
|
+
{
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return kind;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind)
|
|
231
|
+
{
|
|
232
|
+
if (isspace (**cp))
|
|
233
|
+
{
|
|
234
|
+
vString *name = vStringNew ();
|
|
235
|
+
rubyKind actual_kind = parseIdentifier (cp, name, expected_kind);
|
|
236
|
+
|
|
237
|
+
if (actual_kind == K_UNDEFINED || vStringLength (name) == 0)
|
|
238
|
+
{
|
|
239
|
+
/*
|
|
240
|
+
* What kind of tags should we create for code like this?
|
|
241
|
+
*
|
|
242
|
+
* %w(self.clfloor clfloor).each do |name|
|
|
243
|
+
* module_eval <<-"end;"
|
|
244
|
+
* def #{name}(x, y=1)
|
|
245
|
+
* q, r = x.divmod(y)
|
|
246
|
+
* q = q.to_i
|
|
247
|
+
* return q, r
|
|
248
|
+
* end
|
|
249
|
+
* end;
|
|
250
|
+
* end
|
|
251
|
+
*
|
|
252
|
+
* Or this?
|
|
253
|
+
*
|
|
254
|
+
* class << HTTP
|
|
255
|
+
*
|
|
256
|
+
* For now, we don't create any.
|
|
257
|
+
*/
|
|
258
|
+
}
|
|
259
|
+
else
|
|
260
|
+
{
|
|
261
|
+
emitRubyTag (name, actual_kind);
|
|
262
|
+
}
|
|
263
|
+
vStringDelete (name);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static void enterUnnamedScope (void)
|
|
268
|
+
{
|
|
269
|
+
stringListAdd (nesting, vStringNewInit (""));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
static void findRubyTags (void)
|
|
273
|
+
{
|
|
274
|
+
const unsigned char *line;
|
|
275
|
+
boolean inMultiLineComment = FALSE;
|
|
276
|
+
|
|
277
|
+
nesting = stringListNew ();
|
|
278
|
+
|
|
279
|
+
/* FIXME: this whole scheme is wrong, because Ruby isn't line-based.
|
|
280
|
+
* You could perfectly well write:
|
|
281
|
+
*
|
|
282
|
+
* def
|
|
283
|
+
* method
|
|
284
|
+
* puts("hello")
|
|
285
|
+
* end
|
|
286
|
+
*
|
|
287
|
+
* if you wished, and this function would fail to recognize anything.
|
|
288
|
+
*/
|
|
289
|
+
while ((line = fileReadLine ()) != NULL)
|
|
290
|
+
{
|
|
291
|
+
const unsigned char *cp = line;
|
|
292
|
+
|
|
293
|
+
if (canMatch (&cp, "=begin"))
|
|
294
|
+
{
|
|
295
|
+
inMultiLineComment = TRUE;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (canMatch (&cp, "=end"))
|
|
299
|
+
{
|
|
300
|
+
inMultiLineComment = FALSE;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
skipWhitespace (&cp);
|
|
305
|
+
|
|
306
|
+
/* Avoid mistakenly starting a scope for modifiers such as
|
|
307
|
+
*
|
|
308
|
+
* return if <exp>
|
|
309
|
+
*
|
|
310
|
+
* FIXME: this is fooled by code such as
|
|
311
|
+
*
|
|
312
|
+
* result = if <exp>
|
|
313
|
+
* <a>
|
|
314
|
+
* else
|
|
315
|
+
* <b>
|
|
316
|
+
* end
|
|
317
|
+
*
|
|
318
|
+
* FIXME: we're also fooled if someone does something heinous such as
|
|
319
|
+
*
|
|
320
|
+
* puts("hello") \
|
|
321
|
+
* unless <exp>
|
|
322
|
+
*/
|
|
323
|
+
if (canMatch (&cp, "case") || canMatch (&cp, "for") ||
|
|
324
|
+
canMatch (&cp, "if") || canMatch (&cp, "unless") ||
|
|
325
|
+
canMatch (&cp, "while"))
|
|
326
|
+
{
|
|
327
|
+
enterUnnamedScope ();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/*
|
|
331
|
+
* "module M", "class C" and "def m" should only be at the beginning
|
|
332
|
+
* of a line.
|
|
333
|
+
*/
|
|
334
|
+
if (canMatch (&cp, "module"))
|
|
335
|
+
{
|
|
336
|
+
readAndEmitTag (&cp, K_MODULE);
|
|
337
|
+
}
|
|
338
|
+
else if (canMatch (&cp, "class"))
|
|
339
|
+
{
|
|
340
|
+
readAndEmitTag (&cp, K_CLASS);
|
|
341
|
+
}
|
|
342
|
+
else if (canMatch (&cp, "def"))
|
|
343
|
+
{
|
|
344
|
+
readAndEmitTag (&cp, K_METHOD);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
while (*cp != '\0')
|
|
348
|
+
{
|
|
349
|
+
/* FIXME: we don't cope with here documents,
|
|
350
|
+
* or regular expression literals, or ... you get the idea.
|
|
351
|
+
* Hopefully, the restriction above that insists on seeing
|
|
352
|
+
* definitions at the starts of lines should keep us out of
|
|
353
|
+
* mischief.
|
|
354
|
+
*/
|
|
355
|
+
if (inMultiLineComment || isspace (*cp))
|
|
356
|
+
{
|
|
357
|
+
++cp;
|
|
358
|
+
}
|
|
359
|
+
else if (*cp == '#')
|
|
360
|
+
{
|
|
361
|
+
/* FIXME: this is wrong, but there *probably* won't be a
|
|
362
|
+
* definition after an interpolated string (where # doesn't
|
|
363
|
+
* mean 'comment').
|
|
364
|
+
*/
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
else if (canMatch (&cp, "begin") || canMatch (&cp, "do"))
|
|
368
|
+
{
|
|
369
|
+
enterUnnamedScope ();
|
|
370
|
+
}
|
|
371
|
+
else if (canMatch (&cp, "end") && stringListCount (nesting) > 0)
|
|
372
|
+
{
|
|
373
|
+
/* Leave the most recent scope. */
|
|
374
|
+
vStringDelete (stringListLast (nesting));
|
|
375
|
+
stringListRemoveLast (nesting);
|
|
376
|
+
}
|
|
377
|
+
else if (*cp == '"')
|
|
378
|
+
{
|
|
379
|
+
/* Skip string literals.
|
|
380
|
+
* FIXME: should cope with escapes and interpolation.
|
|
381
|
+
*/
|
|
382
|
+
do {
|
|
383
|
+
++cp;
|
|
384
|
+
} while (*cp != 0 && *cp != '"');
|
|
385
|
+
}
|
|
386
|
+
else if (*cp != '\0')
|
|
387
|
+
{
|
|
388
|
+
do
|
|
389
|
+
++cp;
|
|
390
|
+
while (isalnum (*cp) || *cp == '_');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
stringListDelete (nesting);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
extern parserDefinition* RubyParser (void)
|
|
398
|
+
{
|
|
399
|
+
static const char *const extensions [] = { "rb", "ruby", NULL };
|
|
400
|
+
parserDefinition* def = parserNew ("Ruby");
|
|
401
|
+
def->kinds = RubyKinds;
|
|
402
|
+
def->kindCount = KIND_COUNT (RubyKinds);
|
|
403
|
+
def->extensions = extensions;
|
|
404
|
+
def->parser = findRubyTags;
|
|
405
|
+
return def;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/* vi:set tabstop=4 shiftwidth=4: */
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* $Id: scheme.c 443 2006-05-30 04:37:13Z darren $
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2000-2002, Darren Hiebert
|
|
5
|
+
*
|
|
6
|
+
* This source code is released for free distribution under the terms of the
|
|
7
|
+
* GNU General Public License.
|
|
8
|
+
*
|
|
9
|
+
* This module contains functions for generating tags for Scheme language
|
|
10
|
+
* files.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* INCLUDE FILES
|
|
15
|
+
*/
|
|
16
|
+
#include "general.h" /* must always come first */
|
|
17
|
+
|
|
18
|
+
#include <string.h>
|
|
19
|
+
|
|
20
|
+
#include "parse.h"
|
|
21
|
+
#include "read.h"
|
|
22
|
+
#include "vstring.h"
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* DATA DEFINITIONS
|
|
26
|
+
*/
|
|
27
|
+
typedef enum {
|
|
28
|
+
K_FUNCTION, K_SET
|
|
29
|
+
} schemeKind;
|
|
30
|
+
|
|
31
|
+
static kindOption SchemeKinds [] = {
|
|
32
|
+
{ TRUE, 'f', "function", "functions" },
|
|
33
|
+
{ TRUE, 's', "set", "sets" }
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* FUNCTION DEFINITIONS
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/* Algorithm adapted from from GNU etags.
|
|
41
|
+
* Scheme tag functions
|
|
42
|
+
* look for (def... xyzzy
|
|
43
|
+
* look for (def... (xyzzy
|
|
44
|
+
* look for (def ... ((... (xyzzy ....
|
|
45
|
+
* look for (set! xyzzy
|
|
46
|
+
*/
|
|
47
|
+
static void readIdentifier (vString *const name, const unsigned char *cp)
|
|
48
|
+
{
|
|
49
|
+
const unsigned char *p;
|
|
50
|
+
vStringClear (name);
|
|
51
|
+
/* Go till you get to white space or a syntactic break */
|
|
52
|
+
for (p = cp; *p != '\0' && *p != '(' && *p != ')' && !isspace (*p); p++)
|
|
53
|
+
vStringPut (name, (int) *p);
|
|
54
|
+
vStringTerminate (name);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static void findSchemeTags (void)
|
|
58
|
+
{
|
|
59
|
+
vString *name = vStringNew ();
|
|
60
|
+
const unsigned char *line;
|
|
61
|
+
|
|
62
|
+
while ((line = fileReadLine ()) != NULL)
|
|
63
|
+
{
|
|
64
|
+
const unsigned char *cp = line;
|
|
65
|
+
|
|
66
|
+
if (cp [0] == '(' &&
|
|
67
|
+
(cp [1] == 'D' || cp [1] == 'd') &&
|
|
68
|
+
(cp [2] == 'E' || cp [2] == 'e') &&
|
|
69
|
+
(cp [3] == 'F' || cp [3] == 'f'))
|
|
70
|
+
{
|
|
71
|
+
while (!isspace (*cp))
|
|
72
|
+
cp++;
|
|
73
|
+
/* Skip over open parens and white space */
|
|
74
|
+
while (*cp != '\0' && (isspace (*cp) || *cp == '('))
|
|
75
|
+
cp++;
|
|
76
|
+
readIdentifier (name, cp);
|
|
77
|
+
makeSimpleTag (name, SchemeKinds, K_FUNCTION);
|
|
78
|
+
}
|
|
79
|
+
if (cp [0] == '(' &&
|
|
80
|
+
(cp [1] == 'S' || cp [1] == 's') &&
|
|
81
|
+
(cp [2] == 'E' || cp [2] == 'e') &&
|
|
82
|
+
(cp [3] == 'T' || cp [3] == 't') &&
|
|
83
|
+
(cp [4] == '!' || cp [4] == '!') &&
|
|
84
|
+
(isspace (cp [5])))
|
|
85
|
+
{
|
|
86
|
+
while (*cp != '\0' && !isspace (*cp))
|
|
87
|
+
cp++;
|
|
88
|
+
/* Skip over white space */
|
|
89
|
+
while (isspace (*cp))
|
|
90
|
+
cp++;
|
|
91
|
+
readIdentifier (name, cp);
|
|
92
|
+
makeSimpleTag (name, SchemeKinds, K_SET);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
vStringDelete (name);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
extern parserDefinition* SchemeParser (void)
|
|
99
|
+
{
|
|
100
|
+
static const char *const extensions [] = {
|
|
101
|
+
"SCM", "SM", "sch", "scheme", "scm", "sm", NULL
|
|
102
|
+
};
|
|
103
|
+
parserDefinition* def = parserNew ("Scheme");
|
|
104
|
+
def->kinds = SchemeKinds;
|
|
105
|
+
def->kindCount = KIND_COUNT (SchemeKinds);
|
|
106
|
+
def->extensions = extensions;
|
|
107
|
+
def->parser = findSchemeTags;
|
|
108
|
+
return def;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* vi:set tabstop=4 shiftwidth=4: */
|