def test_multiclone_name_conflict(self): # when prototypes share attribute names # the attribute of the first prototype is used cat = proto(name="cat") dog = proto(name="dog") catdog = clone(cat, dog) self.assertEqual(catdog.name, "cat") catdog.name = "catdog" self.assertEqual(catdog.name, "catdog")
def test_multichain_self(self): # as with single chaining, this is not allowed try: cat = proto(meow=lambda self: "meow") dog = proto(bark=lambda self: "guau") catdog = cat.chain(cat, dog) self.assertEqual(catdog.meow(), "meow") self.assertEqual(catdog.bark(), "guau") self.assertTrue(False) except TypeError: self.assertTrue(True)
def test_clone_self(self): # cloning self is allowed as it creates a new object katze = proto(name="klin") katze = clone(katze) katze.size = "small" self.assertEqual(katze.name, "klin") self.assertEqual(katze.size, "small")
def test_chain_methods(self): # basic object creation ringo = proto(en="apple") self.assertEqual(ringo.en, "apple") # update method of parent furutsu = proto(en="fruit") ringo = ringo.chain(furutsu) self.assertNotEqual(str(furutsu), "fruit") self.assertNotEqual(str(ringo), "apple") # new functionality furutsu.__str__ = lambda self: self.en self.assertEqual(str(furutsu), "fruit") self.assertEqual(str(ringo), "apple") # update method of child ringo.__str__ = lambda self: f"I am {self.en}" self.assertEqual(furutsu.__str__(), "fruit") self.assertEqual(ringo.__str__(), "I am apple")
def test_chain_self(self): try: # chaining self is not allowed katze = proto(name="klin") katze = katze.chain(katze) self.assertTrue(False) except TypeError: self.assertTrue(True)
def init_rule(ctx, lhs, rhs): # only and supported on right handside if rhs.kind == "atom": atom = rhs if atom.data in ctx: val = ctx[atom.data] if val.rule == None: val.rule = lhs else: val.rule = proto(kind="or", data=(lhs, val.rule)) else: ctx[atom.data] = proto(data=False, seen=False, rule=lhs) elif rhs.kind == "and": init_rule(ctx, lhs, rhs.data[0]) init_rule(ctx, lhs, rhs.data[1]) else: assert False
def make_fact(ctx, args, ask): for key in ctx: val = ctx[key] val.data = False val.seen = False for arg in args.data: if arg.data in ctx: val = ctx[arg.data] val.data = True val.seen = True else: ctx[arg.data] = proto(data=True, seen=True, rule=None)
def test_chain_members(self): # basic object creation orenji = proto(name="orenji") self.assertEqual(orenji.name, "orenji") # assure propragation from parents to children orange_fruit = proto(color="orange") self.assertEqual(orange_fruit.color, "orange") # old object orenji.chain(orange_fruit) self.assertEqual(orenji.color, "orange") orenji = orenji.chain(orange_fruit) self.assertEqual(orenji.name, "orenji") self.assertEqual(orenji.color, "orange") # new object mikan = proto(name="mikan").chain(orange_fruit) self.assertEqual(mikan.name, "mikan") self.assertEqual(mikan.color, "orange") # assure that children mask parents' values orange_fruit.name = "orange_fruit" self.assertEqual(orange_fruit.name, "orange_fruit") self.assertEqual(orenji.name, "orenji") self.assertEqual(mikan.name, "mikan") # assure that children do not modify parents or siblings mikan.color = "orange-brown" self.assertEqual(mikan.color, "orange-brown") self.assertEqual(orenji.color, "orange") self.assertEqual(orange_fruit.color, "orange") # assure that parents can be changed orange_fruit.fruit_type = "ripe" brown_fruit = proto(color="brown") orenji.chain(brown_fruit) self.assertEqual(orenji.color, "brown") try: _ = orenji.fruit_type # not present in current prototype self.assertTrue(False) except AttributeError: self.assertTrue(True) brown_fruit.fruit_type = "rotten" self.assertEqual(brown_fruit.fruit_type, "rotten") self.assertEqual(orenji.fruit_type, "rotten")
def test_proto(self): # members mikan = proto(name="mikan") self.assertEqual(mikan.name, "mikan") mikan.color = "orange" self.assertEqual(mikan.color, "orange") mikan.type = "fruit" self.assertEqual(mikan.type, "fruit") # methods mikan.__str__ = lambda self: self.name self.assertEqual(str(mikan), mikan.name) self.assertEqual(mikan.__str__(), mikan.name) mikan.introduce = lambda self: f"watashi wa {self.name} desu!" self.assertEqual(mikan.introduce(), "watashi wa mikan desu!")
def test_clone(self): # base object animal = proto(kind="animal") self.assertEqual(animal.kind, "animal") # a simple clone cat = clone(animal) self.assertEqual(cat.kind, "animal") # a clone of a clone kitten = clone(cat) kitten.size = "small" self.assertEqual(kitten.kind, "animal") self.assertEqual(kitten.size, "small") # propagation cat.greet = lambda self: "meow" self.assertEqual(kitten.greet(), "meow")
def eval_atom(ctx, atom, ask): if atom.data in ctx: val = ctx[atom.data] if val.seen: return val.data elif val.rule == None: return False else: val.seen = True val.data = eval_node(ctx, val.rule, ask) return val.data else: print(">> Responda Sim (s) ou Não (n):") val = input(ask[atom.data]) assert val == "s" or val == "n", ">> Você deve responder Sim (s) ou Não (n)." val = True if val == "s" else False ctx[atom.data] = proto(data=val, seen=True, rule=None) return ctx[atom.data].data
from lark import Lark, Transformer from protoclass import proto BASE = proto(__repr__=lambda self: f"{self.kind}({self.data})") class XSys(Transformer): def start(self, args): return args[:] def stmt(self, stmt): (stmt,) = stmt return stmt def expr(self, expr): (expr,) = expr return expr def expr_last(self, expr): (expr,) = expr return expr def atom(self, atom): atom = str(atom[0]) return proto(kind="atom", data=atom).chain(BASE) def make_fact(self, args): args = args[:] return proto(kind="make_fact", data=args).chain(BASE)
def atom(self, atom): atom = str(atom[0]) return proto(kind="atom", data=atom).chain(BASE)
def test_multiclone(self): cat = proto(meow=lambda self: "meow") dog = proto(bark=lambda self: "guau") catdog = clone(cat, dog) self.assertEqual(catdog.meow(), "meow") self.assertEqual(catdog.bark(), "guau")
def expr_xor(self, args): (lhs, rhs) = args return proto(kind="xor", data=(lhs, rhs)).chain(BASE)
def expr_and(self, args): (lhs, rhs) = args return proto(kind="and", data=(lhs, rhs)).chain(BASE)
def expr_not(self, arg): return proto(kind="not", data=arg[0]).chain(BASE)
def make_rule(self, args): (lhs, rhs) = args return proto(kind="make_rule", data=(lhs, rhs)).chain(BASE)
def make_fact(self, args): args = args[:] return proto(kind="make_fact", data=args).chain(BASE)