[Numpy-svn] r3375 - trunk/numpy/f2py/lib/parser

numpy-svn at scipy.org numpy-svn at scipy.org
Fri Oct 20 08:32:29 EDT 2006


Author: pearu
Date: 2006-10-20 07:32:23 -0500 (Fri, 20 Oct 2006)
New Revision: 3375

Added:
   trunk/numpy/f2py/lib/parser/pattern_tools.py
Modified:
   trunk/numpy/f2py/lib/parser/expressions.py
   trunk/numpy/f2py/lib/parser/test_expressions.py
Log:
F2PY G3: Impl. pattern tools for expression parsing.

Modified: trunk/numpy/f2py/lib/parser/expressions.py
===================================================================
--- trunk/numpy/f2py/lib/parser/expressions.py	2006-10-20 06:44:43 UTC (rev 3374)
+++ trunk/numpy/f2py/lib/parser/expressions.py	2006-10-20 12:32:23 UTC (rev 3375)
@@ -28,50 +28,47 @@
     def __str__(self): return '.%s.' % (self.letters)
     def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self.letters)
 
-def set_subclasses(cls):
-    for basecls in cls.__bases__:
-        if issubclass(basecls, Base):
-            try:
-                subclasses = basecls.__dict__['_subclasses']
-            except KeyError:
-                subclasses = basecls._subclasses = []
-            subclasses.append(cls)
-    return
+class NoChildAllowed:
+    pass
+class NoChildAllowedError(Exception):
+    pass
+class NoMatchError(Exception):
+    pass
 
 is_name = re.compile(r'\A[a-z]\w*\Z',re.I).match
 
-class Expression:
-    def __new__(cls, string):
-        if is_name(string):
-            obj = object.__new__(Name)
-            obj._init(string)
-            return obj
+class Base(object):
 
-class NoMatch(Exception):
-    pass
+    subclasses = {}
 
-class Base(object):
     def __new__(cls, string):
         match = getattr(cls,'match',None)
         if match is not None:
             if match(string):
                 obj = object.__new__(cls)
-                obj._init(string)
+                init = cls.__dict__.get('init', Base.init)
+                init(obj, string)
                 return obj
-        else:
-            assert cls._subclasses,`cls`
-            for c in cls._subclasses:
-                try:
-                    return c(string)
-                except NoMatch, msg:
-                    pass
-        raise NoMatch,'%s: %r' % (cls.__name__, string)
-    def _init(self, string):
+        for c in Base.subclasses.get(cls.__name__,[]):
+            try:
+                return c(string)
+            except NoMatchError:
+                pass
+        raise NoMatchError,'%s: %r' % (cls.__name__, string)
+
+    def init(self, string):
         self.string = string
         return
-    def __str__(self): return self.string
+    
+    def __str__(self):
+        str_func = self.__class__.__dict__.get('tostr', None)
+        if str_func is not None:
+            return str_func(self)
+        return self.string
     def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self.string)
 
+
+
 class Primary(Base):
     """
     <primary> = <constant>
@@ -111,12 +108,8 @@
     <structure-component> = <data-ref>
     """
 
-class Name(Designator):
-    """
-    <name> = <letter> [ <alpha-numeric-character> ]...
-    """
-    match = is_name
 
+
 class LiteralConstant(Constant):
     """
     <constant> = <int-literal-constant>
@@ -127,27 +120,122 @@
                  | <boz-literal-constant>
     """
 
