mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	tmp
This commit is contained in:
		
							parent
							
								
									71f7bf7206
								
							
						
					
					
						commit
						4357b0316b
					
				| @ -330,7 +330,7 @@ namespace TokenTraits | ||||
| 	constexpr bool isExperimentalSolidityKeyword(Token tok) | ||||
| 	{ | ||||
| 		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::Pragma || tok == Token::Import || tok == Token::As || tok == Token::Function || tok == Token::Let || | ||||
| 			(tok >= Token::Word && tok < Token::ExperimentalEnd); | ||||
| 	} | ||||
| 	constexpr bool isExperimentalSolidityOnlyKeyword(Token tok) | ||||
|  | ||||
| @ -74,6 +74,8 @@ set(sources | ||||
| 	ast/Types.h | ||||
| 	ast/TypeProvider.cpp | ||||
| 	ast/TypeProvider.h | ||||
| 	ast/experimental/TypeSystem.cpp | ||||
| 	ast/experimental/TypeSystem.h | ||||
| 	codegen/ABIFunctions.cpp | ||||
| 	codegen/ABIFunctions.h | ||||
| 	codegen/ArrayUtils.cpp | ||||
|  | ||||
| @ -18,14 +18,27 @@ | ||||
| #include <libsolidity/analysis/experimental/Analysis.h> | ||||
| 
 | ||||
| #include <libsolidity/analysis/experimental/SyntaxRestrictor.h> | ||||
| #include <libsolidity/analysis/experimental/TypeInference.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::langutil; | ||||
| using namespace solidity::frontend::experimental; | ||||
| 
 | ||||
| bool Analysis::check(ASTNode const& _node) | ||||
| Analysis::Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId): | ||||
| 	m_errorReporter(_errorReporter), | ||||
| 	m_maxAstId(_maxAstId) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| bool Analysis::check(vector<shared_ptr<SourceUnit const>> const& _sourceUnits) | ||||
| { | ||||
| 	SyntaxRestrictor syntaxRestrictor{m_errorReporter}; | ||||
| 	if (!syntaxRestrictor.check(_node)) | ||||
| 	for (auto source: _sourceUnits) | ||||
| 		if (!syntaxRestrictor.check(*source)) | ||||
| 			return false; | ||||
| 	TypeInference typeInference{m_errorReporter}; | ||||
| 	for (auto source: _sourceUnits) | ||||
| 		if (!typeInference.analyze(*source)) | ||||
| 			return false; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @ -18,10 +18,12 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <cstdint> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace solidity::frontend | ||||
| { | ||||
| class ASTNode; | ||||
| class SourceUnit; | ||||
| } | ||||
| 
 | ||||
| namespace solidity::langutil | ||||
| @ -35,11 +37,8 @@ namespace solidity::frontend::experimental | ||||
| class Analysis | ||||
| { | ||||
| public: | ||||
| 	Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId): | ||||
| 	m_errorReporter(_errorReporter), | ||||
| 	m_maxAstId(_maxAstId) | ||||
| 	{} | ||||
| 	bool check(ASTNode const& _ast); | ||||
| 	Analysis(langutil::ErrorReporter& _errorReporter, uint64_t _maxAstId); | ||||
| 	bool check(std::vector<std::shared_ptr<SourceUnit const>> const& _sourceUnits); | ||||
| private: | ||||
| 	langutil::ErrorReporter& m_errorReporter; | ||||
| 	uint64_t m_maxAstId = 0; | ||||
|  | ||||
| @ -49,10 +49,10 @@ 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.modifiers().empty()) | ||||
| 		m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have modifiers."); | ||||
| 	if (_functionDefinition.overrides()) | ||||
| 		m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have override specifiers."); | ||||
| 	if (_functionDefinition.isFree()) | ||||
| 	{ | ||||
| 		if (_functionDefinition.stateMutability() != StateMutability::NonPayable) | ||||
| @ -69,9 +69,7 @@ bool SyntaxRestrictor::visit(FunctionDefinition const& _functionDefinition) | ||||
| 			m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Only fallback functions are supported in contracts."); | ||||
| 	} | ||||
| 
 | ||||
| 	_functionDefinition.body().accept(*this); | ||||
| 
 | ||||
| 	return false; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool SyntaxRestrictor::visit(VariableDeclarationStatement const& _variableDeclarationStatement) | ||||
|  | ||||
| @ -42,12 +42,15 @@ private: | ||||
| 	bool visit(ImportDirective const&) override { return true; } | ||||
| 	bool visit(ContractDefinition const& _contractDefinition) override; | ||||
| 	bool visit(FunctionDefinition const& _functionDefinition) override; | ||||
| 	bool visit(ExpressionStatement const&) override { return true; } | ||||
| 	bool visit(Assignment const&) override { return true; } | ||||
| 	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; } | ||||
| 	bool visit(ParameterList const&) override { return true; } | ||||
| 
 | ||||
| 	langutil::ErrorReporter& m_errorReporter; | ||||
| }; | ||||
|  | ||||
| @ -20,18 +20,119 @@ | ||||
| #include <libsolidity/analysis/experimental/TypeInference.h> | ||||
| #include <liblangutil/Exceptions.h> | ||||
| 
 | ||||
| #include <libyul/AsmAnalysis.h> | ||||
| #include <libyul/AsmAnalysisInfo.h> | ||||
| #include <libyul/AST.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::frontend; | ||||
| using namespace solidity::frontend::experimental; | ||||
| using namespace solidity::langutil; | ||||
| 
 | ||||
