Source code for pyrser.type_system.evalctx
# around a signature store type resolution for monomorphic or polymorphic call
import inspect
from pyrser.type_system.type_name import *
from pyrser.type_system.signature import *
from pyrser.type_system.fun import *
from pyrser.type_system.symbol import *
[docs]class EvalCtx:
"""
Store environment for mono/poly call.
"""
[docs] def __str__(self) -> str:
import pyrser.type_system.to_fmt
return str(self.to_fmt())
[docs] def __init__(self, sig: Signature):
self._sig = sig
self.resolution = dict()
self._translate_to = None
self._variadic_types = None
self.resolve()
[docs] def get_parent(self):
return self._sig.get_parent()
[docs] def internal_name(self):
return self._sig.internal_name()
[docs] def show_name(self):
return self._sig.show_name()
@property
def name(self):
if self._sig is not None:
return self._sig.name
return None
@property
def tret(self):
if self._sig is not None and hasattr(self._sig, 'tret'):
return self._sig.tret
return None
@property
def compute_tret(self):
tret = []
for t in self.tret.components:
if t in self.resolution and self.resolution[t] is not None:
tret.append(self.resolution[t]().show_name())
else:
tret.append(t)
return " ".join(tret)
@property
def tparams(self):
if self._sig is not None and hasattr(self._sig, 'tparams'):
return self._sig.tparams
return None
@property
def variadic(self):
if self._sig is not None and hasattr(self._sig, 'variadic'):
return self._sig.variadic
return None
@property
def is_polymorphic(self) -> bool:
if self._sig is not None and hasattr(self._sig, 'is_polymorphic'):
return self._sig.is_polymorphic
return False
[docs] def from_sig(sig: Signature) -> object:
if isinstance(sig, EvalCtx):
return sig
else:
return EvalCtx(sig)
def set_parent(self, parent) -> object:
"""
Forward to intern Signature
"""
return self._sig.set_parent(parent)
[docs] def __len__(self) -> int:
return len(self._sig)
[docs] def values(self) -> list:
"""
Make EvalCtx iterable (to update a scope with it)
"""
return [self._sig]
[docs] def get_compute_sig(self) -> Signature:
"""
Compute a signature Using resolution!!!
TODO: discuss of relevance of a final generation for a signature
"""
tret = []
tparams = []
for t in self.tret.components:
if t in self.resolution and self.resolution[t] is not None:
tret.append(self.resolution[t]().show_name())
else:
tret.append(t)
if hasattr(self, 'tparams'):
for p in self.tparams:
tp = []
for t in p.components:
if t in self.resolution and self.resolution[t] is not None:
tp.append(self.resolution[t]().show_name())
else:
tp.append(t)
tparams.append(" ".join(tp))
if self.variadic:
if self._variadic_types is None:
raise ValueError("Can't compute the sig "
+ "with unresolved variadic argument"
)
for p in self._variadic_types:
tp = []
for t in p.components:
if (t in self.resolution
and self.resolution[t] is not None
):
tp.append(self.resolution[t]().show_name())
else:
tp.append(t)
tparams.append(" ".join(tp))
ret = Fun(self.name, " ".join(tret), tparams)
# transform as-is into our internal Signature (Val, Var, whatever)
ret.__class__ = self._sig.__class__
return ret
[docs] def set_parent(self, parent) -> object:
"""
When we add a parent (from Symbol), don't forget to resolve.
"""
ret = self
if parent is not None:
ret = self._sig.set_parent(parent)
self.resolve()
elif not hasattr(self, 'parent'):
# only if parent didn't exist yet
self.parent = None
return ret
[docs] def use_translator(self, translator):
"""
Attach a translator to an EvalCtx to convert output of the function
into another type
"""
self._translate_to = translator
self.resolve()
[docs] def use_variadic_types(self, list_type: [TypeName]):
"""
Attach a list of types for extra variadic argument of a call
"""
self._variadic_types = list_type
self.resolve()
[docs] def resolve(self):
"""
Process the signature and find definition for type.
"""
# collect types for resolution
t2resolv = []
if hasattr(self._sig, 'tret'):
t2resolv.append(self._sig.tret)
if hasattr(self._sig, 'tparams') and self._sig.tparams is not None:
for p in self._sig.tparams:
t2resolv.append(p)
if self._translate_to is not None:
t2resolv.append(self._translate_to.target)
if self._variadic_types is not None:
for t in self._variadic_types:
t2resolv.append(t)
for t in t2resolv:
for c in t.components:
if c not in self.resolution or self.resolution[c] is None:
# try to find what is c
parent = self.get_parent()
if parent is not None:
sc = parent.get_by_symbol_name(c)
if len(sc) == 1:
sc = list(sc.values())[0]
# unwrap EvalCtx around Type
if isinstance(sc, EvalCtx):
sc = sc._sig
rtyp = weakref.ref(sc)
self.resolution[c] = rtyp
continue
# unresolved
self.resolution[c] = None
[docs] def get_resolved_names(self, type_name: TypeName) -> list:
"""
Use self.resolution to subsitute type_name.
Allow to instanciate polymorphic type ?1, ?toto
"""
if not isinstance(type_name, TypeName):
raise Exception("Take a TypeName as parameter not a %s"
% type(type_name))
rnames = []
for name in type_name.components:
if name not in self.resolution:
raise Exception("Unknown type %s in a EvalCtx" % name)
rname = self.resolution[name]
if rname is not None:
rname = rname().show_name()
else:
rname = name
rnames.append(rname)
return rnames
[docs] def set_resolved_name(self, ref: dict, type_name2solve: TypeName,
type_name_ref: TypeName):
"""
Warning!!! Need to rethink it when global poly type
"""
if self.resolution[type_name2solve.value] is None:
self.resolution[type_name2solve.value] = ref[type_name_ref.value]