mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #514 from chriseth/sourceLoc
Source location for inline assembly.
This commit is contained in:
		
						commit
						dd4300d5b8
					
				| @ -26,6 +26,7 @@ | ||||
| #include <string> | ||||
| #include <ostream> | ||||
| #include <tuple> | ||||
| #include <libdevcore/Common.h> // defines noexcept macro for MSVC | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -36,24 +37,21 @@ namespace dev | ||||
|  */ | ||||
| struct SourceLocation | ||||
| { | ||||
| 	SourceLocation(): start(-1), end(-1) { } | ||||
| 	SourceLocation(int _start, int _end, std::shared_ptr<std::string const> _sourceName): | ||||
| 		start(_start), end(_end), sourceName(_sourceName) { } | ||||
| 	SourceLocation(): start(-1), end(-1) { } | ||||
| 
 | ||||
| 	SourceLocation(SourceLocation const& _other): | ||||
| 	SourceLocation(SourceLocation&& _other) noexcept: | ||||
| 		start(_other.start), | ||||
| 		end(_other.end), | ||||
| 		sourceName(_other.sourceName) | ||||
| 		sourceName(std::move(_other.sourceName)) | ||||
| 	{} | ||||
| 
 | ||||
| 	SourceLocation& operator=(SourceLocation const& _other) | ||||
| 	SourceLocation(SourceLocation const& _other) = default; | ||||
| 	SourceLocation& operator=(SourceLocation const&) = default; | ||||
| 	SourceLocation& operator=(SourceLocation&& _other) noexcept | ||||
| 	{ | ||||
| 		if (&_other == this) | ||||
| 			return *this; | ||||
| 
 | ||||
| 		start = _other.start; | ||||
| 		end = _other.end; | ||||
| 		sourceName = _other.sourceName; | ||||
| 		sourceName = std::move(_other.sourceName); | ||||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -86,8 +86,12 @@ public: | ||||
| 	void operator()(Label const& _item) | ||||
| 	{ | ||||
| 		if (m_state.labels.count(_item.name)) | ||||
| 			//@TODO location and secondary location
 | ||||
| 			m_state.addError(Error::Type::DeclarationError, "Label " + _item.name + " declared twice."); | ||||
| 			//@TODO secondary location
 | ||||
| 			m_state.addError( | ||||
| 				Error::Type::DeclarationError, | ||||
| 				"Label " + _item.name + " declared twice.", | ||||
| 				_item.location | ||||
| 			); | ||||
| 		m_state.labels.insert(make_pair(_item.name, m_state.assembly.newTag())); | ||||
| 	} | ||||
| 	void operator()(assembly::Block const& _block) | ||||
| @ -117,34 +121,43 @@ public: | ||||
| 			m_identifierAccess = [](assembly::Identifier const&, eth::Assembly&, CodeGenerator::IdentifierContext) { return false; }; | ||||
| 	} | ||||
| 
 | ||||
| 	void operator()(dev::solidity::assembly::Instruction const& _instruction) | ||||
| 	void operator()(assembly::Instruction const& _instruction) | ||||
| 	{ | ||||
| 		m_state.assembly.setSourceLocation(_instruction.location); | ||||
| 		m_state.assembly.append(_instruction.instruction); | ||||
| 	} | ||||
| 	void operator()(assembly::Literal const& _literal) | ||||
| 	{ | ||||
| 		m_state.assembly.setSourceLocation(_literal.location); | ||||
| 		if (_literal.isNumber) | ||||
| 			m_state.assembly.append(u256(_literal.value)); | ||||
| 		else if (_literal.value.size() > 32) | ||||
| 		{ | ||||
| 			m_state.addError( | ||||
| 				Error::Type::TypeError, | ||||
| 				"String literal too long (" + boost::lexical_cast<string>(_literal.value.size()) + " > 32)" | ||||
| 			); | ||||
| 			m_state.assembly.append(u256(0)); | ||||
| 		} | ||||
| 		else | ||||
| 			m_state.assembly.append(_literal.value); | ||||
| 	} | ||||
| 	void operator()(assembly::Identifier const& _identifier) | ||||
| 	{ | ||||
| 		m_state.assembly.setSourceLocation(_identifier.location); | ||||
| 		// First search local variables, then labels, then externals.
 | ||||
| 		if (int const* stackHeight = m_state.findVariable(_identifier.name)) | ||||
| 		{ | ||||
| 			int heightDiff = m_state.assembly.deposit() - *stackHeight; | ||||
| 			if (heightDiff <= 0 || heightDiff > 16) | ||||
| 				//@TODO location
 | ||||
| 			{ | ||||
| 				m_state.addError( | ||||
| 					Error::Type::TypeError, | ||||
| 					"Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")" | ||||
| 					"Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")", | ||||
| 					_identifier.location | ||||
| 				); | ||||
| 				m_state.assembly.append(u256(0)); | ||||
| 			} | ||||
| 			else | ||||
| 				m_state.assembly.append(solidity::dupInstruction(heightDiff)); | ||||
| 			return; | ||||
| @ -152,10 +165,14 @@ public: | ||||
| 		else if (eth::AssemblyItem const* label = m_state.findLabel(_identifier.name)) | ||||
| 			m_state.assembly.append(label->pushTag()); | ||||
| 		else if (!m_identifierAccess(_identifier, m_state.assembly, CodeGenerator::IdentifierContext::RValue)) | ||||
| 		{ | ||||
| 			m_state.addError( | ||||
| 				Error::Type::DeclarationError, | ||||
| 				"Identifier \"" + string(_identifier.name) + "\" not found or not unique" | ||||
| 				"Identifier not found or not unique", | ||||
| 				_identifier.location | ||||
| 			); | ||||
| 			m_state.assembly.append(u256(0)); | ||||
| 		} | ||||
| 	} | ||||
| 	void operator()(FunctionalInstruction const& _instr) | ||||
| 	{ | ||||
| @ -163,30 +180,33 @@ public: | ||||
| 		{ | ||||
| 			int height = m_state.assembly.deposit(); | ||||
| 			boost::apply_visitor(*this, *it); | ||||
| 			expectDeposit(1, height); | ||||
| 			expectDeposit(1, height, locationOf(*it)); | ||||
| 		} | ||||
| 		(*this)(_instr.instruction); | ||||
| 	} | ||||
| 	void operator()(Label const& _label) | ||||
| 	{ | ||||
| 		m_state.assembly.setSourceLocation(_label.location); | ||||
| 		m_state.assembly.append(m_state.labels.at(_label.name)); | ||||
| 	} | ||||
| 	void operator()(assembly::Assignment const& _assignment) | ||||
| 	{ | ||||
| 		generateAssignment(_assignment.variableName); | ||||
| 		m_state.assembly.setSourceLocation(_assignment.location); | ||||
| 		generateAssignment(_assignment.variableName, _assignment.location); | ||||
| 	} | ||||
| 	void operator()(FunctionalAssignment const& _assignment) | ||||
| 	{ | ||||
| 		int height = m_state.assembly.deposit(); | ||||
| 		boost::apply_visitor(*this, *_assignment.value); | ||||
| 		expectDeposit(1, height); | ||||
| 		generateAssignment(_assignment.variableName); | ||||
| 		expectDeposit(1, height, locationOf(*_assignment.value)); | ||||
| 		m_state.assembly.setSourceLocation(_assignment.location); | ||||
| 		generateAssignment(_assignment.variableName, _assignment.location); | ||||
| 	} | ||||
| 	void operator()(assembly::VariableDeclaration const& _varDecl) | ||||
| 	{ | ||||
| 		int height = m_state.assembly.deposit(); | ||||
| 		boost::apply_visitor(*this, *_varDecl.value); | ||||
| 		expectDeposit(1, height); | ||||
| 		expectDeposit(1, height, locationOf(*_varDecl.value)); | ||||
| 		m_state.variables.push_back(make_pair(_varDecl.name, height)); | ||||
| 	} | ||||
| 	void operator()(assembly::Block const& _block) | ||||
| @ -194,7 +214,8 @@ public: | ||||
| 		size_t numVariables = m_state.variables.size(); | ||||
| 		std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); | ||||
| 		// pop variables
 | ||||
