Browse Source

Compiler for assignments.

cl-refactor
Christian 10 years ago
parent
commit
2b6d66374d
  1. 13
      libsolidity/AST.cpp
  2. 9
      libsolidity/AST.h
  3. 109
      libsolidity/Compiler.cpp
  4. 16
      libsolidity/Compiler.h
  5. 1
      libsolidity/Exceptions.h
  6. 58
      solc/main.cpp
  7. 62
      test/solidityCompiler.cpp

13
libsolidity/AST.cpp

@ -326,6 +326,8 @@ void Assignment::checkTypeRequirements()
//@todo lefthandside actually has to be assignable //@todo lefthandside actually has to be assignable
// add a feature to the type system to check that // add a feature to the type system to check that
m_leftHandSide->checkTypeRequirements(); m_leftHandSide->checkTypeRequirements();
if (!m_leftHandSide->isLvalue())
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
expectType(*m_rightHandSide, *m_leftHandSide->getType()); expectType(*m_rightHandSide, *m_leftHandSide->getType());
m_type = m_leftHandSide->getType(); m_type = m_leftHandSide->getType();
if (m_assigmentOperator != Token::ASSIGN) if (m_assigmentOperator != Token::ASSIGN)
@ -338,8 +340,13 @@ void Assignment::checkTypeRequirements()
void UnaryOperation::checkTypeRequirements() void UnaryOperation::checkTypeRequirements()
{ {
// INC, DEC, NOT, BIT_NOT, DELETE // INC, DEC, ADD, SUB, NOT, BIT_NOT, DELETE
m_subExpression->checkTypeRequirements(); m_subExpression->checkTypeRequirements();
if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE)
{
if (!m_subExpression->isLvalue())
BOOST_THROW_EXCEPTION(createTypeError("Expression has to be an lvalue."));
}
m_type = m_subExpression->getType(); m_type = m_subExpression->getType();
if (!m_type->acceptsUnaryOperator(m_operator)) if (!m_type->acceptsUnaryOperator(m_operator))
BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type."));
@ -441,9 +448,9 @@ void Identifier::checkTypeRequirements()
if (variable) if (variable)
{ {
if (!variable->getType()) if (!variable->getType())
BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type " BOOST_THROW_EXCEPTION(createTypeError("Variable referenced before type could be determined."));
"could be determined."));
m_type = variable->getType(); m_type = variable->getType();
m_isLvalue = true;
return; return;
} }
//@todo can we unify these with TypeName::toType()? //@todo can we unify these with TypeName::toType()?

9
libsolidity/AST.h

@ -402,13 +402,17 @@ private:
class Expression: public Statement class Expression: public Statement
{ {
public: public:
Expression(Location const& _location): Statement(_location) {} Expression(Location const& _location): Statement(_location), m_isLvalue(false) {}
std::shared_ptr<Type const> const& getType() const { return m_type; } std::shared_ptr<Type const> const& getType() const { return m_type; }
bool isLvalue() const { return m_isLvalue; }
protected: protected:
//! Inferred type of the expression, only filled after a call to checkTypeRequirements(). //! Inferred type of the expression, only filled after a call to checkTypeRequirements().
std::shared_ptr<Type const> m_type; std::shared_ptr<Type const> m_type;
//! Whether or not this expression is an lvalue, i.e. something that can be assigned to.
//! This is set during calls to @a checkTypeRequirements()
bool m_isLvalue;
}; };
/// @} /// @}
@ -492,6 +496,9 @@ public:
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
Expression& getExpression() const { return *m_expression; }
std::vector<ASTPointer<Expression>> const& getArguments() const { return m_arguments; }
/// Returns true if this is not an actual function call, but an explicit type conversion /// Returns true if this is not an actual function call, but an explicit type conversion
/// or constructor call. /// or constructor call.
bool isTypeConversion() const; bool isTypeConversion() const;

109
libsolidity/Compiler.cpp

