solidity-parser / parser Goto Github PK
View Code? Open in Web Editor NEWA Solidity parser for JS built on top of a robust ANTLR4 grammar
License: MIT License
A Solidity parser for JS built on top of a robust ANTLR4 grammar
License: MIT License
I want to find out function overriding and function modifier overriding in the AST. However, it seems not possible in some situation.
contract A {
function f(uint a) public virtual {
return a + 1;
}
}
contract B is A {
function f(uint a) public override { // cannot detect
return a + 2;
}
}
The override
array of the FunctionDefinition
node of B.f
is empty, which means I cannot know whether a function is overriding another function in the parent contract. However, the code below works:
contract A {
function f(uint a) public virtual {
return a + 1;
}
}
contract B is A {
function f(uint a) public override(A) { // can detect
return a + 2;
}
}
When the name is explicitly given in override(...)
, the override
array contains one element. How can I detect unnamed overriding? The same situation happens on function modifier overriding:
contract A {
modifier m() virtual { _; }
}
contract B is A {
modifier m() override { _; } // cannot detect
}
@fvictorio and @cgewecke thanks for the update in issue #9 .
However, now I get a new Parser Error, I assume one of the following things could be the issue with my expressions in the contract (that compiles fine):
pragma experimental ABIEncoderV2
in order to accept solidity structs
and nested structs
as function params
and to emit
them in events
. (btw the EncoderV2 is not considered experimental any more since 0.6)
I am using solidity try/catch
expressions
An unexpected error occurred:
Error: Could not instrument: gelato_core/GelatoCore.sol. (Please verify solc can compile this file without errors.) Unrecognized expression
at ASTBuilder.Expression (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:758:11)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.Expression (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:700:30)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.TryStatement (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:483:24)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.Statement (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:557:17)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.<anonymous> (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1292:19)
at Array.map (<anonymous>)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1291:16)
at ASTBuilder.Block (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:517:24)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.FunctionDefinition (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:143:20)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.ContractPart (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:127:17)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
at ASTBuilder.<anonymous> (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1292:19)
at Array.map (<anonymous>)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1291:16)
at ASTBuilder.ContractDefinition (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:113:22)
at ASTBuilder.visit (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-diligence/dist/ASTBuilder.js:1304:38)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
I have react app.Β Everything works well with version 0.9.1
, but when I installed 0.13.2
import fails
import parser from '@solidity-parser/parser';
as well as
import * as parser from '@solidity-parser/parser';
const parser require('@solidity-parser/parser');
error:
TypeError: __webpack_require__(...).join is not a function
...
on localhost:
node_modules/@solidity-parser/parser/dist/index.cjs.js:25092
25089 | if (typeof BROWSER !== "undefined") {
25090 | module2.exports = require_Solidity();
25091 | } else {
> 25092 | module2.exports = require("fs").readFileSync(require("path").join(__dirname, "./antlr/Solidity.tokens")).toString();
25093 | }
25094 | });
25095 |
Example:
pragma solidity ^0.8.4;
contract Greeter {
error Unauthorized();
function throwUnauthorized() public pure {
revert Unauthorized();
}
}
Also this explainer
Solidity 0.8.13 introduced a new file-level syntax for specifying a global using
statement on user-defined types:
using ... for ... global;
Solidity parser currently cannot handle this syntax.
Example contract using this syntax:
type Fixed18 is int256;
using Fixed18Lib for Fixed18 global;
library Fixed18Lib {
function add(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {
return Fixed18.wrap(Fixed18.unwrap(a) + Fixed18.unwrap(b));
}
function sub(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {
return Fixed18.wrap(Fixed18.unwrap(a) - Fixed18.unwrap(b));
}
}
contract C {
function f(uint256 a,) external view {}
}
results in
$ prettier --write "contracts/**/*.sol"
contracts/a.sol
[error] contracts/a.sol: Error: Assertion error: unhandled type name case
[error] at ASTBuilder.visitTypeName (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35664:11)
[error] at ASTBuilder.visitParameter (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35499:22)
[error] at ParameterContext.accept (/node_modules/@solidity-parser/parser/dist/index.cjs.js:32870:22)
[error] at ASTBuilder.visit (/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
[error] at /node_modules/@solidity-parser/parser/dist/index.cjs.js:35552:70
[error] at Array.map (<anonymous>)
[error] at ASTBuilder.visitFunctionDefinition (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35552:54)
[error] at FunctionDefinitionContext.accept (/node_modules/@solidity-parser/parser/dist/index.cjs.js:32561:22)
[error] at ASTBuilder.visit (/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
[error] at ASTBuilder.visitContractPart (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35334:17)
The same happens with return parameters:
contract C {
function f(uint256) external view returns (uint256,) {}
}
I think there should be a nicer message saying what failed, if possible?
(Originally opened at prettier-solidity/prettier-plugin-solidity#585. Prettier uses the version 0.13.2 of the parser.)
This throws:
contract Foo {
function f() public {
(uint[][] memory x, uint y) = abi.decode(data, (uint[][], uint));
}
}
Changing
- assembly {
+ assembly ("memory-safe") {
as per https://docs.soliditylang.org/en/v0.8.13/assembly.html#memory-safety
will cause a parser error (in solhin):
195:17 error Parse error: extraneous input '(' expecting {'{', StringLiteralFragment}
195:31 error Parse error: extraneous input ')' expecting '{'
Solidity 0.6.8 introduces SPDX license identifiers so developers can specify the license the contract uses. Source
I think there are tools that use this library that would benefit if this would be implemented for example solhint.
I would like to provide a PR to implement this, but I'm a little bit out of my depth here.. If one can give me a hint how to implement an additional type with the mentioned formatting, would greatly appreciate it.
Original issue: federicobond/solidity-parser-antlr#95
Solidity 0.8.13 introduced this:
assembly ("memory-safe") { ... }
Hi, I would like to transpile solidity source code by first generating AST from source code, modifying AST, and then generating source code based on the modified AST. Is this possible with solidity-parser
? I can only find parse
API in the documentation.
When payable is used as a function (to cast an address to a payable address), the parser doesn't return a proper node:
{
type: 'FunctionCall',
expression: { type: 'TerminalNodeImpl' },
arguments: [ ... ],
names: []
}
Notice that expression
should be { type: 'Identifier', name: 'payable' }
(Thanks a million for maintaining this @fvictorio. It's the best.)
In 71f83ca antlr4 is added as a direct dependency.
Was updating some things to 0.9.1
and am getting the installation error below when is Node < 14.
14 is LTS as of late October but just wanted to double-check with you that this is expected.
[2/4] π Fetching packages...
error [email protected]: The engine "node" is incompatible with this module. Expected version ">=14". Got "12.16.0"
error Found incompatible module.
Since v0.7.0, Solidity has a new syntax for unicode literals (see documents):
string memory a = unicode"Hello π";
However, this is not currently supported by the parser.
For the following Javascript code:
const parser = require('@solidity-parser/parser');
const code = `
contract test {
function f() {
string memory a = unicode"Hello π";
}
}
`;
parser.parse(code);
An error will be thrown:
/.../node_modules/@solidity-parser/parser/src/index.ts:72
throw new ParserError({ errors: listener.getErrors() })
^
Error: extraneous input '"Hello π"' expecting ';' (4:31)
at Object.parse (/.../node_modules/@solidity-parser/parser/src/index.ts:72:11)
Original issue: Consensys/solidity-parser-antlr#3
@Janther this is still relevant, right?
As far as I know, the main syntax change is the new unchecked
blocks, but there might be other things.
When working on a Prettier plugin for Remix I discovered that SharedArrayBuffer
will require cross-origin isolation.
[Deprecation] SharedArrayBuffer will require cross-origin isolation as of M92, around July 2021. See https://developer.chrome.com/blog/enabling-shared-array-buffer/ for more details.
Not sure how this will impact the browser friendly version of this library but you might need to check if this can be addressed.
As reported in prettier-solidity/prettier-plugin-solidity#622
The parser does not yet support namespaces in using ... for
.
Hello guys. I am using truffle-flattener package with openzeppelin. Which is using this repo for parsing solidity code.
When I run truffle-flattener I got this error
Error: Could not parse /home/mentalrob/projects/bnb-barbut-ci/barbut/node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol for extracting its imports: ParserError: missing ';' at '{' (22:18)
at getDependencies (/home/mentalrob/.nvm/versions/node/v14.15.0/lib/node_modules/truffle-flattener/index.js:44:11)
at dependenciesDfs (/home/mentalrob/.nvm/versions/node/v14.15.0/lib/node_modules/truffle-flattener/index.js:64:24)
at async dependenciesDfs (/home/mentalrob/.nvm/versions/node/v14.15.0/lib/node_modules/truffle-flattener/index.js:73:7)
Here is the SafeMath.sol file that i have
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
I guess unchecked
word is causing this issue.
Any ideas to fix this ?
Thanks
Hi,
Like @fvictorio asked me to in this issue in the solidity-coverage repo, I opening the same issue here:
First of all thank you for building and maintaining this tool.
I was trying to use the solidity-coverage
buidler plugin for the first time, and I encountered this solidity-parser bug and some others which all seem to be related to solc 0.6
syntax, I would assume.
An unexpected error occurred:
ParserError: Could not instrument: gelato_core/gelato_provider_module_examples/gelato_user_proxy_provider/ProviderModuleGelatoUserProxy.sol. (Please verify solc can compile this file without errors.) extraneous input 'isProxyExtcodehashProvided' expecting {';', '='} (17:45)
at Object.parse (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-parser-antlr/dist/index.js:79:11)
at Instrumenter.instrument (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-coverage/lib/instrumenter.js:63:30)
at API.instrument (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-coverage/lib/api.js:91:48)
at SimpleTaskDefinition.action (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/solidity-coverage/plugins/buidler.plugin.js:86:23)
at processTicksAndRejections (internal/process/task_queues.js:94:5)
at Environment._runTaskDefinition (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/@nomiclabs/buidler/src/internal/core/runtime-environment.ts:190:14)
at main (/Users/luis/Desktop/gelato-gnosis-safe/node_modules/@nomiclabs/buidler/src/internal/cli/cli.ts:151:5)
This is the source solidity code referenced in the error log:
FILE: ProviderModuleGelatoUserProxy.sol
LINE 17: mapping(bytes32 => bool) public override isProxyExtcodehashProvided;
And all my contracts compile without errors using npx buidler compile
.
I would like to refactor this project to use jest because a lot of tests here are practically snapshot tests.
Modifiers also have virtual
and override
.
Here is the documentation
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.7.0;
contract Base
{
modifier foo() virtual {_;}
}
contract Inherited is Base
{
modifier foo() override {_;}
}
In case of multiple inheritance, all direct base contracts must be specified explicitly:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.7.0;
contract Base1
{
modifier foo() virtual {_;}
}
contract Base2
{
modifier foo() virtual {_;}
}
contract Inherited is Base1, Base2
{
modifier foo() override(Base1, Base2) {_;}
}
For example:
pragma solidity ^0.5.0 || ^0.6.0 || ^0.7.0;
There is a "Error Reporting and Recovery" chapter in the ANTLR book. It would be useful to check if there's something there that can be applied in this parser. Right now the tolerant mode works in some cases, like this:
contract Foo {
but not on other like this:
contract Foo {
contract Bar {}
I have no idea what the trade-offs are here, nor the complexity involved in improving this.
Hi,
I use solidity-parser to parse file BEP20Token.sol ( from Binance ) but I get an error
My code:
const parser = require("@solidity-parser/parser");
const fs = require("fs");
const input = fs.readFileSync("./BEP20Token.sol").toString();
try {
const ast = parser.parse(input);
console.log(ast)
} catch (e) {
console.log(e);
if (e instanceof parser.ParserError) {
console.error(e.errors);
}
}
TypeError: Cannot read property 'length' of undefined
at ASTBuilder.visitExpression (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:36002:26)
at ASTBuilder.visitExpression (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:36064:25)
at ASTBuilder.visitExpressionStatement (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:35932:24)
at ExpressionStatementContext.accept (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:33418:22)
at ASTBuilder.visit (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:17669:19)
at ASTBuilder.visitSimpleStatement (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:35449:17)
at SimpleStatementContext.accept (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:33590:22)
at ASTBuilder.visit (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:17669:19)
at ASTBuilder.visitStatement (D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:35446:17)
at D:\apps\test\testParse\node_modules\@solidity-parser\parser\dist\index.cjs.js:35482:51
Thanks
This is valid code but it generates a parsing error in the let i, j
line:
contract Test {
function foo() public pure {
assembly {
function bar() -> a, b {
a := 1
b := 2
}
let i, j := bar()
}
}
}
Hi There,
I'm running into an issue where a simple parse
on the following contract code results in divergent parsing locally vs. in production (javascript):
// Extremely simple Solidity contract example.
import "File1";
pragma solidity >=0.6.7;
contract Test is Test2 {
uint z = 0;
function test() public returns (uint256) {
other();
y += 1;
z += 1;
}
}
Locally I get an AST element starting with SourceUnit
, in production I get an object like so:
[
{
"type": "p"
}
]
Do you have any thoughts on what may be causing this? Is there perhaps an antlr
compilation step that occurs as the yarn
package is installed?
UPDATE: For more details, see below, but effectively the key problem is this reference: https://github.com/solidity-parser/parser/blob/master/src/ASTBuilder.js#L1458. Classes get renamed during webpack optimisation so references to class names are not supported. This could be fixed by manually adding a type property to each class rather than automatically deriving it from the class name.
The VariableDeclaration
type is missing the isImmutable
boolean value which is available at runtime
export interface VariableDeclaration extends BaseASTNode {
type: 'VariableDeclaration'
isIndexed: boolean
isStateVar: boolean
typeName: TypeName | null
name: string | null
identifier: Identifier | null
isDeclaredConst?: boolean
storageLocation: string | null
expression: Expression | null
visibility?: 'public' | 'private' | 'internal' | 'default'
}```
Fallback functions with the expanded syntax for inputs and output: fallback (bytes calldata input) external [payable] returns (bytes memory output)
are not correctly parsed. This syntax is valid per the latest Solidity documentation.
This issue is in reference to a related bug in the prettier-solidity/prettier-plugin-solidity repo (issue 659) where fallback functions with parameters and returnParameters are not correctly formatted.
I believe the issue is that the parser doesn't capture the parameters and returnsParameters when the fallback
keyword is identified in parser/ASTBuilder.ts
Lines 342 to 345 in 1a7bfb8
A potential fix is using the parameter and returnParameter parsing logic implemented for the function
keyword starting on line 354 of the same file:
parameters = ctx
.parameterList()
.parameter()
.map((x) => this.visit(x))
returnParameters =
ctxReturnParameters !== undefined
? this.visitReturnParameters(ctxReturnParameters)
: null
UserDefined type introduced in solidity 0.8.8 is not able to be parsed with solidity parser.
it may be issue with antlr so I also mad a PR in antlr(solidity-parser/antlr#10)
I guess parser itself also needs an update after fixing antlr.
Starting from solidity 0.7.0, constructors shouldn't have a constructor.
I think the fix here is just to make the keyword optional after constructors, and to update the node properly.
Hey π
I am using this parser in my vscode extension vscode-visual-developer. I just tried updating von 0.12.x to 0.13.x and found out that the location information for VariableDeclaration
AST types is off. It seems to always start at line-start now π€
Here's a screenshot that visualizes this. My extension highlights state-vars by drawing a golden dotted box around state-vars (and their declaration). Since 0.13.0 it highlights the full line (starting from col:1 to end of the declaration).
This may be a bug in the parser. Would be great if you could investigate.
cheers,
tin
Actual: (complete declaration line highlighted: VariableDeclaration.loc
seems to be off.
Expected: behavior from 0.12.x. VariableDeclaration.loc
returns range for the variable name only.
Thank you for implementing the parser - it's very useful.
I'd like to point out some typing problems in dist/ast-types.d.ts
.
BaseASTNode.loc
is wrongexport interface BaseASTNode {
type: ASTNodeTypeString;
range?: [number, number];
loc?: Location;
}
I guess the definition of Location
is missing? The Location
here is an interface in the typescript standard library and has nothing to do with line of code.
ASTNodeTypeString
is unsoundexport declare type ASTNodeTypeString = 'SourceUnit' | 'PragmaDirective' | 'PragmaName' | 'PragmaValue' | 'ImportDirective' | 'ContractDefinition' | 'InheritanceSpecifier' | 'StateVariableDeclaration' | 'UsingForDeclaration' | 'StructDefinition' | 'ModifierDefinition' | 'ModifierInvocation' | 'FunctionDefinition' | 'EventDefinition' | 'EnumValue' | 'EnumDefinition' | 'VariableDeclaration' | 'UserDefinedTypeName' | 'Mapping' | 'ArrayTypeName' | 'FunctionTypeName' | 'StorageLocation' | 'StateMutability' | 'Block' | 'ExpressionStatement' | 'IfStatement' | 'WhileStatement' | 'ForStatement' | 'InlineAssemblyStatement' | 'DoWhileStatement' | 'ContinueStatement' | 'Break' | 'Continue' | 'BreakStatement' | 'ReturnStatement' | 'EmitStatement' | 'ThrowStatement' | 'VariableDeclarationStatement' | 'IdentifierList' | 'ElementaryTypeName' | 'FunctionCall' | 'AssemblyBlock' | 'AssemblyItem' | 'AssemblyCall' | 'AssemblyLocalDefinition' | 'AssemblyAssignment' | 'AssemblyStackAssignment' | 'LabelDefinition' | 'AssemblySwitch' | 'AssemblyCase' | 'AssemblyFunctionDefinition' | 'AssemblyFunctionReturns' | 'AssemblyFor' | 'AssemblyIf' | 'AssemblyLiteral' | 'SubAssembly' | 'TupleExpression' | 'TypeNameExpression' | 'NameValueExpression' | 'BooleanLiteral' | 'NumberLiteral' | 'Identifier' | 'BinaryOperation' | 'UnaryOperation' | 'NewExpression' | 'Conditional' | 'StringLiteral' | 'HexLiteral' | 'HexNumber' | 'DecimalNumber' | 'MemberAccess' | 'IndexAccess' | 'IndexRangeAccess' | 'NameValueList' | 'UncheckedStatement';
Some node types are missing in this declaration, e.g. 'TryStatement'
and 'FileLevelConstant'
.
BaseASTNode
are not givenexport interface SourceUnit extends BaseASTNode {
type: 'SourceUnit';
children: ASTNode[];
}
The interface like this is very useful, but some are missing, e.g. PragmaName
, PragmaValue
, StorageLocation
, StateMutability
, and IdentifierList
.
Nodes like FunctionDefinition
have properties like visibility
and stateMutability
that are plain strings, but that don't have information about the original text. This makes it harder to implement things like the visibility-modifier-order
rule in Solhint because you have no way of knowing the position in the original text where that value comes from. A slightly better idea is that a FunctionDefinition
node has something like a visibilityNode
(maybe?) which has that node. If visibility
is default, visibilityNode
is null. This is a solution that doesn't imply a breaking change. An alternative with a breaking change is to make visibility
be a node, and consumers need to interpret a null
value as a default.
Currently, the parser only supports wei
, szabo
, finney
, ether
as well as time units. But while solc doesn't support szabo
nor finney
since 0.7.0, it supports gwei
since 0.6.11.
After upgrading from "0.13.2"
to "0.14.2"
I receive the following error:
contracts/Perpetual.sol[error] contracts/Perpetual.sol: Error: Assertion error: primary expression should exist when children length is 1
[error] at ASTBuilder.visitExpression (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:36119:17)
[error] at ASTBuilder.visitExpression (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:36177:25)
[error] at ASTBuilder.visitExpression (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:36167:30)
[error] at ASTBuilder.visitExpressionStatement (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:36040:24)
[error] at ExpressionStatementContext.accept (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:33516:22)
[error] at ASTBuilder.visit (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
[error] at ASTBuilder.visitSimpleStatement (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:35550:17)
[error] at SimpleStatementContext.accept (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:33688:22)
[error] at ASTBuilder.visit (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
[error] at ASTBuilder.visitStatement (/Users/username/project/node_modules/@solidity-parser/parser/dist/index.cjs.js:35547:17)
Tried looking for the error in Perpetual.sol
but there's no given line numbers and couldn't find any info on this particular error anywhere.
contract C {
function f() {
require(balanceOf();
}
}
results in
[error] contracts/A.sol: TypeError: Cannot read property 'length' of undefined
[error] at ASTBuilder.visitExpression (/node_modules/@solidity-parser/parser/dist/index.cjs.js:36002:26)
[error] at ASTBuilder.visitExpressionStatement (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35932:24)
[error] at ExpressionStatementContext.accept (/node_modules/@solidity-parser/parser/dist/index.cjs.js:33418:22)
[error] at ASTBuilder.visit (/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
[error] at ASTBuilder.visitSimpleStatement (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35449:17)
[error] at SimpleStatementContext.accept (/node_modules/@solidity-parser/parser/dist/index.cjs.js:33590:22)
[error] at ASTBuilder.visit (/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
[error] at ASTBuilder.visitStatement (/node_modules/@solidity-parser/parser/dist/index.cjs.js:35446:17)
[error] at /node_modules/@solidity-parser/parser/dist/index.cjs.js:35482:51
[error] at Array.map (<anonymous>)
I think there should be a nicer message saying what failed, if possible?
(Originally opened at prettier-solidity/prettier-plugin-solidity#586. Prettier uses the version 0.13.2 of the parser.)
ArrayTypeName
is currently defined with length
having type Expression | null
export interface ArrayTypeName extends BaseASTNode {
type: 'ArrayTypeName'
baseTypeName: TypeName
length: Expression | null
}
At runtime, the length for a fixed length array is returning a length
of type NumberLiteral
. So the type should be
export interface ArrayTypeName extends BaseASTNode {
type: 'ArrayTypeName'
baseTypeName: TypeName
length: NumberLiteral | null
}
Some example fixed length arrays are
bool[2] flags = [true, false];
uint256[2][3] multiDim2x3;
address[3][2] multiDim3x2;
I tried to create a PR for this but I got lost in the required ASTBuilder changes in the visitTypeName
function.
If the contract contains pragma solidity >=0.8.2-nightly <0.9.0;
the parser returns for the pragma node { type: 'PragmaDirective', name: 'solidity', value: '>=0.8.2' }
.
I would expect the value to be >=0.8.2-nightly <0.9.0
Version used: 0.11.1
via hardhat
When using this parser on Node 14, I get this warnings:
pato@pmbp:14% node --trace-warnings node_modules/.bin/buidler test
(node:2572) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency
at emitCircularRequireWarning (internal/modules/cjs/loader.js:823:11)
at Object.get (internal/modules/cjs/loader.js:837:5)
at Object.<anonymous> (/private/tmp/14/node_modules/@solidity-parser/parser/dist/antlr4/RuleContext.js:32:46)
at Module._compile (internal/modules/cjs/loader.js:1200:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10)
at Module.load (internal/modules/cjs/loader.js:1049:32)
at Function.Module._load (internal/modules/cjs/loader.js:937:14)
at Module.require (internal/modules/cjs/loader.js:1089:19)
at require (internal/modules/cjs/helpers.js:73:18)
at Object.<anonymous> (/private/tmp/14/node_modules/@solidity-parser/parser/dist/antlr4/PredictionContext.js:10:19)
at Module._compile (internal/modules/cjs/loader.js:1200:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10)
at Module.load (internal/modules/cjs/loader.js:1049:32)
at Function.Module._load (internal/modules/cjs/loader.js:937:14)
at Module.require (internal/modules/cjs/loader.js:1089:19)
at require (internal/modules/cjs/helpers.js:73:18)
(node:2572) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency
at emitCircularRequireWarning (internal/modules/cjs/loader.js:823:11)
at Object.get (internal/modules/cjs/loader.js:837:5)
at Object.<anonymous> (/private/tmp/14/node_modules/@solidity-parser/parser/dist/antlr4/tree/Trees.js:15:49)
at Module._compile (internal/modules/cjs/loader.js:1200:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10)
at Module.load (internal/modules/cjs/loader.js:1049:32)
at Function.Module._load (internal/modules/cjs/loader.js:937:14)
at Module.require (internal/modules/cjs/loader.js:1089:19)
at require (internal/modules/cjs/helpers.js:73:18)
at Object.<anonymous> (/private/tmp/14/node_modules/@solidity-parser/parser/dist/antlr4/RuleContext.js:126:13)
at Module._compile (internal/modules/cjs/loader.js:1200:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10)
at Module.load (internal/modules/cjs/loader.js:1049:32)
at Function.Module._load (internal/modules/cjs/loader.js:937:14)
at Module.require (internal/modules/cjs/loader.js:1089:19)
at require (internal/modules/cjs/helpers.js:73:18)
Whilst the Solidity compiler compiles this without errors the parser throws (both with Solhint and Prettier) on the following line:
(IUniswapV2Router02 uniswapV2Router, address[][] memory swapPaths) = abi.decode(strategyData, (IUniswapV2Router02, address[][]));
Error (on running Solhint):
/home/zerosnacks/Projects/fuse-v1/node_modules/solhint/lib/index.js:40
throw e
^
Error: Unrecognized expression
at ASTBuilder.visitExpression (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:36165:11)
at ExpressionContext.accept (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:34066:22)
at ASTBuilder.visit (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
at /home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:36301:19
at Array.map (<anonymous>)
at ASTBuilder.visitTupleExpression (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:36297:57)
at TupleExpressionContext.accept (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:34972:22)
at ASTBuilder.visit (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:17669:19)
at ASTBuilder.visitPrimaryExpression (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:36293:17)
at ASTBuilder.visitExpression (/home/zerosnacks/Projects/fuse-v1/node_modules/@solidity-parser/parser/dist/index.cjs.js:36018:21)
This was merged in ethereum/solidity#7524 1 year ago.
Given the case:
string memory a = 'abc' 'def'
'ghi' 'jkl';
string memory b = 'abcdefghijkl';
bytes memory c = hex'dead' hex'beef'
hex'deadbe' hex'ef';
bytes memory d = hex'deadbeefdeadbeef';
a == b
and c == d
in this case. line breaks and spaces can be in between each section.
It makes code readability much easier.
We use prettier, so doing this breaks formatting for us.
There are some semantic checks in the parser, like for example checking if a receive
function is payable
.
In my opinion, this should be a compiler's responsibility. The parser should err on the permissive side, accepting anything that makes sense syntactically. Otherwise, we should also do things like, for example, emitting warning on deprecated constructions. Plus, this kind of stuff depends on the solidity version, but the parser has been pretty version-independent so far, which is nice.
If trying to load the browser friendly parser I get an empty object.
const parser = require('@solidity-parser/parser');
console.log(parser) // { ParserError: [Getter], parse: [Getter], tokenize: [Getter], visit: [Getter] }β
const parser = require('@solidity-parser/parser/dist/index.iife');
console.log(parser) // {}
Example:
contract Foo {
modifier myModifier() virtual;
}
Original issue: Consensys/solidity-parser-antlr#7
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.