| 		//@TODO check height before and after
 | ||||
| 		// we deliberately do not check stack height
 | ||||
| 		m_state.assembly.setSourceLocation(_block.location); | ||||
| 		while (m_state.variables.size() > numVariables) | ||||
| 		{ | ||||
| 			m_state.assembly.append(solidity::Instruction::POP); | ||||
| @ -203,22 +224,20 @@ public: | ||||
| 	} | ||||
| 
 | ||||
| private: | ||||
| 	void generateAssignment(assembly::Identifier const& _variableName) | ||||
| 	void generateAssignment(assembly::Identifier const& _variableName, SourceLocation const& _location) | ||||
| 	{ | ||||
| 		if (int const* stackHeight = m_state.findVariable(_variableName.name)) | ||||
| 		{ | ||||
| 			int heightDiff = m_state.assembly.deposit() - *stackHeight - 1; | ||||
| 			if (heightDiff <= 0 || heightDiff > 16) | ||||
| 				//@TODO location
 | ||||
| 				m_state.addError( | ||||
| 					Error::Type::TypeError, | ||||
| 					"Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")" | ||||
| 					"Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")", | ||||
| 					_location | ||||
| 				); | ||||
| 			else | ||||
| 			{ | ||||
| 				m_state.assembly.append(solidity::swapInstruction(heightDiff)); | ||||
| 				m_state.assembly.append(solidity::Instruction::POP); | ||||
| 			} | ||||
| 			m_state.assembly.append(solidity::Instruction::POP); | ||||
| 			return; | ||||
| 		} | ||||
| 		else if (!m_identifierAccess(_variableName, m_state.assembly, CodeGenerator::IdentifierContext::LValue)) | ||||
| @ -228,16 +247,16 @@ private: | ||||
| 			); | ||||
| 	} | ||||
| 
 | ||||
