aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/inlineasm
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp11
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp146
-rw-r--r--libsolidity/inlineasm/AsmData.h18
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp67
-rw-r--r--libsolidity/inlineasm/AsmParser.h1
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp43
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h2
-rw-r--r--libsolidity/inlineasm/AsmScope.cpp8
-rw-r--r--libsolidity/inlineasm/AsmScope.h21
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.cpp16
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.h3
-rw-r--r--libsolidity/inlineasm/AsmStack.h4
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.