/src/solidity/liblangutil/ParserBase.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** |
19 | | * @author Christian <c@ethdev.com> |
20 | | * @date 2016 |
21 | | * Solidity parser shared functionality. |
22 | | */ |
23 | | |
24 | | #include <liblangutil/ParserBase.h> |
25 | | #include <liblangutil/Scanner.h> |
26 | | #include <liblangutil/ErrorReporter.h> |
27 | | |
28 | | using namespace std; |
29 | | using namespace solidity; |
30 | | using namespace solidity::langutil; |
31 | | |
32 | | SourceLocation ParserBase::currentLocation() const |
33 | 4.90M | { |
34 | 4.90M | return m_scanner->currentLocation(); |
35 | 4.90M | } |
36 | | |
37 | | Token ParserBase::currentToken() const |
38 | 6.59M | { |
39 | 6.59M | return m_scanner->currentToken(); |
40 | 6.59M | } |
41 | | |
42 | | Token ParserBase::peekNextToken() const |
43 | 0 | { |
44 | 0 | return m_scanner->peekNextToken(); |
45 | 0 | } |
46 | | |
47 | | string ParserBase::currentLiteral() const |
48 | 1.90M | { |
49 | 1.90M | return m_scanner->currentLiteral(); |
50 | 1.90M | } |
51 | | |
52 | | Token ParserBase::advance() |
53 | 4.80M | { |
54 | 4.80M | return m_scanner->next(); |
55 | 4.80M | } |
56 | | |
57 | | string ParserBase::tokenName(Token _token) |
58 | 1.83k | { |
59 | 1.83k | if (_token == Token::Identifier) |
60 | 409 | return "identifier"; |
61 | 1.42k | else if (_token == Token::EOS) |
62 | 10 | return "end of source"; |
63 | 1.41k | else if (TokenTraits::isReservedKeyword(_token)) |
64 | 2 | return "reserved keyword '" + TokenTraits::friendlyName(_token) + "'"; |
65 | 1.41k | else if (TokenTraits::isElementaryTypeName(_token)) //for the sake of accuracy in reporting |
66 | 12 | { |
67 | 12 | ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken(); |
68 | 12 | return "'" + elemTypeName.toString() + "'"; |
69 | 12 | } |
70 | 1.39k | else |
71 | 1.39k | return "'" + TokenTraits::friendlyName(_token) + "'"; |
72 | 1.83k | } |
73 | | |
74 | | void ParserBase::expectToken(Token _value, bool _advance) |
75 | 2.96M | { |
76 | 2.96M | Token tok = m_scanner->currentToken(); |
77 | 2.96M | if (tok != _value) |
78 | 916 | { |
79 | 916 | string const expectedToken = ParserBase::tokenName(_value); |
80 | 916 | if (m_parserErrorRecovery) |
81 | 0 | parserError(6635_error, "Expected " + expectedToken + " but got " + tokenName(tok)); |
82 | 916 | else |
83 | 916 | fatalParserError(2314_error, "Expected " + expectedToken + " but got " + tokenName(tok)); |
84 | | // Do not advance so that recovery can sync or make use of the current token. |
85 | | // This is especially useful if the expected token |
86 | | // is the only one that is missing and is at the end of a construct. |
87 | | // "{ ... ; }" is such an example. |
88 | | // ^ |
89 | 916 | _advance = false; |
90 | 916 | } |
91 | 2.96M | if (_advance) |
92 | 2.87M | advance(); |
93 | 2.96M | } |
94 | | |
95 | | void ParserBase::expectTokenOrConsumeUntil(Token _value, string const& _currentNodeName, bool _advance) |
96 | 0 | { |
97 | 0 | solAssert(m_inParserRecovery, "The function is supposed to be called during parser recovery only."); |
98 | | |
99 | 0 | Token tok = m_scanner->currentToken(); |
100 | 0 | if (tok != _value) |
101 | 0 | { |
102 | 0 | SourceLocation errorLoc = currentLocation(); |
103 | 0 | int startPosition = errorLoc.start; |
104 | 0 | while (m_scanner->currentToken() != _value && m_scanner->currentToken() != Token::EOS) |
105 | 0 | advance(); |
106 | |
|
107 | 0 | string const expectedToken = ParserBase::tokenName(_value); |
108 | 0 | if (m_scanner->currentToken() == Token::EOS) |
109 | 0 | { |
110 | | // rollback to where the token started, and raise exception to be caught at a higher level. |
111 | 0 | m_scanner->setPosition(static_cast<size_t>(startPosition)); |
112 | 0 | string const msg = "In " + _currentNodeName + ", " + expectedToken + "is expected; got " + ParserBase::tokenName(tok) + " instead."; |
113 | 0 | fatalParserError(1957_error, errorLoc, msg); |
114 | 0 | } |
115 | 0 | else |
116 | 0 | { |
117 | 0 | parserWarning(3796_error, "Recovered in " + _currentNodeName + " at " + expectedToken + "."); |
118 | 0 | m_inParserRecovery = false; |
119 | 0 | } |
120 | 0 | } |
121 | 0 | else |
122 | 0 | { |
123 | 0 | string expectedToken = ParserBase::tokenName(_value); |
124 | 0 | parserWarning(3347_error, "Recovered in " + _currentNodeName + " at " + expectedToken + "."); |
125 | 0 | m_inParserRecovery = false; |
126 | 0 | } |
127 | |
|
128 | 0 | if (_advance) |
129 | 0 | advance(); |
130 | 0 | } |
131 | | |
132 | | void ParserBase::increaseRecursionDepth() |
133 | 4.57M | { |
134 | 4.57M | m_recursionDepth++; |
135 | 4.57M | if (m_recursionDepth >= 1200) |
136 | 1 | fatalParserError(7319_error, "Maximum recursion depth reached during parsing."); |
137 | 4.57M | } |
138 | | |
139 | | void ParserBase::decreaseRecursionDepth() |
140 | 4.57M | { |
141 | 4.57M | solAssert(m_recursionDepth > 0, ""); |
142 | 4.57M | m_recursionDepth--; |
143 | 4.57M | } |
144 | | |
145 | | void ParserBase::parserWarning(ErrorId _error, string const& _description) |
146 | 2 | { |
147 | 2 | m_errorReporter.warning(_error, currentLocation(), _description); |
148 | 2 | } |
149 | | |
150 | | void ParserBase::parserWarning(ErrorId _error, SourceLocation const& _location, string const& _description) |
151 | 14.7k | { |
152 | 14.7k | m_errorReporter.warning(_error, _location, _description); |
153 | 14.7k | } |
154 | | |
155 | | void ParserBase::parserError(ErrorId _error, SourceLocation const& _location, string const& _description) |
156 | 5.58k | { |
157 | 5.58k | m_errorReporter.parserError(_error, _location, _description); |
158 | 5.58k | } |
159 | | |
160 | | void ParserBase::parserError(ErrorId _error, string const& _description) |
161 | 5.53k | { |
162 | 5.53k | parserError(_error, currentLocation(), _description); |
163 | 5.53k | } |
164 | | |
165 | | void ParserBase::fatalParserError(ErrorId _error, string const& _description) |
166 | 1.97k | { |
167 | 1.97k | fatalParserError(_error, currentLocation(), _description); |
168 | 1.97k | } |
169 | | |
170 | | void ParserBase::fatalParserError(ErrorId _error, SourceLocation const& _location, string const& _description) |
171 | 1.97k | { |
172 | 1.97k | m_errorReporter.fatalParserError(_error, _location, _description); |
173 | 1.97k | } |