2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
18 #include <folly/Conv.h>
19 #include <folly/Format.h>
21 #include "hphp/util/hash.h"
22 #include "hphp/util/bstring.h"
25 ///////////////////////////////////////////////////////////////////////////////
27 bool ParserBase::IsClosureName(const std::string
&name
) {
28 return name
.size() >= 8 && bstrcaseeq(name
.c_str(), "closure$", 8);
31 bool ParserBase::IsAnonymousClassName(folly::StringPiece name
) {
32 return name
.find('$') != std::string::npos
;
35 const char* ParserBase::labelScopeName(LabelScopeKind kind
) {
37 case LabelScopeKind::Invalid
: break;
38 case LabelScopeKind::LoopSwitch
: return "into loop or switch";
39 case LabelScopeKind::Finally
: return "into finally";
40 case LabelScopeKind::Using
: return "into or across using";
43 always_assert(false && "Invalid LabelScope");
46 std::string
ParserBase::newClosureName(
47 const std::string
&namespaceName
,
48 const std::string
&className
,
49 const std::string
&funcName
) {
50 return newAnonClassName("Closure", namespaceName
, className
, funcName
);
53 std::string
ParserBase::newAnonClassName(
54 const std::string
&prefix
,
55 const std::string
&namespaceName
,
56 const std::string
&className
,
57 const std::string
&funcName
) {
59 auto name
= prefix
+ "$";
60 if (!className
.empty()) {
61 name
+= className
+ "::";
62 } else if (!namespaceName
.empty() &&
63 funcName
.find('\\') == std::string::npos
) {
64 // If className is present, it already includes the namespace. Or
65 // else we may be passed a function name already qualified by
66 // namespace, and in either case we don't want to include the
67 // namespace twice in the mangled class name.
68 name
+= namespaceName
+ "\\";
72 auto const id
= ++m_seenAnonClasses
[name
];
74 // we've seen the same name before, uniquify
75 folly::format(&name
, "#{}", id
);
81 ///////////////////////////////////////////////////////////////////////////////
83 ParserBase::ParserBase(Scanner
&scanner
, const char *fileName
)
84 : m_scanner(scanner
), m_fileName(fileName
) {
85 if (m_fileName
== nullptr) m_fileName
= "";
88 m_labelInfos
.reserve(3);
92 ParserBase::~ParserBase() {
95 std::string
ParserBase::getMessage(bool filename
/* = false */,
96 bool rawPosWhenNoError
/* = false */
98 std::string ret
= m_scanner
.getError();
103 if (!ret
.empty() || rawPosWhenNoError
) {
104 ret
+= getMessage(m_scanner
.getLocation()->r
, filename
);
110 std::string
ParserBase::getMessage(const Location::Range
& loc
,
111 bool filename
/* = false */) const {
112 int line
= loc
.line1
;
113 int column
= loc
.char1
;
114 std::string ret
= "(";
116 ret
+= std::string("File: ") + file() + ", ";
118 ret
+= std::string("Line: ") + folly::to
<std::string
>(line
);
119 ret
+= ", Char: " + folly::to
<std::string
>(column
) + ")";
123 const Location::Range
& ParserBase::getRange() const {
127 ///////////////////////////////////////////////////////////////////////////////
128 // T_FUNCTION related functions
130 void ParserBase::pushFuncLocation() {
131 m_funcLocs
.push_back(getRange());
134 Location::Range
ParserBase::popFuncLocation() {
135 assert(!m_funcLocs
.empty());
136 auto loc
= m_funcLocs
.back();
137 m_funcLocs
.pop_back();
141 void ParserBase::pushClass(bool isXhpClass
) {
142 m_classes
.push_back(isXhpClass
);
145 bool ParserBase::peekClass() {
146 assert(!m_classes
.empty());
147 return m_classes
.back();
150 void ParserBase::popClass() {
151 m_classes
.pop_back();
154 ///////////////////////////////////////////////////////////////////////////////
157 void ParserBase::pushTypeScope() {
158 m_typeScopes
.push_back(m_typeVars
);
162 void ParserBase::popTypeScope() {
163 m_typeScopes
.pop_back();
166 void ParserBase::addTypeVar(const std::string
&name
) {
167 m_typeVars
.insert(name
);
170 bool ParserBase::isTypeVar(const std::string
&name
) {
171 for (TypevarScopeStack::iterator iter
= m_typeScopes
.begin();
172 iter
!= m_typeScopes
.end();
174 if (iter
->find(name
) != iter
->end()) {
181 bool ParserBase::isTypeVarInImmediateScope(const std::string
&name
) {
182 int currentScope
= m_typeScopes
.size() - 1;
183 return m_typeScopes
[currentScope
].find(name
)
184 != m_typeScopes
[currentScope
].end();
187 ///////////////////////////////////////////////////////////////////////////////
188 // checks GOTO label syntax
190 void ParserBase::pushLabelInfo() {
191 m_labelInfos
.emplace_back();
192 pushLabelScope(LabelScopeKind::Invalid
);
195 void ParserBase::pushLabelScope(LabelScopeKind kind
) {
196 assert(!m_labelInfos
.empty());
197 LabelInfo
&info
= m_labelInfos
.back();
198 info
.scopes
.emplace_back(kind
, ++info
.scopeId
);
201 void ParserBase::popLabelScope() {
202 assertx(!m_labelInfos
.empty());
203 assertx(!m_labelInfos
.back().scopes
.empty());
204 m_labelInfos
.back().scopes
.pop_back();
207 void ParserBase::addLabel(const std::string
&label
,
208 const Location::Range
& loc
,
209 ScannerToken
*stmt
) {
210 assert(!m_labelInfos
.empty());
211 LabelInfo
&info
= m_labelInfos
.back();
212 if (info
.labels
.find(label
) != info
.labels
.end()) {
213 error("Label '%s' already defined: %s", label
.c_str(),
214 getMessage().c_str());
217 assert(!info
.scopes
.empty());
218 auto const stmtInfo
= LabelStmtInfo
{
219 extractStatement(stmt
),
224 info
.labels
.emplace(label
, stmtInfo
);
227 void ParserBase::addGoto(const std::string
&label
,
228 const Location::Range
& loc
,
229 ScannerToken
*stmt
) {
230 assert(!m_labelInfos
.empty());
231 LabelInfo
&info
= m_labelInfos
.back();
233 gotoInfo
.label
= label
;
234 gotoInfo
.scopes
= info
.scopes
;
236 gotoInfo
.stmt
= extractStatement(stmt
);
237 info
.gotos
.push_back(gotoInfo
);
240 void ParserBase::popLabelInfo() {
241 assert(!m_labelInfos
.empty());
242 LabelInfo
&info
= m_labelInfos
.back();
243 assertx(info
.scopes
.size() == 1);
244 assertx(info
.scopes
.back().kind
== LabelScopeKind::Invalid
);
246 LabelMap labels
= info
.labels
; // shallow copy
248 for (unsigned int i
= 0; i
< info
.gotos
.size(); i
++) {
249 const GotoInfo
&gotoInfo
= info
.gotos
[i
];
250 LabelMap::const_iterator iter
= info
.labels
.find(gotoInfo
.label
);
251 if (iter
== info
.labels
.end()) {
252 error("'goto' to undefined label '%s': %s",
253 gotoInfo
.label
.c_str(), getMessage(gotoInfo
.loc
).c_str());
256 const LabelStmtInfo
&labelInfo
= iter
->second
;
257 int labelScopeId
= labelInfo
.scopeInfo
.id
;
259 for (int j
= gotoInfo
.scopes
.size() - 1; j
>= 0; j
--) {
260 if (labelScopeId
== gotoInfo
.scopes
[j
].id
) {
266 error("'goto' %s statement is disallowed: %s",
267 labelScopeName(labelInfo
.scopeInfo
.kind
),
268 getMessage(gotoInfo
.loc
).c_str());
271 labels
.erase(gotoInfo
.label
);
275 m_labelInfos
.pop_back();
278 ///////////////////////////////////////////////////////////////////////////////