@ -81,22 +81,29 @@ AssemblyItems ExpressionCompiler::compileExpression(CompilerContext& _context,
return compiler.getAssemblyItems(); return compiler.getAssemblyItems();
} }
void ExpressionCompiler::endVisit(Assignment& _assignment) bool ExpressionCompiler::visit(Assignment& _assignment)
{ {
m_currentLValue = nullptr;
_assignment.getLeftHandSide().accept(*this);
Expression& rightHandSide = _assignment.getRightHandSide(); Expression& rightHandSide = _assignment.getRightHandSide();
Token::Value op = _assignment.getAssignmentOperator(); Token::Value op = _assignment.getAssignmentOperator();
if (op != Token::ASSIGN) if (op != Token::ASSIGN)
{ {
// compound assignment // compound assignment
// @todo retrieve lvalue value
rightHandSide.accept(*this); rightHandSide.accept(*this);
Type const& resultType = *_assignment.getType(); Type const& resultType = *_assignment.getType();
cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType);
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType); appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
} }
else else
{
append(eth::Instruction::POP); //@todo do not retrieve the value in the first place
rightHandSide.accept(*this); rightHandSide.accept(*this);
// @todo store value }
storeInLValue(_assignment);
return false;
} }
void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
@ -114,30 +121,31 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation)
append(eth::Instruction::BNOT); append(eth::Instruction::BNOT);
break; break;
case Token::DELETE: // delete case Token::DELETE: // delete
{
// a -> a xor a (= 0). // a -> a xor a (= 0).
// @todo this should also be an assignment
// @todo semantics change for complex types // @todo semantics change for complex types
append(eth::Instruction::DUP1); append(eth::Instruction::DUP1);
append(eth::Instruction::XOR); append(eth::Instruction::XOR);
storeInLValue(_unaryOperation);
break; break;
}
case Token::INC: // ++ (pre- or postfix) case Token::INC: // ++ (pre- or postfix)
// @todo this should also be an assignment case Token::DEC: // -- (pre- or postfix)
if (_unaryOperation.isPrefixOperation()) if (!_unaryOperation.isPrefixOperation())
{ append(eth::Instruction::DUP1);
append(eth::Instruction::PUSH1); append(eth::Instruction::PUSH1);
append(1); append(1);
if (_unaryOperation.getOperator() == Token::INC)
append(eth::Instruction::ADD); append(eth::Instruction::ADD);
} else
break;
case Token::DEC: // -- (pre- or postfix)
// @todo this should also be an assignment
if (_unaryOperation.isPrefixOperation())
{ {
append(eth::Instruction::PUSH1);
append(1);
append(eth::Instruction::SWAP1); //@todo avoid this append(eth::Instruction::SWAP1); //@todo avoid this
append(eth::Instruction::SUB); append(eth::Instruction::SUB);
} }
if (_unaryOperation.isPrefixOperation())
storeInLValue(_unaryOperation);
else
moveToLValue(_unaryOperation);
break; break;
case Token::ADD: // + case Token::ADD: // +
// unary add, so basically no-op // unary add, so basically no-op
@ -190,28 +198,38 @@ void ExpressionCompiler::endVisit(FunctionCall& _functionCall)
{ {
if (_functionCall.isTypeConversion()) if (_functionCall.isTypeConversion())
{ {
//@todo binary representation for all supported types (bool and int) is the same, so no-op //@todo we only have integers and bools for now which cannot be explicitly converted
// here for now. assert(_functionCall.getArguments().size() == 1);
cleanHigherOrderBitsIfNeeded(*_functionCall.getArguments().front()->getType(),
*_functionCall.getType());
} }
else else
{ {
//@todo //@todo: arguments are already on the stack
// push return label (below arguments?)
// jump to function label
// discard all but the first function return argument
} }
} }
void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) void ExpressionCompiler::endVisit(MemberAccess&)
{ {
} }
void ExpressionCompiler::endVisit(IndexAccess& _indexAccess) void ExpressionCompiler::endVisit(IndexAccess&)
{ {
} }
void ExpressionCompiler::endVisit(Identifier& _identifier) void ExpressionCompiler::endVisit(Identifier& _identifier)
{ {
m_currentLValue = _identifier.getReferencedDeclaration();
unsigned stackPos = stackPositionOfLValue();
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_identifier.getLocation())
<< errinfo_comment("Stack too deep."));
appendDup(stackPos + 1);
} }
void ExpressionCompiler::endVisit(Literal& _literal) void ExpressionCompiler::endVisit(Literal& _literal)
@ -224,7 +242,7 @@ void ExpressionCompiler::endVisit(Literal& _literal)
bytes value = _literal.getType()->literalToBigEndian(_literal); bytes value = _literal.getType()->literalToBigEndian(_literal);
assert(value.size() <= 32); assert(value.size() <= 32);
assert(!value.empty()); assert(!value.empty());
append(static_cast<byte>(eth::Instruction::PUSH1) + static_cast<byte>(value.size() - 1)); appendPush(value.size());
append(value); append(value);
break; break;
} }
@ -391,6 +409,24 @@ uint32_t ExpressionCompiler::appendConditionalJump()
return label; return label;
} }
void ExpressionCompiler::appendPush(unsigned _number)
{
assert(1 <= _number && _number <= 32);
append(eth::Instruction(unsigned(eth::Instruction::PUSH1) + _number - 1));
}
void ExpressionCompiler::appendDup(unsigned _number)
{
assert(1 <= _number && _number <= 16);
append(eth::Instruction(unsigned(eth::Instruction::DUP1) + _number - 1));
}
void ExpressionCompiler::appendSwap(unsigned _number)
{
assert(1 <= _number && _number <= 16);
append(eth::Instruction(unsigned(eth::Instruction::SWAP1) + _number - 1));
}
void ExpressionCompiler::append(bytes const& _data) void ExpressionCompiler::append(bytes const& _data)
{ {
m_assemblyItems.reserve(m_assemblyItems.size() + _data.size()); m_assemblyItems.reserve(m_assemblyItems.size() + _data.size());
@ -398,6 +434,37 @@ void ExpressionCompiler::append(bytes const& _data)
append(b); append(b);
} }
void ExpressionCompiler::storeInLValue(Expression const& _expression)
{
assert(m_currentLValue);
moveToLValue(_expression);
unsigned stackPos = stackPositionOfLValue();
if (stackPos > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Stack too deep."));
if (stackPos >= 1)
appendDup(stackPos);
}
void ExpressionCompiler::moveToLValue(Expression const& _expression)
{
assert(m_currentLValue);
unsigned stackPos = stackPositionOfLValue();
if (stackPos > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
<< errinfo_comment("Stack too deep."));
else if (stackPos > 0)
{
appendSwap(stackPos);
append(eth::Instruction::POP);
}
}
unsigned ExpressionCompiler::stackPositionOfLValue() const
{
return 8; // @todo ask the context and track stack changes due to m_assemblyItems
}
} }

