|
| 1 | +# Integration of ANTLR into coala core |
| 2 | + |
| 3 | +| Metadata | | |
| 4 | +| ------------ |-----------------------------------------| |
| 5 | +| cEP | 0018 | |
| 6 | +| Version | 0.1.0 | |
| 7 | +| Title | Integration of ANTLR into coala core | |
| 8 | +| Authors | Viresh Gupta <viresh16118@iiitd.ac.in> | |
| 9 | +| Status | Proposed | |
| 10 | +| Type | Feature | |
| 11 | + |
| 12 | +# Abstract |
| 13 | + |
| 14 | +This document describes how an API based on ANTLR will be constructed and |
| 15 | +maintained. |
| 16 | + |
| 17 | +# Introduction |
| 18 | + |
| 19 | +ANTLR provides parsers for various language grammars and thus we can provide |
| 20 | +an interface from within coala and make it available to bear writers so that |
| 21 | +they can write advanced linting bears. This will aim at supporting the more |
| 22 | +flexible visitor based method of AST traversal (as opposed to listener based |
| 23 | +mechanisms). |
| 24 | + |
| 25 | +The proposal is to introduce a parallel concept to the coala-bears library, |
| 26 | +which will be called the coala-ast hereon. |
| 27 | + |
| 28 | +# Proposed Change |
| 29 | + |
| 30 | +Here is the detailed implementation stepwise: |
| 31 | + |
| 32 | + 1. There will be a separate repository named as coala-ast which will be |
| 33 | + installable via ```pip install coala-ast```. |
| 34 | + 2. A new interface would be introduced in coala-core (```coala/coalib```), |
| 35 | + which would be the new ast package. This would be the ```coalib.ast``` package |
| 36 | + 3. The ```coalib.ast``` package will provide endpoints relevant to the visitor |
| 37 | + model of traversing the ast generated via ANTLR. |
| 38 | + 4. The coala-ast repository will hold parser generated (with python targe) |
| 39 | + beforehand for the supported set of grammars. |
| 40 | + 5. ```coalib.ast``` will have an AST loader class that will be responsible for |
| 41 | + loading the AST of a given file depending on the extension. |
| 42 | + For e.g, a .c file will be loaded using the parser from ```coala-ast``` for c |
| 43 | + language. |
| 44 | + 6. Another AST walker class will be responsible for providing endpoints for |
| 45 | + traversing the AST using methods such as ```get_next_node``` and |
| 46 | + ```get_previous_node```. |
| 47 | + |
| 48 | +# Management of the new ```coala-ast``` repository |
| 49 | + |
| 50 | +Managing a new repository is a heavy task, and this will be highly automated as |
| 51 | +follows: |
| 52 | + |
| 53 | + 1. The parsers in coala-ast would be generated and pushed via travis-builds |
| 54 | + whenever a new grammar is pushed. |
| 55 | + 2. The cib tool can be enhanced to deal with the installation of bears that |
| 56 | + require only some specified parsers (for e.g a PyUnusedVarBear would only |
| 57 | + require parser for python) |
| 58 | + 3. The cib tool can also trigger specialised builds and download the newly |
| 59 | + generated parser on the fly |
| 60 | + |
| 61 | +# Code Samples/Prototypes |
| 62 | +Here is a prototype for the implementations within coalib.ast: |
| 63 | + |
| 64 | +```python |
| 65 | +import parsers |
| 66 | +import antlr4 |
| 67 | + |
| 68 | +class ASTLoader(): |
| 69 | + lexerMapping = { |
| 70 | + 'c' : parser.clexer, |
| 71 | + 'py' : parser.pylexer, |
| 72 | + 'js' : parser.jslexer, |
| 73 | + ... |
| 74 | + } |
| 75 | + parserMapping = { |
| 76 | + 'c' : parser.cparser, |
| 77 | + 'py' : parser.pyparser, |
| 78 | + 'js' : parser.jsparser, |
| 79 | + ... |
| 80 | + } |
| 81 | + |
| 82 | + @staticmethod |
| 83 | + def loadFile(file,filename): |
| 84 | + """ Loads file's AST into memory """ |
| 85 | + ext = get_extension(filename) |
| 86 | + if ext is None: |
| 87 | + raise FileExtensionNotSupported |
| 88 | + inputStream = file.readlines() |
| 89 | + lexer = lexerMapping[ext](inputStream) |
| 90 | + parser = parserMapping[ext](lexer) |
| 91 | + return parser |
| 92 | + |
| 93 | +class ASTWalker(): |
| 94 | + treeRoot = None |
| 95 | + tree = None |
| 96 | + def __init__(file,filename): |
| 97 | + self.tree = ASTLoader.load(file, filename) |
| 98 | + self.treeRoot = self.tree |
| 99 | + |
| 100 | + def get_next_node(self): |
| 101 | + """ Modify the internal tree variable and return the next node """ |
| 102 | + |
| 103 | + def get_prev_node(self): |
| 104 | + """ Modify the internal tree variable and return prev node """ |
| 105 | + |
| 106 | + def reset(self): |
| 107 | + """ Reset the internal tree variable to tree root """ |
| 108 | + |
| 109 | + def isTerminalNode(node): |
| 110 | + """ Determine if the node is terminal """ |
| 111 | + return isinstance(node, antlr4.tree.Tree.TerminalNode) |
| 112 | + |
| 113 | + ... |
| 114 | + |
| 115 | +``` |
| 116 | + |
| 117 | + |
| 118 | +### Prototype of `ASTBear` class implementation: |
| 119 | + |
| 120 | +```python |
| 121 | +from coalib.bears.LocalBear import Bear |
| 122 | +from coalaib.ast import ASTWalker |
| 123 | + |
| 124 | +class ASTBear(LocalBear): |
| 125 | + walker = None |
| 126 | + |
| 127 | + def initialise(file, filename): |
| 128 | + walker = ASTWalker(file, filename) |
| 129 | + |
| 130 | + def run(self, |
| 131 | + filename, |
| 132 | + file, |
| 133 | + tree, |
| 134 | + *args, |
| 135 | + dependency_results=None, |
| 136 | + **kwargs): |
| 137 | + raise NotImplementedError # Needs to be done by bear |
| 138 | + |
| 139 | +``` |
| 140 | + |
| 141 | +A test bear: |
| 142 | + |
| 143 | +```python |
| 144 | +from coalib.results.Result import Result |
| 145 | +from coalib.bears.ASTBear import ASTBear |
| 146 | + |
| 147 | +class TestBear(ASTBear): |
| 148 | + def run(self, |
| 149 | + filename, |
| 150 | + file, |
| 151 | + tree, |
| 152 | + *args, |
| 153 | + dependency_results=None, |
| 154 | + **kwargs): |
| 155 | + self.initialise(file, filename) |
| 156 | + num_nodes = 0 |
| 157 | + while(tree.get_next_node() != None): |
| 158 | + num_nodes += 1 |
| 159 | + yield Result(self, 'File {} has {} nodes ' |
| 160 | + ' in AST.'.format(filename, num_nodes)) |
| 161 | + |
| 162 | +``` |
0 commit comments