| 	void expectDeposit(int _deposit, int _oldHeight) | ||||
| 	void expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location) | ||||
| 	{ | ||||
| 		if (m_state.assembly.deposit() != _oldHeight + 1) | ||||
| 			//@TODO location
 | ||||
| 			m_state.addError(Error::Type::TypeError, | ||||
| 				"Expected instruction(s) to deposit " + | ||||
| 				boost::lexical_cast<string>(_deposit) + | ||||
| 				" item(s) to the stack, but did deposit " + | ||||
| 				boost::lexical_cast<string>(m_state.assembly.deposit() - _oldHeight) + | ||||
| 				" item(s)." | ||||
| 				" item(s).", | ||||
| 				_location | ||||
| 			); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -48,7 +48,7 @@ public: | ||||
| 	/// If in rvalue context, the function is assumed to append instructions to
 | ||||
| 	/// push the value of the identifier onto the stack. On error, the function should return false.
 | ||||
| 	using IdentifierAccess = std::function<bool(assembly::Identifier const&, eth::Assembly&, IdentifierContext)>; | ||||
| 	CodeGenerator( Block const& _parsedData, ErrorList& _errors): | ||||
| 	CodeGenerator(Block const& _parsedData, ErrorList& _errors): | ||||
| 		m_parsedData(_parsedData), m_errors(_errors) {} | ||||
| 	/// Performs type checks and @returns false on error.
 | ||||
| 	/// Actually runs the full code generation but discards the result.
 | ||||
|  | ||||
| @ -24,6 +24,7 @@ | ||||
| 
 | ||||
| #include <boost/variant.hpp> | ||||
| #include <libevmasm/Instruction.h> | ||||
| #include <libevmasm/SourceLocation.h> | ||||
| 
 | ||||
| namespace dev | ||||
| { | ||||
| @ -35,29 +36,43 @@ namespace assembly | ||||
| /// What follows are the AST nodes for assembly.
 | ||||
| 
 | ||||
| /// Direct EVM instruction (except PUSHi and JUMPDEST)
 | ||||
| struct Instruction { solidity::Instruction instruction; }; | ||||
| struct Instruction { SourceLocation location; solidity::Instruction instruction; }; | ||||
| /// Literal number or string (up to 32 bytes)
 | ||||
| struct Literal { bool isNumber; std::string value; }; | ||||
| struct Literal { SourceLocation location; bool isNumber; std::string value; }; | ||||
| /// External / internal identifier or label reference
 | ||||
| struct Identifier { std::string name; }; | ||||
| struct Identifier { SourceLocation location; std::string name; }; | ||||
| struct FunctionalInstruction; | ||||
| /// Jump label ("name:")
 | ||||
| struct Label { std::string name; }; | ||||
| struct Label { SourceLocation location; std::string name; }; | ||||
| /// Assignemnt (":= x", moves stack top into x, potentially multiple slots)
 | ||||
| struct Assignment { Identifier variableName; }; | ||||
| struct Assignment { SourceLocation location; Identifier variableName; }; | ||||
| struct FunctionalAssignment; | ||||
| struct VariableDeclaration; | ||||
| struct Block; | ||||
| using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionalInstruction, VariableDeclaration, 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 { Identifier variableName; std::shared_ptr<Statement> value; }; | ||||
| struct FunctionalAssignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; }; | ||||
| /// Functional instruction, e.g. "mul(mload(20), add(2, x))"
 | ||||
| struct FunctionalInstruction { Instruction instruction; std::vector<Statement> arguments; }; | ||||
| struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; }; | ||||
| /// Block-scope variable declaration ("let x := mload(20)"), non-hoisted
 | ||||
