From 7107ef13a7a3cd65cb805645f8e445fe692145bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 11 Mar 2020 21:15:12 +0100 Subject: [PATCH] [yul-phaser] Program: Add parseObject() --- tools/yulPhaser/Program.cpp | 41 +++++++++++++++++++++++++++++++++++++ tools/yulPhaser/Program.h | 4 ++++ 2 files changed, 45 insertions(+) diff --git a/tools/yulPhaser/Program.cpp b/tools/yulPhaser/Program.cpp index c397cd1f4..7dcfddd79 100644 --- a/tools/yulPhaser/Program.cpp +++ b/tools/yulPhaser/Program.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,46 @@ variant, ErrorList> Program::parseSource(Dialect const& _diale return variant, ErrorList>(move(ast)); } +variant, ErrorList> Program::parseObject(Dialect const& _dialect, CharStream _source) +{ + ErrorList errors; + ErrorReporter errorReporter(errors); + auto scanner = make_shared(move(_source)); + + ObjectParser parser(errorReporter, _dialect); + shared_ptr object = parser.parse(scanner, false); + if (object == nullptr || !errorReporter.errors().empty()) + // NOTE: It's possible to get errors even if the returned object is non-null. + // For example when there are errors in a nested object. + return errors; + + Object* deployedObject = nullptr; + if (object->subObjects.size() > 0) + for (auto& subObject: object->subObjects) + // solc --ir produces an object with a subobject of the same name as the outer object + // but suffixed with "_deployed". + // The other object references the nested one which makes analysis fail. Below we try to + // extract just the nested one for that reason. This is just a heuristic. If there's no + // subobject with such a suffix we fall back to accepting the whole object as is. + if (subObject != nullptr && subObject->name.str() == object->name.str() + "_deployed") + { + deployedObject = dynamic_cast(subObject.get()); + if (deployedObject != nullptr) + break; + } + Object* selectedObject = (deployedObject != nullptr ? deployedObject : object.get()); + + // NOTE: I'm making a copy of the whole AST to get unique_ptr rather than shared_ptr. + // This is a slight performance hit but it's much less than the parsing itself. + // unique_ptr lets me be sure that two Program instances can never share the AST by mistake. + // The public API of the class does not provide access to the smart pointer so it won't be hard + // to switch to shared_ptr if the copying turns out to be an issue (though it would be better + // to refactor ObjectParser and Object to use unique_ptr instead). + auto astCopy = make_unique(get(ASTCopier{}(*selectedObject->code))); + + return variant, ErrorList>(move(astCopy)); +} + variant, ErrorList> Program::analyzeAST(Dialect const& _dialect, Block const& _ast) { ErrorList errors; diff --git a/tools/yulPhaser/Program.h b/tools/yulPhaser/Program.h index 6da9751b9..df44f2ba4 100644 --- a/tools/yulPhaser/Program.h +++ b/tools/yulPhaser/Program.h @@ -98,6 +98,10 @@ private: yul::Dialect const& _dialect, langutil::CharStream _source ); + static std::variant, langutil::ErrorList> parseObject( + yul::Dialect const& _dialect, + langutil::CharStream _source + ); static std::variant, langutil::ErrorList> analyzeAST( yul::Dialect const& _dialect, yul::Block const& _ast