16
libsolidity/Compiler.h

@ -87,7 +87,7 @@ private:
class ExpressionCompiler: public ASTVisitor class ExpressionCompiler: public ASTVisitor
{ {
public: public:
ExpressionCompiler(CompilerContext& _compilerContext): m_context(_compilerContext) {} ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {}
/// Compile the given expression and (re-)populate the assembly item list. /// Compile the given expression and (re-)populate the assembly item list.
void compile(Expression& _expression); void compile(Expression& _expression);
@ -98,7 +98,7 @@ public:
static AssemblyItems compileExpression(CompilerContext& _context, Expression& _expression); static AssemblyItems compileExpression(CompilerContext& _context, Expression& _expression);
private: private:
virtual void endVisit(Assignment& _assignment) override; virtual bool visit(Assignment& _assignment) override;
virtual void endVisit(UnaryOperation& _unaryOperation) override; virtual void endVisit(UnaryOperation& _unaryOperation) override;
virtual bool visit(BinaryOperation& _binaryOperation) override; virtual bool visit(BinaryOperation& _binaryOperation) override;
virtual void endVisit(FunctionCall& _functionCall) override; virtual void endVisit(FunctionCall& _functionCall) override;
@ -123,6 +123,9 @@ private:
/// Appends a JUMPI instruction to a new label and returns the label /// Appends a JUMPI instruction to a new label and returns the label
uint32_t appendConditionalJump(); uint32_t appendConditionalJump();
void appendPush(unsigned _number);
void appendDup(unsigned _number);
void appendSwap(unsigned _number);
/// Append elements to the current instruction list. /// Append elements to the current instruction list.
void append(eth::Instruction const& _instruction) { m_assemblyItems.push_back(AssemblyItem(_instruction)); } void append(eth::Instruction const& _instruction) { m_assemblyItems.push_back(AssemblyItem(_instruction)); }
@ -131,6 +134,15 @@ private:
void appendLabelref(byte _label) { m_assemblyItems.push_back(AssemblyItem::labelRef(_label)); } void appendLabelref(byte _label) { m_assemblyItems.push_back(AssemblyItem::labelRef(_label)); }
void appendLabel(byte _label) { m_assemblyItems.push_back(AssemblyItem::label(_label)); } void appendLabel(byte _label) { m_assemblyItems.push_back(AssemblyItem::label(_label)); }
/// Stores the value on top of the stack in the current lvalue and copies that value to the
/// top of the stack again
void storeInLValue(Expression const& _expression);
/// The same as storeInLValue but do not again retrieve the value to the top of the stack.
void moveToLValue(Expression const& _expression);
/// Returns the position of @a m_currentLValue in the stack, where 0 is the top of the stack.
unsigned stackPositionOfLValue() const;
Declaration* m_currentLValue;
AssemblyItems m_assemblyItems; AssemblyItems m_assemblyItems;
CompilerContext& m_context; CompilerContext& m_context;
}; };

