mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Parsing function calls.
This commit is contained in:
		
							parent
							
								
									5d584aded8
								
							
						
					
					
						commit
						49a919b3e0
					
				| @ -190,6 +190,10 @@ public: | ||||
| 		} | ||||
| 		(*this)(_instr.instruction); | ||||
| 	} | ||||
| 	void operator()(assembly::FunctionCall const&) | ||||
| 	{ | ||||
| 		solAssert(false, "Function call not removed during desugaring phase."); | ||||
| 	} | ||||
| 	void operator()(Label const& _label) | ||||
| 	{ | ||||
| 		m_state.assembly.setSourceLocation(_label.location); | ||||
|  | ||||
| @ -49,13 +49,15 @@ struct Assignment { SourceLocation location; Identifier variableName; }; | ||||
| struct FunctionalAssignment; | ||||
| struct VariableDeclaration; | ||||
| struct FunctionDefinition; | ||||
| struct FunctionCall; | ||||
| struct Block; | ||||
| using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>; | ||||
| using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>; | ||||
| /// Functional assignment ("x := mload(20)", expects push-1-expression on the right hand
 | ||||
| /// side and requires x to occupy exactly one stack slot.
 | ||||
| struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; }; | ||||
| /// Functional instruction, e.g. "mul(mload(20), add(2, x))"
 | ||||
| struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; }; | ||||
| struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; }; | ||||
| /// Block-scope variable declaration ("let x := mload(20)"), non-hoisted
 | ||||
| struct VariableDeclaration { SourceLocation location; std::string name; std::shared_ptr<Statement> value; }; | ||||
| /// Block that creates a scope (frees declared stack variables)
 | ||||
|  | ||||
| @ -257,46 +257,67 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() | ||||
| 	return funDef; | ||||
| } | ||||
| 
 | ||||
| FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction) | ||||
| assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction) | ||||
| { | ||||
| 	if (_instruction.type() != typeid(Instruction)) | ||||
| 		fatalParserError("Assembly instruction required in front of \"(\")"); | ||||
| 	FunctionalInstruction ret; | ||||
| 	ret.instruction = std::move(boost::get<Instruction>(_instruction)); | ||||
| 	ret.location = ret.instruction.location; | ||||
| 	solidity::Instruction instr = ret.instruction.instruction; | ||||
| 	InstructionInfo instrInfo = instructionInfo(instr); | ||||
| 	if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16) | ||||
| 		fatalParserError("DUPi instructions not allowed for functional notation"); | ||||
| 	if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16) | ||||
| 		fatalParserError("SWAPi instructions not allowed for functional notation"); | ||||
| 
 | ||||
| 	expectToken(Token::LParen); | ||||
| 	unsigned args = unsigned(instrInfo.args); | ||||
| 	for (unsigned i = 0; i < args; ++i) | ||||
| 	if (_instruction.type() == typeid(Instruction)) | ||||
| 	{ | ||||
| 		ret.arguments.emplace_back(parseExpression()); | ||||
| 		if (i != args - 1) | ||||
| 		FunctionalInstruction ret; | ||||
| 		ret.instruction = std::move(boost::get<Instruction>(_instruction)); | ||||
| 		ret.location = ret.instruction.location; | ||||
| 		solidity::Instruction instr = ret.instruction.instruction; | ||||
| 		InstructionInfo instrInfo = instructionInfo(instr); | ||||
| 		if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16) | ||||
| 			fatalParserError("DUPi instructions not allowed for functional notation"); | ||||
| 		if (solidity::Instruction::SWAP1 <= instr && instr <= solidity::Instruction::SWAP16) | ||||
| 			fatalParserError("SWAPi instructions not allowed for functional notation"); | ||||
| 		expectToken(Token::LParen); | ||||
| 		unsigned args = unsigned(instrInfo.args); | ||||
| 		for (unsigned i = 0; i < args; ++i) | ||||
| 		{ | ||||
| 			if (m_scanner->currentToken() != Token::Comma) | ||||
| 				fatalParserError(string( | ||||
| 					"Expected comma (" + | ||||
| 					instrInfo.name + | ||||
| 					" expects " + | ||||
| 					boost::lexical_cast<string>(args) + | ||||
| 					" arguments)" | ||||
| 				)); | ||||
| 			else | ||||
| 				m_scanner->next(); | ||||
| 			ret.arguments.emplace_back(parseExpression()); | ||||
| 			if (i != args - 1) | ||||
| 			{ | ||||
| 				if (m_scanner->currentToken() != Token::Comma) | ||||
| 					fatalParserError(string( | ||||
| 						"Expected comma (" + | ||||
| 						instrInfo.name + | ||||
| 						" expects " + | ||||
| 						boost::lexical_cast<string>(args) + | ||||
| 						" arguments)" | ||||
| 					)); | ||||
| 				else | ||||
| 					m_scanner->next(); | ||||
| 			} | ||||
| 		} | ||||
| 		ret.location.end = endPosition(); | ||||
| 		if (m_scanner->currentToken() == Token::Comma) | ||||
| 			fatalParserError( | ||||
| 				string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)") | ||||
| 			); | ||||
| 		expectToken(Token::RParen); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ret.location.end = endPosition(); | ||||
| 	if (m_scanner->currentToken() == Token::Comma) | ||||
| 		fatalParserError( | ||||
| 			string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)") | ||||
| 		); | ||||
| 	expectToken(Token::RParen); | ||||
| 	return ret; | ||||
| 	else if (_instruction.type() == typeid(Identifier)) | ||||
| 	{ | ||||
| 		FunctionCall ret; | ||||
| 		ret.functionName = std::move(boost::get<Identifier>(_instruction)); | ||||
| 		ret.location = ret.functionName.location; | ||||
| 		expectToken(Token::LParen); | ||||
| 		while (m_scanner->currentToken() != Token::RParen) | ||||
| 		{ | ||||
| 			ret.arguments.emplace_back(parseExpression()); | ||||
| 			if (m_scanner->currentToken() == Token::RParen) | ||||
| 				break; | ||||
| 			expectToken(Token::Comma); | ||||
| 		} | ||||
| 		ret.location.end = endPosition(); | ||||
| 		expectToken(Token::RParen); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	else | ||||
| 		fatalParserError("Assembly instruction or function name required in front of \"(\")"); | ||||
| 
 | ||||
| 	return {}; | ||||
| } | ||||
| 
 | ||||
| string Parser::expectAsmIdentifier() | ||||
|  | ||||
| @ -68,7 +68,7 @@ protected: | ||||
| 	Statement parseElementaryOperation(bool _onlySinglePusher = false); | ||||
| 	VariableDeclaration parseVariableDeclaration(); | ||||
| 	FunctionDefinition parseFunctionDefinition(); | ||||
| 	FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction); | ||||
| 	Statement parseFunctionalInstruction(Statement&& _instruction); | ||||
| 	std::string expectAsmIdentifier(); | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -169,6 +169,11 @@ BOOST_AUTO_TEST_CASE(function_definitions_multiple_args) | ||||
| 	BOOST_CHECK(successParse("{ function f(a, d) { } function g(a, d) -> (x, y) { } }")); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(function_calls) | ||||
| { | ||||
| 	BOOST_CHECK(successParse("{ g(1, 2, f(mul(2, 3))) x() }")); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(Printing) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user