0 | 0 |
"""
|
1 | 1 |
Direct evaluator of ALPACA AST nodes.
|
2 | |
|
3 | |
XXX move some of these out into alpaca.analysis
|
4 | 2 |
|
5 | 3 |
"""
|
6 | 4 |
|
7 | 5 |
from alpaca.ast import AST
|
8 | 6 |
from alpaca.playfield import Playfield
|
|
7 |
from alpaca.analysis import (
|
|
8 |
find_state_defn, find_class_defn, state_defn_is_a,
|
|
9 |
)
|
9 | 10 |
|
10 | 11 |
|
11 | 12 |
def eval_state_ref(playfield, x, y, ast):
|
|
17 | 18 |
raise NotImplementedError
|
18 | 19 |
|
19 | 20 |
|
20 | |
def eval_expr(playfield, x, y, ast):
|
|
21 |
def eval_expr(alpaca, playfield, x, y, ast):
|
21 | 22 |
"""Given a playfield and a position within it, and a boolean expression,
|
22 | 23 |
return what the expression evaluates to at that position.
|
23 | 24 |
|
24 | 25 |
"""
|
25 | 26 |
if ast.type == 'BoolOp':
|
26 | |
lhs = eval_expr(playfield, x, y, ast.children[0])
|
27 | |
rhs = eval_expr(playfield, x, y, ast.children[1])
|
|
27 |
lhs = eval_expr(alpaca, playfield, x, y, ast.children[0])
|
|
28 |
rhs = eval_expr(alpaca, playfield, x, y, ast.children[1])
|
28 | 29 |
op = ast.value
|
29 | 30 |
if op == 'and':
|
30 | 31 |
return lhs and rhs
|
|
33 | 34 |
elif op == 'xor':
|
34 | 35 |
return not (lhs == rhs)
|
35 | 36 |
elif ast.type == 'Not':
|
36 | |
return not eval_expr(playfield, x, y, ast.children[0])
|
|
37 |
return not eval_expr(alpaca, playfield, x, y, ast.children[0])
|
37 | 38 |
elif ast.type == 'Adjacency':
|
38 | 39 |
state = eval_state_ref(playfield, x, y, ast.children[0])
|
39 | 40 |
nb = ast.children[1]
|
|
51 | 52 |
return state0 == state1
|
52 | 53 |
elif ast.type == 'RelationalClass':
|
53 | 54 |
state_id = eval_state_ref(playfield, x, y, ast.children[0])
|
54 | |
# XXX damn. should we transform the ast to something
|
55 | |
# easier to work with? or just pass the program ast?
|
56 | |
program_ast = 'damn'
|
57 | |
state_ast = find_state_defn(state_id, program_ast)
|
|
55 |
state_ast = find_state_defn(alpaca, state_id)
|
58 | 56 |
class_id = ast.children[1].value
|
59 | 57 |
return state_defn_is_a(state_ast, class_id)
|
60 | 58 |
elif ast.type == 'BoolLit':
|
|
70 | 68 |
raise NotImplementedError
|
71 | 69 |
|
72 | 70 |
|
73 | |
def eval_rules(playfield, x, y, ast):
|
|
71 |
def eval_rules(alpaca, playfield, x, y, ast):
|
74 | 72 |
"""Given a playfield and a position within it, and a set of rules,
|
75 | 73 |
return the "to" state for the rule that applies.
|
76 | 74 |
|
|
82 | 80 |
assert rule.type == 'Rule'
|
83 | 81 |
s = rule.children[0]
|
84 | 82 |
e = rule.children[1]
|
85 | |
if eval_expr(playfield, x, y, e):
|
|
83 |
if eval_expr(alpaca, playfield, x, y, e):
|
86 | 84 |
return eval_state_ref(playfield, x, y, s)
|
87 | 85 |
return None
|
88 | 86 |
|
89 | 87 |
|
90 | |
def find_defn(type, id, ast):
|
91 | |
assert isinstance(id, basestring)
|
92 | |
assert ast.type == 'Alpaca'
|
93 | |
defns = ast.children[0]
|
94 | |
assert defns.type == 'Defns'
|
95 | |
for defn in defns.children:
|
96 | |
if defn.type == type and defn.value == id:
|
97 | |
return defn
|
98 | |
raise KeyError, "No such %s '%s'" % (type, id)
|
99 | |
|
100 | |
|
101 | |
def find_state_defn(state_id, ast):
|
102 | |
return find_defn('StateDefn', state_id, ast)
|
103 | |
|
104 | |
|
105 | |
def find_class_defn(class_id, ast):
|
106 | |
return find_defn('ClassDefn', class_id, ast)
|
107 | |
|
108 | |
|
109 | |
def state_defn_is_a(state_ast, class_id):
|
110 | |
class_decls = state_ast.children[2]
|
111 | |
assert class_decls.type == 'MembershipDecls'
|
112 | |
for class_decl in class_decls.children:
|
113 | |
assert class_decl.type == 'ClassDecl'
|
114 | |
if class_id == class_decl.value:
|
115 | |
return True
|
116 | |
return False
|
117 | |
|
118 | |
|
119 | |
def construct_representation_map(ast):
|
120 | |
map = {}
|
121 | |
assert ast.type == 'Alpaca'
|
122 | |
defns = ast.children[0]
|
123 | |
assert defns.type == 'Defns'
|
124 | |
for defn in defns.children:
|
125 | |
if defn.type == 'StateDefn':
|
126 | |
repr = defn.children[0]
|
127 | |
assert repr.type == 'CharRepr'
|
128 | |
map[repr.value] = defn.value
|
129 | |
return map
|
130 | |
|
131 | |
|
132 | |
def get_default_state(ast):
|
133 | |
assert ast.type == 'Alpaca'
|
134 | |
defns = ast.children[0]
|
135 | |
assert defns.type == 'Defns'
|
136 | |
for defn in defns.children:
|
137 | |
if defn.type == 'StateDefn':
|
138 | |
return defn.value
|
139 | |
|
140 | |
|
141 | |
def get_defined_playfield(ast):
|
142 | |
assert ast.type == 'Alpaca'
|
143 | |
playast = ast.children[1]
|
144 | |
assert playast.type == 'Playfield'
|
145 | |
repr_map = construct_representation_map(ast)
|
146 | |
pf = Playfield(get_default_state(ast), repr_map)
|
147 | |
for (x, y, ch) in playast.value:
|
148 | |
pf.set(x, y, repr_map[ch])
|
149 | |
pf.recalculate_limits()
|
150 | |
return pf
|
151 | |
|
152 | |
|
153 | |
def evolve_playfield(playfield, new_pf, ast):
|
|
88 |
def evolve_playfield(playfield, new_pf, alpaca):
|
154 | 89 |
# XXX TODO + 1, - 1's in here should reflect the maximum
|
155 | 90 |
# neighbourhood used by any rule
|
156 | 91 |
if playfield.min_y is None:
|
|
161 | 96 |
while x <= playfield.max_x + 1:
|
162 | 97 |
state_id = playfield.get(x, y)
|
163 | 98 |
#print "state at (%d,%d): %s" % (x, y, state_id)
|
164 | |
state_ast = find_state_defn(state_id, ast)
|
|
99 |
state_ast = find_state_defn(alpaca, state_id)
|
165 | 100 |
#print " => %r" % state_ast
|
166 | |
new_state_id = eval_rules(playfield, x, y, state_ast.children[3])
|
|
101 |
new_state_id = eval_rules(alpaca, playfield, x, y, state_ast.children[3])
|
167 | 102 |
class_decls = state_ast.children[2]
|
168 | 103 |
assert class_decls.type == 'MembershipDecls'
|
169 | 104 |
for class_decl in class_decls.children:
|
|
171 | 106 |
if new_state_id is not None:
|
172 | 107 |
break
|
173 | 108 |
class_id = class_decl.value
|
174 | |
class_ast = find_class_defn(class_id, ast)
|
175 | |
new_state_id = eval_rules(playfield, x, y, class_ast.children[0])
|
|
109 |
class_ast = find_class_defn(alpaca, class_id)
|
|
110 |
new_state_id = eval_rules(alpaca, playfield, x, y, class_ast.children[0])
|
176 | 111 |
if new_state_id is None:
|
177 | 112 |
new_state_id = playfield.get(x, y)
|
178 | 113 |
#print "new state: %s" % new_state_id
|