tracing + smarter memoization + better __str__

This commit is contained in:
AF 2021-09-06 14:20:24 +03:00
parent 874fb84957
commit 1f1700e9a8
20 changed files with 173 additions and 40 deletions

View File

@ -23,6 +23,9 @@ class AfterValue(Evaluable):
self.evaluable = self.evaluable.next()
return self
def __str__(self):
return f'{self.evaluable}->{self.target}'
class AVChain(AVTarget):
def __init__(self, target: AVTarget, aftertarget: AVTarget):
@ -31,3 +34,6 @@ class AVChain(AVTarget):
def given(self, value: EValue) -> Evaluable:
return AfterValue(self.target.given(value), self.aftertarget)
def __str__(self):
return f'{self.target}->{self.aftertarget}'

View File

@ -2,13 +2,13 @@
from typing import Mapping
from bu4.evaluation.av.aftervalue import AfterValue
__all__ = ('envtype',)
from bu4.evaluation.constructs.evaluable import Evaluable
try:
from typing import TypeAlias
except ImportError:
TypeAlias = type
envtype: TypeAlias = Mapping[bytes, AfterValue]
envtype: TypeAlias = Mapping[bytes, Evaluable]

View File

@ -2,7 +2,6 @@
from typing import Mapping, Iterator
from bu4.evaluation.av.aftervalue import AfterValue
from bu4.evaluation.av.envtype import envtype
from bu4.evaluation.constructs.evaluable import Evaluable
from bu4.evaluation.targets.avcontainer import AVContainer
@ -10,8 +9,8 @@ from bu4.evaluation.targets.avcontainer import AVContainer
__all__ = ('LambdaEnv',)
class LambdaEnv(Mapping):
def __getitem__(self, k: bytes) -> AfterValue:
class LambdaEnv(Mapping[bytes, Evaluable]):
def __getitem__(self, k: bytes) -> Evaluable:
if k == self.name:
return self.container
else:
@ -20,11 +19,18 @@ class LambdaEnv(Mapping):
def __len__(self) -> int:
return len(self.env) + 1
def __iter__(self) -> Iterator[AfterValue]:
def __iter__(self) -> Iterator[Evaluable]:
yield self.name
yield from self.env
def __init__(self, env: envtype, name: bytes, evaluable: Evaluable):
def __init__(self, env: envtype, name: bytes, evaluable: Evaluable, *, memoize):
self.env = env
self.name = name
self.container = AVContainer(evaluable).after_value
self.container = AVContainer(evaluable, name).after_value if memoize else evaluable
@staticmethod
def strfy(self):
return ''.join(f'\x7b{evaluable}|{name.decode()}\x7d' for name, evaluable in self.items())
def __str__(self):
return self.strfy(self)

View File

@ -15,10 +15,12 @@ class ELambda(EValue):
self.env = env
self.name = name
self.value = value
self.used = name in value.future
self.memoize = name in value.multifuture
def call(self, argument: Evaluable) -> Evaluable:
return ELinked(
LambdaEnv(self.env, self.name, argument),
LambdaEnv(self.env, self.name, argument, memoize=self.memoize) if self.used else self.env,
self.value
)

View File

@ -41,6 +41,9 @@ class AntiProxy:
def __call__(self, value):
return antiproxy(sync(self.evaluable.call(eproxy(value))))
def __str__(self):
return str(self.evaluable)
def eproxy(value: Any) -> Evaluable:
if isinstance(value, Evaluable):

View File

@ -17,3 +17,6 @@ class AVCall(AVTarget):
def given(self, value: EValue) -> Evaluable:
return value.call(ELinked(self.env, self.argument))
def __str__(self):
return f'({self.argument})'

View File

@ -9,9 +9,13 @@ __all__ = ('AVContainer',)
class AVContainer(AVTarget):
def __init__(self, evaluable: Evaluable):
def __init__(self, evaluable: Evaluable, name: bytes):
self.after_value = AfterValue(evaluable, self)
self.name = name
def given(self, value: EValue) -> Evaluable:
self.after_value.evaluable = value
return value
def __str__(self):
return f'[{self.name.decode()}]'

View File

@ -18,6 +18,11 @@ class LCall(Linked):
self.argument = argument
self.lambda_ = lambda_
self.future = self.argument.future | self.lambda_.future
self.multifuture = (
self.argument.multifuture |
self.lambda_.multifuture |
(self.argument.future & self.lambda_.future)
)
def evaluable(self, env: envtype) -> Evaluable:
return AfterValue(ELinked(env, self.lambda_), AVCall(env, self.argument))

View File

@ -12,6 +12,7 @@ class LException(Linked):
def __init__(self, name: bytes):
self.name = name
self.future = set()
self.multifuture = set()
def evaluable(self, env: envtype) -> Evaluable:
return EException(self.name)

View File

@ -8,6 +8,7 @@ __all__ = ('Linked',)
class Linked:
future: set[bytes]
multifuture: set[bytes]
def evaluable(self, env: envtype) -> Evaluable:
raise NotImplementedError

View File

@ -14,11 +14,13 @@ class LLambda(Linked):
def __init__(self, name: bytes, value: Linked):
self.name = name
self.value = value
self.future = self.value.future - {self.name}
self.future = self.value.future - {name}
self.multifuture = self.future
self.used = name in value.future
def evaluable(self, env: envtype) -> Evaluable:
return ELambda(
{name: env[name] for name in self.future},
{name: env[name] for name in self.future} if self.used else env,
self.name,
self.value
)

