blob: 7d977c1251b056533736b69f4b609a2cb29b31c5 [file] [log] [blame]
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +00001//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements parsing for C++ class inline methods.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Parse/Parser.h"
15#include "clang/Parse/DeclSpec.h"
16#include "clang/Parse/Scope.h"
17using namespace clang;
18
19/// ParseInlineCXXMethodDef - We parsed and verified that the specified
20/// Declarator is a well formed C++ inline method definition. Now lex its body
21/// and store its tokens for parsing after the C++ class is complete.
22Parser::DeclTy *
23Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
24 assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
25 "This isn't a function declarator!");
Douglas Gregor7ad83902008-11-05 04:29:56 +000026 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) &&
27 "Current token not a '{' or ':'!");
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +000028
29 DeclTy *FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0, 0);
30
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +000031 // Consume the tokens and store them for later parsing.
32
33 getCurTopClassStack().push(LexedMethod(FnD));
34 TokensTy &Toks = getCurTopClassStack().top().Toks;
35
Douglas Gregor7ad83902008-11-05 04:29:56 +000036 // We may have a constructor initializer here.
37 if (Tok.is(tok::colon)) {
38 // Consume everything up to (and including) the left brace.
39 ConsumeAndStoreUntil(tok::l_brace, Toks);
40 } else {
41 // Begin by storing the '{' token.
42 Toks.push_back(Tok);
43 ConsumeBrace();
44 }
45 // Consume everything up to (and including) the matching right brace.
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +000046 ConsumeAndStoreUntil(tok::r_brace, Toks);
47
48 return FnD;
49}
50
51/// ParseLexedMethodDefs - We finished parsing the member specification of a top
52/// (non-nested) C++ class. Now go over the stack of lexed methods that were
53/// collected during its parsing and parse them all.
54void Parser::ParseLexedMethodDefs() {
55 while (!getCurTopClassStack().empty()) {
56 LexedMethod &LM = getCurTopClassStack().top();
57
58 assert(!LM.Toks.empty() && "Empty body!");
59 // Append the current token at the end of the new token stream so that it
60 // doesn't get lost.
61 LM.Toks.push_back(Tok);
62 PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false);
63
64 // Consume the previously pushed token.
65 ConsumeAnyToken();
Douglas Gregor7ad83902008-11-05 04:29:56 +000066 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) &&
67 "Inline method not starting with '{' or ':'");
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +000068
69 // Parse the method body. Function body parsing code is similar enough
70 // to be re-used for method bodies as well.
71 EnterScope(Scope::FnScope|Scope::DeclScope);
72 Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
73
Douglas Gregor7ad83902008-11-05 04:29:56 +000074 if (Tok.is(tok::colon))
75 ParseConstructorInitializer(LM.D);
76
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +000077 ParseFunctionStatementBody(LM.D, Tok.getLocation(), Tok.getLocation());
78
79 getCurTopClassStack().pop();
80 }
81}
82
83/// ConsumeAndStoreUntil - Consume and store the token at the passed token
84/// container until the token 'T' is reached (which gets consumed/stored too).
85/// Returns true if token 'T' was found.
86/// NOTE: This is a specialized version of Parser::SkipUntil.
87bool Parser::ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks) {
88 // We always want this function to consume at least one token if the first
89 // token isn't T and if not at EOF.
90 bool isFirstTokenConsumed = true;
91 while (1) {
92 // If we found one of the tokens, stop and return true.
93 if (Tok.is(T)) {
94 Toks.push_back(Tok);
95 ConsumeAnyToken();
96 return true;
97 }
98
99 switch (Tok.getKind()) {
100 case tok::eof:
101 // Ran out of tokens.
102 return false;
103
104 case tok::l_paren:
105 // Recursively consume properly-nested parens.
106 Toks.push_back(Tok);
107 ConsumeParen();
108 ConsumeAndStoreUntil(tok::r_paren, Toks);
109 break;
110 case tok::l_square:
111 // Recursively consume properly-nested square brackets.
112 Toks.push_back(Tok);
113 ConsumeBracket();
114 ConsumeAndStoreUntil(tok::r_square, Toks);
115 break;
116 case tok::l_brace:
117 // Recursively consume properly-nested braces.
118 Toks.push_back(Tok);
119 ConsumeBrace();
120 ConsumeAndStoreUntil(tok::r_brace, Toks);
121 break;
122
123 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
124 // Since the user wasn't looking for this token (if they were, it would
125 // already be handled), this isn't balanced. If there is a LHS token at a
126 // higher level, we will assume that this matches the unbalanced token
127 // and return it. Otherwise, this is a spurious RHS token, which we skip.
128 case tok::r_paren:
129 if (ParenCount && !isFirstTokenConsumed)
130 return false; // Matches something.
131 Toks.push_back(Tok);
132 ConsumeParen();
133 break;
134 case tok::r_square:
135 if (BracketCount && !isFirstTokenConsumed)
136 return false; // Matches something.
137 Toks.push_back(Tok);
138 ConsumeBracket();
139 break;
140 case tok::r_brace:
141 if (BraceCount && !isFirstTokenConsumed)
142 return false; // Matches something.
143 Toks.push_back(Tok);
144 ConsumeBrace();
145 break;
146
147 case tok::string_literal:
148 case tok::wide_string_literal:
149 Toks.push_back(Tok);
150 ConsumeStringToken();
151 break;
152 default:
153 // consume this token.
154 Toks.push_back(Tok);
155 ConsumeToken();
156 break;
157 }
158 isFirstTokenConsumed = false;
159 }
160}