tracing + smarter memoization + better __str__
This commit is contained in:
parent
874fb84957
commit
1f1700e9a8
@ -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}'
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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})'
|
||||
|
@ -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()}]'
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -8,6 +8,7 @@ __all__ = ('Linked',)
|
||||
|
||||
class Linked:
|
||||
future: set[bytes]
|
||||
multifuture: set[bytes]
|
||||
|
||||
def evaluable(self, env: envtype) -> Evaluable:
|
||||
raise NotImplementedError
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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]
|
||||
|
@ -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
49
bu4/tracing/probe.py
Normal 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
27
docs/extensions.md
Normal 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
28
main.py
@ -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()
|
||||
|
@ -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
5
src/sys5.bu4
Normal file
@ -0,0 +1,5 @@
|
||||
@@
|
||||
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
[b3]
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
17
src/sys6.bu4
Normal file
17
src/sys6.bu4
Normal file
@ -0,0 +1,17 @@
|
||||
@@
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
/(g)
|
||||
(x)
|
||||
/
|
||||
[x]
|
||||
[g]
|
||||
[YC]
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
(_)
|
||||
/
|
||||
[ID]
|
||||
[YC]
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
(_)
|
||||
/ < (x) /[x][SC] > [SC]
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
Loading…
Reference in New Issue
Block a user