From e5582ffea022b51ecd8195c36febe6e1c5567879 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 3 Dec 2018 17:47:15 +0100 Subject: Use YulString also in expectAsmIdentifier. --- libyul/AsmParser.cpp | 30 +++++++++++++++--------------- libyul/AsmParser.h | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'libyul') diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 2ce94f85..417c0251 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -348,23 +348,23 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() case Token::Byte: case Token::Address: { - string literal; + YulString literal; if (currentToken() == Token::Return) - literal = "return"; + literal = YulString{"return"}; else if (currentToken() == Token::Byte) - literal = "byte"; + literal = YulString{"byte"}; else if (currentToken() == Token::Address) - literal = "address"; + literal = YulString{"address"}; else - literal = currentLiteral(); + literal = YulString{currentLiteral()}; // first search the set of instructions. - if (m_flavour != AsmFlavour::Yul && instructions().count(literal)) + if (m_flavour != AsmFlavour::Yul && instructions().count(literal.str())) { - dev::solidity::Instruction const& instr = instructions().at(literal); + dev::solidity::Instruction const& instr = instructions().at(literal.str()); ret = Instruction{location(), instr}; } else - ret = Identifier{location(), YulString{literal}}; + ret = Identifier{location(), literal}; advance(); break; } @@ -403,7 +403,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() { expectToken(Token::Colon); literal.location.end = endPosition(); - literal.type = YulString{expectAsmIdentifier()}; + literal.type = expectAsmIdentifier(); } else if (kind == LiteralKind::Boolean) fatalParserError("True and false are not valid literals."); @@ -450,7 +450,7 @@ FunctionDefinition Parser::parseFunctionDefinition() RecursionGuard recursionGuard(*this); FunctionDefinition funDef = createWithLocation(); expectToken(Token::Function); - funDef.name = YulString{expectAsmIdentifier()}; + funDef.name = expectAsmIdentifier(); expectToken(Token::LParen); while (currentToken() != Token::RParen) { @@ -565,19 +565,19 @@ TypedName Parser::parseTypedName() { RecursionGuard recursionGuard(*this); TypedName typedName = createWithLocation(); - typedName.name = YulString{expectAsmIdentifier()}; + typedName.name = expectAsmIdentifier(); if (m_flavour == AsmFlavour::Yul) { expectToken(Token::Colon); typedName.location.end = endPosition(); - typedName.type = YulString{expectAsmIdentifier()}; + typedName.type = expectAsmIdentifier(); } return typedName; } -string Parser::expectAsmIdentifier() +YulString Parser::expectAsmIdentifier() { - string name = currentLiteral(); + YulString name = YulString{currentLiteral()}; if (m_flavour == AsmFlavour::Yul) { switch (currentToken()) @@ -592,7 +592,7 @@ string Parser::expectAsmIdentifier() break; } } - else if (instructions().count(name)) + else if (instructions().count(name.str())) fatalParserError("Cannot use instruction names for identifier names."); expectToken(Token::Identifier); return name; diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 52166a20..c1b22334 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -78,7 +78,7 @@ protected: FunctionDefinition parseFunctionDefinition(); Expression parseCall(ElementaryOperation&& _initialOp); TypedName parseTypedName(); - std::string expectAsmIdentifier(); + YulString expectAsmIdentifier(); static bool isValidNumberLiteral(std::string const& _literal); -- cgit v1.2.3 From d829794737233e23b0aa53d0360fa9f626209ba0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 4 Dec 2018 11:22:49 +0100 Subject: Improve yul error messages around number of arguments and variables. --- libyul/AsmAnalysis.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'libyul') diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index d3f6de84..d2efdd9f 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -244,9 +244,18 @@ bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) { int const stackHeight = m_stackHeight; success = boost::apply_visitor(*this, *_varDecl.value); - if ((m_stackHeight - stackHeight) != numVariables) + int numValues = m_stackHeight - stackHeight; + if (numValues != numVariables) { - m_errorReporter.declarationError(_varDecl.location, "Variable count mismatch."); + m_errorReporter.declarationError(_varDecl.location, + "Variable count mismatch: " + + to_string(numVariables) + + " variables and " + + to_string(numValues) + + " values." + ); + // Adjust stack height to avoid misleading additional errors. + m_stackHeight += numVariables - numValues; return false; } } @@ -288,7 +297,7 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) { solAssert(!_funCall.functionName.name.empty(), ""); bool success = true; - size_t arguments = 0; + size_t parameters = 0; size_t returns = 0; if (!m_currentScope->lookup(_funCall.functionName.name, Scope::Visitor( [&](Scope::Variable const&) @@ -310,7 +319,7 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) [&](Scope::Function const& _fun) { /// TODO: compare types too - arguments = _fun.arguments.size(); + parameters = _fun.arguments.size(); returns = _fun.returns.size(); } ))) @@ -319,21 +328,23 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) success = false; } if (success) - { - if (_funCall.arguments.size() != arguments) + if (_funCall.arguments.size() != parameters) { m_errorReporter.typeError( _funCall.functionName.location, - "Expected " + to_string(arguments) + " arguments but got " + + "Function expects " + + to_string(parameters) + + " arguments but got " + to_string(_funCall.arguments.size()) + "." ); success = false; } - } + for (auto const& arg: _funCall.arguments | boost::adaptors::reversed) if (!expectExpression(arg)) success = false; - m_stackHeight += int(returns) - int(arguments); + // Use argument size instead of parameter count to avoid misleading errors. + m_stackHeight += int(returns) - int(_funCall.arguments.size()); m_info.stackHeightInfo[&_funCall] = m_stackHeight; return success; } -- cgit v1.2.3 From 99db4e3ff45c2a8d5d9c645774f099b82b7618ec Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 3 Dec 2018 15:49:23 +0100 Subject: Introduce the concept of builtin functions. --- libyul/AsmAnalysis.cpp | 14 ++++----- libyul/AsmAnalysis.h | 10 +++--- libyul/AsmDataForward.h | 7 ----- libyul/AsmParser.cpp | 26 ++++++++-------- libyul/AsmParser.h | 13 +++++--- libyul/Dialect.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ libyul/ObjectParser.cpp | 2 +- libyul/ObjectParser.h | 7 +++-- 8 files changed, 120 insertions(+), 41 deletions(-) create mode 100644 libyul/Dialect.h (limited to 'libyul') diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index d2efdd9f..5215e5c2 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -101,7 +101,7 @@ bool AsmAnalyzer::operator()(Literal const& _literal) } else if (_literal.kind == LiteralKind::Boolean) { - solAssert(m_flavour == AsmFlavour::Yul, ""); + solAssert(m_dialect.flavour == AsmFlavour::Yul, ""); solAssert(_literal.value == YulString{string("true")} || _literal.value == YulString{string("false")}, ""); } m_info.stackHeightInfo[&_literal] = m_stackHeight; @@ -164,7 +164,7 @@ bool AsmAnalyzer::operator()(Identifier const& _identifier) bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) { - solAssert(m_flavour != AsmFlavour::Yul, ""); + solAssert(m_dialect.flavour != AsmFlavour::Yul, ""); bool success = true; for (auto const& arg: _instr.arguments | boost::adaptors::reversed) if (!expectExpression(arg)) @@ -182,9 +182,9 @@ bool AsmAnalyzer::operator()(ExpressionStatement const& _statement) { int initialStackHeight = m_stackHeight; bool success = boost::apply_visitor(*this, _statement.expression); - if (m_stackHeight != initialStackHeight && (m_flavour != AsmFlavour::Loose || m_errorTypeForLoose)) + if (m_stackHeight != initialStackHeight && (m_dialect.flavour != AsmFlavour::Loose || m_errorTypeForLoose)) { - Error::Type errorType = m_flavour == AsmFlavour::Loose ? *m_errorTypeForLoose : Error::Type::TypeError; + Error::Type errorType = m_dialect.flavour == AsmFlavour::Loose ? *m_errorTypeForLoose : Error::Type::TypeError; string msg = "Top-level expressions are not supposed to return values (this expression returns " + to_string(m_stackHeight - initialStackHeight) + @@ -563,7 +563,7 @@ Scope& AsmAnalyzer::scope(Block const* _block) } void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location) { - if (m_flavour != AsmFlavour::Yul) + if (m_dialect.flavour != AsmFlavour::Yul) return; if (!builtinTypes.count(type)) @@ -623,7 +623,7 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST) { - solAssert(m_flavour == AsmFlavour::Loose, ""); + solAssert(m_dialect.flavour == AsmFlavour::Loose, ""); m_errorReporter.error( m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning, _location, @@ -636,7 +636,7 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio void AsmAnalyzer::checkLooseFeature(SourceLocation const& _location, string const& _description) { - if (m_flavour != AsmFlavour::Loose) + if (m_dialect.flavour != AsmFlavour::Loose) solAssert(false, _description); else if (m_errorTypeForLoose) m_errorReporter.error(*m_errorTypeForLoose, _location, _description); diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h index 34e32eb0..ec2b8868 100644 --- a/libyul/AsmAnalysis.h +++ b/libyul/AsmAnalysis.h @@ -23,12 +23,12 @@ #include #include +#include #include +#include #include -#include - #include #include @@ -59,14 +59,14 @@ public: langutil::ErrorReporter& _errorReporter, dev::solidity::EVMVersion _evmVersion, boost::optional _errorTypeForLoose, - AsmFlavour _flavour = AsmFlavour::Loose, + Dialect _dialect = Dialect::looseAssemblyForEVM(), ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver() ): m_resolver(_resolver), m_info(_analysisInfo), m_errorReporter(_errorReporter), m_evmVersion(_evmVersion), - m_flavour(_flavour), + m_dialect(std::move(_dialect)), m_errorTypeForLoose(_errorTypeForLoose) {} @@ -115,7 +115,7 @@ private: AsmAnalysisInfo& m_info; langutil::ErrorReporter& m_errorReporter; dev::solidity::EVMVersion m_evmVersion; - AsmFlavour m_flavour = AsmFlavour::Loose; + Dialect m_dialect = Dialect::looseAssemblyForEVM(); boost::optional m_errorTypeForLoose; }; diff --git a/libyul/AsmDataForward.h b/libyul/AsmDataForward.h index 046c8248..de564425 100644 --- a/libyul/AsmDataForward.h +++ b/libyul/AsmDataForward.h @@ -49,11 +49,4 @@ struct TypedName; using Expression = boost::variant; using Statement = boost::variant; -enum class AsmFlavour -{ - Loose, // no types, EVM instructions as function, jumps and direct stack manipulations - Strict, // no types, EVM instructions as functions, but no jumps and no direct stack manipulations - Yul // same as Strict mode with types -}; - } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 417c0251..5f393b29 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -107,7 +107,7 @@ Statement Parser::parseStatement() return parseForLoop(); case Token::Assign: { - if (m_flavour != AsmFlavour::Loose) + if (m_dialect.flavour != AsmFlavour::Loose) break; StackAssignment assignment = createWithLocation(); advance(); @@ -174,7 +174,7 @@ Statement Parser::parseStatement() if (currentToken() == Token::Assign && peekNextToken() != Token::Colon) { Assignment assignment = createWithLocation(identifier.location); - if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name.str())) + if (m_dialect.flavour != AsmFlavour::Yul && instructions().count(identifier.name.str())) fatalParserError("Cannot use instruction names for identifier names."); advance(); assignment.variableNames.emplace_back(identifier); @@ -185,7 +185,7 @@ Statement Parser::parseStatement() else { // label - if (m_flavour != AsmFlavour::Loose) + if (m_dialect.flavour != AsmFlavour::Loose) fatalParserError("Labels are not supported."); Label label = createWithLocation