1
libsolidity/Exceptions.h

@ -34,6 +34,7 @@ namespace solidity
struct ParserError: virtual Exception {}; struct ParserError: virtual Exception {};
struct TypeError: virtual Exception {}; struct TypeError: virtual Exception {};
struct DeclarationError: virtual Exception {}; struct DeclarationError: virtual Exception {};
struct CompilerError: virtual Exception {};
typedef boost::error_info<struct tag_sourcePosition, int> errinfo_sourcePosition; typedef boost::error_info<struct tag_sourcePosition, int> errinfo_sourcePosition;
typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation; typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation;

58
solc/main.cpp

@ -34,25 +34,24 @@
#include <libsolidity/Compiler.h> #include <libsolidity/Compiler.h>
#include <libsolidity/SourceReferenceFormatter.h> #include <libsolidity/SourceReferenceFormatter.h>
using namespace std;
using namespace dev; using namespace dev;
using namespace solidity; using namespace solidity;
void help() void help()
{ {
std::cout cout << "Usage solc [OPTIONS] <file>" << endl
<< "Usage solc [OPTIONS] <file>" << std::endl << "Options:" << endl
<< "Options:" << std::endl << " -h,--help Show this help message and exit." << endl
<< " -h,--help Show this help message and exit." << std::endl << " -V,--version Show the version and exit." << endl;
<< " -V,--version Show the version and exit." << std::endl;
exit(0); exit(0);
} }
void version() void version()
{ {
std::cout cout << "solc, the solidity complier commandline interface " << dev::Version << endl
<< "solc, the solidity complier commandline interface " << dev::Version << std::endl << " by Christian <c@ethdev.com>, (c) 2014." << endl
<< " by Christian <c@ethdev.com>, (c) 2014." << std::endl << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl;
<< "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << std::endl;
exit(0); exit(0);
} }
@ -87,10 +86,10 @@ private:
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
std::string infile; string infile;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
{ {
std::string arg = argv[i]; string arg = argv[i];
if (arg == "-h" || arg == "--help") if (arg == "-h" || arg == "--help")
help(); help();
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
@ -98,13 +97,13 @@ int main(int argc, char** argv)
else else
infile = argv[i]; infile = argv[i];
} }
std::string sourceCode; string sourceCode;
if (infile.empty()) if (infile.empty())
{ {
std::string s; string s;
while (!std::cin.eof()) while (!cin.eof())
{ {
getline(std::cin, s); getline(cin, s);
sourceCode.append(s); sourceCode.append(s);
} }
} }
@ -112,7 +111,7 @@ int main(int argc, char** argv)
sourceCode = asString(dev::contents(infile)); sourceCode = asString(dev::contents(infile));
ASTPointer<ContractDefinition> ast; ASTPointer<ContractDefinition> ast;
std::shared_ptr<Scanner> scanner = std::make_shared<Scanner>(CharStream(sourceCode)); shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(sourceCode));
Parser parser; Parser parser;
try try
{ {
@ -120,39 +119,48 @@ int main(int argc, char** argv)
} }
catch (ParserError const& exception) catch (ParserError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Parser error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", *scanner);
return -1; return -1;
} }
dev::solidity::NameAndTypeResolver resolver; NameAndTypeResolver resolver;
try try
{ {
resolver.resolveNamesAndTypes(*ast.get()); resolver.resolveNamesAndTypes(*ast.get());
} }
catch (DeclarationError const& exception) catch (DeclarationError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Declaration error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", *scanner);
return -1; return -1;
} }
catch (TypeError const& exception) catch (TypeError const& exception)
{ {
SourceReferenceFormatter::printExceptionInformation(std::cerr, exception, "Type error", *scanner); SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", *scanner);
return -1; return -1;
} }
std::cout << "Syntax tree for the contract:" << std::endl; cout << "Syntax tree for the contract:" << endl;
dev::solidity::ASTPrinter printer(ast, sourceCode); dev::solidity::ASTPrinter printer(ast, sourceCode);
printer.print(std::cout); printer.print(cout);
FirstExpressionExtractor extractor(*ast); FirstExpressionExtractor extractor(*ast);
CompilerContext context; CompilerContext context;
ExpressionCompiler compiler(context); ExpressionCompiler compiler(context);
try
{
compiler.compile(*extractor.getExpression()); compiler.compile(*extractor.getExpression());
}
catch (CompilerError const& exception)
{
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", *scanner);
return -1;
}
bytes instructions = compiler.getAssembledBytecode(); bytes instructions = compiler.getAssembledBytecode();
// debug
std::cout << "Bytecode for the first expression: " << std::endl; cout << "Bytecode for the first expression: " << endl;
std::cout << eth::disassemble(instructions) << std::endl; cout << eth::disassemble(instructions) << endl;
return 0; return 0;
} }

