aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/inlineasm
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp102
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h21
-rw-r--r--libsolidity/inlineasm/AsmAnalysisInfo.h7
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp252
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h4
-rw-r--r--libsolidity/inlineasm/AsmData.h36
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp145
-rw-r--r--libsolidity/inlineasm/AsmParser.h3
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp31
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h6
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.cpp14
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.h8
-rw-r--r--libsolidity/inlineasm/AsmStack.cpp8
-rw-r--r--libsolidity/inlineasm/AsmStack.h23
14 files changed, 294 insertions, 366 deletions
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
index e03eea2e..eeb7d0a6 100644
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ b/libsolidity/inlineasm/AsmAnalysis.cpp
@@ -38,13 +38,10 @@ using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;
-AsmAnalyzer::AsmAnalyzer(
- AsmAnalysisInfo& _analysisInfo,
- ErrorList& _errors,
- ExternalIdentifierAccess::Resolver const& _resolver
-):
- m_resolver(_resolver), m_info(_analysisInfo), m_errors(_errors)
-{
+namespace {
+
+set<string> const builtinTypes{"bool", "u8", "s8", "u32", "s32", "u64", "s64", "u128", "s128", "u256", "s256"};
+
}
bool AsmAnalyzer::analyze(Block const& _block)
@@ -57,12 +54,14 @@ bool AsmAnalyzer::analyze(Block const& _block)
bool AsmAnalyzer::operator()(Label const& _label)
{
+ solAssert(!m_julia, "");
m_info.stackHeightInfo[&_label] = m_stackHeight;
return true;
}
bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
{
+ solAssert(!m_julia, "");
auto const& info = instructionInfo(_instruction.instruction);
m_stackHeight += info.ret - info.args;
m_info.stackHeightInfo[&_instruction] = m_stackHeight;
@@ -71,6 +70,7 @@ bool AsmAnalyzer::operator()(assembly::Instruction const& _instruction)
bool AsmAnalyzer::operator()(assembly::Literal const& _literal)
{
+ expectValidType(_literal.type, _literal.location);
++m_stackHeight;
if (_literal.kind == assembly::LiteralKind::String && _literal.value.size() > 32)
{
@@ -123,7 +123,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
{
size_t stackSize(-1);
if (m_resolver)
- stackSize = m_resolver(_identifier, IdentifierContext::RValue);
+ stackSize = m_resolver(_identifier, julia::IdentifierContext::RValue);
if (stackSize == size_t(-1))
{
// Only add an error message if the callback did not do it.
@@ -143,6 +143,7 @@ bool AsmAnalyzer::operator()(assembly::Identifier const& _identifier)
bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
{
+ solAssert(!m_julia, "");
bool success = true;
for (auto const& arg: _instr.arguments | boost::adaptors::reversed)
{
@@ -160,15 +161,15 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
return success;
}
-bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
+bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment)
{
+ solAssert(!m_julia, "");
bool success = checkAssignment(_assignment.variableName, size_t(-1));
m_info.stackHeightInfo[&_assignment] = m_stackHeight;
return success;
}
-
-bool AsmAnalyzer::operator()(FunctionalAssignment const& _assignment)
+bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
{
int const stackHeight = m_stackHeight;
bool success = boost::apply_visitor(*this, *_assignment.value);
@@ -181,10 +182,24 @@ bool AsmAnalyzer::operator()(FunctionalAssignment const& _assignment)
bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
{
+ int const expectedItems = _varDecl.variables.size();
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.variable.name)).active = true;
+ if ((m_stackHeight - stackHeight) != expectedItems)
+ {
+ m_errors.push_back(make_shared<Error>(
+ Error::Type::DeclarationError,
+ "Variable count mismatch.",
+ _varDecl.location
+ ));
+ return false;
+ }
+
+ for (auto const& variable: _varDecl.variables)
+ {
+ expectValidType(variable.type, variable.location);
+ boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)).active = true;
+ }
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
return success;
}
@@ -193,7 +208,10 @@ bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef)
{
Scope& bodyScope = scope(&_funDef.body);
for (auto const& var: _funDef.arguments + _funDef.returns)
+ {
+ expectValidType(var.type, var.location);
boost::get<Scope::Variable>(bodyScope.identifiers.at(var.name)).active = true;
+ }
int const stackHeight = m_stackHeight;
m_stackHeight = _funDef.arguments.size() + _funDef.returns.size();
@@ -274,6 +292,48 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall)
return success;
}
+bool AsmAnalyzer::operator()(Switch const& _switch)
+{
+ bool success = true;
+
+ int const initialStackHeight = m_stackHeight;
+ if (!boost::apply_visitor(*this, *_switch.expression))
+ success = false;
+ expectDeposit(1, initialStackHeight, locationOf(*_switch.expression));
+
+ set<tuple<LiteralKind, string>> cases;
+ for (auto const& _case: _switch.cases)
+ {
+ if (_case.value)
+ {
+ int const initialStackHeight = m_stackHeight;
+ if (!(*this)(*_case.value))
+ success = false;
+ expectDeposit(1, initialStackHeight, _case.value->location);
+ m_stackHeight--;
+
+ /// Note: the parser ensures there is only one default case
+ auto val = make_tuple(_case.value->kind, _case.value->value);
+ if (!cases.insert(val).second)
+ {
+ m_errors.push_back(make_shared<Error>(
+ Error::Type::DeclarationError,
+ "Duplicate case defined",
+ _case.location
+ ));
+ success = false;
+ }
+ }
+
+ if (!(*this)(_case.body))
+ success = false;
+ }
+
+ m_stackHeight--;
+
+ return success;
+}
+
bool AsmAnalyzer::operator()(Block const& _block)
{
bool success = true;
@@ -340,7 +400,7 @@ bool AsmAnalyzer::checkAssignment(assembly::Identifier const& _variable, size_t
variableSize = 1;
}
else if (m_resolver)
- variableSize = m_resolver(_variable, IdentifierContext::LValue);
+ variableSize = m_resolver(_variable, julia::IdentifierContext::LValue);
if (variableSize == size_t(-1))
{
// Only add message if the callback did not.
@@ -395,7 +455,21 @@ bool AsmAnalyzer::expectDeposit(int const _deposit, int const _oldHeight, Source
Scope& AsmAnalyzer::scope(Block const* _block)
{
+ solAssert(m_info.scopes.count(_block) == 1, "Scope requested but not present.");
auto scopePtr = m_info.scopes.at(_block);
solAssert(scopePtr, "Scope requested but not present.");
return *scopePtr;
}
+
+void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location)
+{
+ if (!m_julia)
+ return;
+
+ if (!builtinTypes.count(type))
+ m_errors.push_back(make_shared<Error>(
+ Error::Type::TypeError,
+ "\"" + type + "\" is not a valid type (user defined types are not yet supported).",
+ _location
+ ));
+}
diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h
index 426ee0d2..87d41e11 100644
--- a/libsolidity/inlineasm/AsmAnalysis.h
+++ b/libsolidity/inlineasm/AsmAnalysis.h
@@ -40,13 +40,14 @@ struct Literal;
struct Block;
struct Label;
struct FunctionalInstruction;
-struct FunctionalAssignment;
+struct Assignment;
struct VariableDeclaration;
struct Instruction;
struct Identifier;
-struct Assignment;
+struct StackAssignment;
struct FunctionDefinition;
struct FunctionCall;
+struct Switch;
struct Scope;
@@ -60,11 +61,12 @@ struct AsmAnalysisInfo;
class AsmAnalyzer: public boost::static_visitor<bool>
{
public:
- AsmAnalyzer(
+ explicit AsmAnalyzer(
AsmAnalysisInfo& _analysisInfo,
ErrorList& _errors,
- ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver()
- );
+ bool _julia = false,
+ julia::ExternalIdentifierAccess::Resolver const& _resolver = julia::ExternalIdentifierAccess::Resolver()
+ ): m_resolver(_resolver), m_info(_analysisInfo), m_errors(_errors), m_julia(_julia) {}
bool analyze(assembly::Block const& _block);
@@ -73,11 +75,12 @@ public:
bool operator()(assembly::Identifier const&);
bool operator()(assembly::FunctionalInstruction const& _functionalInstruction);
bool operator()(assembly::Label const& _label);
- bool operator()(assembly::Assignment const&);
- bool operator()(assembly::FunctionalAssignment const& _functionalAssignment);
+ bool operator()(assembly::StackAssignment const&);
+ bool operator()(assembly::Assignment const& _assignment);
bool operator()(assembly::VariableDeclaration const& _variableDeclaration);
bool operator()(assembly::FunctionDefinition const& _functionDefinition);
bool operator()(assembly::FunctionCall const& _functionCall);
+ bool operator()(assembly::Switch const& _switch);
bool operator()(assembly::Block const& _block);
private:
@@ -86,16 +89,18 @@ private:
bool checkAssignment(assembly::Identifier const& _assignment, size_t _valueSize = size_t(-1));
bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location);
Scope& scope(assembly::Block const* _block);
+ void expectValidType(std::string const& type, SourceLocation const& _location);
/// This is used when we enter the body of a function definition. There, the parameters
/// and return parameters appear as variables which are already on the stack before
/// we enter the block.
int m_virtualVariablesInNextBlock = 0;
int m_stackHeight = 0;
- ExternalIdentifierAccess::Resolver const& m_resolver;
+ julia::ExternalIdentifierAccess::Resolver const& m_resolver;
Scope* m_currentScope = nullptr;
AsmAnalysisInfo& m_info;
ErrorList& m_errors;
+ bool m_julia = false;
};
}
diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.h b/libsolidity/inlineasm/AsmAnalysisInfo.h
index e21eb2c5..18382db0 100644
--- a/libsolidity/inlineasm/AsmAnalysisInfo.h
+++ b/libsolidity/inlineasm/AsmAnalysisInfo.h
@@ -36,17 +36,18 @@ struct Literal;
struct Block;
struct Label;
struct FunctionalInstruction;
-struct FunctionalAssignment;
+struct Assignment;
struct VariableDeclaration;
struct Instruction;
struct Identifier;
-struct Assignment;
+struct StackAssignment;
struct FunctionDefinition;
struct FunctionCall;
+struct Switch;
struct Scope;
-using Statement = boost::variant<Instruction, Literal, Label, Assignment, Identifier, FunctionalAssignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>;
+using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
struct AsmAnalysisInfo
{
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp
index b8af9dc6..6a44faac 100644
--- a/libsolidity/inlineasm/AsmCodeGen.cpp
+++ b/libsolidity/inlineasm/AsmCodeGen.cpp
@@ -32,7 +32,8 @@
#include <libevmasm/SourceLocation.h>
#include <libevmasm/Instruction.h>
-#include <libjulia/backends/AbstractAssembly.h>
+#include <libjulia/backends/evm/AbstractAssembly.h>
+#include <libjulia/backends/evm/EVMCodeTransform.h>
#include <libdevcore/CommonIO.h>
@@ -48,15 +49,6 @@ using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;
-struct GeneratorState
-{
- GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo):
- errors(_errors), info(_analysisInfo) {}
-
- ErrorList& errors;
- AsmAnalysisInfo info;
-};
-
class EthAssemblyAdapter: public julia::AbstractAssembly
{
public:
@@ -107,246 +99,15 @@ private:
eth::Assembly& m_assembly;
};
-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,
- julia::AbstractAssembly& _assembly,
- assembly::Block const& _block,
- assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess()
- ): CodeTransform(_state, _assembly, _block, _identifierAccess, _assembly.stackHeight())
- {
- }
-
-private:
- CodeTransform(
- GeneratorState& _state,
- julia::AbstractAssembly& _assembly,
- assembly::Block const& _block,
- assembly::ExternalIdentifierAccess const& _identifierAccess,
- int _initialStackHeight
- ):
- m_state(_state),
- m_assembly(_assembly),
- m_scope(*m_state.info.scopes.at(&_block)),
- m_identifierAccess(_identifierAccess),
- m_initialStackHeight(_initialStackHeight)
- {
- int blockStartStackHeight = m_assembly.stackHeight();
- std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this));
-
- m_assembly.setSourceLocation(_block.location);
-
- // pop variables
- for (auto const& identifier: m_scope.identifiers)
- if (identifier.second.type() == typeid(Scope::Variable))
- m_assembly.appendInstruction(solidity::Instruction::POP);
-
- int deposit = m_assembly.stackHeight() - blockStartStackHeight;
- solAssert(deposit == 0, "Invalid stack height at end of block.");
- }
-
-public:
- void operator()(assembly::Instruction const& _instruction)
- {
- m_assembly.setSourceLocation(_instruction.location);
- m_assembly.appendInstruction(_instruction.instruction);
- checkStackHeight(&_instruction);
- }
- void operator()(assembly::Literal const& _literal)
- {
- 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_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft)));
- }
- checkStackHeight(&_literal);
- }
- void operator()(assembly::Identifier const& _identifier)
- {
- 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_assembly.appendInstruction(solidity::dupInstruction(heightDiff));
- else
- // Store something to balance the stack
- m_assembly.appendConstant(u256(0));
- },
- [=](Scope::Label& _label)
- {
- assignLabelIdIfUnset(_label);
- m_assembly.appendLabelReference(*_label.id);
- },
- [=](Scope::Function&)
- {
- solAssert(false, "Function not removed during desugaring.");
- }
- )))
- {
- return;
- }
- solAssert(
- m_identifierAccess.generateCode,
- "Identifier not found and no external access available."
- );
- 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_assembly.stackHeight();
- boost::apply_visitor(*this, *it);
- expectDeposit(1, height);
- }
- (*this)(_instr.instruction);
- checkStackHeight(&_instr);
- }
- void operator()(assembly::FunctionCall const&)
- {
- solAssert(false, "Function call not removed during desugaring phase.");
- }
- void operator()(Label const& _label)
- {
- 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_assembly.appendLabel(*label.id);
- checkStackHeight(&_label);
- }
- void operator()(assembly::Assignment const& _assignment)
- {
- m_assembly.setSourceLocation(_assignment.location);
- generateAssignment(_assignment.variableName, _assignment.location);
- checkStackHeight(&_assignment);
- }
- void operator()(FunctionalAssignment const& _assignment)
- {
- int height = m_assembly.stackHeight();
- boost::apply_visitor(*this, *_assignment.value);
- expectDeposit(1, height);
- m_assembly.setSourceLocation(_assignment.location);
- generateAssignment(_assignment.variableName, _assignment.location);
- checkStackHeight(&_assignment);
- }
- void operator()(assembly::VariableDeclaration const& _varDecl)
- {
- 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.variable.name));
- var.stackHeight = height;
- var.active = true;
- }
- void operator()(assembly::Block const& _block)
- {
- CodeTransform(m_state, m_assembly, _block, m_identifierAccess, m_initialStackHeight);
- checkStackHeight(&_block);
- }
- void operator()(assembly::FunctionDefinition const&)
- {
- solAssert(false, "Function definition not removed during desugaring phase.");
- }
-
-private:
- void generateAssignment(assembly::Identifier const& _variableName, SourceLocation const& _location)
- {
- auto var = m_scope.lookup(_variableName.name);
- if (var)
- {
- Scope::Variable const& _var = boost::get<Scope::Variable>(*var);
- if (int heightDiff = variableHeightDiff(_var, _location, true))
- m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1));
- m_assembly.appendInstruction(solidity::Instruction::POP);
- }
- else
- {
- solAssert(
- m_identifierAccess.generateCode,
- "Identifier not found and no external access available."
- );
- m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_assembly);
- }
- }
-
- /// Determines the stack height difference to the given variables. Automatically generates
- /// errors if it is not yet in scope or the height difference is too large. Returns 0 on
- /// errors and the (positive) stack height difference otherwise.
- int variableHeightDiff(Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap)
- {
- int heightDiff = m_assembly.stackHeight() - _var.stackHeight;
- if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16))
- {
- //@TODO move this to analysis phase.
- m_state.errors.push_back(make_shared<Error>(
- Error::Type::TypeError,
- "Variable inaccessible, too deep inside stack (" + boost::lexical_cast<string>(heightDiff) + ")",
- _location
- ));
- return 0;
- }
- else
- return heightDiff;
- }
-
- void expectDeposit(int _deposit, int _oldHeight)
- {
- 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_assembly.stackHeight() - m_initialStackHeight,
- "Stack height mismatch between analysis and code generation phase."
- );
- }
-
- /// 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)
- _label.id.reset(m_assembly.newLabelId());
- }
-
-
- GeneratorState& m_state;
- julia::AbstractAssembly& m_assembly;
- Scope& m_scope;
- ExternalIdentifierAccess m_identifierAccess;
- int const m_initialStackHeight;
-};
-
eth::Assembly assembly::CodeGenerator::assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
- ExternalIdentifierAccess const& _identifierAccess
+ julia::ExternalIdentifierAccess const& _identifierAccess
)
{
eth::Assembly assembly;
- GeneratorState state(m_errors, _analysisInfo);
EthAssemblyAdapter assemblyAdapter(assembly);
- CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess);
+ julia::CodeTransform(m_errors, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess);
return assembly;
}
@@ -354,10 +115,9 @@ void assembly::CodeGenerator::assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
eth::Assembly& _assembly,
- ExternalIdentifierAccess const& _identifierAccess
+ julia::ExternalIdentifierAccess const& _identifierAccess
)
{
- GeneratorState state(m_errors, _analysisInfo);
EthAssemblyAdapter assemblyAdapter(_assembly);
- CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess);
+ julia::CodeTransform(m_errors, assemblyAdapter, _parsedData, _analysisInfo, _identifierAccess);
}
diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h
index e830e047..1b43d2f6 100644
--- a/libsolidity/inlineasm/AsmCodeGen.h
+++ b/libsolidity/inlineasm/AsmCodeGen.h
@@ -48,14 +48,14 @@ public:
eth::Assembly assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
- ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
+ julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
);
/// Performs code generation and appends generated to to _assembly.
void assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
eth::Assembly& _assembly,
- ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
+ julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
);
private:
diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h
index 8efe1f07..72afeef1 100644
--- a/libsolidity/inlineasm/AsmData.h
+++ b/libsolidity/inlineasm/AsmData.h
@@ -40,6 +40,21 @@ using TypedNameList = std::vector<TypedName>;
/// What follows are the AST nodes for assembly.
+struct Instruction;
+struct Literal;
+struct Label;
+struct StackAssignment;
+struct Identifier;
+struct Assignment;
+struct VariableDeclaration;
+struct FunctionalInstruction;
+struct FunctionDefinition;
+struct FunctionCall;
+struct Switch;
+struct Block;
+
+using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
+
/// Direct EVM instruction (except PUSHi and JUMPDEST)
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
/// Literal number or string (up to 32 bytes)
@@ -47,29 +62,26 @@ 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;
/// Jump label ("name:")
struct Label { SourceLocation location; std::string name; };
-/// Assignemnt (":= x", moves stack top into x, potentially multiple slots)
-struct Assignment { SourceLocation location; Identifier variableName; };
-struct FunctionalAssignment;
-struct VariableDeclaration;
-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:u256)", expects push-1-expression on the right hand
+/// Assignment from stack (":= x", moves stack top into x, potentially multiple slots)
+struct StackAssignment { SourceLocation location; Identifier variableName; };
+/// 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; };
+struct Assignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
/// 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:u256 := mload(20:u256)"), non-hoisted
-struct VariableDeclaration { SourceLocation location; TypedName variable; std::shared_ptr<Statement> value; };
+struct VariableDeclaration { SourceLocation location; TypedNameList variables; 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; TypedNameList arguments; TypedNameList returns; Block body; };
+/// Switch case or default case
+struct Case { SourceLocation location; std::shared_ptr<Literal> value; Block body; };
+/// Switch statement
+struct Switch { SourceLocation location; std::shared_ptr<Statement> expression; std::vector<Case> cases; };
struct LocationExtractor: boost::static_visitor<SourceLocation>
{
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index a96984f5..80409c63 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -50,16 +50,16 @@ assembly::Block Parser::parseBlock()
{
assembly::Block block = createWithLocation<Block>();
expectToken(Token::LBrace);
- while (m_scanner->currentToken() != Token::RBrace)
+ while (currentToken() != Token::RBrace)
block.statements.emplace_back(parseStatement());
block.location.end = endPosition();
- m_scanner->next();
+ advance();
return block;
}
assembly::Statement Parser::parseStatement()
{
- switch (m_scanner->currentToken())
+ switch (currentToken())
{
case Token::Let:
return parseVariableDeclaration();
@@ -67,24 +67,41 @@ assembly::Statement Parser::parseStatement()
return parseFunctionDefinition();
case Token::LBrace:
return parseBlock();
+ case Token::Switch:
+ {
+ assembly::Switch _switch = createWithLocation<assembly::Switch>();
+ m_scanner->next();
+ _switch.expression = make_shared<Statement>(parseExpression());
+ if (_switch.expression->type() == typeid(assembly::Instruction))
+ fatalParserError("Instructions are not supported as expressions for switch.");
+ while (m_scanner->currentToken() == Token::Case)
+ _switch.cases.emplace_back(parseCase());
+ if (m_scanner->currentToken() == Token::Default)
+ _switch.cases.emplace_back(parseCase());
+ if (m_scanner->currentToken() == Token::Default)
+ fatalParserError("Only one default case allowed.");
+ else if (m_scanner->currentToken() == Token::Case)
+ fatalParserError("Case not allowed after default case.");
+ if (_switch.cases.size() == 0)
+ fatalParserError("Switch statement without any cases.");
+ _switch.location.end = _switch.cases.back().body.location.end;
+ return _switch;
+ }
case Token::Assign:
{
if (m_julia)
break;
- assembly::Assignment assignment = createWithLocation<assembly::Assignment>();
- m_scanner->next();
+ assembly::StackAssignment assignment = createWithLocation<assembly::StackAssignment>();
+ advance();
expectToken(Token::Colon);
assignment.variableName.location = location();
- assignment.variableName.name = m_scanner->currentLiteral();
+ assignment.variableName.name = currentLiteral();
if (!m_julia && instructions().count(assignment.variableName.name))
fatalParserError("Identifier expected, got instruction name.");
assignment.location.end = endPosition();
expectToken(Token::Identifier);
return assignment;
}
- case Token::Return: // opcode
- case Token::Byte: // opcode
- case Token::Address: // opcode
default:
break;
}
@@ -93,29 +110,28 @@ assembly::Statement Parser::parseStatement()
// literal,
// identifier (might turn into label or functional assignment)
Statement statement(parseElementaryOperation(false));
- switch (m_scanner->currentToken())
+ switch (currentToken())
{
case Token::LParen:
- return parseFunctionalInstruction(std::move(statement));
+ return parseCall(std::move(statement));
case Token::Colon:
{
if (statement.type() != typeid(assembly::Identifier))
fatalParserError("Label name / variable name must precede \":\".");
assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
- m_scanner->next();
+ advance();
// identifier:=: should be parsed as identifier: =: (i.e. a label),
// while identifier:= (being followed by a non-colon) as identifier := (assignment).
- if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon)
+ if (currentToken() == Token::Assign && peekNextToken() != Token::Colon)
{
- // functional assignment
- FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location);
+ assembly::Assignment assignment = createWithLocation<assembly::Assignment>(identifier.location);
if (!m_julia && instructions().count(identifier.name))
fatalParserError("Cannot use instruction names for identifier names.");
- m_scanner->next();
- funAss.variableName = identifier;
- funAss.value.reset(new Statement(parseExpression()));
- funAss.location.end = locationOf(*funAss.value).end;
- return funAss;
+ advance();
+ assignment.variableName = identifier;
+ assignment.value.reset(new Statement(parseExpression()));
+ assignment.location.end = locationOf(*assignment.value).end;
+ return assignment;
}
else
{
@@ -135,11 +151,31 @@ assembly::Statement Parser::parseStatement()
return statement;
}
+assembly::Case Parser::parseCase()
+{
+ assembly::Case _case = createWithLocation<assembly::Case>();
+ if (m_scanner->currentToken() == Token::Default)
+ m_scanner->next();
+ else if (m_scanner->currentToken() == Token::Case)
+ {
+ m_scanner->next();
+ assembly::Statement statement = parseElementaryOperation();
+ if (statement.type() != typeid(assembly::Literal))
+ fatalParserError("Literal expected.");
+ _case.value = make_shared<Literal>(std::move(boost::get<assembly::Literal>(statement)));
+ }
+ else
+ fatalParserError("Case or default case expected.");
+ _case.body = parseBlock();
+ _case.location.end = _case.body.location.end;
+ return _case;
+}
+
assembly::Statement Parser::parseExpression()
{
Statement operation = parseElementaryOperation(true);
- if (m_scanner->currentToken() == Token::LParen)
- return parseFunctionalInstruction(std::move(operation));
+ if (currentToken() == Token::LParen)
+ return parseCall(std::move(operation));
else
return operation;
}
@@ -171,7 +207,7 @@ std::map<string, dev::solidity::Instruction> const& Parser::instructions()
assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
{
Statement ret;
- switch (m_scanner->currentToken())
+ switch (currentToken())
{
case Token::Identifier:
case Token::Return:
@@ -179,14 +215,14 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
case Token::Address:
{
string literal;
- if (m_scanner->currentToken() == Token::Return)
+ if (currentToken() == Token::Return)
literal = "return";
- else if (m_scanner->currentToken() == Token::Byte)
+ else if (currentToken() == Token::Byte)
literal = "byte";
- else if (m_scanner->currentToken() == Token::Address)
+ else if (currentToken() == Token::Address)
literal = "address";
else
- literal = m_scanner->currentLiteral();
+ literal = currentLiteral();
// first search the set of instructions.
if (!m_julia && instructions().count(literal))
{
@@ -201,7 +237,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
}
else
ret = Identifier{location(), literal};
- m_scanner->next();
+ advance();
break;
}
case Token::StringLiteral:
@@ -210,7 +246,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
case Token::FalseLiteral:
{
LiteralKind kind = LiteralKind::Number;
- switch (m_scanner->currentToken())
+ switch (currentToken())
{
case Token::StringLiteral:
kind = LiteralKind::String;
@@ -229,10 +265,10 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
Literal literal{
location(),
kind,
- m_scanner->currentLiteral(),
+ currentLiteral(),
""
};
- m_scanner->next();
+ advance();
if (m_julia)
{
expectToken(Token::Colon);
@@ -248,7 +284,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher)
fatalParserError(
m_julia ?
"Literal or identifier expected." :
- "Expected elementary inline assembly operation."
+ "Literal, identifier or instruction expected."
);
}
return ret;
@@ -258,7 +294,14 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
{
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
expectToken(Token::Let);
- varDecl.variable = parseTypedName();
+ while (true)
+ {
+ varDecl.variables.emplace_back(parseTypedName());
+ if (currentToken() == Token::Comma)
+ expectToken(Token::Comma);
+ else
+ break;
+ }
expectToken(Token::Colon);
expectToken(Token::Assign);
varDecl.value.reset(new Statement(parseExpression()));
@@ -272,22 +315,22 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
expectToken(Token::Function);
funDef.name = expectAsmIdentifier();
expectToken(Token::LParen);
- while (m_scanner->currentToken() != Token::RParen)
+ while (currentToken() != Token::RParen)
{
funDef.arguments.emplace_back(parseTypedName());
- if (m_scanner->currentToken() == Token::RParen)
+ if (currentToken() == Token::RParen)
break;
expectToken(Token::Comma);
}
expectToken(Token::RParen);
- if (m_scanner->currentToken() == Token::Sub)
+ if (currentToken() == Token::Sub)
{
expectToken(Token::Sub);
expectToken(Token::GreaterThan);
while (true)
{
funDef.returns.emplace_back(parseTypedName());
- if (m_scanner->currentToken() == Token::LBrace)
+ if (currentToken() == Token::LBrace)
break;
expectToken(Token::Comma);
}
@@ -297,7 +340,7 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition()
return funDef;
}
-assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _instruction)
+assembly::Statement Parser::parseCall(assembly::Statement&& _instruction)
{
if (_instruction.type() == typeid(Instruction))
{
@@ -315,10 +358,20 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in
unsigned args = unsigned(instrInfo.args);
for (unsigned i = 0; i < args; ++i)
{
+ /// check for premature closing parentheses
+ if (currentToken() == Token::RParen)
+ fatalParserError(string(
+ "Expected expression (" +
+ instrInfo.name +
+ " expects " +
+ boost::lexical_cast<string>(args) +
+ " arguments)"
+ ));
+
ret.arguments.emplace_back(parseExpression());
if (i != args - 1)
{
- if (m_scanner->currentToken() != Token::Comma)
+ if (currentToken() != Token::Comma)
fatalParserError(string(
"Expected comma (" +
instrInfo.name +
@@ -327,11 +380,11 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in
" arguments)"
));
else
- m_scanner->next();
+ advance();
}
}
ret.location.end = endPosition();
- if (m_scanner->currentToken() == Token::Comma)
+ if (currentToken() == Token::Comma)
fatalParserError(
string("Expected ')' (" + instrInfo.name + " expects " + boost::lexical_cast<string>(args) + " arguments)")
);
@@ -344,10 +397,10 @@ assembly::Statement Parser::parseFunctionalInstruction(assembly::Statement&& _in
ret.functionName = std::move(boost::get<Identifier>(_instruction));
ret.location = ret.functionName.location;
expectToken(Token::LParen);
- while (m_scanner->currentToken() != Token::RParen)
+ while (currentToken() != Token::RParen)
{
ret.arguments.emplace_back(parseExpression());
- if (m_scanner->currentToken() == Token::RParen)
+ if (currentToken() == Token::RParen)
break;
expectToken(Token::Comma);
}
@@ -380,12 +433,12 @@ TypedName Parser::parseTypedName()
string Parser::expectAsmIdentifier()
{
- string name = m_scanner->currentLiteral();
+ string name = currentLiteral();
if (m_julia)
{
- if (m_scanner->currentToken() == Token::Bool)
+ if (currentToken() == Token::Bool)
{
- m_scanner->next();
+ advance();
return name;
}
}
diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h
index addc1725..138af337 100644
--- a/libsolidity/inlineasm/AsmParser.h
+++ b/libsolidity/inlineasm/AsmParser.h
@@ -62,13 +62,14 @@ protected:
Block parseBlock();
Statement parseStatement();
+ Case parseCase();
/// Parses a functional expression that has to push exactly one stack element
Statement parseExpression();
std::map<std::string, dev::solidity::Instruction> const& instructions();
Statement parseElementaryOperation(bool _onlySinglePusher = false);
VariableDeclaration parseVariableDeclaration();
FunctionDefinition parseFunctionDefinition();
- Statement parseFunctionalInstruction(Statement&& _instruction);
+ Statement parseCall(Statement&& _instruction);
TypedName parseTypedName();
std::string expectAsmIdentifier();
diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp
index 636e61b8..e282e5e8 100644
--- a/libsolidity/inlineasm/AsmPrinter.cpp
+++ b/libsolidity/inlineasm/AsmPrinter.cpp
@@ -108,20 +108,29 @@ string AsmPrinter::operator()(assembly::Label const& _label)
return _label.name + ":";
}
-string AsmPrinter::operator()(assembly::Assignment const& _assignment)
+string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
{
solAssert(!m_julia, "");
return "=: " + (*this)(_assignment.variableName);
}
-string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalAssignment)
+string AsmPrinter::operator()(assembly::Assignment const& _assignment)
{
- return (*this)(_functionalAssignment.variableName) + " := " + boost::apply_visitor(*this, *_functionalAssignment.value);
+ return (*this)(_assignment.variableName) + " := " + boost::apply_visitor(*this, *_assignment.value);
}
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
{
- return "let " + _variableDeclaration.variable.name + appendTypeName(_variableDeclaration.variable.type) + " := " + boost::apply_visitor(*this, *_variableDeclaration.value);
+ string out = "let ";
+ out += boost::algorithm::join(
+ _variableDeclaration.variables | boost::adaptors::transformed(
+ [this](TypedName variable) { return variable.name + appendTypeName(variable.type); }
+ ),
+ ", "
+ );
+ out += " := ";
+ out += boost::apply_visitor(*this, *_variableDeclaration.value);
+ return out;
}
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
@@ -158,6 +167,20 @@ string AsmPrinter::operator()(assembly::FunctionCall const& _functionCall)
")";
}
+string AsmPrinter::operator()(Switch const& _switch)
+{
+ string out = "switch " + boost::apply_visitor(*this, *_switch.expression);
+ for (auto const& _case: _switch.cases)
+ {
+ if (!_case.value)
+ out += "\ndefault ";
+ else
+ out += "\ncase " + (*this)(*_case.value) + " ";
+ out += (*this)(_case.body);
+ }
+ return out;
+}
+
string AsmPrinter::operator()(Block const& _block)
{
if (_block.statements.empty())
diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h
index 282fd7e3..b0d7fc09 100644
--- a/libsolidity/inlineasm/AsmPrinter.h
+++ b/libsolidity/inlineasm/AsmPrinter.h
@@ -35,11 +35,12 @@ struct Literal;
struct Identifier;
struct FunctionalInstruction;
struct Label;
+struct StackAssignment;
struct Assignment;
-struct FunctionalAssignment;
struct VariableDeclaration;
struct FunctionDefinition;
struct FunctionCall;
+struct Switch;
struct Block;
class AsmPrinter: public boost::static_visitor<std::string>
@@ -52,11 +53,12 @@ public:
std::string operator()(assembly::Identifier const& _identifier);
std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction);
std::string operator()(assembly::Label const& _label);
+ std::string operator()(assembly::StackAssignment const& _assignment);
std::string operator()(assembly::Assignment const& _assignment);
- std::string operator()(assembly::FunctionalAssignment const& _functionalAssignment);
std::string operator()(assembly::VariableDeclaration const& _variableDeclaration);
std::string operator()(assembly::FunctionDefinition const& _functionDefinition);
std::string operator()(assembly::FunctionCall const& _functionCall);
+ std::string operator()(assembly::Switch const& _switch);
std::string operator()(assembly::Block const& _block);
private:
diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp
index eb10dbb3..7eb6a9ed 100644
--- a/libsolidity/inlineasm/AsmScopeFiller.cpp
+++ b/libsolidity/inlineasm/AsmScopeFiller.cpp
@@ -59,7 +59,10 @@ bool ScopeFiller::operator()(Label const& _item)
bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl)
{
- return registerVariable(_varDecl.variable, _varDecl.location, *m_currentScope);
+ for (auto const& variable: _varDecl.variables)
+ if (!registerVariable(variable, _varDecl.location, *m_currentScope))
+ return false;
+ return true;
}
bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
@@ -94,6 +97,15 @@ bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
return success;
}
+bool ScopeFiller::operator()(Switch const& _switch)
+{
+ bool success = true;
+ for (auto const& _case: _switch.cases)
+ if (!(*this)(_case.body))
+ success = false;
+ return success;
+}
+
bool ScopeFiller::operator()(Block const& _block)
{
bool success = true;
diff --git a/libsolidity/inlineasm/AsmScopeFiller.h b/libsolidity/inlineasm/AsmScopeFiller.h
index 61428eea..c7179b3b 100644
--- a/libsolidity/inlineasm/AsmScopeFiller.h
+++ b/libsolidity/inlineasm/AsmScopeFiller.h
@@ -39,13 +39,14 @@ struct Literal;
struct Block;
struct Label;
struct FunctionalInstruction;
-struct FunctionalAssignment;
+struct Assignment;
struct VariableDeclaration;
struct Instruction;
struct Identifier;
-struct Assignment;
+struct StackAssignment;
struct FunctionDefinition;
struct FunctionCall;
+struct Switch;
struct Scope;
@@ -64,11 +65,12 @@ public:
bool operator()(assembly::Identifier const&) { return true; }
bool operator()(assembly::FunctionalInstruction const&) { return true; }
bool operator()(assembly::Label const& _label);
+ bool operator()(assembly::StackAssignment const&) { return true; }
bool operator()(assembly::Assignment const&) { return true; }
- bool operator()(assembly::FunctionalAssignment const&) { return true; }
bool operator()(assembly::VariableDeclaration const& _variableDeclaration);
bool operator()(assembly::FunctionDefinition const& _functionDefinition);
bool operator()(assembly::FunctionCall const&) { return true; }
+ bool operator()(assembly::Switch const& _switch);
bool operator()(assembly::Block const& _block);
private:
diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp
index c2a7d8ea..fe443c08 100644
--- a/libsolidity/inlineasm/AsmStack.cpp
+++ b/libsolidity/inlineasm/AsmStack.cpp
@@ -42,7 +42,7 @@ using namespace dev::solidity::assembly;
bool InlineAssemblyStack::parse(
shared_ptr<Scanner> const& _scanner,
- ExternalIdentifierAccess::Resolver const& _resolver
+ julia::ExternalIdentifierAccess::Resolver const& _resolver
)
{
m_parserResult = make_shared<Block>();
@@ -53,7 +53,7 @@ bool InlineAssemblyStack::parse(
*m_parserResult = std::move(*result);
AsmAnalysisInfo analysisInfo;
- return (AsmAnalyzer(analysisInfo, m_errors, _resolver)).analyze(*m_parserResult);
+ return (AsmAnalyzer(analysisInfo, m_errors, false, _resolver)).analyze(*m_parserResult);
}
string InlineAssemblyStack::toString()
@@ -73,7 +73,7 @@ eth::Assembly InlineAssemblyStack::assemble()
bool InlineAssemblyStack::parseAndAssemble(
string const& _input,
eth::Assembly& _assembly,
- ExternalIdentifierAccess const& _identifierAccess
+ julia::ExternalIdentifierAccess const& _identifierAccess
)
{
ErrorList errors;
@@ -84,7 +84,7 @@ bool InlineAssemblyStack::parseAndAssemble(
solAssert(parserResult, "");
AsmAnalysisInfo analysisInfo;
- AsmAnalyzer analyzer(analysisInfo, errors, _identifierAccess.resolve);
+ AsmAnalyzer analyzer(analysisInfo, errors, false, _identifierAccess.resolve);
solAssert(analyzer.analyze(*parserResult), "");
CodeGenerator(errors).assemble(*parserResult, analysisInfo, _assembly, _identifierAccess);
diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h
index e223ccc9..23072a88 100644
--- a/libsolidity/inlineasm/AsmStack.h
+++ b/libsolidity/inlineasm/AsmStack.h
@@ -24,7 +24,7 @@
#include <libsolidity/interface/Exceptions.h>
-#include <libjulia/backends/AbstractAssembly.h>
+#include <libjulia/backends/evm/AbstractAssembly.h>
#include <string>
#include <functional>
@@ -43,23 +43,6 @@ namespace assembly
struct Block;
struct Identifier;
-enum class IdentifierContext { LValue, RValue };
-
-/// Object that is used to resolve references and generate code for access to identifiers external
-/// to inline assembly (not used in standalone assembly mode).
-struct ExternalIdentifierAccess
-{
- using Resolver = std::function<size_t(assembly::Identifier const&, IdentifierContext)>;
- /// 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, 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.
- CodeGenerator generateCode;
-};
-
class InlineAssemblyStack
{
public:
@@ -67,7 +50,7 @@ public:
/// @return false or error.
bool parse(
std::shared_ptr<Scanner> const& _scanner,
- ExternalIdentifierAccess::Resolver const& _externalIdentifierResolver = ExternalIdentifierAccess::Resolver()
+ julia::ExternalIdentifierAccess::Resolver const& _externalIdentifierResolver = julia::ExternalIdentifierAccess::Resolver()
);
/// Converts the parser result back into a string form (not necessarily the same form
/// as the source form, but it should parse into the same parsed form again).
@@ -79,7 +62,7 @@ public:
bool parseAndAssemble(
std::string const& _input,
eth::Assembly& _assembly,
- ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess()
+ julia::ExternalIdentifierAccess const& _identifierAccess = julia::ExternalIdentifierAccess()
);
ErrorList const& errors() const { return m_errors; }