-class IntLiteralConstant(LiteralConstant):
+class SignedIntLiteralConstant(LiteralConstant):
     """
+    <signed-int-literal-constant> = [ <sign> ] <int-literal-constant>
+    <sign> = + | -
+    """
+    match = re.compile(r'\A[+-]\s*\d+\Z').match
+
+    def init(self, string):
+        Base.init(self, string)
+        self.content = [string[0], IntLiteralConstant(string[1:].lstrip())]
+        return
+    def tostr(self):
+        return '%s%s' % tuple(self.content)
+
+class NamedConstant(Constant):
+    """
+    <named-constant> = <name>
+    """
+
+def compose_patterns(pattern_list, names join=''):
+    return join.join(pattern_list)
+
+def add_pattern(pattern_name, *pat_list):
+    p = ''
+    for pat in pat_list:
+        if isinstance(pat, PatternOptional):
+            p += '(%s|)' % (add_pattern(None, pat.args))
+        elif isinstance(pat, PatternOr):
+            p += '(%s)' % ('|'.join([add_pattern(None, p1) for p1 in par.args]))
+        else:
+            subpat = pattern_map.get(pat,None)
+            if subpat is None:
+                p += pat
+            else:
+                p += '(?P<%s>%s)' % (pat, subpat)
+    if pattern_map is not None:
+        pattern_map[pattern_name] = p
+    return p
+
+
+
+class PatternBase:
+    def __init__(self,*args):
+        self.args = args
+        return
+
+class PatternOptional(PatternBase):
+    pass
+class PatternOr(PatternBase):
+    pass
+class PatternJoin(PatternBase):
+    join = ''
+
+pattern_map = {
+    'name': r'[a-zA-Z]\w+'
+    'digit-string': r'\d+'
+    }
+add_pattern('kind-param',
+            PatternOr('digit-string','name'))
+add_pattern('int-literal-constant',
+            'digit-string',PatternOptional('_','kind-param'))
+
+name_pat = r'[a-z]\w*'
+digit_pat = r'\d'
+digit_string_pat = r'\d+'
+kind_param_pat = '(%s|%s)' % (digit_string_pat, name_pat)
+
+class Name(Designator, NamedConstant, NoChildAllowed):
+    """
+    <name> = <letter> [ <alpha-numeric-character> ]...
+    """
+    match = re.compile(r'\A'+name_pat+r'\Z',re.I).match
+
+class IntLiteralConstant(SignedIntLiteralConstant, NoChildAllowed):
+    """
     <int-literal-constant> = <digit-string> [ _ <kind-param> ]
     <kind-param> = <digit-string>
                  | <scalar-int-constant-name>
     <digit-string> = <digit> [ <digit> ]...
     """
+    match = compose_pattern([digit_string_pat, '_', kind_param_pat],r'\s*')
+
+    compose_pattern('int-literal-constant','digit-string','_','kind-param')
+
+class DigitString(IntLiteralConstant, NoChildAllowed):
+    """
+    <digit-string> = <digit> [ <digit> ]...
+    """
     match = re.compile(r'\A\d+\Z').match
 
-class NamedConstant(Constant, Name):
+################# Setting up Base.subclasses #####################
+
+def set_subclasses(cls):
     """
-    <named-constant> = <name>
+    Append cls to cls base classes attribute lists `_subclasses`
+    so that all classes derived from Base know their subclasses
+    one level down.
     """
-
+    for basecls in cls.__bases__:
+        if issubclass(basecls, Base):
+            if issubclass(basecls, NoChildAllowed):
+                raise NoChildAllowedError,'%s while adding %s' % (basecls.__name__,cls.__name__)
+            try:
+                Base.subclasses[basecls.__name__].append(cls)
+            except KeyError:
+                Base.subclasses[basecls.__name__] = [cls]
+    return
 ClassType = type(Base)
 for clsname in dir():
     cls = eval(clsname)
     if isinstance(cls, ClassType) and issubclass(cls, Base):
         set_subclasses(cls)
 