62
test/solidityCompiler.cpp

@ -200,22 +200,74 @@ BOOST_AUTO_TEST_CASE(arithmetics)
BOOST_AUTO_TEST_CASE(unary_operators) BOOST_AUTO_TEST_CASE(unary_operators)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"
" function f() { var x = !(~+-(--(++1++)--) == 2); }" " function f() { var x = !(~+-1 == 2); }"
"}\n"; "}\n";
bytes code = compileFirstExpression(sourceCode); bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1, bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x0,
byte(eth::Instruction::SUB),
byte(eth::Instruction::BNOT),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::EQ),
byte(eth::Instruction::NOT)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(unary_inc_dec)
{
char const* sourceCode = "contract test {\n"
" function f(uint a) { var x = ((a++ ^ ++a) ^ a--) ^ --a; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::DUP9), // will change as soon as we have real stack tracking
byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::ADD),
byte(eth::Instruction::SWAP8), // will change
byte(eth::Instruction::POP), // first ++
byte(eth::Instruction::DUP9),
byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::ADD), byte(eth::Instruction::ADD),
byte(eth::Instruction::SWAP8), // will change
byte(eth::Instruction::POP), // second ++
byte(eth::Instruction::DUP8), // will change
byte(eth::Instruction::XOR),
byte(eth::Instruction::DUP9), // will change
byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::SWAP1), byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB), byte(eth::Instruction::SUB),
byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::SWAP8), // will change
byte(eth::Instruction::POP), // first --
byte(eth::Instruction::XOR),
byte(eth::Instruction::DUP9),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB), byte(eth::Instruction::SUB),
byte(eth::Instruction::BNOT), byte(eth::Instruction::SWAP8), // will change
byte(eth::Instruction::POP), // second ++
byte(eth::Instruction::DUP8), // will change
byte(eth::Instruction::XOR)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(assignment)
{
char const* sourceCode = "contract test {\n"
" function f(uint a, uint b) { (a += b) * 2; }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::DUP9), // will change as soon as we have real stack tracking
byte(eth::Instruction::DUP9),
byte(eth::Instruction::ADD),
byte(eth::Instruction::SWAP8), // will change
byte(eth::Instruction::POP), // first ++
byte(eth::Instruction::DUP8),
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::EQ), byte(eth::Instruction::MUL)});
byte(eth::Instruction::NOT)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }

Loading…
Cancel
Save