blob: a38d71629be95a87d10003d0692907bb97acdac8 [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
Scott Baker20997cf2019-04-04 10:10:06 -070017import sys
Zack Williams28f1e492019-02-01 10:02:56 -070018
19
Sapan Bhatia64c72512017-06-23 02:32:45 -070020class LexHelper:
21 offset = 0
Zack Williamsbe7f36d2018-02-02 11:37:11 -070022
Sapan Bhatia64c72512017-06-23 02:32:45 -070023 def get_max_linespan(self, p):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070024 defSpan = [1e60, -1]
25 mSpan = [1e60, -1]
Sapan Bhatia64c72512017-06-23 02:32:45 -070026 for sp in range(0, len(p)):
27 csp = p.linespan(sp)
28 if csp[0] == 0 and csp[1] == 0:
29 if hasattr(p[sp], "linespan"):
30 csp = p[sp].linespan
31 else:
32 continue
Zack Williamsbe7f36d2018-02-02 11:37:11 -070033 if csp is None or len(csp) != 2:
34 continue
35 if csp[0] == 0 and csp[1] == 0:
36 continue
37 if csp[0] < mSpan[0]:
38 mSpan[0] = csp[0]
39 if csp[1] > mSpan[1]:
40 mSpan[1] = csp[1]
41 if defSpan == mSpan:
42 return (0, 0)
43 return tuple([mSpan[0] - self.offset, mSpan[1] - self.offset])
Sapan Bhatia64c72512017-06-23 02:32:45 -070044
45 def get_max_lexspan(self, p):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070046 defSpan = [1e60, -1]
47 mSpan = [1e60, -1]
Sapan Bhatia64c72512017-06-23 02:32:45 -070048 for sp in range(0, len(p)):
49 csp = p.lexspan(sp)
50 if csp[0] == 0 and csp[1] == 0:
51 if hasattr(p[sp], "lexspan"):
52 csp = p[sp].lexspan
53 else:
54 continue
Zack Williamsbe7f36d2018-02-02 11:37:11 -070055 if csp is None or len(csp) != 2:
56 continue
57 if csp[0] == 0 and csp[1] == 0:
58 continue
59 if csp[0] < mSpan[0]:
60 mSpan[0] = csp[0]
61 if csp[1] > mSpan[1]:
62 mSpan[1] = csp[1]
63 if defSpan == mSpan:
64 return (0, 0)
65 return tuple([mSpan[0] - self.offset, mSpan[1] - self.offset])
Sapan Bhatia64c72512017-06-23 02:32:45 -070066
67 def set_parse_object(self, dst, p):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070068 dst.setLexData(
69 linespan=self.get_max_linespan(p),
70 lexspan=self.get_max_lexspan(p))
Sapan Bhatia64c72512017-06-23 02:32:45 -070071 dst.setLexObj(p)
72
Zack Williamsbe7f36d2018-02-02 11:37:11 -070073
Sapan Bhatia64c72512017-06-23 02:32:45 -070074class Base(object):
75 parent = None
76 lexspan = None
77 linespan = None
78
79 def v(self, obj, visitor):
Zack Williamsbe7f36d2018-02-02 11:37:11 -070080 if obj is None:
Sapan Bhatia64c72512017-06-23 02:32:45 -070081 return
82 elif hasattr(obj, "accept"):
83 obj.accept(visitor)
84 elif isinstance(obj, list):
85 for s in obj:
86 self.v(s, visitor)
87 pass
88 pass
89
90 @staticmethod
91 def p(obj, parent):
92 if isinstance(obj, list):
93 for s in obj:
94 Base.p(s, parent)
95
96 if hasattr(obj, "parent"):
97 obj.parent = parent
98
99# Lexical unit - contains lexspan and linespan for later analysis.
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700100
101
Sapan Bhatia64c72512017-06-23 02:32:45 -0700102class LU(Base):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700103
Sapan Bhatia64c72512017-06-23 02:32:45 -0700104 def __init__(self, p, idx):
105 self.p = p
106 self.idx = idx
107 self.pval = p[idx]
108 self.lexspan = p.lexspan(idx)
109 self.linespan = p.linespan(idx)
110
111 # If string is in the value (raw value) and start and stop lexspan is the same, add real span
112 # obtained by string length.
113 if isinstance(self.pval, str) \
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700114 and self.lexspan is not None \
Sapan Bhatia64c72512017-06-23 02:32:45 -0700115 and self.lexspan[0] == self.lexspan[1] \
116 and self.lexspan[0] != 0:
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700117 self.lexspan = tuple(
118 [self.lexspan[0], self.lexspan[0] + len(self.pval)])
Sapan Bhatia64c72512017-06-23 02:32:45 -0700119 super(LU, self).__init__()
120
121 @staticmethod
122 def i(p, idx):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700123 if isinstance(p[idx], LU):
124 return p[idx]
125 if isinstance(p[idx], str):
126 return LU(p, idx)
Sapan Bhatia64c72512017-06-23 02:32:45 -0700127 return p[idx]
128
129 def describe(self):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700130 return "LU(%s,%s)" % (self.pval, self.lexspan)
Sapan Bhatia64c72512017-06-23 02:32:45 -0700131
132 def __str__(self):
133 return self.pval
134
135 def __repr__(self):
136 return self.describe()
137
138 def accept(self, visitor):
139 self.v(self.pval, visitor)
140
141 def __iter__(self):
142 for x in self.pval:
143 yield x
144
145# Base node
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700146
147
Sapan Bhatia64c72512017-06-23 02:32:45 -0700148class SourceElement(Base):
149 '''
150 A SourceElement is the base class for all elements that occur in a Protocol Buffers
151 file parsed by plyproto.
152 '''
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700153
Sapan Bhatia64c72512017-06-23 02:32:45 -0700154 def __init__(self, linespan=[], lexspan=[], p=None):
155 super(SourceElement, self).__init__()
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700156 self._fields = [] # ['linespan', 'lexspan']
Sapan Bhatia64c72512017-06-23 02:32:45 -0700157 self.linespan = linespan
158 self.lexspan = lexspan
159 self.p = p
160
161 def __repr__(self):
162 equals = ("{0}={1!r}".format(k, getattr(self, k))
163 for k in self._fields)
164 args = ", ".join(equals)
165 return "{0}({1})".format(self.__class__.__name__, args)
166
167 def __eq__(self, other):
168 try:
169 return self.__dict__ == other.__dict__
170 except AttributeError:
171 return False
172
173 def __ne__(self, other):
174 return not self == other
175
176 def setLexData(self, linespan, lexspan):
177 self.linespan = linespan
178 self.lexspan = lexspan
179
180 def setLexObj(self, p):
181 self.p = p
182
183 def accept(self, visitor):
184 pass
185
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700186
Sapan Bhatia64c72512017-06-23 02:32:45 -0700187class Visitor(object):
188
189 def __init__(self, verbose=False):
190 self.verbose = verbose
191
192 def __getattr__(self, name):
193 if not name.startswith('visit_'):
Zack Williamsbe7f36d2018-02-02 11:37:11 -0700194 raise AttributeError(
195 'name must start with visit_ but was {}'.format(name))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700196
197 def f(element):
198 if self.verbose:
199 msg = 'unimplemented call to {}; ignoring ({})'
Scott Baker20997cf2019-04-04 10:10:06 -0700200 print((msg.format(name, element)), file=sys.stderr)
Sapan Bhatia64c72512017-06-23 02:32:45 -0700201 return True
202 return f
203
204 # visitor.visit_PackageStatement(self)
205 # visitor.visit_ImportStatement(self)
206 # visitor.visit_OptionStatement(self)
207 # visitor.visit_FieldDirective(self)
208 # visitor.visit_FieldType(self)
209 # visitor.visit_FieldDefinition(self)
210 # visitor.visit_EnumFieldDefinition(self)
211 # visitor.visit_EnumDefinition(self)
212 # visitor.visit_MessageDefinition(self)
213 # visitor.visit_MessageExtension(self)
214 # visitor.visit_MethodDefinition(self)
215 # visitor.visit_ServiceDefinition(self)
216 # visitor.visit_ExtensionsDirective(self)
217 # visitor.visit_Literal(self)
218 # visitor.visit_Name(self)
219 # visitor.visit_Proto(self)
220 # visitor.visit_LU(self)