more.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. from .core import unify, reify # type: ignore[attr-defined]
  2. from .dispatch import dispatch
  3. def unifiable(cls):
  4. """ Register standard unify and reify operations on class
  5. This uses the type and __dict__ or __slots__ attributes to define the
  6. nature of the term
  7. See Also:
  8. >>> # xdoctest: +SKIP
  9. >>> class A(object):
  10. ... def __init__(self, a, b):
  11. ... self.a = a
  12. ... self.b = b
  13. >>> unifiable(A)
  14. <class 'unification.more.A'>
  15. >>> x = var('x')
  16. >>> a = A(1, 2)
  17. >>> b = A(1, x)
  18. >>> unify(a, b, {})
  19. {~x: 2}
  20. """
  21. _unify.add((cls, cls, dict), unify_object)
  22. _reify.add((cls, dict), reify_object)
  23. return cls
  24. #########
  25. # Reify #
  26. #########
  27. def reify_object(o, s):
  28. """ Reify a Python object with a substitution
  29. >>> # xdoctest: +SKIP
  30. >>> class Foo(object):
  31. ... def __init__(self, a, b):
  32. ... self.a = a
  33. ... self.b = b
  34. ... def __str__(self):
  35. ... return "Foo(%s, %s)"%(str(self.a), str(self.b))
  36. >>> x = var('x')
  37. >>> f = Foo(1, x)
  38. >>> print(f)
  39. Foo(1, ~x)
  40. >>> print(reify_object(f, {x: 2}))
  41. Foo(1, 2)
  42. """
  43. if hasattr(o, '__slots__'):
  44. return _reify_object_slots(o, s)
  45. else:
  46. return _reify_object_dict(o, s)
  47. def _reify_object_dict(o, s):
  48. obj = object.__new__(type(o))
  49. d = reify(o.__dict__, s)
  50. if d == o.__dict__:
  51. return o
  52. obj.__dict__.update(d)
  53. return obj
  54. def _reify_object_slots(o, s):
  55. attrs = [getattr(o, attr) for attr in o.__slots__]
  56. new_attrs = reify(attrs, s)
  57. if attrs == new_attrs:
  58. return o
  59. else:
  60. newobj = object.__new__(type(o))
  61. for slot, attr in zip(o.__slots__, new_attrs):
  62. setattr(newobj, slot, attr)
  63. return newobj
  64. @dispatch(slice, dict)
  65. def _reify(o, s):
  66. """ Reify a Python ``slice`` object """
  67. return slice(*reify((o.start, o.stop, o.step), s))
  68. #########
  69. # Unify #
  70. #########
  71. def unify_object(u, v, s):
  72. """ Unify two Python objects
  73. Unifies their type and ``__dict__`` attributes
  74. >>> # xdoctest: +SKIP
  75. >>> class Foo(object):
  76. ... def __init__(self, a, b):
  77. ... self.a = a
  78. ... self.b = b
  79. ... def __str__(self):
  80. ... return "Foo(%s, %s)"%(str(self.a), str(self.b))
  81. >>> x = var('x')
  82. >>> f = Foo(1, x)
  83. >>> g = Foo(1, 2)
  84. >>> unify_object(f, g, {})
  85. {~x: 2}
  86. """
  87. if type(u) != type(v):
  88. return False
  89. if hasattr(u, '__slots__'):
  90. return unify([getattr(u, slot) for slot in u.__slots__],
  91. [getattr(v, slot) for slot in v.__slots__],
  92. s)
  93. else:
  94. return unify(u.__dict__, v.__dict__, s)
  95. @dispatch(slice, slice, dict)
  96. def _unify(u, v, s):
  97. """ Unify a Python ``slice`` object """
  98. return unify((u.start, u.stop, u.step), (v.start, v.stop, v.step), s)