# Commits

committed 38d538f

Class inheritance.

# doc/ALPACA.markdown

`     | ccd`
`     | dcc`
`     = -----`
`-    = dc`
`-    = cc`
`+    = cc `
`+    = ccd`
`     = -----`
` `
` Each state can belong to zero or more classes.  When it belongs to more`
` `
` Example: a cellular automaton with three states and two classes, where all`
` states are members of both classes, but they inherit in different orders.`
`-In it, `One`s always remain `One`s, `Two`s always remain `Two`s, and `Three`s`
`-always remain `Three`s.`
`+In it, `One`s and always become `Four`s, `Two`s always become `Five`s,`
`+and `Three`s always remain `Three`s.`
` `
`     | state Space " ";`
`     | class AlphaType`
`-    |   to One when true;`
`+    |   to Four when true;`
`     | class BetaType`
`-    |   to Two when true;`
`+    |   to Five when true;`
`     | state One "1" is AlphaType is BetaType;`
`     | state Two "2" is BetaType is AlphaType;`
`     | state Three "3" is BetaType is AlphaType`
`-    |   to Three when true`
`+    |   to Three when true;`
`+    | state Four "4";`
`+    | state Five "5"`
`     | begin`
`     | 123`
`     = -----`
`-    = 123`
`+    = 453`
`     = -----`
` `
` In a transition rule, a class-inclusion predicate may be used by`

# src/alpaca/eval.py

` def eval_rules(playfield, x, y, ast):`
`     """Given a playfield and a position within it, and a set of rules,`
`     return the "to" state for the rule that applies.`
`-    `
`+`
`+    If no rule applies, None is returned.`
`+`
`     """`
`     assert ast.type == 'Rules'`
`     for rule in ast.children:`
`         e = rule.children[1]`
`         if eval_expr(playfield, x, y, e):`
`             return eval_state_ref(playfield, x, y, s)`
`-    return playfield.get(x, y)`
`+    return None`
` `
` `
`-def find_state_defn(state_id, ast):`
`-    assert isinstance(state_id, basestring), \`
`-      "why is %r not a string?" % state_id`
`+def find_defn(type, id, ast):`
`+    assert isinstance(id, basestring)`
`     assert ast.type == 'Alpaca'`
`     defns = ast.children[0]`
`     assert defns.type == 'Defns'`
`     for defn in defns.children:`
`-        if defn.type == 'StateDefn':`
`-            if state_id == defn.value:`
`-                return defn`
`-    raise KeyError, "No such state '%s'" % state_sym`
`+        if defn.type == type and defn.value == id:`
`+            return defn`
`+    raise KeyError, "No such %s '%s'" % (type, id)`
`+  `
`+`
`+def find_state_defn(state_id, ast):`
`+    return find_defn('StateDefn', state_id, ast)`
`+`
`+`
`+def find_class_defn(class_id, ast):`
`+    return find_defn('ClassDefn', class_id, ast)`
` `
` `
` def construct_representation_map(ast):`
`             state_ast = find_state_defn(state_id, ast)`
`             #print " => %r" % state_ast`
`             new_state_id = eval_rules(playfield, x, y, state_ast.children[3])`
`+            class_decls = state_ast.children[2]`
`+            assert class_decls.type == 'MembershipDecls'`
`+            for class_decl in class_decls.children:`
`+                assert class_decl.type == 'ClassDecl'`
`+                if new_state_id is not None:`
`+                    break`
`+                class_id = class_decl.value`
`+                class_ast = find_class_defn(class_id, ast)`
`+                new_state_id = eval_rules(playfield, x, y, class_ast.children[0])`
`+            if new_state_id is None:`
`+                new_state_id = playfield.get(x, y)`
`             #print "new state: %s" % new_state_id`
`             new_pf.set(x, y, new_state_id)`
`             x += 1`