29
29
#include < libsolutil/Common.h>
30
30
#include < libsolutil/Visitor.h>
31
31
32
+ #include < range/v3/view/subrange.hpp>
33
+
32
34
#include < boost/algorithm/string.hpp>
33
35
34
36
#include < algorithm>
37
+ #include < regex>
35
38
36
39
using namespace std ;
37
40
using namespace solidity ;
@@ -53,6 +56,18 @@ shared_ptr<DebugData const> updateLocationEndFrom(
53
56
return make_shared<DebugData const >(updatedLocation);
54
57
}
55
58
59
+ optional<int > toInt (string const & _value)
60
+ {
61
+ try
62
+ {
63
+ return stoi (_value);
64
+ }
65
+ catch (...)
66
+ {
67
+ return nullopt;
68
+ }
69
+ }
70
+
56
71
}
57
72
58
73
unique_ptr<Block> Parser::parse (std::shared_ptr<Scanner> const & _scanner, bool _reuseScanner)
@@ -65,6 +80,8 @@ unique_ptr<Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner, bool _
65
80
try
66
81
{
67
82
m_scanner = _scanner;
83
+ if (m_charStreamMap)
84
+ fetchSourceLocationFromComment ();
68
85
auto block = make_unique<Block>(parseBlock ());
69
86
if (!_reuseScanner)
70
87
expectToken (Token::EOS);
@@ -78,14 +95,65 @@ unique_ptr<Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner, bool _
78
95
return nullptr ;
79
96
}
80
97
98
+ langutil::Token Parser::advance ()
99
+ {
100
+ auto const token = ParserBase::advance ();
101
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments)
102
+ fetchSourceLocationFromComment ();
103
+ return token;
104
+ }
105
+
106
+ void Parser::fetchSourceLocationFromComment ()
107
+ {
108
+ solAssert (m_charStreamMap.has_value (), " " );
109
+
110
+ if (m_scanner->currentCommentLiteral ().empty ())
111
+ return ;
112
+
113
+ static regex const lineRE = std::regex (
114
+ R"~~~( (^|\s*)@src\s+(-1|\d+):(-1|\d+):(-1|\d+)(\s+|$))~~~" ,
115
+ std::regex_constants::ECMAScript | std::regex_constants::optimize
116
+ );
117
+
118
+ string const text = m_scanner->currentCommentLiteral ();
119
+ auto from = sregex_iterator (text.begin (), text.end (), lineRE);
120
+ auto to = sregex_iterator ();
121
+
122
+ for (auto const & matchResult: ranges::make_subrange (from, to))
123
+ {
124
+ solAssert (matchResult.size () == 6 , " " );
125
+
126
+ auto const sourceIndex = toInt (matchResult[2 ].str ());
127
+ auto const start = toInt (matchResult[3 ].str ());
128
+ auto const end = toInt (matchResult[4 ].str ());
129
+
130
+ auto const commentLocation = m_scanner->currentCommentLocation ();
131
+ m_locationOverride = SourceLocation{};
132
+ if (!sourceIndex || !start || !end)
133
+ m_errorReporter.syntaxError (6367_error, commentLocation, " Invalid value in source location mapping. Could not parse location specification." );
134
+ else if (!((start < 0 && end < 0 ) || (start >= 0 && *start <= *end)))
135
+ m_errorReporter.syntaxError (5798_error, commentLocation, " Invalid value in source location mapping. Start offset larger than end offset." );
136
+ else if (!(sourceIndex >= 0 && m_charStreamMap->count (static_cast <unsigned >(*sourceIndex))))
137
+ m_errorReporter.syntaxError (2674_error, commentLocation, " Invalid source mapping. Source index not defined via @use-src." );
138
+ else if (sourceIndex >= 0 )
139
+ {
140
+ shared_ptr<CharStream> charStream = m_charStreamMap->at (static_cast <unsigned >(*sourceIndex));
141
+ solAssert (charStream, " " );
142
+
143
+ m_locationOverride = SourceLocation{*start, *end, charStream};
144
+ }
145
+ }
146
+ }
147
+
81
148
Block Parser::parseBlock ()
82
149
{
83
150
RecursionGuard recursionGuard (*this );
84
151
Block block = createWithLocation<Block>();
85
152
expectToken (Token::LBrace);
86
153
while (currentToken () != Token::RBrace)
87
154
block.statements .emplace_back (parseStatement ());
88
- block.debugData = updateLocationEndFrom (block.debugData , currentLocation ());
155
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
156
+ block.debugData = updateLocationEndFrom (block.debugData , currentLocation ());
89
157
advance ();
90
158
return block;
91
159
}
@@ -107,7 +175,8 @@ Statement Parser::parseStatement()
107
175
advance ();
108
176
_if.condition = make_unique<Expression>(parseExpression ());
109
177
_if.body = parseBlock ();
110
- _if.debugData = updateLocationEndFrom (_if.debugData , _if.body .debugData ->location );
178
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
179
+ _if.debugData = updateLocationEndFrom (_if.debugData , _if.body .debugData ->location );
111
180
return Statement{move (_if)};
112
181
}
113
182
case Token::Switch:
@@ -125,7 +194,8 @@ Statement Parser::parseStatement()
125
194
fatalParserError (4904_error, " Case not allowed after default case." );
126
195
if (_switch.cases .empty ())
127
196
fatalParserError (2418_error, " Switch statement without any cases." );
128
- _switch.debugData = updateLocationEndFrom (_switch.debugData , _switch.cases .back ().body .debugData ->location );
197
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
198
+ _switch.debugData = updateLocationEndFrom (_switch.debugData , _switch.cases .back ().body .debugData ->location );
129
199
return Statement{move (_switch)};
130
200
}
131
201
case Token::For:
@@ -207,7 +277,8 @@ Statement Parser::parseStatement()
207
277
expectToken (Token::AssemblyAssign);
208
278
209
279
assignment.value = make_unique<Expression>(parseExpression ());
210
- assignment.debugData = updateLocationEndFrom (assignment.debugData , locationOf (*assignment.value ));
280
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
281
+ assignment.debugData = updateLocationEndFrom (assignment.debugData , locationOf (*assignment.value ));
211
282
212
283
return Statement{move (assignment)};
213
284
}
@@ -237,7 +308,8 @@ Case Parser::parseCase()
237
308
else
238
309
yulAssert (false , " Case or default case expected." );
239
310
_case.body = parseBlock ();
240
- _case.debugData = updateLocationEndFrom (_case.debugData , _case.body .debugData ->location );
311
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
312
+ _case.debugData = updateLocationEndFrom (_case.debugData , _case.body .debugData ->location );
241
313
return _case;
242
314
}
243
315
@@ -257,7 +329,8 @@ ForLoop Parser::parseForLoop()
257
329
forLoop.post = parseBlock ();
258
330
m_currentForLoopComponent = ForLoopComponent::ForLoopBody;
259
331
forLoop.body = parseBlock ();
260
- forLoop.debugData = updateLocationEndFrom (forLoop.debugData , forLoop.body .debugData ->location );
332
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
333
+ forLoop.debugData = updateLocationEndFrom (forLoop.debugData , forLoop.body .debugData ->location );
261
334
262
335
m_currentForLoopComponent = outerForLoopComponent;
263
336
@@ -336,7 +409,8 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
336
409
if (currentToken () == Token::Colon)
337
410
{
338
411
expectToken (Token::Colon);
339
- literal.debugData = updateLocationEndFrom (literal.debugData , currentLocation ());
412
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
413
+ literal.debugData = updateLocationEndFrom (literal.debugData , currentLocation ());
340
414
literal.type = expectAsmIdentifier ();
341
415
}
342
416
@@ -368,9 +442,10 @@ VariableDeclaration Parser::parseVariableDeclaration()
368
442
{
369
443
expectToken (Token::AssemblyAssign);
370
444
varDecl.value = make_unique<Expression>(parseExpression ());
371
- varDecl.debugData = updateLocationEndFrom (varDecl.debugData , locationOf (*varDecl.value ));
445
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
446
+ varDecl.debugData = updateLocationEndFrom (varDecl.debugData , locationOf (*varDecl.value ));
372
447
}
373
- else
448
+ else if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
374
449
varDecl.debugData = updateLocationEndFrom (varDecl.debugData , varDecl.variables .back ().debugData ->location );
375
450
376
451
return varDecl;
@@ -417,7 +492,8 @@ FunctionDefinition Parser::parseFunctionDefinition()
417
492
m_insideFunction = true ;
418
493
funDef.body = parseBlock ();
419
494
m_insideFunction = preInsideFunction;
420
- funDef.debugData = updateLocationEndFrom (funDef.debugData , funDef.body .debugData ->location );
495
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
496
+ funDef.debugData = updateLocationEndFrom (funDef.debugData , funDef.body .debugData ->location );
421
497
422
498
m_currentForLoopComponent = outerForLoopComponent;
423
499
return funDef;
@@ -444,7 +520,8 @@ FunctionCall Parser::parseCall(variant<Literal, Identifier>&& _initialOp)
444
520
ret.arguments .emplace_back (parseExpression ());
445
521
}
446
522
}
447
- ret.debugData = updateLocationEndFrom (ret.debugData , currentLocation ());
523
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
524
+ ret.debugData = updateLocationEndFrom (ret.debugData , currentLocation ());
448
525
expectToken (Token::RParen);
449
526
return ret;
450
527
}
@@ -457,7 +534,8 @@ TypedName Parser::parseTypedName()
457
534
if (currentToken () == Token::Colon)
458
535
{
459
536
expectToken (Token::Colon);
460
- typedName.debugData = updateLocationEndFrom (typedName.debugData , currentLocation ());
537
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
538
+ typedName.debugData = updateLocationEndFrom (typedName.debugData , currentLocation ());
461
539
typedName.type = expectAsmIdentifier ();
462
540
}
463
541
else
0 commit comments