diff options
Diffstat (limited to 'libsolidity/inlineasm')
| -rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.cpp | 11 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 146 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmData.h | 18 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 67 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmParser.h | 1 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmPrinter.cpp | 43 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmPrinter.h | 2 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmScope.cpp | 8 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmScope.h | 21 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmScopeFiller.cpp | 16 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmScopeFiller.h | 3 | ||||
| -rw-r--r-- | libsolidity/inlineasm/AsmStack.h | 4 |
12 files changed, 251 insertions, 89 deletions
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index dad05a78..e03eea2e 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -72,7 +72,7 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction) bool AsmAnalyzer::operator()(assembly::Literal const& _literal) { ++m_stackHeight; - if (!_literal.isNumber && _literal.value.size() > 32) + if (_literal.kind == assembly::LiteralKind::String && _literal.value.size() > 32) { m_errors.push_back(make_shared<Error>( Error::Type::TypeError, @@ -184,7 +184,7 @@ bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl) int const stackHeight = m_stackHeight; bool success = boost::apply_visitor(*this, *_varDecl.value); solAssert(m_stackHeight - stackHeight == 1, "Invalid value size."); - boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.name)).active = true; + boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.variable.name)).active = true; m_info.stackHeightInfo[&_varDecl] = m_stackHeight; return success; } @@ -193,7 +193,7 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef) { Scope& bodyScope = scope(&_funDef.body); for (auto const& var: _funDef.arguments + _funDef.returns) - boost::get<Scope::Variable>(bodyScope.identifiers.at(var)).active = true; + boost::get<Scope::Variable>(bodyScope.identifiers.at(var.name)).active = true; int const stackHeight = m_stackHeight; m_stackHeight = _funDef.arguments.size() + _funDef.returns.size(); @@ -232,8 +232,9 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall) }, [&](Scope::Function const& _fun) { - arguments = _fun.arguments; - returns = _fun.returns; + /// TODO: compare types too + arguments = _fun.arguments.size(); + returns = _fun.returns.size(); } ))) { diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index c19667b4..b8af9dc6 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -32,6 +32,8 @@ #include <libevmasm/SourceLocation.h> #include <libevmasm/Instruction.h> +#include <libjulia/backends/AbstractAssembly.h> + #include <libdevcore/CommonIO.h> #include <boost/range/adaptor/reversed.hpp> @@ -48,14 +50,53 @@ using namespace dev::solidity::assembly; struct GeneratorState { - GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly): - errors(_errors), info(_analysisInfo), assembly(_assembly) {} + GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo): + errors(_errors), info(_analysisInfo) {} - size_t newLabelId() + ErrorList& errors; + AsmAnalysisInfo info; +}; + +class EthAssemblyAdapter: public julia::AbstractAssembly +{ +public: + EthAssemblyAdapter(eth::Assembly& _assembly): + m_assembly(_assembly) + { + } + virtual void setSourceLocation(SourceLocation const& _location) override + { + m_assembly.setSourceLocation(_location); + } + virtual int stackHeight() const override { return m_assembly.deposit(); } + virtual void appendInstruction(solidity::Instruction _instruction) override + { + m_assembly.append(_instruction); + } + virtual void appendConstant(u256 const& _constant) override { - return assemblyTagToIdentifier(assembly.newTag()); + m_assembly.append(_constant); + } + /// Append a label. + virtual void appendLabel(size_t _labelId) override + { + m_assembly.append(eth::AssemblyItem(eth::Tag, _labelId)); + } + /// Append a label reference. + virtual void appendLabelReference(size_t _labelId) override + { + m_assembly.append(eth::AssemblyItem(eth::PushTag, _labelId)); + } + virtual size_t newLabelId() override + { + return assemblyTagToIdentifier(m_assembly.newTag()); + } + virtual void appendLinkerSymbol(std::string const& _linkerSymbol) override + { + m_assembly.appendLibraryAddress(_linkerSymbol); } +private: size_t assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const { u256 id = _tag.data(); @@ -63,9 +104,7 @@ struct GeneratorState return size_t(id); } - ErrorList& errors; - AsmAnalysisInfo info; - eth::Assembly& assembly; + eth::Assembly& m_assembly; }; class CodeTransform: public boost::static_visitor<> @@ -76,74 +115,84 @@ public: /// @param _identifierAccess used to resolve identifiers external to the inline assembly explicit CodeTransform( GeneratorState& _state, + julia::AbstractAssembly& _assembly, assembly::Block const& _block, assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess() - ): CodeTransform(_state, _block, _identifierAccess, _state.assembly.deposit()) + ): CodeTransform(_state, _assembly, _block, _identifierAccess, _assembly.stackHeight()) { } private: CodeTransform( GeneratorState& _state, + julia::AbstractAssembly& _assembly, assembly::Block const& _block, assembly::ExternalIdentifierAccess const& _identifierAccess, - int _initialDeposit + int _initialStackHeight ): m_state(_state), + m_assembly(_assembly), m_scope(*m_state.info.scopes.at(&_block)), m_identifierAccess(_identifierAccess), - m_initialDeposit(_initialDeposit) + m_initialStackHeight(_initialStackHeight) { - int blockStartDeposit = m_state.assembly.deposit(); + int blockStartStackHeight = m_assembly.stackHeight(); std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); - m_state.assembly.setSourceLocation(_block.location); + m_assembly.setSourceLocation(_block.location); // pop variables for (auto const& identifier: m_scope.identifiers) if (identifier.second.type() == typeid(Scope::Variable)) - m_state.assembly.append(solidity::Instruction::POP); + m_assembly.appendInstruction(solidity::Instruction::POP); - int deposit = m_state.assembly.deposit() - blockStartDeposit; + int deposit = m_assembly.stackHeight() - blockStartStackHeight; solAssert(deposit == 0, "Invalid stack height at end of block."); } public: void operator()(assembly::Instruction const& _instruction) { - m_state.assembly.setSourceLocation(_instruction.location); - m_state.assembly.append(_instruction.instruction); + m_assembly.setSourceLocation(_instruction.location); + m_assembly.appendInstruction(_instruction.instruction); checkStackHeight(&_instruction); } void operator()(assembly::Literal const& _literal) { - m_state.assembly.setSourceLocation(_literal.location); - if (_literal.isNumber) - m_state.assembly.append(u256(_literal.value)); + m_assembly.setSourceLocation(_literal.location); + if (_literal.kind == assembly::LiteralKind::Number) + m_assembly.appendConstant(u256(_literal.value)); + else if (_literal.kind == assembly::LiteralKind::Boolean) + { + if (_literal.value == "true") + m_assembly.appendConstant(u256(1)); + else + m_assembly.appendConstant(u256(0)); + } else { solAssert(_literal.value.size() <= 32, ""); - m_state.assembly.append(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); + m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); } checkStackHeight(&_literal); } void operator()(assembly::Identifier const& _identifier) { - m_state.assembly.setSourceLocation(_identifier.location); + m_assembly.setSourceLocation(_identifier.location); // First search internals, then externals. if (m_scope.lookup(_identifier.name, Scope::NonconstVisitor( [=](Scope::Variable& _var) { if (int heightDiff = variableHeightDiff(_var, _identifier.location, false)) - m_state.assembly.append(solidity::dupInstruction(heightDiff)); + m_assembly.appendInstruction(solidity::dupInstruction(heightDiff)); else // Store something to balance the stack - m_state.assembly.append(u256(0)); + m_assembly.appendConstant(u256(0)); }, [=](Scope::Label& _label) { assignLabelIdIfUnset(_label); - m_state.assembly.append(eth::AssemblyItem(eth::PushTag, _label.id)); + m_assembly.appendLabelReference(*_label.id); }, [=](Scope::Function&) { @@ -157,14 +206,14 @@ public: m_identifierAccess.generateCode, "Identifier not found and no external access available." ); - m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_state.assembly); + m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_assembly); checkStackHeight(&_identifier); } void operator()(FunctionalInstruction const& _instr) { for (auto it = _instr.arguments.rbegin(); it != _instr.arguments.rend(); ++it) { - int height = m_state.assembly.deposit(); + int height = m_assembly.stackHeight(); boost::apply_visitor(*this, *it); expectDeposit(1, height); } @@ -177,40 +226,40 @@ public: } void operator()(Label const& _label) { - m_state.assembly.setSourceLocation(_label.location); + m_assembly.setSourceLocation(_label.location); solAssert(m_scope.identifiers.count(_label.name), ""); Scope::Label& label = boost::get<Scope::Label>(m_scope.identifiers.at(_label.name)); assignLabelIdIfUnset(label); - m_state.assembly.append(eth::AssemblyItem(eth::Tag, label.id)); + m_assembly.appendLabel(*label.id); checkStackHeight(&_label); } void operator()(assembly::Assignment const& _assignment) { - m_state.assembly.setSourceLocation(_assignment.location); + m_assembly.setSourceLocation(_assignment.location); generateAssignment(_assignment.variableName, _assignment.location); checkStackHeight(&_assignment); } void operator()(FunctionalAssignment const& _assignment) { - int height = m_state.assembly.deposit(); + int height = m_assembly.stackHeight(); boost::apply_visitor(*this, *_assignment.value); expectDeposit(1, height); - m_state.assembly.setSourceLocation(_assignment.location); + m_assembly.setSourceLocation(_assignment.location); generateAssignment(_assignment.variableName, _assignment.location); checkStackHeight(&_assignment); } void operator()(assembly::VariableDeclaration const& _varDecl) { - int height = m_state.assembly.deposit(); + int height = m_assembly.stackHeight(); boost::apply_visitor(*this, *_varDecl.value); expectDeposit(1, height); - auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.name)); + auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.variable.name)); var.stackHeight = height; var.active = true; } void operator()(assembly::Block const& _block) { - CodeTransform(m_state, _block, m_identifierAccess, m_initialDeposit); + CodeTransform(m_state, m_assembly, _block, m_identifierAccess, m_initialStackHeight); checkStackHeight(&_block); } void operator()(assembly::FunctionDefinition const&) @@ -226,8 +275,8 @@ private: { Scope::Variable const& _var = boost::get<Scope::Variable>(*var); if (int heightDiff = variableHeightDiff(_var, _location, true)) - m_state.assembly.append(solidity::swapInstruction(heightDiff - 1)); - m_state.assembly.append(solidity::Instruction::POP); + m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1)); + m_assembly.appendInstruction(solidity::Instruction::POP); } else { @@ -235,7 +284,7 @@ private: m_identifierAccess.generateCode, "Identifier not found and no external access available." ); - m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_state.assembly); + m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_assembly); } } @@ -244,7 +293,7 @@ private: /// errors and the (positive) stack height difference otherwise. int variableHeightDiff(Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap) { - int heightDiff = m_state.assembly.deposit() - _var.stackHeight; + int heightDiff = m_assembly.stackHeight() - _var.stackHeight; if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16)) { //@TODO move this to analysis phase. @@ -261,14 +310,14 @@ private: void expectDeposit(int _deposit, int _oldHeight) { - solAssert(m_state.assembly.deposit() == _oldHeight + _deposit, "Invalid stack deposit."); + solAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit."); } void checkStackHeight(void const* _astElement) { solAssert(m_state.info.stackHeightInfo.count(_astElement), "Stack height for AST element not found."); solAssert( - m_state.info.stackHeightInfo.at(_astElement) == m_state.assembly.deposit() - m_initialDeposit, + m_state.info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_initialStackHeight, "Stack height mismatch between analysis and code generation phase." ); } @@ -276,15 +325,16 @@ private: /// Assigns the label's id to a value taken from eth::Assembly if it has not yet been set. void assignLabelIdIfUnset(Scope::Label& _label) { - if (_label.id == Scope::Label::unassignedLabelId) - _label.id = m_state.newLabelId(); + if (!_label.id) + _label.id.reset(m_assembly.newLabelId()); } GeneratorState& m_state; + julia::AbstractAssembly& m_assembly; Scope& m_scope; ExternalIdentifierAccess m_identifierAccess; - int const m_initialDeposit; + int const m_initialStackHeight; }; eth::Assembly assembly::CodeGenerator::assemble( @@ -294,8 +344,9 @@ eth::Assembly assembly::CodeGenerator::assemble( ) { eth::Assembly assembly; - GeneratorState state(m_errors, _analysisInfo, assembly); - CodeTransform(state, _parsedData, _identifierAccess); + GeneratorState state(m_errors, _analysisInfo); + EthAssemblyAdapter assemblyAdapter(assembly); + CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess); return assembly; } @@ -306,6 +357,7 @@ void assembly::CodeGenerator::assemble( ExternalIdentifierAccess const& _identifierAccess ) { - GeneratorState state(m_errors, _analysisInfo, _assembly); - CodeTransform(state, _parsedData, _identifierAccess); + GeneratorState state(m_errors, _analysisInfo); + EthAssemblyAdapter assemblyAdapter(_assembly); + CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess); } diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index d61b5803..8efe1f07 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -33,12 +33,18 @@ namespace solidity namespace assembly { +using Type = std::string; + +struct TypedName { SourceLocation location; std::string name; Type type; }; +using TypedNameList = std::vector<TypedName>; + /// What follows are the AST nodes for assembly. /// Direct EVM instruction (except PUSHi and JUMPDEST) struct Instruction { SourceLocation location; solidity::Instruction instruction; }; /// Literal number or string (up to 32 bytes) -struct Literal { SourceLocation location; bool isNumber; std::string value; }; +enum class LiteralKind { Number, Boolean, String }; +struct Literal { SourceLocation location; LiteralKind kind; std::string value; Type type; }; /// External / internal identifier or label reference struct Identifier { SourceLocation location; std::string name; }; struct FunctionalInstruction; @@ -52,18 +58,18 @@ struct FunctionDefinition; struct FunctionCall; struct 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 +/// Functional assignment ("x := mload(20:u256)", 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))" +/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, 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-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted +struct VariableDeclaration { SourceLocation location; TypedName variable; std::shared_ptr<Statement> value; }; /// Block that creates a scope (frees declared stack variables) struct Block { SourceLocation location; std::vector<Statement> statements; }; /// Function definition ("function f(a, b) -> (d, e) { ... }") -struct FunctionDefinition { SourceLocation location; std::string name; std::vector<std::string> arguments; std::vector<std::string> returns; Block body; }; +struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList arguments; TypedNameList returns; Block body; }; struct LocationExtractor: boost::static_visitor<SourceLocation> { diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index d9b0b3e0..a96984f5 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -201,16 +201,47 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) } else ret = Identifier{location(), literal}; + m_scanner->next(); break; } case Token::StringLiteral: case Token::Number: + case Token::TrueLiteral: + case Token::FalseLiteral: { - ret = Literal{ + LiteralKind kind = LiteralKind::Number; + switch (m_scanner->currentToken()) + { + case Token::StringLiteral: + kind = LiteralKind::String; + break; + case Token::Number: + kind = LiteralKind::Number; + break; + case Token::TrueLiteral: + case Token::FalseLiteral: + kind = LiteralKind::Boolean; + break; + default: + break; + } + + Literal literal{ location(), - m_scanner->currentToken() == Token::Number, - m_scanner->currentLiteral() + kind, + m_scanner->currentLiteral(), + "" }; + m_scanner->next(); + if (m_julia) + { + expectToken(Token::Colon); + literal.location.end = endPosition(); + literal.type = expectAsmIdentifier(); + } + else if (kind == LiteralKind::Boolean) + fatalParserError("True and false are not valid literals."); + ret = std::move(literal); break; } default: @@ -220,7 +251,6 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) "Expected elementary inline assembly operation." ); } - m_scanner->next(); return ret; } @@ -228,7 +258,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration() { VariableDeclaration varDecl = createWithLocation<VariableDeclaration>(); expectToken(Token::Let); - varDecl.name = expectAsmIdentifier(); + varDecl.variable = parseTypedName(); expectToken(Token::Colon); expectToken(Token::Assign); varDecl.value.reset(new Statement(parseExpression())); @@ -244,7 +274,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() expectToken(Token::LParen); while (m_scanner->currentToken() != Token::RParen) { - funDef.arguments.push_back(expectAsmIdentifier()); + funDef.arguments.emplace_back(parseTypedName()); if (m_scanner->currentToken() == Token::RParen) break; expectToken(Token::Comma); @@ -256,7 +286,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() expectToken(Token::GreaterThan); while (true) { - funDef.returns.push_back(expectAsmIdentifier()); + funDef.returns.emplace_back(parseTypedName()); if (m_scanner->currentToken() == Token::LBrace) break; expectToken(Token::Comma); @@ -335,10 +365,31 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in return {}; } +TypedName Parser::parseTypedName() +{ + TypedName typedName = createWithLocation<TypedName>(); + typedName.name = expectAsmIdentifier(); + if (m_julia) + { + expectToken(Token::Colon); + typedName.location.end = endPosition(); + typedName.type = expectAsmIdentifier(); + } + return typedName; +} + string Parser::expectAsmIdentifier() { string name = m_scanner->currentLiteral(); - if (!m_julia && instructions().count(name)) + if (m_julia) + { + if (m_scanner->currentToken() == Token::Bool) + { + m_scanner->next(); + return name; + } + } + else if (instructions().count(name)) fatalParserError("Cannot use instruction names for identifier names."); expectToken(Token::Identifier); return name; diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index c55fd2ac..addc1725 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -69,6 +69,7 @@ protected: VariableDeclaration parseVariableDeclaration(); FunctionDefinition parseFunctionDefinition(); Statement parseFunctionalInstruction(Statement&& _instruction); + TypedName parseTypedName(); std::string expectAsmIdentifier(); private: diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index 4a6f975d..636e61b8 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -46,8 +46,16 @@ string AsmPrinter::operator()(assembly::Instruction const& _instruction) string AsmPrinter::operator()(assembly::Literal const& _literal) { - if (_literal.isNumber) - return _literal.value; + switch (_literal.kind) + { + case LiteralKind::Number: + return _literal.value + appendTypeName(_literal.type); + case LiteralKind::Boolean: + return ((_literal.value == "true") ? "true" : "false") + appendTypeName(_literal.type); + case LiteralKind::String: + break; + } + string out; for (char c: _literal.value) if (c == '\\') @@ -74,7 +82,7 @@ string AsmPrinter::operator()(assembly::Literal const& _literal) } else out += c; - return "\"" + out + "\""; + return "\"" + out + "\"" + appendTypeName(_literal.type); } string AsmPrinter::operator()(assembly::Identifier const& _identifier) @@ -113,14 +121,30 @@ string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalA string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration) { - return "let " + _variableDeclaration.name + " := " + boost::apply_visitor(*this, *_variableDeclaration.value); + return "let " + _variableDeclaration.variable.name + appendTypeName(_variableDeclaration.variable.type) + " := " + boost::apply_visitor(*this, *_variableDeclaration.value); } string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition) { - string out = "function " + _functionDefinition.name + "(" + boost::algorithm::join(_functionDefinition.arguments, ", ") + ")"; + string out = "function " + _functionDefinition.name + "("; + out += boost::algorithm::join( + _functionDefinition.arguments | boost::adaptors::transformed( + [this](TypedName argument) { return argument.name + appendTypeName(argument.type); } + ), + ", " + ); + out += ")"; if (!_functionDefinition.returns.empty()) - out += " -> " + boost::algorithm::join(_functionDefinition.returns, ", "); + { + out += " -> "; + out += boost::algorithm::join( + _functionDefinition.returns | boost::adaptors::transformed( + [this](TypedName argument) { return argument.name + appendTypeName(argument.type); } + ), + ", " + ); + } + return out + "\n" + (*this)(_functionDefinition.body); } @@ -145,3 +169,10 @@ string AsmPrinter::operator()(Block const& _block) boost::replace_all(body, "\n", "\n "); return "{\n " + body + "\n}"; } + +string AsmPrinter::appendTypeName(std::string const& _type) +{ + if (m_julia) + return ":" + _type; + return ""; +} diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h index 038c6d85..282fd7e3 100644 --- a/libsolidity/inlineasm/AsmPrinter.h +++ b/libsolidity/inlineasm/AsmPrinter.h @@ -60,6 +60,8 @@ public: std::string operator()(assembly::Block const& _block); private: + std::string appendTypeName(std::string const& _type); + bool m_julia = false; }; diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libsolidity/inlineasm/AsmScope.cpp index 609dca16..e3f4615a 100644 --- a/libsolidity/inlineasm/AsmScope.cpp +++ b/libsolidity/inlineasm/AsmScope.cpp @@ -32,15 +32,17 @@ bool Scope::registerLabel(string const& _name) return true; } -bool Scope::registerVariable(string const& _name) +bool Scope::registerVariable(string const& _name, JuliaType const& _type) { if (exists(_name)) return false; - identifiers[_name] = Variable(); + Variable variable; + variable.type = _type; + identifiers[_name] = variable; return true; } -bool Scope::registerFunction(string const& _name, size_t _arguments, size_t _returns) +bool Scope::registerFunction(string const& _name, std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns) { if (exists(_name)) return false; diff --git a/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h index b70bee67..70786dce 100644 --- a/libsolidity/inlineasm/AsmScope.h +++ b/libsolidity/inlineasm/AsmScope.h @@ -23,6 +23,7 @@ #include <libsolidity/interface/Exceptions.h> #include <boost/variant.hpp> +#include <boost/optional.hpp> #include <functional> #include <memory> @@ -61,6 +62,8 @@ struct GenericVisitor<>: public boost::static_visitor<> { struct Scope { + using JuliaType = std::string; + struct Variable { /// Used during code generation to store the stack height. @todo move there. @@ -68,28 +71,32 @@ struct Scope /// Used during analysis to check whether we already passed the declaration inside the block. /// @todo move there. bool active = false; + JuliaType type; }; struct Label { - size_t id = unassignedLabelId; - static const size_t unassignedLabelId = 0; + boost::optional<size_t> id; }; struct Function { - Function(size_t _arguments, size_t _returns): arguments(_arguments), returns(_returns) {} - size_t arguments = 0; - size_t returns = 0; + Function(std::vector<JuliaType> const& _arguments, std::vector<JuliaType> const& _returns): arguments(_arguments), returns(_returns) {} + std::vector<JuliaType> arguments; + std::vector<JuliaType> returns; }; using Identifier = boost::variant<Variable, Label, Function>; using Visitor = GenericVisitor<Variable const, Label const, Function const>; using NonconstVisitor = GenericVisitor<Variable, Label, Function>; - bool registerVariable(std::string const& _name); + bool registerVariable(std::string const& _name, JuliaType const& _type); bool registerLabel(std::string const& _name); - bool registerFunction(std::string const& _name, size_t _arguments, size_t _returns); + bool registerFunction( + std::string const& _name, + std::vector<JuliaType> const& _arguments, + std::vector<JuliaType> const& _returns + ); /// Looks up the identifier in this or super scopes and returns a valid pointer if found /// or a nullptr if not found. Variable lookups up across function boundaries will fail, as diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp index 4a651388..eb10dbb3 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libsolidity/inlineasm/AsmScopeFiller.cpp @@ -59,13 +59,19 @@ bool ScopeFiller::operator()(Label const& _item) bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl) { - return registerVariable(_varDecl.name, _varDecl.location, *m_currentScope); + return registerVariable(_varDecl.variable, _varDecl.location, *m_currentScope); } bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef) { bool success = true; - if (!m_currentScope->registerFunction(_funDef.name, _funDef.arguments.size(), _funDef.returns.size())) + vector<Scope::JuliaType> arguments; + for (auto const& _argument: _funDef.arguments) + arguments.push_back(_argument.type); + vector<Scope::JuliaType> returns; + for (auto const& _return: _funDef.returns) + returns.push_back(_return.type); + if (!m_currentScope->registerFunction(_funDef.name, arguments, returns)) { //@TODO secondary location m_errors.push_back(make_shared<Error>( @@ -102,14 +108,14 @@ bool ScopeFiller::operator()(Block const& _block) return success; } -bool ScopeFiller::registerVariable(string const& _name, SourceLocation const& _location, Scope& _scope) +bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& _location, Scope& _scope) { - if (!_scope.registerVariable(_name)) + if (!_scope.registerVariable(_name.name, _name.type)) { //@TODO secondary location m_errors.push_back(make_shared<Error>( Error::Type::DeclarationError, - "Variable name " + _name + " already taken in this scope.", + "Variable name " + _name.name + " already taken in this scope.", _location )); return false; diff --git a/libsolidity/inlineasm/AsmScopeFiller.h b/libsolidity/inlineasm/AsmScopeFiller.h index bb62948b..61428eea 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.h +++ b/libsolidity/inlineasm/AsmScopeFiller.h @@ -34,6 +34,7 @@ namespace solidity namespace assembly { +struct TypedName; struct Literal; struct Block; struct Label; @@ -72,7 +73,7 @@ public: private: bool registerVariable( - std::string const& _name, + TypedName const& _name, SourceLocation const& _location, Scope& _scope ); diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h index 77a7e02a..e223ccc9 100644 --- a/libsolidity/inlineasm/AsmStack.h +++ b/libsolidity/inlineasm/AsmStack.h @@ -24,6 +24,8 @@ #include <libsolidity/interface/Exceptions.h> +#include <libjulia/backends/AbstractAssembly.h> + #include <string> #include <functional> @@ -51,7 +53,7 @@ struct ExternalIdentifierAccess /// Resolve a an external reference given by the identifier in the given context. /// @returns the size of the value (number of stack slots) or size_t(-1) if not found. Resolver resolve; - using CodeGenerator = std::function<void(assembly::Identifier const&, IdentifierContext, eth::Assembly&)>; + using CodeGenerator = std::function<void(assembly::Identifier const&, IdentifierContext, julia::AbstractAssembly&)>; /// Generate code for retrieving the value (rvalue context) or storing the value (lvalue context) /// of an identifier. The code should be appended to the assembly. In rvalue context, the value is supposed /// to be put onto the stack, in lvalue context, the value is assumed to be at the top of the stack. |
