from protocols import Interface, Attribute
__all__ = [
'IDispatchFunction', 'ICriterion', 'ISignature', 'IDispatchPredicate',
'IDispatcher', 'AmbiguousMethod', 'NoApplicableMethods',
'IDispatchableExpression', 'IGenericFunction', 'IDispatchTable',
'EXPR_GETTER_ID','IExtensibleFunction', 'DispatchError',
'ISeededCriterion',
]
class DispatchError(Exception):
"""A dispatch error has occurred"""
def __call__(self,*args,**kw):
raise self.__class__(*self.args+(args,kw))
class AmbiguousMethod(DispatchError):
"""More than one choice of method is possible"""
class NoApplicableMethods(DispatchError):
"""No applicable method has been defined for the given arguments"""
EXPR_GETTER_ID = -1
class ICriterion(Interface):
"""A criterion to be applied to an expression
A criterion comprises a "node type" (that determines how the
criterion will be checked, such as an 'isinstance()' check or range
comparison) and a value or values that the expression must match. Note
that a criterion describes only the check(s) to be performed, not the
expression to be checked."""
node_type = Attribute(
"""The type of object that will actually do the dispatching"""
)
def __and__(other):
"""Apply multiple criteria of the same node type to the same expr"""
def __hash__():
"""Equal criteria should have equal hashes"""
def __eq__(other):
"""Return true if equal"""
def __ne__(other):
"""Return false if equal"""
def __invert__():
"""Return an inverse version of this criterion (i.e. '~criterion')"""
def implies(other):
"""Return true if truth of this criterion implies truth of 'other'"""
def subscribe(listener):
"""Call 'listener.criterionChanged()' if applicability changes
Multiple calls with the same listener should be treated as a no-op."""
def unsubscribe(listener):
"""Stop calling 'listener.criterionChanged()'
Unsubscribing a listener that was not subscribed should be a no-op."""
class ISeededCriterion(ICriterion):
"""A criterion that works with a SeededIndex"""
enumerable = Attribute(
"""Can criterion enumerate its implications via ``parent_seeds()``?"""
)
leaf_seed = Attribute(
"""If ``enumerable``, this must be the most-specific parent seed"""
)
def seeds():
"""Return iterable of known-good keys
The keys returned will be used to build outgoing edges in generic
functions' dispatch tables, which will be passed to the
'dispatch_function' for interpretation."""
def __contains__(key):
"""Return true if criterion is true for 'key'
This method will be passed each seed provided by this or any other
criteria with the same 'dispatch_function' that are being applied to
the same expression."""
def matches(table):
"""Return iterable of keys from 'table' that this criterion matches"""
def parent_criteria():
"""Iterable of all the criteria implied by this criterions"""
class IDispatchFunction(Interface):
"""Determine what path to take at a dispatch node, given an expression"""
def __call__(table,ob):
"""Return entry from 'table' that matches 'ob' ('None' if not found)
'table' is an 'IDispatchTable' mapping criterion seeds to dispatch
nodes. The dispatch function should return the appropriate entry from
the dictionary."""
def __eq__(other):
"""Return true if equal"""
def __ne__(other):
"""Return false if equal"""
def __hash__():
"""Return hashcode"""
class IDispatchTable(Interface):
"""A dispatch node for dispatch functions to search"""
def __contains__(key):
"""True if 'key' is in table"""
def __getitem__(key):
"""Return dispatch node for 'key', or raise 'KeyError'"""
def reseed(key):
"""Add 'key' to dispatch table and return the node it should have"""
class ISignature(Interface):
"""Ordered mapping from expression id -> criterion that should be applied
Note that signatures do not/should not interpret expression IDs; the IDs
may be any object that can be used as a dictionary key.
"""
def items():
"""Sequence of '((id,disp_func),criterion)' pairs for this signature"""
def get(expr_id):
"""Return this signature's 'ICriterion' for 'expr_id'"""
def implies(otherSig):
"""Return true if this signature implies 'otherSig'"""
def __eq__(other):
"""Return true if equal"""
def __ne__(other):
"""Return false if equal"""
class IDispatchPredicate(Interface):
"""Sequence of "or"-ed signatures"""
def __iter__():
"""Iterate over "or"-ed signatures"""
def __eq__(other):
"""Return true if equal"""
def __ne__(other):
"""Return false if equal"""
class IDispatchableExpression(Interface):
"""Expression definition suitable for dispatching"""
def asFuncAndIds(generic):
"""Return '(func,idtuple)' pair for expression computation"""
def __eq__(other):
"""Return true if equal"""
def __ne__(other):
"""Return false if equal"""
def __hash__():
"""Return hashcode"""
class IDispatcher(Interface):
"""Multi-dispatch mapping object"""
def __getitem__(argtuple):
"""Return the rule body (or combo thereof) that matches 'argtuple'"""
def __setitem__(signature,body):
"""Store 'body' as the rule body for arg tuples matching 'signature'"""
def parse(expr_string, local_dict, global_dict):
"""Parse 'expr_string' --> ISignature or IDispatchPredicate"""
def getExpressionId(expr):
"""Return an expression ID for use in 'asFuncAndIds()' 'idtuple'
Note that the constant 'EXPR_GETTER_ID' may be used in place of calling
This method, if you want the ID corresponding to a function that will
return the value of any other expression whose ID is passed to it."""
def criterionChanged():
"""Notify that a criterion has changed meaning, invalidating indexes"""
def clear():
"""Empty all signatures, methods, criteria, expressions, etc."""
class IExtensibleFunction(Interface):
def __call__(*__args,**__kw):
"""Invoke the function and return results"""
def addMethod(predicate,method):
"""Call 'method' when input matches 'predicate'
(Note that single and multiple-dispatch functions use different
predicate types: type/class/sequence vs. 'IDispatchPredicate').
"""
def when(cond):
"""Add following function to this GF, w/'cond' as a guard
This is used to add a method to a generic function. E.g.::
import foo
@foo.barFunc.when(XYZ)
def whatever(x,y,z):
# code for situation XYZ
After the execution of this alternate form, 'whatever' will be bound
to the 'whatever' function as shown, but it will also have been added
to 'foo.barFunc' under condition 'XYZ'.
"""
class IGenericFunction(IExtensibleFunction, IDispatcher):
"""Extensible function that stores methods in an IDispatcher"""
# copy() ?
syntax highlighted by Code2HTML, v. 0.9.1