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)) { makeTag (token, GOTAG_FUNCTION); // Skip over parameters. readToken (token); skipToMatched (token); // Skip over result. skipType (token); // Skip over function body. if (isType (token, TOKEN_OPEN_CURLY)) skipToMatched (token); } }
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 parseConstTypeVar (tokenInfo *const token, goKind kind) { // ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . // IdentifierList = identifier { "," identifier } . // ExpressionList = Expression { "," Expression } . // TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . // TypeSpec = identifier Type . // VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . boolean usesParens = FALSE; readToken (token); if (isType (token, TOKEN_OPEN_PAREN)) { usesParens = TRUE; readToken (token); } do { while (!isType (token, TOKEN_EOF)) { if (isType (token, TOKEN_IDENTIFIER)) { makeTag (token, kind); readToken (token); } if (!isType (token, TOKEN_COMMA)) break; readToken (token); } skipType (token); while (!isType (token, TOKEN_SEMICOLON) && !isType (token, TOKEN_CLOSE_PAREN) && !isType (token, TOKEN_EOF)) { readToken (token); skipToMatched (token); } if (usesParens && !isType (token, TOKEN_CLOSE_PAREN)) { // we are at TOKEN_SEMICOLON readToken (token); } } while (!isType (token, TOKEN_EOF) && usesParens && !isType (token, TOKEN_CLOSE_PAREN)); }
static void parseGoFile (tokenInfo *const token) { do { readToken (token); if (isType (token, TOKEN_KEYWORD)) { switch (token->keyword) { case KEYWORD_package: parsePackage (token); break; case KEYWORD_func: parseFunctionOrMethod (token); break; case KEYWORD_const: parseConstTypeVar (token, GOTAG_CONST); break; case KEYWORD_type: parseConstTypeVar (token, GOTAG_TYPE); break; case KEYWORD_var: parseConstTypeVar (token, GOTAG_VAR); break; default: break; } } else if (isType (token, TOKEN_OPEN_PAREN) || isType (token, TOKEN_OPEN_CURLY) || isType (token, TOKEN_OPEN_SQUARE)) { skipToMatched (token); } } while (token->type != TOKEN_EOF); }
static void parseSubProgram (tokenInfo * const token) { tokenInfo *const name = newToken (); boolean endSubProgram = FALSE; const vhdlKind kind = isKeyword (token, KEYWORD_FUNCTION) ? VHDLTAG_FUNCTION : VHDLTAG_PROCEDURE; Assert (isKeyword (token, KEYWORD_FUNCTION) || isKeyword (token, KEYWORD_PROCEDURE)); readToken (name); /* the name of the function or procedure */ readToken (token); if (isType (token, TOKEN_OPEN_PAREN)) { skipToMatched (token); } if (kind == VHDLTAG_FUNCTION) { if (isKeyword (token, KEYWORD_RETURN)) { /* Read datatype */ readToken (token); while (! isKeyword (token, KEYWORD_IS) && ! isType (token, TOKEN_SEMICOLON) && ! isType (token, TOKEN_EOF)) { readToken (token); } } } if (isType (token, TOKEN_SEMICOLON)) { makeVhdlTag (name, VHDLTAG_PROTOTYPE); } else if (isKeyword (token, KEYWORD_IS)) { if (kind == VHDLTAG_FUNCTION) { makeVhdlTag (name, VHDLTAG_FUNCTION); do { readToken (token); if (isKeyword (token, KEYWORD_END)) { readToken (token); endSubProgram = isKeywordOrIdent (token, KEYWORD_FUNCTION, name->string); fileSkipToCharacter (';'); } else { if (isType (token, TOKEN_EOF)) { endSubProgram = TRUE; } else { parseKeywords (token, TRUE); } } } while (!endSubProgram); } else { makeVhdlTag (name, VHDLTAG_PROCEDURE); do { readToken (token); if (isKeyword (token, KEYWORD_END)) { readToken (token); endSubProgram = isKeywordOrIdent (token, KEYWORD_PROCEDURE, name->string); fileSkipToCharacter (';'); } else { if (isType (token, TOKEN_EOF)) { endSubProgram = TRUE; } else { parseKeywords (token, TRUE); } } } while (!endSubProgram); } } deleteToken (name); }
static void parseConstTypeVar (tokenInfo *const token, goKind kind) { // ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . // IdentifierList = identifier { "," identifier } . // ExpressionList = Expression { "," Expression } . // TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . // TypeSpec = identifier Type . // VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . boolean usesParens = FALSE; readToken (token); if (isType (token, TOKEN_OPEN_PAREN)) { usesParens = TRUE; readToken (token); } do { tokenInfo *typeToken = NULL; while (!isType (token, TOKEN_EOF)) { if (isType (token, TOKEN_IDENTIFIER)) { if (kind == GOTAG_TYPE) { typeToken = copyToken (token); readToken (token); if (isKeyword (token, KEYWORD_struct)) makeTag (typeToken, GOTAG_STRUCT, NULL, GOTAG_UNDEFINED, NULL); else if (isKeyword (token, KEYWORD_interface)) makeTag (typeToken, GOTAG_INTERFACE, NULL, GOTAG_UNDEFINED, NULL); else makeTag (typeToken, kind, NULL, GOTAG_UNDEFINED, NULL); break; } else makeTag (token, kind, NULL, GOTAG_UNDEFINED, NULL); readToken (token); } if (!isType (token, TOKEN_COMMA)) break; readToken (token); } if (typeToken) { if (isKeyword (token, KEYWORD_struct)) parseStructMembers (token, typeToken); else skipType (token); deleteToken (typeToken); } else skipType (token); while (!isType (token, TOKEN_SEMICOLON) && !isType (token, TOKEN_CLOSE_PAREN) && !isType (token, TOKEN_EOF)) { readToken (token); skipToMatched (token); } if (usesParens && !isType (token, TOKEN_CLOSE_PAREN)) { // we are at TOKEN_SEMICOLON readToken (token); } } while (!isType (token, TOKEN_EOF) && usesParens && !isType (token, TOKEN_CLOSE_PAREN)); }
static void parseStructMembers (tokenInfo *const token, tokenInfo *const parent_token) { // StructType = "struct" "{" { FieldDecl ";" } "}" . // FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] . // AnonymousField = [ "*" ] TypeName . // Tag = string_lit . readToken (token); if (!isType (token, TOKEN_OPEN_CURLY)) return; readToken (token); while (!isType (token, TOKEN_EOF) && !isType (token, TOKEN_CLOSE_CURLY)) { tokenInfo *memberCandidate = NULL; boolean first = TRUE; while (!isType (token, TOKEN_EOF)) { if (isType (token, TOKEN_IDENTIFIER)) { if (first) { // could be anonymous field like in 'struct {int}' - we don't know yet memberCandidate = copyToken (token); first = FALSE; } else { if (memberCandidate) { // if we are here, there was a comma and memberCandidate isn't an anonymous field makeTag (memberCandidate, GOTAG_MEMBER, parent_token, GOTAG_STRUCT, NULL); deleteToken (memberCandidate); memberCandidate = NULL; } makeTag (token, GOTAG_MEMBER, parent_token, GOTAG_STRUCT, NULL); } readToken (token); } if (!isType (token, TOKEN_COMMA)) break; readToken (token); } // in the case of an anonymous field, we already read part of the // type into memberCandidate and skipType() should return FALSE so no tag should // be generated in this case. if (skipType (token) && memberCandidate) makeTag (memberCandidate, GOTAG_MEMBER, parent_token, GOTAG_STRUCT, NULL); if (memberCandidate) deleteToken (memberCandidate); while (!isType (token, TOKEN_SEMICOLON) && !isType (token, TOKEN_CLOSE_CURLY) && !isType (token, TOKEN_EOF)) { readToken (token); skipToMatched (token); } if (!isType (token, TOKEN_CLOSE_CURLY)) { // we are at TOKEN_SEMICOLON readToken (token); } } }
static boolean skipType (tokenInfo *const token) { // Type = TypeName | TypeLit | "(" Type ")" . // Skips also function multiple return values "(" Type {"," Type} ")" if (isType (token, TOKEN_OPEN_PAREN)) { skipToMatched (token); return TRUE; } // TypeName = QualifiedIdent. // QualifiedIdent = [ PackageName "." ] identifier . // PackageName = identifier . if (isType (token, TOKEN_IDENTIFIER)) { readToken (token); if (isType (token, TOKEN_DOT)) { readToken (token); if (isType (token, TOKEN_IDENTIFIER)) readToken (token); } return TRUE; } // StructType = "struct" "{" { FieldDecl ";" } "}" // InterfaceType = "interface" "{" { MethodSpec ";" } "}" . if (isKeyword (token, KEYWORD_struct) || isKeyword (token, KEYWORD_interface)) { readToken (token); // skip over "{}" skipToMatched (token); return TRUE; } // ArrayType = "[" ArrayLength "]" ElementType . // SliceType = "[" "]" ElementType . // ElementType = Type . if (isType (token, TOKEN_OPEN_SQUARE)) { skipToMatched (token); return skipType (token); } // PointerType = "*" BaseType . // BaseType = Type . // ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType . if (isType (token, TOKEN_STAR) || isKeyword (token, KEYWORD_chan) || isType (token, TOKEN_LEFT_ARROW)) { readToken (token); return skipType (token); } // MapType = "map" "[" KeyType "]" ElementType . // KeyType = Type . if (isKeyword (token, KEYWORD_map)) { readToken (token); // skip over "[]" skipToMatched (token); return skipType (token); } // FunctionType = "func" Signature . // Signature = Parameters [ Result ] . // Result = Parameters | Type . // Parameters = "(" [ ParameterList [ "," ] ] ")" . if (isKeyword (token, KEYWORD_func)) { readToken (token); // Parameters, skip over "()" skipToMatched (token); // Result is parameters or type or nothing. skipType treats anything // surrounded by parentheses as a type, and does nothing if what // follows is not a type. return skipType (token); } return FALSE; }