mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge remote-tracking branch 'origin/develop' into breaking
This commit is contained in:
commit
3e3f9a472f
10
.travis.yml
10
.travis.yml
@ -40,6 +40,8 @@ env:
|
|||||||
- ENCRYPTION_LABEL="6d4541b72666"
|
- ENCRYPTION_LABEL="6d4541b72666"
|
||||||
- SOLC_BUILD_TYPE=RelWithDebInfo
|
- SOLC_BUILD_TYPE=RelWithDebInfo
|
||||||
- SOLC_EMSCRIPTEN=Off
|
- SOLC_EMSCRIPTEN=Off
|
||||||
|
# FIXME: Pushing solcjson.js to solc-bin disabled until we fix the cause of #9261
|
||||||
|
- SOLC_PUBLISH_EMSCRIPTEN=Off
|
||||||
- SOLC_INSTALL_DEPS_TRAVIS=On
|
- SOLC_INSTALL_DEPS_TRAVIS=On
|
||||||
- SOLC_RELEASE=On
|
- SOLC_RELEASE=On
|
||||||
- SOLC_TESTS=On
|
- SOLC_TESTS=On
|
||||||
@ -104,12 +106,12 @@ matrix:
|
|||||||
sudo: required
|
sudo: required
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
node_js:
|
node_js:
|
||||||
- "8"
|
- "10"
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
before_install:
|
before_install:
|
||||||
- nvm install 8
|
- nvm install 10
|
||||||
- nvm use 8
|
- nvm use 10
|
||||||
- docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-2
|
- docker pull ethereum/solidity-buildpack-deps:emsdk-1.39.15-2
|
||||||
env:
|
env:
|
||||||
- SOLC_EMSCRIPTEN=On
|
- SOLC_EMSCRIPTEN=On
|
||||||
@ -213,7 +215,7 @@ deploy:
|
|||||||
# scripts because TravisCI doesn't provide much in the way of conditional logic.
|
# scripts because TravisCI doesn't provide much in the way of conditional logic.
|
||||||
|
|
||||||
- provider: script
|
- provider: script
|
||||||
script: test $SOLC_EMSCRIPTEN != On || (scripts/release_emscripten.sh)
|
script: test $SOLC_PUBLISH_EMSCRIPTEN != On || $SOLC_EMSCRIPTEN != On || (scripts/release_emscripten.sh)
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
on:
|
on:
|
||||||
branch:
|
branch:
|
||||||
|
@ -26,12 +26,14 @@ Bugfixes:
|
|||||||
|
|
||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
|
* General: Add unit denomination ``gwei``
|
||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
* NatSpec: Add fields "kind" and "version" to the JSON output.
|
* NatSpec: Add fields "kind" and "version" to the JSON output.
|
||||||
|
* NatSpec: Inherit tags from unique base if derived function does not provide any.
|
||||||
* Commandline Interface: Prevent some incompatible commandline options from being used together.
|
* Commandline Interface: Prevent some incompatible commandline options from being used together.
|
||||||
|
* NatSpec: Support NatSpec comments on events.
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
* NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments.
|
* NatSpec: Do not consider ``////`` and ``/***`` as NatSpec comments.
|
||||||
|
@ -359,10 +359,10 @@ subAssembly
|
|||||||
: 'assembly' identifier assemblyBlock ;
|
: 'assembly' identifier assemblyBlock ;
|
||||||
|
|
||||||
numberLiteral
|
numberLiteral
|
||||||
: (DecimalNumber | HexNumber) NumberUnit? ;
|
: (DecimalNumber | HexNumber) (NumberUnit | Gwei)?;
|
||||||
|
|
||||||
identifier
|
identifier
|
||||||
: ('from' | 'calldata' | 'address' | Identifier) ;
|
: (Gwei | 'from' | 'calldata' | 'address' | Identifier) ;
|
||||||
|
|
||||||
BooleanLiteral
|
BooleanLiteral
|
||||||
: 'true' | 'false' ;
|
: 'true' | 'false' ;
|
||||||
@ -385,6 +385,8 @@ NumberUnit
|
|||||||
: 'wei' | 'szabo' | 'finney' | 'ether'
|
: 'wei' | 'szabo' | 'finney' | 'ether'
|
||||||
| 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' ;
|
| 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' ;
|
||||||
|
|
||||||
|
Gwei: 'gwei' ;
|
||||||
|
|
||||||
HexLiteralFragment
|
HexLiteralFragment
|
||||||
: 'hex' (('"' HexDigits? '"') | ('\'' HexDigits? '\'')) ;
|
: 'hex' (('"' HexDigits? '"') | ('\'' HexDigits? '\'')) ;
|
||||||
|
|
||||||
|
@ -42,10 +42,6 @@ The following example shows a contract and a function using all available tags.
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
NatSpec currently does NOT apply to public state variables (see
|
|
||||||
`solidity#3418 <https://github.com/ethereum/solidity/issues/3418>`__),
|
|
||||||
even if they are declared public and therefore do affect the ABI.
|
|
||||||
|
|
||||||
The Solidity compiler only interprets tags if they are external or
|
The Solidity compiler only interprets tags if they are external or
|
||||||
public. You are welcome to use similar comments for your internal and
|
public. You are welcome to use similar comments for your internal and
|
||||||
private functions, but those will not be parsed.
|
private functions, but those will not be parsed.
|
||||||
@ -60,7 +56,6 @@ The following example shows a contract and a function using all available tags.
|
|||||||
/// @notice You can use this contract for only the most basic simulation
|
/// @notice You can use this contract for only the most basic simulation
|
||||||
/// @dev All function calls are currently implemented without side effects
|
/// @dev All function calls are currently implemented without side effects
|
||||||
contract Tree {
|
contract Tree {
|
||||||
/// @author Mary A. Botanist
|
|
||||||
/// @notice Calculate tree age in years, rounded up, for live trees
|
/// @notice Calculate tree age in years, rounded up, for live trees
|
||||||
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
/// @dev The Alexandr N. Tetearing algorithm could increase precision
|
||||||
/// @param rings The number of rings from dendrochronological sample
|
/// @param rings The number of rings from dendrochronological sample
|
||||||
@ -84,10 +79,10 @@ in the same way as if it were tagged with ``@notice``.
|
|||||||
Tag Context
|
Tag Context
|
||||||
=========== =============================================================================== =============================
|
=========== =============================================================================== =============================
|
||||||
``@title`` A title that should describe the contract/interface contract, interface
|
``@title`` A title that should describe the contract/interface contract, interface
|
||||||
``@author`` The name of the author contract, interface, function
|
``@author`` The name of the author contract, interface
|
||||||
``@notice`` Explain to an end user what this does contract, interface, function, public state variable
|
``@notice`` Explain to an end user what this does contract, interface, function, public state variable, event
|
||||||
``@dev`` Explain to a developer any extra details contract, interface, function, state variable
|
``@dev`` Explain to a developer any extra details contract, interface, function, state variable, event
|
||||||
``@param`` Documents a parameter just like in doxygen (must be followed by parameter name) function
|
``@param`` Documents a parameter just like in doxygen (must be followed by parameter name) function, event
|
||||||
``@return`` Documents the return variables of a contract's function function, public state variable
|
``@return`` Documents the return variables of a contract's function function, public state variable
|
||||||
=========== =============================================================================== =============================
|
=========== =============================================================================== =============================
|
||||||
|
|
||||||
@ -127,9 +122,11 @@ documentation and you may read more at
|
|||||||
Inheritance Notes
|
Inheritance Notes
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Currently it is undefined whether a contract with a function having no
|
Functions without NatSpec will automatically inherit the documentation of their
|
||||||
NatSpec will inherit the NatSpec of a parent contract/interface for that
|
base function. Exceptions to this are:
|
||||||
same function.
|
|
||||||
|
* When the parameter names are different.
|
||||||
|
* When there is more than one base function.
|
||||||
|
|
||||||
.. _header-output:
|
.. _header-output:
|
||||||
|
|
||||||
@ -193,7 +190,6 @@ file should also be produced and should look like this:
|
|||||||
{
|
{
|
||||||
"age(uint256)" :
|
"age(uint256)" :
|
||||||
{
|
{
|
||||||
"author" : "Mary A. Botanist",
|
|
||||||
"details" : "The Alexandr N. Tetearing algorithm could increase precision",
|
"details" : "The Alexandr N. Tetearing algorithm could increase precision",
|
||||||
"params" :
|
"params" :
|
||||||
{
|
{
|
||||||
|
@ -7,11 +7,12 @@ Units and Globally Available Variables
|
|||||||
Ether Units
|
Ether Units
|
||||||
===========
|
===========
|
||||||
|
|
||||||
A literal number can take a suffix of ``wei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
|
A literal number can take a suffix of ``wei``, ``gwei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
assert(1 wei == 1);
|
assert(1 wei == 1);
|
||||||
|
assert(1 gwei == 1e9);
|
||||||
assert(1 szabo == 1e12);
|
assert(1 szabo == 1e12);
|
||||||
assert(1 finney == 1e15);
|
assert(1 finney == 1e15);
|
||||||
assert(1 ether == 1e18);
|
assert(1 ether == 1e18);
|
||||||
|
28
docs/yul.rst
28
docs/yul.rst
@ -180,7 +180,11 @@ appropriate ``PUSHi`` instruction. In the following example,
|
|||||||
``3`` and ``2`` are added resulting in 5 and then the
|
``3`` and ``2`` are added resulting in 5 and then the
|
||||||
bitwise ``and`` with the string "abc" is computed.
|
bitwise ``and`` with the string "abc" is computed.
|
||||||
The final value is assigned to a local variable called ``x``.
|
The final value is assigned to a local variable called ``x``.
|
||||||
|
|
||||||
Strings are stored left-aligned and cannot be longer than 32 bytes.
|
Strings are stored left-aligned and cannot be longer than 32 bytes.
|
||||||
|
The limit does not apply to string literals passed to builtin functions that require
|
||||||
|
literal arguments (e.g. ``setimmutable`` or ``loadimmutable``). Those strings never end up in the
|
||||||
|
generated bytecode.
|
||||||
|
|
||||||
.. code-block:: yul
|
.. code-block:: yul
|
||||||
|
|
||||||
@ -923,6 +927,30 @@ will store ``value`` at all points in memory that contain a call to
|
|||||||
``loadimmutable("name")``.
|
``loadimmutable("name")``.
|
||||||
|
|
||||||
|
|
||||||
|
linkersymbol
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The function ``linkersymbol("fq_library_name")`` is a placeholder for an address literal to be
|
||||||
|
substituted by the linker. Its first and only argument must be a string literal and represents the
|
||||||
|
fully qualified library name used with the ``--libraries`` option.
|
||||||
|
|
||||||
|
For example this code
|
||||||
|
|
||||||
|
.. code-block:: yul
|
||||||
|
|
||||||
|
let a := linkersymbol("file.sol:Math")
|
||||||
|
|
||||||
|
is equivalent to
|
||||||
|
|
||||||
|
.. code-block:: yul
|
||||||
|
|
||||||
|
let a := 0x1234567890123456789012345678901234567890
|
||||||
|
|
||||||
|
when the linker is invoked with ``--libraries "file.sol:Math:0x1234567890123456789012345678901234567890``
|
||||||
|
option.
|
||||||
|
|
||||||
|
See :ref:`Using the Commandline Compiler <commandline-compiler>` for details about the Solidity linker.
|
||||||
|
|
||||||
|
|
||||||
.. _yul-object:
|
.. _yul-object:
|
||||||
|
|
||||||
|
@ -232,6 +232,7 @@ namespace solidity::langutil
|
|||||||
\
|
\
|
||||||
/* Identifiers (not keywords or future reserved words). */ \
|
/* Identifiers (not keywords or future reserved words). */ \
|
||||||
T(Identifier, nullptr, 0) \
|
T(Identifier, nullptr, 0) \
|
||||||
|
T(SubGwei, "gwei", 0) \
|
||||||
\
|
\
|
||||||
/* Keywords reserved for future use. */ \
|
/* Keywords reserved for future use. */ \
|
||||||
K(After, "after", 0) \
|
K(After, "after", 0) \
|
||||||
|
@ -32,6 +32,33 @@ using namespace solidity;
|
|||||||
using namespace solidity::langutil;
|
using namespace solidity::langutil;
|
||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
void copyMissingTags(StructurallyDocumentedAnnotation& _target, set<CallableDeclaration const*> const& _baseFunctions)
|
||||||
|
{
|
||||||
|
if (_baseFunctions.size() != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& sourceDoc = dynamic_cast<StructurallyDocumentedAnnotation const&>((*_baseFunctions.begin())->annotation());
|
||||||
|
|
||||||
|
set<string> existingTags;
|
||||||
|
|
||||||
|
for (auto const& iterator: _target.docTags)
|
||||||
|
existingTags.insert(iterator.first);
|
||||||
|
|
||||||
|
for (auto const& [tag, content]: sourceDoc.docTags)
|
||||||
|
if (tag != "inheritdoc" && !existingTags.count(tag))
|
||||||
|
_target.docTags.emplace(tag, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parameterNamesEqual(CallableDeclaration const& _a, CallableDeclaration const& _b)
|
||||||
|
{
|
||||||
|
return boost::range::equal(_a.parameters(), _b.parameters(), [](auto const& pa, auto const& pb) { return pa->name() == pb->name(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
|
bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
|
||||||
{
|
{
|
||||||
auto errorWatcher = m_errorReporter.errorWatcher();
|
auto errorWatcher = m_errorReporter.errorWatcher();
|
||||||
@ -65,7 +92,24 @@ bool DocStringAnalyser::visit(VariableDeclaration const& _variable)
|
|||||||
if (_variable.isPublic())
|
if (_variable.isPublic())
|
||||||
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "public state variables");
|
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "public state variables");
|
||||||
else
|
else
|
||||||
|
{
|
||||||
parseDocStrings(_variable, _variable.annotation(), validNonPublicTags, "non-public state variables");
|
parseDocStrings(_variable, _variable.annotation(), validNonPublicTags, "non-public state variables");
|
||||||
|
if (_variable.annotation().docTags.count("notice") > 0)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
7816_error, _variable.documentation()->location(),
|
||||||
|
"Documentation tag on non-public state variables will be disallowed in 0.7.0. "
|
||||||
|
"You will need to use the @dev tag explicitly."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
8532_error, _variable.documentation()->location(),
|
||||||
|
"Documentation tag @title and @author is only allowed on contract definitions. "
|
||||||
|
"It will be disallowed in 0.7.0."
|
||||||
|
);
|
||||||
|
|
||||||
|
if (_variable.annotation().docTags.empty())
|
||||||
|
copyMissingTags(_variable.annotation(), _variable.annotation().baseFunctions);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -129,6 +173,20 @@ void DocStringAnalyser::handleCallable(
|
|||||||
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param"};
|
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param"};
|
||||||
parseDocStrings(_node, _annotation, validTags, "functions");
|
parseDocStrings(_node, _annotation, validTags, "functions");
|
||||||
checkParameters(_callable, _node, _annotation);
|
checkParameters(_callable, _node, _annotation);
|
||||||
|
|
||||||
|
if (
|
||||||
|
_annotation.docTags.empty() &&
|
||||||
|
_callable.annotation().baseFunctions.size() == 1 &&
|
||||||
|
parameterNamesEqual(_callable, **_callable.annotation().baseFunctions.begin())
|
||||||
|
)
|
||||||
|
copyMissingTags(_annotation, _callable.annotation().baseFunctions);
|
||||||
|
|
||||||
|
if (_node.documentation() && _annotation.docTags.count("author") > 0)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
9843_error, _node.documentation()->location(),
|
||||||
|
"Documentation tag @author is only allowed on contract definitions. "
|
||||||
|
"It will be disallowed in 0.7.0."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocStringAnalyser::parseDocStrings(
|
void DocStringAnalyser::parseDocStrings(
|
||||||
|
@ -2084,6 +2084,7 @@ public:
|
|||||||
{
|
{
|
||||||
None = static_cast<int>(Token::Illegal),
|
None = static_cast<int>(Token::Illegal),
|
||||||
Wei = static_cast<int>(Token::SubWei),
|
Wei = static_cast<int>(Token::SubWei),
|
||||||
|
Gwei = static_cast<int>(Token::SubGwei),
|
||||||
Szabo = static_cast<int>(Token::SubSzabo),
|
Szabo = static_cast<int>(Token::SubSzabo),
|
||||||
Finney = static_cast<int>(Token::SubFinney),
|
Finney = static_cast<int>(Token::SubFinney),
|
||||||
Ether = static_cast<int>(Token::SubEther),
|
Ether = static_cast<int>(Token::SubEther),
|
||||||
|
@ -1002,6 +1002,8 @@ Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _no
|
|||||||
|
|
||||||
if (subDenStr == "wei")
|
if (subDenStr == "wei")
|
||||||
return Literal::SubDenomination::Wei;
|
return Literal::SubDenomination::Wei;
|
||||||
|
else if (subDenStr == "gwei")
|
||||||
|
return Literal::SubDenomination::Gwei;
|
||||||
else if (subDenStr == "szabo")
|
else if (subDenStr == "szabo")
|
||||||
return Literal::SubDenomination::Szabo;
|
return Literal::SubDenomination::Szabo;
|
||||||
else if (subDenStr == "finney")
|
else if (subDenStr == "finney")
|
||||||
|
@ -889,6 +889,9 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
|
|||||||
case Literal::SubDenomination::Wei:
|
case Literal::SubDenomination::Wei:
|
||||||
case Literal::SubDenomination::Second:
|
case Literal::SubDenomination::Second:
|
||||||
break;
|
break;
|
||||||
|
case Literal::SubDenomination::Gwei:
|
||||||
|
value *= bigint("1000000000");
|
||||||
|
break;
|
||||||
case Literal::SubDenomination::Szabo:
|
case Literal::SubDenomination::Szabo:
|
||||||
value *= bigint("1000000000000");
|
value *= bigint("1000000000000");
|
||||||
break;
|
break;
|
||||||
|
@ -307,11 +307,6 @@ bool CompilerStack::analyze()
|
|||||||
if (source->ast && !syntaxChecker.checkSyntax(*source->ast))
|
if (source->ast && !syntaxChecker.checkSyntax(*source->ast))
|
||||||
noErrors = false;
|
noErrors = false;
|
||||||
|
|
||||||
DocStringAnalyser docStringAnalyser(m_errorReporter);
|
|
||||||
for (Source const* source: m_sourceOrder)
|
|
||||||
if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
|
|
||||||
noErrors = false;
|
|
||||||
|
|
||||||
m_globalContext = make_shared<GlobalContext>();
|
m_globalContext = make_shared<GlobalContext>();
|
||||||
// We need to keep the same resolver during the whole process.
|
// We need to keep the same resolver during the whole process.
|
||||||
NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter);
|
NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter);
|
||||||
@ -367,6 +362,11 @@ bool CompilerStack::analyze()
|
|||||||
if (!contractLevelChecker.check(*contract))
|
if (!contractLevelChecker.check(*contract))
|
||||||
noErrors = false;
|
noErrors = false;
|
||||||
|
|
||||||
|
DocStringAnalyser docStringAnalyser(m_errorReporter);
|
||||||
|
for (Source const* source: m_sourceOrder)
|
||||||
|
if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
|
||||||
|
noErrors = false;
|
||||||
|
|
||||||
// New we run full type checks that go down to the expression level. This
|
// New we run full type checks that go down to the expression level. This
|
||||||
// cannot be done earlier, because we need cross-contract types and information
|
// cannot be done earlier, because we need cross-contract types and information
|
||||||
// about whether a contract is abstract for the `new` expression.
|
// about whether a contract is abstract for the `new` expression.
|
||||||
|
@ -36,6 +36,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
|||||||
{
|
{
|
||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
|
Json::Value events(Json::objectValue);
|
||||||
|
|
||||||
doc["version"] = Json::Value(c_natspecVersion);
|
doc["version"] = Json::Value(c_natspecVersion);
|
||||||
doc["kind"] = Json::Value("user");
|
doc["kind"] = Json::Value("user");
|
||||||
@ -84,7 +85,17 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto const& event: _contractDef.events())
|
||||||
|
{
|
||||||
|
string value = extractDoc(event->annotation().docTags, "notice");
|
||||||
|
if (!value.empty())
|
||||||
|
events[event->functionType(true)->externalSignature()]["notice"] = value;
|
||||||
|
}
|
||||||
|
|
||||||
doc["methods"] = methods;
|
doc["methods"] = methods;
|
||||||
|
if (!events.empty())
|
||||||
|
doc["events"] = events;
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
@ -145,9 +156,16 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
|
|||||||
stateVariables[varDecl->name()]["return"] = extractDoc(varDecl->annotation().docTags, "return");
|
stateVariables[varDecl->name()]["return"] = extractDoc(varDecl->annotation().docTags, "return");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Json::Value events(Json::objectValue);
|
||||||
|
for (auto const& event: _contractDef.events())
|
||||||
|
if (auto devDoc = devDocumentation(event->annotation().docTags); !devDoc.empty())
|
||||||
|
events[event->functionType(true)->externalSignature()] = devDoc;
|
||||||
|
|
||||||
doc["methods"] = methods;
|
doc["methods"] = methods;
|
||||||
if (!stateVariables.empty())
|
if (!stateVariables.empty())
|
||||||
doc["stateVariables"] = stateVariables;
|
doc["stateVariables"] = stateVariables;
|
||||||
|
if (!events.empty())
|
||||||
|
doc["events"] = events;
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
@ -1825,11 +1825,16 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
|||||||
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
|
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
|
||||||
break;
|
break;
|
||||||
case Token::Number:
|
case Token::Number:
|
||||||
if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken()))
|
if (
|
||||||
|
(m_scanner->peekNextToken() == Token::Identifier && m_scanner->peekLiteral() == "gwei") ||
|
||||||
|
TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken())
|
||||||
|
)
|
||||||
{
|
{
|
||||||
ASTPointer<ASTString> literal = getLiteralAndAdvance();
|
ASTPointer<ASTString> literal = getLiteralAndAdvance();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->currentToken());
|
Token actualToken = m_scanner->currentToken() == Token::Identifier ? Token::SubGwei : m_scanner->currentToken();
|
||||||
|
|
||||||
|
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(actualToken);
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
|
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
|
||||||
}
|
}
|
||||||
|
@ -301,10 +301,15 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
|||||||
for (size_t i = _funCall.arguments.size(); i > 0; i--)
|
for (size_t i = _funCall.arguments.size(); i > 0; i--)
|
||||||
{
|
{
|
||||||
Expression const& arg = _funCall.arguments[i - 1];
|
Expression const& arg = _funCall.arguments[i - 1];
|
||||||
|
bool isLiteralArgument = needsLiteralArguments && (*needsLiteralArguments)[i - 1];
|
||||||
|
bool isStringLiteral = holds_alternative<Literal>(arg) && get<Literal>(arg).kind == LiteralKind::String;
|
||||||
|
|
||||||
argTypes.emplace_back(expectExpression(arg));
|
if (isLiteralArgument && isStringLiteral)
|
||||||
|
argTypes.emplace_back(expectUnlimitedStringLiteral(get<Literal>(arg)));
|
||||||
|
else
|
||||||
|
argTypes.emplace_back(expectExpression(arg));
|
||||||
|
|
||||||
if (needsLiteralArguments && (*needsLiteralArguments)[i - 1])
|
if (isLiteralArgument)
|
||||||
{
|
{
|
||||||
if (!holds_alternative<Literal>(arg))
|
if (!holds_alternative<Literal>(arg))
|
||||||
m_errorReporter.typeError(
|
m_errorReporter.typeError(
|
||||||
@ -433,6 +438,14 @@ YulString AsmAnalyzer::expectExpression(Expression const& _expr)
|
|||||||
return types.empty() ? m_dialect.defaultType : types.front();
|
return types.empty() ? m_dialect.defaultType : types.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
YulString AsmAnalyzer::expectUnlimitedStringLiteral(Literal const& _literal)
|
||||||
|
{
|
||||||
|
yulAssert(_literal.kind == LiteralKind::String, "");
|
||||||
|
yulAssert(m_dialect.validTypeForLiteral(LiteralKind::String, _literal.value, _literal.type), "");
|
||||||
|
|
||||||
|
return {_literal.type};
|
||||||
|
}
|
||||||
|
|
||||||
void AsmAnalyzer::expectBoolExpression(Expression const& _expr)
|
void AsmAnalyzer::expectBoolExpression(Expression const& _expr)
|
||||||
{
|
{
|
||||||
YulString type = expectExpression(_expr);
|
YulString type = expectExpression(_expr);
|
||||||
@ -531,7 +544,7 @@ void AsmAnalyzer::expectType(YulString _expectedType, YulString _givenType, Sour
|
|||||||
bool AsmAnalyzer::warnOnInstructions(std::string const& _instructionIdentifier, langutil::SourceLocation const& _location)
|
bool AsmAnalyzer::warnOnInstructions(std::string const& _instructionIdentifier, langutil::SourceLocation const& _location)
|
||||||
{
|
{
|
||||||
auto const builtin = EVMDialect::strictAssemblyForEVM(EVMVersion{}).builtin(YulString(_instructionIdentifier));
|
auto const builtin = EVMDialect::strictAssemblyForEVM(EVMVersion{}).builtin(YulString(_instructionIdentifier));
|
||||||
if (builtin)
|
if (builtin && builtin->instruction.has_value())
|
||||||
return warnOnInstructions(builtin->instruction.value(), _location);
|
return warnOnInstructions(builtin->instruction.value(), _location);
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@ -97,6 +97,7 @@ private:
|
|||||||
/// Visits the expression, expects that it evaluates to exactly one value and
|
/// Visits the expression, expects that it evaluates to exactly one value and
|
||||||
/// returns the type. Reports errors on errors and returns the default type.
|
/// returns the type. Reports errors on errors and returns the default type.
|
||||||
YulString expectExpression(Expression const& _expr);
|
YulString expectExpression(Expression const& _expr);
|
||||||
|
YulString expectUnlimitedStringLiteral(Literal const& _literal);
|
||||||
/// Vists the expression and expects it to return a single boolean value.
|
/// Vists the expression and expects it to return a single boolean value.
|
||||||
/// Reports an error otherwise.
|
/// Reports an error otherwise.
|
||||||
void expectBoolExpression(Expression const& _expr);
|
void expectBoolExpression(Expression const& _expr);
|
||||||
|
@ -124,6 +124,17 @@ map<YulString, BuiltinFunctionForEVM> createBuiltins(langutil::EVMVersion _evmVe
|
|||||||
)
|
)
|
||||||
builtins.emplace(createEVMFunction(instr.first, instr.second));
|
builtins.emplace(createEVMFunction(instr.first, instr.second));
|
||||||
|
|
||||||
|
builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {true}, [](
|
||||||
|
FunctionCall const& _call,
|
||||||
|
AbstractAssembly& _assembly,
|
||||||
|
BuiltinContext&,
|
||||||
|
function<void(Expression const&)>
|
||||||
|
) {
|
||||||
|
yulAssert(_call.arguments.size() == 1, "");
|
||||||
|
Expression const& arg = _call.arguments.front();
|
||||||
|
_assembly.appendLinkerSymbol(std::get<Literal>(arg).value.str());
|
||||||
|
}));
|
||||||
|
|
||||||
if (_objectAccess)
|
if (_objectAccess)
|
||||||
{
|
{
|
||||||
builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {true}, [](
|
builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {true}, [](
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/range/adaptor/transformed.hpp>
|
#include <boost/range/adaptor/transformed.hpp>
|
||||||
|
#include <boost/range/adaptor/filtered.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
#ifdef _WIN32 // windows
|
#ifdef _WIN32 // windows
|
||||||
@ -1202,9 +1203,14 @@ bool CommandLineInterface::processInput()
|
|||||||
};
|
};
|
||||||
if (countEnabledOptions(nonAssemblyModeOptions) >= 1)
|
if (countEnabledOptions(nonAssemblyModeOptions) >= 1)
|
||||||
{
|
{
|
||||||
|
auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; };
|
||||||
|
auto enabledOptions = boost::copy_range<vector<string>>(nonAssemblyModeOptions | boost::adaptors::filtered(optionEnabled));
|
||||||
|
|
||||||
serr() << "The following options are invalid in assembly mode: ";
|
serr() << "The following options are invalid in assembly mode: ";
|
||||||
serr() << joinOptionNames(nonAssemblyModeOptions) << ". ";
|
serr() << joinOptionNames(enabledOptions) << ".";
|
||||||
serr() << "Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
|
if (m_args.count(g_strOptimizeYul) || m_args.count(g_strNoOptimizeYul))
|
||||||
|
serr() << " Optimization is disabled by default and can be enabled with --" << g_argOptimize << "." << endl;
|
||||||
|
serr() << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ using Address = util::h160;
|
|||||||
// The various denominations; here for ease of use where needed within code.
|
// The various denominations; here for ease of use where needed within code.
|
||||||
static const u256 wei = 1;
|
static const u256 wei = 1;
|
||||||
static const u256 shannon = u256("1000000000");
|
static const u256 shannon = u256("1000000000");
|
||||||
|
static const u256 gwei = shannon;
|
||||||
static const u256 szabo = shannon * 1000;
|
static const u256 szabo = shannon * 1000;
|
||||||
static const u256 finney = szabo * 1000;
|
static const u256 finney = szabo * 1000;
|
||||||
static const u256 ether = finney * 1000;
|
static const u256 ether = finney * 1000;
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
--strict-assembly --optimize-yul
|
@ -0,0 +1 @@
|
|||||||
|
The following options are invalid in assembly mode: --optimize-yul. Optimization is disabled by default and can be enabled with --optimize.
|
@ -0,0 +1 @@
|
|||||||
|
1
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
sstore(0, 1)
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
The following options are invalid in assembly mode: --output-dir, --gas, --combined-json, --optimize-yul, --no-optimize-yul. Optimization is disabled by default and can be enabled with --optimize.
|
The following options are invalid in assembly mode: --output-dir.
|
||||||
|
@ -221,6 +221,21 @@ BOOST_AUTO_TEST_CASE(int_with_wei_ether_subdenomination)
|
|||||||
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(int_with_gwei_ether_subdenomination)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract test {
|
||||||
|
function test () {
|
||||||
|
uint x = 1 gwei;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
bytes code = compileFirstExpression(sourceCode);
|
||||||
|
|
||||||
|
bytes expectation({uint8_t(Instruction::PUSH4), 0x3b, 0x9a, 0xca, 0x00});
|
||||||
|
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
|
BOOST_AUTO_TEST_CASE(int_with_szabo_ether_subdenomination)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -355,6 +355,52 @@ BOOST_AUTO_TEST_CASE(private_state_variable)
|
|||||||
checkNatspec(sourceCode, "test", userDoc, true);
|
checkNatspec(sourceCode, "test", userDoc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(event)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract ERC20 {
|
||||||
|
/// @notice This event is emitted when a transfer occurs.
|
||||||
|
/// @param from The source account.
|
||||||
|
/// @param to The destination account.
|
||||||
|
/// @param amount The amount.
|
||||||
|
/// @dev A test case!
|
||||||
|
event Transfer(address indexed from, address indexed to, uint amount);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const* devDoc = R"ABCDEF(
|
||||||
|
{
|
||||||
|
"events":
|
||||||
|
{
|
||||||
|
"Transfer(address,address,uint256)":
|
||||||
|
{
|
||||||
|
"details": "A test case!",
|
||||||
|
"params":
|
||||||
|
{
|
||||||
|
"amount": "The amount.", "from": "The source account.", "to": "The destination account."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"methods": {}
|
||||||
|
}
|
||||||
|
)ABCDEF";
|
||||||
|
checkNatspec(sourceCode, "ERC20", devDoc, false);
|
||||||
|
|
||||||
|
char const* userDoc = R"ABCDEF(
|
||||||
|
{
|
||||||
|
"events":
|
||||||
|
{
|
||||||
|
"Transfer(address,address,uint256)":
|
||||||
|
{
|
||||||
|
"notice": "This event is emitted when a transfer occurs."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"methods": {}
|
||||||
|
}
|
||||||
|
)ABCDEF";
|
||||||
|
checkNatspec(sourceCode, "ERC20", userDoc, true);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
|
BOOST_AUTO_TEST_CASE(dev_desc_after_nl)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
@ -1218,6 +1264,263 @@ BOOST_AUTO_TEST_CASE(slash3_slash4)
|
|||||||
checkNatspec(sourceCode, "test", natspec, true);
|
checkNatspec(sourceCode, "test", natspec, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_CASE(dev_default_inherit_variable)
|
||||||
|
{
|
||||||
|
char const *sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
/// @notice Hello world
|
||||||
|
/// @dev test
|
||||||
|
function x() virtual external returns (uint) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract D is C {
|
||||||
|
uint public override x;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const *natspec = R"ABCDEF({
|
||||||
|
"methods":
|
||||||
|
{
|
||||||
|
"x()":
|
||||||
|
{
|
||||||
|
"details": "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
char const *natspec1 = R"ABCDEF({
|
||||||
|
"methods" : {},
|
||||||
|
"stateVariables" :
|
||||||
|
{
|
||||||
|
"x" :
|
||||||
|
{
|
||||||
|
"details" : "test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "C", natspec, false);
|
||||||
|
checkNatspec(sourceCode, "D", natspec1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_default_inherit_variable)
|
||||||
|
{
|
||||||
|
char const *sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
/// @notice Hello world
|
||||||
|
/// @dev test
|
||||||
|
function x() virtual external returns (uint) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract D is C {
|
||||||
|
uint public override x;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const *natspec = R"ABCDEF({
|
||||||
|
"methods":
|
||||||
|
{
|
||||||
|
"x()":
|
||||||
|
{
|
||||||
|
"notice": "Hello world"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "C", natspec, true);
|
||||||
|
checkNatspec(sourceCode, "D", natspec, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(dev_default_inherit)
|
||||||
|
{
|
||||||
|
char const *sourceCode = R"(
|
||||||
|
interface ERC20 {
|
||||||
|
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||||
|
/// Second line.
|
||||||
|
/// @author Programmer
|
||||||
|
/// @dev test
|
||||||
|
/// @param to address to transfer to
|
||||||
|
/// @param amount amount to transfer
|
||||||
|
function transfer(address to, uint amount) external returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Middle is ERC20 {
|
||||||
|
function transfer(address to, uint amount) virtual override external returns (bool)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Token is Middle {
|
||||||
|
function transfer(address to, uint amount) override external returns (bool)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const *natspec = R"ABCDEF({
|
||||||
|
"methods":
|
||||||
|
{
|
||||||
|
"transfer(address,uint256)":
|
||||||
|
{
|
||||||
|
"author": "Programmer",
|
||||||
|
"details": "test",
|
||||||
|
"params":
|
||||||
|
{
|
||||||
|
"amount": "amount to transfer",
|
||||||
|
"to": "address to transfer to"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||||
|
checkNatspec(sourceCode, "Middle", natspec, false);
|
||||||
|
checkNatspec(sourceCode, "Token", natspec, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_default_inherit)
|
||||||
|
{
|
||||||
|
char const *sourceCode = R"(
|
||||||
|
interface ERC20 {
|
||||||
|
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||||
|
/// Second line.
|
||||||
|
/// @author Programmer
|
||||||
|
/// @dev test
|
||||||
|
/// @param to address to transfer to
|
||||||
|
/// @param amount amount to transfer
|
||||||
|
function transfer(address to, uint amount) external returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Middle is ERC20 {
|
||||||
|
function transfer(address to, uint amount) virtual override external returns (bool)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Token is Middle {
|
||||||
|
function transfer(address to, uint amount) override external returns (bool)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const *natspec = R"ABCDEF({
|
||||||
|
"methods":
|
||||||
|
{
|
||||||
|
"transfer(address,uint256)":
|
||||||
|
{
|
||||||
|
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``. Second line."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||||
|
checkNatspec(sourceCode, "Middle", natspec, true);
|
||||||
|
checkNatspec(sourceCode, "Token", natspec, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(dev_inherit_parameter_mismatch)
|
||||||
|
{
|
||||||
|
char const *sourceCode = R"(
|
||||||
|
interface ERC20 {
|
||||||
|
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||||
|
/// @author Programmer
|
||||||
|
/// @dev test
|
||||||
|
/// @param to address to transfer to
|
||||||
|
/// @param amount amount to transfer
|
||||||
|
function transfer(address to, uint amount) external returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Middle is ERC20 {
|
||||||
|
function transfer(address to, uint amount) override virtual external returns (bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Token is Middle {
|
||||||
|
function transfer(address too, uint amount) override external returns (bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const *natspec = R"ABCDEF({
|
||||||
|
"methods":
|
||||||
|
{
|
||||||
|
"transfer(address,uint256)":
|
||||||
|
{
|
||||||
|
"author": "Programmer",
|
||||||
|
"details": "test",
|
||||||
|
"params":
|
||||||
|
{
|
||||||
|
"amount": "amount to transfer",
|
||||||
|
"to": "address to transfer to"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
char const *natspec2 = R"ABCDEF({
|
||||||
|
"methods": { }
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "ERC20", natspec, false);
|
||||||
|
checkNatspec(sourceCode, "Middle", natspec, false);
|
||||||
|
checkNatspec(sourceCode, "Token", natspec2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(user_inherit_parameter_mismatch)
|
||||||
|
{
|
||||||
|
char const *sourceCode = R"(
|
||||||
|
interface ERC20 {
|
||||||
|
/// Transfer ``amount`` from ``msg.sender`` to ``to``.
|
||||||
|
/// @author Programmer
|
||||||
|
/// @dev test
|
||||||
|
/// @param to address to transfer to
|
||||||
|
/// @param amount amount to transfer
|
||||||
|
function transfer(address to, uint amount) external returns (bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Middle is ERC20 {
|
||||||
|
function transfer(address to, uint amount) override virtual external returns (bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Token is Middle {
|
||||||
|
function transfer(address too, uint amount) override external returns (bool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
char const *natspec = R"ABCDEF({
|
||||||
|
"methods":
|
||||||
|
{
|
||||||
|
"transfer(address,uint256)":
|
||||||
|
{
|
||||||
|
"notice": "Transfer ``amount`` from ``msg.sender`` to ``to``."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
char const *natspec2 = R"ABCDEF({
|
||||||
|
"methods": { }
|
||||||
|
})ABCDEF";
|
||||||
|
|
||||||
|
checkNatspec(sourceCode, "ERC20", natspec, true);
|
||||||
|
checkNatspec(sourceCode, "Middle", natspec, true);
|
||||||
|
checkNatspec(sourceCode, "Token", natspec2, true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -428,8 +428,9 @@ BOOST_AUTO_TEST_CASE(comments_mixed_in_sequence)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(ether_subdenominations)
|
BOOST_AUTO_TEST_CASE(ether_subdenominations)
|
||||||
{
|
{
|
||||||
Scanner scanner(CharStream("wei szabo finney ether", ""));
|
Scanner scanner(CharStream("wei gwei szabo finney ether", ""));
|
||||||
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::SubWei);
|
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::SubWei);
|
||||||
|
BOOST_CHECK_EQUAL(scanner.next(), Token::Identifier);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::SubSzabo);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::SubSzabo);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::SubFinney);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::SubFinney);
|
||||||
BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther);
|
BOOST_CHECK_EQUAL(scanner.next(), Token::SubEther);
|
||||||
|
10
test/libsolidity/semanticTests/literals/gwei.sol
Normal file
10
test/libsolidity/semanticTests/literals/gwei.sol
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant gwei = 1 gwei;
|
||||||
|
|
||||||
|
function f() public view returns(uint) { return gwei; }
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> 1000000000
|
||||||
|
|
@ -2,5 +2,6 @@ contract C {
|
|||||||
uint constant a = 1 wei + 2 szabo + 3 finney + 4 ether;
|
uint constant a = 1 wei + 2 szabo + 3 finney + 4 ether;
|
||||||
uint constant b = 1 seconds + 2 minutes + 3 hours + 4 days + 5 weeks;
|
uint constant b = 1 seconds + 2 minutes + 3 hours + 4 days + 5 weeks;
|
||||||
uint constant c = 2 szabo / 1 seconds + 3 finney * 3 hours;
|
uint constant c = 2 szabo / 1 seconds + 3 finney * 3 hours;
|
||||||
|
uint constant d = 2 gwei / 1 seconds + 3 finney * 3 hours;
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
3
test/libsolidity/syntaxTests/denominations/gwei.sol
Normal file
3
test/libsolidity/syntaxTests/denominations/gwei.sol
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract C {
|
||||||
|
uint constant gwei = 1 gwei;
|
||||||
|
}
|
4
test/libsolidity/syntaxTests/immutable/long_name.sol
Normal file
4
test/libsolidity/syntaxTests/immutable/long_name.sol
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
contract C {
|
||||||
|
uint immutable long___name___that___definitely___exceeds___the___thirty___two___byte___limit = 0;
|
||||||
|
}
|
||||||
|
// ----
|
@ -0,0 +1,6 @@
|
|||||||
|
contract C {
|
||||||
|
/// @author author
|
||||||
|
function iHaveAuthor() public pure {}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning 9843: (17-35): Documentation tag @author is only allowed on contract definitions. It will be disallowed in 0.7.0.
|
@ -1,15 +1,16 @@
|
|||||||
contract c {
|
contract C {
|
||||||
function f() public
|
function f() public
|
||||||
{
|
{
|
||||||
a = 1 wei;
|
a = 1 wei;
|
||||||
b = 2 szabo;
|
b = 2 szabo;
|
||||||
c = 3 finney;
|
c = 3 finney;
|
||||||
b = 4 ether;
|
d = 4 ether;
|
||||||
|
e = 5 gwei;
|
||||||
}
|
}
|
||||||
uint256 a;
|
uint256 a;
|
||||||
uint256 b;
|
uint256 b;
|
||||||
uint256 c;
|
uint256 c;
|
||||||
uint256 d;
|
uint256 d;
|
||||||
|
uint256 e;
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 2519: (170-179): This declaration shadows an existing declaration.
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
object "a" {
|
||||||
|
code {
|
||||||
|
setimmutable(
|
||||||
|
"long___name___that___definitely___exceeds___the___thirty___two___byte___limit",
|
||||||
|
0x1234567890123456789012345678901234567890
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Assembly:
|
||||||
|
// /* "source":152:194 */
|
||||||
|
// 0x1234567890123456789012345678901234567890
|
||||||
|
// /* "source":32:204 */
|
||||||
|
// assignImmutable("0x85a5b1db611c82c46f5fa18e39ae218397536256c451e5de155a86de843a9ad6")
|
||||||
|
// Bytecode: 73123456789012345678901234567890123456789050
|
||||||
|
// Opcodes: PUSH20 0x1234567890123456789012345678901234567890 POP
|
||||||
|
// SourceMappings: 152:42:0:-:0;32:172
|
42
test/libyul/objectCompiler/linkersymbol.yul
Normal file
42
test/libyul/objectCompiler/linkersymbol.yul
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
object "a" {
|
||||||
|
code {
|
||||||
|
let addr := linkersymbol("contract/test.sol:L")
|
||||||
|
mstore(128, shl(227, 0x18530aaf))
|
||||||
|
let success := call(gas(), addr, 0, 128, 4, 128, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Assembly:
|
||||||
|
// linkerSymbol("f919ba91ac99f96129544b80b9516b27a80e376b9dc693819d0b18b7e0395612")
|
||||||
|
// /* "source":109:119 */
|
||||||
|
// 0x18530aaf
|
||||||
|
// /* "source":104:107 */
|
||||||
|
// 0xe3
|
||||||
|
// /* "source":100:120 */
|
||||||
|
// shl
|
||||||
|
// /* "source":95:98 */
|
||||||
|
// 0x80
|
||||||
|
// /* "source":88:121 */
|
||||||
|
// mstore
|
||||||
|
// /* "source":179:180 */
|
||||||
|
// 0x00
|
||||||
|
// /* "source":174:177 */
|
||||||
|
// 0x80
|
||||||
|
// /* "source":171:172 */
|
||||||
|
// 0x04
|
||||||
|
// /* "source":166:169 */
|
||||||
|
// 0x80
|
||||||
|
// /* "source":163:164 */
|
||||||
|
// 0x00
|
||||||
|
// /* "source":157:161 */
|
||||||
|
// dup6
|
||||||
|
// /* "source":150:155 */
|
||||||
|
// gas
|
||||||
|
// /* "source":145:181 */
|
||||||
|
// call
|
||||||
|
// /* "source":22:187 */
|
||||||
|
// pop
|
||||||
|
// pop
|
||||||
|
// Bytecode: 7300000000000000000000000000000000000000006318530aaf60e31b60805260006080600460806000855af15050
|
||||||
|
// Opcodes: PUSH20 0x0 PUSH4 0x18530AAF PUSH1 0xE3 SHL PUSH1 0x80 MSTORE PUSH1 0x0 PUSH1 0x80 PUSH1 0x4 PUSH1 0x80 PUSH1 0x0 DUP6 GAS CALL POP POP
|
||||||
|
// SourceMappings: :::-:0;109:10:0;104:3;100:20;95:3;88:33;179:1;174:3;171:1;166:3;163:1;157:4;150:5;145:36;22:165;
|
16
test/libyul/yulInterpreterTests/self_balance.yul
Normal file
16
test/libyul/yulInterpreterTests/self_balance.yul
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
mstore(0, balance(address()))
|
||||||
|
mstore(0x20, selfbalance())
|
||||||
|
mstore(0x40, balance(div(mul(address(), 2), 2)))
|
||||||
|
mstore(0x60, balance(add(address(), 1)))
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=istanbul
|
||||||
|
// ----
|
||||||
|
// Trace:
|
||||||
|
// Memory dump:
|
||||||
|
// 0: 0000000000000000000000000000000000000000000000000000000022223333
|
||||||
|
// 20: 0000000000000000000000000000000000000000000000000000000022223333
|
||||||
|
// 40: 0000000000000000000000000000000000000000000000000000000022223333
|
||||||
|
// 60: 0000000000000000000000000000000000000000000000000000000022222222
|
||||||
|
// Storage dump:
|
6
test/libyul/yulSyntaxTests/byte_of_string_literal.yul
Normal file
6
test/libyul/yulSyntaxTests/byte_of_string_literal.yul
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
let x := byte(31, "11112222333344445555666677778888")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
6
test/libyul/yulSyntaxTests/linkersymbol_evm.yul
Normal file
6
test/libyul/yulSyntaxTests/linkersymbol_evm.yul
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
let addr := linkersymbol("contract/library.sol:L")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
6
test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul
Normal file
6
test/libyul/yulSyntaxTests/linkersymbol_evmtyped.yul
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
let addr:u256 := linkersymbol("contract/library.sol:L")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evmTyped
|
||||||
|
// ----
|
7
test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul
Normal file
7
test/libyul/yulSyntaxTests/linkersymbol_ewasm.yul
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
linkersymbol("contract/library.sol:L")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: ewasm
|
||||||
|
// ----
|
||||||
|
// DeclarationError 4619: (6-18): Function not found.
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
let library_name := "contract/library.sol:L"
|
||||||
|
let addr := linkersymbol(library_name)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
||||||
|
// TypeError 9114: (67-79): Function expects direct literals as arguments.
|
6
test/libyul/yulSyntaxTests/loadimmutable.yul
Normal file
6
test/libyul/yulSyntaxTests/loadimmutable.yul
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
let addr := loadimmutable("address")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
setimmutable(loadimmutable("abc"), "abc")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
||||||
|
// TypeError 9114: (6-18): Function expects direct literals as arguments.
|
6
test/libyul/yulSyntaxTests/setimmutable.yul
Normal file
6
test/libyul/yulSyntaxTests/setimmutable.yul
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
setimmutable("address", 0x1234567890123456789012345678901234567890)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
7
test/libyul/yulSyntaxTests/string_literal_too_long.yul
Normal file
7
test/libyul/yulSyntaxTests/string_literal_too_long.yul
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
let name := "long___name___that___definitely___exceeds___the___thirty___two___byte___limit"
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
||||||
|
// TypeError 3069: (18-97): String literal too long (77 > 32)
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
let x := byte(40, "long___value__that___definitely___exceeds___the___thirty___two___byte___limit")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
||||||
|
// TypeError 3069: (24-103): String literal too long (77 > 32)
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
setimmutable(
|
||||||
|
"long___name___that___definitely___exceeds___the___thirty___two___byte___limit",
|
||||||
|
0x1234567890123456789012345678901234567890
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
let addr := linkersymbol("contract/long___name___that___definitely___exceeds___the___thirty___two___byte___limit.sol:L")
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// dialect: evm
|
||||||
|
// ----
|
@ -8,6 +8,7 @@
|
|||||||
" ether "
|
" ether "
|
||||||
" finney "
|
" finney "
|
||||||
" gasleft() "
|
" gasleft() "
|
||||||
|
" gwei "
|
||||||
" hours "
|
" hours "
|
||||||
" minutes "
|
" minutes "
|
||||||
" msg.data "
|
" msg.data "
|
||||||
|
@ -182,7 +182,10 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::ADDRESS:
|
case Instruction::ADDRESS:
|
||||||
return m_state.address;
|
return m_state.address;
|
||||||
case Instruction::BALANCE:
|
case Instruction::BALANCE:
|
||||||
return m_state.balance;
|
if (arg[0] == m_state.address)
|
||||||
|
return m_state.selfbalance;
|
||||||
|
else
|
||||||
|
return m_state.balance;
|
||||||
case Instruction::SELFBALANCE:
|
case Instruction::SELFBALANCE:
|
||||||
return m_state.selfbalance;
|
return m_state.selfbalance;
|
||||||
case Instruction::ORIGIN:
|
case Instruction::ORIGIN:
|
||||||
|
Loading…
Reference in New Issue
Block a user