mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Yul objects.
This commit is contained in:
parent
5e55cb1729
commit
e016cb99e6
@ -30,6 +30,7 @@
|
||||
#include <libyul/AsmCodeGen.h>
|
||||
#include <libyul/backends/evm/EVMCodeTransform.h>
|
||||
#include <libyul/backends/evm/EVMAssembly.h>
|
||||
#include <libyul/YulObjectParser.h>
|
||||
|
||||
#include <libevmasm/Assembly.h>
|
||||
|
||||
@ -69,7 +70,7 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
|
||||
m_errors.clear();
|
||||
m_analysisSuccessful = false;
|
||||
m_scanner = make_shared<Scanner>(CharStream(_source), _sourceName);
|
||||
m_parserResult = yul::Parser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false);
|
||||
m_parserResult = yul::YulObjectParser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false);
|
||||
if (!m_errorReporter.errors().empty())
|
||||
return false;
|
||||
solAssert(m_parserResult, "");
|
||||
@ -77,17 +78,6 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
|
||||
return analyzeParsed();
|
||||
}
|
||||
|
||||
bool AssemblyStack::analyze(yul::Block const& _block, Scanner const* _scanner)
|
||||
{
|
||||
m_errors.clear();
|
||||
m_analysisSuccessful = false;
|
||||
if (_scanner)
|
||||
m_scanner = make_shared<Scanner>(*_scanner);
|
||||
m_parserResult = make_shared<yul::Block>(_block);
|
||||
|
||||
return analyzeParsed();
|
||||
}
|
||||
|
||||
bool AssemblyStack::analyzeParsed()
|
||||
{
|
||||
m_analysisInfo = make_shared<yul::AsmAnalysisInfo>();
|
||||
|
@ -24,6 +24,9 @@
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <libyul/YulObject.h>
|
||||
#include <libyul/YulObjectParser.h>
|
||||
|
||||
#include <libevmasm/LinkerObject.h>
|
||||
|
||||
#include <string>
|
||||
@ -72,10 +75,6 @@ public:
|
||||
/// Multiple calls overwrite the previous state.
|
||||
bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source);
|
||||
|
||||
/// Runs analysis step on the supplied block, returns false if input cannot be assembled.
|
||||
/// Multiple calls overwrite the previous state.
|
||||
bool analyze(yul::Block const& _block, langutil::Scanner const* _scanner = nullptr);
|
||||
|
||||
/// Run the assembly step (should only be called after parseAndAnalyze).
|
||||
MachineAssemblyObject assemble(Machine _machine) const;
|
||||
|
||||
@ -94,8 +93,7 @@ private:
|
||||
std::shared_ptr<langutil::Scanner> m_scanner;
|
||||
|
||||
bool m_analysisSuccessful = false;
|
||||
std::shared_ptr<yul::Block> m_parserResult;
|
||||
std::shared_ptr<yul::AsmAnalysisInfo> m_analysisInfo;
|
||||
std::shared_ptr<yul::YulObject> m_parserResult;
|
||||
langutil::ErrorList m_errors;
|
||||
langutil::ErrorReporter m_errorReporter;
|
||||
};
|
||||
|
@ -6,6 +6,8 @@ add_library(yul
|
||||
AsmPrinter.cpp
|
||||
AsmScope.cpp
|
||||
AsmScopeFiller.cpp
|
||||
Object.cpp
|
||||
ObjectParser.cpp
|
||||
backends/evm/EVMAssembly.cpp
|
||||
backends/evm/EVMCodeTransform.cpp
|
||||
optimiser/ASTCopier.cpp
|
||||
|
61
libyul/Object.cpp
Normal file
61
libyul/Object.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Yul code and data object container.
|
||||
*/
|
||||
|
||||
#include <libyul/Object.h>
|
||||
|
||||
#include <libyul/AsmPrinter.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
|
||||
#include <libdevcore/Visitor.h>
|
||||
#include <libdevcore/CommonData.h>
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
using namespace dev;
|
||||
using namespace yul;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
string indent(std::string const& _input)
|
||||
{
|
||||
if (_input.empty())
|
||||
return _input;
|
||||
return boost::replace_all_copy(" " + _input, "\n", "\n ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
string Data::toString(bool) const
|
||||
{
|
||||
return "data \"" + name.str() + "\" hex\"" + dev::toHex(data) + "\"";
|
||||
}
|
||||
|
||||
string Object::toString(bool _yul) const
|
||||
{
|
||||
yulAssert(code, "No code");
|
||||
string inner = "code " + AsmPrinter{_yul}(*code);
|
||||
|
||||
for (auto const& obj: subObjects)
|
||||
inner += "\n" + obj->toString(_yul);
|
||||
|
||||
return "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}";
|
||||
}
|
72
libyul/Object.h
Normal file
72
libyul/Object.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Yul code and data object container.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libyul/AsmDataForward.h>
|
||||
#include <libyul/YulString.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
struct AsmAnalysisInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Generic base class for both Yul objects and Yul data.
|
||||
*/
|
||||
struct ObjectNode
|
||||
{
|
||||
virtual ~ObjectNode() {}
|
||||
virtual std::string toString(bool _yul) const = 0;
|
||||
|
||||
YulString name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Named data in Yul objects.
|
||||
*/
|
||||
struct Data: ObjectNode
|
||||
{
|
||||
Data(YulString _name, dev::bytes _data): data(std::move(_data)) { name = _name; }
|
||||
std::string toString(bool _yul) const override;
|
||||
|
||||
dev::bytes data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Yul code and data object container.
|
||||
*/
|
||||
struct Object: ObjectNode
|
||||
{
|
||||
public:
|
||||
/// @returns a (parseable) string representation. Includes types if @a _yul is set.
|
||||
std::string toString(bool _yul) const override;
|
||||
|
||||
std::shared_ptr<Block> code;
|
||||
std::vector<std::shared_ptr<ObjectNode>> subObjects;
|
||||
std::map<YulString, size_t> subIndexByName;
|
||||
std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
|
||||
};
|
||||
|
||||
}
|
146
libyul/ObjectParser.cpp
Normal file
146
libyul/ObjectParser.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Parser for Yul code and data object container.
|
||||
*/
|
||||
|
||||
#include <libyul/ObjectParser.h>
|
||||
|
||||
#include <libyul/AsmParser.h>
|
||||
#include <libyul/Exceptions.h>
|
||||
|
||||
#include <liblangutil/Token.h>
|
||||
|
||||
using namespace dev;
|
||||
using namespace langutil;
|
||||
using namespace yul;
|
||||
using namespace std;
|
||||
|
||||
|
||||
shared_ptr<Object> ObjectParser::parse(shared_ptr<Scanner> const& _scanner, bool _reuseScanner)
|
||||
{
|
||||
m_recursionDepth = 0;
|
||||
try
|
||||
{
|
||||
shared_ptr<Object> object;
|
||||
m_scanner = _scanner;
|
||||
if (currentToken() == Token::LBrace)
|
||||
{
|
||||
// Special case: Code-only form.
|
||||
object = make_shared<Object>();
|
||||
object->name = YulString{"object"};
|
||||
object->code = parseBlock();
|
||||
if (!object->code)
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
object = parseObject();
|
||||
if (object && !_reuseScanner)
|
||||
expectToken(Token::EOS);
|
||||
return object;
|
||||
}
|
||||
catch (FatalError const&)
|
||||
{
|
||||
if (m_errorReporter.errors().empty())
|
||||
throw; // Something is weird here, rather throw again.
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shared_ptr<Object> ObjectParser::parseObject(Object* _containingObject)
|
||||
{
|
||||
RecursionGuard guard(*this);
|
||||
|
||||
if (currentToken() != Token::Identifier || currentLiteral() != "object")
|
||||
fatalParserError("Expected keyword \"object\".");
|
||||
advance();
|
||||
|
||||
shared_ptr<Object> ret = make_shared<Object>();
|
||||
ret->name = parseUniqueName(_containingObject);
|
||||
|
||||
expectToken(Token::LBrace);
|
||||
|
||||
ret->code = parseCode();
|
||||
|
||||
while (currentToken() != Token::RBrace)
|
||||
{
|
||||
if (currentToken() == Token::Identifier && currentLiteral() == "object")
|
||||
parseObject(ret.get());
|
||||
else if (currentToken() == Token::Identifier && currentLiteral() == "data")
|
||||
parseData(*ret);
|
||||
else
|
||||
fatalParserError("Expected keyword \"data\" or \"object\" or \"}\".");
|
||||
}
|
||||
if (_containingObject)
|
||||
addNamedSubObject(*_containingObject, ret->name, ret);
|
||||
|
||||
expectToken(Token::RBrace);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
shared_ptr<Block> ObjectParser::parseCode()
|
||||
{
|
||||
if (currentToken() != Token::Identifier || currentLiteral() != "code")
|
||||
fatalParserError("Expected keyword \"code\".");
|
||||
advance();
|
||||
|
||||
return parseBlock();
|
||||
}
|
||||
|
||||
shared_ptr<Block> ObjectParser::parseBlock()
|
||||
{
|
||||
Parser parser(m_errorReporter, m_flavour);
|
||||
shared_ptr<Block> block = parser.parse(m_scanner, true);
|
||||
yulAssert(block || m_errorReporter.hasErrors(), "Invalid block but no error!");
|
||||
return block;
|
||||
}
|
||||
|
||||
void ObjectParser::parseData(Object& _containingObject)
|
||||
{
|
||||
solAssert(
|
||||
currentToken() == Token::Identifier && currentLiteral() == "data",
|
||||
"parseData called on wrong input."
|
||||
);
|
||||
advance();
|
||||
|
||||
YulString name = parseUniqueName(&_containingObject);
|
||||
|
||||
expectToken(Token::StringLiteral, false);
|
||||
addNamedSubObject(_containingObject, name, make_shared<Data>(name, asBytes(currentLiteral())));
|
||||
advance();
|
||||
}
|
||||
|
||||
YulString ObjectParser::parseUniqueName(Object const* _containingObject)
|
||||
{
|
||||
expectToken(Token::StringLiteral, false);
|
||||
YulString name{currentLiteral()};
|
||||
if (name.empty())
|
||||
parserError("Object name cannot be empty.");
|
||||
else if (_containingObject && _containingObject->name == name)
|
||||
parserError("Object name cannot be the same as the name of the containing object.");
|
||||
else if (_containingObject && _containingObject->subIndexByName.count(name))
|
||||
parserError("Object name \"" + name.str() + "\" already exists inside the containing object.");
|
||||
advance();
|
||||
return name;
|
||||
}
|
||||
|
||||
void ObjectParser::addNamedSubObject(Object& _container, YulString _name, shared_ptr<ObjectNode> _subObject)
|
||||
{
|
||||
_container.subIndexByName[_name] = _container.subObjects.size();
|
||||
_container.subObjects.emplace_back(std::move(_subObject));
|
||||
}
|
72
libyul/ObjectParser.h
Normal file
72
libyul/ObjectParser.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* Parser for Yul code and data object container.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libyul/YulString.h>
|
||||
#include <libyul/Object.h>
|
||||
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/ParserBase.h>
|
||||
|
||||
#include <libdevcore/Common.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace langutil
|
||||
{
|
||||
class Scanner;
|
||||
}
|
||||
|
||||
namespace yul
|
||||
{
|
||||
|
||||
/**
|
||||
* Yul object parser. Invokes the inline assembly parser.
|
||||
*/
|
||||
class ObjectParser: public langutil::ParserBase
|
||||
{
|
||||
public:
|
||||
explicit ObjectParser(
|
||||
langutil::ErrorReporter& _errorReporter,
|
||||
yul::AsmFlavour _flavour = yul::AsmFlavour::Loose
|
||||
):
|
||||
ParserBase(_errorReporter), m_flavour(_flavour) {}
|
||||
|
||||
/// Parses a Yul object.
|
||||
/// Falls back to code-only parsing if the source starts with `{`.
|
||||
/// @param _reuseScanner if true, do check for end of input after the last `}`.
|
||||
/// @returns an empty shared pointer on error.
|
||||
std::shared_ptr<Object> parse(std::shared_ptr<langutil::Scanner> const& _scanner, bool _reuseScanner);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Object> parseObject(Object* _containingObject = nullptr);
|
||||
std::shared_ptr<Block> parseCode();
|
||||
std::shared_ptr<Block> parseBlock();
|
||||
void parseData(Object& _containingObject);
|
||||
|
||||
/// Tries to parse a name that is non-empty and unique inside the containing object.
|
||||
YulString parseUniqueName(Object const* _containingObject);
|
||||
void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr<ObjectNode> _subObject);
|
||||
|
||||
yul::AsmFlavour m_flavour;
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user