mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Refactor source comment parsing.
This commit is contained in:
		
							parent
							
								
									0fa24c786b
								
							
						
					
					
						commit
						d708612e27
					
				| @ -104,7 +104,7 @@ unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> const& _scanner) | ||||
| 	{ | ||||
| 		m_scanner = _scanner; | ||||
| 		if (m_sourceNames) | ||||
| 			fetchSourceLocationFromComment(); | ||||
| 			fetchDebugDataFromComment(); | ||||
| 		return make_unique<Block>(parseBlock()); | ||||
| 	} | ||||
| 	catch (FatalError const&) | ||||
| @ -119,99 +119,107 @@ langutil::Token Parser::advance() | ||||
| { | ||||
| 	auto const token = ParserBase::advance(); | ||||
| 	if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments) | ||||
| 		fetchSourceLocationFromComment(); | ||||
| 		fetchDebugDataFromComment(); | ||||
| 	return token; | ||||
| } | ||||
| 
 | ||||
| void Parser::fetchSourceLocationFromComment() | ||||
| void Parser::fetchDebugDataFromComment() | ||||
| { | ||||
| 	solAssert(m_sourceNames.has_value(), ""); | ||||
| 
 | ||||
| 	if (m_scanner->currentCommentLiteral().empty()) | ||||
| 		return; | ||||
| 
 | ||||
| 	static regex const tagRegex = regex( | ||||
| 		R"~~((?:^|\s+)(@[a-zA-Z0-9\-_]+)(?:\s+|$))~~", // tag, e.g: @src
 | ||||
| 		regex_constants::ECMAScript | regex_constants::optimize | ||||
| 	); | ||||
| 	static regex const srcTagArgsRegex = regex( | ||||
| 		R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~"  // index and location, e.g.: 1:234:-1
 | ||||
| 		R"~~(("(?:[^"\\]|\\.)*"?)?)~~",                // optional code snippet, e.g.: "string memory s = \"abc\";..." | ||||
| 		regex_constants::ECMAScript | regex_constants::optimize | ||||
| 	); | ||||
| 
 | ||||
| 	string const commentLiteral = m_scanner->currentCommentLiteral(); | ||||
| 	SourceLocation const commentLocation = m_scanner->currentCommentLocation(); | ||||
| 	smatch tagMatch; | ||||
| 	string::const_iterator position = commentLiteral.begin(); | ||||
| 	string_view commentLiteral = m_scanner->currentCommentLiteral(); | ||||
| 	match_results<string_view::const_iterator> match; | ||||
| 
 | ||||
| 	while (regex_search(position, commentLiteral.end(), tagMatch, tagRegex)) | ||||
| 	langutil::SourceLocation sourceLocation = m_debugDataOverride->location; | ||||
| 
 | ||||
| 	while (regex_search(commentLiteral.cbegin(), commentLiteral.cend(), match, tagRegex)) | ||||
| 	{ | ||||
| 		solAssert(tagMatch.size() == 2, ""); | ||||
| 		position += tagMatch.position() + tagMatch.length(); | ||||
| 		solAssert(match.size() == 2, ""); | ||||
| 		commentLiteral = commentLiteral.substr(static_cast<size_t>(match.position() + match.length())); | ||||
| 
 | ||||
| 		if (tagMatch[1] == "@src") | ||||
| 		if (match[1] == "@src") | ||||
| 		{ | ||||
| 			smatch srcTagArgsMatch; | ||||
| 			if (!regex_search(position, commentLiteral.end(), srcTagArgsMatch, srcTagArgsRegex)) | ||||
| 			{ | ||||
| 				m_errorReporter.syntaxError( | ||||
| 					8387_error, | ||||
| 					commentLocation, | ||||
| 					"Invalid values in source location mapping. Could not parse location specification." | ||||
| 				); | ||||
| 
 | ||||
| 				// If the arguments to @src are malformed, we don't know where they end so we can't continue.
 | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			solAssert(srcTagArgsMatch.size() == 5, ""); | ||||
| 			position += srcTagArgsMatch.position() + srcTagArgsMatch.length(); | ||||
| 
 | ||||
| 			if (srcTagArgsMatch[4].matched && ( | ||||
| 				!boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\"") || | ||||
| 				boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\\\"") | ||||
| 			)) | ||||
| 			{ | ||||
| 				m_errorReporter.syntaxError( | ||||
| 					1544_error, | ||||
| 					commentLocation, | ||||
| 					"Invalid code snippet in source location mapping. Quote is not terminated." | ||||
| 				); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			optional<int> const sourceIndex = toInt(srcTagArgsMatch[1].str()); | ||||
| 			optional<int> const start = toInt(srcTagArgsMatch[2].str()); | ||||
| 			optional<int> const end = toInt(srcTagArgsMatch[3].str()); | ||||
| 
 | ||||
| 			m_debugDataOverride = DebugData::create(); | ||||
| 			if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) | ||||
| 				m_errorReporter.syntaxError( | ||||
| 					6367_error, | ||||
| 					commentLocation, | ||||
| 					"Invalid value in source location mapping. " | ||||
| 					"Expected non-negative integer values or -1 for source index and location." | ||||
| 				); | ||||
| 			else if (sourceIndex == -1) | ||||
| 				m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), nullptr}); | ||||
| 			else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast<unsigned>(sourceIndex.value())))) | ||||
| 				m_errorReporter.syntaxError( | ||||
| 					2674_error, | ||||
| 					commentLocation, | ||||
| 					"Invalid source mapping. Source index not defined via @use-src." | ||||
| 				); | ||||
| 			if (auto parseResult = parseSrcComment(commentLiteral, m_scanner->currentCommentLocation())) | ||||
| 				tie(commentLiteral, sourceLocation) = *parseResult; | ||||
| 			else | ||||
| 			{ | ||||
| 				shared_ptr<string const> sourceName = m_sourceNames->at(static_cast<unsigned>(sourceIndex.value())); | ||||
| 				solAssert(sourceName, ""); | ||||
| 				m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), move(sourceName)}); | ||||
| 			} | ||||
| 				break; | ||||
| 		} | ||||
| 		else | ||||
| 			// Ignore unrecognized tags.
 | ||||
