From 446c7559879d3644f9f8acb15e63cc86ad64089c Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Fri, 3 May 2024 15:15:56 +0100 Subject: [PATCH 01/18] start devdocs --- docs/Makefile | 20 + docs/imgs/exampledir.png | Bin 0 -> 6964 bytes docs/imgs/gptdir.png | Bin 0 -> 3308 bytes docs/imgs/sourceunits.png | Bin 0 -> 13981 bytes docs/imgs/toplevelunits.png | Bin 0 -> 7416 bytes docs/make.bat | 35 + docs/source/autoapi/index.rst | 11 + .../solidity_parser/ast/ast2builder/index.rst | 313 +++ .../ast/funcanalysis/index.rst | 130 + .../solidity_parser/ast/helper/index.rst | 50 + .../solidity_parser/ast/hierarchy/index.rst | 24 + .../autoapi/solidity_parser/ast/index.rst | 33 + .../solidity_parser/ast/mro_helper/index.rst | 45 + .../solidity_parser/ast/nodebase/index.rst | 299 ++ .../ast/parsers/common/index.rst | 111 + .../ast/parsers/errors/index.rst | 38 + .../solidity_parser/ast/parsers/index.rst | 21 + .../ast/parsers/parsers060/index.rst | 316 +++ .../ast/parsers/parsers070/index.rst | 44 + .../ast/parsers/parsers080/index.rst | 300 +++ .../ast/parsers/parsers088/index.rst | 36 + .../ast/parsers/parsers08_22/index.rst | 56 + .../solidity_parser/ast/solnodes/index.rst | 1889 +++++++++++++ .../solidity_parser/ast/solnodes2/index.rst | 2393 +++++++++++++++++ .../solidity_parser/ast/symtab/index.rst | 717 +++++ .../solidity_parser/ast/types/index.rst | 810 ++++++ .../collectors/collector/index.rst | 26 + .../solidity_parser/collectors/index.rst | 19 + .../solidity_parser/collectors/v000/index.rst | 40 + .../solidity_parser/collectors/v060/index.rst | 35 + .../solidity_parser/collectors/v070/index.rst | 35 + .../solidity_parser/collectors/v080/index.rst | 35 + .../autoapi/solidity_parser/errors/index.rst | 43 + .../autoapi/solidity_parser/filesys/index.rst | 178 ++ docs/source/autoapi/solidity_parser/index.rst | 27 + .../autoapi/solidity_parser/util/index.rst | 15 + .../util/version_util/index.rst | 83 + docs/source/conf.py | 40 + docs/source/getstarted/clients.rst | 43 + docs/source/getstarted/index.rst | 12 + docs/source/getstarted/prereq.rst | 40 + docs/source/getstarted/quickstart.rst | 312 +++ docs/source/getstarted/scopes.rst | 132 + docs/source/getstarted/sourcecode.rst | 209 ++ docs/source/getstarted/twoASTs.rst | 198 ++ docs/source/getstarted/vfshooks.rst | 5 + docs/source/index.rst | 28 + 47 files changed, 9246 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/imgs/exampledir.png create mode 100644 docs/imgs/gptdir.png create mode 100644 docs/imgs/sourceunits.png create mode 100644 docs/imgs/toplevelunits.png create mode 100644 docs/make.bat create mode 100644 docs/source/autoapi/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/helper/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/nodebase/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/solnodes/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/symtab/index.rst create mode 100644 docs/source/autoapi/solidity_parser/ast/types/index.rst create mode 100644 docs/source/autoapi/solidity_parser/collectors/collector/index.rst create mode 100644 docs/source/autoapi/solidity_parser/collectors/index.rst create mode 100644 docs/source/autoapi/solidity_parser/collectors/v000/index.rst create mode 100644 docs/source/autoapi/solidity_parser/collectors/v060/index.rst create mode 100644 docs/source/autoapi/solidity_parser/collectors/v070/index.rst create mode 100644 docs/source/autoapi/solidity_parser/collectors/v080/index.rst create mode 100644 docs/source/autoapi/solidity_parser/errors/index.rst create mode 100644 docs/source/autoapi/solidity_parser/filesys/index.rst create mode 100644 docs/source/autoapi/solidity_parser/index.rst create mode 100644 docs/source/autoapi/solidity_parser/util/index.rst create mode 100644 docs/source/autoapi/solidity_parser/util/version_util/index.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/getstarted/clients.rst create mode 100644 docs/source/getstarted/index.rst create mode 100644 docs/source/getstarted/prereq.rst create mode 100644 docs/source/getstarted/quickstart.rst create mode 100644 docs/source/getstarted/scopes.rst create mode 100644 docs/source/getstarted/sourcecode.rst create mode 100644 docs/source/getstarted/twoASTs.rst create mode 100644 docs/source/getstarted/vfshooks.rst create mode 100644 docs/source/index.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/imgs/exampledir.png b/docs/imgs/exampledir.png new file mode 100644 index 0000000000000000000000000000000000000000..6eaa44b834a1eccd6546349c7dd92e17c620d8d7 GIT binary patch literal 6964 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 a6K7Z&TPjv26`h@KxJ9}ntrBAn7 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 literal 0 HcmV?d00001 diff --git a/docs/imgs/gptdir.png b/docs/imgs/gptdir.png new file mode 100644 index 0000000000000000000000000000000000000000..38c76d85cb4f9a3c6219dca7bd34eb55cf6f19c4 GIT binary patch literal 3308 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 literal 0 HcmV?d00001 diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..dc1312a --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/autoapi/index.rst b/docs/source/autoapi/index.rst new file mode 100644 index 0000000..a297ed9 --- /dev/null +++ b/docs/source/autoapi/index.rst @@ -0,0 +1,11 @@ +API Reference +============= + +This page contains auto-generated API reference documentation [#f1]_. + +.. toctree:: + :titlesonly: + + /autoapi/solidity_parser/index + +.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file diff --git a/docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst b/docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst new file mode 100644 index 0000000..3e70625 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst @@ -0,0 +1,313 @@ +:py:mod:`solidity_parser.ast.ast2builder` +========================================= + +.. py:module:: solidity_parser.ast.ast2builder + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.ast2builder.ErrorHandler + solidity_parser.ast.ast2builder.TypeHelper + solidity_parser.ast.ast2builder.Builder + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.ast2builder.T + + +.. py:data:: T + + + +.. py:class:: ErrorHandler(create_state, quiet_errors=True) + + + Keeps track of what AST2Builder is doing and captures the line tracking information when errors happen. Also wraps + Python errors in our own errors types if required and provides assertion failure checking. + + The general idea of this class is to make sure AST2Builder operations return consistent error types by wrapping + them in CodeProcessingErrors so that the client can catch and decide what to do with them. + + .. py:method:: handle_processing_error(error: solidity_parser.errors.CodeProcessingError) + + Error callback handler for AST2Builder functions to call when a CodeProcessingError (only) occurs. + + + .. py:method:: make_processing_error_args(message: str, node: solidity_parser.ast.solnodes.AST1Node) -> solidity_parser.errors.CPEArgs + :staticmethod: + + Helper to make the input args tuple for a CodeProcessingError from a message and AST1 node + + + .. py:method:: with_error_context(func) + + Decorator that takes a function, f, and wraps it in a function that captures the current state of the builder + before executing f and restores the state afterwards. If any errors occur in the process, a CodeProcessingError + (specifically an UnexpectedCodeProcessingError) is raised, which should be allowed to propagate to the client of + the builder. + + + .. py:method:: todo(node) -> T + + Forces an error if the node is not supported by the builder. Since it always raises, the return type is fully + polymorphic and can be used by the builder to do anything. + E.g. a common pattern is to return the result of this function to mark the end of control flow in the builder + code return self.error_handler.todo(node) + + + .. py:method:: error(msg, *predicates) + + Raises an error with the given message if any of the predicates fail. This is used for user level errors, i.e. + the input code is invalid + + + .. py:method:: assert_error(msg, *predicates) + + Raises an assertion error with the given message if any of the predicates fail, very similar to error but used + for 'internal' errors, i.e. compiler assumptions that must pass + + + .. py:method:: _todo(node) -> T + + + .. py:method:: _error(msg, *predicates) + + + .. py:method:: _assert_error(msg, *predicates) + + + +.. py:class:: TypeHelper(builder: Builder, error_handler: ErrorHandler) + + + Helper class for computing AST2 types from AST1 nodes. This is required because AST1 nodes are not linked and do not + have type information associated with some nodes, i.e. the node trees aren't able to compute types on their own. + + .. py:method:: any_or_all(args) + :staticmethod: + + Returns True if any or all args are True + + + .. py:method:: create_filter_using_scope(base_type: solidity_parser.ast.types.Type) + + + .. py:method:: get_current_contract_type(node) -> solidity_parser.ast.solnodes2.ResolvedUserType + + Returns the ResolvedUserType the given node is declared in + + + .. py:method:: get_expr_type(expr: solidity_parser.ast.solnodes.Expr | solidity_parser.ast.types.Type, allow_multiple=False, force_tuple=False, function_callee=False) -> Union[solidity_parser.ast.solnodes2.Types, list[solidity_parser.ast.solnodes2.Types]] + + Main helper function that computes the AST2 type of the given AST1 expression + + :param expr: The AST1 expression to type, may be a Type also as types are part of both the AST1 and AST2 nodeset + :param allow_multiple: Changes the return of this function to a list of types instead of a single type. This is + required for expressions that may need extra contextual information to return a single + resolved Type, e.g. the callee of a function call without its arguments may resolve to + multiple callsites and if this is set to True, the return type will be a list of function + types + :param force_tuple: Forces the return type to be a TupleType instead of a single type in cases where it's + ambiguous, e.g. the expression (x) can be either a bracket expression or a tuple expression + :param function_callee: Whether the expression is the callee of a function call, required to compute the type of + state variable lookups as Solidity generates getter functions if the variable is used as + a function callee + :return: The AST2 type of the expression or a list of types if allow_multiple is True + + + .. py:method:: get_function_expr_type(expr, allow_multiple=False, return_target_symbol=False) + + + .. py:method:: map_as_type_arg(arg) + + This function tries to force the given expr argument into a type if it looks like a type + + The supplied grammar is ambiguous and sometimes parses types as expression e.g. byte[100] would end up as an + array access instead of a fixed length byte array. I've only really seen this happen for arguments of function + calls, i.e. in abi.decode hence the name of the function. Should probably see if this happens in other places in + the grammar too... + + + .. py:method:: param_types(ps) + + Returns the types of the given parameters + + + .. py:method:: symbol_to_ast2_type(symbol, function_callee=False) -> solidity_parser.ast.solnodes2.Types + + Computes the AST2 type of the given symtab Symbol + + + .. py:method:: scopes_for_type(node: solidity_parser.ast.solnodes.AST1Node, ttype: solidity_parser.ast.solnodes2.Types, use_encoded_type_key=True) -> List[solidity_parser.ast.symtab.Scope] + + + .. py:method:: map_type(ttype: solidity_parser.ast.types.Type) -> solidity_parser.ast.solnodes2.Types + + + .. py:method:: get_contract_type(user_type_symbol: solidity_parser.ast.symtab.Symbol) -> solidity_parser.ast.solnodes2.ResolvedUserType + + + .. py:method:: _symtab_top_level_predicate(base_scope) + + + .. py:method:: get_user_type(ttype: solidity_parser.ast.types.UserType) + + Maps an AST1 UserType to AST2 ResolvedUserType in the scope of the AST1 node that references the type + + + +.. py:class:: Builder + + + .. py:class:: State + + + .. py:attribute:: current_node + :type: solidity_parser.ast.solnodes.AST1Node + + + + + .. py:class:: FunctionCallee + + + .. py:attribute:: base + :type: Optional[solidity_parser.ast.solnodes2.Expr | solidity_parser.ast.symtab.Symbol] + + + + .. py:attribute:: symbols + :type: List[solidity_parser.ast.symtab.Symbol] + + + + + .. py:class:: PartialFunctionCallee + + + Bases: :py:obj:`FunctionCallee` + + .. py:attribute:: named_args + :type: Dict[str, solidity_parser.ast.solnodes2.Expr] + + + + + .. py:attribute:: ASSIGN_TO_OP + + + + .. py:method:: link_with_ast1() + + + .. py:method:: get_top_level_units() -> List[solidity_parser.ast.solnodes2.TopLevelUnit] + + + .. py:method:: enqueue_files(files: List[solidity_parser.ast.symtab.FileScope]) + + + .. py:method:: process_all() + + + .. py:method:: load_non_top_level_if_required(ast1_node: solidity_parser.ast.solnodes.SourceUnit | solidity_parser.ast.solnodes.ContractPart) -> solidity_parser.ast.solnodes2.ContractPart + + Ensures the given AST1 non top level node has been skeletoned as an AST2 node. This will + in turn skeleton any parent nodes that need to be made. + + For top level nodes use the load_if_required function instead + + + .. py:method:: load_if_required(user_type_symbol: solidity_parser.ast.symtab.Symbol) -> solidity_parser.ast.solnodes2.TopLevelUnit + + + .. py:method:: refine_stmt(node: solidity_parser.ast.solnodes.Stmt, allow_none=False) + + + .. py:method:: get_declaring_contract_scope(node: solidity_parser.ast.solnodes.AST1Node) -> Union[solidity_parser.ast.symtab.ContractOrInterfaceScope, solidity_parser.ast.symtab.LibraryScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.StructScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.FileScope] + + + .. py:method:: get_declaring_contract_scope_in_scope(scope: solidity_parser.ast.symtab.Symbol) -> Union[solidity_parser.ast.symtab.ContractOrInterfaceScope, solidity_parser.ast.symtab.LibraryScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.StructScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.FileScope] + + + .. py:method:: get_self_object(node: Union[solidity_parser.ast.solnodes.Stmt, solidity_parser.ast.solnodes.Expr]) + + + .. py:method:: get_super_object(node: Union[solidity_parser.ast.solnodes.Stmt, solidity_parser.ast.solnodes.Expr]) + + + .. py:method:: refine_call_function(expr, allow_error=False, allow_stmt=False, allow_event=False) + + + .. py:method:: is_subcontract(a: solidity_parser.ast.symtab.Scope, b: solidity_parser.ast.symtab.Scope) + + + .. py:method:: find_bound_operator_symbol(expr: solidity_parser.ast.solnodes.UnaryOp | solidity_parser.ast.solnodes.BinaryOp, input_types: list[solidity_parser.ast.solnodes2.Types]) + + + .. py:method:: refine_bound_operator(expr: Union[solidity_parser.ast.solnodes.UnaryOp, solidity_parser.ast.solnodes.BinaryOp], inputs: List[solidity_parser.ast.solnodes2.Expr]) + + + .. py:method:: get_function_call_symbol_base(s: solidity_parser.ast.symtab.Symbol) + + + .. py:method:: get_function_callee_buckets(symbols: List[solidity_parser.ast.symtab.Symbol]) + + + .. py:method:: refine_expr(expr: solidity_parser.ast.solnodes.Expr, is_function_callee=False, allow_type=False, allow_tuple_exprs=False, allow_multiple_exprs=False, allow_none=True, allow_stmt=False, is_argument=False, is_assign_rhs=False, allow_event=False) + + + .. py:method:: find_method(possible_matches: list[solidity_parser.ast.symtab.Symbol], arg_types: list[solidity_parser.ast.solnodes2.Types]) + + + .. py:method:: var(node: Union[solidity_parser.ast.solnodes.Var, solidity_parser.ast.solnodes.Parameter]) + + + .. py:method:: parameter(node: solidity_parser.ast.solnodes.Parameter) + + + .. py:method:: error_parameter(node: solidity_parser.ast.solnodes.ErrorParameter) + + + .. py:method:: ident(node: solidity_parser.ast.solnodes.Ident) + + + .. py:method:: modifiers(node_with_modifiers) + + + .. py:method:: modifier(node: solidity_parser.ast.solnodes.Modifier) + + + .. py:method:: process_code_block(node: solidity_parser.ast.solnodes.Block) + + + .. py:method:: block(node: solidity_parser.ast.solnodes.Block) + + + .. py:method:: get_synthetic_owner(source_unit_name, file_scope: solidity_parser.ast.symtab.FileScope) -> solidity_parser.ast.solnodes2.FileDefinition + + + .. py:method:: define_skeleton(ast1_node: solidity_parser.ast.solnodes.SourceUnit, source_unit_name: Optional[str]) -> solidity_parser.ast.solnodes2.TopLevelUnit | solidity_parser.ast.solnodes2.ContractPart + + + .. py:method:: refine_unit_or_part(ast1_node: Union[solidity_parser.ast.solnodes.SourceUnit, solidity_parser.ast.solnodes2.FileDefinition]) + + + .. py:method:: is_top_level(node: solidity_parser.ast.solnodes.AST1Node) + + + .. py:method:: should_create_skeleton(node: solidity_parser.ast.solnodes.AST1Node) -> bool + + + diff --git a/docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst b/docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst new file mode 100644 index 0000000..16272ea --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst @@ -0,0 +1,130 @@ +:py:mod:`solidity_parser.ast.funcanalysis` +========================================== + +.. py:module:: solidity_parser.ast.funcanalysis + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.funcanalysis.PathEdgeKind + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.funcanalysis.find_matching_function_in_type + solidity_parser.ast.funcanalysis.find_possible_matching_functions_for_declared_type + solidity_parser.ast.funcanalysis.add_function_to_cg + solidity_parser.ast.funcanalysis.find_possible_calls + solidity_parser.ast.funcanalysis.mark_sources + solidity_parser.ast.funcanalysis.is_fca_important + solidity_parser.ast.funcanalysis.is_blackbox_node + solidity_parser.ast.funcanalysis.has_inline_yul + solidity_parser.ast.funcanalysis.find_important_paths2 + + + +.. py:function:: find_matching_function_in_type(ttype: solidity_parser.ast.solnodes2.TopLevelUnit, name, arg_types, ignore_current_type=False) + + +.. py:function:: find_possible_matching_functions_for_declared_type(declared_ttype: solidity_parser.ast.solnodes2.ResolvedUserType, name, arg_types, is_super_call) + + +.. py:function:: add_function_to_cg(cg: networkx.DiGraph, finished_functions, function: solidity_parser.ast.solnodes2.FunctionDefinition) + + +.. py:function:: find_possible_calls(declared_ttype: Union[solidity_parser.ast.solnodes2.ResolvedUserType, solidity_parser.ast.solnodes2.SuperType], name: str, arg_types: List[solidity_parser.ast.types.Type], match_filter=lambda x: True, use_subtypes=True) -> List[solidity_parser.ast.solnodes2.FunctionDefinition] + + +.. py:function:: mark_sources(units: List[solidity_parser.ast.solnodes2.TopLevelUnit]) + + +.. py:function:: is_fca_important(f: solidity_parser.ast.solnodes2.FunctionDefinition) + + +.. py:function:: is_blackbox_node(f: solidity_parser.ast.solnodes2.FunctionDefinition) + + +.. py:function:: has_inline_yul(f: solidity_parser.ast.solnodes2.FunctionDefinition) + + +.. py:class:: PathEdgeKind(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Create a collection of name/value pairs. + + Example enumeration: + + >>> class Color(Enum): + ... RED = 1 + ... BLUE = 2 + ... GREEN = 3 + + Access them by: + + - attribute access:: + + >>> Color.RED + + + - value lookup: + + >>> Color(1) + + + - name lookup: + + >>> Color['RED'] + + + Enumerations can be iterated over, and know how many members they have: + + >>> len(Color) + 3 + + >>> list(Color) + [, , ] + + Methods can be added to enumerations, and members can have their own + attributes -- see the documentation for details. + + .. py:attribute:: INTRA_CALL + :value: 1 + + + + .. py:attribute:: SINK_INTER + :value: 2 + + + + .. py:attribute:: SINK_NO_CODE + :value: 3 + + + + .. py:attribute:: SINK_FCA_IMPORTANT + :value: 4 + + + + .. py:attribute:: SINK_INLINE_YUL + :value: 5 + + + + +.. py:function:: find_important_paths2(source: solidity_parser.ast.solnodes2.FunctionDefinition) + + diff --git a/docs/source/autoapi/solidity_parser/ast/helper/index.rst b/docs/source/autoapi/solidity_parser/ast/helper/index.rst new file mode 100644 index 0000000..8545e7c --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/helper/index.rst @@ -0,0 +1,50 @@ +:py:mod:`solidity_parser.ast.helper` +==================================== + +.. py:module:: solidity_parser.ast.helper + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.helper.MyErrorListener + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.helper.get_processors + solidity_parser.ast.helper.make_ast + solidity_parser.ast.helper.param_type_str + + + +.. py:class:: MyErrorListener + + + Bases: :py:obj:`antlr4.error.ErrorListener.ErrorListener` + + .. py:method:: add_error(recognizer, line, column, msg) + + + .. py:method:: syntaxError(recognizer, offendingSymbol, line, column, msg, e) + + + +.. py:function:: get_processors(version: solidity_parser.util.version_util.Version) + + +.. py:function:: make_ast(input_src, version: solidity_parser.util.version_util.Version = None, origin=None) -> List[solidity_parser.ast.solnodes.SourceUnit] + + +.. py:function:: param_type_str(parameters: List[solidity_parser.ast.solnodes.Parameter]) -> str + + diff --git a/docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst b/docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst new file mode 100644 index 0000000..eb1c186 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst @@ -0,0 +1,24 @@ +:py:mod:`solidity_parser.ast.hierarchy` +======================================= + +.. py:module:: solidity_parser.ast.hierarchy + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.hierarchy.build_hierarchy + + + +.. py:function:: build_hierarchy(top_level_units: list[solidity_parser.ast.solnodes2.TopLevelUnit]) -> None + + Annotates the top level units with their direct subtypes, e.g. if A extends B, then A._subtypes = [B] + + diff --git a/docs/source/autoapi/solidity_parser/ast/index.rst b/docs/source/autoapi/solidity_parser/ast/index.rst new file mode 100644 index 0000000..5288e1e --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/index.rst @@ -0,0 +1,33 @@ +:py:mod:`solidity_parser.ast` +============================= + +.. py:module:: solidity_parser.ast + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + parsers/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + ast2builder/index.rst + funcanalysis/index.rst + helper/index.rst + hierarchy/index.rst + mro_helper/index.rst + nodebase/index.rst + solnodes/index.rst + solnodes2/index.rst + symtab/index.rst + types/index.rst + + diff --git a/docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst b/docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst new file mode 100644 index 0000000..c004936 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst @@ -0,0 +1,45 @@ +:py:mod:`solidity_parser.ast.mro_helper` +======================================== + +.. py:module:: solidity_parser.ast.mro_helper + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.mro_helper._merge + solidity_parser.ast.mro_helper.c3_linearise + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.mro_helper.T + + +.. py:function:: _merge(*sequences) + + +.. py:data:: T + + + +.. py:function:: c3_linearise(klass: T, get_supers: Callable[[T], list[T]] = None) -> list[T] + + A function to linearise the class hierarchy using the C3 linearisation algorithm. + + :param klass: The class to linearise. + :param get_supers: A function to get the superclasses of a given class, must return a list of classes with the same + type as the input + :return: A linearised list of classes following the C3 algorithm. + + diff --git a/docs/source/autoapi/solidity_parser/ast/nodebase/index.rst b/docs/source/autoapi/solidity_parser/ast/nodebase/index.rst new file mode 100644 index 0000000..6e9f254 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/nodebase/index.rst @@ -0,0 +1,299 @@ +:py:mod:`solidity_parser.ast.nodebase` +====================================== + +.. py:module:: solidity_parser.ast.nodebase + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.nodebase.SourceLocation + solidity_parser.ast.nodebase.SourceLocationSpan + solidity_parser.ast.nodebase.NodeList + solidity_parser.ast.nodebase.Ref + solidity_parser.ast.nodebase.Node + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.nodebase.NodeDataclass + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.nodebase.__REASON_CHILD__ + solidity_parser.ast.nodebase.__FIELD_PARENT__ + solidity_parser.ast.nodebase.__REASON_INIT__ + solidity_parser.ast.nodebase.T + + +.. py:class:: SourceLocation + + + Bases: :py:obj:`NamedTuple` + + .. py:attribute:: line + :type: int + + Line number, beginning at 1 + + + .. py:attribute:: column + :type: int + + Column number, beginning at 1. E.g. the first character on the line is at column 1. + + + +.. py:class:: SourceLocationSpan + + + Bases: :py:obj:`NamedTuple` + + .. py:attribute:: start + :type: SourceLocation + + + + .. py:attribute:: end + :type: SourceLocation + + + + .. py:method:: does_contain(loc: SourceLocation) + + Checks whether the given 'loc' location is contained within this span. + E.g. if this span represents ((5,1), (10, 1)), i.e lines 5 to 10 and loc is (6, 1), the location is contained + :param loc: + :return: + + + +.. py:data:: __REASON_CHILD__ + :value: '__child__' + + + +.. py:data:: __FIELD_PARENT__ + :value: 'parent' + + + +.. py:data:: __REASON_INIT__ + :value: '__init__' + + + +.. py:function:: NodeDataclass(cls, *args, **kwargs) + + AST node decorator to add an updatable and cachable element based hash to the dataclass + + +.. py:data:: T + + + +.. py:class:: NodeList(parent: T, seq=()) + + + Bases: :py:obj:`list`\ [\ :py:obj:`T`\ ] + + Built-in mutable sequence. + + If no argument is given, the constructor creates a new empty list. + The argument must be an iterable if specified. + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: __repr__() + + Return repr(self). + + + .. py:method:: __setitem__(key, value) + + Set self[key] to value. + + + .. py:method:: __delitem__(key) + + Delete self[key]. + + + .. py:method:: __setslice__(i, j, sequence) + + + .. py:method:: __eq__(other) + + Return self==value. + + + .. py:method:: append(__object) + + Append object to the end of the list. + + + .. py:method:: clear() + + Remove all items from list. + + + .. py:method:: extend(__iterable) + + Extend list by appending elements from the iterable. + + + .. py:method:: insert(__index, __object) + + Insert object before index. + + + .. py:method:: pop(__index) + + Remove and return item at index (default last). + + Raises IndexError if list is empty or index is out of range. + + + .. py:method:: remove(__value) + + Remove first occurrence of value. + + Raises ValueError if the value is not present. + + + .. py:method:: reverse() + + Reverse *IN PLACE*. + + + .. py:method:: sort(*args, **kwargs) + + Sort the list in ascending order and return None. + + The sort is in-place (i.e. the list itself is modified) and stable (i.e. the + order of two equal elements is maintained). + + If a key function is given, apply it once to each list item and sort them, + ascending or descending, according to their function values. + + The reverse flag can be set to sort in descending order. + + + +.. py:class:: Ref + + + Bases: :py:obj:`Generic`\ [\ :py:obj:`T`\ ] + + A weak AST reference to another Node. This is needed when we want to associate a Node with another Node but don't + want it to be marked as a child of the other Node. This is useful if we want to create circular or back references + to help the client use the AST more naturally, e.g. ResolvedUserTypes have a reference to the actual TopLevelUnit + they reference. + + .. py:attribute:: x + :type: T + + The item being referenced + + + .. py:method:: __repr__() + + Return repr(self). + + + +.. py:class:: Node + + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: id_location + :type: str + + LineNumber:LinePosition, this is set dynamically in common.make + + + .. py:attribute:: start_location + :type: SourceLocation + + Source start location of this node (column is inclusive) + + + .. py:attribute:: end_location + :type: SourceLocation + + Source end location of this node (column is exclusive) + + + .. py:attribute:: start_buffer_index + :type: int + + Source start (0-based) position in the input text buffer(inclusive) + + + .. py:attribute:: end_buffer_index + :type: int + + Source end (0-based) position in the input text buffer(exclusive) + + + .. py:attribute:: parent + :type: Optional[Node] + + + + .. py:attribute:: comments + :type: Optional[list[str]] + + + + .. py:method:: __post_init__() + + + .. py:method:: get_source_span() + + + .. py:method:: linenumber() -> int + + + .. py:method:: source_location() + + + .. py:method:: offset() -> int + + + .. py:method:: get_children(predicate: Callable[[Node], bool] = None) -> Generator[Node, None, None] + + + .. py:method:: get_all_children(predicate: Callable[[Node], bool] = None) -> Generator[Node, None, None] + + + .. py:method:: _set_child_parents() + + + .. py:method:: __deepcopy__(memodict) + + + .. py:method:: code_str() + :abstractmethod: + + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst new file mode 100644 index 0000000..b4488d6 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst @@ -0,0 +1,111 @@ +:py:mod:`solidity_parser.ast.parsers.common` +============================================ + +.. py:module:: solidity_parser.ast.parsers.common + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.common.ParserBase + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.common.get_grammar_children + solidity_parser.ast.parsers.common.is_grammar_rule + solidity_parser.ast.parsers.common.map_helper + solidity_parser.ast.parsers.common.get_all_subparsers + solidity_parser.ast.parsers.common.get_subparsers_from_methods + solidity_parser.ast.parsers.common.check_subparser_method + + + +.. py:class:: ParserBase(subparsers, token_stream) + + + .. py:method:: make(rule: antlr4.ParserRuleContext, default=None) + + + .. py:method:: make_first(rule: antlr4.ParserRuleContext) + + Finds the first subrule of the given rule and returns the result of running the appropriate subparser + :param rule: + :return: + + + .. py:method:: make_all(rule: antlr4.ParserRuleContext) + + Takes all the subrules of the given rule and returns a list of the result of running their subparsers + :param rule: + :return: + + + .. py:method:: make_all_rules(rules) + + + .. py:method:: copy_source_data(decorated_node, node_to_decorate) + + + .. py:method:: wrap_node(rule, node, add_comments=False) + + + +.. py:function:: get_grammar_children(rule: antlr4.ParserRuleContext) + + Gets the children of the given rule that are grammar rules and not tokens + :param rule: + :return: + + +.. py:function:: is_grammar_rule(rule) + + Predicate for whether the given rule is a user written rule in the language grammar. + e.g. StatementContext would be a grammar rule, whereas the literal 'for' or lexer token + 'For' would not be + + :param rule: + :return: + + +.. py:function:: map_helper(func, xs) + + +.. py:function:: get_all_subparsers(module) + + Gets all the valid subparser methods from the given module + :param module: + :return: + + +.. py:function:: get_subparsers_from_methods(*methods) + + Gets the valid subparser methods from the list of given methods + :param methods: + :return: + + +.. py:function:: check_subparser_method(name, method) + + Checks whether the given name and method match the form of valid subparsers in the context + of this parsing framework. Subparsers are methods with the form _f(parser, rule: 'RuleType') + where parser is the parent parser that provides a context to the subparser and method is a python + method reference. + The parser parameter must be named 'parser' but the 'rule' parameter can be named anything. The + 'RuleType' must be a string(not a python class type) matching the name of the generated + antlr grammar rule, e.g. StatementContext + + :param name: Name of the given parser or None if no check is required on this parameter + :param method: The subparser method to check + :return: A tuple of (RuleType, method) + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst new file mode 100644 index 0000000..171e59b --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst @@ -0,0 +1,38 @@ +:py:mod:`solidity_parser.ast.parsers.errors` +============================================ + +.. py:module:: solidity_parser.ast.parsers.errors + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.errors.assert_invalid_path + solidity_parser.ast.parsers.errors.unsupported_feature + solidity_parser.ast.parsers.errors.invalid_solidity + + + +.. py:function:: assert_invalid_path() + + +.. py:function:: unsupported_feature(detail) + + +.. py:function:: invalid_solidity(detail) + + +.. py:exception:: ParsingException + + + Bases: :py:obj:`Exception` + + Common base class for all non-exit exceptions. + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/index.rst new file mode 100644 index 0000000..d45639c --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/index.rst @@ -0,0 +1,21 @@ +:py:mod:`solidity_parser.ast.parsers` +===================================== + +.. py:module:: solidity_parser.ast.parsers + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + common/index.rst + errors/index.rst + parsers060/index.rst + parsers070/index.rst + parsers080/index.rst + parsers088/index.rst + parsers08_22/index.rst + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst new file mode 100644 index 0000000..bb3f5cf --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst @@ -0,0 +1,316 @@ +:py:mod:`solidity_parser.ast.parsers.parsers060` +================================================ + +.. py:module:: solidity_parser.ast.parsers.parsers060 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers060.Parser060 + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers060.custom_parsers + solidity_parser.ast.parsers.parsers060._block + solidity_parser.ast.parsers.parsers060._if + solidity_parser.ast.parsers.parsers060._try + solidity_parser.ast.parsers.parsers060._while + solidity_parser.ast.parsers.parsers060._for + solidity_parser.ast.parsers.parsers060._inline_assembly_statement + solidity_parser.ast.parsers.parsers060._dowhile + solidity_parser.ast.parsers.parsers060._continue + solidity_parser.ast.parsers.parsers060._break + solidity_parser.ast.parsers.parsers060._return + solidity_parser.ast.parsers.parsers060._throw + solidity_parser.ast.parsers.parsers060._location + solidity_parser.ast.parsers.parsers060._var + solidity_parser.ast.parsers.parsers060._expr_stmt + solidity_parser.ast.parsers.parsers060._emit + solidity_parser.ast.parsers.parsers060._var_decl_stmt + solidity_parser.ast.parsers.parsers060._identifier + solidity_parser.ast.parsers.parsers060._array_identifier + solidity_parser.ast.parsers.parsers060._name_value + solidity_parser.ast.parsers.parsers060._function_call_args + solidity_parser.ast.parsers.parsers060._function_call + solidity_parser.ast.parsers.parsers060._function_call_expr + solidity_parser.ast.parsers.parsers060._meta_type + solidity_parser.ast.parsers.parsers060._payable_expr + solidity_parser.ast.parsers.parsers060._unary_pre_op + solidity_parser.ast.parsers.parsers060._delete_expr + solidity_parser.ast.parsers.parsers060._unary_logic_op + solidity_parser.ast.parsers.parsers060._unary_post_op + solidity_parser.ast.parsers.parsers060._type_name + solidity_parser.ast.parsers.parsers060._mapping_type + solidity_parser.ast.parsers.parsers060.params_to_types + solidity_parser.ast.parsers.parsers060._function_type_name + solidity_parser.ast.parsers.parsers060._new_obj + solidity_parser.ast.parsers.parsers060._array_slice + solidity_parser.ast.parsers.parsers060._array_load + solidity_parser.ast.parsers.parsers060._binary_expr + solidity_parser.ast.parsers.parsers060._ternary_expr + solidity_parser.ast.parsers.parsers060._primary + solidity_parser.ast.parsers.parsers060._number_literal + solidity_parser.ast.parsers.parsers060._hex_literal + solidity_parser.ast.parsers.parsers060._string_literal + solidity_parser.ast.parsers.parsers060._tuple_expr + solidity_parser.ast.parsers.parsers060._member_load + solidity_parser.ast.parsers.parsers060._parameter + solidity_parser.ast.parsers.parsers060._catch_clause + solidity_parser.ast.parsers.parsers060._elementary_type_name + solidity_parser.ast.parsers.parsers060._user_defined_type + solidity_parser.ast.parsers.parsers060._modifier_invocation + solidity_parser.ast.parsers.parsers060._state_mutability + solidity_parser.ast.parsers.parsers060._visibility_modifier + solidity_parser.ast.parsers.parsers060._pragma_directive + solidity_parser.ast.parsers.parsers060._version + solidity_parser.ast.parsers.parsers060._version_constraint + solidity_parser.ast.parsers.parsers060._module_import + solidity_parser.ast.parsers.parsers060._alias_import + solidity_parser.ast.parsers.parsers060._symbol_import + solidity_parser.ast.parsers.parsers060._import_declaration + solidity_parser.ast.parsers.parsers060.var_to_struct_member + solidity_parser.ast.parsers.parsers060._struct_definition + solidity_parser.ast.parsers.parsers060._enum_definition + solidity_parser.ast.parsers.parsers060._enum_value + solidity_parser.ast.parsers.parsers060._contract_definition + solidity_parser.ast.parsers.parsers060._inheritance_specifier + solidity_parser.ast.parsers.parsers060._state_variable_declaration + solidity_parser.ast.parsers.parsers060._override_specifier + solidity_parser.ast.parsers.parsers060._using_for_declaration + solidity_parser.ast.parsers.parsers060._modifier_definition + solidity_parser.ast.parsers.parsers060._function_definition + solidity_parser.ast.parsers.parsers060._event_definition + solidity_parser.ast.parsers.parsers060._event_parameter + + + +.. py:class:: Parser060(token_stream) + + + Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` + + +.. py:function:: custom_parsers() + + +.. py:function:: _block(parser, block: solidity_parser.grammar.v060.SolidityParser.SolidityParser.BlockContext) + + +.. py:function:: _if(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.IfStatementContext) + + +.. py:function:: _try(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TryStatementContext) + + +.. py:function:: _while(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.WhileStatementContext) + + +.. py:function:: _for(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ForStatementContext) + + +.. py:function:: _inline_assembly_statement(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.InlineAssemblyStatementContext) + + +.. py:function:: _dowhile(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.DoWhileStatementContext) + + +.. py:function:: _continue(parser, _: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ContinueStatementContext) + + +.. py:function:: _break(parser, _: solidity_parser.grammar.v060.SolidityParser.SolidityParser.BreakStatementContext) + + +.. py:function:: _return(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ReturnStatementContext) + + +.. py:function:: _throw(parser, _: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ThrowStatementContext) + + +.. py:function:: _location(parser, loc: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StorageLocationContext) + + +.. py:function:: _var(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VariableDeclarationContext) + + +.. py:function:: _expr_stmt(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ExpressionStatementContext) + + +.. py:function:: _emit(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EmitStatementContext) + + +.. py:function:: _var_decl_stmt(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VariableDeclarationStatementContext) + + +.. py:function:: _identifier(parser, ident: solidity_parser.grammar.v060.SolidityParser.SolidityParser.IdentifierContext) + + +.. py:function:: _array_identifier(parser, ident: solidity_parser.ast.solnodes.Ident, array_dims: int) + + +.. py:function:: _name_value(parser, name_value: solidity_parser.grammar.v060.SolidityParser.SolidityParser.NameValueContext) + + +.. py:function:: _function_call_args(parser, args: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionCallArgumentsContext) + + +.. py:function:: _function_call(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionCallContext) + + +.. py:function:: _function_call_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FuncCallExprContext) + + +.. py:function:: _meta_type(parser, meta_type: solidity_parser.grammar.v060.SolidityParser.SolidityParser.MetaTypeContext) + + +.. py:function:: _payable_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.PayableExprContext) + + +.. py:function:: _unary_pre_op(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UnaryPreOpContext) + + +.. py:function:: _delete_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.DeleteExprContext) + + +.. py:function:: _unary_logic_op(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.LogicOpContext) + + +.. py:function:: _unary_post_op(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UnaryPostOpContext) + + +.. py:function:: _type_name(parser, type_name: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TypeNameContext) + + +.. py:function:: _mapping_type(parser, mapping_type: solidity_parser.grammar.v060.SolidityParser.SolidityParser.MappingContext) + + +.. py:function:: params_to_types(params: solidity_parser.ast.solnodes.Parameter) + + +.. py:function:: _function_type_name(parser, function_type: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionTypeNameContext) + + +.. py:function:: _new_obj(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.NewTypeContext) + + +.. py:function:: _array_slice(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ArraySliceContext) + + +.. py:function:: _array_load(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ArrayLoadContext) + + +.. py:function:: _binary_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.BinaryExprContext) + + +.. py:function:: _ternary_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TernaryExprContext) + + +.. py:function:: _primary(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.PrimaryExpressionContext) + + +.. py:function:: _number_literal(parser, literal: solidity_parser.grammar.v060.SolidityParser.SolidityParser.NumberLiteralContext) + + +.. py:function:: _hex_literal(parser, literal: solidity_parser.grammar.v060.SolidityParser.SolidityParser.HexLiteralContext) + + +.. py:function:: _string_literal(parser, literal: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StringLiteralContext) + + +.. py:function:: _tuple_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TupleExpressionContext) + + +.. py:function:: _member_load(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.MemberLoadContext) + + +.. py:function:: _parameter(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ParameterContext) + + +.. py:function:: _catch_clause(parser, clause: solidity_parser.grammar.v060.SolidityParser.SolidityParser.CatchClauseContext) + + +.. py:function:: _elementary_type_name(parser, name: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ElementaryTypeNameContext) + + +.. py:function:: _user_defined_type(parser, name: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UserDefinedTypeNameContext) + + +.. py:function:: _modifier_invocation(parser, modifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ModifierInvocationContext) + + +.. py:function:: _state_mutability(parser, modifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StateMutabilityContext) + + +.. py:function:: _visibility_modifier(parser, modifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VisibilityModifierContext) + + +.. py:function:: _pragma_directive(parser, pragma_directive: solidity_parser.grammar.v060.SolidityParser.SolidityParser.PragmaDirectiveContext) + + +.. py:function:: _version(parser, version: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VersionContext) + + +.. py:function:: _version_constraint(parser, version_constraint: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VersionConstraintContext) + + +.. py:function:: _module_import(parser, module_import: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ModuleImportContext) + + +.. py:function:: _alias_import(parser, alias_import: solidity_parser.grammar.v060.SolidityParser.SolidityParser.AliasImportContext) + + +.. py:function:: _symbol_import(parser, symbol_import: solidity_parser.grammar.v060.SolidityParser.SolidityParser.SymbolImportContext) + + +.. py:function:: _import_declaration(parser, import_declaration: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ImportDeclarationContext) + + +.. py:function:: var_to_struct_member(var: solidity_parser.ast.solnodes.Var) + + +.. py:function:: _struct_definition(parser, struct_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StructDefinitionContext) + + +.. py:function:: _enum_definition(parser, enum_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EnumDefinitionContext) + + +.. py:function:: _enum_value(parser, enum_value: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EnumValueContext) + + +.. py:function:: _contract_definition(parser, contract_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ContractDefinitionContext) + + +.. py:function:: _inheritance_specifier(parser, inheritance_specifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.InheritanceSpecifierContext) + + +.. py:function:: _state_variable_declaration(parser, state_variable_declaration: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StateVariableDeclarationContext) + + +.. py:function:: _override_specifier(parser, override_specific: solidity_parser.grammar.v060.SolidityParser.SolidityParser.OverrideSpecifierContext) + + +.. py:function:: _using_for_declaration(parser, using_for_declaration: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UsingForDeclarationContext) + + +.. py:function:: _modifier_definition(parser, modifier_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ModifierDefinitionContext) + + +.. py:function:: _function_definition(parser, function_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionDefinitionContext) + + +.. py:function:: _event_definition(parser, event_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EventDefinitionContext) + + +.. py:function:: _event_parameter(parser, event_parameter: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EventParameterContext) + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst new file mode 100644 index 0000000..d278fcd --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst @@ -0,0 +1,44 @@ +:py:mod:`solidity_parser.ast.parsers.parsers070` +================================================ + +.. py:module:: solidity_parser.ast.parsers.parsers070 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers070.Parser070 + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers070._pragma_value + solidity_parser.ast.parsers.parsers070._unicode_string_literal + solidity_parser.ast.parsers.parsers070._number_literal + + + +.. py:class:: Parser070(token_stream) + + + Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` + + +.. py:function:: _pragma_value(parser, pragma_value: solidity_parser.grammar.v070.SolidityParser.SolidityParser.PragmaValueContext) + + +.. py:function:: _unicode_string_literal(parser, literal: solidity_parser.grammar.v070.SolidityParser.SolidityParser.UnicodeStringLiteralContext) + + +.. py:function:: _number_literal(parser, literal: solidity_parser.grammar.v070.SolidityParser.SolidityParser.NumberLiteralContext) + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst new file mode 100644 index 0000000..89187bb --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst @@ -0,0 +1,300 @@ +:py:mod:`solidity_parser.ast.parsers.parsers080` +================================================ + +.. py:module:: solidity_parser.ast.parsers.parsers080 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers080.Parser080 + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers080.custom_parsers + solidity_parser.ast.parsers.parsers080._try + solidity_parser.ast.parsers.parsers080._pragma_directive + solidity_parser.ast.parsers.parsers080._import_directive + solidity_parser.ast.parsers.parsers080._path + solidity_parser.ast.parsers.parsers080._import_alias + solidity_parser.ast.parsers.parsers080._contract_definition + solidity_parser.ast.parsers.parsers080._interface_definition + solidity_parser.ast.parsers.parsers080._library_definition + solidity_parser.ast.parsers.parsers080._inheritance_specifier + solidity_parser.ast.parsers.parsers080._constructor_definition + solidity_parser.ast.parsers.parsers080._function_definition + solidity_parser.ast.parsers.parsers080._constant_variable_declaration + solidity_parser.ast.parsers.parsers080._modifier_definition + solidity_parser.ast.parsers.parsers080._fallback_function_definition + solidity_parser.ast.parsers.parsers080._receive_function_definition + solidity_parser.ast.parsers.parsers080._struct_definition + solidity_parser.ast.parsers.parsers080._struct_member + solidity_parser.ast.parsers.parsers080._enum_definition + solidity_parser.ast.parsers.parsers080._state_variable_declaration + solidity_parser.ast.parsers.parsers080._error_definition + solidity_parser.ast.parsers.parsers080._error_parameter + solidity_parser.ast.parsers.parsers080._using_directive + solidity_parser.ast.parsers.parsers080._override_specifier + solidity_parser.ast.parsers.parsers080._visibility + solidity_parser.ast.parsers.parsers080._state_mutability + solidity_parser.ast.parsers.parsers080._modifier_invocation + solidity_parser.ast.parsers.parsers080._event_definition + solidity_parser.ast.parsers.parsers080._event_parameter + solidity_parser.ast.parsers.parsers080._block + solidity_parser.ast.parsers.parsers080._unchecked_block + solidity_parser.ast.parsers.parsers080._named_argument + solidity_parser.ast.parsers.parsers080._parameter_declaration + solidity_parser.ast.parsers.parsers080._call_argument_list + solidity_parser.ast.parsers.parsers080._var_decl_stmt + solidity_parser.ast.parsers.parsers080._data_location + solidity_parser.ast.parsers.parsers080._variable_declaration + solidity_parser.ast.parsers.parsers080._expr_stmt + solidity_parser.ast.parsers.parsers080._catch_clause + solidity_parser.ast.parsers.parsers080._emit + solidity_parser.ast.parsers.parsers080._revert + solidity_parser.ast.parsers.parsers080._assembly + solidity_parser.ast.parsers.parsers080._index_access + solidity_parser.ast.parsers.parsers080._index_range_access + solidity_parser.ast.parsers.parsers080._member_access + solidity_parser.ast.parsers.parsers080._func_call_expr + solidity_parser.ast.parsers.parsers080._payable_conversion + solidity_parser.ast.parsers.parsers080._meta_type + solidity_parser.ast.parsers.parsers080._type_name + solidity_parser.ast.parsers.parsers080._function_type_name + solidity_parser.ast.parsers.parsers080._mapping_type + solidity_parser.ast.parsers.parsers080._mapping_key_type + solidity_parser.ast.parsers.parsers080._unary_prefix_operation + solidity_parser.ast.parsers.parsers080._unary_suffix_operation + solidity_parser.ast.parsers.parsers080._binary_expr + solidity_parser.ast.parsers.parsers080._conditional_expr + solidity_parser.ast.parsers.parsers080._new_obj + solidity_parser.ast.parsers.parsers080._tuple_expression + solidity_parser.ast.parsers.parsers080._inline_array + solidity_parser.ast.parsers.parsers080._identifier + solidity_parser.ast.parsers.parsers080._identifier_path + solidity_parser.ast.parsers.parsers080._string_literal + solidity_parser.ast.parsers.parsers080._number_literal + solidity_parser.ast.parsers.parsers080._boolean_literal + solidity_parser.ast.parsers.parsers080._hex_string_literal + solidity_parser.ast.parsers.parsers080._unicode_string_literal + solidity_parser.ast.parsers.parsers080._elementary_type_name + + + +.. py:class:: Parser080(token_stream) + + + Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` + + +.. py:function:: custom_parsers() + + +.. py:function:: _try(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.TryStatementContext) + + +.. py:function:: _pragma_directive(parser, pragma_directive: solidity_parser.grammar.v080.SolidityParser.SolidityParser.PragmaDirectiveContext) + + +.. py:function:: _import_directive(parser, directive: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ImportDirectiveContext) + + +.. py:function:: _path(parser, path: solidity_parser.grammar.v080.SolidityParser.SolidityParser.PathContext) + + +.. py:function:: _import_alias(parser, import_alias: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ImportAliasesContext) + + +.. py:function:: _contract_definition(parser, contract_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ContractDefinitionContext) + + +.. py:function:: _interface_definition(parser, interface_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.InterfaceDefinitionContext) + + +.. py:function:: _library_definition(parser, library_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.LibraryDefinitionContext) + + +.. py:function:: _inheritance_specifier(parser, inheritance_specifier: solidity_parser.grammar.v080.SolidityParser.SolidityParser.InheritanceSpecifierContext) + + +.. py:function:: _constructor_definition(parser, constructor_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ConstructorDefinitionContext) + + +.. py:function:: _function_definition(parser, function_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FunctionDefinitionContext) + + +.. py:function:: _constant_variable_declaration(parser, constant_variable_declaration: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ConstantVariableDeclarationContext) + + +.. py:function:: _modifier_definition(parser, modifier_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ModifierDefinitionContext) + + +.. py:function:: _fallback_function_definition(parser, fallback_function_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FallbackFunctionDefinitionContext) + + +.. py:function:: _receive_function_definition(parser, receive_function_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ReceiveFunctionDefinitionContext) + + +.. py:function:: _struct_definition(parser, struct_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StructDefinitionContext) + + +.. py:function:: _struct_member(parser, struct_member: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StructMemberContext) + + +.. py:function:: _enum_definition(parser, enum_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EnumDefinitionContext) + + +.. py:function:: _state_variable_declaration(parser, state_variable_declaration: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StateVariableDeclarationContext) + + +.. py:function:: _error_definition(parser, error_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ErrorDefinitionContext) + + +.. py:function:: _error_parameter(parser, error_parameter: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ErrorParameterContext) + + +.. py:function:: _using_directive(parser, using_directive: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UsingDirectiveContext) + + +.. py:function:: _override_specifier(parser, override_specific: solidity_parser.grammar.v080.SolidityParser.SolidityParser.OverrideSpecifierContext) + + +.. py:function:: _visibility(parser, visibility: solidity_parser.grammar.v080.SolidityParser.SolidityParser.VisibilityContext) + + +.. py:function:: _state_mutability(parser, state_mutability: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StateMutabilityContext) + + +.. py:function:: _modifier_invocation(parser, modifier_invocation: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ModifierInvocationContext) + + +.. py:function:: _event_definition(parser, event_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EventDefinitionContext) + + +.. py:function:: _event_parameter(parser, event_parameter: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EventParameterContext) + + +.. py:function:: _block(parser, block: solidity_parser.grammar.v080.SolidityParser.SolidityParser.BlockContext) + + +.. py:function:: _unchecked_block(parser, block: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UncheckedBlockContext) + + +.. py:function:: _named_argument(parser, named_arg: solidity_parser.grammar.v080.SolidityParser.SolidityParser.NamedArgumentContext) + + +.. py:function:: _parameter_declaration(parser, parameter_declaration: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ParameterDeclarationContext) + + +.. py:function:: _call_argument_list(parser, arg_list: solidity_parser.grammar.v080.SolidityParser.SolidityParser.CallArgumentListContext) + + +.. py:function:: _var_decl_stmt(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.VariableDeclarationStatementContext) + + +.. py:function:: _data_location(parser, location: solidity_parser.grammar.v080.SolidityParser.SolidityParser.DataLocationContext) + + +.. py:function:: _variable_declaration(parser, decl: solidity_parser.grammar.v080.SolidityParser.SolidityParser.VariableDeclarationContext) + + +.. py:function:: _expr_stmt(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ExpressionStatementContext) + + +.. py:function:: _catch_clause(parser, catch_clause: solidity_parser.grammar.v080.SolidityParser.SolidityParser.CatchClauseContext) + + +.. py:function:: _emit(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EmitStatementContext) + + +.. py:function:: _revert(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.RevertStatementContext) + + +.. py:function:: _assembly(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.AssemblyStatementContext) + + +.. py:function:: _index_access(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IndexAccessContext) + + +.. py:function:: _index_range_access(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IndexRangeAccessContext) + + +.. py:function:: _member_access(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MemberAccessContext) + + +.. py:function:: _func_call_expr(parser, func_call_expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FuncCallExprContext) + + +.. py:function:: _payable_conversion(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.PayableConversionContext) + + +.. py:function:: _meta_type(parser, meta_type: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MetaTypeContext) + + +.. py:function:: _type_name(parser, type_name: solidity_parser.grammar.v080.SolidityParser.SolidityParser.TypeNameContext) + + +.. py:function:: _function_type_name(parser, function_type: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FunctionTypeNameContext) + + +.. py:function:: _mapping_type(parser, mapping: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MappingTypeContext) + + +.. py:function:: _mapping_key_type(parser, mapping_key_type: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MappingKeyTypeContext) + + +.. py:function:: _unary_prefix_operation(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UnaryPrefixOperationContext) + + +.. py:function:: _unary_suffix_operation(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UnarySuffixOperationContext) + + +.. py:function:: _binary_expr(parser, expr) + + +.. py:function:: _conditional_expr(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ConditionalContext) + + +.. py:function:: _new_obj(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.NewExpressionContext) + + +.. py:function:: _tuple_expression(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.TupleExpressionContext) + + +.. py:function:: _inline_array(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.InlineArrayExpressionContext) + + +.. py:function:: _identifier(parser, ident: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IdentifierContext) + + +.. py:function:: _identifier_path(parser, ident_path: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IdentifierPathContext) + + +.. py:function:: _string_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StringLiteralContext) + + +.. py:function:: _number_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.NumberLiteralContext) + + +.. py:function:: _boolean_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.BooleanLiteralContext) + + +.. py:function:: _hex_string_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.HexStringLiteralContext) + + +.. py:function:: _unicode_string_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UnicodeStringLiteralContext) + + +.. py:function:: _elementary_type_name(parser, name: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ElementaryTypeNameContext) + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst new file mode 100644 index 0000000..2ae91dd --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst @@ -0,0 +1,36 @@ +:py:mod:`solidity_parser.ast.parsers.parsers088` +================================================ + +.. py:module:: solidity_parser.ast.parsers.parsers088 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers088.Parser088 + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers088._user_defined_value_type_definition + + + +.. py:class:: Parser088(token_stream) + + + Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` + + +.. py:function:: _user_defined_value_type_definition(parser, user_defined_value_type_definition: solidity_parser.grammar.v088.SolidityParser.SolidityParser.UserDefinedValueTypeDefinitionContext) + + diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst new file mode 100644 index 0000000..2e3fcf4 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst @@ -0,0 +1,56 @@ +:py:mod:`solidity_parser.ast.parsers.parsers08_22` +================================================== + +.. py:module:: solidity_parser.ast.parsers.parsers08_22 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers08_22.Parser08_22 + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.parsers.parsers08_22._user_definable_operator + solidity_parser.ast.parsers.parsers08_22._using_directive_alias + solidity_parser.ast.parsers.parsers08_22._using_directive + solidity_parser.ast.parsers.parsers08_22._number_literal + solidity_parser.ast.parsers.parsers08_22._literal_with_sub_denomination + solidity_parser.ast.parsers.parsers08_22._mapping_type + + + +.. py:class:: Parser08_22(token_stream) + + + Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` + + +.. py:function:: _user_definable_operator(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.UserDefinableOperatorContext) + + +.. py:function:: _using_directive_alias(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.UsingDirectiveAliasContext) + + +.. py:function:: _using_directive(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.UsingDirectiveContext) + + +.. py:function:: _number_literal(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.NumberLiteralContext) + + +.. py:function:: _literal_with_sub_denomination(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.LiteralWithSubDenominationContext) + + +.. py:function:: _mapping_type(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.MappingTypeContext) + + diff --git a/docs/source/autoapi/solidity_parser/ast/solnodes/index.rst b/docs/source/autoapi/solidity_parser/ast/solnodes/index.rst new file mode 100644 index 0000000..92bada6 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/solnodes/index.rst @@ -0,0 +1,1889 @@ +:py:mod:`solidity_parser.ast.solnodes` +====================================== + +.. py:module:: solidity_parser.ast.solnodes + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.solnodes.AST1Node + solidity_parser.ast.solnodes.Stmt + solidity_parser.ast.solnodes.Expr + solidity_parser.ast.solnodes.Ident + solidity_parser.ast.solnodes.Location + solidity_parser.ast.solnodes.NamedArg + solidity_parser.ast.solnodes.Unit + solidity_parser.ast.solnodes.Literal + solidity_parser.ast.solnodes.UnaryOpCode + solidity_parser.ast.solnodes.UnaryOp + solidity_parser.ast.solnodes.BinaryOpCode + solidity_parser.ast.solnodes.BinaryOp + solidity_parser.ast.solnodes.TernaryOp + solidity_parser.ast.solnodes.New + solidity_parser.ast.solnodes.NewInlineArray + solidity_parser.ast.solnodes.PayableConversion + solidity_parser.ast.solnodes.GetArrayValue + solidity_parser.ast.solnodes.GetArraySlice + solidity_parser.ast.solnodes.GetMember + solidity_parser.ast.solnodes.CallFunction + solidity_parser.ast.solnodes.Var + solidity_parser.ast.solnodes.VarDecl + solidity_parser.ast.solnodes.Parameter + solidity_parser.ast.solnodes.ExprStmt + solidity_parser.ast.solnodes.Block + solidity_parser.ast.solnodes.If + solidity_parser.ast.solnodes.Catch + solidity_parser.ast.solnodes.Try + solidity_parser.ast.solnodes.While + solidity_parser.ast.solnodes.For + solidity_parser.ast.solnodes.Emit + solidity_parser.ast.solnodes.Revert + solidity_parser.ast.solnodes.AssemblyStmt + solidity_parser.ast.solnodes.DoWhile + solidity_parser.ast.solnodes.Continue + solidity_parser.ast.solnodes.Break + solidity_parser.ast.solnodes.Return + solidity_parser.ast.solnodes.Throw + solidity_parser.ast.solnodes.Modifier + solidity_parser.ast.solnodes.VisibilityModifierKind + solidity_parser.ast.solnodes.MutabilityModifierKind + solidity_parser.ast.solnodes.VisibilityModifier2 + solidity_parser.ast.solnodes.MutabilityModifier2 + solidity_parser.ast.solnodes.InvocationModifier + solidity_parser.ast.solnodes.OverrideSpecifier + solidity_parser.ast.solnodes.SourceUnit + solidity_parser.ast.solnodes.PragmaDirective + solidity_parser.ast.solnodes.ImportDirective + solidity_parser.ast.solnodes.GlobalImportDirective + solidity_parser.ast.solnodes.UnitImportDirective + solidity_parser.ast.solnodes.SymbolAlias + solidity_parser.ast.solnodes.SymbolImportDirective + solidity_parser.ast.solnodes.ContractPart + solidity_parser.ast.solnodes.SpecialFunctionKind + solidity_parser.ast.solnodes.FunctionDefinition + solidity_parser.ast.solnodes.ModifierDefinition + solidity_parser.ast.solnodes.StructMember + solidity_parser.ast.solnodes.StructDefinition + solidity_parser.ast.solnodes.EnumDefinition + solidity_parser.ast.solnodes.StateVariableDeclaration + solidity_parser.ast.solnodes.ConstantVariableDeclaration + solidity_parser.ast.solnodes.UserValueType + solidity_parser.ast.solnodes.EventParameter + solidity_parser.ast.solnodes.EventDefinition + solidity_parser.ast.solnodes.ErrorParameter + solidity_parser.ast.solnodes.ErrorDefinition + solidity_parser.ast.solnodes.UsingAttachment + solidity_parser.ast.solnodes.UsingOperatorBinding + solidity_parser.ast.solnodes.UsingDirective + solidity_parser.ast.solnodes.InheritSpecifier + solidity_parser.ast.solnodes.ContractDefinition + solidity_parser.ast.solnodes.InterfaceDefinition + solidity_parser.ast.solnodes.LibraryDefinition + solidity_parser.ast.solnodes.CreateMetaType + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.solnodes.has_modifier_kind + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.solnodes.ModFunErrEvt + solidity_parser.ast.solnodes.Types + + +.. py:class:: AST1Node + + + Bases: :py:obj:`solidity_parser.ast.nodebase.Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: scope + :type: Scope + + + + .. py:attribute:: ast2_node + :type: AST2Node + + + + +.. py:class:: Stmt + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: Expr + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: Ident + + + Bases: :py:obj:`Expr` + + String identifier node + + .. py:attribute:: text + :type: str + + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: Location(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Solidity reference type storage locations + + These are used to specify in what type of memory context/area a struct/array/mapping is stored + + .. py:attribute:: MEMORY + :value: 'memory' + + An location that does not persist between function calls + + + .. py:attribute:: STORAGE + :value: 'storage' + + A location persists between function calls + + Contract state variables are stored here also + + + .. py:attribute:: CALLDATA + :value: 'calldata' + + A location that contains the function call arguments for external function call parameters + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: NamedArg + + + Bases: :py:obj:`Expr` + + A name-value pair used for calling functions with options + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: value + :type: Expr + + + + +.. py:class:: Unit(_: str, multiplier: int) + + + Bases: :py:obj:`enum.Enum` + + Solidity numerical unit types + + .. py:property:: multiplier + :type: int + + + .. py:attribute:: WEI + :value: ('wei', 1) + + + + .. py:attribute:: GWEI + :value: ('gwei', 1000000000.0) + + + + .. py:attribute:: SZABO + :value: ('szabo', 1000000000000.0) + + + + .. py:attribute:: FINNEY + :value: ('finney', 1000000000000000.0) + + + + .. py:attribute:: ETHER + :value: ('ether', 1e+18) + + + + .. py:attribute:: SECONDS + :value: ('seconds', 1) + + + + .. py:attribute:: MINUTES + :value: ('minutes', 60) + + + + .. py:attribute:: HOURS + :value: ('hours',) + + + + .. py:attribute:: DAYS + :value: ('days',) + + + + .. py:attribute:: WEEKS + :value: ('weeks',) + + + + .. py:attribute:: YEARS + :value: ('years',) + + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: Literal + + + Bases: :py:obj:`Expr` + + Constant value expression that can have an optional unit associated with it + + The value may be a python primitive, e.g. an integer, boolean, string, tuple, etc + + .. py:attribute:: value + :type: Any + + + + .. py:attribute:: unit + :type: Unit + + + + .. py:method:: code_str() + + + +.. py:class:: UnaryOpCode(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Single operand operation types + + .. py:attribute:: INC + :value: '++' + + + + .. py:attribute:: DEC + :value: '--' + + + + .. py:attribute:: SIGN_POS + :value: '+' + + + + .. py:attribute:: SIGN_NEG + :value: '-' + + + + .. py:attribute:: BOOL_NEG + :value: '!' + + + + .. py:attribute:: BIT_NEG + :value: '~' + + + + .. py:attribute:: DELETE + :value: 'delete' + + + + +.. py:class:: UnaryOp + + + Bases: :py:obj:`Expr` + + Single operand expression + + .. py:attribute:: expr + :type: Expr + + + + .. py:attribute:: op + :type: UnaryOpCode + + + + .. py:attribute:: is_pre + :type: bool + + Whether the operation is pre or post, e.g. ++x or x++ + + + +.. py:class:: BinaryOpCode(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Binary/two operand operation types, including assignment types + + .. py:attribute:: EXPONENTIATE + :value: '**' + + + + .. py:attribute:: MUL + :value: '*' + + + + .. py:attribute:: DIV + :value: '/' + + + + .. py:attribute:: MOD + :value: '%' + + + + .. py:attribute:: ADD + :value: '+' + + + + .. py:attribute:: SUB + :value: '-' + + + + .. py:attribute:: LSHIFT + :value: '<<' + + + + .. py:attribute:: RSHIFT + :value: '>>' + + + + .. py:attribute:: BIT_AND + :value: '&' + + + + .. py:attribute:: BIT_XOR + :value: '^' + + + + .. py:attribute:: BIT_OR + :value: '|' + + + + .. py:attribute:: LT + :value: '<' + + + + .. py:attribute:: GT + :value: '>' + + + + .. py:attribute:: LTEQ + :value: '<=' + + + + .. py:attribute:: GTEQ + :value: '>=' + + + + .. py:attribute:: EQ + :value: '==' + + + + .. py:attribute:: NEQ + :value: '!=' + + + + .. py:attribute:: BOOL_AND + :value: '&&' + + + + .. py:attribute:: BOOL_OR + :value: '||' + + + + .. py:attribute:: ASSIGN + :value: '=' + + + + .. py:attribute:: ASSIGN_OR + :value: '|=' + + + + .. py:attribute:: ASSIGN_BIT_NEG + :value: '^=' + + + + .. py:attribute:: ASSIGN_BIT_AND + :value: '&=' + + + + .. py:attribute:: ASSIGN_LSHIFT + :value: '<<=' + + + + .. py:attribute:: ASSIGN_RSHIFT + :value: '>>=' + + + + .. py:attribute:: ASSIGN_ADD + :value: '+=' + + + + .. py:attribute:: ASSIGN_SUB + :value: '-=' + + + + .. py:attribute:: ASSIGN_MUL + :value: '*=' + + + + .. py:attribute:: ASSIGN_DIV + :value: '/=' + + + + .. py:attribute:: ASSIGN_MOD + :value: '%=' + + + + +.. py:class:: BinaryOp + + + Bases: :py:obj:`Expr` + + Binary/two operand expression + + .. py:attribute:: left + :type: Expr + + + + .. py:attribute:: right + :type: Expr + + + + .. py:attribute:: op + :type: BinaryOpCode + + + + +.. py:class:: TernaryOp + + + Bases: :py:obj:`Expr` + + Choice expression that evaluates the given condition and returns one of the two given expressions + + If the condition evaluates to false then the left expression is returned, otherwise the right one is + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: left + :type: Expr + + + + .. py:attribute:: right + :type: Expr + + + + +.. py:class:: New + + + Bases: :py:obj:`Expr` + + New object allocation expression without constructor invocation + + Note that this expression only represents the 'new X' part of a new objects creation 'new X(a,b)'. + This expression must then be used as the base object in a constructor call to instantiate it. + + + .. py:attribute:: type_name + :type: solidity_parser.ast.types.Type + + + + +.. py:class:: NewInlineArray + + + Bases: :py:obj:`Expr` + + Solidity 8 inline array creation + + An inline array is one where the elements are explicitly stated in the definition, for example: + 'int[5] foo2 = [1, 0, 0, 0, 0];' + + .. py:attribute:: elements + :type: list[Expr] + + + + +.. py:class:: PayableConversion + + + Bases: :py:obj:`Expr` + + Converts an address to a payable address + + For example: 'payable(address(myAddressHex))' + + .. py:attribute:: args + :type: list[Expr] + + + + +.. py:class:: GetArrayValue + + + Bases: :py:obj:`Expr` + + Gets the value at the given index from the given array + + .. py:attribute:: array_base + :type: Expr + + + + .. py:attribute:: index + :type: Expr + + + + +.. py:class:: GetArraySlice + + + Bases: :py:obj:`Expr` + + Gets a subarray at the given start and end indices from the given array + + .. py:attribute:: array_base + :type: Expr + + + + .. py:attribute:: start_index + :type: Expr + + + + .. py:attribute:: end_index + :type: Expr + + + + +.. py:class:: GetMember + + + Bases: :py:obj:`Expr` + + Gets a member field or method from a given object + + .. py:attribute:: obj_base + :type: Expr + + + + .. py:attribute:: name + :type: Ident + + + + +.. py:class:: CallFunction + + + Bases: :py:obj:`Expr` + + Invokes a function + + .. py:attribute:: callee + :type: Expr + + This callee is most likely a GetMember expression but can be any callable + + + .. py:attribute:: modifiers + :type: list + + + + .. py:attribute:: args + :type: list[Expr] + + + + +.. py:class:: Var + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: var_name + :type: Ident + + + + .. py:attribute:: var_loc + :type: Optional[Location] + + + + +.. py:class:: VarDecl + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: variables + :type: list[Var] + + + + .. py:attribute:: value + :type: Expr + + + + .. py:attribute:: is_lhs_tuple + :type: bool + :value: False + + + + +.. py:class:: Parameter + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var_type + :type: Ident + + + + .. py:attribute:: var_loc + :type: Location + + + + .. py:attribute:: var_name + :type: Ident + + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: ExprStmt + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: expr + :type: Expr + + + + +.. py:class:: Block + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: stmts + :type: list[Stmt] + + + + .. py:attribute:: is_unchecked + :type: bool + :value: False + + + + +.. py:class:: If + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: true_branch + :type: Stmt + + + + .. py:attribute:: false_branch + :type: Stmt + + + + +.. py:class:: Catch + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ident + :type: Ident + + + + .. py:attribute:: parameters + :type: list[Parameter] + + + + .. py:attribute:: body + :type: Block + + + + +.. py:class:: Try + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: expr + :type: Expr + + + + .. py:attribute:: return_parameters + :type: list[Parameter] + + + + .. py:attribute:: body + :type: Block + + + + .. py:attribute:: catch_clauses + :type: list[Catch] + + + + +.. py:class:: While + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: expr + :type: Expr + + + + .. py:attribute:: body + :type: Stmt + + + + +.. py:class:: For + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: initialiser + :type: Stmt + + + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: advancement + :type: Expr + + + + .. py:attribute:: body + :type: Stmt + + + + +.. py:class:: Emit + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: call + :type: CallFunction + + + + +.. py:class:: Revert + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: call + :type: CallFunction + + + + +.. py:class:: AssemblyStmt + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: code + :type: str + + + + +.. py:class:: DoWhile + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: body + :type: Stmt + + + + .. py:attribute:: condition + :type: Expr + + + + +.. py:class:: Continue + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: Break + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: Return + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: value + :type: Expr + + + + +.. py:class:: Throw + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: Modifier + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: VisibilityModifierKind(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Create a collection of name/value pairs. + + Example enumeration: + + >>> class Color(Enum): + ... RED = 1 + ... BLUE = 2 + ... GREEN = 3 + + Access them by: + + - attribute access:: + + >>> Color.RED + + + - value lookup: + + >>> Color(1) + + + - name lookup: + + >>> Color['RED'] + + + Enumerations can be iterated over, and know how many members they have: + + >>> len(Color) + 3 + + >>> list(Color) + [, , ] + + Methods can be added to enumerations, and members can have their own + attributes -- see the documentation for details. + + .. py:attribute:: EXTERNAL + :value: 'external' + + + + .. py:attribute:: PUBLIC + :value: 'public' + + + + .. py:attribute:: INTERNAL + :value: 'internal' + + + + .. py:attribute:: PRIVATE + :value: 'private' + + + + .. py:attribute:: VIRTUAL + :value: 'virtual' + + + + +.. py:class:: MutabilityModifierKind(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Create a collection of name/value pairs. + + Example enumeration: + + >>> class Color(Enum): + ... RED = 1 + ... BLUE = 2 + ... GREEN = 3 + + Access them by: + + - attribute access:: + + >>> Color.RED + + + - value lookup: + + >>> Color(1) + + + - name lookup: + + >>> Color['RED'] + + + Enumerations can be iterated over, and know how many members they have: + + >>> len(Color) + 3 + + >>> list(Color) + [, , ] + + Methods can be added to enumerations, and members can have their own + attributes -- see the documentation for details. + + .. py:attribute:: PURE + :value: 'pure' + + + + .. py:attribute:: CONSTANT + :value: 'constant' + + + + .. py:attribute:: VIEW + :value: 'view' + + + + .. py:attribute:: PAYABLE + :value: 'payable' + + + + .. py:attribute:: IMMUTABLE + :value: 'immutable' + + + + +.. py:class:: VisibilityModifier2 + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: kind + :type: VisibilityModifierKind + + + + +.. py:class:: MutabilityModifier2 + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: kind + :type: MutabilityModifierKind + + + + +.. py:class:: InvocationModifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: arguments + :type: list[Expr] + + + + +.. py:class:: OverrideSpecifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: arguments + :type: list[solidity_parser.ast.types.UserType] + + + + +.. py:class:: SourceUnit + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: PragmaDirective + + + Bases: :py:obj:`SourceUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: value + :type: str | Expr + + + + +.. py:class:: ImportDirective + + + Bases: :py:obj:`SourceUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: path + :type: str + + + + +.. py:class:: GlobalImportDirective + + + Bases: :py:obj:`ImportDirective` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: UnitImportDirective + + + Bases: :py:obj:`ImportDirective` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: alias + :type: Ident + + + + +.. py:class:: SymbolAlias + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: symbol + :type: Ident + + + + .. py:attribute:: alias + :type: Ident + + + + +.. py:class:: SymbolImportDirective + + + Bases: :py:obj:`ImportDirective` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: aliases + :type: list[SymbolAlias] + + + + +.. py:class:: ContractPart + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: SpecialFunctionKind(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Create a collection of name/value pairs. + + Example enumeration: + + >>> class Color(Enum): + ... RED = 1 + ... BLUE = 2 + ... GREEN = 3 + + Access them by: + + - attribute access:: + + >>> Color.RED + + + - value lookup: + + >>> Color(1) + + + - name lookup: + + >>> Color['RED'] + + + Enumerations can be iterated over, and know how many members they have: + + >>> len(Color) + 3 + + >>> list(Color) + [, , ] + + Methods can be added to enumerations, and members can have their own + attributes -- see the documentation for details. + + .. py:attribute:: CONSTRUCTOR + :value: '<>' + + + + .. py:attribute:: RECEIVE + :value: '<>' + + + + .. py:attribute:: FALLBACK + :value: '<>' + + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: FunctionDefinition + + + Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident | SpecialFunctionKind + + + + .. py:attribute:: parameters + :type: list[Parameter] + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:attribute:: returns + :type: list[Parameter] + + + + .. py:attribute:: code + :type: Block + + + + +.. py:class:: ModifierDefinition + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: parameters + :type: list[Parameter] + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:attribute:: code + :type: Block + + + + +.. py:class:: StructMember + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: member_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: name + :type: Ident + + + + +.. py:class:: StructDefinition + + + Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: members + :type: list[StructMember] + + + + +.. py:class:: EnumDefinition + + + Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: values + :type: list[Ident] + + + + +.. py:class:: StateVariableDeclaration + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: initial_value + :type: Expr + + + + +.. py:class:: ConstantVariableDeclaration + + + Bases: :py:obj:`SourceUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: initial_value + :type: Expr + + + + +.. py:class:: UserValueType + + + Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: value + :type: solidity_parser.ast.types.Type + + + + +.. py:class:: EventParameter + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: is_indexed + :type: bool + + + + +.. py:class:: EventDefinition + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: is_anonymous + :type: bool + + + + .. py:attribute:: parameters + :type: list[EventParameter] + + + + +.. py:class:: ErrorParameter + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: name + :type: Ident + + + + +.. py:class:: ErrorDefinition + + + Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: parameters + :type: list[ErrorParameter] + + + + +.. py:class:: UsingAttachment + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: member_name + :type: Ident + + + + +.. py:class:: UsingOperatorBinding + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: member_name + :type: Ident + + + + .. py:attribute:: operator + :type: UnaryOpCode | BinaryOpCode + + + + +.. py:class:: UsingDirective + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: library_name + :type: Ident + + + + .. py:attribute:: override_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: attachments_or_bindings + :type: list[UsingAttachment | UsingOperatorBinding] + + + + .. py:attribute:: is_global + :type: bool + + + + +.. py:class:: InheritSpecifier + + + Bases: :py:obj:`AST1Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: solidity_parser.ast.types.UserType + + + + .. py:attribute:: args + :type: list[Expr] + + + + +.. py:class:: ContractDefinition + + + Bases: :py:obj:`SourceUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: is_abstract + :type: bool + + + + .. py:attribute:: inherits + :type: list[InheritSpecifier] + + + + .. py:attribute:: parts + :type: list[ContractPart] + + + + +.. py:class:: InterfaceDefinition + + + Bases: :py:obj:`SourceUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: inherits + :type: list[InheritSpecifier] + + + + .. py:attribute:: parts + :type: list[ContractPart] + + + + +.. py:class:: LibraryDefinition + + + Bases: :py:obj:`SourceUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: parts + :type: list[ContractPart] + + + + +.. py:class:: CreateMetaType + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base_type + :type: solidity_parser.ast.types.Type + + + + +.. py:function:: has_modifier_kind(node, *kinds: VisibilityModifierKind | MutabilityModifierKind) + + +.. py:data:: ModFunErrEvt + :type: TypeAlias + + + +.. py:data:: Types + :type: TypeAlias + + + diff --git a/docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst b/docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst new file mode 100644 index 0000000..43c5129 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst @@ -0,0 +1,2393 @@ +:py:mod:`solidity_parser.ast.solnodes2` +======================================= + +.. py:module:: solidity_parser.ast.solnodes2 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.solnodes2.AST2Node + solidity_parser.ast.solnodes2.Stmt + solidity_parser.ast.solnodes2.Expr + solidity_parser.ast.solnodes2.Modifier + solidity_parser.ast.solnodes2.ResolvedUserType + solidity_parser.ast.solnodes2.SuperType + solidity_parser.ast.solnodes2.VisibilityModifier + solidity_parser.ast.solnodes2.MutabilityModifier + solidity_parser.ast.solnodes2.OverrideSpecifier + solidity_parser.ast.solnodes2.SuperConstructorInvocationModifier + solidity_parser.ast.solnodes2.FunctionInvocationModifier + solidity_parser.ast.solnodes2.Ident + solidity_parser.ast.solnodes2.NamedArgument + solidity_parser.ast.solnodes2.TopLevelUnit + solidity_parser.ast.solnodes2.ContractPart + solidity_parser.ast.solnodes2.InheritSpecifier + solidity_parser.ast.solnodes2.LibraryOverride + solidity_parser.ast.solnodes2.FileDefinition + solidity_parser.ast.solnodes2.ContractDefinition + solidity_parser.ast.solnodes2.InterfaceDefinition + solidity_parser.ast.solnodes2.LibraryDefinition + solidity_parser.ast.solnodes2.UserDefinedValueTypeDefinition + solidity_parser.ast.solnodes2.EnumMember + solidity_parser.ast.solnodes2.EnumDefinition + solidity_parser.ast.solnodes2.StructMember + solidity_parser.ast.solnodes2.StructDefinition + solidity_parser.ast.solnodes2.ErrorParameter + solidity_parser.ast.solnodes2.ErrorDefinition + solidity_parser.ast.solnodes2.StateVariableDeclaration + solidity_parser.ast.solnodes2.ConstantVariableDeclaration + solidity_parser.ast.solnodes2.EventParameter + solidity_parser.ast.solnodes2.EventDefinition + solidity_parser.ast.solnodes2.Location + solidity_parser.ast.solnodes2.Var + solidity_parser.ast.solnodes2.Parameter + solidity_parser.ast.solnodes2.Block + solidity_parser.ast.solnodes2.If + solidity_parser.ast.solnodes2.Catch + solidity_parser.ast.solnodes2.Try + solidity_parser.ast.solnodes2.While + solidity_parser.ast.solnodes2.For + solidity_parser.ast.solnodes2.FunctionMarker + solidity_parser.ast.solnodes2.FunctionDefinition + solidity_parser.ast.solnodes2.BuiltinFunction + solidity_parser.ast.solnodes2.ModifierDefinition + solidity_parser.ast.solnodes2.TupleVarDecl + solidity_parser.ast.solnodes2.VarDecl + solidity_parser.ast.solnodes2.ExprStmt + solidity_parser.ast.solnodes2.Literal + solidity_parser.ast.solnodes2.TypeLiteral + solidity_parser.ast.solnodes2.UnaryOp + solidity_parser.ast.solnodes2.BinaryOp + solidity_parser.ast.solnodes2.TernaryOp + solidity_parser.ast.solnodes2.SelfObject + solidity_parser.ast.solnodes2.SuperObject + solidity_parser.ast.solnodes2.StateVarLoad + solidity_parser.ast.solnodes2.StaticVarLoad + solidity_parser.ast.solnodes2.EnumLoad + solidity_parser.ast.solnodes2.StateVarStore + solidity_parser.ast.solnodes2.LocalVarLoad + solidity_parser.ast.solnodes2.LocalVarStore + solidity_parser.ast.solnodes2.ArrayLengthStore + solidity_parser.ast.solnodes2.TupleLoad + solidity_parser.ast.solnodes2.ArrayLoad + solidity_parser.ast.solnodes2.ArrayStore + solidity_parser.ast.solnodes2.ArraySliceLoad + solidity_parser.ast.solnodes2.CreateInlineArray + solidity_parser.ast.solnodes2.MappingLoad + solidity_parser.ast.solnodes2.MappingStore + solidity_parser.ast.solnodes2.GlobalValue + solidity_parser.ast.solnodes2.ABISelector + solidity_parser.ast.solnodes2.DynamicBuiltInValue + solidity_parser.ast.solnodes2.CreateMemoryArray + solidity_parser.ast.solnodes2.CreateStruct + solidity_parser.ast.solnodes2.CreateAndDeployContract + solidity_parser.ast.solnodes2.Call + solidity_parser.ast.solnodes2.DirectCall + solidity_parser.ast.solnodes2.FunctionCall + solidity_parser.ast.solnodes2.FunctionPointerCall + solidity_parser.ast.solnodes2.DynamicBuiltInCall + solidity_parser.ast.solnodes2.BuiltInCall + solidity_parser.ast.solnodes2.Cast + solidity_parser.ast.solnodes2.GetType + solidity_parser.ast.solnodes2.GetFunctionPointer + solidity_parser.ast.solnodes2.EmitEvent + solidity_parser.ast.solnodes2.Revert + solidity_parser.ast.solnodes2.RevertWithError + solidity_parser.ast.solnodes2.RevertWithReason + solidity_parser.ast.solnodes2.Require + solidity_parser.ast.solnodes2.Return + solidity_parser.ast.solnodes2.Continue + solidity_parser.ast.solnodes2.Break + solidity_parser.ast.solnodes2.Assembly + solidity_parser.ast.solnodes2.ExecModifiedCode + solidity_parser.ast.solnodes2.UnprocessedCode + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.solnodes2.raiseNotPrintable + solidity_parser.ast.solnodes2.param_def_str + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.solnodes2.T + solidity_parser.ast.solnodes2.Types + + +.. py:data:: T + + + +.. py:function:: raiseNotPrintable() + + +.. py:function:: param_def_str(ps) + + +.. py:class:: AST2Node + + + Bases: :py:obj:`solidity_parser.ast.nodebase.Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:method:: get_top_level_unit() -> TopLevelUnit + + + +.. py:class:: Stmt + + + Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: Expr + + + Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + :abstractmethod: + + + +.. py:class:: Modifier + + + Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: ResolvedUserType + + + Bases: :py:obj:`solidity_parser.ast.types.Type` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: scope + :type: Scope + + + + .. py:attribute:: value + :type: solidity_parser.ast.nodebase.Ref[TopLevelUnit] + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: __repr__() + + Return repr(self). + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_user_type() -> bool + + Check if the type is a user defined type, e.g. struct, enum, contract, etc + + + .. py:method:: can_implicitly_cast_from(actual_type: solidity_parser.ast.types.Type) -> bool + + + .. py:method:: get_types_for_declared_type() -> list[TopLevelUnit] + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: SuperType + + + Bases: :py:obj:`solidity_parser.ast.types.Type` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: declarer + :type: solidity_parser.ast.nodebase.Ref[Union[ContractDefinition, InterfaceDefinition]] + + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: get_types_for_declared_type() -> list[TopLevelUnit] + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: VisibilityModifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: kind + :type: solidity_parser.ast.solnodes.VisibilityModifierKind + + + + .. py:method:: code_str() + + + +.. py:class:: MutabilityModifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: kind + :type: solidity_parser.ast.solnodes.MutabilityModifierKind + + + + .. py:method:: code_str() + + + +.. py:class:: OverrideSpecifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: bases + :type: list[ResolvedUserType] + + + + .. py:method:: code_str() + + + +.. py:class:: SuperConstructorInvocationModifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base_ttype + :type: ResolvedUserType + + + + .. py:attribute:: inputs + :type: list[Expr] + + + + .. py:method:: code_str() + + + +.. py:class:: FunctionInvocationModifier + + + Bases: :py:obj:`Modifier` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: modifier + :type: solidity_parser.ast.nodebase.Ref[ModifierDefinition] + + + + .. py:attribute:: inputs + :type: list[Expr] + + + + .. py:method:: code_str() + + + +.. py:class:: Ident + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: text + :type: str + + + + .. py:method:: code_str() + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: NamedArgument + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: expr + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: TopLevelUnit + + + Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: source_unit_name + :type: str + + + + .. py:attribute:: name + :type: Ident + + + + .. py:method:: descriptor() -> str + + + .. py:method:: is_subttype_of(other_contract: TopLevelUnit) -> bool + + + .. py:method:: as_type() + + + .. py:method:: get_supers() -> list[Union[ContractDefinition, InterfaceDefinition]] + + + .. py:method:: get_subtypes() -> list[Union[ContractDefinition, InterfaceDefinition]] + + + .. py:method:: is_enum() -> bool + + + .. py:method:: is_struct() -> bool + + + .. py:method:: is_contract() -> bool + + + .. py:method:: is_interface() -> bool + + + .. py:method:: is_udvt() -> bool + + + .. py:method:: find_named_parts(name: str, explore_mro: bool, matching_types) + + + +.. py:class:: ContractPart + + + Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:method:: has_modifier_kind(*kinds: solidity_parser.ast.solnodes.VisibilityModifierKind | solidity_parser.ast.solnodes.MutabilityModifierKind) + + + +.. py:class:: InheritSpecifier + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: ResolvedUserType + + + + .. py:attribute:: args + :type: list[Expr] + + + + .. py:method:: code_str() + + + +.. py:class:: LibraryOverride + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: overriden_type + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: library + :type: ResolvedUserType + + + + +.. py:class:: FileDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: scope + :type: Scope + + + + .. py:attribute:: parts + :type: list[ContractPart] + + + + .. py:method:: descriptor() -> str + + + +.. py:class:: ContractDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: is_abstract + :type: bool + + + + .. py:attribute:: inherits + :type: list[InheritSpecifier] + + + + .. py:attribute:: parts + :type: list[ContractPart] + + + + .. py:attribute:: type_overrides + :type: list[LibraryOverride] + + + + .. py:attribute:: _subtypes + :type: list[solidity_parser.ast.nodebase.Ref[Union[ContractDefinition, InterfaceDefinition]]] + + + + +.. py:class:: InterfaceDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: inherits + :type: list[InheritSpecifier] + + + + .. py:attribute:: parts + :type: list[ContractPart] + + + + .. py:attribute:: type_overrides + :type: list[LibraryOverride] + + + + .. py:attribute:: _subtypes + :type: list[solidity_parser.ast.nodebase.Ref[Union[ContractDefinition, InterfaceDefinition]]] + + + + +.. py:class:: LibraryDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: parts + :type: list[ContractPart] + + + + .. py:attribute:: type_overrides + :type: list[LibraryOverride] + + + + +.. py:class:: UserDefinedValueTypeDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + +.. py:class:: EnumMember + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + +.. py:class:: EnumDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: values + :type: list[EnumMember] + + + + +.. py:class:: StructMember + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: name + :type: Ident + + + + +.. py:class:: StructDefinition + + + Bases: :py:obj:`TopLevelUnit` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: members + :type: list[StructMember] + + + + +.. py:class:: ErrorParameter + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: name + :type: Ident + + + + +.. py:class:: ErrorDefinition + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: inputs + :type: list[ErrorParameter] + + + + +.. py:class:: StateVariableDeclaration + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:attribute:: value + :type: Expr + + + + +.. py:class:: ConstantVariableDeclaration + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: value + :type: Expr + + + + +.. py:class:: EventParameter + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: is_indexed + :type: bool + + + + +.. py:class:: EventDefinition + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: inputs + :type: list[EventParameter] + + + + .. py:attribute:: is_anonymous + :type: bool + + + + +.. py:class:: Location(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Create a collection of name/value pairs. + + Example enumeration: + + >>> class Color(Enum): + ... RED = 1 + ... BLUE = 2 + ... GREEN = 3 + + Access them by: + + - attribute access:: + + >>> Color.RED + + + - value lookup: + + >>> Color(1) + + + - name lookup: + + >>> Color['RED'] + + + Enumerations can be iterated over, and know how many members they have: + + >>> len(Color) + 3 + + >>> list(Color) + [, , ] + + Methods can be added to enumerations, and members can have their own + attributes -- see the documentation for details. + + .. py:attribute:: MEMORY + :value: 'memory' + + + + .. py:attribute:: STORAGE + :value: 'storage' + + + + .. py:attribute:: CALLDATA + :value: 'calldata' + + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: Var + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: location + :type: Location + + + + .. py:method:: code_str() + + + +.. py:class:: Parameter + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var + :type: Var + + + + +.. py:class:: Block + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: stmts + :type: list[Stmt] + + + + .. py:attribute:: is_unchecked + :type: bool + + + + .. py:method:: code_str(brackets=True) + + + +.. py:class:: If + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: true_branch + :type: Stmt + + + + .. py:attribute:: false_branch + :type: Stmt + + + + .. py:method:: code_str() + + + +.. py:class:: Catch + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ident + :type: Ident + + + + .. py:attribute:: parameters + :type: list[Parameter] + + + + .. py:attribute:: body + :type: Block + + + + .. py:method:: code_str() + + + +.. py:class:: Try + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: expr + :type: Expr + + + + .. py:attribute:: return_parameters + :type: list[Parameter] + + + + .. py:attribute:: body + :type: Block + + + + .. py:attribute:: catch_clauses + :type: list[Catch] + + + + .. py:method:: code_str() + + + +.. py:class:: While + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: body + :type: Stmt + + + + .. py:attribute:: is_do_while + :type: bool + + + + .. py:method:: code_str() + + + +.. py:class:: For + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: initialiser + :type: Stmt + + + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: advancement + :type: Expr + + + + .. py:attribute:: body + :type: Stmt + + + + .. py:method:: code_str() + + + +.. py:class:: FunctionMarker(*args, **kwds) + + + Bases: :py:obj:`enum.Enum` + + Special function type markers + + .. py:attribute:: CONSTRUCTOR + :value: 1 + + + + .. py:attribute:: SYNTHETIC_FIELD_GETTER + :value: 2 + + + + +.. py:class:: FunctionDefinition + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: inputs + :type: list[Parameter] + + + + .. py:attribute:: outputs + :type: list[Parameter] + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:attribute:: code + :type: Block + + + + .. py:attribute:: markers + :type: list[FunctionMarker] + + + + .. py:method:: param_str(ps) -> str + :staticmethod: + + + .. py:method:: descriptor() -> str + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: BuiltinFunction + + + Bases: :py:obj:`AST2Node` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: inputs + :type: list[Parameter] + + + + .. py:attribute:: outputs + :type: list[Parameter] + + + + +.. py:class:: ModifierDefinition + + + Bases: :py:obj:`ContractPart` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: inputs + :type: list[Parameter] + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:attribute:: code + :type: Block + + + + +.. py:class:: TupleVarDecl + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: vars + :type: list[Var] + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: VarDecl + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var + :type: Var + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: ExprStmt + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: expr + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: Literal + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: value + :type: Any + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: unit + :type: solidity_parser.ast.solnodes.Unit + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: TypeLiteral + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:method:: type_of() + + + .. py:method:: code_str() + + + +.. py:class:: UnaryOp + + + Bases: :py:obj:`Expr` + + Single operand expression + + .. py:attribute:: expr + :type: Expr + + + + .. py:attribute:: op + :type: solidity_parser.ast.solnodes.UnaryOpCode + + + + .. py:attribute:: is_pre + :type: bool + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: BinaryOp + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: left + :type: Expr + + + + .. py:attribute:: right + :type: Expr + + + + .. py:attribute:: op + :type: solidity_parser.ast.solnodes.BinaryOpCode + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: TernaryOp + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: left + :type: Expr + + + + .. py:attribute:: right + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: SelfObject + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: declarer + :type: solidity_parser.ast.nodebase.Ref[ContractDefinition | InterfaceDefinition] + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: SuperObject + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: SuperType + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: StateVarLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: name + :type: Ident + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: StaticVarLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: ResolvedUserType + + + + .. py:attribute:: name + :type: Ident + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: EnumLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: member + :type: solidity_parser.ast.nodebase.Ref[EnumMember] + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: StateVarStore + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: name + :type: Ident + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: state_var() + + + .. py:method:: code_str() + + + +.. py:class:: LocalVarLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var + :type: Var + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: LocalVarStore + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: var + :type: Var + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: ArrayLengthStore + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + :abstractmethod: + + + +.. py:class:: TupleLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: index + :type: int + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: ArrayLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: index + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: ArrayStore + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: index + :type: Expr + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: ArraySliceLoad + + + Bases: :py:obj:`Expr` + + Gets a subarray at the given start and end indices from the given array + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: start_index + :type: Expr + + + + .. py:attribute:: end_index + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: CreateInlineArray + + + Bases: :py:obj:`Expr` + + Solidity 8 inline array creation + + An inline array is one where the elements are explicitly stated in the definition, for example: + 'int[5] foo2 = [1, 0, 0, 0, 0];' + + .. py:attribute:: elements + :type: list[Expr] + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: MappingLoad + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: key + :type: Expr + + + + .. py:method:: code_str() + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + +.. py:class:: MappingStore + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: key + :type: Expr + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: GlobalValue + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: str + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: ABISelector + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: function + :type: solidity_parser.ast.nodebase.Ref[FunctionDefinition | ErrorDefinition] | Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + + +.. py:class:: DynamicBuiltInValue + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: str + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: base + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: CreateMemoryArray + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.ArrayType + + + + .. py:attribute:: size + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: CreateStruct + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: ResolvedUserType + + + + .. py:attribute:: args + :type: list[Expr] + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: CreateAndDeployContract + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: ResolvedUserType + + + + .. py:attribute:: named_args + :type: list[NamedArgument] + + + + .. py:attribute:: args + :type: list[Expr] + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: Call + + + Bases: :py:obj:`Expr`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: named_args + :type: list[NamedArgument] + + + + .. py:attribute:: args + :type: list[Expr] + + + + .. py:method:: check_arg_types(f: FunctionDefinition) -> bool + + + .. py:method:: param_str() + + + +.. py:class:: DirectCall + + + Bases: :py:obj:`Call` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: ResolvedUserType + + + + .. py:attribute:: name + :type: Ident + + + + .. py:method:: base_type() + + + .. py:method:: resolve_call() -> FunctionDefinition + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: FunctionCall + + + Bases: :py:obj:`Call` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: base + :type: Expr + + + + .. py:attribute:: name + :type: Ident + + + + .. py:method:: base_type() + + + .. py:method:: resolve_call() -> FunctionDefinition + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: FunctionPointerCall + + + Bases: :py:obj:`Call` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: callee + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: DynamicBuiltInCall + + + Bases: :py:obj:`Call` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: base + :type: Expr | ResolvedUserType + + + + .. py:attribute:: name + :type: str + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: BuiltInCall + + + Bases: :py:obj:`Call` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: name + :type: str + + + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: Cast + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:attribute:: value + :type: Expr + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: GetType + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: ttype + :type: solidity_parser.ast.types.Type + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: GetFunctionPointer + + + Bases: :py:obj:`Expr` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: func + :type: solidity_parser.ast.nodebase.Ref[Union[FunctionDefinition, BuiltinFunction]] + + + + .. py:method:: type_of() -> solidity_parser.ast.types.Type + + + .. py:method:: code_str() + + + +.. py:class:: EmitEvent + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: event + :type: solidity_parser.ast.nodebase.Ref[EventDefinition] + + + + .. py:attribute:: args + :type: list[Expr] + + + + .. py:method:: code_str() + + + +.. py:class:: Revert + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: RevertWithError + + + Bases: :py:obj:`Revert` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: error + :type: solidity_parser.ast.nodebase.Ref[ErrorDefinition] + + + + .. py:attribute:: args + :type: list[Expr] + + + + .. py:method:: code_str() + + + +.. py:class:: RevertWithReason + + + Bases: :py:obj:`Revert` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: reason + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: Require + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: condition + :type: Expr + + + + .. py:attribute:: reason + :type: Expr + + + + .. py:method:: code_str() + + + +.. py:class:: Return + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: values + :type: list[Expr] + + + + .. py:method:: code_str() + + + +.. py:class:: Continue + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:method:: code_str() + + + +.. py:class:: Break + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:method:: code_str() + + + +.. py:class:: Assembly + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: code + :type: str + + + + .. py:method:: code_str() + + + +.. py:class:: ExecModifiedCode + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + +.. py:class:: UnprocessedCode + + + Bases: :py:obj:`Stmt` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: error + :type: Exception + + + + +.. py:data:: Types + :type: TypeAlias + + + diff --git a/docs/source/autoapi/solidity_parser/ast/symtab/index.rst b/docs/source/autoapi/solidity_parser/ast/symtab/index.rst new file mode 100644 index 0000000..3d88d00 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/symtab/index.rst @@ -0,0 +1,717 @@ +:py:mod:`solidity_parser.ast.symtab` +==================================== + +.. py:module:: solidity_parser.ast.symtab + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.symtab.Scopeable + solidity_parser.ast.symtab.Symbol + solidity_parser.ast.symtab.CrossScopeSymbolAlias + solidity_parser.ast.symtab.Scope + solidity_parser.ast.symtab.ScopeAndSymbol + solidity_parser.ast.symtab.BuiltinObject + solidity_parser.ast.symtab.BuiltinFunction + solidity_parser.ast.symtab.BuiltinValue + solidity_parser.ast.symtab.RootScope + solidity_parser.ast.symtab.FileScope + solidity_parser.ast.symtab.LibraryScope + solidity_parser.ast.symtab.ContractOrInterfaceScope + solidity_parser.ast.symtab.StructScope + solidity_parser.ast.symtab.UserDefinedValueTypeScope + solidity_parser.ast.symtab.LibraryScope + solidity_parser.ast.symtab.EnumScope + solidity_parser.ast.symtab.ModFunErrEvtScope + solidity_parser.ast.symtab.ImportSymbol + solidity_parser.ast.symtab.AliasImportSymbol + solidity_parser.ast.symtab.UnitImportSymbol + solidity_parser.ast.symtab.ProxyScope + solidity_parser.ast.symtab.UsingDirectiveScope + solidity_parser.ast.symtab.UsingFunctionSymbol + solidity_parser.ast.symtab.UsingOperatorSymbol + solidity_parser.ast.symtab.Builder2 + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.symtab.bytes + solidity_parser.ast.symtab.bytesn + solidity_parser.ast.symtab.bytes32 + solidity_parser.ast.symtab.uint + solidity_parser.ast.symtab.ACCEPT + solidity_parser.ast.symtab.unit_scope_of + solidity_parser.ast.symtab.ACCEPT_INHERITABLE + solidity_parser.ast.symtab.is_top_level + solidity_parser.ast.symtab.is_using_directive_scope + solidity_parser.ast.symtab.predicate_ignore_inherited_usings + solidity_parser.ast.symtab.predicate_accept_top_levels + solidity_parser.ast.symtab.ACCEPT_NO_INHERITED_USINGS + solidity_parser.ast.symtab.ACCEPT_CALLABLES + solidity_parser.ast.symtab.ACCEPT_NOT + solidity_parser.ast.symtab.ACCEPT_TOP_LEVEL_SCOPE + solidity_parser.ast.symtab.ACCEPT_ALL + solidity_parser.ast.symtab.test_predicate + solidity_parser.ast.symtab._add_to_results + solidity_parser.ast.symtab.create_builtin_scope + solidity_parser.ast.symtab.type_key + solidity_parser.ast.symtab.meta_type_key + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.symtab.Aliases + + +.. py:data:: Aliases + :type: TypeAlias + + + +.. py:function:: bytes() + + +.. py:function:: bytesn(n) + + +.. py:function:: bytes32() + + +.. py:function:: uint(size=256) + + +.. py:function:: ACCEPT(x) + + +.. py:function:: unit_scope_of(s) + + +.. py:function:: ACCEPT_INHERITABLE(base_scope) + + +.. py:function:: is_top_level(node: solidity_parser.ast.nodebase.Node) + + +.. py:function:: is_using_directive_scope(sym: Symbol) -> bool + + +.. py:function:: predicate_ignore_inherited_usings(base_scope) + + +.. py:function:: predicate_accept_top_levels(sym: Symbol) -> bool + + +.. py:function:: ACCEPT_NO_INHERITED_USINGS(base_scope) + + +.. py:function:: ACCEPT_CALLABLES(x) + + +.. py:function:: ACCEPT_NOT(p) + + +.. py:function:: ACCEPT_TOP_LEVEL_SCOPE(x) + + +.. py:function:: ACCEPT_ALL(*predicates) + + +.. py:function:: test_predicate(xs, predicate=None) + + +.. py:function:: _add_to_results(possible_symbols: Collection, results: list, found_already: Set) + + +.. py:class:: Scopeable(aliases: Optional[Aliases]) + + + Element that can be added as a child of a Scope + + .. py:attribute:: _T + + + + .. py:method:: set_parent_scope(parent_scope: Scope) + + Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks + + + .. py:method:: find_first_ancestor(predicate: Callable[[Scopeable], bool], get_parent: Optional[Callable[[Scopeable], Scope]] = None) -> Optional[_T] + + Walks up the symbol tree and finds the first element that satisfies the given predicate + + :param predicate: a function that takes a Scopeable and returns a bool to determine if it matches + :param get_parent: a function that takes a Scopeable and returns its parent, defaults to the parent_scope of a + Scopeable + :return: the first Scopeable that satisfies the predicate + + + .. py:method:: find_first_ancestor_of(ttype: Type[_T]) -> Optional[_T] + + Find the first ancestor that is of the given type, note: these are python types and not solc types. + + :param ttype: e.g. ContractOrInterfaceScope + :return: the first ancestor that is of the given type + + + .. py:method:: _check_single_symbol(name, results, default) + + + +.. py:class:: Symbol(aliases: Optional[Aliases], value) + + + Bases: :py:obj:`Scopeable` + + Element that can be added as a child of a Scope + + .. py:method:: get_as_dealiased_symbols() -> list[Symbol] + + + .. py:method:: res_syms() -> list[Symbol] + + + .. py:method:: res_syms_single() + + + .. py:method:: set_parent_scope(parent_scope: Scope) + + Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks + + + .. py:method:: str_type() + + + .. py:method:: __str__(level=0) + + Return str(self). + + + +.. py:class:: CrossScopeSymbolAlias(aliases: Aliases, other_symbol: Symbol) + + + Bases: :py:obj:`Symbol` + + Element that can be added as a child of a Scope + + .. py:method:: res_syms() -> list[Symbol] + + + .. py:method:: get_as_dealiased_symbols() -> list[Symbol] + + + +.. py:class:: Scope(aliases: Optional[Aliases]) + + + Bases: :py:obj:`Scopeable` + + Element that can be added as a child of a Scope + + .. py:method:: is_defined(name: str) -> bool + + Check if the name exists in the current scopes local table, i.e. whether it was declared in the current scope + + + .. py:method:: get_direct_children() -> Collection[Symbol] + + Get all children declared directly in this scope + + + .. py:method:: get_all_children(collect_predicate, explore_branch_predicate) + + Tree explorer for all DECLARED children and grandchildren, i.e. doesn't look at imports + + + .. py:method:: get_all_functions() -> list[ModFunErrEvtScope] + + Gets all DECLARED functions in the current scope/descendant scopes + + + .. py:method:: import_symbols_from_scope(other_scope: Scope) + + Links the symbols in another scope to the current scope, i.e. makes the imported symbols visible in the current + scope + + :param other_scope: The scope whose symbols should be imported + + + .. py:method:: add_global_symbol(symbol: Symbol) + + Helper function to add a symbol to the global scope(RootScope) + + + .. py:method:: add(symbol: Symbol) + + Adds a symbol to the current scope and set its parent scope to this scope + + + .. py:method:: find_current_level(name: str, predicate=None, visited_scopes: Set[Scope] = None) -> list[Symbol] + + Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that + are visible by an expression in the current scope. + + + .. py:method:: find_imported(name: str, predicate=None, visited_scopes: Set = None) -> list[Symbol] + + Finds the given name in all the imported scopes that are linked to the current scope. This can match many + valid symbols so it is up to the caller to choose the right one, however, the results are deduplicated by + checking that two symbols dealias to the same symbol. + + + .. py:method:: find_local(name: str) -> list[Symbol] + + Finds symbols in this scope's symbol table only + + + .. py:method:: find_from_parent(name: str, predicate=None) -> list[Symbol] + + + .. py:method:: find_multi_part_symbol(name: str, find_base_symbol: bool = False, predicate=None) + + Finds a potentially multi-part/qualified symbol (e.g. a.b.c) + + + .. py:method:: find(name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> list[Symbol] + + Entry point for the symbol finder. Finds the given name in this scope and any imported scopes + + Parameters: + name (str): The name to search for. + find_base_symbol (bool): Whether to find base symbols. + predicate (function): A function to filter symbols. + dealias (bool): Whether to dealias symbols. + + Returns: + list[Symbol]: A list of symbols that match the search criteria. + + + .. py:method:: find_single(name: str, find_base_symbol: bool = False, default=None, predicate=None) -> Optional[Symbol] + + + .. py:method:: find_user_type_scope(name, find_base_symbol: bool = False, default=None, predicate=None) -> Union[Scope, list[Scope]] + + Finds the scope of a user-defined type based on the given name. + :param name: The name of the type + :param find_base_symbol: Whether to find the base symbol or whether using scopes are acceptable results + :param default: The default value to return if no matches are found + :param predicate: Optional function to filter during the search + + :return: A single scope if find_base_symbol is True, or a list of scopes if find_base_symbol is False + + + .. py:method:: find_type(ttype, predicate=None, as_single=False) -> Optional[Scope] | list[Scope] + + Finds the scope for the given type in the current scope. The type scope might be different to the scope of the + type where the type was defined because of using statements. + A scope is created if one isn't visible in the current scope. + + :param ttype: The type to search for, CANNOT be a user type, use `find_user_type_scope` for that case + :param predicate: Optional function to filter during the search + :param as_single: Whether to return a single scope or a list of scopes + + :return: The scope if as_single is True or a list of scopes if as_single is False + + + .. py:method:: find_metatype(ttype, is_interface, is_enum) -> Scope + + + .. py:method:: str__symbols(level=0) + + Returns a string representation of all symbols in this scope and its children with indentation + + + .. py:method:: __str__(level=0) + + Return str(self). + + + +.. py:class:: ScopeAndSymbol(aliases: Optional[Aliases], ast_node) + + + Bases: :py:obj:`Scope`, :py:obj:`Symbol` + + Element that can be added as a child of a Scope + + .. py:method:: set_parent_scope(parent_scope: Scope) + + Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks + + + .. py:method:: __str__(level=0) + + Return str(self). + + + +.. py:class:: BuiltinObject(name: str, value=None) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: BuiltinFunction(name: str, input_types: list[solidity_parser.ast.types.Type] | None, output_types: list[solidity_parser.ast.types.Type] | None) + + + Bases: :py:obj:`Symbol` + + Element that can be added as a child of a Scope + + +.. py:class:: BuiltinValue(name: str, ttype: solidity_parser.ast.types.Type) + + + Bases: :py:obj:`Symbol` + + Element that can be added as a child of a Scope + + +.. py:function:: create_builtin_scope(key, value=None, values=None, functions=None) + + +.. py:function:: type_key(ttype) -> str + + +.. py:function:: meta_type_key(ttype) -> str + + +.. py:class:: RootScope(parser_version: solidity_parser.util.version_util.Version) + + + Bases: :py:obj:`Scope` + + Element that can be added as a child of a Scope + + +.. py:class:: FileScope(builder: Builder2, vfs: solidity_parser.filesys.VirtualFileSystem, source_unit_name: str, ast1_units: list[solidity_parser.ast.solnodes.SourceUnit]) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + .. py:method:: alias(source_unit_name: str) + :staticmethod: + + + .. py:method:: get_imported_source_unit(import_path: str) -> Optional[FileScope] + + + .. py:method:: set_parent_scope(parent_scope: Scope) + + Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks + + + +.. py:class:: LibraryScope(ast_node: solidity_parser.ast.solnodes.LibraryDefinition) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: ContractOrInterfaceScope(ast_node: Union[solidity_parser.ast.solnodes.ContractDefinition, solidity_parser.ast.solnodes.InterfaceDefinition]) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + .. py:method:: find_current_level(name: str, predicate=None, visited_scopes: Set = None, check_hierarchy=True) -> Optional[list[Symbol]] + + Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that + are visible by an expression in the current scope. + + + .. py:method:: find_in_contract_hierarchy(name: str, predicate, visited_scopes) + + + .. py:method:: get_supers() -> list[ContractOrInterfaceScope] + + + +.. py:class:: StructScope(ast_node: solidity_parser.ast.solnodes.StructDefinition) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: UserDefinedValueTypeScope(ast_node: solidity_parser.ast.solnodes.UserValueType) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: LibraryScope(ast_node: solidity_parser.ast.solnodes.LibraryDefinition) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: EnumScope(ast_node: solidity_parser.ast.solnodes.EnumDefinition) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: ModFunErrEvtScope(ast_node: Union[solidity_parser.ast.solnodes.FunctionDefinition, solidity_parser.ast.solnodes.EventDefinition, solidity_parser.ast.solnodes.ErrorDefinition, solidity_parser.ast.solnodes.ModifierDefinition]) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: ImportSymbol(aliases: Optional[Aliases], ast_node: solidity_parser.ast.solnodes.ImportDirective) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + .. py:method:: get_as_dealiased_symbols() -> list[Symbol] + + + .. py:method:: get_imported_scope() -> Optional[FileScope] + + + .. py:method:: _get_imported_symbols() -> list[Symbol] + + + .. py:method:: res_syms() -> list[Symbol] + + + .. py:method:: get_direct_children() -> Collection[Symbol] + + Get all children declared directly in this scope + + + .. py:method:: find(name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> Optional[list[Symbol]] + + Entry point for the symbol finder. Finds the given name in this scope and any imported scopes + + Parameters: + name (str): The name to search for. + find_base_symbol (bool): Whether to find base symbols. + predicate (function): A function to filter symbols. + dealias (bool): Whether to dealias symbols. + + Returns: + list[Symbol]: A list of symbols that match the search criteria. + + + .. py:method:: find_metatype(ttype, is_interface, is_enum) -> Scope + + + .. py:method:: find_local(name: str) -> Optional[list[Symbol]] + + Finds symbols in this scope's symbol table only + + + .. py:method:: find_first_ancestor(predicate, get_parent=None) + + Walks up the symbol tree and finds the first element that satisfies the given predicate + + :param predicate: a function that takes a Scopeable and returns a bool to determine if it matches + :param get_parent: a function that takes a Scopeable and returns its parent, defaults to the parent_scope of a + Scopeable + :return: the first Scopeable that satisfies the predicate + + + .. py:method:: find_first_ancestor_of(ttype: Union[Type, Tuple[Type]]) + + Find the first ancestor that is of the given type, note: these are python types and not solc types. + + :param ttype: e.g. ContractOrInterfaceScope + :return: the first ancestor that is of the given type + + + .. py:method:: find_imported(name: str, predicate=None, visited_scopes: Set = None) -> Optional[list[Symbol]] + + Finds the given name in all the imported scopes that are linked to the current scope. This can match many + valid symbols so it is up to the caller to choose the right one, however, the results are deduplicated by + checking that two symbols dealias to the same symbol. + + + .. py:method:: find_current_level(name: str, predicate=None, visited_scopes: Set = None) -> Optional[list[Symbol]] + + Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that + are visible by an expression in the current scope. + + + .. py:method:: find_single(name: str, find_base_symbol: bool = False, default=None, predicate=None) -> Optional[Symbol] + + + .. py:method:: find_from_parent(name: str, predicate=None) -> list[Symbol] + + + +.. py:class:: AliasImportSymbol(ast_node: solidity_parser.ast.solnodes.SymbolImportDirective, alias_index) + + + Bases: :py:obj:`ImportSymbol` + + Element that can be added as a child of a Scope + + .. py:method:: _get_imported_symbols() -> list[Symbol] + + + +.. py:class:: UnitImportSymbol(ast_node: solidity_parser.ast.solnodes.UnitImportDirective) + + + Bases: :py:obj:`ImportSymbol` + + Element that can be added as a child of a Scope + + .. py:method:: _get_imported_symbols() -> list[Symbol] + + + +.. py:class:: ProxyScope(name: str, base_scope: ScopeAndSymbol) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + .. py:method:: res_syms() -> list[Symbol] + + + +.. py:class:: UsingDirectiveScope(node: solidity_parser.ast.solnodes.UsingDirective) + + + Bases: :py:obj:`ScopeAndSymbol` + + Element that can be added as a child of a Scope + + +.. py:class:: UsingFunctionSymbol(target: ModFunErrEvtScope, override_type: solidity_parser.ast.types.Type) + + + Bases: :py:obj:`Symbol` + + Symbol for a function that was added to the current scope by a Solidity using statement. Solidity docs state that + all functions, even those that don't match the type specifier in the using statement have to be added to the scope + the using statement is declared in. This symbol type is required instead of the usual ModFunErrEvtSymbol as we need + to be able to associate the bound type from the using statement and the first parameter type of the "value" of this + symbol(i.e. the FunctionDefinition) may or may not be the same as the specified one. + + .. py:method:: res_syms() -> list[Symbol] + + + +.. py:class:: UsingOperatorSymbol(target: ModFunErrEvtScope, override_type: solidity_parser.ast.types.Type, operator: Union[solidity_parser.ast.solnodes.UnaryOpCode, solidity_parser.ast.solnodes.BinaryOpCode]) + + + Bases: :py:obj:`Symbol` + + Similar to UsingFunctionSymbol except for operator overloads + + .. py:method:: res_syms() -> list[Symbol] + + + +.. py:class:: Builder2(vfs: solidity_parser.filesys.VirtualFileSystem, parser_version: solidity_parser.util.version_util.Version = None) + + + .. py:class:: Context(file_scope, unit_scope) + + + + .. py:method:: process_or_find(loaded_source: solidity_parser.filesys.LoadedSource) + + + .. py:method:: process_or_find_from_base_dir(relative_source_unit_name: str | pathlib.Path) + + + .. py:method:: process_file(source_unit_name: str, source_units: list[solidity_parser.ast.solnodes.SourceUnit] = None) + + + .. py:method:: sort_ast_nodes(nodes) + + + .. py:method:: add_node_dfs(parent_scope, node, context: Context, build_skeletons, visit_index=0) + + Recursively traverse a node and its children and create symbols and scopes in a nested hierarchy + + This function adds newly created symbols and scopes to the given parent scope and does not return anything + + + .. py:method:: make_using_scope(node: solidity_parser.ast.solnodes.UsingDirective) + + + .. py:method:: make_var_decl_scope(node: solidity_parser.ast.solnodes.VarDecl) + + + .. py:method:: add_to_scope(parent: Scope, *children: Symbol) + + + .. py:method:: make_scope(node: solidity_parser.ast.nodebase.Node, name=None) + + + .. py:method:: make_symbol(node: solidity_parser.ast.nodebase.Node, sym_type=Symbol, name=None) + + + .. py:method:: scope_name(base_name, node) + + + .. py:method:: find_using_target_scope_and_name(current_scope, target_type: solidity_parser.ast.types.Type) + + + .. py:method:: make_proxy_scope(scope_name, creator_scope, base_scope, library_scope=None) + + + .. py:method:: get_proxy_scope_for_type(cur_scope, target_type, target_scope_name, target_type_scope, library_scope=None, check_lib=True) + + + .. py:method:: get_using_function_symbol_for_func(target_type, target_type_scope, symbol, operator=None) + + + .. py:method:: process_using_any_type(context: Context, node: solidity_parser.ast.solnodes.UsingDirective) + + + .. py:method:: process_using_library_type(context: Context, node: solidity_parser.ast.solnodes.UsingDirective) + + + .. py:method:: find_using_current_scope(node, context) + + + .. py:method:: process_using_functions(node: solidity_parser.ast.solnodes.UsingDirective, context: Context) + + + .. py:method:: process_using_directive(node: solidity_parser.ast.solnodes.UsingDirective, context: Context) + + + .. py:method:: make_symbols_for_node(node, context: Context, build_skeletons: bool, visit_index: int) + + + diff --git a/docs/source/autoapi/solidity_parser/ast/types/index.rst b/docs/source/autoapi/solidity_parser/ast/types/index.rst new file mode 100644 index 0000000..007c063 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/ast/types/index.rst @@ -0,0 +1,810 @@ +:py:mod:`solidity_parser.ast.types` +=================================== + +.. py:module:: solidity_parser.ast.types + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.types.Type + solidity_parser.ast.types.FloatType + solidity_parser.ast.types.VoidType + solidity_parser.ast.types.ArrayType + solidity_parser.ast.types.FixedLengthArrayType + solidity_parser.ast.types.VariableLengthArrayType + solidity_parser.ast.types.AddressType + solidity_parser.ast.types.ByteType + solidity_parser.ast.types.BytesType + solidity_parser.ast.types.IntType + solidity_parser.ast.types.PreciseIntType + solidity_parser.ast.types.BoolType + solidity_parser.ast.types.StringType + solidity_parser.ast.types.PreciseStringType + solidity_parser.ast.types.MappingType + solidity_parser.ast.types.UserType + solidity_parser.ast.types.BuiltinType + solidity_parser.ast.types.FunctionType + solidity_parser.ast.types.TupleType + solidity_parser.ast.types.MetaTypeType + solidity_parser.ast.types.VarType + solidity_parser.ast.types.AnyType + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.ast.types.UIntType + solidity_parser.ast.types.Bytes + solidity_parser.ast.types.ABIType + + + +.. py:class:: Type + + + Bases: :py:obj:`solidity_parser.ast.nodebase.Node`, :py:obj:`abc.ABC` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: scope + :type: Scope + + Shim for symbol table scoping. The scope field is also defined in solnodes1 Node but since this base class is + defined in this file, it must be defined here as well + + + .. py:method:: are_matching_types(target_param_types, actual_param_types) + :staticmethod: + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_array() -> bool + + + .. py:method:: is_byte_array() -> bool + + Check if the type is any type of byte array, e.g. bytes, bytes1, bytes32 + + + .. py:method:: is_byte_array_underlying() -> bool + + Check if this type is logically an array of bytes, e.g. bytes, bytes1, bytes32 and string + + + .. py:method:: is_string() -> bool + + + .. py:method:: is_function() -> bool + + + .. py:method:: is_int() -> bool + + + .. py:method:: is_bool() -> bool + + + .. py:method:: is_user_type() -> bool + + Check if the type is a user defined type, e.g. struct, enum, contract, etc + + + .. py:method:: is_address() -> bool + + + .. py:method:: is_mapping() -> bool + + + .. py:method:: is_byte() -> bool + + Check if the type is a single "byte" + + + .. py:method:: is_tuple() -> bool + + Check if the type is a tuple. These are synthetic types in Solidity but can be used in ASTs + + + .. py:method:: is_literal_type() -> bool + + Check if the type is a literal type, i.e. an inferred type from a constant number or string expression. + These are not real types in Solidity but are used in solc to aid type inference and optimization rules + + + .. py:method:: is_float() -> bool + + Check whether this type is a compile time float + + + .. py:method:: is_void() -> bool + + Check if the type represents a void return type. This isn't part of Solidity directly but is represented + when a function doesn't define any return types + + + .. py:method:: type_key() + + Returns a unique key for the type that can be used to cache types in the symbol table + + + .. py:method:: __str__() + :abstractmethod: + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: FloatType + + + Bases: :py:obj:`Type` + + This is not a real type in valid Solidity code but the Solidity compiler allows compile time expression evaluation + of floats + + .. py:attribute:: value + :type: float + + Since the value is always known at compile time, we have it here + + + .. py:method:: is_float() -> bool + + Check whether this type is a compile time float + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + +.. py:class:: VoidType + + + Bases: :py:obj:`Type` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:method:: is_void() -> bool + + Check if the type represents a void return type. This isn't part of Solidity directly but is represented + when a function doesn't define any return types + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: ArrayType + + + Bases: :py:obj:`Type` + + Single dimension array type with no size attributes + + .. py:attribute:: base_type + :type: Type + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: has_size() -> bool + + + .. py:method:: is_fixed_size() -> bool + + + .. py:method:: is_array() -> bool + + + +.. py:class:: FixedLengthArrayType + + + Bases: :py:obj:`ArrayType` + + Array type with a known length that is determined at compile time + + .. py:attribute:: size + :type: int + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: is_fixed_size() -> bool + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: VariableLengthArrayType + + + Bases: :py:obj:`ArrayType` + + Array type with a length that is determined at runtime + + .. py:attribute:: size + :type: Expr + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: AddressType + + + Bases: :py:obj:`Type` + + Solidity address/address payable type, functionally this is a uint160 + + .. py:attribute:: is_payable + :type: bool + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_address() -> bool + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: ByteType + + + Bases: :py:obj:`Type` + + Single 8bit byte type + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_byte() -> bool + + Check if the type is a single "byte" + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:function:: UIntType(size=256) + + +.. py:function:: Bytes(size=None) + + +.. py:class:: BytesType + + + Bases: :py:obj:`ArrayType` + + bytes type only (similar but not equal to byte[]/bytes1[]) + + .. py:attribute:: base_type + :type: Type + + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: IntType + + + Bases: :py:obj:`Type` + + Solidity native integer type of various bit length and signedness + + .. py:attribute:: is_signed + :type: bool + + Whether the type is a signed int or unsigned int + + + .. py:attribute:: size + :type: int + + Size of the type in bits + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_int() -> bool + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: PreciseIntType + + + Bases: :py:obj:`IntType` + + Solidity native integer type of various bit length and signedness + + .. py:attribute:: real_bit_length + :type: int + + + + .. py:method:: is_literal_type() -> bool + + Check if the type is a literal type, i.e. an inferred type from a constant number or string expression. + These are not real types in Solidity but are used in solc to aid type inference and optimization rules + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: BoolType + + + Bases: :py:obj:`Type` + + Solidity native boolean type + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_bool() -> bool + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: StringType + + + Bases: :py:obj:`ArrayType` + + Solidity native string type + + .. py:attribute:: base_type + :type: Type + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_string() -> bool + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: PreciseStringType + + + Bases: :py:obj:`StringType` + + String literal type that has a known length at compile time + + .. py:attribute:: real_size + :type: int + + + + .. py:method:: is_literal_type() -> bool + + Check if the type is a literal type, i.e. an inferred type from a constant number or string expression. + These are not real types in Solidity but are used in solc to aid type inference and optimization rules + + + .. py:method:: has_size() -> bool + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: MappingType + + + Bases: :py:obj:`Type` + + Type that represents a function mapping definition + + For example in the mapping '(uint x => Campaign c)', src would be 'unit' and the dst would be 'Campaign', + src_key would be 'x' and dst_key would be 'c' + + .. py:attribute:: src + :type: Type + + + + .. py:attribute:: dst + :type: Type + + + + .. py:attribute:: src_name + :type: Ident + + + + .. py:attribute:: dst_name + :type: Ident + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: is_mapping() -> bool + + + .. py:method:: flatten() -> list[Type] + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:class:: UserType + + + Bases: :py:obj:`Type` + + Type invoked using a valid Solidity reference, e.g. a class, contract, library, enum, etc name. + This is an "unlinked" type, e.g. it has no underlying AST node backing it and has no corresponding context other + than the scope it was declared in. For AST2 use solnodes2.ResolvedUserType instead. + + .. py:attribute:: name + :type: Ident + + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: BuiltinType + + + Bases: :py:obj:`Type` + + Type representing types of Solidity builtin objects, e.g. the type of the 'msg' or 'abi' objects in the expressions + `msg.sender` or `abi.decode(...)` + + .. py:attribute:: name + :type: str + + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + +.. py:function:: ABIType() -> BuiltinType + + +.. py:class:: FunctionType + + + Bases: :py:obj:`Type` + + Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that + clients can traverse all child and parent nodes. + + .. py:attribute:: inputs + :type: list[Type] + + + + .. py:attribute:: outputs + :type: list[Type] + + + + .. py:attribute:: modifiers + :type: list[Modifier] + + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_function() -> bool + + + .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: __str__() + + Return str(self). + + + .. py:method:: type_key() + + Returns a unique key for the type that can be used to cache types in the symbol table + + + +.. py:class:: TupleType + + + Bases: :py:obj:`Type` + + Type of a tuple of elements. This is not a real Solidity type but is used to represent the type of tuple expressions + (e.g. desugaring) in the AST + + .. py:attribute:: ttypes + :type: list[Type] + + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: is_tuple() -> bool + + Check if the type is a tuple. These are synthetic types in Solidity but can be used in ASTs + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: MetaTypeType + + + Bases: :py:obj:`Type` + + Metatype Solidity type, i.e. type(X). This type has a few builtin fields such as min, max, name, creationCode, + runtimeCode and interfaceId + + .. py:attribute:: ttype + :type: Type + + + + .. py:method:: is_builtin() -> bool + + Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc + + + .. py:method:: code_str() + + Returns the string representation of the type in Solidity syntax + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: VarType + + + Bases: :py:obj:`Type` + + Type that wasn't explicitly identified in the code + + This type should not be used without running a subsequent type inference pass. + + An example variable declaration that would use this type symbol: 'var (, mantissa, exponent) = ... ' + + .. py:method:: __str__() + + Return str(self). + + + +.. py:class:: AnyType + + + Bases: :py:obj:`Type` + + Type that is used only in 'using' declarations to specify that the declaration is overriding all possible types + + For example in the declaration 'using SomeLibrary for *', the overriden type here is AnyType(every type + that is imported from SomeLibrary) + + .. py:method:: __str__() + + Return str(self). + + + diff --git a/docs/source/autoapi/solidity_parser/collectors/collector/index.rst b/docs/source/autoapi/solidity_parser/collectors/collector/index.rst new file mode 100644 index 0000000..4802f10 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/collectors/collector/index.rst @@ -0,0 +1,26 @@ +:py:mod:`solidity_parser.collectors.collector` +============================================== + +.. py:module:: solidity_parser.collectors.collector + + +Module Contents +--------------- + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.collectors.collector.get_minor_ver + solidity_parser.collectors.collector.collect_top_level_objects + + + +.. py:function:: get_minor_ver(txt) + + +.. py:function:: collect_top_level_objects(stream, vers, debug=False) + + diff --git a/docs/source/autoapi/solidity_parser/collectors/index.rst b/docs/source/autoapi/solidity_parser/collectors/index.rst new file mode 100644 index 0000000..8faa993 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/collectors/index.rst @@ -0,0 +1,19 @@ +:py:mod:`solidity_parser.collectors` +==================================== + +.. py:module:: solidity_parser.collectors + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + collector/index.rst + v000/index.rst + v060/index.rst + v070/index.rst + v080/index.rst + + diff --git a/docs/source/autoapi/solidity_parser/collectors/v000/index.rst b/docs/source/autoapi/solidity_parser/collectors/v000/index.rst new file mode 100644 index 0000000..9ba96ca --- /dev/null +++ b/docs/source/autoapi/solidity_parser/collectors/v000/index.rst @@ -0,0 +1,40 @@ +:py:mod:`solidity_parser.collectors.v000` +========================================= + +.. py:module:: solidity_parser.collectors.v000 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.collectors.v000.TopLevelObjectCollector + solidity_parser.collectors.v000.TopLevelObject + + + + +.. py:class:: TopLevelObjectCollector + + + .. py:method:: reset() + + + .. py:method:: visit_terminal_node(node, parent=None) + + + .. py:method:: newline() + + + .. py:method:: collect_lines() + + + +.. py:class:: TopLevelObject(name, content, type) + + + diff --git a/docs/source/autoapi/solidity_parser/collectors/v060/index.rst b/docs/source/autoapi/solidity_parser/collectors/v060/index.rst new file mode 100644 index 0000000..297dad3 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/collectors/v060/index.rst @@ -0,0 +1,35 @@ +:py:mod:`solidity_parser.collectors.v060` +========================================= + +.. py:module:: solidity_parser.collectors.v060 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.collectors.v060.TopLevelObjectCollectorV060 + + + + +.. py:class:: TopLevelObjectCollectorV060 + + + Bases: :py:obj:`solidity_parser.collectors.v000.TopLevelObjectCollector` + + .. py:attribute:: TOP_LEVEL_OBJECT_TYPES + + + + .. py:method:: visit(node, parent=None) + + + .. py:method:: collect(stream) + + + diff --git a/docs/source/autoapi/solidity_parser/collectors/v070/index.rst b/docs/source/autoapi/solidity_parser/collectors/v070/index.rst new file mode 100644 index 0000000..c5267d6 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/collectors/v070/index.rst @@ -0,0 +1,35 @@ +:py:mod:`solidity_parser.collectors.v070` +========================================= + +.. py:module:: solidity_parser.collectors.v070 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.collectors.v070.TopLevelObjectCollectorV070 + + + + +.. py:class:: TopLevelObjectCollectorV070 + + + Bases: :py:obj:`solidity_parser.collectors.v000.TopLevelObjectCollector` + + .. py:attribute:: TOP_LEVEL_OBJECT_TYPES + + + + .. py:method:: visit(node, parent=None) + + + .. py:method:: collect(stream) + + + diff --git a/docs/source/autoapi/solidity_parser/collectors/v080/index.rst b/docs/source/autoapi/solidity_parser/collectors/v080/index.rst new file mode 100644 index 0000000..a158f4d --- /dev/null +++ b/docs/source/autoapi/solidity_parser/collectors/v080/index.rst @@ -0,0 +1,35 @@ +:py:mod:`solidity_parser.collectors.v080` +========================================= + +.. py:module:: solidity_parser.collectors.v080 + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.collectors.v080.TopLevelObjectCollectorV080 + + + + +.. py:class:: TopLevelObjectCollectorV080 + + + Bases: :py:obj:`solidity_parser.collectors.v000.TopLevelObjectCollector` + + .. py:attribute:: TOP_LEVEL_OBJECT_TYPES + + + + .. py:method:: visit(node, parent=None) + + + .. py:method:: collect(stream) + + + diff --git a/docs/source/autoapi/solidity_parser/errors/index.rst b/docs/source/autoapi/solidity_parser/errors/index.rst new file mode 100644 index 0000000..b6fe4cf --- /dev/null +++ b/docs/source/autoapi/solidity_parser/errors/index.rst @@ -0,0 +1,43 @@ +:py:mod:`solidity_parser.errors` +================================ + +.. py:module:: solidity_parser.errors + + +Module Contents +--------------- + +.. py:exception:: AntlrParsingError(unit_name: str, version: solidity_parser.util.version_util.Version, input_src: str, details) + + + Bases: :py:obj:`Exception` + + Common base class for all non-exit exceptions. + + .. py:attribute:: Detail + + + + +.. py:data:: CPEArgs + :type: TypeAlias + + message, source_unit_name, line_number, line_offset + + +.. py:exception:: CodeProcessingError(message: str, source_unit_name: str, line_number, line_offset) + + + Bases: :py:obj:`Exception` + + Common base class for all non-exit exceptions. + + +.. py:exception:: UnexpectedCodeProcessingError(message: str, source_unit_name: str, line_number: int, line_offset: int, root_cause: Exception) + + + Bases: :py:obj:`CodeProcessingError` + + Common base class for all non-exit exceptions. + + diff --git a/docs/source/autoapi/solidity_parser/filesys/index.rst b/docs/source/autoapi/solidity_parser/filesys/index.rst new file mode 100644 index 0000000..ad71b44 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/filesys/index.rst @@ -0,0 +1,178 @@ +:py:mod:`solidity_parser.filesys` +================================= + +.. py:module:: solidity_parser.filesys + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.filesys.Source + solidity_parser.filesys.StandardJsonInput + solidity_parser.filesys.LoadedSource + solidity_parser.filesys.VirtualFileSystem + + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.filesys.ImportMapping + + +.. py:class:: Source + + + Structure of a source unit defined in the standard JSON input + + .. py:attribute:: urls + :type: Optional[List[str]] + + + + .. py:attribute:: content + :type: str + + + + +.. py:class:: StandardJsonInput + + + Solidity standard JSON input see: + https://docs.soliditylang.org/en/v0.8.25/using-the-compiler.html#compiler-api + + .. py:attribute:: sources + :type: Dict[str, Source] + + + + +.. py:class:: LoadedSource + + + Source unit loaded inside the virtual filesystem + + .. py:property:: ast + :type: List[solidity_parser.ast.solnodes.SourceUnit] + + Property for getting the AST from the source code lazily + + + .. py:attribute:: source_unit_name + :type: str + + The computed source unit name, see the solidity docs for how this is computed + + + .. py:attribute:: contents + :type: str + + Source code + + + .. py:attribute:: origin + :type: Optional[pathlib.Path] + + Path to the source unit on disk, if it was loaded from disk + + + .. py:attribute:: ast_creator_callback + :type: Optional[Callable[[str], List[solidity_parser.ast.solnodes.SourceUnit]]] + + Optional function for changing the AST creation method, e.g. for testing and forcing the parser version + + + +.. py:data:: ImportMapping + + An import remapping for changing the source unit name before the import is resolved + + +.. py:class:: VirtualFileSystem(base_path: str | pathlib.Path, cwd: str | pathlib.Path = None, include_paths: List[str | pathlib.Path] = None, compiler_version: solidity_parser.util.version_util.Version = None) + + + This is the "virtual file system" defined in the Solidity docs and implemented in solc. The idea is to abstract + away the specifics of how the sources are stored, such as on disk or in memory and the paths used in the source + files to resolve imports. The code is not ideal but it emulates the behaviour of the c++ code of solc. + + https://docs.soliditylang.org/en/v0.8.17/path-resolution.html + + .. py:property:: base_path + + + .. py:property:: include_paths + + + .. py:method:: process_cli_input_file(file_path) + + + .. py:method:: process_standard_json(path: str) + + + .. py:method:: parse_import_remappings(remappings_file_path) + + + .. py:method:: add_import_remapping(context, prefix, target) + + + .. py:method:: lookup_import_path(import_path: str, importer_source_unit_name: str = None) -> LoadedSource + + + .. py:method:: _add_loaded_source(source_unit_name: str, source_code: str, creator=None, origin=None) -> LoadedSource + + + .. py:method:: _read_file(path: str, is_cli_path=True) -> str + + + .. py:method:: _cli_path_to_source_name(input_file_path) -> str + + Computes the source name for a source file supplied via command line invocation of solc + + + .. py:method:: _norm_vfs_path(path: Union[str, pathlib.Path]) -> str + + Path normalisation according to solidity lang docs + + + .. py:method:: _read_file_callback(su_name: str, base_dir: str, include_paths: List[str]) -> Tuple[str, str] + + + .. py:method:: _remap_import(source_unit_name: str, importer_source_unit_name: str) -> str + + Takes a source unit name and checks if it should be remapped + Note: do not pass an import path as the source unit name + + + .. py:method:: _compute_source_unit_name(path: str, importer_source_unit_name: str) -> str + + + .. py:method:: _path_to_generic_string(path: Union[pathlib.Path, str]) -> str + :staticmethod: + + + .. py:method:: _clean_path(*parts: List[str]) -> str + :staticmethod: + + + .. py:method:: _strip_prefix(prefix, path) -> Optional[pathlib.Path] + :staticmethod: + + + .. py:method:: _remove_last_path_segment(path: str) -> str + :staticmethod: + + + .. py:method:: _is_relative_import(path: str) -> bool + :staticmethod: + + + diff --git a/docs/source/autoapi/solidity_parser/index.rst b/docs/source/autoapi/solidity_parser/index.rst new file mode 100644 index 0000000..2c53ef6 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/index.rst @@ -0,0 +1,27 @@ +:py:mod:`solidity_parser` +========================= + +.. py:module:: solidity_parser + + +Subpackages +----------- +.. toctree:: + :titlesonly: + :maxdepth: 3 + + ast/index.rst + collectors/index.rst + util/index.rst + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + errors/index.rst + filesys/index.rst + + diff --git a/docs/source/autoapi/solidity_parser/util/index.rst b/docs/source/autoapi/solidity_parser/util/index.rst new file mode 100644 index 0000000..59f2aa5 --- /dev/null +++ b/docs/source/autoapi/solidity_parser/util/index.rst @@ -0,0 +1,15 @@ +:py:mod:`solidity_parser.util` +============================== + +.. py:module:: solidity_parser.util + + +Submodules +---------- +.. toctree:: + :titlesonly: + :maxdepth: 1 + + version_util/index.rst + + diff --git a/docs/source/autoapi/solidity_parser/util/version_util/index.rst b/docs/source/autoapi/solidity_parser/util/version_util/index.rst new file mode 100644 index 0000000..a3e6e9c --- /dev/null +++ b/docs/source/autoapi/solidity_parser/util/version_util/index.rst @@ -0,0 +1,83 @@ +:py:mod:`solidity_parser.util.version_util` +=========================================== + +.. py:module:: solidity_parser.util.version_util + + +Module Contents +--------------- + +Classes +~~~~~~~ + +.. autoapisummary:: + + solidity_parser.util.version_util.Version + + + +Functions +~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.util.version_util.extract_version_from_src_input + solidity_parser.util.version_util.parse_version + + + +Attributes +~~~~~~~~~~ + +.. autoapisummary:: + + solidity_parser.util.version_util.VERSION_PATTERN + + +.. py:data:: VERSION_PATTERN + + + +.. py:class:: Version + + + .. py:attribute:: major + :type: int + + + + .. py:attribute:: minor + :type: int + + + + .. py:attribute:: patch + :type: int + + + + .. py:method:: is_enforced_in(testing_version: Version) -> bool + + Tests whether a feature that was introduced in the given testing_version is enforced in the current version + E.g. if a feature is only available in or after version 8.0.1 but the current version is 7.0.0, that feature + should not be enforced and this function returns False + + + .. py:method:: __str__() + + Return str(self). + + + +.. py:function:: extract_version_from_src_input(txt: str) -> Version + + Extracts the solidity version from the input source code + :param txt: the entire source file + + +.. py:function:: parse_version(ver_text: str) -> Version + + Parses a solidity version string into a Version object + :param ver_text: the version string only, e.g. "0.6.12" + + diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..b9cbfb3 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,40 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'SOLP' +copyright = '2024, Zellic' +author = 'Zellic' +release = '0.1.16' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx_autodoc_typehints', + 'sphinx.ext.autosummary', + 'autoapi.extension' +] + +autoapi_dirs = ['../../src'] +autoapi_keep_files = True +autoapi_ignore = ['*/grammar/*'] + +templates_path = ['_templates'] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'furo' +html_static_path = ['_static'] + +import os +import sys +sys.path.insert(0, os.path.abspath('../../src')) \ No newline at end of file diff --git a/docs/source/getstarted/clients.rst b/docs/source/getstarted/clients.rst new file mode 100644 index 0000000..2e206eb --- /dev/null +++ b/docs/source/getstarted/clients.rst @@ -0,0 +1,43 @@ +Client Setup +=============== + +.. note:: + Before installing SOLP, follow the instructions in the :doc:`prereq` document.. + +Who is this document for? +^^^^^^^^^^^^^^^^^^^^^^^^^ +People who want to use SOLP in their own projects + +Setup a Virtual Environment (optional) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It's always recommended to setup a virtual environment(venv) instead of installing the package in the global pip cache. + +Create a venv called `venv`: + +.. code-block:: bash + + python -m venv venv + +Then activate the venv: + +Unix: + +.. code-block:: bash + + ./venv/Scripts/activate + +Windows: + +.. code-block:: powershell + + .\venv\Scripts\activate + +Installing +^^^^^^^^^^ + +.. code-block:: bash + + pip install + +Where `` is a path to a clone of the repository or: `git+https://github.com/Zellic/solidity-parser.git` diff --git a/docs/source/getstarted/index.rst b/docs/source/getstarted/index.rst new file mode 100644 index 0000000..63bfa99 --- /dev/null +++ b/docs/source/getstarted/index.rst @@ -0,0 +1,12 @@ +Getting Started +=============== + +.. toctree:: + :maxdepth: 1 + + prereq + clients + quickstart + twoASTs + sourcecode + scopes diff --git a/docs/source/getstarted/prereq.rst b/docs/source/getstarted/prereq.rst new file mode 100644 index 0000000..88f0426 --- /dev/null +++ b/docs/source/getstarted/prereq.rst @@ -0,0 +1,40 @@ +Prerequisites +============= + +Software Requirements +--------------------- + +Python 3.11+ +~~~~~~~~~~~~~ + +To run this software, you need Python version 3.11 or higher installed on your system. If you haven't installed Python +yet, you can download it from the official Python website: + + https://www.python.org/downloads/ + +Java 8+ (for ANTLR grammar stub generation) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For generating ANTLR grammar stubs, you need Java version 8 or higher installed on your system. There are multiple +implementations available but we recommend: + + https://adoptopenjdk.net/releases.html + +After installing Java, make sure to set the `JAVA_HOME` environment variable to the JDK installation directory and +`PATH` to the `bin` directory of the JDK installation. + +Once you have both Python and Java installed, you can proceed with the installation of the software. + +Resolving Conflicts +^^^^^^^^^^^^^^^^^^^ + +Currently SOLP is only available on `Github `_ and when installed, has the +module name `solidity-parser`. Unfortunately there is already a module with the same name in PyPI which can cause be the +cause of problems if accidentally installed. + +Therefore it's recommended that you first run this command globally (outside of an activated virtual environment) to +remove packages which can conflict with SOLP. + +.. code-block:: bash + + pip uninstall solidity-parser diff --git a/docs/source/getstarted/quickstart.rst b/docs/source/getstarted/quickstart.rst new file mode 100644 index 0000000..4e987a8 --- /dev/null +++ b/docs/source/getstarted/quickstart.rst @@ -0,0 +1,312 @@ +Quick Start +=========== + +Welcome to the SOLP docs! This guide will give you a rundown of how to load, parse, analyse and manipulate your Solidity +code using SOLP. + +Before starting, make you've installed the SOLP library by following :doc:`clients`. + +Toy Project +----------- + +This tutorial uses the ``example/project`` Solidity project provided in the SOLP repository. It includes examples of +`imports: `_ and +`solc remappings `_ as well regular Solidity code. + +Here is the contract we'll be parsing. As you can see, it defines contract TestContract, which inherits from Ownable, +uses the inherited ``onlyOwner`` modifier and does some simple function calls: + +.. code-block:: solidity + :caption: TestContract.sol + + // SPDX-License-Identifier: UNLICENSED + pragma solidity ^0.8.0; + + import "@openzeppelin/access/Ownable.sol"; + + contract MyContract is Ownable { + uint256 public myVariable; + + function setMyVariable(uint256 newValue) public onlyOwner { + myVariable = newValue; + } + + function getMyVariable() public view returns (uint256) { + return myVariable; + } + + function addToVariable(uint256 value) public onlyOwner { + myVariable += value; + } + + function addToVariable2(uint256 value) public onlyOwner { + myVariable += value; + } + + function addPositive(uint256 value) public onlyOwner { + require(value > 0); + this.addToVariable2(value); + } + } + + +The ``example/librarycall`` project has an example of the +`using directive `_ and will be used later on in this +tutorial. + +.. image:: ../../imgs/exampledir.png + +Copy the ``example`` folder to somewhere on your machine. ``example/project`` will be the **project directory** from now +on. + +Creating a Virtual File System(VFS) +----------------------------------- + +For SOLP to understand the code in the example project, it has to know where the source files, library files and import +remappings are located and how the project is structured. + +The :py:class:`solidity_parser.filesys.VirtualFileSystem` object takes these options, handles path mappings, reads +the files and generates an unrefined AST. + +.. code-block:: python + :linenos: + + from solidity_parser import filesys + + project_dir = Path('./project') + + vfs = filesys.VirtualFileSystem( + project_dir, + None, + [project_dir / 'contracts', project_dir / 'lib'], + None + ) + +Replace ``./project`` on line 3 with your **project directory** + +Now give the VFS the remapping file + +.. code-block:: python + + remappings_file = project_dir / 'remappings.txt' + if remappings_file.exists(): + vfs.parse_import_remappings(remappings_file) + + +Getting AST1 Nodes +------------------ + +Remember how I mentioned that the VFS gives us an unrefined AST? This form of AST is known as **AST1** and the VFS can +give us this very easily. We can then, for example, get the header information for ``MyContract`` in ``TestContract.sol`` + +.. code-block:: python + + from solidity_parser.ast import solnodes + + loaded_src = vfs.process_cli_input_file('project/contracts/TestContract.sol') + ast_nodes = loaded_src.ast + + my_contract = [c for c in ast_nodes if isinstance(c, solnodes.ContractDefinition)][0] + + print(my_contract.name) + print(my_contract.inherits[0].name) + +While this might be useful, there are two limitations here: + +* We can't get a reference to the ``ContractDefinition`` for ``Ownable`` (the inherited contract), i.e. we only know + it's name at this point but not where it comes from or what it contains +* We have to load each source file one at a time instead of letting SOLP discover its way through the project + + +Getting AST2 Nodes +------------------ + +To resolve the first issue above, we're going to get a more advanced version of the AST called **AST2**. The +:py:class:`SymtabBuilder ` and :py:class:`AST2Builder ` +classes make this super simple! + +.. code-block:: python + :linenos: + + from solidity_parser.ast import symtab, ast2builder + + sym_builder = symtab.Builder2(vfs) + file_sym_info = sym_builder.process_or_find_from_base_dir('TestContract.sol') + + ast2_builder = ast2builder.Builder() + ast2_builder.enqueue_files([file_sym_info]) + + ast2_builder.process_all() + +In this example we only loaded entry point(``TestContract.sol``) but during symbol table building, the ``Ownable.sol`` +file was also parsed. This makes it available later for AST2 building. + +Now get the AST2 nodes using :py:meth:`Builder.get_top_level_units `: +this includes the ``Ownable`` and ``MyContract`` contracts, but to demonstrate the tree searching behavior, we'll use +``MyContract`` only. + +.. code-block:: python + + from solidity_parser.ast import solnodes2 + + my_contract: solnodes2.ContractDefinition = [u for u in ast2_builder.get_top_level_units() if str(u.name) == 'MyContract'][0] + ownable_type: solnodes2.ResolvedUserType = my_contract.inherits[0].name + ownable_contract: solnodes2.ContractDefinition = ownable_type.value.x + +.. note:: These AST2 objects come from the :py:mod:`solidity_parser.ast.solnodes2` module instead of the AST1 :py:mod:`solidity_parser.ast.solnodes` module + +Analysing the AST +----------------- + +Let's now collect the functions defined by ``Ownable`` and compute a measure of complexity based on the number of calls +it makes. This could be part of a tool to generate code insights or highlight areas that look overly complicated and +need to be refactored. + +.. code-block:: python + :linenos: + + ownable_functions = [p for p in ownable_contract.parts if isinstance(p, solnodes2.FunctionDefinition)] + + for f in ownable_functions: + if not f.code: + continue + + all_calls = f.code.get_all_children(lambda c: isinstance(c, solnodes2.Call)) + complexity = len(list(all_calls)) + + print(f'{f.descriptor()} has complexity {complexity}') + +The benefits of using an AST structure mean we can search through the entire code of each function easily and extract +the data we want. + +Working with Nodes +------------------ + +SOLP lists the :py:mod:`AST1 ` and :py:mod:`AST2 ` node +definitions as Python dataclasses and provides convenience features to make the objects easier to work with. Some common +ones are: + +Parenting +^^^^^^^^^ + +All nodes have a ``parent`` attribute that points to the logical parent of the node, i.e. where it's declared in the +Solidity source code. The exact type of the parent differs depending on the node, for example + +* a FunctionDefinition can have a Contract, Interface, Library or FileDefinition parent depending on where it was declared +* an Expr can have a parent that is another Expr or a Stmt + +Equality by Value +^^^^^^^^^^^^^^^^^ + +Despite storing location and parent information, two nodes representing the same data can be compared using the ``==`` operator, +even when they are in different places in the AST. Here is a simple analysis that checks for functions that contain +duplicated code. See how we can also check that the two functions are different(i.e. have a different names and signatures) +but also check the ``code`` nodes in an intuitive way. + +.. code-block:: python + + import itertools + + for f1, f2 in itertools.combinations(funcs, r=2): + if f1 != f2 and f1.code == f2.code: + print(f'{f1.descriptor()} == {f2.descriptor()}') + + +Quick Consistent Hashes +^^^^^^^^^^^^^^^^^^^^^^^ + +Often we want to use nodes as keys in dicts so we need a hash function. Python dataclasses don't support this for +definitions with mutable attributes or lists but SOLP does. Let's find which variables are set by which functions + +.. code-block:: python + + def count_var_uses(functions: list[solnodes2.FunctionDefinition]): + var_stores = defaultdict(list) + for func in functions: + for store in func.code.get_all_children(lambda c: isinstance(c, solnodes2.StateVarStore)): + var_stores[store.state_var()].append(func) + return var_stores + +This operation is also surprisingly fast as the ``state_var`` hash is cached until it's modified! This pattern is very +useful for creating call graphs, e.g. mappings of the type ``FunctionDefinition -> list[FunctionDefinitions]`` + +Deep Copy +^^^^^^^^^ + +Entire node trees can be passed to :py:func:`copy.deepcopy` to produce a full identical tree + +.. code-block:: python + + from copy import deepcopy + type2 = deepcopy(ownable_type) + + assert type2 == ownable_type + assert hash(type2) == hash(ownable_type) + + +Mutability +^^^^^^^^^^ + +Nodes are mutable: they can be modified and inserted into a different branch of the AST. Let's say you wanted to create +a transformer that computes and inlines constant expressions: + +.. code-block:: python + + def compute_constant_stores(func: solnodes2.FunctionDefinition): + store_types = (solnodes2.LocalVarStore, solnodes2.StateVarStore, solnodes2.ArrayStore, solnodes2.MappingStore) + + for store in func.code.get_all_children(lambda c: isinstance(c, store_types)): + stored_expr = store.value + if is_constant_expr(stored_expr): + constant_value = compute_constant_value(stored_expr) + constant_type = stored_expr.type_of() + store.value = solnodes2.Literal(constant_value, constant_type) + + +Python encourages duck typing and SOLP is designed to take advantage of it! The ``value`` attribute is always an ``Expr`` +for store operations, so we can handle all of these different types of store operations at once. + +Code Printing +------------- + +Let's say we made SOLP change the function call to ``addToVariable2`` in ``addPositive`` so that it now calls ``addToVariable``: + +.. code-block:: python + + add_positive_func = [func for func in my_contract.parts if isinstance(func, solnodes2.FunctionDefinition) and func.name.text == 'addPositive'][0] + + print(add_positive_func.code.code_str()) + + func_call = list(add_positive_func.code.get_all_children(lambda c: isinstance(c, solnodes2.FunctionCall)))[0] + func_call.name = solnodes2.Ident('addToVariable') + + print(add_positive_func.code.code_str()) + +This prints: + +.. code-block:: solidity + + { + require(value > 0); + this.addToVariable2(value); + } + { + require(value > 0); + this.addToVariable(value); + } + +``code_str`` can be called on any AST2 node, not just the ``code`` of the function. Because the code is parsed by SOLP, +the output formatting and exact form might not match the original source code, but the result will always be +semantically equal. + +If you need to maintain the original format of the code, there are ways to do this using the +:doc:`line data ` of the node. + +Next Steps +---------- + +This document serves as a primer to SOLP and working with the AST of Solidity programs. You can use the patterns given +here to implement powerful analyses, reason about and generate insights for your own tools. + +Naturally, there are lots of SOLP details that have been omitted that you might come across. The remaining sections in +the Getting Started tab fill in these gaps. Enjoy! diff --git a/docs/source/getstarted/scopes.rst b/docs/source/getstarted/scopes.rst new file mode 100644 index 0000000..dafaa30 --- /dev/null +++ b/docs/source/getstarted/scopes.rst @@ -0,0 +1,132 @@ +Symbols and Scopes +================== + +The :py:mod:`scoping module ` for AST1 is a major service in SOLP that provides scope trees +and tables to the :py:class:`AST2 Builder `. + +We'll work through using this API by considering a service that takes `LSP `_ +requests to find the definition of whatever you click on in the IDE(e.g. Visual Studio Code). This won't be the full plugin: +just the SOLP code required to make it work. + +Line to Node +------------ + +As we saw in the :doc:`sourcecode` tutorial, SOLP lets us map nodes to source code locations easily. Usually IDEs make +requests based on the line and column number and expect the language tool to figure out what is at that location. + +Let's make a function that does that: it should make a list of possible AST1 nodes and a source location and determine the +exact node that is defined at that source location. The :py:meth:`SourceLocationSpan.does_contain() `, +available for every node with :py:meth:`get_source_span() ` will work +for this. + +All we need to do is recurse until we find the deeepest node that is defined in that span: + +.. code-block:: python + + def get_containing_ast_node(src_loc: SourceLocation, nodes: List[Node]) -> Optional[Node]: + for n in nodes: + if not n: + continue + n_span = n.get_source_span() + if n_span.does_contain(src_loc): + children = list(n.get_children()) + return get_containing_ast_node(src_loc, children) if children else n + return None + +Idents Only +----------- + +If this node is an identifier then we can do the reference search: + +.. code-block:: python + + if isinstance(ast1_node, Ident): + return get_definitions_for_node(ast1_node) + +Qualified vs Unqualified References +----------------------------------- + +The reference could be qualified, e.g. ``x.y`` or unqualified ``y``. The way in which ``y`` is accessed changes the +scopes we need to search. The differences between the cases are: + +* Unqualified: search for ``y`` in the :py:attr:`node scope ` of ``ast1_node`` +* Qualified: figure out the type of ``x``, search for that type in ``ast1_node.scope`` to find a ``Type Scope`` and search for ``y`` in that type scope + +Qualified lookups are modelled by the :py:class:`GetMember ` node in AST1. So +far we know that ``y`` is an :py:class:`Ident `, we need to determine what type of +lookup it is: + +.. code-block:: python + + if isinstance(ast1_node.parent, solnodes.GetMember): + # qualified + else: + # unqualified + +Check the parent! Qualified lookups have a base, ``x`` and the member is ``y``. + +Unqualified +^^^^^^^^^^^ + +.. code-block:: python + + symbols = ast1_node.scope.find(ast1_node.text) + for s in symbols: + for rs in s.res_syms(): + links.append(get_symbol_link(rs)) + +.. note:: The ``get_symbol_link`` function will be shown later + +*What does ``res_syms`` do? Why not just return the symbols found in the scope?* + +This is because SOLP has different types of symbols: some are actual symbols based on elements in the real source code +and some are created because of *links* created from inherits and imports or using statements. Since we want to locate +source code elements, we need to get the underlying symbol(s). + +Qualified +^^^^^^^^^ + +To get the base type of ``x``, we're going to cheat a bit and use the :py:class:`TypeHelper ` +that's built into the AST2 builder. + +.. code-block:: python + + type_helper = ast2builder.type_helper + + base_obj: solnodes1.AST1Node = ast1_node.parent.obj_base + base_type: solnodes2.Types = type_helper.get_expr_type(base_obj) + +This bit of code is tricky so it's best to use Python typehints here. The :py:class:`Type ` +returned from the TypeHelper is an :py:attr:`AST2 type `. + +This AST2 type is passed back to the type helper to find the scopes to search: + +.. code-block:: python + + base_scopes = type_helper.scopes_for_type(base_obj, base_type) + +Search these scopes in the same way as the previous case: + +.. code-block:: python + + for scope in base_scopes: + symbols = scope.find(n.text) + for s in symbols: + for rs in s.res_syms(): + links.append(get_symbol_link(rs)) + +get_symbol_link +--------------- + +The exact details of ``get_symbol_link`` depend on what LSP framework you're using. This guide will show you what it +needs to extract for the + + + + + + + + + + diff --git a/docs/source/getstarted/sourcecode.rst b/docs/source/getstarted/sourcecode.rst new file mode 100644 index 0000000..e165db4 --- /dev/null +++ b/docs/source/getstarted/sourcecode.rst @@ -0,0 +1,209 @@ +Working with Source Code +======================== + +SOLP let's you create powerful analyses for Solidity source code. This is enough for some tools, however, others need to +edit the source text or insert the results of the analysis in the code. + +This document will lead you through building a tool that inserts comments above functions with analysis insights from +an AI depending on the user's criteria. + +General Strategy +---------------- + +One important thing that has to be reiterated is that AST2 can contain nodes that weren't in the original source code. +Check out the :doc:`twoASTs` document for why this is. + +This means you have to go through the AST1 nodes, as they are guaranteed to be from the source text, and use the tagged +source location info for modifications. You can still use AST2 for analyses but you have to use AST1 nodes to write the +output. + +Setup +----- + +Create the basic SOLP client setup to read the source files. We have to setup the virtual file system using the project +as a whole but we only want to modify the user specified files. + +.. code-block:: python + + from pathlib import Path + from dataclasses import dataclass + + import re + + from solidity_parser import filesys + from solidity_parser.ast import symtab, ast2builder, solnodes, solnodes2 + + # this is user input + files_to_annotate = ['TheContract.sol'] + project_dir = Path('./gptcomments') + + # setup VFS + vfs = filesys.VirtualFileSystem(project_dir, None, []) + sym_builder = symtab.Builder2(vfs) + +This tutorial uses sample code as an example(generated by chatgpt). The file is too large to list here but check it out +from the ``examples/gptcomments`` directory(named ``TheContract.sol``). + +.. image:: ../../imgs/gptdir.png + +.. note:: This Solidity project doesn't have a source or contracts folder, so we don't pass anything in for ``include_paths``: + the contracts get loaded from the ``base_path`` instead. + +Comment Formatting +^^^^^^^^^^^^^^^^^^ + +We will need these formatting helpers later on, they are not specific to SOLP but make the output nicer: + +.. code-block:: python + + INDENT_REG = re.compile(r'[ \t]+$') + + def get_trailing_whitespace(s) -> str: + match = INDENT_REG.search(s) + if match: + return match.group(0) + else: + return "" + + LINE_REG = re.compile("\r?\n") + + def indent_by(s, indentation) -> str: + return ("\n" + indentation).join(LINE_REG.split(s)) + + +These will be used alongside this ``Insertion`` dataclass to mark which comments will go where: + +.. code-block:: python + + @dataclass + class Insertion: + func: solnodes.FunctionDefinition + comment: str + +Annotation Skeleton +^^^^^^^^^^^^^^^^^^^ + +Now we just need to create a function that loads each file, finds the functions to annotate and annotates them. We will +fill in the details as we go along: + +.. code-block:: python + :linenos: + + def should_annotate_part(part: solnodes.ContractPart): + return True + + def annotate_func(func_src: str, func: solnodes.FunctionDefinition): + return f'This is a test comment for: {func.name}' + + def annotate_file(file_name): + file_sym_info = sym_builder.process_or_find_from_base_dir(file_name) + + loaded_src = vfs.sources[file_name] + ast1_nodes, src_code = loaded_src.ast, loaded_src.contents + + for node in ast1_nodes: + if not node: + continue + + for func in node.get_all_children(lambda x: isinstance(x, solnodes.FunctionDefinition)): + if should_annotate_part(func): + func_code = src_code[func.start_buffer_index:func.end_buffer_index] + comment_contents = annotate_func(func_code, func) + print(comment_contents) + +Working with Source Buffers +""""""""""""""""""""""""""" + +The ``annotate_func`` function is where we would put the call to an AI service that takes the source code of the **function only** +and provides a summary. + +``func_src`` is extracted from the :py:attr:`source text buffer ` using +the :py:attr:`start ` and +:py:attr:`end ` character indices for the function we're currently +annotating. + +IDE Line Data +""""""""""""" + +However, we can also get the corrected and column information for the +:py:attr:`start ` and +:py:attr:`end ` of the node if we need to provide these insights to an +IDE language extension, for example. + +Modifying the Source Text +------------------------- + +Instead of printing the ``comment_contents`` on line 21, create an ``Insertion`` object and store it in a list. + +.. code-block:: python + + insertions = [] # line 12 + ... + insertions.append(Insertion(func, comment_contents)) # line 21 + + +Text Insertions +^^^^^^^^^^^^^^^ + +Now create a function to do the text insertions and return the updated source code. + +.. code-block:: python + :linenos: + + def modify_text(src_code, insertions): + reverse_sorted_insertions = sorted(insertions, key=lambda x: (-x.func.start_location.line, x.func.start_location.column)) + current_source_code = src_code + + for ins in reverse_sorted_insertions: + func_text_offset = ins.func.start_buffer_index + left, right = (current_source_code[0:func_text_offset], current_source_code[func_text_offset:]) + + # for formatting the comments nicely + whitespace = get_trailing_whitespace(left) + formatted_comment = indent_by(f'// {ins.comment}', whitespace) + current_source_code = left + formatted_comment + '\n' + whitespace + right + + return current_source_code + +This code might look scary but we'll go through it step by step: + +* line 1 simply reverse sorts the insertions based on the order of the functions in the original source code. If we did + a top down insertion instead, every insertion would mess up the insertion location of the subsequent ones +* lines 6-7 simply create a split in the text for us to put the function summary comment. Since we're inserting comments + before each function, we use the start_buffer_index. ``left`` then becomes all of the code in the file up to the ``function`` + keyword and right is everything that comes after. When we insert our comment after ``left`` but before ``right`` it + puts our comment right above the function +* lines 10-11 put the comments on the same indentation level as the function to make it easier to read +* line 12 simply joins up all the parts and whitespace required, creating a complete source file's worth of code +* Repeat this for all insertions and we get fully commented code! + + +Putting it all Together +----------------------- + +Now we just call ``modify_text`` from the end of ``annotate_file``: + +.. code-block:: python + + print(modify_text(src_code, insertions)) + +And call ``annotate_file`` with each of our inputs: + +.. code-block:: python + + for f in files_to_annotate: + annotate_file(f) + +And the basic text transformer is done! + +Extending it Further +-------------------- + +There were a few features outside of the scope of this tutorial that would take this project to the next level. Try the +following ideas to get more familiar with the project and SOLP: + +* Connect to a local or online text AI that can take the ``func_code`` and return a summary +* Take user inputs for which functions to annotate and filter using ``should_annotate_part``: + * e.g. only annotate ``public`` functions using :py:func:`modifiers checks ` +* Generate AST2 for the program and for each AST1 function use the :py:attr:`AST2 node ` + to get more refined insights. \ No newline at end of file diff --git a/docs/source/getstarted/twoASTs.rst b/docs/source/getstarted/twoASTs.rst new file mode 100644 index 0000000..5a93bf3 --- /dev/null +++ b/docs/source/getstarted/twoASTs.rst @@ -0,0 +1,198 @@ +Two ASTs? +========= + +.. tip:: SOLP currently has two forms of AST: AST1 and AST2. If you're wondering which one you should use, the short of it is: AST2. + +Preface +------- + +Simply put, AST2 gives you a more consistent and easy to use set of nodes but has a couple of limitations: + +* You need to load the full project into SOLP, which might not be possible(e.g. missing dependencies) or desirable (e.g. too large) +* It takes longer to create as it requires extra builder passes +* In the unlikely case the builder fails due to an unexpected error +* It's not as closely linked to the original source code as AST1, e.g. some synthetic nodes are generated which don't + have source location data linked to them + +If you're specific project that needs to be able to modify the exact source code, check out +:doc:`this guide `, which provides tips on working on Solidity source code transformers. + +The rest of this document highlights some features specific to AST2 to show the reason why it exists and the ways in which +it's different to AST1. + +TopLevelUnits vs SourceUnits +---------------------------- + +.. |sourceunits| image:: ../../imgs/sourceunits.png + +.. |toplevelunits| image:: ../../imgs/toplevelunits.png + + +All nodes have a ``parent`` attribute, right? So let's say I have a function, modifier, event, etc definition and I want to get the contract it +was declared in, I just take the parent and use it like it's a Contract? + +Woah, hold on! There's a couple of assumptions there. Consider the following Solidity valid code: + +.. code-block:: solidity + :caption: FloatingFunc.sol + + pragma solidity ^0.8.0; + + error SafeCast__NegativeValue(); + + library IntHelper { + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) revert SafeCast__NegativeValue(); + return uint256(value); + } + } + +Two things to note here: + +(1) The parent of ``toUint256`` is a ``LibraryDefinition`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This point is solved by changing our mental model slightly. Does it really matter that the parent is a library or a contract? +Usually, not really. Instead we generalise the parent of a something like a function or a state variable to be a ``TopLevelUnit`` in AST2. +Without needing to know the specific definition type, we can: + +* get type information (:py:meth:`as_type() `) +* find contract parts/members (:py:meth:`find_named_parts() `) +* check the inheritance hierarchy (:py:meth:`is_subttype_of() `, :py:meth:`get_supers() `, :py:meth:`get_subtypes() `) +* get common data (:py:meth:`descriptor() `, :py:attr:`name `) + +Look at the list of **TopLevelUnits**: + +|toplevelunits| + +These make sense: all of these Solidity types usually contain related parts all grouped together. Additionally, none of them +are marked as *ContractParts* (see below), meaning they can't be nested inside other TopLevelUnits: they are top level nodes(parentless). + +The equivalent in AST1 are **SourceUnits**, which are defined based on the allowable Solidity grammar rules. + +|sourceunits| + +Solidity allows free floating definitions for functions and events as well as nesting(e.g. putting a library +inside of a contract). This makes traversing AST1 nodes more difficult as you don't have a guarantee that the SourceUnit +is a root node or if it is part of another SourceUnit. + +(2) FileDefinitions +^^^^^^^^^^^^^^^^^^^ + +Ask the virtual file system to load and parse the file above, you'll get a list of source units: + +.. code-block:: python + + PragmaDirective(name=Ident(text='solidity'), value='^0.8.0') + ErrorDefinition(name=Ident(text='SafeCast__NegativeValue'), parameters=[]) + LibraryDefinition(name=Ident(text='IntHelper'), parts=[...]) + +See how ``SafeCast__NegativeValue`` acts as a SourceUnit rather than a pure ContractPart? That's because it was declared at the +top level of the file. As a result, the ``parent`` of ``SafeCast__NegativeValue`` is ``None``. + +In AST2 a :py:class:`FileDefinition ` is created as a kind of +psuedo-contract to hold free floating contract parts like the error definition. + +Compare the source units above to the output of :py:meth:`get_top_level_units() ` +from the AST2 builder: + +.. code-block:: python + + FileDefinition(source_unit_name='FloatingFunc.sol', name=Ident(text='FloatingFunc.sol'), parts=[ErrorDefinition(name=Ident(text='SafeCast__NegativeValue'), inputs=[])]) + LibraryDefinition(source_unit_name='FloatingFunc.sol', name=Ident(text='IntHelper'), parts=[...]) + + +The error can now be referenced like any other contract part: with a base(the file definition) and a name. For example, +in the AST2 ``function.code`` for ``toUint256``, the revert node is: + +.. code-block:: python + + RevertWithError(error=, args=[]) + + +Imports, Pragmas, Usings +------------------------ + +AST1 has a bunch of ``SourceUnit`` subclasses such as ``PragmaDirective``, ``ImportDirective`` and ``UsingDirective``: +I don't see them in AST2, what gives? + +These constructs in Solidity require compiler support for the Solidity code to make sense, for example: + +* Imports need to be resolved using path resolution rules +* Pragmas influence the compiler version +* Using statements change what members are available for a type in a given scope + +These are complicated details which aren't useful to most people who need to the use the AST: they just want to deal +with a simple AST interface that let's them easily navigate the Solidity code. + +The AST2 builder handles these complications and embeds them into the AST2 nodes. + +Consider the contracts: + +.. code-block:: Solidity + :linenos: + + // AdderLib.sol + pragma solidity ^0.8.0; + + library Adder { + function add(uint256 a, uint256 b) public pure returns (uint256) { + return a + b; + } + } + + // MyContract.sol + pragma solidity ^0.8.0; + + import "AdderLib.sol"; + + contract MyContract { + Adder private adder; + uint256 public myVariable; + + function addToVariable(uint256 value) public { + myVariable = adder.add(myVariable, value); + } + + function notALibraryCall() public { + addToVariable(50); + } + } + +Import Resolution +^^^^^^^^^^^^^^^^^ + +The import on line 13 is removed in AST2. The ``LibraryDefinition`` generated from ``AdderLib.sol`` is directly referenced +on line 16 as a :py:class:`ResolvedUserType `, which as the name suggests, is a :py:class:`Type ` +containing a reference to the library definition. However, the AST1 :py:class:`UserType ` only knows the textual name of the type +used in the Solidity source code. + +.. code-block:: python + + # AST1 + StateVariableDeclaration(name=Ident(text='adder'), var_type=UserType(name=Ident(text='Adder')), modifiers=[...]) + # AST2, Adder is a Ref[LibraryDefinition] + StateVariableDeclaration(name=Ident(text='adder'), ttype=ResolvedUserType(Adder), modifiers=[...]) + + +Using Directives +^^^^^^^^^^^^^^^^ + +In a similar vein, the library call on line 20 is made explicit in AST2. As shown by the ``code_str`` of the node below, +the previous 2 argument function call now takes takes the base as the first argument, matching the signature of ``add`` +as defined in the library. + +.. code-block:: Solidity + + Adder.add(this.adder, this.myVariable, value) + + +Final Words +----------- + +Hopefully this document has helped you understand why SOLP as two forms of AST. They look similar but there are +important details that make AST2 better for most developers. + +There is a lot more you can do with SOLPs ASTs: there are other components and use cases of SOLP that will be documented +more in the future. In the meantime, check out the :py:mod:`API reference ` to see +what types are available. \ No newline at end of file diff --git a/docs/source/getstarted/vfshooks.rst b/docs/source/getstarted/vfshooks.rst new file mode 100644 index 0000000..83ccf8d --- /dev/null +++ b/docs/source/getstarted/vfshooks.rst @@ -0,0 +1,5 @@ +Customising File Loading +======================== + +So far all of the guides have used the default config of the :py:class:`VirtualFileSystem ` +to find, load and parse the input Solidity code. This guide goes overs \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..a1d5d4f --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,28 @@ +.. SOLP documentation master file, created by + sphinx-quickstart on Fri Apr 19 14:32:50 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to SOLP's documentation! +================================ + +**SOLP** is a Python library used for reading, parsing and analysing Solidity source projects and contracts without +having to use the solc compiler. Multiple versions of Solidity from 0.4 to the latest are supported. This is done by +having different grammars for different versions of Solidity, transforming them into a common AST and then further +refining that AST into more specialised forms of IR for analysis. +The resulting ASTs and IRs are easily usable by consumer applications without any additional dependencies. + + +.. toctree:: + :maxdepth: 2 + + getstarted/index + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` From 8e2e60002b28c261b3495e1d3206bf51b4208290 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 15:55:03 +0100 Subject: [PATCH 02/18] fix doc editorial review --- docs/source/getstarted/clients.rst | 14 ++--- docs/source/getstarted/prereq.rst | 14 ++--- docs/source/getstarted/quickstart.rst | 74 +++++++++++++-------------- docs/source/getstarted/sourcecode.rst | 61 +++++++++++----------- docs/source/getstarted/twoASTs.rst | 73 +++++++++++++------------- 5 files changed, 116 insertions(+), 120 deletions(-) diff --git a/docs/source/getstarted/clients.rst b/docs/source/getstarted/clients.rst index 2e206eb..07f7722 100644 --- a/docs/source/getstarted/clients.rst +++ b/docs/source/getstarted/clients.rst @@ -4,22 +4,22 @@ Client Setup .. note:: Before installing SOLP, follow the instructions in the :doc:`prereq` document.. -Who is this document for? +Who Is This Document For? ^^^^^^^^^^^^^^^^^^^^^^^^^ -People who want to use SOLP in their own projects +This is for people who want to use SOLP in their own projects. -Setup a Virtual Environment (optional) +Set Up a Virtual Environment (Optional) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -It's always recommended to setup a virtual environment(venv) instead of installing the package in the global pip cache. +It's always recommended to set up a virtual environment (venv) instead of installing the package in the global pip cache. -Create a venv called `venv`: +Create a venv called ``venv``. .. code-block:: bash python -m venv venv -Then activate the venv: +Then activate the venv. Unix: @@ -40,4 +40,4 @@ Installing pip install -Where `` is a path to a clone of the repository or: `git+https://github.com/Zellic/solidity-parser.git` +Where ```` is a path to a clone of the repository or ``git+https://github.com/Zellic/solidity-parser.git``. diff --git a/docs/source/getstarted/prereq.rst b/docs/source/getstarted/prereq.rst index 88f0426..10b349f 100644 --- a/docs/source/getstarted/prereq.rst +++ b/docs/source/getstarted/prereq.rst @@ -16,24 +16,24 @@ Java 8+ (for ANTLR grammar stub generation) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For generating ANTLR grammar stubs, you need Java version 8 or higher installed on your system. There are multiple -implementations available but we recommend: +implementations available, but we recommend this one: https://adoptopenjdk.net/releases.html -After installing Java, make sure to set the `JAVA_HOME` environment variable to the JDK installation directory and -`PATH` to the `bin` directory of the JDK installation. +After installing Java, make sure to set the ``JAVA_HOME`` environment variable to the JDK installation directory and +``PATH`` to the ``bin`` directory of the JDK installation. Once you have both Python and Java installed, you can proceed with the installation of the software. Resolving Conflicts ^^^^^^^^^^^^^^^^^^^ -Currently SOLP is only available on `Github `_ and when installed, has the -module name `solidity-parser`. Unfortunately there is already a module with the same name in PyPI which can cause be the +Currently, SOLP is only available on `GitHub `_, and when installed, has the +module name solidity-parser. Unfortunately, there is already a module with the same name in PyPI, which can be the cause of problems if accidentally installed. -Therefore it's recommended that you first run this command globally (outside of an activated virtual environment) to -remove packages which can conflict with SOLP. +Therefore, it's recommended that you first run this command globally (outside of an activated virtual environment) to +remove packages that can conflict with SOLP. .. code-block:: bash diff --git a/docs/source/getstarted/quickstart.rst b/docs/source/getstarted/quickstart.rst index 4e987a8..02d4edd 100644 --- a/docs/source/getstarted/quickstart.rst +++ b/docs/source/getstarted/quickstart.rst @@ -1,10 +1,10 @@ Quick Start =========== -Welcome to the SOLP docs! This guide will give you a rundown of how to load, parse, analyse and manipulate your Solidity +Welcome to the SOLP docs! This guide will give you a rundown of how to load, parse, analyze, and manipulate your Solidity code using SOLP. -Before starting, make you've installed the SOLP library by following :doc:`clients`. +Before starting, make sure you've installed the SOLP library by following :doc:`clients`. Toy Project ----------- @@ -13,8 +13,8 @@ This tutorial uses the ``example/project`` Solidity project provided in the SOLP `imports: `_ and `solc remappings `_ as well regular Solidity code. -Here is the contract we'll be parsing. As you can see, it defines contract TestContract, which inherits from Ownable, -uses the inherited ``onlyOwner`` modifier and does some simple function calls: +Here is the contract we'll be parsing. As you can see, it defines contract TestContract, which inherits from Ownable; +uses the inherited ``onlyOwner`` modifier; and does some simple function calls: .. code-block:: solidity :caption: TestContract.sol @@ -56,17 +56,17 @@ tutorial. .. image:: ../../imgs/exampledir.png -Copy the ``example`` folder to somewhere on your machine. ``example/project`` will be the **project directory** from now +Copy the ``example`` folder to somewhere on your machine — ``example/project`` will be the **project directory** from now on. -Creating a Virtual File System(VFS) +Creating a Virtual File System (VFS) ----------------------------------- -For SOLP to understand the code in the example project, it has to know where the source files, library files and import +For SOLP to understand the code in the example project, it has to know where the source files, library files, and import remappings are located and how the project is structured. The :py:class:`solidity_parser.filesys.VirtualFileSystem` object takes these options, handles path mappings, reads -the files and generates an unrefined AST. +the files, and generates an unrefined AST. .. code-block:: python :linenos: @@ -82,9 +82,9 @@ the files and generates an unrefined AST. None ) -Replace ``./project`` on line 3 with your **project directory** +Replace ``./project`` on line 3 with your **project directory**. -Now give the VFS the remapping file +Now give the VFS the remapping file. .. code-block:: python @@ -96,8 +96,8 @@ Now give the VFS the remapping file Getting AST1 Nodes ------------------ -Remember how I mentioned that the VFS gives us an unrefined AST? This form of AST is known as **AST1** and the VFS can -give us this very easily. We can then, for example, get the header information for ``MyContract`` in ``TestContract.sol`` +Remember how we mentioned that the VFS gives us an unrefined AST? This form of AST is known as **AST1**, and the VFS can +give us this very easily. We can then, for example, get the header information for MyContract in TestContract.sol. .. code-block:: python @@ -113,9 +113,8 @@ give us this very easily. We can then, for example, get the header information f While this might be useful, there are two limitations here: -* We can't get a reference to the ``ContractDefinition`` for ``Ownable`` (the inherited contract), i.e. we only know - it's name at this point but not where it comes from or what it contains -* We have to load each source file one at a time instead of letting SOLP discover its way through the project +* We can't get a reference to the ``ContractDefinition`` for Ownable (the inherited contract). In other words, we only know its name at this point but not where it comes from or what it contains. +* We have to load each source file one at a time instead of letting SOLP discover its way through the project. Getting AST2 Nodes @@ -138,12 +137,11 @@ classes make this super simple! ast2_builder.process_all() -In this example we only loaded entry point(``TestContract.sol``) but during symbol table building, the ``Ownable.sol`` +In this example, we only loaded the entry point (TestContract.sol), but during symbol-table building, the Ownable.sol file was also parsed. This makes it available later for AST2 building. -Now get the AST2 nodes using :py:meth:`Builder.get_top_level_units `: -this includes the ``Ownable`` and ``MyContract`` contracts, but to demonstrate the tree searching behavior, we'll use -``MyContract`` only. +Now get the AST2 nodes using :py:meth:`Builder.get_top_level_units `. This includes the Ownable and MyContract contracts, but to demonstrate the tree searching behavior, we'll use +MyContract only. .. code-block:: python @@ -153,12 +151,12 @@ this includes the ``Ownable`` and ``MyContract`` contracts, but to demonstrate t ownable_type: solnodes2.ResolvedUserType = my_contract.inherits[0].name ownable_contract: solnodes2.ContractDefinition = ownable_type.value.x -.. note:: These AST2 objects come from the :py:mod:`solidity_parser.ast.solnodes2` module instead of the AST1 :py:mod:`solidity_parser.ast.solnodes` module +.. note:: These AST2 objects come from the :py:mod:`solidity_parser.ast.solnodes2` module instead of the AST1 :py:mod:`solidity_parser.ast.solnodes` module. -Analysing the AST +Analyzing the AST ----------------- -Let's now collect the functions defined by ``Ownable`` and compute a measure of complexity based on the number of calls +Let's now collect the functions defined by Ownable and compute a measure of complexity based on the number of calls it makes. This could be part of a tool to generate code insights or highlight areas that look overly complicated and need to be refactored. @@ -179,28 +177,28 @@ need to be refactored. The benefits of using an AST structure mean we can search through the entire code of each function easily and extract the data we want. -Working with Nodes +Working With Nodes ------------------ SOLP lists the :py:mod:`AST1 ` and :py:mod:`AST2 ` node definitions as Python dataclasses and provides convenience features to make the objects easier to work with. Some common -ones are: +ones are the following. Parenting ^^^^^^^^^ -All nodes have a ``parent`` attribute that points to the logical parent of the node, i.e. where it's declared in the -Solidity source code. The exact type of the parent differs depending on the node, for example +All nodes have a ``parent`` attribute that points to the logical parent of the node (i.e., where it's declared in the +Solidity source code). The exact type of the parent differs depending on the node. For example, -* a FunctionDefinition can have a Contract, Interface, Library or FileDefinition parent depending on where it was declared -* an Expr can have a parent that is another Expr or a Stmt +* A ``FunctionDefinition`` can have a Contract, Interface, Library, or FileDefinition parent depending on where it was declared +* An ``Expr`` can have a parent that is another ``Expr`` or a ``Stmt``. Equality by Value ^^^^^^^^^^^^^^^^^ Despite storing location and parent information, two nodes representing the same data can be compared using the ``==`` operator, even when they are in different places in the AST. Here is a simple analysis that checks for functions that contain -duplicated code. See how we can also check that the two functions are different(i.e. have a different names and signatures) +duplicated code. See how we can check that the two functions are different (i.e., have a different names and signatures) but also check the ``code`` nodes in an intuitive way. .. code-block:: python @@ -215,8 +213,8 @@ but also check the ``code`` nodes in an intuitive way. Quick Consistent Hashes ^^^^^^^^^^^^^^^^^^^^^^^ -Often we want to use nodes as keys in dicts so we need a hash function. Python dataclasses don't support this for -definitions with mutable attributes or lists but SOLP does. Let's find which variables are set by which functions +Often we want to use nodes as keys in dicts, so we need a hash function. Python dataclasses don't support this for +definitions with mutable attributes or lists but SOLP does. Let's find which variables are set by which functions. .. code-block:: python @@ -228,12 +226,12 @@ definitions with mutable attributes or lists but SOLP does. Let's find which var return var_stores This operation is also surprisingly fast as the ``state_var`` hash is cached until it's modified! This pattern is very -useful for creating call graphs, e.g. mappings of the type ``FunctionDefinition -> list[FunctionDefinitions]`` +useful for creating call graphs (e.g., mappings of the type ``FunctionDefinition -> list[FunctionDefinitions]``). Deep Copy ^^^^^^^^^ -Entire node trees can be passed to :py:func:`copy.deepcopy` to produce a full identical tree +Entire node trees can be passed to :py:func:`copy.deepcopy` to produce a full identical tree. .. code-block:: python @@ -247,7 +245,7 @@ Entire node trees can be passed to :py:func:`copy.deepcopy` to produce a full id Mutability ^^^^^^^^^^ -Nodes are mutable: they can be modified and inserted into a different branch of the AST. Let's say you wanted to create +Nodes are mutable; they can be modified and inserted into a different branch of the AST. Let's say you wanted to create a transformer that computes and inlines constant expressions: .. code-block:: python @@ -263,7 +261,7 @@ a transformer that computes and inlines constant expressions: store.value = solnodes2.Literal(constant_value, constant_type) -Python encourages duck typing and SOLP is designed to take advantage of it! The ``value`` attribute is always an ``Expr`` +Python encourages duck typing, and SOLP is designed to take advantage of it! The ``value`` attribute is always an ``Expr`` for store operations, so we can handle all of these different types of store operations at once. Code Printing @@ -282,7 +280,7 @@ Let's say we made SOLP change the function call to ``addToVariable2`` in ``addPo print(add_positive_func.code.code_str()) -This prints: +This prints .. code-block:: solidity @@ -295,7 +293,7 @@ This prints: this.addToVariable(value); } -``code_str`` can be called on any AST2 node, not just the ``code`` of the function. Because the code is parsed by SOLP, +And ``code_str`` can be called on any AST2 node, not just the ``code`` of the function. Because the code is parsed by SOLP, the output formatting and exact form might not match the original source code, but the result will always be semantically equal. @@ -306,7 +304,7 @@ Next Steps ---------- This document serves as a primer to SOLP and working with the AST of Solidity programs. You can use the patterns given -here to implement powerful analyses, reason about and generate insights for your own tools. +here to implement powerful analyses as well as reason about and generate insights for your own tools. Naturally, there are lots of SOLP details that have been omitted that you might come across. The remaining sections in the Getting Started tab fill in these gaps. Enjoy! diff --git a/docs/source/getstarted/sourcecode.rst b/docs/source/getstarted/sourcecode.rst index e165db4..dbd370a 100644 --- a/docs/source/getstarted/sourcecode.rst +++ b/docs/source/getstarted/sourcecode.rst @@ -1,7 +1,7 @@ Working with Source Code ======================== -SOLP let's you create powerful analyses for Solidity source code. This is enough for some tools, however, others need to +SOLP lets you create powerful analyses for Solidity source code. This is enough for some tools; however, others need to edit the source text or insert the results of the analysis in the code. This document will lead you through building a tool that inserts comments above functions with analysis insights from @@ -14,14 +14,14 @@ One important thing that has to be reiterated is that AST2 can contain nodes tha Check out the :doc:`twoASTs` document for why this is. This means you have to go through the AST1 nodes, as they are guaranteed to be from the source text, and use the tagged -source location info for modifications. You can still use AST2 for analyses but you have to use AST1 nodes to write the +source location info for modifications. You can still use AST2 for analyses, but you have to use AST1 nodes to write the output. Setup ----- -Create the basic SOLP client setup to read the source files. We have to setup the virtual file system using the project -as a whole but we only want to modify the user specified files. +Create the basic SOLP client setup to read the source files. We have to set up the virtual file system using the project +as a whole, but we only want to modify the user-specified files. .. code-block:: python @@ -41,18 +41,18 @@ as a whole but we only want to modify the user specified files. vfs = filesys.VirtualFileSystem(project_dir, None, []) sym_builder = symtab.Builder2(vfs) -This tutorial uses sample code as an example(generated by chatgpt). The file is too large to list here but check it out -from the ``examples/gptcomments`` directory(named ``TheContract.sol``). +This tutorial uses sample code as an example (generated by ChatGPT). The file is too large to list here, but check it out +from the ``examples/gptcomments`` directory (named TheContract.sol). .. image:: ../../imgs/gptdir.png -.. note:: This Solidity project doesn't have a source or contracts folder, so we don't pass anything in for ``include_paths``: - the contracts get loaded from the ``base_path`` instead. +.. note:: This Solidity project doesn't have a source or contracts folder, so we don't pass anything in for ``include_paths``. + The contracts get loaded from the ``base_path`` instead. Comment Formatting ^^^^^^^^^^^^^^^^^^ -We will need these formatting helpers later on, they are not specific to SOLP but make the output nicer: +We will need these formatting helpers later on. They are not specific to SOLP but make the output nicer: .. code-block:: python @@ -83,7 +83,7 @@ These will be used alongside this ``Insertion`` dataclass to mark which comments Annotation Skeleton ^^^^^^^^^^^^^^^^^^^ -Now we just need to create a function that loads each file, finds the functions to annotate and annotates them. We will +Now we just need to create a function that loads each file, finds the functions to annotate, and annotates them. We will fill in the details as we go along: .. code-block:: python @@ -111,15 +111,15 @@ fill in the details as we go along: comment_contents = annotate_func(func_code, func) print(comment_contents) -Working with Source Buffers +Working With Source Buffers """"""""""""""""""""""""""" The ``annotate_func`` function is where we would put the call to an AI service that takes the source code of the **function only** and provides a summary. -``func_src`` is extracted from the :py:attr:`source text buffer ` using +Also, ``func_src`` is extracted from the :py:attr:`source text buffer ` using the :py:attr:`start ` and -:py:attr:`end ` character indices for the function we're currently +:py:attr:`end ` character indexes for the function we're currently annotating. IDE Line Data @@ -165,29 +165,29 @@ Now create a function to do the text insertions and return the updated source co return current_source_code -This code might look scary but we'll go through it step by step: +This code might look scary, but we'll go through it step by step: -* line 1 simply reverse sorts the insertions based on the order of the functions in the original source code. If we did - a top down insertion instead, every insertion would mess up the insertion location of the subsequent ones -* lines 6-7 simply create a split in the text for us to put the function summary comment. Since we're inserting comments - before each function, we use the start_buffer_index. ``left`` then becomes all of the code in the file up to the ``function`` - keyword and right is everything that comes after. When we insert our comment after ``left`` but before ``right`` it - puts our comment right above the function -* lines 10-11 put the comments on the same indentation level as the function to make it easier to read -* line 12 simply joins up all the parts and whitespace required, creating a complete source file's worth of code -* Repeat this for all insertions and we get fully commented code! +* Line 1 simply reverse sorts the insertions based on the order of the functions in the original source code. If we did + a top-down insertion instead, every insertion would mess up the insertion location of the subsequent ones. +* Lines 6–7 simply create a split in the text for us to put the function-summary comment. Since we're inserting comments + before each function, we use the ``start_buffer_index`` — ``left`` then becomes all of the code in the file up to the ``function`` + keyword and right is everything that comes after. When we insert our comment after ``left`` but before ``right``, it + puts our comment right above the function. +* Lines 10–11 put the comments on the same indentation level as the function to make it easier to read. +* Line 12 simply joins up all the parts and whitespace required, creating a complete source file's worth of code. +* Repeat this for all insertions, and we get fully commented code. -Putting it all Together +Putting It All Together ----------------------- -Now we just call ``modify_text`` from the end of ``annotate_file``: +Now we just call ``modify_text`` from the end of ``annotate_file``, .. code-block:: python print(modify_text(src_code, insertions)) -And call ``annotate_file`` with each of our inputs: +and call ``annotate_file`` with each of our inputs: .. code-block:: python @@ -196,14 +196,13 @@ And call ``annotate_file`` with each of our inputs: And the basic text transformer is done! -Extending it Further +Extending It Further -------------------- There were a few features outside of the scope of this tutorial that would take this project to the next level. Try the following ideas to get more familiar with the project and SOLP: -* Connect to a local or online text AI that can take the ``func_code`` and return a summary -* Take user inputs for which functions to annotate and filter using ``should_annotate_part``: - * e.g. only annotate ``public`` functions using :py:func:`modifiers checks ` -* Generate AST2 for the program and for each AST1 function use the :py:attr:`AST2 node ` +* Connect to a local or online text AI that can take the ``func_code`` and return a summary. +* Take user inputs for which functions to annotate and filter using ``should_annotate_part`` (e.g., only annotate ``public`` functions using :py:func:`modifiers checks `). +* Generate AST2 for the program, and for each AST1 function, use the :py:attr:`AST2 node ` to get more refined insights. \ No newline at end of file diff --git a/docs/source/getstarted/twoASTs.rst b/docs/source/getstarted/twoASTs.rst index 5a93bf3..8f57415 100644 --- a/docs/source/getstarted/twoASTs.rst +++ b/docs/source/getstarted/twoASTs.rst @@ -1,21 +1,21 @@ Two ASTs? ========= -.. tip:: SOLP currently has two forms of AST: AST1 and AST2. If you're wondering which one you should use, the short of it is: AST2. +.. tip:: SOLP currently has two forms of AST: AST1 and AST2. If you're wondering which one you should use, the short of it is AST2. Preface ------- -Simply put, AST2 gives you a more consistent and easy to use set of nodes but has a couple of limitations: +Simply put, AST2 gives you a more consistent and easy to use set of nodes, but it has a couple of limitations: -* You need to load the full project into SOLP, which might not be possible(e.g. missing dependencies) or desirable (e.g. too large) -* It takes longer to create as it requires extra builder passes -* In the unlikely case the builder fails due to an unexpected error -* It's not as closely linked to the original source code as AST1, e.g. some synthetic nodes are generated which don't - have source location data linked to them +* You need to load the full project into SOLP, which might not be possible (e.g., missing dependencies) or desirable (e.g., too large). +* It takes longer to create as it requires extra builder passes. +* In the unlikely case, the builder fails due to an unexpected error. +* It's not as closely linked to the original source code as AST1 (e.g., some synthetic nodes are generated that don't + have source location data linked to them). -If you're specific project that needs to be able to modify the exact source code, check out -:doc:`this guide `, which provides tips on working on Solidity source code transformers. +If your specific project needs to be able to modify the exact source code, check out +:doc:`this guide `, which provides tips on working on Solidity source-code transformers. The rest of this document highlights some features specific to AST2 to show the reason why it exists and the ways in which it's different to AST1. @@ -28,10 +28,10 @@ TopLevelUnits vs SourceUnits .. |toplevelunits| image:: ../../imgs/toplevelunits.png -All nodes have a ``parent`` attribute, right? So let's say I have a function, modifier, event, etc definition and I want to get the contract it -was declared in, I just take the parent and use it like it's a Contract? +All nodes have a ``parent`` attribute, right? So let's say we have a function, modifier, event (etc.) definition, and we want to get the contract it +was declared in, we just take the parent and use it like it's a Contract. -Woah, hold on! There's a couple of assumptions there. Consider the following Solidity valid code: +Hold on! There's a couple of assumptions there. Consider the following Solidity valid code: .. code-block:: solidity :caption: FloatingFunc.sol @@ -47,14 +47,14 @@ Woah, hold on! There's a couple of assumptions there. Consider the following Sol } } -Two things to note here: +There are two things to note here. -(1) The parent of ``toUint256`` is a ``LibraryDefinition`` +1. The Parent of ``toUint256`` Is a ``LibraryDefinition`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This point is solved by changing our mental model slightly. Does it really matter that the parent is a library or a contract? -Usually, not really. Instead we generalise the parent of a something like a function or a state variable to be a ``TopLevelUnit`` in AST2. -Without needing to know the specific definition type, we can: +Usually, not really. Instead, we generalize the parent of something like a function or a state variable to be a ``TopLevelUnit`` in AST2. +Without needing to know the specific definition type, we can * get type information (:py:meth:`as_type() `) * find contract parts/members (:py:meth:`find_named_parts() `) @@ -65,21 +65,21 @@ Look at the list of **TopLevelUnits**: |toplevelunits| -These make sense: all of these Solidity types usually contain related parts all grouped together. Additionally, none of them -are marked as *ContractParts* (see below), meaning they can't be nested inside other TopLevelUnits: they are top level nodes(parentless). +These make sense. All of these Solidity types usually contain related parts all grouped together. Additionally, none of them +are marked as *ContractParts* (see below), meaning they can't be nested inside other TopLevelUnits; they are top-level nodes (parentless). The equivalent in AST1 are **SourceUnits**, which are defined based on the allowable Solidity grammar rules. |sourceunits| -Solidity allows free floating definitions for functions and events as well as nesting(e.g. putting a library +Solidity allows free-floating definitions for functions and events as well as nesting (e.g., putting a library inside of a contract). This makes traversing AST1 nodes more difficult as you don't have a guarantee that the SourceUnit is a root node or if it is part of another SourceUnit. -(2) FileDefinitions +2. FileDefinitions ^^^^^^^^^^^^^^^^^^^ -Ask the virtual file system to load and parse the file above, you'll get a list of source units: +Ask the virtual file system to load and parse the file above. You'll get a list of source units: .. code-block:: python @@ -90,8 +90,8 @@ Ask the virtual file system to load and parse the file above, you'll get a list See how ``SafeCast__NegativeValue`` acts as a SourceUnit rather than a pure ContractPart? That's because it was declared at the top level of the file. As a result, the ``parent`` of ``SafeCast__NegativeValue`` is ``None``. -In AST2 a :py:class:`FileDefinition ` is created as a kind of -psuedo-contract to hold free floating contract parts like the error definition. +In AST2, a :py:class:`FileDefinition ` is created as a kind of +psuedo-contract to hold free-floating contract parts like the error definition. Compare the source units above to the output of :py:meth:`get_top_level_units() ` from the AST2 builder: @@ -102,8 +102,8 @@ from the AST2 builder: LibraryDefinition(source_unit_name='FloatingFunc.sol', name=Ident(text='IntHelper'), parts=[...]) -The error can now be referenced like any other contract part: with a base(the file definition) and a name. For example, -in the AST2 ``function.code`` for ``toUint256``, the revert node is: +The error can now be referenced like any other contract part — with a base (the file definition) and a name. For example, +in the AST2 ``function.code`` for ``toUint256``, the revert node is this: .. code-block:: python @@ -113,17 +113,16 @@ in the AST2 ``function.code`` for ``toUint256``, the revert node is: Imports, Pragmas, Usings ------------------------ -AST1 has a bunch of ``SourceUnit`` subclasses such as ``PragmaDirective``, ``ImportDirective`` and ``UsingDirective``: -I don't see them in AST2, what gives? +AST1 has a bunch of ``SourceUnit`` subclasses such as ``PragmaDirective``, ``ImportDirective``, and ``UsingDirective``. We don't see them in AST2; what's going on? -These constructs in Solidity require compiler support for the Solidity code to make sense, for example: +These constructs in Solidity require compiler support for the Solidity code to make sense. For example, -* Imports need to be resolved using path resolution rules -* Pragmas influence the compiler version -* Using statements change what members are available for a type in a given scope +* Imports need to be resolved using path resolution rules. +* Pragmas influence the compiler version. +* Using statements changes what members are available for a type in a given scope. -These are complicated details which aren't useful to most people who need to the use the AST: they just want to deal -with a simple AST interface that let's them easily navigate the Solidity code. +These are complicated details that aren't useful to most people who need to the use the AST; they just want to deal +with a simple AST interface that lets them easily navigate the Solidity code. The AST2 builder handles these complications and embeds them into the AST2 nodes. @@ -162,8 +161,8 @@ Consider the contracts: Import Resolution ^^^^^^^^^^^^^^^^^ -The import on line 13 is removed in AST2. The ``LibraryDefinition`` generated from ``AdderLib.sol`` is directly referenced -on line 16 as a :py:class:`ResolvedUserType `, which as the name suggests, is a :py:class:`Type ` +The import on line 13 is removed in AST2. The ``LibraryDefinition`` generated from `dderLib.sol is directly referenced +on line 16 as a :py:class:`ResolvedUserType `, which, as the name suggests, is a :py:class:`Type ` containing a reference to the library definition. However, the AST1 :py:class:`UserType ` only knows the textual name of the type used in the Solidity source code. @@ -190,9 +189,9 @@ as defined in the library. Final Words ----------- -Hopefully this document has helped you understand why SOLP as two forms of AST. They look similar but there are +Hopefully this document has helped you understand why SOLP as two forms of AST. They look similar, but there are important details that make AST2 better for most developers. -There is a lot more you can do with SOLPs ASTs: there are other components and use cases of SOLP that will be documented +There is a lot more you can do with SOLPs ASTs; there are other components and use cases of SOLP that will be documented more in the future. In the meantime, check out the :py:mod:`API reference ` to see what types are available. \ No newline at end of file From fdc97ae7b8ca33218366bb9e0ab382308bc41445 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 15:56:19 +0100 Subject: [PATCH 03/18] add docs ast2 image and builtins --- docs/imgs/astmods2.png | Bin 0 -> 141419 bytes docs/source/getstarted/builtins.sol | 115 ++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 docs/imgs/astmods2.png create mode 100644 docs/source/getstarted/builtins.sol diff --git a/docs/imgs/astmods2.png b/docs/imgs/astmods2.png new file mode 100644 index 0000000000000000000000000000000000000000..aced71abe3f07d713c170fc17a93469bcc23cbdf GIT binary patch literal 141419 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�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 Ly;h)V@! Date: Mon, 6 May 2024 15:56:38 +0100 Subject: [PATCH 04/18] add docs build action --- .github/workflows/gendocs.yml | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/gendocs.yml diff --git a/.github/workflows/gendocs.yml b/.github/workflows/gendocs.yml new file mode 100644 index 0000000..00952a1 --- /dev/null +++ b/.github/workflows/gendocs.yml @@ -0,0 +1,36 @@ +name: gendocs + +on: [push, workflow_dispatch] + +permissions: + contents: write + +jobs: + gendocs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '11' + - name: Set up Python 3.11 + uses: actions/setup-python@v3 + with: + python-version: "3.11" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install . + pip install sphinx furo sphinx-autoapi sphinx_autodoc_typehints + - name: Sphinx build + run: | + sphinx-build -M html docs/source docs/build + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: docs/build/ + force_orphan: true \ No newline at end of file From 4faae19f58ebf47b7bc21196b1050b5d77680541 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 15:57:24 +0100 Subject: [PATCH 05/18] add _do_read_path hook to VFS --- src/solidity_parser/filesys.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/solidity_parser/filesys.py b/src/solidity_parser/filesys.py index 25b031d..22de6b5 100644 --- a/src/solidity_parser/filesys.py +++ b/src/solidity_parser/filesys.py @@ -206,6 +206,9 @@ def _read_file(self, path: str, is_cli_path=True) -> str: logging.getLogger('VFS').debug(f'Reading {path}') + return self._do_read_path(path) + + def _do_read_path(self, path: Path) -> str: with path.open(mode='r', encoding='utf-8') as f: return f.read() From ff39a92ca04dc53752382f15faa292c3cfc67123 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 15:57:39 +0100 Subject: [PATCH 06/18] add vfshooks and scopes docs --- .../autoapi/solidity_parser/filesys/index.rst | 3 + docs/source/getstarted/index.rst | 1 + docs/source/getstarted/scopes.rst | 185 +++++++++++++++++- docs/source/getstarted/sourcecode.rst | 7 +- docs/source/getstarted/vfshooks.rst | 69 ++++++- 5 files changed, 252 insertions(+), 13 deletions(-) diff --git a/docs/source/autoapi/solidity_parser/filesys/index.rst b/docs/source/autoapi/solidity_parser/filesys/index.rst index ad71b44..82cd182 100644 --- a/docs/source/autoapi/solidity_parser/filesys/index.rst +++ b/docs/source/autoapi/solidity_parser/filesys/index.rst @@ -133,6 +133,9 @@ Attributes .. py:method:: _read_file(path: str, is_cli_path=True) -> str + .. py:method:: _do_read_path(path: pathlib.Path) -> str + + .. py:method:: _cli_path_to_source_name(input_file_path) -> str Computes the source name for a source file supplied via command line invocation of solc diff --git a/docs/source/getstarted/index.rst b/docs/source/getstarted/index.rst index 63bfa99..5694281 100644 --- a/docs/source/getstarted/index.rst +++ b/docs/source/getstarted/index.rst @@ -10,3 +10,4 @@ Getting Started twoASTs sourcecode scopes + vfshooks diff --git a/docs/source/getstarted/scopes.rst b/docs/source/getstarted/scopes.rst index dafaa30..864f260 100644 --- a/docs/source/getstarted/scopes.rst +++ b/docs/source/getstarted/scopes.rst @@ -6,7 +6,8 @@ and tables to the :py:class:`AST2 Builder `_ requests to find the definition of whatever you click on in the IDE(e.g. Visual Studio Code). This won't be the full plugin: -just the SOLP code required to make it work. +just the SOLP code required to make it work. The code is adapted from an existing plugin written with the `pygls `_ and +`lsprotocol `_ libraries. Line to Node ------------ @@ -14,12 +15,12 @@ Line to Node As we saw in the :doc:`sourcecode` tutorial, SOLP lets us map nodes to source code locations easily. Usually IDEs make requests based on the line and column number and expect the language tool to figure out what is at that location. -Let's make a function that does that: it should make a list of possible AST1 nodes and a source location and determine the +Let's make a function that does that: it should take a list of possible AST1 nodes and a source location and determine the exact node that is defined at that source location. The :py:meth:`SourceLocationSpan.does_contain() `, available for every node with :py:meth:`get_source_span() ` will work for this. -All we need to do is recurse until we find the deeepest node that is defined in that span: +All we need to do is recurse until we find the deeepest node whose span includes the location: .. code-block:: python @@ -33,24 +34,30 @@ All we need to do is recurse until we find the deeepest node that is defined in return get_containing_ast_node(src_loc, children) if children else n return None +When a node has no more children, it must be the deepest node in the tree(a leaf). + +.. note:: Since each node has a :py:meth:`get_children() ` function, we can + do this in a generic way without having to handle each Node separately using a visitor! + Idents Only ----------- -If this node is an identifier then we can do the reference search: +If this node is an identifier then we can do the reference search. If it's anything else(e.g. a Solidity keyword, a +punctuator, etc) then we can't get a definition. .. code-block:: python if isinstance(ast1_node, Ident): return get_definitions_for_node(ast1_node) -Qualified vs Unqualified References ------------------------------------ +Resolving the Reference +----------------------- The reference could be qualified, e.g. ``x.y`` or unqualified ``y``. The way in which ``y`` is accessed changes the scopes we need to search. The differences between the cases are: * Unqualified: search for ``y`` in the :py:attr:`node scope ` of ``ast1_node`` -* Qualified: figure out the type of ``x``, search for that type in ``ast1_node.scope`` to find a ``Type Scope`` and search for ``y`` in that type scope +* Qualified: figure out the type of ``x``, search for that type in ``ast1_node.scope`` to find a **type scope** and search for ``y`` in that type scope Qualified lookups are modelled by the :py:class:`GetMember ` node in AST1. So far we know that ``y`` is an :py:class:`Ident `, we need to determine what type of @@ -118,15 +125,175 @@ Search these scopes in the same way as the previous case: get_symbol_link --------------- -The exact details of ``get_symbol_link`` depend on what LSP framework you're using. This guide will show you what it -needs to extract for the +The exact details of ``get_symbol_link`` depend on what LSP framework you're using. Usually the following info is needed +from the reference that's found: + +* Whether it's a builtin type/object +* The file it's is defined in +* The span of the Node that defines the Symbol and the span of the Node's descriptor/name + +Scope vs Node +^^^^^^^^^^^^^ + +The AST1 node is found by the :py:attr:`value ` attribute of the Symbol. In +general you can think of the value as being the Node that caused the Symbol to be created in the symbol's scope. + +For Solidity builtin symbols, the ``value`` is usually None, but obviously even if it has a value, it can't +be a real AST1 node: SOLP doesn't parse the builtins, they are created only in the symbol table. + +Checking for Builtins +^^^^^^^^^^^^^^^^^^^^^ + +This part is easy, check if the Symbol is any of the following types: + +* :py:class:`BuiltinFunction `: self explanatory, e.g. ``keccak256()`` or ``abi.encode()`` +* :py:class:`BuiltinObject `: this is the ``msg`` part of ``msg.value``, i.e. the container object that has other builtins +* :py:class:`BuiltinValue `: e.g. ``msg.value`` + +.. code-block:: python + + def is_builtin(sym): + return isinstance(sym, (symtab.BuiltinFunction, symtab.BuiltinObject, symtab.BuiltinValue)) + +Mock Builtin File +""""""""""""""""" + +When the user tries to find the definition for a builtin, let's give them a file to view that contains pseudocode with +documentation, e.g. when they click on ``msg.sender`` it opens a file called ``builtins.sol`` and goes to a struct +member in a struct named ``Msg``. + +To do this, we need to take our builtin symbol table object from above, parse the ``builtins.sol`` file and find a +corresponding AST1 node that we will use for the rest of ``get_symbol_link``. + +To do this let's say we have another VFS and symbol table builder setup with just the ``builtins.sol`` file +loaded(to avoid any nasty mixing with the real Solidity code of the project open in the IDE): + +.. code-block:: python + + builtin_symbol = ... + # getting this env(ironment) is an implementation detail + # it just contains the vfs and symtab builder for builtins.sol only + env = LSP_SERVER.builtin_env + builtins_fs = env.symtab_builder.process_or_find_from_base_dir('solsrc/builtins.sol') + symbol_path = compute_symbol_root_name(builtin_symbol) + real_builtins_symbol = builtins_fs.find_multi_part_symbol(symbol_path) + + +We compute a `root path`, i.e. a fully qualified path from the FileScope of the ``builtin_symbol`` to the symbol itself. +For example, if we had the BuiltinValue representing ``msg.sender``, the key we get is ``msg.sender``. + +``find_multi_part_symbol`` does the qualified search using the key and finds the real symbol. + +To actually compute the key, there are a few tricky details: + +.. code-block:: python + :linenos: + + def compute_symbol_root_name(symbol) -> str: + parts = [] + s = symbol + while not isinstance(s, (symtab.FileScope, symtab.RootScope)): + name = s.aliases[0] + if name == '': + name = '_address' + elif name == '': + name = '_address_payable' + parts.append(name) + s = s.parent_scope + parts.reverse() + + if parts[0] == '_address' and parts[1] in ['transfer', 'send']: + parts[0] = '_address_payable' + + return '.'.join(parts) +The general algorithm goes like this: +* Take the current symbol, find its parents recursively until we get to the FileScope(or RootScope for builtins) + * store the primary alias of the symbol as part of the key(most symbols only have 1 alias) + * this gives a reversed list of each of the parts of the key, e.g. ``['sender', 'msg']`` +* reverse the list and join the parts together with dots +The tricky parts are: +* Lines 6-9: we can't name a contract address or address payable in Solidity as it's a language keyword, instead + prefix these names with an underscore +* Lines 14-15: the ``transfer`` and ``send`` functions are stored under the address object in the symtab as old + versions of Solidity allowed this whereas now it's only supported for for address payable: remap these functions to + address payable in ``builtins.sol`` +Finding the File +^^^^^^^^^^^^^^^^ +The symbol table creates a :py:class:`FileScope ` when it parses each file from +the VFS. It has the `source unit name `_ +which we use to find the file path from the VFS. + +.. code-block:: python + + def get_symbol_file_uri(vfs, symbol): + file_scope = symbol.find_first_ancestor_of(symtab.FileScope) + sun = file_scope.source_unit_name + file_path = vfs.sources[sun].origin + +The LSP deals with URIs, not paths, so convert the resultant path: + +.. code-block:: python + + from pygls import uris + + uris.from_fs_path(str(file_path)) + + +.. note:: If we pass in the appropriate VFS and real symbol for the builtins case, this same function works to give the + URI of the ``builtins.sol``! + +Node Spans +^^^^^^^^^^ + +To recap, we can take a source location, find the AST node there, check if it's a reference, resolve the reference and +find a corresponding AST node that the reference may be referring to. Now all we need to do is get the range of the +name of this node and the range of the entire node to return to the LSP client. + +.. code-block:: python + + def get_node_range(n: Node) -> lsp.Range: + solp_start, solp_end = n.start_location, n.end_location + start = lsp.Position(solp_start.line-1, solp_start.column-1) + end = lsp.Position(solp_end.line-1, solp_end.column-1) + return lsp.Range(start, end) + +This function is very simple, it just copies the data from the node into the ``lsp.Range`` object. I've shown it as it +highlights how SOLP source locations are `1 based` whereas LSP/IDE locations for this usecase are `0 based`, hence the +``-1``s on each position. + +Definition Name Span +"""""""""""""""""""" + +This gets the range of the name of the target node only, e.g. it would highlight just the name of the function or the +name of the contract that has been referenced. + +.. code-block:: python + + if hasattr(node, 'name'): + return get_node_range(node.name) + else: + return None + +Definition Span +""""""""""""""" + +This gets the range of the entire target node, e.g. from the keyword ``function`` all the way to the closing curly brace +of a function definition. + +.. code-block:: python + return get_node_range(node) +Closing Notes +------------- +While this tutorial can't cover the entire plumbing required to make a language server for Solidity, the concepts +introduced here will help you get there. In fact, most of the code in this guide is taken from our open source demo +implementation available on `Github `_. diff --git a/docs/source/getstarted/sourcecode.rst b/docs/source/getstarted/sourcecode.rst index e165db4..aadb1d5 100644 --- a/docs/source/getstarted/sourcecode.rst +++ b/docs/source/getstarted/sourcecode.rst @@ -17,6 +17,11 @@ This means you have to go through the AST1 nodes, as they are guaranteed to be f source location info for modifications. You can still use AST2 for analyses but you have to use AST1 nodes to write the output. +.. figure:: ../../imgs/astmods2.png + :class: with-border + + An overview of the strategy + Setup ----- @@ -114,7 +119,7 @@ fill in the details as we go along: Working with Source Buffers """"""""""""""""""""""""""" -The ``annotate_func`` function is where we would put the call to an AI service that takes the source code of the **function only** +The ``annotate_func`` function is where we would put the call to an AI service(or static analysis) that takes the source code of the **function only** and provides a summary. ``func_src`` is extracted from the :py:attr:`source text buffer ` using diff --git a/docs/source/getstarted/vfshooks.rst b/docs/source/getstarted/vfshooks.rst index 83ccf8d..48f07ad 100644 --- a/docs/source/getstarted/vfshooks.rst +++ b/docs/source/getstarted/vfshooks.rst @@ -1,5 +1,68 @@ -Customising File Loading +Customising File Parsing ======================== -So far all of the guides have used the default config of the :py:class:`VirtualFileSystem ` -to find, load and parse the input Solidity code. This guide goes overs \ No newline at end of file +So far all of the guides have used the default config of the :py:class:`VirtualFileSystem ` +to find, load and parse the input Solidity code. This guide goes over customising parser versions, file resolution and +useful tips for hooking into the VFS. + +Parser Version +-------------- + +SOLP is the only tool that's able to parse any version of Solidity source code; it doesn't require lots of builds of +SOLP and doesn't work on EVM bytecode. To do this, the Solidity version pragma in each file is processed and a suitable +parser version is inferred. + +Sometimes this inference doesn't work: files may have conflicting versions or versions may be omitted. + +To get around this, pass a :py:class:`Version ` to the VFS constructor. +This will force the parser version and the language version for different steps later on, e.g. + +.. code-block:: python + + vfs = VirtualFileSystem(base_path, None, [src_path], compiler_version=Version(0, 8, 22)) + +would force the version to Solidity 0.8.22 + +Overriding File Reading +----------------------- + +Let's say you have a loaded cache of files or want to implement a check before the VFS reads a file. This is done by +setting the :py:meth:`_do_read_path ` hook. + +.. code-block:: python + + allowable_loads: Set[Path] = get_allowable_file_reads() + file_data: dict[Path, str] = get_cached_files() + + def _do_read_path(self, path) -> str: + if path in file_data: + return file_data[path] + + if path in allowable_loads: + return super()._do_read_path(path) + + raise PermissionError(path) + + vfs = VirtualFileSystem(base_path, None, [src_path]) + vfs._do_read_path = _do_read_path + +AST1 Parser Override +-------------------- + +By default SOLP uses :py:func:`` helper to choose a builtin ANTLR parser. For +custom parsers, create a shim for :py:meth:`_add_loaded_source `. + +.. code-block:: python + + def my_creator(input_src, version = None, origin = None): + ... + + add_loaded_source = vfs._add_loaded_source + + def shim(*args, **kwargs): + return add_loaded_source(*args, creator=my_creator, **kwargs) + + vfs._add_loaded_source = shim + +.. note:: The creator has to have the same signature as ``make_ast``. + From 426f36135d8f625466a04b70b3553839d7df8100 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 17:38:15 +0100 Subject: [PATCH 07/18] fix link in docs --- docs/source/getstarted/scopes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/getstarted/scopes.rst b/docs/source/getstarted/scopes.rst index 864f260..df40103 100644 --- a/docs/source/getstarted/scopes.rst +++ b/docs/source/getstarted/scopes.rst @@ -1,7 +1,7 @@ Symbols and Scopes ================== -The :py:mod:`scoping module ` for AST1 is a major service in SOLP that provides scope trees +The :py:mod:`scoping module ` for AST1 is a major service in SOLP that provides scope trees and tables to the :py:class:`AST2 Builder `. We'll work through using this API by considering a service that takes `LSP `_ From 42386e0335cae5aed22f2675290d524c2c681bd8 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 17:40:35 +0100 Subject: [PATCH 08/18] temp fix to force docs publish --- .github/workflows/gendocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gendocs.yml b/.github/workflows/gendocs.yml index 00952a1..f90c3a5 100644 --- a/.github/workflows/gendocs.yml +++ b/.github/workflows/gendocs.yml @@ -28,7 +28,7 @@ jobs: sphinx-build -M html docs/source docs/build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + if: ${{ github.event_name == 'push' }} with: publish_branch: gh-pages github_token: ${{ secrets.GITHUB_TOKEN }} From 2a86194d3a9a59fe1141d684d6316aae34db9a26 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 21:20:29 +0100 Subject: [PATCH 09/18] add autosection to docs --- docs/source/conf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index b9cbfb3..426195a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,12 +15,16 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ + 'sphinx.ext.autosectionlabel', 'sphinx.ext.autodoc', 'sphinx_autodoc_typehints', 'sphinx.ext.autosummary', 'autoapi.extension' ] +# Make sure the target is unique +autosectionlabel_prefix_document = True + autoapi_dirs = ['../../src'] autoapi_keep_files = True autoapi_ignore = ['*/grammar/*'] From 97f104c1286a098ced6c49d013110a8101791069 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 21:20:54 +0100 Subject: [PATCH 10/18] add docs editorial suggestions --- docs/source/getstarted/clients.rst | 4 +++- docs/source/getstarted/quickstart.rst | 12 ++++++------ docs/source/getstarted/sourcecode.rst | 4 ++-- docs/source/getstarted/twoASTs.rst | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/source/getstarted/clients.rst b/docs/source/getstarted/clients.rst index 07f7722..a0aea3c 100644 --- a/docs/source/getstarted/clients.rst +++ b/docs/source/getstarted/clients.rst @@ -9,7 +9,7 @@ Who Is This Document For? This is for people who want to use SOLP in their own projects. Set Up a Virtual Environment (Optional) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It's always recommended to set up a virtual environment (venv) instead of installing the package in the global pip cache. @@ -36,6 +36,8 @@ Windows: Installing ^^^^^^^^^^ +Finally, install the SOLP python package. + .. code-block:: bash pip install diff --git a/docs/source/getstarted/quickstart.rst b/docs/source/getstarted/quickstart.rst index 02d4edd..fa4be15 100644 --- a/docs/source/getstarted/quickstart.rst +++ b/docs/source/getstarted/quickstart.rst @@ -10,8 +10,8 @@ Toy Project ----------- This tutorial uses the ``example/project`` Solidity project provided in the SOLP repository. It includes examples of -`imports: `_ and -`solc remappings `_ as well regular Solidity code. +`imports `_ and +`solc remappings `_ as well regular Solidity code. Here is the contract we'll be parsing. As you can see, it defines contract TestContract, which inherits from Ownable; uses the inherited ``onlyOwner`` modifier; and does some simple function calls: @@ -60,7 +60,7 @@ Copy the ``example`` folder to somewhere on your machine — ``example/project`` on. Creating a Virtual File System (VFS) ------------------------------------ +------------------------------------ For SOLP to understand the code in the example project, it has to know where the source files, library files, and import remappings are located and how the project is structured. @@ -113,8 +113,8 @@ give us this very easily. We can then, for example, get the header information f While this might be useful, there are two limitations here: -* We can't get a reference to the ``ContractDefinition`` for Ownable (the inherited contract). In other words, we only know its name at this point but not where it comes from or what it contains. -* We have to load each source file one at a time instead of letting SOLP discover its way through the project. +# We can't get a reference to the ``ContractDefinition`` for Ownable (the inherited contract). In other words, we only know its name at this point but not where it comes from or what it contains. +# We have to load each source file one at a time instead of letting SOLP discover its way through the project. Getting AST2 Nodes @@ -298,7 +298,7 @@ the output formatting and exact form might not match the original source code, b semantically equal. If you need to maintain the original format of the code, there are ways to do this using the -:doc:`line data ` of the node. +:ref:`getstarted/sourcecode:IDE Line Data` of the node. Next Steps ---------- diff --git a/docs/source/getstarted/sourcecode.rst b/docs/source/getstarted/sourcecode.rst index bf220b8..e99d99a 100644 --- a/docs/source/getstarted/sourcecode.rst +++ b/docs/source/getstarted/sourcecode.rst @@ -130,7 +130,7 @@ annotating. IDE Line Data """"""""""""" -However, we can also get the corrected and column information for the +However, we can also get the corrected column information for the :py:attr:`start ` and :py:attr:`end ` of the node if we need to provide these insights to an IDE language extension, for example. @@ -170,7 +170,7 @@ Now create a function to do the text insertions and return the updated source co return current_source_code -This code might look scary, but we'll go through it step by step: +This code might look intimidating, but we'll go through it step by step: * Line 1 simply reverse sorts the insertions based on the order of the functions in the original source code. If we did a top-down insertion instead, every insertion would mess up the insertion location of the subsequent ones. diff --git a/docs/source/getstarted/twoASTs.rst b/docs/source/getstarted/twoASTs.rst index 8f57415..fa164fa 100644 --- a/docs/source/getstarted/twoASTs.rst +++ b/docs/source/getstarted/twoASTs.rst @@ -189,8 +189,8 @@ as defined in the library. Final Words ----------- -Hopefully this document has helped you understand why SOLP as two forms of AST. They look similar, but there are -important details that make AST2 better for most developers. +This document aimed to clarify why SOLP are two forms of AST. They look similar, but there are important details that +make AST2 better for most developers. There is a lot more you can do with SOLPs ASTs; there are other components and use cases of SOLP that will be documented more in the future. In the meantime, check out the :py:mod:`API reference ` to see From 5e7514b7e35db439ddc10daa4f3ccf0943992368 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 21:22:30 +0100 Subject: [PATCH 11/18] fix sourecode doc typo --- docs/source/getstarted/sourcecode.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/getstarted/sourcecode.rst b/docs/source/getstarted/sourcecode.rst index e99d99a..e0eedb2 100644 --- a/docs/source/getstarted/sourcecode.rst +++ b/docs/source/getstarted/sourcecode.rst @@ -130,7 +130,7 @@ annotating. IDE Line Data """"""""""""" -However, we can also get the corrected column information for the +However, we can also get the corrected line and column information for the :py:attr:`start ` and :py:attr:`end ` of the node if we need to provide these insights to an IDE language extension, for example. From c84cf7b17dd62b0b44b6bab05e89b7905f71fce0 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 21:25:46 +0100 Subject: [PATCH 12/18] update docs --- docs/imgs/astmods2.png | Bin 141419 -> 141474 bytes docs/source/getstarted/scopes.rst | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/imgs/astmods2.png b/docs/imgs/astmods2.png index aced71abe3f07d713c170fc17a93469bcc23cbdf..24670ae96408c271bf8a2ede7ad81c89c30b98b6 100644 GIT binary patch delta 83920 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

`<()^6R?eWtWV^is3m>>xXu_FoKEpBP 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 P5&zTGHqxrpw0rRXH)2Vf diff --git a/docs/source/getstarted/scopes.rst b/docs/source/getstarted/scopes.rst index df40103..f03606b 100644 --- a/docs/source/getstarted/scopes.rst +++ b/docs/source/getstarted/scopes.rst @@ -84,9 +84,10 @@ Unqualified .. note:: The ``get_symbol_link`` function will be shown later -*What does ``res_syms`` do? Why not just return the symbols found in the scope?* +*What does res_syms do? Why not just return the symbols found in the scope?* -This is because SOLP has different types of symbols: some are actual symbols based on elements in the real source code +``res_syms`` resolves symbolic links in the symbol table to their underlying symbols. This is because SOLP has different +types of symbols: some are actual symbols based on elements in the real source code and some are created because of *links* created from inherits and imports or using statements. Since we want to locate source code elements, we need to get the underlying symbol(s). From f4aa9a025e9481ec906c9c52ecad11c2519e8da7 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Mon, 6 May 2024 22:13:32 +0100 Subject: [PATCH 13/18] change doc deploy dir --- .github/workflows/gendocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gendocs.yml b/.github/workflows/gendocs.yml index f90c3a5..f6a9494 100644 --- a/.github/workflows/gendocs.yml +++ b/.github/workflows/gendocs.yml @@ -32,5 +32,5 @@ jobs: with: publish_branch: gh-pages github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: docs/build/ + publish_dir: docs/build/html force_orphan: true \ No newline at end of file From da3766dbc5ae7f48ac918775c95d0b1932e99b08 Mon Sep 17 00:00:00 2001 From: Grace Stone Date: Tue, 7 May 2024 09:55:45 -0600 Subject: [PATCH 14/18] devdocs edit --- docs/source/getstarted/clients.rst | 6 +- docs/source/getstarted/quickstart.rst | 6 +- docs/source/getstarted/scopes.rst | 124 +++++++++++++------------- docs/source/getstarted/sourcecode.rst | 6 +- docs/source/getstarted/twoASTs.rst | 12 +-- docs/source/getstarted/vfshooks.rst | 18 ++-- 6 files changed, 85 insertions(+), 87 deletions(-) diff --git a/docs/source/getstarted/clients.rst b/docs/source/getstarted/clients.rst index a0aea3c..4fc9d4d 100644 --- a/docs/source/getstarted/clients.rst +++ b/docs/source/getstarted/clients.rst @@ -2,7 +2,7 @@ Client Setup =============== .. note:: - Before installing SOLP, follow the instructions in the :doc:`prereq` document.. + Before installing SOLP, follow the instructions in the :doc:`prereq` document. Who Is This Document For? ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,10 +36,10 @@ Windows: Installing ^^^^^^^^^^ -Finally, install the SOLP python package. +Finally, install the SOLP python package, .. code-block:: bash pip install -Where ```` is a path to a clone of the repository or ``git+https://github.com/Zellic/solidity-parser.git``. +where ```` is a path to a clone of the repository or ``git+https://github.com/Zellic/solidity-parser.git``. diff --git a/docs/source/getstarted/quickstart.rst b/docs/source/getstarted/quickstart.rst index fa4be15..02afeb5 100644 --- a/docs/source/getstarted/quickstart.rst +++ b/docs/source/getstarted/quickstart.rst @@ -11,7 +11,7 @@ Toy Project This tutorial uses the ``example/project`` Solidity project provided in the SOLP repository. It includes examples of `imports `_ and -`solc remappings `_ as well regular Solidity code. +`solc remappings `_ as well as regular Solidity code. Here is the contract we'll be parsing. As you can see, it defines contract TestContract, which inherits from Ownable; uses the inherited ``onlyOwner`` modifier; and does some simple function calls: @@ -140,7 +140,7 @@ classes make this super simple! In this example, we only loaded the entry point (TestContract.sol), but during symbol-table building, the Ownable.sol file was also parsed. This makes it available later for AST2 building. -Now get the AST2 nodes using :py:meth:`Builder.get_top_level_units `. This includes the Ownable and MyContract contracts, but to demonstrate the tree searching behavior, we'll use +Now get the AST2 nodes using :py:meth:`Builder.get_top_level_units `. This includes the Ownable and MyContract contracts, but to demonstrate the tree-searching behavior, we'll use MyContract only. .. code-block:: python @@ -214,7 +214,7 @@ Quick Consistent Hashes ^^^^^^^^^^^^^^^^^^^^^^^ Often we want to use nodes as keys in dicts, so we need a hash function. Python dataclasses don't support this for -definitions with mutable attributes or lists but SOLP does. Let's find which variables are set by which functions. +definitions with mutable attributes or lists, but SOLP does. Let's find which variables are set by which functions. .. code-block:: python diff --git a/docs/source/getstarted/scopes.rst b/docs/source/getstarted/scopes.rst index f03606b..11da030 100644 --- a/docs/source/getstarted/scopes.rst +++ b/docs/source/getstarted/scopes.rst @@ -5,19 +5,19 @@ The :py:mod:`scoping module ` for AST1 is a major se and tables to the :py:class:`AST2 Builder `. We'll work through using this API by considering a service that takes `LSP `_ -requests to find the definition of whatever you click on in the IDE(e.g. Visual Studio Code). This won't be the full plugin: -just the SOLP code required to make it work. The code is adapted from an existing plugin written with the `pygls `_ and +requests to find the definition of whatever you click on in the IDE (e.g., Visual Studio Code). This won't be the full plug-in, +just the SOLP code required to make it work. The code is adapted from an existing plug-in written with the `pygls `_ and `lsprotocol `_ libraries. Line to Node ------------ -As we saw in the :doc:`sourcecode` tutorial, SOLP lets us map nodes to source code locations easily. Usually IDEs make +As we saw in the :doc:`sourcecode` tutorial, SOLP lets us map nodes to source code locations easily. Usually, IDEs make requests based on the line and column number and expect the language tool to figure out what is at that location. Let's make a function that does that: it should take a list of possible AST1 nodes and a source location and determine the exact node that is defined at that source location. The :py:meth:`SourceLocationSpan.does_contain() `, -available for every node with :py:meth:`get_source_span() ` will work +available for every node with :py:meth:`get_source_span() `, will work for this. All we need to do is recurse until we find the deeepest node whose span includes the location: @@ -34,16 +34,16 @@ All we need to do is recurse until we find the deeepest node whose span includes return get_containing_ast_node(src_loc, children) if children else n return None -When a node has no more children, it must be the deepest node in the tree(a leaf). +When a node has no more children, it must be the deepest node in the tree (a leaf). .. note:: Since each node has a :py:meth:`get_children() ` function, we can - do this in a generic way without having to handle each Node separately using a visitor! + do this in a generic way without having to handle each node separately using a visitor. Idents Only ----------- -If this node is an identifier then we can do the reference search. If it's anything else(e.g. a Solidity keyword, a -punctuator, etc) then we can't get a definition. +If this node is an identifier, then we can do the reference search. If it's anything else (a Solidity keyword, a +punctuator, etc.), then we can't get a definition. .. code-block:: python @@ -53,15 +53,15 @@ punctuator, etc) then we can't get a definition. Resolving the Reference ----------------------- -The reference could be qualified, e.g. ``x.y`` or unqualified ``y``. The way in which ``y`` is accessed changes the -scopes we need to search. The differences between the cases are: +The reference could be qualified (e.g., ``x.y``) or unqualified (``y``). The way in which ``y`` is accessed changes the +scopes we need to search. The differences between the cases are the following: -* Unqualified: search for ``y`` in the :py:attr:`node scope ` of ``ast1_node`` -* Qualified: figure out the type of ``x``, search for that type in ``ast1_node.scope`` to find a **type scope** and search for ``y`` in that type scope +* Unqualified: Search for ``y`` in the :py:attr:`node scope ` of ``ast1_node``. +* Qualified: Figure out the type of ``x``, search for that type in ``ast1_node.scope`` to find a **type scope**, and search for ``y`` in that type scope. Qualified lookups are modelled by the :py:class:`GetMember ` node in AST1. So -far we know that ``y`` is an :py:class:`Ident `, we need to determine what type of -lookup it is: +far we know that ``y`` is an :py:class:`Ident `; we need to determine what type of +lookup it is. .. code-block:: python @@ -70,7 +70,7 @@ lookup it is: else: # unqualified -Check the parent! Qualified lookups have a base, ``x`` and the member is ``y``. +Check the parent! Qualified lookups have a base ``x``, and the member is ``y``. Unqualified ^^^^^^^^^^^ @@ -82,12 +82,12 @@ Unqualified for rs in s.res_syms(): links.append(get_symbol_link(rs)) -.. note:: The ``get_symbol_link`` function will be shown later +.. note:: The ``get_symbol_link`` function will be shown later. -*What does res_syms do? Why not just return the symbols found in the scope?* +What does ``res_syms`` do? Why not just return the symbols found in the scope? -``res_syms`` resolves symbolic links in the symbol table to their underlying symbols. This is because SOLP has different -types of symbols: some are actual symbols based on elements in the real source code +In short, ``res_syms`` resolves symbolic links in the symbol table to their underlying symbols. This is because SOLP has different +types of symbols; some are actual symbols based on elements in the real source code and some are created because of *links* created from inherits and imports or using statements. Since we want to locate source code elements, we need to get the underlying symbol(s). @@ -104,7 +104,7 @@ that's built into the AST2 builder. base_obj: solnodes1.AST1Node = ast1_node.parent.obj_base base_type: solnodes2.Types = type_helper.get_expr_type(base_obj) -This bit of code is tricky so it's best to use Python typehints here. The :py:class:`Type ` +This bit of code is tricky, so it's best to use Python type hints here. The :py:class:`Type ` returned from the TypeHelper is an :py:attr:`AST2 type `. This AST2 type is passed back to the type helper to find the scopes to search: @@ -123,51 +123,51 @@ Search these scopes in the same way as the previous case: for rs in s.res_syms(): links.append(get_symbol_link(rs)) -get_symbol_link +Details of ``get_symbol_link`` --------------- -The exact details of ``get_symbol_link`` depend on what LSP framework you're using. Usually the following info is needed +The exact details of ``get_symbol_link`` depend on what LSP framework you're using. Usually, the following info is needed from the reference that's found: -* Whether it's a builtin type/object +* Whether it's a built-in type/object * The file it's is defined in -* The span of the Node that defines the Symbol and the span of the Node's descriptor/name +* The span of the node that defines the symbol and the span of the node's descriptor/name Scope vs Node ^^^^^^^^^^^^^ -The AST1 node is found by the :py:attr:`value ` attribute of the Symbol. In -general you can think of the value as being the Node that caused the Symbol to be created in the symbol's scope. +The AST1 node is found by the :py:attr:`value ` attribute of the symbol. In +general, you can think of the value as being the node that caused the symbol to be created in the symbol's scope. -For Solidity builtin symbols, the ``value`` is usually None, but obviously even if it has a value, it can't -be a real AST1 node: SOLP doesn't parse the builtins, they are created only in the symbol table. +For Solidity built-in symbols, the ``value`` is usually ``None``, but even if it has a value, it can't +be a real AST1 node. SOLP doesn't parse the built-ins; they are created only in the symbol table. -Checking for Builtins +Checking for Built-ins ^^^^^^^^^^^^^^^^^^^^^ -This part is easy, check if the Symbol is any of the following types: +This part is simple. Check if the symbol is any of the following types: -* :py:class:`BuiltinFunction `: self explanatory, e.g. ``keccak256()`` or ``abi.encode()`` -* :py:class:`BuiltinObject `: this is the ``msg`` part of ``msg.value``, i.e. the container object that has other builtins -* :py:class:`BuiltinValue `: e.g. ``msg.value`` +* :py:class:`BuiltinFunction ` (self explanatory, for example ``keccak256()`` or ``abi.encode()``) +* :py:class:`BuiltinObject ` (this is the ``msg`` part of ``msg.value``, that is the container object that has other built-ins) +* :py:class:`BuiltinValue ` (e.g., ``msg.value``) .. code-block:: python def is_builtin(sym): return isinstance(sym, (symtab.BuiltinFunction, symtab.BuiltinObject, symtab.BuiltinValue)) -Mock Builtin File +Mock Built-in File """"""""""""""""" -When the user tries to find the definition for a builtin, let's give them a file to view that contains pseudocode with -documentation, e.g. when they click on ``msg.sender`` it opens a file called ``builtins.sol`` and goes to a struct +When the user tries to find the definition for a built-in, let's give them a file to view that contains pseudocode with +documentation. For example, when they click on ``msg.sender``, it opens a file called builtins.sol and goes to a struct member in a struct named ``Msg``. -To do this, we need to take our builtin symbol table object from above, parse the ``builtins.sol`` file and find a +To do this, we need to take our built-in symbol-table object from above, parse the builtins.sol file, and find a corresponding AST1 node that we will use for the rest of ``get_symbol_link``. -To do this let's say we have another VFS and symbol table builder setup with just the ``builtins.sol`` file -loaded(to avoid any nasty mixing with the real Solidity code of the project open in the IDE): +To do this, let's say we have another VFS and symbol-table builder setup with just the builtins.sol file +loaded (to avoid any nasty mixing with the real Solidity code of the project open in the IDE). .. code-block:: python @@ -180,12 +180,12 @@ loaded(to avoid any nasty mixing with the real Solidity code of the project open real_builtins_symbol = builtins_fs.find_multi_part_symbol(symbol_path) -We compute a `root path`, i.e. a fully qualified path from the FileScope of the ``builtin_symbol`` to the symbol itself. -For example, if we had the BuiltinValue representing ``msg.sender``, the key we get is ``msg.sender``. +We compute a `root path` (i.e., a fully qualified path from the FileScope of the ``builtin_symbol`` to the symbol itself). +For example, if we had the ``BuiltinValue`` representing ``msg.sender``, the key we get is ``msg.sender``. -``find_multi_part_symbol`` does the qualified search using the key and finds the real symbol. +Additionally, ``find_multi_part_symbol`` does the qualified search using the key and finds the real symbol. -To actually compute the key, there are a few tricky details: +To actually compute the key, there are a few tricky details. .. code-block:: python :linenos: @@ -210,24 +210,22 @@ To actually compute the key, there are a few tricky details: The general algorithm goes like this: -* Take the current symbol, find its parents recursively until we get to the FileScope(or RootScope for builtins) - * store the primary alias of the symbol as part of the key(most symbols only have 1 alias) - * this gives a reversed list of each of the parts of the key, e.g. ``['sender', 'msg']`` -* reverse the list and join the parts together with dots +* Take the current symbol and find its parents recursively until we get to the FileScope (or RootScope for built-ins). +* Store the primary alias of the symbol as part of the key (most symbols only have one alias). This gives a reversed list of each of the parts of the key (e.g., ``['sender', 'msg']``). +* Reverse the list and join the parts together with dots. -The tricky parts are: +These are the tricky parts: -* Lines 6-9: we can't name a contract address or address payable in Solidity as it's a language keyword, instead - prefix these names with an underscore -* Lines 14-15: the ``transfer`` and ``send`` functions are stored under the address object in the symtab as old - versions of Solidity allowed this whereas now it's only supported for for address payable: remap these functions to - address payable in ``builtins.sol`` +* Lines 6–9. We can't name a contract address or address payable in Solidity as it's a language keyword. Instead, prefix these names with an underscore. +* Lines 14–15. The ``transfer`` and ``send`` functions are stored under the address object in the symtab as old + versions of Solidity allowed this. Whereas now, it's only supported for address payable. Remap these functions to + address payable in builtins.sol. Finding the File ^^^^^^^^^^^^^^^^ The symbol table creates a :py:class:`FileScope ` when it parses each file from -the VFS. It has the `source unit name `_ +the VFS. It has the `source unit name `_, which we use to find the file path from the VFS. .. code-block:: python @@ -246,13 +244,13 @@ The LSP deals with URIs, not paths, so convert the resultant path: uris.from_fs_path(str(file_path)) -.. note:: If we pass in the appropriate VFS and real symbol for the builtins case, this same function works to give the - URI of the ``builtins.sol``! +.. note:: If we pass in the appropriate VFS and real symbol for the built-ins case, this same function works to give the + URI of the builtins.sol! Node Spans ^^^^^^^^^^ -To recap, we can take a source location, find the AST node there, check if it's a reference, resolve the reference and +To recap, we can take a source location, find the AST node there, check if it's a reference, resolve the reference, and find a corresponding AST node that the reference may be referring to. Now all we need to do is get the range of the name of this node and the range of the entire node to return to the LSP client. @@ -264,14 +262,14 @@ name of this node and the range of the entire node to return to the LSP client. end = lsp.Position(solp_end.line-1, solp_end.column-1) return lsp.Range(start, end) -This function is very simple, it just copies the data from the node into the ``lsp.Range`` object. I've shown it as it -highlights how SOLP source locations are `1 based` whereas LSP/IDE locations for this usecase are `0 based`, hence the +This function is very simple. It just copies the data from the node into the ``lsp.Range`` object. We've shown it as it +highlights how SOLP source locations are `1 based` whereas LSP/IDE locations for this use case are `0 based`, hence the ``-1``s on each position. Definition Name Span """""""""""""""""""" -This gets the range of the name of the target node only, e.g. it would highlight just the name of the function or the +This gets the range of the name of the target node only. For example, it would highlight just the name of the function or the name of the contract that has been referenced. .. code-block:: python @@ -284,7 +282,7 @@ name of the contract that has been referenced. Definition Span """"""""""""""" -This gets the range of the entire target node, e.g. from the keyword ``function`` all the way to the closing curly brace +This gets the range of the entire target node, for example from the keyword ``function`` all the way to the closing curly brace of a function definition. .. code-block:: python @@ -295,6 +293,6 @@ Closing Notes ------------- While this tutorial can't cover the entire plumbing required to make a language server for Solidity, the concepts -introduced here will help you get there. In fact, most of the code in this guide is taken from our open source demo -implementation available on `Github `_. +introduced here will help you get there. In fact, most of the code in this guide is taken from our open-source demo +implementation available on `GitHub `_. diff --git a/docs/source/getstarted/sourcecode.rst b/docs/source/getstarted/sourcecode.rst index e0eedb2..64dc65b 100644 --- a/docs/source/getstarted/sourcecode.rst +++ b/docs/source/getstarted/sourcecode.rst @@ -20,7 +20,7 @@ output. .. figure:: ../../imgs/astmods2.png :class: with-border - An overview of the strategy + An overview of the strategy. Setup ----- @@ -119,7 +119,7 @@ fill in the details as we go along: Working With Source Buffers """"""""""""""""""""""""""" -The ``annotate_func`` function is where we would put the call to an AI service(or static analysis) that takes the source code of the **function only** +The ``annotate_func`` function is where we would put the call to an AI service (or static analysis) that takes the source code of the **function only** and provides a summary. Also, ``func_src`` is extracted from the :py:attr:`source text buffer ` using @@ -176,7 +176,7 @@ This code might look intimidating, but we'll go through it step by step: a top-down insertion instead, every insertion would mess up the insertion location of the subsequent ones. * Lines 6–7 simply create a split in the text for us to put the function-summary comment. Since we're inserting comments before each function, we use the ``start_buffer_index`` — ``left`` then becomes all of the code in the file up to the ``function`` - keyword and right is everything that comes after. When we insert our comment after ``left`` but before ``right``, it + keyword and ``right`` is everything that comes after. When we insert our comment after ``left`` but before ``right``, it puts our comment right above the function. * Lines 10–11 put the comments on the same indentation level as the function to make it easier to read. * Line 12 simply joins up all the parts and whitespace required, creating a complete source file's worth of code. diff --git a/docs/source/getstarted/twoASTs.rst b/docs/source/getstarted/twoASTs.rst index fa164fa..9b623bc 100644 --- a/docs/source/getstarted/twoASTs.rst +++ b/docs/source/getstarted/twoASTs.rst @@ -29,7 +29,7 @@ TopLevelUnits vs SourceUnits All nodes have a ``parent`` attribute, right? So let's say we have a function, modifier, event (etc.) definition, and we want to get the contract it -was declared in, we just take the parent and use it like it's a Contract. +was declared in. We just take the parent and use it like it's a contract. Hold on! There's a couple of assumptions there. Consider the following Solidity valid code: @@ -53,7 +53,7 @@ There are two things to note here. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This point is solved by changing our mental model slightly. Does it really matter that the parent is a library or a contract? -Usually, not really. Instead, we generalize the parent of something like a function or a state variable to be a ``TopLevelUnit`` in AST2. +Usually, not really. Instead, we generalize the parent of something like a function or a state variable to be a TopLevelUnit in AST2. Without needing to know the specific definition type, we can * get type information (:py:meth:`as_type() `) @@ -113,13 +113,13 @@ in the AST2 ``function.code`` for ``toUint256``, the revert node is this: Imports, Pragmas, Usings ------------------------ -AST1 has a bunch of ``SourceUnit`` subclasses such as ``PragmaDirective``, ``ImportDirective``, and ``UsingDirective``. We don't see them in AST2; what's going on? +AST1 has a bunch of SourceUnit subclasses such as ``PragmaDirective``, ``ImportDirective``, and ``UsingDirective``. We don't see them in AST2; what's going on? These constructs in Solidity require compiler support for the Solidity code to make sense. For example, * Imports need to be resolved using path resolution rules. * Pragmas influence the compiler version. -* Using statements changes what members are available for a type in a given scope. +* Using statements change what members are available for a type in a given scope. These are complicated details that aren't useful to most people who need to the use the AST; they just want to deal with a simple AST interface that lets them easily navigate the Solidity code. @@ -161,7 +161,7 @@ Consider the contracts: Import Resolution ^^^^^^^^^^^^^^^^^ -The import on line 13 is removed in AST2. The ``LibraryDefinition`` generated from `dderLib.sol is directly referenced +The import on line 13 is removed in AST2. The ``LibraryDefinition`` generated from AdderLib.sol is directly referenced on line 16 as a :py:class:`ResolvedUserType `, which, as the name suggests, is a :py:class:`Type ` containing a reference to the library definition. However, the AST1 :py:class:`UserType ` only knows the textual name of the type used in the Solidity source code. @@ -178,7 +178,7 @@ Using Directives ^^^^^^^^^^^^^^^^ In a similar vein, the library call on line 20 is made explicit in AST2. As shown by the ``code_str`` of the node below, -the previous 2 argument function call now takes takes the base as the first argument, matching the signature of ``add`` +the previous 2-ary function call now takes takes the base as the first argument, matching the signature of ``add`` as defined in the library. .. code-block:: Solidity diff --git a/docs/source/getstarted/vfshooks.rst b/docs/source/getstarted/vfshooks.rst index 48f07ad..892e4db 100644 --- a/docs/source/getstarted/vfshooks.rst +++ b/docs/source/getstarted/vfshooks.rst @@ -1,27 +1,27 @@ -Customising File Parsing +Customizing File Parsing ======================== -So far all of the guides have used the default config of the :py:class:`VirtualFileSystem ` -to find, load and parse the input Solidity code. This guide goes over customising parser versions, file resolution and +So far, all of the guides have used the default config of the :py:class:`VirtualFileSystem ` +to find, load, and parse the input Solidity code. This guide goes over customizing parser versions, file resolution, and useful tips for hooking into the VFS. Parser Version -------------- -SOLP is the only tool that's able to parse any version of Solidity source code; it doesn't require lots of builds of -SOLP and doesn't work on EVM bytecode. To do this, the Solidity version pragma in each file is processed and a suitable +SOLP is the only tool that's able to parse any version of Solidity source code. It doesn't require a lot of builds of +SOLP and doesn't work on EVM bytecode. To do this, the Solidity version pragma in each file is processed, and a suitable parser version is inferred. -Sometimes this inference doesn't work: files may have conflicting versions or versions may be omitted. +Sometimes this inference doesn't work; files may have conflicting versions or versions may be omitted. To get around this, pass a :py:class:`Version ` to the VFS constructor. -This will force the parser version and the language version for different steps later on, e.g. +This will force the parser version and the language version for different steps later on. For example, this .. code-block:: python vfs = VirtualFileSystem(base_path, None, [src_path], compiler_version=Version(0, 8, 22)) -would force the version to Solidity 0.8.22 +would force the version to Solidity 0.8.22. Overriding File Reading ----------------------- @@ -49,7 +49,7 @@ setting the :py:meth:`_do_read_path ` helper to choose a builtin ANTLR parser. For +By default, SOLP uses the :py:func:`` helper to choose a built-in ANTLR parser. For custom parsers, create a shim for :py:meth:`_add_loaded_source `. .. code-block:: python From d71b5fb30b55a74faff67a3629b0b0724a85e3fc Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Tue, 7 May 2024 17:20:02 +0100 Subject: [PATCH 15/18] doc editor review --- docs/source/getstarted/quickstart.rst | 4 ++-- docs/source/getstarted/scopes.rst | 10 ++++++---- docs/source/getstarted/twoASTs.rst | 8 ++++---- docs/source/getstarted/vfshooks.rst | 5 +++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/source/getstarted/quickstart.rst b/docs/source/getstarted/quickstart.rst index 02afeb5..44a1e83 100644 --- a/docs/source/getstarted/quickstart.rst +++ b/docs/source/getstarted/quickstart.rst @@ -113,8 +113,8 @@ give us this very easily. We can then, for example, get the header information f While this might be useful, there are two limitations here: -# We can't get a reference to the ``ContractDefinition`` for Ownable (the inherited contract). In other words, we only know its name at this point but not where it comes from or what it contains. -# We have to load each source file one at a time instead of letting SOLP discover its way through the project. +#. We can't get a reference to the ``ContractDefinition`` for Ownable (the inherited contract). In other words, we only know its name at this point but not where it comes from or what it contains. +#. We have to load each source file one at a time instead of letting SOLP discover its way through the project. Getting AST2 Nodes diff --git a/docs/source/getstarted/scopes.rst b/docs/source/getstarted/scopes.rst index 11da030..d79ad2d 100644 --- a/docs/source/getstarted/scopes.rst +++ b/docs/source/getstarted/scopes.rst @@ -75,6 +75,8 @@ Check the parent! Qualified lookups have a base ``x``, and the member is ``y``. Unqualified ^^^^^^^^^^^ +In the unqualified lookup case, search the node's scope directly: + .. code-block:: python symbols = ast1_node.scope.find(ast1_node.text) @@ -124,7 +126,7 @@ Search these scopes in the same way as the previous case: links.append(get_symbol_link(rs)) Details of ``get_symbol_link`` ---------------- +------------------------------ The exact details of ``get_symbol_link`` depend on what LSP framework you're using. Usually, the following info is needed from the reference that's found: @@ -143,7 +145,7 @@ For Solidity built-in symbols, the ``value`` is usually ``None``, but even if it be a real AST1 node. SOLP doesn't parse the built-ins; they are created only in the symbol table. Checking for Built-ins -^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^ This part is simple. Check if the symbol is any of the following types: @@ -157,7 +159,7 @@ This part is simple. Check if the symbol is any of the following types: return isinstance(sym, (symtab.BuiltinFunction, symtab.BuiltinObject, symtab.BuiltinValue)) Mock Built-in File -""""""""""""""""" +"""""""""""""""""" When the user tries to find the definition for a built-in, let's give them a file to view that contains pseudocode with documentation. For example, when they click on ``msg.sender``, it opens a file called builtins.sol and goes to a struct @@ -264,7 +266,7 @@ name of this node and the range of the entire node to return to the LSP client. This function is very simple. It just copies the data from the node into the ``lsp.Range`` object. We've shown it as it highlights how SOLP source locations are `1 based` whereas LSP/IDE locations for this use case are `0 based`, hence the -``-1``s on each position. +``-1``\'s on each position. Definition Name Span """""""""""""""""""" diff --git a/docs/source/getstarted/twoASTs.rst b/docs/source/getstarted/twoASTs.rst index 9b623bc..8bd8f84 100644 --- a/docs/source/getstarted/twoASTs.rst +++ b/docs/source/getstarted/twoASTs.rst @@ -50,7 +50,7 @@ Hold on! There's a couple of assumptions there. Consider the following Solidity There are two things to note here. 1. The Parent of ``toUint256`` Is a ``LibraryDefinition`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This point is solved by changing our mental model slightly. Does it really matter that the parent is a library or a contract? Usually, not really. Instead, we generalize the parent of something like a function or a state variable to be a TopLevelUnit in AST2. @@ -76,8 +76,8 @@ Solidity allows free-floating definitions for functions and events as well as ne inside of a contract). This makes traversing AST1 nodes more difficult as you don't have a guarantee that the SourceUnit is a root node or if it is part of another SourceUnit. -2. FileDefinitions -^^^^^^^^^^^^^^^^^^^ +2. FileDefinitions Can Contain ContractParts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ask the virtual file system to load and parse the file above. You'll get a list of source units: @@ -119,7 +119,7 @@ These constructs in Solidity require compiler support for the Solidity code to m * Imports need to be resolved using path resolution rules. * Pragmas influence the compiler version. -* Using statements change what members are available for a type in a given scope. +* Using statements change which members are available for a type in a given scope. These are complicated details that aren't useful to most people who need to the use the AST; they just want to deal with a simple AST interface that lets them easily navigate the Solidity code. diff --git a/docs/source/getstarted/vfshooks.rst b/docs/source/getstarted/vfshooks.rst index 892e4db..6b8f968 100644 --- a/docs/source/getstarted/vfshooks.rst +++ b/docs/source/getstarted/vfshooks.rst @@ -66,3 +66,8 @@ custom parsers, create a shim for :py:meth:`_add_loaded_source Date: Thu, 9 May 2024 13:54:35 +0100 Subject: [PATCH 16/18] remove autoapi generated docs --- docs/source/autoapi/index.rst | 11 - .../solidity_parser/ast/ast2builder/index.rst | 313 --- .../ast/funcanalysis/index.rst | 130 - .../solidity_parser/ast/helper/index.rst | 50 - .../solidity_parser/ast/hierarchy/index.rst | 24 - .../autoapi/solidity_parser/ast/index.rst | 33 - .../solidity_parser/ast/mro_helper/index.rst | 45 - .../solidity_parser/ast/nodebase/index.rst | 299 -- .../ast/parsers/common/index.rst | 111 - .../ast/parsers/errors/index.rst | 38 - .../solidity_parser/ast/parsers/index.rst | 21 - .../ast/parsers/parsers060/index.rst | 316 --- .../ast/parsers/parsers070/index.rst | 44 - .../ast/parsers/parsers080/index.rst | 300 --- .../ast/parsers/parsers088/index.rst | 36 - .../ast/parsers/parsers08_22/index.rst | 56 - .../solidity_parser/ast/solnodes/index.rst | 1889 ------------- .../solidity_parser/ast/solnodes2/index.rst | 2393 ----------------- .../solidity_parser/ast/symtab/index.rst | 717 ----- .../solidity_parser/ast/types/index.rst | 810 ------ .../collectors/collector/index.rst | 26 - .../solidity_parser/collectors/index.rst | 19 - .../solidity_parser/collectors/v000/index.rst | 40 - .../solidity_parser/collectors/v060/index.rst | 35 - .../solidity_parser/collectors/v070/index.rst | 35 - .../solidity_parser/collectors/v080/index.rst | 35 - .../autoapi/solidity_parser/errors/index.rst | 43 - .../autoapi/solidity_parser/filesys/index.rst | 181 -- docs/source/autoapi/solidity_parser/index.rst | 27 - .../autoapi/solidity_parser/util/index.rst | 15 - .../util/version_util/index.rst | 83 - 31 files changed, 8175 deletions(-) delete mode 100644 docs/source/autoapi/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/helper/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/nodebase/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/solnodes/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/symtab/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/ast/types/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/collectors/collector/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/collectors/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/collectors/v000/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/collectors/v060/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/collectors/v070/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/collectors/v080/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/errors/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/filesys/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/util/index.rst delete mode 100644 docs/source/autoapi/solidity_parser/util/version_util/index.rst diff --git a/docs/source/autoapi/index.rst b/docs/source/autoapi/index.rst deleted file mode 100644 index a297ed9..0000000 --- a/docs/source/autoapi/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -API Reference -============= - -This page contains auto-generated API reference documentation [#f1]_. - -.. toctree:: - :titlesonly: - - /autoapi/solidity_parser/index - -.. [#f1] Created with `sphinx-autoapi `_ \ No newline at end of file diff --git a/docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst b/docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst deleted file mode 100644 index 3e70625..0000000 --- a/docs/source/autoapi/solidity_parser/ast/ast2builder/index.rst +++ /dev/null @@ -1,313 +0,0 @@ -:py:mod:`solidity_parser.ast.ast2builder` -========================================= - -.. py:module:: solidity_parser.ast.ast2builder - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.ast2builder.ErrorHandler - solidity_parser.ast.ast2builder.TypeHelper - solidity_parser.ast.ast2builder.Builder - - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.ast2builder.T - - -.. py:data:: T - - - -.. py:class:: ErrorHandler(create_state, quiet_errors=True) - - - Keeps track of what AST2Builder is doing and captures the line tracking information when errors happen. Also wraps - Python errors in our own errors types if required and provides assertion failure checking. - - The general idea of this class is to make sure AST2Builder operations return consistent error types by wrapping - them in CodeProcessingErrors so that the client can catch and decide what to do with them. - - .. py:method:: handle_processing_error(error: solidity_parser.errors.CodeProcessingError) - - Error callback handler for AST2Builder functions to call when a CodeProcessingError (only) occurs. - - - .. py:method:: make_processing_error_args(message: str, node: solidity_parser.ast.solnodes.AST1Node) -> solidity_parser.errors.CPEArgs - :staticmethod: - - Helper to make the input args tuple for a CodeProcessingError from a message and AST1 node - - - .. py:method:: with_error_context(func) - - Decorator that takes a function, f, and wraps it in a function that captures the current state of the builder - before executing f and restores the state afterwards. If any errors occur in the process, a CodeProcessingError - (specifically an UnexpectedCodeProcessingError) is raised, which should be allowed to propagate to the client of - the builder. - - - .. py:method:: todo(node) -> T - - Forces an error if the node is not supported by the builder. Since it always raises, the return type is fully - polymorphic and can be used by the builder to do anything. - E.g. a common pattern is to return the result of this function to mark the end of control flow in the builder - code return self.error_handler.todo(node) - - - .. py:method:: error(msg, *predicates) - - Raises an error with the given message if any of the predicates fail. This is used for user level errors, i.e. - the input code is invalid - - - .. py:method:: assert_error(msg, *predicates) - - Raises an assertion error with the given message if any of the predicates fail, very similar to error but used - for 'internal' errors, i.e. compiler assumptions that must pass - - - .. py:method:: _todo(node) -> T - - - .. py:method:: _error(msg, *predicates) - - - .. py:method:: _assert_error(msg, *predicates) - - - -.. py:class:: TypeHelper(builder: Builder, error_handler: ErrorHandler) - - - Helper class for computing AST2 types from AST1 nodes. This is required because AST1 nodes are not linked and do not - have type information associated with some nodes, i.e. the node trees aren't able to compute types on their own. - - .. py:method:: any_or_all(args) - :staticmethod: - - Returns True if any or all args are True - - - .. py:method:: create_filter_using_scope(base_type: solidity_parser.ast.types.Type) - - - .. py:method:: get_current_contract_type(node) -> solidity_parser.ast.solnodes2.ResolvedUserType - - Returns the ResolvedUserType the given node is declared in - - - .. py:method:: get_expr_type(expr: solidity_parser.ast.solnodes.Expr | solidity_parser.ast.types.Type, allow_multiple=False, force_tuple=False, function_callee=False) -> Union[solidity_parser.ast.solnodes2.Types, list[solidity_parser.ast.solnodes2.Types]] - - Main helper function that computes the AST2 type of the given AST1 expression - - :param expr: The AST1 expression to type, may be a Type also as types are part of both the AST1 and AST2 nodeset - :param allow_multiple: Changes the return of this function to a list of types instead of a single type. This is - required for expressions that may need extra contextual information to return a single - resolved Type, e.g. the callee of a function call without its arguments may resolve to - multiple callsites and if this is set to True, the return type will be a list of function - types - :param force_tuple: Forces the return type to be a TupleType instead of a single type in cases where it's - ambiguous, e.g. the expression (x) can be either a bracket expression or a tuple expression - :param function_callee: Whether the expression is the callee of a function call, required to compute the type of - state variable lookups as Solidity generates getter functions if the variable is used as - a function callee - :return: The AST2 type of the expression or a list of types if allow_multiple is True - - - .. py:method:: get_function_expr_type(expr, allow_multiple=False, return_target_symbol=False) - - - .. py:method:: map_as_type_arg(arg) - - This function tries to force the given expr argument into a type if it looks like a type - - The supplied grammar is ambiguous and sometimes parses types as expression e.g. byte[100] would end up as an - array access instead of a fixed length byte array. I've only really seen this happen for arguments of function - calls, i.e. in abi.decode hence the name of the function. Should probably see if this happens in other places in - the grammar too... - - - .. py:method:: param_types(ps) - - Returns the types of the given parameters - - - .. py:method:: symbol_to_ast2_type(symbol, function_callee=False) -> solidity_parser.ast.solnodes2.Types - - Computes the AST2 type of the given symtab Symbol - - - .. py:method:: scopes_for_type(node: solidity_parser.ast.solnodes.AST1Node, ttype: solidity_parser.ast.solnodes2.Types, use_encoded_type_key=True) -> List[solidity_parser.ast.symtab.Scope] - - - .. py:method:: map_type(ttype: solidity_parser.ast.types.Type) -> solidity_parser.ast.solnodes2.Types - - - .. py:method:: get_contract_type(user_type_symbol: solidity_parser.ast.symtab.Symbol) -> solidity_parser.ast.solnodes2.ResolvedUserType - - - .. py:method:: _symtab_top_level_predicate(base_scope) - - - .. py:method:: get_user_type(ttype: solidity_parser.ast.types.UserType) - - Maps an AST1 UserType to AST2 ResolvedUserType in the scope of the AST1 node that references the type - - - -.. py:class:: Builder - - - .. py:class:: State - - - .. py:attribute:: current_node - :type: solidity_parser.ast.solnodes.AST1Node - - - - - .. py:class:: FunctionCallee - - - .. py:attribute:: base - :type: Optional[solidity_parser.ast.solnodes2.Expr | solidity_parser.ast.symtab.Symbol] - - - - .. py:attribute:: symbols - :type: List[solidity_parser.ast.symtab.Symbol] - - - - - .. py:class:: PartialFunctionCallee - - - Bases: :py:obj:`FunctionCallee` - - .. py:attribute:: named_args - :type: Dict[str, solidity_parser.ast.solnodes2.Expr] - - - - - .. py:attribute:: ASSIGN_TO_OP - - - - .. py:method:: link_with_ast1() - - - .. py:method:: get_top_level_units() -> List[solidity_parser.ast.solnodes2.TopLevelUnit] - - - .. py:method:: enqueue_files(files: List[solidity_parser.ast.symtab.FileScope]) - - - .. py:method:: process_all() - - - .. py:method:: load_non_top_level_if_required(ast1_node: solidity_parser.ast.solnodes.SourceUnit | solidity_parser.ast.solnodes.ContractPart) -> solidity_parser.ast.solnodes2.ContractPart - - Ensures the given AST1 non top level node has been skeletoned as an AST2 node. This will - in turn skeleton any parent nodes that need to be made. - - For top level nodes use the load_if_required function instead - - - .. py:method:: load_if_required(user_type_symbol: solidity_parser.ast.symtab.Symbol) -> solidity_parser.ast.solnodes2.TopLevelUnit - - - .. py:method:: refine_stmt(node: solidity_parser.ast.solnodes.Stmt, allow_none=False) - - - .. py:method:: get_declaring_contract_scope(node: solidity_parser.ast.solnodes.AST1Node) -> Union[solidity_parser.ast.symtab.ContractOrInterfaceScope, solidity_parser.ast.symtab.LibraryScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.StructScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.FileScope] - - - .. py:method:: get_declaring_contract_scope_in_scope(scope: solidity_parser.ast.symtab.Symbol) -> Union[solidity_parser.ast.symtab.ContractOrInterfaceScope, solidity_parser.ast.symtab.LibraryScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.StructScope, solidity_parser.ast.symtab.EnumScope, solidity_parser.ast.symtab.FileScope] - - - .. py:method:: get_self_object(node: Union[solidity_parser.ast.solnodes.Stmt, solidity_parser.ast.solnodes.Expr]) - - - .. py:method:: get_super_object(node: Union[solidity_parser.ast.solnodes.Stmt, solidity_parser.ast.solnodes.Expr]) - - - .. py:method:: refine_call_function(expr, allow_error=False, allow_stmt=False, allow_event=False) - - - .. py:method:: is_subcontract(a: solidity_parser.ast.symtab.Scope, b: solidity_parser.ast.symtab.Scope) - - - .. py:method:: find_bound_operator_symbol(expr: solidity_parser.ast.solnodes.UnaryOp | solidity_parser.ast.solnodes.BinaryOp, input_types: list[solidity_parser.ast.solnodes2.Types]) - - - .. py:method:: refine_bound_operator(expr: Union[solidity_parser.ast.solnodes.UnaryOp, solidity_parser.ast.solnodes.BinaryOp], inputs: List[solidity_parser.ast.solnodes2.Expr]) - - - .. py:method:: get_function_call_symbol_base(s: solidity_parser.ast.symtab.Symbol) - - - .. py:method:: get_function_callee_buckets(symbols: List[solidity_parser.ast.symtab.Symbol]) - - - .. py:method:: refine_expr(expr: solidity_parser.ast.solnodes.Expr, is_function_callee=False, allow_type=False, allow_tuple_exprs=False, allow_multiple_exprs=False, allow_none=True, allow_stmt=False, is_argument=False, is_assign_rhs=False, allow_event=False) - - - .. py:method:: find_method(possible_matches: list[solidity_parser.ast.symtab.Symbol], arg_types: list[solidity_parser.ast.solnodes2.Types]) - - - .. py:method:: var(node: Union[solidity_parser.ast.solnodes.Var, solidity_parser.ast.solnodes.Parameter]) - - - .. py:method:: parameter(node: solidity_parser.ast.solnodes.Parameter) - - - .. py:method:: error_parameter(node: solidity_parser.ast.solnodes.ErrorParameter) - - - .. py:method:: ident(node: solidity_parser.ast.solnodes.Ident) - - - .. py:method:: modifiers(node_with_modifiers) - - - .. py:method:: modifier(node: solidity_parser.ast.solnodes.Modifier) - - - .. py:method:: process_code_block(node: solidity_parser.ast.solnodes.Block) - - - .. py:method:: block(node: solidity_parser.ast.solnodes.Block) - - - .. py:method:: get_synthetic_owner(source_unit_name, file_scope: solidity_parser.ast.symtab.FileScope) -> solidity_parser.ast.solnodes2.FileDefinition - - - .. py:method:: define_skeleton(ast1_node: solidity_parser.ast.solnodes.SourceUnit, source_unit_name: Optional[str]) -> solidity_parser.ast.solnodes2.TopLevelUnit | solidity_parser.ast.solnodes2.ContractPart - - - .. py:method:: refine_unit_or_part(ast1_node: Union[solidity_parser.ast.solnodes.SourceUnit, solidity_parser.ast.solnodes2.FileDefinition]) - - - .. py:method:: is_top_level(node: solidity_parser.ast.solnodes.AST1Node) - - - .. py:method:: should_create_skeleton(node: solidity_parser.ast.solnodes.AST1Node) -> bool - - - diff --git a/docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst b/docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst deleted file mode 100644 index 16272ea..0000000 --- a/docs/source/autoapi/solidity_parser/ast/funcanalysis/index.rst +++ /dev/null @@ -1,130 +0,0 @@ -:py:mod:`solidity_parser.ast.funcanalysis` -========================================== - -.. py:module:: solidity_parser.ast.funcanalysis - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.funcanalysis.PathEdgeKind - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.funcanalysis.find_matching_function_in_type - solidity_parser.ast.funcanalysis.find_possible_matching_functions_for_declared_type - solidity_parser.ast.funcanalysis.add_function_to_cg - solidity_parser.ast.funcanalysis.find_possible_calls - solidity_parser.ast.funcanalysis.mark_sources - solidity_parser.ast.funcanalysis.is_fca_important - solidity_parser.ast.funcanalysis.is_blackbox_node - solidity_parser.ast.funcanalysis.has_inline_yul - solidity_parser.ast.funcanalysis.find_important_paths2 - - - -.. py:function:: find_matching_function_in_type(ttype: solidity_parser.ast.solnodes2.TopLevelUnit, name, arg_types, ignore_current_type=False) - - -.. py:function:: find_possible_matching_functions_for_declared_type(declared_ttype: solidity_parser.ast.solnodes2.ResolvedUserType, name, arg_types, is_super_call) - - -.. py:function:: add_function_to_cg(cg: networkx.DiGraph, finished_functions, function: solidity_parser.ast.solnodes2.FunctionDefinition) - - -.. py:function:: find_possible_calls(declared_ttype: Union[solidity_parser.ast.solnodes2.ResolvedUserType, solidity_parser.ast.solnodes2.SuperType], name: str, arg_types: List[solidity_parser.ast.types.Type], match_filter=lambda x: True, use_subtypes=True) -> List[solidity_parser.ast.solnodes2.FunctionDefinition] - - -.. py:function:: mark_sources(units: List[solidity_parser.ast.solnodes2.TopLevelUnit]) - - -.. py:function:: is_fca_important(f: solidity_parser.ast.solnodes2.FunctionDefinition) - - -.. py:function:: is_blackbox_node(f: solidity_parser.ast.solnodes2.FunctionDefinition) - - -.. py:function:: has_inline_yul(f: solidity_parser.ast.solnodes2.FunctionDefinition) - - -.. py:class:: PathEdgeKind(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Create a collection of name/value pairs. - - Example enumeration: - - >>> class Color(Enum): - ... RED = 1 - ... BLUE = 2 - ... GREEN = 3 - - Access them by: - - - attribute access:: - - >>> Color.RED - - - - value lookup: - - >>> Color(1) - - - - name lookup: - - >>> Color['RED'] - - - Enumerations can be iterated over, and know how many members they have: - - >>> len(Color) - 3 - - >>> list(Color) - [, , ] - - Methods can be added to enumerations, and members can have their own - attributes -- see the documentation for details. - - .. py:attribute:: INTRA_CALL - :value: 1 - - - - .. py:attribute:: SINK_INTER - :value: 2 - - - - .. py:attribute:: SINK_NO_CODE - :value: 3 - - - - .. py:attribute:: SINK_FCA_IMPORTANT - :value: 4 - - - - .. py:attribute:: SINK_INLINE_YUL - :value: 5 - - - - -.. py:function:: find_important_paths2(source: solidity_parser.ast.solnodes2.FunctionDefinition) - - diff --git a/docs/source/autoapi/solidity_parser/ast/helper/index.rst b/docs/source/autoapi/solidity_parser/ast/helper/index.rst deleted file mode 100644 index 8545e7c..0000000 --- a/docs/source/autoapi/solidity_parser/ast/helper/index.rst +++ /dev/null @@ -1,50 +0,0 @@ -:py:mod:`solidity_parser.ast.helper` -==================================== - -.. py:module:: solidity_parser.ast.helper - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.helper.MyErrorListener - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.helper.get_processors - solidity_parser.ast.helper.make_ast - solidity_parser.ast.helper.param_type_str - - - -.. py:class:: MyErrorListener - - - Bases: :py:obj:`antlr4.error.ErrorListener.ErrorListener` - - .. py:method:: add_error(recognizer, line, column, msg) - - - .. py:method:: syntaxError(recognizer, offendingSymbol, line, column, msg, e) - - - -.. py:function:: get_processors(version: solidity_parser.util.version_util.Version) - - -.. py:function:: make_ast(input_src, version: solidity_parser.util.version_util.Version = None, origin=None) -> List[solidity_parser.ast.solnodes.SourceUnit] - - -.. py:function:: param_type_str(parameters: List[solidity_parser.ast.solnodes.Parameter]) -> str - - diff --git a/docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst b/docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst deleted file mode 100644 index eb1c186..0000000 --- a/docs/source/autoapi/solidity_parser/ast/hierarchy/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -:py:mod:`solidity_parser.ast.hierarchy` -======================================= - -.. py:module:: solidity_parser.ast.hierarchy - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.hierarchy.build_hierarchy - - - -.. py:function:: build_hierarchy(top_level_units: list[solidity_parser.ast.solnodes2.TopLevelUnit]) -> None - - Annotates the top level units with their direct subtypes, e.g. if A extends B, then A._subtypes = [B] - - diff --git a/docs/source/autoapi/solidity_parser/ast/index.rst b/docs/source/autoapi/solidity_parser/ast/index.rst deleted file mode 100644 index 5288e1e..0000000 --- a/docs/source/autoapi/solidity_parser/ast/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -:py:mod:`solidity_parser.ast` -============================= - -.. py:module:: solidity_parser.ast - - -Subpackages ------------ -.. toctree:: - :titlesonly: - :maxdepth: 3 - - parsers/index.rst - - -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - - ast2builder/index.rst - funcanalysis/index.rst - helper/index.rst - hierarchy/index.rst - mro_helper/index.rst - nodebase/index.rst - solnodes/index.rst - solnodes2/index.rst - symtab/index.rst - types/index.rst - - diff --git a/docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst b/docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst deleted file mode 100644 index c004936..0000000 --- a/docs/source/autoapi/solidity_parser/ast/mro_helper/index.rst +++ /dev/null @@ -1,45 +0,0 @@ -:py:mod:`solidity_parser.ast.mro_helper` -======================================== - -.. py:module:: solidity_parser.ast.mro_helper - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.mro_helper._merge - solidity_parser.ast.mro_helper.c3_linearise - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.mro_helper.T - - -.. py:function:: _merge(*sequences) - - -.. py:data:: T - - - -.. py:function:: c3_linearise(klass: T, get_supers: Callable[[T], list[T]] = None) -> list[T] - - A function to linearise the class hierarchy using the C3 linearisation algorithm. - - :param klass: The class to linearise. - :param get_supers: A function to get the superclasses of a given class, must return a list of classes with the same - type as the input - :return: A linearised list of classes following the C3 algorithm. - - diff --git a/docs/source/autoapi/solidity_parser/ast/nodebase/index.rst b/docs/source/autoapi/solidity_parser/ast/nodebase/index.rst deleted file mode 100644 index 6e9f254..0000000 --- a/docs/source/autoapi/solidity_parser/ast/nodebase/index.rst +++ /dev/null @@ -1,299 +0,0 @@ -:py:mod:`solidity_parser.ast.nodebase` -====================================== - -.. py:module:: solidity_parser.ast.nodebase - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.nodebase.SourceLocation - solidity_parser.ast.nodebase.SourceLocationSpan - solidity_parser.ast.nodebase.NodeList - solidity_parser.ast.nodebase.Ref - solidity_parser.ast.nodebase.Node - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.nodebase.NodeDataclass - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.nodebase.__REASON_CHILD__ - solidity_parser.ast.nodebase.__FIELD_PARENT__ - solidity_parser.ast.nodebase.__REASON_INIT__ - solidity_parser.ast.nodebase.T - - -.. py:class:: SourceLocation - - - Bases: :py:obj:`NamedTuple` - - .. py:attribute:: line - :type: int - - Line number, beginning at 1 - - - .. py:attribute:: column - :type: int - - Column number, beginning at 1. E.g. the first character on the line is at column 1. - - - -.. py:class:: SourceLocationSpan - - - Bases: :py:obj:`NamedTuple` - - .. py:attribute:: start - :type: SourceLocation - - - - .. py:attribute:: end - :type: SourceLocation - - - - .. py:method:: does_contain(loc: SourceLocation) - - Checks whether the given 'loc' location is contained within this span. - E.g. if this span represents ((5,1), (10, 1)), i.e lines 5 to 10 and loc is (6, 1), the location is contained - :param loc: - :return: - - - -.. py:data:: __REASON_CHILD__ - :value: '__child__' - - - -.. py:data:: __FIELD_PARENT__ - :value: 'parent' - - - -.. py:data:: __REASON_INIT__ - :value: '__init__' - - - -.. py:function:: NodeDataclass(cls, *args, **kwargs) - - AST node decorator to add an updatable and cachable element based hash to the dataclass - - -.. py:data:: T - - - -.. py:class:: NodeList(parent: T, seq=()) - - - Bases: :py:obj:`list`\ [\ :py:obj:`T`\ ] - - Built-in mutable sequence. - - If no argument is given, the constructor creates a new empty list. - The argument must be an iterable if specified. - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: __repr__() - - Return repr(self). - - - .. py:method:: __setitem__(key, value) - - Set self[key] to value. - - - .. py:method:: __delitem__(key) - - Delete self[key]. - - - .. py:method:: __setslice__(i, j, sequence) - - - .. py:method:: __eq__(other) - - Return self==value. - - - .. py:method:: append(__object) - - Append object to the end of the list. - - - .. py:method:: clear() - - Remove all items from list. - - - .. py:method:: extend(__iterable) - - Extend list by appending elements from the iterable. - - - .. py:method:: insert(__index, __object) - - Insert object before index. - - - .. py:method:: pop(__index) - - Remove and return item at index (default last). - - Raises IndexError if list is empty or index is out of range. - - - .. py:method:: remove(__value) - - Remove first occurrence of value. - - Raises ValueError if the value is not present. - - - .. py:method:: reverse() - - Reverse *IN PLACE*. - - - .. py:method:: sort(*args, **kwargs) - - Sort the list in ascending order and return None. - - The sort is in-place (i.e. the list itself is modified) and stable (i.e. the - order of two equal elements is maintained). - - If a key function is given, apply it once to each list item and sort them, - ascending or descending, according to their function values. - - The reverse flag can be set to sort in descending order. - - - -.. py:class:: Ref - - - Bases: :py:obj:`Generic`\ [\ :py:obj:`T`\ ] - - A weak AST reference to another Node. This is needed when we want to associate a Node with another Node but don't - want it to be marked as a child of the other Node. This is useful if we want to create circular or back references - to help the client use the AST more naturally, e.g. ResolvedUserTypes have a reference to the actual TopLevelUnit - they reference. - - .. py:attribute:: x - :type: T - - The item being referenced - - - .. py:method:: __repr__() - - Return repr(self). - - - -.. py:class:: Node - - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: id_location - :type: str - - LineNumber:LinePosition, this is set dynamically in common.make - - - .. py:attribute:: start_location - :type: SourceLocation - - Source start location of this node (column is inclusive) - - - .. py:attribute:: end_location - :type: SourceLocation - - Source end location of this node (column is exclusive) - - - .. py:attribute:: start_buffer_index - :type: int - - Source start (0-based) position in the input text buffer(inclusive) - - - .. py:attribute:: end_buffer_index - :type: int - - Source end (0-based) position in the input text buffer(exclusive) - - - .. py:attribute:: parent - :type: Optional[Node] - - - - .. py:attribute:: comments - :type: Optional[list[str]] - - - - .. py:method:: __post_init__() - - - .. py:method:: get_source_span() - - - .. py:method:: linenumber() -> int - - - .. py:method:: source_location() - - - .. py:method:: offset() -> int - - - .. py:method:: get_children(predicate: Callable[[Node], bool] = None) -> Generator[Node, None, None] - - - .. py:method:: get_all_children(predicate: Callable[[Node], bool] = None) -> Generator[Node, None, None] - - - .. py:method:: _set_child_parents() - - - .. py:method:: __deepcopy__(memodict) - - - .. py:method:: code_str() - :abstractmethod: - - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst deleted file mode 100644 index b4488d6..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/common/index.rst +++ /dev/null @@ -1,111 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.common` -============================================ - -.. py:module:: solidity_parser.ast.parsers.common - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.common.ParserBase - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.common.get_grammar_children - solidity_parser.ast.parsers.common.is_grammar_rule - solidity_parser.ast.parsers.common.map_helper - solidity_parser.ast.parsers.common.get_all_subparsers - solidity_parser.ast.parsers.common.get_subparsers_from_methods - solidity_parser.ast.parsers.common.check_subparser_method - - - -.. py:class:: ParserBase(subparsers, token_stream) - - - .. py:method:: make(rule: antlr4.ParserRuleContext, default=None) - - - .. py:method:: make_first(rule: antlr4.ParserRuleContext) - - Finds the first subrule of the given rule and returns the result of running the appropriate subparser - :param rule: - :return: - - - .. py:method:: make_all(rule: antlr4.ParserRuleContext) - - Takes all the subrules of the given rule and returns a list of the result of running their subparsers - :param rule: - :return: - - - .. py:method:: make_all_rules(rules) - - - .. py:method:: copy_source_data(decorated_node, node_to_decorate) - - - .. py:method:: wrap_node(rule, node, add_comments=False) - - - -.. py:function:: get_grammar_children(rule: antlr4.ParserRuleContext) - - Gets the children of the given rule that are grammar rules and not tokens - :param rule: - :return: - - -.. py:function:: is_grammar_rule(rule) - - Predicate for whether the given rule is a user written rule in the language grammar. - e.g. StatementContext would be a grammar rule, whereas the literal 'for' or lexer token - 'For' would not be - - :param rule: - :return: - - -.. py:function:: map_helper(func, xs) - - -.. py:function:: get_all_subparsers(module) - - Gets all the valid subparser methods from the given module - :param module: - :return: - - -.. py:function:: get_subparsers_from_methods(*methods) - - Gets the valid subparser methods from the list of given methods - :param methods: - :return: - - -.. py:function:: check_subparser_method(name, method) - - Checks whether the given name and method match the form of valid subparsers in the context - of this parsing framework. Subparsers are methods with the form _f(parser, rule: 'RuleType') - where parser is the parent parser that provides a context to the subparser and method is a python - method reference. - The parser parameter must be named 'parser' but the 'rule' parameter can be named anything. The - 'RuleType' must be a string(not a python class type) matching the name of the generated - antlr grammar rule, e.g. StatementContext - - :param name: Name of the given parser or None if no check is required on this parameter - :param method: The subparser method to check - :return: A tuple of (RuleType, method) - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst deleted file mode 100644 index 171e59b..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/errors/index.rst +++ /dev/null @@ -1,38 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.errors` -============================================ - -.. py:module:: solidity_parser.ast.parsers.errors - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.errors.assert_invalid_path - solidity_parser.ast.parsers.errors.unsupported_feature - solidity_parser.ast.parsers.errors.invalid_solidity - - - -.. py:function:: assert_invalid_path() - - -.. py:function:: unsupported_feature(detail) - - -.. py:function:: invalid_solidity(detail) - - -.. py:exception:: ParsingException - - - Bases: :py:obj:`Exception` - - Common base class for all non-exit exceptions. - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/index.rst deleted file mode 100644 index d45639c..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers` -===================================== - -.. py:module:: solidity_parser.ast.parsers - - -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - - common/index.rst - errors/index.rst - parsers060/index.rst - parsers070/index.rst - parsers080/index.rst - parsers088/index.rst - parsers08_22/index.rst - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst deleted file mode 100644 index bb3f5cf..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/parsers060/index.rst +++ /dev/null @@ -1,316 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.parsers060` -================================================ - -.. py:module:: solidity_parser.ast.parsers.parsers060 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers060.Parser060 - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers060.custom_parsers - solidity_parser.ast.parsers.parsers060._block - solidity_parser.ast.parsers.parsers060._if - solidity_parser.ast.parsers.parsers060._try - solidity_parser.ast.parsers.parsers060._while - solidity_parser.ast.parsers.parsers060._for - solidity_parser.ast.parsers.parsers060._inline_assembly_statement - solidity_parser.ast.parsers.parsers060._dowhile - solidity_parser.ast.parsers.parsers060._continue - solidity_parser.ast.parsers.parsers060._break - solidity_parser.ast.parsers.parsers060._return - solidity_parser.ast.parsers.parsers060._throw - solidity_parser.ast.parsers.parsers060._location - solidity_parser.ast.parsers.parsers060._var - solidity_parser.ast.parsers.parsers060._expr_stmt - solidity_parser.ast.parsers.parsers060._emit - solidity_parser.ast.parsers.parsers060._var_decl_stmt - solidity_parser.ast.parsers.parsers060._identifier - solidity_parser.ast.parsers.parsers060._array_identifier - solidity_parser.ast.parsers.parsers060._name_value - solidity_parser.ast.parsers.parsers060._function_call_args - solidity_parser.ast.parsers.parsers060._function_call - solidity_parser.ast.parsers.parsers060._function_call_expr - solidity_parser.ast.parsers.parsers060._meta_type - solidity_parser.ast.parsers.parsers060._payable_expr - solidity_parser.ast.parsers.parsers060._unary_pre_op - solidity_parser.ast.parsers.parsers060._delete_expr - solidity_parser.ast.parsers.parsers060._unary_logic_op - solidity_parser.ast.parsers.parsers060._unary_post_op - solidity_parser.ast.parsers.parsers060._type_name - solidity_parser.ast.parsers.parsers060._mapping_type - solidity_parser.ast.parsers.parsers060.params_to_types - solidity_parser.ast.parsers.parsers060._function_type_name - solidity_parser.ast.parsers.parsers060._new_obj - solidity_parser.ast.parsers.parsers060._array_slice - solidity_parser.ast.parsers.parsers060._array_load - solidity_parser.ast.parsers.parsers060._binary_expr - solidity_parser.ast.parsers.parsers060._ternary_expr - solidity_parser.ast.parsers.parsers060._primary - solidity_parser.ast.parsers.parsers060._number_literal - solidity_parser.ast.parsers.parsers060._hex_literal - solidity_parser.ast.parsers.parsers060._string_literal - solidity_parser.ast.parsers.parsers060._tuple_expr - solidity_parser.ast.parsers.parsers060._member_load - solidity_parser.ast.parsers.parsers060._parameter - solidity_parser.ast.parsers.parsers060._catch_clause - solidity_parser.ast.parsers.parsers060._elementary_type_name - solidity_parser.ast.parsers.parsers060._user_defined_type - solidity_parser.ast.parsers.parsers060._modifier_invocation - solidity_parser.ast.parsers.parsers060._state_mutability - solidity_parser.ast.parsers.parsers060._visibility_modifier - solidity_parser.ast.parsers.parsers060._pragma_directive - solidity_parser.ast.parsers.parsers060._version - solidity_parser.ast.parsers.parsers060._version_constraint - solidity_parser.ast.parsers.parsers060._module_import - solidity_parser.ast.parsers.parsers060._alias_import - solidity_parser.ast.parsers.parsers060._symbol_import - solidity_parser.ast.parsers.parsers060._import_declaration - solidity_parser.ast.parsers.parsers060.var_to_struct_member - solidity_parser.ast.parsers.parsers060._struct_definition - solidity_parser.ast.parsers.parsers060._enum_definition - solidity_parser.ast.parsers.parsers060._enum_value - solidity_parser.ast.parsers.parsers060._contract_definition - solidity_parser.ast.parsers.parsers060._inheritance_specifier - solidity_parser.ast.parsers.parsers060._state_variable_declaration - solidity_parser.ast.parsers.parsers060._override_specifier - solidity_parser.ast.parsers.parsers060._using_for_declaration - solidity_parser.ast.parsers.parsers060._modifier_definition - solidity_parser.ast.parsers.parsers060._function_definition - solidity_parser.ast.parsers.parsers060._event_definition - solidity_parser.ast.parsers.parsers060._event_parameter - - - -.. py:class:: Parser060(token_stream) - - - Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` - - -.. py:function:: custom_parsers() - - -.. py:function:: _block(parser, block: solidity_parser.grammar.v060.SolidityParser.SolidityParser.BlockContext) - - -.. py:function:: _if(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.IfStatementContext) - - -.. py:function:: _try(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TryStatementContext) - - -.. py:function:: _while(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.WhileStatementContext) - - -.. py:function:: _for(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ForStatementContext) - - -.. py:function:: _inline_assembly_statement(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.InlineAssemblyStatementContext) - - -.. py:function:: _dowhile(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.DoWhileStatementContext) - - -.. py:function:: _continue(parser, _: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ContinueStatementContext) - - -.. py:function:: _break(parser, _: solidity_parser.grammar.v060.SolidityParser.SolidityParser.BreakStatementContext) - - -.. py:function:: _return(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ReturnStatementContext) - - -.. py:function:: _throw(parser, _: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ThrowStatementContext) - - -.. py:function:: _location(parser, loc: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StorageLocationContext) - - -.. py:function:: _var(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VariableDeclarationContext) - - -.. py:function:: _expr_stmt(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ExpressionStatementContext) - - -.. py:function:: _emit(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EmitStatementContext) - - -.. py:function:: _var_decl_stmt(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VariableDeclarationStatementContext) - - -.. py:function:: _identifier(parser, ident: solidity_parser.grammar.v060.SolidityParser.SolidityParser.IdentifierContext) - - -.. py:function:: _array_identifier(parser, ident: solidity_parser.ast.solnodes.Ident, array_dims: int) - - -.. py:function:: _name_value(parser, name_value: solidity_parser.grammar.v060.SolidityParser.SolidityParser.NameValueContext) - - -.. py:function:: _function_call_args(parser, args: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionCallArgumentsContext) - - -.. py:function:: _function_call(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionCallContext) - - -.. py:function:: _function_call_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FuncCallExprContext) - - -.. py:function:: _meta_type(parser, meta_type: solidity_parser.grammar.v060.SolidityParser.SolidityParser.MetaTypeContext) - - -.. py:function:: _payable_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.PayableExprContext) - - -.. py:function:: _unary_pre_op(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UnaryPreOpContext) - - -.. py:function:: _delete_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.DeleteExprContext) - - -.. py:function:: _unary_logic_op(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.LogicOpContext) - - -.. py:function:: _unary_post_op(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UnaryPostOpContext) - - -.. py:function:: _type_name(parser, type_name: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TypeNameContext) - - -.. py:function:: _mapping_type(parser, mapping_type: solidity_parser.grammar.v060.SolidityParser.SolidityParser.MappingContext) - - -.. py:function:: params_to_types(params: solidity_parser.ast.solnodes.Parameter) - - -.. py:function:: _function_type_name(parser, function_type: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionTypeNameContext) - - -.. py:function:: _new_obj(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.NewTypeContext) - - -.. py:function:: _array_slice(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ArraySliceContext) - - -.. py:function:: _array_load(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ArrayLoadContext) - - -.. py:function:: _binary_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.BinaryExprContext) - - -.. py:function:: _ternary_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TernaryExprContext) - - -.. py:function:: _primary(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.PrimaryExpressionContext) - - -.. py:function:: _number_literal(parser, literal: solidity_parser.grammar.v060.SolidityParser.SolidityParser.NumberLiteralContext) - - -.. py:function:: _hex_literal(parser, literal: solidity_parser.grammar.v060.SolidityParser.SolidityParser.HexLiteralContext) - - -.. py:function:: _string_literal(parser, literal: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StringLiteralContext) - - -.. py:function:: _tuple_expr(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.TupleExpressionContext) - - -.. py:function:: _member_load(parser, expr: solidity_parser.grammar.v060.SolidityParser.SolidityParser.MemberLoadContext) - - -.. py:function:: _parameter(parser, stmt: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ParameterContext) - - -.. py:function:: _catch_clause(parser, clause: solidity_parser.grammar.v060.SolidityParser.SolidityParser.CatchClauseContext) - - -.. py:function:: _elementary_type_name(parser, name: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ElementaryTypeNameContext) - - -.. py:function:: _user_defined_type(parser, name: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UserDefinedTypeNameContext) - - -.. py:function:: _modifier_invocation(parser, modifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ModifierInvocationContext) - - -.. py:function:: _state_mutability(parser, modifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StateMutabilityContext) - - -.. py:function:: _visibility_modifier(parser, modifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VisibilityModifierContext) - - -.. py:function:: _pragma_directive(parser, pragma_directive: solidity_parser.grammar.v060.SolidityParser.SolidityParser.PragmaDirectiveContext) - - -.. py:function:: _version(parser, version: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VersionContext) - - -.. py:function:: _version_constraint(parser, version_constraint: solidity_parser.grammar.v060.SolidityParser.SolidityParser.VersionConstraintContext) - - -.. py:function:: _module_import(parser, module_import: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ModuleImportContext) - - -.. py:function:: _alias_import(parser, alias_import: solidity_parser.grammar.v060.SolidityParser.SolidityParser.AliasImportContext) - - -.. py:function:: _symbol_import(parser, symbol_import: solidity_parser.grammar.v060.SolidityParser.SolidityParser.SymbolImportContext) - - -.. py:function:: _import_declaration(parser, import_declaration: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ImportDeclarationContext) - - -.. py:function:: var_to_struct_member(var: solidity_parser.ast.solnodes.Var) - - -.. py:function:: _struct_definition(parser, struct_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StructDefinitionContext) - - -.. py:function:: _enum_definition(parser, enum_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EnumDefinitionContext) - - -.. py:function:: _enum_value(parser, enum_value: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EnumValueContext) - - -.. py:function:: _contract_definition(parser, contract_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ContractDefinitionContext) - - -.. py:function:: _inheritance_specifier(parser, inheritance_specifier: solidity_parser.grammar.v060.SolidityParser.SolidityParser.InheritanceSpecifierContext) - - -.. py:function:: _state_variable_declaration(parser, state_variable_declaration: solidity_parser.grammar.v060.SolidityParser.SolidityParser.StateVariableDeclarationContext) - - -.. py:function:: _override_specifier(parser, override_specific: solidity_parser.grammar.v060.SolidityParser.SolidityParser.OverrideSpecifierContext) - - -.. py:function:: _using_for_declaration(parser, using_for_declaration: solidity_parser.grammar.v060.SolidityParser.SolidityParser.UsingForDeclarationContext) - - -.. py:function:: _modifier_definition(parser, modifier_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.ModifierDefinitionContext) - - -.. py:function:: _function_definition(parser, function_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.FunctionDefinitionContext) - - -.. py:function:: _event_definition(parser, event_definition: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EventDefinitionContext) - - -.. py:function:: _event_parameter(parser, event_parameter: solidity_parser.grammar.v060.SolidityParser.SolidityParser.EventParameterContext) - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst deleted file mode 100644 index d278fcd..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/parsers070/index.rst +++ /dev/null @@ -1,44 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.parsers070` -================================================ - -.. py:module:: solidity_parser.ast.parsers.parsers070 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers070.Parser070 - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers070._pragma_value - solidity_parser.ast.parsers.parsers070._unicode_string_literal - solidity_parser.ast.parsers.parsers070._number_literal - - - -.. py:class:: Parser070(token_stream) - - - Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` - - -.. py:function:: _pragma_value(parser, pragma_value: solidity_parser.grammar.v070.SolidityParser.SolidityParser.PragmaValueContext) - - -.. py:function:: _unicode_string_literal(parser, literal: solidity_parser.grammar.v070.SolidityParser.SolidityParser.UnicodeStringLiteralContext) - - -.. py:function:: _number_literal(parser, literal: solidity_parser.grammar.v070.SolidityParser.SolidityParser.NumberLiteralContext) - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst deleted file mode 100644 index 89187bb..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/parsers080/index.rst +++ /dev/null @@ -1,300 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.parsers080` -================================================ - -.. py:module:: solidity_parser.ast.parsers.parsers080 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers080.Parser080 - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers080.custom_parsers - solidity_parser.ast.parsers.parsers080._try - solidity_parser.ast.parsers.parsers080._pragma_directive - solidity_parser.ast.parsers.parsers080._import_directive - solidity_parser.ast.parsers.parsers080._path - solidity_parser.ast.parsers.parsers080._import_alias - solidity_parser.ast.parsers.parsers080._contract_definition - solidity_parser.ast.parsers.parsers080._interface_definition - solidity_parser.ast.parsers.parsers080._library_definition - solidity_parser.ast.parsers.parsers080._inheritance_specifier - solidity_parser.ast.parsers.parsers080._constructor_definition - solidity_parser.ast.parsers.parsers080._function_definition - solidity_parser.ast.parsers.parsers080._constant_variable_declaration - solidity_parser.ast.parsers.parsers080._modifier_definition - solidity_parser.ast.parsers.parsers080._fallback_function_definition - solidity_parser.ast.parsers.parsers080._receive_function_definition - solidity_parser.ast.parsers.parsers080._struct_definition - solidity_parser.ast.parsers.parsers080._struct_member - solidity_parser.ast.parsers.parsers080._enum_definition - solidity_parser.ast.parsers.parsers080._state_variable_declaration - solidity_parser.ast.parsers.parsers080._error_definition - solidity_parser.ast.parsers.parsers080._error_parameter - solidity_parser.ast.parsers.parsers080._using_directive - solidity_parser.ast.parsers.parsers080._override_specifier - solidity_parser.ast.parsers.parsers080._visibility - solidity_parser.ast.parsers.parsers080._state_mutability - solidity_parser.ast.parsers.parsers080._modifier_invocation - solidity_parser.ast.parsers.parsers080._event_definition - solidity_parser.ast.parsers.parsers080._event_parameter - solidity_parser.ast.parsers.parsers080._block - solidity_parser.ast.parsers.parsers080._unchecked_block - solidity_parser.ast.parsers.parsers080._named_argument - solidity_parser.ast.parsers.parsers080._parameter_declaration - solidity_parser.ast.parsers.parsers080._call_argument_list - solidity_parser.ast.parsers.parsers080._var_decl_stmt - solidity_parser.ast.parsers.parsers080._data_location - solidity_parser.ast.parsers.parsers080._variable_declaration - solidity_parser.ast.parsers.parsers080._expr_stmt - solidity_parser.ast.parsers.parsers080._catch_clause - solidity_parser.ast.parsers.parsers080._emit - solidity_parser.ast.parsers.parsers080._revert - solidity_parser.ast.parsers.parsers080._assembly - solidity_parser.ast.parsers.parsers080._index_access - solidity_parser.ast.parsers.parsers080._index_range_access - solidity_parser.ast.parsers.parsers080._member_access - solidity_parser.ast.parsers.parsers080._func_call_expr - solidity_parser.ast.parsers.parsers080._payable_conversion - solidity_parser.ast.parsers.parsers080._meta_type - solidity_parser.ast.parsers.parsers080._type_name - solidity_parser.ast.parsers.parsers080._function_type_name - solidity_parser.ast.parsers.parsers080._mapping_type - solidity_parser.ast.parsers.parsers080._mapping_key_type - solidity_parser.ast.parsers.parsers080._unary_prefix_operation - solidity_parser.ast.parsers.parsers080._unary_suffix_operation - solidity_parser.ast.parsers.parsers080._binary_expr - solidity_parser.ast.parsers.parsers080._conditional_expr - solidity_parser.ast.parsers.parsers080._new_obj - solidity_parser.ast.parsers.parsers080._tuple_expression - solidity_parser.ast.parsers.parsers080._inline_array - solidity_parser.ast.parsers.parsers080._identifier - solidity_parser.ast.parsers.parsers080._identifier_path - solidity_parser.ast.parsers.parsers080._string_literal - solidity_parser.ast.parsers.parsers080._number_literal - solidity_parser.ast.parsers.parsers080._boolean_literal - solidity_parser.ast.parsers.parsers080._hex_string_literal - solidity_parser.ast.parsers.parsers080._unicode_string_literal - solidity_parser.ast.parsers.parsers080._elementary_type_name - - - -.. py:class:: Parser080(token_stream) - - - Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` - - -.. py:function:: custom_parsers() - - -.. py:function:: _try(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.TryStatementContext) - - -.. py:function:: _pragma_directive(parser, pragma_directive: solidity_parser.grammar.v080.SolidityParser.SolidityParser.PragmaDirectiveContext) - - -.. py:function:: _import_directive(parser, directive: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ImportDirectiveContext) - - -.. py:function:: _path(parser, path: solidity_parser.grammar.v080.SolidityParser.SolidityParser.PathContext) - - -.. py:function:: _import_alias(parser, import_alias: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ImportAliasesContext) - - -.. py:function:: _contract_definition(parser, contract_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ContractDefinitionContext) - - -.. py:function:: _interface_definition(parser, interface_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.InterfaceDefinitionContext) - - -.. py:function:: _library_definition(parser, library_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.LibraryDefinitionContext) - - -.. py:function:: _inheritance_specifier(parser, inheritance_specifier: solidity_parser.grammar.v080.SolidityParser.SolidityParser.InheritanceSpecifierContext) - - -.. py:function:: _constructor_definition(parser, constructor_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ConstructorDefinitionContext) - - -.. py:function:: _function_definition(parser, function_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FunctionDefinitionContext) - - -.. py:function:: _constant_variable_declaration(parser, constant_variable_declaration: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ConstantVariableDeclarationContext) - - -.. py:function:: _modifier_definition(parser, modifier_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ModifierDefinitionContext) - - -.. py:function:: _fallback_function_definition(parser, fallback_function_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FallbackFunctionDefinitionContext) - - -.. py:function:: _receive_function_definition(parser, receive_function_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ReceiveFunctionDefinitionContext) - - -.. py:function:: _struct_definition(parser, struct_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StructDefinitionContext) - - -.. py:function:: _struct_member(parser, struct_member: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StructMemberContext) - - -.. py:function:: _enum_definition(parser, enum_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EnumDefinitionContext) - - -.. py:function:: _state_variable_declaration(parser, state_variable_declaration: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StateVariableDeclarationContext) - - -.. py:function:: _error_definition(parser, error_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ErrorDefinitionContext) - - -.. py:function:: _error_parameter(parser, error_parameter: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ErrorParameterContext) - - -.. py:function:: _using_directive(parser, using_directive: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UsingDirectiveContext) - - -.. py:function:: _override_specifier(parser, override_specific: solidity_parser.grammar.v080.SolidityParser.SolidityParser.OverrideSpecifierContext) - - -.. py:function:: _visibility(parser, visibility: solidity_parser.grammar.v080.SolidityParser.SolidityParser.VisibilityContext) - - -.. py:function:: _state_mutability(parser, state_mutability: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StateMutabilityContext) - - -.. py:function:: _modifier_invocation(parser, modifier_invocation: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ModifierInvocationContext) - - -.. py:function:: _event_definition(parser, event_definition: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EventDefinitionContext) - - -.. py:function:: _event_parameter(parser, event_parameter: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EventParameterContext) - - -.. py:function:: _block(parser, block: solidity_parser.grammar.v080.SolidityParser.SolidityParser.BlockContext) - - -.. py:function:: _unchecked_block(parser, block: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UncheckedBlockContext) - - -.. py:function:: _named_argument(parser, named_arg: solidity_parser.grammar.v080.SolidityParser.SolidityParser.NamedArgumentContext) - - -.. py:function:: _parameter_declaration(parser, parameter_declaration: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ParameterDeclarationContext) - - -.. py:function:: _call_argument_list(parser, arg_list: solidity_parser.grammar.v080.SolidityParser.SolidityParser.CallArgumentListContext) - - -.. py:function:: _var_decl_stmt(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.VariableDeclarationStatementContext) - - -.. py:function:: _data_location(parser, location: solidity_parser.grammar.v080.SolidityParser.SolidityParser.DataLocationContext) - - -.. py:function:: _variable_declaration(parser, decl: solidity_parser.grammar.v080.SolidityParser.SolidityParser.VariableDeclarationContext) - - -.. py:function:: _expr_stmt(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ExpressionStatementContext) - - -.. py:function:: _catch_clause(parser, catch_clause: solidity_parser.grammar.v080.SolidityParser.SolidityParser.CatchClauseContext) - - -.. py:function:: _emit(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.EmitStatementContext) - - -.. py:function:: _revert(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.RevertStatementContext) - - -.. py:function:: _assembly(parser, stmt: solidity_parser.grammar.v080.SolidityParser.SolidityParser.AssemblyStatementContext) - - -.. py:function:: _index_access(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IndexAccessContext) - - -.. py:function:: _index_range_access(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IndexRangeAccessContext) - - -.. py:function:: _member_access(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MemberAccessContext) - - -.. py:function:: _func_call_expr(parser, func_call_expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FuncCallExprContext) - - -.. py:function:: _payable_conversion(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.PayableConversionContext) - - -.. py:function:: _meta_type(parser, meta_type: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MetaTypeContext) - - -.. py:function:: _type_name(parser, type_name: solidity_parser.grammar.v080.SolidityParser.SolidityParser.TypeNameContext) - - -.. py:function:: _function_type_name(parser, function_type: solidity_parser.grammar.v080.SolidityParser.SolidityParser.FunctionTypeNameContext) - - -.. py:function:: _mapping_type(parser, mapping: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MappingTypeContext) - - -.. py:function:: _mapping_key_type(parser, mapping_key_type: solidity_parser.grammar.v080.SolidityParser.SolidityParser.MappingKeyTypeContext) - - -.. py:function:: _unary_prefix_operation(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UnaryPrefixOperationContext) - - -.. py:function:: _unary_suffix_operation(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UnarySuffixOperationContext) - - -.. py:function:: _binary_expr(parser, expr) - - -.. py:function:: _conditional_expr(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ConditionalContext) - - -.. py:function:: _new_obj(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.NewExpressionContext) - - -.. py:function:: _tuple_expression(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.TupleExpressionContext) - - -.. py:function:: _inline_array(parser, expr: solidity_parser.grammar.v080.SolidityParser.SolidityParser.InlineArrayExpressionContext) - - -.. py:function:: _identifier(parser, ident: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IdentifierContext) - - -.. py:function:: _identifier_path(parser, ident_path: solidity_parser.grammar.v080.SolidityParser.SolidityParser.IdentifierPathContext) - - -.. py:function:: _string_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.StringLiteralContext) - - -.. py:function:: _number_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.NumberLiteralContext) - - -.. py:function:: _boolean_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.BooleanLiteralContext) - - -.. py:function:: _hex_string_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.HexStringLiteralContext) - - -.. py:function:: _unicode_string_literal(parser, literal: solidity_parser.grammar.v080.SolidityParser.SolidityParser.UnicodeStringLiteralContext) - - -.. py:function:: _elementary_type_name(parser, name: solidity_parser.grammar.v080.SolidityParser.SolidityParser.ElementaryTypeNameContext) - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst deleted file mode 100644 index 2ae91dd..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/parsers088/index.rst +++ /dev/null @@ -1,36 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.parsers088` -================================================ - -.. py:module:: solidity_parser.ast.parsers.parsers088 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers088.Parser088 - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers088._user_defined_value_type_definition - - - -.. py:class:: Parser088(token_stream) - - - Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` - - -.. py:function:: _user_defined_value_type_definition(parser, user_defined_value_type_definition: solidity_parser.grammar.v088.SolidityParser.SolidityParser.UserDefinedValueTypeDefinitionContext) - - diff --git a/docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst b/docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst deleted file mode 100644 index 2e3fcf4..0000000 --- a/docs/source/autoapi/solidity_parser/ast/parsers/parsers08_22/index.rst +++ /dev/null @@ -1,56 +0,0 @@ -:py:mod:`solidity_parser.ast.parsers.parsers08_22` -================================================== - -.. py:module:: solidity_parser.ast.parsers.parsers08_22 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers08_22.Parser08_22 - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.parsers.parsers08_22._user_definable_operator - solidity_parser.ast.parsers.parsers08_22._using_directive_alias - solidity_parser.ast.parsers.parsers08_22._using_directive - solidity_parser.ast.parsers.parsers08_22._number_literal - solidity_parser.ast.parsers.parsers08_22._literal_with_sub_denomination - solidity_parser.ast.parsers.parsers08_22._mapping_type - - - -.. py:class:: Parser08_22(token_stream) - - - Bases: :py:obj:`solidity_parser.ast.parsers.common.ParserBase` - - -.. py:function:: _user_definable_operator(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.UserDefinableOperatorContext) - - -.. py:function:: _using_directive_alias(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.UsingDirectiveAliasContext) - - -.. py:function:: _using_directive(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.UsingDirectiveContext) - - -.. py:function:: _number_literal(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.NumberLiteralContext) - - -.. py:function:: _literal_with_sub_denomination(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.LiteralWithSubDenominationContext) - - -.. py:function:: _mapping_type(parser, rule: solidity_parser.grammar.v08_22.SolidityParser.SolidityParser.MappingTypeContext) - - diff --git a/docs/source/autoapi/solidity_parser/ast/solnodes/index.rst b/docs/source/autoapi/solidity_parser/ast/solnodes/index.rst deleted file mode 100644 index 92bada6..0000000 --- a/docs/source/autoapi/solidity_parser/ast/solnodes/index.rst +++ /dev/null @@ -1,1889 +0,0 @@ -:py:mod:`solidity_parser.ast.solnodes` -====================================== - -.. py:module:: solidity_parser.ast.solnodes - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.solnodes.AST1Node - solidity_parser.ast.solnodes.Stmt - solidity_parser.ast.solnodes.Expr - solidity_parser.ast.solnodes.Ident - solidity_parser.ast.solnodes.Location - solidity_parser.ast.solnodes.NamedArg - solidity_parser.ast.solnodes.Unit - solidity_parser.ast.solnodes.Literal - solidity_parser.ast.solnodes.UnaryOpCode - solidity_parser.ast.solnodes.UnaryOp - solidity_parser.ast.solnodes.BinaryOpCode - solidity_parser.ast.solnodes.BinaryOp - solidity_parser.ast.solnodes.TernaryOp - solidity_parser.ast.solnodes.New - solidity_parser.ast.solnodes.NewInlineArray - solidity_parser.ast.solnodes.PayableConversion - solidity_parser.ast.solnodes.GetArrayValue - solidity_parser.ast.solnodes.GetArraySlice - solidity_parser.ast.solnodes.GetMember - solidity_parser.ast.solnodes.CallFunction - solidity_parser.ast.solnodes.Var - solidity_parser.ast.solnodes.VarDecl - solidity_parser.ast.solnodes.Parameter - solidity_parser.ast.solnodes.ExprStmt - solidity_parser.ast.solnodes.Block - solidity_parser.ast.solnodes.If - solidity_parser.ast.solnodes.Catch - solidity_parser.ast.solnodes.Try - solidity_parser.ast.solnodes.While - solidity_parser.ast.solnodes.For - solidity_parser.ast.solnodes.Emit - solidity_parser.ast.solnodes.Revert - solidity_parser.ast.solnodes.AssemblyStmt - solidity_parser.ast.solnodes.DoWhile - solidity_parser.ast.solnodes.Continue - solidity_parser.ast.solnodes.Break - solidity_parser.ast.solnodes.Return - solidity_parser.ast.solnodes.Throw - solidity_parser.ast.solnodes.Modifier - solidity_parser.ast.solnodes.VisibilityModifierKind - solidity_parser.ast.solnodes.MutabilityModifierKind - solidity_parser.ast.solnodes.VisibilityModifier2 - solidity_parser.ast.solnodes.MutabilityModifier2 - solidity_parser.ast.solnodes.InvocationModifier - solidity_parser.ast.solnodes.OverrideSpecifier - solidity_parser.ast.solnodes.SourceUnit - solidity_parser.ast.solnodes.PragmaDirective - solidity_parser.ast.solnodes.ImportDirective - solidity_parser.ast.solnodes.GlobalImportDirective - solidity_parser.ast.solnodes.UnitImportDirective - solidity_parser.ast.solnodes.SymbolAlias - solidity_parser.ast.solnodes.SymbolImportDirective - solidity_parser.ast.solnodes.ContractPart - solidity_parser.ast.solnodes.SpecialFunctionKind - solidity_parser.ast.solnodes.FunctionDefinition - solidity_parser.ast.solnodes.ModifierDefinition - solidity_parser.ast.solnodes.StructMember - solidity_parser.ast.solnodes.StructDefinition - solidity_parser.ast.solnodes.EnumDefinition - solidity_parser.ast.solnodes.StateVariableDeclaration - solidity_parser.ast.solnodes.ConstantVariableDeclaration - solidity_parser.ast.solnodes.UserValueType - solidity_parser.ast.solnodes.EventParameter - solidity_parser.ast.solnodes.EventDefinition - solidity_parser.ast.solnodes.ErrorParameter - solidity_parser.ast.solnodes.ErrorDefinition - solidity_parser.ast.solnodes.UsingAttachment - solidity_parser.ast.solnodes.UsingOperatorBinding - solidity_parser.ast.solnodes.UsingDirective - solidity_parser.ast.solnodes.InheritSpecifier - solidity_parser.ast.solnodes.ContractDefinition - solidity_parser.ast.solnodes.InterfaceDefinition - solidity_parser.ast.solnodes.LibraryDefinition - solidity_parser.ast.solnodes.CreateMetaType - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.solnodes.has_modifier_kind - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.solnodes.ModFunErrEvt - solidity_parser.ast.solnodes.Types - - -.. py:class:: AST1Node - - - Bases: :py:obj:`solidity_parser.ast.nodebase.Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: scope - :type: Scope - - - - .. py:attribute:: ast2_node - :type: AST2Node - - - - -.. py:class:: Stmt - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: Expr - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: Ident - - - Bases: :py:obj:`Expr` - - String identifier node - - .. py:attribute:: text - :type: str - - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: Location(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Solidity reference type storage locations - - These are used to specify in what type of memory context/area a struct/array/mapping is stored - - .. py:attribute:: MEMORY - :value: 'memory' - - An location that does not persist between function calls - - - .. py:attribute:: STORAGE - :value: 'storage' - - A location persists between function calls - - Contract state variables are stored here also - - - .. py:attribute:: CALLDATA - :value: 'calldata' - - A location that contains the function call arguments for external function call parameters - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: NamedArg - - - Bases: :py:obj:`Expr` - - A name-value pair used for calling functions with options - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: value - :type: Expr - - - - -.. py:class:: Unit(_: str, multiplier: int) - - - Bases: :py:obj:`enum.Enum` - - Solidity numerical unit types - - .. py:property:: multiplier - :type: int - - - .. py:attribute:: WEI - :value: ('wei', 1) - - - - .. py:attribute:: GWEI - :value: ('gwei', 1000000000.0) - - - - .. py:attribute:: SZABO - :value: ('szabo', 1000000000000.0) - - - - .. py:attribute:: FINNEY - :value: ('finney', 1000000000000000.0) - - - - .. py:attribute:: ETHER - :value: ('ether', 1e+18) - - - - .. py:attribute:: SECONDS - :value: ('seconds', 1) - - - - .. py:attribute:: MINUTES - :value: ('minutes', 60) - - - - .. py:attribute:: HOURS - :value: ('hours',) - - - - .. py:attribute:: DAYS - :value: ('days',) - - - - .. py:attribute:: WEEKS - :value: ('weeks',) - - - - .. py:attribute:: YEARS - :value: ('years',) - - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: Literal - - - Bases: :py:obj:`Expr` - - Constant value expression that can have an optional unit associated with it - - The value may be a python primitive, e.g. an integer, boolean, string, tuple, etc - - .. py:attribute:: value - :type: Any - - - - .. py:attribute:: unit - :type: Unit - - - - .. py:method:: code_str() - - - -.. py:class:: UnaryOpCode(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Single operand operation types - - .. py:attribute:: INC - :value: '++' - - - - .. py:attribute:: DEC - :value: '--' - - - - .. py:attribute:: SIGN_POS - :value: '+' - - - - .. py:attribute:: SIGN_NEG - :value: '-' - - - - .. py:attribute:: BOOL_NEG - :value: '!' - - - - .. py:attribute:: BIT_NEG - :value: '~' - - - - .. py:attribute:: DELETE - :value: 'delete' - - - - -.. py:class:: UnaryOp - - - Bases: :py:obj:`Expr` - - Single operand expression - - .. py:attribute:: expr - :type: Expr - - - - .. py:attribute:: op - :type: UnaryOpCode - - - - .. py:attribute:: is_pre - :type: bool - - Whether the operation is pre or post, e.g. ++x or x++ - - - -.. py:class:: BinaryOpCode(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Binary/two operand operation types, including assignment types - - .. py:attribute:: EXPONENTIATE - :value: '**' - - - - .. py:attribute:: MUL - :value: '*' - - - - .. py:attribute:: DIV - :value: '/' - - - - .. py:attribute:: MOD - :value: '%' - - - - .. py:attribute:: ADD - :value: '+' - - - - .. py:attribute:: SUB - :value: '-' - - - - .. py:attribute:: LSHIFT - :value: '<<' - - - - .. py:attribute:: RSHIFT - :value: '>>' - - - - .. py:attribute:: BIT_AND - :value: '&' - - - - .. py:attribute:: BIT_XOR - :value: '^' - - - - .. py:attribute:: BIT_OR - :value: '|' - - - - .. py:attribute:: LT - :value: '<' - - - - .. py:attribute:: GT - :value: '>' - - - - .. py:attribute:: LTEQ - :value: '<=' - - - - .. py:attribute:: GTEQ - :value: '>=' - - - - .. py:attribute:: EQ - :value: '==' - - - - .. py:attribute:: NEQ - :value: '!=' - - - - .. py:attribute:: BOOL_AND - :value: '&&' - - - - .. py:attribute:: BOOL_OR - :value: '||' - - - - .. py:attribute:: ASSIGN - :value: '=' - - - - .. py:attribute:: ASSIGN_OR - :value: '|=' - - - - .. py:attribute:: ASSIGN_BIT_NEG - :value: '^=' - - - - .. py:attribute:: ASSIGN_BIT_AND - :value: '&=' - - - - .. py:attribute:: ASSIGN_LSHIFT - :value: '<<=' - - - - .. py:attribute:: ASSIGN_RSHIFT - :value: '>>=' - - - - .. py:attribute:: ASSIGN_ADD - :value: '+=' - - - - .. py:attribute:: ASSIGN_SUB - :value: '-=' - - - - .. py:attribute:: ASSIGN_MUL - :value: '*=' - - - - .. py:attribute:: ASSIGN_DIV - :value: '/=' - - - - .. py:attribute:: ASSIGN_MOD - :value: '%=' - - - - -.. py:class:: BinaryOp - - - Bases: :py:obj:`Expr` - - Binary/two operand expression - - .. py:attribute:: left - :type: Expr - - - - .. py:attribute:: right - :type: Expr - - - - .. py:attribute:: op - :type: BinaryOpCode - - - - -.. py:class:: TernaryOp - - - Bases: :py:obj:`Expr` - - Choice expression that evaluates the given condition and returns one of the two given expressions - - If the condition evaluates to false then the left expression is returned, otherwise the right one is - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: left - :type: Expr - - - - .. py:attribute:: right - :type: Expr - - - - -.. py:class:: New - - - Bases: :py:obj:`Expr` - - New object allocation expression without constructor invocation - - Note that this expression only represents the 'new X' part of a new objects creation 'new X(a,b)'. - This expression must then be used as the base object in a constructor call to instantiate it. - - - .. py:attribute:: type_name - :type: solidity_parser.ast.types.Type - - - - -.. py:class:: NewInlineArray - - - Bases: :py:obj:`Expr` - - Solidity 8 inline array creation - - An inline array is one where the elements are explicitly stated in the definition, for example: - 'int[5] foo2 = [1, 0, 0, 0, 0];' - - .. py:attribute:: elements - :type: list[Expr] - - - - -.. py:class:: PayableConversion - - - Bases: :py:obj:`Expr` - - Converts an address to a payable address - - For example: 'payable(address(myAddressHex))' - - .. py:attribute:: args - :type: list[Expr] - - - - -.. py:class:: GetArrayValue - - - Bases: :py:obj:`Expr` - - Gets the value at the given index from the given array - - .. py:attribute:: array_base - :type: Expr - - - - .. py:attribute:: index - :type: Expr - - - - -.. py:class:: GetArraySlice - - - Bases: :py:obj:`Expr` - - Gets a subarray at the given start and end indices from the given array - - .. py:attribute:: array_base - :type: Expr - - - - .. py:attribute:: start_index - :type: Expr - - - - .. py:attribute:: end_index - :type: Expr - - - - -.. py:class:: GetMember - - - Bases: :py:obj:`Expr` - - Gets a member field or method from a given object - - .. py:attribute:: obj_base - :type: Expr - - - - .. py:attribute:: name - :type: Ident - - - - -.. py:class:: CallFunction - - - Bases: :py:obj:`Expr` - - Invokes a function - - .. py:attribute:: callee - :type: Expr - - This callee is most likely a GetMember expression but can be any callable - - - .. py:attribute:: modifiers - :type: list - - - - .. py:attribute:: args - :type: list[Expr] - - - - -.. py:class:: Var - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: var_name - :type: Ident - - - - .. py:attribute:: var_loc - :type: Optional[Location] - - - - -.. py:class:: VarDecl - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: variables - :type: list[Var] - - - - .. py:attribute:: value - :type: Expr - - - - .. py:attribute:: is_lhs_tuple - :type: bool - :value: False - - - - -.. py:class:: Parameter - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var_type - :type: Ident - - - - .. py:attribute:: var_loc - :type: Location - - - - .. py:attribute:: var_name - :type: Ident - - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: ExprStmt - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: expr - :type: Expr - - - - -.. py:class:: Block - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: stmts - :type: list[Stmt] - - - - .. py:attribute:: is_unchecked - :type: bool - :value: False - - - - -.. py:class:: If - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: true_branch - :type: Stmt - - - - .. py:attribute:: false_branch - :type: Stmt - - - - -.. py:class:: Catch - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ident - :type: Ident - - - - .. py:attribute:: parameters - :type: list[Parameter] - - - - .. py:attribute:: body - :type: Block - - - - -.. py:class:: Try - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: expr - :type: Expr - - - - .. py:attribute:: return_parameters - :type: list[Parameter] - - - - .. py:attribute:: body - :type: Block - - - - .. py:attribute:: catch_clauses - :type: list[Catch] - - - - -.. py:class:: While - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: expr - :type: Expr - - - - .. py:attribute:: body - :type: Stmt - - - - -.. py:class:: For - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: initialiser - :type: Stmt - - - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: advancement - :type: Expr - - - - .. py:attribute:: body - :type: Stmt - - - - -.. py:class:: Emit - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: call - :type: CallFunction - - - - -.. py:class:: Revert - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: call - :type: CallFunction - - - - -.. py:class:: AssemblyStmt - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: code - :type: str - - - - -.. py:class:: DoWhile - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: body - :type: Stmt - - - - .. py:attribute:: condition - :type: Expr - - - - -.. py:class:: Continue - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: Break - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: Return - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: value - :type: Expr - - - - -.. py:class:: Throw - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: Modifier - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: VisibilityModifierKind(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Create a collection of name/value pairs. - - Example enumeration: - - >>> class Color(Enum): - ... RED = 1 - ... BLUE = 2 - ... GREEN = 3 - - Access them by: - - - attribute access:: - - >>> Color.RED - - - - value lookup: - - >>> Color(1) - - - - name lookup: - - >>> Color['RED'] - - - Enumerations can be iterated over, and know how many members they have: - - >>> len(Color) - 3 - - >>> list(Color) - [, , ] - - Methods can be added to enumerations, and members can have their own - attributes -- see the documentation for details. - - .. py:attribute:: EXTERNAL - :value: 'external' - - - - .. py:attribute:: PUBLIC - :value: 'public' - - - - .. py:attribute:: INTERNAL - :value: 'internal' - - - - .. py:attribute:: PRIVATE - :value: 'private' - - - - .. py:attribute:: VIRTUAL - :value: 'virtual' - - - - -.. py:class:: MutabilityModifierKind(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Create a collection of name/value pairs. - - Example enumeration: - - >>> class Color(Enum): - ... RED = 1 - ... BLUE = 2 - ... GREEN = 3 - - Access them by: - - - attribute access:: - - >>> Color.RED - - - - value lookup: - - >>> Color(1) - - - - name lookup: - - >>> Color['RED'] - - - Enumerations can be iterated over, and know how many members they have: - - >>> len(Color) - 3 - - >>> list(Color) - [, , ] - - Methods can be added to enumerations, and members can have their own - attributes -- see the documentation for details. - - .. py:attribute:: PURE - :value: 'pure' - - - - .. py:attribute:: CONSTANT - :value: 'constant' - - - - .. py:attribute:: VIEW - :value: 'view' - - - - .. py:attribute:: PAYABLE - :value: 'payable' - - - - .. py:attribute:: IMMUTABLE - :value: 'immutable' - - - - -.. py:class:: VisibilityModifier2 - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: kind - :type: VisibilityModifierKind - - - - -.. py:class:: MutabilityModifier2 - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: kind - :type: MutabilityModifierKind - - - - -.. py:class:: InvocationModifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: arguments - :type: list[Expr] - - - - -.. py:class:: OverrideSpecifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: arguments - :type: list[solidity_parser.ast.types.UserType] - - - - -.. py:class:: SourceUnit - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: PragmaDirective - - - Bases: :py:obj:`SourceUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: value - :type: str | Expr - - - - -.. py:class:: ImportDirective - - - Bases: :py:obj:`SourceUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: path - :type: str - - - - -.. py:class:: GlobalImportDirective - - - Bases: :py:obj:`ImportDirective` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: UnitImportDirective - - - Bases: :py:obj:`ImportDirective` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: alias - :type: Ident - - - - -.. py:class:: SymbolAlias - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: symbol - :type: Ident - - - - .. py:attribute:: alias - :type: Ident - - - - -.. py:class:: SymbolImportDirective - - - Bases: :py:obj:`ImportDirective` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: aliases - :type: list[SymbolAlias] - - - - -.. py:class:: ContractPart - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: SpecialFunctionKind(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Create a collection of name/value pairs. - - Example enumeration: - - >>> class Color(Enum): - ... RED = 1 - ... BLUE = 2 - ... GREEN = 3 - - Access them by: - - - attribute access:: - - >>> Color.RED - - - - value lookup: - - >>> Color(1) - - - - name lookup: - - >>> Color['RED'] - - - Enumerations can be iterated over, and know how many members they have: - - >>> len(Color) - 3 - - >>> list(Color) - [, , ] - - Methods can be added to enumerations, and members can have their own - attributes -- see the documentation for details. - - .. py:attribute:: CONSTRUCTOR - :value: '<>' - - - - .. py:attribute:: RECEIVE - :value: '<>' - - - - .. py:attribute:: FALLBACK - :value: '<>' - - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: FunctionDefinition - - - Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident | SpecialFunctionKind - - - - .. py:attribute:: parameters - :type: list[Parameter] - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:attribute:: returns - :type: list[Parameter] - - - - .. py:attribute:: code - :type: Block - - - - -.. py:class:: ModifierDefinition - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: parameters - :type: list[Parameter] - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:attribute:: code - :type: Block - - - - -.. py:class:: StructMember - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: member_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: name - :type: Ident - - - - -.. py:class:: StructDefinition - - - Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: members - :type: list[StructMember] - - - - -.. py:class:: EnumDefinition - - - Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: values - :type: list[Ident] - - - - -.. py:class:: StateVariableDeclaration - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: initial_value - :type: Expr - - - - -.. py:class:: ConstantVariableDeclaration - - - Bases: :py:obj:`SourceUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: initial_value - :type: Expr - - - - -.. py:class:: UserValueType - - - Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: value - :type: solidity_parser.ast.types.Type - - - - -.. py:class:: EventParameter - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: is_indexed - :type: bool - - - - -.. py:class:: EventDefinition - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: is_anonymous - :type: bool - - - - .. py:attribute:: parameters - :type: list[EventParameter] - - - - -.. py:class:: ErrorParameter - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: name - :type: Ident - - - - -.. py:class:: ErrorDefinition - - - Bases: :py:obj:`SourceUnit`, :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: parameters - :type: list[ErrorParameter] - - - - -.. py:class:: UsingAttachment - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: member_name - :type: Ident - - - - -.. py:class:: UsingOperatorBinding - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: member_name - :type: Ident - - - - .. py:attribute:: operator - :type: UnaryOpCode | BinaryOpCode - - - - -.. py:class:: UsingDirective - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: library_name - :type: Ident - - - - .. py:attribute:: override_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: attachments_or_bindings - :type: list[UsingAttachment | UsingOperatorBinding] - - - - .. py:attribute:: is_global - :type: bool - - - - -.. py:class:: InheritSpecifier - - - Bases: :py:obj:`AST1Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: solidity_parser.ast.types.UserType - - - - .. py:attribute:: args - :type: list[Expr] - - - - -.. py:class:: ContractDefinition - - - Bases: :py:obj:`SourceUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: is_abstract - :type: bool - - - - .. py:attribute:: inherits - :type: list[InheritSpecifier] - - - - .. py:attribute:: parts - :type: list[ContractPart] - - - - -.. py:class:: InterfaceDefinition - - - Bases: :py:obj:`SourceUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: inherits - :type: list[InheritSpecifier] - - - - .. py:attribute:: parts - :type: list[ContractPart] - - - - -.. py:class:: LibraryDefinition - - - Bases: :py:obj:`SourceUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: parts - :type: list[ContractPart] - - - - -.. py:class:: CreateMetaType - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base_type - :type: solidity_parser.ast.types.Type - - - - -.. py:function:: has_modifier_kind(node, *kinds: VisibilityModifierKind | MutabilityModifierKind) - - -.. py:data:: ModFunErrEvt - :type: TypeAlias - - - -.. py:data:: Types - :type: TypeAlias - - - diff --git a/docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst b/docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst deleted file mode 100644 index 43c5129..0000000 --- a/docs/source/autoapi/solidity_parser/ast/solnodes2/index.rst +++ /dev/null @@ -1,2393 +0,0 @@ -:py:mod:`solidity_parser.ast.solnodes2` -======================================= - -.. py:module:: solidity_parser.ast.solnodes2 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.solnodes2.AST2Node - solidity_parser.ast.solnodes2.Stmt - solidity_parser.ast.solnodes2.Expr - solidity_parser.ast.solnodes2.Modifier - solidity_parser.ast.solnodes2.ResolvedUserType - solidity_parser.ast.solnodes2.SuperType - solidity_parser.ast.solnodes2.VisibilityModifier - solidity_parser.ast.solnodes2.MutabilityModifier - solidity_parser.ast.solnodes2.OverrideSpecifier - solidity_parser.ast.solnodes2.SuperConstructorInvocationModifier - solidity_parser.ast.solnodes2.FunctionInvocationModifier - solidity_parser.ast.solnodes2.Ident - solidity_parser.ast.solnodes2.NamedArgument - solidity_parser.ast.solnodes2.TopLevelUnit - solidity_parser.ast.solnodes2.ContractPart - solidity_parser.ast.solnodes2.InheritSpecifier - solidity_parser.ast.solnodes2.LibraryOverride - solidity_parser.ast.solnodes2.FileDefinition - solidity_parser.ast.solnodes2.ContractDefinition - solidity_parser.ast.solnodes2.InterfaceDefinition - solidity_parser.ast.solnodes2.LibraryDefinition - solidity_parser.ast.solnodes2.UserDefinedValueTypeDefinition - solidity_parser.ast.solnodes2.EnumMember - solidity_parser.ast.solnodes2.EnumDefinition - solidity_parser.ast.solnodes2.StructMember - solidity_parser.ast.solnodes2.StructDefinition - solidity_parser.ast.solnodes2.ErrorParameter - solidity_parser.ast.solnodes2.ErrorDefinition - solidity_parser.ast.solnodes2.StateVariableDeclaration - solidity_parser.ast.solnodes2.ConstantVariableDeclaration - solidity_parser.ast.solnodes2.EventParameter - solidity_parser.ast.solnodes2.EventDefinition - solidity_parser.ast.solnodes2.Location - solidity_parser.ast.solnodes2.Var - solidity_parser.ast.solnodes2.Parameter - solidity_parser.ast.solnodes2.Block - solidity_parser.ast.solnodes2.If - solidity_parser.ast.solnodes2.Catch - solidity_parser.ast.solnodes2.Try - solidity_parser.ast.solnodes2.While - solidity_parser.ast.solnodes2.For - solidity_parser.ast.solnodes2.FunctionMarker - solidity_parser.ast.solnodes2.FunctionDefinition - solidity_parser.ast.solnodes2.BuiltinFunction - solidity_parser.ast.solnodes2.ModifierDefinition - solidity_parser.ast.solnodes2.TupleVarDecl - solidity_parser.ast.solnodes2.VarDecl - solidity_parser.ast.solnodes2.ExprStmt - solidity_parser.ast.solnodes2.Literal - solidity_parser.ast.solnodes2.TypeLiteral - solidity_parser.ast.solnodes2.UnaryOp - solidity_parser.ast.solnodes2.BinaryOp - solidity_parser.ast.solnodes2.TernaryOp - solidity_parser.ast.solnodes2.SelfObject - solidity_parser.ast.solnodes2.SuperObject - solidity_parser.ast.solnodes2.StateVarLoad - solidity_parser.ast.solnodes2.StaticVarLoad - solidity_parser.ast.solnodes2.EnumLoad - solidity_parser.ast.solnodes2.StateVarStore - solidity_parser.ast.solnodes2.LocalVarLoad - solidity_parser.ast.solnodes2.LocalVarStore - solidity_parser.ast.solnodes2.ArrayLengthStore - solidity_parser.ast.solnodes2.TupleLoad - solidity_parser.ast.solnodes2.ArrayLoad - solidity_parser.ast.solnodes2.ArrayStore - solidity_parser.ast.solnodes2.ArraySliceLoad - solidity_parser.ast.solnodes2.CreateInlineArray - solidity_parser.ast.solnodes2.MappingLoad - solidity_parser.ast.solnodes2.MappingStore - solidity_parser.ast.solnodes2.GlobalValue - solidity_parser.ast.solnodes2.ABISelector - solidity_parser.ast.solnodes2.DynamicBuiltInValue - solidity_parser.ast.solnodes2.CreateMemoryArray - solidity_parser.ast.solnodes2.CreateStruct - solidity_parser.ast.solnodes2.CreateAndDeployContract - solidity_parser.ast.solnodes2.Call - solidity_parser.ast.solnodes2.DirectCall - solidity_parser.ast.solnodes2.FunctionCall - solidity_parser.ast.solnodes2.FunctionPointerCall - solidity_parser.ast.solnodes2.DynamicBuiltInCall - solidity_parser.ast.solnodes2.BuiltInCall - solidity_parser.ast.solnodes2.Cast - solidity_parser.ast.solnodes2.GetType - solidity_parser.ast.solnodes2.GetFunctionPointer - solidity_parser.ast.solnodes2.EmitEvent - solidity_parser.ast.solnodes2.Revert - solidity_parser.ast.solnodes2.RevertWithError - solidity_parser.ast.solnodes2.RevertWithReason - solidity_parser.ast.solnodes2.Require - solidity_parser.ast.solnodes2.Return - solidity_parser.ast.solnodes2.Continue - solidity_parser.ast.solnodes2.Break - solidity_parser.ast.solnodes2.Assembly - solidity_parser.ast.solnodes2.ExecModifiedCode - solidity_parser.ast.solnodes2.UnprocessedCode - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.solnodes2.raiseNotPrintable - solidity_parser.ast.solnodes2.param_def_str - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.solnodes2.T - solidity_parser.ast.solnodes2.Types - - -.. py:data:: T - - - -.. py:function:: raiseNotPrintable() - - -.. py:function:: param_def_str(ps) - - -.. py:class:: AST2Node - - - Bases: :py:obj:`solidity_parser.ast.nodebase.Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:method:: get_top_level_unit() -> TopLevelUnit - - - -.. py:class:: Stmt - - - Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: Expr - - - Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - :abstractmethod: - - - -.. py:class:: Modifier - - - Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: ResolvedUserType - - - Bases: :py:obj:`solidity_parser.ast.types.Type` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: scope - :type: Scope - - - - .. py:attribute:: value - :type: solidity_parser.ast.nodebase.Ref[TopLevelUnit] - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: __repr__() - - Return repr(self). - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_user_type() -> bool - - Check if the type is a user defined type, e.g. struct, enum, contract, etc - - - .. py:method:: can_implicitly_cast_from(actual_type: solidity_parser.ast.types.Type) -> bool - - - .. py:method:: get_types_for_declared_type() -> list[TopLevelUnit] - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: SuperType - - - Bases: :py:obj:`solidity_parser.ast.types.Type` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: declarer - :type: solidity_parser.ast.nodebase.Ref[Union[ContractDefinition, InterfaceDefinition]] - - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: get_types_for_declared_type() -> list[TopLevelUnit] - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: VisibilityModifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: kind - :type: solidity_parser.ast.solnodes.VisibilityModifierKind - - - - .. py:method:: code_str() - - - -.. py:class:: MutabilityModifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: kind - :type: solidity_parser.ast.solnodes.MutabilityModifierKind - - - - .. py:method:: code_str() - - - -.. py:class:: OverrideSpecifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: bases - :type: list[ResolvedUserType] - - - - .. py:method:: code_str() - - - -.. py:class:: SuperConstructorInvocationModifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base_ttype - :type: ResolvedUserType - - - - .. py:attribute:: inputs - :type: list[Expr] - - - - .. py:method:: code_str() - - - -.. py:class:: FunctionInvocationModifier - - - Bases: :py:obj:`Modifier` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: modifier - :type: solidity_parser.ast.nodebase.Ref[ModifierDefinition] - - - - .. py:attribute:: inputs - :type: list[Expr] - - - - .. py:method:: code_str() - - - -.. py:class:: Ident - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: text - :type: str - - - - .. py:method:: code_str() - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: NamedArgument - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: expr - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: TopLevelUnit - - - Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: source_unit_name - :type: str - - - - .. py:attribute:: name - :type: Ident - - - - .. py:method:: descriptor() -> str - - - .. py:method:: is_subttype_of(other_contract: TopLevelUnit) -> bool - - - .. py:method:: as_type() - - - .. py:method:: get_supers() -> list[Union[ContractDefinition, InterfaceDefinition]] - - - .. py:method:: get_subtypes() -> list[Union[ContractDefinition, InterfaceDefinition]] - - - .. py:method:: is_enum() -> bool - - - .. py:method:: is_struct() -> bool - - - .. py:method:: is_contract() -> bool - - - .. py:method:: is_interface() -> bool - - - .. py:method:: is_udvt() -> bool - - - .. py:method:: find_named_parts(name: str, explore_mro: bool, matching_types) - - - -.. py:class:: ContractPart - - - Bases: :py:obj:`AST2Node`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:method:: has_modifier_kind(*kinds: solidity_parser.ast.solnodes.VisibilityModifierKind | solidity_parser.ast.solnodes.MutabilityModifierKind) - - - -.. py:class:: InheritSpecifier - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: ResolvedUserType - - - - .. py:attribute:: args - :type: list[Expr] - - - - .. py:method:: code_str() - - - -.. py:class:: LibraryOverride - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: overriden_type - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: library - :type: ResolvedUserType - - - - -.. py:class:: FileDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: scope - :type: Scope - - - - .. py:attribute:: parts - :type: list[ContractPart] - - - - .. py:method:: descriptor() -> str - - - -.. py:class:: ContractDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: is_abstract - :type: bool - - - - .. py:attribute:: inherits - :type: list[InheritSpecifier] - - - - .. py:attribute:: parts - :type: list[ContractPart] - - - - .. py:attribute:: type_overrides - :type: list[LibraryOverride] - - - - .. py:attribute:: _subtypes - :type: list[solidity_parser.ast.nodebase.Ref[Union[ContractDefinition, InterfaceDefinition]]] - - - - -.. py:class:: InterfaceDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: inherits - :type: list[InheritSpecifier] - - - - .. py:attribute:: parts - :type: list[ContractPart] - - - - .. py:attribute:: type_overrides - :type: list[LibraryOverride] - - - - .. py:attribute:: _subtypes - :type: list[solidity_parser.ast.nodebase.Ref[Union[ContractDefinition, InterfaceDefinition]]] - - - - -.. py:class:: LibraryDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: parts - :type: list[ContractPart] - - - - .. py:attribute:: type_overrides - :type: list[LibraryOverride] - - - - -.. py:class:: UserDefinedValueTypeDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - -.. py:class:: EnumMember - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - -.. py:class:: EnumDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: values - :type: list[EnumMember] - - - - -.. py:class:: StructMember - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: name - :type: Ident - - - - -.. py:class:: StructDefinition - - - Bases: :py:obj:`TopLevelUnit` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: members - :type: list[StructMember] - - - - -.. py:class:: ErrorParameter - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: name - :type: Ident - - - - -.. py:class:: ErrorDefinition - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: inputs - :type: list[ErrorParameter] - - - - -.. py:class:: StateVariableDeclaration - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:attribute:: value - :type: Expr - - - - -.. py:class:: ConstantVariableDeclaration - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: value - :type: Expr - - - - -.. py:class:: EventParameter - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: is_indexed - :type: bool - - - - -.. py:class:: EventDefinition - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: inputs - :type: list[EventParameter] - - - - .. py:attribute:: is_anonymous - :type: bool - - - - -.. py:class:: Location(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Create a collection of name/value pairs. - - Example enumeration: - - >>> class Color(Enum): - ... RED = 1 - ... BLUE = 2 - ... GREEN = 3 - - Access them by: - - - attribute access:: - - >>> Color.RED - - - - value lookup: - - >>> Color(1) - - - - name lookup: - - >>> Color['RED'] - - - Enumerations can be iterated over, and know how many members they have: - - >>> len(Color) - 3 - - >>> list(Color) - [, , ] - - Methods can be added to enumerations, and members can have their own - attributes -- see the documentation for details. - - .. py:attribute:: MEMORY - :value: 'memory' - - - - .. py:attribute:: STORAGE - :value: 'storage' - - - - .. py:attribute:: CALLDATA - :value: 'calldata' - - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: Var - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: location - :type: Location - - - - .. py:method:: code_str() - - - -.. py:class:: Parameter - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var - :type: Var - - - - -.. py:class:: Block - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: stmts - :type: list[Stmt] - - - - .. py:attribute:: is_unchecked - :type: bool - - - - .. py:method:: code_str(brackets=True) - - - -.. py:class:: If - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: true_branch - :type: Stmt - - - - .. py:attribute:: false_branch - :type: Stmt - - - - .. py:method:: code_str() - - - -.. py:class:: Catch - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ident - :type: Ident - - - - .. py:attribute:: parameters - :type: list[Parameter] - - - - .. py:attribute:: body - :type: Block - - - - .. py:method:: code_str() - - - -.. py:class:: Try - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: expr - :type: Expr - - - - .. py:attribute:: return_parameters - :type: list[Parameter] - - - - .. py:attribute:: body - :type: Block - - - - .. py:attribute:: catch_clauses - :type: list[Catch] - - - - .. py:method:: code_str() - - - -.. py:class:: While - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: body - :type: Stmt - - - - .. py:attribute:: is_do_while - :type: bool - - - - .. py:method:: code_str() - - - -.. py:class:: For - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: initialiser - :type: Stmt - - - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: advancement - :type: Expr - - - - .. py:attribute:: body - :type: Stmt - - - - .. py:method:: code_str() - - - -.. py:class:: FunctionMarker(*args, **kwds) - - - Bases: :py:obj:`enum.Enum` - - Special function type markers - - .. py:attribute:: CONSTRUCTOR - :value: 1 - - - - .. py:attribute:: SYNTHETIC_FIELD_GETTER - :value: 2 - - - - -.. py:class:: FunctionDefinition - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: inputs - :type: list[Parameter] - - - - .. py:attribute:: outputs - :type: list[Parameter] - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:attribute:: code - :type: Block - - - - .. py:attribute:: markers - :type: list[FunctionMarker] - - - - .. py:method:: param_str(ps) -> str - :staticmethod: - - - .. py:method:: descriptor() -> str - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: BuiltinFunction - - - Bases: :py:obj:`AST2Node` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: inputs - :type: list[Parameter] - - - - .. py:attribute:: outputs - :type: list[Parameter] - - - - -.. py:class:: ModifierDefinition - - - Bases: :py:obj:`ContractPart` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: inputs - :type: list[Parameter] - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:attribute:: code - :type: Block - - - - -.. py:class:: TupleVarDecl - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: vars - :type: list[Var] - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: VarDecl - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var - :type: Var - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: ExprStmt - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: expr - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: Literal - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: value - :type: Any - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: unit - :type: solidity_parser.ast.solnodes.Unit - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: TypeLiteral - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:method:: type_of() - - - .. py:method:: code_str() - - - -.. py:class:: UnaryOp - - - Bases: :py:obj:`Expr` - - Single operand expression - - .. py:attribute:: expr - :type: Expr - - - - .. py:attribute:: op - :type: solidity_parser.ast.solnodes.UnaryOpCode - - - - .. py:attribute:: is_pre - :type: bool - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: BinaryOp - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: left - :type: Expr - - - - .. py:attribute:: right - :type: Expr - - - - .. py:attribute:: op - :type: solidity_parser.ast.solnodes.BinaryOpCode - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: TernaryOp - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: left - :type: Expr - - - - .. py:attribute:: right - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: SelfObject - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: declarer - :type: solidity_parser.ast.nodebase.Ref[ContractDefinition | InterfaceDefinition] - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: SuperObject - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: SuperType - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: StateVarLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: name - :type: Ident - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: StaticVarLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: ResolvedUserType - - - - .. py:attribute:: name - :type: Ident - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: EnumLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: member - :type: solidity_parser.ast.nodebase.Ref[EnumMember] - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: StateVarStore - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: name - :type: Ident - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: state_var() - - - .. py:method:: code_str() - - - -.. py:class:: LocalVarLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var - :type: Var - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: LocalVarStore - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: var - :type: Var - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: ArrayLengthStore - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - :abstractmethod: - - - -.. py:class:: TupleLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: index - :type: int - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: ArrayLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: index - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: ArrayStore - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: index - :type: Expr - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: ArraySliceLoad - - - Bases: :py:obj:`Expr` - - Gets a subarray at the given start and end indices from the given array - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: start_index - :type: Expr - - - - .. py:attribute:: end_index - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: CreateInlineArray - - - Bases: :py:obj:`Expr` - - Solidity 8 inline array creation - - An inline array is one where the elements are explicitly stated in the definition, for example: - 'int[5] foo2 = [1, 0, 0, 0, 0];' - - .. py:attribute:: elements - :type: list[Expr] - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: MappingLoad - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: key - :type: Expr - - - - .. py:method:: code_str() - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - -.. py:class:: MappingStore - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: key - :type: Expr - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: GlobalValue - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: str - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: ABISelector - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: function - :type: solidity_parser.ast.nodebase.Ref[FunctionDefinition | ErrorDefinition] | Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - - -.. py:class:: DynamicBuiltInValue - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: str - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: base - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: CreateMemoryArray - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.ArrayType - - - - .. py:attribute:: size - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: CreateStruct - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: ResolvedUserType - - - - .. py:attribute:: args - :type: list[Expr] - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: CreateAndDeployContract - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: ResolvedUserType - - - - .. py:attribute:: named_args - :type: list[NamedArgument] - - - - .. py:attribute:: args - :type: list[Expr] - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: Call - - - Bases: :py:obj:`Expr`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: named_args - :type: list[NamedArgument] - - - - .. py:attribute:: args - :type: list[Expr] - - - - .. py:method:: check_arg_types(f: FunctionDefinition) -> bool - - - .. py:method:: param_str() - - - -.. py:class:: DirectCall - - - Bases: :py:obj:`Call` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: ResolvedUserType - - - - .. py:attribute:: name - :type: Ident - - - - .. py:method:: base_type() - - - .. py:method:: resolve_call() -> FunctionDefinition - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: FunctionCall - - - Bases: :py:obj:`Call` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: base - :type: Expr - - - - .. py:attribute:: name - :type: Ident - - - - .. py:method:: base_type() - - - .. py:method:: resolve_call() -> FunctionDefinition - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: FunctionPointerCall - - - Bases: :py:obj:`Call` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: callee - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: DynamicBuiltInCall - - - Bases: :py:obj:`Call` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: base - :type: Expr | ResolvedUserType - - - - .. py:attribute:: name - :type: str - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: BuiltInCall - - - Bases: :py:obj:`Call` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: name - :type: str - - - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: Cast - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:attribute:: value - :type: Expr - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: GetType - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: ttype - :type: solidity_parser.ast.types.Type - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: GetFunctionPointer - - - Bases: :py:obj:`Expr` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: func - :type: solidity_parser.ast.nodebase.Ref[Union[FunctionDefinition, BuiltinFunction]] - - - - .. py:method:: type_of() -> solidity_parser.ast.types.Type - - - .. py:method:: code_str() - - - -.. py:class:: EmitEvent - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: event - :type: solidity_parser.ast.nodebase.Ref[EventDefinition] - - - - .. py:attribute:: args - :type: list[Expr] - - - - .. py:method:: code_str() - - - -.. py:class:: Revert - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: RevertWithError - - - Bases: :py:obj:`Revert` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: error - :type: solidity_parser.ast.nodebase.Ref[ErrorDefinition] - - - - .. py:attribute:: args - :type: list[Expr] - - - - .. py:method:: code_str() - - - -.. py:class:: RevertWithReason - - - Bases: :py:obj:`Revert` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: reason - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: Require - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: condition - :type: Expr - - - - .. py:attribute:: reason - :type: Expr - - - - .. py:method:: code_str() - - - -.. py:class:: Return - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: values - :type: list[Expr] - - - - .. py:method:: code_str() - - - -.. py:class:: Continue - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:method:: code_str() - - - -.. py:class:: Break - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:method:: code_str() - - - -.. py:class:: Assembly - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: code - :type: str - - - - .. py:method:: code_str() - - - -.. py:class:: ExecModifiedCode - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - -.. py:class:: UnprocessedCode - - - Bases: :py:obj:`Stmt` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: error - :type: Exception - - - - -.. py:data:: Types - :type: TypeAlias - - - diff --git a/docs/source/autoapi/solidity_parser/ast/symtab/index.rst b/docs/source/autoapi/solidity_parser/ast/symtab/index.rst deleted file mode 100644 index 3d88d00..0000000 --- a/docs/source/autoapi/solidity_parser/ast/symtab/index.rst +++ /dev/null @@ -1,717 +0,0 @@ -:py:mod:`solidity_parser.ast.symtab` -==================================== - -.. py:module:: solidity_parser.ast.symtab - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.symtab.Scopeable - solidity_parser.ast.symtab.Symbol - solidity_parser.ast.symtab.CrossScopeSymbolAlias - solidity_parser.ast.symtab.Scope - solidity_parser.ast.symtab.ScopeAndSymbol - solidity_parser.ast.symtab.BuiltinObject - solidity_parser.ast.symtab.BuiltinFunction - solidity_parser.ast.symtab.BuiltinValue - solidity_parser.ast.symtab.RootScope - solidity_parser.ast.symtab.FileScope - solidity_parser.ast.symtab.LibraryScope - solidity_parser.ast.symtab.ContractOrInterfaceScope - solidity_parser.ast.symtab.StructScope - solidity_parser.ast.symtab.UserDefinedValueTypeScope - solidity_parser.ast.symtab.LibraryScope - solidity_parser.ast.symtab.EnumScope - solidity_parser.ast.symtab.ModFunErrEvtScope - solidity_parser.ast.symtab.ImportSymbol - solidity_parser.ast.symtab.AliasImportSymbol - solidity_parser.ast.symtab.UnitImportSymbol - solidity_parser.ast.symtab.ProxyScope - solidity_parser.ast.symtab.UsingDirectiveScope - solidity_parser.ast.symtab.UsingFunctionSymbol - solidity_parser.ast.symtab.UsingOperatorSymbol - solidity_parser.ast.symtab.Builder2 - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.symtab.bytes - solidity_parser.ast.symtab.bytesn - solidity_parser.ast.symtab.bytes32 - solidity_parser.ast.symtab.uint - solidity_parser.ast.symtab.ACCEPT - solidity_parser.ast.symtab.unit_scope_of - solidity_parser.ast.symtab.ACCEPT_INHERITABLE - solidity_parser.ast.symtab.is_top_level - solidity_parser.ast.symtab.is_using_directive_scope - solidity_parser.ast.symtab.predicate_ignore_inherited_usings - solidity_parser.ast.symtab.predicate_accept_top_levels - solidity_parser.ast.symtab.ACCEPT_NO_INHERITED_USINGS - solidity_parser.ast.symtab.ACCEPT_CALLABLES - solidity_parser.ast.symtab.ACCEPT_NOT - solidity_parser.ast.symtab.ACCEPT_TOP_LEVEL_SCOPE - solidity_parser.ast.symtab.ACCEPT_ALL - solidity_parser.ast.symtab.test_predicate - solidity_parser.ast.symtab._add_to_results - solidity_parser.ast.symtab.create_builtin_scope - solidity_parser.ast.symtab.type_key - solidity_parser.ast.symtab.meta_type_key - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.symtab.Aliases - - -.. py:data:: Aliases - :type: TypeAlias - - - -.. py:function:: bytes() - - -.. py:function:: bytesn(n) - - -.. py:function:: bytes32() - - -.. py:function:: uint(size=256) - - -.. py:function:: ACCEPT(x) - - -.. py:function:: unit_scope_of(s) - - -.. py:function:: ACCEPT_INHERITABLE(base_scope) - - -.. py:function:: is_top_level(node: solidity_parser.ast.nodebase.Node) - - -.. py:function:: is_using_directive_scope(sym: Symbol) -> bool - - -.. py:function:: predicate_ignore_inherited_usings(base_scope) - - -.. py:function:: predicate_accept_top_levels(sym: Symbol) -> bool - - -.. py:function:: ACCEPT_NO_INHERITED_USINGS(base_scope) - - -.. py:function:: ACCEPT_CALLABLES(x) - - -.. py:function:: ACCEPT_NOT(p) - - -.. py:function:: ACCEPT_TOP_LEVEL_SCOPE(x) - - -.. py:function:: ACCEPT_ALL(*predicates) - - -.. py:function:: test_predicate(xs, predicate=None) - - -.. py:function:: _add_to_results(possible_symbols: Collection, results: list, found_already: Set) - - -.. py:class:: Scopeable(aliases: Optional[Aliases]) - - - Element that can be added as a child of a Scope - - .. py:attribute:: _T - - - - .. py:method:: set_parent_scope(parent_scope: Scope) - - Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks - - - .. py:method:: find_first_ancestor(predicate: Callable[[Scopeable], bool], get_parent: Optional[Callable[[Scopeable], Scope]] = None) -> Optional[_T] - - Walks up the symbol tree and finds the first element that satisfies the given predicate - - :param predicate: a function that takes a Scopeable and returns a bool to determine if it matches - :param get_parent: a function that takes a Scopeable and returns its parent, defaults to the parent_scope of a - Scopeable - :return: the first Scopeable that satisfies the predicate - - - .. py:method:: find_first_ancestor_of(ttype: Type[_T]) -> Optional[_T] - - Find the first ancestor that is of the given type, note: these are python types and not solc types. - - :param ttype: e.g. ContractOrInterfaceScope - :return: the first ancestor that is of the given type - - - .. py:method:: _check_single_symbol(name, results, default) - - - -.. py:class:: Symbol(aliases: Optional[Aliases], value) - - - Bases: :py:obj:`Scopeable` - - Element that can be added as a child of a Scope - - .. py:method:: get_as_dealiased_symbols() -> list[Symbol] - - - .. py:method:: res_syms() -> list[Symbol] - - - .. py:method:: res_syms_single() - - - .. py:method:: set_parent_scope(parent_scope: Scope) - - Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks - - - .. py:method:: str_type() - - - .. py:method:: __str__(level=0) - - Return str(self). - - - -.. py:class:: CrossScopeSymbolAlias(aliases: Aliases, other_symbol: Symbol) - - - Bases: :py:obj:`Symbol` - - Element that can be added as a child of a Scope - - .. py:method:: res_syms() -> list[Symbol] - - - .. py:method:: get_as_dealiased_symbols() -> list[Symbol] - - - -.. py:class:: Scope(aliases: Optional[Aliases]) - - - Bases: :py:obj:`Scopeable` - - Element that can be added as a child of a Scope - - .. py:method:: is_defined(name: str) -> bool - - Check if the name exists in the current scopes local table, i.e. whether it was declared in the current scope - - - .. py:method:: get_direct_children() -> Collection[Symbol] - - Get all children declared directly in this scope - - - .. py:method:: get_all_children(collect_predicate, explore_branch_predicate) - - Tree explorer for all DECLARED children and grandchildren, i.e. doesn't look at imports - - - .. py:method:: get_all_functions() -> list[ModFunErrEvtScope] - - Gets all DECLARED functions in the current scope/descendant scopes - - - .. py:method:: import_symbols_from_scope(other_scope: Scope) - - Links the symbols in another scope to the current scope, i.e. makes the imported symbols visible in the current - scope - - :param other_scope: The scope whose symbols should be imported - - - .. py:method:: add_global_symbol(symbol: Symbol) - - Helper function to add a symbol to the global scope(RootScope) - - - .. py:method:: add(symbol: Symbol) - - Adds a symbol to the current scope and set its parent scope to this scope - - - .. py:method:: find_current_level(name: str, predicate=None, visited_scopes: Set[Scope] = None) -> list[Symbol] - - Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that - are visible by an expression in the current scope. - - - .. py:method:: find_imported(name: str, predicate=None, visited_scopes: Set = None) -> list[Symbol] - - Finds the given name in all the imported scopes that are linked to the current scope. This can match many - valid symbols so it is up to the caller to choose the right one, however, the results are deduplicated by - checking that two symbols dealias to the same symbol. - - - .. py:method:: find_local(name: str) -> list[Symbol] - - Finds symbols in this scope's symbol table only - - - .. py:method:: find_from_parent(name: str, predicate=None) -> list[Symbol] - - - .. py:method:: find_multi_part_symbol(name: str, find_base_symbol: bool = False, predicate=None) - - Finds a potentially multi-part/qualified symbol (e.g. a.b.c) - - - .. py:method:: find(name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> list[Symbol] - - Entry point for the symbol finder. Finds the given name in this scope and any imported scopes - - Parameters: - name (str): The name to search for. - find_base_symbol (bool): Whether to find base symbols. - predicate (function): A function to filter symbols. - dealias (bool): Whether to dealias symbols. - - Returns: - list[Symbol]: A list of symbols that match the search criteria. - - - .. py:method:: find_single(name: str, find_base_symbol: bool = False, default=None, predicate=None) -> Optional[Symbol] - - - .. py:method:: find_user_type_scope(name, find_base_symbol: bool = False, default=None, predicate=None) -> Union[Scope, list[Scope]] - - Finds the scope of a user-defined type based on the given name. - :param name: The name of the type - :param find_base_symbol: Whether to find the base symbol or whether using scopes are acceptable results - :param default: The default value to return if no matches are found - :param predicate: Optional function to filter during the search - - :return: A single scope if find_base_symbol is True, or a list of scopes if find_base_symbol is False - - - .. py:method:: find_type(ttype, predicate=None, as_single=False) -> Optional[Scope] | list[Scope] - - Finds the scope for the given type in the current scope. The type scope might be different to the scope of the - type where the type was defined because of using statements. - A scope is created if one isn't visible in the current scope. - - :param ttype: The type to search for, CANNOT be a user type, use `find_user_type_scope` for that case - :param predicate: Optional function to filter during the search - :param as_single: Whether to return a single scope or a list of scopes - - :return: The scope if as_single is True or a list of scopes if as_single is False - - - .. py:method:: find_metatype(ttype, is_interface, is_enum) -> Scope - - - .. py:method:: str__symbols(level=0) - - Returns a string representation of all symbols in this scope and its children with indentation - - - .. py:method:: __str__(level=0) - - Return str(self). - - - -.. py:class:: ScopeAndSymbol(aliases: Optional[Aliases], ast_node) - - - Bases: :py:obj:`Scope`, :py:obj:`Symbol` - - Element that can be added as a child of a Scope - - .. py:method:: set_parent_scope(parent_scope: Scope) - - Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks - - - .. py:method:: __str__(level=0) - - Return str(self). - - - -.. py:class:: BuiltinObject(name: str, value=None) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: BuiltinFunction(name: str, input_types: list[solidity_parser.ast.types.Type] | None, output_types: list[solidity_parser.ast.types.Type] | None) - - - Bases: :py:obj:`Symbol` - - Element that can be added as a child of a Scope - - -.. py:class:: BuiltinValue(name: str, ttype: solidity_parser.ast.types.Type) - - - Bases: :py:obj:`Symbol` - - Element that can be added as a child of a Scope - - -.. py:function:: create_builtin_scope(key, value=None, values=None, functions=None) - - -.. py:function:: type_key(ttype) -> str - - -.. py:function:: meta_type_key(ttype) -> str - - -.. py:class:: RootScope(parser_version: solidity_parser.util.version_util.Version) - - - Bases: :py:obj:`Scope` - - Element that can be added as a child of a Scope - - -.. py:class:: FileScope(builder: Builder2, vfs: solidity_parser.filesys.VirtualFileSystem, source_unit_name: str, ast1_units: list[solidity_parser.ast.solnodes.SourceUnit]) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - .. py:method:: alias(source_unit_name: str) - :staticmethod: - - - .. py:method:: get_imported_source_unit(import_path: str) -> Optional[FileScope] - - - .. py:method:: set_parent_scope(parent_scope: Scope) - - Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks - - - -.. py:class:: LibraryScope(ast_node: solidity_parser.ast.solnodes.LibraryDefinition) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: ContractOrInterfaceScope(ast_node: Union[solidity_parser.ast.solnodes.ContractDefinition, solidity_parser.ast.solnodes.InterfaceDefinition]) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - .. py:method:: find_current_level(name: str, predicate=None, visited_scopes: Set = None, check_hierarchy=True) -> Optional[list[Symbol]] - - Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that - are visible by an expression in the current scope. - - - .. py:method:: find_in_contract_hierarchy(name: str, predicate, visited_scopes) - - - .. py:method:: get_supers() -> list[ContractOrInterfaceScope] - - - -.. py:class:: StructScope(ast_node: solidity_parser.ast.solnodes.StructDefinition) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: UserDefinedValueTypeScope(ast_node: solidity_parser.ast.solnodes.UserValueType) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: LibraryScope(ast_node: solidity_parser.ast.solnodes.LibraryDefinition) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: EnumScope(ast_node: solidity_parser.ast.solnodes.EnumDefinition) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: ModFunErrEvtScope(ast_node: Union[solidity_parser.ast.solnodes.FunctionDefinition, solidity_parser.ast.solnodes.EventDefinition, solidity_parser.ast.solnodes.ErrorDefinition, solidity_parser.ast.solnodes.ModifierDefinition]) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: ImportSymbol(aliases: Optional[Aliases], ast_node: solidity_parser.ast.solnodes.ImportDirective) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - .. py:method:: get_as_dealiased_symbols() -> list[Symbol] - - - .. py:method:: get_imported_scope() -> Optional[FileScope] - - - .. py:method:: _get_imported_symbols() -> list[Symbol] - - - .. py:method:: res_syms() -> list[Symbol] - - - .. py:method:: get_direct_children() -> Collection[Symbol] - - Get all children declared directly in this scope - - - .. py:method:: find(name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> Optional[list[Symbol]] - - Entry point for the symbol finder. Finds the given name in this scope and any imported scopes - - Parameters: - name (str): The name to search for. - find_base_symbol (bool): Whether to find base symbols. - predicate (function): A function to filter symbols. - dealias (bool): Whether to dealias symbols. - - Returns: - list[Symbol]: A list of symbols that match the search criteria. - - - .. py:method:: find_metatype(ttype, is_interface, is_enum) -> Scope - - - .. py:method:: find_local(name: str) -> Optional[list[Symbol]] - - Finds symbols in this scope's symbol table only - - - .. py:method:: find_first_ancestor(predicate, get_parent=None) - - Walks up the symbol tree and finds the first element that satisfies the given predicate - - :param predicate: a function that takes a Scopeable and returns a bool to determine if it matches - :param get_parent: a function that takes a Scopeable and returns its parent, defaults to the parent_scope of a - Scopeable - :return: the first Scopeable that satisfies the predicate - - - .. py:method:: find_first_ancestor_of(ttype: Union[Type, Tuple[Type]]) - - Find the first ancestor that is of the given type, note: these are python types and not solc types. - - :param ttype: e.g. ContractOrInterfaceScope - :return: the first ancestor that is of the given type - - - .. py:method:: find_imported(name: str, predicate=None, visited_scopes: Set = None) -> Optional[list[Symbol]] - - Finds the given name in all the imported scopes that are linked to the current scope. This can match many - valid symbols so it is up to the caller to choose the right one, however, the results are deduplicated by - checking that two symbols dealias to the same symbol. - - - .. py:method:: find_current_level(name: str, predicate=None, visited_scopes: Set = None) -> Optional[list[Symbol]] - - Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that - are visible by an expression in the current scope. - - - .. py:method:: find_single(name: str, find_base_symbol: bool = False, default=None, predicate=None) -> Optional[Symbol] - - - .. py:method:: find_from_parent(name: str, predicate=None) -> list[Symbol] - - - -.. py:class:: AliasImportSymbol(ast_node: solidity_parser.ast.solnodes.SymbolImportDirective, alias_index) - - - Bases: :py:obj:`ImportSymbol` - - Element that can be added as a child of a Scope - - .. py:method:: _get_imported_symbols() -> list[Symbol] - - - -.. py:class:: UnitImportSymbol(ast_node: solidity_parser.ast.solnodes.UnitImportDirective) - - - Bases: :py:obj:`ImportSymbol` - - Element that can be added as a child of a Scope - - .. py:method:: _get_imported_symbols() -> list[Symbol] - - - -.. py:class:: ProxyScope(name: str, base_scope: ScopeAndSymbol) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - .. py:method:: res_syms() -> list[Symbol] - - - -.. py:class:: UsingDirectiveScope(node: solidity_parser.ast.solnodes.UsingDirective) - - - Bases: :py:obj:`ScopeAndSymbol` - - Element that can be added as a child of a Scope - - -.. py:class:: UsingFunctionSymbol(target: ModFunErrEvtScope, override_type: solidity_parser.ast.types.Type) - - - Bases: :py:obj:`Symbol` - - Symbol for a function that was added to the current scope by a Solidity using statement. Solidity docs state that - all functions, even those that don't match the type specifier in the using statement have to be added to the scope - the using statement is declared in. This symbol type is required instead of the usual ModFunErrEvtSymbol as we need - to be able to associate the bound type from the using statement and the first parameter type of the "value" of this - symbol(i.e. the FunctionDefinition) may or may not be the same as the specified one. - - .. py:method:: res_syms() -> list[Symbol] - - - -.. py:class:: UsingOperatorSymbol(target: ModFunErrEvtScope, override_type: solidity_parser.ast.types.Type, operator: Union[solidity_parser.ast.solnodes.UnaryOpCode, solidity_parser.ast.solnodes.BinaryOpCode]) - - - Bases: :py:obj:`Symbol` - - Similar to UsingFunctionSymbol except for operator overloads - - .. py:method:: res_syms() -> list[Symbol] - - - -.. py:class:: Builder2(vfs: solidity_parser.filesys.VirtualFileSystem, parser_version: solidity_parser.util.version_util.Version = None) - - - .. py:class:: Context(file_scope, unit_scope) - - - - .. py:method:: process_or_find(loaded_source: solidity_parser.filesys.LoadedSource) - - - .. py:method:: process_or_find_from_base_dir(relative_source_unit_name: str | pathlib.Path) - - - .. py:method:: process_file(source_unit_name: str, source_units: list[solidity_parser.ast.solnodes.SourceUnit] = None) - - - .. py:method:: sort_ast_nodes(nodes) - - - .. py:method:: add_node_dfs(parent_scope, node, context: Context, build_skeletons, visit_index=0) - - Recursively traverse a node and its children and create symbols and scopes in a nested hierarchy - - This function adds newly created symbols and scopes to the given parent scope and does not return anything - - - .. py:method:: make_using_scope(node: solidity_parser.ast.solnodes.UsingDirective) - - - .. py:method:: make_var_decl_scope(node: solidity_parser.ast.solnodes.VarDecl) - - - .. py:method:: add_to_scope(parent: Scope, *children: Symbol) - - - .. py:method:: make_scope(node: solidity_parser.ast.nodebase.Node, name=None) - - - .. py:method:: make_symbol(node: solidity_parser.ast.nodebase.Node, sym_type=Symbol, name=None) - - - .. py:method:: scope_name(base_name, node) - - - .. py:method:: find_using_target_scope_and_name(current_scope, target_type: solidity_parser.ast.types.Type) - - - .. py:method:: make_proxy_scope(scope_name, creator_scope, base_scope, library_scope=None) - - - .. py:method:: get_proxy_scope_for_type(cur_scope, target_type, target_scope_name, target_type_scope, library_scope=None, check_lib=True) - - - .. py:method:: get_using_function_symbol_for_func(target_type, target_type_scope, symbol, operator=None) - - - .. py:method:: process_using_any_type(context: Context, node: solidity_parser.ast.solnodes.UsingDirective) - - - .. py:method:: process_using_library_type(context: Context, node: solidity_parser.ast.solnodes.UsingDirective) - - - .. py:method:: find_using_current_scope(node, context) - - - .. py:method:: process_using_functions(node: solidity_parser.ast.solnodes.UsingDirective, context: Context) - - - .. py:method:: process_using_directive(node: solidity_parser.ast.solnodes.UsingDirective, context: Context) - - - .. py:method:: make_symbols_for_node(node, context: Context, build_skeletons: bool, visit_index: int) - - - diff --git a/docs/source/autoapi/solidity_parser/ast/types/index.rst b/docs/source/autoapi/solidity_parser/ast/types/index.rst deleted file mode 100644 index 007c063..0000000 --- a/docs/source/autoapi/solidity_parser/ast/types/index.rst +++ /dev/null @@ -1,810 +0,0 @@ -:py:mod:`solidity_parser.ast.types` -=================================== - -.. py:module:: solidity_parser.ast.types - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.types.Type - solidity_parser.ast.types.FloatType - solidity_parser.ast.types.VoidType - solidity_parser.ast.types.ArrayType - solidity_parser.ast.types.FixedLengthArrayType - solidity_parser.ast.types.VariableLengthArrayType - solidity_parser.ast.types.AddressType - solidity_parser.ast.types.ByteType - solidity_parser.ast.types.BytesType - solidity_parser.ast.types.IntType - solidity_parser.ast.types.PreciseIntType - solidity_parser.ast.types.BoolType - solidity_parser.ast.types.StringType - solidity_parser.ast.types.PreciseStringType - solidity_parser.ast.types.MappingType - solidity_parser.ast.types.UserType - solidity_parser.ast.types.BuiltinType - solidity_parser.ast.types.FunctionType - solidity_parser.ast.types.TupleType - solidity_parser.ast.types.MetaTypeType - solidity_parser.ast.types.VarType - solidity_parser.ast.types.AnyType - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.ast.types.UIntType - solidity_parser.ast.types.Bytes - solidity_parser.ast.types.ABIType - - - -.. py:class:: Type - - - Bases: :py:obj:`solidity_parser.ast.nodebase.Node`, :py:obj:`abc.ABC` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: scope - :type: Scope - - Shim for symbol table scoping. The scope field is also defined in solnodes1 Node but since this base class is - defined in this file, it must be defined here as well - - - .. py:method:: are_matching_types(target_param_types, actual_param_types) - :staticmethod: - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_array() -> bool - - - .. py:method:: is_byte_array() -> bool - - Check if the type is any type of byte array, e.g. bytes, bytes1, bytes32 - - - .. py:method:: is_byte_array_underlying() -> bool - - Check if this type is logically an array of bytes, e.g. bytes, bytes1, bytes32 and string - - - .. py:method:: is_string() -> bool - - - .. py:method:: is_function() -> bool - - - .. py:method:: is_int() -> bool - - - .. py:method:: is_bool() -> bool - - - .. py:method:: is_user_type() -> bool - - Check if the type is a user defined type, e.g. struct, enum, contract, etc - - - .. py:method:: is_address() -> bool - - - .. py:method:: is_mapping() -> bool - - - .. py:method:: is_byte() -> bool - - Check if the type is a single "byte" - - - .. py:method:: is_tuple() -> bool - - Check if the type is a tuple. These are synthetic types in Solidity but can be used in ASTs - - - .. py:method:: is_literal_type() -> bool - - Check if the type is a literal type, i.e. an inferred type from a constant number or string expression. - These are not real types in Solidity but are used in solc to aid type inference and optimization rules - - - .. py:method:: is_float() -> bool - - Check whether this type is a compile time float - - - .. py:method:: is_void() -> bool - - Check if the type represents a void return type. This isn't part of Solidity directly but is represented - when a function doesn't define any return types - - - .. py:method:: type_key() - - Returns a unique key for the type that can be used to cache types in the symbol table - - - .. py:method:: __str__() - :abstractmethod: - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: FloatType - - - Bases: :py:obj:`Type` - - This is not a real type in valid Solidity code but the Solidity compiler allows compile time expression evaluation - of floats - - .. py:attribute:: value - :type: float - - Since the value is always known at compile time, we have it here - - - .. py:method:: is_float() -> bool - - Check whether this type is a compile time float - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - -.. py:class:: VoidType - - - Bases: :py:obj:`Type` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:method:: is_void() -> bool - - Check if the type represents a void return type. This isn't part of Solidity directly but is represented - when a function doesn't define any return types - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: ArrayType - - - Bases: :py:obj:`Type` - - Single dimension array type with no size attributes - - .. py:attribute:: base_type - :type: Type - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: has_size() -> bool - - - .. py:method:: is_fixed_size() -> bool - - - .. py:method:: is_array() -> bool - - - -.. py:class:: FixedLengthArrayType - - - Bases: :py:obj:`ArrayType` - - Array type with a known length that is determined at compile time - - .. py:attribute:: size - :type: int - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: is_fixed_size() -> bool - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: VariableLengthArrayType - - - Bases: :py:obj:`ArrayType` - - Array type with a length that is determined at runtime - - .. py:attribute:: size - :type: Expr - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: AddressType - - - Bases: :py:obj:`Type` - - Solidity address/address payable type, functionally this is a uint160 - - .. py:attribute:: is_payable - :type: bool - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_address() -> bool - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: ByteType - - - Bases: :py:obj:`Type` - - Single 8bit byte type - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_byte() -> bool - - Check if the type is a single "byte" - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:function:: UIntType(size=256) - - -.. py:function:: Bytes(size=None) - - -.. py:class:: BytesType - - - Bases: :py:obj:`ArrayType` - - bytes type only (similar but not equal to byte[]/bytes1[]) - - .. py:attribute:: base_type - :type: Type - - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: IntType - - - Bases: :py:obj:`Type` - - Solidity native integer type of various bit length and signedness - - .. py:attribute:: is_signed - :type: bool - - Whether the type is a signed int or unsigned int - - - .. py:attribute:: size - :type: int - - Size of the type in bits - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_int() -> bool - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: PreciseIntType - - - Bases: :py:obj:`IntType` - - Solidity native integer type of various bit length and signedness - - .. py:attribute:: real_bit_length - :type: int - - - - .. py:method:: is_literal_type() -> bool - - Check if the type is a literal type, i.e. an inferred type from a constant number or string expression. - These are not real types in Solidity but are used in solc to aid type inference and optimization rules - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: BoolType - - - Bases: :py:obj:`Type` - - Solidity native boolean type - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_bool() -> bool - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: StringType - - - Bases: :py:obj:`ArrayType` - - Solidity native string type - - .. py:attribute:: base_type - :type: Type - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_string() -> bool - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: PreciseStringType - - - Bases: :py:obj:`StringType` - - String literal type that has a known length at compile time - - .. py:attribute:: real_size - :type: int - - - - .. py:method:: is_literal_type() -> bool - - Check if the type is a literal type, i.e. an inferred type from a constant number or string expression. - These are not real types in Solidity but are used in solc to aid type inference and optimization rules - - - .. py:method:: has_size() -> bool - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: MappingType - - - Bases: :py:obj:`Type` - - Type that represents a function mapping definition - - For example in the mapping '(uint x => Campaign c)', src would be 'unit' and the dst would be 'Campaign', - src_key would be 'x' and dst_key would be 'c' - - .. py:attribute:: src - :type: Type - - - - .. py:attribute:: dst - :type: Type - - - - .. py:attribute:: src_name - :type: Ident - - - - .. py:attribute:: dst_name - :type: Ident - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: is_mapping() -> bool - - - .. py:method:: flatten() -> list[Type] - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:class:: UserType - - - Bases: :py:obj:`Type` - - Type invoked using a valid Solidity reference, e.g. a class, contract, library, enum, etc name. - This is an "unlinked" type, e.g. it has no underlying AST node backing it and has no corresponding context other - than the scope it was declared in. For AST2 use solnodes2.ResolvedUserType instead. - - .. py:attribute:: name - :type: Ident - - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: BuiltinType - - - Bases: :py:obj:`Type` - - Type representing types of Solidity builtin objects, e.g. the type of the 'msg' or 'abi' objects in the expressions - `msg.sender` or `abi.decode(...)` - - .. py:attribute:: name - :type: str - - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - -.. py:function:: ABIType() -> BuiltinType - - -.. py:class:: FunctionType - - - Bases: :py:obj:`Type` - - Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that - clients can traverse all child and parent nodes. - - .. py:attribute:: inputs - :type: list[Type] - - - - .. py:attribute:: outputs - :type: list[Type] - - - - .. py:attribute:: modifiers - :type: list[Modifier] - - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_function() -> bool - - - .. py:method:: can_implicitly_cast_from(actual_type: Type) -> bool - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: __str__() - - Return str(self). - - - .. py:method:: type_key() - - Returns a unique key for the type that can be used to cache types in the symbol table - - - -.. py:class:: TupleType - - - Bases: :py:obj:`Type` - - Type of a tuple of elements. This is not a real Solidity type but is used to represent the type of tuple expressions - (e.g. desugaring) in the AST - - .. py:attribute:: ttypes - :type: list[Type] - - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: is_tuple() -> bool - - Check if the type is a tuple. These are synthetic types in Solidity but can be used in ASTs - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: MetaTypeType - - - Bases: :py:obj:`Type` - - Metatype Solidity type, i.e. type(X). This type has a few builtin fields such as min, max, name, creationCode, - runtimeCode and interfaceId - - .. py:attribute:: ttype - :type: Type - - - - .. py:method:: is_builtin() -> bool - - Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc - - - .. py:method:: code_str() - - Returns the string representation of the type in Solidity syntax - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: VarType - - - Bases: :py:obj:`Type` - - Type that wasn't explicitly identified in the code - - This type should not be used without running a subsequent type inference pass. - - An example variable declaration that would use this type symbol: 'var (, mantissa, exponent) = ... ' - - .. py:method:: __str__() - - Return str(self). - - - -.. py:class:: AnyType - - - Bases: :py:obj:`Type` - - Type that is used only in 'using' declarations to specify that the declaration is overriding all possible types - - For example in the declaration 'using SomeLibrary for *', the overriden type here is AnyType(every type - that is imported from SomeLibrary) - - .. py:method:: __str__() - - Return str(self). - - - diff --git a/docs/source/autoapi/solidity_parser/collectors/collector/index.rst b/docs/source/autoapi/solidity_parser/collectors/collector/index.rst deleted file mode 100644 index 4802f10..0000000 --- a/docs/source/autoapi/solidity_parser/collectors/collector/index.rst +++ /dev/null @@ -1,26 +0,0 @@ -:py:mod:`solidity_parser.collectors.collector` -============================================== - -.. py:module:: solidity_parser.collectors.collector - - -Module Contents ---------------- - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.collectors.collector.get_minor_ver - solidity_parser.collectors.collector.collect_top_level_objects - - - -.. py:function:: get_minor_ver(txt) - - -.. py:function:: collect_top_level_objects(stream, vers, debug=False) - - diff --git a/docs/source/autoapi/solidity_parser/collectors/index.rst b/docs/source/autoapi/solidity_parser/collectors/index.rst deleted file mode 100644 index 8faa993..0000000 --- a/docs/source/autoapi/solidity_parser/collectors/index.rst +++ /dev/null @@ -1,19 +0,0 @@ -:py:mod:`solidity_parser.collectors` -==================================== - -.. py:module:: solidity_parser.collectors - - -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - - collector/index.rst - v000/index.rst - v060/index.rst - v070/index.rst - v080/index.rst - - diff --git a/docs/source/autoapi/solidity_parser/collectors/v000/index.rst b/docs/source/autoapi/solidity_parser/collectors/v000/index.rst deleted file mode 100644 index 9ba96ca..0000000 --- a/docs/source/autoapi/solidity_parser/collectors/v000/index.rst +++ /dev/null @@ -1,40 +0,0 @@ -:py:mod:`solidity_parser.collectors.v000` -========================================= - -.. py:module:: solidity_parser.collectors.v000 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.collectors.v000.TopLevelObjectCollector - solidity_parser.collectors.v000.TopLevelObject - - - - -.. py:class:: TopLevelObjectCollector - - - .. py:method:: reset() - - - .. py:method:: visit_terminal_node(node, parent=None) - - - .. py:method:: newline() - - - .. py:method:: collect_lines() - - - -.. py:class:: TopLevelObject(name, content, type) - - - diff --git a/docs/source/autoapi/solidity_parser/collectors/v060/index.rst b/docs/source/autoapi/solidity_parser/collectors/v060/index.rst deleted file mode 100644 index 297dad3..0000000 --- a/docs/source/autoapi/solidity_parser/collectors/v060/index.rst +++ /dev/null @@ -1,35 +0,0 @@ -:py:mod:`solidity_parser.collectors.v060` -========================================= - -.. py:module:: solidity_parser.collectors.v060 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.collectors.v060.TopLevelObjectCollectorV060 - - - - -.. py:class:: TopLevelObjectCollectorV060 - - - Bases: :py:obj:`solidity_parser.collectors.v000.TopLevelObjectCollector` - - .. py:attribute:: TOP_LEVEL_OBJECT_TYPES - - - - .. py:method:: visit(node, parent=None) - - - .. py:method:: collect(stream) - - - diff --git a/docs/source/autoapi/solidity_parser/collectors/v070/index.rst b/docs/source/autoapi/solidity_parser/collectors/v070/index.rst deleted file mode 100644 index c5267d6..0000000 --- a/docs/source/autoapi/solidity_parser/collectors/v070/index.rst +++ /dev/null @@ -1,35 +0,0 @@ -:py:mod:`solidity_parser.collectors.v070` -========================================= - -.. py:module:: solidity_parser.collectors.v070 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.collectors.v070.TopLevelObjectCollectorV070 - - - - -.. py:class:: TopLevelObjectCollectorV070 - - - Bases: :py:obj:`solidity_parser.collectors.v000.TopLevelObjectCollector` - - .. py:attribute:: TOP_LEVEL_OBJECT_TYPES - - - - .. py:method:: visit(node, parent=None) - - - .. py:method:: collect(stream) - - - diff --git a/docs/source/autoapi/solidity_parser/collectors/v080/index.rst b/docs/source/autoapi/solidity_parser/collectors/v080/index.rst deleted file mode 100644 index a158f4d..0000000 --- a/docs/source/autoapi/solidity_parser/collectors/v080/index.rst +++ /dev/null @@ -1,35 +0,0 @@ -:py:mod:`solidity_parser.collectors.v080` -========================================= - -.. py:module:: solidity_parser.collectors.v080 - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.collectors.v080.TopLevelObjectCollectorV080 - - - - -.. py:class:: TopLevelObjectCollectorV080 - - - Bases: :py:obj:`solidity_parser.collectors.v000.TopLevelObjectCollector` - - .. py:attribute:: TOP_LEVEL_OBJECT_TYPES - - - - .. py:method:: visit(node, parent=None) - - - .. py:method:: collect(stream) - - - diff --git a/docs/source/autoapi/solidity_parser/errors/index.rst b/docs/source/autoapi/solidity_parser/errors/index.rst deleted file mode 100644 index b6fe4cf..0000000 --- a/docs/source/autoapi/solidity_parser/errors/index.rst +++ /dev/null @@ -1,43 +0,0 @@ -:py:mod:`solidity_parser.errors` -================================ - -.. py:module:: solidity_parser.errors - - -Module Contents ---------------- - -.. py:exception:: AntlrParsingError(unit_name: str, version: solidity_parser.util.version_util.Version, input_src: str, details) - - - Bases: :py:obj:`Exception` - - Common base class for all non-exit exceptions. - - .. py:attribute:: Detail - - - - -.. py:data:: CPEArgs - :type: TypeAlias - - message, source_unit_name, line_number, line_offset - - -.. py:exception:: CodeProcessingError(message: str, source_unit_name: str, line_number, line_offset) - - - Bases: :py:obj:`Exception` - - Common base class for all non-exit exceptions. - - -.. py:exception:: UnexpectedCodeProcessingError(message: str, source_unit_name: str, line_number: int, line_offset: int, root_cause: Exception) - - - Bases: :py:obj:`CodeProcessingError` - - Common base class for all non-exit exceptions. - - diff --git a/docs/source/autoapi/solidity_parser/filesys/index.rst b/docs/source/autoapi/solidity_parser/filesys/index.rst deleted file mode 100644 index 82cd182..0000000 --- a/docs/source/autoapi/solidity_parser/filesys/index.rst +++ /dev/null @@ -1,181 +0,0 @@ -:py:mod:`solidity_parser.filesys` -================================= - -.. py:module:: solidity_parser.filesys - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.filesys.Source - solidity_parser.filesys.StandardJsonInput - solidity_parser.filesys.LoadedSource - solidity_parser.filesys.VirtualFileSystem - - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.filesys.ImportMapping - - -.. py:class:: Source - - - Structure of a source unit defined in the standard JSON input - - .. py:attribute:: urls - :type: Optional[List[str]] - - - - .. py:attribute:: content - :type: str - - - - -.. py:class:: StandardJsonInput - - - Solidity standard JSON input see: - https://docs.soliditylang.org/en/v0.8.25/using-the-compiler.html#compiler-api - - .. py:attribute:: sources - :type: Dict[str, Source] - - - - -.. py:class:: LoadedSource - - - Source unit loaded inside the virtual filesystem - - .. py:property:: ast - :type: List[solidity_parser.ast.solnodes.SourceUnit] - - Property for getting the AST from the source code lazily - - - .. py:attribute:: source_unit_name - :type: str - - The computed source unit name, see the solidity docs for how this is computed - - - .. py:attribute:: contents - :type: str - - Source code - - - .. py:attribute:: origin - :type: Optional[pathlib.Path] - - Path to the source unit on disk, if it was loaded from disk - - - .. py:attribute:: ast_creator_callback - :type: Optional[Callable[[str], List[solidity_parser.ast.solnodes.SourceUnit]]] - - Optional function for changing the AST creation method, e.g. for testing and forcing the parser version - - - -.. py:data:: ImportMapping - - An import remapping for changing the source unit name before the import is resolved - - -.. py:class:: VirtualFileSystem(base_path: str | pathlib.Path, cwd: str | pathlib.Path = None, include_paths: List[str | pathlib.Path] = None, compiler_version: solidity_parser.util.version_util.Version = None) - - - This is the "virtual file system" defined in the Solidity docs and implemented in solc. The idea is to abstract - away the specifics of how the sources are stored, such as on disk or in memory and the paths used in the source - files to resolve imports. The code is not ideal but it emulates the behaviour of the c++ code of solc. - - https://docs.soliditylang.org/en/v0.8.17/path-resolution.html - - .. py:property:: base_path - - - .. py:property:: include_paths - - - .. py:method:: process_cli_input_file(file_path) - - - .. py:method:: process_standard_json(path: str) - - - .. py:method:: parse_import_remappings(remappings_file_path) - - - .. py:method:: add_import_remapping(context, prefix, target) - - - .. py:method:: lookup_import_path(import_path: str, importer_source_unit_name: str = None) -> LoadedSource - - - .. py:method:: _add_loaded_source(source_unit_name: str, source_code: str, creator=None, origin=None) -> LoadedSource - - - .. py:method:: _read_file(path: str, is_cli_path=True) -> str - - - .. py:method:: _do_read_path(path: pathlib.Path) -> str - - - .. py:method:: _cli_path_to_source_name(input_file_path) -> str - - Computes the source name for a source file supplied via command line invocation of solc - - - .. py:method:: _norm_vfs_path(path: Union[str, pathlib.Path]) -> str - - Path normalisation according to solidity lang docs - - - .. py:method:: _read_file_callback(su_name: str, base_dir: str, include_paths: List[str]) -> Tuple[str, str] - - - .. py:method:: _remap_import(source_unit_name: str, importer_source_unit_name: str) -> str - - Takes a source unit name and checks if it should be remapped - Note: do not pass an import path as the source unit name - - - .. py:method:: _compute_source_unit_name(path: str, importer_source_unit_name: str) -> str - - - .. py:method:: _path_to_generic_string(path: Union[pathlib.Path, str]) -> str - :staticmethod: - - - .. py:method:: _clean_path(*parts: List[str]) -> str - :staticmethod: - - - .. py:method:: _strip_prefix(prefix, path) -> Optional[pathlib.Path] - :staticmethod: - - - .. py:method:: _remove_last_path_segment(path: str) -> str - :staticmethod: - - - .. py:method:: _is_relative_import(path: str) -> bool - :staticmethod: - - - diff --git a/docs/source/autoapi/solidity_parser/index.rst b/docs/source/autoapi/solidity_parser/index.rst deleted file mode 100644 index 2c53ef6..0000000 --- a/docs/source/autoapi/solidity_parser/index.rst +++ /dev/null @@ -1,27 +0,0 @@ -:py:mod:`solidity_parser` -========================= - -.. py:module:: solidity_parser - - -Subpackages ------------ -.. toctree:: - :titlesonly: - :maxdepth: 3 - - ast/index.rst - collectors/index.rst - util/index.rst - - -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - - errors/index.rst - filesys/index.rst - - diff --git a/docs/source/autoapi/solidity_parser/util/index.rst b/docs/source/autoapi/solidity_parser/util/index.rst deleted file mode 100644 index 59f2aa5..0000000 --- a/docs/source/autoapi/solidity_parser/util/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -:py:mod:`solidity_parser.util` -============================== - -.. py:module:: solidity_parser.util - - -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - - version_util/index.rst - - diff --git a/docs/source/autoapi/solidity_parser/util/version_util/index.rst b/docs/source/autoapi/solidity_parser/util/version_util/index.rst deleted file mode 100644 index a3e6e9c..0000000 --- a/docs/source/autoapi/solidity_parser/util/version_util/index.rst +++ /dev/null @@ -1,83 +0,0 @@ -:py:mod:`solidity_parser.util.version_util` -=========================================== - -.. py:module:: solidity_parser.util.version_util - - -Module Contents ---------------- - -Classes -~~~~~~~ - -.. autoapisummary:: - - solidity_parser.util.version_util.Version - - - -Functions -~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.util.version_util.extract_version_from_src_input - solidity_parser.util.version_util.parse_version - - - -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - - solidity_parser.util.version_util.VERSION_PATTERN - - -.. py:data:: VERSION_PATTERN - - - -.. py:class:: Version - - - .. py:attribute:: major - :type: int - - - - .. py:attribute:: minor - :type: int - - - - .. py:attribute:: patch - :type: int - - - - .. py:method:: is_enforced_in(testing_version: Version) -> bool - - Tests whether a feature that was introduced in the given testing_version is enforced in the current version - E.g. if a feature is only available in or after version 8.0.1 but the current version is 7.0.0, that feature - should not be enforced and this function returns False - - - .. py:method:: __str__() - - Return str(self). - - - -.. py:function:: extract_version_from_src_input(txt: str) -> Version - - Extracts the solidity version from the input source code - :param txt: the entire source file - - -.. py:function:: parse_version(ver_text: str) -> Version - - Parses a solidity version string into a Version object - :param ver_text: the version string only, e.g. "0.6.12" - - From fdfeb9fe64c01af70c37aeed25d4e524c74d7102 Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Thu, 9 May 2024 13:54:53 +0100 Subject: [PATCH 17/18] change to cloudfare page docs --- .github/workflows/gendocs.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/gendocs.yml b/.github/workflows/gendocs.yml index f6a9494..d13bf01 100644 --- a/.github/workflows/gendocs.yml +++ b/.github/workflows/gendocs.yml @@ -2,12 +2,13 @@ name: gendocs on: [push, workflow_dispatch] -permissions: - contents: write - jobs: gendocs: runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + name: Deploy to Cloudflare Pages steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 @@ -26,11 +27,12 @@ jobs: - name: Sphinx build run: | sphinx-build -M html docs/source docs/build - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.event_name == 'push' }} + - name: Publish + uses: cloudflare/pages-action@1 with: - publish_branch: gh-pages - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: docs/build/html - force_orphan: true \ No newline at end of file + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + projectName: docs + directory: docs/build/html + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + wranglerVersion: '3' From 05f27d69f62fd574b5c2632aed457ffff5b89f8b Mon Sep 17 00:00:00 2001 From: Bilal Tariq Date: Thu, 9 May 2024 13:56:24 +0100 Subject: [PATCH 18/18] add cloudfare acc id --- .github/workflows/gendocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gendocs.yml b/.github/workflows/gendocs.yml index d13bf01..9e87818 100644 --- a/.github/workflows/gendocs.yml +++ b/.github/workflows/gendocs.yml @@ -31,7 +31,7 @@ jobs: uses: cloudflare/pages-action@1 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + accountId: aa2caed8dec0b29b442a9f250bd48ba6 projectName: docs directory: docs/build/html gitHubToken: ${{ secrets.GITHUB_TOKEN }}