mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #6774 from ethereum/dialectRefactor
Dialect refactor
This commit is contained in:
		
						commit
						4f3b7b232b
					
				| @ -69,10 +69,7 @@ bool AsmAnalyzer::analyze(Block const& _block) | |||||||
| 	return success && !m_errorReporter.hasErrors(); | 	return success && !m_errorReporter.hasErrors(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect( | AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Block const& _ast) | ||||||
| 	shared_ptr<Dialect> _dialect, |  | ||||||
| 	Block const& _ast |  | ||||||
| ) |  | ||||||
| { | { | ||||||
| 	ErrorList errorList; | 	ErrorList errorList; | ||||||
| 	langutil::ErrorReporter errors(errorList); | 	langutil::ErrorReporter errors(errorList); | ||||||
| @ -134,7 +131,7 @@ bool AsmAnalyzer::operator()(Literal const& _literal) | |||||||
| 	} | 	} | ||||||
| 	else if (_literal.kind == LiteralKind::Boolean) | 	else if (_literal.kind == LiteralKind::Boolean) | ||||||
| 	{ | 	{ | ||||||
| 		solAssert(m_dialect->flavour == AsmFlavour::Yul, ""); | 		solAssert(m_dialect.flavour == AsmFlavour::Yul, ""); | ||||||
| 		solAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, ""); | 		solAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, ""); | ||||||
| 	} | 	} | ||||||
| 	m_info.stackHeightInfo[&_literal] = m_stackHeight; | 	m_info.stackHeightInfo[&_literal] = m_stackHeight; | ||||||
| @ -197,7 +194,7 @@ bool AsmAnalyzer::operator()(Identifier const& _identifier) | |||||||
| 
 | 
 | ||||||
| bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) | bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) | ||||||
| { | { | ||||||
| 	solAssert(m_dialect->flavour != AsmFlavour::Yul, ""); | 	solAssert(m_dialect.flavour != AsmFlavour::Yul, ""); | ||||||
| 	bool success = true; | 	bool success = true; | ||||||
| 	for (auto const& arg: _instr.arguments | boost::adaptors::reversed) | 	for (auto const& arg: _instr.arguments | boost::adaptors::reversed) | ||||||
| 		if (!expectExpression(arg)) | 		if (!expectExpression(arg)) | ||||||
| @ -215,9 +212,9 @@ bool AsmAnalyzer::operator()(ExpressionStatement const& _statement) | |||||||
| { | { | ||||||
| 	int initialStackHeight = m_stackHeight; | 	int initialStackHeight = m_stackHeight; | ||||||
| 	bool success = boost::apply_visitor(*this, _statement.expression); | 	bool success = boost::apply_visitor(*this, _statement.expression); | ||||||
| 	if (m_stackHeight != initialStackHeight && (m_dialect->flavour != AsmFlavour::Loose || m_errorTypeForLoose)) | 	if (m_stackHeight != initialStackHeight && (m_dialect.flavour != AsmFlavour::Loose || m_errorTypeForLoose)) | ||||||
| 	{ | 	{ | ||||||
| 		Error::Type errorType = m_dialect->flavour == AsmFlavour::Loose ? *m_errorTypeForLoose : Error::Type::TypeError; | 		Error::Type errorType = m_dialect.flavour == AsmFlavour::Loose ? *m_errorTypeForLoose : Error::Type::TypeError; | ||||||
| 		string msg = | 		string msg = | ||||||
| 			"Top-level expressions are not supposed to return values (this expression returns " + | 			"Top-level expressions are not supposed to return values (this expression returns " + | ||||||
| 			to_string(m_stackHeight - initialStackHeight) + | 			to_string(m_stackHeight - initialStackHeight) + | ||||||
| @ -333,7 +330,7 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) | |||||||
| 	size_t parameters = 0; | 	size_t parameters = 0; | ||||||
| 	size_t returns = 0; | 	size_t returns = 0; | ||||||
| 	bool needsLiteralArguments = false; | 	bool needsLiteralArguments = false; | ||||||
| 	if (BuiltinFunction const* f = m_dialect->builtin(_funCall.functionName.name)) | 	if (BuiltinFunction const* f = m_dialect.builtin(_funCall.functionName.name)) | ||||||
| 	{ | 	{ | ||||||
| 		// TODO: compare types, too
 | 		// TODO: compare types, too
 | ||||||
| 		parameters = f->parameters.size(); | 		parameters = f->parameters.size(); | ||||||
| @ -423,7 +420,7 @@ bool AsmAnalyzer::operator()(Switch const& _switch) | |||||||
| 	if (!expectExpression(*_switch.expression)) | 	if (!expectExpression(*_switch.expression)) | ||||||
| 		success = false; | 		success = false; | ||||||
| 
 | 
 | ||||||
| 	if (m_dialect->flavour == AsmFlavour::Yul) | 	if (m_dialect.flavour == AsmFlavour::Yul) | ||||||
| 	{ | 	{ | ||||||
| 		YulString caseType; | 		YulString caseType; | ||||||
| 		bool mismatchingTypes = false; | 		bool mismatchingTypes = false; | ||||||
| @ -658,7 +655,7 @@ Scope& AsmAnalyzer::scope(Block const* _block) | |||||||
| } | } | ||||||
| void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location) | void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location) | ||||||
| { | { | ||||||
| 	if (m_dialect->flavour != AsmFlavour::Yul) | 	if (m_dialect.flavour != AsmFlavour::Yul) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	if (!builtinTypes.count(type)) | 	if (!builtinTypes.count(type)) | ||||||
| @ -675,7 +672,7 @@ void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocatio | |||||||
| 	solAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), ""); | 	solAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), ""); | ||||||
| 	// Similarly we assume bitwise shifting and create2 go together.
 | 	// Similarly we assume bitwise shifting and create2 go together.
 | ||||||
| 	solAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), ""); | 	solAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), ""); | ||||||
| 	solAssert(m_dialect->flavour != AsmFlavour::Yul, ""); | 	solAssert(m_dialect.flavour != AsmFlavour::Yul, ""); | ||||||
| 
 | 
 | ||||||
