diff options
author | chriseth <c@ethdev.com> | 2016-03-02 05:56:39 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2016-03-30 08:37:00 +0800 |
commit | f0494307232e52dcc268f5f32d26cc89d7e98e3a (patch) | |
tree | 5a03eae3515eb50d67388e7d7d1193d016baaddf /libsolidity/inlineasm | |
parent | 949b00ed591303c531ed8fa73087b710b7a554de (diff) | |
download | dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.gz dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.bz2 dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.lz dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.xz dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.tar.zst dexon-solidity-f0494307232e52dcc268f5f32d26cc89d7e98e3a.zip |
Code generation (missing external access and source locations).
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 263 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.h | 66 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmData.h | 60 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 67 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.h | 21 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.cpp | 47 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.h | 59 |
7 files changed, 512 insertions, 71 deletions
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp new file mode 100644 index 00000000..89e95bc1 --- /dev/null +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -0,0 +1,263 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2016 + * Code-generating part of inline assembly. + */ + +#include <libsolidity/inlineasm/AsmCodeGen.h> +#include <memory> +#include <functional> +#include <libevmasm/Assembly.h> +#include <libevmasm/SourceLocation.h> +#include <libsolidity/inlineasm/AsmParser.h> +#include <libsolidity/inlineasm/AsmData.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; +using namespace dev::solidity::assembly; + +struct GeneratorState +{ + explicit GeneratorState(ErrorList& _errors): errors(_errors) {} + + void addError(Error::Type _type, std::string const& _description, SourceLocation const& _location = SourceLocation()) + { + auto err = make_shared<Error>(_type); + if (!_location.isEmpty()) + *err << errinfo_sourceLocation(_location); + *err << errinfo_comment(_description); + errors.push_back(err); + } + + int const* findVariable(string const& _variableName) const + { + auto localVariable = find_if( + variables.rbegin(), + variables.rend(), + [&](pair<string, int> const& _var) { return _var.first == _variableName; } + ); + return localVariable != variables.rend() ? &localVariable->second : nullptr; + } + eth::AssemblyItem const* findLabel(string const& _labelName) const + { + auto label = find_if( + labels.begin(), + labels.end(), + [&](pair<string, eth::AssemblyItem> const& _label) { return _label.first == _labelName; } + ); + return label != labels.end() ? &label->second : nullptr; + } + + eth::Assembly assembly; + map<string, eth::AssemblyItem> labels; + vector<pair<string, int>> variables; ///< name plus stack height + ErrorList& errors; +}; + +/** + * Scans the inline assembly data for labels, creates tags in the assembly and searches for + * duplicate labels. + */ +class LabelOrganizer: public boost::static_visitor<> +{ +public: + LabelOrganizer(GeneratorState& _state): m_state(_state) {} + + template <class T> + void operator()(T const& /*_item*/) { } + 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."); + m_state.labels.insert(make_pair(_item.name, m_state.assembly.newTag())); + } + void operator()(assembly::Block const& _block) + { + std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); + } + +private: + GeneratorState& m_state; +}; + +class CodeTransform: public boost::static_visitor<> +{ +public: + /// Create the code transformer which appends assembly to _state.assembly when called + /// with parsed assembly data. + /// @param _identifierAccess used to resolve identifiers external to the inline assembly + explicit CodeTransform( + GeneratorState& _state, + assembly::CodeGenerator::IdentifierAccess const& _identifierAccess = assembly::CodeGenerator::IdentifierAccess() + ): + m_state(_state) + { + if (_identifierAccess) + m_identifierAccess = _identifierAccess; + else + m_identifierAccess = [](assembly::Identifier const&, eth::Assembly&, CodeGenerator::IdentifierContext) { return false; }; + } + + void operator()(Instruction const& _instruction) + { + m_state.assembly.append(_instruction.instruction); + } + void operator()(assembly::Literal const& _literal) + { + 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)" + ); + else + m_state.assembly.append(_literal.value); + } + void operator()(assembly::Identifier const& _identifier) + { + // 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) + ")" + ); + else + m_state.assembly.append(eth::dupInstruction(heightDiff)); + return; + } + 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" + ); + } + void operator()(FunctionalInstruction const& _instr) + { + for (auto it = _instr.arguments.rbegin(); it != _instr.arguments.rend(); ++it) + { + int height = m_state.assembly.deposit(); + boost::apply_visitor(*this, *it); + expectDeposit(1, height); + } + (*this)(_instr.instruction); + } + void operator()(Label const& _label) + { + m_state.assembly.append(m_state.labels.at(_label.name)); + } + void operator()(assembly::Assignment const& _assignment) + { + generateAssignment(_assignment.variableName); + } + void operator()(FunctionalAssignment const& _assignment) + { + int height = m_state.assembly.deposit(); + boost::apply_visitor(*this, *_assignment.value); + expectDeposit(1, height); + generateAssignment(_assignment.variableName); + } + void operator()(assembly::VariableDeclaration const& _varDecl) + { + int height = m_state.assembly.deposit(); + boost::apply_visitor(*this, *_varDecl.value); + expectDeposit(1, height); + m_state.variables.push_back(make_pair(_varDecl.name, height)); + } + void operator()(assembly::Block const& _block) + { + 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 + while (m_state.variables.size() > numVariables) + { + m_state.assembly.append(eth::Instruction::POP); + m_state.variables.pop_back(); + } + } + +private: + void generateAssignment(assembly::Identifier const& _variableName) + { + 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) + ")" + ); + else + { + m_state.assembly.append(eth::swapInstruction(heightDiff)); + m_state.assembly.append(eth::Instruction::POP); + } + return; + } + else if (!m_identifierAccess(_variableName, m_state.assembly, CodeGenerator::IdentifierContext::LValue)) + m_state.addError( + Error::Type::DeclarationError, + "Identifier \"" + string(_variableName.name) + "\" not found, not unique or not lvalue." + ); + } + + void expectDeposit(int _deposit, int _oldHeight) + { + 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)." + ); + } + + GeneratorState& m_state; + assembly::CodeGenerator::IdentifierAccess m_identifierAccess; +}; + +bool assembly::CodeGenerator::typeCheck(assembly::CodeGenerator::IdentifierAccess const& _identifierAccess) +{ + size_t initialErrorLen = m_errors.size(); + GeneratorState state(m_errors); + (LabelOrganizer(state))(m_parsedData); + (CodeTransform(state, _identifierAccess))(m_parsedData); + return m_errors.size() == initialErrorLen; +} + +eth::Assembly assembly::CodeGenerator::assemble(assembly::CodeGenerator::IdentifierAccess const& _identifierAccess) +{ + GeneratorState state(m_errors); + (LabelOrganizer(state))(m_parsedData); + (CodeTransform(state, _identifierAccess))(m_parsedData); + return state.assembly; +} + diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h new file mode 100644 index 00000000..f749ba50 --- /dev/null +++ b/libsolidity/inlineasm/AsmCodeGen.h @@ -0,0 +1,66 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2016 + * Code-generating part of inline assembly. + */ + +#pragma once + +#include <functional> +#include <libsolidity/interface/Exceptions.h> + +namespace dev +{ +namespace eth +{ +class Assembly; +} +namespace solidity +{ +namespace assembly +{ +struct Block; +struct Identifier; + +class CodeGenerator +{ +public: + enum class IdentifierContext { LValue, RValue }; + /// Function type that is called for external identifiers. Such a function should search for + /// the identifier and append appropriate assembly items to the assembly. If in lvalue context, + /// the value to assign is assumed to be on the stack and an assignment is to be performed. + /// 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): + m_parsedData(_parsedData), m_errors(_errors) {} + /// Performs type checks and @returns false on error. + /// Actually runs the full code generation but discards the result. + bool typeCheck(IdentifierAccess const& _identifierAccess = IdentifierAccess()); + /// Performs code generation and @returns the result. + eth::Assembly assemble(IdentifierAccess const& _identifierAccess = IdentifierAccess()); + +private: + Block const& m_parsedData; + ErrorList& m_errors; +}; + +} +} +} diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index a38a9d36..0361a4c2 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -29,42 +29,36 @@ namespace dev { namespace solidity { - -class AsmData +namespace assembly { -public: - /// Direct EVM instruction (except PUSHi and JUMPDEST) - struct Instruction { eth::Instruction instruction; }; - /// Literal number or string (up to 32 bytes) - struct Literal { bool isNumber; std::string value; }; - /// External / internal identifier or label reference - struct Identifier { std::string name; }; - struct FunctionalInstruction; - /// Jump label ("name:") - struct Label { std::string name; }; - /// Assignemnt (":= x", moves stack top into x, potentially multiple slots) - struct Assignment { 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; }; - /// Functional instruction, e.g. "mul(mload(20), add(2, x))" - struct FunctionalInstruction { 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; }; - /// Block that creates a scope (frees declared stack variables) - struct Block { std::vector<Statement> statements; }; - - AsmData(Block&& _statements): m_statements(_statements) {} - Block const& statements() const { return m_statements; } +/// What follows are the AST nodes for assembly. -private: - Block m_statements; -}; +/// Direct EVM instruction (except PUSHi and JUMPDEST) +struct Instruction { eth::Instruction instruction; }; +/// Literal number or string (up to 32 bytes) +struct Literal { bool isNumber; std::string value; }; +/// External / internal identifier or label reference +struct Identifier { std::string name; }; +struct FunctionalInstruction; +/// Jump label ("name:") +struct Label { std::string name; }; +/// Assignemnt (":= x", moves stack top into x, potentially multiple slots) +struct Assignment { 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; }; +/// Functional instruction, e.g. "mul(mload(20), add(2, x))" +struct FunctionalInstruction { 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; }; +/// Block that creates a scope (frees declared stack variables) +struct Block { std::vector<Statement> statements; }; } } +} diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 28fd5354..124a5d26 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -29,13 +29,14 @@ using namespace std; using namespace dev; using namespace dev::solidity; +using namespace dev::solidity::assembly; -shared_ptr<AsmData> InlineAssemblyParser::parse(std::shared_ptr<Scanner> const& _scanner) +shared_ptr<assembly::Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner) { try { m_scanner = _scanner; - return make_shared<AsmData>(parseBlock()); + return make_shared<assembly::Block>(parseBlock()); } catch (FatalError const&) { @@ -45,17 +46,17 @@ shared_ptr<AsmData> InlineAssemblyParser::parse(std::shared_ptr<Scanner> const& return nullptr; } -AsmData::Block InlineAssemblyParser::parseBlock() +assembly::Block Parser::parseBlock() { expectToken(Token::LBrace); - AsmData::Block block; + Block block; while (m_scanner->currentToken() != Token::RBrace) block.statements.emplace_back(parseStatement()); m_scanner->next(); return block; } -AsmData::Statement InlineAssemblyParser::parseStatement() +assembly::Statement Parser::parseStatement() { switch (m_scanner->currentToken()) { @@ -69,8 +70,9 @@ AsmData::Statement InlineAssemblyParser::parseStatement() expectToken(Token::Colon); string name = m_scanner->currentLiteral(); expectToken(Token::Identifier); - return AsmData::Assignment{AsmData::Identifier{name}}; + return assembly::Assignment{assembly::Identifier{name}}; } + case Token::Return: // opcode default: break; } @@ -78,28 +80,28 @@ AsmData::Statement InlineAssemblyParser::parseStatement() // Simple instruction (might turn into functional), // literal, // identifier (might turn into label or functional assignment) - AsmData::Statement statement(parseElementaryOperation()); + Statement statement(parseElementaryOperation()); switch (m_scanner->currentToken()) { case Token::LParen: return parseFunctionalInstruction(statement); case Token::Colon: { - if (statement.type() != typeid(AsmData::Identifier)) + if (statement.type() != typeid(assembly::Identifier)) fatalParserError("Label name / variable name must precede \":\"."); - string const& name = boost::get<AsmData::Identifier>(statement).name; + string const& name = boost::get<assembly::Identifier>(statement).name; m_scanner->next(); if (m_scanner->currentToken() == Token::Assign) { // functional assignment m_scanner->next(); - unique_ptr<AsmData::Statement> value; - value.reset(new AsmData::Statement(parseExpression())); - return AsmData::FunctionalAssignment{{move(name)}, move(value)}; + unique_ptr<Statement> value; + value.reset(new Statement(parseExpression())); + return FunctionalAssignment{{std::move(name)}, std::move(value)}; } else // label - return AsmData::Label{name}; + return Label{name}; } default: break; @@ -107,16 +109,16 @@ AsmData::Statement InlineAssemblyParser::parseStatement() return statement; } -AsmData::Statement InlineAssemblyParser::parseExpression() +assembly::Statement Parser::parseExpression() { - AsmData::Statement operation = parseElementaryOperation(true); + Statement operation = parseElementaryOperation(true); if (m_scanner->currentToken() == Token::LParen) return parseFunctionalInstruction(operation); else return operation; } -AsmData::Statement InlineAssemblyParser::parseElementaryOperation(bool _onlySinglePusher) +assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) { // Allowed instructions, lowercase names. static map<string, eth::Instruction> s_instructions; @@ -129,6 +131,8 @@ AsmData::Statement InlineAssemblyParser::parseElementaryOperation(bool _onlySing ) continue; string name = instruction.first; + if (instruction.second == eth::Instruction::SUICIDE) + name = "selfdestruct"; transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); s_instructions[name] = instruction.second; } @@ -138,8 +142,13 @@ AsmData::Statement InlineAssemblyParser::parseElementaryOperation(bool _onlySing switch (m_scanner->currentToken()) { case Token::Identifier: + case Token::Return: { - string literal = m_scanner->currentLiteral(); + string literal; + if (m_scanner->currentToken() == Token::Return) + literal = "return"; + else + literal = m_scanner->currentLiteral(); // first search the set of instructions. if (s_instructions.count(literal)) { @@ -151,17 +160,17 @@ AsmData::Statement InlineAssemblyParser::parseElementaryOperation(bool _onlySing fatalParserError("Instruction " + info.name + " not allowed in this context."); } m_scanner->next(); - return AsmData::Instruction{instr}; + return Instruction{instr}; } else m_scanner->next(); - return AsmData::Identifier{literal}; + return Identifier{literal}; break; } case Token::StringLiteral: case Token::Number: { - AsmData::Literal literal{ + Literal literal{ m_scanner->currentToken() == Token::Number, m_scanner->currentLiteral() }; @@ -175,23 +184,23 @@ AsmData::Statement InlineAssemblyParser::parseElementaryOperation(bool _onlySing return {}; } -AsmData::VariableDeclaration InlineAssemblyParser::parseVariableDeclaration() +assembly::VariableDeclaration Parser::parseVariableDeclaration() { expectToken(Token::Let); string name = m_scanner->currentLiteral(); expectToken(Token::Identifier); expectToken(Token::Colon); expectToken(Token::Assign); - unique_ptr<AsmData::Statement> value; - value.reset(new AsmData::Statement(parseExpression())); - return AsmData::VariableDeclaration{name, move(value)}; + unique_ptr<Statement> value; + value.reset(new Statement(parseExpression())); + return VariableDeclaration{name, std::move(value)}; } -AsmData::FunctionalInstruction InlineAssemblyParser::parseFunctionalInstruction(AsmData::Statement const& _instruction) +FunctionalInstruction Parser::parseFunctionalInstruction(assembly::Statement const& _instruction) { - if (_instruction.type() != typeid(AsmData::Instruction)) + if (_instruction.type() != typeid(Instruction)) fatalParserError("Assembly instruction required in front of \"(\")"); - eth::Instruction instr = boost::get<AsmData::Instruction>(_instruction).instruction; + eth::Instruction instr = boost::get<Instruction>(_instruction).instruction; eth::InstructionInfo instrInfo = eth::instructionInfo(instr); if (eth::Instruction::DUP1 <= instr && instr <= eth::Instruction::DUP16) fatalParserError("DUPi instructions not allowed for functional notation"); @@ -199,7 +208,7 @@ AsmData::FunctionalInstruction InlineAssemblyParser::parseFunctionalInstruction( fatalParserError("SWAPi instructions not allowed for functional notation"); expectToken(Token::LParen); - vector<AsmData::Statement> arguments; + vector<Statement> arguments; unsigned args = unsigned(instrInfo.args); for (unsigned i = 0; i < args; ++i) { @@ -208,5 +217,5 @@ AsmData::FunctionalInstruction InlineAssemblyParser::parseFunctionalInstruction( expectToken(Token::Comma); } expectToken(Token::RParen); - return AsmData::FunctionalInstruction{{instr}, move(arguments)}; + return FunctionalInstruction{{instr}, std::move(arguments)}; } diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index fe84470d..b54da941 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -31,25 +31,28 @@ namespace dev { namespace solidity { +namespace assembly +{ -class InlineAssemblyParser: public ParserBase +class Parser: public ParserBase { public: - InlineAssemblyParser(ErrorList& _errors): ParserBase(_errors) {} + Parser(ErrorList& _errors): ParserBase(_errors) {} /// Parses an inline assembly block starting with `{` and ending with `}`. /// @returns an empty shared pointer on error. - std::shared_ptr<AsmData> parse(std::shared_ptr<Scanner> const& _scanner); + std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner); protected: - AsmData::Block parseBlock(); - AsmData::Statement parseStatement(); + Block parseBlock(); + Statement parseStatement(); /// Parses a functional expression that has to push exactly one stack element - AsmData::Statement parseExpression(); - AsmData::Statement parseElementaryOperation(bool _onlySinglePusher = false); - AsmData::VariableDeclaration parseVariableDeclaration(); - AsmData::FunctionalInstruction parseFunctionalInstruction(AsmData::Statement const& _instruction); + Statement parseExpression(); + Statement parseElementaryOperation(bool _onlySinglePusher = false); + VariableDeclaration parseVariableDeclaration(); + FunctionalInstruction parseFunctionalInstruction(Statement const& _instruction); }; } } +} diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp new file mode 100644 index 00000000..22042ada --- /dev/null +++ b/libsolidity/inlineasm/AsmStack.cpp @@ -0,0 +1,47 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2016 + * Full-stack Solidity inline assember. + */ + +#include <libsolidity/inlineasm/AsmStack.h> +#include <memory> +#include <libevmasm/Assembly.h> +#include <libevmasm/SourceLocation.h> +#include <libsolidity/inlineasm/AsmParser.h> +#include <libsolidity/inlineasm/AsmCodeGen.h> + +using namespace std; +using namespace dev; +using namespace dev::solidity; +using namespace dev::solidity::assembly; + +bool InlineAssemblyStack::parse(const std::shared_ptr<Scanner>& _scanner) +{ + Parser parser(m_errors); + m_asmBlock = parser.parse(_scanner); + return !!m_asmBlock; +} + +eth::Assembly InlineAssemblyStack::assemble() +{ + CodeGenerator codeGen(*m_asmBlock, m_errors); + return codeGen.assemble(); +} + diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h new file mode 100644 index 00000000..73ca9583 --- /dev/null +++ b/libsolidity/inlineasm/AsmStack.h @@ -0,0 +1,59 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2016 + * Full-stack Solidity inline assember. + */ + +#pragma once + +#include <string> +#include <functional> +#include <libsolidity/interface/Exceptions.h> + +namespace dev +{ +namespace eth +{ +class Assembly; +} +namespace solidity +{ +class Scanner; +namespace assembly +{ +struct Block; + +class InlineAssemblyStack +{ +public: + /// Parse the given inline assembly chunk starting with `{` and ending with the corresponding `}`. + /// @return false or error. + bool parse(std::shared_ptr<Scanner> const& _scanner); + eth::Assembly assemble(); + + ErrorList const& errors() const { return m_errors; } + +private: + std::shared_ptr<Block> m_asmBlock; + ErrorList m_errors; +}; + +} +} +} |