I’ll try this again.
I want to ask for builtins with the signatures
def pureread(f: Callable) -> bool:
return False # TODO
def purewrite(f: Callable) -> bool:
return False # TODO
def purefunc(f: Callable) -> bool:
return pureread(f) && purewrite(f)
Applying to the function
def fib(n: Any) -> Any:
if n < 1:
return n
return fib(n-1) + fib(n-2)
With consideration of the following type
COUNTER = 0
class OpCounter(int):
def __sub__(self, other):
global COUNTER
COUNTER += 1
return OpCounter(int(self) - other)
On the following examples
is_int_pureread = pureread(fib(3))
is_OpCounter_pureread = pureread(fib(Tracker(3)))
print(is_int_pureread)
print(is_OpCounter_pureread)
Would print the following:
True
False
Because of the rationale on the former
Call fib on `n`
pass by value type int 3, `n` tagged as local
read local `n` # READ LOCAL
load constant `1` #READ LOCAL
Call __le__ on `n`, `1`
pass by value type int 3, `self` tagged as local
pass by value type int 1, `other` tagged as local
create temporary, tagged as local
assign temporary to bool OP_LESS_THAN_OR_EQUAL `self` value of 3, `other` value of 1, results in False #READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary # RETURN
temporary assigned to type bool with value from return as False # WRITE LOCAL
OP_JUMP_IF_FALSE temporary, FALSE_ADDRESS # READ LOCAL
FALSE_ADDRESS
read local `n` # READ LOCAL
load constant 1 # READ LOCAL
call __sub__ on `n`, 1
pass by value type int 3, `self` tagged as local
pass by value type int 1, `other` tagged as local
create temporary, tagged as local
assign temporary to int OP_SUBSTRACT `self` value of 3, `other` value of 1, result of 2, # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary # RETURN
temporary assigned to type int with value from return as 2 # WRITE LOCAL
create temporary_fib_2
Call fib on `n` # SAME PATTERN AS TOP LEVEL CALL
pass by value type int 2, `n` tagged as local
...
temporary_fib_2 assigned to type int with value 1 # WRITE LOCAL
read local `n` # READ LOCAL
load constant 1 # READ LOCAL
call __sub__ on `n`, 2
pass by value type int 3, `self` tagged as local
pass by value type int 2, `other` tagged as local
create temporary, tagged as local
assign temporary to int OP_SUBSTRACT `self` value of 3, `other` value of 2, result of 1 # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary
temporary assigned to type int with value from return as 1 # WRITE LOCAL
create temporary_fib_1
Call fib on `n`
pass by value type int 1, `n` tagged as local
read local `n` # READ LOCAL
load constant 1 # READ LOCAL
Call __le__ on `self`, `other`
pass by value type int 1, `self` tagged as local
pass by value type int `, `other` tagged as local
create temporary, tagged as local
assign temporary to bool OP_LESS_THAN_OR_EQUAL `self` value of 1, `other` value of 1, result of True # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary
temporary assigned to type bool with value False # LOCAL WRITE
OP _JUMP_IF_FALSE, temporary, FALSE_ADDRESS # LOCAL READ
read local `n` # LOCAL READ
return `n` # RETURN
temporary_fib_1 assigned to type int with value 1 # WRITE LOCAL
create temporary, tagged as local
call __add__ on `self`, `other`
pass by value type int 1, `self` tagged as local
pass by value type int 1, `other` tagged as local
create temporary, tagged as local
assign temporary to int OP_ADDITION `self value of 1, `other` value of 1, result of 2 # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary
temporary assigned to type int with value 2 # WRITE LOCAL
return temporary
Because of the rationale on the latter
Call fib on `n`
pass by reference type OpCounter 3, `n` tagged as local
read local `n` # READ LOCAL
load constant `1` #READ LOCAL
Call __le__ on `n`, `1`
pass by value type OpCounter 3, `self` tagged as local
pass by value type int 1, `other` tagged as local
create temporary, tagged as local
assign temporary to bool OP_LESS_THAN_OR_EQUAL `self` value of 3, `other` value of 1, results in False # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary # RETURN
temporary assigned to type bool with value from return as False # WRITE LOCAL
OP_JUMP_IF_FALSE temporary, FALSE_ADDRESS # READ LOCAL
FALSE_ADDRESS
read local `n` # READ LOCAL
load constant 1 # READ LOCAL
call __sub__ on `n`, 1
pass by reference type OpCounter 3, `self` tagged as local
pass by value type int 1, `other` tagged as local
reference global CONSTANT
load constant of type int 1
call __iadd__ on `self`, `other`
pass by reference type int, `self` tagged as external
pass by value type int, `other` tagged as local
create temporary
assign `self` to int OP_ADDITION `self` value of 0, `other` value of 1, results in 1 # READ EXTERNAL, READ LOCAL, WRITE EXTERNAL
create temporary, tagged as local
assign temporary to int OP_SUBSTRACT `self` value of 3, `other` value of 1, result of 2, # READ LOCAL, READ LOCAL, WRITE LOCAL
assign temporary to type OpCounter of value 2 # LOCAL WRITE, INTENTIONAL OMISSION OF `OpCounter__init__()`
return temporary # RETURN
temporary assigned to type OpCounter with value from return as 2 # WRITE LOCAL
create temporary_fib_2
Call fib on `n` # SAME PATTERN AS TOP LEVEL CALL
pass by reference type OpCounter 2, `n` tagged as local
...
temporary_fib_2 assigned to type OpCounter with value 1 # WRITE LOCAL
read local `n` # READ LOCAL
load constant 1 # READ LOCAL
call __sub__ on `n`, 2
pass by reference type OpCounter 3, `self` tagged as local
pass by value type int 2, `other` tagged as local
reference global CONSTANT
load constant of type int 1
call __iadd__ on `self`, `other`
pass by reference type int, `self` tagged as external
pass by value type int, `other` tagged as local
create temporary
assign `self` to int OP_ADDITION `self` value of 2, `other` value of 1, results in 3 # READ EXTERNAL, READ LOCAL, WRITE EXTERNAL
create temporary, tagged as local
assign temporary to int OP_SUBSTRACT `self` value of 3, `other` value of 2, result of 1 # READ LOCAL, READ LOCAL, WRITE LOCAL
assign temporary to type OpCounter of value 1 # LOCAL WRITE, INTENTIONAL OMISSION OF `OpCounter__init__()`
return temporary
temporary assigned to type OpCounter with value from return as 1 # WRITE LOCAL
create temporary_fib_1
Call fib on `n`
pass by reference type OpCounter 1, `n` tagged as local
read local `n` # READ LOCAL
load constant 1 # READ LOCAL
Call __le__ on `self`, `other`
pass by value type OpCounter 1, `self` tagged as local
pass by value type int `, `other` tagged as local
create temporary, tagged as local
assign temporary to bool OP_LESS_THAN_OR_EQUAL `self` value of 1, `other` value of 1, result of True # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary
temporary assigned to type bool with value False # LOCAL WRITE
OP _JUMP_IF_FALSE, temporary, FALSE_ADDRESS # LOCAL READ
read local `n` # LOCAL READ
return `n` # RETURN
temporary_fib_1 assigned to type OpCounter with value 1 # WRITE LOCAL
create temporary, tagged as local
call __add__ on `self`, `other`
pass by value type OpCounter 1, `self` tagged as local
pass by value type OpCounter 1, `other` tagged as local
create temporary, tagged as local
assign temporary to int OP_ADDITION `self` value of 1, `other` value of 1, result of 2 # READ LOCAL, READ LOCAL, WRITE LOCAL
return temporary
assign temporary to type OpCounter of value 2 # LOCAL WRITE, INTENTIONAL OMISSION OF `OpCounter__init__()`
temporary assigned to type OpCounter with value 2 # WRITE LOCAL
return temporary
In the former, all statements are able to be verified as local at runtime from the bytecode generated with the passed arguments. In the latter, some are able to be marked as reading and writing to external state. So the former when called in purefunc(fib(3)) would return True while the latter when called in pureread(fib(OpCounter(3))) would return False and purewrite(fib(OpCounter(3))) would return False.
Please tell me this is what you’ve been asking for.