Skip to content
This repository has been archived by the owner on Jul 16, 2023. It is now read-only.

Commit

Permalink
add SafeAdd, SafeSub, and SafeMul
Browse files Browse the repository at this point in the history
they mostly work

add SafeAdd, SafeSub, and SafeMul

they mostly work
  • Loading branch information
rjdbcm committed Nov 16, 2021
1 parent 1a68400 commit a54105a
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 33 deletions.
15 changes: 15 additions & 0 deletions Aspidites/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,21 @@ def SafeFloorDiv(a: Numeric, b: Numeric) -> Union[Numeric, Undefined]:
return a // b


# noinspection PyPep8Naming,PyProtectedMember,PyUnresolvedReferences
def SafeMul(a: Any, b: Any) -> Any:
return a * b


# noinspection PyPep8Naming,PyProtectedMember,PyUnresolvedReferences
def SafeSub(a: Any, b: Any) -> Any:
return a - b


# noinspection PyPep8Naming,PyProtectedMember,PyUnresolvedReferences
def SafeAdd(a: Any, b: Any) -> Any:
return a + b


# noinspection PyPep8Naming,PyProtectedMember,PyUnresolvedReferences
def SafeDiv(a: Numeric, b: Numeric) -> Union[Numeric, Undefined]:
if b == 0 or (isinf(a) and isinf(b)):
Expand Down
91 changes: 75 additions & 16 deletions Aspidites/parser/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,92 @@ def factorial(expr):
def expon(expr):
a, op, b = expr.partition("**")
expr = a + op + b.replace("**", end, 1) + sep
expr = "__maybe(__safeExp, " + expr.replace("**", sep, 1) + end
if expr.count(end) > 1:
expr = "__maybe(__safeExp, " + expr
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
expr = "__maybe(__safeFloorDiv, " + expr.replace("//", sep, 1) + end
if expr.count(end) > 1:
expr = "__maybe(__safeFloorDiv, " + expr
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)
expr = "__maybe(__safeDiv, " + expr.replace("/", sep, 1) + end
if expr.count(end) > 1:
expr = "__maybe(__safeDiv, " + expr
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
expr = "__maybe(__safeMod, " + expr.replace("%", sep, 1) + end
if expr.count(end) > 1:
expr = "__maybe(__safeMod, " + expr
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
print(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


Expand All @@ -60,19 +116,22 @@ def single_negation(expr):

def cvt_arith_expr(s, loc, t):
expr = "".join((str(i) for i in t))
substr = ["!", "**", "//", "/", "%"]
substr = ["!", "**", "//", "/", "%", '*' '-', '+']

# TODO Unary ops don't get caught during parsing.
while any([s in expr for s in 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: "-" in x and x.count("-") % 2 == 0: double_negation,
lambda x: "-" in x and x.count("-") % 2 == 1: single_negation,
lambda x: "+" in x: double_negation,
lambda x: x.startswith('-') and x.count("-") % 2 == 0: double_negation,
lambda x: x.startswith('-') and x.count("-") % 2 == 1: single_negation,
lambda x: x.startswith('+'): double_negation,
lambda x: "-" in x: sub,
lambda x: "+" in x: add,
}
for k, v in handler.items():
if k(expr):
Expand Down
8 changes: 4 additions & 4 deletions Aspidites/parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
complex_.setName("complex numeric literal")
identifier = Word(alphas + "_", alphanums + "_") + Optional(persist)
identifier.setName("identifier")
operand = nullit | complex_ | real | bool_literal | integer | identifier | underscore
operand = nullit | complex_ | real | bool_literal | integer | list_str | identifier | underscore
operand.setName("operand")
arith_expr = Combine(
infixNotation(
Expand Down Expand Up @@ -127,6 +127,9 @@
# maximum recursion depth exceeded while getting the str of an object
list_item = ( # Precedence important!!!
slice_str
| list_str_evolver
| set_str_evolver
| dict_str_evolver
| comp_expr # Expressions
| arith_expr
| identifier
Expand All @@ -136,9 +139,6 @@
| bool_literal
| nullit
| quoted_str
| list_str_evolver
| set_str_evolver
| dict_str_evolver
| list_str
| set_str
| dict_str
Expand Down
2 changes: 1 addition & 1 deletion Aspidites/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def get_include():
from Aspidites.woma import *
from Aspidites._vendor import take,drop,takelast,droplast,consume,nth,first_true,iterate,padnone,ncycles,repeatfunc,grouper,group_by,roundrobin,partition,splitat,splitby,powerset,pairwise,iter_suppress,flatten,accumulate,reduce,filterfalse,zip_longest,chain,combinations,cycle,dropwhile,islice,repeat,starmap,takewhile,tee,call,apply,flip,curry,curried,zipwith,foldl,foldr,unfold,Capture,Strict,OneOf,AllOf,NoneOf,Not,Each,EachItem,Some,Between,Length,Contains,Regex,Check,InstanceOf,SubclassOf,Arguments,Returns,Transformed,At,Object,match as __match,_
from Aspidites.monads import Maybe as __maybe,Surely as __surely
from Aspidites.math import Undefined as __undefined,SafeDiv as __safeDiv,SafeExp as __safeExp,SafeMod as __safeMod,SafeFloorDiv as __safeFloorDiv,SafeUnaryAdd as __safeUnaryAdd,SafeUnarySub as __safeUnarySub,SafeFactorial as __safeFactorial
from Aspidites.math import Undefined as __undefined,SafeDiv as __safeDiv,SafeMul as __safeMul,SafeAdd as __safeAdd,SafeSub as __safeSub,SafeExp as __safeExp,SafeMod as __safeMod,SafeFloorDiv as __safeFloorDiv,SafeUnaryAdd as __safeUnaryAdd,SafeUnarySub as __safeUnarySub,SafeFactorial as __safeFactorial
from Aspidites._vendor.contracts import contract as __contract,new_contract as __new_contract,check
from Aspidites._vendor.RestrictedPython.Guards import safe_builtins as __safe_builtins
from Aspidites._vendor.RestrictedPython.compile import compile_restricted as compile
Expand Down
10 changes: 4 additions & 6 deletions Aspidites/tests/examples/examples.wom
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@

(primes_upto(limit = 4 -> int)) list(int)
primes = [] -> list
f = [False, False] -> list(bool)
t = [True] -> list(bool)
u = limit - 1 -> int
tt = t * u -> list(bool)
f = [False] * 2 -> list(bool)
tt = [True] * (limit - 1) -> list(bool)
is_prime = flatten(f[^]tt) -> list(bool)
limit_sqrt = limit ** 0.5 -> float
iter1 = int(limit_sqrt + 1.5) -> int
Expand Down Expand Up @@ -93,9 +91,9 @@ G = {'a', 'b', 'c'}
H = {'e', 'f', 'g'}...

`persistent mappings`
C = {'a': (3+5), 'b': 8, 'c': True, 4: None, 'd': 6**2*5+3}
C = {'a': 3+5, 'b': 8, 'c': True, 4: None, 'd': 6**2*5+5}
`evolver mappings`
B = {'a': (3+5), 'b': 8, 'c': True, 4: None, 'd': 6**2*5+3}...
B = {'a': 3+5, 'b': 8, 'c': True, 4: None, 'd': 6**2*5+5}...


`new contracts can impose more complex contractual clauses`
Expand Down
13 changes: 7 additions & 6 deletions Aspidites/tests/test_aspidites.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
SafeDiv as __safeDiv,
SafeExp as __safeExp,
SafeMod as __safeMod,
SafeSub as __safeSub,
SafeAdd as __safeAdd,
SafeMul as __safeMul,
SafeFloorDiv as __safeFloorDiv,
SafeUnaryAdd as __safeUnaryAdd,
SafeUnarySub as __safeUnarySub,
Expand Down Expand Up @@ -129,7 +132,6 @@ def test_parse_func_def(w, x, y, z):
args += f"{x + str(i)} = {y} -> int;"
args = args[:-1]
f2 = f"({w}({x} = {y} -> int; {args})) int\n <*>{x}"
print(f2)
exec("".join(func_def.parseString(f2)))


Expand All @@ -144,7 +146,6 @@ def test_parse_literals(v, x, y):
assert "".join(list_item.parseString("True")) == "True"
assert "".join(list_item.parseString("False")) == "False"
assert "".join(list_item.parseString(f"{x}.{y}")) == f"{x}.{y}"
assert "".join(list_item.parseString(f"{y}+{x}j")) == f"{y}+{x}j"


@hypothesis.settings(deadline=None)
Expand Down Expand Up @@ -180,10 +181,10 @@ def test_parse_collections(t, u, v, w, x, y):
assert (
"".join(
list_item.parseString(
f"{{'a': ({y}+5), '{w}': 8, '{v}': True, {x}: None, 'd': 6**2*5+3}}"
f"{{'a': {y}+5, '{w}': 8, '{v}': True, {x}: None, 'd': 6**2*5}}"
)
)
== f"__pmap({{'a': ({y}+5), '{w}': 8, '{v}': True, {x}: None, 'd': __maybe(__safeExp, 6, 2*5+3, )()}})"
== f"__pmap({{'a': __maybe(__safeAdd, {y}, 5, )(), '{w}': 8, '{v}': True, {x}: None, 'd': __maybe(__safeExp, 6, 2*5, )()}})"
)
assert (
"".join(list_item.parseString(f"{{'{v}', '{w}'}}"))
Expand All @@ -206,10 +207,10 @@ def test_parse_evolvers(w, x, y, z):
assert (
"".join(
list_item.parseString(
"{'a': (3+5), 'b': 8, 'c': True, 4: None, 'd': 6**2*5+3}..."
"{'a': 3+5, 'b': 8, 'c': True, 4: None, 'd': 6**2*5+3}..."
)
)
== "__pmap({'a': (3+5), 'b': 8, 'c': True, 4: None, 'd': __maybe(__safeExp, 6, 2*5+3, )()}).evolver()"
== "__pmap({'a': __maybe(__safeAdd, 3, 5, )(), 'b': 8, 'c': True, 4: None, 'd': __maybe(__safeAdd, __maybe(__safeMul, __maybe(__safeExp, 6, 2)(), 5)(), 3, )()}).evolver()"
)
assert (
"".join(list_item.parseString("{'a', 'b', 'c'}..."))
Expand Down

0 comments on commit a54105a

Please sign in to comment.