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,66 @@ 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_debugDataOverride = DebugData::create ();
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 == -1 && (0 <= *start && *start <= *end)) // Use source index -1 to indicate original source.
137
+ m_debugDataOverride = DebugData::create (SourceLocation{*start, *end, ParserBase::currentLocation ().source });
138
+ else if (!(sourceIndex >= 0 && m_charStreamMap->count (static_cast <unsigned >(*sourceIndex))))
139
+ m_errorReporter.syntaxError (2674_error, commentLocation, " Invalid source mapping. Source index not defined via @use-src." );
140
+ else
141
+ {
142
+ shared_ptr<CharStream> charStream = m_charStreamMap->at (static_cast <unsigned >(*sourceIndex));
143
+ solAssert (charStream, " " );
144
+ m_debugDataOverride = DebugData::create (SourceLocation{*start, *end, charStream});
145
+ }
146
+ }
147
+ }
148
+
81
149
Block Parser::parseBlock ()
82
150
{
83
151
RecursionGuard recursionGuard (*this );
84
152
Block block = createWithLocation<Block>();
85
153
expectToken (Token::LBrace);
86
154
while (currentToken () != Token::RBrace)
87
155
block.statements .emplace_back (parseStatement ());
88
- block.debugData = updateLocationEndFrom (block.debugData , currentLocation ());
156
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
157
+ block.debugData = updateLocationEndFrom (block.debugData , currentLocation ());
89
158
advance ();
90
159
return block;
91
160
}
@@ -107,7 +176,8 @@ Statement Parser::parseStatement()
107
176
advance ();
108
177
_if.condition = make_unique<Expression>(parseExpression ());
109
178
_if.body = parseBlock ();
110
- _if.debugData = updateLocationEndFrom (_if.debugData , _if.body .debugData ->location );
179
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
180
+ _if.debugData = updateLocationEndFrom (_if.debugData , _if.body .debugData ->location );
111
181
return Statement{move (_if)};
112
182
}
113
183
case Token::Switch:
@@ -125,7 +195,8 @@ Statement Parser::parseStatement()
125
195
fatalParserError (4904_error, " Case not allowed after default case." );
126
196
if (_switch.cases .empty ())
127
197
fatalParserError (2418_error, " Switch statement without any cases." );
128
- _switch.debugData = updateLocationEndFrom (_switch.debugData , _switch.cases .back ().body .debugData ->location );
198
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
199
+ _switch.debugData = updateLocationEndFrom (_switch.debugData , _switch.cases .back ().body .debugData ->location );
129
200
return Statement{move (_switch)};
130
201
}
131
202
case Token::For:
@@ -207,7 +278,8 @@ Statement Parser::parseStatement()
207
278
expectToken (Token::AssemblyAssign);
208
279
209
280
assignment.value = make_unique<Expression>(parseExpression ());
210
- assignment.debugData = updateLocationEndFrom (assignment.debugData , locationOf (*assignment.value ));
281
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
282
+ assignment.debugData = updateLocationEndFrom (assignment.debugData , locationOf (*assignment.value ));
211
283
212
284
return Statement{move (assignment)};
213
285
}
@@ -237,7 +309,8 @@ Case Parser::parseCase()
237
309
else
238
310
yulAssert (false , " Case or default case expected." );
239
311
_case.body = parseBlock ();
240
- _case.debugData = updateLocationEndFrom (_case.debugData , _case.body .debugData ->location );
312
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
313
+ _case.debugData = updateLocationEndFrom (_case.debugData , _case.body .debugData ->location );
241
314
return _case;
242
315
}
243
316
@@ -257,7 +330,8 @@ ForLoop Parser::parseForLoop()
257
330
forLoop.post = parseBlock ();
258
331
m_currentForLoopComponent = ForLoopComponent::ForLoopBody;
259
332
forLoop.body = parseBlock ();
260
- forLoop.debugData = updateLocationEndFrom (forLoop.debugData , forLoop.body .debugData ->location );
333
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
334
+ forLoop.debugData = updateLocationEndFrom (forLoop.debugData , forLoop.body .debugData ->location );
261
335
262
336
m_currentForLoopComponent = outerForLoopComponent;
263
337
@@ -296,7 +370,7 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
296
370
{
297
371
case Token::Identifier:
298
372
{
299
- Identifier identifier{DebugData::create ( currentLocation () ), YulString{currentLiteral ()}};
373
+ Identifier identifier{createDebugData ( ), YulString{currentLiteral ()}};
300
374
advance ();
301
375
return identifier;
302
376
}
@@ -327,7 +401,7 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
327
401
}
328
402
329
403
Literal literal{
330
- DebugData::create ( currentLocation () ),
404
+ createDebugData ( ),
331
405
kind,
332
406
YulString{currentLiteral ()},
333
407
kind == LiteralKind::Boolean ? m_dialect.boolType : m_dialect.defaultType
@@ -336,7 +410,8 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
336
410
if (currentToken () == Token::Colon)
337
411
{
338
412
expectToken (Token::Colon);
339
- literal.debugData = updateLocationEndFrom (literal.debugData , currentLocation ());
413
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
414
+ literal.debugData = updateLocationEndFrom (literal.debugData , currentLocation ());
340
415
literal.type = expectAsmIdentifier ();
341
416
}
342
417
@@ -368,9 +443,10 @@ VariableDeclaration Parser::parseVariableDeclaration()
368
443
{
369
444
expectToken (Token::AssemblyAssign);
370
445
varDecl.value = make_unique<Expression>(parseExpression ());
371
- varDecl.debugData = updateLocationEndFrom (varDecl.debugData , locationOf (*varDecl.value ));
446
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
447
+ varDecl.debugData = updateLocationEndFrom (varDecl.debugData , locationOf (*varDecl.value ));
372
448
}
373
- else
449
+ else if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
374
450
varDecl.debugData = updateLocationEndFrom (varDecl.debugData , varDecl.variables .back ().debugData ->location );
375
451
376
452
return varDecl;
@@ -417,7 +493,8 @@ FunctionDefinition Parser::parseFunctionDefinition()
417
493
m_insideFunction = true ;
418
494
funDef.body = parseBlock ();
419
495
m_insideFunction = preInsideFunction;
420
- funDef.debugData = updateLocationEndFrom (funDef.debugData , funDef.body .debugData ->location );
496
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
497
+ funDef.debugData = updateLocationEndFrom (funDef.debugData , funDef.body .debugData ->location );
421
498
422
499
m_currentForLoopComponent = outerForLoopComponent;
423
500
return funDef;
@@ -444,7 +521,8 @@ FunctionCall Parser::parseCall(variant<Literal, Identifier>&& _initialOp)
444
521
ret.arguments .emplace_back (parseExpression ());
445
522
}
446
523
}
447
- ret.debugData = updateLocationEndFrom (ret.debugData , currentLocation ());
524
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
525
+ ret.debugData = updateLocationEndFrom (ret.debugData , currentLocation ());
448
526
expectToken (Token::RParen);
449
527
return ret;
450
528
}
@@ -457,7 +535,8 @@ TypedName Parser::parseTypedName()
457
535
if (currentToken () == Token::Colon)
458
536
{
459
537
expectToken (Token::Colon);
460
- typedName.debugData = updateLocationEndFrom (typedName.debugData , currentLocation ());
538
+ if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner)
539
+ typedName.debugData = updateLocationEndFrom (typedName.debugData , currentLocation ());
461
540
typedName.type = expectAsmIdentifier ();
462
541
}
463
542
else
0 commit comments