From 71f7bf720615ecb6c63eb09c84ddcf512774e70a Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 14 Jun 2023 12:48:38 +0200 Subject: [PATCH] tmp --- liblangutil/Token.h | 15 ++- libsolidity/CMakeLists.txt | 6 + .../analysis/experimental/Analysis.cpp | 7 +- libsolidity/analysis/experimental/Analysis.h | 7 +- .../experimental/SyntaxRestrictor.cpp | 110 +++++++++++++++++ .../analysis/experimental/SyntaxRestrictor.h | 55 +++++++++ .../analysis/experimental/TypeInference.cpp | 37 ++++++ .../analysis/experimental/TypeInference.h | 111 ++++++++++++++++++ .../experimental/IRGeneratorForStatements.cpp | 26 ++++ .../experimental/IRGeneratorForStatements.h | 38 ++++++ libsolidity/interface/CompilerStack.cpp | 4 +- libsolidity/parsing/Parser.h | 4 +- libstdlib/src/stub.sol | 3 +- .../semanticTests/experimental/stub.sol | 15 +++ .../syntaxTests/experimental_keywords.sol | 4 + 15 files changed, 430 insertions(+), 12 deletions(-) create mode 100644 libsolidity/analysis/experimental/SyntaxRestrictor.cpp create mode 100644 libsolidity/analysis/experimental/SyntaxRestrictor.h create mode 100644 libsolidity/analysis/experimental/TypeInference.cpp create mode 100644 libsolidity/analysis/experimental/TypeInference.h create mode 100644 libsolidity/codegen/experimental/IRGeneratorForStatements.cpp create mode 100644 libsolidity/codegen/experimental/IRGeneratorForStatements.h create mode 100644 test/libsolidity/semanticTests/experimental/stub.sol create mode 100644 test/libsolidity/syntaxTests/experimental_keywords.sol diff --git a/liblangutil/Token.h b/liblangutil/Token.h index cca90be20..a0c384a7d 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -268,6 +268,11 @@ namespace solidity::langutil /* Yul-specific tokens, but not keywords. */ \ T(Leave, "leave", 0) \ \ + /* Experimental Solidity specific keywords. */ \ + K(Word, "word", 0) \ + K(StaticAssert, "static_assert", 0) \ + T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \ + \ /* Illegal token - not able to scan. */ \ T(Illegal, "ILLEGAL", 0) \ \ @@ -290,7 +295,7 @@ namespace TokenTraits constexpr size_t count() { return static_cast(Token::NUM_TOKENS); } // Predicates - constexpr bool isElementaryTypeName(Token tok) { return Token::Int <= tok && tok < Token::TypesEnd; } + constexpr bool isElementaryTypeName(Token tok) { return (Token::Int <= tok && tok < Token::TypesEnd) || tok == Token::Word; } constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; } constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; } constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd || @@ -324,11 +329,13 @@ namespace TokenTraits } constexpr bool isExperimentalSolidityKeyword(Token tok) { - return tok == Token::Assembly || tok == Token::Contract || tok == Token::External || tok == Token::Fallback; + return tok == Token::Assembly || tok == Token::Contract || tok == Token::External || tok == Token::Fallback || + tok == Token::Pragma || tok == Token::Import || tok == Token::As || tok == Token::Function || + (tok >= Token::Word && tok < Token::ExperimentalEnd); } - constexpr bool isExperimentalSolidityOnlyKeyword(Token) + constexpr bool isExperimentalSolidityOnlyKeyword(Token tok) { - return false; + return tok >= Token::Word && tok < Token::ExperimentalEnd; } bool isYulKeyword(std::string const& _literal); diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index 7feb7b294..8bf9f9fe6 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -48,6 +48,10 @@ set(sources analysis/ViewPureChecker.h analysis/experimental/Analysis.cpp analysis/experimental/Analysis.h + analysis/experimental/TypeInference.cpp + analysis/experimental/TypeInference.h + analysis/experimental/SyntaxRestrictor.cpp + analysis/experimental/SyntaxRestrictor.h ast/AST.cpp ast/AST.h ast/AST_accept.h @@ -94,6 +98,8 @@ set(sources codegen/YulUtilFunctions.cpp codegen/experimental/IRGenerator.cpp codegen/experimental/IRGenerator.h + codegen/experimental/IRGeneratorForStatements.cpp + codegen/experimental/IRGeneratorForStatements.h codegen/ir/Common.cpp codegen/ir/Common.h codegen/ir/IRGenerator.cpp diff --git a/libsolidity/analysis/experimental/Analysis.cpp b/libsolidity/analysis/experimental/Analysis.cpp index 5138ff280..919fc80df 100644 --- a/libsolidity/analysis/experimental/Analysis.cpp +++ b/libsolidity/analysis/experimental/Analysis.cpp @@ -17,10 +17,15 @@ // SPDX-License-Identifier: GPL-3.0 #include +#include + using namespace solidity::langutil; using namespace solidity::frontend::experimental; -bool Analysis::check(ASTNode const&) +bool Analysis::check(ASTNode const& _node) { + SyntaxRestrictor syntaxRestrictor{m_errorReporter}; + if (!syntaxRestrictor.check(_node)) + return false; return true; } diff --git a/libsolidity/analysis/experimental/Analysis.h b/libsolidity/analysis/experimental/Analysis.h index 9433508e4..d94eb5c8b 100644 --- a/libsolidity/analysis/experimental/Analysis.h +++ b/libsolidity/analysis/experimental/Analysis.h @@ -17,6 +17,8 @@ // SPDX-License-Identifier: GPL-3.0 #pragma once +#include + namespace solidity::frontend { class ASTNode; @@ -33,11 +35,14 @@ namespace solidity::frontend::experimental class Analysis { public: - Analysis(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) + Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId): + m_errorReporter(_errorReporter), + m_maxAstId(_maxAstId) {} bool check(ASTNode const& _ast); private: langutil::ErrorReporter& m_errorReporter; + uint64_t m_maxAstId = 0; }; } diff --git a/libsolidity/analysis/experimental/SyntaxRestrictor.cpp b/libsolidity/analysis/experimental/SyntaxRestrictor.cpp new file mode 100644 index 000000000..142d46011 --- /dev/null +++ b/libsolidity/analysis/experimental/SyntaxRestrictor.cpp @@ -0,0 +1,110 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +#include + +using namespace solidity::frontend; +using namespace solidity::frontend::experimental; +using namespace solidity::langutil; + +bool SyntaxRestrictor::check(ASTNode const& _astRoot) +{ + _astRoot.accept(*this); + return !Error::containsErrors(m_errorReporter.errors()); +} + +bool SyntaxRestrictor::visitNode(ASTNode const& _node) +{ + m_errorReporter.syntaxError(0000_error, _node.location(), "Unsupported AST node."); + return false; +} + +bool SyntaxRestrictor::visit(ContractDefinition const& _contractDefinition) +{ + if (_contractDefinition.contractKind() != ContractKind::Contract) + m_errorReporter.syntaxError(0000_error, _contractDefinition.location(), "Only contracts are supported."); + if (!_contractDefinition.baseContracts().empty()) + m_errorReporter.syntaxError(0000_error, _contractDefinition.location(), "Inheritance unsupported."); + return true; +} + +bool SyntaxRestrictor::visit(FunctionDefinition const& _functionDefinition) +{ + if (!_functionDefinition.isImplemented()) + m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Functions must be implemented."); + if (!_functionDefinition.parameterList().parameters().empty()) + m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have arguments."); + if (_functionDefinition.returnParameterList() && !_functionDefinition.returnParameterList()->parameters().empty()) + m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have return variables."); + if (_functionDefinition.isFree()) + { + if (_functionDefinition.stateMutability() != StateMutability::NonPayable) + m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Free functions may not have a mutability."); + } + else + { + if (_functionDefinition.isFallback()) + { + if (_functionDefinition.visibility() != Visibility::External) + m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Fallback function must be external."); + } + else + m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Only fallback functions are supported in contracts."); + } + + _functionDefinition.body().accept(*this); + + return false; +} + +bool SyntaxRestrictor::visit(VariableDeclarationStatement const& _variableDeclarationStatement) +{ + if (_variableDeclarationStatement.initialValue()) + m_errorReporter.syntaxError(0000_error, _variableDeclarationStatement.initialValue()->location(), "Variable declarations with initial value not supported."); + if (_variableDeclarationStatement.declarations().size() == 1) + { + if (!_variableDeclarationStatement.declarations().front()) + m_errorReporter.syntaxError(0000_error, _variableDeclarationStatement.initialValue()->location(), "Variable declaration has to declare a single variable."); + } + else + m_errorReporter.syntaxError(0000_error, _variableDeclarationStatement.initialValue()->location(), "Variable declarations can only declare a single variable."); + return true; +} + +bool SyntaxRestrictor::visit(VariableDeclaration const& _variableDeclaration) +{ + if (_variableDeclaration.value()) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.value()->location(), "Variable declarations with initial value not supported."); + if (_variableDeclaration.isStateVariable()) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "State variables are not supported."); + if (!_variableDeclaration.isLocalVariable()) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "Only local variables are supported."); + if (_variableDeclaration.mutability() != VariableDeclaration::Mutability::Mutable) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "Only mutable variables are supported."); + if (_variableDeclaration.isIndexed()) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "Indexed variables are not supported."); + if (!_variableDeclaration.noVisibilitySpecified()) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "Variables with visibility not supported."); + if (_variableDeclaration.overrides()) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "Variables with override specifier not supported."); + if (_variableDeclaration.referenceLocation() != VariableDeclaration::Location::Unspecified) + m_errorReporter.syntaxError(0000_error, _variableDeclaration.location(), "Variables with reference location not supported."); + return true; +} \ No newline at end of file diff --git a/libsolidity/analysis/experimental/SyntaxRestrictor.h b/libsolidity/analysis/experimental/SyntaxRestrictor.h new file mode 100644 index 000000000..aff673626 --- /dev/null +++ b/libsolidity/analysis/experimental/SyntaxRestrictor.h @@ -0,0 +1,55 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 +#pragma once + +#include + +#include +#include + +namespace solidity::frontend::experimental +{ + +class SyntaxRestrictor: public ASTConstVisitor +{ +public: + /// @param _errorReporter provides the error logging functionality. + explicit SyntaxRestrictor(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {} + + bool check(ASTNode const& _astRoot); + +private: + /// Default visit will reject all AST nodes that are not explicitly allowed. + bool visitNode(ASTNode const& _node) override; + + bool visit(SourceUnit const&) override { return true; } + bool visit(PragmaDirective const&) override { return true; } + bool visit(ImportDirective const&) override { return true; } + bool visit(ContractDefinition const& _contractDefinition) override; + bool visit(FunctionDefinition const& _functionDefinition) override; + bool visit(Block const&) override { return true; } + bool visit(InlineAssembly const&) override { return true; } + bool visit(Identifier const&) override { return true; } + bool visit(VariableDeclarationStatement const&) override; + bool visit(VariableDeclaration const&) override; + bool visit(ElementaryTypeName const&) override { return true; } + + langutil::ErrorReporter& m_errorReporter; +}; + +} diff --git a/libsolidity/analysis/experimental/TypeInference.cpp b/libsolidity/analysis/experimental/TypeInference.cpp new file mode 100644 index 000000000..db7ac2356 --- /dev/null +++ b/libsolidity/analysis/experimental/TypeInference.cpp @@ -0,0 +1,37 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + + +#include +#include + +using namespace solidity::frontend; +using namespace solidity::frontend::experimental; +using namespace solidity::langutil; + +bool TypeInference::visitNode(ASTNode const& _node) +{ + m_errorReporter.typeError(0000_error, _node.location(), "Unsupported AST node during type inference."); + return false; +} + +bool TypeInference::visit(VariableDeclaration const&) +{ +// m_env.assignType(&_varialeDeclaration, m_env.lookupType(_varialeDeclaration.typeName())); + return false; +} diff --git a/libsolidity/analysis/experimental/TypeInference.h b/libsolidity/analysis/experimental/TypeInference.h new file mode 100644 index 000000000..f1decb8ff --- /dev/null +++ b/libsolidity/analysis/experimental/TypeInference.h @@ -0,0 +1,111 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 +#pragma once + +#include + +#include + +#include + +namespace solidity::frontend::experimental +{ + +class GlobalTypeContext; + +struct SumType; +struct TupleType; +struct FunctionType; +struct WordType; +struct UserDefinedType; +struct TypeVariable; +struct FreeType; + +using Type = std::variant; + +struct SumType +{ + std::vector alternatives; +}; + +struct TupleType +{ + std::vector components; +}; + +struct FunctionType +{ + Type const* codomain = nullptr; + Type const* domain = nullptr; +}; + +struct WordType +{ +}; + +struct UserDefinedType +{ + Declaration const* declaration = nullptr; + std::vector arguments; +}; + +struct TypeVariable +{ + uint64_t index = 0; +}; + +struct FreeType +{ + uint64_t index = 0; +}; + +Type unify(Type _a, Type _b) +{ + +} + +class TypeEnvironment +{ +public: + TypeEnvironment() {} + void assignType(Declaration const* _declaration, Type _typeAssignment) + { + m_types.emplace(std::piecewise_construct, std::forward_as_tuple(_declaration), std::forward_as_tuple(std::move(_typeAssignment))); + } +private: + uint64_t m_numTypeVariables = 0; + std::map m_types; +}; + +class TypeInference: public ASTConstVisitor +{ +public: + TypeInference(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {} +private: + bool visit(Block const&) override { return true; } + bool visit(VariableDeclarationStatement const&) override { return true; } + bool visit(VariableDeclaration const& _variableDeclaration) override; + + bool visitNode(ASTNode const& _node) override; + +private: + langutil::ErrorReporter& m_errorReporter; + TypeEnvironment m_env; +}; + +} \ No newline at end of file diff --git a/libsolidity/codegen/experimental/IRGeneratorForStatements.cpp b/libsolidity/codegen/experimental/IRGeneratorForStatements.cpp new file mode 100644 index 000000000..913c916ee --- /dev/null +++ b/libsolidity/codegen/experimental/IRGeneratorForStatements.cpp @@ -0,0 +1,26 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::frontend; +using namespace solidity::frontend::experimental; +using namespace std::string_literals; diff --git a/libsolidity/codegen/experimental/IRGeneratorForStatements.h b/libsolidity/codegen/experimental/IRGeneratorForStatements.h new file mode 100644 index 000000000..70f4f9c5b --- /dev/null +++ b/libsolidity/codegen/experimental/IRGeneratorForStatements.h @@ -0,0 +1,38 @@ +/* + 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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include + +#include + +namespace solidity::frontend::experimental +{ + +class IRGeneratorForStatements: public ASTConstVisitor +{ +public: + IRGeneratorForStatements() {} + +private: + /// Default visit will reject all AST nodes that are not explicitly supported. + bool visitNode(ASTNode const& _node) override; +}; + +} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 4c8bd954a..9163cfada 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -668,8 +668,8 @@ bool CompilerStack::analyzeLegacy(bool _noErrorsSoFar) bool CompilerStack::analyzeExperimental() { bool noErrors = true; - solAssert(m_maxAstId); - m_experimentalAnalysis = make_unique(m_errorReporter); + solAssert(m_maxAstId && *m_maxAstId >= 0); + m_experimentalAnalysis = make_unique(m_errorReporter, static_cast(*m_maxAstId)); for (Source const* source: m_sourceOrder) if (source->ast) if (!m_experimentalAnalysis->check(*source->ast)) diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 4073ed607..4566a69e1 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -49,6 +49,8 @@ public: ASTPointer parse(langutil::CharStream& _charStream); + /// Returns the maximal AST node ID assigned so far + int64_t maxID() const { return m_currentNodeID; } private: class ASTNodeFactory; @@ -198,8 +200,6 @@ private: /// Returns the next AST node ID int64_t nextID() { return ++m_currentNodeID; } - /// Returns the maximal AST node ID assigned so far - int64_t maxID() const { return m_currentNodeID; } std::pair tryParseIndexAccessedPath(); /// Performs limited look-ahead to distinguish between variable declaration and expression statement. diff --git a/libstdlib/src/stub.sol b/libstdlib/src/stub.sol index 46ae21dcf..bd34e0475 100644 --- a/libstdlib/src/stub.sol +++ b/libstdlib/src/stub.sol @@ -3,7 +3,6 @@ pragma solidity >=0.0; pragma experimental solidity; -function identity(uint256 x) pure returns (uint256) +function identity() { - return x; } diff --git a/test/libsolidity/semanticTests/experimental/stub.sol b/test/libsolidity/semanticTests/experimental/stub.sol new file mode 100644 index 000000000..88b0e1199 --- /dev/null +++ b/test/libsolidity/semanticTests/experimental/stub.sol @@ -0,0 +1,15 @@ +pragma experimental solidity; + +contract C { + fallback() external { + word x; + assembly { + mstore(0, 42) + return(0, 32) + } + } +} +// ==== +// compileViaYul: true +// ---- +// () -> 42 diff --git a/test/libsolidity/syntaxTests/experimental_keywords.sol b/test/libsolidity/syntaxTests/experimental_keywords.sol new file mode 100644 index 000000000..b5920aed0 --- /dev/null +++ b/test/libsolidity/syntaxTests/experimental_keywords.sol @@ -0,0 +1,4 @@ +function f() pure { + uint word; word; + uint static_assert; static_assert; +} \ No newline at end of file