Skip to content

Commit

Permalink
ADDED: Visitor and Listener implementation with an exemplary run_pars…
Browse files Browse the repository at this point in the history
…er.py code.

TODO: README Usage section
  • Loading branch information
yjkellyjoo committed Dec 30, 2021
1 parent a3f6b0c commit 84ebda1
Show file tree
Hide file tree
Showing 6 changed files with 1,739 additions and 4 deletions.
45 changes: 45 additions & 0 deletions MySolidityListener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from antlr4_generated.SolidityParser import SolidityParser
from antlr4_generated.SolidityListener import SolidityListener


class MySolidityListener(SolidityListener):
def __init__(self):
self.function_strings = []
self.function_names = []
self.contract_names = []

def getNodeText(self, ctx, i, var):
for child in ctx.getChildren():
if child.getChildCount() != 0:
self.getNodeText(child, i, var)
else:
var[i] += child.getText() + ' '

def enterContractDefinition(self, ctx:SolidityParser.ContractDefinitionContext):
self.contract_names.append(ctx.identifier().getText())

def enterFunctionDefinition(self, ctx: SolidityParser.FunctionDefinitionContext):
if ctx.block() is not None:
ind = len(self.function_names)

if ctx.functionDescriptor().identifier() is not None:
self.function_names.append(ctx.functionDescriptor().identifier().getText())
# fallback function definition's identifier can be None
elif "function" in ctx.functionDescriptor().getText():
self.function_names.append("")
# rest of the cases: constructor, fallback (with keyword) or receive. get the type and save as name.
else:
self.function_names.append("")
self.getNodeText(ctx.functionDescriptor(), ind, self.function_names)

self.function_strings.append("")
self.getNodeText(ctx, ind, self.function_strings)

def enterModifierDefinition(self, ctx:SolidityParser.ModifierDefinitionContext):
if ctx.block() is not None:
ind = len(self.function_names)

self.function_names.append(ctx.identifier().getText())

self.function_strings.append("")
self.getNodeText(ctx, ind, self.function_strings)
121 changes: 121 additions & 0 deletions MySolidityVisitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import rsc.constants as constants
from antlr4_generated.SolidityListener import SolidityListener
from antlr4_generated.SolidityParser import SolidityParser
from antlr4_generated.SolidityVisitor import SolidityVisitor


class MySolidityVisitor(SolidityVisitor):
def __init__(self):
# initialize all identifiers
self.resultMap = {}

self.fparamIds = set()
self.elementaryTypes = set()
self.functionCalls = set()
self.eventCalls = set()
self.identifiers = set()

self.structNames = set()
self.contractNames = set()

def make_resultMap(self):
# link every Sets into the identifier Map
self.resultMap[constants.fparam] = self.fparamIds
self.resultMap[constants.dtype] = self.elementaryTypes
self.resultMap[constants.funccall] = self.functionCalls

## struct name starting with a capital letter could be misled as an event function call.
for struct in self.structNames:
if struct in self.eventCalls:
self.eventCalls.remove(struct)
## contract name can also be.
for contract in self.contractNames:
if contract in self.eventCalls:
self.eventCalls.remove(contract)
self.resultMap[constants.eventcall] = self.eventCalls

self.resultMap[constants.lvar] = self.identifiers

def visitSourceUnit(self, ctx:SolidityParser.SourceUnitContext):
self.visitChildren(ctx)
self.make_resultMap()
return self.resultMap

def visitContractPart(self, ctx:SolidityParser.ContractPartContext):
self.visitChildren(ctx)
self.make_resultMap()
return self.resultMap

def visitParameter(self, ctx:SolidityParser.ParameterContext):
if ctx.identifier() is not None:
self.fparamIds.add(ctx.identifier().getText())

return self.visitChildren(ctx)

def visitElementaryTypeName(self, ctx:SolidityParser.ElementaryTypeNameContext):
self.elementaryTypes.add(ctx.getText())

return self.visitChildren(ctx)

