mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8066 from ethereum/removeAsmFlavour
Remove asm flavour
This commit is contained in:
commit
ed87b08911
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
* Allow accessing external functions via contract and interface names to obtain their selector.
|
* Allow accessing external functions via contract and interface names to obtain their selector.
|
||||||
|
* Inline Assembly: Support literals ``true`` and ``false``.
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
@ -78,7 +78,7 @@ struct CopyTranslate: public yul::ASTCopier
|
|||||||
_identifier.location,
|
_identifier.location,
|
||||||
yul::LiteralKind::Number,
|
yul::LiteralKind::Number,
|
||||||
yul::YulString{value},
|
yul::YulString{value},
|
||||||
yul::YulString{"uint256"}
|
{}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,6 @@ using namespace solidity::yul;
|
|||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
set<string> const builtinTypes{"bool", "u8", "s8", "u32", "s32", "u64", "s64", "u128", "s128", "u256", "s256"};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsmAnalyzer::analyze(Block const& _block)
|
bool AsmAnalyzer::analyze(Block const& _block)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
@ -88,7 +81,7 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect,
|
|||||||
|
|
||||||
bool AsmAnalyzer::operator()(Literal const& _literal)
|
bool AsmAnalyzer::operator()(Literal const& _literal)
|
||||||
{
|
{
|
||||||
expectValidType(_literal.type.str(), _literal.location);
|
expectValidType(_literal.type, _literal.location);
|
||||||
++m_stackHeight;
|
++m_stackHeight;
|
||||||
if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32)
|
if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32)
|
||||||
{
|
{
|
||||||
@ -107,10 +100,7 @@ bool AsmAnalyzer::operator()(Literal const& _literal)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (_literal.kind == LiteralKind::Boolean)
|
else if (_literal.kind == LiteralKind::Boolean)
|
||||||
{
|
|
||||||
yulAssert(m_dialect.flavour == AsmFlavour::Yul, "");
|
|
||||||
yulAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, "");
|
yulAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, "");
|
||||||
}
|
|
||||||
m_info.stackHeightInfo[&_literal] = m_stackHeight;
|
m_info.stackHeightInfo[&_literal] = m_stackHeight;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -250,7 +240,7 @@ bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
|
|||||||
|
|
||||||
for (auto const& variable: _varDecl.variables)
|
for (auto const& variable: _varDecl.variables)
|
||||||
{
|
{
|
||||||
expectValidType(variable.type.str(), variable.location);
|
expectValidType(variable.type, variable.location);
|
||||||
m_activeVariables.insert(&std::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
m_activeVariables.insert(&std::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
|
||||||
}
|
}
|
||||||
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
||||||
@ -265,7 +255,7 @@ bool AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
|
|||||||
Scope& varScope = scope(virtualBlock);
|
Scope& varScope = scope(virtualBlock);
|
||||||
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
||||||
{
|
{
|
||||||
expectValidType(var.type.str(), var.location);
|
expectValidType(var.type, var.location);
|
||||||
m_activeVariables.insert(&std::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
m_activeVariables.insert(&std::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,27 +378,25 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
|
|||||||
if (!expectExpression(*_switch.expression))
|
if (!expectExpression(*_switch.expression))
|
||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
if (m_dialect.flavour == AsmFlavour::Yul)
|
YulString caseType;
|
||||||
{
|
bool mismatchingTypes = false;
|
||||||
YulString caseType;
|
for (auto const& _case: _switch.cases)
|
||||||
bool mismatchingTypes = false;
|
if (_case.value)
|
||||||
for (auto const& _case: _switch.cases)
|
{
|
||||||
if (_case.value)
|
if (caseType.empty())
|
||||||
|
caseType = _case.value->type;
|
||||||
|
else if (caseType != _case.value->type)
|
||||||
{
|
{
|
||||||
if (caseType.empty())
|
mismatchingTypes = true;
|
||||||
caseType = _case.value->type;
|
break;
|
||||||
else if (caseType != _case.value->type)
|
|
||||||
{
|
|
||||||
mismatchingTypes = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (mismatchingTypes)
|
}
|
||||||
m_errorReporter.typeError(
|
|
||||||
_switch.location,
|
if (mismatchingTypes)
|
||||||
"Switch cases have non-matching types."
|
m_errorReporter.typeError(
|
||||||
);
|
_switch.location,
|
||||||
}
|
"Switch cases have non-matching types."
|
||||||
|
);
|
||||||
|
|
||||||
set<u256> cases;
|
set<u256> cases;
|
||||||
for (auto const& _case: _switch.cases)
|
for (auto const& _case: _switch.cases)
|
||||||
@ -630,15 +618,12 @@ Scope& AsmAnalyzer::scope(Block const* _block)
|
|||||||
yulAssert(scopePtr, "Scope requested but not present.");
|
yulAssert(scopePtr, "Scope requested but not present.");
|
||||||
return *scopePtr;
|
return *scopePtr;
|
||||||
}
|
}
|
||||||
void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location)
|
void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _location)
|
||||||
{
|
{
|
||||||
if (m_dialect.flavour != AsmFlavour::Yul)
|
if (!_type.empty() && !contains(m_dialect.types, _type))
|
||||||
return;
|
|
||||||
|
|
||||||
if (!builtinTypes.count(type))
|
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
_location,
|
_location,
|
||||||
"\"" + type + "\" is not a valid type (user defined types are not yet supported)."
|
"\"" + _type.str() + "\" is not a valid type (user defined types are not yet supported)."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,7 +643,6 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
|
|||||||
yulAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), "");
|
yulAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), "");
|
||||||
// Similarly we assume bitwise shifting and create2 go together.
|
// Similarly we assume bitwise shifting and create2 go together.
|
||||||
yulAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), "");
|
yulAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), "");
|
||||||
yulAssert(m_dialect.flavour != AsmFlavour::Yul, "");
|
|
||||||
|
|
||||||
auto errorForVM = [=](string const& vmKindMessage) {
|
auto errorForVM = [=](string const& vmKindMessage) {
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
|
@ -102,7 +102,7 @@ private:
|
|||||||
bool checkAssignment(Identifier const& _assignment, size_t _valueSize = size_t(-1));
|
bool checkAssignment(Identifier const& _assignment, size_t _valueSize = size_t(-1));
|
||||||
|
|
||||||
Scope& scope(Block const* _block);
|
Scope& scope(Block const* _block);
|
||||||
void expectValidType(std::string const& type, langutil::SourceLocation const& _location);
|
void expectValidType(YulString _type, langutil::SourceLocation const& _location);
|
||||||
bool warnOnInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location);
|
bool warnOnInstructions(evmasm::Instruction _instr, langutil::SourceLocation const& _location);
|
||||||
bool warnOnInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
|
bool warnOnInstructions(std::string const& _instrIdentifier, langutil::SourceLocation const& _location);
|
||||||
|
|
||||||
|
@ -369,23 +369,18 @@ Parser::ElementaryOperation Parser::parseElementaryOperation()
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
advance();
|
advance();
|
||||||
if (m_dialect.flavour == AsmFlavour::Yul)
|
if (currentToken() == Token::Colon)
|
||||||
{
|
{
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
literal.location.end = endPosition();
|
literal.location.end = endPosition();
|
||||||
literal.type = expectAsmIdentifier();
|
literal.type = expectAsmIdentifier();
|
||||||
}
|
}
|
||||||
else if (kind == LiteralKind::Boolean)
|
|
||||||
fatalParserError("True and false are not valid literals.");
|
|
||||||
ret = std::move(literal);
|
ret = std::move(literal);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fatalParserError(
|
fatalParserError("Literal or identifier expected.");
|
||||||
m_dialect.flavour == AsmFlavour::Yul ?
|
|
||||||
"Literal or identifier expected." :
|
|
||||||
"Literal, identifier or instruction expected."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -474,11 +469,7 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp)
|
|||||||
else if (holds_alternative<FunctionCall>(_initialOp))
|
else if (holds_alternative<FunctionCall>(_initialOp))
|
||||||
ret = std::move(std::get<FunctionCall>(_initialOp));
|
ret = std::move(std::get<FunctionCall>(_initialOp));
|
||||||
else
|
else
|
||||||
fatalParserError(
|
fatalParserError("Function name expected.");
|
||||||
m_dialect.flavour == AsmFlavour::Yul ?
|
|
||||||
"Function name expected." :
|
|
||||||
"Assembly instruction or function name required in front of \"(\")"
|
|
||||||
);
|
|
||||||
|
|
||||||
expectToken(Token::LParen);
|
expectToken(Token::LParen);
|
||||||
if (currentToken() != Token::RParen)
|
if (currentToken() != Token::RParen)
|
||||||
@ -500,7 +491,7 @@ TypedName Parser::parseTypedName()
|
|||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
TypedName typedName = createWithLocation<TypedName>();
|
TypedName typedName = createWithLocation<TypedName>();
|
||||||
typedName.name = expectAsmIdentifier();
|
typedName.name = expectAsmIdentifier();
|
||||||
if (m_dialect.flavour == AsmFlavour::Yul)
|
if (currentToken() == Token::Colon)
|
||||||
{
|
{
|
||||||
expectToken(Token::Colon);
|
expectToken(Token::Colon);
|
||||||
typedName.location.end = endPosition();
|
typedName.location.end = endPosition();
|
||||||
|
@ -238,7 +238,7 @@ string AsmPrinter::formatTypedName(TypedName _variable) const
|
|||||||
|
|
||||||
string AsmPrinter::appendTypeName(YulString _type) const
|
string AsmPrinter::appendTypeName(YulString _type) const
|
||||||
{
|
{
|
||||||
if (m_yul && !_type.empty())
|
if (!_type.empty())
|
||||||
return ":" + _type.str();
|
return ":" + _type.str();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,12 @@
|
|||||||
|
|
||||||
namespace solidity::yul
|
namespace solidity::yul
|
||||||
{
|
{
|
||||||
|
struct Dialect;
|
||||||
|
|
||||||
class AsmPrinter
|
class AsmPrinter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AsmPrinter(bool _yul = false): m_yul(_yul) {}
|
explicit AsmPrinter() {}
|
||||||
|
|
||||||
std::string operator()(Literal const& _literal) const;
|
std::string operator()(Literal const& _literal) const;
|
||||||
std::string operator()(Identifier const& _identifier) const;
|
std::string operator()(Identifier const& _identifier) const;
|
||||||
@ -52,8 +53,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::string formatTypedName(TypedName _variable) const;
|
std::string formatTypedName(TypedName _variable) const;
|
||||||
std::string appendTypeName(YulString _type) const;
|
std::string appendTypeName(YulString _type) const;
|
||||||
|
|
||||||
bool m_yul = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ add_library(yul
|
|||||||
AssemblyStack.cpp
|
AssemblyStack.cpp
|
||||||
CompilabilityChecker.cpp
|
CompilabilityChecker.cpp
|
||||||
CompilabilityChecker.h
|
CompilabilityChecker.h
|
||||||
|
Dialect.cpp
|
||||||
Dialect.h
|
Dialect.h
|
||||||
Exceptions.h
|
Exceptions.h
|
||||||
Object.cpp
|
Object.cpp
|
||||||
|
@ -39,11 +39,6 @@ map<YulString, int> CompilabilityChecker::run(
|
|||||||
bool _optimizeStackAllocation
|
bool _optimizeStackAllocation
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (_dialect.flavour == AsmFlavour::Yul)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
yulAssert(_dialect.flavour == AsmFlavour::Strict, "");
|
|
||||||
|
|
||||||
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&_dialect))
|
||||||
{
|
{
|
||||||
NoOutputEVMDialect noOutputDialect(*evmDialect);
|
NoOutputEVMDialect noOutputDialect(*evmDialect);
|
||||||
|
53
libyul/Dialect.cpp
Normal file
53
libyul/Dialect.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
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 dialect.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libyul/Dialect.h>
|
||||||
|
|
||||||
|
using namespace solidity::yul;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Dialect const& Dialect::yul()
|
||||||
|
{
|
||||||
|
static unique_ptr<Dialect> dialect;
|
||||||
|
static YulStringRepository::ResetCallback callback{[&] { dialect.reset(); }};
|
||||||
|
|
||||||
|
if (!dialect)
|
||||||
|
{
|
||||||
|
// TODO will probably change, especially the list of types.
|
||||||
|
dialect = make_unique<Dialect>();
|
||||||
|
dialect->defaultType = "u256"_yulstring;
|
||||||
|
dialect->boolType = "bool"_yulstring;
|
||||||
|
dialect->types = {
|
||||||
|
"bool"_yulstring,
|
||||||
|
"u8"_yulstring,
|
||||||
|
"s8"_yulstring,
|
||||||
|
"u32"_yulstring,
|
||||||
|
"s32"_yulstring,
|
||||||
|
"u64"_yulstring,
|
||||||
|
"s64"_yulstring,
|
||||||
|
"u128"_yulstring,
|
||||||
|
"s128"_yulstring,
|
||||||
|
"u256"_yulstring,
|
||||||
|
"s256"_yulstring
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return *dialect;
|
||||||
|
}
|
@ -34,12 +34,6 @@ namespace solidity::yul
|
|||||||
class YulString;
|
class YulString;
|
||||||
using Type = YulString;
|
using Type = YulString;
|
||||||
|
|
||||||
enum class AsmFlavour
|
|
||||||
{
|
|
||||||
Strict, // no types, EVM instructions as functions, but no jumps and no direct stack manipulations
|
|
||||||
Yul // same as Strict mode with types
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BuiltinFunction
|
struct BuiltinFunction
|
||||||
{
|
{
|
||||||
YulString name;
|
YulString name;
|
||||||
@ -54,7 +48,11 @@ struct BuiltinFunction
|
|||||||
|
|
||||||
struct Dialect: boost::noncopyable
|
struct Dialect: boost::noncopyable
|
||||||
{
|
{
|
||||||
AsmFlavour const flavour = AsmFlavour::Strict;
|
YulString defaultType;
|
||||||
|
/// Type used for the literals "true" and "false".
|
||||||
|
YulString boolType;
|
||||||
|
std::vector<YulString> types;
|
||||||
|
|
||||||
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
||||||
virtual BuiltinFunction const* builtin(YulString /*_name*/) const { return nullptr; }
|
virtual BuiltinFunction const* builtin(YulString /*_name*/) const { return nullptr; }
|
||||||
|
|
||||||
@ -64,14 +62,10 @@ struct Dialect: boost::noncopyable
|
|||||||
|
|
||||||
virtual std::set<YulString> fixedFunctionNames() const { return {}; }
|
virtual std::set<YulString> fixedFunctionNames() const { return {}; }
|
||||||
|
|
||||||
Dialect(AsmFlavour _flavour): flavour(_flavour) {}
|
Dialect() = default;
|
||||||
virtual ~Dialect() = default;
|
virtual ~Dialect() = default;
|
||||||
|
|
||||||
static Dialect const& yul()
|
static Dialect const& yul();
|
||||||
{
|
|
||||||
static Dialect yulDialect(AsmFlavour::Yul);
|
|
||||||
return yulDialect;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ string Data::toString(bool) const
|
|||||||
string Object::toString(bool _yul) const
|
string Object::toString(bool _yul) const
|
||||||
{
|
{
|
||||||
yulAssert(code, "No code");
|
yulAssert(code, "No code");
|
||||||
string inner = "code " + AsmPrinter{_yul}(*code);
|
string inner = "code " + AsmPrinter{}(*code);
|
||||||
|
|
||||||
for (auto const& obj: subObjects)
|
for (auto const& obj: subObjects)
|
||||||
inner += "\n" + obj->toString(_yul);
|
inner += "\n" + obj->toString(_yul);
|
||||||
|
@ -169,8 +169,7 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EVMDialect::EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVersion _evmVersion):
|
EVMDialect::EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess):
|
||||||
Dialect{_flavour},
|
|
||||||
m_objectAccess(_objectAccess),
|
m_objectAccess(_objectAccess),
|
||||||
m_evmVersion(_evmVersion),
|
m_evmVersion(_evmVersion),
|
||||||
m_functions(createBuiltins(_evmVersion, _objectAccess))
|
m_functions(createBuiltins(_evmVersion, _objectAccess))
|
||||||
@ -191,7 +190,7 @@ EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version
|
|||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||||
if (!dialects[_version])
|
if (!dialects[_version])
|
||||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Strict, false, _version);
|
dialects[_version] = make_unique<EVMDialect>(_version, false);
|
||||||
return *dialects[_version];
|
return *dialects[_version];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +199,7 @@ EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _
|
|||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||||
if (!dialects[_version])
|
if (!dialects[_version])
|
||||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Strict, true, _version);
|
dialects[_version] = make_unique<EVMDialect>(_version, true);
|
||||||
return *dialects[_version];
|
return *dialects[_version];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,7 +208,7 @@ EVMDialect const& EVMDialect::yulForEVM(langutil::EVMVersion _version)
|
|||||||
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects;
|
||||||
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
static YulStringRepository::ResetCallback callback{[&] { dialects.clear(); }};
|
||||||
if (!dialects[_version])
|
if (!dialects[_version])
|
||||||
dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Yul, false, _version);
|
dialects[_version] = make_unique<EVMDialect>(_version, false);
|
||||||
return *dialects[_version];
|
return *dialects[_version];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ struct BuiltinFunctionForEVM: BuiltinFunction
|
|||||||
struct EVMDialect: public Dialect
|
struct EVMDialect: public Dialect
|
||||||
{
|
{
|
||||||
/// Constructor, should only be used internally. Use the factory functions below.
|
/// Constructor, should only be used internally. Use the factory functions below.
|
||||||
EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVersion _evmVersion);
|
EVMDialect(langutil::EVMVersion _evmVersion, bool _objectAccess);
|
||||||
|
|
||||||
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
|
||||||
BuiltinFunctionForEVM const* builtin(YulString _name) const override;
|
BuiltinFunctionForEVM const* builtin(YulString _name) const override;
|
||||||
|
@ -143,7 +143,7 @@ AbstractAssembly::SubID NoOutputAssembly::appendData(bytes const&)
|
|||||||
}
|
}
|
||||||
|
|
||||||
NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom):
|
NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom):
|
||||||
EVMDialect(_copyFrom.flavour, _copyFrom.providesObjectAccess(), _copyFrom.evmVersion())
|
EVMDialect(_copyFrom.evmVersion(), _copyFrom.providesObjectAccess())
|
||||||
{
|
{
|
||||||
for (auto& fun: m_functions)
|
for (auto& fun: m_functions)
|
||||||
{
|
{
|
||||||
|
@ -23,9 +23,12 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
|
|
||||||
WasmDialect::WasmDialect():
|
WasmDialect::WasmDialect()
|
||||||
Dialect{AsmFlavour::Strict}
|
|
||||||
{
|
{
|
||||||
|
defaultType = "i64"_yulstring;
|
||||||
|
boolType = "i64"_yulstring;
|
||||||
|
types = {"i64"_yulstring, "i32"_yulstring};
|
||||||
|
|
||||||
for (auto const& name: {
|
for (auto const& name: {
|
||||||
"i64.add",
|
"i64.add",
|
||||||
"i64.sub",
|
"i64.sub",
|
||||||
|
@ -97,12 +97,12 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
ret.push_back(VariableDeclaration{
|
ret.push_back(VariableDeclaration{
|
||||||
varDecl.location,
|
varDecl.location,
|
||||||
{TypedName{varDecl.location, newLhs[i], "u64"_yulstring}},
|
{TypedName{varDecl.location, newLhs[i], m_defaultType}},
|
||||||
make_unique<Expression>(Literal{locationOf(*varDecl.value), LiteralKind::Number, "0"_yulstring, "u64"_yulstring})
|
make_unique<Expression>(Literal{locationOf(*varDecl.value), LiteralKind::Number, "0"_yulstring, m_defaultType})
|
||||||
});
|
});
|
||||||
ret.push_back(VariableDeclaration{
|
ret.push_back(VariableDeclaration{
|
||||||
varDecl.location,
|
varDecl.location,
|
||||||
{TypedName{varDecl.location, newLhs[3], "u64"_yulstring}},
|
{TypedName{varDecl.location, newLhs[3], m_defaultType}},
|
||||||
std::move(varDecl.value)
|
std::move(varDecl.value)
|
||||||
});
|
});
|
||||||
return {std::move(ret)};
|
return {std::move(ret)};
|
||||||
@ -130,7 +130,7 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
ret.push_back(
|
ret.push_back(
|
||||||
VariableDeclaration{
|
VariableDeclaration{
|
||||||
varDecl.location,
|
varDecl.location,
|
||||||
{TypedName{varDecl.location, newLhs[i], "u64"_yulstring}},
|
{TypedName{varDecl.location, newLhs[i], m_defaultType}},
|
||||||
std::move(newRhs[i])
|
std::move(newRhs[i])
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -157,7 +157,7 @@ void WordSizeTransform::operator()(Block& _block)
|
|||||||
ret.push_back(Assignment{
|
ret.push_back(Assignment{
|
||||||
assignment.location,
|
assignment.location,
|
||||||
{Identifier{assignment.location, newLhs[i]}},
|
{Identifier{assignment.location, newLhs[i]}},
|
||||||
make_unique<Expression>(Literal{locationOf(*assignment.value), LiteralKind::Number, "0"_yulstring, "u64"_yulstring})
|
make_unique<Expression>(Literal{locationOf(*assignment.value), LiteralKind::Number, "0"_yulstring, m_defaultType})
|
||||||
});
|
});
|
||||||
ret.push_back(Assignment{
|
ret.push_back(Assignment{
|
||||||
assignment.location,
|
assignment.location,
|
||||||
@ -208,7 +208,8 @@ void WordSizeTransform::run(Dialect const& _inputDialect, Block& _ast, NameDispe
|
|||||||
{
|
{
|
||||||
// Free the name `or_bool`.
|
// Free the name `or_bool`.
|
||||||
NameDisplacer{_nameDispenser, {"or_bool"_yulstring}}(_ast);
|
NameDisplacer{_nameDispenser, {"or_bool"_yulstring}}(_ast);
|
||||||
WordSizeTransform{_inputDialect, _nameDispenser}(_ast);
|
YulString defaultType; // should be i64 at some point.
|
||||||
|
WordSizeTransform{_inputDialect, _nameDispenser, defaultType}(_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WordSizeTransform::rewriteVarDeclList(TypedNameList& _nameList)
|
void WordSizeTransform::rewriteVarDeclList(TypedNameList& _nameList)
|
||||||
@ -219,7 +220,7 @@ void WordSizeTransform::rewriteVarDeclList(TypedNameList& _nameList)
|
|||||||
{
|
{
|
||||||
TypedNameList ret;
|
TypedNameList ret;
|
||||||
for (auto newName: generateU64IdentifierNames(_n.name))
|
for (auto newName: generateU64IdentifierNames(_n.name))
|
||||||
ret.emplace_back(TypedName{_n.location, newName, "u64"_yulstring});
|
ret.emplace_back(TypedName{_n.location, newName, m_defaultType});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -283,7 +284,7 @@ vector<Statement> WordSizeTransform::handleSwitchInternal(
|
|||||||
|
|
||||||
for (auto& c: cases)
|
for (auto& c: cases)
|
||||||
{
|
{
|
||||||
Literal label{_location, LiteralKind::Number, YulString(c.first.str()), "u64"_yulstring};
|
Literal label{_location, LiteralKind::Number, YulString(c.first.str()), m_defaultType};
|
||||||
ret.cases.emplace_back(Case{
|
ret.cases.emplace_back(Case{
|
||||||
c.second.front().location,
|
c.second.front().location,
|
||||||
make_unique<Literal>(std::move(label)),
|
make_unique<Literal>(std::move(label)),
|
||||||
@ -304,7 +305,7 @@ vector<Statement> WordSizeTransform::handleSwitchInternal(
|
|||||||
Assignment{
|
Assignment{
|
||||||
_location,
|
_location,
|
||||||
{{_location, _runDefaultFlag}},
|
{{_location, _runDefaultFlag}},
|
||||||
make_unique<Expression>(Literal{_location, LiteralKind::Number, "1"_yulstring, "u64"_yulstring})
|
make_unique<Expression>(Literal{_location, LiteralKind::Number, "1"_yulstring, m_defaultType})
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
});
|
});
|
||||||
@ -329,7 +330,7 @@ std::vector<Statement> WordSizeTransform::handleSwitch(Switch& _switch)
|
|||||||
_switch.cases.pop_back();
|
_switch.cases.pop_back();
|
||||||
ret.emplace_back(VariableDeclaration{
|
ret.emplace_back(VariableDeclaration{
|
||||||
_switch.location,
|
_switch.location,
|
||||||
{TypedName{_switch.location, runDefaultFlag, "u64"_yulstring}},
|
{TypedName{_switch.location, runDefaultFlag, m_defaultType}},
|
||||||
{}
|
{}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -384,7 +385,7 @@ array<unique_ptr<Expression>, 4> WordSizeTransform::expandValue(Expression const
|
|||||||
lit.location,
|
lit.location,
|
||||||
LiteralKind::Number,
|
LiteralKind::Number,
|
||||||
YulString(currentVal.str()),
|
YulString(currentVal.str()),
|
||||||
"u64"_yulstring
|
m_defaultType
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,14 @@ public:
|
|||||||
static void run(Dialect const& _inputDialect, Block& _ast, NameDispenser& _nameDispenser);
|
static void run(Dialect const& _inputDialect, Block& _ast, NameDispenser& _nameDispenser);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit WordSizeTransform(Dialect const& _inputDialect, NameDispenser& _nameDispenser):
|
explicit WordSizeTransform(
|
||||||
|
Dialect const& _inputDialect,
|
||||||
|
NameDispenser& _nameDispenser,
|
||||||
|
YulString _defaultType
|
||||||
|
):
|
||||||
m_inputDialect(_inputDialect),
|
m_inputDialect(_inputDialect),
|
||||||
m_nameDispenser(_nameDispenser)
|
m_nameDispenser(_nameDispenser),
|
||||||
|
m_defaultType(_defaultType)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void rewriteVarDeclList(std::vector<TypedName>&);
|
void rewriteVarDeclList(std::vector<TypedName>&);
|
||||||
@ -94,6 +99,7 @@ private:
|
|||||||
|
|
||||||
Dialect const& m_inputDialect;
|
Dialect const& m_inputDialect;
|
||||||
NameDispenser& m_nameDispenser;
|
NameDispenser& m_nameDispenser;
|
||||||
|
YulString m_defaultType;
|
||||||
/// maps original u256 variable's name to corresponding u64 variables' names
|
/// maps original u256 variable's name to corresponding u64 variables' names
|
||||||
std::map<YulString, std::array<YulString, 4>> m_variableMapping;
|
std::map<YulString, std::array<YulString, 4>> m_variableMapping;
|
||||||
};
|
};
|
||||||
|
@ -15,9 +15,9 @@ object "object" {
|
|||||||
function main()
|
function main()
|
||||||
{
|
{
|
||||||
let _1 := 0
|
let _1 := 0
|
||||||
mstore_internal(0, _1, _1, _1, _1)
|
mstore_internal(_1, _1, _1, _1, _1)
|
||||||
mstore_internal(32, _1, _1, _1, 1)
|
mstore_internal(32, _1, _1, _1, 1)
|
||||||
eth.storageStore(0, 32)
|
eth.storageStore(_1, 32)
|
||||||
}
|
}
|
||||||
function endian_swap_16(x) -> y
|
function endian_swap_16(x) -> y
|
||||||
{
|
{
|
||||||
@ -45,7 +45,7 @@ object "object" {
|
|||||||
|
|
||||||
|
|
||||||
Binary representation:
|
Binary representation:
|
||||||
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021004200200020002000200010054220200020002000420110054200a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b
|
0061736d0100000001160460000060017e017e60057e7e7e7e7e0060027f7f0002190108657468657265756d0c73746f7261676553746f7265000303060500010101020503010001060100071102066d656d6f72790200046d61696e00010ab501052801017e420021002000200020002000200010054220200020002000420110052000a74220a710000b1c01017e20004208864280fe0383200042088842ff018384210120010b1b01027e20001002421086210220022000421088100284210120010b1b01027e20001003422086210220022000422088100384210120010b3501007e2000a720011004370300200042087ca720021004370300200042107ca720031004370300200042187ca7200410043703000b
|
||||||
|
|
||||||
Text representation:
|
Text representation:
|
||||||
(module
|
(module
|
||||||
@ -56,9 +56,9 @@ Text representation:
|
|||||||
(func $main
|
(func $main
|
||||||
(local $_1 i64)
|
(local $_1 i64)
|
||||||
(local.set $_1 (i64.const 0))
|
(local.set $_1 (i64.const 0))
|
||||||
(call $mstore_internal (i64.const 0) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
(call $mstore_internal (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))
|
||||||
(call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
|
(call $mstore_internal (i64.const 32) (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 1))
|
||||||
(call $eth.storageStore (i32.wrap_i64 (i64.const 0)) (i32.wrap_i64 (i64.const 32)))
|
(call $eth.storageStore (i32.wrap_i64 (local.get $_1)) (i32.wrap_i64 (i64.const 32)))
|
||||||
)
|
)
|
||||||
|
|
||||||
(func $endian_swap_16
|
(func $endian_swap_16
|
||||||
|
@ -10,23 +10,21 @@
|
|||||||
(local $p i64)
|
(local $p i64)
|
||||||
(local $r i64)
|
(local $r i64)
|
||||||
(local $hi i64)
|
(local $hi i64)
|
||||||
(local $hi_1 i64)
|
|
||||||
(local $y i64)
|
(local $y i64)
|
||||||
(local $hi_2 i64)
|
(local $hi_1 i64)
|
||||||
(local $_2 i64)
|
(local $_2 i64)
|
||||||
(local.set $_1 (i64.const 0))
|
(local.set $_1 (i64.const 0))
|
||||||
(local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64)))
|
(local.set $p (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (i64.const 64)))
|
||||||
(local.set $r (i64.add (local.get $p) (i64.const 64)))
|
(local.set $r (i64.add (local.get $p) (i64.const 64)))
|
||||||
(if (i64.ne (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $p))) (i64.const 0)) (then
|
(if (i64.ne (i64.extend_i32_u (i64.lt_u (local.get $r) (local.get $p))) (i64.const 0)) (then
|
||||||
(unreachable)))
|
(unreachable)))
|
||||||
(local.set $hi (i64.shl (call $endian_swap_16 (local.get $_1)) (i64.const 16)))
|
(local.set $hi (i64.shl (i64.or (i64.shl (i64.or (i64.and (i64.shl (local.get $_1) (i64.const 8)) (i64.const 65280)) (i64.and (i64.shr_u (local.get $_1) (i64.const 8)) (i64.const 255))) (i64.const 16)) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32)))
|
||||||
(local.set $hi_1 (i64.shl (i64.or (local.get $hi) (call $endian_swap_16 (i64.shr_u (local.get $_1) (i64.const 16)))) (i64.const 32)))
|
(local.set $y (i64.or (local.get $hi) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32)))))
|
||||||
(local.set $y (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (local.get $_1) (i64.const 32)))))
|
|
||||||
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $y))
|
(i64.store (i32.wrap_i64 (local.get $r)) (local.get $y))
|
||||||
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 8))) (local.get $y))
|
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 8))) (local.get $y))
|
||||||
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 16))) (local.get $y))
|
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 16))) (local.get $y))
|
||||||
(local.set $hi_2 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
|
(local.set $hi_1 (i64.shl (call $endian_swap_32 (i64.const 128)) (i64.const 32)))
|
||||||
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 24))) (i64.or (local.get $hi_2) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32)))))
|
(i64.store (i32.wrap_i64 (i64.add (local.get $r) (i64.const 24))) (i64.or (local.get $hi_1) (call $endian_swap_32 (i64.shr_u (i64.const 128) (i64.const 32)))))
|
||||||
(local.set $_2 (datasize \"C_2_deployed\"))
|
(local.set $_2 (datasize \"C_2_deployed\"))
|
||||||
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
(call $eth.codeCopy (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (dataoffset \"C_2_deployed\"))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
||||||
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
(call $eth.finish (i32.wrap_i64 (call $to_internal_i32ptr (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_1))) (i32.wrap_i64 (call $u256_to_i32 (local.get $_1) (local.get $_1) (local.get $_1) (local.get $_2))))
|
||||||
|
@ -224,8 +224,8 @@ BOOST_AUTO_TEST_CASE(vardecl_multi_conflict)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(vardecl_bool)
|
BOOST_AUTO_TEST_CASE(vardecl_bool)
|
||||||
{
|
{
|
||||||
CHECK_PARSE_ERROR("{ let x := true }", ParserError, "True and false are not valid literals.");
|
successParse("{ let x := true }");
|
||||||
CHECK_PARSE_ERROR("{ let x := false }", ParserError, "True and false are not valid literals.");
|
successParse("{ let x := false }");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(vardecl_empty)
|
BOOST_AUTO_TEST_CASE(vardecl_empty)
|
||||||
@ -313,7 +313,7 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
|
BOOST_AUTO_TEST_CASE(switch_invalid_expression)
|
||||||
{
|
{
|
||||||
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected.");
|
CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal or identifier expected.");
|
||||||
CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' but got reserved keyword 'default'");
|
CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected '(' but got reserved keyword 'default'");
|
||||||
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to return one item to the stack, but did return 0 items");
|
CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", TypeError, "Expected expression to return one item to the stack, but did return 0 items");
|
||||||
}
|
}
|
||||||
@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(for_statement)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(for_invalid_expression)
|
BOOST_AUTO_TEST_CASE(for_invalid_expression)
|
||||||
{
|
{
|
||||||
CHECK_PARSE_ERROR("{ for {} {} {} {} }", ParserError, "Literal, identifier or instruction expected.");
|
CHECK_PARSE_ERROR("{ for {} {} {} {} }", ParserError, "Literal or identifier expected.");
|
||||||
CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected '{' but got 'Number'");
|
CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected '{' but got 'Number'");
|
||||||
CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected '{' but got 'Number'");
|
CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected '{' but got 'Number'");
|
||||||
CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected '{' but got 'Number'");
|
CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected '{' but got 'Number'");
|
||||||
|
12
test/libsolidity/semanticTests/inlineAssembly/truefalse.sol
Normal file
12
test/libsolidity/semanticTests/inlineAssembly/truefalse.sol
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public returns (uint x, uint y) {
|
||||||
|
assembly {
|
||||||
|
x := true
|
||||||
|
y := false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> 1, 0
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (101-102): Literal, identifier or instruction expected.
|
// ParserError: (101-102): Literal or identifier expected.
|
||||||
|
@ -8,4 +8,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (103-104): Literal, identifier or instruction expected.
|
// ParserError: (103-104): Literal or identifier expected.
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (96-97): Literal, identifier or instruction expected.
|
// ParserError: (96-97): Literal or identifier expected.
|
||||||
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (72-73): Literal, identifier or instruction expected.
|
// ParserError: (72-73): Literal or identifier expected.
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (87-89): Literal, identifier or instruction expected.
|
// ParserError: (87-89): Literal or identifier expected.
|
||||||
|
@ -6,4 +6,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (69-70): Literal, identifier or instruction expected.
|
// ParserError: (71-72): Expected identifier but got '='
|
||||||
|
@ -7,4 +7,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// ParserError: (107-108): Literal, identifier or instruction expected.
|
// ParserError: (109-110): Expected identifier but got '='
|
||||||
|
@ -75,6 +75,27 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(strin
|
|||||||
return make_pair(stack.parserResult()->code, stack.parserResult()->analysisInfo);
|
return make_pair(stack.parserResult()->code, stack.parserResult()->analysisInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(
|
||||||
|
string const& _source,
|
||||||
|
Dialect const& _dialect,
|
||||||
|
ErrorList& _errors
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ErrorReporter errorReporter(_errors);
|
||||||
|
shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(_source, ""));
|
||||||
|
shared_ptr<Object> parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false);
|
||||||
|
if (!parserResult)
|
||||||
|
return {};
|
||||||
|
if (!parserResult->code || !errorReporter.errors().empty())
|
||||||
|
return {};
|
||||||
|
shared_ptr<AsmAnalysisInfo> analysisInfo = make_shared<AsmAnalysisInfo>();
|
||||||
|
AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->dataNames());
|
||||||
|
// TODO this should be done recursively.
|
||||||
|
if (!analyzer.analyze(*parserResult->code) || !errorReporter.errors().empty())
|
||||||
|
return {};
|
||||||
|
return {std::move(parserResult->code), std::move(analysisInfo)};
|
||||||
|
}
|
||||||
|
|
||||||
yul::Block yul::test::disambiguate(string const& _source, bool _yul)
|
yul::Block yul::test::disambiguate(string const& _source, bool _yul)
|
||||||
{
|
{
|
||||||
auto result = parse(_source, _yul);
|
auto result = parse(_source, _yul);
|
||||||
@ -83,5 +104,5 @@ yul::Block yul::test::disambiguate(string const& _source, bool _yul)
|
|||||||
|
|
||||||
string yul::test::format(string const& _source, bool _yul)
|
string yul::test::format(string const& _source, bool _yul)
|
||||||
{
|
{
|
||||||
return yul::AsmPrinter(_yul)(*parse(_source, _yul).first);
|
return yul::AsmPrinter()(*parse(_source, _yul).first);
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,20 @@ using ErrorList = std::vector<std::shared_ptr<Error const>>;
|
|||||||
namespace solidity::yul
|
namespace solidity::yul
|
||||||
{
|
{
|
||||||
struct AsmAnalysisInfo;
|
struct AsmAnalysisInfo;
|
||||||
|
struct Dialect;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace solidity::yul::test
|
namespace solidity::yul::test
|
||||||
{
|
{
|
||||||
|
|
||||||
void printErrors(langutil::ErrorList const& _errors);
|
void printErrors(langutil::ErrorList const& _errors);
|
||||||
|
|
||||||
std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>>
|
std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>>
|
||||||
parse(std::string const& _source, bool _yul = true);
|
parse(std::string const& _source, bool _yul = true);
|
||||||
|
|
||||||
|
std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>>
|
||||||
|
parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& _errors);
|
||||||
|
|
||||||
Block disambiguate(std::string const& _source, bool _yul = true);
|
Block disambiguate(std::string const& _source, bool _yul = true);
|
||||||
std::string format(std::string const& _source, bool _yul = true);
|
std::string format(std::string const& _source, bool _yul = true);
|
||||||
|
|
||||||
|
@ -161,9 +161,9 @@ BOOST_AUTO_TEST_CASE(period_not_as_identifier_start)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(period_in_identifier_spaced)
|
BOOST_AUTO_TEST_CASE(period_in_identifier_spaced)
|
||||||
{
|
{
|
||||||
CHECK_ERROR("{ let x. y:u256 }", ParserError, "Expected ':' but got identifier");
|
CHECK_ERROR("{ let x. y:u256 }", ParserError, "Call or assignment expected");
|
||||||
CHECK_ERROR("{ let x .y:u256 }", ParserError, "Expected ':' but got '.'");
|
CHECK_ERROR("{ let x .y:u256 }", ParserError, "Literal or identifier expected");
|
||||||
CHECK_ERROR("{ let x . y:u256 }", ParserError, "Expected ':' but got '.'");
|
CHECK_ERROR("{ let x . y:u256 }", ParserError, "Literal or identifier expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(period_in_identifier_start)
|
BOOST_AUTO_TEST_CASE(period_in_identifier_start)
|
||||||
@ -234,12 +234,12 @@ BOOST_AUTO_TEST_CASE(tokens_as_identifers)
|
|||||||
BOOST_CHECK(successParse("{ let bool:u256 := 1:u256 }"));
|
BOOST_CHECK(successParse("{ let bool:u256 := 1:u256 }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(lacking_types)
|
BOOST_AUTO_TEST_CASE(optional_types)
|
||||||
{
|
{
|
||||||
CHECK_ERROR("{ let x := 1:u256 }", ParserError, "Expected ':' but got ':='");
|
BOOST_CHECK(successParse("{ let x := 1:u256 }"));
|
||||||
CHECK_ERROR("{ let x:u256 := 1 }", ParserError, "Expected ':' but got '}'");
|
BOOST_CHECK(successParse("{ let x:u256 := 1 }"));
|
||||||
CHECK_ERROR("{ function f(a) {} }", ParserError, "Expected ':' but got ')'");
|
BOOST_CHECK(successParse("{ function f(a) {} }"));
|
||||||
CHECK_ERROR("{ function f(a:u256) -> b {} }", ParserError, "Expected ':' but got '{'");
|
BOOST_CHECK(successParse("{ function f(a:u256) -> b {} }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(invalid_types)
|
BOOST_AUTO_TEST_CASE(invalid_types)
|
||||||
@ -531,7 +531,6 @@ BOOST_AUTO_TEST_CASE(builtins_parser)
|
|||||||
{
|
{
|
||||||
struct SimpleDialect: public Dialect
|
struct SimpleDialect: public Dialect
|
||||||
{
|
{
|
||||||
SimpleDialect(): Dialect(AsmFlavour::Strict) {}
|
|
||||||
BuiltinFunction const* builtin(YulString _name) const override
|
BuiltinFunction const* builtin(YulString _name) const override
|
||||||
{
|
{
|
||||||
return _name == "builtin"_yulstring ? &f : nullptr;
|
return _name == "builtin"_yulstring ? &f : nullptr;
|
||||||
@ -551,7 +550,6 @@ BOOST_AUTO_TEST_CASE(builtins_analysis)
|
|||||||
{
|
{
|
||||||
struct SimpleDialect: public Dialect
|
struct SimpleDialect: public Dialect
|
||||||
{
|
{
|
||||||
SimpleDialect(): Dialect(AsmFlavour::Strict) {}
|
|
||||||
BuiltinFunction const* builtin(YulString _name) const override
|
BuiltinFunction const* builtin(YulString _name) const override
|
||||||
{
|
{
|
||||||
return _name == "builtin"_yulstring ? &f : nullptr;
|
return _name == "builtin"_yulstring ? &f : nullptr;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <test/libyul/YulOptimizerTest.h>
|
#include <test/libyul/YulOptimizerTest.h>
|
||||||
|
|
||||||
#include <test/libsolidity/util/SoltestErrors.h>
|
#include <test/libsolidity/util/SoltestErrors.h>
|
||||||
|
#include <test/libyul/Common.h>
|
||||||
#include <test/Options.h>
|
#include <test/Options.h>
|
||||||
|
|
||||||
#include <libyul/optimiser/BlockFlattener.h>
|
#include <libyul/optimiser/BlockFlattener.h>
|
||||||
@ -364,7 +365,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
|||||||
return TestResult::FatalError;
|
return TestResult::FatalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_obtainedResult = AsmPrinter{m_dialect->flavour == AsmFlavour::Yul}(*m_ast) + "\n";
|
m_obtainedResult = AsmPrinter{}(*m_ast) + "\n";
|
||||||
|
|
||||||
if (m_optimizerStep != m_validatedSettings["step"])
|
if (m_optimizerStep != m_validatedSettings["step"])
|
||||||
{
|
{
|
||||||
@ -418,19 +419,15 @@ void YulOptimizerTest::printIndented(ostream& _stream, string const& _output, st
|
|||||||
|
|
||||||
bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted)
|
||||||
{
|
{
|
||||||
AssemblyStack stack(
|
ErrorList errors;
|
||||||
solidity::test::Options::get().evmVersion(),
|
soltestAssert(m_dialect, "");
|
||||||
m_dialect->flavour == AsmFlavour::Yul ? AssemblyStack::Language::Yul : AssemblyStack::Language::StrictAssembly,
|
std::tie(m_ast, m_analysisInfo) = yul::test::parse(m_source, *m_dialect, errors);
|
||||||
solidity::frontend::OptimiserSettings::none()
|
if (!m_ast || !m_analysisInfo || !errors.empty())
|
||||||
);
|
|
||||||
if (!stack.parseAndAnalyze("", m_source) || !stack.errors().empty())
|
|
||||||
{
|
{
|
||||||
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl;
|
||||||
printErrors(_stream, stack.errors());
|
printErrors(_stream, errors);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_ast = stack.parserResult()->code;
|
|
||||||
m_analysisInfo = stack.parserResult()->analysisInfo;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user