Merge pull request #514 from chriseth/sourceLoc

Source location for inline assembly.
This commit is contained in:
chriseth 2016-04-22 19:28:28 +02:00
commit dd4300d5b8
9 changed files with 159 additions and 81 deletions

View File

@ -26,6 +26,7 @@
#include <string> #include <string>
#include <ostream> #include <ostream>
#include <tuple> #include <tuple>
#include <libdevcore/Common.h> // defines noexcept macro for MSVC
namespace dev namespace dev
{ {
@ -36,24 +37,21 @@ namespace dev
*/ */
struct SourceLocation struct SourceLocation
{ {
SourceLocation(): start(-1), end(-1) { }
SourceLocation(int _start, int _end, std::shared_ptr<std::string const> _sourceName): SourceLocation(int _start, int _end, std::shared_ptr<std::string const> _sourceName):
start(_start), end(_end), sourceName(_sourceName) { } start(_start), end(_end), sourceName(_sourceName) { }
SourceLocation(): start(-1), end(-1) { } SourceLocation(SourceLocation&& _other) noexcept:
SourceLocation(SourceLocation const& _other):
start(_other.start), start(_other.start),
end(_other.end), end(_other.end),
sourceName(_other.sourceName) sourceName(std::move(_other.sourceName))
{} {}
SourceLocation(SourceLocation const& _other) = default;
SourceLocation& operator=(SourceLocation const& _other) SourceLocation& operator=(SourceLocation const&) = default;
SourceLocation& operator=(SourceLocation&& _other) noexcept
{ {
if (&_other == this)
return *this;
start = _other.start; start = _other.start;
end = _other.end; end = _other.end;
sourceName = _other.sourceName; sourceName = std::move(_other.sourceName);
return *this; return *this;
} }

View File

@ -86,8 +86,12 @@ public:
void operator()(Label const& _item) void operator()(Label const& _item)
{ {
if (m_state.labels.count(_item.name)) if (m_state.labels.count(_item.name))
//@TODO location and secondary location //@TODO secondary location
m_state.addError(Error::Type::DeclarationError, "Label " + _item.name + " declared twice."); 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())); m_state.labels.insert(make_pair(_item.name, m_state.assembly.newTag()));
} }
void operator()(assembly::Block const& _block) void operator()(assembly::Block const& _block)
@ -117,34 +121,43 @@ public:
m_identifierAccess = [](assembly::Identifier const&, eth::Assembly&, CodeGenerator::IdentifierContext) { return false; }; 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); m_state.assembly.append(_instruction.instruction);
} }
void operator()(assembly::Literal const& _literal) void operator()(assembly::Literal const& _literal)
{ {
m_state.assembly.setSourceLocation(_literal.location);
if (_literal.isNumber) if (_literal.isNumber)
m_state.assembly.append(u256(_literal.value)); m_state.assembly.append(u256(_literal.value));
else if (_literal.value.size() > 32) else if (_literal.value.size() > 32)
{
m_state.addError( m_state.addError(
Error::Type::TypeError, Error::Type::TypeError,
"String literal too long (" + boost::lexical_cast<string>(_literal.value.size()) + " > 32)" "String literal too long (" + boost::lexical_cast<string>(_literal.value.size()) + " > 32)"
); );
m_state.assembly.append(u256(0));
}
else else
m_state.assembly.append(_literal.value); m_state.assembly.append(_literal.value);
} }
void operator()(assembly::Identifier const& _identifier) void operator()(assembly::Identifier const& _identifier)
{ {
m_state.assembly.setSourceLocation(_identifier.location);
// First search local variables, then labels, then externals. // First search local variables, then labels, then externals.
if (int const* stackHeight = m_state.findVariable(_identifier.name)) if (int const* stackHeight = m_state.findVariable(_identifier.name))
{ {
int heightDiff = m_state.assembly.deposit() - *stackHeight; int heightDiff = m_state.assembly.deposit() - *stackHeight;
if (heightDiff <= 0 || heightDiff > 16) if (heightDiff <= 0 || heightDiff > 16)
//@TODO location {
m_state.addError( m_state.addError(
Error::Type::TypeError, 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 else
m_state.assembly.append(solidity::dupInstruction(heightDiff)); m_state.assembly.append(solidity::dupInstruction(heightDiff));
return; return;
@ -152,10 +165,14 @@ public:
else if (eth::AssemblyItem const* label = m_state.findLabel(_identifier.name)) else if (eth::AssemblyItem const* label = m_state.findLabel(_identifier.name))
m_state.assembly.append(label->pushTag()); m_state.assembly.append(label->pushTag());
else if (!m_identifierAccess(_identifier, m_state.assembly, CodeGenerator::IdentifierContext::RValue)) else if (!m_identifierAccess(_identifier, m_state.assembly, CodeGenerator::IdentifierContext::RValue))
{
m_state.addError( m_state.addError(
Error::Type::DeclarationError, 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) void operator()(FunctionalInstruction const& _instr)
{ {
@ -163,30 +180,33 @@ public:
{ {
int height = m_state.assembly.deposit(); int height = m_state.assembly.deposit();
boost::apply_visitor(*this, *it); boost::apply_visitor(*this, *it);
expectDeposit(1, height); expectDeposit(1, height, locationOf(*it));
} }
(*this)(_instr.instruction); (*this)(_instr.instruction);
} }
void operator()(Label const& _label) void operator()(Label const& _label)
{ {
m_state.assembly.setSourceLocation(_label.location);
m_state.assembly.append(m_state.labels.at(_label.name)); m_state.assembly.append(m_state.labels.at(_label.name));
} }
void operator()(assembly::Assignment const& _assignment) 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) void operator()(FunctionalAssignment const& _assignment)
{ {
int height = m_state.assembly.deposit(); int height = m_state.assembly.deposit();
boost::apply_visitor(*this, *_assignment.value); boost::apply_visitor(*this, *_assignment.value);
expectDeposit(1, height); expectDeposit(1, height, locationOf(*_assignment.value));
generateAssignment(_assignment.variableName); m_state.assembly.setSourceLocation(_assignment.location);
generateAssignment(_assignment.variableName, _assignment.location);
} }
void operator()(assembly::VariableDeclaration const& _varDecl) void operator()(assembly::VariableDeclaration const& _varDecl)
{ {
int height = m_state.assembly.deposit(); int height = m_state.assembly.deposit();
boost::apply_visitor(*this, *_varDecl.value); 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)); m_state.variables.push_back(make_pair(_varDecl.name, height));
} }
void operator()(assembly::Block const& _block) void operator()(assembly::Block const& _block)
@ -194,7 +214,8 @@ public:
size_t numVariables = m_state.variables.size(); size_t numVariables = m_state.variables.size();
std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this));
// pop variables // 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) while (m_state.variables.size() > numVariables)
{ {
m_state.assembly.append(solidity::Instruction::POP); m_state.assembly.append(solidity::Instruction::POP);
@ -203,22 +224,20 @@ public:
} }
private: 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)) if (int const* stackHeight = m_state.findVariable(_variableName.name))
{ {
int heightDiff = m_state.assembly.deposit() - *stackHeight - 1; int heightDiff = m_state.assembly.deposit() - *stackHeight - 1;
if (heightDiff <= 0 || heightDiff > 16) if (heightDiff <= 0 || heightDiff > 16)
//@TODO location
m_state.addError( m_state.addError(
Error::Type::TypeError, 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 else
{
m_state.assembly.append(solidity::swapInstruction(heightDiff)); m_state.assembly.append(solidity::swapInstruction(heightDiff));
m_state.assembly.append(solidity::Instruction::POP); m_state.assembly.append(solidity::Instruction::POP);
}
return; return;
} }
else if (!m_identifierAccess(_variableName, m_state.assembly, CodeGenerator::IdentifierContext::LValue)) 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) if (m_state.assembly.deposit() != _oldHeight + 1)
//@TODO location
m_state.addError(Error::Type::TypeError, m_state.addError(Error::Type::TypeError,
"Expected instruction(s) to deposit " + "Expected instruction(s) to deposit " +
boost::lexical_cast<string>(_deposit) + boost::lexical_cast<string>(_deposit) +
" item(s) to the stack, but did deposit " + " item(s) to the stack, but did deposit " +
boost::lexical_cast<string>(m_state.assembly.deposit() - _oldHeight) + boost::lexical_cast<string>(m_state.assembly.deposit() - _oldHeight) +
" item(s)." " item(s).",
_location
); );
} }

