Lexical units added
* Lexical support added to the model. Enables to get information about position of a particular element in the source text (character number). This helps with refactoring (search & replace).
* Lexical unit object wraps raw string occurrence so it can be easily found.
diff --git a/plyproto/model.py b/plyproto/model.py
index f3b33d6..bcff7ee 100644
--- a/plyproto/model.py
+++ b/plyproto/model.py
@@ -36,6 +36,46 @@
# visitor.visit_Name(self)
# visitor.visit_Proto(self)
+# Lexical unit - contains lexspan and linespan for later analysis.
+class LU(object):
+ def __init__(self, p, idx):
+ self.p = p
+ self.idx = idx
+ self.pval = p[idx]
+ self.lexspan = p.lexspan(idx)
+ self.linespan = p.linespan(idx)
+
+ # If string is in the value (raw value) and start and stop lexspan is the same, add real span
+ # obtained by string length.
+ if isinstance(self.pval, str) \
+ and self.lexspan != None \
+ and self.lexspan[0] == self.lexspan[1] \
+ and self.lexspan[0] != 0:
+ self.lexspan = tuple([self.lexspan[0], self.lexspan[0] + len(self.pval)])
+ super(LU, self).__init__()
+
+ @staticmethod
+ def i(p, idx):
+ if isinstance(p[idx], LU): return p[idx]
+ if isinstance(p[idx], str): return LU(p, idx)
+ return p[idx]
+
+ def describe(self):
+ return "LU(%s,%s)" % (self.pval, self.lexspan)
+
+ def __str__(self):
+ return self.pval
+
+ def __repr__(self):
+ return self.describe()
+
+ def accept(self, visitor):
+ pass
+
+ def __iter__(self):
+ for x in self.pval:
+ yield x
+
# Base node
class SourceElement(object):
'''
@@ -232,6 +272,7 @@
super(Name, self).__init__(linespan=linespan, lexspan=lexspan, p=p)
self._fields += ['value']
self.value = value
+ self.deriveLex()
def append_name(self, name):
try:
@@ -239,9 +280,37 @@
except:
self.value = self.value + '.' + name
+ def deriveLex(self):
+ if hasattr(self.value, "lexspan"):
+ self.lexspan = self.value.lexspan
+ self.linespan = self.value.linespan
+ else:
+ return
+
def accept(self, visitor):
visitor.visit_Name(self)
+class DotName(Name):
+ elements = []
+ def __init__(self, elements, linespan=None, lexspan=None, p=None):
+ super(DotName, self).__init__('.'.join([str(x) for x in elements]), linespan=linespan, lexspan=lexspan, p=p)
+ self._fields += ['elements']
+ self.elements = elements
+ self.deriveLex()
+
+ def deriveLex(self):
+ if isinstance(self.elements, list) and len(self.elements)>0:
+ self.lexspan = (min([x.lexspan[0] for x in self.elements if x.lexspan[0] != 0]), max([x.lexspan[1] for x in self.elements if x.lexspan[1] != 0]))
+ self.linespan = (min([x.linespan[0] for x in self.elements if x.linespan[0] != 0]), max([x.linespan[1] for x in self.elements if x.linespan[1] != 0]))
+ elif hasattr(self.elements, "lexspan"):
+ self.lexspan = self.elements.lexspan
+ self.linespan = self.elements.linespan
+ else:
+ return
+
+ def accept(self, visitor):
+ visitor.visit_DotName(self)
+
class ProtoFile(SourceElement):
def __init__(self, pkg, body, linespan=None, lexspan=None, p=None):