View File

@ -11,6 +11,7 @@ class LName(Linked):
def __init__(self, name: bytes):
self.name = name
self.future = {name}
self.multifuture = set()
def evaluable(self, env: envtype) -> Evaluable:
return env[self.name]

View File

@ -11,6 +11,7 @@ __all__ = ('LNull',)
class LNull(Linked):
def __init__(self):
self.future = set()
self.multifuture = set()
def evaluable(self, env: envtype) -> Evaluable:
return ENull()

49
bu4/tracing/probe.py Normal file
View File

@ -0,0 +1,49 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
from bu4.evaluation.constructs.elambda import ELambda
from bu4.evaluation.constructs.evaluable import Evaluable
from bu4.evaluation.constructs.evalue import EValue
from bu4.evaluation.sync import sync
class Probe(EValue):
def call(self, argument: Evaluable) -> Evaluable:
return ProbeB(self, argument)
def start_and_list(self):
probe = self
list_ = []
while isinstance(probe, ProbeB):
list_.append(probe.argument)
probe = probe.prev
assert isinstance(probe, ProbeA)
return probe.start, reversed(list_)
def __str__(self):
start, list_ = self.start_and_list()
return f'probe {start} [ {" ; ".join(map(str, list_))} ]'
class ProbeA(Probe):
def __init__(self, start):
self.start = start
class ProbeB(Probe):
def __init__(self, prev: Probe, argument):
self.prev = prev
self.argument = argument
_probe_index = 0
def trace(lambda_: EValue):
global _probe_index
size = 0
while True:
if not isinstance(lambda_, ELambda):
return size, lambda_
lambda_ = sync(lambda_.call(ProbeA(_probe_index)))
_probe_index += 1
size += 1

27
docs/extensions.md Normal file
View File

@ -0,0 +1,27 @@
Application (essential):
* Call
Abstraction:
* Lambda
* Name
Common:
* Null (=exception/undefined)
* Quot
* Qopn-Qcls
* Skip
Special:
* Namespaces (evaluable imports)
* String literals (exceptions)
* Static literals (constants and platform values)
* Trace/probes
* Classes (named lambda constructs)
* Methods (static types, optionally explicit)
* Factories (static types, optionally explicit)
* Await/after constructs with callbacks (and mutability/io monads)
* Speculative execution (asynchronousity and multithreading)
* Index-based linking (more static)
* Hashes (v13 extension)
* Typing decorators (v13 extension)
* Evaluable to parsed conversion (compilation inversion)

28
main.py
View File

@ -1,12 +1,13 @@
# Copyright (c) PARRRATE T&V 2021. All rights reserved.
import random
from collections import deque
from bu4.common_interface import with_common_interface
from bu4.evaluation.constructs.proxy import antiproxy, eproxy
from bu4.evaluation.sync import sync
from bu4.parsing.toolchain.readfile import readfile
from bu4.synced import synced
from bu4.tracing.probe import trace, Probe
from timesample import TimeSample
with TimeSample('all'):
@ -64,3 +65,28 @@ with TimeSample('all'):
TimeSample.print(sys1)
with TimeSample('sys4'):
TimeSample.print(with_common_interface(synced(readfile('src/sys4'))))
with TimeSample('sys5'):
sys5 = synced(readfile('src/sys5'))
queue = deque([(0, 0, sys5)])
for trace_index in range(1, 100 + 1):
if not queue:
break
tab, parent, evaluable = queue.popleft()
for _ in range(10000):
evaluable = evaluable.next()
_probe_index, probe = trace(evaluable)
prefix = ('.', ' ' * tab, parent, trace_index)
if isinstance(probe, Probe):
start, list_ = probe.start_and_list()
TimeSample.print(*prefix, _probe_index, probe)
queue.extend((tab + 1, trace_index, deeper_evaluable) for deeper_evaluable in list_)
else:
TimeSample.print(*prefix, '...')
with TimeSample('sys6'):
sys6 = synced(readfile('src/sys6')).call(synced('?'))
for _ in range(100):
sys6 = sys6.next()
print(sys6)
for _ in range(10000000):
sys6 = sys6.next()

View File

@ -1,26 +0,0 @@
Application (essential):
* Call
Abstraction:
* Lambda
* Name
Common:
* Null (=exception/undefined)
* Quot
* Qopn-Qcls
* Skip
Special:
* Namespaces (E- inputs)
* String literals (=exceptions)
* Trace/probes
* Classes (named lambda constructs)
* Methods (statically typed, optionally explicitly)
* Factories (statically typed, optionally explicitly)
* Await/after constructs with callbacks (and mutability/io quasimonads)
* Speculative execution (anychronousity and multithreading)
* Index-based linking (more static)
* Hashes (v13 extension)
* Bitstring call protocol (v13 extension)
* Evaluable to parsed

5
src/sys5.bu4 Normal file
View File

@ -0,0 +1,5 @@
@@
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
[b3]
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

17
src/sys6.bu4 Normal file
View File

@ -0,0 +1,17 @@
@@
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
/(g)
(x)
/
[x]
[g]
[YC]
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
(_)
/
[ID]
[YC]
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
(_)
/ < (x) /[x][SC] > [SC]
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""