[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