| bool TypeInference::analyze(SourceUnit const& _sourceUnit) | ||||
| { | ||||
| 	_sourceUnit.accept(*this); | ||||
| 	return !m_errorReporter.hasErrors(); | ||||
| } | ||||
| 
 | ||||
| bool TypeInference::visit(FunctionDefinition const& _functionDefinition) | ||||
| { | ||||
| 	ScopedSaveAndRestore env{m_env, {}}; | ||||
| 	_functionDefinition.parameterList().accept(*this); | ||||
| 	if (_functionDefinition.returnParameterList()) | ||||
| 		_functionDefinition.returnParameterList()->accept(*this); | ||||
| 
 | ||||
| 	_functionDefinition.body().accept(*this); | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool TypeInference::visit(ParameterList const&) | ||||
| { | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| 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&) | ||||
| experimental::Type TypeInference::fromTypeName(TypeName const& _typeName) | ||||
| { | ||||
| //	m_env.assignType(&_varialeDeclaration, m_env.lookupType(_varialeDeclaration.typeName()));
 | ||||
| 	if (auto const* elementaryTypeName = dynamic_cast<ElementaryTypeName const*>(&_typeName)) | ||||
| 	{ | ||||
| 		switch(elementaryTypeName->typeName().token()) | ||||
| 		{ | ||||
| 		case Token::Word: | ||||
| 			return WordType{}; | ||||
| 		default: | ||||
| 			m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported."); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 		m_errorReporter.typeError(0000_error, _typeName.location(), "Only elementary types are supported."); | ||||
| 	return m_env.freshFreeType(); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool TypeInference::visit(InlineAssembly const& _inlineAssembly) | ||||
| { | ||||
| 	// External references have already been resolved in a prior stage and stored in the annotation.
 | ||||
| 	// We run the resolve step again regardless.
 | ||||
| 	yul::ExternalIdentifierAccess::Resolver identifierAccess = [&]( | ||||
| 		yul::Identifier const& _identifier, | ||||
| 		yul::IdentifierContext _context, | ||||
| 		bool | ||||
| 	) -> bool | ||||
| 	{ | ||||
| 		if (_context == yul::IdentifierContext::NonExternal) | ||||
| 		{ | ||||
| 			// Hack until we can disallow any shadowing: If we found an internal reference,
 | ||||
| 			// clear the external references, so that codegen does not use it.
 | ||||
| 			_inlineAssembly.annotation().externalReferences.erase(& _identifier); | ||||
| 			return false; | ||||
| 		} | ||||
| 		auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); | ||||
| 		if (ref == _inlineAssembly.annotation().externalReferences.end()) | ||||
| 			return false; | ||||
| 		InlineAssemblyAnnotation::ExternalIdentifierInfo& identifierInfo = ref->second; | ||||
| 		Declaration const* declaration = identifierInfo.declaration; | ||||
| 		solAssert(!!declaration, ""); | ||||
| 
 | ||||
| 		m_env.assignType(m_typeSystem, declaration, WordType{}); | ||||
| 		identifierInfo.valueSize = 1; | ||||
| 		return true; | ||||
| 	}; | ||||
| 	solAssert(!_inlineAssembly.annotation().analysisInfo, ""); | ||||
| 	_inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>(); | ||||
| 	yul::AsmAnalyzer analyzer( | ||||
| 		*_inlineAssembly.annotation().analysisInfo, | ||||
| 		m_errorReporter, | ||||
| 		_inlineAssembly.dialect(), | ||||
| 		identifierAccess | ||||
| 	); | ||||
| 	if (!analyzer.analyze(_inlineAssembly.operations())) | ||||
| 		solAssert(m_errorReporter.hasErrors()); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool TypeInference::visit(VariableDeclaration const& _variableDeclaration) | ||||
| { | ||||
| 	Type type = _variableDeclaration.hasTypeName() ? fromTypeName(_variableDeclaration.typeName()) : m_typeSystem.freshTypeVariable(); | ||||
| 	m_env.assignType(m_typeSystem, &_variableDeclaration, type); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool TypeInference::visit(Assignment const& _assignment) | ||||
| { | ||||
| 	(void)_assignment; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool TypeInference::visit(Identifier const& _identifier) | ||||
| { | ||||
| 	(void)_identifier; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @ -18,6 +18,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <libsolidity/ast/ASTVisitor.h> | ||||
| #include <libsolidity/ast/experimental/TypeSystem.h> | ||||
| 
 | ||||
| #include <liblangutil/ErrorReporter.h> | ||||
| 
 | ||||
| @ -26,84 +27,32 @@ | ||||
| namespace solidity::frontend::experimental | ||||
| { | ||||
| 
 | ||||
| class GlobalTypeContext; | ||||
| 
 | ||||
| struct SumType; | ||||
| struct TupleType; | ||||
| struct FunctionType; | ||||
| struct WordType; | ||||
| struct UserDefinedType; | ||||
| struct TypeVariable; | ||||
| struct FreeType; | ||||
| 
 | ||||
| using Type = std::variant<SumType, TupleType, FunctionType, WordType, UserDefinedType, TypeVariable, FreeType>; | ||||
| 
 | ||||
| struct SumType | ||||
| { | ||||
| 	std::vector<Type const*> alternatives; | ||||
| }; | ||||
| 
 | ||||
| struct TupleType | ||||
| { | ||||
| 	std::vector<Type const*> components; | ||||
| }; | ||||
| 
 | ||||
| struct FunctionType | ||||
| { | ||||
| 	Type const* codomain = nullptr; | ||||
| 	Type const* domain = nullptr; | ||||
| }; | ||||
| 
 | ||||
| struct WordType | ||||
| { | ||||
| }; | ||||
| 
 | ||||
| struct UserDefinedType | ||||
| { | ||||
| 	Declaration const* declaration = nullptr; | ||||
| 	std::vector<Type const*> 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<Declaration const*, Type> m_types; | ||||
| }; | ||||
| 
 | ||||
| class TypeInference: public ASTConstVisitor | ||||
| { | ||||
| public: | ||||
| 	TypeInference(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {} | ||||
| 
 | ||||
| 	bool analyze(SourceUnit const& _sourceUnit); | ||||
| private: | ||||
| 	bool visit(Block const&) override { return true; } | ||||
| 	bool visit(VariableDeclarationStatement const&) override { return true; } | ||||
| 	bool visit(VariableDeclaration const& _variableDeclaration) override; | ||||
| 
 | ||||
| 	bool visit(FunctionDefinition const& _functionDefinition) override; | ||||
| 	bool visit(ParameterList const& _parameterList) override; | ||||
| 	bool visit(SourceUnit const&) override { return true; } | ||||
| 	bool visit(ContractDefinition const&) override { return true; } | ||||
| 	bool visit(InlineAssembly const& _inlineAssembly) override; | ||||
| 	bool visit(PragmaDirective const&) override { return false; } | ||||
| 
 | ||||
| 	bool visit(ExpressionStatement const&) override { return true; } | ||||
| 	bool visit(Assignment const&) override; | ||||
| 	bool visit(Identifier const&) override; | ||||
| 
 | ||||
| 	bool visitNode(ASTNode const& _node) override; | ||||
| 
 | ||||
| private: | ||||
| 	Type fromTypeName(TypeName const& _typeName); | ||||
| 	TypeSystem m_typeSystem; | ||||
| 	langutil::ErrorReporter& m_errorReporter; | ||||
| 	TypeEnvironment m_env; | ||||
| }; | ||||
|  | ||||
| @ -1077,13 +1077,15 @@ public: | ||||
| 		m_overrides(std::move(_overrides)), | ||||
| 		m_location(_referenceLocation) | ||||
| 	{ | ||||
| 		solAssert(m_typeName, ""); | ||||
| 		// TODO: consider still asserting unless we are in experimental solidity.
 | ||||
| 		// solAssert(m_typeName, "");
 | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	void accept(ASTVisitor& _visitor) override; | ||||
| 	void accept(ASTConstVisitor& _visitor) const override; | ||||
| 
 | ||||
| 	bool hasTypeName() const { return m_typeName != nullptr; } | ||||
| 	TypeName const& typeName() const { return *m_typeName; } | ||||
| 	ASTPointer<Expression> const& value() const { return m_value; } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										64
									
								
								libsolidity/ast/experimental/TypeSystem.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								libsolidity/ast/experimental/TypeSystem.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| /*
 | ||||
| 	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/>.
 | ||||
| */ | ||||
| // SPDX-License-Identifier: GPL-3.0
 | ||||
| 
 | ||||
| 
 | ||||
| #include <libsolidity/ast/experimental/TypeSystem.h> | ||||
| #include <liblangutil/Exceptions.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity::frontend; | ||||
| using namespace solidity::frontend::experimental; | ||||
| 
 | ||||
| void TypeEnvironment::assignType(TypeSystem& _typeSystem, Declaration const* _declaration, Type _typeAssignment) | ||||
| { | ||||
| 	auto&& [type, newlyInserted] = m_types.emplace(std::piecewise_construct, std::forward_as_tuple(_declaration), std::forward_as_tuple(std::move(_typeAssignment))); | ||||
| 	if (!newlyInserted) | ||||
| 	{ | ||||
| 		unify(_typeSystem, type->second, _typeAssignment); | ||||
| 	} | ||||
| } | ||||
| Type TypeEnvironment::lookup(TypeSystem& _typeSystem, Declaration const* _declaration) | ||||
| { | ||||
| 	if (m_types.count(_declaration)) | ||||
| 		return m_types[_declaration]; | ||||
| 	Type result = _typeSystem.freshTypeVariable(); | ||||
| 	m_types.emplace(std::piecewise_construct, std::forward_as_tuple(_declaration), std::forward_as_tuple(result)); | ||||
| 	return result; | ||||
| } | ||||
| Type TypeEnvironment::freshFreeType() | ||||
| { | ||||
| 	return FreeType{m_numFreeTypes++}; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void TypeEnvironment::unify(TypeSystem& _context, Type _a, Type _b) | ||||
| { | ||||
| 	_a = _context.resolve(_a); | ||||
| 	_b = _context.resolve(_b); | ||||
| 	if (auto* varA = get_if<TypeVariable>(&_a)) | ||||
| 		_context.instantiate(*varA, _b); | ||||
| 	else if (holds_alternative<WordType>(_a)) | ||||
| 	{ | ||||
| 		if (holds_alternative<WordType>(_b)) | ||||
| 			return; | ||||
| 		else | ||||
| 			solAssert(false, "unification failed"); | ||||
| 	} | ||||
| 
 | ||||
| 	solAssert(false, fmt::format("cannot unify {} and {}", typeToString(_a), typeToString(_b))); | ||||
| } | ||||
							
								
								
									
										167
									
								
								libsolidity/ast/experimental/TypeSystem.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								libsolidity/ast/experimental/TypeSystem.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,167 @@ | ||||
| /*
 | ||||
| 	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/>.
 | ||||
| */ | ||||
| // SPDX-License-Identifier: GPL-3.0
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <liblangutil/Exceptions.h> | ||||
| 
 | ||||
| #include <fmt/format.h> | ||||
| 
 | ||||
| #include <optional> | ||||
| #include <string> | ||||
| #include <variant> | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace solidity::frontend | ||||
| { | ||||
| class Declaration; | ||||
| } | ||||
| 
 | ||||
| namespace solidity::frontend::experimental | ||||
| { | ||||
| 
 | ||||
| class TypeSystem; | ||||
| 
 | ||||
| struct SumType; | ||||
| struct TupleType; | ||||
| struct FunctionType; | ||||
| struct WordType; | ||||
| struct UserDefinedType; | ||||
| struct TypeVariable; | ||||
| struct FreeType; | ||||
| 
 | ||||
| using Type = std::variant<SumType, TupleType, FunctionType, WordType, UserDefinedType, TypeVariable, FreeType>; | ||||
| 
 | ||||
| struct SumType | ||||
| { | ||||
| 	std::vector<Type const*> alternatives; | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return "sum"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct TupleType | ||||
| { | ||||
| 	std::vector<Type const*> components; | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return "tuple"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct FunctionType | ||||
| { | ||||
| 	Type const* codomain = nullptr; | ||||
| 	Type const* domain = nullptr; | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return "fun"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct WordType | ||||
| { | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return "word"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct UserDefinedType | ||||
| { | ||||
| 	Declaration const* declaration = nullptr; | ||||
| 	std::vector<Type const*> arguments; | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return "user_defined_type"; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| struct TypeVariable | ||||
| { | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return fmt::format("var<{}>", m_index); | ||||
| 	} | ||||
| private: | ||||
| 	uint64_t index() const { return m_index; } | ||||
| 	friend class TypeSystem; | ||||
| 	uint64_t m_index = 0; | ||||
| 	TypeVariable(uint64_t _index): m_index(_index) {} | ||||
| }; | ||||
| 
 | ||||
| struct FreeType | ||||
| { | ||||
| 	uint64_t index = 0; | ||||
| 	std::string toString() const | ||||
| 	{ | ||||
| 		return fmt::format("free<{}>", index); | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| inline std::string typeToString(Type const& _type) | ||||
| { | ||||
| 	return std::visit([](auto _type) { return _type.toString(); }, _type); | ||||
| } | ||||
| 
 | ||||
| class TypeEnvironment | ||||
| { | ||||
| public: | ||||
| 	void assignType(TypeSystem& _typeSystem, Declaration const* _declaration, Type _typeAssignment); | ||||
| 	Type lookup(TypeSystem& _typeSystem, Declaration const* _declaration); | ||||
| 	Type freshFreeType(); | ||||
| 	void unify(TypeSystem& _typeSystem, Type _a, Type _b); | ||||
| private: | ||||
| 	uint64_t m_numFreeTypes = 0; | ||||
| 	std::map<Declaration const*, Type> m_types; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| class TypeSystem | ||||
| { | ||||
| public: | ||||
| 	TypeSystem() {} | ||||
| 	TypeSystem(TypeSystem const&) = delete; | ||||
| 	TypeSystem const& operator=(TypeSystem const&) = delete; | ||||
| 	Type freshTypeVariable() | ||||
| 	{ | ||||
| 		uint64_t index = m_typeVariables.size(); | ||||
| 		m_typeVariables.emplace_back(std::nullopt); | ||||
| 		return TypeVariable(index); | ||||
| 	} | ||||
| 	void instantiate(TypeVariable _variable, Type _type) | ||||
| 	{ | ||||
| 		solAssert(_variable.index() < m_typeVariables.size()); | ||||
| 		solAssert(!m_typeVariables.at(_variable.index()).has_value()); | ||||
| 		m_typeVariables[_variable.index()] = _type; | ||||
| 	} | ||||
| 	Type resolve(Type _type) | ||||
| 	{ | ||||
| 		Type result = _type; | ||||
| 		while(auto const* var = std::get_if<TypeVariable>(&result)) | ||||
| 			if (auto value = m_typeVariables.at(var->index())) | ||||
| 				result = *value; | ||||
| 			else | ||||
| 				break; | ||||
| 		return result; | ||||
| 	} | ||||
| private: | ||||
| 	std::vector<std::optional<Type>> m_typeVariables; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| @ -18,6 +18,8 @@ | ||||
| 
 | ||||
| #include <libsolidity/codegen/experimental/IRGenerator.h> | ||||
| 
 | ||||
| #include <libsolidity/codegen/experimental/IRGeneratorForStatements.h> | ||||
| 
 | ||||
| #include <libsolidity/codegen/ir/Common.h> | ||||
| 
 | ||||
| #include <libyul/YulStack.h> | ||||
| @ -87,74 +89,9 @@ string IRGenerator::generate(FunctionDefinition const& _function) const | ||||
| 	code << "function " << IRNames::function(_function) << "() {\n"; | ||||
| 	for (auto _statement: _function.body().statements()) | ||||
| 	{ | ||||
| 		if (auto assembly = dynamic_cast<InlineAssembly const*>(_statement.get())) | ||||
| 			code << generate(*assembly) << "\n"; | ||||
| 		else | ||||
| 			solUnimplemented("Unsupported statement type."); | ||||
| 		IRGeneratorForStatements statementGenerator{m_analysis}; | ||||
| 		code << statementGenerator.generate(*_statement); | ||||
| 	} | ||||
| 	code << "}\n"; | ||||
| 	return code.str(); | ||||
| } | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| struct CopyTranslate: public yul::ASTCopier | ||||
| { | ||||
| 	CopyTranslate( | ||||
| 		yul::Dialect const& _dialect, | ||||
| 		map<yul::Identifier const*, void*> _references | ||||
| 	): m_dialect(_dialect), m_references(std::move(_references)) {} | ||||
| 
 | ||||
| 	using ASTCopier::operator(); | ||||
| 
 | ||||
| 	yul::Expression operator()(yul::Identifier const& _identifier) override | ||||
| 	{ | ||||
| 		// The operator() function is only called in lvalue context. In rvalue context,
 | ||||
| 		// only translate(yul::Identifier) is called.
 | ||||
| 		if (m_references.count(&_identifier)) | ||||
| 			return translateReference(_identifier); | ||||
| 		else | ||||
| 			return ASTCopier::operator()(_identifier); | ||||
| 	} | ||||
| 
 | ||||
| 	yul::YulString translateIdentifier(yul::YulString _name) override | ||||
| 	{ | ||||
| 		if (m_dialect.builtin(_name)) | ||||
| 			return _name; | ||||
| 		else | ||||
| 			return yul::YulString{"usr$" + _name.str()}; | ||||
| 	} | ||||
| 
 | ||||
| 	yul::Identifier translate(yul::Identifier const& _identifier) override | ||||
| 	{ | ||||
| 		if (!m_references.count(&_identifier)) | ||||
| 			return ASTCopier::translate(_identifier); | ||||
| 
 | ||||
| 		yul::Expression translated = translateReference(_identifier); | ||||
| 		solAssert(holds_alternative<yul::Identifier>(translated)); | ||||
| 		return get<yul::Identifier>(std::move(translated)); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
| 	/// Translates a reference to a local variable, potentially including
 | ||||
| 	/// a suffix. Might return a literal, which causes this to be invalid in
 | ||||
| 	/// lvalue-context.
 | ||||
| 	yul::Expression translateReference(yul::Identifier const&) | ||||
| 	{ | ||||
| 		solUnimplemented("External references in inline assembly not implemented."); | ||||
| 	} | ||||
| 
 | ||||
| 	yul::Dialect const& m_dialect; | ||||
| 	map<yul::Identifier const*, void*> m_references; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| string IRGenerator::generate(InlineAssembly const& _assembly) const | ||||
| { | ||||
| 	CopyTranslate bodyCopier{_assembly.dialect(), {}}; | ||||
| 	yul::Statement modified = bodyCopier(_assembly.operations()); | ||||
| 	solAssert(holds_alternative<yul::Block>(modified)); | ||||
| 	return yul::AsmPrinter()(std::get<yul::Block>(modified)); | ||||
| } | ||||
| @ -35,6 +35,7 @@ namespace solidity::frontend::experimental | ||||
| { | ||||
| 
 | ||||
| class SourceUnit; | ||||
| class Analysis; | ||||
| 
 | ||||
| class IRGenerator | ||||
| { | ||||
| @ -45,12 +46,14 @@ public: | ||||
| 		RevertStrings /*_revertStrings*/, | ||||
| 		std::map<std::string, unsigned> /*_sourceIndices*/, | ||||
| 		langutil::DebugInfoSelection const& _debugInfoSelection, | ||||
| 		langutil::CharStreamProvider const* _soliditySourceProvider | ||||
| 		langutil::CharStreamProvider const* _soliditySourceProvider, | ||||
| 		Analysis const& _analysis | ||||
| 	): | ||||
| 		m_evmVersion(_evmVersion), | ||||
| 		m_eofVersion(_eofVersion), | ||||
| 		m_debugInfoSelection(_debugInfoSelection), | ||||
| 		m_soliditySourceProvider(_soliditySourceProvider) | ||||
| 		m_soliditySourceProvider(_soliditySourceProvider), | ||||
| 		m_analysis(_analysis) | ||||
| 	{} | ||||
| 
 | ||||
| 	std::string run( | ||||
| @ -61,13 +64,13 @@ public: | ||||
| 
 | ||||
| 	std::string generate(ContractDefinition const& _contract) const; | ||||
| 	std::string generate(FunctionDefinition const& _function) const; | ||||
| 	std::string generate(InlineAssembly const& _assembly) const; | ||||
| private: | ||||
| 	langutil::EVMVersion const m_evmVersion; | ||||
| 	std::optional<uint8_t> const m_eofVersion; | ||||
| 	OptimiserSettings const m_optimiserSettings; | ||||
| 	langutil::DebugInfoSelection m_debugInfoSelection = {}; | ||||
| 	langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; | ||||
| 	Analysis const& m_analysis; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -18,9 +18,108 @@ | ||||
| 
 | ||||
| #include <libsolidity/codegen/experimental/IRGeneratorForStatements.h> | ||||
| 
 | ||||
| #include <libyul/YulStack.h> | ||||
| #include <libyul/AsmPrinter.h> | ||||
| #include <libyul/AST.h> | ||||
| #include <libyul/optimiser/ASTCopier.h> | ||||
| 
 | ||||
| #include <libsolidity/codegen/ir/Common.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace solidity; | ||||
| using namespace solidity::util; | ||||
| using namespace solidity::frontend; | ||||
| using namespace solidity::frontend::experimental; | ||||
| using namespace std::string_literals; | ||||
| 
 | ||||
| std::string IRGeneratorForStatements::generate(ASTNode const& _node) | ||||
| { | ||||
| 	_node.accept(*this); | ||||
| 	return m_code.str(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| struct CopyTranslate: public yul::ASTCopier | ||||
| { | ||||
| 	CopyTranslate( | ||||
| 		yul::Dialect const& _dialect, | ||||
| 		map<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> _references | ||||
| 		): m_dialect(_dialect), m_references(std::move(_references)) {} | ||||
| 
 | ||||
| 	using ASTCopier::operator(); | ||||
| 
 | ||||
| 	yul::Expression operator()(yul::Identifier const& _identifier) override | ||||
| 	{ | ||||
| 		// The operator() function is only called in lvalue context. In rvalue context,
 | ||||
| 		// only translate(yul::Identifier) is called.
 | ||||
| 		if (m_references.count(&_identifier)) | ||||
| 			return translateReference(_identifier); | ||||
| 		else | ||||
| 			return ASTCopier::operator()(_identifier); | ||||
| 	} | ||||
| 
 | ||||
| 	yul::YulString translateIdentifier(yul::YulString _name) override | ||||
| 	{ | ||||
| 		if (m_dialect.builtin(_name)) | ||||
| 			return _name; | ||||
| 		else | ||||
| 			return yul::YulString{"usr$" + _name.str()}; | ||||
| 	} | ||||
| 
 | ||||
| 	yul::Identifier translate(yul::Identifier const& _identifier) override | ||||
| 	{ | ||||
| 		if (!m_references.count(&_identifier)) | ||||
| 			return ASTCopier::translate(_identifier); | ||||
| 
 | ||||
| 		yul::Expression translated = translateReference(_identifier); | ||||
| 		solAssert(holds_alternative<yul::Identifier>(translated)); | ||||
| 		return get<yul::Identifier>(std::move(translated)); | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 
 | ||||
| 	/// Translates a reference to a local variable, potentially including
 | ||||
| 	/// a suffix. Might return a literal, which causes this to be invalid in
 | ||||
| 	/// lvalue-context.
 | ||||
| 	yul::Expression translateReference(yul::Identifier const& _identifier) | ||||
| 	{ | ||||
| 		auto const& reference = m_references.at(&_identifier); | ||||
| 		auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration); | ||||
| 		solAssert(varDecl, "External reference in inline assembly to something that is not a variable declaration."); | ||||
| 		// TODO: validate that variable is known and has word type.
 | ||||
| 		string value = IRNames::localVariable(*varDecl); | ||||
| 		return yul::Identifier{_identifier.debugData, yul::YulString{value}}; | ||||
| 	} | ||||
| 
 | ||||
| 	yul::Dialect const& m_dialect; | ||||
| 	map<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> m_references; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool IRGeneratorForStatements::visit(InlineAssembly const& _assembly) | ||||
| { | ||||
| 	CopyTranslate bodyCopier{_assembly.dialect(), _assembly.annotation().externalReferences}; | ||||
| 	yul::Statement modified = bodyCopier(_assembly.operations()); | ||||
| 	solAssert(holds_alternative<yul::Block>(modified)); | ||||
| 	m_code << yul::AsmPrinter()(std::get<yul::Block>(modified)); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _variableDeclarationStatement) | ||||
| { | ||||
| 	solAssert(_variableDeclarationStatement.declarations().size() == 1, "multi variable declarations not supported"); | ||||
| 	solAssert(!_variableDeclarationStatement.initialValue(), "initial values not yet supported"); | ||||
| 	VariableDeclaration const* variableDeclaration = _variableDeclarationStatement.declarations().front().get(); | ||||
| 	solAssert(variableDeclaration); | ||||
| 	// TODO: check the type of the variable; register local variable; initialize
 | ||||
| 	m_code << "let " << IRNames::localVariable(*variableDeclaration) << "\n"; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool IRGeneratorForStatements::visitNode(ASTNode const&) | ||||
| { | ||||
| 	solAssert(false, "Unsupported AST node during statement code generation."); | ||||
| } | ||||
| @ -21,18 +21,25 @@ | ||||
| #include <libsolidity/ast/ASTVisitor.h> | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace solidity::frontend::experimental | ||||
| { | ||||
| class Analysis; | ||||
| 
 | ||||
| class IRGeneratorForStatements: public ASTConstVisitor | ||||
| { | ||||
| public: | ||||
| 	IRGeneratorForStatements() {} | ||||
| 	IRGeneratorForStatements(Analysis const& _analysis): m_analysis(_analysis) {} | ||||
| 
 | ||||
| 	std::string generate(ASTNode const& _node); | ||||
| private: | ||||
| 	bool visit(InlineAssembly const& _inlineAssembly) override; | ||||
| 	bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; | ||||
| 	/// Default visit will reject all AST nodes that are not explicitly supported.
 | ||||
| 	bool visitNode(ASTNode const& _node) override; | ||||
| 	Analysis const& m_analysis; | ||||
| 	std::stringstream m_code; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -670,9 +670,11 @@ bool CompilerStack::analyzeExperimental() | ||||
| 	bool noErrors = true; | ||||
| 	solAssert(m_maxAstId && *m_maxAstId >= 0); | ||||
| 	m_experimentalAnalysis = make_unique<experimental::Analysis>(m_errorReporter, static_cast<uint64_t>(*m_maxAstId)); | ||||
| 	vector<shared_ptr<SourceUnit const>> sourceAsts; | ||||
| 	for (Source const* source: m_sourceOrder) | ||||
| 		if (source->ast) | ||||
| 			if (!m_experimentalAnalysis->check(*source->ast)) | ||||
| 			sourceAsts.emplace_back(source->ast); | ||||
| 	if (!m_experimentalAnalysis->check(sourceAsts)) | ||||
| 		noErrors = false; | ||||
| 	return noErrors; | ||||
| } | ||||
| @ -1519,7 +1521,8 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) | ||||
| 			m_revertStrings, | ||||
| 			sourceIndices(), | ||||
| 			m_debugInfoSelection, | ||||
| 			this | ||||
| 			this, | ||||
| 			*m_experimentalAnalysis | ||||
| 		); | ||||
| 		compiledContract.yulIR = generator.run( | ||||
| 			_contract, | ||||
|  | ||||
| @ -610,7 +610,9 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari | ||||
| 		else | ||||
| 			break; | ||||
| 	} | ||||
| 	if (m_scanner->currentToken() == Token::Returns) | ||||
| 	if ( | ||||
| 		m_scanner->currentToken() == (m_experimentalSolidityEnabledInCurrentSourceUnit ? Token::RightArrow : Token::Returns) | ||||
| 	) | ||||
| 	{ | ||||
| 		bool const permitEmptyParameterList = false; | ||||
| 		advance(); | ||||
| @ -1269,15 +1271,21 @@ ASTPointer<ParameterList> Parser::parseParameterList( | ||||
| 	VarDeclParserOptions options(_options); | ||||
| 	options.allowEmptyName = true; | ||||
| 	expectToken(Token::LParen); | ||||
| 	auto parseSingleVariableDeclaration = [&]() { | ||||
| 		if (m_experimentalSolidityEnabledInCurrentSourceUnit) | ||||
| 			return parsePostfixVariableDeclaration(); | ||||
| 		else | ||||
| 			return parseVariableDeclaration(options); | ||||
| 	}; | ||||
| 	if (!_allowEmpty || m_scanner->currentToken() != Token::RParen) | ||||
| 	{ | ||||
| 		parameters.push_back(parseVariableDeclaration(options)); | ||||
| 		parameters.push_back(parseSingleVariableDeclaration()); | ||||
| 		while (m_scanner->currentToken() != Token::RParen) | ||||
| 		{ | ||||
| 			if (m_scanner->currentToken() == Token::Comma && m_scanner->peekNextToken() == Token::RParen) | ||||
| 				fatalParserError(7591_error, "Unexpected trailing comma in parameter list."); | ||||
| 			expectToken(Token::Comma); | ||||
| 			parameters.push_back(parseVariableDeclaration(options)); | ||||
| 			parameters.push_back(parseSingleVariableDeclaration()); | ||||
| 		} | ||||
| 	} | ||||
| 	nodeFactory.markEndPosition(); | ||||
| @ -1658,12 +1666,66 @@ ASTPointer<RevertStatement> Parser::parseRevertStatement(ASTPointer<ASTString> c | ||||
| 	return nodeFactory.createNode<RevertStatement>(_docString, errorCall); | ||||
| } | ||||
| 
 | ||||
| ASTPointer<VariableDeclarationStatement> Parser::parsePostfixVariableDeclarationStatement( | ||||
| 	ASTPointer<ASTString> const& _docString | ||||
| ) | ||||
| { | ||||
| 	RecursionGuard recursionGuard(*this); | ||||
| 	ASTNodeFactory nodeFactory(*this); | ||||
| 
 | ||||
| 	expectToken(Token::Let); | ||||
| 
 | ||||
| 	vector<ASTPointer<VariableDeclaration>> variables; | ||||
| 	variables.emplace_back(parsePostfixVariableDeclaration()); | ||||
| 	nodeFactory.setEndPositionFromNode(variables.back()); | ||||
| 
 | ||||
| 	ASTPointer<Expression> value; | ||||
| 	if (m_scanner->currentToken() == Token::Assign) | ||||
| 	{ | ||||
| 		advance(); | ||||
| 		value = parseExpression(); | ||||
| 		nodeFactory.setEndPositionFromNode(value); | ||||
| 	} | ||||
| 	return nodeFactory.createNode<VariableDeclarationStatement>(_docString, variables, value); | ||||
| } | ||||
| 
 | ||||
| ASTPointer<VariableDeclaration> Parser::parsePostfixVariableDeclaration() | ||||
| { | ||||
| 	RecursionGuard recursionGuard(*this); | ||||
| 	ASTNodeFactory nodeFactory(*this); | ||||
| 
 | ||||
| 	ASTPointer<StructuredDocumentation> const documentation = parseStructuredDocumentation(); | ||||
| 
 | ||||
| 	nodeFactory.markEndPosition(); | ||||
| 	auto [identifier, nameLocation] = expectIdentifierWithLocation(); | ||||
| 
 | ||||
| 	ASTPointer<TypeName> type; | ||||
| 	if (m_scanner->currentToken() == Token::Colon) | ||||
| 	{ | ||||
| 		advance(); | ||||
| 		type = parseTypeName(); | ||||
| 		nodeFactory.setEndPositionFromNode(type); | ||||
| 	} | ||||
| 
 | ||||
| 	return nodeFactory.createNode<VariableDeclaration>( | ||||
| 		type, | ||||
| 		identifier, | ||||
| 		nameLocation, | ||||
| 		nullptr, | ||||
| 		Visibility::Default, | ||||
| 		documentation | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& _docString) | ||||
| { | ||||
| 	RecursionGuard recursionGuard(*this); | ||||
| 	LookAheadInfo statementType; | ||||
| 	IndexAccessedPath iap; | ||||
| 
 | ||||
| 	if (m_experimentalSolidityEnabledInCurrentSourceUnit && m_scanner->currentToken() == Token::Let) | ||||
| 		return parsePostfixVariableDeclarationStatement(_docString); | ||||
| 
 | ||||
| 	if (m_scanner->currentToken() == Token::LParen) | ||||
| 	{ | ||||
| 		ASTNodeFactory nodeFactory(*this); | ||||
| @ -1766,7 +1828,10 @@ pair<Parser::LookAheadInfo, Parser::IndexAccessedPath> Parser::tryParseIndexAcce | ||||
| 	{ | ||||
| 	case LookAheadInfo::VariableDeclaration: | ||||
| 	case LookAheadInfo::Expression: | ||||
| 		return make_pair(statementType, IndexAccessedPath()); | ||||
| 		return make_pair( | ||||
| 			m_experimentalSolidityEnabledInCurrentSourceUnit ? LookAheadInfo::Expression : statementType, | ||||
| 			IndexAccessedPath() | ||||
| 		); | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| @ -1777,6 +1842,9 @@ pair<Parser::LookAheadInfo, Parser::IndexAccessedPath> Parser::tryParseIndexAcce | ||||
| 	// VariableDeclarationStatement out of it.
 | ||||
| 	IndexAccessedPath iap = parseIndexAccessedPath(); | ||||
| 
 | ||||
| 	if (m_experimentalSolidityEnabledInCurrentSourceUnit) | ||||
| 		return make_pair(LookAheadInfo::Expression, std::move(iap)); | ||||
| 
 | ||||
| 	if (m_scanner->currentToken() == Token::Identifier || TokenTraits::isLocationSpecifier(m_scanner->currentToken())) | ||||
| 		return make_pair(LookAheadInfo::VariableDeclaration, std::move(iap)); | ||||
| 	else | ||||
|  | ||||
| @ -170,6 +170,14 @@ private: | ||||
| 	std::pair<ASTPointer<ASTString>, langutil::SourceLocation> expectIdentifierWithLocation(); | ||||
| 	///@}
 | ||||
| 
 | ||||
| 	///@{
 | ||||
| 	///@name Specialized parsing functions for the AST nodes of experimental solidity.
 | ||||
| 	ASTPointer<VariableDeclarationStatement> parsePostfixVariableDeclarationStatement( | ||||
| 		ASTPointer<ASTString> const& _docString | ||||
| 	); | ||||
| 	ASTPointer<VariableDeclaration> parsePostfixVariableDeclaration(); | ||||
| 	///@}
 | ||||
| 
 | ||||
| 	///@{
 | ||||
| 	///@name Helper functions
 | ||||
| 
 | ||||
|  | ||||
| @ -116,8 +116,9 @@ unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> const& _scanner) | ||||
| { | ||||
| 	m_recursionDepth = 0; | ||||
| 
 | ||||
| 	auto previousScannerKind = _scanner->scannerKind(); | ||||
| 	_scanner->setScannerMode(ScannerKind::Yul); | ||||
| 	ScopeGuard resetScanner([&]{ _scanner->setScannerMode(ScannerKind::Solidity); }); | ||||
| 	ScopeGuard resetScanner([&]{ _scanner->setScannerMode(previousScannerKind); }); | ||||
| 
 | ||||
| 	try | ||||
| 	{ | ||||
|  | ||||
| @ -1,10 +1,21 @@ | ||||
| pragma experimental solidity; | ||||
| 
 | ||||
| function f(a:word) -> (b:word) { | ||||
|     assembly { | ||||
|         b := a | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| contract C { | ||||
| 	fallback() external { | ||||
| 	    word x; | ||||
| 		let x : word; | ||||
| 		let y : word; | ||||
| 		assembly { | ||||
| 			mstore(0, 42) | ||||
| 			x := 0x42 | ||||
| 		} | ||||
| 		y = x; | ||||
| 		assembly { | ||||
| 			mstore(0, y) | ||||
| 			return(0, 32) | ||||
| 		} | ||||
| 	} | ||||
| @ -12,4 +23,4 @@ contract C { | ||||
| // ==== | ||||
| // compileViaYul: true | ||||
| // ---- | ||||
| // () -> 42 | ||||
| // () -> 0x42 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user