From be1913d58e194c5e8e80fe134e98add75997772b Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Thu, 15 Feb 2024 21:47:11 +0100 Subject: [PATCH] [yul] Add support for parsing debug data attributes. --- liblangutil/DebugData.h | 15 ++++++--- libyul/AsmParser.cpp | 71 ++++++++++++++++++++++++++++++++--------- libyul/AsmParser.h | 8 +++++ 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/liblangutil/DebugData.h b/liblangutil/DebugData.h index 70259bd039f3..913b186b7a99 100644 --- a/liblangutil/DebugData.h +++ b/liblangutil/DebugData.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include #include @@ -32,23 +33,27 @@ struct DebugData explicit DebugData( langutil::SourceLocation _nativeLocation = {}, langutil::SourceLocation _originLocation = {}, - std::optional _astID = {} + std::optional _astID = {}, + Json _attributes = {} ): nativeLocation(std::move(_nativeLocation)), originLocation(std::move(_originLocation)), - astID(_astID) + astID(_astID), + attributes(std::move(_attributes)) {} static DebugData::ConstPtr create( langutil::SourceLocation _nativeLocation, langutil::SourceLocation _originLocation = {}, - std::optional _astID = {} + std::optional _astID = {}, + Json _attributes = {} ) { return std::make_shared( std::move(_nativeLocation), std::move(_originLocation), - _astID + _astID, + std::move(_attributes) ); } @@ -65,6 +70,8 @@ struct DebugData langutil::SourceLocation originLocation; /// ID in the (Solidity) source AST. std::optional astID; + /// Additional debug data attributes. + Json attributes; }; } // namespace solidity::langutil diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 3635b096af99..fdfcfa159cb7 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -64,11 +64,11 @@ langutil::DebugData::ConstPtr Parser::createDebugData() const switch (m_useSourceLocationFrom) { case UseSourceLocationFrom::Scanner: - return DebugData::create(ParserBase::currentLocation(), ParserBase::currentLocation()); + return DebugData::create(ParserBase::currentLocation(), ParserBase::currentLocation(), {}, m_currentDebugDataAttributes); case UseSourceLocationFrom::LocationOverride: - return DebugData::create(m_locationOverride, m_locationOverride); + return DebugData::create(m_locationOverride, m_locationOverride, {}, m_currentDebugDataAttributes); case UseSourceLocationFrom::Comments: - return DebugData::create(ParserBase::currentLocation(), m_locationFromComment, m_astIDFromComment); + return DebugData::create(ParserBase::currentLocation(), m_locationFromComment, m_astIDFromComment, m_currentDebugDataAttributes); } solAssert(false, ""); } @@ -122,8 +122,7 @@ std::unique_ptr Parser::parseInline(std::shared_ptr const& _scan try { m_scanner = _scanner; - if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments) - fetchDebugDataFromComment(); + fetchDebugDataFromComment(); return std::make_unique(parseBlock()); } catch (FatalError const&) @@ -137,15 +136,12 @@ std::unique_ptr Parser::parseInline(std::shared_ptr const& _scan langutil::Token Parser::advance() { auto const token = ParserBase::advance(); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments) - fetchDebugDataFromComment(); + fetchDebugDataFromComment(); return token; } void Parser::fetchDebugDataFromComment() { - solAssert(m_sourceNames.has_value(), ""); - static std::regex const tagRegex = std::regex( R"~~((?:^|\s+)(@[a-zA-Z0-9\-_]+)(?:\s+|$))~~", // tag, e.g: @src std::regex_constants::ECMAScript | std::regex_constants::optimize @@ -154,7 +150,6 @@ void Parser::fetchDebugDataFromComment() std::string_view commentLiteral = m_scanner->currentCommentLiteral(); std::match_results match; - langutil::SourceLocation originLocation = m_locationFromComment; // Empty for each new node. std::optional astID; @@ -165,10 +160,14 @@ void Parser::fetchDebugDataFromComment() if (match[1] == "@src") { - if (auto parseResult = parseSrcComment(commentLiteral, m_scanner->currentCommentLocation())) - tie(commentLiteral, originLocation) = *parseResult; - else - break; + if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments) + { + solAssert(m_sourceNames.has_value(), ""); + if (auto parseResult = parseSrcComment(commentLiteral, m_scanner->currentCommentLocation())) + tie(commentLiteral, m_locationFromComment) = *parseResult; + else + break; + } } else if (match[1] == "@ast-id") { @@ -177,15 +176,57 @@ void Parser::fetchDebugDataFromComment() else break; } + else if (match[1] == "@attribute") + { + if (auto parseResult = parseDebugDataAttributeOperationComment(commentLiteral, m_scanner->currentCommentLocation())) + { + commentLiteral = parseResult->first; + if (parseResult->second.has_value()) + applyDebugDataAttributeOperation(m_currentDebugDataAttributes, parseResult->second.value()); + } + else + break; + } else // Ignore unrecognized tags. continue; } - m_locationFromComment = originLocation; m_astIDFromComment = astID; } +std::optional>> Parser::parseDebugDataAttributeOperationComment( + std::string_view _arguments, + langutil::SourceLocation const& +) +{ + std::optional jsonData; + try + { + jsonData = Json::parse(_arguments.begin(), _arguments.end(), nullptr, true); + } + catch (nlohmann::json::parse_error& e) + { + try + { + jsonData = Json::parse(_arguments.substr(0, e.byte - 1), nullptr, true); + } + catch(nlohmann::json::parse_error&) + { + jsonData.reset(); + } + _arguments = _arguments.substr(e.byte - 1); + } + return {{_arguments, jsonData}}; +} + +void Parser::applyDebugDataAttributeOperation(Json& _attributes, Json const& _attributeOperation) +{ + (void)_attributes; + (void)_attributeOperation; + std::cout << "attributes='" << _attributes.dump(2) << "' attributeOperation='" << _attributeOperation.dump(2) << "'" << std::endl; +} + std::optional> Parser::parseSrcComment( std::string_view const _arguments, langutil::SourceLocation const& _commentLocation diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 3e0af66acc10..23bb29976dbf 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -117,6 +117,13 @@ class Parser: public langutil::ParserBase langutil::SourceLocation const& _commentLocation ); + std::optional>> parseDebugDataAttributeOperationComment( + std::string_view _arguments, + langutil::SourceLocation const& _commentLocation + ); + + void applyDebugDataAttributeOperation(Json& _attributes, Json const& _attributeOperation); + /// Creates a DebugData object with the correct source location set. langutil::DebugData::ConstPtr createDebugData() const; @@ -163,6 +170,7 @@ class Parser: public langutil::ParserBase UseSourceLocationFrom m_useSourceLocationFrom = UseSourceLocationFrom::Scanner; ForLoopComponent m_currentForLoopComponent = ForLoopComponent::None; bool m_insideFunction = false; + Json m_currentDebugDataAttributes = Json::object(); }; }