View File

@ -48,7 +48,7 @@ public:
/// If in rvalue context, the function is assumed to append instructions to /// 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. /// 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)>; 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) {} m_parsedData(_parsedData), m_errors(_errors) {}
/// Performs type checks and @returns false on error. /// Performs type checks and @returns false on error.
/// Actually runs the full code generation but discards the result. /// Actually runs the full code generation but discards the result.

View File

@ -24,6 +24,7 @@
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <libevmasm/Instruction.h> #include <libevmasm/Instruction.h>
#include <libevmasm/SourceLocation.h>
namespace dev namespace dev
{ {
@ -35,29 +36,43 @@ namespace assembly
/// What follows are the AST nodes for assembly. /// What follows are the AST nodes for assembly.
/// Direct EVM instruction (except PUSHi and JUMPDEST) /// 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) /// 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 /// External / internal identifier or label reference
struct Identifier { std::string name; }; struct Identifier { SourceLocation location; std::string name; };
struct FunctionalInstruction; struct FunctionalInstruction;
/// Jump label ("name:") /// 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) /// Assignemnt (":= x", moves stack top into x, potentially multiple slots)
struct Assignment { Identifier variableName; }; struct Assignment { SourceLocation location; Identifier variableName; };
struct FunctionalAssignment; struct FunctionalAssignment;
struct VariableDeclaration; struct VariableDeclaration;
struct Block; struct Block;
using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionalInstruction, VariableDeclaration, 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 /// Functional assignment ("x := mload(20)", expects push-1-expression on the right hand
/// side and requires x to occupy exactly one stack slot. /// 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))" /// 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 /// 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) /// 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);
}
} }
} }

