def create(s): e = E() e.t = 'string' e.v = s f = E() f.t = 'const' f.v = '?' return E.func('`apply', [f, e])
def _gc(el, repls): if type(el) in [list, tuple]: if len(el) == 0: return (False, el) res = [_gc(e, repls) for e in el] if not max(e[0] for e in res): return (False, el) res = [e[1] for e in res] if type(el) == tuple: res = tuple(res) return (True, res) if not isinstance(el, E): return (False, el) if el.t != 'f': return (False, el) if len(el.args) == 0: return (False, el) if el.v == '`apply': for e in repls: if e[2][0] == el[0]: e[0] = True print('Use =>', el) return (False, el) if el.v == ';': # [use? gced? repl] isChange = False subrepls = [[False, False, e] for e in el[:-1]] (c, resE) = _gc(el[-1], repls + subrepls) if c: isChange = True isDo = True while isDo: isDo = False for i in range(len(subrepls) - 1, -1, -1): if not subrepls[i][0] or subrepls[i][1]: continue isDo = True (c, res) = _gc(subrepls[i][2][2], repls + subrepls[:i]) if c: subrepls[i][2] = E.func( '`repl', subrepls[i][2][:2] + [res] + subrepls[i][2][3:]) isChange = True subrepls[i][1] = True nsubrepls = [e[2] for e in subrepls if e[0]] if len(nsubrepls) != len(subrepls): isChange = True if not isChange: return (False, el) return (True, E.func(';', nsubrepls + [resE])) args = [_gc(e, repls) for e in el.args] if el.v == '`pipely' and args[0][1].isFunc('`apply'): return (True, E.func('`apply', [args[0][1][0]] + [e[1] for e in args[1:]])) if not max(e[0] for e in args): return (False, el) return (True, E.func(el.v, [e[1] for e in args]))
def bind(el, faker=None): if faker is None: faker = E.Fake() repls = [] r = Unclosure._bind(el, [], repls, faker) if len(repls) > 0: return E.func(';', repls + [r]) else: return r
def _res2E(res): if type(res) in [int, float]: el = E() el.t = 'number' el.v = str(res) return el if type(res) in [str]: el = E() el.t = 'string' el.v = res return el if type(res) == E: if res.isFunc('≺'): return res return E.func('≺', [res]) return None
def inject(dst, data): if R.iff(dst): if dst[1].v not in data: raise Exception('No template <%s> in dst' % dst[1].v) return data[dst[1].v] if (type(dst) != E or dst.t != 'f'): return dst return E.func(dst.v, [inject(e, data) for e in dst.args])
def _gorun(el, repls): s = E.func(';', repls + [el]) s = Unclosure.bind(s) MACRO.clear() s = cody(s, 'py', 'generators/py.py') s = execute(s) s = s() s = _res2E(s) return s
def vl(lvars, lstat): lv = lvars[-len(v.args):] lf = [ walk_t_apply(E.func('`apply', [f] + lv), lvars, lstat).copy() for f in v.dict ] for i in range(len(lf)): lf[i].n = el[2][i] return walk_exc(el[3], lvars + lf, lstat)
def apply(eqn, src, dst, isRec=True): if isinstance(dst, type(lambda: 0)): dstf = dst elif isinstance(dst, E): def dstf(data): return inject(dst, data) else: raise Exception('dst must be tree or function') eqn = _apply(eqn, src, dstf, isRec) return E.squeeze(eqn)
def _apply(eqn, src, dst, isRec): data = {} r = eject(eqn, src, data) if r: if isRec: for k in data: data[k] = _apply(data[k], src, dst, isRec) d = dst(data) if d is None: if not isRec: return eqn else: return d if (type(eqn) != E or eqn.t != 'f'): return eqn return E.func(eqn.v, [_apply(e, src, dst, isRec) for e in eqn.args])
def _insert_full(el, repls, uncert): (isChange, nel) = _insert(el, uncert) if isChange: return nel ri = None for i in range(len(repls)): ii = len(repls) - i - 1 if repls[ii][2] is None: continue (isChange, nel) = _insert(repls[ii], uncert) if not isChange: continue if ri is not None: raise Exception('Multi nodes find by uncert') ri = ii break if ri is None: raise Exception('Cannot find uncert node') return E.func(';', [nel] + repls[ri + 1:] + [el])
def _insert(el, uncert): if type(el) in [list, tuple]: if len(el) == 0: return (False, el) res = [_insert(e, uncert) for e in el] if not max(e[0] for e in res): return (False, el) res = [e[1] for e in res] if type(el) == tuple: res = tuple(res) return (True, res) if not isinstance(el, E): return (False, el) if el.t != 'f': return (False, el) if el.v == '≻' and el[0] == uncert.obj[0]: return (True, uncert.args[0]) if len(el.args) == 0: return (False, el) args = [_insert(e, uncert) for e in el.args] if not max(e[0] for e in args): return (False, el) nel = E.func(el.v, [e[1] for e in args]) return (True, nel)
def findnext(lvars, lstat, d): i = 0 lv = v.dictm[1 if d else 0] while True: if v.dictf is None: fv = lv else: fv = walk_t_apply(E.func('`apply', [v.dictf, lv]), lvars, lstat) # TODO handle None? fv = fv.copy() fv.n = el[2] rv = walk_exc(el[3], lvars + [fv], lstat) rv = match_cast(AE.gettype('bool'), rv, el)[1] lv.value += 1 if d else -1 if rv.value: v.dict[v.dictm[3 if d else 2]] = fv v.dictm[3 if d else 2] += 1 if d else -1 return i += 1 if i > OVERITER: raise AError( 'Over %d iterations for %s duration' % (OVERITER, 'right' if d else 'left'), el)
def _walk(el, repls): if type(el) in [list, tuple]: if len(el) == 0: return (NOCONST, el) res = [] for e in el: (c, e) = _walk(e, repls) if c == CONST: (c, e) = _run((c, e), repls) assert c == CONST res.append(e) if type(el) == tuple: res = tuple(res) return (NOCONST, res) if not isinstance(el, E): return (NOCONST, el) if _isConst(el): return (CONST, el) if el.t != 'f': return (NOCONST, el) if el.v == '`apply': if len(el.args) > 1: return _walk( E.func('`pipely', [E.func('`apply', el[:1])] + el[1:]), repls) res = _find_repl(el[0], repls) if res is None: return (DIFFCONST, el) if res[0] == CONST and len(res[1][1]) == 0: return (CONST, res[1][2]) return (res[0], el) if el.v == 'msub': return _walk(E.func('`apply', [el]), repls) if el.v == '`repl': subrepls = repls + [(DIFFCONST, E.func('`repl', [e, [], None])) for e in el[1]] (resC, resE) = _walk(el[2], subrepls) if resC == CONST: (resC, resE) = _run((CONST, resE), subrepls) return (resC, E.func('`repl', el[:2] + [resE] + el[3:])) if el.v == ';': subrepls = repls[:] for e in el[:-1]: subrepls.append(_walk(e, subrepls)) res = _walk(el[-1], subrepls) return (res[0], E.func(';', [e[1] for e in subrepls[len(repls):]] + [res[1]])) res = [_walk(e, repls) for e in el.args] resE = E.func(el.v, []) if el.v == '`pipely': resF = res[0] res = res[1:] resE.args.append(resF[1]) resC = min(e[0] for e in res) for (c, e) in res: if c == resC: resE.args.append(e) continue if c == CONST: (c, e) = _run((CONST, e), repls) assert c == CONST resE.args.append(e) continue resE.args.append(e) if el.v == '`pipely': # t2(t1), t3 is type of t2 t1 = resC t2 = resF[0] ARG_t2 = 0 REPL_t2 = 1 TREE_t2 = 2 t3 = TREE_t2 if resF[1].isFunc('`apply'): replF = _find_repl(resF[1][0], repls) if replF is None: t3 = REPL_t2 elif replF[1][2] is None: t3 = ARG_t2 else: t3 = REPL_t2 if t2 == DIFFCONST: if t3 == REPL_t2: if t1 == CONST: return _run((DIFFCONST, resE), repls) if t1 == NOCONST: return (NOCONST, resE) return (DIFFCONST, resE) if t3 == ARG_t2: raise Exception('Inpossible') if t2 == CONST and t3 == REPL_t2: return (CONST, replF[1][2]) if t1 == CONST: return _run((t2, resE), repls) return (t1, resE) return (resC, resE)
def cody(e, t, f, n=None): cache = {} def load(t, p): p = path.sep.join(p) if p in cache: return cache[p] if t == 'py': g = loadPy(p) elif t == 'gn': g = loadGn(p) else: raise PbTranslatorError('Unknown gen type <%s>' % t) cache[p] = g return g def loadPy(p): s = util.spec_from_file_location("some_case", p) if s is None: raise PbTranslatorError('Wrong gen file <%s>' % p) m = util.module_from_spec(s) try: s.loader.exec_module(m) except Exception: raise PbTranslatorError('Exception while load gen file <%s>' % p) if 'case' not in m.__dict__: raise PbTranslatorError( 'Gen file do not contains function `case(el, cody, gen)` <%s>' % p ) return m.case def loadGn(p): if not path.isfile(p): raise PbTranslatorError('No gen file <%s>' % p) try: with open(p, 'r', encoding='utf8') as f: s = f.readlines() except Exception: raise PbTranslatorError( 'Cannot read gen file <%s> (utf8 required)' % p ) i = -1 parts = [] while True: i += 1 if i == len(s): break if s[i][0:3] == '# \\': continue if s[i][0:5] == '# > \\' or s[i][0:5] == '# < \\': cd = [] for j in s[i+1:]: if j[0:3] == '# \\': break cd.append(j[:-1]) parts.append((s[i][2], i, '\n'.join(cd))) i += len(cd) + 1 if s[i][0:3] == '# >' or s[i][0:3] == '# <': parts.append((s[i][2], i, s[i][3:-1])) cd = [] for i in range(0, len(parts), 2): (si, ni, cdi) = parts[i] if len(parts) == i+1: raise PbTranslatorError( 'Unexpected end of gen file <%s>' % p ) (so, no, cdo) = parts[i+1] if si != '>': raise PbTranslatorError( 'Part on <%s:%d> must be contidion' % (p, ni + 1) ) if so != '<': raise PbTranslatorError( 'Part on <%s:%d> must be template' % (p, no + 1) ) cdo = cdo.strip().replace('\\', '\\\\').split('#%') for j in range(1, len(cdo), 2): if j == len(cdo) - 1: raise PbTranslatorError( 'Template on <%s:%d> has unclosed inserts' % (p, no + 1) ) cdo[j] = '""" + (%s) + """' % cdo[j] cd += [ 'if (%s):' % cdi, '\treturn """%s"""' % ''.join(cdo) ] cd = 'def case(e, r, g):\n%s\n' % '\n'.join('\t' + s for s in cd) return loadPyCode(p, cd) class PbGen(PbError): def __init__(self, r): self.r = r def loadPyCode(p, cd): m = {} try: exec(cd, m) except Exception: try: raise PbTranslatorError('Error in compiled template <%s>' % p) except Exception: raise PbCodeHelper(cd) def wrap(e, r, g): try: return m['case'](e, r, g) except PbError as e: raise e except Exception: raise PbCodeHelper(cd) return wrap def gen(ps, e, t, f): ps = ps + f.split('/')[:-1] f = f.split('/')[-1] m = load(t, ps + [f]) try: r = m(e, rec, lambda t, f: gen(ps, e, t, f)) except PbError as e: raise e except Exception: raise PbTranslatorError( 'Error while apply gen file <%s>' % '/'.join(ps + [f]) ) if r is not None: raise PbGen(r) def wrap(e, r, g): if type(e) != E: raise PbTranslatorError('Tree error: unknown %s' % str(e)) g(t, f) raise PbTranslatorError('Tree error: unmathed %s' % str(e)) def rec(e): try: r = wrap(e, rec, lambda t, f: gen([], e, t, f)) except PbGen as e: return e.r return r if n is None: n = '_main' e = E.func('`codywrap', [e, n]) return rec(e)
def _bind(el, vars, repls, faker): if type(el) == list: return [Unclosure._bind(e, vars, repls, faker) for e in el] if type(el) != E or el.t != 'f': return el if el.v == '≺': return el if el.v == '`repl': subvars = el[1] r = Unclosure._bind(el[2], subvars, repls, faker) repl = E.func('`repl', [el[0], subvars, r] + el[3:]) return repl if el.v == ';': args = el.args[:] i = -1 while True: i += 1 if i == len(args): break subrepls = [] r = Unclosure._bind(args[i], vars, subrepls, faker) args = args[:i] + subrepls + [r] + args[i+1:] i += len(subrepls) repl = E.func('`repl', [ faker.fake(), vars, E.func(';', args) ]) repls.append(repl) apply = E.func('`apply', [repl[0]] + [ E.func('`apply', [var]) for var in vars ]) return apply if el.v == '`pipely': n = faker.fake() return Unclosure._bind( E.func(';', [ E.func('`repl', [ n, [], el[0] ]), E.func('`apply', [ n ] + el[1:]) ]), vars, repls, faker ) if el.v in ['`series', '`matrix', '`inject']: nf = faker.fake() ns = faker.fake() subvars = vars[:] if el.v == '`series': if isinstance(el[2], E): subvars += [el[2]] elif type(el[2]) in [list, tuple]: subvars += el[2] else: raise Exception('Wrong series vars ' + str(el)) repl = E.func('`repl', [ nf, vars, E.func(';', [ E.func('`repl', [ ns, [], E.func(el.v, [ Unclosure._bind(e, subvars, repls, faker) for e in el.args ]) ]), E.func('`apply', [ns]) ]) ]) repls.append(repl) apply = E.func('`apply', [nf] + [ E.func('`apply', [var]) for var in vars ]) return apply return E.func(el.v, [ Unclosure._bind(e, vars, repls, faker) for e in el.args ])
def iff(e): return (E.isFunc(e, '`apply') and e[0].t == 'const' and e[0].v == '?' and e[1].t == 'string')