rjdbcm/Aspidites

View on GitHub
Aspidites/api/convert.py

Summary

Maintainability
A
1 hr
Test Coverage
# cython: language_level=3, annotation_typing=True, c_string_encoding=utf-8, boundscheck=False, wraparound=True, initializedcheck=False
import re

from .reserved import *
from Aspidites._vendor.pyparsing import ParserElement

pmap_re = re.compile(r"(pmap\(\{.*\}\))")
end = lit_rparen + lit_lparen + lit_rparen


def factorial(expr):
    expr = "__maybe(__safeFactorial, " + expr.replace("!", "", 1) + end
    if expr.count(end) > 1:
        expr = "__maybe(__safeFactorial, " + expr
    return expr


def expon(expr):
    a, op, b = expr.partition("**")
    expr = a + op + b.replace("**", end, 1) + sep
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeExp, " + expr.replace("**", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeExp, " + expr.replace("**", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeExp, " + expr
    return expr


def floordiv(expr):
    a, op, b = expr.partition("//")
    expr = a + op + b.replace("//", end, 1) + sep
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeFloorDiv, " + expr.replace("//", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeFloorDiv, " + expr.replace("//", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeFloorDiv, " + expr
    return expr


def div(expr):
    a, op, b = expr.partition("/")
    expr = a + op + b.replace("/", end + sep, 1)
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeDiv, " + expr.replace("/", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeDiv, " + expr.replace("/", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeDiv, " + expr
    return expr


def mod(expr):
    a, op, b = expr.partition("%")
    expr = a + op + b.replace("%", end, 1) + sep
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeMod, " + expr.replace("%", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeMod, " + expr.replace("%", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeMod, " + expr
    return expr


def mult(expr):
    a, op, b = expr.partition("*")
    expr = a + op + b.replace("*", end, 1) + sep
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeMul, " + expr.replace("*", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeMul, " + expr.replace("*", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeMul, " + expr
    return expr


def sub(expr):
    a, op, b = expr.partition("-")
    expr = a + op + b.replace("-", end, 1) + sep
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeSub, " + expr.replace("-", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeSub, " + expr.replace("-", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeSub, " + expr
    return expr


def add(expr):
    a, op, b = expr.partition("+")
    expr = a + op + b.replace("+", end, 1) + sep
    if '__maybe' in expr:  # nesting
        expr = "__maybe(__safeAdd, " + expr.replace("+", end + sep, 1) + end
        expr = ''.join(expr.rsplit(end + sep, 1))
    else:
        expr = "__maybe(__safeAdd, " + expr.replace("+", sep, 1) + end
        if expr.count(end) > 1:
            expr = "__maybe(__safeAdd, " + expr
    return expr


def double_negation(expr):
    return "__maybe(__safeUnaryAdd, " + expr.replace("+", "") + end


def single_negation(expr):
    return "__maybe(__safeUnarySub, " + expr.replace("-", "") + end


def cvt_arith_expr(s, loc, t):
    expr = "".join((str(i) for i in t))
    substr = ["!", "**", "//", "/", "%", '*' '-', '+']
    handler = {
        lambda x: "!" in x: factorial,
        lambda x: "**" in x: expon,
        lambda x: "*" in x: mult,
        lambda x: "//" in x: floordiv,
        lambda x: "/" in x: div,
        lambda x: "%" in x: mod,
        lambda x: x.startswith('-'): single_negation,
        lambda x: x.startswith('+'): double_negation,
        lambda x: "-" in x: sub,
        lambda x: "+" in x: add,
    }
    while any([s in expr for s in substr]):
        for k, v in handler.items():
            if k(expr):
                expr = v(expr)
    else:
        for k, v in handler.items():
            if k(expr):
                expr = v(expr)
    return expr


def cvt_pragma(s, loc, t):
    t: list = t.asList()
    return "\n".join(t) + "\n"


def cvt_int(s, loc, t):
    return int(t[0])


def cvt_real(s, loc, t):
    return float(t[0])


def cvt_tuple(s, loc, t):
    return "(" + ", ".join(t.asList()) + ")"


def cvt_comment_line(s, loc, t):
    return "# comment_line %s:" % (len([c for c in s[:loc] if c == "\n"]) + 1) + t[0]


def cvt_for_loop_decl(s, loc, t):
    t = t[0]
    if len(t) == 5:
        r = pmap_re.match(t[4])
        if r:
            m = r.group(1) + ".items()"
        else:
            m = t[4]
        s = str(t[3] + "".join(t[:3]) + " in __maybe(__safeLoop, " + m + end + lit_colon).encode("UTF-8")
    else:
        s = str(t[1] + t[0] + " in __maybe(__safeLoop, " + t[2] + end + lit_colon).encode("UTF-8")
    return s.decode("UTF-8")


def cvt_dict(s, loc, t):
    t: list = t.asList()
    s: bytes
    for i, v in enumerate(t):
        key, val = v
        if isinstance(key, str):  # string keys only
            t[i] = f"{key}: {val}"
        else:  # integer key
            t[i] = f"{key}: {val}"
    s = f'{", ".join(t)}'.encode("UTF-8")
    return f"__pmap({{{s.decode('UTF-8')}}})"


def cvt_list(s, loc, t):
    t: list = t.asList()
    s: bytes
    for i, v in enumerate(t):
        if isinstance(v, str):  # string keys only
            t[i] = v
        else:  # integer key
            t[i] = int(v)
    s = f'{", ".join(t)}'.encode("UTF-8")
    return f"__pvector([{s.decode('UTF-8')}])"


def cvt_list_index(s, loc, t):
    t = t.asList()
    arg = ''.join(t[2:])
    fn = ''.join(t[:2])
    return f"__maybe({fn}, {arg})()"


def cvt_set(s, loc, t):
    t: list = t.asList()
    s: bytes
    for i, v in enumerate(t):
        if isinstance(v, str):  # string keys only
            t[i] = v
        else:  # integer key
            t[i] = int(v)
    s = f'{", ".join(t)}'.encode("UTF-8")
    return f"__pset({{{s.decode('UTF-8')}}})"


def cvt_contract_assign(s, loc, t):
    t: list = t.asList()
    s: str
    i: str
    t = swap_val_to_idx(t, ":", 1)
    t[2], t[4] = t[4], t[2]
    s = " ".join((str(i) for i in t))
    return s


def cvt_contract_define(s, loc, t):
    t[0], t[1] = t[1], t[0]
    t[1] = "'" + t[1] + "'"
    args = f"({', '.join(t[1:])})"
    t = t[0] + args
    return "".join(t)


def swap_val_to_idx(lst: list, val, idx: int) -> list:
    val_idx = lst.index(val)
    if val_idx == idx:
        pass  # maybe error?
    lst[val_idx], lst[idx] = lst[idx], lst[val_idx]
    return lst


def cvt_clos_call(s, loc, t):
    return "__maybe" + t[0][1] + t[0][0] + sep + sep.join(t[0][2:-1]) + t[0][-1]


def cvt_func_call(s, loc, t):
    return (
        "__maybe"
        + t[0][1]
        + t[0][0]
        + sep
        + sep.join(t[0][2:-1])
        + t[0][-1]
        + lit_lparen
        + lit_rparen
    )