View File

@ -35,7 +35,7 @@ shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scann
try try
{ {
m_scanner = _scanner; m_scanner = _scanner;
return make_shared<assembly::Block>(parseBlock()); return make_shared<Block>(parseBlock());
} }
catch (FatalError const&) 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 Parser::parseBlock()
{ {
assembly::Block block = createWithLocation<Block>();
expectToken(Token::LBrace); expectToken(Token::LBrace);
Block block;
while (m_scanner->currentToken() != Token::RBrace) while (m_scanner->currentToken() != Token::RBrace)
block.statements.emplace_back(parseStatement()); block.statements.emplace_back(parseStatement());
block.location.end = endPosition();
m_scanner->next(); m_scanner->next();
return block; return block;
} }
@ -65,11 +66,14 @@ assembly::Statement Parser::parseStatement()
return parseBlock(); return parseBlock();
case Token::Assign: case Token::Assign:
{ {
assembly::Assignment assignment = createWithLocation<assembly::Assignment>();
m_scanner->next(); m_scanner->next();
expectToken(Token::Colon); 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); expectToken(Token::Identifier);
return assembly::Assignment{assembly::Identifier{name}}; return assignment;
} }
case Token::Return: // opcode case Token::Return: // opcode
case Token::Byte: // opcode case Token::Byte: // opcode
@ -84,24 +88,30 @@ assembly::Statement Parser::parseStatement()
switch (m_scanner->currentToken()) switch (m_scanner->currentToken())
{ {
case Token::LParen: case Token::LParen:
return parseFunctionalInstruction(statement); return parseFunctionalInstruction(std::move(statement));
case Token::Colon: case Token::Colon:
{ {
if (statement.type() != typeid(assembly::Identifier)) if (statement.type() != typeid(assembly::Identifier))
fatalParserError("Label name / variable name must precede \":\"."); 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(); m_scanner->next();
if (m_scanner->currentToken() == Token::Assign) if (m_scanner->currentToken() == Token::Assign)
{ {
// functional assignment // functional assignment
FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location);
m_scanner->next(); m_scanner->next();
unique_ptr<Statement> value; funAss.variableName = identifier;
value.reset(new Statement(parseExpression())); funAss.value.reset(new Statement(parseExpression()));
return FunctionalAssignment{{std::move(name)}, std::move(value)}; funAss.location.end = locationOf(*funAss.value).end;
return funAss;
} }
else else
{
// label // label
return Label{name}; Label label = createWithLocation<Label>(identifier.location);
label.name = identifier.name;
return label;
}
} }
default: default:
break; break;
@ -113,7 +123,7 @@ assembly::Statement Parser::parseExpression()
{ {
Statement operation = parseElementaryOperation(true); Statement operation = parseElementaryOperation(true);
if (m_scanner->currentToken() == Token::LParen) if (m_scanner->currentToken() == Token::LParen)
return parseFunctionalInstruction(operation); return parseFunctionalInstruction(std::move(operation));
else else
return operation; return operation;
} }
@ -137,8 +147,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
s_instructions[name] = instruction.second; s_instructions[name] = instruction.second;
} }
//@TODO track location Statement ret;
switch (m_scanner->currentToken()) switch (m_scanner->currentToken())
{ {
case Token::Identifier: case Token::Identifier:
@ -162,48 +171,50 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
if (info.ret != 1) if (info.ret != 1)
fatalParserError("Instruction " + info.name + " not allowed in this context."); fatalParserError("Instruction " + info.name + " not allowed in this context.");
} }
m_scanner->next(); ret = Instruction{location(), instr};
return Instruction{instr};
} }
else else
m_scanner->next(); ret = Identifier{location(), literal};
return Identifier{literal};
break; break;
} }
case Token::StringLiteral: case Token::StringLiteral:
case Token::Number: case Token::Number:
{ {
Literal literal{ ret = Literal{
location(),
m_scanner->currentToken() == Token::Number, m_scanner->currentToken() == Token::Number,
m_scanner->currentLiteral() m_scanner->currentLiteral()
}; };
m_scanner->next();
return literal;
}
default:
break; break;
} }
fatalParserError("Expected elementary inline assembly operation."); default:
return {}; fatalParserError("Expected elementary inline assembly operation.");
}
m_scanner->next();
return ret;
} }
assembly::VariableDeclaration Parser::parseVariableDeclaration() assembly::VariableDeclaration Parser::parseVariableDeclaration()
{ {
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
expectToken(Token::Let); expectToken(Token::Let);
string name = m_scanner->currentLiteral(); varDecl.name = m_scanner->currentLiteral();
expectToken(Token::Identifier); expectToken(Token::Identifier);
expectToken(Token::Colon); expectToken(Token::Colon);
expectToken(Token::Assign); expectToken(Token::Assign);
unique_ptr<Statement> value; varDecl.value.reset(new Statement(parseExpression()));
value.reset(new Statement(parseExpression())); varDecl.location.end = locationOf(*varDecl.value).end;
return VariableDeclaration{name, std::move(value)}; return varDecl;
} }
FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement const& _instruction) FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
{ {
if (_instruction.type() != typeid(Instruction)) if (_instruction.type() != typeid(Instruction))
fatalParserError("Assembly instruction required in front of \"(\")"); 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); InstructionInfo instrInfo = instructionInfo(instr);
if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16) if (solidity::Instruction::DUP1 <= instr && instr <= solidity::Instruction::DUP16)
fatalParserError("DUPi instructions not allowed for functional notation"); 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"); fatalParserError("SWAPi instructions not allowed for functional notation");
expectToken(Token::LParen); expectToken(Token::LParen);
vector<Statement> arguments;
unsigned args = unsigned(instrInfo.args); unsigned args = unsigned(instrInfo.args);
for (unsigned i = 0; i < args; ++i) for (unsigned i = 0; i < args; ++i)
{ {
arguments.push_back(parseExpression()); ret.arguments.emplace_back(parseExpression());
if (i != args - 1) 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); expectToken(Token::RParen);
return FunctionalInstruction{{instr}, std::move(arguments)}; return ret;
} }