-class Level1Expression(Primary):
+####################################################################
+
+class Level1Expression:#(Primary):
     """
     <level-1-expr> = [ <defined-unary-op> ] <primary>
     <defined-unary-op> = . <letter> [ <letter> ]... .

Added: trunk/numpy/f2py/lib/parser/pattern_tools.py
===================================================================
--- trunk/numpy/f2py/lib/parser/pattern_tools.py	2006-10-20 06:44:43 UTC (rev 3374)
+++ trunk/numpy/f2py/lib/parser/pattern_tools.py	2006-10-20 12:32:23 UTC (rev 3375)
@@ -0,0 +1,119 @@
+
+import re
+
+class Pattern:
+    """
+    p1 | p2    -> <p1> | <p2>
+    p1 + p2    -> <p1> <p2>
+    p1 & p2    -> <p1><p2>
+    ~p1        -> [ <p1> ]
+    ~~p1       -> [ <p1> ]...
+    ~~~p1      -> <p1> [ <p1> ]...
+    ~~~~p1     -> <p1> [ <p1> ]...
+    abs(p1)    -> whole string match of <p1>
+    p1.named(name) -> match of <p1> has name
+    p1.match(string) -> return string match with <p1>
+    """
+    _special_symbol_map = {'.': '[.]',
+                           '*': '[*]',
+                           '+': '[+]',
+                           '|': '[|]',
+                           '(': r'\(',
+                           ')': r'\)',
+                           }
+
+    def __init__(self, label, pattern, optional=0):
+        self.label = label
+        self.pattern = pattern
+        self.optional = optional
+        return
+
+    def match(self, string):
+        if hasattr(self, '_compiled_match'):
+            return self._compiled.match(string)
+        self._compiled = compiled = re.compile(self.pattern)
+        return compiled.match(string)
+
+    def __abs__(self):
+        return Pattern(self.label, r'\A' + self.pattern+ r'\Z')
+
+    def __repr__(self):
+        return '%s(%r, %r)' % (self.__class__.__name__, self.label, self.pattern)
+
+    def __or__(self, other):
+        label = '( %s OR %s )' % (self.label, other.label)
+        pattern = '(%s|%s)' % (self.pattern, other.pattern)
+        return Pattern(label, pattern)
+
+    def __and__(self, other):
+        if isinstance(other, Pattern):
+            label = '%s%s' % (self.label, other.label)
+            pattern = self.pattern + other.pattern
+        else:
+            assert isinstance(other,str),`other`
+            label = '%s%s' % (self.label, other)
+            pattern = self.pattern + other
+        return Pattern(label, pattern)
+
+    def __rand__(self, other):
+        assert isinstance(other,str),`other`
+        label = '%s%s' % (other, self.label)
+        pattern = other + self.pattern
+        return Pattern(label, pattern)
+
+    def __invert__(self):
+        if self.optional:
+            if self.optional==1:
+                return Pattern(self.label + '...', self.pattern[:-1] + '*', 2)
+            if self.optional==2:
+                return Pattern('%s %s' % (self.label[1:-4].strip(), self.label), self.pattern[:-1] + '+', 3)
+            return self
+        label = '[ %s ]' % (self.label)
+        pattern = '(%s)?' % (self.pattern)
+        return Pattern(label, pattern, 1)
+
+    def __add__(self, other):
+        if isinstance(other, Pattern):
+            label = '%s %s' % (self.label, other.label)
+            pattern = self.pattern + r'\s*' + other.pattern
+        else:
+            assert isinstance(other,str),`other`
+            label = '%s %s' % (self.label, other)
+            other = self._special_symbol_map.get(other, other)
+            pattern = self.pattern + r'\s*' + other
+        return Pattern(label, pattern)
+
+    def __radd__(self, other):
+        assert isinstance(other,str),`other`
+        label = '%s %s' % (other, self.label)
+        other = self._special_symbol_map.get(other, other)
+        pattern = other + r'\s*' + self.pattern
+        return Pattern(label, pattern)
+
+    def named(self, name = None):
+        if name is None:
+            label = self.label
+            assert label[0]+label[-1]=='<>' and ' ' not in label,`label`
+        else:
+            label = '<%s>' % (name)
+        pattern = '(?P%s%s)' % (label.replace('-','_'), self.pattern)
+        return Pattern(label, pattern)
+
+name = Pattern('<name>', r'[a-z]\w*')
+digit_string = Pattern('<digit-string>',r'\d+')
+sign = Pattern('<sign>',r'[+-]')
+exponent_letter = Pattern('<exponent-letter>',r'[ED]')
+
+kind_param = digit_string | name
+signed_digit_string = ~sign + digit_string
+int_literal_constant = digit_string + ~('_' + kind_param)
+signed_int_literal_constant = ~sign + int_literal_constant
+
+exponent = signed_digit_string
+significand = digit_string + '.' + ~digit_string | '.' + digit_string
+real_literal_constant = significand + ~(exponent_letter + exponent) + ~ ('_' + kind_param) | \
+                        digit_string + exponent_letter + exponent + ~ ('_' + kind_param)
+signed_real_literal_constant = ~sign + real_literal_constant
+
+
+print signed_real_literal_constant

Modified: trunk/numpy/f2py/lib/parser/test_expressions.py
===================================================================
--- trunk/numpy/f2py/lib/parser/test_expressions.py	2006-10-20 06:44:43 UTC (rev 3374)
+++ trunk/numpy/f2py/lib/parser/test_expressions.py	2006-10-20 12:32:23 UTC (rev 3375)
@@ -11,7 +11,7 @@
         assert isinstance(a,Name),`a`
         a = Designator('a')
         assert isinstance(a,Name),`a`
-        a = Primary('a')
+        a = Constant('a')
         assert isinstance(a,Name),`a`
         a = Base('a')
         assert isinstance(a,Name),`a`
@@ -29,6 +29,10 @@
         assert isinstance(a,IntLiteralConstant),`a`
         a = Base('1')
         assert isinstance(a,IntLiteralConstant),`a`
+        a = Base('+1')
+        assert isinstance(a,SignedIntLiteralConstant),`a`
+        a = IntLiteralConstant('0')
+        assert isinstance(a,IntLiteralConstant),`a`
         #a = NamedConstant('1') # raise NoMatch error
 
 if __name__ == "__main__":




More information about the Numpy-svn mailing list