Zack Williams | 28f1e49 | 2019-02-01 10:02:56 -0700 | [diff] [blame^] | 1 | # Copyright 2017-present Open Networking Foundation and others |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
| 15 | from __future__ import print_function |
| 16 | from six.moves import range |
| 17 | |
| 18 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 19 | class LexHelper: |
| 20 | offset = 0 |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 21 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 22 | def get_max_linespan(self, p): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 23 | defSpan = [1e60, -1] |
| 24 | mSpan = [1e60, -1] |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 25 | for sp in range(0, len(p)): |
| 26 | csp = p.linespan(sp) |
| 27 | if csp[0] == 0 and csp[1] == 0: |
| 28 | if hasattr(p[sp], "linespan"): |
| 29 | csp = p[sp].linespan |
| 30 | else: |
| 31 | continue |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 32 | if csp is None or len(csp) != 2: |
| 33 | continue |
| 34 | if csp[0] == 0 and csp[1] == 0: |
| 35 | continue |
| 36 | if csp[0] < mSpan[0]: |
| 37 | mSpan[0] = csp[0] |
| 38 | if csp[1] > mSpan[1]: |
| 39 | mSpan[1] = csp[1] |
| 40 | if defSpan == mSpan: |
| 41 | return (0, 0) |
| 42 | return tuple([mSpan[0] - self.offset, mSpan[1] - self.offset]) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 43 | |
| 44 | def get_max_lexspan(self, p): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 45 | defSpan = [1e60, -1] |
| 46 | mSpan = [1e60, -1] |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 47 | for sp in range(0, len(p)): |
| 48 | csp = p.lexspan(sp) |
| 49 | if csp[0] == 0 and csp[1] == 0: |
| 50 | if hasattr(p[sp], "lexspan"): |
| 51 | csp = p[sp].lexspan |
| 52 | else: |
| 53 | continue |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 54 | if csp is None or len(csp) != 2: |
| 55 | continue |
| 56 | if csp[0] == 0 and csp[1] == 0: |
| 57 | continue |
| 58 | if csp[0] < mSpan[0]: |
| 59 | mSpan[0] = csp[0] |
| 60 | if csp[1] > mSpan[1]: |
| 61 | mSpan[1] = csp[1] |
| 62 | if defSpan == mSpan: |
| 63 | return (0, 0) |
| 64 | return tuple([mSpan[0] - self.offset, mSpan[1] - self.offset]) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 65 | |
| 66 | def set_parse_object(self, dst, p): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 67 | dst.setLexData( |
| 68 | linespan=self.get_max_linespan(p), |
| 69 | lexspan=self.get_max_lexspan(p)) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 70 | dst.setLexObj(p) |
| 71 | |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 72 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 73 | class Base(object): |
| 74 | parent = None |
| 75 | lexspan = None |
| 76 | linespan = None |
| 77 | |
| 78 | def v(self, obj, visitor): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 79 | if obj is None: |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 80 | return |
| 81 | elif hasattr(obj, "accept"): |
| 82 | obj.accept(visitor) |
| 83 | elif isinstance(obj, list): |
| 84 | for s in obj: |
| 85 | self.v(s, visitor) |
| 86 | pass |
| 87 | pass |
| 88 | |
| 89 | @staticmethod |
| 90 | def p(obj, parent): |
| 91 | if isinstance(obj, list): |
| 92 | for s in obj: |
| 93 | Base.p(s, parent) |
| 94 | |
| 95 | if hasattr(obj, "parent"): |
| 96 | obj.parent = parent |
| 97 | |
| 98 | # Lexical unit - contains lexspan and linespan for later analysis. |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 99 | |
| 100 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 101 | class LU(Base): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 102 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 103 | def __init__(self, p, idx): |
| 104 | self.p = p |
| 105 | self.idx = idx |
| 106 | self.pval = p[idx] |
| 107 | self.lexspan = p.lexspan(idx) |
| 108 | self.linespan = p.linespan(idx) |
| 109 | |
| 110 | # If string is in the value (raw value) and start and stop lexspan is the same, add real span |
| 111 | # obtained by string length. |
| 112 | if isinstance(self.pval, str) \ |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 113 | and self.lexspan is not None \ |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 114 | and self.lexspan[0] == self.lexspan[1] \ |
| 115 | and self.lexspan[0] != 0: |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 116 | self.lexspan = tuple( |
| 117 | [self.lexspan[0], self.lexspan[0] + len(self.pval)]) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 118 | super(LU, self).__init__() |
| 119 | |
| 120 | @staticmethod |
| 121 | def i(p, idx): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 122 | if isinstance(p[idx], LU): |
| 123 | return p[idx] |
| 124 | if isinstance(p[idx], str): |
| 125 | return LU(p, idx) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 126 | return p[idx] |
| 127 | |
| 128 | def describe(self): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 129 | return "LU(%s,%s)" % (self.pval, self.lexspan) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 130 | |
| 131 | def __str__(self): |
| 132 | return self.pval |
| 133 | |
| 134 | def __repr__(self): |
| 135 | return self.describe() |
| 136 | |
| 137 | def accept(self, visitor): |
| 138 | self.v(self.pval, visitor) |
| 139 | |
| 140 | def __iter__(self): |
| 141 | for x in self.pval: |
| 142 | yield x |
| 143 | |
| 144 | # Base node |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 145 | |
| 146 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 147 | class SourceElement(Base): |
| 148 | ''' |
| 149 | A SourceElement is the base class for all elements that occur in a Protocol Buffers |
| 150 | file parsed by plyproto. |
| 151 | ''' |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 152 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 153 | def __init__(self, linespan=[], lexspan=[], p=None): |
| 154 | super(SourceElement, self).__init__() |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 155 | self._fields = [] # ['linespan', 'lexspan'] |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 156 | self.linespan = linespan |
| 157 | self.lexspan = lexspan |
| 158 | self.p = p |
| 159 | |
| 160 | def __repr__(self): |
| 161 | equals = ("{0}={1!r}".format(k, getattr(self, k)) |
| 162 | for k in self._fields) |
| 163 | args = ", ".join(equals) |
| 164 | return "{0}({1})".format(self.__class__.__name__, args) |
| 165 | |
| 166 | def __eq__(self, other): |
| 167 | try: |
| 168 | return self.__dict__ == other.__dict__ |
| 169 | except AttributeError: |
| 170 | return False |
| 171 | |
| 172 | def __ne__(self, other): |
| 173 | return not self == other |
| 174 | |
| 175 | def setLexData(self, linespan, lexspan): |
| 176 | self.linespan = linespan |
| 177 | self.lexspan = lexspan |
| 178 | |
| 179 | def setLexObj(self, p): |
| 180 | self.p = p |
| 181 | |
| 182 | def accept(self, visitor): |
| 183 | pass |
| 184 | |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 185 | |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 186 | class Visitor(object): |
| 187 | |
| 188 | def __init__(self, verbose=False): |
| 189 | self.verbose = verbose |
| 190 | |
| 191 | def __getattr__(self, name): |
| 192 | if not name.startswith('visit_'): |
Zack Williams | be7f36d | 2018-02-02 11:37:11 -0700 | [diff] [blame] | 193 | raise AttributeError( |
| 194 | 'name must start with visit_ but was {}'.format(name)) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 195 | |
| 196 | def f(element): |
| 197 | if self.verbose: |
| 198 | msg = 'unimplemented call to {}; ignoring ({})' |
Zack Williams | 28f1e49 | 2019-02-01 10:02:56 -0700 | [diff] [blame^] | 199 | print((msg.format(name, element))) |
Sapan Bhatia | 64c7251 | 2017-06-23 02:32:45 -0700 | [diff] [blame] | 200 | return True |
| 201 | return f |
| 202 | |
| 203 | # visitor.visit_PackageStatement(self) |
| 204 | # visitor.visit_ImportStatement(self) |
| 205 | # visitor.visit_OptionStatement(self) |
| 206 | # visitor.visit_FieldDirective(self) |
| 207 | # visitor.visit_FieldType(self) |
| 208 | # visitor.visit_FieldDefinition(self) |
| 209 | # visitor.visit_EnumFieldDefinition(self) |
| 210 | # visitor.visit_EnumDefinition(self) |
| 211 | # visitor.visit_MessageDefinition(self) |
| 212 | # visitor.visit_MessageExtension(self) |
| 213 | # visitor.visit_MethodDefinition(self) |
| 214 | # visitor.visit_ServiceDefinition(self) |
| 215 | # visitor.visit_ExtensionsDirective(self) |
| 216 | # visitor.visit_Literal(self) |
| 217 | # visitor.visit_Name(self) |
| 218 | # visitor.visit_Proto(self) |
| 219 | # visitor.visit_LU(self) |