Package hm :: Package app :: Package lib :: Module patterns
[hide private]
[frames] | no frames]

Source Code for Module hm.app.lib.patterns

  1   
  2  import re 
  3  from structures import * 
  4   
  5   
  6  ## Regex-generators 
  7  ## - generates alternating lists, e.g. expr,comma,expr,comma,expr 
  8   
  9  #chain_s (simple/short - i.e. don't need pattern, just 'expr', 'comma') 
10 -def chain_s(pattern, separator='none', next='next', rest='rest', 11 allow_dangle=True, allow_blank=True):
12 p = PID(p="%("+pattern+")s", 13 s="%("+separator+")s", 14 dangle='', blank='|', next=next, rest=rest) 15 if allow_dangle: p['dangle'] = r'(?:%(s)s)?' % p 16 if not allow_blank: p['blank'] = '' 17 return r'(?:%(p)s(?:%(s)s(?:%(p)s%(s)s)*%(p)s)?%(dangle)s%(blank)s)' % p
18 19 #After chain_s has verified the format of the chain, efficiently 20 #iterate through it.
21 -def chain_iter(pattern, separator='none'):
22 p = PID(p="%("+pattern+")s", 23 p_n="%("+pattern+"_n)s", 24 s="%("+separator+")s") 25 return r'(?:(?P<next>%(p_n)s)(?:%(s)s)?)' % p
26 27 28 29 BLANK_RE = r'' 30 UNMATCHABLE_RE = r'$^' # r'(?!)' 31 32 33 #PartialInterpolationDict 34 #- if the dict doesn't have the key,
35 -class PartialInterpolationDict(dict):
36 - def __getitem__(self, key):
37 return self.get(key, "%("+str(key)+")s")
38 PID = PartialInterpolationDict 39 40 #FinalInterpolationDict 41 #- returns unmatchable '$^' regex to immediately fail when too deep
42 -class FinalInterpolationDict(dict):
43 - def __getitem__(self, key):
44 if not hasattr(self, 'count_'): 45 self.count_ = 0 46 else: 47 self.count_ += 1 48 #return self.get(key, "(?P<TooDeep"+str(self.count_)+">"+UNMATCHABLE_RE+")") 49 return self.get(key, UNMATCHABLE_RE)
50 Fid = FinalInterpolationDict() 51 52 #ChainMap 53 #- like Context, but simpler
54 -class ChainMap(object):
55 """Combine multiple mappings for sequential lookup. Raymond Hettinger, 56 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305268 """
57 - def __init__(self, *maps):
58 self._maps = maps
59 - def get(self, key, default):
60 try: 61 return self[key] 62 except KeyError: 63 return default
64 - def __getitem__(self, key):
65 for mapping in self._maps: 66 try: 67 return mapping[key] 68 except KeyError: 69 pass 70 raise KeyError(key)
71 - def items(self):
72 ret = {} 73 [ret.update(mapping) for mapping in self._maps] 74 return ret.items()
75 76 77 DEFAULT_DEPTH = 14 78
79 -def init_patterns(patterns):
80 closed = {} 81 open = {} 82 for k,v in patterns.items(): 83 pat = render(k, patterns) 84 if not "%(" in pat: 85 closed[k] = pat 86 else: 87 open[k] = v 88 ret = dict(closed) 89 closed = PartialInterpolationDict(closed) 90 for k,v in open.items(): 91 ret[k] = v % closed 92 return ret
93 94 95 BASE_PATTERNS = { 96 'none' : r'', 97 'space?': r'\s*', 98 'space' : r'\s+', 99 100 #'maybecomma': r'(?:\s*,|,\s*|\s+)', 101 'comma' : r'(?:\s*,\s*)', 102 'equal' : r'(?:\s*=\s*)', 103 'bar' : r'(?:\s*\|\s*)', 104 'colon' : r'(?:\s*:\s*)', 105 106 'string_single':r'\'(?:[^\'\\]*(?:\\.[^\'\\]*)*)\'', 107 'string_double':r'\"(?:[^\"\\]*(?:\\.[^\"\\]*)*)\"', 108 'string' : r'%(string_double)s|%(string_single)s', 109 'float' : r'\d+\.\d*|\.\d+', 110 'int' : r'\d+', 111 112 'simple_literal' : r'(?:%(string)s|%(float)s|%(int)s)', 113 #'simple_literal_p': r'(?:(%(string)s)|(%(float)s)|(%(int)s))', 114 'simple_literal_n' : r'(?:(?P<string>%(string)s)|(?P<float>%(float)s)|(?P<int>%(int)s))', 115 116 #array => [expr, expr, ...] 117 'array_items': chain_s('expr', 'comma'), 118 'array_items_iter':chain_iter('expr', 'comma'), 119 'larray_items': chain_s('literal', 'comma'), 120 'larray_items_iter':chain_iter('literal', 'comma'), 121 'array' : r'\[\s*%(array_items)s\s*\]', 122 'array_n' : r'\[\s*(?P<array_items>%(array_items)s)\s*\]', 123 124 #dict => { key:value, key:value } 125 'dictpair' : r'(?:%(expr)s)%(colon)s(?:%(expr)s)', 126 'dictpair_n': r'(?P<key>%(expr)s)%(colon)s(?P<value>%(expr)s)', 127 'dictpairs' : chain_s('dictpair', 'comma'), 128 'dict_pairs_iter':chain_iter('dictpair', 'comma'), 129 'dict' : r'\{\s*%(dictpairs)s\s*\}', 130 'dict_n' : r'\{\s*(?P<dict_items>%(dictpairs)s)\s*\}', 131 132 #range => (?:expr\:)|(?:\:expr)|(?:expr\:expr)|(?:expr\:expr\:expr) 133 'range' : r':|%(expr)s:|:%(expr)s|%(expr)s:%(expr)s|%(expr)s:%(expr)s:%(expr)s', 134 'range_n' : r'(?P<range_open_both>:)|(?P<range_open_end>%(expr)s):|(?P<range_open_start>:%(expr)s)|(?P<range_full>%(expr)s:%(expr)s)|(?P<range_full_step>%(expr)s:%(expr)s:%(expr)s)', 135 136 'complex_literal': r'(?:%(array)s|%(range)s)',#|%(dict)s)', 137 'complex_literal_n': r'(?:(?P<array>%(array_n)s)|(?P<range>%(range_n)s))',#|(?P<dict>%(dict_n)s))', 138 139 #NOTE: Complex literals (array/dict/range) are commented out, since 140 # since they make the regex get huge. 141 'literal': r'(?:%(simple_literal)s|%(complex_literal)s)', 142 'literal_n': r'(?:%(simple_literal_n)s|%(complex_literal_n)s)', 143 144 #hash_call => [expr, expr, ...] => now with more keys! 145 'hash_call' : r'\[\s*%(array_items)s\s*\]', 146 'hash_call_n' : r'\[\s*(?P<hash_params>%(array_items)s)\s*\]', 147 148 #func_call => (expr, expr, ...) 149 'func_call' : r'\(\s*%(array_items)s\s*\)', 150 'func_call_n' : r'\(\s*(?P<func_params>%(array_items)s)\s*\)', 151 152 'attribute' : r'\.%(identifier)s', 153 'attribute_n' : r'\.(?P<attribute>%(identifier)s)', 154 155 'identifier' : r'[a-zA-Z_][a-zA-Z0-9_]*', 156 157 'chain_base' : r'(?:%(identifier)s)',#|\(\s*%(expr)s\s*\) 158 'chain_base_n': r'(?:(?P<identifier>%(identifier)s))',#|\(\s*(?P<expr>%(expr)s)\s*\) 159 'chain_link' : r'(?:%(hash_call)s|%(attribute)s)',#|%(func_call)s', 160 'chain_link_n': r'(?:%(hash_call_n)s|%(attribute_n)s)',#|%(func_call_n)s)', 161 'chain_links' : chain_s('chain_link'), 162 'chain_links_iter':chain_iter('chain_link'), 163 'method_chain' : r'%(chain_base)s(?:%(chain_links)s)', 164 'method_chain_n': r'(?P<base>%(chain_base_n)s)(?P<items>(?:%(chain_links)s))', 165 166 'expr' : r'(?:%(method_chain)s|%(literal)s)', 167 'expr_n': r'(?:(?P<method_chain>%(method_chain_n)s)|(?P<literal>%(literal_n)s))', 168 169 'whole' : r'^%(expr_n)s$', 170 } 171
172 -def render_raw(regex, patterns=BASE_PATTERNS, depth=DEFAULT_DEPTH):
173 return reduce(lambda p,d: p%d, [patterns for i in xrange(depth)], regex)
174
175 -def render(key, patterns=BASE_PATTERNS, depth=DEFAULT_DEPTH):
176 return render_raw(patterns[key], patterns, depth)
177 #return reduce(lambda p,d: p%d, [patterns for i in xrange(depth)], patterns[key]) 178
179 -def compile_raw(regex, patterns=BASE_PATTERNS, depth=DEFAULT_DEPTH):
180 return re.compile(render_raw(regex, patterns, depth) % Fid)
181
182 -def compile(key, patterns=BASE_PATTERNS, depth=DEFAULT_DEPTH):
183 return re.compile(render(key, patterns, depth) % Fid)
184 185 186 187 """ 188 Returns [args, kwargs] without resolving or modifying text 189 - args is the list of arguments and keys in their original order 190 - kwargs is a dict 191 192 """ 193 194 195 array_items_iter = compile('array_items_iter', BASE_PATTERNS) 196 dict_pairs_iter = compile('dict_pairs_iter', BASE_PATTERNS) 197 chain_links_iter = compile('chain_links_iter', BASE_PATTERNS) 198 whole_re = compile('whole', BASE_PATTERNS) 199 expr_re = compile('expr_n', BASE_PATTERNS)
200 -def parse_expr(s):
201 tree = [] 202 m = whole_re.match(s) 203 print m.groups() 204 if not m: 205 raise StructureSyntaxError("Invalid syntax: %s" % (s,)) 206 d = m.groupdict() 207 if d['literal']: 208 if d['string']: return d['string'][1:-1] 209 elif d['int']: return int(d['int']) 210 elif d['float']: return float(d['float']) 211 elif d['array']: 212 ret = [] 213 for m in array_items_iter.finditer(d['array_items']): 214 ret.append(parse_expr(m.group('next'))) 215 return ret 216 #elif d['dict']: 217 # ret = [] 218 # for m in dict_pairs_iter.finditer(d['dict_items']): 219 # ret.append([parse_expr(m.group('key')), parse_expr(m.group('value'))]) 220 # return ret 221 elif d['range']: 222 #print d['range'] 223 return d['range'] 224 225 else: 226 raise RuntimeError("") 227 elif d['method_chain']: 228 if d['identifier']: 229 base = d['identifier'] 230 else: 231 raise RuntimeError("") 232 ret = [base] 233 for m in chain_links_iter.finditer(d['items']): 234 d = m.groupdict() 235 #if d['func_params'] != None: 236 # args = [] 237 # for m in array_items_iter.finditer(d['func_params']): 238 # args.append(parse_expr(m.group('next'))) 239 # ret.append(args) 240 if d['hash_params'] != None: 241 args = [] 242 for m in array_items_iter.finditer(d['hash_params']): 243 args.append(parse_expr(m.group('next'))) 244 ret.append('__getitem__') 245 ret.append(args) 246 elif d['attribute'] != None: 247 ret.append(d['attribute']) 248 else: 249 raise RuntimeError("") 250 return ret 251 else: 252 raise RuntimeError("")
253