Merge remote-tracking branch 'ethereum/develop' into sol_optimizer

This commit is contained in:
Christian 2014-11-07 02:13:31 +01:00
commit 4fe64b22de
5 changed files with 201 additions and 72 deletions

View File

@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
byte(Instruction::JUMPDEST), // beginning of g
byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), // initialized e and h
byte(Instruction::PUSH1), byte(0x20 + shift), // ret address
byte(Instruction::PUSH1), 0x1,
byte(Instruction::PUSH1), 0x2,
byte(Instruction::PUSH1), 0x3,
byte(Instruction::PUSH1), 0x29 + shift, // ret address
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), byte(0x1 + shift),
// stack here: ret e h 0x20 1 2 3 0x1
byte(Instruction::JUMP),

View File

@ -41,31 +41,31 @@ class ExecutionFramework
public:
ExecutionFramework() { g_logVerbosity = 0; }
bytes compileAndRun(std::string const& _sourceCode)
bytes const& compileAndRun(std::string const& _sourceCode)
{
bytes code = dev::solidity::CompilerStack::compile(_sourceCode);
sendMessage(code, true);
BOOST_REQUIRE(!m_output.empty());
return m_output;
}
bytes callFunction(byte _index, bytes const& _data)
bytes const& callFunction(byte _index, bytes const& _data)
{
sendMessage(bytes(1, _index) + _data, false);
return m_output;
}
bytes callFunction(byte _index, u256 const& _argument1)
bytes const& callFunction(byte _index, u256 const& _argument1)
{
callFunction(_index, toBigEndian(_argument1));
return m_output;
return callFunction(_index, toBigEndian(_argument1));
}
private:
void sendMessage(bytes const& _data, bool _isCreation)
{
eth::Executive executive(m_state);
eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data)
: eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data);
eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
bytes transactionRLP = t.rlp();
try
{
@ -77,13 +77,14 @@ private:
{
BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address()));
m_contractAddress = executive.newAddress();
BOOST_REQUIRE(m_contractAddress);
BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
}
else
BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
BOOST_REQUIRE(executive.go());
executive.finalize();
m_output = executive.out().toBytes();
m_output = executive.out().toVector();
}
Address m_contractAddress;
@ -93,27 +94,24 @@ private:
bytes m_output;
};
BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest)
BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework)
BOOST_AUTO_TEST_CASE(smoke_test)
{
char const* sourceCode = "contract test {\n"
" function f(uint a) returns(uint d) { return a * 7; }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
compileAndRun(sourceCode);
u256 a = 0x200030004;
bytes result = framework.callFunction(0, a);
BOOST_CHECK(result == toBigEndian(a * 7));
BOOST_CHECK(callFunction(0, a) == toBigEndian(a * 7));
}
BOOST_AUTO_TEST_CASE(empty_contract)
{
char const* sourceCode = "contract test {\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, bytes()).empty());
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes()).empty());
}
BOOST_AUTO_TEST_CASE(recursive_calls)
@ -124,13 +122,12 @@ BOOST_AUTO_TEST_CASE(recursive_calls)
" else return n * f(n - 1);\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2)));
BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6)));
BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24)));
}
BOOST_AUTO_TEST_CASE(while_loop)
@ -142,13 +139,12 @@ BOOST_AUTO_TEST_CASE(while_loop)
" while (i <= n) nfac *= i++;\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2)));
BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6)));
BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24)));
}
BOOST_AUTO_TEST_CASE(break_outside_loop)
@ -217,13 +213,12 @@ BOOST_AUTO_TEST_CASE(calling_other_functions)
" return 3 * x + 1;\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0)));
BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1)));
BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1)));
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(2, u256(0)) == toBigEndian(u256(0)));
BOOST_CHECK(callFunction(2, u256(1)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(2, u256(2)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(2, u256(8)) == toBigEndian(u256(1)));
BOOST_CHECK(callFunction(2, u256(127)) == toBigEndian(u256(1)));
}
BOOST_AUTO_TEST_CASE(many_local_variables)
@ -235,12 +230,25 @@ BOOST_AUTO_TEST_CASE(many_local_variables)
" y += b + x2;\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
== toBigEndian(u256(0x121121)));
}
BOOST_AUTO_TEST_CASE(packing_unpacking_types)
{
char const* sourceCode = "contract test {\n"
" function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n"
" if (a) y = 1;\n"
" y = y * 0x100000000 | ~b;\n"
" y = y * 0x10000000000000000 | ~c;\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0"))
== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f"));
}
BOOST_AUTO_TEST_CASE(multiple_return_values)
{
char const* sourceCode = "contract test {\n"
@ -248,9 +256,8 @@ BOOST_AUTO_TEST_CASE(multiple_return_values)
" y1 = x2; y2 = x1;\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
}
@ -262,13 +269,59 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
" return x;"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8)));
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(0)));
BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(8)));
}
//@todo test smaller types
BOOST_AUTO_TEST_CASE(high_bits_cleaning)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" uint32 x = uint32(0xffffffff) + 10;\n"
" if (x >= 0xffffffff) return 0;\n"
" return x;"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(9)));
}
BOOST_AUTO_TEST_CASE(sign_extension)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" int64 x = -int32(0xff);\n"
" if (x >= 0xff) return 0;\n"
" return -uint256(x);"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xff)));
}
BOOST_AUTO_TEST_CASE(small_unsigned_types)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" uint32 x = uint32(0xffffff) * 0xffffff;\n"
" return x / 0x100;"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xfe0000)));
}
BOOST_AUTO_TEST_CASE(small_signed_types)
{
char const* sourceCode = "contract test {\n"
" function run() returns(int256 y) {\n"
" return -int32(10) * -int64(20);\n"
" }\n"
"}\n";
compileAndRun(sourceCode);
BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(200)));
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -154,8 +154,8 @@ BOOST_AUTO_TEST_CASE(comparison)
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa,
byte(eth::Instruction::PUSH2), 0x11, 0xaa,
bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::EQ),
@ -172,16 +172,16 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
bytes expectation({byte(eth::Instruction::PUSH1), 0xa,
byte(eth::Instruction::PUSH1), 0x8,
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT),
byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4
byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x14,
byte(eth::Instruction::PUSH1), 0x20,
byte(eth::Instruction::JUMPI), // short-circuit if it is true
byte(eth::Instruction::POP),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x9,
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO), // after this we have 2 != 9
byte(eth::Instruction::JUMPDEST),
@ -197,10 +197,11 @@ BOOST_AUTO_TEST_CASE(arithmetics)
" function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x3,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::PUSH1), 0x5,
byte(eth::Instruction::PUSH1), 0x6,
@ -213,8 +214,10 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB),
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::MOD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::DIV),
byte(eth::Instruction::MUL)});
@ -224,15 +227,15 @@ BOOST_AUTO_TEST_CASE(arithmetics)
BOOST_AUTO_TEST_CASE(unary_operators)
{
char const* sourceCode = "contract test {\n"
" function f() { var x = !(~+-1 == 2); }"
" function f() { var x = !(~+- 1 == 2); }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x0,
byte(eth::Instruction::SUB),
byte(eth::Instruction::NOT),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
@ -305,7 +308,7 @@ BOOST_AUTO_TEST_CASE(assignment)
byte(eth::Instruction::POP),
byte(eth::Instruction::DUP2),
// Stack here: a+b b a+b
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@ -320,17 +323,17 @@ BOOST_AUTO_TEST_CASE(function_call)
{{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b
bytes expectation({byte(eth::Instruction::PUSH1), 0x0a,
bytes expectation({byte(eth::Instruction::PUSH1), 0x0d,
byte(eth::Instruction::DUP3),
byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::ADD),
// Stack here: a b <ret label> (a+1)
byte(eth::Instruction::DUP3),
byte(eth::Instruction::PUSH1), 0x14,
byte(eth::Instruction::PUSH1), 0x1a,
byte(eth::Instruction::JUMP),
byte(eth::Instruction::JUMPDEST),
// Stack here: a b g(a+1, b)
byte(eth::Instruction::PUSH1), 0x02,
byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MUL),
// Stack here: a b g(a+1, b)*2
byte(eth::Instruction::DUP3),
@ -344,6 +347,45 @@ BOOST_AUTO_TEST_CASE(function_call)
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(negative_literals_8bits)
{
// these all fit in 8 bits
char const* sourceCode = "contract test {\n"
" function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) +
bytes({byte(eth::Instruction::ADD)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_CASE(negative_literals_16bits)
{
// -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible
// from the SIGNEXTEND opcodes
char const* sourceCode = "contract test {\n"
" function f() { int64 x = int64(-1 + -129); }\n"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) +
bytes({byte(eth::Instruction::PUSH1), 0x00,
byte(eth::Instruction::SIGNEXTEND),
byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) +
bytes({byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::SIGNEXTEND)}));
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
BOOST_AUTO_TEST_SUITE_END()
}

View File

@ -162,6 +162,22 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call)
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison)
{
char const* text = "contract test {\n"
" function f() { uint32(2) == int64(2); }"
"}\n";
BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text));
}
BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid)
{
char const* text = "contract test {\n"
" function f() { int32(2) == uint64(2); }"
"}\n";
BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
}
BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion)
{
char const* text = "contract test {\n"

View File

@ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers)
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(negative_numbers)
{
Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;"));
BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3");
BOOST_CHECK_EQUAL(scanner.next(), Token::ADD);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9");
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
}
BOOST_AUTO_TEST_CASE(locations)
{
Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment"));
@ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations)
BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25);
BOOST_CHECK_EQUAL(scanner.next(), Token::SUB);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27);
BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32);
BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER);
BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45);