static void parseFunctionOrMethod (tokenInfo *const token) { // FunctionDecl = "func" identifier Signature [ Body ] . // Body = Block. // // MethodDecl = "func" Receiver MethodName Signature [ Body ] . // Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" . // BaseTypeName = identifier . // Skip over receiver. readToken (token); if (isType (token, TOKEN_OPEN_PAREN)) skipToMatched (token); if (isType (token, TOKEN_IDENTIFIER)) { vString *argList; tokenInfo *functionToken = copyToken (token); // Start recording signature signature = vStringNew (); // Skip over parameters. readToken (token); skipToMatchedNoRead (token); vStringStripLeading (signature); vStringStripTrailing (signature); argList = signature; signature = vStringNew (); readToken (token); // Skip over result. skipType (token); // Remove the extra { we have just read vStringStripTrailing (signature); vStringChop (signature); vStringStripLeading (signature); vStringStripTrailing (signature); makeTag (functionToken, GOTAG_FUNCTION, NULL, GOTAG_UNDEFINED, argList->buffer, signature->buffer); deleteToken (functionToken); vStringDelete(signature); vStringDelete(argList); // Stop recording signature signature = NULL; // Skip over function body. if (isType (token, TOKEN_OPEN_CURLY)) skipToMatched (token); } }
static void appendText (vString *text, vString *appendedText) { if (text != NULL && vStringLength (appendedText) > 0) { if (vStringLength (text) > 0 && vStringLast (text) == ' ' && vStringLength (appendedText) > 0 && vStringChar (appendedText, 0) == ' ') { vStringStripTrailing (text); } vStringCat (text, appendedText); } }
static void matchTagPattern (const vString* const line, const regexPattern* const patbuf, const regmatch_t* const pmatch) { vString *const name = substitute (vStringValue (line), patbuf->u.tag.name_pattern, BACK_REFERENCE_COUNT, pmatch); vStringStripLeading (name); vStringStripTrailing (name); if (vStringLength (name) > 0) makeRegexTag (name, &patbuf->u.tag.kind); else error (WARNING, "%s:%ld: null expansion of name pattern \"%s\"", getInputFileName (), getInputLineNumber (), patbuf->u.tag.name_pattern); vStringDelete (name); }
static boolean loadPathKind (xcmdPath *const path, char* line, char *args[]) { const char* backup = line; char* off; vString *desc; kindOption *kind; if (line[0] == '\0') return FALSE; else if (!isblank(line[1])) { error (WARNING, "[%s] a space after letter is not found in kind description line: %s", args[0], backup); return FALSE; } path->kinds = xRealloc (path->kinds, path->n_kinds + 1, kindOption); kind = &path->kinds [path->n_kinds]; memset (kind, 0, sizeof (*kind)); kind->enabled = TRUE; kind->letter = line[0]; kind->name = NULL; kind->description = NULL; kind->referenceOnly = FALSE; kind->nRoles = 0; kind->roles = NULL; verbose (" kind letter: <%c>\n", kind->letter); for (line++; isblank(*line); line++) ; /* do nothing */ if (*line == '\0') { error (WARNING, "[%s] unexpectedly a kind description line is terminated: %s", args[0], backup); return FALSE; } Assert (!isblank (*line)); off = strrstr(line, "[off]"); if (off == line) { error (WARNING, "[%s] [off] is given but no kind description is found: %s", args[0], backup); return FALSE; } else if (off) { if (!isblank (*(off - 1))) { error (WARNING, "[%s] a whitespace must precede [off] flag: %s", args[0], backup); return FALSE; } kind->enabled = FALSE; *off = '\0'; } desc = vStringNewInit (line); vStringStripTrailing (desc); Assert (vStringLength (desc) > 0); kind->description = vStringDeleteUnwrap (desc); /* TODO: This conversion should be part of protocol. */ { char *tmp = eStrdup (kind->description); char *c; for (c = tmp; *c != '\0'; c++) { if (*c == ' ' || *c == '\t') *c = '_'; } kind->name = tmp; } path->n_kinds += 1; return TRUE; }
static void findMakeTags (void) { stringList *identifiers = stringListNew (); boolean newline = TRUE; boolean in_define = FALSE; boolean in_rule = FALSE; boolean variable_possible = TRUE; int c; while ((c = nextChar ()) != EOF) { if (newline) { if (in_rule) { if (c == '\t' || (c = skipToNonWhite (c)) == '#') { skipLine (); /* skip rule or comment */ c = nextChar (); } else if (c != '\n') in_rule = FALSE; } stringListClear (identifiers); variable_possible = (boolean)(!in_rule); newline = FALSE; } if (c == '\n') newline = TRUE; else if (isspace (c)) continue; else if (c == '#') skipLine (); else if (variable_possible && c == '?') { c = nextChar (); ungetcToInputFile (c); variable_possible = (c == '='); } else if (variable_possible && c == ':' && stringListCount (identifiers) > 0) { c = nextChar (); ungetcToInputFile (c); if (c != '=') { unsigned int i; for (i = 0; i < stringListCount (identifiers); i++) newTarget (stringListItem (identifiers, i)); stringListClear (identifiers); in_rule = TRUE; } } else if (variable_possible && c == '=' && stringListCount (identifiers) == 1) { newMacro (stringListItem (identifiers, 0)); skipLine (); in_rule = FALSE; } else if (variable_possible && isIdentifier (c)) { vString *name = vStringNew (); readIdentifier (c, name); stringListAdd (identifiers, name); if (stringListCount (identifiers) == 1) { if (in_define && ! strcmp (vStringValue (name), "endef")) in_define = FALSE; else if (in_define) skipLine (); else if (! strcmp (vStringValue (name), "define")) { in_define = TRUE; c = skipToNonWhite (nextChar ()); vStringClear (name); /* all remaining characters on the line are the name -- even spaces */ while (c != EOF && c != '\n') { vStringPut (name, c); c = nextChar (); } if (c == '\n') ungetcToInputFile (c); vStringTerminate (name); vStringStripTrailing (name); newMacro (name); } else if (! strcmp (vStringValue (name), "export")) stringListClear (identifiers); else if (! strcmp (vStringValue (name), "include") || ! strcmp (vStringValue (name), "sinclude") || ! strcmp (vStringValue (name), "-include")) { boolean optional = (vStringValue (name)[0] == 'i')? FALSE: TRUE; while (1) { c = skipToNonWhite (nextChar ()); readIdentifier (c, name); vStringStripTrailing (name); if (isAcceptableAsInclude(name)) newInclude (name, optional); /* non-space characters after readIdentifier() may * be rejected by the function: * e.g. * include $* * * Here, remove such characters from input stream. */ do c = nextChar (); while (c != EOF && c != '\n' && (!isspace (c))); if (c == '\n') ungetcToInputFile (c); if (c == EOF || c == '\n') break; } } } } else variable_possible = FALSE; } stringListDelete (identifiers); }
static void findMakeTags (void) { stringList *identifiers = stringListNew (); boolean newline = TRUE; boolean in_define = FALSE; boolean in_rule = FALSE; boolean variable_possible = TRUE; int c; while ((c = nextChar ()) != EOF) { if (newline) { if (in_rule) { if (c == '\t' || (c = skipToNonWhite (c)) == '#') { skipLine (); /* skip rule or comment */ c = nextChar (); } else if (c != '\n') in_rule = FALSE; } stringListClear (identifiers); variable_possible = (boolean)(!in_rule); newline = FALSE; } if (c == '\n') newline = TRUE; else if (isspace (c)) continue; else if (c == '#') skipLine (); else if (variable_possible && c == '?') { c = nextChar (); fileUngetc (c); variable_possible = (c == '='); } else if (variable_possible && c == ':' && stringListCount (identifiers) > 0) { c = nextChar (); fileUngetc (c); if (c != '=') { unsigned int i; for (i = 0; i < stringListCount (identifiers); i++) newTarget (stringListItem (identifiers, i)); stringListClear (identifiers); in_rule = TRUE; } } else if (variable_possible && c == '=' && stringListCount (identifiers) == 1) { newMacro (stringListItem (identifiers, 0)); skipLine (); in_rule = FALSE; } else if (variable_possible && isIdentifier (c)) { vString *name = vStringNew (); readIdentifier (c, name); stringListAdd (identifiers, name); if (stringListCount (identifiers) == 1) { if (in_define && ! strcmp (vStringValue (name), "endef")) in_define = FALSE; else if (in_define) skipLine (); else if (! strcmp (vStringValue (name), "define")) { in_define = TRUE; c = skipToNonWhite (nextChar ()); vStringClear (name); /* all remaining characters on the line are the name -- even spaces */ while (c != EOF && c != '\n') { vStringPut (name, c); c = nextChar (); } if (c == '\n') fileUngetc (c); vStringTerminate (name); vStringStripTrailing (name); newMacro (name); } else if (! strcmp (vStringValue (name), "export")) stringListClear (identifiers); } } else variable_possible = FALSE; } stringListDelete (identifiers); }
/* Function format: * "fn" <ident>[<type_bounds>] "(" [<args>] ")" ["->" <ret_type>] "{" [<body>] "}"*/ static void parseFn (lexerState *lexer, vString *scope, int parent_kind) { int kind = (parent_kind == K_TRAIT || parent_kind == K_IMPL) ? K_METHOD : K_FN; vString *name; vString *arg_list; unsigned long line; fpos_t pos; int paren_level = 0; boolean found_paren = FALSE; boolean valid_signature = TRUE; advanceToken(lexer, TRUE); if (lexer->cur_token != TOKEN_IDENT) return; name = vStringNewCopy(lexer->token_str); arg_list = vStringNew(); line = lexer->line; pos = lexer->pos; advanceToken(lexer, TRUE); /* HACK: This is a bit coarse as far as what tag entry means by * 'arglist'... */ while (lexer->cur_token != '{' && lexer->cur_token != ';') { if (lexer->cur_token == '}') { valid_signature = FALSE; break; } else if (lexer->cur_token == '(') { found_paren = TRUE; paren_level++; } else if (lexer->cur_token == ')') { paren_level--; if (paren_level < 0) { valid_signature = FALSE; break; } } else if (lexer->cur_token == TOKEN_EOF) { valid_signature = FALSE; break; } writeCurTokenToStr(lexer, arg_list); advanceToken(lexer, FALSE); } if (!found_paren || paren_level != 0) valid_signature = FALSE; if (valid_signature) { vStringStripTrailing(arg_list); addTag(name, arg_list->buffer, kind, line, pos, scope, parent_kind); addToScope(scope, name); parseBlock(lexer, TRUE, kind, scope); } vStringDelete(name); vStringDelete(arg_list); }
static void findConfTags (void) { vString *name = vStringNew (); vString *scope = vStringNew (); const unsigned char *line; while ((line = fileReadLine ()) != NULL) { const unsigned char* cp = line; boolean possible = TRUE; if (isspace ((int) *cp) || *cp == '#' || (*cp != '\0' && *cp == '/' && *(cp+1) == '/')) continue; /* look for a section */ if (*cp != '\0' && *cp == '[') { ++cp; while (*cp != '\0' && *cp != ']') { vStringPut (name, (int) *cp); ++cp; } vStringTerminate (name); makeSimpleTag (name, ConfKinds, K_SECTION); /* remember section name */ vStringCopy (scope, name); vStringTerminate (scope); vStringClear (name); continue; } while (*cp != '\0') { /* We look for any sequence of identifier characters following a white space */ if (possible && isIdentifier ((int) *cp)) { while (isIdentifier ((int) *cp)) { vStringPut (name, (int) *cp); ++cp; } vStringTerminate (name); vStringStripTrailing (name); while (isspace ((int) *cp)) ++cp; if (*cp == '=') { if (vStringLength (scope) > 0) makeSimpleScopedTag (name, ConfKinds, K_KEY, "section", vStringValue(scope), NULL); else makeSimpleTag (name, ConfKinds, K_KEY); } vStringClear (name); } else if (isspace ((int) *cp)) possible = TRUE; else possible = FALSE; if (*cp != '\0') ++cp; } } vStringDelete (name); vStringDelete (scope); }
static void readTag (tokenInfo *token, vString *text, int depth) { bool textCreated = false; readToken (token, true); if (token->type == TOKEN_NAME) { keywordId startTag; bool isHeading; bool isVoid; startTag = lookupKeyword (vStringValue (token->string), Lang_html); isHeading = (startTag == KEYWORD_h1 || startTag == KEYWORD_h2 || startTag == KEYWORD_h3); isVoid = (startTag >= KEYWORD_area && startTag <= KEYWORD_wbr); if (text == NULL && isHeading) { text = vStringNew (); textCreated = true; } do { readToken (token, true); if (startTag == KEYWORD_a && token->type == TOKEN_NAME) { keywordId attribute = lookupKeyword (vStringValue (token->string), Lang_html); if (attribute == KEYWORD_name) { readToken (token, true); if (token->type == TOKEN_EQUAL) { readToken (token, true); if (token->type == TOKEN_STRING || token->type == TOKEN_NAME) makeSimpleTag (token->string, HtmlKinds, K_ANCHOR); } } } } while (token->type != TOKEN_TAG_END && token->type != TOKEN_TAG_END2 && token->type != TOKEN_EOF); if (!isVoid && token->type == TOKEN_TAG_END && depth < MAX_DEPTH) { long startSourceLineNumber = getSourceLineNumber (); long startLineNumber = getInputLineNumber (); long startLineOffset = getInputLineOffset (); long endLineNumber; long endLineOffset; bool tag_start2; if (startTag == KEYWORD_script) { bool script = skipScriptContent (token, &endLineNumber, &endLineOffset); if (script) makePromise ("JavaScript", startLineNumber, startLineOffset, endLineNumber, endLineOffset, startSourceLineNumber); readToken (token, true); goto out; } tag_start2 = readTagContent (token, text, &endLineNumber, &endLineOffset, depth); if (tag_start2) { readToken (token, true); if (isHeading && textCreated && vStringLength (text) > 0) { keywordId endTag = lookupKeyword (vStringValue (token->string), Lang_html); if (startTag == endTag) { htmlKind headingKind; if (startTag == KEYWORD_h1) headingKind = K_HEADING1; else if (startTag == KEYWORD_h2) headingKind = K_HEADING2; else headingKind = K_HEADING3; vStringStripTrailing (text); makeSimpleTag (text, HtmlKinds, headingKind); } } else if (startTag == KEYWORD_style) { keywordId endTag = lookupKeyword (vStringValue (token->string), Lang_html); if (startTag == endTag) makePromise ("CSS", startLineNumber, startLineOffset, endLineNumber, endLineOffset, startSourceLineNumber); } readToken (token, true); } } } out: if (textCreated) vStringDelete (text); }
static void makeResTag(vString *name, ResKind kind) { vStringStripTrailing(name); makeSimpleTag(name, ResKinds, kind); vStringClear(name); }