blob: 15136f517135bd50864ed1a660817eac89aa6369 [file] [log] [blame]
Zack Williams28f1e492019-02-01 10:02:56 -07001# 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
15from __future__ import print_function
16from six.moves import range
17
18
Sapan Bhatia64c72512017-06-23 02:32:45 -070019class LexHelper:
20 offset = 0
Zack Williamsbe7f36d2018-02-02 11:37:11 -070021
Sapan Bhatia64c72512017-06-23 02:32:45 -070022 def get_max_linespan(self, p):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070023 defSpan = [1e60, -1]
24 mSpan = [1e60, -1]
Sapan Bhatia64c72512017-06-23 02:32:45 -070025 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 Williamsbe7f36d2018-02-02 11:37:11 -070032 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 Bhatia64c72512017-06-23 02:32:45 -070043
44 def get_max_lexspan(self, p):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070045 defSpan = [1e60, -1]
46 mSpan = [1e60, -1]
Sapan Bhatia64c72512017-06-23 02:32:45 -070047 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 Williamsbe7f36d2018-02-02 11:37:11 -070054 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 Bhatia64c72512017-06-23 02:32:45 -070065
66 def set_parse_object(self, dst, p):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070067 dst.setLexData(
68 linespan=self.get_max_linespan(p),
69 lexspan=self.get_max_lexspan(p))
Sapan Bhatia64c72512017-06-23 02:32:45 -070070 dst.setLexObj(p)
71
Zack Williamsbe7f36d2018-02-02 11:37:11 -070072
Sapan Bhatia64c72512017-06-23 02:32:45 -070073class Base(object):
74 parent = None
75 lexspan = None
76 linespan = None
77
78 def v(self, obj, visitor):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070079 if obj is None:
Sapan Bhatia64c72512017-06-23 02:32:45 -070080 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 Williamsbe7f36d2018-02-02 11:37:11 -070099
100
Sapan Bhatia64c72512017-06-23 02:32:45 -0700101class LU(Base):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700102
Sapan Bhatia64c72512017-06-23 02:32:45 -0700103 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 Williamsbe7f36d2018-02-02 11:37:11 -0700113 and self.lexspan is not None \
Sapan Bhatia64c72512017-06-23 02:32:45 -0700114 and self.lexspan[0] == self.lexspan[1] \
115 and self.lexspan[0] != 0:
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700116 self.lexspan = tuple(
117 [self.lexspan[0], self.lexspan[0] + len(self.pval)])
Sapan Bhatia64c72512017-06-23 02:32:45 -0700118 super(LU, self).__init__()
119
120 @staticmethod
121 def i(p, idx):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700122 if isinstance(p[idx], LU):
123 return p[idx]
124 if isinstance(p[idx], str):
125 return LU(p, idx)
Sapan Bhatia64c72512017-06-23 02:32:45 -0700126 return p[idx]
127
128 def describe(self):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700129 return "LU(%s,%s)" % (self.pval, self.lexspan)
Sapan Bhatia64c72512017-06-23 02:32:45 -0700130
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 Williamsbe7f36d2018-02-02 11:37:11 -0700145
146
Sapan Bhatia64c72512017-06-23 02:32:45 -0700147class 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 Williamsbe7f36d2018-02-02 11:37:11 -0700152
Sapan Bhatia64c72512017-06-23 02:32:45 -0700153 def __init__(self, linespan=[], lexspan=[], p=None):
154 super(SourceElement, self).__init__()
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700155 self._fields = [] # ['linespan', 'lexspan']
Sapan Bhatia64c72512017-06-23 02:32:45 -0700156 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 Williamsbe7f36d2018-02-02 11:37:11 -0700185
Sapan Bhatia64c72512017-06-23 02:32:45 -0700186class 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 Williamsbe7f36d2018-02-02 11:37:11 -0700193 raise AttributeError(
194 'name must start with visit_ but was {}'.format(name))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700195
196 def f(element):
197 if self.verbose:
198 msg = 'unimplemented call to {}; ignoring ({})'
Zack Williams28f1e492019-02-01 10:02:56 -0700199 print((msg.format(name, element)))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700200 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)