diff options
Diffstat (limited to 'libsolidity')
81 files changed, 1551 insertions, 749 deletions
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index bdd8f61e..7057eab7 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h index f311efbf..9ec04ebe 100644 --- a/libsolidity/analysis/ConstantEvaluator.h +++ b/libsolidity/analysis/ConstantEvaluator.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index 042b7a6a..1599b83a 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/DeclarationContainer.h b/libsolidity/analysis/DeclarationContainer.h index 5862f7a5..9c7c89e7 100644 --- a/libsolidity/analysis/DeclarationContainer.h +++ b/libsolidity/analysis/DeclarationContainer.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index 4f75f03d..58261144 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/DocStringAnalyser.h b/libsolidity/analysis/DocStringAnalyser.h index cdf297e3..bfc8befc 100644 --- a/libsolidity/analysis/DocStringAnalyser.h +++ b/libsolidity/analysis/DocStringAnalyser.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index d075949e..e46868be 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/GlobalContext.h b/libsolidity/analysis/GlobalContext.h index 482391d3..4ed08711 100644 --- a/libsolidity/analysis/GlobalContext.h +++ b/libsolidity/analysis/GlobalContext.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 26d38cfe..2a33a501 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 89b9818b..68c3ffa1 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index a7b9e8b8..66bf1d0e 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -83,6 +83,31 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName) fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract."); } +void ReferencesResolver::endVisit(FunctionTypeName const& _typeName) +{ + switch (_typeName.visibility()) + { + case VariableDeclaration::Visibility::Default: + case VariableDeclaration::Visibility::Internal: + case VariableDeclaration::Visibility::External: + break; + default: + typeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\"."); + } + + if (_typeName.isPayable() && _typeName.visibility() != VariableDeclaration::Visibility::External) + fatalTypeError(_typeName.location(), "Only external function types can be payable."); + if (_typeName.visibility() == VariableDeclaration::Visibility::External) + for (auto const& t: _typeName.parameterTypes() + _typeName.returnParameterTypes()) + { + solAssert(t->annotation().type, "Type not set for parameter."); + if (!t->annotation().type->canBeUsedExternally(false)) + fatalTypeError(t->location(), "Internal type cannot be used for external function type."); + } + + _typeName.annotation().type = make_shared<FunctionType>(_typeName); +} + void ReferencesResolver::endVisit(Mapping const& _typeName) { TypePointer keyType = _typeName.keyType().annotation().type; diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index 1986b2bb..caa3a78f 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -62,6 +62,7 @@ private: virtual bool visit(Identifier const& _identifier) override; virtual bool visit(ElementaryTypeName const& _typeName) override; virtual void endVisit(UserDefinedTypeName const& _typeName) override; + virtual void endVisit(FunctionTypeName const& _typeName) override; virtual void endVisit(Mapping const& _typeName) override; virtual void endVisit(ArrayTypeName const& _typeName) override; virtual bool visit(InlineAssembly const& _inlineAssembly) override; diff --git a/libsolidity/analysis/SemVerHandler.cpp b/libsolidity/analysis/SemVerHandler.cpp index c7b212b2..42186396 100644 --- a/libsolidity/analysis/SemVerHandler.cpp +++ b/libsolidity/analysis/SemVerHandler.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <chris@ethereum.org> diff --git a/libsolidity/analysis/SemVerHandler.h b/libsolidity/analysis/SemVerHandler.h index e3b642db..fae0a764 100644 --- a/libsolidity/analysis/SemVerHandler.h +++ b/libsolidity/analysis/SemVerHandler.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <chris@ethereum.org> diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp new file mode 100644 index 00000000..c39f874e --- /dev/null +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -0,0 +1,78 @@ +/* + 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/>. +*/ +/** + * @author Federico Bond <federicobond@gmail.com> + * @date 2016 + * Static analyzer and checker. + */ + +#include <libsolidity/analysis/StaticAnalyzer.h> +#include <memory> +#include <libsolidity/ast/AST.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; + + +bool StaticAnalyzer::analyze(SourceUnit const& _sourceUnit) +{ + _sourceUnit.accept(*this); + return Error::containsOnlyWarnings(m_errors); +} + +bool StaticAnalyzer::visit(ContractDefinition const& _contract) +{ + m_library = _contract.isLibrary(); + return true; +} + +void StaticAnalyzer::endVisit(ContractDefinition const&) +{ + m_library = false; +} + +bool StaticAnalyzer::visit(FunctionDefinition const& _function) +{ + m_nonPayablePublic = _function.isPublic() && !_function.isPayable(); + return true; +} + +void StaticAnalyzer::endVisit(FunctionDefinition const&) +{ + m_nonPayablePublic = false; +} + +bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) +{ + if (m_nonPayablePublic && !m_library) + if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type.get())) + if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "value") + warning(_memberAccess.location(), "\"msg.value\" used in non-payable function. Do you want to add the \"payable\" modifier to this function?"); + + return true; +} + +void StaticAnalyzer::warning(SourceLocation const& _location, string const& _description) +{ + auto err = make_shared<Error>(Error::Type::Warning); + *err << + errinfo_sourceLocation(_location) << + errinfo_comment(_description); + + m_errors.push_back(err); +} diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h new file mode 100644 index 00000000..b6cf783e --- /dev/null +++ b/libsolidity/analysis/StaticAnalyzer.h @@ -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/>. +*/ +/** + * @author Federico Bond <federicobond@gmail.com> + * @date 2016 + * Static analyzer and checker. + */ + +#pragma once + +#include <libsolidity/analysis/TypeChecker.h> +#include <libsolidity/ast/Types.h> +#include <libsolidity/ast/ASTAnnotations.h> +#include <libsolidity/ast/ASTForward.h> +#include <libsolidity/ast/ASTVisitor.h> + +namespace dev +{ +namespace solidity +{ + + +/** + * The module that performs static analysis on the AST. + */ +class StaticAnalyzer: private ASTConstVisitor +{ +public: + /// @param _errors the reference to the list of errors and warnings to add them found during static analysis. + explicit StaticAnalyzer(ErrorList& _errors): m_errors(_errors) {} + + /// Performs static analysis on the given source unit and all of its sub-nodes. + /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings + bool analyze(SourceUnit const& _sourceUnit); + +private: + /// Adds a new warning to the list of errors. + void warning(SourceLocation const& _location, std::string const& _description); + + virtual bool visit(ContractDefinition const& _contract) override; + virtual void endVisit(ContractDefinition const& _contract) override; + + virtual bool visit(FunctionDefinition const& _function) override; + virtual void endVisit(FunctionDefinition const& _function) override; + + virtual bool visit(MemberAccess const& _memberAccess) override; + + ErrorList& m_errors; + + /// Flag that indicates whether the current contract definition is a library. + bool m_library = false; + + /// Flag that indicates whether a public function does not contain the "payable" modifier. + bool m_nonPayablePublic = false; +}; + +} +} diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index dbaa15ed..0a4943fe 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ #include <libsolidity/analysis/SyntaxChecker.h> diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h index ac8ed872..c24bae09 100644 --- a/libsolidity/analysis/SyntaxChecker.h +++ b/libsolidity/analysis/SyntaxChecker.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ #pragma once diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 46f4f7f6..7235b57a 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -574,6 +574,14 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) return false; } +void TypeChecker::endVisit(FunctionTypeName const& _funType) +{ + FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type); + if (fun.location() == FunctionType::Location::External) + if (!fun.canBeUsedExternally(false)) + typeError(_funType.location(), "External function type uses internal types."); +} + bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { // Inline assembly does not have its own type-checking phase, so we just run the @@ -996,9 +1004,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple) fatalTypeError(components[i]->location(), "Invalid mobile type."); if (i == 0) - inlineArrayType = types[i]->mobileType(); + inlineArrayType = types[i]; else if (inlineArrayType) - inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType()); + inlineArrayType = Type::commonType(inlineArrayType, types[i]); } } else diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index be1e02be..143b15b2 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -87,6 +87,7 @@ private: /// case this is a base constructor call. void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases); virtual bool visit(EventDefinition const& _eventDef) override; + virtual void endVisit(FunctionTypeName const& _funType) override; virtual bool visit(InlineAssembly const& _inlineAssembly) override; virtual bool visit(IfStatement const& _ifStatement) override; virtual bool visit(WhileStatement const& _whileStatement) override; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 695d9881..3cd1dfbe 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -63,6 +63,15 @@ SourceUnitAnnotation& SourceUnit::annotation() const return static_cast<SourceUnitAnnotation&>(*m_annotation); } +string Declaration::sourceUnitName() const +{ + solAssert(!!m_scope, ""); + ASTNode const* scope = m_scope; + while (dynamic_cast<Declaration const*>(scope) && dynamic_cast<Declaration const*>(scope)->m_scope) + scope = dynamic_cast<Declaration const*>(scope)->m_scope; + return dynamic_cast<SourceUnit const&>(*scope).annotation().path; +} + ImportAnnotation& ImportDirective::annotation() const { if (!m_annotation) @@ -160,22 +169,22 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter return *m_interfaceFunctionList; } -string const& ContractDefinition::devDocumentation() const +Json::Value const& ContractDefinition::devDocumentation() const { return m_devDocumentation; } -string const& ContractDefinition::userDocumentation() const +Json::Value const& ContractDefinition::userDocumentation() const { return m_userDocumentation; } -void ContractDefinition::setDevDocumentation(string const& _devDocumentation) +void ContractDefinition::setDevDocumentation(Json::Value const& _devDocumentation) { m_devDocumentation = _devDocumentation; } -void ContractDefinition::setUserDocumentation(string const& _userDocumentation) +void ContractDefinition::setUserDocumentation(Json::Value const& _userDocumentation) { m_userDocumentation = _userDocumentation; } diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 7ed4ddce..ab4be1ea 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -35,6 +35,7 @@ #include <libsolidity/ast/Types.h> #include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/ASTAnnotations.h> +#include <json/json.h> namespace dev { @@ -157,6 +158,10 @@ public: ASTNode const* scope() const { return m_scope; } void setScope(ASTNode const* _scope) { m_scope = _scope; } + /// @returns the source name this declaration is present in. + /// Can be combined with annotation().canonicalName to form a globally unique name. + std::string sourceUnitName() const; + virtual bool isLValue() const { return false; } virtual bool isPartOfExternalInterface() const { return false; } @@ -343,11 +348,11 @@ public: /// Returns the fallback function or nullptr if no fallback function was specified. FunctionDefinition const* fallbackFunction() const; - std::string const& userDocumentation() const; - void setUserDocumentation(std::string const& _userDocumentation); + Json::Value const& userDocumentation() const; + void setUserDocumentation(Json::Value const& _userDocumentation); - std::string const& devDocumentation() const; - void setDevDocumentation(std::string const& _devDocumentation); + Json::Value const& devDocumentation() const; + void setDevDocumentation(Json::Value const& _devDocumentation); virtual TypePointer type() const override; @@ -359,8 +364,8 @@ private: bool m_isLibrary; // parsed Natspec documentation of the contract. - std::string m_userDocumentation; - std::string m_devDocumentation; + Json::Value m_userDocumentation; + Json::Value m_devDocumentation; std::vector<ContractDefinition const*> m_linearizedBaseContracts; mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList; @@ -822,6 +827,41 @@ private: }; /** + * A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)" + */ +class FunctionTypeName: public TypeName +{ +public: + FunctionTypeName( + SourceLocation const& _location, + ASTPointer<ParameterList> const& _parameterTypes, + ASTPointer<ParameterList> const& _returnTypes, + Declaration::Visibility _visibility, + bool _isDeclaredConst, + bool _isPayable + ): + TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes), + m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable) + {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + + std::vector<ASTPointer<VariableDeclaration>> const& parameterTypes() const { return m_parameterTypes->parameters(); } + std::vector<ASTPointer<VariableDeclaration>> const& returnParameterTypes() const { return m_returnTypes->parameters(); } + + Declaration::Visibility visibility() const { return m_visibility; } + bool isDeclaredConst() const { return m_isDeclaredConst; } + bool isPayable() const { return m_isPayable; } + +private: + ASTPointer<ParameterList> m_parameterTypes; + ASTPointer<ParameterList> m_returnTypes; + Declaration::Visibility m_visibility; + bool m_isDeclaredConst; + bool m_isPayable; +}; + +/** * A mapping type. Its source form is "mapping('keyType' => 'valueType')" */ class Mapping: public TypeName @@ -1005,18 +1045,22 @@ public: SourceLocation const& _location, ASTPointer<ASTString> const& _docString, ASTPointer<Expression> const& _condition, - ASTPointer<Statement> const& _body + ASTPointer<Statement> const& _body, + bool _isDoWhile ): - BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body) {} + BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body), + m_isDoWhile(_isDoWhile) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; Expression const& condition() const { return *m_condition; } Statement const& body() const { return *m_body; } + bool isDoWhile() const { return m_isDoWhile; } private: ASTPointer<Expression> m_condition; ASTPointer<Statement> m_body; + bool m_isDoWhile; }; /** diff --git a/libsolidity/ast/ASTAnnotations.cpp b/libsolidity/ast/ASTAnnotations.cpp index 416e6b44..0f958a38 100644 --- a/libsolidity/ast/ASTAnnotations.cpp +++ b/libsolidity/ast/ASTAnnotations.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 2a192e47..768e56db 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index 59fc1b57..cfeeaa58 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -54,6 +54,7 @@ class MagicVariableDeclaration; class TypeName; class ElementaryTypeName; class UserDefinedTypeName; +class FunctionTypeName; class Mapping; class ArrayTypeName; class Statement; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index b573feda..493707b9 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Lefteris <lefteris@ethdev.com> @@ -226,6 +226,20 @@ bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) return true; } +bool ASTJsonConverter::visit(FunctionTypeName const& _node) +{ + string visibility = "internal"; + if (_node.visibility() == Declaration::Visibility::External) + visibility = "external"; + + addJsonNode(_node, "FunctionTypeName", { + make_pair("payable", _node.isPayable()), + make_pair("visibility", visibility), + make_pair("constant", _node.isDeclaredConst()) + }, true); + return true; +} + bool ASTJsonConverter::visit(Mapping const& _node) { addJsonNode(_node, "Mapping", {}, true); @@ -264,7 +278,11 @@ bool ASTJsonConverter::visit(IfStatement const& _node) bool ASTJsonConverter::visit(WhileStatement const& _node) { - addJsonNode(_node, "WhileStatement", {}, true); + addJsonNode( + _node, + _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement", + {}, + true); return true; } @@ -300,7 +318,7 @@ bool ASTJsonConverter::visit(Throw const& _node) bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node) { - addJsonNode(_node, "VariableDefinitionStatement", {}, true); + addJsonNode(_node, "VariableDeclarationStatement", {}, true); return true; } @@ -389,7 +407,7 @@ bool ASTJsonConverter::visit(Identifier const& _node) bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { - addJsonNode(_node, "ElementaryTypenameExpression", { + addJsonNode(_node, "ElementaryTypeNameExpression", { make_pair("value", _node.typeName().toString()), make_pair("type", type(_node)) }); @@ -399,9 +417,8 @@ bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) bool ASTJsonConverter::visit(Literal const& _node) { char const* tokenString = Token::toString(_node.token()); - size_t invalidPos = 0; Json::Value value{_node.value()}; - if (!dev::validate(_node.value(), invalidPos)) + if (!dev::validateUTF8(_node.value())) value = Json::nullValue; Token::Value subdenomination = Token::Value(_node.subDenomination()); addJsonNode(_node, "Literal", { @@ -503,6 +520,11 @@ void ASTJsonConverter::endVisit(UserDefinedTypeName const&) { } +void ASTJsonConverter::endVisit(FunctionTypeName const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(Mapping const&) { goUp(); diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 7c7b37f8..277476d5 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Lefteris <lefteris@ethdev.com> @@ -69,6 +69,7 @@ public: bool visit(TypeName const& _node) override; bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; + bool visit(FunctionTypeName const& _node) override; bool visit(Mapping const& _node) override; bool visit(ArrayTypeName const& _node) override; bool visit(InlineAssembly const& _node) override; @@ -114,6 +115,7 @@ public: void endVisit(TypeName const&) override; void endVisit(ElementaryTypeName const&) override; void endVisit(UserDefinedTypeName const&) override; + void endVisit(FunctionTypeName const&) override; void endVisit(Mapping const&) override; void endVisit(ArrayTypeName const&) override; void endVisit(InlineAssembly const&) override; diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp index a9de457a..23eb3b64 100644 --- a/libsolidity/ast/ASTPrinter.cpp +++ b/libsolidity/ast/ASTPrinter.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -164,6 +164,13 @@ bool ASTPrinter::visit(UserDefinedTypeName const& _node) return goDeeper(); } +bool ASTPrinter::visit(FunctionTypeName const& _node) +{ + writeLine("FunctionTypeName"); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(Mapping const& _node) { writeLine("Mapping"); @@ -208,7 +215,7 @@ bool ASTPrinter::visit(IfStatement const& _node) bool ASTPrinter::visit(WhileStatement const& _node) { - writeLine("WhileStatement"); + writeLine(_node.isDoWhile() ? "DoWhileStatement" : "WhileStatement"); printSourcePart(_node); return goDeeper(); } @@ -442,6 +449,11 @@ void ASTPrinter::endVisit(UserDefinedTypeName const&) m_indentation--; } +void ASTPrinter::endVisit(FunctionTypeName const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(Mapping const&) { m_indentation--; diff --git a/libsolidity/ast/ASTPrinter.h b/libsolidity/ast/ASTPrinter.h index f0ab1098..4a37f17f 100644 --- a/libsolidity/ast/ASTPrinter.h +++ b/libsolidity/ast/ASTPrinter.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -63,6 +63,7 @@ public: bool visit(TypeName const& _node) override; bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; + bool visit(FunctionTypeName const& _node) override; bool visit(Mapping const& _node) override; bool visit(ArrayTypeName const& _node) override; bool visit(InlineAssembly const& _node) override; @@ -106,6 +107,7 @@ public: void endVisit(TypeName const&) override; void endVisit(ElementaryTypeName const&) override; void endVisit(UserDefinedTypeName const&) override; + void endVisit(FunctionTypeName const&) override; void endVisit(Mapping const&) override; void endVisit(ArrayTypeName const&) override; void endVisit(InlineAssembly const&) override; diff --git a/libsolidity/ast/ASTUtils.cpp b/libsolidity/ast/ASTUtils.cpp index e9b70b62..7d180490 100644 --- a/libsolidity/ast/ASTUtils.cpp +++ b/libsolidity/ast/ASTUtils.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/ast/ASTUtils.h b/libsolidity/ast/ASTUtils.h index 237537ec..f7cacf3e 100644 --- a/libsolidity/ast/ASTUtils.h +++ b/libsolidity/ast/ASTUtils.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 3a1b55d3..20be634b 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -61,6 +61,7 @@ public: virtual bool visit(TypeName& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); } virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); } + virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); } virtual bool visit(Mapping& _node) { return visitNode(_node); } virtual bool visit(ArrayTypeName& _node) { return visitNode(_node); } virtual bool visit(InlineAssembly& _node) { return visitNode(_node); } @@ -106,6 +107,7 @@ public: virtual void endVisit(TypeName& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); } virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); } + virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); } virtual void endVisit(Mapping& _node) { endVisitNode(_node); } virtual void endVisit(ArrayTypeName& _node) { endVisitNode(_node); } virtual void endVisit(InlineAssembly& _node) { endVisitNode(_node); } @@ -163,6 +165,7 @@ public: virtual bool visit(TypeName const& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); } virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); } + virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); } virtual bool visit(Mapping const& _node) { return visitNode(_node); } virtual bool visit(ArrayTypeName const& _node) { return visitNode(_node); } virtual bool visit(Block const& _node) { return visitNode(_node); } @@ -208,6 +211,7 @@ public: virtual void endVisit(TypeName const& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); } virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); } + virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); } virtual void endVisit(Mapping const& _node) { endVisitNode(_node); } virtual void endVisit(ArrayTypeName const& _node) { endVisitNode(_node); } virtual void endVisit(Block const& _node) { endVisitNode(_node); } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index b5a3806b..7c1c64b0 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -327,6 +327,26 @@ void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void FunctionTypeName::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + m_parameterTypes->accept(_visitor); + m_returnTypes->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void FunctionTypeName::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + m_parameterTypes->accept(_visitor); + m_returnTypes->accept(_visitor); + } + _visitor.endVisit(*this); +} + void Mapping::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 7fe97fa7..d9660bc0 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -200,10 +200,10 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b) { if (!_a || !_b) return TypePointer(); - else if (_b->isImplicitlyConvertibleTo(*_a)) - return _a; - else if (_a->isImplicitlyConvertibleTo(*_b)) - return _b; + else if (_b->isImplicitlyConvertibleTo(*_a->mobileType())) + return _a->mobileType(); + else if (_a->isImplicitlyConvertibleTo(*_b->mobileType())) + return _b->mobileType(); else return TypePointer(); } @@ -879,7 +879,8 @@ bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo)) return arrayType->isByteArray() && - !(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer()); + !(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer()) && + !(arrayType->isString() && !isValidUTF8()); else return false; } @@ -895,7 +896,7 @@ std::string StringLiteralType::toString(bool) const { size_t invalidSequence; - if (!dev::validate(m_value, invalidSequence)) + if (!dev::validateUTF8(m_value, invalidSequence)) return "literal_string (contains invalid UTF-8 sequence at position " + dev::toString(invalidSequence) + ")"; return "literal_string \"" + m_value + "\""; @@ -906,6 +907,11 @@ TypePointer StringLiteralType::mobileType() const return make_shared<ArrayType>(DataLocation::Memory, true); } +bool StringLiteralType::isValidUTF8() const +{ + return dev::validateUTF8(m_value); +} + shared_ptr<FixedBytesType> FixedBytesType::smallestTypeForLiteral(string const& _literal) { if (_literal.length() <= 32) @@ -1265,6 +1271,7 @@ TypePointer ArrayType::decodingType() const TypePointer ArrayType::interfaceType(bool _inLibrary) const { + // Note: This has to fulfill canBeUsedExternally(_inLibrary) == !!interfaceType(_inLibrary) if (_inLibrary && location() == DataLocation::Storage) return shared_from_this(); @@ -1282,6 +1289,21 @@ TypePointer ArrayType::interfaceType(bool _inLibrary) const return make_shared<ArrayType>(DataLocation::Memory, baseExt, m_length); } +bool ArrayType::canBeUsedExternally(bool _inLibrary) const +{ + // Note: This has to fulfill canBeUsedExternally(_inLibrary) == !!interfaceType(_inLibrary) + if (_inLibrary && location() == DataLocation::Storage) + return true; + else if (m_arrayKind != ArrayKind::Ordinary) + return true; + else if (!m_baseType->canBeUsedExternally(_inLibrary)) + return false; + else if (m_baseType->category() == Category::Array && m_baseType->isDynamicallySized()) + return false; + else + return true; +} + u256 ArrayType::memorySize() const { solAssert(!isDynamicallySized(), ""); @@ -1451,7 +1473,7 @@ u256 StructType::storageSize() const string StructType::toString(bool _short) const { - string ret = "struct " + m_struct.name(); + string ret = "struct " + m_struct.annotation().canonicalName; if (!_short) ret += " " + stringForReferencePart(); return ret; @@ -1561,7 +1583,7 @@ bool EnumType::operator==(Type const& _other) const unsigned EnumType::storageBytes() const { - size_t elements = m_enum.members().size(); + size_t elements = numberOfMembers(); if (elements <= 1) return 1; else @@ -1570,7 +1592,7 @@ unsigned EnumType::storageBytes() const string EnumType::toString(bool) const { - return string("enum ") + m_enum.name(); + return string("enum ") + m_enum.annotation().canonicalName; } string EnumType::canonicalName(bool) const @@ -1578,9 +1600,14 @@ string EnumType::canonicalName(bool) const return m_enum.annotation().canonicalName; } +size_t EnumType::numberOfMembers() const +{ + return m_enum.members().size(); +}; + bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - return _convertTo.category() == category() || _convertTo.category() == Category::Integer; + return _convertTo == *this || _convertTo.category() == Category::Integer; } unsigned EnumType::memberValue(ASTString const& _member) const @@ -1699,7 +1726,7 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_location(_isInternal ? Location::Internal : Location::External), m_isConstant(_function.isDeclaredConst()), - m_isPayable(_function.isPayable()), + m_isPayable(_isInternal ? false : _function.isPayable()), m_declaration(&_function) { TypePointers params; @@ -1800,6 +1827,38 @@ FunctionType::FunctionType(EventDefinition const& _event): swap(paramNames, m_parameterNames); } +FunctionType::FunctionType(FunctionTypeName const& _typeName): + m_location(_typeName.visibility() == VariableDeclaration::Visibility::External ? Location::External : Location::Internal), + m_isConstant(_typeName.isDeclaredConst()), + m_isPayable(_typeName.isPayable()) +{ + if (_typeName.isPayable()) + { + solAssert(m_location == Location::External, "Internal payable function type used."); + solAssert(!m_isConstant, "Payable constant function"); + } + for (auto const& t: _typeName.parameterTypes()) + { + solAssert(t->annotation().type, "Type not set for parameter."); + if (m_location == Location::External) + solAssert( + t->annotation().type->canBeUsedExternally(false), + "Internal type used as parameter for external function." + ); + m_parameterTypes.push_back(t->annotation().type); + } + for (auto const& t: _typeName.returnParameterTypes()) + { + solAssert(t->annotation().type, "Type not set for return parameter."); + if (m_location == Location::External) + solAssert( + t->annotation().type->canBeUsedExternally(false), + "Internal type used as return parameter for external function." + ); + m_returnParameterTypes.push_back(t->annotation().type); + } +} + FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _contract) { FunctionDefinition const* constructor = _contract.constructor(); @@ -1875,22 +1934,69 @@ bool FunctionType::operator==(Type const& _other) const return true; } +TypePointer FunctionType::unaryOperatorResult(Token::Value _operator) const +{ + if (_operator == Token::Value::Delete) + return make_shared<TupleType>(); + return TypePointer(); +} + +string FunctionType::canonicalName(bool) const +{ + solAssert(m_location == Location::External, ""); + return "function"; +} + string FunctionType::toString(bool _short) const { string name = "function ("; for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ","); - name += ") returns ("; - for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it) - name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ","); - return name + ")"; + name += ")"; + if (m_isConstant) + name += " constant"; + if (m_isPayable) + name += " payable"; + if (m_location == Location::External) + name += " external"; + if (!m_returnParameterTypes.empty()) + { + name += " returns ("; + for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it) + name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ","); + name += ")"; + } + return name; +} + +unsigned FunctionType::calldataEncodedSize(bool _padded) const +{ + unsigned size = storageBytes(); + if (_padded) + size = ((size + 31) / 32) * 32; + return size; } u256 FunctionType::storageSize() const { - BOOST_THROW_EXCEPTION( - InternalCompilerError() - << errinfo_comment("Storage size of non-storable function type requested.")); + if (m_location == Location::External || m_location == Location::Internal) + return 1; + else + BOOST_THROW_EXCEPTION( + InternalCompilerError() + << errinfo_comment("Storage size of non-storable function type requested.")); +} + +unsigned FunctionType::storageBytes() const +{ + if (m_location == Location::External) + return 20 + 4; + else if (m_location == Location::Internal) + return 8; // it should really not be possible to create larger programs + else + BOOST_THROW_EXCEPTION( + InternalCompilerError() + << errinfo_comment("Storage size of non-storable function type requested.")); } unsigned FunctionType::sizeOnStack() const @@ -2013,6 +2119,23 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con } } +TypePointer FunctionType::encodingType() const +{ + // Only external functions can be encoded, internal functions cannot leave code boundaries. + if (m_location == Location::External) + return shared_from_this(); + else + return TypePointer(); +} + +TypePointer FunctionType::interfaceType(bool /*_inLibrary*/) const +{ + if (m_location == Location::External) + return shared_from_this(); + else + return TypePointer(); +} + bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const { solAssert(!bound() || _selfType, ""); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 3f94d11a..26e2b8f2 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -254,6 +254,9 @@ public: /// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types /// are returned without modification. virtual TypePointer interfaceType(bool /*_inLibrary*/) const { return TypePointer(); } + /// @returns true iff this type can be passed on via calls (to libraries if _inLibrary is true), + /// should be have identical to !!interfaceType(_inLibrary) but might do optimizations. + virtual bool canBeUsedExternally(bool _inLibrary) const { return !!interfaceType(_inLibrary); } private: /// @returns a member list containing all members added to this type by `using for` directives. @@ -422,6 +425,8 @@ public: virtual std::string toString(bool) const override; virtual TypePointer mobileType() const override; + bool isValidUTF8() const; + std::string const& value() const { return m_value; } private: @@ -580,6 +585,7 @@ public: virtual TypePointer encodingType() const override; virtual TypePointer decodingType() const override; virtual TypePointer interfaceType(bool _inLibrary) const override; + virtual bool canBeUsedExternally(bool _inLibrary) const override; /// @returns true if this is a byte array or a string bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } @@ -738,6 +744,7 @@ public: EnumDefinition const& enumDefinition() const { return m_enum; } /// @returns the value that the string has in the Enum unsigned int memberValue(ASTString const& _member) const; + size_t numberOfMembers() const; private: EnumDefinition const& m_enum; @@ -820,6 +827,8 @@ public: explicit FunctionType(VariableDeclaration const& _varDecl); /// Creates the function type of an event. explicit FunctionType(EventDefinition const& _event); + /// Creates the type of a function type name. + explicit FunctionType(FunctionTypeName const& _typeName); /// Function type constructor to be used for a plain type (not derived from a declaration). FunctionType( strings const& _parameterTypes, @@ -889,12 +898,19 @@ public: TypePointer selfType() const; virtual bool operator==(Type const& _other) const override; + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; + virtual std::string canonicalName(bool /*_addDataLocation*/) const override; virtual std::string toString(bool _short) const override; - virtual bool canBeStored() const override { return false; } + virtual unsigned calldataEncodedSize(bool _padded) const override; + virtual bool canBeStored() const override { return m_location == Location::Internal || m_location == Location::External; } virtual u256 storageSize() const override; - virtual bool canLiveOutsideStorage() const override { return false; } + virtual unsigned storageBytes() const override; + virtual bool isValueType() const override { return true; } + virtual bool canLiveOutsideStorage() const override { return m_location == Location::Internal || m_location == Location::External; } virtual unsigned sizeOnStack() const override; virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; + virtual TypePointer encodingType() const override; + virtual TypePointer interfaceType(bool _inLibrary) const override; /// @returns TypePointer of a new FunctionType object. All input/return parameters are an /// appropriate external types (i.e. the interfaceType()s) of input/return parameters of @@ -1101,6 +1117,8 @@ public: virtual std::string toString(bool _short) const override; + Kind kind() const { return m_kind; } + private: Kind m_kind; }; diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index e7e8a98e..2c982982 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -200,7 +200,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons else if (sourceBaseType->isValueType()) CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false); else - solAssert(false, "Copying of type " + _sourceType.toString(false) + " to storage not yet supported."); + solUnimplemented("Copying of type " + _sourceType.toString(false) + " to storage not yet supported."); // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>... solAssert( 2 + byteOffsetSize + sourceBaseType->sizeOnStack() <= 16, @@ -270,7 +270,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries) const { - solAssert( + solUnimplementedAssert( !_sourceType.baseType()->isDynamicallySized(), "Nested dynamic arrays not implemented here." ); diff --git a/libsolidity/codegen/ArrayUtils.h b/libsolidity/codegen/ArrayUtils.h index 53d36c14..d0ba2892 100644 --- a/libsolidity/codegen/ArrayUtils.h +++ b/libsolidity/codegen/ArrayUtils.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index 1ae5dda9..44264a07 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -30,23 +30,20 @@ using namespace dev::solidity; void Compiler::compileContract( ContractDefinition const& _contract, - std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts + std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts, + bytes const& _metadata ) { - ContractCompiler runtimeCompiler(m_runtimeContext, m_optimize); + ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize); runtimeCompiler.compileContract(_contract, _contracts); + m_runtimeContext.appendAuxiliaryData(_metadata); - ContractCompiler creationCompiler(m_context, m_optimize); - m_runtimeSub = creationCompiler.compileConstructor(m_runtimeContext, _contract, _contracts); + // This might modify m_runtimeContext because it can access runtime functions at + // creation time. + ContractCompiler creationCompiler(&runtimeCompiler, m_context, m_optimize); + m_runtimeSub = creationCompiler.compileConstructor(_contract, _contracts); - if (m_optimize) - m_context.optimise(m_optimizeRuns); - - if (_contract.isLibrary()) - { - solAssert(m_runtimeSub != size_t(-1), ""); - m_context.injectVersionStampIntoSub(m_runtimeSub); - } + m_context.optimise(m_optimize, m_optimizeRuns); } void Compiler::compileClone( @@ -54,11 +51,11 @@ void Compiler::compileClone( map<ContractDefinition const*, eth::Assembly const*> const& _contracts ) { - ContractCompiler cloneCompiler(m_context, m_optimize); + ContractCompiler runtimeCompiler(nullptr, m_runtimeContext, m_optimize); + ContractCompiler cloneCompiler(&runtimeCompiler, m_context, m_optimize); m_runtimeSub = cloneCompiler.compileClone(_contract, _contracts); - if (m_optimize) - m_context.optimise(m_optimizeRuns); + m_context.optimise(m_optimize, m_optimizeRuns); } eth::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _function) const diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index fccb68a9..eef078c1 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -35,12 +35,15 @@ class Compiler public: explicit Compiler(bool _optimize = false, unsigned _runs = 200): m_optimize(_optimize), - m_optimizeRuns(_runs) + m_optimizeRuns(_runs), + m_runtimeContext(), + m_context(&m_runtimeContext) { } void compileContract( ContractDefinition const& _contract, - std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts + std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts, + bytes const& _metadata ); /// Compiles a contract that uses DELEGATECALL to call into a pre-deployed version of the given /// contract at runtime, but contains the full creation-time code. @@ -69,9 +72,9 @@ public: private: bool const m_optimize; unsigned const m_optimizeRuns; - CompilerContext m_context; - size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present. CompilerContext m_runtimeContext; + size_t m_runtimeSub = size_t(-1); ///< Identifier of the runtime sub-assembly, if present. + CompilerContext m_context; }; } diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 3ac5bd3c..2de5a3ec 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -60,8 +60,8 @@ void CompilerContext::startFunction(Declaration const& _function) void CompilerContext::addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent) { - solAssert(m_asm.deposit() >= 0 && unsigned(m_asm.deposit()) >= _offsetToCurrent, ""); - m_localVariables[&_declaration] = unsigned(m_asm.deposit()) - _offsetToCurrent; + solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, ""); + m_localVariables[&_declaration] = unsigned(m_asm->deposit()) - _offsetToCurrent; } void CompilerContext::removeVariable(VariableDeclaration const& _declaration) @@ -92,22 +92,22 @@ eth::AssemblyItem CompilerContext::functionEntryLabelIfExists(Declaration const& return m_functionCompilationQueue.entryLabelIfExists(_declaration); } -eth::AssemblyItem CompilerContext::virtualFunctionEntryLabel(FunctionDefinition const& _function) +FunctionDefinition const& CompilerContext::resolveVirtualFunction(FunctionDefinition const& _function) { // Libraries do not allow inheritance and their functions can be inlined, so we should not // search the inheritance hierarchy (which will be the wrong one in case the function // is inlined). if (auto scope = dynamic_cast<ContractDefinition const*>(_function.scope())) if (scope->isLibrary()) - return functionEntryLabel(_function); + return _function; solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); - return virtualFunctionEntryLabel(_function, m_inheritanceHierarchy.begin()); + return resolveVirtualFunction(_function, m_inheritanceHierarchy.begin()); } -eth::AssemblyItem CompilerContext::superFunctionEntryLabel(FunctionDefinition const& _function, ContractDefinition const& _base) +FunctionDefinition const& CompilerContext::superFunction(FunctionDefinition const& _function, ContractDefinition const& _base) { solAssert(!m_inheritanceHierarchy.empty(), "No inheritance hierarchy set."); - return virtualFunctionEntryLabel(_function, superContract(_base)); + return resolveVirtualFunction(_function, superContract(_base)); } FunctionDefinition const* CompilerContext::nextConstructor(ContractDefinition const& _contract) const @@ -145,12 +145,12 @@ unsigned CompilerContext::baseStackOffsetOfVariable(Declaration const& _declarat unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const { - return m_asm.deposit() - _baseOffset - 1; + return m_asm->deposit() - _baseOffset - 1; } unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const { - return m_asm.deposit() - _offset - 1; + return m_asm->deposit() - _offset - 1; } pair<u256, unsigned> CompilerContext::storageLocationOfVariable(const Declaration& _declaration) const @@ -217,17 +217,10 @@ void CompilerContext::appendInlineAssembly( return true; }; - solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, m_asm, identifierAccess), ""); + solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, *m_asm, identifierAccess), ""); } -void CompilerContext::injectVersionStampIntoSub(size_t _subIndex) -{ - eth::Assembly& sub = m_asm.sub(_subIndex); - sub.injectStart(Instruction::POP); - sub.injectStart(fromBigEndian<u256>(binaryVersion())); -} - -eth::AssemblyItem CompilerContext::virtualFunctionEntryLabel( +FunctionDefinition const& CompilerContext::resolveVirtualFunction( FunctionDefinition const& _function, vector<ContractDefinition const*>::const_iterator _searchStart ) @@ -242,9 +235,9 @@ eth::AssemblyItem CompilerContext::virtualFunctionEntryLabel( !function->isConstructor() && FunctionType(*function).hasEqualArgumentTypes(functionType) ) - return functionEntryLabel(*function); + return *function; solAssert(false, "Super function " + name + " not found."); - return m_asm.newTag(); // not reached + return _function; // not reached } vector<ContractDefinition const*>::const_iterator CompilerContext::superContract(ContractDefinition const& _contract) const @@ -257,7 +250,7 @@ vector<ContractDefinition const*>::const_iterator CompilerContext::superContract void CompilerContext::updateSourceLocation() { - m_asm.setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location()); + m_asm->setSourceLocation(m_visitedNodes.empty() ? SourceLocation() : m_visitedNodes.top()->location()); } eth::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel( diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 0c1500b0..80671528 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -44,6 +44,14 @@ namespace solidity { class CompilerContext { public: + CompilerContext(CompilerContext* _runtimeContext = nullptr): + m_asm(std::make_shared<eth::Assembly>()), + m_runtimeContext(_runtimeContext) + { + if (m_runtimeContext) + m_runtimeSub = size_t(m_asm->newSub(m_runtimeContext->m_asm).data()); + } + void addMagicGlobal(MagicVariableDeclaration const& _declaration); void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); @@ -52,9 +60,9 @@ public: void setCompiledContracts(std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts) { m_compiledContracts = _contracts; } eth::Assembly const& compiledContract(ContractDefinition const& _contract) const; - void setStackOffset(int _offset) { m_asm.setDeposit(_offset); } - void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); } - unsigned stackHeight() const { solAssert(m_asm.deposit() >= 0, ""); return unsigned(m_asm.deposit()); } + void setStackOffset(int _offset) { m_asm->setDeposit(_offset); } + void adjustStackOffset(int _adjustment) { m_asm->adjustDeposit(_adjustment); } + unsigned stackHeight() const { solAssert(m_asm->deposit() >= 0, ""); return unsigned(m_asm->deposit()); } bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration) != 0; } bool isLocalVariable(Declaration const* _declaration) const; @@ -67,10 +75,10 @@ public: eth::AssemblyItem functionEntryLabelIfExists(Declaration const& _declaration) const; void setInheritanceHierarchy(std::vector<ContractDefinition const*> const& _hierarchy) { m_inheritanceHierarchy = _hierarchy; } /// @returns the entry label of the given function and takes overrides into account. - eth::AssemblyItem virtualFunctionEntryLabel(FunctionDefinition const& _function); - /// @returns the entry label of a function that overrides the given declaration from the most derived class just + FunctionDefinition const& resolveVirtualFunction(FunctionDefinition const& _function); + /// @returns the function that overrides the given declaration from the most derived class just /// above _base in the current inheritance hierarchy. - eth::AssemblyItem superFunctionEntryLabel(FunctionDefinition const& _function, ContractDefinition const& _base); + FunctionDefinition const& superFunction(FunctionDefinition const& _function, ContractDefinition const& _base); FunctionDefinition const* nextConstructor(ContractDefinition const& _contract) const; /// @returns the next function in the queue of functions that are still to be compiled @@ -95,30 +103,33 @@ public: std::pair<u256, unsigned> storageLocationOfVariable(Declaration const& _declaration) const; /// Appends a JUMPI instruction to a new tag and @returns the tag - eth::AssemblyItem appendConditionalJump() { return m_asm.appendJumpI().tag(); } + eth::AssemblyItem appendConditionalJump() { return m_asm->appendJumpI().tag(); } /// Appends a JUMPI instruction to @a _tag - CompilerContext& appendConditionalJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJumpI(_tag); return *this; } + CompilerContext& appendConditionalJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJumpI(_tag); return *this; } /// Appends a JUMP to a new tag and @returns the tag - eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } + eth::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); /// Returns an "ErrorTag" - eth::AssemblyItem errorTag() { return m_asm.errorTag(); } + eth::AssemblyItem errorTag() { return m_asm->errorTag(); } /// Appends a JUMP to a specific tag - CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } + CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJump(_tag); return *this; } /// Appends pushing of a new tag and @returns the new tag. - eth::AssemblyItem pushNewTag() { return m_asm.append(m_asm.newPushTag()).tag(); } + eth::AssemblyItem pushNewTag() { return m_asm->append(m_asm->newPushTag()).tag(); } /// @returns a new tag without pushing any opcodes or data - eth::AssemblyItem newTag() { return m_asm.newTag(); } + eth::AssemblyItem newTag() { return m_asm->newTag(); } /// Adds a subroutine to the code (in the data section) and pushes its size (via a tag) - /// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset. - eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); } + /// on the stack. @returns the pushsub assembly item. + eth::AssemblyItem addSubroutine(eth::AssemblyPointer const& _assembly) { auto sub = m_asm->newSub(_assembly); m_asm->append(m_asm->newPushSubSize(size_t(sub.data()))); return sub; } + void pushSubroutineSize(size_t _subRoutine) { m_asm->append(m_asm->newPushSubSize(_subRoutine)); } + /// Pushes the offset of the subroutine. + void pushSubroutineOffset(size_t _subRoutine) { m_asm->append(eth::AssemblyItem(eth::PushSub, _subRoutine)); } /// Pushes the size of the final program - void appendProgramSize() { return m_asm.appendProgramSize(); } + void appendProgramSize() { m_asm->appendProgramSize(); } /// Adds data to the data section, pushes a reference to the stack - eth::AssemblyItem appendData(bytes const& _data) { return m_asm.append(_data); } + eth::AssemblyItem appendData(bytes const& _data) { return m_asm->append(_data); } /// Appends the address (virtual, will be filled in by linker) of a library. - void appendLibraryAddress(std::string const& _identifier) { m_asm.appendLibraryAddress(_identifier); } + void appendLibraryAddress(std::string const& _identifier) { m_asm->appendLibraryAddress(_identifier); } /// Resets the stack of visited nodes with a new stack having only @c _node void resetVisitedNodes(ASTNode const* _node); /// Pops the stack of visited nodes @@ -127,10 +138,10 @@ public: void pushVisitedNodes(ASTNode const* _node) { m_visitedNodes.push(_node); updateSourceLocation(); } /// Append elements to the current instruction list and adjust @a m_stackOffset. - CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; } - CompilerContext& operator<<(Instruction _instruction) { m_asm.append(_instruction); return *this; } - CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; } - CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; } + CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm->append(_item); return *this; } + CompilerContext& operator<<(Instruction _instruction) { m_asm->append(_instruction); return *this; } + CompilerContext& operator<<(u256 const& _value) { m_asm->append(_value); return *this; } + CompilerContext& operator<<(bytes const& _data) { m_asm->append(_data); return *this; } /// Appends inline assembly. @a _replacements are string-matching replacements that are performed /// prior to parsing the inline assembly. @@ -141,25 +152,30 @@ public: std::map<std::string, std::string> const& _replacements = std::map<std::string, std::string>{} ); - /// Prepends "PUSH <compiler version number> POP" - void injectVersionStampIntoSub(size_t _subIndex); + /// Appends arbitrary data to the end of the bytecode. + void appendAuxiliaryData(bytes const& _data) { m_asm->appendAuxiliaryDataToEnd(_data); } + + void optimise(bool _fullOptimsation, unsigned _runs = 200) { m_asm->optimise(_fullOptimsation, true, _runs); } - void optimise(unsigned _runs = 200) { m_asm.optimise(true, true, _runs); } + /// @returns the runtime context if in creation mode and runtime context is set, nullptr otherwise. + CompilerContext* runtimeContext() { return m_runtimeContext; } + /// @returns the identifier of the runtime subroutine. + size_t runtimeSub() const { return m_runtimeSub; } - eth::Assembly const& assembly() const { return m_asm; } + eth::Assembly const& assembly() const { return *m_asm; } /// @returns non-const reference to the underlying assembly. Should be avoided in favour of /// wrappers in this class. - eth::Assembly& nonConstAssembly() { return m_asm; } + eth::Assembly& nonConstAssembly() { return *m_asm; } /// @arg _sourceCodes is the map of input files to source code strings /// @arg _inJsonFormat shows whether the out should be in Json format Json::Value streamAssembly(std::ostream& _stream, StringMap const& _sourceCodes = StringMap(), bool _inJsonFormat = false) const { - return m_asm.stream(_stream, "", _sourceCodes, _inJsonFormat); + return m_asm->stream(_stream, "", _sourceCodes, _inJsonFormat); } - eth::LinkerObject const& assembledObject() { return m_asm.assemble(); } - eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) { return m_asm.sub(_subIndex).assemble(); } + eth::LinkerObject const& assembledObject() { return m_asm->assemble(); } + eth::LinkerObject const& assembledRuntimeObject(size_t _subIndex) { return m_asm->sub(_subIndex).assemble(); } /** * Helper class to pop the visited nodes stack when a scope closes @@ -172,9 +188,9 @@ public: }; private: - /// @returns the entry label of the given function - searches the inheritance hierarchy - /// startig from the given point towards the base. - eth::AssemblyItem virtualFunctionEntryLabel( + /// Searches the inheritance hierarchy towards the base starting from @a _searchStart and returns + /// the first function definition that is overwritten by _function. + FunctionDefinition const& resolveVirtualFunction( FunctionDefinition const& _function, std::vector<ContractDefinition const*>::const_iterator _searchStart ); @@ -215,7 +231,7 @@ private: mutable std::queue<Declaration const*> m_functionsToCompile; } m_functionCompilationQueue; - eth::Assembly m_asm; + eth::AssemblyPointer m_asm; /// Magic global variables like msg, tx or this, distinguished by type. std::set<Declaration const*> m_magicGlobals; /// Other already compiled contracts to be used in contract creation calls. @@ -228,6 +244,10 @@ private: std::vector<ContractDefinition const*> m_inheritanceHierarchy; /// Stack of current visited AST nodes, used for location attachment std::stack<ASTNode const*> m_visitedNodes; + /// The runtime context if in Creation mode, this is used for generating tags that would be stored into the storage and then used at runtime. + CompilerContext *m_runtimeContext; + /// The index of the runtime subroutine. + size_t m_runtimeSub = -1; }; } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index e064c1a6..7c159ff7 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -133,12 +133,22 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound m_context << u256(str->value().size()); m_context << Instruction::ADD; } + else if ( + _type.category() == Type::Category::Function && + dynamic_cast<FunctionType const&>(_type).location() == FunctionType::Location::External + ) + { + solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented."); + combineExternalFunctionType(true); + m_context << Instruction::DUP2 << Instruction::MSTORE; + m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; + } else { unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); if (numBytes > 0) { - solAssert( + solUnimplementedAssert( _type.sizeOnStack() == 1, "Memory store of types with stack size != 1 not implemented." ); @@ -161,7 +171,7 @@ void CompilerUtils::encodeToMemory( solAssert(targetTypes.size() == _givenTypes.size(), ""); for (TypePointer& t: targetTypes) { - solAssert( + solUnimplementedAssert( t->mobileType() && t->mobileType()->interfaceType(_encodeAsLibraryTypes) && t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(), @@ -206,7 +216,8 @@ void CompilerUtils::encodeToMemory( else if ( _givenTypes[i]->dataStoredIn(DataLocation::Storage) || _givenTypes[i]->dataStoredIn(DataLocation::CallData) || - _givenTypes[i]->category() == Type::Category::StringLiteral + _givenTypes[i]->category() == Type::Category::StringLiteral || + _givenTypes[i]->category() == Type::Category::Function ) type = _givenTypes[i]; // delay conversion else @@ -301,10 +312,54 @@ void CompilerUtils::memoryCopy() m_context << Instruction::DIV << u256(c_identityWordGas) << Instruction::MUL; m_context << u256(c_identityGas) << Instruction::ADD; m_context << Instruction::CALL; - m_context << Instruction::POP; // ignore return value + m_context << Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); } -void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) +void CompilerUtils::splitExternalFunctionType(bool _leftAligned) +{ + // We have to split the left-aligned <address><function identifier> into two stack slots: + // address (right aligned), function identifier (right aligned) + if (_leftAligned) + { + m_context << Instruction::DUP1 << (u256(1) << (64 + 32)) << Instruction::SWAP1 << Instruction::DIV; + // <input> <address> + m_context << Instruction::SWAP1 << (u256(1) << 64) << Instruction::SWAP1 << Instruction::DIV; + } + else + { + m_context << Instruction::DUP1 << (u256(1) << 32) << Instruction::SWAP1 << Instruction::DIV; + m_context << ((u256(1) << 160) - 1) << Instruction::AND << Instruction::SWAP1; + } + m_context << u256(0xffffffffUL) << Instruction::AND; +} + +void CompilerUtils::combineExternalFunctionType(bool _leftAligned) +{ + // <address> <function_id> + m_context << u256(0xffffffffUL) << Instruction::AND << Instruction::SWAP1; + if (!_leftAligned) + m_context << ((u256(1) << 160) - 1) << Instruction::AND; + m_context << (u256(1) << 32) << Instruction::MUL; + m_context << Instruction::OR; + if (_leftAligned) + m_context << (u256(1) << 64) << Instruction::MUL; +} + +void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function) +{ + m_context << m_context.functionEntryLabel(_function).pushTag(); + // If there is a runtime context, we have to merge both labels into the same + // stack slot in case we store it in storage. + if (CompilerContext* rtc = m_context.runtimeContext()) + m_context << + (u256(1) << 32) << + Instruction::MUL << + rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) << + Instruction::OR; +} + +void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded, bool _chopSignBits) { // For a type extension, we need to remove all higher-order bits that we might have ignored in // previous operations. @@ -315,6 +370,14 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp Type::Category stackTypeCategory = _typeOnStack.category(); Type::Category targetTypeCategory = _targetType.category(); + bool enumOverflowCheckPending = (targetTypeCategory == Type::Category::Enum || stackTypeCategory == Type::Category::Enum); + bool chopSignBitsPending = _chopSignBits && targetTypeCategory == Type::Category::Integer; + if (chopSignBitsPending) + { + const IntegerType& targetIntegerType = dynamic_cast<const IntegerType &>(_targetType); + chopSignBitsPending = targetIntegerType.isSigned(); + } + switch (stackTypeCategory) { case Type::Category::FixedBytes: @@ -348,10 +411,18 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp } break; case Type::Category::Enum: - solAssert(targetTypeCategory == Type::Category::Integer || targetTypeCategory == Type::Category::Enum, ""); + solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, ""); + if (enumOverflowCheckPending) + { + EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack); + solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); + m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; + m_context.appendConditionalJumpTo(m_context.errorTag()); + enumOverflowCheckPending = false; + } break; case Type::Category::FixedPoint: - solAssert(false, "Not yet implemented - FixedPointType."); + solUnimplemented("Not yet implemented - FixedPointType."); case Type::Category::Integer: case Type::Category::Contract: case Type::Category::RationalNumber: @@ -372,6 +443,11 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp solAssert(_typeOnStack.mobileType(), ""); // just clean convertType(_typeOnStack, *_typeOnStack.mobileType(), true); + EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType); + solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); + m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; + m_context.appendConditionalJumpTo(m_context.errorTag()); + enumOverflowCheckPending = false; } else if (targetTypeCategory == Type::Category::FixedPoint) { @@ -386,7 +462,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack)) if (targetFixedPointType.integerBits() > typeOnStack->numBits()) cleanHigherOrderBits(*typeOnStack); - solAssert(false, "Not yet implemented - FixedPointType."); + solUnimplemented("Not yet implemented - FixedPointType."); } else { @@ -399,7 +475,7 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp RationalNumberType const& constType = dynamic_cast<RationalNumberType const&>(_typeOnStack); // We know that the stack is clean, we only have to clean for a narrowing conversion // where cleanup is forced. - solAssert(!constType.isFractional(), "Not yet implemented - FixedPointType."); + solUnimplementedAssert(!constType.isFractional(), "Not yet implemented - FixedPointType."); if (targetType.numBits() < constType.integerType()->numBits() && _cleanupNeeded) cleanHigherOrderBits(targetType); } @@ -413,6 +489,14 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp cleanHigherOrderBits(typeOnStack); else if (_cleanupNeeded) cleanHigherOrderBits(targetType); + if (chopSignBitsPending) + { + if (typeOnStack.numBits() < 256) + m_context + << ((u256(1) << typeOnStack.numBits()) - 1) + << Instruction::AND; + chopSignBitsPending = false; + } } } break; @@ -651,15 +735,31 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp solAssert(_targetType == _typeOnStack, "Invalid conversion for bool."); if (_cleanupNeeded) m_context << Instruction::ISZERO << Instruction::ISZERO; + break; default: // All other types should not be convertible to non-equal types. solAssert(_typeOnStack == _targetType, "Invalid type conversion requested."); + if (_cleanupNeeded && _targetType.canBeStored() && _targetType.storageBytes() < 32) + m_context + << ((u256(1) << (8 * _targetType.storageBytes())) - 1) + << Instruction::AND; break; } + + solAssert(!enumOverflowCheckPending, "enum overflow checking missing."); + solAssert(!chopSignBitsPending, "forgot to chop the sign bits."); } void CompilerUtils::pushZeroValue(Type const& _type) { + if (auto const* funType = dynamic_cast<FunctionType const*>(&_type)) + { + if (funType->location() == FunctionType::Location::Internal) + { + m_context << m_context.errorTag(); + return; + } + } auto const* referenceType = dynamic_cast<ReferenceType const*>(&_type); if (!referenceType || referenceType->location() == DataLocation::Storage) { @@ -804,22 +904,30 @@ void CompilerUtils::storeStringData(bytesConstRef _data) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) { unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries); - bool leftAligned = _type.category() == Type::Category::FixedBytes; + bool isExternalFunctionType = false; + if (auto const* funType = dynamic_cast<FunctionType const*>(&_type)) + if (funType->location() == FunctionType::Location::External) + isExternalFunctionType = true; if (numBytes == 0) + { m_context << Instruction::POP << u256(0); - else + return numBytes; + } + solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); + m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD); + if (isExternalFunctionType) + splitExternalFunctionType(true); + else if (numBytes != 32) { - solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested."); - m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD); - if (numBytes != 32) - { - // add leading or trailing zeros by dividing/multiplying depending on alignment - u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); - m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV; - if (leftAligned) - m_context << shiftFactor << Instruction::MUL; - } + bool leftAligned = _type.category() == Type::Category::FixedBytes; + // add leading or trailing zeros by dividing/multiplying depending on alignment + u256 shiftFactor = u256(1) << ((32 - numBytes) * 8); + m_context << shiftFactor << Instruction::SWAP1 << Instruction::DIV; + if (leftAligned) + m_context << shiftFactor << Instruction::MUL; } + if (_fromCalldata) + convertType(_type, _type, true); return numBytes; } @@ -834,7 +942,7 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack) m_context << ((u256(1) << _typeOnStack.numBits()) - 1) << Instruction::AND; } -unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const +unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) { unsigned numBytes = _type.calldataEncodedSize(_padToWordBoundaries); bool leftAligned = _type.category() == Type::Category::FixedBytes; @@ -843,6 +951,7 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBou else { solAssert(numBytes <= 32, "Memory store of more than 32 bytes requested."); + convertType(_type, _type, true); if (numBytes != 32 && !leftAligned && !_padToWordBoundaries) // shift the value accordingly before storing m_context << (u256(1) << ((32 - numBytes) * 8)) << Instruction::MUL; diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index da74dc90..0a5d8e1c 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -114,12 +114,24 @@ public: /// Stack post: void memoryCopy(); + /// Converts the combined and left-aligned (right-aligned if @a _rightAligned is true) + /// external function type <address><function identifier> into two stack slots: + /// address (right aligned), function identifier (right aligned) + void splitExternalFunctionType(bool _rightAligned); + /// Performs the opposite operation of splitExternalFunctionType(_rightAligned) + void combineExternalFunctionType(bool _rightAligned); + /// Appends code that combines the construction-time (if available) and runtime function + /// entry label of the given function into a single stack slot. + /// Note: This might cause the compilation queue of the runtime context to be extended. + void pushCombinedFunctionEntryLabel(Declaration const& _function); + /// Appends code for an implicit or explicit type conversion. This includes erasing higher /// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory /// if a reference type is converted from calldata or storage to memory. /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be /// necessary. - void convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); + /// If @a _chopSignBits, the function resets the signed bits out of the width of the signed integer. + void convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false, bool _chopSignBits = false); /// Creates a zero-value for the given type and puts it onto the stack. This might allocate /// memory for memory references. @@ -173,7 +185,7 @@ private: void cleanHigherOrderBits(IntegerType const& _typeOnStack); /// Prepares the given type for storing in memory by shifting it if necessary. - unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const; + unsigned prepareMemoryStore(Type const& _type, bool _padToWordBoundaries); /// Loads type from memory assuming memory offset is on stack top. unsigned loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index ebb84784..a0f196bc 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -60,14 +60,13 @@ void ContractCompiler::compileContract( } size_t ContractCompiler::compileConstructor( - CompilerContext const& _runtimeContext, ContractDefinition const& _contract, std::map<const ContractDefinition*, eth::Assembly const*> const& _contracts ) { CompilerContext::LocationSetter locationSetter(m_context, _contract); initializeContext(_contract, _contracts); - return packIntoContractCreator(_contract, _runtimeContext); + return packIntoContractCreator(_contract); } size_t ContractCompiler::compileClone( @@ -80,7 +79,7 @@ size_t ContractCompiler::compileClone( appendInitAndConstructorCode(_contract); //@todo determine largest return size of all runtime functions - eth::AssemblyItem runtimeSub = m_context.addSubroutine(cloneRuntime()); + auto runtimeSub = m_context.addSubroutine(cloneRuntime()); // stack contains sub size m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; @@ -88,7 +87,6 @@ size_t ContractCompiler::compileClone( appendMissingFunctions(); - solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), ""); return size_t(runtimeSub.data()); } @@ -104,6 +102,13 @@ void ContractCompiler::initializeContext( m_context.resetVisitedNodes(&_contract); } +void ContractCompiler::appendCallValueCheck() +{ + // Throw if function is not payable but call contained ether. + m_context << Instruction::CALLVALUE; + m_context.appendConditionalJumpTo(m_context.errorTag()); +} + void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _contract) { // Determine the arguments that are used for the base constructors. @@ -139,23 +144,35 @@ void ContractCompiler::appendInitAndConstructorCode(ContractDefinition const& _c appendConstructor(*constructor); else if (auto c = m_context.nextConstructor(_contract)) appendBaseConstructor(*c); + else + appendCallValueCheck(); } -size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext) +size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _contract) { - appendInitAndConstructorCode(_contract); + solAssert(!!m_runtimeCompiler, ""); - eth::AssemblyItem runtimeSub = m_context.addSubroutine(_runtimeContext.assembly()); + appendInitAndConstructorCode(_contract); - // stack contains sub size - m_context << Instruction::DUP1 << runtimeSub << u256(0) << Instruction::CODECOPY; - m_context << u256(0) << Instruction::RETURN; + // We jump to the deploy routine because we first have to append all missing functions, + // which can cause further functions to be added to the runtime context. + eth::AssemblyItem deployRoutine = m_context.appendJumpToNew(); - // note that we have to include the functions again because of absolute jump labels + // We have to include copies of functions in the construction time and runtime context + // because of absolute jumps. appendMissingFunctions(); + m_runtimeCompiler->appendMissingFunctions(); - solAssert(runtimeSub.data() < numeric_limits<size_t>::max(), ""); - return size_t(runtimeSub.data()); + m_context << deployRoutine; + + solAssert(m_context.runtimeSub() != size_t(-1), "Runtime sub not registered"); + m_context.pushSubroutineSize(m_context.runtimeSub()); + m_context << Instruction::DUP1; + m_context.pushSubroutineOffset(m_context.runtimeSub()); + m_context << u256(0) << Instruction::CODECOPY; + m_context << u256(0) << Instruction::RETURN; + + return m_context.runtimeSub(); } void ContractCompiler::appendBaseConstructor(FunctionDefinition const& _constructor) @@ -176,6 +193,9 @@ void ContractCompiler::appendBaseConstructor(FunctionDefinition const& _construc void ContractCompiler::appendConstructor(FunctionDefinition const& _constructor) { CompilerContext::LocationSetter locationSetter(m_context, _constructor); + if (!_constructor.isPayable()) + appendCallValueCheck(); + // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program if (!_constructor.parameters().empty()) { @@ -243,11 +263,8 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac if (fallback) { if (!fallback->isPayable()) - { - // Throw if function is not payable but call contained ether. - m_context << Instruction::CALLVALUE; - m_context.appendConditionalJumpTo(m_context.errorTag()); - } + appendCallValueCheck(); + eth::AssemblyItem returnTag = m_context.pushNewTag(); fallback->accept(*this); m_context << returnTag; @@ -266,11 +283,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac // We have to allow this for libraries, because value of the previous // call is still visible in the delegatecall. if (!functionType->isPayable() && !_contract.isLibrary()) - { - // Throw if function is not payable but call contained ether. - m_context << Instruction::CALLVALUE; - m_context.appendConditionalJumpTo(m_context.errorTag()); - } + appendCallValueCheck(); eth::AssemblyItem returnTag = m_context.pushNewTag(); m_context << CompilerUtils::dataStartOffset; @@ -293,13 +306,14 @@ void ContractCompiler::appendCalldataUnpacker(TypePointers const& _typeParameter { // stack: v1 v2 ... v(k-1) base_offset current_offset TypePointer type = parameterType->decodingType(); + solAssert(type, "No decoding type found."); if (type->category() == Type::Category::Array) { auto const& arrayType = dynamic_cast<ArrayType const&>(*type); - solAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); + solUnimplementedAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); if (_fromMemory) { - solAssert( + solUnimplementedAssert( arrayType.baseType()->isValueType(), "Nested memory arrays not yet implemented here." ); @@ -515,7 +529,19 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { solAssert(!!decl->type(), "Type of declaration required but not yet determined."); if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(decl)) - _assembly.append(m_context.virtualFunctionEntryLabel(*functionDef).pushTag()); + { + functionDef = &m_context.resolveVirtualFunction(*functionDef); + _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag()); + // If there is a runtime context, we have to merge both labels into the same + // stack slot in case we store it in storage. + if (CompilerContext* rtc = m_context.runtimeContext()) + { + _assembly.append(u256(1) << 32); + _assembly.append(Instruction::MUL); + _assembly.append(rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub())); + _assembly.append(Instruction::OR); + } + } else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl)) { solAssert(!variable->isConstant(), ""); @@ -557,7 +583,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) // lvalue context auto variable = dynamic_cast<VariableDeclaration const*>(decl); solAssert( - !!variable || !m_context.isLocalVariable(variable), + !!variable && m_context.isLocalVariable(variable), "Can only assign to stack variables in inline assembly." ); unsigned size = variable->type()->sizeOnStack(); @@ -611,12 +637,25 @@ bool ContractCompiler::visit(WhileStatement const& _whileStatement) m_breakTags.push_back(loopEnd); m_context << loopStart; - compileExpression(_whileStatement.condition()); - m_context << Instruction::ISZERO; - m_context.appendConditionalJumpTo(loopEnd); + + // While loops have the condition prepended + if (!_whileStatement.isDoWhile()) + { + compileExpression(_whileStatement.condition()); + m_context << Instruction::ISZERO; + m_context.appendConditionalJumpTo(loopEnd); + } _whileStatement.body().accept(*this); + // Do-while loops have the condition appended + if (_whileStatement.isDoWhile()) + { + compileExpression(_whileStatement.condition()); + m_context << Instruction::ISZERO; + m_context.appendConditionalJumpTo(loopEnd); + } + m_context.appendJumpTo(loopStart); m_context << loopEnd; @@ -823,8 +862,6 @@ void ContractCompiler::appendModifierOrFunctionCode() CompilerUtils::sizeOnStack(modifier.parameters()) + CompilerUtils::sizeOnStack(modifier.localVariables()); codeBlock = &modifier.body(); - - codeBlock = &modifier.body(); } } @@ -858,7 +895,7 @@ void ContractCompiler::compileExpression(Expression const& _expression, TypePoin CompilerUtils(m_context).convertType(*_expression.annotation().type, *_targetType); } -eth::Assembly ContractCompiler::cloneRuntime() +eth::AssemblyPointer ContractCompiler::cloneRuntime() { eth::Assembly a; a << Instruction::CALLDATASIZE; @@ -876,5 +913,5 @@ eth::Assembly ContractCompiler::cloneRuntime() a.appendJumpI(a.errorTag()); //@todo adjust for larger return values, make this dynamic. a << u256(0x20) << u256(0) << Instruction::RETURN; - return a; + return make_shared<eth::Assembly>(a); } diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 0799a543..38c1e045 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -38,11 +38,12 @@ namespace solidity { class ContractCompiler: private ASTConstVisitor { public: - explicit ContractCompiler(CompilerContext& _context, bool _optimise): + explicit ContractCompiler(ContractCompiler* _runtimeCompiler, CompilerContext& _context, bool _optimise): m_optimise(_optimise), + m_runtimeCompiler(_runtimeCompiler), m_context(_context) { - m_context = CompilerContext(); + m_context = CompilerContext(_runtimeCompiler ? &_runtimeCompiler->m_context : nullptr); } void compileContract( @@ -52,7 +53,6 @@ public: /// Compiles the constructor part of the contract. /// @returns the identifier of the runtime sub-assembly. size_t compileConstructor( - CompilerContext const& _runtimeContext, ContractDefinition const& _contract, std::map<ContractDefinition const*, eth::Assembly const*> const& _contracts ); @@ -74,12 +74,13 @@ private: /// Adds the code that is run at creation time. Should be run after exchanging the run-time context /// with a new and initialized context. Adds the constructor code. /// @returns the identifier of the runtime sub assembly - size_t packIntoContractCreator(ContractDefinition const& _contract, CompilerContext const& _runtimeContext); + size_t packIntoContractCreator(ContractDefinition const& _contract); /// Appends state variable initialisation and constructor code. void appendInitAndConstructorCode(ContractDefinition const& _contract); void appendBaseConstructor(FunctionDefinition const& _constructor); void appendConstructor(FunctionDefinition const& _constructor); void appendFunctionSelector(ContractDefinition const& _contract); + void appendCallValueCheck(); /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. /// From memory if @a _fromMemory is true, otherwise from call data. /// Expects source offset on the stack, which is removed. @@ -114,9 +115,11 @@ private: void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); /// @returns the runtime assembly for clone contracts. - static eth::Assembly cloneRuntime(); + static eth::AssemblyPointer cloneRuntime(); bool const m_optimise; + /// Pointer to the runtime compiler in case this is a creation compiler. + ContractCompiler* m_runtimeCompiler = nullptr; CompilerContext& m_context; std::vector<eth::AssemblyItem> m_breakTags; ///< tag to jump to for a "break" statement std::vector<eth::AssemblyItem> m_continueTags; ///< tag to jump to for a "continue" statement diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 9a096e2d..5748d818 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -99,7 +99,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get())) { solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); - solAssert( + solUnimplementedAssert( !paramTypes[i]->isDynamicallySized(), "Accessors for mapping with dynamically-sized keys not yet implemented." ); @@ -211,7 +211,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) Token::Value op = _assignment.assignmentOperator(); if (op != Token::Assign) // compound assignment { - solAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types."); + solUnimplementedAssert(_assignment.annotation().type->isValueType(), "Compound operators not implemented for non-value types."); unsigned lvalueSize = m_currentLValue->sizeOnStack(); unsigned itemSize = _assignment.annotation().type->sizeOnStack(); if (lvalueSize > 0) @@ -312,7 +312,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) if (!_unaryOperation.isPrefixOperation()) { // store value for later - solAssert(_unaryOperation.annotation().type->sizeOnStack() == 1, "Stack size != 1 not implemented."); + solUnimplementedAssert(_unaryOperation.annotation().type->sizeOnStack() == 1, "Stack size != 1 not implemented."); m_context << Instruction::DUP1; if (m_currentLValue->sizeOnStack() > 0) for (unsigned i = 1 + m_currentLValue->sizeOnStack(); i > 0; --i) @@ -488,6 +488,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) parameterSize += function.selfType()->sizeOnStack(); } + if (m_context.runtimeContext()) + // We have a runtime context, so we need the creation part. + m_context << (u256(1) << 32) << Instruction::SWAP1 << Instruction::DIV; + else + // Extract the runtime part. + m_context << ((u256(1) << 32) - 1) << Instruction::AND; + m_context.appendJump(eth::AssemblyItem::JumpType::IntoFunction); m_context << returnLabel; @@ -521,8 +528,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // copy the contract's code into memory eth::Assembly const& assembly = m_context.compiledContract(contract); utils().fetchFreeMemoryPointer(); + // TODO we create a copy here, which is actually what we want. + // This should be revisited at the point where we fix + // https://github.com/ethereum/solidity/issues/1092 // pushes size - eth::AssemblyItem subroutine = m_context.addSubroutine(assembly); + auto subroutine = m_context.addSubroutine(make_shared<eth::Assembly>(assembly)); m_context << Instruction::DUP1 << subroutine; m_context << Instruction::DUP4 << Instruction::CODECOPY; @@ -845,9 +855,8 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) ); if (funType->location() == FunctionType::Location::Internal) { - m_context << m_context.functionEntryLabel( - dynamic_cast<FunctionDefinition const&>(funType->declaration()) - ).pushTag(); + FunctionDefinition const& funDef = dynamic_cast<decltype(funDef)>(funType->declaration()); + utils().pushCombinedFunctionEntryLabel(funDef); utils().moveIntoStack(funType->selfType()->sizeOnStack(), 1); } else @@ -883,7 +892,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) // us to link against it although we actually do not need it. auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration); solAssert(!!function, "Function not found in member access"); - m_context << m_context.functionEntryLabel(*function).pushTag(); + utils().pushCombinedFunctionEntryLabel(*function); } } else if (dynamic_cast<TypeType const*>(_memberAccess.annotation().type.get())) @@ -915,10 +924,10 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) if (type.isSuper()) { solAssert(!!_memberAccess.annotation().referencedDeclaration, "Referenced declaration not resolved."); - m_context << m_context.superFunctionEntryLabel( + utils().pushCombinedFunctionEntryLabel(m_context.superFunction( dynamic_cast<FunctionDefinition const&>(*_memberAccess.annotation().referencedDeclaration), type.contractDefinition() - ).pushTag(); + )); } else { @@ -1141,7 +1150,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) break; case DataLocation::CallData: //@todo if we implement this, the value in calldata has to be added to the base offset - solAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); + solUnimplementedAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); if (arrayType.baseType()->isValueType()) CompilerUtils(m_context).loadFromMemoryDynamic( *arrayType.baseType(), @@ -1203,7 +1212,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) } } else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration)) - m_context << m_context.virtualFunctionEntryLabel(*functionDef).pushTag(); + utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef)); else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration)) appendVariable(*variable, static_cast<Expression const&>(_identifier)); else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration)) @@ -1243,7 +1252,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) case Type::Category::StringLiteral: break; // will be done during conversion default: - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now.")); + solUnimplemented("Only integer, boolean and string literals implemented for now."); } } @@ -1266,6 +1275,17 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type { if (_operator == Token::Equal || _operator == Token::NotEqual) { + if (FunctionType const* funType = dynamic_cast<decltype(funType)>(&_type)) + { + if (funType->location() == FunctionType::Location::Internal) + { + // We have to remove the upper bits (construction time value) because they might + // be "unknown" in one of the operands and not in the other. + m_context << ((u256(1) << 32) - 1) << Instruction::AND; + m_context << Instruction::SWAP1; + m_context << ((u256(1) << 32) - 1) << Instruction::AND; + } + } m_context << Instruction::EQ; if (_operator == Token::NotEqual) m_context << Instruction::ISZERO; @@ -1318,7 +1338,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty bool const c_isSigned = type.isSigned(); if (_type.category() == Type::Category::FixedPoint) - solAssert(false, "Not yet implemented - FixedPointType."); + solUnimplemented("Not yet implemented - FixedPointType."); switch (_operator) { @@ -1372,7 +1392,7 @@ void ExpressionCompiler::appendBitOperatorCode(Token::Value _operator) void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) { - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Shift operators not yet implemented.")); + solUnimplemented("Shift operators not yet implemented."); switch (_operator) { case Token::SHL: @@ -1634,7 +1654,7 @@ void ExpressionCompiler::appendExternalFunctionCall( void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression) { - solAssert(_expectedType.isValueType(), "Not implemented for non-value types."); + solUnimplementedAssert(_expectedType.isValueType(), "Not implemented for non-value types."); _expression.accept(*this); utils().convertType(*_expression.annotation().type, _expectedType, true); utils().storeInMemoryDynamic(_expectedType); diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index f4ce1fec..f08bded9 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index c1e05792..b9e141d8 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -120,7 +120,7 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool } else { - solAssert(_sourceType == *m_dataType, "Conversion not implemented for assignment to memory."); + solUnimplementedAssert(_sourceType == *m_dataType, "Conversion not implemented for assignment to memory."); solAssert(m_dataType->sizeOnStack() == 1, ""); if (!_move) @@ -153,7 +153,8 @@ StorageItem::StorageItem(CompilerContext& _compilerContext, Type const& _type): { if (m_dataType->isValueType()) { - solAssert(m_dataType->storageSize() == m_dataType->sizeOnStack(), ""); + if (m_dataType->category() != Type::Category::Function) + solAssert(m_dataType->storageSize() == m_dataType->sizeOnStack(), ""); solAssert(m_dataType->storageSize() == 1, "Invalid storage size."); } } @@ -176,27 +177,47 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const m_context << Instruction::POP << Instruction::SLOAD; else { + bool cleaned = false; m_context << Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1 << u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV; if (m_dataType->category() == Type::Category::FixedPoint) // implementation should be very similar to the integer case. - solAssert(false, "Not yet implemented - FixedPointType."); + solUnimplemented("Not yet implemented - FixedPointType."); if (m_dataType->category() == Type::Category::FixedBytes) + { m_context << (u256(0x1) << (256 - 8 * m_dataType->storageBytes())) << Instruction::MUL; + cleaned = true; + } else if ( m_dataType->category() == Type::Category::Integer && dynamic_cast<IntegerType const&>(*m_dataType).isSigned() ) + { m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND; - else + cleaned = true; + } + else if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType)) + { + if (fun->location() == FunctionType::Location::External) + { + CompilerUtils(m_context).splitExternalFunctionType(false); + cleaned = true; + } + } + if (!cleaned) + { + solAssert(m_dataType->sizeOnStack() == 1, ""); m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::AND; + } } } void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _location, bool _move) const { CompilerUtils utils(m_context); + solAssert(m_dataType, ""); + // stack: value storage_key storage_offset if (m_dataType->isValueType()) { @@ -204,10 +225,16 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc solAssert(m_dataType->storageBytes() > 0, "Invalid storage bytes size."); if (m_dataType->storageBytes() == 32) { + solAssert(m_dataType->sizeOnStack() == 1, "Invalid stack size."); // offset should be zero m_context << Instruction::POP; if (!_move) m_context << Instruction::DUP2 << Instruction::SWAP1; + + m_context << Instruction::SWAP1; + utils.convertType(_sourceType, *m_dataType, true); + m_context << Instruction::SWAP1; + m_context << Instruction::SSTORE; } else @@ -222,28 +249,39 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc m_context << Instruction::DUP2 << ((u256(1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::MUL; - m_context << Instruction::NOT << Instruction::AND; - // stack: value storage_ref multiplier cleared_value - m_context - << Instruction::SWAP1 << Instruction::DUP4; + m_context << Instruction::NOT << Instruction::AND << Instruction::SWAP1; + // stack: value storage_ref cleared_value multiplier + utils.copyToStackTop(3 + m_dataType->sizeOnStack(), m_dataType->sizeOnStack()); // stack: value storage_ref cleared_value multiplier value - if (m_dataType->category() == Type::Category::FixedBytes) + if (FunctionType const* fun = dynamic_cast<decltype(fun)>(m_dataType)) + { + solAssert(_sourceType == *m_dataType, "function item stored but target is not equal to source"); + if (fun->location() == FunctionType::Location::External) + // Combine the two-item function type into a single stack slot. + utils.combineExternalFunctionType(false); + else + m_context << + ((u256(1) << (8 * m_dataType->storageBytes())) - 1) << + Instruction::AND; + } + else if (m_dataType->category() == Type::Category::FixedBytes) + { + solAssert(_sourceType.category() == Type::Category::FixedBytes, "source not fixed bytes"); m_context << (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(*m_dataType).numBytes())) << Instruction::SWAP1 << Instruction::DIV; + } else + { + solAssert(m_dataType->sizeOnStack() == 1, "Invalid stack size for opaque type."); // remove the higher order bits - m_context - << (u256(1) << (8 * (32 - m_dataType->storageBytes()))) - << Instruction::SWAP1 - << Instruction::DUP2 - << Instruction::MUL - << Instruction::DIV; + utils.convertType(_sourceType, *m_dataType, true, true); + } m_context << Instruction::MUL << Instruction::OR; // stack: value storage_ref updated_value m_context << Instruction::SWAP1 << Instruction::SSTORE; if (_move) - m_context << Instruction::POP; + utils.popStackElement(*m_dataType); } } else diff --git a/libsolidity/codegen/LValue.h b/libsolidity/codegen/LValue.h index a2f979db..f8b68362 100644 --- a/libsolidity/codegen/LValue.h +++ b/libsolidity/codegen/LValue.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index 813fa3ab..2903a4e3 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -410,6 +410,16 @@ bool Why3Translator::visit(WhileStatement const& _node) { addSourceFromDocStrings(_node.annotation()); + // Why3 does not appear to support do-while loops, + // so we will simulate them by performing a while + // loop with the body prepended once. + + if (_node.isDoWhile()) + { + visitIndentedUnlessBlock(_node.body()); + newLine(); + } + add("while "); _node.condition().accept(*this); newLine(); diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h index 4fdac385..03f3bf9c 100644 --- a/libsolidity/formal/Why3Translator.h +++ b/libsolidity/formal/Why3Translator.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt deleted file mode 100644 index d84ee10c..00000000 --- a/libsolidity/grammar.txt +++ /dev/null @@ -1,106 +0,0 @@ -SourceUnit = (PragmaDirective | ImportDirective | ContractDefinition)* - -// Pragma actually parses anything up to the trailing ';' to be fully forward-compatible. -PragmaDirective = 'pragma' Identifier Expression ';' - -ImportDirective = 'import' StringLiteral ('as' Identifier)? ';' - | 'import' ('*' | Identifier) ('as' Identifier)? 'from' StringLiteral ';' - | 'import' '{' Identifier ('as' Identifier)? ( ',' Identifier ('as' Identifier)? )* '}' 'from' StringLiteral ';' - -ContractDefinition = ( 'contract' | 'library' ) Identifier - ( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )? - '{' ContractPart* '}' - -ContractPart = StateVariableDeclaration | UsingForDeclaration - | StructDefinition | ModifierDefinition | FunctionDefinition | EventDefinition | EnumDefinition - -InheritanceSpecifier = Identifier ( '(' Expression ( ',' Expression )* ')' )? - -StateVariableDeclaration = TypeName ( 'public' | 'internal' | 'private' )? Identifier ('=' Expression)? ';' -UsingForDeclaration = 'using' Identifier 'for' ('*' | TypeName) ';' -StructDefinition = 'struct' Identifier '{' - ( VariableDeclaration ';' (VariableDeclaration ';')* )? '}' -ModifierDefinition = 'modifier' Identifier ParameterList? Block -FunctionDefinition = 'function' Identifier? ParameterList - ( FunctionCall | Identifier | 'constant' | 'external' | 'public' | 'internal' | 'private' )* - ( 'returns' ParameterList )? Block -EventDefinition = 'event' Identifier IndexedParameterList 'anonymous'? ';' - -EnumValue = Identifier -EnumDefinition = 'enum' Identifier '{' EnumValue? (',' EnumValue)* '}' - -IndexedParameterList = '(' ( TypeName 'indexed'? Identifier? (',' TypeName 'indexed'? Identifier?)* )? ')' -ParameterList = '(' ( TypeName Identifier? (',' TypeName Identifier?)* )? ')' - -// semantic restriction: mappings and structs (recursively) containing mappings -// are not allowed in argument lists -VariableDeclaration = TypeName Identifier -TypeName = ElementaryTypeName | Identifier StorageLocation? | Mapping | ArrayTypeName -Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')' -ArrayTypeName = TypeName StorageLocation? '[' Expression? ']' -StorageLocation = 'memory' | 'storage' - -Block = '{' Statement* '}' -Statement = IfStatement | WhileStatement | ForStatement | Block | - ( PlaceholderStatement | Continue | Break | Return | - Throw | SimpleStatement ) ';' - -ExpressionStatement = Expression -IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )? -WhileStatement = 'while' '(' Expression ')' Statement -PlaceholderStatement = '_' -SimpleStatement = VariableDefinition | ExpressionStatement -ForStatement = 'for' '(' (SimpleStatement)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement -Continue = 'continue' -Break = 'break' -Return = 'return' Expression? -Throw = 'throw' -VariableDefinition = VariableDeclaration ( '=' Expression )? - -// Precedence by order (see github.com/ethereum/solidity/pull/732) -Expression = - ( Expression ('++' | '--') | FunctionCall | IndexAccess | MemberAccess | '(' Expression ')' ) - | ('!' | '~' | 'delete' | '++' | '--' | '+' | '-') Expression - | Expression '**' Expression - | Expression ('*' | '/' | '%') Expression - | Expression ('+' | '-') Expression - | Expression ('<<' | '>>' | '>>>') - | Expression '&' Expression - | Expression '^' Expression - | Expression '|' Expression - | Expression ('<' | '>' | '<=' | '>=') Expression - | Expression ('==' | '!=') Expression - | Expression '&&' Expression - | Expression '||' Expression - | Expression '?' Expression ':' Expression - | Expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') Expression - | Expression? (',' Expression) - | PrimaryExpression - -PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | HexLiteral | StringLiteral - -FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' Expression? ( ',' Expression )* ')' -NewExpression = 'new' Identifier -MemberAccess = Expression '.' Identifier -IndexAccess = Expression '[' Expression? ']' - -BooleanLiteral = 'true' | 'false' -NumberLiteral = '0x'? [0-9]+ (' ' NumberUnit)? -NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether' - | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' -HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'') -StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"' -Identifier = [a-zA-Z_] [a-zA-Z_0-9]* - -ElementaryTypeName = 'address' | 'bool' | 'string' | 'var' - | Int | Uint | Byte | Fixed | Ufixed - -Int = 'int' | 'int8' | 'int16' | 'int24' | 'int32' | 'int40' | 'int48' | 'int56' | 'int64' | 'int72' | 'int80' | 'int88' | 'int96' | 'int104' | 'int112' | 'int120' | 'int128' | 'int136' | 'int144' | 'int152' | 'int160' | 'int168' | 'int176' | 'int184' | 'int192' | 'int200' | 'int208' | 'int216' | 'int224' | 'int232' | 'int240' | 'int248' | 'int256' - -Uint = 'uint' | 'uint8' | 'uint16' | 'uint24' | 'uint32' | 'uint40' | 'uint48' | 'uint56' | 'uint64' | 'uint72' | 'uint80' | 'uint88' | 'uint96' | 'uint104' | 'uint112' | 'uint120' | 'uint128' | 'uint136' | 'uint144' | 'uint152' | 'uint160' | 'uint168' | 'uint176' | 'uint184' | 'uint192' | 'uint200' | 'uint208' | 'uint216' | 'uint224' | 'uint232' | 'uint240' | 'uint248' | 'uint256' - -Byte = 'byte' | 'bytes' | 'bytes1' | 'bytes2' | 'bytes3' | 'bytes4' | 'bytes5' | 'bytes6' | 'bytes7' | 'bytes8' | 'bytes9' | 'bytes10' | 'bytes11' | 'bytes12' | 'bytes13' | 'bytes14' | 'bytes15' | 'bytes16' | 'bytes17' | 'bytes18' | 'bytes19' | 'bytes20' | 'bytes21' | 'bytes22' | 'bytes23' | 'bytes24' | 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32' - -Fixed = 'fixed' | 'fixed0x8' | 'fixed0x16' | 'fixed0x24' | 'fixed0x32' | 'fixed0x40' | 'fixed0x48' | 'fixed0x56' | 'fixed0x64' | 'fixed0x72' | 'fixed0x80' | 'fixed0x88' | 'fixed0x96' | 'fixed0x104' | 'fixed0x112' | 'fixed0x120' | 'fixed0x128' | 'fixed0x136' | 'fixed0x144' | 'fixed0x152' | 'fixed0x160' | 'fixed0x168' | 'fixed0x176' | 'fixed0x184' | 'fixed0x192' | 'fixed0x200' | 'fixed0x208' | 'fixed0x216' | 'fixed0x224' | 'fixed0x232' | 'fixed0x240' | 'fixed0x248' | 'fixed0x256' | 'fixed8x8' | 'fixed8x16' | 'fixed8x24' | 'fixed8x32' | 'fixed8x40' | 'fixed8x48' | 'fixed8x56' | 'fixed8x64' | 'fixed8x72' | 'fixed8x80' | 'fixed8x88' | 'fixed8x96' | 'fixed8x104' | 'fixed8x112' | 'fixed8x120' | 'fixed8x128' | 'fixed8x136' | 'fixed8x144' | 'fixed8x152' | 'fixed8x160' | 'fixed8x168' | 'fixed8x176' | 'fixed8x184' | 'fixed8x192' | 'fixed8x200' | 'fixed8x208' | 'fixed8x216' | 'fixed8x224' | 'fixed8x232' | 'fixed8x240' | 'fixed8x248' | 'fixed16x8' | 'fixed16x16' | 'fixed16x24' | 'fixed16x32' | 'fixed16x40' | 'fixed16x48' | 'fixed16x56' | 'fixed16x64' | 'fixed16x72' | 'fixed16x80' | 'fixed16x88' | 'fixed16x96' | 'fixed16x104' | 'fixed16x112' | 'fixed16x120' | 'fixed16x128' | 'fixed16x136' | 'fixed16x144' | 'fixed16x152' | 'fixed16x160' | 'fixed16x168' | 'fixed16x176' | 'fixed16x184' | 'fixed16x192' | 'fixed16x200' | 'fixed16x208' | 'fixed16x216' | 'fixed16x224' | 'fixed16x232' | 'fixed16x240' | 'fixed24x8' | 'fixed24x16' | 'fixed24x24' | 'fixed24x32' | 'fixed24x40' | 'fixed24x48' | 'fixed24x56' | 'fixed24x64' | 'fixed24x72' | 'fixed24x80' | 'fixed24x88' | 'fixed24x96' | 'fixed24x104' | 'fixed24x112' | 'fixed24x120' | 'fixed24x128' | 'fixed24x136' | 'fixed24x144' | 'fixed24x152' | 'fixed24x160' | 'fixed24x168' | 'fixed24x176' | 'fixed24x184' | 'fixed24x192' | 'fixed24x200' | 'fixed24x208' | 'fixed24x216' | 'fixed24x224' | 'fixed24x232' | 'fixed32x8' | 'fixed32x16' | 'fixed32x24' | 'fixed32x32' | 'fixed32x40' | 'fixed32x48' | 'fixed32x56' | 'fixed32x64' | 'fixed32x72' | 'fixed32x80' | 'fixed32x88' | 'fixed32x96' | 'fixed32x104' | 'fixed32x112' | 'fixed32x120' | 'fixed32x128' | 'fixed32x136' | 'fixed32x144' | 'fixed32x152' | 'fixed32x160' | 'fixed32x168' | 'fixed32x176' | 'fixed32x184' | 'fixed32x192' | 'fixed32x200' | 'fixed32x208' | 'fixed32x216' | 'fixed32x224' | 'fixed40x8' | 'fixed40x16' | 'fixed40x24' | 'fixed40x32' | 'fixed40x40' | 'fixed40x48' | 'fixed40x56' | 'fixed40x64' | 'fixed40x72' | 'fixed40x80' | 'fixed40x88' | 'fixed40x96' | 'fixed40x104' | 'fixed40x112' | 'fixed40x120' | 'fixed40x128' | 'fixed40x136' | 'fixed40x144' | 'fixed40x152' | 'fixed40x160' | 'fixed40x168' | 'fixed40x176' | 'fixed40x184' | 'fixed40x192' | 'fixed40x200' | 'fixed40x208' | 'fixed40x216' | 'fixed48x8' | 'fixed48x16' | 'fixed48x24' | 'fixed48x32' | 'fixed48x40' | 'fixed48x48' | 'fixed48x56' | 'fixed48x64' | 'fixed48x72' | 'fixed48x80' | 'fixed48x88' | 'fixed48x96' | 'fixed48x104' | 'fixed48x112' | 'fixed48x120' | 'fixed48x128' | 'fixed48x136' | 'fixed48x144' | 'fixed48x152' | 'fixed48x160' | 'fixed48x168' | 'fixed48x176' | 'fixed48x184' | 'fixed48x192' | 'fixed48x200' | 'fixed48x208' | 'fixed56x8' | 'fixed56x16' | 'fixed56x24' | 'fixed56x32' | 'fixed56x40' | 'fixed56x48' | 'fixed56x56' | 'fixed56x64' | 'fixed56x72' | 'fixed56x80' | 'fixed56x88' | 'fixed56x96' | 'fixed56x104' | 'fixed56x112' | 'fixed56x120' | 'fixed56x128' | 'fixed56x136' | 'fixed56x144' | 'fixed56x152' | 'fixed56x160' | 'fixed56x168' | 'fixed56x176' | 'fixed56x184' | 'fixed56x192' | 'fixed56x200' | 'fixed64x8' | 'fixed64x16' | 'fixed64x24' | 'fixed64x32' | 'fixed64x40' | 'fixed64x48' | 'fixed64x56' | 'fixed64x64' | 'fixed64x72' | 'fixed64x80' | 'fixed64x88' | 'fixed64x96' | 'fixed64x104' | 'fixed64x112' | 'fixed64x120' | 'fixed64x128' | 'fixed64x136' | 'fixed64x144' | 'fixed64x152' | 'fixed64x160' | 'fixed64x168' | 'fixed64x176' | 'fixed64x184' | 'fixed64x192' | 'fixed72x8' | 'fixed72x16' | 'fixed72x24' | 'fixed72x32' | 'fixed72x40' | 'fixed72x48' | 'fixed72x56' | 'fixed72x64' | 'fixed72x72' | 'fixed72x80' | 'fixed72x88' | 'fixed72x96' | 'fixed72x104' | 'fixed72x112' | 'fixed72x120' | 'fixed72x128' | 'fixed72x136' | 'fixed72x144' | 'fixed72x152' | 'fixed72x160' | 'fixed72x168' | 'fixed72x176' | 'fixed72x184' | 'fixed80x8' | 'fixed80x16' | 'fixed80x24' | 'fixed80x32' | 'fixed80x40' | 'fixed80x48' | 'fixed80x56' | 'fixed80x64' | 'fixed80x72' | 'fixed80x80' | 'fixed80x88' | 'fixed80x96' | 'fixed80x104' | 'fixed80x112' | 'fixed80x120' | 'fixed80x128' | 'fixed80x136' | 'fixed80x144' | 'fixed80x152' | 'fixed80x160' | 'fixed80x168' | 'fixed80x176' | 'fixed88x8' | 'fixed88x16' | 'fixed88x24' | 'fixed88x32' | 'fixed88x40' | 'fixed88x48' | 'fixed88x56' | 'fixed88x64' | 'fixed88x72' | 'fixed88x80' | 'fixed88x88' | 'fixed88x96' | 'fixed88x104' | 'fixed88x112' | 'fixed88x120' | 'fixed88x128' | 'fixed88x136' | 'fixed88x144' | 'fixed88x152' | 'fixed88x160' | 'fixed88x168' | 'fixed96x8' | 'fixed96x16' | 'fixed96x24' | 'fixed96x32' | 'fixed96x40' | 'fixed96x48' | 'fixed96x56' | 'fixed96x64' | 'fixed96x72' | 'fixed96x80' | 'fixed96x88' | 'fixed96x96' | 'fixed96x104' | 'fixed96x112' | 'fixed96x120' | 'fixed96x128' | 'fixed96x136' | 'fixed96x144' | 'fixed96x152' | 'fixed96x160' | 'fixed104x8' | 'fixed104x16' | 'fixed104x24' | 'fixed104x32' | 'fixed104x40' | 'fixed104x48' | 'fixed104x56' | 'fixed104x64' | 'fixed104x72' | 'fixed104x80' | 'fixed104x88' | 'fixed104x96' | 'fixed104x104' | 'fixed104x112' | 'fixed104x120' | 'fixed104x128' | 'fixed104x136' | 'fixed104x144' | 'fixed104x152' | 'fixed112x8' | 'fixed112x16' | 'fixed112x24' | 'fixed112x32' | 'fixed112x40' | 'fixed112x48' | 'fixed112x56' | 'fixed112x64' | 'fixed112x72' | 'fixed112x80' | 'fixed112x88' | 'fixed112x96' | 'fixed112x104' | 'fixed112x112' | 'fixed112x120' | 'fixed112x128' | 'fixed112x136' | 'fixed112x144' | 'fixed120x8' | 'fixed120x16' | 'fixed120x24' | 'fixed120x32' | 'fixed120x40' | 'fixed120x48' | 'fixed120x56' | 'fixed120x64' | 'fixed120x72' | 'fixed120x80' | 'fixed120x88' | 'fixed120x96' | 'fixed120x104' | 'fixed120x112' | 'fixed120x120' | 'fixed120x128' | 'fixed120x136' | 'fixed128x8' | 'fixed128x16' | 'fixed128x24' | 'fixed128x32' | 'fixed128x40' | 'fixed128x48' | 'fixed128x56' | 'fixed128x64' | 'fixed128x72' | 'fixed128x80' | 'fixed128x88' | 'fixed128x96' | 'fixed128x104' | 'fixed128x112' | 'fixed128x120' | 'fixed128x128' | 'fixed136x8' | 'fixed136x16' | 'fixed136x24' | 'fixed136x32' | 'fixed136x40' | 'fixed136x48' | 'fixed136x56' | 'fixed136x64' | 'fixed136x72' | 'fixed136x80' | 'fixed136x88' | 'fixed136x96' | 'fixed136x104' | 'fixed136x112' | 'fixed136x120' | 'fixed144x8' | 'fixed144x16' | 'fixed144x24' | 'fixed144x32' | 'fixed144x40' | 'fixed144x48' | 'fixed144x56' | 'fixed144x64' | 'fixed144x72' | 'fixed144x80' | 'fixed144x88' | 'fixed144x96' | 'fixed144x104' | 'fixed144x112' | 'fixed152x8' | 'fixed152x16' | 'fixed152x24' | 'fixed152x32' | 'fixed152x40' | 'fixed152x48' | 'fixed152x56' | 'fixed152x64' | 'fixed152x72' | 'fixed152x80' | 'fixed152x88' | 'fixed152x96' | 'fixed152x104' | 'fixed160x8' | 'fixed160x16' | 'fixed160x24' | 'fixed160x32' | 'fixed160x40' | 'fixed160x48' | 'fixed160x56' | 'fixed160x64' | 'fixed160x72' | 'fixed160x80' | 'fixed160x88' | 'fixed160x96' | 'fixed168x8' | 'fixed168x16' | 'fixed168x24' | 'fixed168x32' | 'fixed168x40' | 'fixed168x48' | 'fixed168x56' | 'fixed168x64' | 'fixed168x72' | 'fixed168x80' | 'fixed168x88' | 'fixed176x8' | 'fixed176x16' | 'fixed176x24' | 'fixed176x32' | 'fixed176x40' | 'fixed176x48' | 'fixed176x56' | 'fixed176x64' | 'fixed176x72' | 'fixed176x80' | 'fixed184x8' | 'fixed184x16' | 'fixed184x24' | 'fixed184x32' | 'fixed184x40' | 'fixed184x48' | 'fixed184x56' | 'fixed184x64' | 'fixed184x72' | 'fixed192x8' | 'fixed192x16' | 'fixed192x24' | 'fixed192x32' | 'fixed192x40' | 'fixed192x48' | 'fixed192x56' | 'fixed192x64' | 'fixed200x8' | 'fixed200x16' | 'fixed200x24' | 'fixed200x32' | 'fixed200x40' | 'fixed200x48' | 'fixed200x56' | 'fixed208x8' | 'fixed208x16' | 'fixed208x24' | 'fixed208x32' | 'fixed208x40' | 'fixed208x48' | 'fixed216x8' | 'fixed216x16' | 'fixed216x24' | 'fixed216x32' | 'fixed216x40' | 'fixed224x8' | 'fixed224x16' | 'fixed224x24' | 'fixed224x32' | 'fixed232x8' | 'fixed232x16' | 'fixed232x24' | 'fixed240x8' | 'fixed240x16' | 'fixed248x8' - -Ufixed = 'ufixed' | 'ufixed0x8' | 'ufixed0x16' | 'ufixed0x24' | 'ufixed0x32' | 'ufixed0x40' | 'ufixed0x48' | 'ufixed0x56' | 'ufixed0x64' | 'ufixed0x72' | 'ufixed0x80' | 'ufixed0x88' | 'ufixed0x96' | 'ufixed0x104' | 'ufixed0x112' | 'ufixed0x120' | 'ufixed0x128' | 'ufixed0x136' | 'ufixed0x144' | 'ufixed0x152' | 'ufixed0x160' | 'ufixed0x168' | 'ufixed0x176' | 'ufixed0x184' | 'ufixed0x192' | 'ufixed0x200' | 'ufixed0x208' | 'ufixed0x216' | 'ufixed0x224' | 'ufixed0x232' | 'ufixed0x240' | 'ufixed0x248' | 'ufixed0x256' | 'ufixed8x8' | 'ufixed8x16' | 'ufixed8x24' | 'ufixed8x32' | 'ufixed8x40' | 'ufixed8x48' | 'ufixed8x56' | 'ufixed8x64' | 'ufixed8x72' | 'ufixed8x80' | 'ufixed8x88' | 'ufixed8x96' | 'ufixed8x104' | 'ufixed8x112' | 'ufixed8x120' | 'ufixed8x128' | 'ufixed8x136' | 'ufixed8x144' | 'ufixed8x152' | 'ufixed8x160' | 'ufixed8x168' | 'ufixed8x176' | 'ufixed8x184' | 'ufixed8x192' | 'ufixed8x200' | 'ufixed8x208' | 'ufixed8x216' | 'ufixed8x224' | 'ufixed8x232' | 'ufixed8x240' | 'ufixed8x248' | 'ufixed16x8' | 'ufixed16x16' | 'ufixed16x24' | 'ufixed16x32' | 'ufixed16x40' | 'ufixed16x48' | 'ufixed16x56' | 'ufixed16x64' | 'ufixed16x72' | 'ufixed16x80' | 'ufixed16x88' | 'ufixed16x96' | 'ufixed16x104' | 'ufixed16x112' | 'ufixed16x120' | 'ufixed16x128' | 'ufixed16x136' | 'ufixed16x144' | 'ufixed16x152' | 'ufixed16x160' | 'ufixed16x168' | 'ufixed16x176' | 'ufixed16x184' | 'ufixed16x192' | 'ufixed16x200' | 'ufixed16x208' | 'ufixed16x216' | 'ufixed16x224' | 'ufixed16x232' | 'ufixed16x240' | 'ufixed24x8' | 'ufixed24x16' | 'ufixed24x24' | 'ufixed24x32' | 'ufixed24x40' | 'ufixed24x48' | 'ufixed24x56' | 'ufixed24x64' | 'ufixed24x72' | 'ufixed24x80' | 'ufixed24x88' | 'ufixed24x96' | 'ufixed24x104' | 'ufixed24x112' | 'ufixed24x120' | 'ufixed24x128' | 'ufixed24x136' | 'ufixed24x144' | 'ufixed24x152' | 'ufixed24x160' | 'ufixed24x168' | 'ufixed24x176' | 'ufixed24x184' | 'ufixed24x192' | 'ufixed24x200' | 'ufixed24x208' | 'ufixed24x216' | 'ufixed24x224' | 'ufixed24x232' | 'ufixed32x8' | 'ufixed32x16' | 'ufixed32x24' | 'ufixed32x32' | 'ufixed32x40' | 'ufixed32x48' | 'ufixed32x56' | 'ufixed32x64' | 'ufixed32x72' | 'ufixed32x80' | 'ufixed32x88' | 'ufixed32x96' | 'ufixed32x104' | 'ufixed32x112' | 'ufixed32x120' | 'ufixed32x128' | 'ufixed32x136' | 'ufixed32x144' | 'ufixed32x152' | 'ufixed32x160' | 'ufixed32x168' | 'ufixed32x176' | 'ufixed32x184' | 'ufixed32x192' | 'ufixed32x200' | 'ufixed32x208' | 'ufixed32x216' | 'ufixed32x224' | 'ufixed40x8' | 'ufixed40x16' | 'ufixed40x24' | 'ufixed40x32' | 'ufixed40x40' | 'ufixed40x48' | 'ufixed40x56' | 'ufixed40x64' | 'ufixed40x72' | 'ufixed40x80' | 'ufixed40x88' | 'ufixed40x96' | 'ufixed40x104' | 'ufixed40x112' | 'ufixed40x120' | 'ufixed40x128' | 'ufixed40x136' | 'ufixed40x144' | 'ufixed40x152' | 'ufixed40x160' | 'ufixed40x168' | 'ufixed40x176' | 'ufixed40x184' | 'ufixed40x192' | 'ufixed40x200' | 'ufixed40x208' | 'ufixed40x216' | 'ufixed48x8' | 'ufixed48x16' | 'ufixed48x24' | 'ufixed48x32' | 'ufixed48x40' | 'ufixed48x48' | 'ufixed48x56' | 'ufixed48x64' | 'ufixed48x72' | 'ufixed48x80' | 'ufixed48x88' | 'ufixed48x96' | 'ufixed48x104' | 'ufixed48x112' | 'ufixed48x120' | 'ufixed48x128' | 'ufixed48x136' | 'ufixed48x144' | 'ufixed48x152' | 'ufixed48x160' | 'ufixed48x168' | 'ufixed48x176' | 'ufixed48x184' | 'ufixed48x192' | 'ufixed48x200' | 'ufixed48x208' | 'ufixed56x8' | 'ufixed56x16' | 'ufixed56x24' | 'ufixed56x32' | 'ufixed56x40' | 'ufixed56x48' | 'ufixed56x56' | 'ufixed56x64' | 'ufixed56x72' | 'ufixed56x80' | 'ufixed56x88' | 'ufixed56x96' | 'ufixed56x104' | 'ufixed56x112' | 'ufixed56x120' | 'ufixed56x128' | 'ufixed56x136' | 'ufixed56x144' | 'ufixed56x152' | 'ufixed56x160' | 'ufixed56x168' | 'ufixed56x176' | 'ufixed56x184' | 'ufixed56x192' | 'ufixed56x200' | 'ufixed64x8' | 'ufixed64x16' | 'ufixed64x24' | 'ufixed64x32' | 'ufixed64x40' | 'ufixed64x48' | 'ufixed64x56' | 'ufixed64x64' | 'ufixed64x72' | 'ufixed64x80' | 'ufixed64x88' | 'ufixed64x96' | 'ufixed64x104' | 'ufixed64x112' | 'ufixed64x120' | 'ufixed64x128' | 'ufixed64x136' | 'ufixed64x144' | 'ufixed64x152' | 'ufixed64x160' | 'ufixed64x168' | 'ufixed64x176' | 'ufixed64x184' | 'ufixed64x192' | 'ufixed72x8' | 'ufixed72x16' | 'ufixed72x24' | 'ufixed72x32' | 'ufixed72x40' | 'ufixed72x48' | 'ufixed72x56' | 'ufixed72x64' | 'ufixed72x72' | 'ufixed72x80' | 'ufixed72x88' | 'ufixed72x96' | 'ufixed72x104' | 'ufixed72x112' | 'ufixed72x120' | 'ufixed72x128' | 'ufixed72x136' | 'ufixed72x144' | 'ufixed72x152' | 'ufixed72x160' | 'ufixed72x168' | 'ufixed72x176' | 'ufixed72x184' | 'ufixed80x8' | 'ufixed80x16' | 'ufixed80x24' | 'ufixed80x32' | 'ufixed80x40' | 'ufixed80x48' | 'ufixed80x56' | 'ufixed80x64' | 'ufixed80x72' | 'ufixed80x80' | 'ufixed80x88' | 'ufixed80x96' | 'ufixed80x104' | 'ufixed80x112' | 'ufixed80x120' | 'ufixed80x128' | 'ufixed80x136' | 'ufixed80x144' | 'ufixed80x152' | 'ufixed80x160' | 'ufixed80x168' | 'ufixed80x176' | 'ufixed88x8' | 'ufixed88x16' | 'ufixed88x24' | 'ufixed88x32' | 'ufixed88x40' | 'ufixed88x48' | 'ufixed88x56' | 'ufixed88x64' | 'ufixed88x72' | 'ufixed88x80' | 'ufixed88x88' | 'ufixed88x96' | 'ufixed88x104' | 'ufixed88x112' | 'ufixed88x120' | 'ufixed88x128' | 'ufixed88x136' | 'ufixed88x144' | 'ufixed88x152' | 'ufixed88x160' | 'ufixed88x168' | 'ufixed96x8' | 'ufixed96x16' | 'ufixed96x24' | 'ufixed96x32' | 'ufixed96x40' | 'ufixed96x48' | 'ufixed96x56' | 'ufixed96x64' | 'ufixed96x72' | 'ufixed96x80' | 'ufixed96x88' | 'ufixed96x96' | 'ufixed96x104' | 'ufixed96x112' | 'ufixed96x120' | 'ufixed96x128' | 'ufixed96x136' | 'ufixed96x144' | 'ufixed96x152' | 'ufixed96x160' | 'ufixed104x8' | 'ufixed104x16' | 'ufixed104x24' | 'ufixed104x32' | 'ufixed104x40' | 'ufixed104x48' | 'ufixed104x56' | 'ufixed104x64' | 'ufixed104x72' | 'ufixed104x80' | 'ufixed104x88' | 'ufixed104x96' | 'ufixed104x104' | 'ufixed104x112' | 'ufixed104x120' | 'ufixed104x128' | 'ufixed104x136' | 'ufixed104x144' | 'ufixed104x152' | 'ufixed112x8' | 'ufixed112x16' | 'ufixed112x24' | 'ufixed112x32' | 'ufixed112x40' | 'ufixed112x48' | 'ufixed112x56' | 'ufixed112x64' | 'ufixed112x72' | 'ufixed112x80' | 'ufixed112x88' | 'ufixed112x96' | 'ufixed112x104' | 'ufixed112x112' | 'ufixed112x120' | 'ufixed112x128' | 'ufixed112x136' | 'ufixed112x144' | 'ufixed120x8' | 'ufixed120x16' | 'ufixed120x24' | 'ufixed120x32' | 'ufixed120x40' | 'ufixed120x48' | 'ufixed120x56' | 'ufixed120x64' | 'ufixed120x72' | 'ufixed120x80' | 'ufixed120x88' | 'ufixed120x96' | 'ufixed120x104' | 'ufixed120x112' | 'ufixed120x120' | 'ufixed120x128' | 'ufixed120x136' | 'ufixed128x8' | 'ufixed128x16' | 'ufixed128x24' | 'ufixed128x32' | 'ufixed128x40' | 'ufixed128x48' | 'ufixed128x56' | 'ufixed128x64' | 'ufixed128x72' | 'ufixed128x80' | 'ufixed128x88' | 'ufixed128x96' | 'ufixed128x104' | 'ufixed128x112' | 'ufixed128x120' | 'ufixed128x128' | 'ufixed136x8' | 'ufixed136x16' | 'ufixed136x24' | 'ufixed136x32' | 'ufixed136x40' | 'ufixed136x48' | 'ufixed136x56' | 'ufixed136x64' | 'ufixed136x72' | 'ufixed136x80' | 'ufixed136x88' | 'ufixed136x96' | 'ufixed136x104' | 'ufixed136x112' | 'ufixed136x120' | 'ufixed144x8' | 'ufixed144x16' | 'ufixed144x24' | 'ufixed144x32' | 'ufixed144x40' | 'ufixed144x48' | 'ufixed144x56' | 'ufixed144x64' | 'ufixed144x72' | 'ufixed144x80' | 'ufixed144x88' | 'ufixed144x96' | 'ufixed144x104' | 'ufixed144x112' | 'ufixed152x8' | 'ufixed152x16' | 'ufixed152x24' | 'ufixed152x32' | 'ufixed152x40' | 'ufixed152x48' | 'ufixed152x56' | 'ufixed152x64' | 'ufixed152x72' | 'ufixed152x80' | 'ufixed152x88' | 'ufixed152x96' | 'ufixed152x104' | 'ufixed160x8' | 'ufixed160x16' | 'ufixed160x24' | 'ufixed160x32' | 'ufixed160x40' | 'ufixed160x48' | 'ufixed160x56' | 'ufixed160x64' | 'ufixed160x72' | 'ufixed160x80' | 'ufixed160x88' | 'ufixed160x96' | 'ufixed168x8' | 'ufixed168x16' | 'ufixed168x24' | 'ufixed168x32' | 'ufixed168x40' | 'ufixed168x48' | 'ufixed168x56' | 'ufixed168x64' | 'ufixed168x72' | 'ufixed168x80' | 'ufixed168x88' | 'ufixed176x8' | 'ufixed176x16' | 'ufixed176x24' | 'ufixed176x32' | 'ufixed176x40' | 'ufixed176x48' | 'ufixed176x56' | 'ufixed176x64' | 'ufixed176x72' | 'ufixed176x80' | 'ufixed184x8' | 'ufixed184x16' | 'ufixed184x24' | 'ufixed184x32' | 'ufixed184x40' | 'ufixed184x48' | 'ufixed184x56' | 'ufixed184x64' | 'ufixed184x72' | 'ufixed192x8' | 'ufixed192x16' | 'ufixed192x24' | 'ufixed192x32' | 'ufixed192x40' | 'ufixed192x48' | 'ufixed192x56' | 'ufixed192x64' | 'ufixed200x8' | 'ufixed200x16' | 'ufixed200x24' | 'ufixed200x32' | 'ufixed200x40' | 'ufixed200x48' | 'ufixed200x56' | 'ufixed208x8' | 'ufixed208x16' | 'ufixed208x24' | 'ufixed208x32' | 'ufixed208x40' | 'ufixed208x48' | 'ufixed216x8' | 'ufixed216x16' | 'ufixed216x24' | 'ufixed216x32' | 'ufixed216x40' | 'ufixed224x8' | 'ufixed224x16' | 'ufixed224x24' | 'ufixed224x32' | 'ufixed232x8' | 'ufixed232x16' | 'ufixed232x24' | 'ufixed240x8' | 'ufixed240x16' | 'ufixed248x8' diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index 5d920cb7..43c3b27a 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -81,7 +81,11 @@ struct GeneratorState class LabelOrganizer: public boost::static_visitor<> { public: - LabelOrganizer(GeneratorState& _state): m_state(_state) {} + LabelOrganizer(GeneratorState& _state): m_state(_state) + { + // Make the Solidity ErrorTag available to inline assembly + m_state.labels.insert(make_pair("invalidJumpLabel", m_state.assembly.errorTag())); + } template <class T> void operator()(T const& /*_item*/) { } @@ -216,10 +220,18 @@ public: size_t numVariables = m_state.variables.size(); int deposit = m_state.assembly.deposit(); std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); - deposit = m_state.assembly.deposit() - deposit; + + // pop variables + while (m_state.variables.size() > numVariables) + { + m_state.assembly.append(solidity::Instruction::POP); + m_state.variables.pop_back(); + } m_state.assembly.setSourceLocation(_block.location); + deposit = m_state.assembly.deposit() - deposit; + // issue warnings for stack height discrepancies if (deposit < 0) { @@ -238,12 +250,6 @@ public: ); } - // pop variables - while (m_state.variables.size() > numVariables) - { - m_state.assembly.append(solidity::Instruction::POP); - m_state.variables.pop_back(); - } } private: diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h index b1fafe15..bd71812e 100644 --- a/libsolidity/inlineasm/AsmCodeGen.h +++ b/libsolidity/inlineasm/AsmCodeGen.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index d6abf67f..d622ff54 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 8d2c2ed4..ef3da255 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index 0a9d51d5..8b56ab90 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp index 11c6e28f..b8e0e857 100644 --- a/libsolidity/inlineasm/AsmStack.cpp +++ b/libsolidity/inlineasm/AsmStack.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h index 521f5fe7..1543cb2a 100644 --- a/libsolidity/inlineasm/AsmStack.h +++ b/libsolidity/inlineasm/AsmStack.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index efbbd237..eb588fc2 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -32,12 +32,18 @@ #include <libsolidity/analysis/NameAndTypeResolver.h> #include <libsolidity/analysis/TypeChecker.h> #include <libsolidity/analysis/DocStringAnalyser.h> +#include <libsolidity/analysis/StaticAnalyzer.h> #include <libsolidity/analysis/SyntaxChecker.h> #include <libsolidity/codegen/Compiler.h> #include <libsolidity/interface/InterfaceHandler.h> #include <libsolidity/formal/Why3Translator.h> -#include <libdevcore/SHA3.h> +#include <libevmasm/Exceptions.h> + +#include <libdevcore/SwarmHash.h> +#include <libdevcore/JSON.h> + +#include <json/json.h> #include <boost/algorithm/string.hpp> #include <boost/filesystem.hpp> @@ -78,6 +84,8 @@ void CompilerStack::reset(bool _keepSources) { m_sources.clear(); } + m_optimize = false; + m_optimizeRuns = 200; m_globalContext.reset(); m_sourceOrder.clear(); m_contracts.clear(); @@ -195,6 +203,15 @@ bool CompilerStack::parse() m_contracts[contract->name()].contract = contract; } + + if (noErrors) + { + StaticAnalyzer staticAnalyzer(m_errors); + for (Source const* source: m_sourceOrder) + if (!staticAnalyzer.analyze(*source->ast)) + noErrors = false; + } + m_parseSuccessful = noErrors; return m_parseSuccessful; } @@ -216,32 +233,37 @@ vector<string> CompilerStack::contractNames() const } -bool CompilerStack::compile(bool _optimize, unsigned _runs) +bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> const& _libraries) { if (!m_parseSuccessful) if (!parse()) return false; + m_optimize = _optimize; + m_optimizeRuns = _runs; + m_libraries = _libraries; + map<ContractDefinition const*, eth::Assembly const*> compiledContracts; for (Source const* source: m_sourceOrder) for (ASTPointer<ASTNode> const& node: source->ast->nodes()) if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) - compileContract(_optimize, _runs, *contract, compiledContracts); + compileContract(*contract, compiledContracts); + this->link(); return true; } -bool CompilerStack::compile(string const& _sourceCode, bool _optimize) +bool CompilerStack::compile(string const& _sourceCode, bool _optimize, unsigned _runs) { - return parse(_sourceCode) && compile(_optimize); + return parse(_sourceCode) && compile(_optimize, _runs); } -void CompilerStack::link(const std::map<string, h160>& _libraries) +void CompilerStack::link() { for (auto& contract: m_contracts) { - contract.second.object.link(_libraries); - contract.second.runtimeObject.link(_libraries); - contract.second.cloneObject.link(_libraries); + contract.second.object.link(m_libraries); + contract.second.runtimeObject.link(m_libraries); + contract.second.cloneObject.link(m_libraries); } } @@ -345,30 +367,38 @@ map<string, unsigned> CompilerStack::sourceIndices() const return indices; } -string const& CompilerStack::interface(string const& _contractName) const +Json::Value const& CompilerStack::interface(string const& _contractName) const { return metadata(_contractName, DocumentationType::ABIInterface); } -string const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const +Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - std::unique_ptr<string const>* doc; - Contract const& currentContract = contract(_contractName); + return metadata(contract(_contractName), _type); +} + +Json::Value const& CompilerStack::metadata(Contract const& _contract, DocumentationType _type) const +{ + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + solAssert(_contract.contract, ""); + std::unique_ptr<Json::Value const>* doc; // checks wheather we already have the documentation switch (_type) { case DocumentationType::NatspecUser: - doc = ¤tContract.userDocumentation; + doc = &_contract.userDocumentation; break; case DocumentationType::NatspecDev: - doc = ¤tContract.devDocumentation; + doc = &_contract.devDocumentation; break; case DocumentationType::ABIInterface: - doc = ¤tContract.interface; + doc = &_contract.interface; break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); @@ -376,11 +406,19 @@ string const& CompilerStack::metadata(string const& _contractName, Documentation // caches the result if (!*doc) - doc->reset(new string(InterfaceHandler::documentation(*currentContract.contract, _type))); + doc->reset(new Json::Value(InterfaceHandler::documentation(*_contract.contract, _type))); return *(*doc); } +string const& CompilerStack::onChainMetadata(string const& _contractName) const +{ + if (!m_parseSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + + return contract(_contractName).onChainMetadata; +} + Scanner const& CompilerStack::scanner(string const& _sourceName) const { return *source(_sourceName).scanner; @@ -571,8 +609,6 @@ string CompilerStack::absolutePath(string const& _path, string const& _reference } void CompilerStack::compileContract( - bool _optimize, - unsigned _runs, ContractDefinition const& _contract, map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts ) @@ -580,19 +616,38 @@ void CompilerStack::compileContract( if (_compiledContracts.count(&_contract) || !_contract.annotation().isFullyImplemented) return; for (auto const* dependency: _contract.annotation().contractDependencies) - compileContract(_optimize, _runs, *dependency, _compiledContracts); + compileContract(*dependency, _compiledContracts); - shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize, _runs); - compiler->compileContract(_contract, _compiledContracts); + shared_ptr<Compiler> compiler = make_shared<Compiler>(m_optimize, m_optimizeRuns); Contract& compiledContract = m_contracts.at(_contract.name()); + string onChainMetadata = createOnChainMetadata(compiledContract); + bytes cborEncodedMetadata = + // CBOR-encoding of {"bzzr0": dev::swarmHash(onChainMetadata)} + bytes{0xa1, 0x65, 'b', 'z', 'z', 'r', '0', 0x58, 0x20} + + dev::swarmHash(onChainMetadata).asBytes(); + solAssert(cborEncodedMetadata.size() <= 0xffff, "Metadata too large"); + // 16-bit big endian length + cborEncodedMetadata += toCompactBigEndian(cborEncodedMetadata.size(), 2); + compiler->compileContract(_contract, _compiledContracts, cborEncodedMetadata); compiledContract.compiler = compiler; compiledContract.object = compiler->assembledObject(); compiledContract.runtimeObject = compiler->runtimeObject(); + compiledContract.onChainMetadata = onChainMetadata; _compiledContracts[compiledContract.contract] = &compiler->assembly(); - Compiler cloneCompiler(_optimize, _runs); - cloneCompiler.compileClone(_contract, _compiledContracts); - compiledContract.cloneObject = cloneCompiler.assembledObject(); + try + { + Compiler cloneCompiler(m_optimize, m_optimizeRuns); + cloneCompiler.compileClone(_contract, _compiledContracts); + compiledContract.cloneObject = cloneCompiler.assembledObject(); + } + catch (eth::AssemblyException const&) + { + // In some cases (if the constructor requests a runtime function), it is not + // possible to compile the clone. + + // TODO: Report error / warning + } } std::string CompilerStack::defaultContractName() const @@ -626,6 +681,45 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co return it->second; } +string CompilerStack::createOnChainMetadata(Contract const& _contract) const +{ + Json::Value meta; + meta["version"] = 1; + meta["language"] = "Solidity"; + meta["compiler"]["version"] = VersionString; + + meta["sources"] = Json::objectValue; + for (auto const& s: m_sources) + { + solAssert(s.second.scanner, "Scanner not available"); + meta["sources"][s.first]["keccak256"] = + "0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes()); + meta["sources"][s.first]["url"] = + "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes()); + } + meta["settings"]["optimizer"]["enabled"] = m_optimize; + meta["settings"]["optimizer"]["runs"] = m_optimizeRuns; + meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] = + _contract.contract->annotation().canonicalName; + + meta["settings"]["remappings"] = Json::arrayValue; + set<string> remappings; + for (auto const& r: m_remappings) + remappings.insert(r.context + ":" + r.prefix + "=" + r.target); + for (auto const& r: remappings) + meta["settings"]["remappings"].append(r); + + meta["settings"]["libraries"] = Json::objectValue; + for (auto const& library: m_libraries) + meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes()); + + meta["output"]["abi"] = metadata(_contract, DocumentationType::ABIInterface); + meta["output"]["userdoc"] = metadata(_contract, DocumentationType::NatspecUser); + meta["output"]["devdoc"] = metadata(_contract, DocumentationType::NatspecDev); + + return jsonCompactPrint(meta); +} + string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const { string ret; diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index da479638..f98a457a 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -113,13 +113,14 @@ public: /// Compiles the source units that were previously added and parsed. /// @returns false on error. - bool compile(bool _optimize = false, unsigned _runs = 200); + bool compile( + bool _optimize = false, + unsigned _runs = 200, + std::map<std::string, h160> const& _libraries = std::map<std::string, h160>{} + ); /// Parses and compiles the given source code. /// @returns false on error. - bool compile(std::string const& _sourceCode, bool _optimize = false); - - /// Inserts the given addresses into the linker objects of all compiled contracts. - void link(std::map<std::string, h160> const& _libraries); + bool compile(std::string const& _sourceCode, bool _optimize = false, unsigned _runs = 200); /// Tries to translate all source files into a language suitable for formal analysis. /// @param _errors list to store errors - defaults to the internal error list. @@ -162,14 +163,15 @@ public: /// @returns a mapping assigning each source name its index inside the vector returned /// by sourceNames(). std::map<std::string, unsigned> sourceIndices() const; - /// @returns a string representing the contract interface in JSON. + /// @returns a JSON representing the contract interface. /// Prerequisite: Successful call to parse or compile. - std::string const& interface(std::string const& _contractName = "") const; - /// @returns a string representing the contract's documentation in JSON. + Json::Value const& interface(std::string const& _contractName = "") const; + /// @returns a JSON representing the contract's documentation. /// Prerequisite: Successful call to parse or compile. /// @param type The type of the documentation to get. /// Can be one of 4 types defined at @c DocumentationType - std::string const& metadata(std::string const& _contractName, DocumentationType _type) const; + Json::Value const& metadata(std::string const& _contractName, DocumentationType _type) const; + std::string const& onChainMetadata(std::string const& _contractName) const; /// @returns the previously used scanner, useful for counting lines during error reporting. Scanner const& scanner(std::string const& _sourceName = "") const; @@ -213,9 +215,10 @@ private: eth::LinkerObject object; eth::LinkerObject runtimeObject; eth::LinkerObject cloneObject; - mutable std::unique_ptr<std::string const> interface; - mutable std::unique_ptr<std::string const> userDocumentation; - mutable std::unique_ptr<std::string const> devDocumentation; + std::string onChainMetadata; ///< The metadata json that will be hashed into the chain. + mutable std::unique_ptr<Json::Value const> interface; + mutable std::unique_ptr<Json::Value const> userDocumentation; + mutable std::unique_ptr<Json::Value const> devDocumentation; mutable std::unique_ptr<std::string const> sourceMapping; mutable std::unique_ptr<std::string const> runtimeSourceMapping; }; @@ -233,16 +236,18 @@ private: std::string absolutePath(std::string const& _path, std::string const& _reference) const; /// Compile a single contract and put the result in @a _compiledContracts. void compileContract( - bool _optimize, - unsigned _runs, ContractDefinition const& _contract, std::map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts ); + void link(); + Contract const& contract(std::string const& _contractName = "") const; Source const& source(std::string const& _sourceName = "") const; + std::string createOnChainMetadata(Contract const& _contract) const; std::string computeSourceMapping(eth::AssemblyItems const& _items) const; + Json::Value const& metadata(Contract const&, DocumentationType _type) const; struct Remapping { @@ -252,6 +257,9 @@ private: }; ReadFileCallback m_readFile; + bool m_optimize = false; + unsigned m_optimizeRuns = 200; + std::map<std::string, h160> m_libraries; /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum /// "context:prefix=target" std::vector<Remapping> m_remappings; diff --git a/libsolidity/interface/Exceptions.cpp b/libsolidity/interface/Exceptions.cpp index 6d72520b..90a680b4 100644 --- a/libsolidity/interface/Exceptions.cpp +++ b/libsolidity/interface/Exceptions.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Liana <liana@ethdev.com> diff --git a/libsolidity/interface/Exceptions.h b/libsolidity/interface/Exceptions.h index 07835320..81716c41 100644 --- a/libsolidity/interface/Exceptions.h +++ b/libsolidity/interface/Exceptions.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -37,6 +37,7 @@ using ErrorList = std::vector<std::shared_ptr<Error const>>; struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; struct FatalError: virtual Exception {}; +struct UnimplementedFeatureError: virtual Exception{}; class Error: virtual public Exception { diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 1c804b78..852b392c 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/interface/GasEstimator.h b/libsolidity/interface/GasEstimator.h index 518e58e4..bf63df96 100644 --- a/libsolidity/interface/GasEstimator.h +++ b/libsolidity/interface/GasEstimator.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/interface/InterfaceHandler.cpp b/libsolidity/interface/InterfaceHandler.cpp index de16a372..9944bb22 100644 --- a/libsolidity/interface/InterfaceHandler.cpp +++ b/libsolidity/interface/InterfaceHandler.cpp @@ -8,7 +8,7 @@ using namespace std; using namespace dev; using namespace dev::solidity; -string InterfaceHandler::documentation( +Json::Value InterfaceHandler::documentation( ContractDefinition const& _contractDef, DocumentationType _type ) @@ -24,10 +24,9 @@ string InterfaceHandler::documentation( } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation type")); - return ""; } -string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) +Json::Value InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) { Json::Value abi(Json::arrayValue); @@ -67,8 +66,9 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) { Json::Value method; method["type"] = "constructor"; - auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType(); + auto externalFunction = FunctionType(*_contractDef.constructor(), false).interfaceFunctionType(); solAssert(!!externalFunction, ""); + method["payable"] = externalFunction->isPayable(); method["inputs"] = populateParameters( externalFunction->parameterNames(), externalFunction->parameterTypeNames(_contractDef.isLibrary()) @@ -77,7 +77,7 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) } if (_contractDef.fallbackFunction()) { - auto externalFunctionType = FunctionType(*_contractDef.fallbackFunction()).interfaceFunctionType(); + auto externalFunctionType = FunctionType(*_contractDef.fallbackFunction(), false).interfaceFunctionType(); solAssert(!!externalFunctionType, ""); Json::Value method; method["type"] = "fallback"; @@ -103,10 +103,11 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef) event["inputs"] = params; abi.append(event); } - return Json::FastWriter().write(abi); + + return abi; } -string InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef) +Json::Value InterfaceHandler::userDocumentation(ContractDefinition const& _contractDef) { Json::Value doc; Json::Value methods(Json::objectValue); @@ -126,10 +127,10 @@ string InterfaceHandler::userDocumentation(ContractDefinition const& _contractDe } doc["methods"] = methods; - return Json::StyledWriter().write(doc); + return doc; } -string InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef) +Json::Value InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef) { Json::Value doc; Json::Value methods(Json::objectValue); @@ -175,7 +176,7 @@ string InterfaceHandler::devDocumentation(ContractDefinition const& _contractDef } doc["methods"] = methods; - return Json::StyledWriter().write(doc); + return doc; } string InterfaceHandler::extractDoc(multimap<string, DocTag> const& _tags, string const& _name) diff --git a/libsolidity/interface/InterfaceHandler.h b/libsolidity/interface/InterfaceHandler.h index 54199e4e..b7e1bb00 100644 --- a/libsolidity/interface/InterfaceHandler.h +++ b/libsolidity/interface/InterfaceHandler.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Lefteris <lefteris@ethdev.com> @@ -64,24 +64,24 @@ public: /// @param _contractDef The contract definition /// @param _type The type of the documentation. Can be one of the /// types provided by @c DocumentationType - /// @return A string with the json representation of provided type - static std::string documentation( + /// @return A JSON representation of provided type + static Json::Value documentation( ContractDefinition const& _contractDef, DocumentationType _type ); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition - /// @return A string with the json representation of the contract's ABI Interface - static std::string abiInterface(ContractDefinition const& _contractDef); + /// @return A JSONrepresentation of the contract's ABI Interface + static Json::Value abiInterface(ContractDefinition const& _contractDef); /// Get the User documentation of the contract /// @param _contractDef The contract definition - /// @return A string with the json representation of the contract's user documentation - static std::string userDocumentation(ContractDefinition const& _contractDef); + /// @return A JSON representation of the contract's user documentation + static Json::Value userDocumentation(ContractDefinition const& _contractDef); /// Genereates the Developer's documentation of the contract /// @param _contractDef The contract definition - /// @return A string with the json representation + /// @return A JSON representation /// of the contract's developer documentation - static std::string devDocumentation(ContractDefinition const& _contractDef); + static Json::Value devDocumentation(ContractDefinition const& _contractDef); private: /// @returns concatenation of all content under the given tag name. diff --git a/libsolidity/interface/SourceReferenceFormatter.cpp b/libsolidity/interface/SourceReferenceFormatter.cpp index f09d2d45..7730a99a 100644 --- a/libsolidity/interface/SourceReferenceFormatter.cpp +++ b/libsolidity/interface/SourceReferenceFormatter.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/interface/SourceReferenceFormatter.h b/libsolidity/interface/SourceReferenceFormatter.h index 2b908c46..7034f4ab 100644 --- a/libsolidity/interface/SourceReferenceFormatter.h +++ b/libsolidity/interface/SourceReferenceFormatter.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/interface/Utils.h b/libsolidity/interface/Utils.h index 738669ac..0027759c 100644 --- a/libsolidity/interface/Utils.h +++ b/libsolidity/interface/Utils.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -30,6 +30,7 @@ namespace dev namespace solidity { struct InternalCompilerError; +struct UnimplementedFeatureError; } } @@ -37,3 +38,8 @@ struct InternalCompilerError; #define solAssert(CONDITION, DESCRIPTION) \ assertThrow(CONDITION, ::dev::solidity::InternalCompilerError, DESCRIPTION) +#define solUnimplementedAssert(CONDITION, DESCRIPTION) \ + assertThrow(CONDITION, ::dev::solidity::UnimplementedFeatureError, DESCRIPTION) + +#define solUnimplemented(DESCRIPTION) \ + solUnimplementedAssert(false, DESCRIPTION) diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp index 0dca1ced..ff66f039 100644 --- a/libsolidity/interface/Version.cpp +++ b/libsolidity/interface/Version.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/interface/Version.h b/libsolidity/interface/Version.h index fea73997..5b07b3f4 100644 --- a/libsolidity/interface/Version.h +++ b/libsolidity/interface/Version.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/parsing/DocStringParser.h b/libsolidity/parsing/DocStringParser.h index f67b8bbd..c7f81c55 100644 --- a/libsolidity/parsing/DocStringParser.h +++ b/libsolidity/parsing/DocStringParser.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Lefteris <lefteris@ethdev.com> diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 0e99d1e7..f02a4a45 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -217,7 +217,9 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) if (currentTokenValue == Token::RBrace) break; else if (currentTokenValue == Token::Function) - subNodes.push_back(parseFunctionDefinition(name.get())); + // This can be a function or a state variable of function type (especially + // complicated to distinguish fallback function from function type state variable) + subNodes.push_back(parseFunctionDefinitionOrFunctionTypeStateVariable(name.get())); else if (currentTokenValue == Token::Struct) subNodes.push_back(parseStructDefinition()); else if (currentTokenValue == Token::Enum) @@ -288,81 +290,121 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) return visibility; } -ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName) +Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers) { - ASTNodeFactory nodeFactory(*this); - ASTPointer<ASTString> docstring; - if (m_scanner->currentCommentLiteral() != "") - docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral()); - + FunctionHeaderParserResult result; expectToken(Token::Function); - ASTPointer<ASTString> name; - if (m_scanner->currentToken() == Token::LParen) - name = make_shared<ASTString>(); // anonymous function + if (_forceEmptyName || m_scanner->currentToken() == Token::LParen) + result.name = make_shared<ASTString>(); // anonymous function else - name = expectIdentifierToken(); + result.name = expectIdentifierToken(); VarDeclParserOptions options; options.allowLocationSpecifier = true; - ASTPointer<ParameterList> parameters(parseParameterList(options)); - bool isDeclaredConst = false; - bool isPayable = false; - Declaration::Visibility visibility(Declaration::Visibility::Default); - vector<ASTPointer<ModifierInvocation>> modifiers; + result.parameters = parseParameterList(options); while (true) { Token::Value token = m_scanner->currentToken(); if (token == Token::Const) { - isDeclaredConst = true; + result.isDeclaredConst = true; m_scanner->next(); } else if (m_scanner->currentToken() == Token::Payable) { - isPayable = true; + result.isPayable = true; m_scanner->next(); } - else if (token == Token::Identifier) - modifiers.push_back(parseModifierInvocation()); + else if (_allowModifiers && token == Token::Identifier) + { + // This can either be a modifier (function declaration) or the name of the + // variable (function type name plus variable). + if ( + m_scanner->peekNextToken() == Token::Semicolon || + m_scanner->peekNextToken() == Token::Assign + ) + // Variable declaration, break here. + break; + else + result.modifiers.push_back(parseModifierInvocation()); + } else if (Token::isVisibilitySpecifier(token)) { - if (visibility != Declaration::Visibility::Default) + if (result.visibility != Declaration::Visibility::Default) fatalParserError(string("Multiple visibility specifiers.")); - visibility = parseVisibilitySpecifier(token); + result.visibility = parseVisibilitySpecifier(token); } else break; } - ASTPointer<ParameterList> returnParameters; if (m_scanner->currentToken() == Token::Returns) { bool const permitEmptyParameterList = false; m_scanner->next(); - returnParameters = parseParameterList(options, permitEmptyParameterList); + result.returnParameters = parseParameterList(options, permitEmptyParameterList); } else - returnParameters = createEmptyParameterList(); - ASTPointer<Block> block = ASTPointer<Block>(); - nodeFactory.markEndPosition(); - if (m_scanner->currentToken() != Token::Semicolon) + result.returnParameters = createEmptyParameterList(); + return result; +} + +ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName) +{ + ASTNodeFactory nodeFactory(*this); + ASTPointer<ASTString> docstring; + if (m_scanner->currentCommentLiteral() != "") + docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral()); + + FunctionHeaderParserResult header = parseFunctionHeader(false, true); + + if ( + !header.modifiers.empty() || + !header.name->empty() || + m_scanner->currentToken() == Token::Semicolon || + m_scanner->currentToken() == Token::LBrace + ) { - block = parseBlock(); - nodeFactory.setEndPositionFromNode(block); + // this has to be a function + ASTPointer<Block> block = ASTPointer<Block>(); + nodeFactory.markEndPosition(); + if (m_scanner->currentToken() != Token::Semicolon) + { + block = parseBlock(); + nodeFactory.setEndPositionFromNode(block); + } + else + m_scanner->next(); // just consume the ';' + bool const c_isConstructor = (_contractName && *header.name == *_contractName); + return nodeFactory.createNode<FunctionDefinition>( + header.name, + header.visibility, + c_isConstructor, + docstring, + header.parameters, + header.isDeclaredConst, + header.modifiers, + header.returnParameters, + header.isPayable, + block + ); } else - m_scanner->next(); // just consume the ';' - bool const c_isConstructor = (_contractName && *name == *_contractName); - return nodeFactory.createNode<FunctionDefinition>( - name, - visibility, - c_isConstructor, - docstring, - parameters, - isDeclaredConst, - modifiers, - returnParameters, - isPayable, - block - ); + { + // this has to be a state variable + ASTPointer<TypeName> type = nodeFactory.createNode<FunctionTypeName>( + header.parameters, + header.returnParameters, + header.visibility, + header.isDeclaredConst, + header.isPayable + ); + type = parseTypeNameSuffix(type, nodeFactory); + VarDeclParserOptions options; + options.isStateVariable = true; + options.allowInitialValue = true; + auto node = parseVariableDeclaration(options, type); + expectToken(Token::Semicolon); + return node; + } } ASTPointer<StructDefinition> Parser::parseStructDefinition() @@ -406,6 +448,8 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition() if (m_scanner->currentToken() != Token::Identifier) fatalParserError(string("Expected Identifier after ','")); } + if (members.size() == 0) + parserError({"enum with no members is not allowed."}); nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -609,6 +653,21 @@ ASTPointer<UserDefinedTypeName> Parser::parseUserDefinedTypeName() return nodeFactory.createNode<UserDefinedTypeName>(identifierPath); } +ASTPointer<TypeName> Parser::parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory) +{ + while (m_scanner->currentToken() == Token::LBrack) + { + m_scanner->next(); + ASTPointer<Expression> length; + if (m_scanner->currentToken() != Token::RBrack) + length = parseExpression(); + nodeFactory.markEndPosition(); + expectToken(Token::RBrack); + type = nodeFactory.createNode<ArrayTypeName>(type, length); + } + return type; +} + ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) { ASTNodeFactory nodeFactory(*this); @@ -629,6 +688,8 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) fatalParserError(string("Expected explicit type name.")); m_scanner->next(); } + else if (token == Token::Function) + type = parseFunctionType(); else if (token == Token::Mapping) type = parseMapping(); else if (token == Token::Identifier) @@ -638,19 +699,23 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) if (type) // Parse "[...]" postfixes for arrays. - while (m_scanner->currentToken() == Token::LBrack) - { - m_scanner->next(); - ASTPointer<Expression> length; - if (m_scanner->currentToken() != Token::RBrack) - length = parseExpression(); - nodeFactory.markEndPosition(); - expectToken(Token::RBrack); - type = nodeFactory.createNode<ArrayTypeName>(type, length); - } + type = parseTypeNameSuffix(type, nodeFactory); return type; } +ASTPointer<FunctionTypeName> Parser::parseFunctionType() +{ + ASTNodeFactory nodeFactory(*this); + FunctionHeaderParserResult header = parseFunctionHeader(true, false); + return nodeFactory.createNode<FunctionTypeName>( + header.parameters, + header.returnParameters, + header.visibility, + header.isDeclaredConst, + header.isPayable + ); +} + ASTPointer<Mapping> Parser::parseMapping() { ASTNodeFactory nodeFactory(*this); @@ -722,6 +787,8 @@ ASTPointer<Statement> Parser::parseStatement() return parseIfStatement(docString); case Token::While: return parseWhileStatement(docString); + case Token::Do: + return parseDoWhileStatement(docString); case Token::For: return parseForStatement(docString); case Token::LBrace: @@ -816,9 +883,24 @@ ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> con expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); - return nodeFactory.createNode<WhileStatement>(_docString, condition, body); + return nodeFactory.createNode<WhileStatement>(_docString, condition, body, false); +} + +ASTPointer<WhileStatement> Parser::parseDoWhileStatement(ASTPointer<ASTString> const& _docString) +{ + ASTNodeFactory nodeFactory(*this); + expectToken(Token::Do); + ASTPointer<Statement> body = parseStatement(); + expectToken(Token::While); + expectToken(Token::LParen); + ASTPointer<Expression> condition = parseExpression(); + expectToken(Token::RParen); + nodeFactory.markEndPosition(); + expectToken(Token::Semicolon); + return nodeFactory.createNode<WhileStatement>(_docString, condition, body, true); } + ASTPointer<ForStatement> Parser::parseForStatement(ASTPointer<ASTString> const& _docString) { ASTNodeFactory nodeFactory(*this); @@ -1259,7 +1341,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const Token::Value token(m_scanner->currentToken()); bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); - if (token == Token::Mapping || token == Token::Var) + if (token == Token::Mapping || token == Token::Function || token == Token::Var) return LookAheadInfo::VariableDeclarationStatement; if (mightBeTypeName) { diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 9c30cf60..79d1d1d4 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> @@ -53,6 +53,18 @@ private: bool allowLocationSpecifier = false; }; + /// This struct is shared for parsing a function header and a function type. + struct FunctionHeaderParserResult + { + ASTPointer<ASTString> name; + ASTPointer<ParameterList> parameters; + ASTPointer<ParameterList> returnParameters; + Declaration::Visibility visibility = Declaration::Visibility::Default; + bool isDeclaredConst = false; + bool isPayable = false; + std::vector<ASTPointer<ModifierInvocation>> modifiers; + }; + ///@{ ///@name Parsing functions for the AST nodes ASTPointer<PragmaDirective> parsePragmaDirective(); @@ -60,6 +72,8 @@ private: ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary); ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); + FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers); + ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName); ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName); ASTPointer<StructDefinition> parseStructDefinition(); ASTPointer<EnumDefinition> parseEnumDefinition(); @@ -74,7 +88,9 @@ private: ASTPointer<ModifierInvocation> parseModifierInvocation(); ASTPointer<Identifier> parseIdentifier(); ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName(); + ASTPointer<TypeName> parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory); ASTPointer<TypeName> parseTypeName(bool _allowVar); + ASTPointer<FunctionTypeName> parseFunctionType(); ASTPointer<Mapping> parseMapping(); ASTPointer<ParameterList> parseParameterList( VarDeclParserOptions const& _options, @@ -85,6 +101,7 @@ private: ASTPointer<InlineAssembly> parseInlineAssembly(ASTPointer<ASTString> const& _docString = {}); ASTPointer<IfStatement> parseIfStatement(ASTPointer<ASTString> const& _docString); ASTPointer<WhileStatement> parseWhileStatement(ASTPointer<ASTString> const& _docString); + ASTPointer<WhileStatement> parseDoWhileStatement(ASTPointer<ASTString> const& _docString); ASTPointer<ForStatement> parseForStatement(ASTPointer<ASTString> const& _docString); /// A "simple statement" can be a variable declaration statement or an expression statement. ASTPointer<Statement> parseSimpleStatement(ASTPointer<ASTString> const& _docString); diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp index 2abf58cc..87d47f4b 100644 --- a/libsolidity/parsing/ParserBase.cpp +++ b/libsolidity/parsing/ParserBase.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/parsing/ParserBase.h b/libsolidity/parsing/ParserBase.h index 9705228f..dfb7cab7 100644 --- a/libsolidity/parsing/ParserBase.h +++ b/libsolidity/parsing/ParserBase.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 603f3e42..3623f23f 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. This file is derived from the file "scanner.cc", which was part of the V8 project. The original copyright header follows: @@ -327,7 +327,12 @@ Token::Value Scanner::scanMultiLineDocComment() if (isLineTerminator(m_char)) { skipWhitespace(); - if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) != '/') + if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '*') + { // it is unknown if this leads to the end of the comment + addCommentLiteralChar('*'); + advance(); + } + else if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) != '/') { // skip first '*' in subsequent lines if (charsAdded) addCommentLiteralChar('\n'); diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h index 36cba112..d6b48c6f 100644 --- a/libsolidity/parsing/Scanner.h +++ b/libsolidity/parsing/Scanner.h @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of solidity. - cpp-ethereum is free software: you can redistribute it and/or modify + 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. - cpp-ethereum is distributed in the hope that it will be useful, + 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. + along with solidity. If not, see <http://www.gnu.org/licenses/>. This file is derived from the file "scanner.h", which was part of the V8 project. The original copyright header follows: @@ -80,6 +80,8 @@ public: void reset() { m_position = 0; } + std::string const& source() const { return m_source; } + ///@{ ///@name Error printing helper functions /// Functions that help pretty-printing parse errors @@ -102,6 +104,8 @@ public: explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); } + std::string source() const { return m_source.source(); } + /// Resets the scanner as if newly constructed with _source and _sourceName as input. void reset(CharStream const& _source, std::string const& _sourceName); /// Resets scanner to the start of input. diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index 0ab97988..66312f69 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -25,20 +25,20 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Modifications as part of cpp-ethereum under the following license: +// Modifications as part of solidity under the following license: // -// cpp-ethereum is free software: you can redistribute it and/or modify +// 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. // -// cpp-ethereum is distributed in the hope that it will be useful, +// 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +// along with solidity. If not, see <http://www.gnu.org/licenses/>. #include <map> #include <libsolidity/parsing/Token.h> diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 5dd42992..c6d050bb 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -25,20 +25,20 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Modifications as part of cpp-ethereum under the following license: +// Modifications as part of solidity under the following license: // -// cpp-ethereum is free software: you can redistribute it and/or modify +// 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. // -// cpp-ethereum is distributed in the hope that it will be useful, +// 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +// along with solidity. If not, see <http://www.gnu.org/licenses/>. #pragma once @@ -147,7 +147,6 @@ namespace solidity K(Const, "constant", 0) \ K(Continue, "continue", 0) \ K(Contract, "contract", 0) \ - K(Default, "default", 0) \ K(Do, "do", 0) \ K(Else, "else", 0) \ K(Enum, "enum", 0) \ @@ -208,7 +207,6 @@ namespace solidity T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ \ /* Literals */ \ - K(NullLiteral, "null", 0) \ K(TrueLiteral, "true", 0) \ K(FalseLiteral, "false", 0) \ T(Number, NULL, 0) \ @@ -223,12 +221,14 @@ namespace solidity K(After, "after", 0) \ K(Case, "case", 0) \ K(Catch, "catch", 0) \ + K(Default, "default", 0) \ K(Final, "final", 0) \ K(In, "in", 0) \ K(Inline, "inline", 0) \ K(Interface, "interface", 0) \ K(Let, "let", 0) \ K(Match, "match", 0) \ + K(NullLiteral, "null", 0) \ K(Of, "of", 0) \ K(Pure, "pure", 0) \ K(Relocatable, "relocatable", 0) \ |