Skip to content

Commit ea6c7e1

Browse files
committed
Ruby: provide an interface for subparsers
Signed-off-by: Masatake YAMATO <[email protected]>
1 parent 6f0c51d commit ea6c7e1

File tree

5 files changed

+131
-3
lines changed

5 files changed

+131
-3
lines changed

parsers/ruby.c

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
#include "read.h"
2626
#include "routines.h"
2727
#include "strlist.h"
28+
#include "subparser.h"
2829
#include "vstring.h"
2930

31+
#include "ruby.h"
32+
3033
/*
3134
* DATA DECLARATIONS
3235
*/
@@ -82,6 +85,8 @@ static fieldDefinition RubyFields[] = {
8285

8386
struct blockData {
8487
stringList *mixin;
88+
rubySubparser *subparser;
89+
int subparserCorkIndex;
8590
};
8691

8792
static NestingLevels* nesting = NULL;
@@ -205,7 +210,8 @@ static bool advanceWhile (const unsigned char** s, bool (*predicate) (int))
205210
return *s != original_pos;
206211
}
207212

208-
static bool canMatchKeyword (const unsigned char** s, const char* literal)
213+
#define canMatchKeyword rubyCanMatchKeyword
214+
extern bool rubyCanMatchKeyword (const unsigned char** s, const char* literal)
209215
{
210216
return canMatch (s, literal, notIdentChar);
211217
}
@@ -214,7 +220,8 @@ static bool canMatchKeyword (const unsigned char** s, const char* literal)
214220
* Extends canMatch. Works similarly, but allows assignment to precede
215221
* the keyword, as block assignment is a common Ruby idiom.
216222
*/
217-
static bool canMatchKeywordWithAssign (const unsigned char** s, const char* literal)
223+
#define canMatchKeywordWithAssign rubyCanMatchKeywordWithAssign
224+
extern bool rubyCanMatchKeywordWithAssign (const unsigned char** s, const char* literal)
218225
{
219226
const unsigned char* original_pos = *s;
220227

@@ -360,7 +367,8 @@ static bool charIsIn (char ch, const char* list)
360367
}
361368

