From bce7b3a24e4a435434ce1330634dba6d107c6fe8 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 13 Jan 2025 17:17:26 +0000 Subject: [PATCH] Deployed 7ccf52a to main with MkDocs 1.6.1 and mike 2.1.3 --- main/search/search_index.json | 2 +- main/sitemap.xml | 132 +++++++++--------- main/sitemap.xml.gz | Bin 799 -> 799 bytes .../rust-crate/using-the-cursor/index.html | 34 ++--- .../rust-crate/using-the-parser/index.html | 33 +++-- 5 files changed, 98 insertions(+), 103 deletions(-) diff --git a/main/search/search_index.json b/main/search/search_index.json index cfe0a5f6f1..a60d921c84 100644 --- a/main/search/search_index.json +++ b/main/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"slang","text":""},{"location":"#solidity-compiler-tooling-by-nomicfoundation","title":"Solidity compiler tooling by @NomicFoundation","text":"

A modular set of compiler APIs empowering the next generation of Solidity code analysis and developer tooling. Written in Rust and distributed in multiple languages.

This repository maintains the source code and release process for these projects:

\u2757 This project is still in alpha, and is under active development. If you are planning on using it, please reach out to us on Telegram so we can help you get started.

"},{"location":"internals/","title":"Internals","text":""},{"location":"internals/development/","title":"Development","text":""},{"location":"internals/development/#dev-containers","title":"Dev Containers","text":"

To make the developer experience as seamless and consistent as possible, we recommend using the VS Code devcontainer included in this repository. It is a light image that has the minimum required tools to build this project. If you are not familiar with containerized development, I recommend taking a look at the official VS Code guide. Using a devcontainer allows us to quickly setup/teardown the environment, and install/setup different dependencies for different projects, without polluting the local environment. In the future, it will enable us to include Windows and Mac OS specific images for cross-platform testing.

If you would like to still develop outside a container, this should still be possible, as the CI will guarantee that your changes are safe. We intend to keep the images to a bare minimum, and install most dependencies through scripts you can run locally. However, using a common development container means sharing and standardizing useful settings and extensions for the editor (VS Code), the terminal (zsh), and any other tools.

In the future, if we decide to enable code spaces, we can have a 1-click button to create and warm up a powerful dev machine to use in seconds, and running completely remote in a browser tab. It will make it trivial to switch between different versions and branches, or even use and debug multiple ones at the same time from different tabs.

"},{"location":"internals/development/#hermit","title":"Hermit","text":"

To install language-specific binaries and packages, we use Hermit, which installs all tools only when it is first needed/invoked, so you can quickly setup and build different projects quickly. It also takes care of updating your $PATH as you cd in and out of different projects, to make sure you are using the right tools every time. Follow this guide to install it locally to your machine, or simply build any included project, and it will bootstrap itself if it is missing.

"},{"location":"internals/development/#infra-cli","title":"Infra CLI","text":"

To ensure consistency, and a good experience for first-time developers, all build/test/run/debug commands should be written, versioned, and documented inside the infra_cli crate. This means that any dev instructions are well documented, versioned, and verified/executed with every build. It also means that we can minimize any manual setup or teardown steps during development, and just rely on that cli.

You can access all such commands (from the hermit environment) by just running the infra script, which just refers to $REPO_ROOT/scripts/bin/infra. If this is your first time contributing, we recommend starting with infra --help to familiarize yourself with its capabilities.

"},{"location":"internals/development/#versioning-and-publishing","title":"Versioning and Publishing","text":"

We manage versioning through changesets. Each pull request can describe what user facing changes it is introducing, and include this information as a \"changeset\" markdown file along with source changes. These changeset files are analyzed and used to create another pull request to bump the repository version and update dependencies. Once the version bump is merged, artifacts are built and released to all registries.

"},{"location":"internals/development/#managing-dependencies","title":"Managing Dependencies","text":"

Our $REPO_ROOT/.github/dependabot.yml config runs automatic updates to our dependencies on a weekly basis. This handles github-actions, npm, cargo, and pip packages. However, two kinds of dependencies still need to be updated manually for now:

  1. Rust toolchains: $RUST_STABLE_VERSION and $RUST_NIGHTLY_VERSION defined in hermit.hcl and updated via rustup install.
  2. Hermit binaries defined in $REPO_ROOT/bin/XXX.pkg, and updated via hermit install.
"},{"location":"internals/repository-structure/","title":"Repository Structure","text":"

This repository is split into multiple projects at the root folder. Each project has its own dependencies and tools used to build, test, and ship different parts of the repository. For example, a Rust environment for the compiler, a Python environment for documentation, and a NodeJS environment for linters. This allows us to implement different binaries, APIs, and internal tools/scripts, and package/version them together, while having minimal inter-dependencies.

All dependencies should have exact full versions, and we can rely on tooling to automatically upgrade it over time. It allows us to have perfectly reproducible builds for every commit, a critical aspect for compilers, and developer tools in general.

"},{"location":"internals/repository-structure/#directory-structure","title":"Directory Structure","text":"

Currently, the repository has the following projects:

"},{"location":"internals/design-docs/","title":"Design Docs","text":""},{"location":"internals/design-docs/language-definition-v2/","title":"Language Definition v2","text":"

This document describes the new language definition model (AKA DSL v2), and the features/possibilities it enables for both syntax and semantic analysis. Each section describes a part of the definition model, and how it can affect the scanner, parser, CST, and AST.

This is a collection of different discussions we had over the last few weeks, and can (and should) be broken down into smaller work items if needed. It should be possible to map the current definition to the old one, so that we do incremental progress, instead of rewriting everything at once.

"},{"location":"internals/design-docs/language-definition-v2/#cst","title":"CST","text":"

We currently produce an untyped tree of nodes. It holds all parts of the input (byte for byte), even whitespace, comments, and unrecognized (skipped) parts. We can reconstruct the original input back from the CST, just by iterating on nodes in order. For memory/performance reasons, we don't hold positions/location information in the tree, but they are calculated during iterating/visiting the tree.

The CST is useful for many use cases:

Here is an example of the node type, similar to what we have now:

pub enum Node {\n    Terminal { node: Rc<TerminalNode> },\n    Nonterminal { node: Rc<NonterminalNode> },\n}\n\npub struct TerminalNode {\n    pub kind: TerminalKind,\n    pub text: String,\n}\n\npub struct NonterminalNode {\n    pub kind: NonterminalKind,\n    pub text_length: TextIndex,\n    pub children: Vec<Node>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#ast","title":"AST","text":"

We intend to also produce a strongly typed tree (structs and enums). Having strong types provides safety/correctness guarantees for users. It also allows us to generate visitor and rewriter APIs automatically.

Each AST node should provide an API to get the underlying CST node, where users can iterate over the actual terminals as they appear in input, and get their position in the source code. However, this is a one-way operation. CST nodes don't hold references to their AST nodes.

Note: some compilers drop syntactic elements that don't carry semantic information from their AST (like semicolons, or commas). However, we don't make that distinction, as we intend to implement further analysis in the form of micro-passes, that each can rewrite and pick parts of the tree that are relevant to them. So our initial tree (AST) should be complete.

"},{"location":"internals/design-docs/language-definition-v2/#versioning","title":"Versioning","text":"

The biggest benefit of the new language definition is that it allows scanners and parsers to attempt parsing input belonging to any language version, and report errors afterwards if the input is not valid for the selected version. This is a huge benefit over existing parsers, where they will either parse an inaccurate superset of all versions, or they parse a specific version, and produce unhelpful errors like Unrecognized 'abstract' keyword when the current language version doesn't support it.

Not only we will be able to recover from such errors and continue parsing, producing an accurate/complete tree at the end, but we will also be able to produce much better errors like: The 'abstract' keyword is not supported in the current version X. Please upgrade to version Y instead to be able to use it.

"},{"location":"internals/design-docs/language-definition-v2/#terminals","title":"Terminals","text":""},{"location":"internals/design-docs/language-definition-v2/#token-items","title":"Token Items","text":"

Tokens consist of one or more TokenDefinition. Each definition is separate/unique, but produces the same TerminalKind. This is useful for tokens like DecimalLiteral and HexLiteral who can have multiple forms, but each form is enabled or disabled in certain versions of the language.

All definitions have a unique Scanner, and they can be combined in the same trie/FSM to produce a single token at each position in the input. Afterwards, the scanner can compare the definition's enabled property with the current language version, adding an error if they don't match, but continue parsing anyway.

"},{"location":"internals/design-docs/language-definition-v2/#keyword-items","title":"Keyword Items","text":"

Keywords also contribute a TerminalKind, and consist of one or more KeywordDefinition. But they have additional semantics:

First, instead of defining a regular Scanner, it defines a KeywordValue that produces a finite set of possibilities. Most only produce one value (like abstract or contract), but some can produce multiple, like bytesN or fixedMxN, that can have different values for M and N. This is important for us to build hash sets and quickly check for membership.

Second, because keywords can also overlap with identifiers, each keyword has an identifier property that refers to which identifier token they can match. Instead of being part of same trie/FSM as tokens, whenever we want to scan a keyword, we try to scan its identifier instead. Afterwards, we check if its contents match one of the values of the keyword.

Third, they have two additional reserved property. We should use these when we scan identifiers, to make sure that the resulting identifier doesn't match a reserved keyword, and if so, we should report an error, but continue parsing.

Unique to Solidity, keywords can be reserved in versions before or after the versions they are enabled in. They can also be not reserved in versions before or after the versions they stop being enabled in. So we have to have these additional checks, to be able to catch cases like when a certain input can both be a keyword and an identifier, or neither.

We should also be able to generate a public API is_keyword(TerminalKind) for users to conveniently detect them if needed.

"},{"location":"internals/design-docs/language-definition-v2/#trivia-items","title":"Trivia Items","text":"

Trivia items are similar tokens, contributing their own TerminalKind. They are referred to from the language's top-level leading_trivia and trailing_trivia properties. Before and after each token, the scanner should try to scan these tokens, collecting them in a flat list.

Previously, we used to create many LeadingTrivia and TrailingTrivia nodes that hold whitespace/comments. Not only this is wasteful memory-wise, it is also unnatural/unexpected to wrap whitespace in nonterminal nodes. Instead, I propose treating them like any other token, and storing them as siblings to the tokens they belong to (in-order). Not only this is simpler, it is also more efficient, and is natural to how input is consumed and produced.

"},{"location":"internals/design-docs/language-definition-v2/#fragment-items","title":"Fragment Items","text":"

Fragments are not visible to users, and don't contribute a TerminalKind. They are just a utility used to refactor common parts of the grammar, and avoid duplication. During processing the language definition, they are inlined wherever they are referenced.

"},{"location":"internals/design-docs/language-definition-v2/#nonterminals","title":"Nonterminals","text":""},{"location":"internals/design-docs/language-definition-v2/#struct-items","title":"Struct Items","text":"

Structs represent a flat list (sequence) of typed fields. They are the simplest nonterminal, and generate a struct AST type. Their fields match 1-1 with the item fields. The struct name contributes a NonterminalKind.

Each field can be either Required(T) or Optional(T). Required fields are always present and parsed. Optional fields can be omitted if they don't exist, and are represented with Rust's Option<T> type (or TypeScript T | undefined). However, optional fields have an additional enabled property. After parsing optional fields, we should compare them with the current language version, and produce errors if they don't match, but continue parsing normally.

The type of each field can be a Nonterminal(T) or Terminal(Set<T>). A nonterminal field refers to another item, and holds its type. A terminal field refers to one or more terminal items (all valid in this position), and is of type TerminalNode.

Additionally, the struct also stores the CST node that holds its contents:

Definition
Struct(\n    name = ParametersDeclaration,\n    fields = (\n        open_paren = Required(Terminal([OpenParen])),\n        parameters = Required(Nonterminal(Parameters)),\n        close_paren = Required(Terminal([CloseParen]))\n    )\n)\n
AST Type
pub struct ParametersDeclaration {\n    pub open_paren: Rc<TerminalNode>,\n    pub parameters: Rc<Parameters>,\n    pub close_paren: Rc<TerminalNode>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#enum-items","title":"Enum Items","text":"

Enums represent an ordered choice operator of multiple variants (possibilities). The enum name itself does NOT contribute a NonterminalKind, since it will always result in one of its variants (each with a unique TerminalKind or a NonterminalKind. They only exist in the AST, and don't affect the CST at all.

We attempt to parse each variant (in-order), and choose the first one that succeeds. However, each variant can have an additional enabled property. We should always try to parse the variants that are valid in the current version first, and if not, still parse the rest, but produce an error afterwards. The fields of each variant are parsed similar to a struct fields (example above).

Definition
Enum(\n    name = FunctionBody,\n    variants = [\n        EnumVariant(name = Block, reference = Block),\n        EnumVariant(name = Semicolon, reference = Semicolon)\n    ]\n)\n
AST Type
pub enum FunctionBody {\n    Block {\n        block: Rc<Block>,\n\n        cst: Rc<NonterminalNode>,\n    },\n    Semicolon {\n        semicolon: Rc<TerminalNode>,\n\n        cst: Rc<NonterminalNode>,\n    },\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#repeated-items","title":"Repeated Items","text":"

Repeated items represent a list of items of the same kind. The item name contributes a NonterminalKind. The AST type is a wrapper around a Vec<T>, with any utilities we need to add for convenience.

It has an allow_empty boolean property, which allows parsing zero items. If it is false, we should still allow parsing zero items, but produce an error afterwards.

Definition
Repeated(\n    name = FunctionAttributes,\n    repeated = FunctionAttribute,\n    allow_empty = true\n)\n
AST Type
pub struct FunctionAttributes {\n    pub items: Vec<Rc<FunctionAttribute>>\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#separated-items","title":"Separated Items","text":"

Separated items represent a list of items of the same kind, separated by a delimiter. The item name contributes a NonterminalKind. The AST type is a wrapper around two Vec<T> for items and their delimiters, with any utilities we need to add for convenience. For example, we should add APIs to create iterators for only the separated items, the separators, or both (in-order).

It has an allow_empty boolean property, which allows parsing zero items. If it is false, we should still allow parsing zero items, but produce an error afterwards. We should also allow parsing a trailing separator at the end, but still produce an error afterwards.

Definition
Separated(\n    name = EventParameters,\n    separated = EventParameter,\n    separator = Comma,\n    allow_empty = true\n)\n
AST Type
pub struct EventParameters {\n    pub items: Vec<Rc<EventParameter>>\n    pub separators: Vec<Rc<TerminalNode>>\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#precedence-items","title":"Precedence Items","text":"

This is perhaps the most complex nonterminal. It still uses the same PRATT algorithm from the previous implementation (no changes there), but adapted for the new AST types. It has two lists:

First, a list of precedence_expressions, with each expression having a list of operators. Each operator has its own versioning (enabled property), a list of fields, and a model (prefix/postfix/binary).

The operators from all expressions are flattened and combined in the parent PRATT parser. That grouping is only used to indicate that some operators can produce the same PrecedenceExpression name. However, we should exclude operators that don't match the current language version. This is useful for things like ExponentiationExpression where it has two operators with different associativity, but defined in enabled/disabled in different versions.

Second, a list of primary_expressions, with their own versioning (enabled property) as well. We should try to parse them as an operator (similar to EnumItem), and produce an error if the version doesn't match afterwards.

It is important to note that the item name doesn't contribute a NonterminalKind, but each PrecedenceExpression under it contributes one.

Definition
Precedence(\n    name = Expression,\n    precedence_expressions = [\n        PrecedenceExpression(\n            name = AdditionExpression,\n            operators = [PrecedenceOperator(\n                model = BinaryLeftAssociative,\n                fields = (operator = Required(Terminal([Plus])))\n            )]\n        ),\n        PrecedenceExpression(\n            name = FunctionCallExpression,\n            operators = [PrecedenceOperator(\n                model = Postfix,\n                fields = (\n                    open_paren = Required(Terminal([OpenParen])),\n                    arguments = Required(Nonterminal(Arguments)),\n                    close_paren = Required(Terminal([CloseParen]))\n                )\n            )]\n        ),\n        PrecedenceExpression(\n            name = NegationExpression,\n            operators = [PrecedenceOperator(\n                model = Prefix,\n                fields = (operator = Required(Terminal([Not])))\n            )]\n        )\n    )],\n    primary_expressions = [\n        PrimaryExpression(expression = Identifier),\n        PrimaryExpression(expression = NumberLiteral),\n        PrimaryExpression(expression = StringLiteral)\n    ]\n)\n
AST Type
pub enum Expression {\n    AdditionExpression { expression: Rc<AdditionExpression> },\n    FunctionCallExpression { expression: Rc<FunctionCallExpression> },\n    NegationExpression { expression: Rc<NegationExpression> },\n\n    Identifier { expression: Rc<TerminalNode> },\n    NumberLiteral { expression: Rc<TerminalNode> },\n    StringLiteral { expression: Rc<TerminalNode> },\n}\n\npub struct AdditionExpression {\n    // 'left_operand' auto-generated (before) because it is a binary expression, and same type as parent\n    pub left_operand: Rc<Expression>,\n    // operator 'fields' are flattened into the expression node here\n    pub operator: Rc<TerminalNode>,\n    // 'right_operand' auto-generated (after) because it is a binary expression, and same type as parent\n    pub right_operand: Rc<Expression>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n\npub struct FunctionCallExpression {\n    // 'operand' auto-generated (before) because it is a postfix expression, and same type as parent\n    pub operand: Rc<Expression>,\n    // operator 'fields' are flattened into the expression node here\n    pub open_paren: Rc<TerminalNode>,\n    pub arguments: Rc<Arguments>,\n    pub close_paren: Rc<TerminalNode>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n\npub struct NegationExpression {\n    // operator 'fields' are flattened into the expression node here\n    pub operator: Rc<TerminalNode>,\n    // 'operand' auto-generated (after) because it is a prefix expression, and same type as parent\n    pub operand: Rc<Expression>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#error-recovery","title":"Error Recovery","text":"

For the CST, I think the current algorithms work well, and we should be able to keep them. Unrecognized (skipped) input is grouped into one token, and we can just add it as-is to the cst node under its AST node.

During AST construction, we will simply check for TerminalKind::UNRECOGNIZED nodes, and skip construction if there are any.

"},{"location":"internals/design-docs/language-definition-v2/#public-api-changes","title":"Public API Changes","text":"

Based on the above, I propose the following changes to the current public API:

"},{"location":"internals/design-docs/language-definition-v2/#visitors-and-cursors","title":"Visitors and Cursors","text":"

The current CST visitors/cursors should still work as-is, since the CST tree will be unchanged. However, the new AST types allow us in the future to produce typed visitors and traits with named functions for every node type, similar to a lot of other AST processing libraries. I want to at least produce an immutable Visitor and a mutable Rewriter.

"},{"location":"solidity-specification/","title":"Solidity Specification","text":""},{"location":"solidity-specification/#solidity-specification","title":"Solidity Specification","text":""},{"location":"solidity-specification/supported-versions/","title":"Supported Versions","text":"

This specification compiles information from 83 publicly released versions of Solidity:

0.4.11 0.4.12 0.4.13 0.4.14 0.4.15 0.4.16 0.4.17 0.4.18 0.4.19 0.4.20 0.4.21 0.4.22 0.4.23 0.4.24 0.4.25 0.4.26 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 0.5.8 0.5.9 0.5.10 0.5.11 0.5.12 0.5.13 0.5.14 0.5.15 0.5.16 0.5.17 0.6.0 0.6.1 0.6.2 0.6.3 0.6.4 0.6.5 0.6.6 0.6.7 0.6.8 0.6.9 0.6.10 0.6.11 0.6.12 0.7.0 0.7.1 0.7.2 0.7.3 0.7.4 0.7.5 0.7.6 0.8.0 0.8.1 0.8.2 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 0.8.8 0.8.9 0.8.10 0.8.11 0.8.12 0.8.13 0.8.14 0.8.15 0.8.16 0.8.17 0.8.18 0.8.19 0.8.20 0.8.21 0.8.22 0.8.23 0.8.24 0.8.25 0.8.26 0.8.27 0.8.28

Among which, 34 versions have breaking changes:

0.4.11 0.4.12 0.4.14 0.4.16 0.4.21 0.4.22 0.4.25 0.5.0 0.5.3 0.5.5 0.5.8 0.5.10 0.5.12 0.5.14 0.6.0 0.6.2 0.6.5 0.6.7 0.6.8 0.6.11 0.7.0 0.7.1 0.7.4 0.8.0 0.8.4 0.8.7 0.8.8 0.8.13 0.8.18 0.8.19 0.8.22 0.8.24 0.8.25 0.8.27

"},{"location":"solidity-specification/01-file-structure/","title":"1. File Structure","text":""},{"location":"solidity-specification/01-file-structure/#1-file-structure","title":"1. File Structure","text":""},{"location":"solidity-specification/01-file-structure/01-license-specifiers/","title":"1.1. License Specifiers","text":""},{"location":"solidity-specification/01-file-structure/01-license-specifiers/#11-license-specifiers","title":"1.1. License Specifiers","text":""},{"location":"solidity-specification/01-file-structure/01-license-specifiers/#license-comment","title":"License Comment","text":"

This comment line declares that the source code is licensed under the GPL version 3.0. Machine-readable license specifiers are important in a setting where publishing the source code is the default. The comment is recognized by the compiler anywhere in the file at the file level, but it is recommended to put it at the top of the file.

// SPDX-License-Identifier: GPL-3.0\n

When omitted, the compiler produces a warning to add one. The compiler does not validate that the license is part of the list allowed by SPDX, but it does include the supplied string in the metadata.

If you do not want to specify a license or if the source code is not open-source, please use the special value UNLICENSED. Note that UNLICENSED (no usage allowed, not present in SPDX license list) is different from UNLICENSE (grants all rights to everyone).

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/02-source-unit/","title":"1.2. Source Unit","text":""},{"location":"solidity-specification/01-file-structure/02-source-unit/#12-source-unit","title":"1.2. Source Unit","text":""},{"location":"solidity-specification/01-file-structure/02-source-unit/#syntax","title":"Syntax","text":"
SourceUnit = (* members: *) SourceUnitMembers;
 
SourceUnitMembers = (* item: *) SourceUnitMember*;
 
SourceUnitMember = (* variant: *) PragmaDirective                 | (* variant: *) ImportDirective                 | (* variant: *) ContractDefinition                 | (* variant: *) InterfaceDefinition                 | (* variant: *) LibraryDefinition                 | (* variant: *) StructDefinition (* Introduced in 0.6.0 *)                 | (* variant: *) EnumDefinition (* Introduced in 0.6.0 *)                 | (* variant: *) FunctionDefinition (* Introduced in 0.7.1 *)                 | (* variant: *) ErrorDefinition (* Introduced in 0.8.4 *)                 | (* variant: *) UserDefinedValueTypeDefinition (* Introduced in 0.8.8 *)                 | (* variant: *) UsingDirective (* Introduced in 0.8.13 *)                 | (* variant: *) EventDefinition (* Introduced in 0.8.22 *)                 | (* variant: *) ConstantDefinition; (* Introduced in 0.7.4 *)
"},{"location":"solidity-specification/01-file-structure/02-source-unit/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/","title":"1.3. Pragma Directives","text":""},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#13-pragma-directives","title":"1.3. Pragma Directives","text":""},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#syntax","title":"Syntax","text":"
PragmaDirective = (* pragma_keyword: *) PRAGMA_KEYWORD                  (* pragma: *) Pragma                  (* semicolon: *) SEMICOLON;
 
Pragma = (* variant: *) AbicoderPragma       | (* variant: *) ExperimentalPragma       | (* variant: *) VersionPragma;
 
AbicoderPragma = (* abicoder_keyword: *) ABICODER_KEYWORD                 (* version: *) IDENTIFIER;
 
ExperimentalPragma = (* experimental_keyword: *) EXPERIMENTAL_KEYWORD                     (* feature: *) ExperimentalFeature;
 
ExperimentalFeature = (* variant: *) IDENTIFIER                    | (* variant: *) StringLiteral;
 
VersionPragma = (* solidity_keyword: *) SOLIDITY_KEYWORD                (* sets: *) VersionExpressionSets;
 
VersionExpressionSets = (* item: *) VersionExpressionSet ((* separator: *) BAR_BAR (* item: *) VersionExpressionSet)*;
 
VersionExpressionSet = (* item: *) VersionExpression+;
 
VersionExpression = (* variant: *) VersionRange                  | (* variant: *) VersionTerm;
 
VersionRange = (* start: *) VersionLiteral               (* minus: *) MINUS               (* end: *) VersionLiteral;
 
VersionTerm = (* operator: *) VersionOperator?              (* literal: *) VersionLiteral;
 
VersionOperator = (* variant: *) CARET                | (* variant: *) TILDE                | (* variant: *) EQUAL                | (* variant: *) LESS_THAN                | (* variant: *) GREATER_THAN                | (* variant: *) LESS_THAN_EQUAL                | (* variant: *) GREATER_THAN_EQUAL;
 
VersionLiteral = (* variant: *) SimpleVersionLiteral               | (* variant: *) SINGLE_QUOTED_VERSION_LITERAL               | (* variant: *) DOUBLE_QUOTED_VERSION_LITERAL;
 
SimpleVersionLiteral = (* item: *) VERSION_SPECIFIER ((* separator: *) PERIOD (* item: *) VERSION_SPECIFIER)*;
 
VERSION_SPECIFIER = \u00abVERSION_SPECIFIER_FRAGMENT\u00bb;
 
SINGLE_QUOTED_VERSION_LITERAL = \"'\" \u00abVERSION_SPECIFIER_FRAGMENT\u00bb (\".\" \u00abVERSION_SPECIFIER_FRAGMENT\u00bb)* \"'\";
 
DOUBLE_QUOTED_VERSION_LITERAL = '\"' \u00abVERSION_SPECIFIER_FRAGMENT\u00bb (\".\" \u00abVERSION_SPECIFIER_FRAGMENT\u00bb)* '\"';
 
\u00abVERSION_SPECIFIER_FRAGMENT\u00bb = (\"0\"\u2026\"9\" | \"x\" | \"X\" | \"*\")+;
 
(* Never reserved *)ABICODER_KEYWORD = \"abicoder\";
 
(* Never reserved *)EXPERIMENTAL_KEYWORD = \"experimental\";
 
(* Never reserved *)SOLIDITY_KEYWORD = \"solidity\";
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#version-pragma","title":"Version Pragma","text":"

This line declares which Solidity language version it was written for. This is to ensure that the contract is not compilable with a new (breaking) compiler version, where it could behave differently. An error is produced if the running compiler version does not match these requirements.

Note that multiple version pragmas are supported, and the compiler will verify each pragma separately.

For example, this line specifies that the source code is written for Solidity version 0.4.16, or a newer version of the language up to, but not including version 0.9.0:

pragma solidity >=0.4.16 <0.9.0;\n
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#abi-coder-pragma","title":"ABI Coder Pragma","text":"

Used to instruct the compiler to choose a specific ABI encoder/decoder. The new ABI coder (v2) is able to encode and decode arbitrarily nested arrays and structs. It might produce less optimal code and has not received as much testing as the old encoder.

pragma abicoder v1;\n// OR\npragma abicoder v2;\n
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#experimental-pragma","title":"Experimental Pragma","text":"

It can be used to enable features of the compiler or language that are not yet enabled by default. Compilers should produce an error on unrecognized pragmas (or earlier versions before they were released), and a warning before the stable version. After the stable version, this should not have an effect.

"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#abiencoderv2","title":"ABIEncoderV2","text":"

Please see the abicoder pragma defined above.

pragma experimental ABIEncoderV2;\n
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#smtchecker","title":"SMTChecker","text":"

If you use SMTChecker, then you get additional safety warnings which are obtained by querying an SMT solver. The component does not yet support all features of the Solidity language and likely outputs many warnings. In case it reports unsupported features, the analysis may not be fully sound.

pragma experimental SMTChecker;\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/04-import-directives/","title":"1.4. Import Directives","text":""},{"location":"solidity-specification/01-file-structure/04-import-directives/#14-import-directives","title":"1.4. Import Directives","text":""},{"location":"solidity-specification/01-file-structure/04-import-directives/#syntax","title":"Syntax","text":"
ImportDirective = (* import_keyword: *) IMPORT_KEYWORD                  (* clause: *) ImportClause                  (* semicolon: *) SEMICOLON;
 
ImportClause = (* variant: *) PathImport             | (* variant: *) NamedImport             | (* variant: *) ImportDeconstruction;
 
PathImport = (* path: *) StringLiteral             (* alias: *) ImportAlias?;
 
NamedImport = (* asterisk: *) ASTERISK              (* alias: *) ImportAlias              (* from_keyword: *) FROM_KEYWORD              (* path: *) StringLiteral;
 
ImportDeconstruction = (* open_brace: *) OPEN_BRACE                       (* symbols: *) ImportDeconstructionSymbols                       (* close_brace: *) CLOSE_BRACE                       (* from_keyword: *) FROM_KEYWORD                       (* path: *) StringLiteral;
 
ImportDeconstructionSymbols = (* item: *) ImportDeconstructionSymbol ((* separator: *) COMMA (* item: *) ImportDeconstructionSymbol)*;
 
ImportDeconstructionSymbol = (* name: *) IDENTIFIER                             (* alias: *) ImportAlias?;
 
ImportAlias = (* as_keyword: *) AS_KEYWORD              (* identifier: *) IDENTIFIER;
"},{"location":"solidity-specification/01-file-structure/04-import-directives/#importing-files","title":"Importing Files","text":"

At a file level, you can use import statements of the following form:

import \"filename\";\n

This statement imports all global symbols from filename (and symbols imported there) into the current global scope. This form is not recommended for use, because it unpredictably pollutes the namespace. If you add new top-level items inside filename, they automatically appear in all files that import like this from \u201cfilename\u201d. It is better to import specific symbols explicitly, which results in all global symbols being available under the myFile symbol:

import * as myFile from \"filename\";\n// OR\nimport \"filename\" as myFile;\n
"},{"location":"solidity-specification/01-file-structure/04-import-directives/#importing-specific-symbols","title":"Importing Specific Symbols","text":"

You can import only the symbols you use from a specific file, using the syntax:

import {symbol1, symbol2} from \"filename\";\n

Which will create symbol1 and symbol1 to use in your code. If there is a naming collision, you can rename symbols while importing. For example, the code below creates new global symbols alias and symbol2 which reference symbol1 and symbol2 from inside filename, respectively:

import {symbol1 as alias, symbol2} from \"filename\";\n
"},{"location":"solidity-specification/01-file-structure/04-import-directives/#virtual-file-system","title":"Virtual File System","text":"

In order to be able to support reproducible builds on all platforms, the Solidity compiler has to abstract away the details of the filesystem where source files are stored. For this reason import paths do not refer directly to files in the host filesystem. Instead the compiler maintains an internal database (virtual filesystem or VFS for short) where each source unit is assigned a unique source unit name which is an opaque and unstructured identifier. The import path specified in an import statement is translated into a source unit name and used to find the corresponding source unit in this database.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/05-using-directives/","title":"1.5. Using Directives","text":""},{"location":"solidity-specification/01-file-structure/05-using-directives/#15-using-directives","title":"1.5. Using Directives","text":""},{"location":"solidity-specification/01-file-structure/05-using-directives/#syntax","title":"Syntax","text":"
UsingDirective = (* using_keyword: *) USING_KEYWORD                 (* clause: *) UsingClause                 (* for_keyword: *) FOR_KEYWORD                 (* target: *) UsingTarget                 (* global_keyword: *) GLOBAL_KEYWORD? (* Introduced in 0.8.13 *)                 (* semicolon: *) SEMICOLON;
 
UsingClause = (* variant: *) IdentifierPath            | (* variant: *) UsingDeconstruction; (* Introduced in 0.8.13 *)
 
(* Introduced in 0.8.13 *)UsingDeconstruction = (* open_brace: *) OPEN_BRACE                      (* symbols: *) UsingDeconstructionSymbols                      (* close_brace: *) CLOSE_BRACE;
 
(* Introduced in 0.8.13 *)UsingDeconstructionSymbols = (* item: *) UsingDeconstructionSymbol ((* separator: *) COMMA (* item: *) UsingDeconstructionSymbol)*;
 
(* Introduced in 0.8.13 *)UsingDeconstructionSymbol = (* name: *) IdentifierPath                            (* alias: *) UsingAlias?; (* Introduced in 0.8.19 *)
 
(* Introduced in 0.8.19 *)UsingAlias = (* as_keyword: *) AS_KEYWORD             (* operator: *) UsingOperator;
 
(* Introduced in 0.8.19 *)UsingOperator = (* variant: *) AMPERSAND              | (* variant: *) ASTERISK              | (* variant: *) BANG_EQUAL              | (* variant: *) BAR              | (* variant: *) CARET              | (* variant: *) EQUAL_EQUAL              | (* variant: *) GREATER_THAN              | (* variant: *) GREATER_THAN_EQUAL              | (* variant: *) LESS_THAN              | (* variant: *) LESS_THAN_EQUAL              | (* variant: *) MINUS              | (* variant: *) PERCENT              | (* variant: *) PLUS              | (* variant: *) SLASH              | (* variant: *) TILDE;
 
UsingTarget = (* variant: *) TypeName            | (* variant: *) ASTERISK;
"},{"location":"solidity-specification/01-file-structure/05-using-directives/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/06-trivia/","title":"1.6. Trivia","text":""},{"location":"solidity-specification/01-file-structure/06-trivia/#16-trivia","title":"1.6. Trivia","text":""},{"location":"solidity-specification/01-file-structure/06-trivia/#syntax","title":"Syntax","text":"
WHITESPACE = (\" \" | \"\\t\")+;
 
END_OF_LINE = \"\\n\" | (\"\\r\" \"\\n\"?);
 
SINGLE_LINE_COMMENT = \"//\" (?!\"/\") (!(\"\\r\" | \"\\n\"))*;
 
MULTI_LINE_COMMENT = \"/*\" (?!\"*\" !\"/\") (!\"*\" | (\"*\" (?!\"/\")))* \"*/\";
 
SINGLE_LINE_NAT_SPEC_COMMENT = \"///\" (!(\"\\r\" | \"\\n\"))*;
 
MULTI_LINE_NAT_SPEC_COMMENT = \"/**\" (?!\"/\") (!\"*\" | (\"*\" (?!\"/\")))* \"*/\";
"},{"location":"solidity-specification/01-file-structure/06-trivia/#single-line-comments","title":"Single Line Comments","text":"

A single-line comment is terminated by any unicode line terminator (LF, VF, FF, CR, NEL, LS or PS) in UTF-8 encoding. The terminator is still part of the source code after the comment, so if it is not an ASCII symbol (these are NEL, LS and PS), it will lead to a parser error.

// This is a single-line comment.\n
"},{"location":"solidity-specification/01-file-structure/06-trivia/#multi-line-comments","title":"Multi-line Comments","text":"

Comments starting with /* and ending with */ are allowed to range multiple lines:

/*\nThis is a\nmulti-line comment.\n*/\n
"},{"location":"solidity-specification/01-file-structure/06-trivia/#natspec-comments","title":"NatSpec Comments","text":"

Additionally, there is another type of comment called a NatSpec comment. They are written with a triple slash /// or a double asterisk block /**...*/ and they should be used directly above function declarations or statements. It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI).

/// @author My Team Name\n/// @title A simple contract example\ncontract MyContract {}\n

Please see the NatSpec Format section for further information.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/","title":"1.7. Nat Spec Format","text":""},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#17-nat-spec-format","title":"1.7. Nat Spec Format","text":""},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#what-is-natspec","title":"What is NatSpec?","text":"

Solidity contracts can use a special form of comments to provide rich documentation for functions, return variables and more. This special form is named the Ethereum Natural Language Specification Format (NatSpec). It was inspired by Doxygen, and while it uses Doxygen-style comments and tags, there is no intention to keep strict compatibility with Doxygen.

It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI). It is used in:

Documentation can be inserted above each contract, interface, library, function, event and state variable.

They can either exist in a single line format, starting with ///:

/// @title An example contract\ncontract MyContract {}\n

And also in multi-line format, starting with /** and ending with */:

/**\n * @title An example contract\n */\ncontract MyContract {}\n
"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#tags","title":"Tags","text":"

Tags categorize different comments according to their purpose. The table below shows the different tags supported. Please note that they are optional, and without one, the entire comment will be interpreted as it had a @notice tag.

Tag Description Context @title A title that should describe the contract/interface contract, library, interface @author The name of the author contract, library, interface @notice Explain to an end user what this does contract, library, interface, function, event, state variable @dev Explain to a developer any extra details contract, library, interface, function, event, state variable @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, state variable @inheritdoc Copies all missing tags from the base function (must be followed by the contract name) function, state variable @custom:FOO Custom tag, semantics is application-defined can be used everywhere"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#function-return-types","title":"Function Return Types","text":"

If your function returns multiple values, like (int quotient, int remainder) then use multiple @return statements in the same format as the @param statements.

"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#custom-tags","title":"Custom Tags","text":"

Custom tags start with @custom: and must be followed by one or more lowercase letters or hyphens. It cannot start with a hyphen however. They can be used everywhere and are part of the developer documentation. For example, @custom:foo or @custom:foo-bar. A good use case is analysis and verification tools.

"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#dynamic-expressions","title":"Dynamic expressions","text":"

The Solidity compiler will pass through NatSpec documentation from your Solidity source code to the JSON output as described in this guide. The consumer of this JSON output may present this to the end-user directly or it may apply some pre-processing.

Specifying these dynamic expressions is outside the scope of the Solidity documentation. However, you can find one useful example in the RadSpec Project, where it evaluates references to function inputs to its values. For example, this line:

/// @notice This function will multiply `a` by 7\n

Can be evaluated as the following, where the value of a is 10:

This function will multiply 10 by 7\n
"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#inheritance","title":"Inheritance","text":"

Functions without NatSpec will automatically inherit the documentation of their base function. Exceptions to this are:

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/08-keywords/","title":"1.8. Keywords","text":""},{"location":"solidity-specification/01-file-structure/08-keywords/#18-keywords","title":"1.8. Keywords","text":""},{"location":"solidity-specification/01-file-structure/08-keywords/#syntax","title":"Syntax","text":"
(* Introduced in 0.6.0 *)ABSTRACT_KEYWORD = \"abstract\";
 
(* Never reserved *)ADDRESS_KEYWORD = \"address\";
 
AFTER_KEYWORD = \"after\";
 
(* Reserved in 0.5.0 *)ALIAS_KEYWORD = \"alias\";
 
ANONYMOUS_KEYWORD = \"anonymous\";
 
(* Reserved in 0.5.0 *)APPLY_KEYWORD = \"apply\";
 
AS_KEYWORD = \"as\";
 
ASSEMBLY_KEYWORD = \"assembly\";
 
(* Reserved in 0.5.0 *)AUTO_KEYWORD = \"auto\";
 
BOOL_KEYWORD = \"bool\";
 
BREAK_KEYWORD = \"break\";
 
(* Deprecated in 0.8.0 *)BYTE_KEYWORD = \"byte\";
 
BYTES_KEYWORD = \"bytes\" (\"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"16\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"24\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"32\")?;
 
(* Introduced in 0.5.0 *)(* Reserved in 0.5.0 *)CALL_DATA_KEYWORD = \"calldata\";
 
CASE_KEYWORD = \"case\";
 
(* Introduced in 0.6.0 *)CATCH_KEYWORD = \"catch\";
 
CONSTANT_KEYWORD = \"constant\";
 
(* Introduced in 0.4.22 *)(* Reserved in 0.5.0 *)CONSTRUCTOR_KEYWORD = \"constructor\";
 
CONTINUE_KEYWORD = \"continue\";
 
CONTRACT_KEYWORD = \"contract\";
 
(* Reserved in 0.5.0 *)COPY_OF_KEYWORD = \"copyof\";
 
DAYS_KEYWORD = \"days\";
 
DEFAULT_KEYWORD = \"default\";
 
(* Reserved in 0.5.0 *)DEFINE_KEYWORD = \"define\";
 
DELETE_KEYWORD = \"delete\";
 
DO_KEYWORD = \"do\";
 
ELSE_KEYWORD = \"else\";
 
(* Introduced in 0.4.21 *)(* Reserved in 0.5.0 *)EMIT_KEYWORD = \"emit\";
 
ENUM_KEYWORD = \"enum\";
 
(* Introduced in 0.8.4 *)(* Never reserved *)ERROR_KEYWORD = \"error\";
 
ETHER_KEYWORD = \"ether\";
 
EVENT_KEYWORD = \"event\";
 
EXTERNAL_KEYWORD = \"external\";
 
(* Reserved in 0.6.0 *)FALLBACK_KEYWORD = \"fallback\";
 
FALSE_KEYWORD = \"false\";
 
FINAL_KEYWORD = \"final\";
 
(* Deprecated in 0.7.0 *)(* Reserved until 0.7.0 *)FINNEY_KEYWORD = \"finney\";
 
FIXED_KEYWORD = \"fixed\";FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");FIXED_KEYWORD = \"fixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved in 0.4.14 *)FIXED_KEYWORD = \"fixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved in 0.4.14 *)FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
FOR_KEYWORD = \"for\";
 
(* Never reserved *)FROM_KEYWORD = \"from\";
 
FUNCTION_KEYWORD = \"function\";
 
(* Introduced in 0.8.13 *)(* Never reserved *)GLOBAL_KEYWORD = \"global\";
 
(* Introduced in 0.6.11 *)(* Reserved in 0.7.0 *)GWEI_KEYWORD = \"gwei\";
 
HEX_KEYWORD = \"hex\";
 
HOURS_KEYWORD = \"hours\";
 
IF_KEYWORD = \"if\";
 
(* Introduced in 0.6.5 *)(* Reserved in 0.5.0 *)IMMUTABLE_KEYWORD = \"immutable\";
 
(* Reserved in 0.5.0 *)IMPLEMENTS_KEYWORD = \"implements\";
 
IMPORT_KEYWORD = \"import\";
 
INDEXED_KEYWORD = \"indexed\";
 
IN_KEYWORD = \"in\";
 
INLINE_KEYWORD = \"inline\";
 
INTERFACE_KEYWORD = \"interface\";
 
INTERNAL_KEYWORD = \"internal\";
 
INT_KEYWORD = \"int\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
IS_KEYWORD = \"is\";
 
LET_KEYWORD = \"let\";
 
LIBRARY_KEYWORD = \"library\";
 
(* Reserved in 0.5.0 *)MACRO_KEYWORD = \"macro\";
 
MAPPING_KEYWORD = \"mapping\";
 
MATCH_KEYWORD = \"match\";
 
MEMORY_KEYWORD = \"memory\";
 
MINUTES_KEYWORD = \"minutes\";
 
MODIFIER_KEYWORD = \"modifier\";
 
(* Reserved in 0.5.0 *)MUTABLE_KEYWORD = \"mutable\";
 
NEW_KEYWORD = \"new\";
 
NULL_KEYWORD = \"null\";
 
OF_KEYWORD = \"of\";
 
(* Introduced in 0.6.0 *)(* Reserved in 0.5.0 *)OVERRIDE_KEYWORD = \"override\";
 
(* Reserved in 0.5.0 *)PARTIAL_KEYWORD = \"partial\";
 
PAYABLE_KEYWORD = \"payable\";
 
PRAGMA_KEYWORD = \"pragma\";
 
PRIVATE_KEYWORD = \"private\";
 
(* Reserved in 0.5.0 *)PROMISE_KEYWORD = \"promise\";
 
PUBLIC_KEYWORD = \"public\";
 
(* Introduced in 0.4.16 *)PURE_KEYWORD = \"pure\";
 
(* Reserved in 0.6.0 *)RECEIVE_KEYWORD = \"receive\";
 
(* Reserved in 0.5.0 *)REFERENCE_KEYWORD = \"reference\";
 
RELOCATABLE_KEYWORD = \"relocatable\";
 
RETURN_KEYWORD = \"return\";
 
RETURNS_KEYWORD = \"returns\";
 
(* Introduced in 0.8.4 *)(* Never reserved *)REVERT_KEYWORD = \"revert\";
 
(* Reserved in 0.5.0 *)SEALED_KEYWORD = \"sealed\";
 
SECONDS_KEYWORD = \"seconds\";
 
(* Reserved in 0.5.0 *)SIZE_OF_KEYWORD = \"sizeof\";
 
STATIC_KEYWORD = \"static\";
 
STORAGE_KEYWORD = \"storage\";
 
STRING_KEYWORD = \"string\";
 
STRUCT_KEYWORD = \"struct\";
 
SUPER_KEYWORD = \"super\";
 
(* Reserved in 0.5.0 *)SUPPORTS_KEYWORD = \"supports\";
 
SWITCH_KEYWORD = \"switch\";
 
(* Deprecated in 0.7.0 *)(* Reserved until 0.7.0 *)SZABO_KEYWORD = \"szabo\";
 
THIS_KEYWORD = \"this\";
 
(* Deprecated in 0.5.0 *)THROW_KEYWORD = \"throw\";
 
(* Introduced in 0.8.27 *)(* Never reserved *)TRANSIENT_KEYWORD = \"transient\";
 
TRUE_KEYWORD = \"true\";
 
(* Introduced in 0.6.0 *)TRY_KEYWORD = \"try\";
 
(* Reserved in 0.5.0 *)TYPE_DEF_KEYWORD = \"typedef\";
 
(* Introduced in 0.5.3 *)TYPE_KEYWORD = \"type\";
 
TYPE_OF_KEYWORD = \"typeof\";
 
UFIXED_KEYWORD = \"ufixed\";UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");UFIXED_KEYWORD = \"ufixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved in 0.4.14 *)UFIXED_KEYWORD = \"ufixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved in 0.4.14 *)UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
UINT_KEYWORD = \"uint\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
(* Introduced in 0.8.0 *)(* Reserved in 0.5.0 *)UNCHECKED_KEYWORD = \"unchecked\";
 
USING_KEYWORD = \"using\";
 
(* Deprecated in 0.5.0 *)VAR_KEYWORD = \"var\";
 
(* Introduced in 0.4.16 *)VIEW_KEYWORD = \"view\";
 
(* Introduced in 0.6.0 *)(* Reserved in 0.6.0 *)VIRTUAL_KEYWORD = \"virtual\";
 
WEEKS_KEYWORD = \"weeks\";
 
WEI_KEYWORD = \"wei\";
 
WHILE_KEYWORD = \"while\";
 
(* Deprecated in 0.5.0 *)YEARS_KEYWORD = \"years\";
"},{"location":"solidity-specification/01-file-structure/08-keywords/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/09-punctuation/","title":"1.9. Punctuation","text":""},{"location":"solidity-specification/01-file-structure/09-punctuation/#19-punctuation","title":"1.9. Punctuation","text":""},{"location":"solidity-specification/01-file-structure/09-punctuation/#syntax","title":"Syntax","text":"
OPEN_PAREN = \"(\";
 
CLOSE_PAREN = \")\";
 
OPEN_BRACKET = \"[\";
 
CLOSE_BRACKET = \"]\";
 
OPEN_BRACE = \"{\";
 
CLOSE_BRACE = \"}\";
 
COMMA = \",\";
 
PERIOD = \".\";
 
QUESTION_MARK = \"?\";
 
SEMICOLON = \";\";
 
COLON = \":\";
 
COLON_EQUAL = \":=\";
 
EQUAL = \"=\";
 
(* Deprecated in 0.5.0 *)EQUAL_COLON = \"=:\";
 
EQUAL_EQUAL = \"==\";
 
EQUAL_GREATER_THAN = \"=>\";
 
ASTERISK = \"*\";
 
ASTERISK_EQUAL = \"*=\";
 
ASTERISK_ASTERISK = \"**\";
 
BAR = \"|\";
 
BAR_EQUAL = \"|=\";
 
BAR_BAR = \"||\";
 
AMPERSAND = \"&\";
 
AMPERSAND_EQUAL = \"&=\";
 
AMPERSAND_AMPERSAND = \"&&\";
 
LESS_THAN = \"<\";
 
LESS_THAN_EQUAL = \"<=\";
 
LESS_THAN_LESS_THAN = \"<<\";
 
LESS_THAN_LESS_THAN_EQUAL = \"<<=\";
 
GREATER_THAN = \">\";
 
GREATER_THAN_EQUAL = \">=\";
 
GREATER_THAN_GREATER_THAN = \">>\";
 
GREATER_THAN_GREATER_THAN_EQUAL = \">>=\";
 
GREATER_THAN_GREATER_THAN_GREATER_THAN = \">>>\";
 
GREATER_THAN_GREATER_THAN_GREATER_THAN_EQUAL = \">>>=\";
 
PLUS = \"+\";
 
PLUS_EQUAL = \"+=\";
 
PLUS_PLUS = \"++\";
 
MINUS = \"-\";
 
MINUS_EQUAL = \"-=\";
 
MINUS_MINUS = \"--\";
 
MINUS_GREATER_THAN = \"->\";
 
SLASH = \"/\" (?!\"*\" | \"/\" | \"=\");
 
SLASH_EQUAL = \"/=\";
 
PERCENT = \"%\";
 
PERCENT_EQUAL = \"%=\";
 
BANG = \"!\";
 
BANG_EQUAL = \"!=\";
 
CARET = \"^\";
 
CARET_EQUAL = \"^=\";
 
TILDE = \"~\";
"},{"location":"solidity-specification/01-file-structure/09-punctuation/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/","title":"2. Definitions","text":""},{"location":"solidity-specification/02-definitions/#2-definitions","title":"2. Definitions","text":""},{"location":"solidity-specification/02-definitions/01-contracts/","title":"2.1. Contracts","text":""},{"location":"solidity-specification/02-definitions/01-contracts/#21-contracts","title":"2.1. Contracts","text":""},{"location":"solidity-specification/02-definitions/01-contracts/#syntax","title":"Syntax","text":"
ContractDefinition = (* abstract_keyword: *) ABSTRACT_KEYWORD? (* Introduced in 0.6.0 *)                     (* contract_keyword: *) CONTRACT_KEYWORD                     (* name: *) IDENTIFIER                     (* inheritance: *) InheritanceSpecifier?                     (* open_brace: *) OPEN_BRACE                     (* members: *) ContractMembers                     (* close_brace: *) CLOSE_BRACE;
 
InheritanceSpecifier = (* is_keyword: *) IS_KEYWORD                       (* types: *) InheritanceTypes;
 
InheritanceTypes = (* item: *) InheritanceType ((* separator: *) COMMA (* item: *) InheritanceType)*;
 
InheritanceType = (* type_name: *) IdentifierPath                  (* arguments: *) ArgumentsDeclaration?;
 
ContractMembers = (* item: *) ContractMember*;
 
ContractMember = (* variant: *) UsingDirective               | (* variant: *) FunctionDefinition               | (* variant: *) ConstructorDefinition (* Introduced in 0.4.22 *)               | (* variant: *) ReceiveFunctionDefinition (* Introduced in 0.6.0 *)               | (* variant: *) FallbackFunctionDefinition (* Introduced in 0.6.0 *)               | (* variant: *) UnnamedFunctionDefinition (* Deprecated in 0.6.0 *)               | (* variant: *) ModifierDefinition               | (* variant: *) StructDefinition               | (* variant: *) EnumDefinition               | (* variant: *) EventDefinition               | (* variant: *) ErrorDefinition (* Introduced in 0.8.4 *)               | (* variant: *) UserDefinedValueTypeDefinition (* Introduced in 0.8.8 *)               | (* variant: *) StateVariableDefinition;
"},{"location":"solidity-specification/02-definitions/01-contracts/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/02-interfaces/","title":"2.2. Interfaces","text":""},{"location":"solidity-specification/02-definitions/02-interfaces/#22-interfaces","title":"2.2. Interfaces","text":""},{"location":"solidity-specification/02-definitions/02-interfaces/#syntax","title":"Syntax","text":"
InterfaceDefinition = (* interface_keyword: *) INTERFACE_KEYWORD                      (* name: *) IDENTIFIER                      (* inheritance: *) InheritanceSpecifier?                      (* open_brace: *) OPEN_BRACE                      (* members: *) InterfaceMembers                      (* close_brace: *) CLOSE_BRACE;
 
InterfaceMembers = (* item: *) ContractMember*;
"},{"location":"solidity-specification/02-definitions/02-interfaces/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/03-libraries/","title":"2.3. Libraries","text":""},{"location":"solidity-specification/02-definitions/03-libraries/#23-libraries","title":"2.3. Libraries","text":""},{"location":"solidity-specification/02-definitions/03-libraries/#syntax","title":"Syntax","text":"
LibraryDefinition = (* library_keyword: *) LIBRARY_KEYWORD                    (* name: *) IDENTIFIER                    (* open_brace: *) OPEN_BRACE                    (* members: *) LibraryMembers                    (* close_brace: *) CLOSE_BRACE;
 
LibraryMembers = (* item: *) ContractMember*;
"},{"location":"solidity-specification/02-definitions/03-libraries/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/04-structs/","title":"2.4. Structs","text":""},{"location":"solidity-specification/02-definitions/04-structs/#24-structs","title":"2.4. Structs","text":""},{"location":"solidity-specification/02-definitions/04-structs/#syntax","title":"Syntax","text":"
StructDefinition = (* struct_keyword: *) STRUCT_KEYWORD                   (* name: *) IDENTIFIER                   (* open_brace: *) OPEN_BRACE                   (* members: *) StructMembers                   (* close_brace: *) CLOSE_BRACE;
 
StructMembers = (* item: *) StructMember*;
 
StructMember = (* type_name: *) TypeName               (* name: *) IDENTIFIER               (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/02-definitions/04-structs/#struct-types","title":"Struct Types","text":"

Structs are custom defined types that can group several variables. They can be defined inside or outside contracts.

struct Voter {\n    address delegate;\n    uint vote;\n}\n

You can also create new objects of this struct using the following syntax:

contract MyContract {\n    function create() public  {\n        Voter memory v = Voter({\n            delegate: msg.sender,\n            vote: 1\n        });\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/05-enums/","title":"2.5. Enums","text":""},{"location":"solidity-specification/02-definitions/05-enums/#25-enums","title":"2.5. Enums","text":""},{"location":"solidity-specification/02-definitions/05-enums/#syntax","title":"Syntax","text":"
EnumDefinition = (* enum_keyword: *) ENUM_KEYWORD                 (* name: *) IDENTIFIER                 (* open_brace: *) OPEN_BRACE                 (* members: *) EnumMembers                 (* close_brace: *) CLOSE_BRACE;
 
EnumMembers = ((* item: *) IDENTIFIER ((* separator: *) COMMA (* item: *) IDENTIFIER)*)?;
"},{"location":"solidity-specification/02-definitions/05-enums/#enum-types","title":"Enum Types","text":"

Enums can be used to create custom types with a finite set of constant values. Enums can be declared on the file level, outside of contract or library definitions.

enum ActionChoices {\n    One,\n    Two\n}\n\ncontract MyContract {\n    function choose() public pure returns (ActionChoices) {\n        return ActionChoices.Two;\n    }\n}\n

Enums require at least one member, and its default value when declared is the first member. Enums cannot have more than 256 members.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/06-constants/","title":"2.6. Constants","text":""},{"location":"solidity-specification/02-definitions/06-constants/#26-constants","title":"2.6. Constants","text":""},{"location":"solidity-specification/02-definitions/06-constants/#syntax","title":"Syntax","text":"
(* Introduced in 0.7.4 *)ConstantDefinition = (* type_name: *) TypeName                     (* constant_keyword: *) CONSTANT_KEYWORD                     (* name: *) IDENTIFIER                     (* equal: *) EQUAL                     (* value: *) Expression                     (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/02-definitions/06-constants/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/07-state-variables/","title":"2.7. State Variables","text":""},{"location":"solidity-specification/02-definitions/07-state-variables/#27-state-variables","title":"2.7. State Variables","text":""},{"location":"solidity-specification/02-definitions/07-state-variables/#syntax","title":"Syntax","text":"
StateVariableDefinition = (* type_name: *) TypeName                          (* attributes: *) StateVariableAttributes                          (* name: *) IDENTIFIER                          (* value: *) StateVariableDefinitionValue?                          (* semicolon: *) SEMICOLON;
 
StateVariableDefinitionValue = (* equal: *) EQUAL                               (* value: *) Expression;
 
StateVariableAttributes = (* item: *) StateVariableAttribute*;
 
StateVariableAttribute = (* variant: *) OverrideSpecifier (* Introduced in 0.6.0 *)                       | (* variant: *) CONSTANT_KEYWORD                       | (* variant: *) INTERNAL_KEYWORD                       | (* variant: *) PRIVATE_KEYWORD                       | (* variant: *) PUBLIC_KEYWORD                       | (* variant: *) IMMUTABLE_KEYWORD (* Introduced in 0.6.5 *)                       | (* variant: *) TRANSIENT_KEYWORD; (* Introduced in 0.8.27 *)
"},{"location":"solidity-specification/02-definitions/07-state-variables/#state-variables","title":"State Variables","text":"

State variables are variables whose values are permanently stored in contract storage.

contract MyContract {\n    uint myStateVariable;\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/08-functions/","title":"2.8. Functions","text":""},{"location":"solidity-specification/02-definitions/08-functions/#28-functions","title":"2.8. Functions","text":""},{"location":"solidity-specification/02-definitions/08-functions/#syntax","title":"Syntax","text":"
FunctionDefinition = (* function_keyword: *) FUNCTION_KEYWORD                     (* name: *) FunctionName                     (* parameters: *) ParametersDeclaration                     (* attributes: *) FunctionAttributes                     (* returns: *) ReturnsDeclaration?                     (* body: *) FunctionBody;
 
FunctionName = (* variant: *) IDENTIFIER             | (* variant: *) FALLBACK_KEYWORD             | (* variant: *) RECEIVE_KEYWORD;
 
ParametersDeclaration = (* open_paren: *) OPEN_PAREN                        (* parameters: *) Parameters                        (* close_paren: *) CLOSE_PAREN;
 
Parameters = ((* item: *) Parameter ((* separator: *) COMMA (* item: *) Parameter)*)?;
 
Parameter = (* type_name: *) TypeName            (* storage_location: *) StorageLocation?            (* name: *) IDENTIFIER?;
 
FunctionAttributes = (* item: *) FunctionAttribute*;
 
FunctionAttribute = (* variant: *) ModifierInvocation                  | (* variant: *) OverrideSpecifier (* Introduced in 0.6.0 *)                  | (* variant: *) CONSTANT_KEYWORD (* Deprecated in 0.5.0 *)                  | (* variant: *) EXTERNAL_KEYWORD                  | (* variant: *) INTERNAL_KEYWORD                  | (* variant: *) PAYABLE_KEYWORD                  | (* variant: *) PRIVATE_KEYWORD                  | (* variant: *) PUBLIC_KEYWORD                  | (* variant: *) PURE_KEYWORD (* Introduced in 0.4.16 *)                  | (* variant: *) VIEW_KEYWORD (* Introduced in 0.4.16 *)                  | (* variant: *) VIRTUAL_KEYWORD; (* Introduced in 0.6.0 *)
 
(* Introduced in 0.6.0 *)OverrideSpecifier = (* override_keyword: *) OVERRIDE_KEYWORD                    (* overridden: *) OverridePathsDeclaration?;
 
(* Introduced in 0.6.0 *)OverridePathsDeclaration = (* open_paren: *) OPEN_PAREN                           (* paths: *) OverridePaths                           (* close_paren: *) CLOSE_PAREN;
 
(* Introduced in 0.6.0 *)OverridePaths = (* item: *) IdentifierPath ((* separator: *) COMMA (* item: *) IdentifierPath)*;
 
ReturnsDeclaration = (* returns_keyword: *) RETURNS_KEYWORD                     (* variables: *) ParametersDeclaration;
 
FunctionBody = (* variant: *) Block             | (* variant: *) SEMICOLON;
 
(* Introduced in 0.4.22 *)ConstructorDefinition = (* constructor_keyword: *) CONSTRUCTOR_KEYWORD                        (* parameters: *) ParametersDeclaration                        (* attributes: *) ConstructorAttributes                        (* body: *) Block;
 
(* Introduced in 0.4.22 *)ConstructorAttributes = (* item: *) ConstructorAttribute*;
 
(* Introduced in 0.4.22 *)ConstructorAttribute = (* variant: *) ModifierInvocation                     | (* variant: *) INTERNAL_KEYWORD                     | (* variant: *) OVERRIDE_KEYWORD (* Introduced in 0.6.0 and deprecated in 0.6.7. *)                     | (* variant: *) PAYABLE_KEYWORD                     | (* variant: *) PUBLIC_KEYWORD                     | (* variant: *) VIRTUAL_KEYWORD; (* Introduced in 0.6.0 and deprecated in 0.6.7. *)
 
(* Deprecated in 0.6.0 *)UnnamedFunctionDefinition = (* function_keyword: *) FUNCTION_KEYWORD                            (* parameters: *) ParametersDeclaration                            (* attributes: *) UnnamedFunctionAttributes                            (* body: *) FunctionBody;
 
(* Deprecated in 0.6.0 *)UnnamedFunctionAttributes = (* item: *) UnnamedFunctionAttribute*;
 
(* Deprecated in 0.6.0 *)UnnamedFunctionAttribute = (* variant: *) ModifierInvocation                         | (* variant: *) CONSTANT_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) EXTERNAL_KEYWORD                         | (* variant: *) INTERNAL_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) PAYABLE_KEYWORD                         | (* variant: *) PRIVATE_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) PUBLIC_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) PURE_KEYWORD (* Introduced in 0.4.16 and deprecated in 0.6.0. *)                         | (* variant: *) VIEW_KEYWORD; (* Introduced in 0.4.16 and deprecated in 0.6.0. *)
 
(* Introduced in 0.6.0 *)FallbackFunctionDefinition = (* fallback_keyword: *) FALLBACK_KEYWORD                             (* parameters: *) ParametersDeclaration                             (* attributes: *) FallbackFunctionAttributes                             (* returns: *) ReturnsDeclaration?                             (* body: *) FunctionBody;
 
(* Introduced in 0.6.0 *)FallbackFunctionAttributes = (* item: *) FallbackFunctionAttribute*;
 
(* Introduced in 0.6.0 *)FallbackFunctionAttribute = (* variant: *) ModifierInvocation                          | (* variant: *) OverrideSpecifier                          | (* variant: *) EXTERNAL_KEYWORD                          | (* variant: *) PAYABLE_KEYWORD                          | (* variant: *) PURE_KEYWORD                          | (* variant: *) VIEW_KEYWORD                          | (* variant: *) VIRTUAL_KEYWORD;
 
(* Introduced in 0.6.0 *)ReceiveFunctionDefinition = (* receive_keyword: *) RECEIVE_KEYWORD                            (* parameters: *) ParametersDeclaration                            (* attributes: *) ReceiveFunctionAttributes                            (* body: *) FunctionBody;
 
(* Introduced in 0.6.0 *)ReceiveFunctionAttributes = (* item: *) ReceiveFunctionAttribute*;
 
(* Introduced in 0.6.0 *)ReceiveFunctionAttribute = (* variant: *) ModifierInvocation                         | (* variant: *) OverrideSpecifier                         | (* variant: *) EXTERNAL_KEYWORD                         | (* variant: *) PAYABLE_KEYWORD                         | (* variant: *) VIRTUAL_KEYWORD;
"},{"location":"solidity-specification/02-definitions/08-functions/#function-definitions","title":"Function Definitions","text":"

Functions are the executable units of code. Functions are usually defined inside a contract, but they can also be defined outside of contracts.

contract MyContract {\n    function contractFunction() public {\n        // Inside the contract\n    }\n}\n\nfunction helperFunction() {\n    // Outside the contract\n}\n

Functions can be overloaded, where multiple functions with the same name, but with different parameters, can co-exist.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/09-modifiers/","title":"2.9. Modifiers","text":""},{"location":"solidity-specification/02-definitions/09-modifiers/#29-modifiers","title":"2.9. Modifiers","text":""},{"location":"solidity-specification/02-definitions/09-modifiers/#syntax","title":"Syntax","text":"
ModifierDefinition = (* modifier_keyword: *) MODIFIER_KEYWORD                     (* name: *) IDENTIFIER                     (* parameters: *) ParametersDeclaration?                     (* attributes: *) ModifierAttributes                     (* body: *) FunctionBody;
 
ModifierAttributes = (* item: *) ModifierAttribute*;
 
ModifierAttribute = (* variant: *) OverrideSpecifier (* Introduced in 0.6.0 *)                  | (* variant: *) VIRTUAL_KEYWORD; (* Introduced in 0.6.0 *)
 
ModifierInvocation = (* name: *) IdentifierPath                     (* arguments: *) ArgumentsDeclaration?;
"},{"location":"solidity-specification/02-definitions/09-modifiers/#function-modifiers","title":"Function Modifiers","text":"

Function modifiers can be used to amend the semantics of functions in a declarative way:

contract MyContract {\n    modifier onlySeller() {\n        require(msg.sender == seller, \"Only seller can call this.\");\n        _; // Function body will be inserted here\n    }\n\n    function myFunction() public view onlySeller {\n        // Code here will be executed after `onlySeller` is executed.\n    }\n}\n

Unlike functions, modifiers cannot be overloaded.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/10-events/","title":"2.10. Events","text":""},{"location":"solidity-specification/02-definitions/10-events/#210-events","title":"2.10. Events","text":""},{"location":"solidity-specification/02-definitions/10-events/#syntax","title":"Syntax","text":"
EventDefinition = (* event_keyword: *) EVENT_KEYWORD                  (* name: *) IDENTIFIER                  (* parameters: *) EventParametersDeclaration                  (* anonymous_keyword: *) ANONYMOUS_KEYWORD?                  (* semicolon: *) SEMICOLON;
 
EventParametersDeclaration = (* open_paren: *) OPEN_PAREN                             (* parameters: *) EventParameters                             (* close_paren: *) CLOSE_PAREN;
 
EventParameters = ((* item: *) EventParameter ((* separator: *) COMMA (* item: *) EventParameter)*)?;
 
EventParameter = (* type_name: *) TypeName                 (* indexed_keyword: *) INDEXED_KEYWORD?                 (* name: *) IDENTIFIER?;
"},{"location":"solidity-specification/02-definitions/10-events/#event-definitions","title":"Event Definitions","text":"

Events are convenient interfaces with the EVM logging facilities. They have to be defined inside a contract:

contract MyContract {\n    // Defining an event\n    event BidPlacedEvent(address bidder, uint amount);\n\n    function bid() public payable {\n        // Triggering an event\n        emit BidPlacedEvent(msg.sender, msg.value);\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/","title":"2.11. User Defined Value Types","text":""},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/#211-user-defined-value-types","title":"2.11. User Defined Value Types","text":""},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/#syntax","title":"Syntax","text":"
(* Introduced in 0.8.8 *)UserDefinedValueTypeDefinition = (* type_keyword: *) TYPE_KEYWORD                                 (* name: *) IDENTIFIER                                 (* is_keyword: *) IS_KEYWORD                                 (* value_type: *) ElementaryType                                 (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/#user-defined-value-types","title":"User Defined Value Types","text":"

A user defined value type allows creating a zero cost abstraction over an elementary value type. This is similar to a type alias. A user defined value type is defined using type C is V, where C is the name of the newly introduced type and V has to be a built-in value type (the underlying type).

type MyInteger is uint256;\n\nlibrary MyLibrary {\n    function add(MyInteger a, MyInteger b) internal pure returns (MyInteger) {\n        return MyInteger.wrap(MyInteger.unwrap(a) + MyInteger.unwrap(b));\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/12-errors/","title":"2.12. Errors","text":""},{"location":"solidity-specification/02-definitions/12-errors/#212-errors","title":"2.12. Errors","text":""},{"location":"solidity-specification/02-definitions/12-errors/#syntax","title":"Syntax","text":"
(* Introduced in 0.8.4 *)ErrorDefinition = (* error_keyword: *) ERROR_KEYWORD                  (* name: *) IDENTIFIER                  (* members: *) ErrorParametersDeclaration                  (* semicolon: *) SEMICOLON;
 
(* Introduced in 0.8.4 *)ErrorParametersDeclaration = (* open_paren: *) OPEN_PAREN                             (* parameters: *) ErrorParameters                             (* close_paren: *) CLOSE_PAREN;
 
(* Introduced in 0.8.4 *)ErrorParameters = ((* item: *) ErrorParameter ((* separator: *) COMMA (* item: *) ErrorParameter)*)?;
 
(* Introduced in 0.8.4 *)ErrorParameter = (* type_name: *) TypeName                 (* name: *) IDENTIFIER?;
"},{"location":"solidity-specification/02-definitions/12-errors/#error-definitions","title":"Error Definitions","text":"

Errors allow you to define descriptive names and data for failure situations. Errors can be used in revert statements. In comparison to string descriptions, errors are much cheaper and allow you to encode additional data. You can use NatSpec to describe the error to the user. They can also be defined inside or outside contracts:

contract Token {\n    error NotEnoughFunds(uint requested, uint available);\n\n    function transfer(address to, uint amount) public {\n        uint balance = balances[msg.sender];\n        if (balance < amount)\n            revert NotEnoughFunds(amount, balance);\n\n        // Continue with the transfer...\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/03-types/","title":"3. Types","text":""},{"location":"solidity-specification/03-types/#3-types","title":"3. Types","text":""},{"location":"solidity-specification/03-types/01-advanced-types/","title":"3.1. Advanced Types","text":""},{"location":"solidity-specification/03-types/01-advanced-types/#31-advanced-types","title":"3.1. Advanced Types","text":""},{"location":"solidity-specification/03-types/01-advanced-types/#syntax","title":"Syntax","text":"
TypeName = (* variant: *) ArrayTypeName         | (* variant: *) FunctionType         | (* variant: *) MappingType         | (* variant: *) ElementaryType         | (* variant: *) IdentifierPath;
 
(* Postfix unary operator *)ArrayTypeName = (* operand: *) TypeName                (* open_bracket: *) OPEN_BRACKET                (* index: *) Expression?                (* close_bracket: *) CLOSE_BRACKET;
 
FunctionType = (* function_keyword: *) FUNCTION_KEYWORD               (* parameters: *) ParametersDeclaration               (* attributes: *) FunctionTypeAttributes               (* returns: *) ReturnsDeclaration?;
 
FunctionTypeAttributes = (* item: *) FunctionTypeAttribute*;
 
FunctionTypeAttribute = (* variant: *) INTERNAL_KEYWORD                      | (* variant: *) EXTERNAL_KEYWORD                      | (* variant: *) PRIVATE_KEYWORD                      | (* variant: *) PUBLIC_KEYWORD                      | (* variant: *) CONSTANT_KEYWORD (* Deprecated in 0.5.0 *)                      | (* variant: *) PURE_KEYWORD (* Introduced in 0.4.16 *)                      | (* variant: *) VIEW_KEYWORD (* Introduced in 0.4.16 *)                      | (* variant: *) PAYABLE_KEYWORD;
 
MappingType = (* mapping_keyword: *) MAPPING_KEYWORD              (* open_paren: *) OPEN_PAREN              (* key_type: *) MappingKey              (* equal_greater_than: *) EQUAL_GREATER_THAN              (* value_type: *) MappingValue              (* close_paren: *) CLOSE_PAREN;
 
MappingKey = (* key_type: *) MappingKeyType             (* name: *) IDENTIFIER?; (* Introduced in 0.8.18 *)
 
MappingKeyType = (* variant: *) ElementaryType               | (* variant: *) IdentifierPath;
 
MappingValue = (* type_name: *) TypeName               (* name: *) IDENTIFIER?; (* Introduced in 0.8.18 *)
"},{"location":"solidity-specification/03-types/01-advanced-types/#function-types","title":"Function Types","text":"

Function types are the types of functions. Variables of function type can be assigned from functions and function parameters of function type can be used to pass functions to and return functions from function calls. They come in two flavors, internal and external.

Function types are notated as follows:

function (<parameter types>) {internal|external} [pure|view|payable] [returns (<return types>)]\n

In contrast to the parameter types, the return types cannot be empty. If the function type should not return anything, the whole returns (<return types>) part has to be omitted.

By default, function types are internal, so the internal keyword can be omitted. Note that this only applies to function types. Visibility has to be specified explicitly for functions defined in contracts, they do not have a default.

contract Oracle {\n    Request[] private requests;\n\n    function query(bytes memory data, function(uint) external callback) public {\n        requests.push(Request(data, callback));\n    }\n\n    function reply(uint requestID, uint response) public {\n        requests[requestID].callback(response);\n    }\n}\n
"},{"location":"solidity-specification/03-types/01-advanced-types/#mapping-types","title":"Mapping Types","text":"

Mapping types use the syntax mapping(_KeyType => _ValueType) and variables of mapping type are declared using the syntax mapping(_KeyType => _ValueType) _VariableName.

contract MappingExample {\n    mapping(address => uint) public balances;\n\n    function update(uint newBalance) public {\n        balances[msg.sender] = newBalance;\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/03-types/02-elementary-types/","title":"3.2. Elementary Types","text":""},{"location":"solidity-specification/03-types/02-elementary-types/#32-elementary-types","title":"3.2. Elementary Types","text":""},{"location":"solidity-specification/03-types/02-elementary-types/#syntax","title":"Syntax","text":"
ElementaryType = (* variant: *) BOOL_KEYWORD               | (* variant: *) BYTE_KEYWORD (* Deprecated in 0.8.0 *)               | (* variant: *) STRING_KEYWORD               | (* variant: *) AddressType               | (* variant: *) BYTES_KEYWORD               | (* variant: *) INT_KEYWORD               | (* variant: *) UINT_KEYWORD               | (* variant: *) FIXED_KEYWORD               | (* variant: *) UFIXED_KEYWORD;
 
AddressType = (* address_keyword: *) ADDRESS_KEYWORD              (* payable_keyword: *) PAYABLE_KEYWORD?;
"},{"location":"solidity-specification/03-types/02-elementary-types/#address-types","title":"Address Types","text":"

The address type comes in two flavours, which are largely identical:

Hexadecimal literals that pass the address checksum test, for example 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF are of address type. Hexadecimal literals that are between 39 and 41 digits long and do not pass the checksum test produce an error. You can prepend (for int types) or append (for bytesNN types) zeros to remove the error.

"},{"location":"solidity-specification/03-types/02-elementary-types/#fixed-size-byte-arrays","title":"Fixed-Size Byte Arrays","text":"

The value types bytes1, bytes2, bytes3, \u2026, bytes32 hold a sequence of bytes from one to up to 32.

"},{"location":"solidity-specification/03-types/02-elementary-types/#dynamic-string-and-byte-arrays","title":"Dynamic String and Byte Arrays","text":"

The bytes type is similar to bytes1[], but it is packed tightly in calldata and memory.

Variables of type string are equal to bytes but do not allow length or index access. If you want to access the byte-representation of a string s, use bytes(s). Keep in mind that you are accessing the low-level bytes of the UTF-8 representation, and not the individual characters.

Memory arrays with dynamic length can be created using the new keyword:

contract MyContract {\n    function myFunction(uint length) public pure {\n        bytes memory b = new bytes(length);\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/","title":"4. Statements","text":""},{"location":"solidity-specification/04-statements/#4-statements","title":"4. Statements","text":""},{"location":"solidity-specification/04-statements/01-blocks/","title":"4.1. Blocks","text":""},{"location":"solidity-specification/04-statements/01-blocks/#41-blocks","title":"4.1. Blocks","text":""},{"location":"solidity-specification/04-statements/01-blocks/#syntax","title":"Syntax","text":"
Block = (* open_brace: *) OPEN_BRACE        (* statements: *) Statements        (* close_brace: *) CLOSE_BRACE;
 
Statements = (* item: *) Statement*;
 
Statement = (* variant: *) IfStatement          | (* variant: *) ForStatement          | (* variant: *) WhileStatement          | (* variant: *) DoWhileStatement          | (* variant: *) ContinueStatement          | (* variant: *) BreakStatement          | (* variant: *) ReturnStatement          | (* variant: *) ThrowStatement (* Deprecated in 0.5.0 *)          | (* variant: *) EmitStatement (* Introduced in 0.4.21 *)          | (* variant: *) TryStatement (* Introduced in 0.6.0 *)          | (* variant: *) RevertStatement (* Introduced in 0.8.4 *)          | (* variant: *) AssemblyStatement          | (* variant: *) Block          | (* variant: *) UncheckedBlock (* Introduced in 0.8.0 *)          | (* variant: *) TupleDeconstructionStatement          | (* variant: *) VariableDeclarationStatement          | (* variant: *) ExpressionStatement;
 
(* Introduced in 0.8.0 *)UncheckedBlock = (* unchecked_keyword: *) UNCHECKED_KEYWORD                 (* block: *) Block;
 
ExpressionStatement = (* expression: *) Expression                      (* semicolon: *) SEMICOLON;
 
AssemblyStatement = (* assembly_keyword: *) ASSEMBLY_KEYWORD                    (* label: *) StringLiteral?                    (* flags: *) AssemblyFlagsDeclaration?                    (* body: *) YulBlock;
 
AssemblyFlagsDeclaration = (* open_paren: *) OPEN_PAREN                           (* flags: *) AssemblyFlags                           (* close_paren: *) CLOSE_PAREN;
 
AssemblyFlags = (* item: *) StringLiteral ((* separator: *) COMMA (* item: *) StringLiteral)*;
"},{"location":"solidity-specification/04-statements/01-blocks/#unchecked-blocks","title":"Unchecked Blocks","text":"

Starting with v0.8.0, by default, all arithmetic operations are checked for underflow or overflow, which means that if the result of an operation falls outside the value range of the type, the call is reverted through a failing assertion. This can be disabled using the unchecked block, resulting in wrapping arithmetic:

unchecked {\n  i++;\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/02-declaration-statements/","title":"4.2. Declaration Statements","text":""},{"location":"solidity-specification/04-statements/02-declaration-statements/#42-declaration-statements","title":"4.2. Declaration Statements","text":""},{"location":"solidity-specification/04-statements/02-declaration-statements/#syntax","title":"Syntax","text":"
TupleDeconstructionStatement = (* var_keyword: *) VAR_KEYWORD? (* Deprecated in 0.5.0 *)                               (* open_paren: *) OPEN_PAREN                               (* elements: *) TupleDeconstructionElements                               (* close_paren: *) CLOSE_PAREN                               (* equal: *) EQUAL                               (* expression: *) Expression                               (* semicolon: *) SEMICOLON;
 
TupleDeconstructionElements = (* item: *) TupleDeconstructionElement ((* separator: *) COMMA (* item: *) TupleDeconstructionElement)*;
 
TupleDeconstructionElement = (* member: *) TupleMember?;
 
TupleMember = (* variant: *) TypedTupleMember            | (* variant: *) UntypedTupleMember;
 
TypedTupleMember = (* type_name: *) TypeName                   (* storage_location: *) StorageLocation?                   (* name: *) IDENTIFIER;
 
UntypedTupleMember = (* storage_location: *) StorageLocation?                     (* name: *) IDENTIFIER;
 
VariableDeclarationStatement = (* variable_type: *) VariableDeclarationType                               (* storage_location: *) StorageLocation?                               (* name: *) IDENTIFIER                               (* value: *) VariableDeclarationValue?                               (* semicolon: *) SEMICOLON;
 
VariableDeclarationType = (* variant: *) TypeName                        | (* variant: *) VAR_KEYWORD; (* Deprecated in 0.5.0 *)
 
VariableDeclarationValue = (* equal: *) EQUAL                           (* expression: *) Expression;
 
StorageLocation = (* variant: *) MEMORY_KEYWORD                | (* variant: *) STORAGE_KEYWORD                | (* variant: *) CALL_DATA_KEYWORD; (* Introduced in 0.5.0 *)
"},{"location":"solidity-specification/04-statements/02-declaration-statements/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/03-control-statements/","title":"4.3. Control Statements","text":""},{"location":"solidity-specification/04-statements/03-control-statements/#43-control-statements","title":"4.3. Control Statements","text":""},{"location":"solidity-specification/04-statements/03-control-statements/#syntax","title":"Syntax","text":"
IfStatement = (* if_keyword: *) IF_KEYWORD              (* open_paren: *) OPEN_PAREN              (* condition: *) Expression              (* close_paren: *) CLOSE_PAREN              (* body: *) Statement              (* else_branch: *) ElseBranch?;
 
ElseBranch = (* else_keyword: *) ELSE_KEYWORD             (* body: *) Statement;
 
ForStatement = (* for_keyword: *) FOR_KEYWORD               (* open_paren: *) OPEN_PAREN               (* initialization: *) ForStatementInitialization               (* condition: *) ForStatementCondition               (* iterator: *) Expression?               (* close_paren: *) CLOSE_PAREN               (* body: *) Statement;
 
ForStatementInitialization = (* variant: *) TupleDeconstructionStatement                           | (* variant: *) VariableDeclarationStatement                           | (* variant: *) ExpressionStatement                           | (* variant: *) SEMICOLON;
 
ForStatementCondition = (* variant: *) ExpressionStatement                      | (* variant: *) SEMICOLON;
 
WhileStatement = (* while_keyword: *) WHILE_KEYWORD                 (* open_paren: *) OPEN_PAREN                 (* condition: *) Expression                 (* close_paren: *) CLOSE_PAREN                 (* body: *) Statement;
 
DoWhileStatement = (* do_keyword: *) DO_KEYWORD                   (* body: *) Statement                   (* while_keyword: *) WHILE_KEYWORD                   (* open_paren: *) OPEN_PAREN                   (* condition: *) Expression                   (* close_paren: *) CLOSE_PAREN                   (* semicolon: *) SEMICOLON;
 
ContinueStatement = (* continue_keyword: *) CONTINUE_KEYWORD                    (* semicolon: *) SEMICOLON;
 
BreakStatement = (* break_keyword: *) BREAK_KEYWORD                 (* semicolon: *) SEMICOLON;
 
ReturnStatement = (* return_keyword: *) RETURN_KEYWORD                  (* expression: *) Expression?                  (* semicolon: *) SEMICOLON;
 
(* Introduced in 0.4.21 *)EmitStatement = (* emit_keyword: *) EMIT_KEYWORD                (* event: *) IdentifierPath                (* arguments: *) ArgumentsDeclaration                (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/04-statements/03-control-statements/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/04-error-handling/","title":"4.4. Error Handling","text":""},{"location":"solidity-specification/04-statements/04-error-handling/#44-error-handling","title":"4.4. Error Handling","text":""},{"location":"solidity-specification/04-statements/04-error-handling/#syntax","title":"Syntax","text":"
(* Introduced in 0.6.0 *)TryStatement = (* try_keyword: *) TRY_KEYWORD               (* expression: *) Expression               (* returns: *) ReturnsDeclaration?               (* body: *) Block               (* catch_clauses: *) CatchClauses;
 
(* Introduced in 0.6.0 *)CatchClauses = (* item: *) CatchClause+;
 
(* Introduced in 0.6.0 *)CatchClause = (* catch_keyword: *) CATCH_KEYWORD              (* error: *) CatchClauseError?              (* body: *) Block;
 
(* Introduced in 0.6.0 *)CatchClauseError = (* name: *) IDENTIFIER?                   (* parameters: *) ParametersDeclaration;
 
(* Introduced in 0.8.4 *)RevertStatement = (* revert_keyword: *) REVERT_KEYWORD                  (* error: *) IdentifierPath?                  (* arguments: *) ArgumentsDeclaration                  (* semicolon: *) SEMICOLON;
 
(* Deprecated in 0.5.0 *)ThrowStatement = (* throw_keyword: *) THROW_KEYWORD                 (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/04-statements/04-error-handling/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/","title":"5. Expressions","text":""},{"location":"solidity-specification/05-expressions/#5-expressions","title":"5. Expressions","text":""},{"location":"solidity-specification/05-expressions/01-base-expressions/","title":"5.1. Base Expressions","text":""},{"location":"solidity-specification/05-expressions/01-base-expressions/#51-base-expressions","title":"5.1. Base Expressions","text":""},{"location":"solidity-specification/05-expressions/01-base-expressions/#syntax","title":"Syntax","text":"
Expression = (* variant: *) AssignmentExpression           | (* variant: *) ConditionalExpression           | (* variant: *) OrExpression           | (* variant: *) AndExpression           | (* variant: *) EqualityExpression           | (* variant: *) ComparisonExpression           | (* variant: *) BitwiseOrExpression           | (* variant: *) BitwiseXorExpression           | (* variant: *) BitwiseAndExpression           | (* variant: *) ShiftExpression           | (* variant: *) AdditiveExpression           | (* variant: *) MultiplicativeExpression           | (* variant: *) ExponentiationExpression           | (* variant: *) PostfixExpression           | (* variant: *) PrefixExpression           | (* variant: *) FunctionCallExpression           | (* variant: *) CallOptionsExpression           | (* variant: *) MemberAccessExpression           | (* variant: *) IndexAccessExpression           | (* variant: *) NewExpression           | (* variant: *) TupleExpression           | (* variant: *) TypeExpression (* Introduced in 0.5.3 *)           | (* variant: *) ArrayExpression           | (* variant: *) HexNumberExpression           | (* variant: *) DecimalNumberExpression           | (* variant: *) StringExpression           | (* variant: *) ElementaryType           | (* variant: *) PAYABLE_KEYWORD (* Introduced in 0.6.0 *)           | (* variant: *) THIS_KEYWORD           | (* variant: *) SUPER_KEYWORD           | (* variant: *) TRUE_KEYWORD           | (* variant: *) FALSE_KEYWORD           | (* variant: *) IDENTIFIER;
 
(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) BAR_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) PLUS_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) MINUS_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) CARET_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) SLASH_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) PERCENT_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) ASTERISK_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) AMPERSAND_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) LESS_THAN_LESS_THAN_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN_GREATER_THAN_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN_GREATER_THAN_GREATER_THAN_EQUAL                       (* right_operand: *) Expression;
 
(* Postfix unary operator *)ConditionalExpression = (* operand: *) Expression                        (* question_mark: *) QUESTION_MARK                        (* true_expression: *) Expression                        (* colon: *) COLON                        (* false_expression: *) Expression;
 
(* Left-associative binary operator *)OrExpression = (* left_operand: *) Expression               (* operator: *) BAR_BAR               (* right_operand: *) Expression;
 
(* Left-associative binary operator *)AndExpression = (* left_operand: *) Expression                (* operator: *) AMPERSAND_AMPERSAND                (* right_operand: *) Expression;
 
(* Left-associative binary operator *)EqualityExpression = (* left_operand: *) Expression                     (* operator: *) EQUAL_EQUAL                     (* right_operand: *) Expression;(* Left-associative binary operator *)EqualityExpression = (* left_operand: *) Expression                     (* operator: *) BANG_EQUAL                     (* right_operand: *) Expression;
 
(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) LESS_THAN                       (* right_operand: *) Expression;(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN                       (* right_operand: *) Expression;(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) LESS_THAN_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN_EQUAL                       (* right_operand: *) Expression;
 
(* Left-associative binary operator *)BitwiseOrExpression = (* left_operand: *) Expression                      (* operator: *) BAR                      (* right_operand: *) Expression;
 
(* Left-associative binary operator *)BitwiseXorExpression = (* left_operand: *) Expression                       (* operator: *) CARET                       (* right_operand: *) Expression;
 
(* Left-associative binary operator *)BitwiseAndExpression = (* left_operand: *) Expression                       (* operator: *) AMPERSAND                       (* right_operand: *) Expression;
 
(* Left-associative binary operator *)ShiftExpression = (* left_operand: *) Expression                  (* operator: *) LESS_THAN_LESS_THAN                  (* right_operand: *) Expression;(* Left-associative binary operator *)ShiftExpression = (* left_operand: *) Expression                  (* operator: *) GREATER_THAN_GREATER_THAN                  (* right_operand: *) Expression;(* Left-associative binary operator *)ShiftExpression = (* left_operand: *) Expression                  (* operator: *) GREATER_THAN_GREATER_THAN_GREATER_THAN                  (* right_operand: *) Expression;
 
(* Left-associative binary operator *)AdditiveExpression = (* left_operand: *) Expression                     (* operator: *) PLUS                     (* right_operand: *) Expression;(* Left-associative binary operator *)AdditiveExpression = (* left_operand: *) Expression                     (* operator: *) MINUS                     (* right_operand: *) Expression;
 
(* Left-associative binary operator *)MultiplicativeExpression = (* left_operand: *) Expression                           (* operator: *) ASTERISK                           (* right_operand: *) Expression;(* Left-associative binary operator *)MultiplicativeExpression = (* left_operand: *) Expression                           (* operator: *) SLASH                           (* right_operand: *) Expression;(* Left-associative binary operator *)MultiplicativeExpression = (* left_operand: *) Expression                           (* operator: *) PERCENT                           (* right_operand: *) Expression;
 
(* Left-associative binary operator *)(* Deprecated in 0.8.0 *)ExponentiationExpression = (* left_operand: *) Expression                           (* operator: *) ASTERISK_ASTERISK                           (* right_operand: *) Expression;(* Right-associative binary operator *)(* Introduced in 0.8.0 *)ExponentiationExpression = (* left_operand: *) Expression                           (* operator: *) ASTERISK_ASTERISK                           (* right_operand: *) Expression;
 
(* Postfix unary operator *)PostfixExpression = (* operand: *) Expression                    (* operator: *) PLUS_PLUS;(* Postfix unary operator *)PostfixExpression = (* operand: *) Expression                    (* operator: *) MINUS_MINUS;
 
(* Prefix unary operator *)PrefixExpression = (* operator: *) PLUS_PLUS                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) MINUS_MINUS                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) TILDE                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) BANG                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) MINUS                   (* operand: *) Expression;(* Prefix unary operator *)(* Deprecated in 0.5.0 *)PrefixExpression = (* operator: *) PLUS                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) DELETE_KEYWORD                   (* operand: *) Expression;
 
(* Postfix unary operator *)FunctionCallExpression = (* operand: *) Expression                         (* arguments: *) ArgumentsDeclaration;
 
(* Postfix unary operator *)(* Introduced in 0.6.2 *)CallOptionsExpression = (* operand: *) Expression                        (* open_brace: *) OPEN_BRACE                        (* options: *) CallOptions                        (* close_brace: *) CLOSE_BRACE;
 
(* Postfix unary operator *)MemberAccessExpression = (* operand: *) Expression                         (* period: *) PERIOD                         (* member: *) IDENTIFIER;
 
(* Postfix unary operator *)IndexAccessExpression = (* operand: *) Expression                        (* open_bracket: *) OPEN_BRACKET                        (* start: *) Expression?                        (* end: *) IndexAccessEnd?                        (* close_bracket: *) CLOSE_BRACKET;
 
IndexAccessEnd = (* colon: *) COLON                 (* end: *) Expression?;
"},{"location":"solidity-specification/05-expressions/01-base-expressions/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/02-function-calls/","title":"5.2. Function Calls","text":""},{"location":"solidity-specification/05-expressions/02-function-calls/#52-function-calls","title":"5.2. Function Calls","text":""},{"location":"solidity-specification/05-expressions/02-function-calls/#syntax","title":"Syntax","text":"
ArgumentsDeclaration = (* variant: *) PositionalArgumentsDeclaration                     | (* variant: *) NamedArgumentsDeclaration;
 
PositionalArgumentsDeclaration = (* open_paren: *) OPEN_PAREN                                 (* arguments: *) PositionalArguments                                 (* close_paren: *) CLOSE_PAREN;
 
PositionalArguments = ((* item: *) Expression ((* separator: *) COMMA (* item: *) Expression)*)?;
 
NamedArgumentsDeclaration = (* open_paren: *) OPEN_PAREN                            (* arguments: *) NamedArgumentGroup?                            (* close_paren: *) CLOSE_PAREN;
 
NamedArgumentGroup = (* open_brace: *) OPEN_BRACE                     (* arguments: *) NamedArguments                     (* close_brace: *) CLOSE_BRACE;
 
NamedArguments = ((* item: *) NamedArgument ((* separator: *) COMMA (* item: *) NamedArgument)*)?;
 
(* Introduced in 0.6.2 *)CallOptions = (* item: *) NamedArgument ((* separator: *) COMMA (* item: *) NamedArgument)*;
 
NamedArgument = (* name: *) IDENTIFIER                (* colon: *) COLON                (* value: *) Expression;
"},{"location":"solidity-specification/05-expressions/02-function-calls/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/03-primary-expressions/","title":"5.3. Primary Expressions","text":""},{"location":"solidity-specification/05-expressions/03-primary-expressions/#53-primary-expressions","title":"5.3. Primary Expressions","text":""},{"location":"solidity-specification/05-expressions/03-primary-expressions/#syntax","title":"Syntax","text":"
(* Introduced in 0.5.3 *)TypeExpression = (* type_keyword: *) TYPE_KEYWORD                 (* open_paren: *) OPEN_PAREN                 (* type_name: *) TypeName                 (* close_paren: *) CLOSE_PAREN;
 
NewExpression = (* new_keyword: *) NEW_KEYWORD                (* type_name: *) TypeName;
 
TupleExpression = (* open_paren: *) OPEN_PAREN                  (* items: *) TupleValues                  (* close_paren: *) CLOSE_PAREN;
 
TupleValues = (* item: *) TupleValue ((* separator: *) COMMA (* item: *) TupleValue)*;
 
TupleValue = (* expression: *) Expression?;
 
ArrayExpression = (* open_bracket: *) OPEN_BRACKET                  (* items: *) ArrayValues                  (* close_bracket: *) CLOSE_BRACKET;
 
ArrayValues = (* item: *) Expression ((* separator: *) COMMA (* item: *) Expression)*;
"},{"location":"solidity-specification/05-expressions/03-primary-expressions/#array-literals","title":"Array Literals","text":"

An array literal is a comma-separated list of one or more expressions, enclosed in square brackets ([...]). For example [1, a, f(3)]. It is always a statically-sized memory array whose length is the number of expressions.

contract MyContract {\n    function someFunction() public pure {\n        otherFunction([uint(1), 2, 3]);\n    }\n}\n
"},{"location":"solidity-specification/05-expressions/03-primary-expressions/#array-slices","title":"Array Slices","text":"

Array slices are a view on a contiguous portion of an array. They are written as x[start:end], where start and end are expressions resulting in a uint256 type (or implicitly convertible to it). The first element of the slice is x[start] and the last element is x[end - 1].

Both start and end are optional: start defaults to 0 and end defaults to the length of the array.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/04-numbers/","title":"5.4. Numbers","text":""},{"location":"solidity-specification/05-expressions/04-numbers/#54-numbers","title":"5.4. Numbers","text":""},{"location":"solidity-specification/05-expressions/04-numbers/#syntax","title":"Syntax","text":"
HexNumberExpression = (* literal: *) HEX_LITERAL                      (* unit: *) NumberUnit?; (* Deprecated in 0.5.0 *)
 
DecimalNumberExpression = (* literal: *) DECIMAL_LITERAL                          (* unit: *) NumberUnit?;
 
HEX_LITERAL = \"0x\" \u00abHEX_CHARACTER\u00bb+ (\"_\" \u00abHEX_CHARACTER\u00bb+)* (?!\u00abIDENTIFIER_START\u00bb);(* Deprecated in 0.5.0 *)HEX_LITERAL = \"0X\" \u00abHEX_CHARACTER\u00bb+ (\"_\" \u00abHEX_CHARACTER\u00bb+)* (?!\u00abIDENTIFIER_START\u00bb);
 
DECIMAL_LITERAL = \".\" \u00abDECIMAL_DIGITS\u00bb \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb (?!\".\") \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);(* Deprecated in 0.5.0 *)DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb \".\" (?!\u00abDECIMAL_DIGITS\u00bb) \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);(* Deprecated in 0.5.0 *)DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb \".\" \u00abDECIMAL_DIGITS\u00bb \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);(* Introduced in 0.5.0 *)DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb (\".\" \u00abDECIMAL_DIGITS\u00bb)? \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);
 
\u00abDECIMAL_DIGITS\u00bb = \"0\"\u2026\"9\"+ (\"_\" \"0\"\u2026\"9\"+)*;
 
\u00abDECIMAL_EXPONENT\u00bb = (\"e\" | \"E\") \"-\"? \u00abDECIMAL_DIGITS\u00bb;
 
NumberUnit = (* variant: *) WEI_KEYWORD           | (* variant: *) GWEI_KEYWORD (* Introduced in 0.6.11 *)           | (* variant: *) SZABO_KEYWORD (* Deprecated in 0.7.0 *)           | (* variant: *) FINNEY_KEYWORD (* Deprecated in 0.7.0 *)           | (* variant: *) ETHER_KEYWORD           | (* variant: *) SECONDS_KEYWORD           | (* variant: *) MINUTES_KEYWORD           | (* variant: *) HOURS_KEYWORD           | (* variant: *) DAYS_KEYWORD           | (* variant: *) WEEKS_KEYWORD           | (* variant: *) YEARS_KEYWORD; (* Deprecated in 0.5.0 *)
"},{"location":"solidity-specification/05-expressions/04-numbers/#integers","title":"Integers","text":"

Signed (int8..int256) and unsigned (uint8..uint256) integers of various sizes, from 8 to 256 bits, moving up in steps of 8 bits. uint and int are aliases for uint256 and int256, respectively.

Integers in Solidity are restricted to a certain range. For example, with uint32, this is 0 up to 2**32 - 1.

Integer literals are formed from a sequence of digits in the range 0-9. They are interpreted as decimals. For example, 69 means sixty nine.

Octal literals do not exist in Solidity and leading zeros are invalid.

"},{"location":"solidity-specification/05-expressions/04-numbers/#decimals","title":"Decimals","text":"

Decimal fractional literals are formed by a . with at least one number on one side. Examples include 1., .1 and 1.3.

"},{"location":"solidity-specification/05-expressions/04-numbers/#fixed-point-numbers","title":"Fixed Point Numbers","text":"

Signed fixed and unsigned fixed ufixed point number of various sizes. Keywords ufixedMxN and fixedMxN, where M represents the number of bits taken by the type and N represents how many decimal points are available. M must be divisible by 8 and goes from 8 to 256 bits. N must be between 0 and 80, inclusive. ufixed and fixed are aliases for ufixed128x18 and fixed128x18, respectively.

Fixed point numbers are not fully supported by Solidity yet. They can be declared, but cannot be assigned to or from.

"},{"location":"solidity-specification/05-expressions/04-numbers/#scientific-notation","title":"Scientific Notation","text":"

Scientific notation in the form of 2e10 is also supported, where the mantissa can be fractional but the exponent has to be an integer. The literal MeE is equivalent to M * 10**E. Examples include 2e10, -2e10, 2e-10, 2.5e1.

"},{"location":"solidity-specification/05-expressions/04-numbers/#using-underscores","title":"Using Underscores","text":"

Underscores can be used to separate the digits of a numeric literal to aid readability. For example, decimal 123_000, hexadecimal 0x2eff_abcde, scientific decimal notation 1_2e345_678 are all valid. Underscores are only allowed between two digits and only one consecutive underscore is allowed. There is no additional semantic meaning added to a number literal containing underscores, the underscores are ignored.

"},{"location":"solidity-specification/05-expressions/04-numbers/#ether-units","title":"Ether Units","text":"

A literal number can take a suffix of wei, gwei or ether to specify a sub-denomination of Ether, where Ether numbers without a postfix are assumed to be Wei.

assert(1 wei == 1);\nassert(1 gwei == 1e9);\nassert(1 szabo == 1e12);\nassert(1 finney == 1e15);\nassert(1 ether == 1e18);\n
"},{"location":"solidity-specification/05-expressions/04-numbers/#time-units","title":"Time Units","text":"

Suffixes that can be used to specify units of time where seconds are the base unit and units are considered naively in the following way:

assert(1 == 1 seconds);\nassert(1 minutes == 60 seconds);\nassert(1 hours == 60 minutes);\nassert(1 days == 24 hours);\nassert(1 weeks == 7 days);\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/05-strings/","title":"5.5. Strings","text":""},{"location":"solidity-specification/05-expressions/05-strings/#55-strings","title":"5.5. Strings","text":""},{"location":"solidity-specification/05-expressions/05-strings/#syntax","title":"Syntax","text":"
StringExpression = (* variant: *) StringLiteral (* Deprecated in 0.5.14 *)                 | (* variant: *) StringLiterals (* Introduced in 0.5.14 *)                 | (* variant: *) HexStringLiteral (* Deprecated in 0.5.14 *)                 | (* variant: *) HexStringLiterals (* Introduced in 0.5.14 *)                 | (* variant: *) UnicodeStringLiterals; (* Introduced in 0.7.0 *)
 
(* Introduced in 0.5.14 *)StringLiterals = (* item: *) StringLiteral+;
 
StringLiteral = (* variant: *) SINGLE_QUOTED_STRING_LITERAL              | (* variant: *) DOUBLE_QUOTED_STRING_LITERAL;
 
(* Deprecated in 0.4.25 *)SINGLE_QUOTED_STRING_LITERAL = \"'\" (\u00abESCAPE_SEQUENCE_ARBITRARY\u00bb | !(\"'\" | \"\\\\\" | \"\\r\" | \"\\n\"))* \"'\";(* Introduced in 0.4.25 and deprecated in 0.7.0. *)SINGLE_QUOTED_STRING_LITERAL = \"'\" (\u00abESCAPE_SEQUENCE\u00bb | !(\"'\" | \"\\\\\" | \"\\r\" | \"\\n\"))* \"'\";SINGLE_QUOTED_STRING_LITERAL = \"'\" (\u00abESCAPE_SEQUENCE\u00bb | \" \"\u2026\"&\" | \"(\"\u2026\"[\" | \"]\"\u2026\"~\")* \"'\";
 
(* Deprecated in 0.4.25 *)DOUBLE_QUOTED_STRING_LITERAL = '\"' (\u00abESCAPE_SEQUENCE_ARBITRARY\u00bb | !('\"' | \"\\\\\" | \"\\r\" | \"\\n\"))* '\"';(* Introduced in 0.4.25 and deprecated in 0.7.0. *)DOUBLE_QUOTED_STRING_LITERAL = '\"' (\u00abESCAPE_SEQUENCE\u00bb | !('\"' | \"\\\\\" | \"\\r\" | \"\\n\"))* '\"';DOUBLE_QUOTED_STRING_LITERAL = '\"' (\u00abESCAPE_SEQUENCE\u00bb | \" \"\u2026\"!\" | \"#\"\u2026\"[\" | \"]\"\u2026\"~\")* '\"';
 
(* Introduced in 0.5.14 *)HexStringLiterals = (* item: *) HexStringLiteral+;
 
HexStringLiteral = (* variant: *) SINGLE_QUOTED_HEX_STRING_LITERAL                 | (* variant: *) DOUBLE_QUOTED_HEX_STRING_LITERAL;
 
SINGLE_QUOTED_HEX_STRING_LITERAL = \"hex'\" \u00abHEX_STRING_CONTENTS\u00bb? \"'\";
 
DOUBLE_QUOTED_HEX_STRING_LITERAL = 'hex\"' \u00abHEX_STRING_CONTENTS\u00bb? '\"';
 
\u00abHEX_STRING_CONTENTS\u00bb = \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb (\"_\"? \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb)*;
 
\u00abHEX_CHARACTER\u00bb = \"0\"\u2026\"9\" | \"a\"\u2026\"f\" | \"A\"\u2026\"F\";
 
(* Introduced in 0.7.0 *)UnicodeStringLiterals = (* item: *) UnicodeStringLiteral+;
 
(* Introduced in 0.7.0 *)UnicodeStringLiteral = (* variant: *) SINGLE_QUOTED_UNICODE_STRING_LITERAL                     | (* variant: *) DOUBLE_QUOTED_UNICODE_STRING_LITERAL;
 
(* Introduced in 0.7.0 *)SINGLE_QUOTED_UNICODE_STRING_LITERAL = \"unicode'\" (\u00abESCAPE_SEQUENCE\u00bb | !(\"'\" | \"\\\\\" | \"\\r\" | \"\\n\"))* \"'\";
 
(* Introduced in 0.7.0 *)DOUBLE_QUOTED_UNICODE_STRING_LITERAL = 'unicode\"' (\u00abESCAPE_SEQUENCE\u00bb | !('\"' | \"\\\\\" | \"\\r\" | \"\\n\"))* '\"';
 
\u00abESCAPE_SEQUENCE\u00bb = \"\\\\\" (\u00abASCII_ESCAPE\u00bb | \u00abHEX_BYTE_ESCAPE\u00bb | \u00abUNICODE_ESCAPE\u00bb);
 
(* Deprecated in 0.4.25 *)\u00abESCAPE_SEQUENCE_ARBITRARY\u00bb = \"\\\\\" (!(\"x\" | \"u\") | \u00abHEX_BYTE_ESCAPE\u00bb | \u00abUNICODE_ESCAPE\u00bb);
 
\u00abASCII_ESCAPE\u00bb = \"n\" | \"r\" | \"t\" | \"'\" | '\"' | \"\\\\\" | \"\\r\\n\" | \"\\r\" | \"\\n\";
 
\u00abHEX_BYTE_ESCAPE\u00bb = \"x\" \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb;
 
\u00abUNICODE_ESCAPE\u00bb = \"u\" \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb;
"},{"location":"solidity-specification/05-expressions/05-strings/#string-literals","title":"String Literals","text":"

String literals are written with either double or single-quotes (\"foo\" or 'bar'), and they can also be split into multiple consecutive parts (\"foo\" \"bar\" is equivalent to \"foobar\") which can be helpful when dealing with long strings. They do not imply trailing zeroes as in C; \"foo\" represents three bytes, not four. As with integer literals, their type can vary, but they are implicitly convertible to bytes1, ..., bytes32 if they fit.

String literals can only contain printable ASCII characters, which means the characters between 0x20 and 0x7E inclusively.

"},{"location":"solidity-specification/05-expressions/05-strings/#unicode-literals","title":"Unicode Literals","text":"

While regular string literals can only contain ASCII, unicode literals (prefixed with the keyword unicode) can contain any valid UTF-8 sequence. They also support the very same escape sequences as regular string literals.

string memory a = unicode\"Hello \ud83d\ude03\";\n
"},{"location":"solidity-specification/05-expressions/05-strings/#hexadecimal-literals","title":"Hexadecimal Literals","text":"

Hexadecimal literals are prefixed with the keyword hex and are enclosed in double or single-quotes (hex\"001122FF\", hex'0011_22_FF'). Their content must be hexadecimal digits which can optionally use a single underscore as separator between byte boundaries. The value of the literal will be the binary representation of the hexadecimal sequence.

Hexadecimal literals behave like string literals and have the same convertibility restrictions. Additionally, multiple hexadecimal literals separated by whitespace are concatenated into a single literal: hex\"00112233\" hex\"44556677\" is equivalent to hex\"0011223344556677\"

"},{"location":"solidity-specification/05-expressions/05-strings/#escape-sequences","title":"Escape Sequences","text":"

String literals also support the following escape characters:

Any Unicode line terminator which is not a newline (i.e. LF, VF, FF, CR, NEL, LS, PS) is considered to terminate the string literal. Newline only terminates the string literal if it is not preceded by a \\.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/06-identifiers/","title":"5.6. Identifiers","text":""},{"location":"solidity-specification/05-expressions/06-identifiers/#56-identifiers","title":"5.6. Identifiers","text":""},{"location":"solidity-specification/05-expressions/06-identifiers/#syntax","title":"Syntax","text":"
IdentifierPath = (* item: *) IDENTIFIER ((* separator: *) PERIOD (* item: *) IDENTIFIER)*;
 
IDENTIFIER = \u00abIDENTIFIER_START\u00bb \u00abIDENTIFIER_PART\u00bb*;
 
\u00abIDENTIFIER_START\u00bb = \"_\" | \"$\" | \"a\"\u2026\"z\" | \"A\"\u2026\"Z\";
 
\u00abIDENTIFIER_PART\u00bb = \u00abIDENTIFIER_START\u00bb | \"0\"\u2026\"9\";
"},{"location":"solidity-specification/05-expressions/06-identifiers/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/06-yul/","title":"6. Yul","text":""},{"location":"solidity-specification/06-yul/#6-yul","title":"6. Yul","text":""},{"location":"solidity-specification/06-yul/01-yul-statements/","title":"6.1. Yul Statements","text":""},{"location":"solidity-specification/06-yul/01-yul-statements/#61-yul-statements","title":"6.1. Yul Statements","text":""},{"location":"solidity-specification/06-yul/01-yul-statements/#syntax","title":"Syntax","text":"
YulBlock = (* open_brace: *) OPEN_BRACE           (* statements: *) YulStatements           (* close_brace: *) CLOSE_BRACE;
 
YulStatements = (* item: *) YulStatement*;
 
YulStatement = (* variant: *) YulBlock             | (* variant: *) YulFunctionDefinition             | (* variant: *) YulStackAssignmentStatement (* Deprecated in 0.5.0 *)             | (* variant: *) YulIfStatement             | (* variant: *) YulForStatement             | (* variant: *) YulSwitchStatement             | (* variant: *) YulLeaveStatement (* Introduced in 0.6.0 *)             | (* variant: *) YulBreakStatement             | (* variant: *) YulContinueStatement             | (* variant: *) YulVariableAssignmentStatement             | (* variant: *) YulLabel (* Deprecated in 0.5.0 *)             | (* variant: *) YulVariableDeclarationStatement             | (* variant: *) YulExpression;
 
YulFunctionDefinition = (* function_keyword: *) YUL_FUNCTION_KEYWORD                        (* name: *) YUL_IDENTIFIER                        (* parameters: *) YulParametersDeclaration                        (* returns: *) YulReturnsDeclaration?                        (* body: *) YulBlock;
 
YulParametersDeclaration = (* open_paren: *) OPEN_PAREN                           (* parameters: *) YulParameters                           (* close_paren: *) CLOSE_PAREN;
 
YulParameters = ((* item: *) YUL_IDENTIFIER ((* separator: *) COMMA (* item: *) YUL_IDENTIFIER)*)?;
 
YulReturnsDeclaration = (* minus_greater_than: *) MINUS_GREATER_THAN                        (* variables: *) YulVariableNames;
 
YulVariableNames = (* item: *) YUL_IDENTIFIER ((* separator: *) COMMA (* item: *) YUL_IDENTIFIER)*;
 
YulVariableDeclarationStatement = (* let_keyword: *) YUL_LET_KEYWORD                                  (* variables: *) YulVariableNames                                  (* value: *) YulVariableDeclarationValue?;
 
YulVariableDeclarationValue = (* assignment: *) YulAssignmentOperator                              (* expression: *) YulExpression;
 
YulVariableAssignmentStatement = (* variables: *) YulPaths                                 (* assignment: *) YulAssignmentOperator                                 (* expression: *) YulExpression;
 
YulAssignmentOperator = (* variant: *) COLON_EQUAL                      | (* variant: *) YulColonAndEqual; (* Deprecated in 0.5.5 *)
 
(* Deprecated in 0.5.5 *)YulColonAndEqual = (* colon: *) COLON                   (* equal: *) EQUAL;
 
(* Deprecated in 0.5.0 *)YulStackAssignmentStatement = (* assignment: *) YulStackAssignmentOperator                              (* variable: *) YUL_IDENTIFIER;
 
(* Deprecated in 0.5.0 *)YulStackAssignmentOperator = (* variant: *) EQUAL_COLON                           | (* variant: *) YulEqualAndColon;
 
(* Deprecated in 0.5.0 *)YulEqualAndColon = (* equal: *) EQUAL                   (* colon: *) COLON;
 
YulIfStatement = (* if_keyword: *) YUL_IF_KEYWORD                 (* condition: *) YulExpression                 (* body: *) YulBlock;
 
YulForStatement = (* for_keyword: *) YUL_FOR_KEYWORD                  (* initialization: *) YulBlock                  (* condition: *) YulExpression                  (* iterator: *) YulBlock                  (* body: *) YulBlock;
 
YulSwitchStatement = (* switch_keyword: *) YUL_SWITCH_KEYWORD                     (* expression: *) YulExpression                     (* cases: *) YulSwitchCases;
 
YulSwitchCases = (* item: *) YulSwitchCase+;
 
YulSwitchCase = (* variant: *) YulDefaultCase              | (* variant: *) YulValueCase;
 
YulDefaultCase = (* default_keyword: *) YUL_DEFAULT_KEYWORD                 (* body: *) YulBlock;
 
YulValueCase = (* case_keyword: *) YUL_CASE_KEYWORD               (* value: *) YulLiteral               (* body: *) YulBlock;
 
(* Introduced in 0.6.0 *)YulLeaveStatement = (* leave_keyword: *) YUL_LEAVE_KEYWORD;
 
YulBreakStatement = (* break_keyword: *) YUL_BREAK_KEYWORD;
 
YulContinueStatement = (* continue_keyword: *) YUL_CONTINUE_KEYWORD;
 
(* Deprecated in 0.5.0 *)YulLabel = (* label: *) YUL_IDENTIFIER           (* colon: *) COLON;
"},{"location":"solidity-specification/06-yul/01-yul-statements/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/06-yul/02-yul-expressions/","title":"6.2. Yul Expressions","text":""},{"location":"solidity-specification/06-yul/02-yul-expressions/#62-yul-expressions","title":"6.2. Yul Expressions","text":""},{"location":"solidity-specification/06-yul/02-yul-expressions/#syntax","title":"Syntax","text":"
YulExpression = (* variant: *) YulFunctionCallExpression              | (* variant: *) YulLiteral              | (* variant: *) YulBuiltInFunction              | (* variant: *) YulPath;
 
(* Postfix unary operator *)YulFunctionCallExpression = (* operand: *) YulExpression                            (* open_paren: *) OPEN_PAREN                            (* arguments: *) YulArguments                            (* close_paren: *) CLOSE_PAREN;
 
YulArguments = ((* item: *) YulExpression ((* separator: *) COMMA (* item: *) YulExpression)*)?;
 
YulPaths = (* item: *) YulPath ((* separator: *) COMMA (* item: *) YulPath)*;
 
YulPath = (* item: *) YUL_IDENTIFIER ((* separator: *) PERIOD (* item: *) YUL_IDENTIFIER)*;
 
(* Introduced in 0.5.8 and deprecated in 0.7.0. *)YUL_IDENTIFIER = \u00abIDENTIFIER_START\u00bb (\u00abIDENTIFIER_PART\u00bb | \".\")*;YUL_IDENTIFIER = \u00abIDENTIFIER_START\u00bb \u00abIDENTIFIER_PART\u00bb*;
 
YulBuiltInFunction = (* variant: *) YUL_ADD_KEYWORD                   | (* variant: *) YUL_ADD_MOD_KEYWORD                   | (* variant: *) YUL_ADDRESS_KEYWORD                   | (* variant: *) YUL_AND_KEYWORD                   | (* variant: *) YUL_BALANCE_KEYWORD                   | (* variant: *) YUL_BLOCK_HASH_KEYWORD                   | (* variant: *) YUL_BYTE_KEYWORD                   | (* variant: *) YUL_CALL_CODE_KEYWORD                   | (* variant: *) YUL_CALL_DATA_COPY_KEYWORD                   | (* variant: *) YUL_CALL_DATA_LOAD_KEYWORD                   | (* variant: *) YUL_CALL_DATA_SIZE_KEYWORD                   | (* variant: *) YUL_CALLER_KEYWORD                   | (* variant: *) YUL_CALL_KEYWORD                   | (* variant: *) YUL_CALL_VALUE_KEYWORD                   | (* variant: *) YUL_COIN_BASE_KEYWORD                   | (* variant: *) YUL_CREATE_KEYWORD                   | (* variant: *) YUL_DELEGATE_CALL_KEYWORD                   | (* variant: *) YUL_DIV_KEYWORD                   | (* variant: *) YUL_EQ_KEYWORD                   | (* variant: *) YUL_EXP_KEYWORD                   | (* variant: *) YUL_EXT_CODE_COPY_KEYWORD                   | (* variant: *) YUL_EXT_CODE_SIZE_KEYWORD                   | (* variant: *) YUL_GAS_KEYWORD                   | (* variant: *) YUL_GAS_LIMIT_KEYWORD                   | (* variant: *) YUL_GAS_PRICE_KEYWORD                   | (* variant: *) YUL_GT_KEYWORD                   | (* variant: *) YUL_INVALID_KEYWORD                   | (* variant: *) YUL_IS_ZERO_KEYWORD                   | (* variant: *) YUL_JUMP_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_JUMPI_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_LOG_0_KEYWORD                   | (* variant: *) YUL_LOG_1_KEYWORD                   | (* variant: *) YUL_LOG_2_KEYWORD                   | (* variant: *) YUL_LOG_3_KEYWORD                   | (* variant: *) YUL_LOG_4_KEYWORD                   | (* variant: *) YUL_LT_KEYWORD                   | (* variant: *) YUL_M_LOAD_KEYWORD                   | (* variant: *) YUL_MOD_KEYWORD                   | (* variant: *) YUL_M_SIZE_KEYWORD                   | (* variant: *) YUL_M_STORE_8_KEYWORD                   | (* variant: *) YUL_M_STORE_KEYWORD                   | (* variant: *) YUL_MUL_KEYWORD                   | (* variant: *) YUL_MUL_MOD_KEYWORD                   | (* variant: *) YUL_NOT_KEYWORD                   | (* variant: *) YUL_NUMBER_KEYWORD                   | (* variant: *) YUL_ORIGIN_KEYWORD                   | (* variant: *) YUL_OR_KEYWORD                   | (* variant: *) YUL_POP_KEYWORD                   | (* variant: *) YUL_RETURN_KEYWORD                   | (* variant: *) YUL_REVERT_KEYWORD                   | (* variant: *) YUL_S_DIV_KEYWORD                   | (* variant: *) YUL_SELF_DESTRUCT_KEYWORD                   | (* variant: *) YUL_SGT_KEYWORD                   | (* variant: *) YUL_SIGN_EXTEND_KEYWORD                   | (* variant: *) YUL_S_LOAD_KEYWORD                   | (* variant: *) YUL_SLT_KEYWORD                   | (* variant: *) YUL_S_MOD_KEYWORD                   | (* variant: *) YUL_S_STORE_KEYWORD                   | (* variant: *) YUL_STOP_KEYWORD                   | (* variant: *) YUL_SUB_KEYWORD                   | (* variant: *) YUL_TIMESTAMP_KEYWORD                   | (* variant: *) YUL_XOR_KEYWORD                   | (* variant: *) YUL_KECCAK_256_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_SHA_3_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_SUICIDE_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_RETURN_DATA_COPY_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_RETURN_DATA_SIZE_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_STATIC_CALL_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_CREATE_2_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_EXT_CODE_HASH_KEYWORD (* Introduced in 0.5.0 *)                   | (* variant: *) YUL_SAR_KEYWORD                   | (* variant: *) YUL_SHL_KEYWORD                   | (* variant: *) YUL_SHR_KEYWORD                   | (* variant: *) YUL_CHAIN_ID_KEYWORD                   | (* variant: *) YUL_SELF_BALANCE_KEYWORD                   | (* variant: *) YUL_BASE_FEE_KEYWORD (* Introduced in 0.8.7 *)                   | (* variant: *) YUL_DIFFICULTY_KEYWORD (* Deprecated in 0.8.18 *)                   | (* variant: *) YUL_PREV_RANDAO_KEYWORD (* Introduced in 0.8.18 *)                   | (* variant: *) YUL_BLOB_BASE_FEE_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_BLOB_HASH_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_T_LOAD_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_T_STORE_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_M_COPY_KEYWORD; (* Introduced in 0.8.24 *)
 
YulLiteral = (* variant: *) YUL_TRUE_KEYWORD           | (* variant: *) YUL_FALSE_KEYWORD           | (* variant: *) YUL_DECIMAL_LITERAL           | (* variant: *) YUL_HEX_LITERAL           | (* variant: *) HexStringLiteral           | (* variant: *) StringLiteral;
 
YUL_DECIMAL_LITERAL = (\"0\" | (\"1\"\u2026\"9\" \"0\"\u2026\"9\"*)) (?!\u00abIDENTIFIER_START\u00bb);
 
YUL_HEX_LITERAL = \"0x\" \u00abHEX_CHARACTER\u00bb+ (?!\u00abIDENTIFIER_START\u00bb);
"},{"location":"solidity-specification/06-yul/02-yul-expressions/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/06-yul/03-yul-keywords/","title":"6.3. Yul Keywords","text":""},{"location":"solidity-specification/06-yul/03-yul-keywords/#63-yul-keywords","title":"6.3. Yul Keywords","text":""},{"location":"solidity-specification/06-yul/03-yul-keywords/#syntax","title":"Syntax","text":"
(* Reserved until 0.7.1 *)YUL_ABSTRACT_KEYWORD = \"abstract\";
 
YUL_ADD_KEYWORD = \"add\";
 
YUL_ADD_MOD_KEYWORD = \"addmod\";
 
(* Never reserved *)YUL_ADDRESS_KEYWORD = \"address\";
 
(* Reserved until 0.7.1 *)YUL_AFTER_KEYWORD = \"after\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_ALIAS_KEYWORD = \"alias\";
 
YUL_AND_KEYWORD = \"and\";
 
(* Reserved until 0.7.1 *)YUL_ANONYMOUS_KEYWORD = \"anonymous\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_APPLY_KEYWORD = \"apply\";
 
(* Reserved until 0.7.1 *)YUL_AS_KEYWORD = \"as\";
 
(* Reserved until 0.7.1 *)YUL_ASSEMBLY_KEYWORD = \"assembly\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_AUTO_KEYWORD = \"auto\";
 
YUL_BALANCE_KEYWORD = \"balance\";
 
(* Introduced in 0.8.7 *)(* Reserved in 0.8.7 *)YUL_BASE_FEE_KEYWORD = \"basefee\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_BLOB_BASE_FEE_KEYWORD = \"blobbasefee\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_BLOB_HASH_KEYWORD = \"blobhash\";
 
YUL_BLOCK_HASH_KEYWORD = \"blockhash\";
 
(* Reserved until 0.5.10 *)YUL_BOOL_KEYWORD = \"bool\";
 
YUL_BREAK_KEYWORD = \"break\";
 
YUL_BYTE_KEYWORD = \"byte\";
 
(* Reserved until 0.7.1 *)YUL_BYTES_KEYWORD = \"bytes\" (\"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"16\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"24\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"32\")?;
 
YUL_CALL_CODE_KEYWORD = \"callcode\";
 
YUL_CALL_DATA_COPY_KEYWORD = \"calldatacopy\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_CALL_DATA_KEYWORD = \"calldata\";
 
YUL_CALL_DATA_LOAD_KEYWORD = \"calldataload\";
 
YUL_CALL_DATA_SIZE_KEYWORD = \"calldatasize\";
 
YUL_CALLER_KEYWORD = \"caller\";
 
YUL_CALL_KEYWORD = \"call\";
 
YUL_CALL_VALUE_KEYWORD = \"callvalue\";
 
YUL_CASE_KEYWORD = \"case\";
 
(* Reserved until 0.7.1 *)YUL_CATCH_KEYWORD = \"catch\";
 
(* Reserved in 0.5.12 *)YUL_CHAIN_ID_KEYWORD = \"chainid\";
 
YUL_COIN_BASE_KEYWORD = \"coinbase\";
 
(* Reserved until 0.7.1 *)YUL_CONSTANT_KEYWORD = \"constant\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_CONSTRUCTOR_KEYWORD = \"constructor\";
 
YUL_CONTINUE_KEYWORD = \"continue\";
 
(* Reserved until 0.7.1 *)YUL_CONTRACT_KEYWORD = \"contract\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_COPY_OF_KEYWORD = \"copyof\";
 
YUL_CREATE_KEYWORD = \"create\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_CREATE_2_KEYWORD = \"create2\";
 
(* Reserved until 0.7.1 *)YUL_DAYS_KEYWORD = \"days\";
 
YUL_DEFAULT_KEYWORD = \"default\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_DEFINE_KEYWORD = \"define\";
 
YUL_DELEGATE_CALL_KEYWORD = \"delegatecall\";
 
(* Reserved until 0.7.1 *)YUL_DELETE_KEYWORD = \"delete\";
 
(* Deprecated in 0.8.18 *)YUL_DIFFICULTY_KEYWORD = \"difficulty\";
 
YUL_DIV_KEYWORD = \"div\";
 
(* Reserved until 0.7.1 *)YUL_DO_KEYWORD = \"do\";
 
(* Reserved until 0.7.1 *)YUL_ELSE_KEYWORD = \"else\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_EMIT_KEYWORD = \"emit\";
 
(* Reserved until 0.7.1 *)YUL_ENUM_KEYWORD = \"enum\";
 
YUL_EQ_KEYWORD = \"eq\";
 
(* Reserved until 0.7.1 *)YUL_ETHER_KEYWORD = \"ether\";
 
(* Reserved until 0.7.1 *)YUL_EVENT_KEYWORD = \"event\";
 
YUL_EXP_KEYWORD = \"exp\";
 
YUL_EXT_CODE_COPY_KEYWORD = \"extcodecopy\";
 
(* Introduced in 0.5.0 *)(* Reserved in 0.5.0 *)YUL_EXT_CODE_HASH_KEYWORD = \"extcodehash\";
 
YUL_EXT_CODE_SIZE_KEYWORD = \"extcodesize\";
 
(* Reserved until 0.7.1 *)YUL_EXTERNAL_KEYWORD = \"external\";
 
(* Reserved from 0.6.0 until 0.7.1 *)YUL_FALLBACK_KEYWORD = \"fallback\";
 
YUL_FALSE_KEYWORD = \"false\";
 
(* Reserved until 0.7.1 *)YUL_FINAL_KEYWORD = \"final\";
 
(* Reserved until 0.7.0 *)YUL_FINNEY_KEYWORD = \"finney\";
 
(* Reserved until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\";(* Reserved until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");(* Reserved until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
YUL_FOR_KEYWORD = \"for\";
 
YUL_FUNCTION_KEYWORD = \"function\";
 
YUL_GAS_KEYWORD = \"gas\";
 
YUL_GAS_LIMIT_KEYWORD = \"gaslimit\";
 
YUL_GAS_PRICE_KEYWORD = \"gasprice\";
 
YUL_GT_KEYWORD = \"gt\";
 
(* Reserved from 0.7.0 until 0.7.1 *)YUL_GWEI_KEYWORD = \"gwei\";
 
YUL_HEX_KEYWORD = \"hex\";
 
(* Reserved until 0.7.1 *)YUL_HOURS_KEYWORD = \"hours\";
 
YUL_IF_KEYWORD = \"if\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_IMMUTABLE_KEYWORD = \"immutable\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_IMPLEMENTS_KEYWORD = \"implements\";
 
(* Reserved until 0.7.1 *)YUL_IMPORT_KEYWORD = \"import\";
 
(* Reserved until 0.7.1 *)YUL_INDEXED_KEYWORD = \"indexed\";
 
(* Reserved until 0.6.8 *)YUL_IN_KEYWORD = \"in\";
 
(* Reserved until 0.7.1 *)YUL_INLINE_KEYWORD = \"inline\";
 
(* Reserved until 0.7.1 *)YUL_INTERFACE_KEYWORD = \"interface\";
 
(* Reserved until 0.7.1 *)YUL_INTERNAL_KEYWORD = \"internal\";
 
(* Reserved until 0.7.1 *)YUL_INT_KEYWORD = \"int\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
YUL_INVALID_KEYWORD = \"invalid\";
 
(* Reserved until 0.7.1 *)YUL_IS_KEYWORD = \"is\";
 
YUL_IS_ZERO_KEYWORD = \"iszero\";
 
(* Deprecated in 0.5.0 *)YUL_JUMP_KEYWORD = \"jump\";
 
(* Deprecated in 0.5.0 *)YUL_JUMPI_KEYWORD = \"jumpi\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_KECCAK_256_KEYWORD = \"keccak256\";
 
(* Introduced in 0.6.0 *)(* Reserved in 0.7.1 *)YUL_LEAVE_KEYWORD = \"leave\";
 
YUL_LET_KEYWORD = \"let\";
 
(* Reserved until 0.7.1 *)YUL_LIBRARY_KEYWORD = \"library\";
 
YUL_LOG_0_KEYWORD = \"log0\";
 
YUL_LOG_1_KEYWORD = \"log1\";
 
YUL_LOG_2_KEYWORD = \"log2\";
 
YUL_LOG_3_KEYWORD = \"log3\";
 
YUL_LOG_4_KEYWORD = \"log4\";
 
YUL_LT_KEYWORD = \"lt\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_MACRO_KEYWORD = \"macro\";
 
(* Reserved until 0.7.1 *)YUL_MAPPING_KEYWORD = \"mapping\";
 
(* Reserved until 0.7.1 *)YUL_MATCH_KEYWORD = \"match\";
 
(* Reserved until 0.7.1 *)YUL_MEMORY_KEYWORD = \"memory\";
 
(* Reserved until 0.7.1 *)YUL_MINUTES_KEYWORD = \"minutes\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_M_COPY_KEYWORD = \"mcopy\";
 
YUL_M_LOAD_KEYWORD = \"mload\";
 
YUL_MOD_KEYWORD = \"mod\";
 
(* Reserved until 0.7.1 *)YUL_MODIFIER_KEYWORD = \"modifier\";
 
YUL_M_SIZE_KEYWORD = \"msize\";
 
YUL_M_STORE_KEYWORD = \"mstore\";
 
YUL_M_STORE_8_KEYWORD = \"mstore8\";
 
YUL_MUL_KEYWORD = \"mul\";
 
YUL_MUL_MOD_KEYWORD = \"mulmod\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_MUTABLE_KEYWORD = \"mutable\";
 
(* Reserved until 0.7.1 *)YUL_NEW_KEYWORD = \"new\";
 
YUL_NOT_KEYWORD = \"not\";
 
(* Reserved until 0.7.1 *)YUL_NULL_KEYWORD = \"null\";
 
YUL_NUMBER_KEYWORD = \"number\";
 
(* Reserved until 0.7.1 *)YUL_OF_KEYWORD = \"of\";
 
YUL_OR_KEYWORD = \"or\";
 
YUL_ORIGIN_KEYWORD = \"origin\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_OVERRIDE_KEYWORD = \"override\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_PARTIAL_KEYWORD = \"partial\";
 
(* Reserved until 0.7.1 *)YUL_PAYABLE_KEYWORD = \"payable\";
 
YUL_POP_KEYWORD = \"pop\";
 
(* Reserved until 0.7.1 *)YUL_PRAGMA_KEYWORD = \"pragma\";
 
(* Introduced in 0.8.18 *)(* Reserved in 0.8.18 *)YUL_PREV_RANDAO_KEYWORD = \"prevrandao\";
 
(* Reserved until 0.7.1 *)YUL_PRIVATE_KEYWORD = \"private\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_PROMISE_KEYWORD = \"promise\";
 
(* Reserved until 0.7.1 *)YUL_PUBLIC_KEYWORD = \"public\";
 
(* Reserved until 0.7.1 *)YUL_PURE_KEYWORD = \"pure\";
 
(* Reserved from 0.6.0 until 0.7.1 *)YUL_RECEIVE_KEYWORD = \"receive\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_REFERENCE_KEYWORD = \"reference\";
 
(* Reserved until 0.7.1 *)YUL_RELOCATABLE_KEYWORD = \"relocatable\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_RETURN_DATA_COPY_KEYWORD = \"returndatacopy\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_RETURN_DATA_SIZE_KEYWORD = \"returndatasize\";
 
YUL_RETURN_KEYWORD = \"return\";
 
(* Reserved until 0.7.1 *)YUL_RETURNS_KEYWORD = \"returns\";
 
YUL_REVERT_KEYWORD = \"revert\";
 
(* Reserved in 0.4.21 *)YUL_SAR_KEYWORD = \"sar\";
 
YUL_S_DIV_KEYWORD = \"sdiv\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_SEALED_KEYWORD = \"sealed\";
 
(* Reserved until 0.7.1 *)YUL_SECONDS_KEYWORD = \"seconds\";
 
(* Reserved in 0.5.12 *)YUL_SELF_BALANCE_KEYWORD = \"selfbalance\";
 
YUL_SELF_DESTRUCT_KEYWORD = \"selfdestruct\";
 
YUL_SGT_KEYWORD = \"sgt\";
 
(* Deprecated in 0.5.0 *)(* Reserved until 0.5.0 *)YUL_SHA_3_KEYWORD = \"sha3\";
 
(* Reserved in 0.4.21 *)YUL_SHL_KEYWORD = \"shl\";
 
(* Reserved in 0.4.21 *)YUL_SHR_KEYWORD = \"shr\";
 
YUL_SIGN_EXTEND_KEYWORD = \"signextend\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_SIZE_OF_KEYWORD = \"sizeof\";
 
YUL_S_LOAD_KEYWORD = \"sload\";
 
YUL_SLT_KEYWORD = \"slt\";
 
YUL_S_MOD_KEYWORD = \"smod\";
 
YUL_S_STORE_KEYWORD = \"sstore\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_STATIC_CALL_KEYWORD = \"staticcall\";
 
(* Reserved until 0.7.1 *)YUL_STATIC_KEYWORD = \"static\";
 
YUL_STOP_KEYWORD = \"stop\";
 
(* Reserved until 0.7.1 *)YUL_STORAGE_KEYWORD = \"storage\";
 
(* Reserved until 0.7.1 *)YUL_STRING_KEYWORD = \"string\";
 
(* Reserved until 0.7.1 *)YUL_STRUCT_KEYWORD = \"struct\";
 
YUL_SUB_KEYWORD = \"sub\";
 
(* Deprecated in 0.5.0 *)(* Reserved until 0.5.0 *)YUL_SUICIDE_KEYWORD = \"suicide\";
 
YUL_SUPER_KEYWORD = \"super\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_SUPPORTS_KEYWORD = \"supports\";
 
YUL_SWITCH_KEYWORD = \"switch\";
 
(* Reserved until 0.7.0 *)YUL_SZABO_KEYWORD = \"szabo\";
 
YUL_TIMESTAMP_KEYWORD = \"timestamp\";
 
YUL_THIS_KEYWORD = \"this\";
 
(* Reserved until 0.7.1 *)YUL_THROW_KEYWORD = \"throw\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_T_LOAD_KEYWORD = \"tload\";
 
YUL_TRUE_KEYWORD = \"true\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_T_STORE_KEYWORD = \"tstore\";
 
(* Reserved until 0.7.1 *)YUL_TRY_KEYWORD = \"try\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_TYPE_DEF_KEYWORD = \"typedef\";
 
(* Reserved until 0.7.1 *)YUL_TYPE_KEYWORD = \"type\";
 
(* Reserved until 0.7.1 *)YUL_TYPE_OF_KEYWORD = \"typeof\";
 
(* Reserved until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\";(* Reserved until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");(* Reserved until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
(* Reserved until 0.7.1 *)YUL_UINT_KEYWORD = \"uint\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_UNCHECKED_KEYWORD = \"unchecked\";
 
(* Reserved until 0.7.1 *)YUL_USING_KEYWORD = \"using\";
 
(* Reserved until 0.6.5 *)YUL_VAR_KEYWORD = \"var\";
 
(* Reserved until 0.7.1 *)YUL_VIEW_KEYWORD = \"view\";
 
(* Reserved from 0.6.0 until 0.7.1 *)YUL_VIRTUAL_KEYWORD = \"virtual\";
 
(* Reserved until 0.7.1 *)YUL_WEEKS_KEYWORD = \"weeks\";
 
(* Reserved until 0.7.1 *)YUL_WEI_KEYWORD = \"wei\";
 
(* Reserved until 0.7.1 *)YUL_WHILE_KEYWORD = \"while\";
 
(* Reserved until 0.7.1 *)YUL_YEARS_KEYWORD = \"years\";
 
YUL_XOR_KEYWORD = \"xor\";
"},{"location":"solidity-specification/06-yul/03-yul-keywords/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"user-guide/","title":"User Guide","text":""},{"location":"user-guide/concepts/","title":"Concepts","text":"

At its core, Slang is a collection of APIs that are meant to analyze the source code, starting with the source code itself and ending with a rich structure that can be reasoned about. This is a departure from the classic approach of \"black-box\" compilers, which are handed the input and only their output can be observed.

"},{"location":"user-guide/concepts/#language-versions","title":"Language Versions","text":"

To use Slang, you start by initializing a Parser object with a specific version of the language. The earliest Solidity version we support is 0.4.11, and we plan on supporting all future versions as they are released.

From a Parser object, you can analyze any source text according to the nonterminals of that specific version. Providing an accurate language version is important, as it affects the shape of the syntax tree, and possible errors produced. You can use the LanguageFacts::supportedVersions() API to get a list of all supported versions for the current Slang release.

The Parser::parse() API is the main entry point for the parser, and to generate concrete syntax trees (CSTs) that can be used for further analysis. Each parse() operation accepts the input source code, and a NonterminalKind variant. This allows callers to parse entire source files (NonterminalKind::SourceUnit), individual contracts (NonterminalKind::ContractDefinition), methods (NonterminalKind::FunctionDefinition), or any other syntax nodes.

The resulting ParseOutput object will contain syntax errors (if any), and the syntax tree corresponding to the input source code.

"},{"location":"user-guide/concepts/#concrete-syntax-tree-cst","title":"Concrete Syntax Tree (CST)","text":"

Slang is capable of parsing the source code into a Concrete Syntax Tree (CST; also sometimes called \"full-fidelity\"), which is a tree structure of the program that also includes things like punctuation or whitespace.

This is done by using the (standard) approach of lexical analysis followed by syntax analysis. The source text as a sequence of characters is recognized into a sequence of terminals (lexical analysis), which then in turn is parsed into the CST.

The resulting CST is a regular tree data structure that you can visit. The tree nodes are represented by the Node structure, which can be one of two kinds:

"},{"location":"user-guide/concepts/#cst-cursors","title":"CST Cursors","text":"

For many code analysis tasks, it is useful to traverse the parse tree and visit each node. The Cursor object allows callers to traverse the parse tree in an efficient pre-order manner.

It provides several goTo*() navigation functions, each returning true if the cursor was successfully moved, and false otherwise. There are three main ways to do it:

As such, the cursor is stateful and keeps track of the path it has taken through the CST. It starts at the root it was created at and is completed when it reaches its root when navigating forward.

"},{"location":"user-guide/concepts/#cst-queries","title":"CST Queries","text":"

The Cursor API is a low-level API that allows you to traverse the CST in a procedural manner. However, it is often more convenient to use the declarative Query API. Queries allow you to express your intent more concisely, and also allows you to reuse the same query in multiple places. Queries can largely replace the need for both internal (cursor), and external (visitor) iterator patterns.

The query language is based on pattern matching, and the execution semantics are closer to unification than to regular expression matching i.e. a query returns all possible matches, not just the longest/shortest/first/last match. There is no concept of a 'greedy' operator for example.

Query execution is based on Cursors, and the resulting matches and unification captures are returned as Cursors as well. This allows you to mix and match manual traversal, cursors, and queries.

Multiple queries can be executed in a batch, and efficiently traverse the tree looking for matches. This mode of operation can replace all visitor patterns.

"},{"location":"user-guide/concepts/#abstract-syntax-tree-ast","title":"Abstract Syntax Tree (AST)","text":"

AST types are a set of abstractions that provide a typed view of the untyped CST nodes. You can convert any untyped CST node to its corresponding AST type using their constructors.

There is a corresponding type for each NonterminalKind in the language. AST types are immutable. Additionally, their fields are constructed lazily as they are accessed for the first time.

AST nodes maintain a reference to the CST node they were constructed from, and can be used to navigate to the corresponding CST node.

"},{"location":"user-guide/introduction/","title":"Introduction","text":"

Welcome to the Slang user guide! This aims to be an introduction to Slang itself, its concepts and also contains a collection of guides how you can achieve basic tasks with it.

"},{"location":"user-guide/introduction/#what-is-slang","title":"What is Slang?","text":"

Slang is intended to be a modular Solidity compiler, specifically targeting code analysis and developer tooling. This means servicing tools with domain-specific APIs and, in general, facilitating working with and analyzing the Solidity source code. If you're in the editor writing Solidity or performing linting or additional validation, there's a chance that you are, or could be, running Slang!

To get a good grasp on the concepts used in Slang, see the Concepts section.

"},{"location":"user-guide/introduction/#what-slang-is-not","title":"What Slang is not?","text":"

First and foremost, it is not a replacement for solc, the standard Solidity compiler. We do not plan at the moment to support emitting optimized EVM bytecode for use in production. Secondly, it does not perform formal verification of contracts or Solidity logic in general. However, other tools that serve this purpose are intended to be built on top of it.

"},{"location":"user-guide/introduction/#supporting-multiple-versions","title":"Supporting multiple versions","text":"

The Solidity programming language has evolved quite a bit since its inception. Some features were introduced, some changed, while some eventually became obsolete and were removed altogether.

While it's good for a programming language to evolve and better serve the needs of its users, not being able to easily upgrade or re-deploy existing contracts poses a unique challenge. Developer tooling must be able to understand and consume older contracts that are still being used on the blockchain, written in older versions of Solidity.

Because of that, Slang must be able to reason about different versions of Solidity; how the language grammar, name capture rules, and semantics have changed across different versions. One of our goals is to document differences as part of our Solidity Specification.

This is why, instead of having to download separate versions of the tool for each Solidity version, you can access the Slang language APIs by simply specifying the Solidity version that you want to work with.

"},{"location":"user-guide/introduction/#distributions","title":"Distributions","text":"

Slang itself is written in Rust, compiled as a WASM component, and distributed as an npm package with a TypeScript interface. In the future, we are also looking into publishing it as a Rust crate, a Python library, and possibly more.

"},{"location":"user-guide/tree-query-language/","title":"The Tree Query Language","text":""},{"location":"user-guide/tree-query-language/#query-syntax","title":"Query Syntax","text":"

A query is a pattern that matches a certain set of nodes in a tree. The expression to match a given node consists of a pair of brackets ([]) containing two things: the node's kind, and optionally, a series of other patterns that match the node's children. For example, this pattern would match any MultiplicativeExpression node that has two children Expression nodes, with an Asterisk node in between:

[MultiplicativeExpression [Expression] [Asterisk] [Expression]]\n

The children of a node can optionally be labeled. The label is a property of the edge from the node to the child, and is not a property of the child. For example, this pattern will match a MultiplicativeExpression node with the two Expression children labeled left_operand and right_operand:

[MultiplicativeExpression left_operand:[Expression] [Asterisk] right_operand:[Expression]]\n

You can also match a node's textual content using a string literal. For example, this pattern would match a MultiplicativeExpression with a * operator (for clarity):

[MultiplicativeExpression left_operand:[_] operator:[\"*\"] right_operand:[_]]\n

If you don't care about the kind of a node, you can use an underscore _, which matches any kind. For example, this pattern will match a MultiplicativeExpression node with two children, one of any kind labeled left_operand and one of any kind:

[MultiplicativeExpression left_operand:[_] [_]]\n

Children can be elided. For example, this would produce multiple matches for a MultiplicativeExpression where at least one of the children is an expression of a StringExpression variant, where each match is associated with each of the StringExpression children:

[MultiplicativeExpression [Expression [StringExpression]]]\n

Trivia nodes (whitespace, comments, etc.) will be skipped over when running a query. Furthermore, trivia nodes cannot be explicitly (or implicitly with _) matched by queries.

"},{"location":"user-guide/tree-query-language/#capturing-nodes","title":"Capturing Nodes","text":"

When matching patterns, you may want to process specific nodes within the pattern. Captures allow you to associate names with specific nodes in a pattern, so that you can later refer to those nodes by those names. Capture names are written before the nodes that they refer to, and start with an @ character.

For example, this pattern would match any struct definition and it would associate the name struct_name with the identifier:

[StructDefinition @struct_name name:[Identifier]]\n

And this pattern would match all event definitions for a contract, associating the name event_name with the event name, contract_name with the containing contract name:

[ContractDefinition\n    @contract_name name:[Identifier]\n    members:[ContractMembers\n        [ContractMember\n            [EventDefinition @event_name name:[Identifier]]\n        ]\n    ]\n]\n
"},{"location":"user-guide/tree-query-language/#quantification","title":"Quantification","text":"

You can surround a sequence of patterns in parenthesis (()), followed by a ?, * or + operator. The ? operator matches zero or one repetitions of a pattern, the * operator matches zero or more, and the + operator matches one or more.

For example, this pattern would match a sequence of one or more import directives at the top of the file:

[SourceUnit members:[_ ([_ @import [ImportDirective]])+]]\n

This pattern would match a structure definition with one or more members, capturing their names:

[StructDefinition\n    @name name:[_]\n    members:[_ ([_ @member [Identifier]])+]\n]\n

This pattern would match all function calls, capturing a string argument if one was present:

[FunctionCallExpression\n    arguments:[ArgumentsDeclaration\n        variant:[PositionalArgumentsDeclaration\n            arguments:[PositionalArguments\n                (@arg [Expression variant:[StringExpression]])?\n            ]\n        ]\n    ]\n]\n
"},{"location":"user-guide/tree-query-language/#alternations","title":"Alternations","text":"

An alternation is written as a sequence of patterns separated by | and surrounded by parentheses.

For example, this pattern would match a call to either a variable or an object property. In the case of a variable, capture it as @function, and in the case of a property, capture it as @method:

[FunctionCallExpression\n    operand:[Expression\n        (@function variant:[Identifier]\n        | @method variant:[MemberAccessExpression])\n    ]\n]\n

This pattern would match a set of possible keyword terminals, capturing them as @keyword:

@keyword (\n    [\"break\"]\n  | [\"delete\"]\n  | [\"else\"]\n  | [\"for\"]\n  | [\"function\"]\n  | [\"if\"]\n  | [\"return\"]\n  | [\"try\"]\n  | [\"while\"]\n)\n
"},{"location":"user-guide/tree-query-language/#adjacency","title":"Adjacency","text":"

By using the adjacency operator . you can constrain a pattern to only match the first or the last child nodes.

For example, the following pattern would match only the first parameter declaration in a function definition:

[FunctionDefinition\n    [ParametersDeclaration\n        [Parameters . @first_param [Parameter]]\n    ]\n]\n

And conversely the following will match only the last parameter:

[FunctionDefinition\n    [ParametersDeclaration\n        [Parameters @last_param [Parameter] .]\n    ]\n]\n

If the adjacency operator is used in between two patterns it constrains matches on both patterns to occur consecutively, ie. without any other sibling node in between. For example, this pattern matches pairs of consecutive statements:

[Statements @stmt1 [Statement] . @stmt2 [Statement]]\n
"},{"location":"user-guide/npm-package/","title":"NPM Package","text":""},{"location":"user-guide/npm-package/installation/","title":"Installation","text":"

You can install Slang NPM package simply by running the following npm command:

npm install \"@nomicfoundation/slang\"\n

Or if you are using yarn for package management:

yarn add \"@nomicfoundation/slang\"\n
"},{"location":"user-guide/npm-package/using-queries/","title":"Using Queries","text":"

It's often more convenient to use the declarative Query API to traverse the CST, as they allow you to express your intent more concisely and can largely replace the need for both internal (cursor), and external (visitor) iterator patterns.

The Tree Query Language is based on pattern matching, and the execution semantics are closer to unification than to regular expression matching. A query returns all possible matches, not just the longest/shortest/first/last match.

If not specified otherwise, let's assume we already parsed a Solidity source and have a cursor pointing to the root node of the CST (created with createTreeCursor, see Using the Cursor).

"},{"location":"user-guide/npm-package/using-queries/#creating-and-executing-queries","title":"Creating and executing queries","text":"

You can create a Query object using Query.parse, which accepts a string value. These can be then used by Cursor.query to execute it.

You can pass multiple queries to a cursor to and efficiently traverse the tree looking for matches. They will be executed concurrently, returning matches in the order they appear in input.

// Any `Cursor` can be used to create a query.\nconst cursor = parseOutput.createTreeCursor();\n\nconst query = Query.parse(\"[ContractDefinition]\");\nconst matches: QueryMatchIterator = cursor.query([query]);\n
"},{"location":"user-guide/npm-package/using-queries/#iterating-over-node-patterns","title":"Iterating over node patterns","text":"

Queries allow you to iterate over all node patterns that match the query, which can replace your need for manual iteration via cursors or visitors. In order to get a Cursor that points to the matched node, you need to capture them with a name capture (@capture_name) to a specific node in the query pattern.

Let's use this to list all the contract definitions in the source file:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
const found = [];\n\nconst query = Query.parse(\"@contract [ContractDefinition]\");\nconst matches = cursor.query([query]);\n\nfor (const match of matches) {\n  const cursor = match.captures[\"contract\"]![0]!;\n\n  assertIsNonterminalNode(cursor.node);\n  found.push(cursor.node.unparse().trim());\n}\n\nassert.deepStrictEqual(found, [\"contract Foo {}\", \"contract Bar {}\", \"contract Baz {}\"]);\n
"},{"location":"user-guide/npm-package/using-queries/#multiple-patterns-simultaneously","title":"Multiple patterns simultaneously","text":"

We can also intersperse multiple patterns in a single query, which will return all the matches for each pattern. This can be useful when you want to match multiple types of nodes in a single pass.

const names = [];\n\nconst structDefinition = Query.parse(\"[StructDefinition @name [Identifier]]\");\nconst enumDefinition = Query.parse(\"[EnumDefinition @name [Identifier]]\");\nconst matches = cursor.query([structDefinition, enumDefinition]);\n\nfor (const match of matches) {\n  const index = match.queryNumber;\n  const cursor = match.captures[\"name\"]![0]!;\n\n  names.push([index, cursor.node.unparse()]);\n}\n\nassert.deepStrictEqual(names, [\n  [0, \"Foo\"],\n  [1, \"Bar\"],\n  [0, \"Baz\"],\n  [1, \"Qux\"],\n]);\n
"},{"location":"user-guide/npm-package/using-queries/#matching-on-nodes-label","title":"Matching on node's label","text":"

We can match not only on the node's kind, but also on its label. This can be useful if there may be two children with the same kind but different labels or to be more declarative.

To do so, we use [label: _] syntax. Here, we also use _ to allow matching any kind of node, as long as it matches the given label.

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
const names = [];\n\nconst query = Query.parse(\"[TypedTupleMember @type type_name:[_]]\");\nconst matches = cursor.query([query]);\n\nfor (const match of matches) {\n  const cursor = match.captures[\"type\"]![0]!;\n\n  names.push(cursor.node.unparse());\n}\n\nassert.deepStrictEqual(names, [\"uint\", \" uint16\", \" uint64\", \" uint256\"]);\n
"},{"location":"user-guide/npm-package/using-queries/#matching-on-nodes-literal-content","title":"Matching on node's literal content","text":"

Lastly, we can also match on the node's literal content. This can be useful when you want to match a specific identifier, string, or number.

Let's say we prefer our code to be explicit and prefer using uint256 instead of uint. To find all instances of the uint alias we could do the following:

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
const names = [];\n\nconst query = Query.parse(`[ElementaryType @uint_keyword variant:[\"uint\"]]`);\nconst matches = cursor.query([query]);\n\nfor (const match of matches) {\n  const cursor = match.captures[\"uint_keyword\"]![0]!;\n\n  names.push(cursor.node.unparse());\n}\n\nassert.deepStrictEqual(names, [\"uint\"]);\n
"},{"location":"user-guide/npm-package/using-queries/#example-finding-txorigin-patterns","title":"Example: Finding tx.origin patterns","text":"

As a more realistic example, let's say we want to write a linter that unconditionally lints against all tx.origin accesses.

Let's use the motivating example from https://soliditylang.org:

input.sol
// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.0 <0.9.0;\n// THIS CONTRACT CONTAINS A BUG - DO NOT USE\ncontract TxUserWallet {\n    address owner;\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    function transferTo(address payable dest, uint amount) public {\n        // THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin\n        require(tx.origin == owner);\n        dest.transfer(amount);\n    }\n}\n

Now, we can above features to write a query that matches all tx.origin patterns:

const query = Query.parse(`\n@txorigin [MemberAccessExpression\n  [Expression @start [\"tx\"]]\n  [\"origin\"]\n]`);\n\nconst matches = cursor.query([query]);\nconst found = [];\n\nfor (const match of matches) {\n  const cursor = match.captures[\"txorigin\"]![0]!;\n\n  found.push([cursor.textOffset.utf8, cursor.node.unparse()]);\n}\n\nassert.deepStrictEqual(found, [[375, \"tx.origin\"]]);\n
"},{"location":"user-guide/npm-package/using-the-ast/","title":"Using the AST","text":"

Let's try to analyze the following Solidity source file, containing a simple function:

input.sol
function add(uint256 a, uint256 b) public pure returns (uint256) {\n    return a + b;\n}\n

We start as usual by parsing the input, and then we can use the ParseOutput root to create the CST type. Since it is a node of kind FunctionDefinition, we are using the AST type of the same name to analyze it:

import assert from \"node:assert\";\nimport { Parser } from \"@nomicfoundation/slang/parser\";\nimport { NonterminalKind } from \"@nomicfoundation/slang/cst\";\nimport { FunctionDefinition } from \"@nomicfoundation/slang/ast\";\n\nconst parser = Parser.create(\"0.8.0\");\n\nconst parseOutput = parser.parse(NonterminalKind.FunctionDefinition, source);\n

The FunctionDefinition type has named fields to access all its children. For example, we can check the name of the function:

const $function = new FunctionDefinition(parseOutput.tree.asNonterminalNode()!);\n\nassert.equal($function.name.variant.unparse(), \"add\");\n

We can also list its parameters:

const parameters = $function.parameters.parameters.items.map((parameter) => {\n  return parameter.name!.unparse();\n});\n\nassert.deepEqual(parameters, [\"a\", \"b\"]);\n

Or attributes:

const attributes = $function.attributes.items.map((attribute) => {\n  return attribute.cst.unparse().trim();\n});\n\nassert.deepEqual(attributes, [\"public\", \"pure\"]);\n
"},{"location":"user-guide/npm-package/using-the-cursor/","title":"Using the Cursor","text":"

This guide will walk you through the basics of using a CST cursor in your project. Let's start with this source file, that contains three contracts:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
import assert from \"node:assert\";\nimport { Parser } from \"@nomicfoundation/slang/parser\";\nimport { assertIsTerminalNode, NonterminalKind, TerminalKind } from \"@nomicfoundation/slang/cst\";\n\nconst parser = Parser.create(\"0.8.0\");\n\nconst parseOutput = parser.parse(NonterminalKind.SourceUnit, source);\n
"},{"location":"user-guide/npm-package/using-the-cursor/#listing-contract-names","title":"Listing Contract Names","text":"

The below example uses a cursor to list the names of all contracts in a source file:

const contracts = [];\n\nconst cursor = parseOutput.createTreeCursor();\n\nwhile (cursor.goToNextNonterminalWithKind(NonterminalKind.ContractDefinition)) {\n  assert(cursor.goToFirstChild());\n  assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier));\n\n  assertIsTerminalNode(cursor.node);\n  contracts.push(cursor.node.unparse());\n\n  assert(cursor.goToParent());\n}\n\nassert.deepStrictEqual(contracts, [\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/npm-package/using-the-cursor/#visiting-only-a-sub-tree","title":"Visiting Only a Sub-tree","text":"

In cases like the above, we needed to visit a sub-tree of the CST (to get the contract name). But we also need to remember to return the cursor to its original position after each read, which is inconvenient, and can lead to subtle bugs.

To avoid this, we can use the spawn() API, which cheaply creates a new cursor that starts at the given node, without copying the previous path history. This lets us visit the sub-tree of each contract, without modifying the original cursor:

const contracts = [];\n\nconst cursor = parseOutput.createTreeCursor();\n\nwhile (cursor.goToNextNonterminalWithKind(NonterminalKind.ContractDefinition)) {\n  const childCursor = cursor.spawn();\n  assert(childCursor.goToNextTerminalWithKind(TerminalKind.Identifier));\n\n  assertIsTerminalNode(childCursor.node);\n  contracts.push(childCursor.node.unparse());\n}\n\nassert.deepStrictEqual(contracts, [\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/npm-package/using-the-cursor/#accessing-node-positions","title":"Accessing Node Positions","text":"

The Cursor API also tracks the position and range of the current node it is visiting. Here is an example that records the source range of each contract, along with its text:

const contracts = [];\n\nconst cursor = parseOutput.createTreeCursor();\n\nwhile (cursor.goToNextNonterminalWithKind(NonterminalKind.ContractDefinition)) {\n  const range = cursor.textRange;\n\n  const contractNode = cursor.node;\n\n  contracts.push([\n    range.start.line,\n    range.start.column,\n    range.end.line,\n    range.end.column,\n    contractNode.unparse().trim(),\n  ]);\n}\n\nassert.deepStrictEqual(contracts, [\n  [0, 0, 1, 0, \"contract Foo {}\"],\n  [1, 0, 2, 0, \"contract Bar {}\"],\n  [2, 0, 2, 15, \"contract Baz {}\"],\n]);\n
"},{"location":"user-guide/npm-package/using-the-parser/","title":"Using the Parser","text":"

Using the API directly provides us with a more fine-grained control over the parsing process. It allows us to parse not just the input as a top-level source unit, but also individual constructs like contracts, various definitions, and even expressions.

"},{"location":"user-guide/npm-package/using-the-parser/#parsing-source-files","title":"Parsing Source Files","text":"

Let's start with this simple source file, that contains a single contract:

input.sol
contract Foo {}\n

We begin by creating a Parser object with a specified version. This is an entry point for our parser API. Then we can use it to parse the source file, specifying the top-level nonterminal to parse:

import assert from \"node:assert\";\nimport { Parser } from \"@nomicfoundation/slang/parser\";\nimport {\n  assertIsNonterminalNode,\n  assertIsTerminalNode,\n  NonterminalKind,\n  TerminalKind,\n} from \"@nomicfoundation/slang/cst\";\n\nconst parser = Parser.create(\"0.8.0\");\n\nconst parseOutput = parser.parse(NonterminalKind.ContractDefinition, source);\n
"},{"location":"user-guide/npm-package/using-the-parser/#checking-for-syntax-errors","title":"Checking for Syntax Errors","text":"

If the file has errors, we can get them from the ParseOutput type, and print them out:

for (const error of parseOutput.errors()) {\n  console.error(`Error at byte offset ${error.textRange.start.utf8}: ${error.message}`);\n}\n

Otherwise, we can check if input is valid using this helpful utility:

assert(parseOutput.isValid());\n
"},{"location":"user-guide/npm-package/using-the-parser/#inspecting-the-parse-tree","title":"Inspecting the Parse Tree","text":"

Now, let's try to inspect the resulting CST, and iterate on its children:

const contract = parseOutput.tree;\nassertIsNonterminalNode(contract, NonterminalKind.ContractDefinition);\n\nconst contractChildren = contract.children();\nassert.equal(contractChildren.length, 7);\n\nconst [contractKeyword, firstSpace, contractName, secondSpace, openBrace, members, closeBrace] = contractChildren;\n\nassertIsTerminalNode(contractKeyword!.node, TerminalKind.ContractKeyword, \"contract\");\nassertIsTerminalNode(firstSpace!.node, TerminalKind.Whitespace, \" \");\nassertIsTerminalNode(contractName!.node, TerminalKind.Identifier, \"Foo\");\nassertIsTerminalNode(secondSpace!.node, TerminalKind.Whitespace, \" \");\nassertIsTerminalNode(openBrace!.node, TerminalKind.OpenBrace, \"{\");\nassertIsNonterminalNode(members!.node, NonterminalKind.ContractMembers);\nassertIsTerminalNode(closeBrace!.node, TerminalKind.CloseBrace, \"}\");\n

Additionally, we can convert the CST node back into the input string:

const contractSource = contract.unparse();\nassert.equal(contractSource, \"contract Foo {}\");\n
"},{"location":"user-guide/rust-crate/","title":"Rust Crate","text":""},{"location":"user-guide/rust-crate/installation/","title":"Installation","text":"

The Rust package is published to crates.io as slang_solidity (docs). It can be used both as a regular Rust dependency and as a standalone CLI (installable with Cargo).

You can install the CLI as a cargo binary using:

cargo install \"slang_solidity_cli\"\n

Or you can add the API as a dependency to your project:

cargo add \"slang_solidity\"\n
"},{"location":"user-guide/rust-crate/using-queries/","title":"Using Queries","text":"

It's often more convenient to use the declarative Query API to traverse the CST, as they allow you to express your intent more concisely and can largely replace the need for both internal (cursor), and external (visitor) iterator patterns.

The query language is based on pattern matching, and the execution semantics are closer to unification than to regular expression matching. A query returns all possible matches, not just the longest/shortest/first/last match.

If not specified otherwise, let's assume we already parsed a Solidity source and have a cursor pointing to the root node of the CST (created with create_tree_cursor, see Using the Cursor).

"},{"location":"user-guide/rust-crate/using-queries/#creating-and-executing-queries","title":"Creating and executing queries","text":"

You can create a Query struct using Query::parse, which accepts a &str. These can be then used by Cursor::query to execute it.

You can pass multiple queries to a cursor to and efficiently traverse the tree looking for matches. They will be executed concurrently, returning matches in the order they appear in input.

use slang_solidity::cst::Query;\n\n// Any `Cursor` can be used to create a query.\nlet cursor = parse_output.create_tree_cursor();\n\nlet query = Query::parse(\"[ContractDefinition]\").unwrap();\nlet result: QueryMatchIterator = cursor.query(vec![query]);\n
"},{"location":"user-guide/rust-crate/using-queries/#iterating-over-node-patterns","title":"Iterating over node patterns","text":"

Queries allow you to iterate over all node patterns that match the query, which can replace your need for manual iteration via cursors or visitors. In order to get a Cursor that points to the matched node, you need to capture them with a name capture (@capture_name) to a specific node in the query pattern.

Let's use this to list all the contract definitions in the source file:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
let mut found = vec![];\n\nlet query = Query::parse(\"@contract [ContractDefinition]\").unwrap();\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"contract\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    found.push(cursor.node().unparse().trim().to_owned());\n}\n\nassert_eq!(\n    found,\n    [\"contract Foo {}\", \"contract Bar {}\", \"contract Baz {}\"]\n);\n
"},{"location":"user-guide/rust-crate/using-queries/#multiple-patterns-simultaneously","title":"Multiple patterns simultaneously","text":"

We can also intersperse multiple patterns in a single query, which will return all the matches for each pattern. This can be useful when you want to match multiple types of nodes in a single pass.

let mut names = vec![];\n\nlet struct_def = Query::parse(\"[StructDefinition @name [Identifier]]\").unwrap();\nlet enum_def = Query::parse(\"[EnumDefinition @name [Identifier]]\").unwrap();\n\nfor r#match in cursor.query(vec![struct_def, enum_def]) {\n    let index = r#match.query_number;\n    let captures = r#match.captures;\n    let cursors = captures.get(\"name\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    names.push((index, cursor.node().unparse()));\n}\n\nassert_eq!(\n    names,\n    &[\n        (0, \"Foo\".to_string()),\n        (1, \"Bar\".to_string()),\n        (0, \"Baz\".to_string()),\n        (1, \"Qux\".to_string())\n    ]\n);\n
"},{"location":"user-guide/rust-crate/using-queries/#matching-on-nodes-label","title":"Matching on node's label","text":"

We can match not only on the node's kind, but also on its label. This can be useful if there may be two children with the same kind but different labels or to be more declarative.

To do so, we use [label: _] syntax. Here, we also use _ to allow matching any kind of node, as long as it matches the given label.

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
let mut names = vec![];\n\nlet query = Query::parse(\"[TypedTupleMember @type type_name:[_]]\").unwrap();\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"type\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    names.push(cursor.node().unparse());\n}\n\nassert_eq!(names, &[\"uint\", \" uint16\", \" uint64\", \" uint256\"]);\n
"},{"location":"user-guide/rust-crate/using-queries/#matching-on-nodes-literal-content","title":"Matching on node's literal content","text":"

Lastly, we can also match on the node's literal content. This can be useful when you want to match a specific identifier, string, or number.

Let's say we prefer our code to be explicit and prefer using uint256 instead of uint. To find all instances of the uint alias we could do the following:

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
let mut names = vec![];\n\nlet query = Query::parse(r#\"[ElementaryType @uint_keyword variant:[\"uint\"]]\"#).unwrap();\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"uint_keyword\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    names.push(cursor.node().unparse());\n}\n\nassert_eq!(names, &[\"uint\"]);\n
"},{"location":"user-guide/rust-crate/using-queries/#example-finding-txorigin-patterns","title":"Example: Finding tx.origin patterns","text":"

As a more realistic example, let's say we want to write a linter that unconditionally lints against all tx.origin accesses.

Let's use the motivating example from https://soliditylang.org:

input.sol
// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.0 <0.9.0;\n// THIS CONTRACT CONTAINS A BUG - DO NOT USE\ncontract TxUserWallet {\n    address owner;\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    function transferTo(address payable dest, uint amount) public {\n        // THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin\n        require(tx.origin == owner);\n        dest.transfer(amount);\n    }\n}\n

Now, we can above features to write a query that matches all tx.origin patterns:

let query = Query::parse(\n    r#\"@txorigin [MemberAccessExpression\n            [Expression @start [\"tx\"]]\n            [\"origin\"]\n        ]\"#,\n)\n.unwrap();\n\nlet mut results = vec![];\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"txorigin\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    results.push((cursor.text_offset().utf8, cursor.node().unparse()));\n}\n\nassert_eq!(results, &[(375usize, \"tx.origin\".to_string())]);\n
"},{"location":"user-guide/rust-crate/using-the-cli/","title":"Using the CLI","text":""},{"location":"user-guide/rust-crate/using-the-cli/#parsing-source-files","title":"Parsing Source Files","text":"

The parse command will take a path to a Solidity file, and a --version flag. Specifying the correct version is important, as it will affect the grammar used to parse inputs.

All parse errors are printed in a human-readable format; the command will succeed if there are no parse errors, and fail otherwise.

$ slang_solidity parse --help\n\nUsage: slang_solidity parse [OPTIONS] --version <VERSION> <FILE_PATH>\n\nArguments:\n  <FILE_PATH>\n          File path to the Solidity (*.sol) source file to parse\n\nOptions:\n  -v, --version <VERSION>\n          The Solidity language version to use for parsing\n      --json\n          Print the concrete syntax tree as JSON\n  -h, --help\n          Print help\n

Here is an example of the JSON output it can print:

// A Nonterminal node\n\"Nonterminal\": {\n  // Name of the nonterminal kind\n  \"kind\": \"SourceUnit\",\n  // Length of the nonterminal in Unicode code points, depending on the encoding used\n  \"text_len\": {\n    \"utf8\": 24,\n    \"utf16\": 24,\n    \"char\": 24 // de facto utf32\n  },\n  \"children\": [/* Nonterminal or Terminal nodes */]\n}\n// A Terminal node\n\"Terminal\": {\n  // Name of the terminal kind\n  \"kind\": \"PragmaKeyword\",\n  // Literal value, taken from the source code\n  \"text\": \"pragma\"\n}\n
"},{"location":"user-guide/rust-crate/using-the-cli/#inspecting-json-output","title":"Inspecting JSON Output","text":"

Now let's try to use that command to parse the following Solidity file, and inspect its contents:

input.sol
pragma solidity ^0.8.0;\n
slang_solidity parse --json --version \"0.8.0\" \"input.sol\" > \"output.json\"\n

Because the resulting structure is well-defined and recursive, we can use the popular jq tool to quickly analyze the resulting output:

JQ_QUERY='recurse | select(.Terminal?) | .Terminal'\ncat output.json | jq \"$JQ_QUERY\"\n

This gives us a flat list of the Terminal nodes:

{\n  \"kind\": \"PragmaKeyword\",\n  \"text\": \"pragma\"\n}\n{\n  \"kind\": \"Whitespace\",\n  \"text\": \" \"\n}\n{\n  \"kind\": \"SolidityKeyword\",\n  \"text\": \"solidity\"\n}\n{\n  \"kind\": \"Whitespace\",\n  \"text\": \" \"\n}\n{\n  \"kind\": \"Caret\",\n  \"text\": \"^\"\n}\n{\n  \"kind\": \"VersionPragmaValue\",\n  \"text\": \"0\"\n}\n{\n  \"kind\": \"Period\",\n  \"text\": \".\"\n}\n{\n  \"kind\": \"VersionPragmaValue\",\n  \"text\": \"8\"\n}\n{\n  \"kind\": \"Period\",\n  \"text\": \".\"\n}\n{\n  \"kind\": \"VersionPragmaValue\",\n  \"text\": \"0\"\n}\n{\n  \"kind\": \"Semicolon\",\n  \"text\": \";\"\n}\n{\n  \"kind\": \"EndOfLine\",\n  \"text\": \"\\n\"\n}\n

Now, we can adapt the query to select the text fields of the nodes and concatenate them, which gives us back the reconstructed source code! \ud83c\udf89

$ JQ_QUERY='[recurse | select(.Terminal?) | .Terminal.text] | join(\"\")'\n$ cat output.json | jq \"$JQ_QUERY\"\n\n\"pragma solidity ^0.8.0;\\n\"\n
"},{"location":"user-guide/rust-crate/using-the-cursor/","title":"Using the Cursor","text":"

This guide will walk you through the basics of using a CST cursor in your project. Let's start with this source file, that contains three contracts:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
use semver::Version;\nuse slang_solidity::cst::{EdgeLabel, NonterminalKind, TerminalKind, TextRangeExtensions};\nuse slang_solidity::parser::Parser;\n\nlet parser = Parser::create(Version::parse(\"0.8.0\")?)?;\n\nlet parse_output = parser.parse(NonterminalKind::SourceUnit, source);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#listing-contract-names","title":"Listing Contract Names","text":"

The below example uses a cursor to list the names of all contracts in a source file:

let mut contracts = Vec::new();\n\nlet mut cursor = parse_output.create_tree_cursor();\n\nwhile cursor.go_to_next_nonterminal_with_kind(NonterminalKind::ContractDefinition) {\n    assert!(cursor.go_to_first_child());\n    assert!(cursor.go_to_next_terminal_with_kind(TerminalKind::Identifier));\n\n    let terminal_node = cursor.node();\n    contracts.push(terminal_node.as_terminal().unwrap().text.clone());\n\n    // You have to make sure you return the cursor to its original position:\n    assert!(cursor.go_to_parent());\n}\n\nassert_eq!(contracts, &[\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#visiting-only-a-sub-tree","title":"Visiting Only a Sub-tree","text":"

In cases like the above, we needed to visit a sub-tree of the CST (to get the contract name). But we also need to remember to return the cursor to its original position after each read, which is inconvenient, and can lead to subtle bugs.

To avoid this, we can use the spawn() API, which cheaply creates a new cursor that starts at the given node, without copying the previous path history. This lets us visit the sub-tree of each contract, without modifying the original cursor:

let mut contracts = Vec::new();\n\nlet mut cursor = parse_output.create_tree_cursor();\n\nwhile cursor.go_to_next_nonterminal_with_kind(NonterminalKind::ContractDefinition) {\n    let mut child_cursor = cursor.spawn();\n    assert!(child_cursor.go_to_next_terminal_with_kind(TerminalKind::Identifier));\n\n    let terminal_node = child_cursor.node();\n    contracts.push(terminal_node.as_terminal().unwrap().text.clone());\n}\n\nassert_eq!(contracts, &[\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#accessing-node-positions","title":"Accessing Node Positions","text":"

The Cursor API also tracks the position and range of the current node it is visiting. Here is an example that records the source range of each contract, along with its text:

let mut contracts = Vec::new();\n\nlet mut cursor = parse_output.create_tree_cursor();\n\nwhile cursor.go_to_next_nonterminal_with_kind(NonterminalKind::ContractDefinition) {\n    let range = cursor.text_range().utf8();\n    let text = cursor.node().unparse();\n\n    contracts.push((range, text.trim().to_owned()));\n}\n\nassert_eq!(\n    contracts,\n    &[\n        (0..16, \"contract Foo {}\".to_string()),\n        (16..32, \"contract Bar {}\".to_string()),\n        (32..47, \"contract Baz {}\".to_string()),\n    ]\n);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#using-iterator-api","title":"Using Iterator API","text":"

In addition to the procedural-style methods, the Cursor struct also implements the Iterator trait, which allows you to use it in a functional style.

Let's use that to extract all Identifier nodes from the source text using that API:

let identifiers: Vec<_> = parse_output\n    .tree()\n    .clone()\n    .descendants()\n    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))\n    .map(|identifier| identifier.unparse())\n    .collect();\n\nassert_eq!(identifiers, &[\"Foo\", \"Bar\", \"Baz\"]);\n

Note

It's important to note that Iterator::next first visits the current node, yields it, and then moves the cursor to the next node. As such, accessor associated functions called on the Cursor that reference the \"current\" will point to the one that is not yet yielded by the iterator. This might be an important, when mixing the two styles.

"},{"location":"user-guide/rust-crate/using-the-cursor/#using-a-cursor-with-labels","title":"Using a Cursor with Labels","text":"

The cursor also keeps track of the labels of the nodes it visits. Let's use that to extract all nodes that are labeled Name:

let identifiers: Vec<_> = parse_output\n    .tree()\n    .clone()\n    .descendants()\n    .filter(|edge| edge.label == Some(EdgeLabel::Name))\n    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))\n    .map(|identifier| identifier.unparse())\n    .collect();\n\nassert_eq!(identifiers, &[\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/rust-crate/using-the-parser/","title":"Using the Parser","text":"

Using the API directly provides us with a more fine-grained control over the parsing process. It allows us to parse not just the input as a top-level source unit, but also individual nonterminals like contracts, various definitions, and even expressions.

"},{"location":"user-guide/rust-crate/using-the-parser/#parsing-source-files","title":"Parsing Source Files","text":"

Let's start with this simple source file, that contains a single contract:

input.sol
contract Foo {}\n

We begin by creating a Parser object with a specified version. This is an entry point for our parser API. Then we can use it to parse the source file, specifying the top-level nonterminal to parse:

use semver::Version;\nuse slang_solidity::cst::{Node, NonterminalKind, TerminalKind};\nuse slang_solidity::parser::Parser;\n\nlet parser = Parser::create(Version::parse(\"0.8.0\")?)?;\n\nlet parse_output = parser.parse(NonterminalKind::ContractDefinition, source);\n
"},{"location":"user-guide/rust-crate/using-the-parser/#checking-for-syntax-errors","title":"Checking for Syntax Errors","text":"

If the file has errors, we can get them from the ParseOutput type, and print them out:

for error in parse_output.errors() {\n    eprintln!(\n        \"Error at byte offset {offset}: {message}\",\n        offset = error.text_range().start.utf8,\n        message = error.message()\n    );\n}\n

Otherwise, we can check if input is valid using this helpful utility:

assert!(parse_output.is_valid());\n
"},{"location":"user-guide/rust-crate/using-the-parser/#inspecting-the-parse-tree","title":"Inspecting the Parse Tree","text":"

Now, let's try to inspect the resulting CST, and iterate on its children:

let tree = parse_output.tree();\n\nlet contract = tree.as_nonterminal().unwrap();\nassert_eq!(contract.kind, NonterminalKind::ContractDefinition);\nassert_eq!(contract.children.len(), 7);\n\nlet children = &contract.children;\nassert!(\n    matches!(&children[0].node, Node::Terminal(t) if t.kind == TerminalKind::ContractKeyword)\n);\nassert!(matches!(&children[1].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));\nassert!(matches!(&children[2].node, Node::Terminal(t) if t.kind == TerminalKind::Identifier));\nassert!(matches!(&children[3].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));\nassert!(matches!(&children[4].node, Node::Terminal(t) if t.kind == TerminalKind::OpenBrace));\nassert!(\n    matches!(&children[5].node, Node::Nonterminal(r) if r.kind == NonterminalKind::ContractMembers)\n);\nassert!(matches!(&children[6].node, Node::Terminal(t) if t.kind == TerminalKind::CloseBrace));\n

Additionally, we can convert the CST node back into the input string:

assert_eq!(contract.unparse(), \"contract Foo {}\");\n
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"slang","text":""},{"location":"#solidity-compiler-tooling-by-nomicfoundation","title":"Solidity compiler tooling by @NomicFoundation","text":"

A modular set of compiler APIs empowering the next generation of Solidity code analysis and developer tooling. Written in Rust and distributed in multiple languages.

This repository maintains the source code and release process for these projects:

\u2757 This project is still in alpha, and is under active development. If you are planning on using it, please reach out to us on Telegram so we can help you get started.

"},{"location":"internals/","title":"Internals","text":""},{"location":"internals/development/","title":"Development","text":""},{"location":"internals/development/#dev-containers","title":"Dev Containers","text":"

To make the developer experience as seamless and consistent as possible, we recommend using the VS Code devcontainer included in this repository. It is a light image that has the minimum required tools to build this project. If you are not familiar with containerized development, I recommend taking a look at the official VS Code guide. Using a devcontainer allows us to quickly setup/teardown the environment, and install/setup different dependencies for different projects, without polluting the local environment. In the future, it will enable us to include Windows and Mac OS specific images for cross-platform testing.

If you would like to still develop outside a container, this should still be possible, as the CI will guarantee that your changes are safe. We intend to keep the images to a bare minimum, and install most dependencies through scripts you can run locally. However, using a common development container means sharing and standardizing useful settings and extensions for the editor (VS Code), the terminal (zsh), and any other tools.

In the future, if we decide to enable code spaces, we can have a 1-click button to create and warm up a powerful dev machine to use in seconds, and running completely remote in a browser tab. It will make it trivial to switch between different versions and branches, or even use and debug multiple ones at the same time from different tabs.

"},{"location":"internals/development/#hermit","title":"Hermit","text":"

To install language-specific binaries and packages, we use Hermit, which installs all tools only when it is first needed/invoked, so you can quickly setup and build different projects quickly. It also takes care of updating your $PATH as you cd in and out of different projects, to make sure you are using the right tools every time. Follow this guide to install it locally to your machine, or simply build any included project, and it will bootstrap itself if it is missing.

"},{"location":"internals/development/#infra-cli","title":"Infra CLI","text":"

To ensure consistency, and a good experience for first-time developers, all build/test/run/debug commands should be written, versioned, and documented inside the infra_cli crate. This means that any dev instructions are well documented, versioned, and verified/executed with every build. It also means that we can minimize any manual setup or teardown steps during development, and just rely on that cli.

You can access all such commands (from the hermit environment) by just running the infra script, which just refers to $REPO_ROOT/scripts/bin/infra. If this is your first time contributing, we recommend starting with infra --help to familiarize yourself with its capabilities.

"},{"location":"internals/development/#versioning-and-publishing","title":"Versioning and Publishing","text":"

We manage versioning through changesets. Each pull request can describe what user facing changes it is introducing, and include this information as a \"changeset\" markdown file along with source changes. These changeset files are analyzed and used to create another pull request to bump the repository version and update dependencies. Once the version bump is merged, artifacts are built and released to all registries.

"},{"location":"internals/development/#managing-dependencies","title":"Managing Dependencies","text":"

Our $REPO_ROOT/.github/dependabot.yml config runs automatic updates to our dependencies on a weekly basis. This handles github-actions, npm, cargo, and pip packages. However, two kinds of dependencies still need to be updated manually for now:

  1. Rust toolchains: $RUST_STABLE_VERSION and $RUST_NIGHTLY_VERSION defined in hermit.hcl and updated via rustup install.
  2. Hermit binaries defined in $REPO_ROOT/bin/XXX.pkg, and updated via hermit install.
"},{"location":"internals/repository-structure/","title":"Repository Structure","text":"

This repository is split into multiple projects at the root folder. Each project has its own dependencies and tools used to build, test, and ship different parts of the repository. For example, a Rust environment for the compiler, a Python environment for documentation, and a NodeJS environment for linters. This allows us to implement different binaries, APIs, and internal tools/scripts, and package/version them together, while having minimal inter-dependencies.

All dependencies should have exact full versions, and we can rely on tooling to automatically upgrade it over time. It allows us to have perfectly reproducible builds for every commit, a critical aspect for compilers, and developer tools in general.

"},{"location":"internals/repository-structure/#directory-structure","title":"Directory Structure","text":"

Currently, the repository has the following projects:

"},{"location":"internals/design-docs/","title":"Design Docs","text":""},{"location":"internals/design-docs/language-definition-v2/","title":"Language Definition v2","text":"

This document describes the new language definition model (AKA DSL v2), and the features/possibilities it enables for both syntax and semantic analysis. Each section describes a part of the definition model, and how it can affect the scanner, parser, CST, and AST.

This is a collection of different discussions we had over the last few weeks, and can (and should) be broken down into smaller work items if needed. It should be possible to map the current definition to the old one, so that we do incremental progress, instead of rewriting everything at once.

"},{"location":"internals/design-docs/language-definition-v2/#cst","title":"CST","text":"

We currently produce an untyped tree of nodes. It holds all parts of the input (byte for byte), even whitespace, comments, and unrecognized (skipped) parts. We can reconstruct the original input back from the CST, just by iterating on nodes in order. For memory/performance reasons, we don't hold positions/location information in the tree, but they are calculated during iterating/visiting the tree.

The CST is useful for many use cases:

Here is an example of the node type, similar to what we have now:

pub enum Node {\n    Terminal { node: Rc<TerminalNode> },\n    Nonterminal { node: Rc<NonterminalNode> },\n}\n\npub struct TerminalNode {\n    pub kind: TerminalKind,\n    pub text: String,\n}\n\npub struct NonterminalNode {\n    pub kind: NonterminalKind,\n    pub text_length: TextIndex,\n    pub children: Vec<Node>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#ast","title":"AST","text":"

We intend to also produce a strongly typed tree (structs and enums). Having strong types provides safety/correctness guarantees for users. It also allows us to generate visitor and rewriter APIs automatically.

Each AST node should provide an API to get the underlying CST node, where users can iterate over the actual terminals as they appear in input, and get their position in the source code. However, this is a one-way operation. CST nodes don't hold references to their AST nodes.

Note: some compilers drop syntactic elements that don't carry semantic information from their AST (like semicolons, or commas). However, we don't make that distinction, as we intend to implement further analysis in the form of micro-passes, that each can rewrite and pick parts of the tree that are relevant to them. So our initial tree (AST) should be complete.

"},{"location":"internals/design-docs/language-definition-v2/#versioning","title":"Versioning","text":"

The biggest benefit of the new language definition is that it allows scanners and parsers to attempt parsing input belonging to any language version, and report errors afterwards if the input is not valid for the selected version. This is a huge benefit over existing parsers, where they will either parse an inaccurate superset of all versions, or they parse a specific version, and produce unhelpful errors like Unrecognized 'abstract' keyword when the current language version doesn't support it.

Not only we will be able to recover from such errors and continue parsing, producing an accurate/complete tree at the end, but we will also be able to produce much better errors like: The 'abstract' keyword is not supported in the current version X. Please upgrade to version Y instead to be able to use it.

"},{"location":"internals/design-docs/language-definition-v2/#terminals","title":"Terminals","text":""},{"location":"internals/design-docs/language-definition-v2/#token-items","title":"Token Items","text":"

Tokens consist of one or more TokenDefinition. Each definition is separate/unique, but produces the same TerminalKind. This is useful for tokens like DecimalLiteral and HexLiteral who can have multiple forms, but each form is enabled or disabled in certain versions of the language.

All definitions have a unique Scanner, and they can be combined in the same trie/FSM to produce a single token at each position in the input. Afterwards, the scanner can compare the definition's enabled property with the current language version, adding an error if they don't match, but continue parsing anyway.

"},{"location":"internals/design-docs/language-definition-v2/#keyword-items","title":"Keyword Items","text":"

Keywords also contribute a TerminalKind, and consist of one or more KeywordDefinition. But they have additional semantics:

First, instead of defining a regular Scanner, it defines a KeywordValue that produces a finite set of possibilities. Most only produce one value (like abstract or contract), but some can produce multiple, like bytesN or fixedMxN, that can have different values for M and N. This is important for us to build hash sets and quickly check for membership.

Second, because keywords can also overlap with identifiers, each keyword has an identifier property that refers to which identifier token they can match. Instead of being part of same trie/FSM as tokens, whenever we want to scan a keyword, we try to scan its identifier instead. Afterwards, we check if its contents match one of the values of the keyword.

Third, they have two additional reserved property. We should use these when we scan identifiers, to make sure that the resulting identifier doesn't match a reserved keyword, and if so, we should report an error, but continue parsing.

Unique to Solidity, keywords can be reserved in versions before or after the versions they are enabled in. They can also be not reserved in versions before or after the versions they stop being enabled in. So we have to have these additional checks, to be able to catch cases like when a certain input can both be a keyword and an identifier, or neither.

We should also be able to generate a public API is_keyword(TerminalKind) for users to conveniently detect them if needed.

"},{"location":"internals/design-docs/language-definition-v2/#trivia-items","title":"Trivia Items","text":"

Trivia items are similar tokens, contributing their own TerminalKind. They are referred to from the language's top-level leading_trivia and trailing_trivia properties. Before and after each token, the scanner should try to scan these tokens, collecting them in a flat list.

Previously, we used to create many LeadingTrivia and TrailingTrivia nodes that hold whitespace/comments. Not only this is wasteful memory-wise, it is also unnatural/unexpected to wrap whitespace in nonterminal nodes. Instead, I propose treating them like any other token, and storing them as siblings to the tokens they belong to (in-order). Not only this is simpler, it is also more efficient, and is natural to how input is consumed and produced.

"},{"location":"internals/design-docs/language-definition-v2/#fragment-items","title":"Fragment Items","text":"

Fragments are not visible to users, and don't contribute a TerminalKind. They are just a utility used to refactor common parts of the grammar, and avoid duplication. During processing the language definition, they are inlined wherever they are referenced.

"},{"location":"internals/design-docs/language-definition-v2/#nonterminals","title":"Nonterminals","text":""},{"location":"internals/design-docs/language-definition-v2/#struct-items","title":"Struct Items","text":"

Structs represent a flat list (sequence) of typed fields. They are the simplest nonterminal, and generate a struct AST type. Their fields match 1-1 with the item fields. The struct name contributes a NonterminalKind.

Each field can be either Required(T) or Optional(T). Required fields are always present and parsed. Optional fields can be omitted if they don't exist, and are represented with Rust's Option<T> type (or TypeScript T | undefined). However, optional fields have an additional enabled property. After parsing optional fields, we should compare them with the current language version, and produce errors if they don't match, but continue parsing normally.

The type of each field can be a Nonterminal(T) or Terminal(Set<T>). A nonterminal field refers to another item, and holds its type. A terminal field refers to one or more terminal items (all valid in this position), and is of type TerminalNode.

Additionally, the struct also stores the CST node that holds its contents:

Definition
Struct(\n    name = ParametersDeclaration,\n    fields = (\n        open_paren = Required(Terminal([OpenParen])),\n        parameters = Required(Nonterminal(Parameters)),\n        close_paren = Required(Terminal([CloseParen]))\n    )\n)\n
AST Type
pub struct ParametersDeclaration {\n    pub open_paren: Rc<TerminalNode>,\n    pub parameters: Rc<Parameters>,\n    pub close_paren: Rc<TerminalNode>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#enum-items","title":"Enum Items","text":"

Enums represent an ordered choice operator of multiple variants (possibilities). The enum name itself does NOT contribute a NonterminalKind, since it will always result in one of its variants (each with a unique TerminalKind or a NonterminalKind. They only exist in the AST, and don't affect the CST at all.

We attempt to parse each variant (in-order), and choose the first one that succeeds. However, each variant can have an additional enabled property. We should always try to parse the variants that are valid in the current version first, and if not, still parse the rest, but produce an error afterwards. The fields of each variant are parsed similar to a struct fields (example above).

Definition
Enum(\n    name = FunctionBody,\n    variants = [\n        EnumVariant(name = Block, reference = Block),\n        EnumVariant(name = Semicolon, reference = Semicolon)\n    ]\n)\n
AST Type
pub enum FunctionBody {\n    Block {\n        block: Rc<Block>,\n\n        cst: Rc<NonterminalNode>,\n    },\n    Semicolon {\n        semicolon: Rc<TerminalNode>,\n\n        cst: Rc<NonterminalNode>,\n    },\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#repeated-items","title":"Repeated Items","text":"

Repeated items represent a list of items of the same kind. The item name contributes a NonterminalKind. The AST type is a wrapper around a Vec<T>, with any utilities we need to add for convenience.

It has an allow_empty boolean property, which allows parsing zero items. If it is false, we should still allow parsing zero items, but produce an error afterwards.

Definition
Repeated(\n    name = FunctionAttributes,\n    repeated = FunctionAttribute,\n    allow_empty = true\n)\n
AST Type
pub struct FunctionAttributes {\n    pub items: Vec<Rc<FunctionAttribute>>\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#separated-items","title":"Separated Items","text":"

Separated items represent a list of items of the same kind, separated by a delimiter. The item name contributes a NonterminalKind. The AST type is a wrapper around two Vec<T> for items and their delimiters, with any utilities we need to add for convenience. For example, we should add APIs to create iterators for only the separated items, the separators, or both (in-order).

It has an allow_empty boolean property, which allows parsing zero items. If it is false, we should still allow parsing zero items, but produce an error afterwards. We should also allow parsing a trailing separator at the end, but still produce an error afterwards.

Definition
Separated(\n    name = EventParameters,\n    separated = EventParameter,\n    separator = Comma,\n    allow_empty = true\n)\n
AST Type
pub struct EventParameters {\n    pub items: Vec<Rc<EventParameter>>\n    pub separators: Vec<Rc<TerminalNode>>\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#precedence-items","title":"Precedence Items","text":"

This is perhaps the most complex nonterminal. It still uses the same PRATT algorithm from the previous implementation (no changes there), but adapted for the new AST types. It has two lists:

First, a list of precedence_expressions, with each expression having a list of operators. Each operator has its own versioning (enabled property), a list of fields, and a model (prefix/postfix/binary).

The operators from all expressions are flattened and combined in the parent PRATT parser. That grouping is only used to indicate that some operators can produce the same PrecedenceExpression name. However, we should exclude operators that don't match the current language version. This is useful for things like ExponentiationExpression where it has two operators with different associativity, but defined in enabled/disabled in different versions.

Second, a list of primary_expressions, with their own versioning (enabled property) as well. We should try to parse them as an operator (similar to EnumItem), and produce an error if the version doesn't match afterwards.

It is important to note that the item name doesn't contribute a NonterminalKind, but each PrecedenceExpression under it contributes one.

Definition
Precedence(\n    name = Expression,\n    precedence_expressions = [\n        PrecedenceExpression(\n            name = AdditionExpression,\n            operators = [PrecedenceOperator(\n                model = BinaryLeftAssociative,\n                fields = (operator = Required(Terminal([Plus])))\n            )]\n        ),\n        PrecedenceExpression(\n            name = FunctionCallExpression,\n            operators = [PrecedenceOperator(\n                model = Postfix,\n                fields = (\n                    open_paren = Required(Terminal([OpenParen])),\n                    arguments = Required(Nonterminal(Arguments)),\n                    close_paren = Required(Terminal([CloseParen]))\n                )\n            )]\n        ),\n        PrecedenceExpression(\n            name = NegationExpression,\n            operators = [PrecedenceOperator(\n                model = Prefix,\n                fields = (operator = Required(Terminal([Not])))\n            )]\n        )\n    )],\n    primary_expressions = [\n        PrimaryExpression(expression = Identifier),\n        PrimaryExpression(expression = NumberLiteral),\n        PrimaryExpression(expression = StringLiteral)\n    ]\n)\n
AST Type
pub enum Expression {\n    AdditionExpression { expression: Rc<AdditionExpression> },\n    FunctionCallExpression { expression: Rc<FunctionCallExpression> },\n    NegationExpression { expression: Rc<NegationExpression> },\n\n    Identifier { expression: Rc<TerminalNode> },\n    NumberLiteral { expression: Rc<TerminalNode> },\n    StringLiteral { expression: Rc<TerminalNode> },\n}\n\npub struct AdditionExpression {\n    // 'left_operand' auto-generated (before) because it is a binary expression, and same type as parent\n    pub left_operand: Rc<Expression>,\n    // operator 'fields' are flattened into the expression node here\n    pub operator: Rc<TerminalNode>,\n    // 'right_operand' auto-generated (after) because it is a binary expression, and same type as parent\n    pub right_operand: Rc<Expression>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n\npub struct FunctionCallExpression {\n    // 'operand' auto-generated (before) because it is a postfix expression, and same type as parent\n    pub operand: Rc<Expression>,\n    // operator 'fields' are flattened into the expression node here\n    pub open_paren: Rc<TerminalNode>,\n    pub arguments: Rc<Arguments>,\n    pub close_paren: Rc<TerminalNode>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n\npub struct NegationExpression {\n    // operator 'fields' are flattened into the expression node here\n    pub operator: Rc<TerminalNode>,\n    // 'operand' auto-generated (after) because it is a prefix expression, and same type as parent\n    pub operand: Rc<Expression>,\n\n    pub cst: Rc<NonterminalNode>,\n}\n
"},{"location":"internals/design-docs/language-definition-v2/#error-recovery","title":"Error Recovery","text":"

For the CST, I think the current algorithms work well, and we should be able to keep them. Unrecognized (skipped) input is grouped into one token, and we can just add it as-is to the cst node under its AST node.

During AST construction, we will simply check for TerminalKind::UNRECOGNIZED nodes, and skip construction if there are any.

"},{"location":"internals/design-docs/language-definition-v2/#public-api-changes","title":"Public API Changes","text":"

Based on the above, I propose the following changes to the current public API:

"},{"location":"internals/design-docs/language-definition-v2/#visitors-and-cursors","title":"Visitors and Cursors","text":"

The current CST visitors/cursors should still work as-is, since the CST tree will be unchanged. However, the new AST types allow us in the future to produce typed visitors and traits with named functions for every node type, similar to a lot of other AST processing libraries. I want to at least produce an immutable Visitor and a mutable Rewriter.

"},{"location":"solidity-specification/","title":"Solidity Specification","text":""},{"location":"solidity-specification/#solidity-specification","title":"Solidity Specification","text":""},{"location":"solidity-specification/supported-versions/","title":"Supported Versions","text":"

This specification compiles information from 83 publicly released versions of Solidity:

0.4.11 0.4.12 0.4.13 0.4.14 0.4.15 0.4.16 0.4.17 0.4.18 0.4.19 0.4.20 0.4.21 0.4.22 0.4.23 0.4.24 0.4.25 0.4.26 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 0.5.8 0.5.9 0.5.10 0.5.11 0.5.12 0.5.13 0.5.14 0.5.15 0.5.16 0.5.17 0.6.0 0.6.1 0.6.2 0.6.3 0.6.4 0.6.5 0.6.6 0.6.7 0.6.8 0.6.9 0.6.10 0.6.11 0.6.12 0.7.0 0.7.1 0.7.2 0.7.3 0.7.4 0.7.5 0.7.6 0.8.0 0.8.1 0.8.2 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 0.8.8 0.8.9 0.8.10 0.8.11 0.8.12 0.8.13 0.8.14 0.8.15 0.8.16 0.8.17 0.8.18 0.8.19 0.8.20 0.8.21 0.8.22 0.8.23 0.8.24 0.8.25 0.8.26 0.8.27 0.8.28

Among which, 34 versions have breaking changes:

0.4.11 0.4.12 0.4.14 0.4.16 0.4.21 0.4.22 0.4.25 0.5.0 0.5.3 0.5.5 0.5.8 0.5.10 0.5.12 0.5.14 0.6.0 0.6.2 0.6.5 0.6.7 0.6.8 0.6.11 0.7.0 0.7.1 0.7.4 0.8.0 0.8.4 0.8.7 0.8.8 0.8.13 0.8.18 0.8.19 0.8.22 0.8.24 0.8.25 0.8.27

"},{"location":"solidity-specification/01-file-structure/","title":"1. File Structure","text":""},{"location":"solidity-specification/01-file-structure/#1-file-structure","title":"1. File Structure","text":""},{"location":"solidity-specification/01-file-structure/01-license-specifiers/","title":"1.1. License Specifiers","text":""},{"location":"solidity-specification/01-file-structure/01-license-specifiers/#11-license-specifiers","title":"1.1. License Specifiers","text":""},{"location":"solidity-specification/01-file-structure/01-license-specifiers/#license-comment","title":"License Comment","text":"

This comment line declares that the source code is licensed under the GPL version 3.0. Machine-readable license specifiers are important in a setting where publishing the source code is the default. The comment is recognized by the compiler anywhere in the file at the file level, but it is recommended to put it at the top of the file.

// SPDX-License-Identifier: GPL-3.0\n

When omitted, the compiler produces a warning to add one. The compiler does not validate that the license is part of the list allowed by SPDX, but it does include the supplied string in the metadata.

If you do not want to specify a license or if the source code is not open-source, please use the special value UNLICENSED. Note that UNLICENSED (no usage allowed, not present in SPDX license list) is different from UNLICENSE (grants all rights to everyone).

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/02-source-unit/","title":"1.2. Source Unit","text":""},{"location":"solidity-specification/01-file-structure/02-source-unit/#12-source-unit","title":"1.2. Source Unit","text":""},{"location":"solidity-specification/01-file-structure/02-source-unit/#syntax","title":"Syntax","text":"
SourceUnit = (* members: *) SourceUnitMembers;
 
SourceUnitMembers = (* item: *) SourceUnitMember*;
 
SourceUnitMember = (* variant: *) PragmaDirective                 | (* variant: *) ImportDirective                 | (* variant: *) ContractDefinition                 | (* variant: *) InterfaceDefinition                 | (* variant: *) LibraryDefinition                 | (* variant: *) StructDefinition (* Introduced in 0.6.0 *)                 | (* variant: *) EnumDefinition (* Introduced in 0.6.0 *)                 | (* variant: *) FunctionDefinition (* Introduced in 0.7.1 *)                 | (* variant: *) ErrorDefinition (* Introduced in 0.8.4 *)                 | (* variant: *) UserDefinedValueTypeDefinition (* Introduced in 0.8.8 *)                 | (* variant: *) UsingDirective (* Introduced in 0.8.13 *)                 | (* variant: *) EventDefinition (* Introduced in 0.8.22 *)                 | (* variant: *) ConstantDefinition; (* Introduced in 0.7.4 *)
"},{"location":"solidity-specification/01-file-structure/02-source-unit/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/","title":"1.3. Pragma Directives","text":""},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#13-pragma-directives","title":"1.3. Pragma Directives","text":""},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#syntax","title":"Syntax","text":"
PragmaDirective = (* pragma_keyword: *) PRAGMA_KEYWORD                  (* pragma: *) Pragma                  (* semicolon: *) SEMICOLON;
 
Pragma = (* variant: *) AbicoderPragma       | (* variant: *) ExperimentalPragma       | (* variant: *) VersionPragma;
 
AbicoderPragma = (* abicoder_keyword: *) ABICODER_KEYWORD                 (* version: *) IDENTIFIER;
 
ExperimentalPragma = (* experimental_keyword: *) EXPERIMENTAL_KEYWORD                     (* feature: *) ExperimentalFeature;
 
ExperimentalFeature = (* variant: *) IDENTIFIER                    | (* variant: *) StringLiteral;
 
VersionPragma = (* solidity_keyword: *) SOLIDITY_KEYWORD                (* sets: *) VersionExpressionSets;
 
VersionExpressionSets = (* item: *) VersionExpressionSet ((* separator: *) BAR_BAR (* item: *) VersionExpressionSet)*;
 
VersionExpressionSet = (* item: *) VersionExpression+;
 
VersionExpression = (* variant: *) VersionRange                  | (* variant: *) VersionTerm;
 
VersionRange = (* start: *) VersionLiteral               (* minus: *) MINUS               (* end: *) VersionLiteral;
 
VersionTerm = (* operator: *) VersionOperator?              (* literal: *) VersionLiteral;
 
VersionOperator = (* variant: *) CARET                | (* variant: *) TILDE                | (* variant: *) EQUAL                | (* variant: *) LESS_THAN                | (* variant: *) GREATER_THAN                | (* variant: *) LESS_THAN_EQUAL                | (* variant: *) GREATER_THAN_EQUAL;
 
VersionLiteral = (* variant: *) SimpleVersionLiteral               | (* variant: *) SINGLE_QUOTED_VERSION_LITERAL               | (* variant: *) DOUBLE_QUOTED_VERSION_LITERAL;
 
SimpleVersionLiteral = (* item: *) VERSION_SPECIFIER ((* separator: *) PERIOD (* item: *) VERSION_SPECIFIER)*;
 
VERSION_SPECIFIER = \u00abVERSION_SPECIFIER_FRAGMENT\u00bb;
 
SINGLE_QUOTED_VERSION_LITERAL = \"'\" \u00abVERSION_SPECIFIER_FRAGMENT\u00bb (\".\" \u00abVERSION_SPECIFIER_FRAGMENT\u00bb)* \"'\";
 
DOUBLE_QUOTED_VERSION_LITERAL = '\"' \u00abVERSION_SPECIFIER_FRAGMENT\u00bb (\".\" \u00abVERSION_SPECIFIER_FRAGMENT\u00bb)* '\"';
 
\u00abVERSION_SPECIFIER_FRAGMENT\u00bb = (\"0\"\u2026\"9\" | \"x\" | \"X\" | \"*\")+;
 
(* Never reserved *)ABICODER_KEYWORD = \"abicoder\";
 
(* Never reserved *)EXPERIMENTAL_KEYWORD = \"experimental\";
 
(* Never reserved *)SOLIDITY_KEYWORD = \"solidity\";
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#version-pragma","title":"Version Pragma","text":"

This line declares which Solidity language version it was written for. This is to ensure that the contract is not compilable with a new (breaking) compiler version, where it could behave differently. An error is produced if the running compiler version does not match these requirements.

Note that multiple version pragmas are supported, and the compiler will verify each pragma separately.

For example, this line specifies that the source code is written for Solidity version 0.4.16, or a newer version of the language up to, but not including version 0.9.0:

pragma solidity >=0.4.16 <0.9.0;\n
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#abi-coder-pragma","title":"ABI Coder Pragma","text":"

Used to instruct the compiler to choose a specific ABI encoder/decoder. The new ABI coder (v2) is able to encode and decode arbitrarily nested arrays and structs. It might produce less optimal code and has not received as much testing as the old encoder.

pragma abicoder v1;\n// OR\npragma abicoder v2;\n
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#experimental-pragma","title":"Experimental Pragma","text":"

It can be used to enable features of the compiler or language that are not yet enabled by default. Compilers should produce an error on unrecognized pragmas (or earlier versions before they were released), and a warning before the stable version. After the stable version, this should not have an effect.

"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#abiencoderv2","title":"ABIEncoderV2","text":"

Please see the abicoder pragma defined above.

pragma experimental ABIEncoderV2;\n
"},{"location":"solidity-specification/01-file-structure/03-pragma-directives/#smtchecker","title":"SMTChecker","text":"

If you use SMTChecker, then you get additional safety warnings which are obtained by querying an SMT solver. The component does not yet support all features of the Solidity language and likely outputs many warnings. In case it reports unsupported features, the analysis may not be fully sound.

pragma experimental SMTChecker;\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/04-import-directives/","title":"1.4. Import Directives","text":""},{"location":"solidity-specification/01-file-structure/04-import-directives/#14-import-directives","title":"1.4. Import Directives","text":""},{"location":"solidity-specification/01-file-structure/04-import-directives/#syntax","title":"Syntax","text":"
ImportDirective = (* import_keyword: *) IMPORT_KEYWORD                  (* clause: *) ImportClause                  (* semicolon: *) SEMICOLON;
 
ImportClause = (* variant: *) PathImport             | (* variant: *) NamedImport             | (* variant: *) ImportDeconstruction;
 
PathImport = (* path: *) StringLiteral             (* alias: *) ImportAlias?;
 
NamedImport = (* asterisk: *) ASTERISK              (* alias: *) ImportAlias              (* from_keyword: *) FROM_KEYWORD              (* path: *) StringLiteral;
 
ImportDeconstruction = (* open_brace: *) OPEN_BRACE                       (* symbols: *) ImportDeconstructionSymbols                       (* close_brace: *) CLOSE_BRACE                       (* from_keyword: *) FROM_KEYWORD                       (* path: *) StringLiteral;
 
ImportDeconstructionSymbols = (* item: *) ImportDeconstructionSymbol ((* separator: *) COMMA (* item: *) ImportDeconstructionSymbol)*;
 
ImportDeconstructionSymbol = (* name: *) IDENTIFIER                             (* alias: *) ImportAlias?;
 
ImportAlias = (* as_keyword: *) AS_KEYWORD              (* identifier: *) IDENTIFIER;
"},{"location":"solidity-specification/01-file-structure/04-import-directives/#importing-files","title":"Importing Files","text":"

At a file level, you can use import statements of the following form:

import \"filename\";\n

This statement imports all global symbols from filename (and symbols imported there) into the current global scope. This form is not recommended for use, because it unpredictably pollutes the namespace. If you add new top-level items inside filename, they automatically appear in all files that import like this from \u201cfilename\u201d. It is better to import specific symbols explicitly, which results in all global symbols being available under the myFile symbol:

import * as myFile from \"filename\";\n// OR\nimport \"filename\" as myFile;\n
"},{"location":"solidity-specification/01-file-structure/04-import-directives/#importing-specific-symbols","title":"Importing Specific Symbols","text":"

You can import only the symbols you use from a specific file, using the syntax:

import {symbol1, symbol2} from \"filename\";\n

Which will create symbol1 and symbol1 to use in your code. If there is a naming collision, you can rename symbols while importing. For example, the code below creates new global symbols alias and symbol2 which reference symbol1 and symbol2 from inside filename, respectively:

import {symbol1 as alias, symbol2} from \"filename\";\n
"},{"location":"solidity-specification/01-file-structure/04-import-directives/#virtual-file-system","title":"Virtual File System","text":"

In order to be able to support reproducible builds on all platforms, the Solidity compiler has to abstract away the details of the filesystem where source files are stored. For this reason import paths do not refer directly to files in the host filesystem. Instead the compiler maintains an internal database (virtual filesystem or VFS for short) where each source unit is assigned a unique source unit name which is an opaque and unstructured identifier. The import path specified in an import statement is translated into a source unit name and used to find the corresponding source unit in this database.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/05-using-directives/","title":"1.5. Using Directives","text":""},{"location":"solidity-specification/01-file-structure/05-using-directives/#15-using-directives","title":"1.5. Using Directives","text":""},{"location":"solidity-specification/01-file-structure/05-using-directives/#syntax","title":"Syntax","text":"
UsingDirective = (* using_keyword: *) USING_KEYWORD                 (* clause: *) UsingClause                 (* for_keyword: *) FOR_KEYWORD                 (* target: *) UsingTarget                 (* global_keyword: *) GLOBAL_KEYWORD? (* Introduced in 0.8.13 *)                 (* semicolon: *) SEMICOLON;
 
UsingClause = (* variant: *) IdentifierPath            | (* variant: *) UsingDeconstruction; (* Introduced in 0.8.13 *)
 
(* Introduced in 0.8.13 *)UsingDeconstruction = (* open_brace: *) OPEN_BRACE                      (* symbols: *) UsingDeconstructionSymbols                      (* close_brace: *) CLOSE_BRACE;
 
(* Introduced in 0.8.13 *)UsingDeconstructionSymbols = (* item: *) UsingDeconstructionSymbol ((* separator: *) COMMA (* item: *) UsingDeconstructionSymbol)*;
 
(* Introduced in 0.8.13 *)UsingDeconstructionSymbol = (* name: *) IdentifierPath                            (* alias: *) UsingAlias?; (* Introduced in 0.8.19 *)
 
(* Introduced in 0.8.19 *)UsingAlias = (* as_keyword: *) AS_KEYWORD             (* operator: *) UsingOperator;
 
(* Introduced in 0.8.19 *)UsingOperator = (* variant: *) AMPERSAND              | (* variant: *) ASTERISK              | (* variant: *) BANG_EQUAL              | (* variant: *) BAR              | (* variant: *) CARET              | (* variant: *) EQUAL_EQUAL              | (* variant: *) GREATER_THAN              | (* variant: *) GREATER_THAN_EQUAL              | (* variant: *) LESS_THAN              | (* variant: *) LESS_THAN_EQUAL              | (* variant: *) MINUS              | (* variant: *) PERCENT              | (* variant: *) PLUS              | (* variant: *) SLASH              | (* variant: *) TILDE;
 
UsingTarget = (* variant: *) TypeName            | (* variant: *) ASTERISK;
"},{"location":"solidity-specification/01-file-structure/05-using-directives/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/06-trivia/","title":"1.6. Trivia","text":""},{"location":"solidity-specification/01-file-structure/06-trivia/#16-trivia","title":"1.6. Trivia","text":""},{"location":"solidity-specification/01-file-structure/06-trivia/#syntax","title":"Syntax","text":"
WHITESPACE = (\" \" | \"\\t\")+;
 
END_OF_LINE = \"\\n\" | (\"\\r\" \"\\n\"?);
 
SINGLE_LINE_COMMENT = \"//\" (?!\"/\") (!(\"\\r\" | \"\\n\"))*;
 
MULTI_LINE_COMMENT = \"/*\" (?!\"*\" !\"/\") (!\"*\" | (\"*\" (?!\"/\")))* \"*/\";
 
SINGLE_LINE_NAT_SPEC_COMMENT = \"///\" (!(\"\\r\" | \"\\n\"))*;
 
MULTI_LINE_NAT_SPEC_COMMENT = \"/**\" (?!\"/\") (!\"*\" | (\"*\" (?!\"/\")))* \"*/\";
"},{"location":"solidity-specification/01-file-structure/06-trivia/#single-line-comments","title":"Single Line Comments","text":"

A single-line comment is terminated by any unicode line terminator (LF, VF, FF, CR, NEL, LS or PS) in UTF-8 encoding. The terminator is still part of the source code after the comment, so if it is not an ASCII symbol (these are NEL, LS and PS), it will lead to a parser error.

// This is a single-line comment.\n
"},{"location":"solidity-specification/01-file-structure/06-trivia/#multi-line-comments","title":"Multi-line Comments","text":"

Comments starting with /* and ending with */ are allowed to range multiple lines:

/*\nThis is a\nmulti-line comment.\n*/\n
"},{"location":"solidity-specification/01-file-structure/06-trivia/#natspec-comments","title":"NatSpec Comments","text":"

Additionally, there is another type of comment called a NatSpec comment. They are written with a triple slash /// or a double asterisk block /**...*/ and they should be used directly above function declarations or statements. It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI).

/// @author My Team Name\n/// @title A simple contract example\ncontract MyContract {}\n

Please see the NatSpec Format section for further information.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/","title":"1.7. Nat Spec Format","text":""},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#17-nat-spec-format","title":"1.7. Nat Spec Format","text":""},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#what-is-natspec","title":"What is NatSpec?","text":"

Solidity contracts can use a special form of comments to provide rich documentation for functions, return variables and more. This special form is named the Ethereum Natural Language Specification Format (NatSpec). It was inspired by Doxygen, and while it uses Doxygen-style comments and tags, there is no intention to keep strict compatibility with Doxygen.

It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI). It is used in:

Documentation can be inserted above each contract, interface, library, function, event and state variable.

They can either exist in a single line format, starting with ///:

/// @title An example contract\ncontract MyContract {}\n

And also in multi-line format, starting with /** and ending with */:

/**\n * @title An example contract\n */\ncontract MyContract {}\n
"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#tags","title":"Tags","text":"

Tags categorize different comments according to their purpose. The table below shows the different tags supported. Please note that they are optional, and without one, the entire comment will be interpreted as it had a @notice tag.

Tag Description Context @title A title that should describe the contract/interface contract, library, interface @author The name of the author contract, library, interface @notice Explain to an end user what this does contract, library, interface, function, event, state variable @dev Explain to a developer any extra details contract, library, interface, function, event, state variable @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, state variable @inheritdoc Copies all missing tags from the base function (must be followed by the contract name) function, state variable @custom:FOO Custom tag, semantics is application-defined can be used everywhere"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#function-return-types","title":"Function Return Types","text":"

If your function returns multiple values, like (int quotient, int remainder) then use multiple @return statements in the same format as the @param statements.

"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#custom-tags","title":"Custom Tags","text":"

Custom tags start with @custom: and must be followed by one or more lowercase letters or hyphens. It cannot start with a hyphen however. They can be used everywhere and are part of the developer documentation. For example, @custom:foo or @custom:foo-bar. A good use case is analysis and verification tools.

"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#dynamic-expressions","title":"Dynamic expressions","text":"

The Solidity compiler will pass through NatSpec documentation from your Solidity source code to the JSON output as described in this guide. The consumer of this JSON output may present this to the end-user directly or it may apply some pre-processing.

Specifying these dynamic expressions is outside the scope of the Solidity documentation. However, you can find one useful example in the RadSpec Project, where it evaluates references to function inputs to its values. For example, this line:

/// @notice This function will multiply `a` by 7\n

Can be evaluated as the following, where the value of a is 10:

This function will multiply 10 by 7\n
"},{"location":"solidity-specification/01-file-structure/07-nat-spec-format/#inheritance","title":"Inheritance","text":"

Functions without NatSpec will automatically inherit the documentation of their base function. Exceptions to this are:

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/08-keywords/","title":"1.8. Keywords","text":""},{"location":"solidity-specification/01-file-structure/08-keywords/#18-keywords","title":"1.8. Keywords","text":""},{"location":"solidity-specification/01-file-structure/08-keywords/#syntax","title":"Syntax","text":"
(* Introduced in 0.6.0 *)ABSTRACT_KEYWORD = \"abstract\";
 
(* Never reserved *)ADDRESS_KEYWORD = \"address\";
 
AFTER_KEYWORD = \"after\";
 
(* Reserved in 0.5.0 *)ALIAS_KEYWORD = \"alias\";
 
ANONYMOUS_KEYWORD = \"anonymous\";
 
(* Reserved in 0.5.0 *)APPLY_KEYWORD = \"apply\";
 
AS_KEYWORD = \"as\";
 
ASSEMBLY_KEYWORD = \"assembly\";
 
(* Reserved in 0.5.0 *)AUTO_KEYWORD = \"auto\";
 
BOOL_KEYWORD = \"bool\";
 
BREAK_KEYWORD = \"break\";
 
(* Deprecated in 0.8.0 *)BYTE_KEYWORD = \"byte\";
 
BYTES_KEYWORD = \"bytes\" (\"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"16\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"24\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"32\")?;
 
(* Introduced in 0.5.0 *)(* Reserved in 0.5.0 *)CALL_DATA_KEYWORD = \"calldata\";
 
CASE_KEYWORD = \"case\";
 
(* Introduced in 0.6.0 *)CATCH_KEYWORD = \"catch\";
 
CONSTANT_KEYWORD = \"constant\";
 
(* Introduced in 0.4.22 *)(* Reserved in 0.5.0 *)CONSTRUCTOR_KEYWORD = \"constructor\";
 
CONTINUE_KEYWORD = \"continue\";
 
CONTRACT_KEYWORD = \"contract\";
 
(* Reserved in 0.5.0 *)COPY_OF_KEYWORD = \"copyof\";
 
DAYS_KEYWORD = \"days\";
 
DEFAULT_KEYWORD = \"default\";
 
(* Reserved in 0.5.0 *)DEFINE_KEYWORD = \"define\";
 
DELETE_KEYWORD = \"delete\";
 
DO_KEYWORD = \"do\";
 
ELSE_KEYWORD = \"else\";
 
(* Introduced in 0.4.21 *)(* Reserved in 0.5.0 *)EMIT_KEYWORD = \"emit\";
 
ENUM_KEYWORD = \"enum\";
 
(* Introduced in 0.8.4 *)(* Never reserved *)ERROR_KEYWORD = \"error\";
 
ETHER_KEYWORD = \"ether\";
 
EVENT_KEYWORD = \"event\";
 
EXTERNAL_KEYWORD = \"external\";
 
(* Reserved in 0.6.0 *)FALLBACK_KEYWORD = \"fallback\";
 
FALSE_KEYWORD = \"false\";
 
FINAL_KEYWORD = \"final\";
 
(* Deprecated in 0.7.0 *)(* Reserved until 0.7.0 *)FINNEY_KEYWORD = \"finney\";
 
FIXED_KEYWORD = \"fixed\";FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");FIXED_KEYWORD = \"fixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved in 0.4.14 *)FIXED_KEYWORD = \"fixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved in 0.4.14 *)FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
FOR_KEYWORD = \"for\";
 
(* Never reserved *)FROM_KEYWORD = \"from\";
 
FUNCTION_KEYWORD = \"function\";
 
(* Introduced in 0.8.13 *)(* Never reserved *)GLOBAL_KEYWORD = \"global\";
 
(* Introduced in 0.6.11 *)(* Reserved in 0.7.0 *)GWEI_KEYWORD = \"gwei\";
 
HEX_KEYWORD = \"hex\";
 
HOURS_KEYWORD = \"hours\";
 
IF_KEYWORD = \"if\";
 
(* Introduced in 0.6.5 *)(* Reserved in 0.5.0 *)IMMUTABLE_KEYWORD = \"immutable\";
 
(* Reserved in 0.5.0 *)IMPLEMENTS_KEYWORD = \"implements\";
 
IMPORT_KEYWORD = \"import\";
 
INDEXED_KEYWORD = \"indexed\";
 
IN_KEYWORD = \"in\";
 
INLINE_KEYWORD = \"inline\";
 
INTERFACE_KEYWORD = \"interface\";
 
INTERNAL_KEYWORD = \"internal\";
 
INT_KEYWORD = \"int\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
IS_KEYWORD = \"is\";
 
LET_KEYWORD = \"let\";
 
LIBRARY_KEYWORD = \"library\";
 
(* Reserved in 0.5.0 *)MACRO_KEYWORD = \"macro\";
 
MAPPING_KEYWORD = \"mapping\";
 
MATCH_KEYWORD = \"match\";
 
MEMORY_KEYWORD = \"memory\";
 
MINUTES_KEYWORD = \"minutes\";
 
MODIFIER_KEYWORD = \"modifier\";
 
(* Reserved in 0.5.0 *)MUTABLE_KEYWORD = \"mutable\";
 
NEW_KEYWORD = \"new\";
 
NULL_KEYWORD = \"null\";
 
OF_KEYWORD = \"of\";
 
(* Introduced in 0.6.0 *)(* Reserved in 0.5.0 *)OVERRIDE_KEYWORD = \"override\";
 
(* Reserved in 0.5.0 *)PARTIAL_KEYWORD = \"partial\";
 
PAYABLE_KEYWORD = \"payable\";
 
PRAGMA_KEYWORD = \"pragma\";
 
PRIVATE_KEYWORD = \"private\";
 
(* Reserved in 0.5.0 *)PROMISE_KEYWORD = \"promise\";
 
PUBLIC_KEYWORD = \"public\";
 
(* Introduced in 0.4.16 *)PURE_KEYWORD = \"pure\";
 
(* Reserved in 0.6.0 *)RECEIVE_KEYWORD = \"receive\";
 
(* Reserved in 0.5.0 *)REFERENCE_KEYWORD = \"reference\";
 
RELOCATABLE_KEYWORD = \"relocatable\";
 
RETURN_KEYWORD = \"return\";
 
RETURNS_KEYWORD = \"returns\";
 
(* Introduced in 0.8.4 *)(* Never reserved *)REVERT_KEYWORD = \"revert\";
 
(* Reserved in 0.5.0 *)SEALED_KEYWORD = \"sealed\";
 
SECONDS_KEYWORD = \"seconds\";
 
(* Reserved in 0.5.0 *)SIZE_OF_KEYWORD = \"sizeof\";
 
STATIC_KEYWORD = \"static\";
 
STORAGE_KEYWORD = \"storage\";
 
STRING_KEYWORD = \"string\";
 
STRUCT_KEYWORD = \"struct\";
 
SUPER_KEYWORD = \"super\";
 
(* Reserved in 0.5.0 *)SUPPORTS_KEYWORD = \"supports\";
 
SWITCH_KEYWORD = \"switch\";
 
(* Deprecated in 0.7.0 *)(* Reserved until 0.7.0 *)SZABO_KEYWORD = \"szabo\";
 
THIS_KEYWORD = \"this\";
 
(* Deprecated in 0.5.0 *)THROW_KEYWORD = \"throw\";
 
(* Introduced in 0.8.27 *)(* Never reserved *)TRANSIENT_KEYWORD = \"transient\";
 
TRUE_KEYWORD = \"true\";
 
(* Introduced in 0.6.0 *)TRY_KEYWORD = \"try\";
 
(* Reserved in 0.5.0 *)TYPE_DEF_KEYWORD = \"typedef\";
 
(* Introduced in 0.5.3 *)TYPE_KEYWORD = \"type\";
 
TYPE_OF_KEYWORD = \"typeof\";
 
UFIXED_KEYWORD = \"ufixed\";UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");UFIXED_KEYWORD = \"ufixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved in 0.4.14 *)UFIXED_KEYWORD = \"ufixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved in 0.4.14 *)UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
UINT_KEYWORD = \"uint\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
(* Introduced in 0.8.0 *)(* Reserved in 0.5.0 *)UNCHECKED_KEYWORD = \"unchecked\";
 
USING_KEYWORD = \"using\";
 
(* Deprecated in 0.5.0 *)VAR_KEYWORD = \"var\";
 
(* Introduced in 0.4.16 *)VIEW_KEYWORD = \"view\";
 
(* Introduced in 0.6.0 *)(* Reserved in 0.6.0 *)VIRTUAL_KEYWORD = \"virtual\";
 
WEEKS_KEYWORD = \"weeks\";
 
WEI_KEYWORD = \"wei\";
 
WHILE_KEYWORD = \"while\";
 
(* Deprecated in 0.5.0 *)YEARS_KEYWORD = \"years\";
"},{"location":"solidity-specification/01-file-structure/08-keywords/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/01-file-structure/09-punctuation/","title":"1.9. Punctuation","text":""},{"location":"solidity-specification/01-file-structure/09-punctuation/#19-punctuation","title":"1.9. Punctuation","text":""},{"location":"solidity-specification/01-file-structure/09-punctuation/#syntax","title":"Syntax","text":"
OPEN_PAREN = \"(\";
 
CLOSE_PAREN = \")\";
 
OPEN_BRACKET = \"[\";
 
CLOSE_BRACKET = \"]\";
 
OPEN_BRACE = \"{\";
 
CLOSE_BRACE = \"}\";
 
COMMA = \",\";
 
PERIOD = \".\";
 
QUESTION_MARK = \"?\";
 
SEMICOLON = \";\";
 
COLON = \":\";
 
COLON_EQUAL = \":=\";
 
EQUAL = \"=\";
 
(* Deprecated in 0.5.0 *)EQUAL_COLON = \"=:\";
 
EQUAL_EQUAL = \"==\";
 
EQUAL_GREATER_THAN = \"=>\";
 
ASTERISK = \"*\";
 
ASTERISK_EQUAL = \"*=\";
 
ASTERISK_ASTERISK = \"**\";
 
BAR = \"|\";
 
BAR_EQUAL = \"|=\";
 
BAR_BAR = \"||\";
 
AMPERSAND = \"&\";
 
AMPERSAND_EQUAL = \"&=\";
 
AMPERSAND_AMPERSAND = \"&&\";
 
LESS_THAN = \"<\";
 
LESS_THAN_EQUAL = \"<=\";
 
LESS_THAN_LESS_THAN = \"<<\";
 
LESS_THAN_LESS_THAN_EQUAL = \"<<=\";
 
GREATER_THAN = \">\";
 
GREATER_THAN_EQUAL = \">=\";
 
GREATER_THAN_GREATER_THAN = \">>\";
 
GREATER_THAN_GREATER_THAN_EQUAL = \">>=\";
 
GREATER_THAN_GREATER_THAN_GREATER_THAN = \">>>\";
 
GREATER_THAN_GREATER_THAN_GREATER_THAN_EQUAL = \">>>=\";
 
PLUS = \"+\";
 
PLUS_EQUAL = \"+=\";
 
PLUS_PLUS = \"++\";
 
MINUS = \"-\";
 
MINUS_EQUAL = \"-=\";
 
MINUS_MINUS = \"--\";
 
MINUS_GREATER_THAN = \"->\";
 
SLASH = \"/\" (?!\"*\" | \"/\" | \"=\");
 
SLASH_EQUAL = \"/=\";
 
PERCENT = \"%\";
 
PERCENT_EQUAL = \"%=\";
 
BANG = \"!\";
 
BANG_EQUAL = \"!=\";
 
CARET = \"^\";
 
CARET_EQUAL = \"^=\";
 
TILDE = \"~\";
"},{"location":"solidity-specification/01-file-structure/09-punctuation/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/","title":"2. Definitions","text":""},{"location":"solidity-specification/02-definitions/#2-definitions","title":"2. Definitions","text":""},{"location":"solidity-specification/02-definitions/01-contracts/","title":"2.1. Contracts","text":""},{"location":"solidity-specification/02-definitions/01-contracts/#21-contracts","title":"2.1. Contracts","text":""},{"location":"solidity-specification/02-definitions/01-contracts/#syntax","title":"Syntax","text":"
ContractDefinition = (* abstract_keyword: *) ABSTRACT_KEYWORD? (* Introduced in 0.6.0 *)                     (* contract_keyword: *) CONTRACT_KEYWORD                     (* name: *) IDENTIFIER                     (* inheritance: *) InheritanceSpecifier?                     (* open_brace: *) OPEN_BRACE                     (* members: *) ContractMembers                     (* close_brace: *) CLOSE_BRACE;
 
InheritanceSpecifier = (* is_keyword: *) IS_KEYWORD                       (* types: *) InheritanceTypes;
 
InheritanceTypes = (* item: *) InheritanceType ((* separator: *) COMMA (* item: *) InheritanceType)*;
 
InheritanceType = (* type_name: *) IdentifierPath                  (* arguments: *) ArgumentsDeclaration?;
 
ContractMembers = (* item: *) ContractMember*;
 
ContractMember = (* variant: *) UsingDirective               | (* variant: *) FunctionDefinition               | (* variant: *) ConstructorDefinition (* Introduced in 0.4.22 *)               | (* variant: *) ReceiveFunctionDefinition (* Introduced in 0.6.0 *)               | (* variant: *) FallbackFunctionDefinition (* Introduced in 0.6.0 *)               | (* variant: *) UnnamedFunctionDefinition (* Deprecated in 0.6.0 *)               | (* variant: *) ModifierDefinition               | (* variant: *) StructDefinition               | (* variant: *) EnumDefinition               | (* variant: *) EventDefinition               | (* variant: *) ErrorDefinition (* Introduced in 0.8.4 *)               | (* variant: *) UserDefinedValueTypeDefinition (* Introduced in 0.8.8 *)               | (* variant: *) StateVariableDefinition;
"},{"location":"solidity-specification/02-definitions/01-contracts/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/02-interfaces/","title":"2.2. Interfaces","text":""},{"location":"solidity-specification/02-definitions/02-interfaces/#22-interfaces","title":"2.2. Interfaces","text":""},{"location":"solidity-specification/02-definitions/02-interfaces/#syntax","title":"Syntax","text":"
InterfaceDefinition = (* interface_keyword: *) INTERFACE_KEYWORD                      (* name: *) IDENTIFIER                      (* inheritance: *) InheritanceSpecifier?                      (* open_brace: *) OPEN_BRACE                      (* members: *) InterfaceMembers                      (* close_brace: *) CLOSE_BRACE;
 
InterfaceMembers = (* item: *) ContractMember*;
"},{"location":"solidity-specification/02-definitions/02-interfaces/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/03-libraries/","title":"2.3. Libraries","text":""},{"location":"solidity-specification/02-definitions/03-libraries/#23-libraries","title":"2.3. Libraries","text":""},{"location":"solidity-specification/02-definitions/03-libraries/#syntax","title":"Syntax","text":"
LibraryDefinition = (* library_keyword: *) LIBRARY_KEYWORD                    (* name: *) IDENTIFIER                    (* open_brace: *) OPEN_BRACE                    (* members: *) LibraryMembers                    (* close_brace: *) CLOSE_BRACE;
 
LibraryMembers = (* item: *) ContractMember*;
"},{"location":"solidity-specification/02-definitions/03-libraries/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/04-structs/","title":"2.4. Structs","text":""},{"location":"solidity-specification/02-definitions/04-structs/#24-structs","title":"2.4. Structs","text":""},{"location":"solidity-specification/02-definitions/04-structs/#syntax","title":"Syntax","text":"
StructDefinition = (* struct_keyword: *) STRUCT_KEYWORD                   (* name: *) IDENTIFIER                   (* open_brace: *) OPEN_BRACE                   (* members: *) StructMembers                   (* close_brace: *) CLOSE_BRACE;
 
StructMembers = (* item: *) StructMember*;
 
StructMember = (* type_name: *) TypeName               (* name: *) IDENTIFIER               (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/02-definitions/04-structs/#struct-types","title":"Struct Types","text":"

Structs are custom defined types that can group several variables. They can be defined inside or outside contracts.

struct Voter {\n    address delegate;\n    uint vote;\n}\n

You can also create new objects of this struct using the following syntax:

contract MyContract {\n    function create() public  {\n        Voter memory v = Voter({\n            delegate: msg.sender,\n            vote: 1\n        });\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/05-enums/","title":"2.5. Enums","text":""},{"location":"solidity-specification/02-definitions/05-enums/#25-enums","title":"2.5. Enums","text":""},{"location":"solidity-specification/02-definitions/05-enums/#syntax","title":"Syntax","text":"
EnumDefinition = (* enum_keyword: *) ENUM_KEYWORD                 (* name: *) IDENTIFIER                 (* open_brace: *) OPEN_BRACE                 (* members: *) EnumMembers                 (* close_brace: *) CLOSE_BRACE;
 
EnumMembers = ((* item: *) IDENTIFIER ((* separator: *) COMMA (* item: *) IDENTIFIER)*)?;
"},{"location":"solidity-specification/02-definitions/05-enums/#enum-types","title":"Enum Types","text":"

Enums can be used to create custom types with a finite set of constant values. Enums can be declared on the file level, outside of contract or library definitions.

enum ActionChoices {\n    One,\n    Two\n}\n\ncontract MyContract {\n    function choose() public pure returns (ActionChoices) {\n        return ActionChoices.Two;\n    }\n}\n

Enums require at least one member, and its default value when declared is the first member. Enums cannot have more than 256 members.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/06-constants/","title":"2.6. Constants","text":""},{"location":"solidity-specification/02-definitions/06-constants/#26-constants","title":"2.6. Constants","text":""},{"location":"solidity-specification/02-definitions/06-constants/#syntax","title":"Syntax","text":"
(* Introduced in 0.7.4 *)ConstantDefinition = (* type_name: *) TypeName                     (* constant_keyword: *) CONSTANT_KEYWORD                     (* name: *) IDENTIFIER                     (* equal: *) EQUAL                     (* value: *) Expression                     (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/02-definitions/06-constants/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/07-state-variables/","title":"2.7. State Variables","text":""},{"location":"solidity-specification/02-definitions/07-state-variables/#27-state-variables","title":"2.7. State Variables","text":""},{"location":"solidity-specification/02-definitions/07-state-variables/#syntax","title":"Syntax","text":"
StateVariableDefinition = (* type_name: *) TypeName                          (* attributes: *) StateVariableAttributes                          (* name: *) IDENTIFIER                          (* value: *) StateVariableDefinitionValue?                          (* semicolon: *) SEMICOLON;
 
StateVariableDefinitionValue = (* equal: *) EQUAL                               (* value: *) Expression;
 
StateVariableAttributes = (* item: *) StateVariableAttribute*;
 
StateVariableAttribute = (* variant: *) OverrideSpecifier (* Introduced in 0.6.0 *)                       | (* variant: *) CONSTANT_KEYWORD                       | (* variant: *) INTERNAL_KEYWORD                       | (* variant: *) PRIVATE_KEYWORD                       | (* variant: *) PUBLIC_KEYWORD                       | (* variant: *) IMMUTABLE_KEYWORD (* Introduced in 0.6.5 *)                       | (* variant: *) TRANSIENT_KEYWORD; (* Introduced in 0.8.27 *)
"},{"location":"solidity-specification/02-definitions/07-state-variables/#state-variables","title":"State Variables","text":"

State variables are variables whose values are permanently stored in contract storage.

contract MyContract {\n    uint myStateVariable;\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/08-functions/","title":"2.8. Functions","text":""},{"location":"solidity-specification/02-definitions/08-functions/#28-functions","title":"2.8. Functions","text":""},{"location":"solidity-specification/02-definitions/08-functions/#syntax","title":"Syntax","text":"
FunctionDefinition = (* function_keyword: *) FUNCTION_KEYWORD                     (* name: *) FunctionName                     (* parameters: *) ParametersDeclaration                     (* attributes: *) FunctionAttributes                     (* returns: *) ReturnsDeclaration?                     (* body: *) FunctionBody;
 
FunctionName = (* variant: *) IDENTIFIER             | (* variant: *) FALLBACK_KEYWORD             | (* variant: *) RECEIVE_KEYWORD;
 
ParametersDeclaration = (* open_paren: *) OPEN_PAREN                        (* parameters: *) Parameters                        (* close_paren: *) CLOSE_PAREN;
 
Parameters = ((* item: *) Parameter ((* separator: *) COMMA (* item: *) Parameter)*)?;
 
Parameter = (* type_name: *) TypeName            (* storage_location: *) StorageLocation?            (* name: *) IDENTIFIER?;
 
FunctionAttributes = (* item: *) FunctionAttribute*;
 
FunctionAttribute = (* variant: *) ModifierInvocation                  | (* variant: *) OverrideSpecifier (* Introduced in 0.6.0 *)                  | (* variant: *) CONSTANT_KEYWORD (* Deprecated in 0.5.0 *)                  | (* variant: *) EXTERNAL_KEYWORD                  | (* variant: *) INTERNAL_KEYWORD                  | (* variant: *) PAYABLE_KEYWORD                  | (* variant: *) PRIVATE_KEYWORD                  | (* variant: *) PUBLIC_KEYWORD                  | (* variant: *) PURE_KEYWORD (* Introduced in 0.4.16 *)                  | (* variant: *) VIEW_KEYWORD (* Introduced in 0.4.16 *)                  | (* variant: *) VIRTUAL_KEYWORD; (* Introduced in 0.6.0 *)
 
(* Introduced in 0.6.0 *)OverrideSpecifier = (* override_keyword: *) OVERRIDE_KEYWORD                    (* overridden: *) OverridePathsDeclaration?;
 
(* Introduced in 0.6.0 *)OverridePathsDeclaration = (* open_paren: *) OPEN_PAREN                           (* paths: *) OverridePaths                           (* close_paren: *) CLOSE_PAREN;
 
(* Introduced in 0.6.0 *)OverridePaths = (* item: *) IdentifierPath ((* separator: *) COMMA (* item: *) IdentifierPath)*;
 
ReturnsDeclaration = (* returns_keyword: *) RETURNS_KEYWORD                     (* variables: *) ParametersDeclaration;
 
FunctionBody = (* variant: *) Block             | (* variant: *) SEMICOLON;
 
(* Introduced in 0.4.22 *)ConstructorDefinition = (* constructor_keyword: *) CONSTRUCTOR_KEYWORD                        (* parameters: *) ParametersDeclaration                        (* attributes: *) ConstructorAttributes                        (* body: *) Block;
 
(* Introduced in 0.4.22 *)ConstructorAttributes = (* item: *) ConstructorAttribute*;
 
(* Introduced in 0.4.22 *)ConstructorAttribute = (* variant: *) ModifierInvocation                     | (* variant: *) INTERNAL_KEYWORD                     | (* variant: *) OVERRIDE_KEYWORD (* Introduced in 0.6.0 and deprecated in 0.6.7. *)                     | (* variant: *) PAYABLE_KEYWORD                     | (* variant: *) PUBLIC_KEYWORD                     | (* variant: *) VIRTUAL_KEYWORD; (* Introduced in 0.6.0 and deprecated in 0.6.7. *)
 
(* Deprecated in 0.6.0 *)UnnamedFunctionDefinition = (* function_keyword: *) FUNCTION_KEYWORD                            (* parameters: *) ParametersDeclaration                            (* attributes: *) UnnamedFunctionAttributes                            (* body: *) FunctionBody;
 
(* Deprecated in 0.6.0 *)UnnamedFunctionAttributes = (* item: *) UnnamedFunctionAttribute*;
 
(* Deprecated in 0.6.0 *)UnnamedFunctionAttribute = (* variant: *) ModifierInvocation                         | (* variant: *) CONSTANT_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) EXTERNAL_KEYWORD                         | (* variant: *) INTERNAL_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) PAYABLE_KEYWORD                         | (* variant: *) PRIVATE_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) PUBLIC_KEYWORD (* Deprecated in 0.5.0 *)                         | (* variant: *) PURE_KEYWORD (* Introduced in 0.4.16 and deprecated in 0.6.0. *)                         | (* variant: *) VIEW_KEYWORD; (* Introduced in 0.4.16 and deprecated in 0.6.0. *)
 
(* Introduced in 0.6.0 *)FallbackFunctionDefinition = (* fallback_keyword: *) FALLBACK_KEYWORD                             (* parameters: *) ParametersDeclaration                             (* attributes: *) FallbackFunctionAttributes                             (* returns: *) ReturnsDeclaration?                             (* body: *) FunctionBody;
 
(* Introduced in 0.6.0 *)FallbackFunctionAttributes = (* item: *) FallbackFunctionAttribute*;
 
(* Introduced in 0.6.0 *)FallbackFunctionAttribute = (* variant: *) ModifierInvocation                          | (* variant: *) OverrideSpecifier                          | (* variant: *) EXTERNAL_KEYWORD                          | (* variant: *) PAYABLE_KEYWORD                          | (* variant: *) PURE_KEYWORD                          | (* variant: *) VIEW_KEYWORD                          | (* variant: *) VIRTUAL_KEYWORD;
 
(* Introduced in 0.6.0 *)ReceiveFunctionDefinition = (* receive_keyword: *) RECEIVE_KEYWORD                            (* parameters: *) ParametersDeclaration                            (* attributes: *) ReceiveFunctionAttributes                            (* body: *) FunctionBody;
 
(* Introduced in 0.6.0 *)ReceiveFunctionAttributes = (* item: *) ReceiveFunctionAttribute*;
 
(* Introduced in 0.6.0 *)ReceiveFunctionAttribute = (* variant: *) ModifierInvocation                         | (* variant: *) OverrideSpecifier                         | (* variant: *) EXTERNAL_KEYWORD                         | (* variant: *) PAYABLE_KEYWORD                         | (* variant: *) VIRTUAL_KEYWORD;
"},{"location":"solidity-specification/02-definitions/08-functions/#function-definitions","title":"Function Definitions","text":"

Functions are the executable units of code. Functions are usually defined inside a contract, but they can also be defined outside of contracts.

contract MyContract {\n    function contractFunction() public {\n        // Inside the contract\n    }\n}\n\nfunction helperFunction() {\n    // Outside the contract\n}\n

Functions can be overloaded, where multiple functions with the same name, but with different parameters, can co-exist.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/09-modifiers/","title":"2.9. Modifiers","text":""},{"location":"solidity-specification/02-definitions/09-modifiers/#29-modifiers","title":"2.9. Modifiers","text":""},{"location":"solidity-specification/02-definitions/09-modifiers/#syntax","title":"Syntax","text":"
ModifierDefinition = (* modifier_keyword: *) MODIFIER_KEYWORD                     (* name: *) IDENTIFIER                     (* parameters: *) ParametersDeclaration?                     (* attributes: *) ModifierAttributes                     (* body: *) FunctionBody;
 
ModifierAttributes = (* item: *) ModifierAttribute*;
 
ModifierAttribute = (* variant: *) OverrideSpecifier (* Introduced in 0.6.0 *)                  | (* variant: *) VIRTUAL_KEYWORD; (* Introduced in 0.6.0 *)
 
ModifierInvocation = (* name: *) IdentifierPath                     (* arguments: *) ArgumentsDeclaration?;
"},{"location":"solidity-specification/02-definitions/09-modifiers/#function-modifiers","title":"Function Modifiers","text":"

Function modifiers can be used to amend the semantics of functions in a declarative way:

contract MyContract {\n    modifier onlySeller() {\n        require(msg.sender == seller, \"Only seller can call this.\");\n        _; // Function body will be inserted here\n    }\n\n    function myFunction() public view onlySeller {\n        // Code here will be executed after `onlySeller` is executed.\n    }\n}\n

Unlike functions, modifiers cannot be overloaded.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/10-events/","title":"2.10. Events","text":""},{"location":"solidity-specification/02-definitions/10-events/#210-events","title":"2.10. Events","text":""},{"location":"solidity-specification/02-definitions/10-events/#syntax","title":"Syntax","text":"
EventDefinition = (* event_keyword: *) EVENT_KEYWORD                  (* name: *) IDENTIFIER                  (* parameters: *) EventParametersDeclaration                  (* anonymous_keyword: *) ANONYMOUS_KEYWORD?                  (* semicolon: *) SEMICOLON;
 
EventParametersDeclaration = (* open_paren: *) OPEN_PAREN                             (* parameters: *) EventParameters                             (* close_paren: *) CLOSE_PAREN;
 
EventParameters = ((* item: *) EventParameter ((* separator: *) COMMA (* item: *) EventParameter)*)?;
 
EventParameter = (* type_name: *) TypeName                 (* indexed_keyword: *) INDEXED_KEYWORD?                 (* name: *) IDENTIFIER?;
"},{"location":"solidity-specification/02-definitions/10-events/#event-definitions","title":"Event Definitions","text":"

Events are convenient interfaces with the EVM logging facilities. They have to be defined inside a contract:

contract MyContract {\n    // Defining an event\n    event BidPlacedEvent(address bidder, uint amount);\n\n    function bid() public payable {\n        // Triggering an event\n        emit BidPlacedEvent(msg.sender, msg.value);\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/","title":"2.11. User Defined Value Types","text":""},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/#211-user-defined-value-types","title":"2.11. User Defined Value Types","text":""},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/#syntax","title":"Syntax","text":"
(* Introduced in 0.8.8 *)UserDefinedValueTypeDefinition = (* type_keyword: *) TYPE_KEYWORD                                 (* name: *) IDENTIFIER                                 (* is_keyword: *) IS_KEYWORD                                 (* value_type: *) ElementaryType                                 (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/02-definitions/11-user-defined-value-types/#user-defined-value-types","title":"User Defined Value Types","text":"

A user defined value type allows creating a zero cost abstraction over an elementary value type. This is similar to a type alias. A user defined value type is defined using type C is V, where C is the name of the newly introduced type and V has to be a built-in value type (the underlying type).

type MyInteger is uint256;\n\nlibrary MyLibrary {\n    function add(MyInteger a, MyInteger b) internal pure returns (MyInteger) {\n        return MyInteger.wrap(MyInteger.unwrap(a) + MyInteger.unwrap(b));\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/02-definitions/12-errors/","title":"2.12. Errors","text":""},{"location":"solidity-specification/02-definitions/12-errors/#212-errors","title":"2.12. Errors","text":""},{"location":"solidity-specification/02-definitions/12-errors/#syntax","title":"Syntax","text":"
(* Introduced in 0.8.4 *)ErrorDefinition = (* error_keyword: *) ERROR_KEYWORD                  (* name: *) IDENTIFIER                  (* members: *) ErrorParametersDeclaration                  (* semicolon: *) SEMICOLON;
 
(* Introduced in 0.8.4 *)ErrorParametersDeclaration = (* open_paren: *) OPEN_PAREN                             (* parameters: *) ErrorParameters                             (* close_paren: *) CLOSE_PAREN;
 
(* Introduced in 0.8.4 *)ErrorParameters = ((* item: *) ErrorParameter ((* separator: *) COMMA (* item: *) ErrorParameter)*)?;
 
(* Introduced in 0.8.4 *)ErrorParameter = (* type_name: *) TypeName                 (* name: *) IDENTIFIER?;
"},{"location":"solidity-specification/02-definitions/12-errors/#error-definitions","title":"Error Definitions","text":"

Errors allow you to define descriptive names and data for failure situations. Errors can be used in revert statements. In comparison to string descriptions, errors are much cheaper and allow you to encode additional data. You can use NatSpec to describe the error to the user. They can also be defined inside or outside contracts:

contract Token {\n    error NotEnoughFunds(uint requested, uint available);\n\n    function transfer(address to, uint amount) public {\n        uint balance = balances[msg.sender];\n        if (balance < amount)\n            revert NotEnoughFunds(amount, balance);\n\n        // Continue with the transfer...\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/03-types/","title":"3. Types","text":""},{"location":"solidity-specification/03-types/#3-types","title":"3. Types","text":""},{"location":"solidity-specification/03-types/01-advanced-types/","title":"3.1. Advanced Types","text":""},{"location":"solidity-specification/03-types/01-advanced-types/#31-advanced-types","title":"3.1. Advanced Types","text":""},{"location":"solidity-specification/03-types/01-advanced-types/#syntax","title":"Syntax","text":"
TypeName = (* variant: *) ArrayTypeName         | (* variant: *) FunctionType         | (* variant: *) MappingType         | (* variant: *) ElementaryType         | (* variant: *) IdentifierPath;
 
(* Postfix unary operator *)ArrayTypeName = (* operand: *) TypeName                (* open_bracket: *) OPEN_BRACKET                (* index: *) Expression?                (* close_bracket: *) CLOSE_BRACKET;
 
FunctionType = (* function_keyword: *) FUNCTION_KEYWORD               (* parameters: *) ParametersDeclaration               (* attributes: *) FunctionTypeAttributes               (* returns: *) ReturnsDeclaration?;
 
FunctionTypeAttributes = (* item: *) FunctionTypeAttribute*;
 
FunctionTypeAttribute = (* variant: *) INTERNAL_KEYWORD                      | (* variant: *) EXTERNAL_KEYWORD                      | (* variant: *) PRIVATE_KEYWORD                      | (* variant: *) PUBLIC_KEYWORD                      | (* variant: *) CONSTANT_KEYWORD (* Deprecated in 0.5.0 *)                      | (* variant: *) PURE_KEYWORD (* Introduced in 0.4.16 *)                      | (* variant: *) VIEW_KEYWORD (* Introduced in 0.4.16 *)                      | (* variant: *) PAYABLE_KEYWORD;
 
MappingType = (* mapping_keyword: *) MAPPING_KEYWORD              (* open_paren: *) OPEN_PAREN              (* key_type: *) MappingKey              (* equal_greater_than: *) EQUAL_GREATER_THAN              (* value_type: *) MappingValue              (* close_paren: *) CLOSE_PAREN;
 
MappingKey = (* key_type: *) MappingKeyType             (* name: *) IDENTIFIER?; (* Introduced in 0.8.18 *)
 
MappingKeyType = (* variant: *) ElementaryType               | (* variant: *) IdentifierPath;
 
MappingValue = (* type_name: *) TypeName               (* name: *) IDENTIFIER?; (* Introduced in 0.8.18 *)
"},{"location":"solidity-specification/03-types/01-advanced-types/#function-types","title":"Function Types","text":"

Function types are the types of functions. Variables of function type can be assigned from functions and function parameters of function type can be used to pass functions to and return functions from function calls. They come in two flavors, internal and external.

Function types are notated as follows:

function (<parameter types>) {internal|external} [pure|view|payable] [returns (<return types>)]\n

In contrast to the parameter types, the return types cannot be empty. If the function type should not return anything, the whole returns (<return types>) part has to be omitted.

By default, function types are internal, so the internal keyword can be omitted. Note that this only applies to function types. Visibility has to be specified explicitly for functions defined in contracts, they do not have a default.

contract Oracle {\n    Request[] private requests;\n\n    function query(bytes memory data, function(uint) external callback) public {\n        requests.push(Request(data, callback));\n    }\n\n    function reply(uint requestID, uint response) public {\n        requests[requestID].callback(response);\n    }\n}\n
"},{"location":"solidity-specification/03-types/01-advanced-types/#mapping-types","title":"Mapping Types","text":"

Mapping types use the syntax mapping(_KeyType => _ValueType) and variables of mapping type are declared using the syntax mapping(_KeyType => _ValueType) _VariableName.

contract MappingExample {\n    mapping(address => uint) public balances;\n\n    function update(uint newBalance) public {\n        balances[msg.sender] = newBalance;\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/03-types/02-elementary-types/","title":"3.2. Elementary Types","text":""},{"location":"solidity-specification/03-types/02-elementary-types/#32-elementary-types","title":"3.2. Elementary Types","text":""},{"location":"solidity-specification/03-types/02-elementary-types/#syntax","title":"Syntax","text":"
ElementaryType = (* variant: *) BOOL_KEYWORD               | (* variant: *) BYTE_KEYWORD (* Deprecated in 0.8.0 *)               | (* variant: *) STRING_KEYWORD               | (* variant: *) AddressType               | (* variant: *) BYTES_KEYWORD               | (* variant: *) INT_KEYWORD               | (* variant: *) UINT_KEYWORD               | (* variant: *) FIXED_KEYWORD               | (* variant: *) UFIXED_KEYWORD;
 
AddressType = (* address_keyword: *) ADDRESS_KEYWORD              (* payable_keyword: *) PAYABLE_KEYWORD?;
"},{"location":"solidity-specification/03-types/02-elementary-types/#address-types","title":"Address Types","text":"

The address type comes in two flavours, which are largely identical:

Hexadecimal literals that pass the address checksum test, for example 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF are of address type. Hexadecimal literals that are between 39 and 41 digits long and do not pass the checksum test produce an error. You can prepend (for int types) or append (for bytesNN types) zeros to remove the error.

"},{"location":"solidity-specification/03-types/02-elementary-types/#fixed-size-byte-arrays","title":"Fixed-Size Byte Arrays","text":"

The value types bytes1, bytes2, bytes3, \u2026, bytes32 hold a sequence of bytes from one to up to 32.

"},{"location":"solidity-specification/03-types/02-elementary-types/#dynamic-string-and-byte-arrays","title":"Dynamic String and Byte Arrays","text":"

The bytes type is similar to bytes1[], but it is packed tightly in calldata and memory.

Variables of type string are equal to bytes but do not allow length or index access. If you want to access the byte-representation of a string s, use bytes(s). Keep in mind that you are accessing the low-level bytes of the UTF-8 representation, and not the individual characters.

Memory arrays with dynamic length can be created using the new keyword:

contract MyContract {\n    function myFunction(uint length) public pure {\n        bytes memory b = new bytes(length);\n    }\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/","title":"4. Statements","text":""},{"location":"solidity-specification/04-statements/#4-statements","title":"4. Statements","text":""},{"location":"solidity-specification/04-statements/01-blocks/","title":"4.1. Blocks","text":""},{"location":"solidity-specification/04-statements/01-blocks/#41-blocks","title":"4.1. Blocks","text":""},{"location":"solidity-specification/04-statements/01-blocks/#syntax","title":"Syntax","text":"
Block = (* open_brace: *) OPEN_BRACE        (* statements: *) Statements        (* close_brace: *) CLOSE_BRACE;
 
Statements = (* item: *) Statement*;
 
Statement = (* variant: *) IfStatement          | (* variant: *) ForStatement          | (* variant: *) WhileStatement          | (* variant: *) DoWhileStatement          | (* variant: *) ContinueStatement          | (* variant: *) BreakStatement          | (* variant: *) ReturnStatement          | (* variant: *) ThrowStatement (* Deprecated in 0.5.0 *)          | (* variant: *) EmitStatement (* Introduced in 0.4.21 *)          | (* variant: *) TryStatement (* Introduced in 0.6.0 *)          | (* variant: *) RevertStatement (* Introduced in 0.8.4 *)          | (* variant: *) AssemblyStatement          | (* variant: *) Block          | (* variant: *) UncheckedBlock (* Introduced in 0.8.0 *)          | (* variant: *) TupleDeconstructionStatement          | (* variant: *) VariableDeclarationStatement          | (* variant: *) ExpressionStatement;
 
(* Introduced in 0.8.0 *)UncheckedBlock = (* unchecked_keyword: *) UNCHECKED_KEYWORD                 (* block: *) Block;
 
ExpressionStatement = (* expression: *) Expression                      (* semicolon: *) SEMICOLON;
 
AssemblyStatement = (* assembly_keyword: *) ASSEMBLY_KEYWORD                    (* label: *) StringLiteral?                    (* flags: *) AssemblyFlagsDeclaration?                    (* body: *) YulBlock;
 
AssemblyFlagsDeclaration = (* open_paren: *) OPEN_PAREN                           (* flags: *) AssemblyFlags                           (* close_paren: *) CLOSE_PAREN;
 
AssemblyFlags = (* item: *) StringLiteral ((* separator: *) COMMA (* item: *) StringLiteral)*;
"},{"location":"solidity-specification/04-statements/01-blocks/#unchecked-blocks","title":"Unchecked Blocks","text":"

Starting with v0.8.0, by default, all arithmetic operations are checked for underflow or overflow, which means that if the result of an operation falls outside the value range of the type, the call is reverted through a failing assertion. This can be disabled using the unchecked block, resulting in wrapping arithmetic:

unchecked {\n  i++;\n}\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/02-declaration-statements/","title":"4.2. Declaration Statements","text":""},{"location":"solidity-specification/04-statements/02-declaration-statements/#42-declaration-statements","title":"4.2. Declaration Statements","text":""},{"location":"solidity-specification/04-statements/02-declaration-statements/#syntax","title":"Syntax","text":"
TupleDeconstructionStatement = (* var_keyword: *) VAR_KEYWORD? (* Deprecated in 0.5.0 *)                               (* open_paren: *) OPEN_PAREN                               (* elements: *) TupleDeconstructionElements                               (* close_paren: *) CLOSE_PAREN                               (* equal: *) EQUAL                               (* expression: *) Expression                               (* semicolon: *) SEMICOLON;
 
TupleDeconstructionElements = (* item: *) TupleDeconstructionElement ((* separator: *) COMMA (* item: *) TupleDeconstructionElement)*;
 
TupleDeconstructionElement = (* member: *) TupleMember?;
 
TupleMember = (* variant: *) TypedTupleMember            | (* variant: *) UntypedTupleMember;
 
TypedTupleMember = (* type_name: *) TypeName                   (* storage_location: *) StorageLocation?                   (* name: *) IDENTIFIER;
 
UntypedTupleMember = (* storage_location: *) StorageLocation?                     (* name: *) IDENTIFIER;
 
VariableDeclarationStatement = (* variable_type: *) VariableDeclarationType                               (* storage_location: *) StorageLocation?                               (* name: *) IDENTIFIER                               (* value: *) VariableDeclarationValue?                               (* semicolon: *) SEMICOLON;
 
VariableDeclarationType = (* variant: *) TypeName                        | (* variant: *) VAR_KEYWORD; (* Deprecated in 0.5.0 *)
 
VariableDeclarationValue = (* equal: *) EQUAL                           (* expression: *) Expression;
 
StorageLocation = (* variant: *) MEMORY_KEYWORD                | (* variant: *) STORAGE_KEYWORD                | (* variant: *) CALL_DATA_KEYWORD; (* Introduced in 0.5.0 *)
"},{"location":"solidity-specification/04-statements/02-declaration-statements/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/03-control-statements/","title":"4.3. Control Statements","text":""},{"location":"solidity-specification/04-statements/03-control-statements/#43-control-statements","title":"4.3. Control Statements","text":""},{"location":"solidity-specification/04-statements/03-control-statements/#syntax","title":"Syntax","text":"
IfStatement = (* if_keyword: *) IF_KEYWORD              (* open_paren: *) OPEN_PAREN              (* condition: *) Expression              (* close_paren: *) CLOSE_PAREN              (* body: *) Statement              (* else_branch: *) ElseBranch?;
 
ElseBranch = (* else_keyword: *) ELSE_KEYWORD             (* body: *) Statement;
 
ForStatement = (* for_keyword: *) FOR_KEYWORD               (* open_paren: *) OPEN_PAREN               (* initialization: *) ForStatementInitialization               (* condition: *) ForStatementCondition               (* iterator: *) Expression?               (* close_paren: *) CLOSE_PAREN               (* body: *) Statement;
 
ForStatementInitialization = (* variant: *) TupleDeconstructionStatement                           | (* variant: *) VariableDeclarationStatement                           | (* variant: *) ExpressionStatement                           | (* variant: *) SEMICOLON;
 
ForStatementCondition = (* variant: *) ExpressionStatement                      | (* variant: *) SEMICOLON;
 
WhileStatement = (* while_keyword: *) WHILE_KEYWORD                 (* open_paren: *) OPEN_PAREN                 (* condition: *) Expression                 (* close_paren: *) CLOSE_PAREN                 (* body: *) Statement;
 
DoWhileStatement = (* do_keyword: *) DO_KEYWORD                   (* body: *) Statement                   (* while_keyword: *) WHILE_KEYWORD                   (* open_paren: *) OPEN_PAREN                   (* condition: *) Expression                   (* close_paren: *) CLOSE_PAREN                   (* semicolon: *) SEMICOLON;
 
ContinueStatement = (* continue_keyword: *) CONTINUE_KEYWORD                    (* semicolon: *) SEMICOLON;
 
BreakStatement = (* break_keyword: *) BREAK_KEYWORD                 (* semicolon: *) SEMICOLON;
 
ReturnStatement = (* return_keyword: *) RETURN_KEYWORD                  (* expression: *) Expression?                  (* semicolon: *) SEMICOLON;
 
(* Introduced in 0.4.21 *)EmitStatement = (* emit_keyword: *) EMIT_KEYWORD                (* event: *) IdentifierPath                (* arguments: *) ArgumentsDeclaration                (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/04-statements/03-control-statements/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/04-statements/04-error-handling/","title":"4.4. Error Handling","text":""},{"location":"solidity-specification/04-statements/04-error-handling/#44-error-handling","title":"4.4. Error Handling","text":""},{"location":"solidity-specification/04-statements/04-error-handling/#syntax","title":"Syntax","text":"
(* Introduced in 0.6.0 *)TryStatement = (* try_keyword: *) TRY_KEYWORD               (* expression: *) Expression               (* returns: *) ReturnsDeclaration?               (* body: *) Block               (* catch_clauses: *) CatchClauses;
 
(* Introduced in 0.6.0 *)CatchClauses = (* item: *) CatchClause+;
 
(* Introduced in 0.6.0 *)CatchClause = (* catch_keyword: *) CATCH_KEYWORD              (* error: *) CatchClauseError?              (* body: *) Block;
 
(* Introduced in 0.6.0 *)CatchClauseError = (* name: *) IDENTIFIER?                   (* parameters: *) ParametersDeclaration;
 
(* Introduced in 0.8.4 *)RevertStatement = (* revert_keyword: *) REVERT_KEYWORD                  (* error: *) IdentifierPath?                  (* arguments: *) ArgumentsDeclaration                  (* semicolon: *) SEMICOLON;
 
(* Deprecated in 0.5.0 *)ThrowStatement = (* throw_keyword: *) THROW_KEYWORD                 (* semicolon: *) SEMICOLON;
"},{"location":"solidity-specification/04-statements/04-error-handling/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/","title":"5. Expressions","text":""},{"location":"solidity-specification/05-expressions/#5-expressions","title":"5. Expressions","text":""},{"location":"solidity-specification/05-expressions/01-base-expressions/","title":"5.1. Base Expressions","text":""},{"location":"solidity-specification/05-expressions/01-base-expressions/#51-base-expressions","title":"5.1. Base Expressions","text":""},{"location":"solidity-specification/05-expressions/01-base-expressions/#syntax","title":"Syntax","text":"
Expression = (* variant: *) AssignmentExpression           | (* variant: *) ConditionalExpression           | (* variant: *) OrExpression           | (* variant: *) AndExpression           | (* variant: *) EqualityExpression           | (* variant: *) ComparisonExpression           | (* variant: *) BitwiseOrExpression           | (* variant: *) BitwiseXorExpression           | (* variant: *) BitwiseAndExpression           | (* variant: *) ShiftExpression           | (* variant: *) AdditiveExpression           | (* variant: *) MultiplicativeExpression           | (* variant: *) ExponentiationExpression           | (* variant: *) PostfixExpression           | (* variant: *) PrefixExpression           | (* variant: *) FunctionCallExpression           | (* variant: *) CallOptionsExpression           | (* variant: *) MemberAccessExpression           | (* variant: *) IndexAccessExpression           | (* variant: *) NewExpression           | (* variant: *) TupleExpression           | (* variant: *) TypeExpression (* Introduced in 0.5.3 *)           | (* variant: *) ArrayExpression           | (* variant: *) HexNumberExpression           | (* variant: *) DecimalNumberExpression           | (* variant: *) StringExpression           | (* variant: *) ElementaryType           | (* variant: *) PAYABLE_KEYWORD (* Introduced in 0.6.0 *)           | (* variant: *) THIS_KEYWORD           | (* variant: *) SUPER_KEYWORD           | (* variant: *) TRUE_KEYWORD           | (* variant: *) FALSE_KEYWORD           | (* variant: *) IDENTIFIER;
 
(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) BAR_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) PLUS_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) MINUS_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) CARET_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) SLASH_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) PERCENT_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) ASTERISK_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) AMPERSAND_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) LESS_THAN_LESS_THAN_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN_GREATER_THAN_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)AssignmentExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN_GREATER_THAN_GREATER_THAN_EQUAL                       (* right_operand: *) Expression;
 
(* Postfix unary operator *)ConditionalExpression = (* operand: *) Expression                        (* question_mark: *) QUESTION_MARK                        (* true_expression: *) Expression                        (* colon: *) COLON                        (* false_expression: *) Expression;
 
(* Left-associative binary operator *)OrExpression = (* left_operand: *) Expression               (* operator: *) BAR_BAR               (* right_operand: *) Expression;
 
(* Left-associative binary operator *)AndExpression = (* left_operand: *) Expression                (* operator: *) AMPERSAND_AMPERSAND                (* right_operand: *) Expression;
 
(* Left-associative binary operator *)EqualityExpression = (* left_operand: *) Expression                     (* operator: *) EQUAL_EQUAL                     (* right_operand: *) Expression;(* Left-associative binary operator *)EqualityExpression = (* left_operand: *) Expression                     (* operator: *) BANG_EQUAL                     (* right_operand: *) Expression;
 
(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) LESS_THAN                       (* right_operand: *) Expression;(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN                       (* right_operand: *) Expression;(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) LESS_THAN_EQUAL                       (* right_operand: *) Expression;(* Left-associative binary operator *)ComparisonExpression = (* left_operand: *) Expression                       (* operator: *) GREATER_THAN_EQUAL                       (* right_operand: *) Expression;
 
(* Left-associative binary operator *)BitwiseOrExpression = (* left_operand: *) Expression                      (* operator: *) BAR                      (* right_operand: *) Expression;
 
(* Left-associative binary operator *)BitwiseXorExpression = (* left_operand: *) Expression                       (* operator: *) CARET                       (* right_operand: *) Expression;
 
(* Left-associative binary operator *)BitwiseAndExpression = (* left_operand: *) Expression                       (* operator: *) AMPERSAND                       (* right_operand: *) Expression;
 
(* Left-associative binary operator *)ShiftExpression = (* left_operand: *) Expression                  (* operator: *) LESS_THAN_LESS_THAN                  (* right_operand: *) Expression;(* Left-associative binary operator *)ShiftExpression = (* left_operand: *) Expression                  (* operator: *) GREATER_THAN_GREATER_THAN                  (* right_operand: *) Expression;(* Left-associative binary operator *)ShiftExpression = (* left_operand: *) Expression                  (* operator: *) GREATER_THAN_GREATER_THAN_GREATER_THAN                  (* right_operand: *) Expression;
 
(* Left-associative binary operator *)AdditiveExpression = (* left_operand: *) Expression                     (* operator: *) PLUS                     (* right_operand: *) Expression;(* Left-associative binary operator *)AdditiveExpression = (* left_operand: *) Expression                     (* operator: *) MINUS                     (* right_operand: *) Expression;
 
(* Left-associative binary operator *)MultiplicativeExpression = (* left_operand: *) Expression                           (* operator: *) ASTERISK                           (* right_operand: *) Expression;(* Left-associative binary operator *)MultiplicativeExpression = (* left_operand: *) Expression                           (* operator: *) SLASH                           (* right_operand: *) Expression;(* Left-associative binary operator *)MultiplicativeExpression = (* left_operand: *) Expression                           (* operator: *) PERCENT                           (* right_operand: *) Expression;
 
(* Left-associative binary operator *)(* Deprecated in 0.8.0 *)ExponentiationExpression = (* left_operand: *) Expression                           (* operator: *) ASTERISK_ASTERISK                           (* right_operand: *) Expression;(* Right-associative binary operator *)(* Introduced in 0.8.0 *)ExponentiationExpression = (* left_operand: *) Expression                           (* operator: *) ASTERISK_ASTERISK                           (* right_operand: *) Expression;
 
(* Postfix unary operator *)PostfixExpression = (* operand: *) Expression                    (* operator: *) PLUS_PLUS;(* Postfix unary operator *)PostfixExpression = (* operand: *) Expression                    (* operator: *) MINUS_MINUS;
 
(* Prefix unary operator *)PrefixExpression = (* operator: *) PLUS_PLUS                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) MINUS_MINUS                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) TILDE                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) BANG                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) MINUS                   (* operand: *) Expression;(* Prefix unary operator *)(* Deprecated in 0.5.0 *)PrefixExpression = (* operator: *) PLUS                   (* operand: *) Expression;(* Prefix unary operator *)PrefixExpression = (* operator: *) DELETE_KEYWORD                   (* operand: *) Expression;
 
(* Postfix unary operator *)FunctionCallExpression = (* operand: *) Expression                         (* arguments: *) ArgumentsDeclaration;
 
(* Postfix unary operator *)(* Introduced in 0.6.2 *)CallOptionsExpression = (* operand: *) Expression                        (* open_brace: *) OPEN_BRACE                        (* options: *) CallOptions                        (* close_brace: *) CLOSE_BRACE;
 
(* Postfix unary operator *)MemberAccessExpression = (* operand: *) Expression                         (* period: *) PERIOD                         (* member: *) IDENTIFIER;
 
(* Postfix unary operator *)IndexAccessExpression = (* operand: *) Expression                        (* open_bracket: *) OPEN_BRACKET                        (* start: *) Expression?                        (* end: *) IndexAccessEnd?                        (* close_bracket: *) CLOSE_BRACKET;
 
IndexAccessEnd = (* colon: *) COLON                 (* end: *) Expression?;
"},{"location":"solidity-specification/05-expressions/01-base-expressions/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/02-function-calls/","title":"5.2. Function Calls","text":""},{"location":"solidity-specification/05-expressions/02-function-calls/#52-function-calls","title":"5.2. Function Calls","text":""},{"location":"solidity-specification/05-expressions/02-function-calls/#syntax","title":"Syntax","text":"
ArgumentsDeclaration = (* variant: *) PositionalArgumentsDeclaration                     | (* variant: *) NamedArgumentsDeclaration;
 
PositionalArgumentsDeclaration = (* open_paren: *) OPEN_PAREN                                 (* arguments: *) PositionalArguments                                 (* close_paren: *) CLOSE_PAREN;
 
PositionalArguments = ((* item: *) Expression ((* separator: *) COMMA (* item: *) Expression)*)?;
 
NamedArgumentsDeclaration = (* open_paren: *) OPEN_PAREN                            (* arguments: *) NamedArgumentGroup?                            (* close_paren: *) CLOSE_PAREN;
 
NamedArgumentGroup = (* open_brace: *) OPEN_BRACE                     (* arguments: *) NamedArguments                     (* close_brace: *) CLOSE_BRACE;
 
NamedArguments = ((* item: *) NamedArgument ((* separator: *) COMMA (* item: *) NamedArgument)*)?;
 
(* Introduced in 0.6.2 *)CallOptions = (* item: *) NamedArgument ((* separator: *) COMMA (* item: *) NamedArgument)*;
 
NamedArgument = (* name: *) IDENTIFIER                (* colon: *) COLON                (* value: *) Expression;
"},{"location":"solidity-specification/05-expressions/02-function-calls/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/03-primary-expressions/","title":"5.3. Primary Expressions","text":""},{"location":"solidity-specification/05-expressions/03-primary-expressions/#53-primary-expressions","title":"5.3. Primary Expressions","text":""},{"location":"solidity-specification/05-expressions/03-primary-expressions/#syntax","title":"Syntax","text":"
(* Introduced in 0.5.3 *)TypeExpression = (* type_keyword: *) TYPE_KEYWORD                 (* open_paren: *) OPEN_PAREN                 (* type_name: *) TypeName                 (* close_paren: *) CLOSE_PAREN;
 
NewExpression = (* new_keyword: *) NEW_KEYWORD                (* type_name: *) TypeName;
 
TupleExpression = (* open_paren: *) OPEN_PAREN                  (* items: *) TupleValues                  (* close_paren: *) CLOSE_PAREN;
 
TupleValues = (* item: *) TupleValue ((* separator: *) COMMA (* item: *) TupleValue)*;
 
TupleValue = (* expression: *) Expression?;
 
ArrayExpression = (* open_bracket: *) OPEN_BRACKET                  (* items: *) ArrayValues                  (* close_bracket: *) CLOSE_BRACKET;
 
ArrayValues = (* item: *) Expression ((* separator: *) COMMA (* item: *) Expression)*;
"},{"location":"solidity-specification/05-expressions/03-primary-expressions/#array-literals","title":"Array Literals","text":"

An array literal is a comma-separated list of one or more expressions, enclosed in square brackets ([...]). For example [1, a, f(3)]. It is always a statically-sized memory array whose length is the number of expressions.

contract MyContract {\n    function someFunction() public pure {\n        otherFunction([uint(1), 2, 3]);\n    }\n}\n
"},{"location":"solidity-specification/05-expressions/03-primary-expressions/#array-slices","title":"Array Slices","text":"

Array slices are a view on a contiguous portion of an array. They are written as x[start:end], where start and end are expressions resulting in a uint256 type (or implicitly convertible to it). The first element of the slice is x[start] and the last element is x[end - 1].

Both start and end are optional: start defaults to 0 and end defaults to the length of the array.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/04-numbers/","title":"5.4. Numbers","text":""},{"location":"solidity-specification/05-expressions/04-numbers/#54-numbers","title":"5.4. Numbers","text":""},{"location":"solidity-specification/05-expressions/04-numbers/#syntax","title":"Syntax","text":"
HexNumberExpression = (* literal: *) HEX_LITERAL                      (* unit: *) NumberUnit?; (* Deprecated in 0.5.0 *)
 
DecimalNumberExpression = (* literal: *) DECIMAL_LITERAL                          (* unit: *) NumberUnit?;
 
HEX_LITERAL = \"0x\" \u00abHEX_CHARACTER\u00bb+ (\"_\" \u00abHEX_CHARACTER\u00bb+)* (?!\u00abIDENTIFIER_START\u00bb);(* Deprecated in 0.5.0 *)HEX_LITERAL = \"0X\" \u00abHEX_CHARACTER\u00bb+ (\"_\" \u00abHEX_CHARACTER\u00bb+)* (?!\u00abIDENTIFIER_START\u00bb);
 
DECIMAL_LITERAL = \".\" \u00abDECIMAL_DIGITS\u00bb \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb (?!\".\") \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);(* Deprecated in 0.5.0 *)DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb \".\" (?!\u00abDECIMAL_DIGITS\u00bb) \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);(* Deprecated in 0.5.0 *)DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb \".\" \u00abDECIMAL_DIGITS\u00bb \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);(* Introduced in 0.5.0 *)DECIMAL_LITERAL = \u00abDECIMAL_DIGITS\u00bb (\".\" \u00abDECIMAL_DIGITS\u00bb)? \u00abDECIMAL_EXPONENT\u00bb? (?!\u00abIDENTIFIER_START\u00bb);
 
\u00abDECIMAL_DIGITS\u00bb = \"0\"\u2026\"9\"+ (\"_\" \"0\"\u2026\"9\"+)*;
 
\u00abDECIMAL_EXPONENT\u00bb = (\"e\" | \"E\") \"-\"? \u00abDECIMAL_DIGITS\u00bb;
 
NumberUnit = (* variant: *) WEI_KEYWORD           | (* variant: *) GWEI_KEYWORD (* Introduced in 0.6.11 *)           | (* variant: *) SZABO_KEYWORD (* Deprecated in 0.7.0 *)           | (* variant: *) FINNEY_KEYWORD (* Deprecated in 0.7.0 *)           | (* variant: *) ETHER_KEYWORD           | (* variant: *) SECONDS_KEYWORD           | (* variant: *) MINUTES_KEYWORD           | (* variant: *) HOURS_KEYWORD           | (* variant: *) DAYS_KEYWORD           | (* variant: *) WEEKS_KEYWORD           | (* variant: *) YEARS_KEYWORD; (* Deprecated in 0.5.0 *)
"},{"location":"solidity-specification/05-expressions/04-numbers/#integers","title":"Integers","text":"

Signed (int8..int256) and unsigned (uint8..uint256) integers of various sizes, from 8 to 256 bits, moving up in steps of 8 bits. uint and int are aliases for uint256 and int256, respectively.

Integers in Solidity are restricted to a certain range. For example, with uint32, this is 0 up to 2**32 - 1.

Integer literals are formed from a sequence of digits in the range 0-9. They are interpreted as decimals. For example, 69 means sixty nine.

Octal literals do not exist in Solidity and leading zeros are invalid.

"},{"location":"solidity-specification/05-expressions/04-numbers/#decimals","title":"Decimals","text":"

Decimal fractional literals are formed by a . with at least one number on one side. Examples include 1., .1 and 1.3.

"},{"location":"solidity-specification/05-expressions/04-numbers/#fixed-point-numbers","title":"Fixed Point Numbers","text":"

Signed fixed and unsigned fixed ufixed point number of various sizes. Keywords ufixedMxN and fixedMxN, where M represents the number of bits taken by the type and N represents how many decimal points are available. M must be divisible by 8 and goes from 8 to 256 bits. N must be between 0 and 80, inclusive. ufixed and fixed are aliases for ufixed128x18 and fixed128x18, respectively.

Fixed point numbers are not fully supported by Solidity yet. They can be declared, but cannot be assigned to or from.

"},{"location":"solidity-specification/05-expressions/04-numbers/#scientific-notation","title":"Scientific Notation","text":"

Scientific notation in the form of 2e10 is also supported, where the mantissa can be fractional but the exponent has to be an integer. The literal MeE is equivalent to M * 10**E. Examples include 2e10, -2e10, 2e-10, 2.5e1.

"},{"location":"solidity-specification/05-expressions/04-numbers/#using-underscores","title":"Using Underscores","text":"

Underscores can be used to separate the digits of a numeric literal to aid readability. For example, decimal 123_000, hexadecimal 0x2eff_abcde, scientific decimal notation 1_2e345_678 are all valid. Underscores are only allowed between two digits and only one consecutive underscore is allowed. There is no additional semantic meaning added to a number literal containing underscores, the underscores are ignored.

"},{"location":"solidity-specification/05-expressions/04-numbers/#ether-units","title":"Ether Units","text":"

A literal number can take a suffix of wei, gwei or ether to specify a sub-denomination of Ether, where Ether numbers without a postfix are assumed to be Wei.

assert(1 wei == 1);\nassert(1 gwei == 1e9);\nassert(1 szabo == 1e12);\nassert(1 finney == 1e15);\nassert(1 ether == 1e18);\n
"},{"location":"solidity-specification/05-expressions/04-numbers/#time-units","title":"Time Units","text":"

Suffixes that can be used to specify units of time where seconds are the base unit and units are considered naively in the following way:

assert(1 == 1 seconds);\nassert(1 minutes == 60 seconds);\nassert(1 hours == 60 minutes);\nassert(1 days == 24 hours);\nassert(1 weeks == 7 days);\n

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/05-strings/","title":"5.5. Strings","text":""},{"location":"solidity-specification/05-expressions/05-strings/#55-strings","title":"5.5. Strings","text":""},{"location":"solidity-specification/05-expressions/05-strings/#syntax","title":"Syntax","text":"
StringExpression = (* variant: *) StringLiteral (* Deprecated in 0.5.14 *)                 | (* variant: *) StringLiterals (* Introduced in 0.5.14 *)                 | (* variant: *) HexStringLiteral (* Deprecated in 0.5.14 *)                 | (* variant: *) HexStringLiterals (* Introduced in 0.5.14 *)                 | (* variant: *) UnicodeStringLiterals; (* Introduced in 0.7.0 *)
 
(* Introduced in 0.5.14 *)StringLiterals = (* item: *) StringLiteral+;
 
StringLiteral = (* variant: *) SINGLE_QUOTED_STRING_LITERAL              | (* variant: *) DOUBLE_QUOTED_STRING_LITERAL;
 
(* Deprecated in 0.4.25 *)SINGLE_QUOTED_STRING_LITERAL = \"'\" (\u00abESCAPE_SEQUENCE_ARBITRARY\u00bb | !(\"'\" | \"\\\\\" | \"\\r\" | \"\\n\"))* \"'\";(* Introduced in 0.4.25 and deprecated in 0.7.0. *)SINGLE_QUOTED_STRING_LITERAL = \"'\" (\u00abESCAPE_SEQUENCE\u00bb | !(\"'\" | \"\\\\\" | \"\\r\" | \"\\n\"))* \"'\";SINGLE_QUOTED_STRING_LITERAL = \"'\" (\u00abESCAPE_SEQUENCE\u00bb | \" \"\u2026\"&\" | \"(\"\u2026\"[\" | \"]\"\u2026\"~\")* \"'\";
 
(* Deprecated in 0.4.25 *)DOUBLE_QUOTED_STRING_LITERAL = '\"' (\u00abESCAPE_SEQUENCE_ARBITRARY\u00bb | !('\"' | \"\\\\\" | \"\\r\" | \"\\n\"))* '\"';(* Introduced in 0.4.25 and deprecated in 0.7.0. *)DOUBLE_QUOTED_STRING_LITERAL = '\"' (\u00abESCAPE_SEQUENCE\u00bb | !('\"' | \"\\\\\" | \"\\r\" | \"\\n\"))* '\"';DOUBLE_QUOTED_STRING_LITERAL = '\"' (\u00abESCAPE_SEQUENCE\u00bb | \" \"\u2026\"!\" | \"#\"\u2026\"[\" | \"]\"\u2026\"~\")* '\"';
 
(* Introduced in 0.5.14 *)HexStringLiterals = (* item: *) HexStringLiteral+;
 
HexStringLiteral = (* variant: *) SINGLE_QUOTED_HEX_STRING_LITERAL                 | (* variant: *) DOUBLE_QUOTED_HEX_STRING_LITERAL;
 
SINGLE_QUOTED_HEX_STRING_LITERAL = \"hex'\" \u00abHEX_STRING_CONTENTS\u00bb? \"'\";
 
DOUBLE_QUOTED_HEX_STRING_LITERAL = 'hex\"' \u00abHEX_STRING_CONTENTS\u00bb? '\"';
 
\u00abHEX_STRING_CONTENTS\u00bb = \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb (\"_\"? \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb)*;
 
\u00abHEX_CHARACTER\u00bb = \"0\"\u2026\"9\" | \"a\"\u2026\"f\" | \"A\"\u2026\"F\";
 
(* Introduced in 0.7.0 *)UnicodeStringLiterals = (* item: *) UnicodeStringLiteral+;
 
(* Introduced in 0.7.0 *)UnicodeStringLiteral = (* variant: *) SINGLE_QUOTED_UNICODE_STRING_LITERAL                     | (* variant: *) DOUBLE_QUOTED_UNICODE_STRING_LITERAL;
 
(* Introduced in 0.7.0 *)SINGLE_QUOTED_UNICODE_STRING_LITERAL = \"unicode'\" (\u00abESCAPE_SEQUENCE\u00bb | !(\"'\" | \"\\\\\" | \"\\r\" | \"\\n\"))* \"'\";
 
(* Introduced in 0.7.0 *)DOUBLE_QUOTED_UNICODE_STRING_LITERAL = 'unicode\"' (\u00abESCAPE_SEQUENCE\u00bb | !('\"' | \"\\\\\" | \"\\r\" | \"\\n\"))* '\"';
 
\u00abESCAPE_SEQUENCE\u00bb = \"\\\\\" (\u00abASCII_ESCAPE\u00bb | \u00abHEX_BYTE_ESCAPE\u00bb | \u00abUNICODE_ESCAPE\u00bb);
 
(* Deprecated in 0.4.25 *)\u00abESCAPE_SEQUENCE_ARBITRARY\u00bb = \"\\\\\" (!(\"x\" | \"u\") | \u00abHEX_BYTE_ESCAPE\u00bb | \u00abUNICODE_ESCAPE\u00bb);
 
\u00abASCII_ESCAPE\u00bb = \"n\" | \"r\" | \"t\" | \"'\" | '\"' | \"\\\\\" | \"\\r\\n\" | \"\\r\" | \"\\n\";
 
\u00abHEX_BYTE_ESCAPE\u00bb = \"x\" \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb;
 
\u00abUNICODE_ESCAPE\u00bb = \"u\" \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb \u00abHEX_CHARACTER\u00bb;
"},{"location":"solidity-specification/05-expressions/05-strings/#string-literals","title":"String Literals","text":"

String literals are written with either double or single-quotes (\"foo\" or 'bar'), and they can also be split into multiple consecutive parts (\"foo\" \"bar\" is equivalent to \"foobar\") which can be helpful when dealing with long strings. They do not imply trailing zeroes as in C; \"foo\" represents three bytes, not four. As with integer literals, their type can vary, but they are implicitly convertible to bytes1, ..., bytes32 if they fit.

String literals can only contain printable ASCII characters, which means the characters between 0x20 and 0x7E inclusively.

"},{"location":"solidity-specification/05-expressions/05-strings/#unicode-literals","title":"Unicode Literals","text":"

While regular string literals can only contain ASCII, unicode literals (prefixed with the keyword unicode) can contain any valid UTF-8 sequence. They also support the very same escape sequences as regular string literals.

string memory a = unicode\"Hello \ud83d\ude03\";\n
"},{"location":"solidity-specification/05-expressions/05-strings/#hexadecimal-literals","title":"Hexadecimal Literals","text":"

Hexadecimal literals are prefixed with the keyword hex and are enclosed in double or single-quotes (hex\"001122FF\", hex'0011_22_FF'). Their content must be hexadecimal digits which can optionally use a single underscore as separator between byte boundaries. The value of the literal will be the binary representation of the hexadecimal sequence.

Hexadecimal literals behave like string literals and have the same convertibility restrictions. Additionally, multiple hexadecimal literals separated by whitespace are concatenated into a single literal: hex\"00112233\" hex\"44556677\" is equivalent to hex\"0011223344556677\"

"},{"location":"solidity-specification/05-expressions/05-strings/#escape-sequences","title":"Escape Sequences","text":"

String literals also support the following escape characters:

Any Unicode line terminator which is not a newline (i.e. LF, VF, FF, CR, NEL, LS, PS) is considered to terminate the string literal. Newline only terminates the string literal if it is not preceded by a \\.

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/05-expressions/06-identifiers/","title":"5.6. Identifiers","text":""},{"location":"solidity-specification/05-expressions/06-identifiers/#56-identifiers","title":"5.6. Identifiers","text":""},{"location":"solidity-specification/05-expressions/06-identifiers/#syntax","title":"Syntax","text":"
IdentifierPath = (* item: *) IDENTIFIER ((* separator: *) PERIOD (* item: *) IDENTIFIER)*;
 
IDENTIFIER = \u00abIDENTIFIER_START\u00bb \u00abIDENTIFIER_PART\u00bb*;
 
\u00abIDENTIFIER_START\u00bb = \"_\" | \"$\" | \"a\"\u2026\"z\" | \"A\"\u2026\"Z\";
 
\u00abIDENTIFIER_PART\u00bb = \u00abIDENTIFIER_START\u00bb | \"0\"\u2026\"9\";
"},{"location":"solidity-specification/05-expressions/06-identifiers/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/06-yul/","title":"6. Yul","text":""},{"location":"solidity-specification/06-yul/#6-yul","title":"6. Yul","text":""},{"location":"solidity-specification/06-yul/01-yul-statements/","title":"6.1. Yul Statements","text":""},{"location":"solidity-specification/06-yul/01-yul-statements/#61-yul-statements","title":"6.1. Yul Statements","text":""},{"location":"solidity-specification/06-yul/01-yul-statements/#syntax","title":"Syntax","text":"
YulBlock = (* open_brace: *) OPEN_BRACE           (* statements: *) YulStatements           (* close_brace: *) CLOSE_BRACE;
 
YulStatements = (* item: *) YulStatement*;
 
YulStatement = (* variant: *) YulBlock             | (* variant: *) YulFunctionDefinition             | (* variant: *) YulStackAssignmentStatement (* Deprecated in 0.5.0 *)             | (* variant: *) YulIfStatement             | (* variant: *) YulForStatement             | (* variant: *) YulSwitchStatement             | (* variant: *) YulLeaveStatement (* Introduced in 0.6.0 *)             | (* variant: *) YulBreakStatement             | (* variant: *) YulContinueStatement             | (* variant: *) YulVariableAssignmentStatement             | (* variant: *) YulLabel (* Deprecated in 0.5.0 *)             | (* variant: *) YulVariableDeclarationStatement             | (* variant: *) YulExpression;
 
YulFunctionDefinition = (* function_keyword: *) YUL_FUNCTION_KEYWORD                        (* name: *) YUL_IDENTIFIER                        (* parameters: *) YulParametersDeclaration                        (* returns: *) YulReturnsDeclaration?                        (* body: *) YulBlock;
 
YulParametersDeclaration = (* open_paren: *) OPEN_PAREN                           (* parameters: *) YulParameters                           (* close_paren: *) CLOSE_PAREN;
 
YulParameters = ((* item: *) YUL_IDENTIFIER ((* separator: *) COMMA (* item: *) YUL_IDENTIFIER)*)?;
 
YulReturnsDeclaration = (* minus_greater_than: *) MINUS_GREATER_THAN                        (* variables: *) YulVariableNames;
 
YulVariableNames = (* item: *) YUL_IDENTIFIER ((* separator: *) COMMA (* item: *) YUL_IDENTIFIER)*;
 
YulVariableDeclarationStatement = (* let_keyword: *) YUL_LET_KEYWORD                                  (* variables: *) YulVariableNames                                  (* value: *) YulVariableDeclarationValue?;
 
YulVariableDeclarationValue = (* assignment: *) YulAssignmentOperator                              (* expression: *) YulExpression;
 
YulVariableAssignmentStatement = (* variables: *) YulPaths                                 (* assignment: *) YulAssignmentOperator                                 (* expression: *) YulExpression;
 
YulAssignmentOperator = (* variant: *) COLON_EQUAL                      | (* variant: *) YulColonAndEqual; (* Deprecated in 0.5.5 *)
 
(* Deprecated in 0.5.5 *)YulColonAndEqual = (* colon: *) COLON                   (* equal: *) EQUAL;
 
(* Deprecated in 0.5.0 *)YulStackAssignmentStatement = (* assignment: *) YulStackAssignmentOperator                              (* variable: *) YUL_IDENTIFIER;
 
(* Deprecated in 0.5.0 *)YulStackAssignmentOperator = (* variant: *) EQUAL_COLON                           | (* variant: *) YulEqualAndColon;
 
(* Deprecated in 0.5.0 *)YulEqualAndColon = (* equal: *) EQUAL                   (* colon: *) COLON;
 
YulIfStatement = (* if_keyword: *) YUL_IF_KEYWORD                 (* condition: *) YulExpression                 (* body: *) YulBlock;
 
YulForStatement = (* for_keyword: *) YUL_FOR_KEYWORD                  (* initialization: *) YulBlock                  (* condition: *) YulExpression                  (* iterator: *) YulBlock                  (* body: *) YulBlock;
 
YulSwitchStatement = (* switch_keyword: *) YUL_SWITCH_KEYWORD                     (* expression: *) YulExpression                     (* cases: *) YulSwitchCases;
 
YulSwitchCases = (* item: *) YulSwitchCase+;
 
YulSwitchCase = (* variant: *) YulDefaultCase              | (* variant: *) YulValueCase;
 
YulDefaultCase = (* default_keyword: *) YUL_DEFAULT_KEYWORD                 (* body: *) YulBlock;
 
YulValueCase = (* case_keyword: *) YUL_CASE_KEYWORD               (* value: *) YulLiteral               (* body: *) YulBlock;
 
(* Introduced in 0.6.0 *)YulLeaveStatement = (* leave_keyword: *) YUL_LEAVE_KEYWORD;
 
YulBreakStatement = (* break_keyword: *) YUL_BREAK_KEYWORD;
 
YulContinueStatement = (* continue_keyword: *) YUL_CONTINUE_KEYWORD;
 
(* Deprecated in 0.5.0 *)YulLabel = (* label: *) YUL_IDENTIFIER           (* colon: *) COLON;
"},{"location":"solidity-specification/06-yul/01-yul-statements/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/06-yul/02-yul-expressions/","title":"6.2. Yul Expressions","text":""},{"location":"solidity-specification/06-yul/02-yul-expressions/#62-yul-expressions","title":"6.2. Yul Expressions","text":""},{"location":"solidity-specification/06-yul/02-yul-expressions/#syntax","title":"Syntax","text":"
YulExpression = (* variant: *) YulFunctionCallExpression              | (* variant: *) YulLiteral              | (* variant: *) YulBuiltInFunction              | (* variant: *) YulPath;
 
(* Postfix unary operator *)YulFunctionCallExpression = (* operand: *) YulExpression                            (* open_paren: *) OPEN_PAREN                            (* arguments: *) YulArguments                            (* close_paren: *) CLOSE_PAREN;
 
YulArguments = ((* item: *) YulExpression ((* separator: *) COMMA (* item: *) YulExpression)*)?;
 
YulPaths = (* item: *) YulPath ((* separator: *) COMMA (* item: *) YulPath)*;
 
YulPath = (* item: *) YUL_IDENTIFIER ((* separator: *) PERIOD (* item: *) YUL_IDENTIFIER)*;
 
(* Introduced in 0.5.8 and deprecated in 0.7.0. *)YUL_IDENTIFIER = \u00abIDENTIFIER_START\u00bb (\u00abIDENTIFIER_PART\u00bb | \".\")*;YUL_IDENTIFIER = \u00abIDENTIFIER_START\u00bb \u00abIDENTIFIER_PART\u00bb*;
 
YulBuiltInFunction = (* variant: *) YUL_ADD_KEYWORD                   | (* variant: *) YUL_ADD_MOD_KEYWORD                   | (* variant: *) YUL_ADDRESS_KEYWORD                   | (* variant: *) YUL_AND_KEYWORD                   | (* variant: *) YUL_BALANCE_KEYWORD                   | (* variant: *) YUL_BLOCK_HASH_KEYWORD                   | (* variant: *) YUL_BYTE_KEYWORD                   | (* variant: *) YUL_CALL_CODE_KEYWORD                   | (* variant: *) YUL_CALL_DATA_COPY_KEYWORD                   | (* variant: *) YUL_CALL_DATA_LOAD_KEYWORD                   | (* variant: *) YUL_CALL_DATA_SIZE_KEYWORD                   | (* variant: *) YUL_CALLER_KEYWORD                   | (* variant: *) YUL_CALL_KEYWORD                   | (* variant: *) YUL_CALL_VALUE_KEYWORD                   | (* variant: *) YUL_COIN_BASE_KEYWORD                   | (* variant: *) YUL_CREATE_KEYWORD                   | (* variant: *) YUL_DELEGATE_CALL_KEYWORD                   | (* variant: *) YUL_DIV_KEYWORD                   | (* variant: *) YUL_EQ_KEYWORD                   | (* variant: *) YUL_EXP_KEYWORD                   | (* variant: *) YUL_EXT_CODE_COPY_KEYWORD                   | (* variant: *) YUL_EXT_CODE_SIZE_KEYWORD                   | (* variant: *) YUL_GAS_KEYWORD                   | (* variant: *) YUL_GAS_LIMIT_KEYWORD                   | (* variant: *) YUL_GAS_PRICE_KEYWORD                   | (* variant: *) YUL_GT_KEYWORD                   | (* variant: *) YUL_INVALID_KEYWORD                   | (* variant: *) YUL_IS_ZERO_KEYWORD                   | (* variant: *) YUL_JUMP_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_JUMPI_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_LOG_0_KEYWORD                   | (* variant: *) YUL_LOG_1_KEYWORD                   | (* variant: *) YUL_LOG_2_KEYWORD                   | (* variant: *) YUL_LOG_3_KEYWORD                   | (* variant: *) YUL_LOG_4_KEYWORD                   | (* variant: *) YUL_LT_KEYWORD                   | (* variant: *) YUL_M_LOAD_KEYWORD                   | (* variant: *) YUL_MOD_KEYWORD                   | (* variant: *) YUL_M_SIZE_KEYWORD                   | (* variant: *) YUL_M_STORE_8_KEYWORD                   | (* variant: *) YUL_M_STORE_KEYWORD                   | (* variant: *) YUL_MUL_KEYWORD                   | (* variant: *) YUL_MUL_MOD_KEYWORD                   | (* variant: *) YUL_NOT_KEYWORD                   | (* variant: *) YUL_NUMBER_KEYWORD                   | (* variant: *) YUL_ORIGIN_KEYWORD                   | (* variant: *) YUL_OR_KEYWORD                   | (* variant: *) YUL_POP_KEYWORD                   | (* variant: *) YUL_RETURN_KEYWORD                   | (* variant: *) YUL_REVERT_KEYWORD                   | (* variant: *) YUL_S_DIV_KEYWORD                   | (* variant: *) YUL_SELF_DESTRUCT_KEYWORD                   | (* variant: *) YUL_SGT_KEYWORD                   | (* variant: *) YUL_SIGN_EXTEND_KEYWORD                   | (* variant: *) YUL_S_LOAD_KEYWORD                   | (* variant: *) YUL_SLT_KEYWORD                   | (* variant: *) YUL_S_MOD_KEYWORD                   | (* variant: *) YUL_S_STORE_KEYWORD                   | (* variant: *) YUL_STOP_KEYWORD                   | (* variant: *) YUL_SUB_KEYWORD                   | (* variant: *) YUL_TIMESTAMP_KEYWORD                   | (* variant: *) YUL_XOR_KEYWORD                   | (* variant: *) YUL_KECCAK_256_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_SHA_3_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_SUICIDE_KEYWORD (* Deprecated in 0.5.0 *)                   | (* variant: *) YUL_RETURN_DATA_COPY_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_RETURN_DATA_SIZE_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_STATIC_CALL_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_CREATE_2_KEYWORD (* Introduced in 0.4.12 *)                   | (* variant: *) YUL_EXT_CODE_HASH_KEYWORD (* Introduced in 0.5.0 *)                   | (* variant: *) YUL_SAR_KEYWORD                   | (* variant: *) YUL_SHL_KEYWORD                   | (* variant: *) YUL_SHR_KEYWORD                   | (* variant: *) YUL_CHAIN_ID_KEYWORD                   | (* variant: *) YUL_SELF_BALANCE_KEYWORD                   | (* variant: *) YUL_BASE_FEE_KEYWORD (* Introduced in 0.8.7 *)                   | (* variant: *) YUL_DIFFICULTY_KEYWORD (* Deprecated in 0.8.18 *)                   | (* variant: *) YUL_PREV_RANDAO_KEYWORD (* Introduced in 0.8.18 *)                   | (* variant: *) YUL_BLOB_BASE_FEE_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_BLOB_HASH_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_T_LOAD_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_T_STORE_KEYWORD (* Introduced in 0.8.24 *)                   | (* variant: *) YUL_M_COPY_KEYWORD; (* Introduced in 0.8.24 *)
 
YulLiteral = (* variant: *) YUL_TRUE_KEYWORD           | (* variant: *) YUL_FALSE_KEYWORD           | (* variant: *) YUL_DECIMAL_LITERAL           | (* variant: *) YUL_HEX_LITERAL           | (* variant: *) HexStringLiteral           | (* variant: *) StringLiteral;
 
YUL_DECIMAL_LITERAL = (\"0\" | (\"1\"\u2026\"9\" \"0\"\u2026\"9\"*)) (?!\u00abIDENTIFIER_START\u00bb);
 
YUL_HEX_LITERAL = \"0x\" \u00abHEX_CHARACTER\u00bb+ (?!\u00abIDENTIFIER_START\u00bb);
"},{"location":"solidity-specification/06-yul/02-yul-expressions/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"solidity-specification/06-yul/03-yul-keywords/","title":"6.3. Yul Keywords","text":""},{"location":"solidity-specification/06-yul/03-yul-keywords/#63-yul-keywords","title":"6.3. Yul Keywords","text":""},{"location":"solidity-specification/06-yul/03-yul-keywords/#syntax","title":"Syntax","text":"
(* Reserved until 0.7.1 *)YUL_ABSTRACT_KEYWORD = \"abstract\";
 
YUL_ADD_KEYWORD = \"add\";
 
YUL_ADD_MOD_KEYWORD = \"addmod\";
 
(* Never reserved *)YUL_ADDRESS_KEYWORD = \"address\";
 
(* Reserved until 0.7.1 *)YUL_AFTER_KEYWORD = \"after\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_ALIAS_KEYWORD = \"alias\";
 
YUL_AND_KEYWORD = \"and\";
 
(* Reserved until 0.7.1 *)YUL_ANONYMOUS_KEYWORD = \"anonymous\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_APPLY_KEYWORD = \"apply\";
 
(* Reserved until 0.7.1 *)YUL_AS_KEYWORD = \"as\";
 
(* Reserved until 0.7.1 *)YUL_ASSEMBLY_KEYWORD = \"assembly\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_AUTO_KEYWORD = \"auto\";
 
YUL_BALANCE_KEYWORD = \"balance\";
 
(* Introduced in 0.8.7 *)(* Reserved in 0.8.7 *)YUL_BASE_FEE_KEYWORD = \"basefee\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_BLOB_BASE_FEE_KEYWORD = \"blobbasefee\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_BLOB_HASH_KEYWORD = \"blobhash\";
 
YUL_BLOCK_HASH_KEYWORD = \"blockhash\";
 
(* Reserved until 0.5.10 *)YUL_BOOL_KEYWORD = \"bool\";
 
YUL_BREAK_KEYWORD = \"break\";
 
YUL_BYTE_KEYWORD = \"byte\";
 
(* Reserved until 0.7.1 *)YUL_BYTES_KEYWORD = \"bytes\" (\"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"8\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"16\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"24\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"32\")?;
 
YUL_CALL_CODE_KEYWORD = \"callcode\";
 
YUL_CALL_DATA_COPY_KEYWORD = \"calldatacopy\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_CALL_DATA_KEYWORD = \"calldata\";
 
YUL_CALL_DATA_LOAD_KEYWORD = \"calldataload\";
 
YUL_CALL_DATA_SIZE_KEYWORD = \"calldatasize\";
 
YUL_CALLER_KEYWORD = \"caller\";
 
YUL_CALL_KEYWORD = \"call\";
 
YUL_CALL_VALUE_KEYWORD = \"callvalue\";
 
YUL_CASE_KEYWORD = \"case\";
 
(* Reserved until 0.7.1 *)YUL_CATCH_KEYWORD = \"catch\";
 
(* Reserved in 0.5.12 *)YUL_CHAIN_ID_KEYWORD = \"chainid\";
 
YUL_COIN_BASE_KEYWORD = \"coinbase\";
 
(* Reserved until 0.7.1 *)YUL_CONSTANT_KEYWORD = \"constant\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_CONSTRUCTOR_KEYWORD = \"constructor\";
 
YUL_CONTINUE_KEYWORD = \"continue\";
 
(* Reserved until 0.7.1 *)YUL_CONTRACT_KEYWORD = \"contract\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_COPY_OF_KEYWORD = \"copyof\";
 
YUL_CREATE_KEYWORD = \"create\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_CREATE_2_KEYWORD = \"create2\";
 
(* Reserved until 0.7.1 *)YUL_DAYS_KEYWORD = \"days\";
 
YUL_DEFAULT_KEYWORD = \"default\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_DEFINE_KEYWORD = \"define\";
 
YUL_DELEGATE_CALL_KEYWORD = \"delegatecall\";
 
(* Reserved until 0.7.1 *)YUL_DELETE_KEYWORD = \"delete\";
 
(* Deprecated in 0.8.18 *)YUL_DIFFICULTY_KEYWORD = \"difficulty\";
 
YUL_DIV_KEYWORD = \"div\";
 
(* Reserved until 0.7.1 *)YUL_DO_KEYWORD = \"do\";
 
(* Reserved until 0.7.1 *)YUL_ELSE_KEYWORD = \"else\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_EMIT_KEYWORD = \"emit\";
 
(* Reserved until 0.7.1 *)YUL_ENUM_KEYWORD = \"enum\";
 
YUL_EQ_KEYWORD = \"eq\";
 
(* Reserved until 0.7.1 *)YUL_ETHER_KEYWORD = \"ether\";
 
(* Reserved until 0.7.1 *)YUL_EVENT_KEYWORD = \"event\";
 
YUL_EXP_KEYWORD = \"exp\";
 
YUL_EXT_CODE_COPY_KEYWORD = \"extcodecopy\";
 
(* Introduced in 0.5.0 *)(* Reserved in 0.5.0 *)YUL_EXT_CODE_HASH_KEYWORD = \"extcodehash\";
 
YUL_EXT_CODE_SIZE_KEYWORD = \"extcodesize\";
 
(* Reserved until 0.7.1 *)YUL_EXTERNAL_KEYWORD = \"external\";
 
(* Reserved from 0.6.0 until 0.7.1 *)YUL_FALLBACK_KEYWORD = \"fallback\";
 
YUL_FALSE_KEYWORD = \"false\";
 
(* Reserved until 0.7.1 *)YUL_FINAL_KEYWORD = \"final\";
 
(* Reserved until 0.7.0 *)YUL_FINNEY_KEYWORD = \"finney\";
 
(* Reserved until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\";(* Reserved until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");(* Reserved until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_FIXED_KEYWORD = \"fixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
YUL_FOR_KEYWORD = \"for\";
 
YUL_FUNCTION_KEYWORD = \"function\";
 
YUL_GAS_KEYWORD = \"gas\";
 
YUL_GAS_LIMIT_KEYWORD = \"gaslimit\";
 
YUL_GAS_PRICE_KEYWORD = \"gasprice\";
 
YUL_GT_KEYWORD = \"gt\";
 
(* Reserved from 0.7.0 until 0.7.1 *)YUL_GWEI_KEYWORD = \"gwei\";
 
YUL_HEX_KEYWORD = \"hex\";
 
(* Reserved until 0.7.1 *)YUL_HOURS_KEYWORD = \"hours\";
 
YUL_IF_KEYWORD = \"if\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_IMMUTABLE_KEYWORD = \"immutable\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_IMPLEMENTS_KEYWORD = \"implements\";
 
(* Reserved until 0.7.1 *)YUL_IMPORT_KEYWORD = \"import\";
 
(* Reserved until 0.7.1 *)YUL_INDEXED_KEYWORD = \"indexed\";
 
(* Reserved until 0.6.8 *)YUL_IN_KEYWORD = \"in\";
 
(* Reserved until 0.7.1 *)YUL_INLINE_KEYWORD = \"inline\";
 
(* Reserved until 0.7.1 *)YUL_INTERFACE_KEYWORD = \"interface\";
 
(* Reserved until 0.7.1 *)YUL_INTERNAL_KEYWORD = \"internal\";
 
(* Reserved until 0.7.1 *)YUL_INT_KEYWORD = \"int\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
YUL_INVALID_KEYWORD = \"invalid\";
 
(* Reserved until 0.7.1 *)YUL_IS_KEYWORD = \"is\";
 
YUL_IS_ZERO_KEYWORD = \"iszero\";
 
(* Deprecated in 0.5.0 *)YUL_JUMP_KEYWORD = \"jump\";
 
(* Deprecated in 0.5.0 *)YUL_JUMPI_KEYWORD = \"jumpi\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_KECCAK_256_KEYWORD = \"keccak256\";
 
(* Introduced in 0.6.0 *)(* Reserved in 0.7.1 *)YUL_LEAVE_KEYWORD = \"leave\";
 
YUL_LET_KEYWORD = \"let\";
 
(* Reserved until 0.7.1 *)YUL_LIBRARY_KEYWORD = \"library\";
 
YUL_LOG_0_KEYWORD = \"log0\";
 
YUL_LOG_1_KEYWORD = \"log1\";
 
YUL_LOG_2_KEYWORD = \"log2\";
 
YUL_LOG_3_KEYWORD = \"log3\";
 
YUL_LOG_4_KEYWORD = \"log4\";
 
YUL_LT_KEYWORD = \"lt\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_MACRO_KEYWORD = \"macro\";
 
(* Reserved until 0.7.1 *)YUL_MAPPING_KEYWORD = \"mapping\";
 
(* Reserved until 0.7.1 *)YUL_MATCH_KEYWORD = \"match\";
 
(* Reserved until 0.7.1 *)YUL_MEMORY_KEYWORD = \"memory\";
 
(* Reserved until 0.7.1 *)YUL_MINUTES_KEYWORD = \"minutes\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_M_COPY_KEYWORD = \"mcopy\";
 
YUL_M_LOAD_KEYWORD = \"mload\";
 
YUL_MOD_KEYWORD = \"mod\";
 
(* Reserved until 0.7.1 *)YUL_MODIFIER_KEYWORD = \"modifier\";
 
YUL_M_SIZE_KEYWORD = \"msize\";
 
YUL_M_STORE_KEYWORD = \"mstore\";
 
YUL_M_STORE_8_KEYWORD = \"mstore8\";
 
YUL_MUL_KEYWORD = \"mul\";
 
YUL_MUL_MOD_KEYWORD = \"mulmod\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_MUTABLE_KEYWORD = \"mutable\";
 
(* Reserved until 0.7.1 *)YUL_NEW_KEYWORD = \"new\";
 
YUL_NOT_KEYWORD = \"not\";
 
(* Reserved until 0.7.1 *)YUL_NULL_KEYWORD = \"null\";
 
YUL_NUMBER_KEYWORD = \"number\";
 
(* Reserved until 0.7.1 *)YUL_OF_KEYWORD = \"of\";
 
YUL_OR_KEYWORD = \"or\";
 
YUL_ORIGIN_KEYWORD = \"origin\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_OVERRIDE_KEYWORD = \"override\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_PARTIAL_KEYWORD = \"partial\";
 
(* Reserved until 0.7.1 *)YUL_PAYABLE_KEYWORD = \"payable\";
 
YUL_POP_KEYWORD = \"pop\";
 
(* Reserved until 0.7.1 *)YUL_PRAGMA_KEYWORD = \"pragma\";
 
(* Introduced in 0.8.18 *)(* Reserved in 0.8.18 *)YUL_PREV_RANDAO_KEYWORD = \"prevrandao\";
 
(* Reserved until 0.7.1 *)YUL_PRIVATE_KEYWORD = \"private\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_PROMISE_KEYWORD = \"promise\";
 
(* Reserved until 0.7.1 *)YUL_PUBLIC_KEYWORD = \"public\";
 
(* Reserved until 0.7.1 *)YUL_PURE_KEYWORD = \"pure\";
 
(* Reserved from 0.6.0 until 0.7.1 *)YUL_RECEIVE_KEYWORD = \"receive\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_REFERENCE_KEYWORD = \"reference\";
 
(* Reserved until 0.7.1 *)YUL_RELOCATABLE_KEYWORD = \"relocatable\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_RETURN_DATA_COPY_KEYWORD = \"returndatacopy\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_RETURN_DATA_SIZE_KEYWORD = \"returndatasize\";
 
YUL_RETURN_KEYWORD = \"return\";
 
(* Reserved until 0.7.1 *)YUL_RETURNS_KEYWORD = \"returns\";
 
YUL_REVERT_KEYWORD = \"revert\";
 
(* Reserved in 0.4.21 *)YUL_SAR_KEYWORD = \"sar\";
 
YUL_S_DIV_KEYWORD = \"sdiv\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_SEALED_KEYWORD = \"sealed\";
 
(* Reserved until 0.7.1 *)YUL_SECONDS_KEYWORD = \"seconds\";
 
(* Reserved in 0.5.12 *)YUL_SELF_BALANCE_KEYWORD = \"selfbalance\";
 
YUL_SELF_DESTRUCT_KEYWORD = \"selfdestruct\";
 
YUL_SGT_KEYWORD = \"sgt\";
 
(* Deprecated in 0.5.0 *)(* Reserved until 0.5.0 *)YUL_SHA_3_KEYWORD = \"sha3\";
 
(* Reserved in 0.4.21 *)YUL_SHL_KEYWORD = \"shl\";
 
(* Reserved in 0.4.21 *)YUL_SHR_KEYWORD = \"shr\";
 
YUL_SIGN_EXTEND_KEYWORD = \"signextend\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_SIZE_OF_KEYWORD = \"sizeof\";
 
YUL_S_LOAD_KEYWORD = \"sload\";
 
YUL_SLT_KEYWORD = \"slt\";
 
YUL_S_MOD_KEYWORD = \"smod\";
 
YUL_S_STORE_KEYWORD = \"sstore\";
 
(* Introduced in 0.4.12 *)(* Reserved in 0.4.12 *)YUL_STATIC_CALL_KEYWORD = \"staticcall\";
 
(* Reserved until 0.7.1 *)YUL_STATIC_KEYWORD = \"static\";
 
YUL_STOP_KEYWORD = \"stop\";
 
(* Reserved until 0.7.1 *)YUL_STORAGE_KEYWORD = \"storage\";
 
(* Reserved until 0.7.1 *)YUL_STRING_KEYWORD = \"string\";
 
(* Reserved until 0.7.1 *)YUL_STRUCT_KEYWORD = \"struct\";
 
YUL_SUB_KEYWORD = \"sub\";
 
(* Deprecated in 0.5.0 *)(* Reserved until 0.5.0 *)YUL_SUICIDE_KEYWORD = \"suicide\";
 
YUL_SUPER_KEYWORD = \"super\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_SUPPORTS_KEYWORD = \"supports\";
 
YUL_SWITCH_KEYWORD = \"switch\";
 
(* Reserved until 0.7.0 *)YUL_SZABO_KEYWORD = \"szabo\";
 
YUL_TIMESTAMP_KEYWORD = \"timestamp\";
 
YUL_THIS_KEYWORD = \"this\";
 
(* Reserved until 0.7.1 *)YUL_THROW_KEYWORD = \"throw\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_T_LOAD_KEYWORD = \"tload\";
 
YUL_TRUE_KEYWORD = \"true\";
 
(* Introduced in 0.8.24 *)(* Reserved in 0.8.25 *)YUL_T_STORE_KEYWORD = \"tstore\";
 
(* Reserved until 0.7.1 *)YUL_TRY_KEYWORD = \"try\";
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_TYPE_DEF_KEYWORD = \"typedef\";
 
(* Reserved until 0.7.1 *)YUL_TYPE_KEYWORD = \"type\";
 
(* Reserved until 0.7.1 *)YUL_TYPE_OF_KEYWORD = \"typeof\";
 
(* Reserved until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\";(* Reserved until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\") \"x\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\");(* Reserved until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"184x8\" | \"184x16\" | \"184x24\" | \"184x32\" | \"184x40\" | \"184x48\" | \"184x56\" | \"184x64\" | \"184x72\" | \"192x8\" | \"192x16\" | \"192x24\" | \"192x32\" | \"192x40\" | \"192x48\" | \"192x56\" | \"192x64\" | \"200x8\" | \"200x16\" | \"200x24\" | \"200x32\" | \"200x40\" | \"200x48\" | \"200x56\" | \"208x8\" | \"208x16\" | \"208x24\" | \"208x32\" | \"208x40\" | \"208x48\" | \"216x8\" | \"216x16\" | \"216x24\" | \"216x32\" | \"216x40\" | \"224x8\" | \"224x16\" | \"224x24\" | \"224x32\" | \"232x8\" | \"232x16\" | \"232x24\" | \"240x8\" | \"240x16\" | \"248x8\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"184x80\" | \"192x72\" | \"192x80\" | \"200x64\" | \"200x72\" | \"200x80\" | \"208x56\" | \"208x64\" | \"208x72\" | \"208x80\" | \"216x48\" | \"216x56\" | \"216x64\" | \"216x72\" | \"216x80\" | \"224x40\" | \"224x48\" | \"224x56\" | \"224x64\" | \"224x72\" | \"224x80\" | \"232x32\" | \"232x40\" | \"232x48\" | \"232x56\" | \"232x64\" | \"232x72\" | \"232x80\" | \"240x24\" | \"240x32\" | \"240x40\" | \"240x48\" | \"240x56\" | \"240x64\" | \"240x72\" | \"240x80\" | \"248x16\" | \"248x24\" | \"248x32\" | \"248x40\" | \"248x48\" | \"248x56\" | \"248x64\" | \"248x72\" | \"248x80\" | \"256x8\" | \"256x16\" | \"256x24\" | \"256x32\" | \"256x40\" | \"256x48\" | \"256x56\" | \"256x64\" | \"256x72\" | \"256x80\");(* Reserved from 0.4.14 until 0.7.1 *)YUL_UFIXED_KEYWORD = \"ufixed\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\") \"x\" (\"0\" | \"1\" | \"2\" | \"3\" | \"4\" | \"5\" | \"6\" | \"7\" | \"9\" | \"10\" | \"11\" | \"12\" | \"13\" | \"14\" | \"15\" | \"17\" | \"18\" | \"19\" | \"20\" | \"21\" | \"22\" | \"23\" | \"25\" | \"26\" | \"27\" | \"28\" | \"29\" | \"30\" | \"31\" | \"33\" | \"34\" | \"35\" | \"36\" | \"37\" | \"38\" | \"39\" | \"41\" | \"42\" | \"43\" | \"44\" | \"45\" | \"46\" | \"47\" | \"49\" | \"50\" | \"51\" | \"52\" | \"53\" | \"54\" | \"55\" | \"57\" | \"58\" | \"59\" | \"60\" | \"61\" | \"62\" | \"63\" | \"65\" | \"66\" | \"67\" | \"68\" | \"69\" | \"70\" | \"71\" | \"73\" | \"74\" | \"75\" | \"76\" | \"77\" | \"78\" | \"79\");
 
(* Reserved until 0.7.1 *)YUL_UINT_KEYWORD = \"uint\" (\"8\" | \"16\" | \"24\" | \"32\" | \"40\" | \"48\" | \"56\" | \"64\" | \"72\" | \"80\" | \"88\" | \"96\" | \"104\" | \"112\" | \"120\" | \"128\" | \"136\" | \"144\" | \"152\" | \"160\" | \"168\" | \"176\" | \"184\" | \"192\" | \"200\" | \"208\" | \"216\" | \"224\" | \"232\" | \"240\" | \"248\" | \"256\")?;
 
(* Reserved from 0.5.0 until 0.7.1 *)YUL_UNCHECKED_KEYWORD = \"unchecked\";
 
(* Reserved until 0.7.1 *)YUL_USING_KEYWORD = \"using\";
 
(* Reserved until 0.6.5 *)YUL_VAR_KEYWORD = \"var\";
 
(* Reserved until 0.7.1 *)YUL_VIEW_KEYWORD = \"view\";
 
(* Reserved from 0.6.0 until 0.7.1 *)YUL_VIRTUAL_KEYWORD = \"virtual\";
 
(* Reserved until 0.7.1 *)YUL_WEEKS_KEYWORD = \"weeks\";
 
(* Reserved until 0.7.1 *)YUL_WEI_KEYWORD = \"wei\";
 
(* Reserved until 0.7.1 *)YUL_WHILE_KEYWORD = \"while\";
 
(* Reserved until 0.7.1 *)YUL_YEARS_KEYWORD = \"years\";
 
YUL_XOR_KEYWORD = \"xor\";
"},{"location":"solidity-specification/06-yul/03-yul-keywords/#documentation","title":"Documentation","text":"

Note

This section is under construction. You are more than welcome to contribute suggestions to our GitHub repository.

"},{"location":"user-guide/","title":"User Guide","text":""},{"location":"user-guide/concepts/","title":"Concepts","text":"

At its core, Slang is a collection of APIs that are meant to analyze the source code, starting with the source code itself and ending with a rich structure that can be reasoned about. This is a departure from the classic approach of \"black-box\" compilers, which are handed the input and only their output can be observed.

"},{"location":"user-guide/concepts/#language-versions","title":"Language Versions","text":"

To use Slang, you start by initializing a Parser object with a specific version of the language. The earliest Solidity version we support is 0.4.11, and we plan on supporting all future versions as they are released.

From a Parser object, you can analyze any source text according to the nonterminals of that specific version. Providing an accurate language version is important, as it affects the shape of the syntax tree, and possible errors produced. You can use the LanguageFacts::supportedVersions() API to get a list of all supported versions for the current Slang release.

The Parser::parse() API is the main entry point for the parser, and to generate concrete syntax trees (CSTs) that can be used for further analysis. Each parse() operation accepts the input source code, and a NonterminalKind variant. This allows callers to parse entire source files (NonterminalKind::SourceUnit), individual contracts (NonterminalKind::ContractDefinition), methods (NonterminalKind::FunctionDefinition), or any other syntax nodes.

The resulting ParseOutput object will contain syntax errors (if any), and the syntax tree corresponding to the input source code.

"},{"location":"user-guide/concepts/#concrete-syntax-tree-cst","title":"Concrete Syntax Tree (CST)","text":"

Slang is capable of parsing the source code into a Concrete Syntax Tree (CST; also sometimes called \"full-fidelity\"), which is a tree structure of the program that also includes things like punctuation or whitespace.

This is done by using the (standard) approach of lexical analysis followed by syntax analysis. The source text as a sequence of characters is recognized into a sequence of terminals (lexical analysis), which then in turn is parsed into the CST.

The resulting CST is a regular tree data structure that you can visit. The tree nodes are represented by the Node structure, which can be one of two kinds:

"},{"location":"user-guide/concepts/#cst-cursors","title":"CST Cursors","text":"

For many code analysis tasks, it is useful to traverse the parse tree and visit each node. The Cursor object allows callers to traverse the parse tree in an efficient pre-order manner.

It provides several goTo*() navigation functions, each returning true if the cursor was successfully moved, and false otherwise. There are three main ways to do it:

As such, the cursor is stateful and keeps track of the path it has taken through the CST. It starts at the root it was created at and is completed when it reaches its root when navigating forward.

"},{"location":"user-guide/concepts/#cst-queries","title":"CST Queries","text":"

The Cursor API is a low-level API that allows you to traverse the CST in a procedural manner. However, it is often more convenient to use the declarative Query API. Queries allow you to express your intent more concisely, and also allows you to reuse the same query in multiple places. Queries can largely replace the need for both internal (cursor), and external (visitor) iterator patterns.

The query language is based on pattern matching, and the execution semantics are closer to unification than to regular expression matching i.e. a query returns all possible matches, not just the longest/shortest/first/last match. There is no concept of a 'greedy' operator for example.

Query execution is based on Cursors, and the resulting matches and unification captures are returned as Cursors as well. This allows you to mix and match manual traversal, cursors, and queries.

Multiple queries can be executed in a batch, and efficiently traverse the tree looking for matches. This mode of operation can replace all visitor patterns.

"},{"location":"user-guide/concepts/#abstract-syntax-tree-ast","title":"Abstract Syntax Tree (AST)","text":"

AST types are a set of abstractions that provide a typed view of the untyped CST nodes. You can convert any untyped CST node to its corresponding AST type using their constructors.

There is a corresponding type for each NonterminalKind in the language. AST types are immutable. Additionally, their fields are constructed lazily as they are accessed for the first time.

AST nodes maintain a reference to the CST node they were constructed from, and can be used to navigate to the corresponding CST node.

"},{"location":"user-guide/introduction/","title":"Introduction","text":"

Welcome to the Slang user guide! This aims to be an introduction to Slang itself, its concepts and also contains a collection of guides how you can achieve basic tasks with it.

"},{"location":"user-guide/introduction/#what-is-slang","title":"What is Slang?","text":"

Slang is intended to be a modular Solidity compiler, specifically targeting code analysis and developer tooling. This means servicing tools with domain-specific APIs and, in general, facilitating working with and analyzing the Solidity source code. If you're in the editor writing Solidity or performing linting or additional validation, there's a chance that you are, or could be, running Slang!

To get a good grasp on the concepts used in Slang, see the Concepts section.

"},{"location":"user-guide/introduction/#what-slang-is-not","title":"What Slang is not?","text":"

First and foremost, it is not a replacement for solc, the standard Solidity compiler. We do not plan at the moment to support emitting optimized EVM bytecode for use in production. Secondly, it does not perform formal verification of contracts or Solidity logic in general. However, other tools that serve this purpose are intended to be built on top of it.

"},{"location":"user-guide/introduction/#supporting-multiple-versions","title":"Supporting multiple versions","text":"

The Solidity programming language has evolved quite a bit since its inception. Some features were introduced, some changed, while some eventually became obsolete and were removed altogether.

While it's good for a programming language to evolve and better serve the needs of its users, not being able to easily upgrade or re-deploy existing contracts poses a unique challenge. Developer tooling must be able to understand and consume older contracts that are still being used on the blockchain, written in older versions of Solidity.

Because of that, Slang must be able to reason about different versions of Solidity; how the language grammar, name capture rules, and semantics have changed across different versions. One of our goals is to document differences as part of our Solidity Specification.

This is why, instead of having to download separate versions of the tool for each Solidity version, you can access the Slang language APIs by simply specifying the Solidity version that you want to work with.

"},{"location":"user-guide/introduction/#distributions","title":"Distributions","text":"

Slang itself is written in Rust, compiled as a WASM component, and distributed as an npm package with a TypeScript interface. In the future, we are also looking into publishing it as a Rust crate, a Python library, and possibly more.

"},{"location":"user-guide/tree-query-language/","title":"The Tree Query Language","text":""},{"location":"user-guide/tree-query-language/#query-syntax","title":"Query Syntax","text":"

A query is a pattern that matches a certain set of nodes in a tree. The expression to match a given node consists of a pair of brackets ([]) containing two things: the node's kind, and optionally, a series of other patterns that match the node's children. For example, this pattern would match any MultiplicativeExpression node that has two children Expression nodes, with an Asterisk node in between:

[MultiplicativeExpression [Expression] [Asterisk] [Expression]]\n

The children of a node can optionally be labeled. The label is a property of the edge from the node to the child, and is not a property of the child. For example, this pattern will match a MultiplicativeExpression node with the two Expression children labeled left_operand and right_operand:

[MultiplicativeExpression left_operand:[Expression] [Asterisk] right_operand:[Expression]]\n

You can also match a node's textual content using a string literal. For example, this pattern would match a MultiplicativeExpression with a * operator (for clarity):

[MultiplicativeExpression left_operand:[_] operator:[\"*\"] right_operand:[_]]\n

If you don't care about the kind of a node, you can use an underscore _, which matches any kind. For example, this pattern will match a MultiplicativeExpression node with two children, one of any kind labeled left_operand and one of any kind:

[MultiplicativeExpression left_operand:[_] [_]]\n

Children can be elided. For example, this would produce multiple matches for a MultiplicativeExpression where at least one of the children is an expression of a StringExpression variant, where each match is associated with each of the StringExpression children:

[MultiplicativeExpression [Expression [StringExpression]]]\n

Trivia nodes (whitespace, comments, etc.) will be skipped over when running a query. Furthermore, trivia nodes cannot be explicitly (or implicitly with _) matched by queries.

"},{"location":"user-guide/tree-query-language/#capturing-nodes","title":"Capturing Nodes","text":"

When matching patterns, you may want to process specific nodes within the pattern. Captures allow you to associate names with specific nodes in a pattern, so that you can later refer to those nodes by those names. Capture names are written before the nodes that they refer to, and start with an @ character.

For example, this pattern would match any struct definition and it would associate the name struct_name with the identifier:

[StructDefinition @struct_name name:[Identifier]]\n

And this pattern would match all event definitions for a contract, associating the name event_name with the event name, contract_name with the containing contract name:

[ContractDefinition\n    @contract_name name:[Identifier]\n    members:[ContractMembers\n        [ContractMember\n            [EventDefinition @event_name name:[Identifier]]\n        ]\n    ]\n]\n
"},{"location":"user-guide/tree-query-language/#quantification","title":"Quantification","text":"

You can surround a sequence of patterns in parenthesis (()), followed by a ?, * or + operator. The ? operator matches zero or one repetitions of a pattern, the * operator matches zero or more, and the + operator matches one or more.

For example, this pattern would match a sequence of one or more import directives at the top of the file:

[SourceUnit members:[_ ([_ @import [ImportDirective]])+]]\n

This pattern would match a structure definition with one or more members, capturing their names:

[StructDefinition\n    @name name:[_]\n    members:[_ ([_ @member [Identifier]])+]\n]\n

This pattern would match all function calls, capturing a string argument if one was present:

[FunctionCallExpression\n    arguments:[ArgumentsDeclaration\n        variant:[PositionalArgumentsDeclaration\n            arguments:[PositionalArguments\n                (@arg [Expression variant:[StringExpression]])?\n            ]\n        ]\n    ]\n]\n
"},{"location":"user-guide/tree-query-language/#alternations","title":"Alternations","text":"

An alternation is written as a sequence of patterns separated by | and surrounded by parentheses.

For example, this pattern would match a call to either a variable or an object property. In the case of a variable, capture it as @function, and in the case of a property, capture it as @method:

[FunctionCallExpression\n    operand:[Expression\n        (@function variant:[Identifier]\n        | @method variant:[MemberAccessExpression])\n    ]\n]\n

This pattern would match a set of possible keyword terminals, capturing them as @keyword:

@keyword (\n    [\"break\"]\n  | [\"delete\"]\n  | [\"else\"]\n  | [\"for\"]\n  | [\"function\"]\n  | [\"if\"]\n  | [\"return\"]\n  | [\"try\"]\n  | [\"while\"]\n)\n
"},{"location":"user-guide/tree-query-language/#adjacency","title":"Adjacency","text":"

By using the adjacency operator . you can constrain a pattern to only match the first or the last child nodes.

For example, the following pattern would match only the first parameter declaration in a function definition:

[FunctionDefinition\n    [ParametersDeclaration\n        [Parameters . @first_param [Parameter]]\n    ]\n]\n

And conversely the following will match only the last parameter:

[FunctionDefinition\n    [ParametersDeclaration\n        [Parameters @last_param [Parameter] .]\n    ]\n]\n

If the adjacency operator is used in between two patterns it constrains matches on both patterns to occur consecutively, ie. without any other sibling node in between. For example, this pattern matches pairs of consecutive statements:

[Statements @stmt1 [Statement] . @stmt2 [Statement]]\n
"},{"location":"user-guide/npm-package/","title":"NPM Package","text":""},{"location":"user-guide/npm-package/installation/","title":"Installation","text":"

You can install Slang NPM package simply by running the following npm command:

npm install \"@nomicfoundation/slang\"\n

Or if you are using yarn for package management:

yarn add \"@nomicfoundation/slang\"\n
"},{"location":"user-guide/npm-package/using-queries/","title":"Using Queries","text":"

It's often more convenient to use the declarative Query API to traverse the CST, as they allow you to express your intent more concisely and can largely replace the need for both internal (cursor), and external (visitor) iterator patterns.

The Tree Query Language is based on pattern matching, and the execution semantics are closer to unification than to regular expression matching. A query returns all possible matches, not just the longest/shortest/first/last match.

If not specified otherwise, let's assume we already parsed a Solidity source and have a cursor pointing to the root node of the CST (created with createTreeCursor, see Using the Cursor).

"},{"location":"user-guide/npm-package/using-queries/#creating-and-executing-queries","title":"Creating and executing queries","text":"

You can create a Query object using Query.parse, which accepts a string value. These can be then used by Cursor.query to execute it.

You can pass multiple queries to a cursor to and efficiently traverse the tree looking for matches. They will be executed concurrently, returning matches in the order they appear in input.

// Any `Cursor` can be used to create a query.\nconst cursor = parseOutput.createTreeCursor();\n\nconst query = Query.parse(\"[ContractDefinition]\");\nconst matches: QueryMatchIterator = cursor.query([query]);\n
"},{"location":"user-guide/npm-package/using-queries/#iterating-over-node-patterns","title":"Iterating over node patterns","text":"

Queries allow you to iterate over all node patterns that match the query, which can replace your need for manual iteration via cursors or visitors. In order to get a Cursor that points to the matched node, you need to capture them with a name capture (@capture_name) to a specific node in the query pattern.

Let's use this to list all the contract definitions in the source file:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
const found = [];\n\nconst query = Query.parse(\"@contract [ContractDefinition]\");\nconst matches = cursor.query([query]);\n\nfor (const match of matches) {\n  const cursor = match.captures[\"contract\"]![0]!;\n\n  assertIsNonterminalNode(cursor.node);\n  found.push(cursor.node.unparse().trim());\n}\n\nassert.deepStrictEqual(found, [\"contract Foo {}\", \"contract Bar {}\", \"contract Baz {}\"]);\n
"},{"location":"user-guide/npm-package/using-queries/#multiple-patterns-simultaneously","title":"Multiple patterns simultaneously","text":"

We can also intersperse multiple patterns in a single query, which will return all the matches for each pattern. This can be useful when you want to match multiple types of nodes in a single pass.

const names = [];\n\nconst structDefinition = Query.parse(\"[StructDefinition @name [Identifier]]\");\nconst enumDefinition = Query.parse(\"[EnumDefinition @name [Identifier]]\");\nconst matches = cursor.query([structDefinition, enumDefinition]);\n\nfor (const match of matches) {\n  const index = match.queryNumber;\n  const cursor = match.captures[\"name\"]![0]!;\n\n  names.push([index, cursor.node.unparse()]);\n}\n\nassert.deepStrictEqual(names, [\n  [0, \"Foo\"],\n  [1, \"Bar\"],\n  [0, \"Baz\"],\n  [1, \"Qux\"],\n]);\n
"},{"location":"user-guide/npm-package/using-queries/#matching-on-nodes-label","title":"Matching on node's label","text":"

We can match not only on the node's kind, but also on its label. This can be useful if there may be two children with the same kind but different labels or to be more declarative.

To do so, we use [label: _] syntax. Here, we also use _ to allow matching any kind of node, as long as it matches the given label.

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
const names = [];\n\nconst query = Query.parse(\"[TypedTupleMember @type type_name:[_]]\");\nconst matches = cursor.query([query]);\n\nfor (const match of matches) {\n  const cursor = match.captures[\"type\"]![0]!;\n\n  names.push(cursor.node.unparse());\n}\n\nassert.deepStrictEqual(names, [\"uint\", \" uint16\", \" uint64\", \" uint256\"]);\n
"},{"location":"user-guide/npm-package/using-queries/#matching-on-nodes-literal-content","title":"Matching on node's literal content","text":"

Lastly, we can also match on the node's literal content. This can be useful when you want to match a specific identifier, string, or number.

Let's say we prefer our code to be explicit and prefer using uint256 instead of uint. To find all instances of the uint alias we could do the following:

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
const names = [];\n\nconst query = Query.parse(`[ElementaryType @uint_keyword variant:[\"uint\"]]`);\nconst matches = cursor.query([query]);\n\nfor (const match of matches) {\n  const cursor = match.captures[\"uint_keyword\"]![0]!;\n\n  names.push(cursor.node.unparse());\n}\n\nassert.deepStrictEqual(names, [\"uint\"]);\n
"},{"location":"user-guide/npm-package/using-queries/#example-finding-txorigin-patterns","title":"Example: Finding tx.origin patterns","text":"

As a more realistic example, let's say we want to write a linter that unconditionally lints against all tx.origin accesses.

Let's use the motivating example from https://soliditylang.org:

input.sol
// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.0 <0.9.0;\n// THIS CONTRACT CONTAINS A BUG - DO NOT USE\ncontract TxUserWallet {\n    address owner;\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    function transferTo(address payable dest, uint amount) public {\n        // THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin\n        require(tx.origin == owner);\n        dest.transfer(amount);\n    }\n}\n

Now, we can above features to write a query that matches all tx.origin patterns:

const query = Query.parse(`\n@txorigin [MemberAccessExpression\n  [Expression @start [\"tx\"]]\n  [\"origin\"]\n]`);\n\nconst matches = cursor.query([query]);\nconst found = [];\n\nfor (const match of matches) {\n  const cursor = match.captures[\"txorigin\"]![0]!;\n\n  found.push([cursor.textOffset.utf8, cursor.node.unparse()]);\n}\n\nassert.deepStrictEqual(found, [[375, \"tx.origin\"]]);\n
"},{"location":"user-guide/npm-package/using-the-ast/","title":"Using the AST","text":"

Let's try to analyze the following Solidity source file, containing a simple function:

input.sol
function add(uint256 a, uint256 b) public pure returns (uint256) {\n    return a + b;\n}\n

We start as usual by parsing the input, and then we can use the ParseOutput root to create the CST type. Since it is a node of kind FunctionDefinition, we are using the AST type of the same name to analyze it:

import assert from \"node:assert\";\nimport { Parser } from \"@nomicfoundation/slang/parser\";\nimport { NonterminalKind } from \"@nomicfoundation/slang/cst\";\nimport { FunctionDefinition } from \"@nomicfoundation/slang/ast\";\n\nconst parser = Parser.create(\"0.8.0\");\n\nconst parseOutput = parser.parse(NonterminalKind.FunctionDefinition, source);\n

The FunctionDefinition type has named fields to access all its children. For example, we can check the name of the function:

const $function = new FunctionDefinition(parseOutput.tree.asNonterminalNode()!);\n\nassert.equal($function.name.variant.unparse(), \"add\");\n

We can also list its parameters:

const parameters = $function.parameters.parameters.items.map((parameter) => {\n  return parameter.name!.unparse();\n});\n\nassert.deepEqual(parameters, [\"a\", \"b\"]);\n

Or attributes:

const attributes = $function.attributes.items.map((attribute) => {\n  return attribute.cst.unparse().trim();\n});\n\nassert.deepEqual(attributes, [\"public\", \"pure\"]);\n
"},{"location":"user-guide/npm-package/using-the-cursor/","title":"Using the Cursor","text":"

This guide will walk you through the basics of using a CST cursor in your project. Let's start with this source file, that contains three contracts:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
import assert from \"node:assert\";\nimport { Parser } from \"@nomicfoundation/slang/parser\";\nimport { assertIsTerminalNode, NonterminalKind, TerminalKind } from \"@nomicfoundation/slang/cst\";\n\nconst parser = Parser.create(\"0.8.0\");\n\nconst parseOutput = parser.parse(NonterminalKind.SourceUnit, source);\n
"},{"location":"user-guide/npm-package/using-the-cursor/#listing-contract-names","title":"Listing Contract Names","text":"

The below example uses a cursor to list the names of all contracts in a source file:

const contracts = [];\n\nconst cursor = parseOutput.createTreeCursor();\n\nwhile (cursor.goToNextNonterminalWithKind(NonterminalKind.ContractDefinition)) {\n  assert(cursor.goToFirstChild());\n  assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier));\n\n  assertIsTerminalNode(cursor.node);\n  contracts.push(cursor.node.unparse());\n\n  assert(cursor.goToParent());\n}\n\nassert.deepStrictEqual(contracts, [\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/npm-package/using-the-cursor/#visiting-only-a-sub-tree","title":"Visiting Only a Sub-tree","text":"

In cases like the above, we needed to visit a sub-tree of the CST (to get the contract name). But we also need to remember to return the cursor to its original position after each read, which is inconvenient, and can lead to subtle bugs.

To avoid this, we can use the spawn() API, which cheaply creates a new cursor that starts at the given node, without copying the previous path history. This lets us visit the sub-tree of each contract, without modifying the original cursor:

const contracts = [];\n\nconst cursor = parseOutput.createTreeCursor();\n\nwhile (cursor.goToNextNonterminalWithKind(NonterminalKind.ContractDefinition)) {\n  const childCursor = cursor.spawn();\n  assert(childCursor.goToNextTerminalWithKind(TerminalKind.Identifier));\n\n  assertIsTerminalNode(childCursor.node);\n  contracts.push(childCursor.node.unparse());\n}\n\nassert.deepStrictEqual(contracts, [\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/npm-package/using-the-cursor/#accessing-node-positions","title":"Accessing Node Positions","text":"

The Cursor API also tracks the position and range of the current node it is visiting. Here is an example that records the source range of each contract, along with its text:

const contracts = [];\n\nconst cursor = parseOutput.createTreeCursor();\n\nwhile (cursor.goToNextNonterminalWithKind(NonterminalKind.ContractDefinition)) {\n  const range = cursor.textRange;\n\n  const contractNode = cursor.node;\n\n  contracts.push([\n    range.start.line,\n    range.start.column,\n    range.end.line,\n    range.end.column,\n    contractNode.unparse().trim(),\n  ]);\n}\n\nassert.deepStrictEqual(contracts, [\n  [0, 0, 1, 0, \"contract Foo {}\"],\n  [1, 0, 2, 0, \"contract Bar {}\"],\n  [2, 0, 2, 15, \"contract Baz {}\"],\n]);\n
"},{"location":"user-guide/npm-package/using-the-parser/","title":"Using the Parser","text":"

Using the API directly provides us with a more fine-grained control over the parsing process. It allows us to parse not just the input as a top-level source unit, but also individual constructs like contracts, various definitions, and even expressions.

"},{"location":"user-guide/npm-package/using-the-parser/#parsing-source-files","title":"Parsing Source Files","text":"

Let's start with this simple source file, that contains a single contract:

input.sol
contract Foo {}\n

We begin by creating a Parser object with a specified version. This is an entry point for our parser API. Then we can use it to parse the source file, specifying the top-level nonterminal to parse:

import assert from \"node:assert\";\nimport { Parser } from \"@nomicfoundation/slang/parser\";\nimport {\n  assertIsNonterminalNode,\n  assertIsTerminalNode,\n  NonterminalKind,\n  TerminalKind,\n} from \"@nomicfoundation/slang/cst\";\n\nconst parser = Parser.create(\"0.8.0\");\n\nconst parseOutput = parser.parse(NonterminalKind.ContractDefinition, source);\n
"},{"location":"user-guide/npm-package/using-the-parser/#checking-for-syntax-errors","title":"Checking for Syntax Errors","text":"

If the file has errors, we can get them from the ParseOutput type, and print them out:

for (const error of parseOutput.errors()) {\n  console.error(`Error at byte offset ${error.textRange.start.utf8}: ${error.message}`);\n}\n

Otherwise, we can check if input is valid using this helpful utility:

assert(parseOutput.isValid());\n
"},{"location":"user-guide/npm-package/using-the-parser/#inspecting-the-parse-tree","title":"Inspecting the Parse Tree","text":"

Now, let's try to inspect the resulting CST, and iterate on its children:

const contract = parseOutput.tree;\nassertIsNonterminalNode(contract, NonterminalKind.ContractDefinition);\n\nconst contractChildren = contract.children();\nassert.equal(contractChildren.length, 7);\n\nconst [contractKeyword, firstSpace, contractName, secondSpace, openBrace, members, closeBrace] = contractChildren;\n\nassertIsTerminalNode(contractKeyword!.node, TerminalKind.ContractKeyword, \"contract\");\nassertIsTerminalNode(firstSpace!.node, TerminalKind.Whitespace, \" \");\nassertIsTerminalNode(contractName!.node, TerminalKind.Identifier, \"Foo\");\nassertIsTerminalNode(secondSpace!.node, TerminalKind.Whitespace, \" \");\nassertIsTerminalNode(openBrace!.node, TerminalKind.OpenBrace, \"{\");\nassertIsNonterminalNode(members!.node, NonterminalKind.ContractMembers);\nassertIsTerminalNode(closeBrace!.node, TerminalKind.CloseBrace, \"}\");\n

Additionally, we can convert the CST node back into the input string:

const contractSource = contract.unparse();\nassert.equal(contractSource, \"contract Foo {}\");\n
"},{"location":"user-guide/rust-crate/","title":"Rust Crate","text":""},{"location":"user-guide/rust-crate/installation/","title":"Installation","text":"

The Rust package is published to crates.io as slang_solidity (docs). It can be used both as a regular Rust dependency and as a standalone CLI (installable with Cargo).

You can install the CLI as a cargo binary using:

cargo install \"slang_solidity_cli\"\n

Or you can add the API as a dependency to your project:

cargo add \"slang_solidity\"\n
"},{"location":"user-guide/rust-crate/using-queries/","title":"Using Queries","text":"

It's often more convenient to use the declarative Query API to traverse the CST, as they allow you to express your intent more concisely and can largely replace the need for both internal (cursor), and external (visitor) iterator patterns.

The query language is based on pattern matching, and the execution semantics are closer to unification than to regular expression matching. A query returns all possible matches, not just the longest/shortest/first/last match.

If not specified otherwise, let's assume we already parsed a Solidity source and have a cursor pointing to the root node of the CST (created with create_tree_cursor, see Using the Cursor).

"},{"location":"user-guide/rust-crate/using-queries/#creating-and-executing-queries","title":"Creating and executing queries","text":"

You can create a Query struct using Query::parse, which accepts a &str. These can be then used by Cursor::query to execute it.

You can pass multiple queries to a cursor to and efficiently traverse the tree looking for matches. They will be executed concurrently, returning matches in the order they appear in input.

use slang_solidity::cst::Query;\n\n// Any `Cursor` can be used to create a query.\nlet cursor = parse_output.create_tree_cursor();\n\nlet query = Query::parse(\"[ContractDefinition]\").unwrap();\nlet result: QueryMatchIterator = cursor.query(vec![query]);\n
"},{"location":"user-guide/rust-crate/using-queries/#iterating-over-node-patterns","title":"Iterating over node patterns","text":"

Queries allow you to iterate over all node patterns that match the query, which can replace your need for manual iteration via cursors or visitors. In order to get a Cursor that points to the matched node, you need to capture them with a name capture (@capture_name) to a specific node in the query pattern.

Let's use this to list all the contract definitions in the source file:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
let mut found = vec![];\n\nlet query = Query::parse(\"@contract [ContractDefinition]\").unwrap();\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"contract\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    found.push(cursor.node().unparse().trim().to_owned());\n}\n\nassert_eq!(\n    found,\n    [\"contract Foo {}\", \"contract Bar {}\", \"contract Baz {}\"]\n);\n
"},{"location":"user-guide/rust-crate/using-queries/#multiple-patterns-simultaneously","title":"Multiple patterns simultaneously","text":"

We can also intersperse multiple patterns in a single query, which will return all the matches for each pattern. This can be useful when you want to match multiple types of nodes in a single pass.

let mut names = vec![];\n\nlet struct_def = Query::parse(\"[StructDefinition @name [Identifier]]\").unwrap();\nlet enum_def = Query::parse(\"[EnumDefinition @name [Identifier]]\").unwrap();\n\nfor r#match in cursor.query(vec![struct_def, enum_def]) {\n    let index = r#match.query_number;\n    let captures = r#match.captures;\n    let cursors = captures.get(\"name\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    names.push((index, cursor.node().unparse()));\n}\n\nassert_eq!(\n    names,\n    &[\n        (0, \"Foo\".to_string()),\n        (1, \"Bar\".to_string()),\n        (0, \"Baz\".to_string()),\n        (1, \"Qux\".to_string())\n    ]\n);\n
"},{"location":"user-guide/rust-crate/using-queries/#matching-on-nodes-label","title":"Matching on node's label","text":"

We can match not only on the node's kind, but also on its label. This can be useful if there may be two children with the same kind but different labels or to be more declarative.

To do so, we use [label: _] syntax. Here, we also use _ to allow matching any kind of node, as long as it matches the given label.

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
let mut names = vec![];\n\nlet query = Query::parse(\"[TypedTupleMember @type type_name:[_]]\").unwrap();\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"type\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    names.push(cursor.node().unparse());\n}\n\nassert_eq!(names, &[\"uint\", \" uint16\", \" uint64\", \" uint256\"]);\n
"},{"location":"user-guide/rust-crate/using-queries/#matching-on-nodes-literal-content","title":"Matching on node's literal content","text":"

Lastly, we can also match on the node's literal content. This can be useful when you want to match a specific identifier, string, or number.

Let's say we prefer our code to be explicit and prefer using uint256 instead of uint. To find all instances of the uint alias we could do the following:

input.sol
contract Example {\n    function foo() public {\n        (uint a, uint16 b, uint64 c, uint256 d) = (1, 2, 3, 4);\n    }\n}\n
let mut names = vec![];\n\nlet query = Query::parse(r#\"[ElementaryType @uint_keyword variant:[\"uint\"]]\"#).unwrap();\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"uint_keyword\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    names.push(cursor.node().unparse());\n}\n\nassert_eq!(names, &[\"uint\"]);\n
"},{"location":"user-guide/rust-crate/using-queries/#example-finding-txorigin-patterns","title":"Example: Finding tx.origin patterns","text":"

As a more realistic example, let's say we want to write a linter that unconditionally lints against all tx.origin accesses.

Let's use the motivating example from https://soliditylang.org:

input.sol
// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.0 <0.9.0;\n// THIS CONTRACT CONTAINS A BUG - DO NOT USE\ncontract TxUserWallet {\n    address owner;\n\n    constructor() {\n        owner = msg.sender;\n    }\n\n    function transferTo(address payable dest, uint amount) public {\n        // THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin\n        require(tx.origin == owner);\n        dest.transfer(amount);\n    }\n}\n

Now, we can above features to write a query that matches all tx.origin patterns:

let query = Query::parse(\n    r#\"@txorigin [MemberAccessExpression\n            [Expression @start [\"tx\"]]\n            [\"origin\"]\n        ]\"#,\n)\n.unwrap();\n\nlet mut results = vec![];\n\nfor r#match in cursor.query(vec![query]) {\n    let captures = r#match.captures;\n    let cursors = captures.get(\"txorigin\").unwrap();\n\n    let cursor = cursors.first().unwrap();\n\n    results.push((cursor.text_offset().utf8, cursor.node().unparse()));\n}\n\nassert_eq!(results, &[(375usize, \"tx.origin\".to_string())]);\n
"},{"location":"user-guide/rust-crate/using-the-cli/","title":"Using the CLI","text":""},{"location":"user-guide/rust-crate/using-the-cli/#parsing-source-files","title":"Parsing Source Files","text":"

The parse command will take a path to a Solidity file, and a --version flag. Specifying the correct version is important, as it will affect the grammar used to parse inputs.

All parse errors are printed in a human-readable format; the command will succeed if there are no parse errors, and fail otherwise.

$ slang_solidity parse --help\n\nUsage: slang_solidity parse [OPTIONS] --version <VERSION> <FILE_PATH>\n\nArguments:\n  <FILE_PATH>\n          File path to the Solidity (*.sol) source file to parse\n\nOptions:\n  -v, --version <VERSION>\n          The Solidity language version to use for parsing\n      --json\n          Print the concrete syntax tree as JSON\n  -h, --help\n          Print help\n

Here is an example of the JSON output it can print:

// A Nonterminal node\n\"Nonterminal\": {\n  // Name of the nonterminal kind\n  \"kind\": \"SourceUnit\",\n  // Length of the nonterminal in Unicode code points, depending on the encoding used\n  \"text_len\": {\n    \"utf8\": 24,\n    \"utf16\": 24,\n    \"char\": 24 // de facto utf32\n  },\n  \"children\": [/* Nonterminal or Terminal nodes */]\n}\n// A Terminal node\n\"Terminal\": {\n  // Name of the terminal kind\n  \"kind\": \"PragmaKeyword\",\n  // Literal value, taken from the source code\n  \"text\": \"pragma\"\n}\n
"},{"location":"user-guide/rust-crate/using-the-cli/#inspecting-json-output","title":"Inspecting JSON Output","text":"

Now let's try to use that command to parse the following Solidity file, and inspect its contents:

input.sol
pragma solidity ^0.8.0;\n
slang_solidity parse --json --version \"0.8.0\" \"input.sol\" > \"output.json\"\n

Because the resulting structure is well-defined and recursive, we can use the popular jq tool to quickly analyze the resulting output:

JQ_QUERY='recurse | select(.Terminal?) | .Terminal'\ncat output.json | jq \"$JQ_QUERY\"\n

This gives us a flat list of the Terminal nodes:

{\n  \"kind\": \"PragmaKeyword\",\n  \"text\": \"pragma\"\n}\n{\n  \"kind\": \"Whitespace\",\n  \"text\": \" \"\n}\n{\n  \"kind\": \"SolidityKeyword\",\n  \"text\": \"solidity\"\n}\n{\n  \"kind\": \"Whitespace\",\n  \"text\": \" \"\n}\n{\n  \"kind\": \"Caret\",\n  \"text\": \"^\"\n}\n{\n  \"kind\": \"VersionPragmaValue\",\n  \"text\": \"0\"\n}\n{\n  \"kind\": \"Period\",\n  \"text\": \".\"\n}\n{\n  \"kind\": \"VersionPragmaValue\",\n  \"text\": \"8\"\n}\n{\n  \"kind\": \"Period\",\n  \"text\": \".\"\n}\n{\n  \"kind\": \"VersionPragmaValue\",\n  \"text\": \"0\"\n}\n{\n  \"kind\": \"Semicolon\",\n  \"text\": \";\"\n}\n{\n  \"kind\": \"EndOfLine\",\n  \"text\": \"\\n\"\n}\n

Now, we can adapt the query to select the text fields of the nodes and concatenate them, which gives us back the reconstructed source code! \ud83c\udf89

$ JQ_QUERY='[recurse | select(.Terminal?) | .Terminal.text] | join(\"\")'\n$ cat output.json | jq \"$JQ_QUERY\"\n\n\"pragma solidity ^0.8.0;\\n\"\n
"},{"location":"user-guide/rust-crate/using-the-cursor/","title":"Using the Cursor","text":"

This guide will walk you through the basics of using a CST cursor in your project. Let's start with this source file, that contains three contracts:

input.sol
contract Foo {}\ncontract Bar {}\ncontract Baz {}\n
use semver::Version;\nuse slang_solidity::cst::{EdgeLabel, NonterminalKind, TerminalKind, TextRangeExtensions};\nuse slang_solidity::parser::Parser;\n\nlet parser = Parser::create(Version::parse(\"0.8.0\")?)?;\n\nlet parse_output = parser.parse(NonterminalKind::SourceUnit, source);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#listing-contract-names","title":"Listing Contract Names","text":"

The below example uses a cursor to list the names of all contracts in a source file:

let mut contracts = Vec::new();\n\nlet mut cursor = parse_output.create_tree_cursor();\n\nwhile cursor.go_to_next_nonterminal_with_kind(NonterminalKind::ContractDefinition) {\n    assert!(cursor.go_to_first_child());\n    assert!(cursor.go_to_next_terminal_with_kind(TerminalKind::Identifier));\n\n    let terminal_node = cursor.node();\n    contracts.push(terminal_node.as_terminal().unwrap().text.clone());\n\n    // You have to make sure you return the cursor to its original position:\n    assert!(cursor.go_to_parent());\n}\n\nassert_eq!(contracts, &[\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#visiting-only-a-sub-tree","title":"Visiting Only a Sub-tree","text":"

In cases like the above, we needed to visit a sub-tree of the CST (to get the contract name). But we also need to remember to return the cursor to its original position after each read, which is inconvenient, and can lead to subtle bugs.

To avoid this, we can use the spawn() API, which cheaply creates a new cursor that starts at the given node, without copying the previous path history. This lets us visit the sub-tree of each contract, without modifying the original cursor:

let mut contracts = Vec::new();\n\nlet mut cursor = parse_output.create_tree_cursor();\n\nwhile cursor.go_to_next_nonterminal_with_kind(NonterminalKind::ContractDefinition) {\n    let mut child_cursor = cursor.spawn();\n    assert!(child_cursor.go_to_next_terminal_with_kind(TerminalKind::Identifier));\n\n    let terminal_node = child_cursor.node();\n    contracts.push(terminal_node.as_terminal().unwrap().text.clone());\n}\n\nassert_eq!(contracts, &[\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#accessing-node-positions","title":"Accessing Node Positions","text":"

The Cursor API also tracks the position and range of the current node it is visiting. Here is an example that records the source range of each contract, along with its text:

let mut contracts = Vec::new();\n\nlet mut cursor = parse_output.create_tree_cursor();\n\nwhile cursor.go_to_next_nonterminal_with_kind(NonterminalKind::ContractDefinition) {\n    let range = cursor.text_range().utf8();\n    let text = cursor.node().unparse();\n\n    contracts.push((range, text.trim().to_owned()));\n}\n\nassert_eq!(\n    contracts,\n    &[\n        (0..16, \"contract Foo {}\".to_string()),\n        (16..32, \"contract Bar {}\".to_string()),\n        (32..47, \"contract Baz {}\".to_string()),\n    ]\n);\n
"},{"location":"user-guide/rust-crate/using-the-cursor/#using-iterator-api","title":"Using Iterator API","text":"

In addition to the procedural-style methods, the Cursor struct also implements the Iterator trait, which allows you to use it in a functional style.

Let's use that to extract all Identifier nodes from the source text using that API:

let identifiers: Vec<_> = Rc::clone(parse_output.tree())\n    .descendants()\n    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))\n    .map(|identifier| identifier.unparse())\n    .collect();\n\nassert_eq!(identifiers, &[\"Foo\", \"Bar\", \"Baz\"]);\n

Note

It's important to note that Iterator::next first visits the current node, yields it, and then moves the cursor to the next node. As such, accessor associated functions called on the Cursor that reference the \"current\" will point to the one that is not yet yielded by the iterator. This might be an important, when mixing the two styles.

"},{"location":"user-guide/rust-crate/using-the-cursor/#using-a-cursor-with-labels","title":"Using a Cursor with Labels","text":"

The cursor also keeps track of the labels of the nodes it visits. Let's use that to extract all nodes that are labeled Name:

let identifiers: Vec<_> = Rc::clone(parse_output.tree())\n    .descendants()\n    .filter(|edge| edge.label == Some(EdgeLabel::Name))\n    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))\n    .map(|identifier| identifier.unparse())\n    .collect();\n\nassert_eq!(identifiers, &[\"Foo\", \"Bar\", \"Baz\"]);\n
"},{"location":"user-guide/rust-crate/using-the-parser/","title":"Using the Parser","text":"

Using the API directly provides us with a more fine-grained control over the parsing process. It allows us to parse not just the input as a top-level source unit, but also individual nonterminals like contracts, various definitions, and even expressions.

"},{"location":"user-guide/rust-crate/using-the-parser/#parsing-source-files","title":"Parsing Source Files","text":"

Let's start with this simple source file, that contains a single contract:

input.sol
contract Foo {}\n

We begin by creating a Parser object with a specified version. This is an entry point for our parser API. Then we can use it to parse the source file, specifying the top-level nonterminal to parse:

use semver::Version;\nuse slang_solidity::cst::{Node, NonterminalKind, TerminalKind};\nuse slang_solidity::parser::Parser;\n\nlet parser = Parser::create(Version::parse(\"0.8.0\")?)?;\n\nlet parse_output = parser.parse(NonterminalKind::ContractDefinition, source);\n
"},{"location":"user-guide/rust-crate/using-the-parser/#checking-for-syntax-errors","title":"Checking for Syntax Errors","text":"

If the file has errors, we can get them from the ParseOutput type, and print them out:

for error in parse_output.errors() {\n    eprintln!(\n        \"Error at byte offset {offset}: {message}\",\n        offset = error.text_range().start.utf8,\n        message = error.message()\n    );\n}\n

Otherwise, we can check if input is valid using this helpful utility:

assert!(parse_output.is_valid());\n
"},{"location":"user-guide/rust-crate/using-the-parser/#inspecting-the-parse-tree","title":"Inspecting the Parse Tree","text":"

Now, let's try to inspect the resulting CST, and iterate on its children:

let contract = parse_output.tree();\n\nassert_eq!(contract.kind, NonterminalKind::ContractDefinition);\nassert_eq!(contract.children.len(), 7);\n\nlet children = &contract.children;\nassert!(\n    matches!(&children[0].node, Node::Terminal(t) if t.kind == TerminalKind::ContractKeyword)\n);\nassert!(matches!(&children[1].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));\nassert!(matches!(&children[2].node, Node::Terminal(t) if t.kind == TerminalKind::Identifier));\nassert!(matches!(&children[3].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));\nassert!(matches!(&children[4].node, Node::Terminal(t) if t.kind == TerminalKind::OpenBrace));\nassert!(\n    matches!(&children[5].node, Node::Nonterminal(r) if r.kind == NonterminalKind::ContractMembers)\n);\nassert!(matches!(&children[6].node, Node::Terminal(t) if t.kind == TerminalKind::CloseBrace));\n

Additionally, we can convert the CST node back into the input string:

assert_eq!(contract.unparse(), \"contract Foo {}\");\n
"}]} \ No newline at end of file diff --git a/main/sitemap.xml b/main/sitemap.xml index 61329827c7..5e3f747caa 100644 --- a/main/sitemap.xml +++ b/main/sitemap.xml @@ -2,266 +2,266 @@ https://NomicFoundation.github.io/slang/latest/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/internals/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/internals/development/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/internals/repository-structure/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/internals/design-docs/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/internals/design-docs/language-definition-v2/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/supported-versions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/01-license-specifiers/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/02-source-unit/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/03-pragma-directives/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/04-import-directives/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/05-using-directives/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/06-trivia/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/07-nat-spec-format/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/08-keywords/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/01-file-structure/09-punctuation/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/01-contracts/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/02-interfaces/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/03-libraries/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/04-structs/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/05-enums/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/06-constants/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/07-state-variables/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/08-functions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/09-modifiers/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/10-events/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/11-user-defined-value-types/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/02-definitions/12-errors/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/03-types/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/03-types/01-advanced-types/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/03-types/02-elementary-types/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/04-statements/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/04-statements/01-blocks/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/04-statements/02-declaration-statements/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/04-statements/03-control-statements/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/04-statements/04-error-handling/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/01-base-expressions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/02-function-calls/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/03-primary-expressions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/04-numbers/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/05-strings/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/05-expressions/06-identifiers/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/06-yul/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/06-yul/01-yul-statements/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/06-yul/02-yul-expressions/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/solidity-specification/06-yul/03-yul-keywords/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/concepts/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/introduction/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/tree-query-language/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/npm-package/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/npm-package/installation/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/npm-package/using-queries/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/npm-package/using-the-ast/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/npm-package/using-the-cursor/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/npm-package/using-the-parser/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/rust-crate/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/rust-crate/installation/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/rust-crate/using-queries/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/rust-crate/using-the-cli/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/rust-crate/using-the-cursor/ - 2025-01-09 + 2025-01-13 https://NomicFoundation.github.io/slang/latest/user-guide/rust-crate/using-the-parser/ - 2025-01-09 + 2025-01-13 \ No newline at end of file diff --git a/main/sitemap.xml.gz b/main/sitemap.xml.gz index 3e52539c931689629fa79440b7fb8cb6e1533c0c..6d4f623430d47ac726b6242e9eb9d8bd9d21fb0d 100644 GIT binary patch literal 799 zcmV+)1K|80iwFpSSA=H*|8r?{Wo=<_E_iKh0M(k!Zrd;nfbV^ZAa};G^V4=n(_4=_ zZ4aQxj3ZQ*H2pZu+mCY6F5QN0zy^%U#g0NtA1IO{8E+n6dOaD?2W8E}w4TkU6ExDc z%5)FY&!3*)Zu+>r*(9$6#t8|V@Gw2Z=sr}{@pzmC6|omC%&hOKAP@83A`-={Q}K{?Gi9rwh3P6SB8FIPs{GLP93sTt zw%cajtYBV4y&#dx*m=?FZPkCUzA_QL5jrp;X>mYpU5|#7empu$CSd&uLi9<-;CXMMyLF5xY3C8dS; zN+Tm@`D0KT(MqBT_$o@eE(pJYV3U^!iQKFp?gcn6x?Vu5Jj$pBEJ^E2P<{5zGU->4 z0;NY~!mlBEH7HRK@+}wkfPoBI z>~uM{dA;h%z8grvn_!D#H<@wy`SqF!Akc6?Lxt~kH&2d3$;m04#)Ar(A zg;-r4`tlrt;UG+_6+O)ro6_SK=P~f^Jin*RZYTnlNZ!1qoFIkP#c=0FuIlrdQlQe8 zKo#JQbISZ3@G2MC6g7$gUV~~W@G&n;)^JLiIUTJ}ml6)V3vV;>mJk&#z>5)>O}~3A zHoHXr!wH2FFNrR)Qjf~HV4Eb1cK;Pu^oZ~!AsvpdZ$xmyGp+|G2p$~U^-oydzH(rXj%6`5ugjgBa|s??g#{`T$2fpR8|6vXM2oWayst@lK)pTXqx*p(GAz zP4q&>VvuVXlGMGBSPb)=vXY$_UX_EqxO!kQz)L`rx?*rw+4DjarW_65lS$A6(32sH zoi4|gA7GykkdgxP8fbmy<;#2I*%YwHa?E))qr4gYWh__aLMMcHcE#BBtOoSnGPaO8 zbA7(@5rJrWVIA;h%z8grvn_%n0n#pT@SSOx_3oQ~F~O9=Q+eF_mI752!KimOZCAhPx79~cK; d(TYDKJAeKu=HI&Wa0wW (32..47, "contract Baz {}".to_string()), ] ); -

Using Iterator API#

In addition to the procedural-style methods, the Cursor struct also implements the Iterator trait, which allows you to use it in a functional style.

Let's use that to extract all Identifier nodes from the source text using that API:

let identifiers: Vec<_> = parse_output
-    .tree()
-    .clone()
-    .descendants()
-    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))
-    .map(|identifier| identifier.unparse())
-    .collect();
-
-assert_eq!(identifiers, &["Foo", "Bar", "Baz"]);
-

Note

It's important to note that Iterator::next first visits the current node, yields it, and then moves the cursor to the next node. As such, accessor associated functions called on the Cursor that reference the "current" will point to the one that is not yet yielded by the iterator. This might be an important, when mixing the two styles.

Using a Cursor with Labels#

The cursor also keeps track of the labels of the nodes it visits. Let's use that to extract all nodes that are labeled Name:

let identifiers: Vec<_> = parse_output
-    .tree()
-    .clone()
-    .descendants()
-    .filter(|edge| edge.label == Some(EdgeLabel::Name))
-    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))
-    .map(|identifier| identifier.unparse())
-    .collect();
-
-assert_eq!(identifiers, &["Foo", "Bar", "Baz"]);
+

Using Iterator API#

In addition to the procedural-style methods, the Cursor struct also implements the Iterator trait, which allows you to use it in a functional style.

Let's use that to extract all Identifier nodes from the source text using that API:

let identifiers: Vec<_> = Rc::clone(parse_output.tree())
+    .descendants()
+    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))
+    .map(|identifier| identifier.unparse())
+    .collect();
+
+assert_eq!(identifiers, &["Foo", "Bar", "Baz"]);
+

Note

It's important to note that Iterator::next first visits the current node, yields it, and then moves the cursor to the next node. As such, accessor associated functions called on the Cursor that reference the "current" will point to the one that is not yet yielded by the iterator. This might be an important, when mixing the two styles.

Using a Cursor with Labels#

The cursor also keeps track of the labels of the nodes it visits. Let's use that to extract all nodes that are labeled Name:

let identifiers: Vec<_> = Rc::clone(parse_output.tree())
+    .descendants()
+    .filter(|edge| edge.label == Some(EdgeLabel::Name))
+    .filter(|edge| edge.is_terminal_with_kind(TerminalKind::Identifier))
+    .map(|identifier| identifier.unparse())
+    .collect();
+
+assert_eq!(identifiers, &["Foo", "Bar", "Baz"]);
 
\ No newline at end of file diff --git a/main/user-guide/rust-crate/using-the-parser/index.html b/main/user-guide/rust-crate/using-the-parser/index.html index 9b53bcc206..ecaeb67ff3 100644 --- a/main/user-guide/rust-crate/using-the-parser/index.html +++ b/main/user-guide/rust-crate/using-the-parser/index.html @@ -15,23 +15,22 @@ ); }

Otherwise, we can check if input is valid using this helpful utility:

assert!(parse_output.is_valid());
-

Inspecting the Parse Tree#

Now, let's try to inspect the resulting CST, and iterate on its children:

let tree = parse_output.tree();
+

Inspecting the Parse Tree#

Now, let's try to inspect the resulting CST, and iterate on its children:

let contract = parse_output.tree();
 
-let contract = tree.as_nonterminal().unwrap();
-assert_eq!(contract.kind, NonterminalKind::ContractDefinition);
-assert_eq!(contract.children.len(), 7);
-
-let children = &contract.children;
-assert!(
-    matches!(&children[0].node, Node::Terminal(t) if t.kind == TerminalKind::ContractKeyword)
-);
-assert!(matches!(&children[1].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));
-assert!(matches!(&children[2].node, Node::Terminal(t) if t.kind == TerminalKind::Identifier));
-assert!(matches!(&children[3].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));
-assert!(matches!(&children[4].node, Node::Terminal(t) if t.kind == TerminalKind::OpenBrace));
-assert!(
-    matches!(&children[5].node, Node::Nonterminal(r) if r.kind == NonterminalKind::ContractMembers)
-);
-assert!(matches!(&children[6].node, Node::Terminal(t) if t.kind == TerminalKind::CloseBrace));
+assert_eq!(contract.kind, NonterminalKind::ContractDefinition);
+assert_eq!(contract.children.len(), 7);
+
+let children = &contract.children;
+assert!(
+    matches!(&children[0].node, Node::Terminal(t) if t.kind == TerminalKind::ContractKeyword)
+);
+assert!(matches!(&children[1].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));
+assert!(matches!(&children[2].node, Node::Terminal(t) if t.kind == TerminalKind::Identifier));
+assert!(matches!(&children[3].node, Node::Terminal(t) if t.kind == TerminalKind::Whitespace));
+assert!(matches!(&children[4].node, Node::Terminal(t) if t.kind == TerminalKind::OpenBrace));
+assert!(
+    matches!(&children[5].node, Node::Nonterminal(r) if r.kind == NonterminalKind::ContractMembers)
+);
+assert!(matches!(&children[6].node, Node::Terminal(t) if t.kind == TerminalKind::CloseBrace));
 

Additionally, we can convert the CST node back into the input string:

assert_eq!(contract.unparse(), "contract Foo {}");
 
\ No newline at end of file