| 	auto errorForVM = [=](string const& vmKindMessage) { | 	auto errorForVM = [=](string const& vmKindMessage) { | ||||||
| 		m_errorReporter.typeError( | 		m_errorReporter.typeError( | ||||||
| @ -724,7 +721,7 @@ void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocatio | |||||||
| 		_instr == dev::eth::Instruction::JUMPDEST | 		_instr == dev::eth::Instruction::JUMPDEST | ||||||
| 	) | 	) | ||||||
| 	{ | 	{ | ||||||
| 		if (m_dialect->flavour == AsmFlavour::Loose) | 		if (m_dialect.flavour == AsmFlavour::Loose) | ||||||
| 			m_errorReporter.error( | 			m_errorReporter.error( | ||||||
| 				m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning, | 				m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning, | ||||||
| 				_location, | 				_location, | ||||||
| @ -745,7 +742,7 @@ void AsmAnalyzer::warnOnInstructions(dev::eth::Instruction _instr, SourceLocatio | |||||||
| 
 | 
 | ||||||
| void AsmAnalyzer::checkLooseFeature(SourceLocation const& _location, string const& _description) | void AsmAnalyzer::checkLooseFeature(SourceLocation const& _location, string const& _description) | ||||||
| { | { | ||||||
| 	if (m_dialect->flavour != AsmFlavour::Loose) | 	if (m_dialect.flavour != AsmFlavour::Loose) | ||||||
| 		solAssert(false, _description); | 		solAssert(false, _description); | ||||||
| 	else if (m_errorTypeForLoose) | 	else if (m_errorTypeForLoose) | ||||||
| 		m_errorReporter.error(*m_errorTypeForLoose, _location, _description); | 		m_errorReporter.error(*m_errorTypeForLoose, _location, _description); | ||||||
|  | |||||||
| @ -60,25 +60,22 @@ public: | |||||||
| 		AsmAnalysisInfo& _analysisInfo, | 		AsmAnalysisInfo& _analysisInfo, | ||||||
| 		langutil::ErrorReporter& _errorReporter, | 		langutil::ErrorReporter& _errorReporter, | ||||||
| 		boost::optional<langutil::Error::Type> _errorTypeForLoose, | 		boost::optional<langutil::Error::Type> _errorTypeForLoose, | ||||||
| 		std::shared_ptr<Dialect> _dialect, | 		Dialect const& _dialect, | ||||||
| 		ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver() | 		ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver() | ||||||
| 	): | 	): | ||||||
| 		m_resolver(_resolver), | 		m_resolver(_resolver), | ||||||
| 		m_info(_analysisInfo), | 		m_info(_analysisInfo), | ||||||
| 		m_errorReporter(_errorReporter), | 		m_errorReporter(_errorReporter), | ||||||
| 		m_dialect(std::move(_dialect)), | 		m_dialect(_dialect), | ||||||
| 		m_errorTypeForLoose(_errorTypeForLoose) | 		m_errorTypeForLoose(_errorTypeForLoose) | ||||||
| 	{ | 	{ | ||||||
| 		if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(m_dialect.get())) | 		if (EVMDialect const* evmDialect = dynamic_cast<EVMDialect const*>(&m_dialect)) | ||||||
| 			m_evmVersion = evmDialect->evmVersion(); | 			m_evmVersion = evmDialect->evmVersion(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool analyze(Block const& _block); | 	bool analyze(Block const& _block); | ||||||
| 
 | 
 | ||||||
| 	static AsmAnalysisInfo analyzeStrictAssertCorrect( | 	static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Block const& _ast); | ||||||
| 		std::shared_ptr<Dialect> _dialect, |  | ||||||
| 		Block const& _ast |  | ||||||
| 	); |  | ||||||
| 
 | 
 | ||||||
| 	bool operator()(Instruction const&); | 	bool operator()(Instruction const&); | ||||||
| 	bool operator()(Literal const& _literal); | 	bool operator()(Literal const& _literal); | ||||||
| @ -125,7 +122,7 @@ private: | |||||||
| 	AsmAnalysisInfo& m_info; | 	AsmAnalysisInfo& m_info; | ||||||
| 	langutil::ErrorReporter& m_errorReporter; | 	langutil::ErrorReporter& m_errorReporter; | ||||||
| 	langutil::EVMVersion m_evmVersion; | 	langutil::EVMVersion m_evmVersion; | ||||||
| 	std::shared_ptr<Dialect> m_dialect; | 	Dialect const& m_dialect; | ||||||
| 	boost::optional<langutil::Error::Type> m_errorTypeForLoose; | 	boost::optional<langutil::Error::Type> m_errorTypeForLoose; | ||||||
| 	ForLoop const* m_currentForLoop = nullptr; | 	ForLoop const* m_currentForLoop = nullptr; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -146,14 +146,14 @@ Statement Parser::parseStatement() | |||||||
| 	} | 	} | ||||||
| 	case Token::Assign: | 	case Token::Assign: | ||||||
| 	{ | 	{ | ||||||
| 		if (m_dialect->flavour != AsmFlavour::Loose) | 		if (m_dialect.flavour != AsmFlavour::Loose) | ||||||
| 			break; | 			break; | ||||||
| 		StackAssignment assignment = createWithLocation<StackAssignment>(); | 		StackAssignment assignment = createWithLocation<StackAssignment>(); | ||||||
| 		advance(); | 		advance(); | ||||||
| 		expectToken(Token::Colon); | 		expectToken(Token::Colon); | ||||||
| 		assignment.variableName.location = location(); | 		assignment.variableName.location = location(); | ||||||
| 		assignment.variableName.name = YulString(currentLiteral()); | 		assignment.variableName.name = YulString(currentLiteral()); | ||||||
| 		if (m_dialect->builtin(assignment.variableName.name)) | 		if (m_dialect.builtin(assignment.variableName.name)) | ||||||
| 			fatalParserError("Identifier expected, got builtin symbol."); | 			fatalParserError("Identifier expected, got builtin symbol."); | ||||||
| 		else if (instructions().count(assignment.variableName.name.str())) | 		else if (instructions().count(assignment.variableName.name.str())) | ||||||
| 			fatalParserError("Identifier expected, got instruction name."); | 			fatalParserError("Identifier expected, got instruction name."); | ||||||
| @ -197,7 +197,7 @@ Statement Parser::parseStatement() | |||||||
| 
 | 
 | ||||||
| 			auto const& identifier = boost::get<Identifier>(elementary); | 			auto const& identifier = boost::get<Identifier>(elementary); | ||||||
| 
 | 
 | ||||||
| 			if (m_dialect->builtin(identifier.name)) | 			if (m_dialect.builtin(identifier.name)) | ||||||
| 				fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); | 				fatalParserError("Cannot assign to builtin function \"" + identifier.name.str() + "\"."); | ||||||
| 
 | 
 | ||||||
| 			variableNames.emplace_back(identifier); | 			variableNames.emplace_back(identifier); | ||||||
| @ -231,7 +231,7 @@ Statement Parser::parseStatement() | |||||||
| 		advance(); | 		advance(); | ||||||
| 
 | 
 | ||||||
| 		// label
 | 		// label
 | ||||||
| 		if (m_dialect->flavour != AsmFlavour::Loose) | 		if (m_dialect.flavour != AsmFlavour::Loose) | ||||||
| 			fatalParserError("Labels are not supported."); | 			fatalParserError("Labels are not supported."); | ||||||
| 
 | 
 | ||||||
| 		Label label = createWithLocation<Label>(identifier.location); | 		Label label = createWithLocation<Label>(identifier.location); | ||||||
| @ -239,7 +239,7 @@ Statement Parser::parseStatement() | |||||||
| 		return label; | 		return label; | ||||||
| 	} | 	} | ||||||
| 	default: | 	default: | ||||||
| 		if (m_dialect->flavour != AsmFlavour::Loose) | 		if (m_dialect.flavour != AsmFlavour::Loose) | ||||||
| 			fatalParserError("Call or assignment expected."); | 			fatalParserError("Call or assignment expected."); | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| @ -325,7 +325,7 @@ Expression Parser::parseExpression() | |||||||
| 				instructionNames().at(instr.instruction) + | 				instructionNames().at(instr.instruction) + | ||||||
| 				"\" not allowed in this context." | 				"\" not allowed in this context." | ||||||
| 			); | 			); | ||||||
| 		if (m_dialect->flavour != AsmFlavour::Loose && currentToken() != Token::LParen) | 		if (m_dialect.flavour != AsmFlavour::Loose && currentToken() != Token::LParen) | ||||||
| 			fatalParserError( | 			fatalParserError( | ||||||
| 				"Non-functional instructions are not allowed in this context." | 				"Non-functional instructions are not allowed in this context." | ||||||
| 			); | 			); | ||||||
| @ -345,7 +345,7 @@ Expression Parser::parseExpression() | |||||||
| 	else if (operation.type() == typeid(Instruction)) | 	else if (operation.type() == typeid(Instruction)) | ||||||
| 	{ | 	{ | ||||||
| 		// Instructions not taking arguments are allowed as expressions.
 | 		// Instructions not taking arguments are allowed as expressions.
 | ||||||
| 		solAssert(m_dialect->flavour == AsmFlavour::Loose, ""); | 		solAssert(m_dialect.flavour == AsmFlavour::Loose, ""); | ||||||
| 		Instruction& instr = boost::get<Instruction>(operation); | 		Instruction& instr = boost::get<Instruction>(operation); | ||||||
| 		return FunctionalInstruction{std::move(instr.location), instr.instruction, {}}; | 		return FunctionalInstruction{std::move(instr.location), instr.instruction, {}}; | ||||||
| 	} | 	} | ||||||
| @ -393,9 +393,9 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() | |||||||
| 		else | 		else | ||||||
| 			literal = YulString{currentLiteral()}; | 			literal = YulString{currentLiteral()}; | ||||||
| 		// first search the set of builtins, then the instructions.
 | 		// first search the set of builtins, then the instructions.
 | ||||||
| 		if (m_dialect->builtin(literal)) | 		if (m_dialect.builtin(literal)) | ||||||
| 			ret = Identifier{location(), literal}; | 			ret = Identifier{location(), literal}; | ||||||
| 		else if (m_dialect->flavour != AsmFlavour::Yul && instructions().count(literal.str())) | 		else if (m_dialect.flavour != AsmFlavour::Yul && instructions().count(literal.str())) | ||||||
| 		{ | 		{ | ||||||
| 			dev::eth::Instruction const& instr = instructions().at(literal.str()); | 			dev::eth::Instruction const& instr = instructions().at(literal.str()); | ||||||
| 			ret = Instruction{location(), instr}; | 			ret = Instruction{location(), instr}; | ||||||
| @ -436,7 +436,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() | |||||||
| 			{} | 			{} | ||||||
| 		}; | 		}; | ||||||
| 		advance(); | 		advance(); | ||||||
| 		if (m_dialect->flavour == AsmFlavour::Yul) | 		if (m_dialect.flavour == AsmFlavour::Yul) | ||||||
| 		{ | 		{ | ||||||
| 			expectToken(Token::Colon); | 			expectToken(Token::Colon); | ||||||
| 			literal.location.end = endPosition(); | 			literal.location.end = endPosition(); | ||||||
| @ -449,7 +449,7 @@ Parser::ElementaryOperation Parser::parseElementaryOperation() | |||||||
| 	} | 	} | ||||||
| 	default: | 	default: | ||||||
| 		fatalParserError( | 		fatalParserError( | ||||||
| 			m_dialect->flavour == AsmFlavour::Yul ? | 			m_dialect.flavour == AsmFlavour::Yul ? | ||||||
| 			"Literal or identifier expected." : | 			"Literal or identifier expected." : | ||||||
| 			"Literal, identifier or instruction expected." | 			"Literal, identifier or instruction expected." | ||||||
| 		); | 		); | ||||||
| @ -530,7 +530,7 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) | |||||||
| 	RecursionGuard recursionGuard(*this); | 	RecursionGuard recursionGuard(*this); | ||||||
| 	if (_initialOp.type() == typeid(Instruction)) | 	if (_initialOp.type() == typeid(Instruction)) | ||||||
| 	{ | 	{ | ||||||
| 		solAssert(m_dialect->flavour != AsmFlavour::Yul, "Instructions are invalid in Yul"); | 		solAssert(m_dialect.flavour != AsmFlavour::Yul, "Instructions are invalid in Yul"); | ||||||
| 		Instruction& instruction = boost::get<Instruction>(_initialOp); | 		Instruction& instruction = boost::get<Instruction>(_initialOp); | ||||||
| 		FunctionalInstruction ret; | 		FunctionalInstruction ret; | ||||||
| 		ret.instruction = instruction.instruction; | 		ret.instruction = instruction.instruction; | ||||||
| @ -601,7 +601,7 @@ Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) | |||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 		fatalParserError( | 		fatalParserError( | ||||||
| 			m_dialect->flavour == AsmFlavour::Yul ? | 			m_dialect.flavour == AsmFlavour::Yul ? | ||||||
| 			"Function name expected." : | 			"Function name expected." : | ||||||
| 			"Assembly instruction or function name required in front of \"(\")" | 			"Assembly instruction or function name required in front of \"(\")" | ||||||
| 		); | 		); | ||||||
| @ -614,7 +614,7 @@ TypedName Parser::parseTypedName() | |||||||
| 	RecursionGuard recursionGuard(*this); | 	RecursionGuard recursionGuard(*this); | ||||||
| 	TypedName typedName = createWithLocation<TypedName>(); | 	TypedName typedName = createWithLocation<TypedName>(); | ||||||
| 	typedName.name = expectAsmIdentifier(); | 	typedName.name = expectAsmIdentifier(); | ||||||
| 	if (m_dialect->flavour == AsmFlavour::Yul) | 	if (m_dialect.flavour == AsmFlavour::Yul) | ||||||
| 	{ | 	{ | ||||||
| 		expectToken(Token::Colon); | 		expectToken(Token::Colon); | ||||||
| 		typedName.location.end = endPosition(); | 		typedName.location.end = endPosition(); | ||||||
| @ -626,7 +626,7 @@ TypedName Parser::parseTypedName() | |||||||
| YulString Parser::expectAsmIdentifier() | YulString Parser::expectAsmIdentifier() | ||||||
| { | { | ||||||
| 	YulString name = YulString{currentLiteral()}; | 	YulString name = YulString{currentLiteral()}; | ||||||
| 	if (m_dialect->flavour == AsmFlavour::Yul) | 	if (m_dialect.flavour == AsmFlavour::Yul) | ||||||
| 	{ | 	{ | ||||||
| 		switch (currentToken()) | 		switch (currentToken()) | ||||||
| 		{ | 		{ | ||||||
| @ -640,7 +640,7 @@ YulString Parser::expectAsmIdentifier() | |||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else if (m_dialect->builtin(name)) | 	else if (m_dialect.builtin(name)) | ||||||
| 		fatalParserError("Cannot use builtin function name \"" + name.str() + "\" as identifier name."); | 		fatalParserError("Cannot use builtin function name \"" + name.str() + "\" as identifier name."); | ||||||
| 	else if (instructions().count(name.str())) | 	else if (instructions().count(name.str())) | ||||||
| 		fatalParserError("Cannot use instruction names for identifier names."); | 		fatalParserError("Cannot use instruction names for identifier names."); | ||||||
|  | |||||||
| @ -44,8 +44,8 @@ public: | |||||||
| 		None, ForLoopPre, ForLoopPost, ForLoopBody | 		None, ForLoopPre, ForLoopPost, ForLoopBody | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	explicit Parser(langutil::ErrorReporter& _errorReporter, std::shared_ptr<Dialect> _dialect): | 	explicit Parser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect): | ||||||
| 		ParserBase(_errorReporter), m_dialect(std::move(_dialect)) {} | 		ParserBase(_errorReporter), m_dialect(_dialect) {} | ||||||
| 
 | 
 | ||||||
| 	/// Parses an inline assembly block starting with `{` and ending with `}`.
 | 	/// Parses an inline assembly block starting with `{` and ending with `}`.
 | ||||||
| 	/// @param _reuseScanner if true, do check for end of input after the `}`.
 | 	/// @param _reuseScanner if true, do check for end of input after the `}`.
 | ||||||
| @ -97,7 +97,7 @@ protected: | |||||||
| 	static bool isValidNumberLiteral(std::string const& _literal); | 	static bool isValidNumberLiteral(std::string const& _literal); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	std::shared_ptr<Dialect> m_dialect; | 	Dialect const& m_dialect; | ||||||
| 	ForLoopComponent m_currentForLoopComponent = ForLoopComponent::None; | 	ForLoopComponent m_currentForLoopComponent = ForLoopComponent::None; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ using namespace yul; | |||||||
| 
 | 
 | ||||||
| namespace | namespace | ||||||
| { | { | ||||||
| shared_ptr<Dialect> languageToDialect(AssemblyStack::Language _language, EVMVersion _version) | Dialect const& languageToDialect(AssemblyStack::Language _language, EVMVersion _version) | ||||||
| { | { | ||||||
| 	switch (_language) | 	switch (_language) | ||||||
| 	{ | 	{ | ||||||
| @ -58,7 +58,7 @@ shared_ptr<Dialect> languageToDialect(AssemblyStack::Language _language, EVMVers | |||||||
| 	case AssemblyStack::Language::Yul: | 	case AssemblyStack::Language::Yul: | ||||||
| 		return Dialect::yul(); | 		return Dialect::yul(); | ||||||
| 	case AssemblyStack::Language::EWasm: | 	case AssemblyStack::Language::EWasm: | ||||||
| 		return make_shared<WasmDialect>(); | 		return WasmDialect::instance(); | ||||||
| 	} | 	} | ||||||
| 	solAssert(false, ""); | 	solAssert(false, ""); | ||||||
| 	return Dialect::yul(); | 	return Dialect::yul(); | ||||||
| @ -124,14 +124,14 @@ bool AssemblyStack::analyzeParsed(Object& _object) | |||||||
| 
 | 
 | ||||||
| void AssemblyStack::compileEVM(AbstractAssembly& _assembly, bool _evm15, bool _optimize) const | void AssemblyStack::compileEVM(AbstractAssembly& _assembly, bool _evm15, bool _optimize) const | ||||||
| { | { | ||||||
| 	shared_ptr<EVMDialect> dialect; | 	EVMDialect const* dialect = nullptr; | ||||||
| 
 | 
 | ||||||
| 	if (m_language == Language::Assembly) | 	if (m_language == Language::Assembly) | ||||||
| 		dialect = EVMDialect::looseAssemblyForEVM(m_evmVersion); | 		dialect = &EVMDialect::looseAssemblyForEVM(m_evmVersion); | ||||||
| 	else if (m_language == AssemblyStack::Language::StrictAssembly) | 	else if (m_language == AssemblyStack::Language::StrictAssembly) | ||||||
| 		dialect = EVMDialect::strictAssemblyForEVMObjects(m_evmVersion); | 		dialect = &EVMDialect::strictAssemblyForEVMObjects(m_evmVersion); | ||||||
| 	else if (m_language == AssemblyStack::Language::Yul) | 	else if (m_language == AssemblyStack::Language::Yul) | ||||||
| 		dialect = EVMDialect::yulForEVM(m_evmVersion); | 		dialect = &EVMDialect::yulForEVM(m_evmVersion); | ||||||
| 	else | 	else | ||||||
| 		solAssert(false, "Invalid language."); | 		solAssert(false, "Invalid language."); | ||||||
| 
 | 
 | ||||||
| @ -184,10 +184,10 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const | |||||||
| 	case Machine::eWasm: | 	case Machine::eWasm: | ||||||
| 	{ | 	{ | ||||||
| 		solAssert(m_language == Language::EWasm, ""); | 		solAssert(m_language == Language::EWasm, ""); | ||||||
| 		shared_ptr<Dialect> dialect = languageToDialect(m_language, EVMVersion{}); | 		Dialect const& dialect = languageToDialect(m_language, EVMVersion{}); | ||||||
| 
 | 
 | ||||||
| 		MachineAssemblyObject object; | 		MachineAssemblyObject object; | ||||||
| 		object.assembly = EWasmObjectCompiler::compile(*m_parserResult, *dialect); | 		object.assembly = EWasmObjectCompiler::compile(*m_parserResult, dialect); | ||||||
| 		return object; | 		return object; | ||||||
| 	} | 	} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -33,24 +33,25 @@ using namespace yul; | |||||||
| using namespace dev; | using namespace dev; | ||||||
| 
 | 
 | ||||||
| map<YulString, int> CompilabilityChecker::run( | map<YulString, int> CompilabilityChecker::run( | ||||||
| 	shared_ptr<Dialect> _dialect, | 	Dialect const& _dialect, | ||||||
| 	Block const& _ast, | 	Block const& _ast, | ||||||
| 	bool _optimizeStackAllocation | 	bool _optimizeStackAllocation | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	if (_dialect->flavour == AsmFlavour::Yul) | 	if (_dialect.flavour == AsmFlavour::Yul) | ||||||
| 		return {}; | 		return {}; | ||||||
| 
 | 
 | ||||||
| 	solAssert(_dialect->flavour == AsmFlavour::Strict, ""); | 	solAssert(_dialect.flavour == AsmFlavour::Strict, ""); | ||||||
| 
 | 
 | ||||||
| 	solAssert(dynamic_cast<EVMDialect const*>(_dialect.get()), ""); | 	solAssert(dynamic_cast<EVMDialect const*>(&_dialect), ""); | ||||||
| 	shared_ptr<NoOutputEVMDialect> noOutputDialect = make_shared<NoOutputEVMDialect>(dynamic_pointer_cast<EVMDialect>(_dialect)); | 	NoOutputEVMDialect noOutputDialect(dynamic_cast<EVMDialect const&>(_dialect)); | ||||||
|  | 	BuiltinContext builtinContext; | ||||||
| 
 | 
 | ||||||
| 	yul::AsmAnalysisInfo analysisInfo = | 	yul::AsmAnalysisInfo analysisInfo = | ||||||
| 		yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _ast); | 		yul::AsmAnalyzer::analyzeStrictAssertCorrect(noOutputDialect, _ast); | ||||||
| 
 | 
 | ||||||
| 	NoOutputAssembly assembly; | 	NoOutputAssembly assembly; | ||||||
| 	CodeTransform transform(assembly, analysisInfo, _ast, *noOutputDialect, _optimizeStackAllocation); | 	CodeTransform transform(assembly, analysisInfo, _ast, noOutputDialect, builtinContext, _optimizeStackAllocation); | ||||||
| 	try | 	try | ||||||
| 	{ | 	{ | ||||||
| 		transform(_ast); | 		transform(_ast); | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ class CompilabilityChecker | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	static std::map<YulString, int> run( | 	static std::map<YulString, int> run( | ||||||
| 		std::shared_ptr<Dialect> _dialect, | 		Dialect const& _dialect, | ||||||
| 		Block const& _ast, | 		Block const& _ast, | ||||||
| 		bool _optimizeStackAllocation | 		bool _optimizeStackAllocation | ||||||
| 	); | 	); | ||||||
|  | |||||||
| @ -64,10 +64,10 @@ struct Dialect: boost::noncopyable | |||||||
| 	Dialect(AsmFlavour _flavour): flavour(_flavour) {} | 	Dialect(AsmFlavour _flavour): flavour(_flavour) {} | ||||||
| 	virtual ~Dialect() = default; | 	virtual ~Dialect() = default; | ||||||
| 
 | 
 | ||||||
| 	static std::shared_ptr<Dialect> yul() | 	static Dialect const& yul() | ||||||
| 	{ | 	{ | ||||||
| 		// Will have to add builtins later.
 | 		static Dialect yulDialect(AsmFlavour::Yul); | ||||||
| 		return std::make_shared<Dialect>(AsmFlavour::Yul); | 		return yulDialect; | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -45,11 +45,8 @@ namespace yul | |||||||
| class ObjectParser: public langutil::ParserBase | class ObjectParser: public langutil::ParserBase | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	explicit ObjectParser( | 	explicit ObjectParser(langutil::ErrorReporter& _errorReporter, Dialect const& _dialect): | ||||||
| 		langutil::ErrorReporter& _errorReporter, | 		ParserBase(_errorReporter), m_dialect(_dialect) {} | ||||||
| 		std::shared_ptr<Dialect> _dialect |  | ||||||
| 	): |  | ||||||
| 		ParserBase(_errorReporter), m_dialect(std::move(_dialect)) {} |  | ||||||
| 
 | 
 | ||||||
| 	/// Parses a Yul object.
 | 	/// Parses a Yul object.
 | ||||||
| 	/// Falls back to code-only parsing if the source starts with `{`.
 | 	/// Falls back to code-only parsing if the source starts with `{`.
 | ||||||
| @ -67,7 +64,7 @@ private: | |||||||
| 	YulString parseUniqueName(Object const* _containingObject); | 	YulString parseUniqueName(Object const* _containingObject); | ||||||
| 	void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr<ObjectNode> _subObject); | 	void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr<ObjectNode> _subObject); | ||||||
| 
 | 
 | ||||||
| 	std::shared_ptr<Dialect> m_dialect; | 	Dialect const& m_dialect; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -184,12 +184,13 @@ void CodeGenerator::assemble( | |||||||
| ) | ) | ||||||
| { | { | ||||||
| 	EthAssemblyAdapter assemblyAdapter(_assembly); | 	EthAssemblyAdapter assemblyAdapter(_assembly); | ||||||
| 	shared_ptr<EVMDialect> dialect = EVMDialect::strictAssemblyForEVM(_evmVersion); | 	BuiltinContext builtinContext; | ||||||
| 	CodeTransform transform( | 	CodeTransform transform( | ||||||
| 		assemblyAdapter, | 		assemblyAdapter, | ||||||
| 		_analysisInfo, | 		_analysisInfo, | ||||||
| 		_parsedData, | 		_parsedData, | ||||||
| 		*dialect, | 		EVMDialect::strictAssemblyForEVM(_evmVersion), | ||||||
|  | 		builtinContext, | ||||||
| 		_optimizeStackAllocation, | 		_optimizeStackAllocation, | ||||||
| 		false, | 		false, | ||||||
| 		_identifierAccess, | 		_identifierAccess, | ||||||
|  | |||||||
| @ -96,6 +96,7 @@ CodeTransform::CodeTransform( | |||||||
| 	Block const& _block, | 	Block const& _block, | ||||||
| 	bool _allowStackOpt, | 	bool _allowStackOpt, | ||||||
| 	EVMDialect const& _dialect, | 	EVMDialect const& _dialect, | ||||||
|  | 	BuiltinContext& _builtinContext, | ||||||
| 	bool _evm15, | 	bool _evm15, | ||||||
| 	ExternalIdentifierAccess const& _identifierAccess, | 	ExternalIdentifierAccess const& _identifierAccess, | ||||||
| 	bool _useNamedLabelsForFunctions, | 	bool _useNamedLabelsForFunctions, | ||||||
| @ -105,6 +106,7 @@ CodeTransform::CodeTransform( | |||||||
| 	m_assembly(_assembly), | 	m_assembly(_assembly), | ||||||
| 	m_info(_analysisInfo), | 	m_info(_analysisInfo), | ||||||
| 	m_dialect(_dialect), | 	m_dialect(_dialect), | ||||||
|  | 	m_builtinContext(_builtinContext), | ||||||
| 	m_allowStackOpt(_allowStackOpt), | 	m_allowStackOpt(_allowStackOpt), | ||||||
| 	m_evm15(_evm15), | 	m_evm15(_evm15), | ||||||
| 	m_useNamedLabelsForFunctions(_useNamedLabelsForFunctions), | 	m_useNamedLabelsForFunctions(_useNamedLabelsForFunctions), | ||||||
| @ -280,7 +282,7 @@ void CodeTransform::operator()(FunctionCall const& _call) | |||||||
| 
 | 
 | ||||||
| 	if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) | 	if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) | ||||||
| 	{ | 	{ | ||||||
| 		builtin->generateCode(_call, m_assembly, [&]() { | 		builtin->generateCode(_call, m_assembly, m_builtinContext, [&]() { | ||||||
| 			for (auto const& arg: _call.arguments | boost::adaptors::reversed) | 			for (auto const& arg: _call.arguments | boost::adaptors::reversed) | ||||||
| 				visitExpression(arg); | 				visitExpression(arg); | ||||||
| 			m_assembly.setSourceLocation(_call.location); | 			m_assembly.setSourceLocation(_call.location); | ||||||
| @ -519,6 +521,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) | |||||||
| 			_function.body, | 			_function.body, | ||||||
| 			m_allowStackOpt, | 			m_allowStackOpt, | ||||||
| 			m_dialect, | 			m_dialect, | ||||||
|  | 			m_builtinContext, | ||||||
| 			m_evm15, | 			m_evm15, | ||||||
| 			m_identifierAccess, | 			m_identifierAccess, | ||||||
| 			m_useNamedLabelsForFunctions, | 			m_useNamedLabelsForFunctions, | ||||||
|  | |||||||
| @ -121,6 +121,7 @@ public: | |||||||
| 		AsmAnalysisInfo& _analysisInfo, | 		AsmAnalysisInfo& _analysisInfo, | ||||||
| 		Block const& _block, | 		Block const& _block, | ||||||
| 		EVMDialect const& _dialect, | 		EVMDialect const& _dialect, | ||||||
|  | 		BuiltinContext& _builtinContext, | ||||||
| 		bool _allowStackOpt = false, | 		bool _allowStackOpt = false, | ||||||
| 		bool _evm15 = false, | 		bool _evm15 = false, | ||||||
| 		ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess(), | 		ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess(), | ||||||
| @ -131,6 +132,7 @@ public: | |||||||
| 		_block, | 		_block, | ||||||
| 		_allowStackOpt, | 		_allowStackOpt, | ||||||
| 		_dialect, | 		_dialect, | ||||||
|  | 		_builtinContext, | ||||||
| 		_evm15, | 		_evm15, | ||||||
| 		_identifierAccess, | 		_identifierAccess, | ||||||
| 		_useNamedLabelsForFunctions, | 		_useNamedLabelsForFunctions, | ||||||
| @ -151,6 +153,7 @@ protected: | |||||||
| 		Block const& _block, | 		Block const& _block, | ||||||
| 		bool _allowStackOpt, | 		bool _allowStackOpt, | ||||||
| 		EVMDialect const& _dialect, | 		EVMDialect const& _dialect, | ||||||
|  | 		BuiltinContext& _builtinContext, | ||||||
| 		bool _evm15, | 		bool _evm15, | ||||||
| 		ExternalIdentifierAccess const& _identifierAccess, | 		ExternalIdentifierAccess const& _identifierAccess, | ||||||
| 		bool _useNamedLabelsForFunctions, | 		bool _useNamedLabelsForFunctions, | ||||||
| @ -225,6 +228,7 @@ private: | |||||||
| 	AsmAnalysisInfo& m_info; | 	AsmAnalysisInfo& m_info; | ||||||
| 	Scope* m_scope = nullptr; | 	Scope* m_scope = nullptr; | ||||||
| 	EVMDialect const& m_dialect; | 	EVMDialect const& m_dialect; | ||||||
|  | 	BuiltinContext& m_builtinContext; | ||||||
| 	bool const m_allowStackOpt = true; | 	bool const m_allowStackOpt = true; | ||||||
| 	bool const m_evm15 = false; | 	bool const m_evm15 = false; | ||||||
| 	bool const m_useNamedLabelsForFunctions = false; | 	bool const m_useNamedLabelsForFunctions = false; | ||||||
|  | |||||||
| @ -35,55 +35,98 @@ using namespace std; | |||||||
| using namespace dev; | using namespace dev; | ||||||
| using namespace yul; | using namespace yul; | ||||||
| 
 | 
 | ||||||
| EVMDialect::EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVersion _evmVersion): | namespace | ||||||
| 	Dialect{_flavour}, m_objectAccess(_objectAccess), m_evmVersion(_evmVersion) |  | ||||||
| { | { | ||||||
| 	// The EVM instructions will be moved to builtins at some point.
 | pair<YulString, BuiltinFunctionForEVM> createFunction( | ||||||
| 	if (!m_objectAccess) | 	string _name, | ||||||
| 		return; | 	size_t _params, | ||||||
|  | 	size_t _returns, | ||||||
|  | 	bool _movable, | ||||||
|  | 	bool _sideEffectFree, | ||||||
|  | 	bool _literalArguments, | ||||||
|  | 	std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void()>)> _generateCode | ||||||
|  | ) | ||||||
|  | { | ||||||
|  | 	YulString name{std::move(_name)}; | ||||||
|  | 	BuiltinFunctionForEVM f; | ||||||
|  | 	f.name = name; | ||||||
|  | 	f.parameters.resize(_params); | ||||||
|  | 	f.returns.resize(_returns); | ||||||
|  | 	f.movable = _movable; | ||||||
|  | 	f.literalArguments = _literalArguments; | ||||||
|  | 	f.sideEffectFree = _sideEffectFree; | ||||||
|  | 	f.generateCode = std::move(_generateCode); | ||||||
|  | 	return {name, f}; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	addFunction("datasize", 1, 1, true, true, true, [this]( | map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion, bool _objectAccess) | ||||||
| 		FunctionCall const& _call, | { | ||||||
| 		AbstractAssembly& _assembly, | 	map<YulString, BuiltinFunctionForEVM> builtins; | ||||||
| 		std::function<void()> | 	if (_objectAccess) | ||||||
| 	) { | 	{ | ||||||
| 		yulAssert(m_currentObject, "No object available."); | 		builtins.emplace(createFunction("datasize", 1, 1, true, true, true, []( | ||||||
| 		yulAssert(_call.arguments.size() == 1, ""); | 			FunctionCall const& _call, | ||||||
| 		Expression const& arg = _call.arguments.front(); | 			AbstractAssembly& _assembly, | ||||||
| 		YulString dataName = boost::get<Literal>(arg).value; | 			BuiltinContext& _context, | ||||||
| 		if (m_currentObject->name == dataName) | 			function<void()> | ||||||
| 			_assembly.appendAssemblySize(); | 		) { | ||||||
| 		else | 			yulAssert(_context.currentObject, "No object available."); | ||||||
| 		{ | 			yulAssert(_call.arguments.size() == 1, ""); | ||||||
| 			yulAssert(m_subIDs.count(dataName) != 0, "Could not find assembly object <" + dataName.str() + ">."); | 			Expression const& arg = _call.arguments.front(); | ||||||
| 			_assembly.appendDataSize(m_subIDs.at(dataName)); | 			YulString dataName = boost::get<Literal>(arg).value; | ||||||
| 		} | 			if (_context.currentObject->name == dataName) | ||||||
| 	}); | 				_assembly.appendAssemblySize(); | ||||||
| 	addFunction("dataoffset", 1, 1, true, true, true, [this]( | 			else | ||||||
| 		FunctionCall const& _call, | 			{ | ||||||
| 		AbstractAssembly& _assembly, | 				yulAssert( | ||||||
| 		std::function<void()> | 					_context.subIDs.count(dataName) != 0, | ||||||
| 	) { | 					"Could not find assembly object <" + dataName.str() + ">." | ||||||
| 		yulAssert(m_currentObject, "No object available."); | 				); | ||||||
| 		yulAssert(_call.arguments.size() == 1, ""); | 				_assembly.appendDataSize(_context.subIDs.at(dataName)); | ||||||
| 		Expression const& arg = _call.arguments.front(); | 			} | ||||||
| 		YulString dataName = boost::get<Literal>(arg).value; | 		})); | ||||||
| 		if (m_currentObject->name == dataName) | 		builtins.emplace(createFunction("dataoffset", 1, 1, true, true, true, []( | ||||||
| 			_assembly.appendConstant(0); | 			FunctionCall const& _call, | ||||||
| 		else | 			AbstractAssembly& _assembly, | ||||||
| 		{ | 			BuiltinContext& _context, | ||||||
| 			yulAssert(m_subIDs.count(dataName) != 0, "Could not find assembly object <" + dataName.str() + ">."); | 			std::function<void()> | ||||||
| 			_assembly.appendDataOffset(m_subIDs.at(dataName)); | 		) { | ||||||
| 		} | 			yulAssert(_context.currentObject, "No object available."); | ||||||
| 	}); | 			yulAssert(_call.arguments.size() == 1, ""); | ||||||
| 	addFunction("datacopy", 3, 0, false, false, false, []( | 			Expression const& arg = _call.arguments.front(); | ||||||
| 		FunctionCall const&, | 			YulString dataName = boost::get<Literal>(arg).value; | ||||||
| 		AbstractAssembly& _assembly, | 			if (_context.currentObject->name == dataName) | ||||||
| 		std::function<void()> _visitArguments | 				_assembly.appendConstant(0); | ||||||
| 	) { | 			else | ||||||
| 		_visitArguments(); | 			{ | ||||||
| 		_assembly.appendInstruction(dev::eth::Instruction::CODECOPY); | 				yulAssert( | ||||||
| 	}); | 					_context.subIDs.count(dataName) != 0, | ||||||
|  | 					"Could not find assembly object <" + dataName.str() + ">." | ||||||
|  | 				); | ||||||
|  | 				_assembly.appendDataOffset(_context.subIDs.at(dataName)); | ||||||
|  | 			} | ||||||
|  | 		})); | ||||||
|  | 		builtins.emplace(createFunction("datacopy", 3, 0, false, false, false, []( | ||||||
|  | 			FunctionCall const&, | ||||||
|  | 			AbstractAssembly& _assembly, | ||||||
|  | 			BuiltinContext&, | ||||||
|  | 			std::function<void()> _visitArguments | ||||||
|  | 		) { | ||||||
|  | 			_visitArguments(); | ||||||
|  | 			_assembly.appendInstruction(dev::eth::Instruction::CODECOPY); | ||||||
|  | 		})); | ||||||
|  | 	} | ||||||
|  | 	return builtins; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | EVMDialect::EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVersion _evmVersion): | ||||||
|  | 	Dialect{_flavour}, | ||||||
|  | 	m_objectAccess(_objectAccess), | ||||||
|  | 	m_evmVersion(_evmVersion), | ||||||
|  | 	m_functions(createBuiltins(_evmVersion, _objectAccess)) | ||||||
|  | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const | BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const | ||||||
| @ -95,55 +138,34 @@ BuiltinFunctionForEVM const* EVMDialect::builtin(YulString _name) const | |||||||
| 		return nullptr; | 		return nullptr; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| shared_ptr<EVMDialect> EVMDialect::looseAssemblyForEVM(langutil::EVMVersion _version) | EVMDialect const& EVMDialect::looseAssemblyForEVM(langutil::EVMVersion _version) | ||||||
| { | { | ||||||
| 	return make_shared<EVMDialect>(AsmFlavour::Loose, false, _version); | 	static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; | ||||||
|  | 	if (!dialects[_version]) | ||||||
|  | 		dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Loose, false, _version); | ||||||
|  | 	return *dialects[_version]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| shared_ptr<EVMDialect> EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version) | EVMDialect const& EVMDialect::strictAssemblyForEVM(langutil::EVMVersion _version) | ||||||
| { | { | ||||||
| 	return make_shared<EVMDialect>(AsmFlavour::Strict, false, _version); | 	static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; | ||||||
|  | 	if (!dialects[_version]) | ||||||
|  | 		dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Strict, false, _version); | ||||||
|  | 	return *dialects[_version]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| shared_ptr<EVMDialect> EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version) | EVMDialect const& EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion _version) | ||||||
| { | { | ||||||
| 	return make_shared<EVMDialect>(AsmFlavour::Strict, true, _version); | 	static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; | ||||||
|  | 	if (!dialects[_version]) | ||||||
|  | 		dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Strict, true, _version); | ||||||
|  | 	return *dialects[_version]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| shared_ptr<yul::EVMDialect> EVMDialect::yulForEVM(langutil::EVMVersion _version) | EVMDialect const& EVMDialect::yulForEVM(langutil::EVMVersion _version) | ||||||
| { | { | ||||||
| 	return make_shared<EVMDialect>(AsmFlavour::Yul, false, _version); | 	static map<langutil::EVMVersion, unique_ptr<EVMDialect const>> dialects; | ||||||
| } | 	if (!dialects[_version]) | ||||||
| 
 | 		dialects[_version] = make_unique<EVMDialect>(AsmFlavour::Yul, false, _version); | ||||||
| void EVMDialect::setSubIDs(map<YulString, AbstractAssembly::SubID> _subIDs) | 	return *dialects[_version]; | ||||||
| { |  | ||||||
| 	yulAssert(m_objectAccess, "Sub IDs set with dialect that does not support object access."); |  | ||||||
| 	m_subIDs = std::move(_subIDs); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EVMDialect::setCurrentObject(Object const* _object) |  | ||||||
| { |  | ||||||
| 	yulAssert(m_objectAccess, "Current object set with dialect that does not support object access."); |  | ||||||
| 	m_currentObject = _object; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EVMDialect::addFunction( |  | ||||||
| 	string _name, |  | ||||||
| 	size_t _params, |  | ||||||
| 	size_t _returns, |  | ||||||
| 	bool _movable, |  | ||||||
| 	bool _sideEffectFree, |  | ||||||
| 	bool _literalArguments, |  | ||||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, std::function<void()>)> _generateCode |  | ||||||
| ) |  | ||||||
| { |  | ||||||
| 	YulString name{std::move(_name)}; |  | ||||||
| 	BuiltinFunctionForEVM& f = m_functions[name]; |  | ||||||
| 	f.name = name; |  | ||||||
| 	f.parameters.resize(_params); |  | ||||||
| 	f.returns.resize(_returns); |  | ||||||
| 	f.movable = _movable; |  | ||||||
| 	f.sideEffectFree = _sideEffectFree; |  | ||||||
| 	f.literalArguments = _literalArguments; |  | ||||||
| 	f.generateCode = std::move(_generateCode); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -35,14 +35,25 @@ using Type = YulString; | |||||||
| struct FunctionCall; | struct FunctionCall; | ||||||
| struct Object; | struct Object; | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Context used during code generation. | ||||||
|  |  */ | ||||||
|  | struct BuiltinContext | ||||||
|  | { | ||||||
|  | 	Object const* currentObject = nullptr; | ||||||
|  | 	/// Mapping from named objects to abstract assembly sub IDs.
 | ||||||
|  | 	std::map<YulString, AbstractAssembly::SubID> subIDs; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct BuiltinFunctionForEVM: BuiltinFunction | struct BuiltinFunctionForEVM: BuiltinFunction | ||||||
| { | { | ||||||
| 	/// Function to generate code for the given function call and append it to the abstract
 | 	/// Function to generate code for the given function call and append it to the abstract
 | ||||||
| 	/// assembly. The third parameter is called to visit (and generate code for) the arguments
 | 	/// assembly. The fourth parameter is called to visit (and generate code for) the arguments
 | ||||||
| 	/// from right to left.
 | 	/// from right to left.
 | ||||||
| 	std::function<void(FunctionCall const&, AbstractAssembly&, std::function<void()>)> generateCode; | 	std::function<void(FunctionCall const&, AbstractAssembly&, BuiltinContext&, std::function<void()>)> generateCode; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Yul dialect for EVM as a backend. |  * Yul dialect for EVM as a backend. | ||||||
|  * The main difference is that the builtin functions take an AbstractAssembly for the |  * The main difference is that the builtin functions take an AbstractAssembly for the | ||||||
| @ -50,41 +61,24 @@ struct BuiltinFunctionForEVM: BuiltinFunction | |||||||
|  */ |  */ | ||||||
| struct EVMDialect: public Dialect | struct EVMDialect: public Dialect | ||||||
| { | { | ||||||
|  | 	/// Constructor, should only be used internally. Use the factory functions below.
 | ||||||
| 	EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVersion _evmVersion); | 	EVMDialect(AsmFlavour _flavour, bool _objectAccess, langutil::EVMVersion _evmVersion); | ||||||
| 
 | 
 | ||||||
| 	/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
 | 	/// @returns the builtin function of the given name or a nullptr if it is not a builtin function.
 | ||||||
| 	BuiltinFunctionForEVM const* builtin(YulString _name) const override; | 	BuiltinFunctionForEVM const* builtin(YulString _name) const override; | ||||||
| 
 | 
 | ||||||
| 	static std::shared_ptr<EVMDialect> looseAssemblyForEVM(langutil::EVMVersion _version); | 	static EVMDialect const& looseAssemblyForEVM(langutil::EVMVersion _version); | ||||||
| 	static std::shared_ptr<EVMDialect> strictAssemblyForEVM(langutil::EVMVersion _version); | 	static EVMDialect const& strictAssemblyForEVM(langutil::EVMVersion _version); | ||||||
| 	static std::shared_ptr<EVMDialect> strictAssemblyForEVMObjects(langutil::EVMVersion _version); | 	static EVMDialect const& strictAssemblyForEVMObjects(langutil::EVMVersion _version); | ||||||
| 	static std::shared_ptr<EVMDialect> yulForEVM(langutil::EVMVersion _version); | 	static EVMDialect const& yulForEVM(langutil::EVMVersion _version); | ||||||
| 
 | 
 | ||||||
| 	langutil::EVMVersion evmVersion() const { return m_evmVersion; } | 	langutil::EVMVersion evmVersion() const { return m_evmVersion; } | ||||||
| 
 | 
 | ||||||
| 	bool providesObjectAccess() const { return m_objectAccess; } | 	bool providesObjectAccess() const { return m_objectAccess; } | ||||||
| 
 | 
 | ||||||
| 	/// Sets the mapping of current sub assembly IDs. Used during code generation.
 |  | ||||||
| 	void setSubIDs(std::map<YulString, AbstractAssembly::SubID> _subIDs); |  | ||||||
| 	/// Sets the current object. Used during code generation.
 |  | ||||||
| 	void setCurrentObject(Object const* _object); |  | ||||||
| 
 |  | ||||||
| protected: | protected: | ||||||
| 	void addFunction( | 	bool const m_objectAccess; | ||||||
| 		std::string _name, | 	langutil::EVMVersion const m_evmVersion; | ||||||
| 		size_t _params, |  | ||||||
| 		size_t _returns, |  | ||||||
| 		bool _movable, |  | ||||||
| 		bool _sideEffectFree, |  | ||||||
| 		bool _literalArguments, |  | ||||||
| 		std::function<void(FunctionCall const&, AbstractAssembly&, std::function<void()>)> _generateCode |  | ||||||
| 	); |  | ||||||
| 
 |  | ||||||
| 	bool m_objectAccess; |  | ||||||
| 	langutil::EVMVersion m_evmVersion; |  | ||||||
| 	Object const* m_currentObject = nullptr; |  | ||||||
| 	/// Mapping from named objects to abstract assembly sub IDs.
 |  | ||||||
| 	std::map<YulString, AbstractAssembly::SubID> m_subIDs; |  | ||||||
| 	std::map<YulString, BuiltinFunctionForEVM> m_functions; | 	std::map<YulString, BuiltinFunctionForEVM> m_functions; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -29,7 +29,7 @@ | |||||||
| using namespace yul; | using namespace yul; | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
| void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, EVMDialect& _dialect, bool _evm15, bool _optimize) | void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, EVMDialect const& _dialect, bool _evm15, bool _optimize) | ||||||
| { | { | ||||||
| 	EVMObjectCompiler compiler(_assembly, _dialect, _evm15); | 	EVMObjectCompiler compiler(_assembly, _dialect, _evm15); | ||||||
| 	compiler.run(_object, _optimize); | 	compiler.run(_object, _optimize); | ||||||
| @ -37,32 +37,27 @@ void EVMObjectCompiler::compile(Object& _object, AbstractAssembly& _assembly, EV | |||||||
| 
 | 
 | ||||||
| void EVMObjectCompiler::run(Object& _object, bool _optimize) | void EVMObjectCompiler::run(Object& _object, bool _optimize) | ||||||
| { | { | ||||||
| 	map<YulString, AbstractAssembly::SubID> subIDs; | 	BuiltinContext context; | ||||||
|  | 	context.currentObject = &_object; | ||||||
| 
 | 
 | ||||||
| 	for (auto& subNode: _object.subObjects) | 	for (auto& subNode: _object.subObjects) | ||||||
| 		if (Object* subObject = dynamic_cast<Object*>(subNode.get())) | 		if (Object* subObject = dynamic_cast<Object*>(subNode.get())) | ||||||
| 		{ | 		{ | ||||||
| 			auto subAssemblyAndID = m_assembly.createSubAssembly(); | 			auto subAssemblyAndID = m_assembly.createSubAssembly(); | ||||||
| 			subIDs[subObject->name] = subAssemblyAndID.second; | 			context.subIDs[subObject->name] = subAssemblyAndID.second; | ||||||
| 			compile(*subObject, *subAssemblyAndID.first, m_dialect, m_evm15, _optimize); | 			compile(*subObject, *subAssemblyAndID.first, m_dialect, m_evm15, _optimize); | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			Data const& data = dynamic_cast<Data const&>(*subNode); | 			Data const& data = dynamic_cast<Data const&>(*subNode); | ||||||
| 			subIDs[data.name] = m_assembly.appendData(data.data); | 			context.subIDs[data.name] = m_assembly.appendData(data.data); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	if (m_dialect.providesObjectAccess()) |  | ||||||
| 	{ |  | ||||||
| 		m_dialect.setSubIDs(std::move(subIDs)); |  | ||||||
| 		m_dialect.setCurrentObject(&_object); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	yulAssert(_object.analysisInfo, "No analysis info."); | 	yulAssert(_object.analysisInfo, "No analysis info."); | ||||||
| 	yulAssert(_object.code, "No code."); | 	yulAssert(_object.code, "No code."); | ||||||
| 	// We do not catch and re-throw the stack too deep exception here because it is a YulException,
 | 	// We do not catch and re-throw the stack too deep exception here because it is a YulException,
 | ||||||
| 	// which should be native to this part of the code.
 | 	// which should be native to this part of the code.
 | ||||||
| 	CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, _optimize, m_evm15}; | 	CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, context, _optimize, m_evm15}; | ||||||
| 	transform(*_object.code); | 	transform(*_object.code); | ||||||
| 	yulAssert(transform.stackErrors().empty(), "Stack errors present but not thrown."); | 	yulAssert(transform.stackErrors().empty(), "Stack errors present but not thrown."); | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,16 +29,16 @@ struct EVMDialect; | |||||||
| class EVMObjectCompiler | class EVMObjectCompiler | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	static void compile(Object& _object, AbstractAssembly& _assembly, EVMDialect& _dialect, bool _evm15, bool _optimize); | 	static void compile(Object& _object, AbstractAssembly& _assembly, EVMDialect const& _dialect, bool _evm15, bool _optimize); | ||||||
| private: | private: | ||||||
| 	EVMObjectCompiler(AbstractAssembly& _assembly, EVMDialect& _dialect, bool _evm15): | 	EVMObjectCompiler(AbstractAssembly& _assembly, EVMDialect const& _dialect, bool _evm15): | ||||||
| 		m_assembly(_assembly), m_dialect(_dialect), m_evm15(_evm15) | 		m_assembly(_assembly), m_dialect(_dialect), m_evm15(_evm15) | ||||||
| 	{} | 	{} | ||||||
| 
 | 
 | ||||||
| 	void run(Object& _object, bool _optimize); | 	void run(Object& _object, bool _optimize); | ||||||
| 
 | 
 | ||||||
| 	AbstractAssembly& m_assembly; | 	AbstractAssembly& m_assembly; | ||||||
| 	EVMDialect& m_dialect; | 	EVMDialect const& m_dialect; | ||||||
| 	bool m_evm15 = false; | 	bool m_evm15 = false; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -142,14 +142,14 @@ AbstractAssembly::SubID NoOutputAssembly::appendData(bytes const&) | |||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| NoOutputEVMDialect::NoOutputEVMDialect(shared_ptr<EVMDialect> const& _copyFrom): | NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): | ||||||
| 	EVMDialect(_copyFrom->flavour, _copyFrom->providesObjectAccess(), _copyFrom->evmVersion()) | 	EVMDialect(_copyFrom.flavour, _copyFrom.providesObjectAccess(), _copyFrom.evmVersion()) | ||||||
| { | { | ||||||
| 	for (auto& fun: m_functions) | 	for (auto& fun: m_functions) | ||||||
| 	{ | 	{ | ||||||
| 		size_t parameters = fun.second.parameters.size(); | 		size_t parameters = fun.second.parameters.size(); | ||||||
| 		size_t returns = fun.second.returns.size(); | 		size_t returns = fun.second.returns.size(); | ||||||
| 		fun.second.generateCode = [=](FunctionCall const&, AbstractAssembly& _assembly, std::function<void()> _visitArguments) | 		fun.second.generateCode = [=](FunctionCall const&, AbstractAssembly& _assembly, BuiltinContext&, std::function<void()> _visitArguments) | ||||||
| 		{ | 		{ | ||||||
| 			_visitArguments(); | 			_visitArguments(); | ||||||
| 			for (size_t i = 0; i < parameters; i++) | 			for (size_t i = 0; i < parameters; i++) | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ private: | |||||||
|  */ |  */ | ||||||
| struct NoOutputEVMDialect: public EVMDialect | struct NoOutputEVMDialect: public EVMDialect | ||||||
| { | { | ||||||
| 	explicit NoOutputEVMDialect(std::shared_ptr<EVMDialect> const& _copyFrom); | 	explicit NoOutputEVMDialect(EVMDialect const& _copyFrom); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ | |||||||
| using namespace yul; | using namespace yul; | ||||||
| using namespace std; | using namespace std; | ||||||
| 
 | 
 | ||||||
| string EWasmObjectCompiler::compile(Object& _object, Dialect& _dialect) | string EWasmObjectCompiler::compile(Object& _object, Dialect const& _dialect) | ||||||
| { | { | ||||||
| 	EWasmObjectCompiler compiler(_dialect); | 	EWasmObjectCompiler compiler(_dialect); | ||||||
| 	return compiler.run(_object); | 	return compiler.run(_object); | ||||||
|  | |||||||
| @ -30,15 +30,15 @@ struct Dialect; | |||||||
| class EWasmObjectCompiler | class EWasmObjectCompiler | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	static std::string compile(Object& _object, Dialect& _dialect); | 	static std::string compile(Object& _object, Dialect const& _dialect); | ||||||
| private: | private: | ||||||
| 	EWasmObjectCompiler(Dialect& _dialect): | 	EWasmObjectCompiler(Dialect const& _dialect): | ||||||
| 		m_dialect(_dialect) | 		m_dialect(_dialect) | ||||||
| 	{} | 	{} | ||||||
| 
 | 
 | ||||||
| 	std::string run(Object& _object); | 	std::string run(Object& _object); | ||||||
| 
 | 
 | ||||||
| 	Dialect& m_dialect; | 	Dialect const& m_dialect; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -42,11 +42,17 @@ struct Object; | |||||||
|  */ |  */ | ||||||
| struct WasmDialect: public Dialect | struct WasmDialect: public Dialect | ||||||
| { | { | ||||||
| 	WasmDialect(); |  | ||||||
| 
 |  | ||||||
| 	BuiltinFunction const* builtin(YulString _name) const override; | 	BuiltinFunction const* builtin(YulString _name) const override; | ||||||
| 
 | 
 | ||||||
|  | 	static WasmDialect const& instance() | ||||||
|  | 	{ | ||||||
|  | 		static WasmDialect dialect; | ||||||
|  | 		return dialect; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| protected: | protected: | ||||||
|  | 	WasmDialect(); | ||||||
|  | 
 | ||||||
| 	void addFunction(std::string _name, size_t _params, size_t _returns); | 	void addFunction(std::string _name, size_t _params, size_t _returns); | ||||||
| 
 | 
 | ||||||
| 	std::map<YulString, BuiltinFunction> m_functions; | 	std::map<YulString, BuiltinFunction> m_functions; | ||||||
|  | |||||||
| @ -112,9 +112,9 @@ public: | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| template <typename ASTNode> | template <typename ASTNode> | ||||||
| void eliminateVariables(shared_ptr<Dialect> const& _dialect, ASTNode& _node, size_t _numVariables) | void eliminateVariables(Dialect const& _dialect, ASTNode& _node, size_t _numVariables) | ||||||
| { | { | ||||||
| 	RematCandidateSelector selector{*_dialect}; | 	RematCandidateSelector selector{_dialect}; | ||||||
| 	selector(_node); | 	selector(_node); | ||||||
| 
 | 
 | ||||||
| 	// Select at most _numVariables
 | 	// Select at most _numVariables
 | ||||||
| @ -126,14 +126,14 @@ void eliminateVariables(shared_ptr<Dialect> const& _dialect, ASTNode& _node, siz | |||||||
| 		varsToEliminate.insert(costs.second); | 		varsToEliminate.insert(costs.second); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	Rematerialiser::run(*_dialect, _node, std::move(varsToEliminate)); | 	Rematerialiser::run(_dialect, _node, std::move(varsToEliminate)); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, _node); | 	UnusedPruner::runUntilStabilised(_dialect, _node); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool StackCompressor::run( | bool StackCompressor::run( | ||||||
| 	shared_ptr<Dialect> const& _dialect, | 	Dialect const& _dialect, | ||||||
| 	Block& _ast, | 	Block& _ast, | ||||||
| 	bool _optimizeStackAllocation, | 	bool _optimizeStackAllocation, | ||||||
| 	size_t _maxIterations | 	size_t _maxIterations | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ public: | |||||||
| 	/// Try to remove local variables until the AST is compilable.
 | 	/// Try to remove local variables until the AST is compilable.
 | ||||||
| 	/// @returns true if it was successful.
 | 	/// @returns true if it was successful.
 | ||||||
| 	static bool run( | 	static bool run( | ||||||
| 		std::shared_ptr<Dialect> const& _dialect, | 		Dialect const& _dialect, | ||||||
| 		Block& _ast, | 		Block& _ast, | ||||||
| 		bool _optimizeStackAllocation, | 		bool _optimizeStackAllocation, | ||||||
| 		size_t _maxIterations | 		size_t _maxIterations | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ using namespace dev; | |||||||
| using namespace yul; | using namespace yul; | ||||||
| 
 | 
 | ||||||
| void OptimiserSuite::run( | void OptimiserSuite::run( | ||||||
| 	shared_ptr<Dialect> const& _dialect, | 	Dialect const& _dialect, | ||||||
| 	Block& _ast, | 	Block& _ast, | ||||||
| 	AsmAnalysisInfo const& _analysisInfo, | 	AsmAnalysisInfo const& _analysisInfo, | ||||||
| 	bool _optimizeStackAllocation, | 	bool _optimizeStackAllocation, | ||||||
| @ -67,7 +67,7 @@ void OptimiserSuite::run( | |||||||
| { | { | ||||||
| 	set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; | 	set<YulString> reservedIdentifiers = _externallyUsedIdentifiers; | ||||||
| 
 | 
 | ||||||
| 	Block ast = boost::get<Block>(Disambiguator(*_dialect, _analysisInfo, reservedIdentifiers)(_ast)); | 	Block ast = boost::get<Block>(Disambiguator(_dialect, _analysisInfo, reservedIdentifiers)(_ast)); | ||||||
| 
 | 
 | ||||||
| 	VarDeclInitializer{}(ast); | 	VarDeclInitializer{}(ast); | ||||||
| 	FunctionHoister{}(ast); | 	FunctionHoister{}(ast); | ||||||
| @ -76,16 +76,16 @@ void OptimiserSuite::run( | |||||||
| 	DeadCodeEliminator{}(ast); | 	DeadCodeEliminator{}(ast); | ||||||
| 	FunctionGrouper{}(ast); | 	FunctionGrouper{}(ast); | ||||||
| 	EquivalentFunctionCombiner::run(ast); | 	EquivalentFunctionCombiner::run(ast); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 	BlockFlattener{}(ast); | 	BlockFlattener{}(ast); | ||||||
| 	ControlFlowSimplifier{}(ast); | 	ControlFlowSimplifier{}(ast); | ||||||
| 	StructuralSimplifier{*_dialect}(ast); | 	StructuralSimplifier{_dialect}(ast); | ||||||
| 	ControlFlowSimplifier{}(ast); | 	ControlFlowSimplifier{}(ast); | ||||||
| 	BlockFlattener{}(ast); | 	BlockFlattener{}(ast); | ||||||
| 
 | 
 | ||||||
| 	// None of the above can make stack problems worse.
 | 	// None of the above can make stack problems worse.
 | ||||||
| 
 | 
 | ||||||
| 	NameDispenser dispenser{*_dialect, ast}; | 	NameDispenser dispenser{_dialect, ast}; | ||||||
| 
 | 
 | ||||||
| 	size_t codeSize = 0; | 	size_t codeSize = 0; | ||||||
| 	for (size_t rounds = 0; rounds < 12; ++rounds) | 	for (size_t rounds = 0; rounds < 12; ++rounds) | ||||||
| @ -99,35 +99,35 @@ void OptimiserSuite::run( | |||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			// Turn into SSA and simplify
 | 			// Turn into SSA and simplify
 | ||||||
| 			ExpressionSplitter{*_dialect, dispenser}(ast); | 			ExpressionSplitter{_dialect, dispenser}(ast); | ||||||
| 			SSATransform::run(ast, dispenser); | 			SSATransform::run(ast, dispenser); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 
 | 
 | ||||||
| 			ExpressionSimplifier::run(*_dialect, ast); | 			ExpressionSimplifier::run(_dialect, ast); | ||||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | 			CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			// still in SSA, perform structural simplification
 | 			// still in SSA, perform structural simplification
 | ||||||
| 			ControlFlowSimplifier{}(ast); | 			ControlFlowSimplifier{}(ast); | ||||||
| 			StructuralSimplifier{*_dialect}(ast); | 			StructuralSimplifier{_dialect}(ast); | ||||||
| 			ControlFlowSimplifier{}(ast); | 			ControlFlowSimplifier{}(ast); | ||||||
| 			BlockFlattener{}(ast); | 			BlockFlattener{}(ast); | ||||||
| 			DeadCodeEliminator{}(ast); | 			DeadCodeEliminator{}(ast); | ||||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 			UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 		} | 		} | ||||||
| 		{ | 		{ | ||||||
| 			// simplify again
 | 			// simplify again
 | ||||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | 			CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 			UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			// reverse SSA
 | 			// reverse SSA
 | ||||||
| 			SSAReverser::run(ast); | 			SSAReverser::run(ast); | ||||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | 			CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 			UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 
 | 
 | ||||||
| 			ExpressionJoiner::run(ast); | 			ExpressionJoiner::run(ast); | ||||||
| 			ExpressionJoiner::run(ast); | 			ExpressionJoiner::run(ast); | ||||||
| @ -137,17 +137,17 @@ void OptimiserSuite::run( | |||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			// run functional expression inliner
 | 			// run functional expression inliner
 | ||||||
| 			ExpressionInliner(*_dialect, ast).run(); | 			ExpressionInliner(_dialect, ast).run(); | ||||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 			UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| 			// Turn into SSA again and simplify
 | 			// Turn into SSA again and simplify
 | ||||||
| 			ExpressionSplitter{*_dialect, dispenser}(ast); | 			ExpressionSplitter{_dialect, dispenser}(ast); | ||||||
| 			SSATransform::run(ast, dispenser); | 			SSATransform::run(ast, dispenser); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | 			CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		{ | 		{ | ||||||
| @ -161,39 +161,39 @@ void OptimiserSuite::run( | |||||||
| 		{ | 		{ | ||||||
| 			// SSA plus simplify
 | 			// SSA plus simplify
 | ||||||
| 			SSATransform::run(ast, dispenser); | 			SSATransform::run(ast, dispenser); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			ExpressionSimplifier::run(*_dialect, ast); | 			ExpressionSimplifier::run(_dialect, ast); | ||||||
| 			StructuralSimplifier{*_dialect}(ast); | 			StructuralSimplifier{_dialect}(ast); | ||||||
| 			BlockFlattener{}(ast); | 			BlockFlattener{}(ast); | ||||||
| 			DeadCodeEliminator{}(ast); | 			DeadCodeEliminator{}(ast); | ||||||
| 			ControlFlowSimplifier{}(ast); | 			ControlFlowSimplifier{}(ast); | ||||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | 			CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 			SSATransform::run(ast, dispenser); | 			SSATransform::run(ast, dispenser); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			RedundantAssignEliminator::run(*_dialect, ast); | 			RedundantAssignEliminator::run(_dialect, ast); | ||||||
| 			UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 			UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 			CommonSubexpressionEliminator{*_dialect}(ast); | 			CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Make source short and pretty.
 | 	// Make source short and pretty.
 | ||||||
| 
 | 
 | ||||||
| 	ExpressionJoiner::run(ast); | 	ExpressionJoiner::run(ast); | ||||||
| 	Rematerialiser::run(*_dialect, ast); | 	Rematerialiser::run(_dialect, ast); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 	ExpressionJoiner::run(ast); | 	ExpressionJoiner::run(ast); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 	ExpressionJoiner::run(ast); | 	ExpressionJoiner::run(ast); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 
 | 
 | ||||||
| 	SSAReverser::run(ast); | 	SSAReverser::run(ast); | ||||||
| 	CommonSubexpressionEliminator{*_dialect}(ast); | 	CommonSubexpressionEliminator{_dialect}(ast); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 
 | 
 | ||||||
| 	ExpressionJoiner::run(ast); | 	ExpressionJoiner::run(ast); | ||||||
| 	Rematerialiser::run(*_dialect, ast); | 	Rematerialiser::run(_dialect, ast); | ||||||
| 	UnusedPruner::runUntilStabilised(*_dialect, ast, reservedIdentifiers); | 	UnusedPruner::runUntilStabilised(_dialect, ast, reservedIdentifiers); | ||||||
| 
 | 
 | ||||||
| 	// This is a tuning parameter, but actually just prevents infinite loops.
 | 	// This is a tuning parameter, but actually just prevents infinite loops.
 | ||||||
| 	size_t stackCompressorMaxIterations = 16; | 	size_t stackCompressorMaxIterations = 16; | ||||||
| @ -206,7 +206,7 @@ void OptimiserSuite::run( | |||||||
| 	ControlFlowSimplifier{}(ast); | 	ControlFlowSimplifier{}(ast); | ||||||
| 
 | 
 | ||||||
| 	FunctionGrouper{}(ast); | 	FunctionGrouper{}(ast); | ||||||
| 	VarNameCleaner{ast, *_dialect, reservedIdentifiers}(ast); | 	VarNameCleaner{ast, _dialect, reservedIdentifiers}(ast); | ||||||
| 	yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast); | 	yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast); | ||||||
| 
 | 
 | ||||||
| 	_ast = std::move(ast); | 	_ast = std::move(ast); | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ class OptimiserSuite | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	static void run( | 	static void run( | ||||||
| 		std::shared_ptr<Dialect> const& _dialect, | 		Dialect const& _dialect, | ||||||
| 		Block& _ast, | 		Block& _ast, | ||||||
| 		AsmAnalysisInfo const& _analysisInfo, | 		AsmAnalysisInfo const& _analysisInfo, | ||||||
| 		bool _optimizeStackAllocation, | 		bool _optimizeStackAllocation, | ||||||
|  | |||||||
| @ -43,7 +43,7 @@ using namespace yul; | |||||||
| 
 | 
 | ||||||
| namespace | namespace | ||||||
| { | { | ||||||
| shared_ptr<Dialect> defaultDialect(bool _yul) | Dialect const& defaultDialect(bool _yul) | ||||||
| { | { | ||||||
| 	return _yul ? yul::Dialect::yul() : yul::EVMDialect::strictAssemblyForEVM(dev::test::Options::get().evmVersion()); | 	return _yul ? yul::Dialect::yul() : yul::EVMDialect::strictAssemblyForEVM(dev::test::Options::get().evmVersion()); | ||||||
| } | } | ||||||
| @ -75,7 +75,7 @@ pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(strin | |||||||
| yul::Block yul::test::disambiguate(string const& _source, bool _yul) | yul::Block yul::test::disambiguate(string const& _source, bool _yul) | ||||||
| { | { | ||||||
| 	auto result = parse(_source, _yul); | 	auto result = parse(_source, _yul); | ||||||
| 	return boost::get<Block>(Disambiguator(*defaultDialect(_yul), *result.second, {})(*result.first)); | 	return boost::get<Block>(Disambiguator(defaultDialect(_yul), *result.second, {})(*result.first)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| string yul::test::format(string const& _source, bool _yul) | string yul::test::format(string const& _source, bool _yul) | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ namespace test | |||||||
| namespace | namespace | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| bool parse(string const& _source, std::shared_ptr<Dialect> _dialect, ErrorReporter& errorReporter) | bool parse(string const& _source, Dialect const& _dialect, ErrorReporter& errorReporter) | ||||||
| { | { | ||||||
| 	try | 	try | ||||||
| 	{ | 	{ | ||||||
| @ -73,7 +73,7 @@ bool parse(string const& _source, std::shared_ptr<Dialect> _dialect, ErrorReport | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| boost::optional<Error> parseAndReturnFirstError(string const& _source, shared_ptr<Dialect> _dialect, bool _allowWarnings = true) | boost::optional<Error> parseAndReturnFirstError(string const& _source, Dialect const& _dialect, bool _allowWarnings = true) | ||||||
| { | { | ||||||
| 	ErrorList errors; | 	ErrorList errors; | ||||||
| 	ErrorReporter errorReporter(errors); | 	ErrorReporter errorReporter(errors); | ||||||
| @ -98,12 +98,12 @@ boost::optional<Error> parseAndReturnFirstError(string const& _source, shared_pt | |||||||
| 	return {}; | 	return {}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool successParse(std::string const& _source, shared_ptr<Dialect> _dialect = Dialect::yul(), bool _allowWarnings = true) | bool successParse(std::string const& _source, Dialect const& _dialect = Dialect::yul(), bool _allowWarnings = true) | ||||||
| { | { | ||||||
| 	return !parseAndReturnFirstError(_source, _dialect, _allowWarnings); | 	return !parseAndReturnFirstError(_source, _dialect, _allowWarnings); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Error expectError(std::string const& _source, shared_ptr<Dialect> _dialect = Dialect::yul(), bool _allowWarnings = false) | Error expectError(std::string const& _source, Dialect const& _dialect = Dialect::yul(), bool _allowWarnings = false) | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 	auto error = parseAndReturnFirstError(_source, _dialect, _allowWarnings); | 	auto error = parseAndReturnFirstError(_source, _dialect, _allowWarnings); | ||||||
| @ -324,41 +324,39 @@ BOOST_AUTO_TEST_CASE(if_statement) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(break_outside_of_for_loop) | BOOST_AUTO_TEST_CASE(break_outside_of_for_loop) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); |  | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ let x if x { break } }", | 		"{ let x if x { break } }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| 		"Keyword \"break\" needs to be inside a for-loop body.", | 		"Keyword \"break\" needs to be inside a for-loop body.", | ||||||
| 		dialect | 		EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()) | ||||||
| 	); | 	); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(continue_outside_of_for_loop) | BOOST_AUTO_TEST_CASE(continue_outside_of_for_loop) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); |  | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ let x if x { continue } }", | 		"{ let x if x { continue } }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| 		"Keyword \"continue\" needs to be inside a for-loop body.", | 		"Keyword \"continue\" needs to be inside a for-loop body.", | ||||||
| 		dialect | 		EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()) | ||||||
| 	); | 	); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement) | BOOST_AUTO_TEST_CASE(for_statement) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {} }", dialect)); | 	BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_break) | BOOST_AUTO_TEST_CASE(for_statement_break) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {break} }", dialect)); | 	BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {break} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_break_init) | BOOST_AUTO_TEST_CASE(for_statement_break_init) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {let i := 0 break} iszero(eq(i, 10)) {i := add(i, 1)} {} }", | 		"{ for {let i := 0 break} iszero(eq(i, 10)) {i := add(i, 1)} {} }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -369,7 +367,7 @@ BOOST_AUTO_TEST_CASE(for_statement_break_init) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_break_post) | BOOST_AUTO_TEST_CASE(for_statement_break_post) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1) break} {} }", | 		"{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1) break} {} }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -380,7 +378,7 @@ BOOST_AUTO_TEST_CASE(for_statement_break_post) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_nested_break) | BOOST_AUTO_TEST_CASE(for_statement_nested_break) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {let i := 0} iszero(eq(i, 10)) {} { function f() { break } } }", | 		"{ for {let i := 0} iszero(eq(i, 10)) {} { function f() { break } } }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -391,13 +389,13 @@ BOOST_AUTO_TEST_CASE(for_statement_nested_break) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_continue) | BOOST_AUTO_TEST_CASE(for_statement_continue) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {continue} }", dialect)); | 	BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {continue} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_continue_fail_init) | BOOST_AUTO_TEST_CASE(for_statement_continue_fail_init) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {let i := 0 continue} iszero(eq(i, 10)) {i := add(i, 1)} {} }", | 		"{ for {let i := 0 continue} iszero(eq(i, 10)) {i := add(i, 1)} {} }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -408,7 +406,7 @@ BOOST_AUTO_TEST_CASE(for_statement_continue_fail_init) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_continue_fail_post) | BOOST_AUTO_TEST_CASE(for_statement_continue_fail_post) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1) continue} {} }", | 		"{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1) continue} {} }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -419,7 +417,7 @@ BOOST_AUTO_TEST_CASE(for_statement_continue_fail_post) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_nested_continue) | BOOST_AUTO_TEST_CASE(for_statement_nested_continue) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {let i := 0} iszero(eq(i, 10)) {} { function f() { continue } } }", | 		"{ for {let i := 0} iszero(eq(i, 10)) {} { function f() { continue } } }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -430,7 +428,7 @@ BOOST_AUTO_TEST_CASE(for_statement_nested_continue) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_continue_nested_init_in_body) | BOOST_AUTO_TEST_CASE(for_statement_continue_nested_init_in_body) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople()); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| 		"{ for {} 1 {} {let x for { continue } x {} {}} }", | 		"{ for {} 1 {} {let x for { continue } x {} {}} }", | ||||||
| 		SyntaxError, | 		SyntaxError, | ||||||
| @ -441,31 +439,31 @@ BOOST_AUTO_TEST_CASE(for_statement_continue_nested_init_in_body) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_continue_nested_body_in_init) | BOOST_AUTO_TEST_CASE(for_statement_continue_nested_body_in_init) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | ||||||
| 	BOOST_CHECK(successParse("{ for {let x for {} x {} { continue }} 1 {} {} }", dialect)); | 	BOOST_CHECK(successParse("{ for {let x for {} x {} { continue }} 1 {} {} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_break_nested_body_in_init) | BOOST_AUTO_TEST_CASE(for_statement_break_nested_body_in_init) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | ||||||
| 	BOOST_CHECK(successParse("{ for {let x for {} x {} { break }} 1 {} {} }", dialect)); | 	BOOST_CHECK(successParse("{ for {let x for {} x {} { break }} 1 {} {} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_continue_nested_body_in_post) | BOOST_AUTO_TEST_CASE(for_statement_continue_nested_body_in_post) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | ||||||
| 	BOOST_CHECK(successParse("{ for {} 1 {let x for {} x {} { continue }} {} }", dialect)); | 	BOOST_CHECK(successParse("{ for {} 1 {let x for {} x {} { continue }} {} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(for_statement_break_nested_body_in_post) | BOOST_AUTO_TEST_CASE(for_statement_break_nested_body_in_post) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | ||||||
| 	BOOST_CHECK(successParse("{ for {} 1 {let x for {} x {} { break }} {} }", dialect)); | 	BOOST_CHECK(successParse("{ for {} 1 {let x for {} x {} { break }} {} }", dialect)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(function_defined_in_init_block) | BOOST_AUTO_TEST_CASE(function_defined_in_init_block) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | ||||||
| 	BOOST_CHECK(successParse("{ for { } 1 { function f() {} } {} }", dialect)); | 	BOOST_CHECK(successParse("{ for { } 1 { function f() {} } {} }", dialect)); | ||||||
| 	BOOST_CHECK(successParse("{ for { } 1 {} { function f() {} } }", dialect)); | 	BOOST_CHECK(successParse("{ for { } 1 {} { function f() {} } }", dialect)); | ||||||
| 	CHECK_ERROR_DIALECT( | 	CHECK_ERROR_DIALECT( | ||||||
| @ -478,7 +476,7 @@ BOOST_AUTO_TEST_CASE(function_defined_in_init_block) | |||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_CASE(function_defined_in_init_nested) | BOOST_AUTO_TEST_CASE(function_defined_in_init_nested) | ||||||
| { | { | ||||||
| 	auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | 	auto const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); | ||||||
| 	BOOST_CHECK(successParse( | 	BOOST_CHECK(successParse( | ||||||
| 		"{ for {" | 		"{ for {" | ||||||
| 			"for { } 1 { function f() {} } {}" | 			"for { } 1 { function f() {} } {}" | ||||||
| @ -548,7 +546,7 @@ BOOST_AUTO_TEST_CASE(builtins_parser) | |||||||
| 		BuiltinFunction f; | 		BuiltinFunction f; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	shared_ptr<Dialect> dialect = make_shared<SimpleDialect>(); | 	SimpleDialect dialect; | ||||||
| 	CHECK_ERROR_DIALECT("{ let builtin := 6 }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); | 	CHECK_ERROR_DIALECT("{ let builtin := 6 }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); | ||||||
| 	CHECK_ERROR_DIALECT("{ function builtin() {} }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); | 	CHECK_ERROR_DIALECT("{ function builtin() {} }", ParserError, "Cannot use builtin function name \"builtin\" as identifier name.", dialect); | ||||||
| 	CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Cannot assign to builtin function \"builtin\".", dialect); | 	CHECK_ERROR_DIALECT("{ builtin := 6 }", ParserError, "Cannot assign to builtin function \"builtin\".", dialect); | ||||||
| @ -567,7 +565,7 @@ BOOST_AUTO_TEST_CASE(builtins_analysis) | |||||||
| 		BuiltinFunction f{"builtin"_yulstring, vector<Type>(2), vector<Type>(3), false, false}; | 		BuiltinFunction f{"builtin"_yulstring, vector<Type>(2), vector<Type>(3), false, false}; | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	shared_ptr<Dialect> dialect = make_shared<SimpleDialect>(); | 	SimpleDialect dialect; | ||||||
| 	BOOST_CHECK(successParse("{ let a, b, c := builtin(1, 2) }", dialect)); | 	BOOST_CHECK(successParse("{ let a, b, c := builtin(1, 2) }", dialect)); | ||||||
| 	CHECK_ERROR_DIALECT("{ let a, b, c := builtin(1) }", TypeError, "Function expects 2 arguments but got 1", dialect); | 	CHECK_ERROR_DIALECT("{ let a, b, c := builtin(1) }", TypeError, "Function expects 2 arguments but got 1", dialect); | ||||||
| 	CHECK_ERROR_DIALECT("{ let a, b := builtin(1, 2) }", DeclarationError, "Variable count mismatch: 2 variables and 3 values.", dialect); | 	CHECK_ERROR_DIALECT("{ let a, b := builtin(1, 2) }", DeclarationError, "Variable count mismatch: 2 variables and 3 values.", dialect); | ||||||
|  | |||||||
| @ -132,8 +132,7 @@ string YulInterpreterTest::interpret() | |||||||
| 	state.maxTraceSize = 10000; | 	state.maxTraceSize = 10000; | ||||||
| 	state.maxSteps = 10000; | 	state.maxSteps = 10000; | ||||||
| 	state.maxMemSize = 0x20000000; | 	state.maxMemSize = 0x20000000; | ||||||
| 	shared_ptr<Dialect> dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); | 	Interpreter interpreter(state, EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); | ||||||
| 	Interpreter interpreter(state, *dialect); |  | ||||||
| 	try | 	try | ||||||
| 	{ | 	{ | ||||||
| 		interpreter(*m_ast); | 		interpreter(*m_ast); | ||||||
|  | |||||||
| @ -109,6 +109,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | |||||||
| 	if (!parse(_stream, _linePrefix, _formatted)) | 	if (!parse(_stream, _linePrefix, _formatted)) | ||||||
| 		return TestResult::FatalError; | 		return TestResult::FatalError; | ||||||
| 
 | 
 | ||||||
|  | 	soltestAssert(m_dialect, "Dialect not set."); | ||||||
| 	if (m_optimizerStep == "disambiguator") | 	if (m_optimizerStep == "disambiguator") | ||||||
| 		disambiguate(); | 		disambiguate(); | ||||||
| 	else if (m_optimizerStep == "blockFlattener") | 	else if (m_optimizerStep == "blockFlattener") | ||||||
| @ -270,7 +271,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | |||||||
| 		disambiguate(); | 		disambiguate(); | ||||||
| 		(FunctionGrouper{})(*m_ast); | 		(FunctionGrouper{})(*m_ast); | ||||||
| 		size_t maxIterations = 16; | 		size_t maxIterations = 16; | ||||||
| 		StackCompressor::run(m_dialect, *m_ast, true, maxIterations); | 		StackCompressor::run(*m_dialect, *m_ast, true, maxIterations); | ||||||
| 		(BlockFlattener{})(*m_ast); | 		(BlockFlattener{})(*m_ast); | ||||||
| 	} | 	} | ||||||
| 	else if (m_optimizerStep == "wordSizeTransform") | 	else if (m_optimizerStep == "wordSizeTransform") | ||||||
| @ -281,7 +282,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line | |||||||
| 		WordSizeTransform::run(*m_ast, nameDispenser); | 		WordSizeTransform::run(*m_ast, nameDispenser); | ||||||
| 	} | 	} | ||||||
| 	else if (m_optimizerStep == "fullSuite") | 	else if (m_optimizerStep == "fullSuite") | ||||||
| 		OptimiserSuite::run(m_dialect, *m_ast, *m_analysisInfo, true); | 		OptimiserSuite::run(*m_dialect, *m_ast, *m_analysisInfo, true); | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << endl; | 		AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << endl; | ||||||
| @ -353,7 +354,7 @@ bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool c | |||||||
| 		printErrors(_stream, stack.errors()); | 		printErrors(_stream, stack.errors()); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 	m_dialect = m_yul ? Dialect::yul() : EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion()); | 	m_dialect = m_yul ? &Dialect::yul() : &EVMDialect::strictAssemblyForEVMObjects(dev::test::Options::get().evmVersion()); | ||||||
| 	m_ast = stack.parserResult()->code; | 	m_ast = stack.parserResult()->code; | ||||||
| 	m_analysisInfo = stack.parserResult()->analysisInfo; | 	m_analysisInfo = stack.parserResult()->analysisInfo; | ||||||
| 	return true; | 	return true; | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ private: | |||||||
| 	std::string m_optimizerStep; | 	std::string m_optimizerStep; | ||||||
| 	std::string m_expectation; | 	std::string m_expectation; | ||||||
| 
 | 
 | ||||||
| 	std::shared_ptr<Dialect> m_dialect; | 	Dialect const* m_dialect = nullptr; | ||||||
| 	std::shared_ptr<Block> m_ast; | 	std::shared_ptr<Block> m_ast; | ||||||
| 	std::shared_ptr<AsmAnalysisInfo> m_analysisInfo; | 	std::shared_ptr<AsmAnalysisInfo> m_analysisInfo; | ||||||
| 	std::string m_obtainedResult; | 	std::string m_obtainedResult; | ||||||
|  | |||||||
| @ -81,7 +81,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) | |||||||
| 		yulFuzzerUtil::interpret( | 		yulFuzzerUtil::interpret( | ||||||
| 			os1, | 			os1, | ||||||
| 			stack.parserResult()->code, | 			stack.parserResult()->code, | ||||||
| 			*EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) | 			EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
| 	catch (yul::test::StepLimitReached const&) | 	catch (yul::test::StepLimitReached const&) | ||||||
| @ -98,7 +98,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) | |||||||
| 		yulFuzzerUtil::interpret( | 		yulFuzzerUtil::interpret( | ||||||
| 			os2, | 			os2, | ||||||
| 			stack.parserResult()->code, | 			stack.parserResult()->code, | ||||||
| 			*EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), | 			EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), | ||||||
| 			(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 1.5) | 			(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 1.5) | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -79,7 +79,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | |||||||
| 		yulFuzzerUtil::interpret( | 		yulFuzzerUtil::interpret( | ||||||
| 			os1, | 			os1, | ||||||
| 			stack.parserResult()->code, | 			stack.parserResult()->code, | ||||||
| 			*EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) | 			EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
| 	catch (yul::test::StepLimitReached const&) | 	catch (yul::test::StepLimitReached const&) | ||||||
| @ -96,7 +96,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) | |||||||
| 		yulFuzzerUtil::interpret( | 		yulFuzzerUtil::interpret( | ||||||
| 			os2, | 			os2, | ||||||
| 			stack.parserResult()->code, | 			stack.parserResult()->code, | ||||||
| 			*EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), | 			EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), | ||||||
| 			(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 1.5) | 			(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 1.5) | ||||||
| 		); | 		); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -122,9 +122,9 @@ public: | |||||||
| 				return; | 				return; | ||||||
| 			if (!disambiguated) | 			if (!disambiguated) | ||||||
| 			{ | 			{ | ||||||
| 				*m_ast = boost::get<yul::Block>(Disambiguator(*m_dialect, *m_analysisInfo)(*m_ast)); | 				*m_ast = boost::get<yul::Block>(Disambiguator(m_dialect, *m_analysisInfo)(*m_ast)); | ||||||
| 				m_analysisInfo.reset(); | 				m_analysisInfo.reset(); | ||||||
| 				m_nameDispenser = make_shared<NameDispenser>(*m_dialect, *m_ast); | 				m_nameDispenser = make_shared<NameDispenser>(m_dialect, *m_ast); | ||||||
| 				disambiguated = true; | 				disambiguated = true; | ||||||
| 			} | 			} | ||||||
| 			cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl; | 			cout << "(q)quit/(f)flatten/(c)se/initialize var(d)ecls/(x)plit/(j)oin/(g)rouper/(h)oister/" << endl; | ||||||
| @ -146,16 +146,16 @@ public: | |||||||
| 				ForLoopInitRewriter{}(*m_ast); | 				ForLoopInitRewriter{}(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'c': | 			case 'c': | ||||||
| 				(CommonSubexpressionEliminator{*m_dialect})(*m_ast); | 				(CommonSubexpressionEliminator{m_dialect})(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'd': | 			case 'd': | ||||||
| 				(VarDeclInitializer{})(*m_ast); | 				(VarDeclInitializer{})(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'l': | 			case 'l': | ||||||
| 				VarNameCleaner{*m_ast, *m_dialect}(*m_ast); | 				VarNameCleaner{*m_ast, m_dialect}(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'x': | 			case 'x': | ||||||
| 				ExpressionSplitter{*m_dialect, *m_nameDispenser}(*m_ast); | 				ExpressionSplitter{m_dialect, *m_nameDispenser}(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'j': | 			case 'j': | ||||||
| 				ExpressionJoiner::run(*m_ast); | 				ExpressionJoiner::run(*m_ast); | ||||||
| @ -167,22 +167,22 @@ public: | |||||||
| 				(FunctionHoister{})(*m_ast); | 				(FunctionHoister{})(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'e': | 			case 'e': | ||||||
| 				ExpressionInliner{*m_dialect, *m_ast}.run(); | 				ExpressionInliner{m_dialect, *m_ast}.run(); | ||||||
| 				break; | 				break; | ||||||
| 			case 'i': | 			case 'i': | ||||||
| 				FullInliner(*m_ast, *m_nameDispenser).run(); | 				FullInliner(*m_ast, *m_nameDispenser).run(); | ||||||
| 				break; | 				break; | ||||||
| 			case 's': | 			case 's': | ||||||
| 				ExpressionSimplifier::run(*m_dialect, *m_ast); | 				ExpressionSimplifier::run(m_dialect, *m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 't': | 			case 't': | ||||||
| 				(StructuralSimplifier{*m_dialect})(*m_ast); | 				(StructuralSimplifier{m_dialect})(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'n': | 			case 'n': | ||||||
| 				(ControlFlowSimplifier{})(*m_ast); | 				(ControlFlowSimplifier{})(*m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'u': | 			case 'u': | ||||||
| 				UnusedPruner::runUntilStabilised(*m_dialect, *m_ast); | 				UnusedPruner::runUntilStabilised(m_dialect, *m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'D': | 			case 'D': | ||||||
| 				DeadCodeEliminator{}(*m_ast); | 				DeadCodeEliminator{}(*m_ast); | ||||||
| @ -191,10 +191,10 @@ public: | |||||||
| 				SSATransform::run(*m_ast, *m_nameDispenser); | 				SSATransform::run(*m_ast, *m_nameDispenser); | ||||||
| 				break; | 				break; | ||||||
| 			case 'r': | 			case 'r': | ||||||
| 				RedundantAssignEliminator::run(*m_dialect, *m_ast); | 				RedundantAssignEliminator::run(m_dialect, *m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'm': | 			case 'm': | ||||||
| 				Rematerialiser::run(*m_dialect, *m_ast); | 				Rematerialiser::run(m_dialect, *m_ast); | ||||||
| 				break; | 				break; | ||||||
| 			case 'v': | 			case 'v': | ||||||
| 				EquivalentFunctionCombiner::run(*m_ast); | 				EquivalentFunctionCombiner::run(*m_ast); | ||||||
| @ -215,7 +215,7 @@ public: | |||||||
| private: | private: | ||||||
| 	ErrorList m_errors; | 	ErrorList m_errors; | ||||||
| 	shared_ptr<yul::Block> m_ast; | 	shared_ptr<yul::Block> m_ast; | ||||||
| 	shared_ptr<Dialect> m_dialect{EVMDialect::strictAssemblyForEVMObjects(EVMVersion{})}; | 	Dialect const& m_dialect{EVMDialect::strictAssemblyForEVMObjects(EVMVersion{})}; | ||||||
| 	shared_ptr<AsmAnalysisInfo> m_analysisInfo; | 	shared_ptr<AsmAnalysisInfo> m_analysisInfo; | ||||||
| 	shared_ptr<NameDispenser> m_nameDispenser; | 	shared_ptr<NameDispenser> m_nameDispenser; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -88,8 +88,8 @@ void interpret(string const& _source) | |||||||
| 	InterpreterState state; | 	InterpreterState state; | ||||||
| 	state.maxTraceSize = 10000; | 	state.maxTraceSize = 10000; | ||||||
| 	state.maxMemSize = 0x20000000; | 	state.maxMemSize = 0x20000000; | ||||||
| 	shared_ptr<Dialect> dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); | 	Dialect const& dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); | ||||||
| 	Interpreter interpreter(state, *dialect); | 	Interpreter interpreter(state, dialect); | ||||||
| 	try | 	try | ||||||
| 	{ | 	{ | ||||||
| 		interpreter(*ast); | 		interpreter(*ast); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user