def visitFunctionCall(self, ctx:SolidityParser.FunctionCallContext):
func_expression = ctx.expression()
child_count = func_expression.getChildCount()
last_child = func_expression.getChild(child_count-1)
functionCall = last_child.getText()
if functionCall == '':
return self.visitChildren(ctx)
elif functionCall[0].isupper(): ## for event call cases before v0.4.21
self.eventCalls.add(functionCall)
else:
self.functionCalls.add(functionCall)

return self.visitChildren(ctx)

def visitFunctionCallWithOptions(self, ctx:SolidityParser.FunctionCallWithOptionsContext):
func_expression = ctx.expression()
child_count = func_expression.getChildCount()
last_child = func_expression.getChild(child_count-1)
functionCall = last_child.getText()
if functionCall[0].isupper(): ## for event call cases before v0.4.21
self.eventCalls.add(functionCall)
else:
self.functionCalls.add(functionCall)

return self.visitChildren(ctx)

def visitStructDefinition(self, ctx:SolidityParser.StructDefinitionContext):
self.structNames.add(ctx.identifier().getText())

return self.visitChildren(ctx)

def visitContractDefinition(self, ctx:SolidityParser.ContractDefinitionContext):
self.contractNames.add(ctx.identifier().getText())
for ihe in ctx.inheritanceSpecifier():
self.contractNames.add(ihe.getText())

return self.visitChildren(ctx)

def visitIdentifier(self, ctx:SolidityParser.IdentifierContext):
if ctx.Identifier() is not None:
self.identifiers.add(ctx.Identifier().getText())
else:
self.identifiers.add(ctx.getText())
return self.visitChildren(ctx)


class VisitSolidityListener(SolidityListener):
def __init__(self):
self.type_conversion_strings = []

def getNodeText(self, ctx, i, var):
for child in ctx.getChildren():
if child.getChildCount() != 0:
self.getNodeText(child, i, var)
else:
var[i].append(child.getText())

def enterTypeConversion(self, ctx:SolidityParser.TypeConversionContext):
ind = len(self.type_conversion_strings)

self.type_conversion_strings.append([])
self.getNodeText(ctx, ind, self.type_conversion_strings)
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Python version 3.8.X (I have used 3.8.5) with [antlr4-python3-runtime](https://p
$ pip install antlr4-python3-runtime
```
#### (Optional) ANTLR4
If you wish to edit the .g4 and try out your own grammar, set up ANTLR4 (I have used version 4.9.2).
If you wish to _edit the .g4 and try out your own grammar_, set up ANTLR4 (I have used version 4.9.2).
* For Windows:
[Following blog](https://levlaz.org/setting-up-antlr4-on-windows/) gives good step-by-step instructions for Windows.

Expand Down Expand Up @@ -139,9 +139,9 @@ If you wish to edit the .g4 and try out your own grammar, set up ANTLR4 (I have

## Usage

[comment]: <> (Use this space to show useful examples of how a project can be used. Additional screenshots, code examples and demos work well in this space. You may also link to more resources.)

[comment]: <> (_For more examples, please refer to the [Documentation]&#40;https://example.com&#41;_)

TODO

```shell
$ antlr4 -o /antlr4-generated/ -Dlanguage=Python3 -visitor Solidity.g4
Expand Down Expand Up @@ -182,7 +182,7 @@ Don't forget to give the project a star! Thanks again!

## License

Distributed under the GNU General Public License. See [LICENSE](https://github.com/yjkellyjoo/Solidity-complete-parser/blob/main/LICENSE) for more information.
Distributed under the GNU General Public License v3.0. See [LICENSE](https://github.com/yjkellyjoo/Solidity-complete-parser/blob/main/LICENSE) for more information.

<p align="right">(<a href="#top">back to top</a>)</p>

Expand Down
5 changes: 5 additions & 0 deletions rsc/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fparam = "FPARAM"
dtype = "DTYPE"
funccall = "FUNCCALL"
eventcall = "EVENTCALL"
lvar = "VAR"
Loading

0 comments on commit 84ebda1

Please sign in to comment.