diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | Changelog.md | 7 | ||||
-rw-r--r-- | docs/common-patterns.rst | 2 | ||||
-rw-r--r-- | docs/contracts.rst | 2 | ||||
-rw-r--r-- | docs/control-structures.rst | 3 | ||||
-rw-r--r-- | docs/frequently-asked-questions.rst | 2 | ||||
-rw-r--r-- | docs/index.rst | 10 | ||||
-rw-r--r-- | docs/installing-solidity.rst | 11 | ||||
-rw-r--r-- | docs/layout-of-source-files.rst | 6 | ||||
-rw-r--r-- | docs/security-considerations.rst | 2 | ||||
-rw-r--r-- | docs/style-guide.rst | 2 | ||||
-rw-r--r-- | docs/types.rst | 7 | ||||
-rw-r--r-- | docs/units-and-global-variables.rst | 14 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 5 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 115 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 3 | ||||
-rw-r--r-- | scripts/Dockerfile | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 33 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 26 | ||||
-rw-r--r-- | test/libsolidity/SolidityParser.cpp | 15 | ||||
-rw-r--r-- | test/libsolidity/SolidityScanner.cpp | 17 |
22 files changed, 205 insertions, 85 deletions
@@ -1,5 +1,5 @@ -.commit_hash.txt -.prerelease.txt +commit_hash.txt +prerelease.txt # Compiled Object files *.slo diff --git a/CMakeLists.txt b/CMakeLists.txt index cea219ff..931a8a0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.4.10") +set(PROJECT_VERSION "0.4.11") project(solidity VERSION ${PROJECT_VERSION}) # Let's find our dependencies diff --git a/Changelog.md b/Changelog.md index 69c75615..99089b46 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,6 @@ -### 0.4.10 (unreleased) +### 0.4.11 (unreleased) + +### 0.4.10 (2017-03-15) Features: * Add ``assert(condition)``, which throws if condition is false (meant for internal errors). @@ -7,8 +9,10 @@ Features: * Introduce ``.transfer(value)`` for sending Ether. * Code generator: Support ``revert()`` to abort with rolling back, but not consuming all gas. * Inline assembly: Support ``revert`` (EIP140) as an opcode. + * Parser: Support scientific notation in numbers (e.g. ``2e8`` and ``200e-2``). * Type system: Support explicit conversion of external function to address. * Type system: Warn if base of exponentiation is literal (result type might be unexpected). + * Type system: Warn if constant state variables are not compile-time constants. Bugfixes: * Commandline interface: Always escape filenames (replace ``/``, ``:`` and ``.`` with ``_``). @@ -20,7 +24,6 @@ Bugfixes: * Type system: Detect cyclic dependencies between constants. * Type system: Disallow arrays with negative length. * Type system: Fix a crash related to invalid binary operators. - * Type system: Warn if constant state variables are not compile-time constants. * Type system: Disallow ``var`` declaration with empty tuple type. * Type system: Correctly convert function argument types to pointers for member functions. * Type system: Move privateness of constructor into AST itself. diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index a2d7ce71..5fa84242 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -23,7 +23,7 @@ contract in order to become the "richest", inspired by `King of the Ether <https://www.kingoftheether.com/>`_. In the following contract, if you are usurped as the richest, -you will recieve the funds of the person who has gone on to +you will receive the funds of the person who has gone on to become the new richest. :: diff --git a/docs/contracts.rst b/docs/contracts.rst index 9145f016..2ee04675 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -1101,7 +1101,7 @@ Restrictions for libraries in comparison to contracts: - No state variables - Cannot inherit nor be inherited -- Cannot recieve Ether +- Cannot receive Ether (These might be lifted at a later point.) diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 25bf203b..a3af41dd 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -399,6 +399,7 @@ Currently, Solidity automatically generates a runtime exception in the following #. If you call ``assert`` with an argument that evaluates to false. While a user-provided exception is generated in the following situations: + #. Calling ``throw``. #. Calling ``require`` with an argument that evaluates to ``false``. @@ -411,4 +412,4 @@ did not occur. Because we want to retain the atomicity of transactions, the safe If contracts are written so that ``assert`` is only used to test internal conditions and ``require`` is used in case of malformed input, a formal analysis tool that verifies that the invalid -opcode can never be reached can be used to check for the absence of errors assuming valid inputs.
\ No newline at end of file +opcode can never be reached can be used to check for the absence of errors assuming valid inputs. diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 8a68ae5b..639eb83e 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -68,7 +68,7 @@ creator. Save it. Then ``selfdestruct(creator);`` to kill and return funds. Note that if you ``import "mortal"`` at the top of your contracts and declare ``contract SomeContract is mortal { ...`` and compile with a compiler that already -has it (which includes `browser-solidity <https://ethereum.github.io/browser-solidity/>`_), then +has it (which includes `Remix <https://remix.ethereum.org/>`_), then ``kill()`` is taken care of for you. Once a contract is "mortal", then you can ``contractname.kill.sendTransaction({from:eth.coinbase})``, just the same as my examples. diff --git a/docs/index.rst b/docs/index.rst index fc1a4231..61cff7ac 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ Solidity ======== Solidity is a contract-oriented, high-level language whose syntax is similar to that of JavaScript -and it is designed to target the Ethereum Virtual Machine. +and it is designed to target the Ethereum Virtual Machine (EVM). Solidity is statically typed, supports inheritance, libraries and complex user-defined types among other features. @@ -11,8 +11,8 @@ As you will see, it is possible to create contracts for voting, crowdfunding, blind auctions, multi-signature wallets and more. .. note:: - The best way to try out Solidity right now is using the - `Browser-Based Compiler <https://ethereum.github.io/browser-solidity/>`_ + The best way to try out Solidity right now is using + `Remix <https://remix.ethereum.org/>`_ (it can take a while to load, please be patient). Useful links @@ -33,7 +33,7 @@ Useful links Available Solidity Integrations ------------------------------- -* `Browser-Based Compiler <https://ethereum.github.io/browser-solidity/>`_ +* `Remix <https://remix.ethereum.org/>`_ Browser-based IDE with integrated compiler and Solidity runtime environment without server-side components. * `Ethereum Studio <https://live.ether.camp/>`_ @@ -109,7 +109,7 @@ and the :ref:`Ethereum Virtual Machine <the-ethereum-virtual-machine>`. The next section will explain several *features* of Solidity by giving useful :ref:`example contracts <voting>` Remember that you can always try out the contracts -`in your browser <https://ethereum.github.io/browser-solidity>`_! +`in your browser <https://remix.ethereum.org>`_! The last and most extensive section will cover all aspects of Solidity in depth. diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index fb405475..a2a3c3da 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -15,11 +15,11 @@ are not guaranteed to be working and despite best efforts they might contain und and/or broken changes. We recommend using the latest release. Package installers below will use the latest release. -Browser-Solidity -================ +Remix +===== If you just want to try Solidity for small contracts, you -can try `browser-solidity <https://ethereum.github.io/browser-solidity>`_ +can try `Remix <https://remix.ethereum.org/>`_ which does not need any installation. If you want to use it without connection to the Internet, you can go to https://github.com/ethereum/browser-solidity/tree/gh-pages and @@ -31,7 +31,7 @@ npm / Node.js This is probably the most portable and most convenient way to install Solidity locally. A platform-independent JavaScript library is provided by compiling the C++ source -into JavaScript using Emscripten. It can be used in projects directly (such as Browser-Solidity). +into JavaScript using Emscripten. It can be used in projects directly (such as Remix). Please refer to the `solc-js <https://github.com/ethereum/solc-js>`_ repository for instructions. It also contains a commandline tool called `solcjs`, which can be installed via npm: @@ -250,6 +250,7 @@ The version string in detail ============================ The Solidity version string contains four parts: + - the version number - pre-release tag, usually set to ``develop.YYYY.MM.DD`` or ``nightly.YYYY.MM.DD`` - commit in the format of ``commit.GITHASH`` @@ -280,4 +281,4 @@ Example: 3. a breaking change is introduced - version is bumped to 0.5.0 4. the 0.5.0 release is made -This behaviour works well with the version pragma. +This behaviour works well with the :ref:`version pragma <version_pragma>`. diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index 1e27b7c0..05708964 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -7,6 +7,8 @@ and pragma directives. .. index:: ! pragma, version +.. _version_pragma: + Version Pragma ============== @@ -151,9 +153,9 @@ remapping ``=/``. If there are multiple remappings that lead to a valid file, the remapping with the longest common prefix is chosen. -**browser-solidity**: +**Remix**: -The `browser-based compiler <https://ethereum.github.io/browser-solidity>`_ +`Remix <https://remix.ethereum.org/>`_ provides an automatic remapping for github and will also automatically retrieve the file over the network: You can import the iterable mapping by e.g. diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 77e1bf08..7c3f87ee 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -117,7 +117,7 @@ Sending and Receiving Ether During the execution of the fallback function, the contract can only rely on the "gas stipend" (2300 gas) being available to it at that time. This stipend is not enough to access storage in any way. To be sure that your contract can receive Ether in that way, check the gas requirements of the fallback function - (for example in the "details" section in browser-solidity). + (for example in the "details" section in Remix). - There is a way to forward more gas to the receiving contract using ``addr.call.value(x)()``. This is essentially the same as ``addr.send(x)``, diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 9aae3d7b..0742d2e9 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -164,7 +164,7 @@ Functions should be grouped according to their visibility and ordered: - internal - private -Within a grouping, place the `constant` functions last. +Within a grouping, place the ``constant`` functions last. Yes:: diff --git a/docs/types.rst b/docs/types.rst index f89a8ee5..6379f01c 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -202,6 +202,9 @@ Octal literals do not exist in Solidity and leading zeros are invalid. Decimal fraction literals are formed by a ``.`` with at least one number on one side. Examples include ``1.``, ``.1`` and ``1.3``. +Scientific notation is also supported, where the base can have fractions, while the exponent cannot. +Examples include ``2e10``, ``-2e10``, ``2e-10``, ``2.5e1``. + Number literal expressions retain arbitrary precision until they are converted to a non-literal type (i.e. by using them together with a non-literal expression). This means that computations do not overflow and divisions do not truncate @@ -229,7 +232,7 @@ a non-rational number). Integer literals and rational number literals belong to number literal types. Moreover, all number literal expressions (i.e. the expressions that contain only number literals and operators) belong to number literal - types. So the number literal expressions `1 + 2` and `2 + 1` both + types. So the number literal expressions ``1 + 2`` and ``2 + 1`` both belong to the same number literal type for the rational number three. .. note:: @@ -258,7 +261,7 @@ a non-rational number). String Literals --------------- -String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``). They do not imply trailing zeroes as in C; `"foo"`` represents three bytes not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``. +String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``). They do not imply trailing zeroes as in C; ``"foo"`` represents three bytes not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``. String literals support escape characters, such as ``\n``, ``\xNN`` and ``\uNNNN``. ``\xNN`` takes a hex value and inserts the appropriate byte, while ``\uNNNN`` takes a Unicode codepoint and inserts an UTF-8 sequence. diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 49fe5d84..7a43343f 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -93,7 +93,7 @@ Mathematical and Cryptographic Functions ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments ``sha3(...) returns (bytes32)``: - alias to `keccak256()` + alias to ``keccak256()`` ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments ``ripemd160(...) returns (bytes20)``: @@ -128,17 +128,23 @@ Address Related ``<address>.balance`` (``uint256``): balance of the :ref:`address` in Wei -``<address>.send(uint256 amount) returns (bool)``: - send given amount of Wei to :ref:`address`, returns ``false`` on failure ``<address>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure +``<address>.send(uint256 amount) returns (bool)``: + send given amount of Wei to :ref:`address`, returns ``false`` on failure +``<address>.call(...) returns (bool)``: + issue low-level ``CALL``, returns ``false`` on failure +``<address>.callcode(...) returns (bool)``: + issue low-level ``CALLCODE``, returns ``false`` on failure +``<address>.delegatecall(...) returns (bool)``: + issue low-level ``DELEGATECALL``, returns ``false`` on failure For more information, see the section on :ref:`address`. .. warning:: There are some dangers in using ``send``: The transfer fails if the call stack depth is at 1024 (this can always be forced by the caller) and it also fails if the recipient runs out of gas. So in order - to make safe Ether transfers, always check the return value of ``send`` or even better: + to make safe Ether transfers, always check the return value of ``send``, use ``transfer`` or even better: Use a pattern where the recipient withdraws the money. .. index:: this, selfdestruct diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 8e7ec29b..512493cd 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -891,10 +891,11 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) if ( location == Location::Bare || location == Location::BareCallCode || - location == Location::BareDelegateCall || - location == Location::Send + location == Location::BareDelegateCall ) warning(_statement.location(), "Return value of low-level calls not used."); + else if (location == Location::Send) + warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead."); } } } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 0e11c3ec..e7f53422 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -32,6 +32,7 @@ #include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/replace.hpp> +#include <boost/algorithm/string/predicate.hpp> #include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/sliced.hpp> #include <boost/range/adaptor/transformed.hpp> @@ -571,39 +572,99 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi return commonType; } -tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal) +tuple<bool, rational> RationalNumberType::parseRational(string const& _value) { - rational x; + rational value; try { - rational numerator; - rational denominator(1); - - auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.'); - if (radixPoint != _literal.value().end()) + auto radixPoint = find(_value.begin(), _value.end(), '.'); + + if (radixPoint != _value.end()) { if ( - !all_of(radixPoint + 1, _literal.value().end(), ::isdigit) || - !all_of(_literal.value().begin(), radixPoint, ::isdigit) + !all_of(radixPoint + 1, _value.end(), ::isdigit) || + !all_of(_value.begin(), radixPoint, ::isdigit) ) return make_tuple(false, rational(0)); - //Only decimal notation allowed here, leading zeros would switch to octal. + + // Only decimal notation allowed here, leading zeros would switch to octal. auto fractionalBegin = find_if_not( - radixPoint + 1, - _literal.value().end(), + radixPoint + 1, + _value.end(), [](char const& a) { return a == '0'; } ); - denominator = bigint(string(fractionalBegin, _literal.value().end())); + rational numerator; + rational denominator(1); + + denominator = bigint(string(fractionalBegin, _value.end())); denominator /= boost::multiprecision::pow( - bigint(10), - distance(radixPoint + 1, _literal.value().end()) + bigint(10), + distance(radixPoint + 1, _value.end()) ); - numerator = bigint(string(_literal.value().begin(), radixPoint)); - x = numerator + denominator; + numerator = bigint(string(_value.begin(), radixPoint)); + value = numerator + denominator; } else - x = bigint(_literal.value()); + value = bigint(_value); + return make_tuple(true, value); + } + catch (...) + { + return make_tuple(false, rational(0)); + } +} + +tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal) +{ + rational value; + try + { + auto expPoint = find(_literal.value().begin(), _literal.value().end(), 'e'); + if (expPoint == _literal.value().end()) + expPoint = find(_literal.value().begin(), _literal.value().end(), 'E'); + + if (boost::starts_with(_literal.value(), "0x")) + { + // process as hex + value = bigint(_literal.value()); + } + else if (expPoint != _literal.value().end()) + { + // parse the exponent + bigint exp = bigint(string(expPoint + 1, _literal.value().end())); + + if (exp > numeric_limits<int32_t>::max() || exp < numeric_limits<int32_t>::min()) + return make_tuple(false, rational(0)); + + // parse the base + tuple<bool, rational> base = parseRational(string(_literal.value().begin(), expPoint)); + if (!get<0>(base)) + return make_tuple(false, rational(0)); + value = get<1>(base); + + if (exp < 0) + { + exp *= -1; + value /= boost::multiprecision::pow( + bigint(10), + exp.convert_to<int32_t>() + ); + } + else + value *= boost::multiprecision::pow( + bigint(10), + exp.convert_to<int32_t>() + ); + } + else + { + // parse as rational number + tuple<bool, rational> tmp = parseRational(_literal.value()); + if (!get<0>(tmp)) + return tmp; + value = get<1>(tmp); + } } catch (...) { @@ -616,33 +677,33 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal case Literal::SubDenomination::Second: break; case Literal::SubDenomination::Szabo: - x *= bigint("1000000000000"); + value *= bigint("1000000000000"); break; case Literal::SubDenomination::Finney: - x *= bigint("1000000000000000"); + value *= bigint("1000000000000000"); break; case Literal::SubDenomination::Ether: - x *= bigint("1000000000000000000"); + value *= bigint("1000000000000000000"); break; case Literal::SubDenomination::Minute: - x *= bigint("60"); + value *= bigint("60"); break; case Literal::SubDenomination::Hour: - x *= bigint("3600"); + value *= bigint("3600"); break; case Literal::SubDenomination::Day: - x *= bigint("86400"); + value *= bigint("86400"); break; case Literal::SubDenomination::Week: - x *= bigint("604800"); + value *= bigint("604800"); break; case Literal::SubDenomination::Year: - x *= bigint("31536000"); + value *= bigint("31536000"); break; } - return make_tuple(true, x); + return make_tuple(true, value); } bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 0a4878b8..78326aa6 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -416,6 +416,9 @@ public: private: rational m_value; + + /// @returns true if the literal is a valid rational number. + static std::tuple<bool, rational> parseRational(std::string const& _value); }; /** diff --git a/scripts/Dockerfile b/scripts/Dockerfile index 8be19783..ad448fd3 100644 --- a/scripts/Dockerfile +++ b/scripts/Dockerfile @@ -13,4 +13,4 @@ cmake -DCMAKE_BUILD_TYPE=Release -DTESTS=0 -DSTATIC_LINKING=1 &&\ make solc && install -s solc/solc /usr/bin &&\ cd / && rm -rf solidity &&\ apk del sed build-base git make cmake gcc g++ musl-dev curl-dev boost-dev &&\ -rm -rf /var/cache/apk/*
\ No newline at end of file +rm -rf /var/cache/apk/* diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index a4fab721..7ef34383 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -9233,6 +9233,39 @@ BOOST_AUTO_TEST_CASE(revert) BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(42))); } +BOOST_AUTO_TEST_CASE(scientific_notation) +{ + char const* sourceCode = R"( + contract C { + function f() returns (uint) { + return 2e10 wei; + } + function g() returns (uint) { + return 200e-2 wei; + } + function h() returns (uint) { + return 2.5e1; + } + function i() returns (int) { + return -2e10; + } + function j() returns (int) { + return -200e-2; + } + function k() returns (int) { + return -2.5e1; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(20000000000))); + BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(2))); + BOOST_CHECK(callContractFunction("h()") == encodeArgs(u256(25))); + BOOST_CHECK(callContractFunction("i()") == encodeArgs(u256(-20000000000))); + BOOST_CHECK(callContractFunction("j()") == encodeArgs(u256(-2))); + BOOST_CHECK(callContractFunction("k()") == encodeArgs(u256(-25))); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 27791775..fa310434 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2790,18 +2790,6 @@ BOOST_AUTO_TEST_CASE(literal_strings) CHECK_SUCCESS(text); } -BOOST_AUTO_TEST_CASE(invalid_integer_literal_exp) -{ - char const* text = R"( - contract Foo { - function f() { - var x = 1e2; - } - } - )"; - CHECK_ERROR(text, TypeError, ""); -} - BOOST_AUTO_TEST_CASE(memory_structs_with_mappings) { char const* text = R"( @@ -4420,7 +4408,7 @@ BOOST_AUTO_TEST_CASE(unused_return_value_send) } } )"; - CHECK_WARNING(text, "Return value of low-level calls not used"); + CHECK_WARNING(text, "Failure condition of 'send' ignored. Consider using 'transfer' instead."); } BOOST_AUTO_TEST_CASE(unused_return_value_call) @@ -4951,18 +4939,6 @@ BOOST_AUTO_TEST_CASE(external_function_type_to_uint) CHECK_ERROR(text, TypeError, "Explicit type conversion not allowed"); } -BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal) -{ - char const* text = R"( - contract A { - function a() { - .8E0; - } - } - )"; - CHECK_ERROR(text, TypeError, ""); -} - BOOST_AUTO_TEST_CASE(shift_constant_left_negative_rvalue) { char const* text = R"( diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index e5362e78..ffb4b6f2 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -1479,6 +1479,21 @@ BOOST_AUTO_TEST_CASE(function_type_state_variable) BOOST_CHECK(successParse(text)); } +BOOST_AUTO_TEST_CASE(scientific_notation) +{ + char const* text = R"( + contract test { + uint256 a = 2e10; + uint256 b = 2E10; + uint256 c = 200e-2; + uint256 d = 2E10 wei; + uint256 e = 2.5e10; + } + )"; + BOOST_CHECK(successParse(text)); +} + + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityScanner.cpp b/test/libsolidity/SolidityScanner.cpp index 3a5c6f24..020bce7f 100644 --- a/test/libsolidity/SolidityScanner.cpp +++ b/test/libsolidity/SolidityScanner.cpp @@ -115,9 +115,21 @@ BOOST_AUTO_TEST_CASE(octal_numbers) BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Number); } +BOOST_AUTO_TEST_CASE(scientific_notation) +{ + Scanner scanner(CharStream("var x = 2e10;")); + BOOST_CHECK_EQUAL(scanner.currentToken(), 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.currentLiteral(), "2e10"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Semicolon); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + BOOST_AUTO_TEST_CASE(negative_numbers) { - Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;")); + Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9 + 2e-2;")); BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Var); BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier); BOOST_CHECK_EQUAL(scanner.next(), Token::Assign); @@ -135,6 +147,9 @@ BOOST_AUTO_TEST_CASE(negative_numbers) BOOST_CHECK_EQUAL(scanner.next(), Token::Add); BOOST_CHECK_EQUAL(scanner.next(), Token::Number); BOOST_CHECK_EQUAL(scanner.currentLiteral(), "8.9"); + BOOST_CHECK_EQUAL(scanner.next(), Token::Add); + BOOST_CHECK_EQUAL(scanner.next(), Token::Number); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), "2e-2"); BOOST_CHECK_EQUAL(scanner.next(), Token::Semicolon); BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); } |