def lst(k, l, p): """ Matches 0 or more repetitions of p, extracting values of l and assigning them to the list k >>> t = seq(html('<body>'), seq(lst('names', 'name', seq(html('<h2>'), seq(safe('name'), html('</h2>')))), html('</body>'))) >>> [(m, v, y) for m, v, y in t({}, '<body><h2>Ori</h2></body>') if m] [(True, {'names': ['Ori']}, '')] >>> [(m, v, y) for m, v, y in t({}, '<body><h2>Ori</h2><h2>Dori</h2></body>') if m] [(True, {'names': ['Ori', 'Dori']}, ''), (True, {'names': ['Ori</h2><h2>Dori']}, '')] >>> t = seq(html('<body>'), seq(lst('character.names', 'name', seq(html('<h2>'), seq(esc('name'), html('</h2>')))), html('</body>'))) >>> [(m, v, y) for m, v, y in t({}, '<body><h2>Ori</h2></body>') if m] [(True, {'character': {'names': ['Ori']}}, '')] >>> t = lst('names', 'name', seq(lit('<'), seq(esc('tag'), seq(lit('>'), seq(esc('name'), seq(lit('</'), seq(esc('tag'), lit('>')))))))) >>> [(m, v, y) for m, v, y in t({}, '<h2>Ori</h2><h2>Dori</h2>') if m and y == ''] [(True, {'names': ['Ori', 'Dori'], 'tag': 'h2'}, '')] >>> [(m, v, y) for m, v, y in t({}, '<h1>Ori</h1><h2>Dori</h2>') if m] [(True, {'names': ['Ori'], 'tag': 'h1'}, '<h2>Dori</h2>'), (True, {'names': []}, '<h1>Ori</h1><h2>Dori</h2>')] """ def q(c, x): for m, d, y in p(c, x): if m: v = sat.get(l, d) e = sat.rem(l, sat.upd(k, lambda w: w + [v], d)) yield True, e, y else: yield m, d, y def f(): return alt(seq(q, ref(f)), eps()) return let(lambda: [sat.ctx(k, [])], ref(f))
def p(c, x): v = '' y = x while len(y) > 0 and y[0] not in r: d = sat.ctx(k, f(v)) if sat.cmp(c, d): yield True, sat.cmb(c, d), y # note: not yielding a failure here, because it would be either: # - unnecessary because of a match at the end # - identical to the failure yielded at the end v = v + y[0] y = y[1:] d = sat.ctx(k, f(v)) if sat.cmp(c, d): yield True, sat.cmb(c, d), y else: yield False, sat.get(k, c), x
def var(k): """ Match a value into a variable k >>> e = var('foo') >>> e('bar') [{'foo': 'bar'}] """ return lambda x: [sat.ctx(k, x)]
def _calc_lookup_key(self, target_expression, key_expression): if target_expression.data == 'target_object' and key_expression.data == 'target_object': pairs = { str(target_pair.children[0]): (target_pair.children[1] if target_pair.data == 'target_full_pair' else Tree( 'target_variable', target_pair.children)) for target_pair in target_expression.children if target_pair.data in ('target_shorthand_pair', 'target_full_pair') } rest = next((child.children[0] for child in target_expression.children if child.data == 'target_rest_expression'), None) lookup_key = {} for child in key_expression.children: if child.data == 'target_shorthand_pair': key = str(child.children[0]) if key not in pairs: return None elif pairs[key].data != 'target_constant': return None else: lookup_key = sat.cmb( lookup_key, sat.ctx(key, json.loads(pairs[key].children[0]))) elif child.data == 'target_full_pair': key = str(child.children[0]) if key not in pairs: return None else: lookup_key = sat.cmb( lookup_key, self._calc_lookup_key(pairs[key], child.children[1])) elif child.data == 'target_rest_expression': if rest is None: return None return lookup_key elif target_expression.data == 'target_constant' and key_expression.data == 'target_variable': return sat.ctx(str(key_expression.children[0]), json.loads(target_expression.children[0])) else: return None
def als(e, k): """ Destructure a value using expression e, assigning te original value to alias k >>> e = als(lit('foo'), 'foo') >>> e('bar') [] >>> e('foo') [{'foo': 'foo'}] """ return lambda x: [ sat.cmb(c, d) for c in e(x) for d in [sat.ctx(k, x)] if sat.cmp(c, d) ]
def key(i): """ Match a value into key i >>> e = key(0) >>> e('bar') # doctest: +ELLIPSIS [{'$keys': <function ...>}] >>> sat.cmp(e('bar')[0], {'$keys': ['bar', 'baz']}) True >>> sat.cmp(e('bar')[0], {'$keys': ['baz', 'bar']}) False """ return lambda x: [ sat.ctx('$keys', lambda y: isinstance(y, list) and len(y) > i and y[i] == x) ]