| 			continue; | ||||
| 	} | ||||
| 
 | ||||
| 	m_debugDataOverride = DebugData::create(sourceLocation); | ||||
| } | ||||
| 
 | ||||
| optional<pair<string_view, SourceLocation>> Parser::parseSrcComment( | ||||
| 	string_view const _arguments, | ||||
| 	langutil::SourceLocation const& _commentLocation | ||||
| ) | ||||
| { | ||||
| 	static regex const argsRegex = regex( | ||||
| 		R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~"  // index and location, e.g.: 1:234:-1
 | ||||
| 		R"~~(("(?:[^"\\]|\\.)*"?)?)~~",                // optional code snippet, e.g.: "string memory s = \"abc\";..." | ||||
| 		regex_constants::ECMAScript | regex_constants::optimize | ||||
| 	); | ||||
| 	match_results<string_view::const_iterator> match; | ||||
| 	if (!regex_search(_arguments.cbegin(), _arguments.cend(), match, argsRegex)) | ||||
| 	{ | ||||
| 		m_errorReporter.syntaxError( | ||||
| 			8387_error, | ||||
| 			_commentLocation, | ||||
| 			"Invalid values in source location mapping. Could not parse location specification." | ||||
| 		); | ||||
| 		return nullopt; | ||||
| 	} | ||||
| 
 | ||||
| 	solAssert(match.size() == 5, ""); | ||||
| 	string_view tail = _arguments.substr(static_cast<size_t>(match.position() + match.length())); | ||||
| 
 | ||||
| 	if (match[4].matched && ( | ||||
| 		!boost::algorithm::ends_with(match[4].str(), "\"") || | ||||
| 		boost::algorithm::ends_with(match[4].str(), "\\\"") | ||||
| 	)) | ||||
| 	{ | ||||
| 		m_errorReporter.syntaxError( | ||||
| 			1544_error, | ||||
| 			_commentLocation, | ||||
| 			"Invalid code snippet in source location mapping. Quote is not terminated." | ||||
| 		); | ||||
| 		return {{tail, SourceLocation{}}}; | ||||
| 	} | ||||
| 
 | ||||
| 	optional<int> const sourceIndex = toInt(match[1].str()); | ||||
| 	optional<int> const start = toInt(match[2].str()); | ||||
| 	optional<int> const end = toInt(match[3].str()); | ||||
| 
 | ||||
| 	if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) | ||||
| 		m_errorReporter.syntaxError( | ||||
| 			6367_error, | ||||
| 			_commentLocation, | ||||
| 			"Invalid value in source location mapping. " | ||||
| 			"Expected non-negative integer values or -1 for source index and location." | ||||
| 		); | ||||
| 	else if (sourceIndex == -1) | ||||
| 		return {{tail, SourceLocation{start.value(), end.value(), nullptr}}}; | ||||
| 	else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast<unsigned>(sourceIndex.value())))) | ||||
| 		m_errorReporter.syntaxError( | ||||
| 			2674_error, | ||||
| 			_commentLocation, | ||||
| 			"Invalid source mapping. Source index not defined via @use-src." | ||||
| 		); | ||||
| 	else | ||||
| 	{ | ||||
| 		shared_ptr<string const> sourceName = m_sourceNames->at(static_cast<unsigned>(sourceIndex.value())); | ||||
| 		solAssert(sourceName, ""); | ||||
| 		return {{tail, SourceLocation{start.value(), end.value(), move(sourceName)}}}; | ||||
| 	} | ||||
| 	return {{tail, SourceLocation{}}}; | ||||
| } | ||||
| 
 | ||||
| Block Parser::parseBlock() | ||||
|  | ||||
| @ -35,6 +35,7 @@ | ||||
| #include <memory> | ||||
| #include <variant> | ||||
| #include <vector> | ||||
| #include <string_view> | ||||
| 
 | ||||
| namespace solidity::yul | ||||
| { | ||||
| @ -68,8 +69,8 @@ public: | ||||
| 		} | ||||
| 	{} | ||||
| 
 | ||||
| 	/// Constructs a Yul parser that is using the source locations
 | ||||
| 	/// from the comments (via @src).
 | ||||
| 	/// Constructs a Yul parser that is using the debug data
 | ||||
| 	/// from the comments (via @src and other tags).
 | ||||
| 	explicit Parser( | ||||
| 		langutil::ErrorReporter& _errorReporter, | ||||
| 		Dialect const& _dialect, | ||||
| @ -105,7 +106,13 @@ protected: | ||||
| 
 | ||||
| 	langutil::Token advance() override; | ||||
| 
 | ||||
| 	void fetchSourceLocationFromComment(); | ||||
| 	void fetchDebugDataFromComment(); | ||||
| 
 | ||||
| 	std::optional<std::pair<std::string_view, langutil::SourceLocation>> | ||||
| 	parseSrcComment( | ||||
| 		std::string_view _arguments, | ||||
| 		langutil::SourceLocation const& _commentLocation | ||||
| 	); | ||||
| 
 | ||||
| 	/// Creates a DebugData object with the correct source location set.
 | ||||
| 	std::shared_ptr<DebugData const> createDebugData() const; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user