View File

@ -44,13 +44,29 @@ public:
std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner); std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner);
protected: 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(); Block parseBlock();
Statement parseStatement(); Statement parseStatement();
/// Parses a functional expression that has to push exactly one stack element /// Parses a functional expression that has to push exactly one stack element
Statement parseExpression(); Statement parseExpression();
Statement parseElementaryOperation(bool _onlySinglePusher = false); Statement parseElementaryOperation(bool _onlySinglePusher = false);
VariableDeclaration parseVariableDeclaration(); VariableDeclaration parseVariableDeclaration();
FunctionalInstruction parseFunctionalInstruction(Statement const& _instruction); FunctionalInstruction parseFunctionalInstruction(Statement&& _instruction);
}; };
} }

View File

@ -34,14 +34,18 @@ using namespace dev::solidity::assembly;
bool InlineAssemblyStack::parse(const std::shared_ptr<Scanner>& _scanner) bool InlineAssemblyStack::parse(const std::shared_ptr<Scanner>& _scanner)
{ {
m_parserResult = make_shared<Block>();
Parser parser(m_errors); Parser parser(m_errors);
m_asmBlock = parser.parse(_scanner); auto result = parser.parse(_scanner);
return !!m_asmBlock; if (!result)
return false;
*m_parserResult = std::move(*result);
return true;
} }
eth::Assembly InlineAssemblyStack::assemble() eth::Assembly InlineAssemblyStack::assemble()
{ {
CodeGenerator codeGen(*m_asmBlock, m_errors); CodeGenerator codeGen(*m_parserResult, m_errors);
return codeGen.assemble(); return codeGen.assemble();
} }

View File

@ -50,7 +50,7 @@ public:
ErrorList const& errors() const { return m_errors; } ErrorList const& errors() const { return m_errors; }
private: private:
std::shared_ptr<Block> m_asmBlock; std::shared_ptr<Block> m_parserResult;
ErrorList m_errors; ErrorList m_errors;
}; };

View File

@ -861,7 +861,7 @@ void CommandLineInterface::outputAssembly()
cout << endl << "======= " << src.first << " =======" << endl; cout << endl << "======= " << src.first << " =======" << endl;
eth::Assembly assembly = m_assemblyStacks[src.first].assemble(); eth::Assembly assembly = m_assemblyStacks[src.first].assemble();
cout << assembly.assemble().toHex() << endl; cout << assembly.assemble().toHex() << endl;
cout << assembly.out(); assembly.stream(cout, "", m_sourceCodes);
} }
} }