| struct VariableDeclaration { std::string name; std::shared_ptr<Statement> value; }; | ||||
| struct VariableDeclaration { SourceLocation location; std::string name; std::shared_ptr<Statement> value; }; | ||||
| /// Block that creates a scope (frees declared stack variables)
 | ||||
| struct Block { std::vector<Statement> statements; }; | ||||
| struct Block { SourceLocation location; std::vector<Statement> statements; }; | ||||
| 
 | ||||
| struct LocationExtractor: boost::static_visitor<SourceLocation> | ||||
| { | ||||
| 	template <class T> SourceLocation operator()(T const& _node) const | ||||
| 	{ | ||||
| 		return _node.location; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| /// Extracts the source location from an inline assembly node.
 | ||||
| template <class T> inline SourceLocation locationOf(T const& _node) | ||||
| { | ||||
| 	return boost::apply_visitor(LocationExtractor(), _node); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -35,7 +35,7 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann | ||||
| 	try | ||||
| 	{ | ||||
| 		m_scanner = _scanner; | ||||
| 		return make_shared<assembly::Block>(parseBlock()); | ||||
| 		return make_shared<Block>(parseBlock()); | ||||
| 	} | ||||
| 	catch (FatalError const&) | ||||
| 	{ | ||||
| @ -47,10 +47,11 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann | ||||
| 
 | ||||
| assembly::Block Parser::parseBlock() | ||||
| { | ||||
| 	assembly::Block block = createWithLocation<Block>(); | ||||
| 	expectToken(Token::LBrace); | ||||
| 	Block block; | ||||
| 	while (m_scanner->currentToken() != Token::RBrace) | ||||
| 		block.statements.emplace_back(parseStatement()); | ||||
| 	block.location.end = endPosition(); | ||||
| 	m_scanner->next(); | ||||
| 	return block; | ||||
| } | ||||
| @ -65,11 +66,14 @@ assembly::Statement Parser::parseStatement() | ||||
| 		return parseBlock(); | ||||
| 	case Token::Assign: | ||||
| 	{ | ||||
| 		assembly::Assignment assignment = createWithLocation<assembly::Assignment>(); | ||||
| 		m_scanner->next(); | ||||
| 		expectToken(Token::Colon); | ||||
| 		string name = m_scanner->currentLiteral(); | ||||
| 		assignment.variableName.location = location(); | ||||
| 		assignment.variableName.name = m_scanner->currentLiteral(); | ||||
| 		assignment.location.end = endPosition(); | ||||
| 		expectToken(Token::Identifier); | ||||
| 		return assembly::Assignment{assembly::Identifier{name}}; | ||||
| 		return assignment; | ||||
| 	} | ||||
| 	case Token::Return: // opcode
 | ||||
| 	case Token::Byte: // opcode
 | ||||
| @ -84,24 +88,30 @@ assembly::Statement Parser::parseStatement() | ||||
| 	switch (m_scanner->currentToken()) | ||||
| 	{ | ||||
| 	case Token::LParen: | ||||
| 		return parseFunctionalInstruction(statement); | ||||
| 		return parseFunctionalInstruction(std::move(statement)); | ||||
| 	case Token::Colon: | ||||
| 	{ | ||||
| 		if (statement.type() != typeid(assembly::Identifier)) | ||||
| 			fatalParserError("Label name / variable name must precede \":\"."); | ||||
| 		string const& name = boost::get<assembly::Identifier>(statement).name; | ||||
| 		assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); | ||||
| 		m_scanner->next(); | ||||
| 		if (m_scanner->currentToken() == Token::Assign) | ||||
| 		{ | ||||
| 			// functional assignment
 | ||||
| 			FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location); | ||||
| 			m_scanner->next(); | ||||
| 			unique_ptr<Statement> value; | ||||
| 			value.reset(new Statement(parseExpression())); | ||||
| 			return FunctionalAssignment{{std::move(name)}, std::move(value)}; | ||||
| 			funAss.variableName = identifier; | ||||
| 			funAss.value.reset(new Statement(parseExpression())); | ||||
| 			funAss.location.end = locationOf(*funAss.value).end; | ||||
| 			return funAss; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// label
 | ||||
| 			return Label{name}; | ||||
| 			Label label = createWithLocation<Label>(identifier.location); | ||||
| 			label.name = identifier.name; | ||||
| 			return label; | ||||
| 		} | ||||
| 	} | ||||
| 	default: | ||||
| 		break; | ||||
| @ -113,7 +123,7 @@ assembly::Statement Parser::parseExpression() | ||||
| { | ||||
| 	Statement operation = parseElementaryOperation(true); | ||||
| 	if (m_scanner->currentToken() == Token::LParen) | ||||
| 		return parseFunctionalInstruction(operation); | ||||
| 		return parseFunctionalInstruction(std::move(operation)); | ||||
| 	else | ||||
| 		return operation; | ||||
| } | ||||
| @ -137,8 +147,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) | ||||
| 			s_instructions[name] = instruction.second; | ||||
| 		} | ||||
| 
 | ||||
| 	//@TODO track location
 | ||||
| 
 | ||||
| 	Statement ret; | ||||
| 	switch (m_scanner->currentToken()) | ||||
| 	{ | ||||
| 	case Token::Identifier: | ||||
| @ -162,48 +171,50 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) | ||||
| 				if (info.ret != 1) | ||||
| 					fatalParserError("Instruction " + info.name + " not allowed in this context."); | ||||
| 			} | ||||
| 			m_scanner->next(); | ||||
| 			return Instruction{instr}; | ||||
| 			ret = Instruction{location(), instr}; | ||||
| 		} | ||||
| 		else | ||||
| 			m_scanner->next(); | ||||
| 			return Identifier{literal}; | ||||
| 			ret = Identifier{location(), literal}; | ||||
| 		break; | ||||
| 	} | ||||
| 	case Token::StringLiteral: | ||||
| 	case Token::Number: | ||||
| 	{ | ||||
| 		Literal literal{ | ||||
| 		ret = Literal{ | ||||
| 			location(), | ||||
| 			m_scanner->currentToken() == Token::Number, | ||||
| 			m_scanner->currentLiteral() | ||||
| 		}; | ||||
| 		m_scanner->next(); | ||||
| 		return literal; | ||||
| 	} | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 	fatalParserError("Expected elementary inline assembly operation."); | ||||
| 	return {}; | ||||
| 	default: | ||||
| 		fatalParserError("Expected elementary inline assembly operation."); | ||||
| 	} | ||||
| 	m_scanner->next(); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| assembly::VariableDeclaration Parser::parseVariableDeclaration() | ||||
| { | ||||
| 	VariableDeclaration varDecl = createWithLocation<VariableDeclaration>(); | ||||
| 	expectToken(Token::Let); | ||||
| 	string name = m_scanner->currentLiteral(); | ||||
| 	varDecl.name = m_scanner->currentLiteral(); | ||||
| 	expectToken(Token::Identifier); | ||||
| 	expectToken(Token::Colon); | ||||
| 	expectToken(Token::Assign); | ||||
| 	unique_ptr<Statement> value; | ||||
| 	value.reset(new Statement(parseExpression())); | ||||
| 	return VariableDeclaration{name, std::move(value)}; | ||||
| 	varDecl.value.reset(new Statement(parseExpression())); | ||||
| 	varDecl.location.end = locationOf(*varDecl.value).end; | ||||
| 	return varDecl; | ||||
| } | ||||
| 
 | ||||
| FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement const& _instruction) | ||||
| FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction) | ||||
| { | ||||
| 	if (_instruction.type() != typeid(Instruction)) | ||||
| 		fatalParserError("Assembly instruction required in front of \"(\")"); | ||||
| 	solidity::Instruction instr = boost::get<solidity::assembly::Instruction>(_instruction).instruction; | ||||
| 	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"); | ||||
| @ -211,14 +222,29 @@ FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement con | ||||
| 		fatalParserError("SWAPi instructions not allowed for functional notation"); | ||||
| 
 | ||||
| 	expectToken(Token::LParen); | ||||
| 	vector<Statement> arguments; | ||||
| 	unsigned args = unsigned(instrInfo.args); | ||||
| 	for (unsigned i = 0; i < args; ++i) | ||||
| 	{ | ||||
| 		arguments.push_back(parseExpression()); | ||||
| 		ret.arguments.emplace_back(parseExpression()); | ||||
| 		if (i != args - 1) | ||||
| 			expectToken(Token::Comma); | ||||
| 		{ | ||||
| 			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 FunctionalInstruction{{instr}, std::move(arguments)}; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -44,13 +44,29 @@ public: | ||||
| 	std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner); | ||||
| 
 | ||||
| protected: | ||||
| 	/// Creates an inline assembly node with the given source location.
 | ||||
| 	template <class T> T createWithLocation(SourceLocation const& _loc = SourceLocation()) | ||||
| 	{ | ||||
| 		T r; | ||||
| 		r.location = _loc; | ||||
| 		if (r.location.isEmpty()) | ||||
| 		{ | ||||
| 			r.location.start = position(); | ||||
| 			r.location.end = endPosition(); | ||||
| 		} | ||||
| 		if (!r.location.sourceName) | ||||
| 			r.location.sourceName = sourceName(); | ||||
| 		return r; | ||||
| 	} | ||||
| 	SourceLocation location() const { return SourceLocation(position(), endPosition(), sourceName()); } | ||||
| 
 | ||||
| 	Block parseBlock(); | ||||
| 	Statement parseStatement(); | ||||
| 	/// Parses a functional expression that has to push exactly one stack element
 | ||||
| 	Statement parseExpression(); | ||||
| 	Statement parseElementaryOperation(bool _onlySinglePusher = false); | ||||
| 	VariableDeclaration parseVariableDeclaration(); | ||||
| 	FunctionalInstruction parseFunctionalInstruction(Statement const& _instruction); | ||||
| 	FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -34,14 +34,18 @@ using namespace dev::solidity::assembly; | ||||
| 
 | ||||
| bool InlineAssemblyStack::parse(const std::shared_ptr<Scanner>& _scanner) | ||||
| { | ||||
| 	m_parserResult = make_shared<Block>(); | ||||
| 	Parser parser(m_errors); | ||||
| 	m_asmBlock = parser.parse(_scanner); | ||||
| 	return !!m_asmBlock; | ||||
| 	auto result = parser.parse(_scanner); | ||||
| 	if (!result) | ||||
| 		return false; | ||||
| 	*m_parserResult = std::move(*result); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| eth::Assembly InlineAssemblyStack::assemble() | ||||
| { | ||||
| 	CodeGenerator codeGen(*m_asmBlock, m_errors); | ||||
| 	CodeGenerator codeGen(*m_parserResult, m_errors); | ||||
| 	return codeGen.assemble(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -50,7 +50,7 @@ public: | ||||
| 	ErrorList const& errors() const { return m_errors; } | ||||
| 
 | ||||
| private: | ||||
| 	std::shared_ptr<Block> m_asmBlock; | ||||
| 	std::shared_ptr<Block> m_parserResult; | ||||
| 	ErrorList m_errors; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -861,7 +861,7 @@ void CommandLineInterface::outputAssembly() | ||||
| 		cout << endl << "======= " << src.first << " =======" << endl; | ||||
| 		eth::Assembly assembly = m_assemblyStacks[src.first].assemble(); | ||||
| 		cout << assembly.assemble().toHex() << endl; | ||||
| 		cout << assembly.out(); | ||||
| 		assembly.stream(cout, "", m_sourceCodes); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user