Skip to content

Commit

Permalink
[yul] Add support for parsing debug data attributes.
Browse files Browse the repository at this point in the history
  • Loading branch information
aarlt committed Mar 12, 2024
1 parent a0eb445 commit be1913d
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 19 deletions.
15 changes: 11 additions & 4 deletions liblangutil/DebugData.h
Expand Up @@ -19,6 +19,7 @@
#pragma once

#include <liblangutil/SourceLocation.h>
#include <libsolutil/JSON.h>
#include <optional>
#include <memory>

Expand All @@ -32,23 +33,27 @@ struct DebugData
explicit DebugData(
langutil::SourceLocation _nativeLocation = {},
langutil::SourceLocation _originLocation = {},
std::optional<int64_t> _astID = {}
std::optional<int64_t> _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<int64_t> _astID = {}
std::optional<int64_t> _astID = {},
Json _attributes = {}
)
{
return std::make_shared<DebugData>(
std::move(_nativeLocation),
std::move(_originLocation),
_astID
_astID,
std::move(_attributes)
);
}

Expand All @@ -65,6 +70,8 @@ struct DebugData
langutil::SourceLocation originLocation;
/// ID in the (Solidity) source AST.
std::optional<int64_t> astID;
/// Additional debug data attributes.
Json attributes;
};

} // namespace solidity::langutil
71 changes: 56 additions & 15 deletions libyul/AsmParser.cpp
Expand Up @@ -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, "");
}
Expand Down Expand Up @@ -122,8 +122,7 @@ std::unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> const& _scan
try
{
m_scanner = _scanner;
if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments)
fetchDebugDataFromComment();
fetchDebugDataFromComment();
return std::make_unique<Block>(parseBlock());
}
catch (FatalError const&)
Expand All @@ -137,15 +136,12 @@ std::unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> 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
Expand All @@ -154,7 +150,6 @@ void Parser::fetchDebugDataFromComment()
std::string_view commentLiteral = m_scanner->currentCommentLiteral();
std::match_results<std::string_view::const_iterator> match;

langutil::SourceLocation originLocation = m_locationFromComment;
// Empty for each new node.
std::optional<int> astID;

Expand All @@ -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")
{
Expand All @@ -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<std::pair<std::string_view, std::optional<Json>>> Parser::parseDebugDataAttributeOperationComment(
std::string_view _arguments,
langutil::SourceLocation const&
)
{
std::optional<Json> 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<std::pair<std::string_view, SourceLocation>> Parser::parseSrcComment(
std::string_view const _arguments,
langutil::SourceLocation const& _commentLocation
Expand Down
8 changes: 8 additions & 0 deletions libyul/AsmParser.h
Expand Up @@ -117,6 +117,13 @@ class Parser: public langutil::ParserBase
langutil::SourceLocation const& _commentLocation
);

std::optional<std::pair<std::string_view, std::optional<Json>>> 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;

Expand Down Expand Up @@ -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();
};

}

0 comments on commit be1913d

Please sign in to comment.