362369
/* Advances 'cp' over leading whitespace. */
363-
static void skipWhitespace (const unsigned char** cp)
370+
#define skipWhitespace rubySkipWhitespace
371+
extern void rubySkipWhitespace (const unsigned char** cp)
364372
{
365373
while (isspace (**cp))
366374
{
@@ -452,6 +460,16 @@ static rubyKind parseIdentifier (
452460
return kind;
453461
}
454462

463+
extern bool rubyParseMethodName (const unsigned char **cp, vString* vstr)
464+
{
465+
return (parseIdentifier (cp, vstr, K_METHOD) == K_METHOD);
466+
}
467+
468+
extern bool rubyParseModuleName (const unsigned char **cp, vString* vstr)
469+
{
470+
return (parseIdentifier (cp, vstr, K_MODULE) == K_MODULE);
471+
}
472+
455473
static void parseString (const unsigned char** cp, unsigned char boundary, vString* vstr)
456474
{
457475
while (**cp != 0 && **cp != boundary)
@@ -466,6 +484,13 @@ static void parseString (const unsigned char** cp, unsigned char boundary, vStri
466484
++*cp;
467485
}
468486

487+
extern bool rubyParseString (const unsigned char** cp, unsigned char boundary, vString* vstr)
488+
{
489+
const unsigned char *p = *cp;
490+
parseString (cp, boundary, vstr);
491+
return (p != *cp);
492+
}
493+
469494
static void parseSignature (const unsigned char** cp, vString* vstr)
470495
{
471496
int depth = 1;
@@ -646,6 +671,17 @@ static void enterUnnamedScope (void)
646671
nestingLevelsPush (nesting, r);
647672
}
648673

674+
static void parasiteToScope (rubySubparser *subparser, int subparserCorkIndex)
675+
{
676+
NestingLevel *nl = nestingLevelsGetCurrent (nesting);
677+
struct blockData *bdata = nestingLevelGetUserData (nl);
678+
bdata->subparser = subparser;
679+
bdata->subparserCorkIndex = subparserCorkIndex;
680+
681+
if (subparser->enterBlockNotify)
682+
subparser->enterBlockNotify (subparser, subparserCorkIndex);
683+
}
684+
649685
static void attachMixinField (int corkIndex, stringList *mixinSpec)
650686
{
651687
vString *mixinField = stringListItem (mixinSpec, 0);
@@ -672,6 +708,16 @@ static void deleteBlockData (NestingLevel *nl)
672708
if (e && !e->placeholder)
673709
e->extensionFields.endLine = getInputLineNumber ();
674710

711+
tagEntryInfo *sub_e;
712+
if (bdata->subparserCorkIndex != CORK_NIL
713+
&& (sub_e = getEntryInCorkQueue (bdata->subparserCorkIndex)))
714+
{
715+
sub_e->extensionFields.endLine = getInputLineNumber ();
716+
if (bdata->subparser)
717+
bdata->subparser->leaveBlockNotify (bdata->subparser,
718+
bdata->subparserCorkIndex);
719+
}
720+
675721
if (bdata->mixin)
676722
stringListDelete (bdata->mixin);
677723
}
@@ -862,6 +908,33 @@ static int readAndEmitDef (const unsigned char **cp)
862908
return corkIndex;
863909
}
864910

911+
static rubySubparser *notifyLine (const unsigned char **cp)
912+
{
913+
subparser *sub;
914+
rubySubparser *rubysub = NULL;
915+
916+
foreachSubparser (sub, false)
917+
{
918+
rubysub = (rubySubparser *)sub;
919+
rubysub->corkIndex = CORK_NIL;
920+
921+
if (rubysub->lineNotify)
922+
{
923+
enterSubparser(sub);
924+
const unsigned char *base = *cp;
925+
rubysub->corkIndex = rubysub->lineNotify(rubysub, cp);
926+
leaveSubparser();
927+
if (rubysub->corkIndex != CORK_NIL)
928+
break;
929+
*cp = base;
930+
}
931+
}
932+
933+
if (rubysub && rubysub->corkIndex != CORK_NIL)
934+
return rubysub;
935+
return NULL;
936+
}
937+
865938
static void findRubyTags (void)
866939
{
867940
const unsigned char *line;
@@ -882,6 +955,7 @@ static void findRubyTags (void)
882955
*/
883956
while ((line = readLineFromInputFile ()) != NULL)
884957
{
958+
rubySubparser *subparser = CORK_NIL;
885959
const unsigned char *cp = line;
886960
/* if we expect a separator after a while, for, or until statement
887961
* separators are "do", ";" or newline */
@@ -1028,6 +1102,8 @@ static void findRubyTags (void)
10281102
/* TODO: store the method for controlling visibility
10291103
* to the "access:" field of the tag.*/
10301104
}
1105+
else
1106+
subparser = notifyLine(&cp);
10311107

10321108

10331109
while (*cp != '\0')
@@ -1057,7 +1133,11 @@ static void findRubyTags (void)
10571133
else if (canMatchKeyword (&cp, "do"))
10581134
{
10591135
if (! expect_separator)
1136+
{
10601137
enterUnnamedScope ();
1138+
if (subparser && subparser->corkIndex)
1139+
parasiteToScope (subparser, subparser->corkIndex);
1140+
}
10611141
else
10621142
expect_separator = false;
10631143
}

parsers/ruby.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2000-2001, Thaddeus Covert <[email protected]>
3+
* Copyright (c) 2002 Matthias Veit <[email protected]>
4+
* Copyright (c) 2004 Elliott Hughes <[email protected]>
5+
*
6+
* This source code is released for free distribution under the terms of the
7+
* GNU General Public License version 2 or (at your option) any later version.
8+
*
9+
* This module contains functions for generating tags for Ruby language
10+
* files.
11+
*/
12+
13+
#ifndef CTAGS_PARSER_RUBY_H
14+
#define CTAGS_PARSER_RUBY_H
15+
16+
/*
17+
* INCLUDE FILES
18+
*/
19+
#include "general.h" /* must always come first */
20+
21+
#include "subparser.h"
22+
23+
typedef struct sRubySubparser rubySubparser;
24+
25+
struct sRubySubparser {
26+
subparser subparser;
27+
/* Returning other than CORK_NIL means the string is consumed. */
28+
int (* lineNotify) (rubySubparser *s, const unsigned char **cp);
29+
void (* enterBlockNotify) (rubySubparser *s, int corkIndex);
30+
void (* leaveBlockNotify) (rubySubparser *s, int corkIndex);
31+
/* Privately used in Ruby parser side. */
32+
int corkIndex;
33+
};
34+
35+
extern void rubySkipWhitespace (const unsigned char **cp);
36+
extern bool rubyCanMatchKeyword (const unsigned char** s, const char* literal);
37+
extern bool rubyCanMatchKeywordWithAssign (const unsigned char** s, const char* literal);
38+
39+
extern bool rubyParseString (const unsigned char** cp, unsigned char boundary, vString* vstr);
40+
extern bool rubyParseMethodName (const unsigned char **cp, vString* vstr);
41+
extern bool rubyParseModuleName (const unsigned char **cp, vString* vstr);
42+
43+
#endif

source.mak

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ PARSER_HEADS = \
238238
parsers/make.h \
239239
parsers/perl.h \
240240
parsers/r.h \
241+
parsers/ruby.h \
241242
parsers/tcl.h \
242243
parsers/tex.h \
243244
\

win32/ctags_vs2013.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@
448448
<ClInclude Include="..\parsers\make.h" />
449449
<ClInclude Include="..\parsers\perl.h" />
450450
<ClInclude Include="..\parsers\r.h" />
451+
<ClInclude Include="..\parsers\ruby.h" />
451452
<ClInclude Include="..\parsers\tcl.h" />
452453
<ClInclude Include="..\parsers\tex.h" />
453454
<ClInclude Include="resource.h" />

win32/ctags_vs2013.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,9 @@
863863
<ClInclude Include="..\parsers\r.h">
864864
<Filter>Header Files</Filter>
865865
</ClInclude>
866+
<ClInclude Include="..\parsers\ruby.h">
867+
<Filter>Header Files</Filter>
868+
</ClInclude>
866869
<ClInclude Include="..\parsers\tcl.h">
867870
<Filter>Header Files</Filter>
868871
</ClInclude>

0 commit comments

Comments
 (0)