static void findTxt2tagsTags (void) { NestingLevels *nls = nestingLevelsNew(); vString *name = vStringNew(); const unsigned char *line; while ((line = fileReadLine()) != NULL) { int depth; if (isTxt2tagsLine(line)) ; /* skip not to improperly match titles */ else if (parseTxt2tagsTitle(line, name, &depth)) { NestingLevel *nl = nestingLevelsGetCurrent(nls); while (nl && nl->indentation >= depth) { nestingLevelsPop(nls); nl = nestingLevelsGetCurrent(nls); } vStringTerminate(name); makeTxt2tagsTag(name, nls, K_SECTION); nestingLevelsPush(nls, name, K_SECTION); nestingLevelsGetCurrent(nls)->indentation = depth; } } vStringDelete (name); nestingLevelsFree(nls); }
static NestingLevel *getNestingLevel(const int kind) { NestingLevel *nl; tagEntryInfo *e; int d = 0; if (kind > K_EOF) { d++; /* 1. we want the line before the '---' underline chars */ d++; /* 2. we want the line before the next section/chapter title. */ } while (1) { nl = nestingLevelsGetCurrent(nestingLevels); e = getEntryOfNestingLevel (nl); if ((nl && (e == NULL)) || (e && (e->kind - RstKinds) >= kind)) { if (e) e->extensionFields.endLine = (getInputLineNumber() - d); nestingLevelsPop(nestingLevels); } else break; } return nl; }
extern void nestingLevelsPop(NestingLevels *nls) { const NestingLevel *nl = nestingLevelsGetCurrent(nls); Assert (nl != NULL); vStringClear(nl->name); nls->n--; }
extern void nestingLevelsPop(NestingLevels *nls) { NestingLevel *nl = nestingLevelsGetCurrent(nls); Assert (nl != NULL); nl->corkIndex = CORK_NIL; nls->n--; }
extern NestingLevel *nestingLevelsTruncate(NestingLevels *nls, int depth, int corkIndex) { NestingLevel *nl; nls->n = depth; nl = nestingLevelsGetCurrent(nls); nl->corkIndex = corkIndex; return nl; }
/* * Emits a tag for the given 'name' of kind 'kind' at the current nesting. */ static void emitRubyTag (vString* name, rubyKind kind) { tagEntryInfo tag; vString* scope; tagEntryInfo *parent; rubyKind parent_kind = K_UNDEFINED; NestingLevel *lvl; const char *unqualified_name; const char *qualified_name; int r; if (!RubyKinds[kind].enabled) { return; } vStringTerminate (name); scope = nestingLevelsToScope (nesting); lvl = nestingLevelsGetCurrent (nesting); parent = getEntryOfNestingLevel (lvl); if (parent) parent_kind = parent->kind - RubyKinds; qualified_name = vStringValue (name); unqualified_name = strrchr (qualified_name, SCOPE_SEPARATOR); if (unqualified_name && unqualified_name[1]) { if (unqualified_name > qualified_name) { if (vStringLength (scope) > 0) vStringPut (scope, SCOPE_SEPARATOR); vStringNCatS (scope, qualified_name, unqualified_name - qualified_name); /* assume module parent type for a lack of a better option */ parent_kind = K_MODULE; } unqualified_name++; } else unqualified_name = qualified_name; initTagEntry (&tag, unqualified_name, &(RubyKinds [kind])); if (vStringLength (scope) > 0) { Assert (0 <= parent_kind && (size_t) parent_kind < (ARRAY_SIZE (RubyKinds))); tag.extensionFields.scopeKind = &(RubyKinds [parent_kind]); tag.extensionFields.scopeName = vStringValue (scope); } r = makeTagEntry (&tag); nestingLevelsPush (nesting, r); vStringClear (name); vStringDelete (scope); }
static NestingLevel *getNestingLevel(const int kind) { NestingLevel *nl; while (1) { nl = nestingLevelsGetCurrent(nestingLevels); if (nl && nl->kindIndex >= kind) nestingLevelsPop(nestingLevels); else break; } return nl; }
static void enterUnnamedScope (void) { int r = CORK_NIL; NestingLevel *parent = nestingLevelsGetCurrent (nesting); tagEntryInfo *e_parent = getEntryOfNestingLevel (parent); if (e_parent) { tagEntryInfo e; initTagEntry (&e, "", e_parent->kind); e.placeholder = 1; r = makeTagEntry (&e); } nestingLevelsPush (nesting, r); }
static void initPythonEntry (tagEntryInfo *const e, const tokenInfo *const token, const pythonKind kind) { accessType access; int parentKind = -1; NestingLevel *nl; initTagEntry (e, vStringValue (token->string), kind); e->lineNumber = token->lineNumber; e->filePosition = token->filePosition; nl = nestingLevelsGetCurrent (PythonNestingLevels); if (nl) { tagEntryInfo *nlEntry = getEntryOfNestingLevel (nl); e->extensionFields.scopeIndex = nl->corkIndex; /* nlEntry can be NULL if a kind was disabled. But what can we do * here? Even disabled kinds should count for the hierarchy I * guess -- as it'd otherwise be wrong -- but with cork we're * f****d up as there's nothing to look up. Damn. */ if (nlEntry) { parentKind = nlEntry->kindIndex; /* functions directly inside classes are methods, fix it up */ if (kind == K_FUNCTION && parentKind == K_CLASS) e->kindIndex = K_METHOD; } } access = accessFromIdentifier (token->string, kind, parentKind); e->extensionFields.access = PythonAccesses[access]; /* FIXME: should we really set isFileScope in addition to access? */ if (access == ACCESS_PRIVATE) e->isFileScope = true; }
static void findRubyTags (void) { const unsigned char *line; boolean inMultiLineComment = FALSE; nesting = nestingLevelsNew (0); /* FIXME: this whole scheme is wrong, because Ruby isn't line-based. * You could perfectly well write: * * def * method * puts("hello") * end * * if you wished, and this function would fail to recognize anything. */ while ((line = readLineFromInputFile ()) != NULL) { const unsigned char *cp = line; /* if we expect a separator after a while, for, or until statement * separators are "do", ";" or newline */ boolean expect_separator = FALSE; if (canMatch (&cp, "=begin", isWhitespace)) { inMultiLineComment = TRUE; continue; } if (canMatch (&cp, "=end", isWhitespace)) { inMultiLineComment = FALSE; continue; } if (inMultiLineComment) continue; skipWhitespace (&cp); /* Avoid mistakenly starting a scope for modifiers such as * * return if <exp> * * FIXME: this is fooled by code such as * * result = if <exp> * <a> * else * <b> * end * * FIXME: we're also fooled if someone does something heinous such as * * puts("hello") \ * unless <exp> */ if (canMatchKeyword (&cp, "for") || canMatchKeyword (&cp, "until") || canMatchKeyword (&cp, "while")) { expect_separator = TRUE; enterUnnamedScope (); } else if (canMatchKeyword (&cp, "case") || canMatchKeyword (&cp, "if") || canMatchKeyword (&cp, "unless")) { enterUnnamedScope (); } /* * "module M", "class C" and "def m" should only be at the beginning * of a line. */ if (canMatchKeyword (&cp, "module")) { readAndEmitTag (&cp, K_MODULE); } else if (canMatchKeyword (&cp, "class")) { readAndEmitTag (&cp, K_CLASS); } else if (canMatchKeyword (&cp, "def")) { rubyKind kind = K_METHOD; NestingLevel *nl = nestingLevelsGetCurrent (nesting); tagEntryInfo *e = getEntryOfNestingLevel (nl); /* if the def is inside an unnamed scope at the class level, assume * it's from a singleton from a construct like this: * * class C * class << self * def singleton * ... * end * end * end */ if (e && (e->kind - RubyKinds) == K_CLASS && strlen (e->name) == 0) kind = K_SINGLETON; readAndEmitTag (&cp, kind); } while (*cp != '\0') { /* FIXME: we don't cope with here documents, * or regular expression literals, or ... you get the idea. * Hopefully, the restriction above that insists on seeing * definitions at the starts of lines should keep us out of * mischief. */ if (inMultiLineComment || isspace (*cp)) { ++cp; } else if (*cp == '#') { /* FIXME: this is wrong, but there *probably* won't be a * definition after an interpolated string (where # doesn't * mean 'comment'). */ break; } else if (canMatchKeyword (&cp, "begin")) { enterUnnamedScope (); } else if (canMatchKeyword (&cp, "do")) { if (! expect_separator) enterUnnamedScope (); else expect_separator = FALSE; } else if (canMatchKeyword (&cp, "end") && nesting->n > 0) { /* Leave the most recent scope. */ nestingLevelsPop (nesting); } else if (*cp == '"') { /* Skip string literals. * FIXME: should cope with escapes and interpolation. */ do { ++cp; } while (*cp != 0 && *cp != '"'); if (*cp == '"') cp++; /* skip the last found '"' */ } else if (*cp == ';') { ++cp; expect_separator = FALSE; } else if (*cp != '\0') { do ++cp; while (isIdentChar (*cp)); } } } nestingLevelsFree (nesting); }