1 # Copyright (C) 2005-2008, Parrot Foundation.
6 TGE::Tree - The top-level node of every tree.
10 A TGE::Tree is the core object at the center of every tree transformation. You
11 can think of it as something like a PGE::Match object. The first step of
12 applying every tree grammar is to create a TGE::Tree object and wrap it around
13 the tree being transformed. The TGE::Tree object handles result caching for
14 particular transform rules on particular nodes, maintains connections between
15 particular nodes and the transforms that can apply to those nodes, and will
16 eventually handle indexing for faster tree searches.
20 .namespace [ 'TGE'; 'Tree' ]
25 newclass base, ['TGE';'Tree']
26 addattribute base, "cell" # a hash for storing values of tree nodes
27 addattribute base, "visit" # arrays of rules that apply to each node type
28 addattribute base, "data" # the original unmodified tree
29 addattribute base, "grammar" # the current grammar object
30 addattribute base, "agid" # a hash of node address => node id
36 Returns a simple initialized TGE::Tree object. Doesn't accept any
37 constructor parameters.
41 .sub init :vtable :method
45 setattribute self, "cell", $P0
46 setattribute self, "visit", $P1
47 setattribute self, "data", $P2
48 $P3 = new 'AddrRegistry'
49 setattribute self, "agid", $P3
52 # Call all visitors for a given node
53 .sub _scan_node :method
55 .param pmc name :optional
56 .param int got_name :opt_flag
59 # If the user passed in a special name, look up visit actions for that one,
60 # otherwise look them up for the type name of the node.
61 if got_name goto name_from_arg
68 # Iterate over the elements of the visit hash for the given type
72 $P2 = getattribute self, 'visit'
73 $I2 = exists $P2[type]
74 unless $I2 goto end_loop
79 if index < 0 goto end_loop
80 currule = actions[index]
81 self.'_install_action'(node, currule)
89 value = Tree.get('attrname')
91 Fetches the value of a particular attribute from the root node of the
94 value = Tree.get('attrname', node)
95 value = Tree.get('attrname', node, 'type')
97 Fetches the value of a particular attribute from the node passed in.
98 When working with a tree where the nodes don't know their type (PGE
99 match objects, for example), you must also tell C<get> the type of the
106 .param pmc node :optional
107 .param int got_node :opt_flag
108 .param pmc type :optional
109 .param int got_type :opt_flag
111 # If no node was passed in, use top level node.
112 if got_node goto node_exists
113 node = getattribute self, 'data'
117 id = self.'_lookup_id'(node)
120 $P1 = getattribute self, "cell"
121 # First check to see if cell exists
123 $I1 = exists $P1[name]
124 if $I1 goto name_hash_exists
131 if $I0 goto eval_cell
133 if got_type goto scan_with_type
134 self.'_scan_node'(node)
137 self.'_scan_node'(node,type)
139 # Second check to see if _scan_node defined the cell
142 if $I0 goto eval_cell
143 # Cell still not defined, grammar is unresolvable.
144 print "Cannot find the attribute '"
147 unless got_type goto class_is_type
153 print ") that you asked for.\n"
156 $P3 = self.'_eval_cell'(cell,node)
161 .sub _eval_cell :method
166 if $I0 goto run_thunk_action
170 grammar = getattribute self, 'grammar'
171 # the stored node (parent for inherited attributes, self for
172 # synthesized attributes)
175 # the action is a method on the grammar object
176 value = grammar.$S0(self, $P1)
177 cell['value'] = value
181 value = cell['value']
185 # Install a thunk in a particular attribute slot of a particular object.
186 .sub _install_action :method
190 # Grab the 'cell' hash from the grammar object.
192 cell_hash = getattribute self, 'cell'
194 # Retrieve the hash within 'cell' keyed by the name of the attribute.
195 # If the hash doesn't exist, create it.
198 name = getattribute rule, "name"
199 cellattr = cell_hash[name]
200 $I1 = exists cell_hash[name]
201 if $I1 goto name_hash_exists
202 cellattr = new 'Hash'
203 cell_hash[name] = cellattr
206 # Decide which node to operate on. If 'parent' was '.', then operate on
207 # the node passed in, otherwise, operate on a child node named in
211 parent = getattribute rule, 'parent'
212 if parent == '.' goto use_parent_id
213 .local pmc child_node
214 child_node = self.'_lookup_child'(node, parent)
215 id = self.'_lookup_id'(child_node)
218 id = self.'_lookup_id'(node)
221 # Check that the entry (by attribute name and id) in the "cell" hash
222 # doesn't already exist (the grammar should only create one entry
223 # for each unique node id).
225 $I2 = exists cellattr[id]
226 if $I2 goto error_defined
228 # Create the entry in the "cell" tree that stores the action to
229 # calculate the value of a given attribute in a given node. Also
230 # store an empty space for the value after it has been calculated,
231 # and a flag ("thunk") noting whether the action has been run.
235 $P4 = getattribute rule, "action"
236 thunk['action'] = $P4
244 print "Nonlinear attribute: you have two or more ways to "
245 print "assign a value to the attribute '"
247 print "' on node type '"
250 print "' with rule name '"
251 $P4 = getattribute rule, "action"
253 print "' near grammar line "
254 $P7 = getattribute rule, "line"
260 # This determines the semantics of .attr.
261 .sub _lookup_child :method
265 $P1 = getattribute node, $S0
269 .sub _lookup_id :method
274 # Get the id of the node, or if it doesn't exist, generate one.
275 id_hash = getattribute self, 'agid'
277 if id goto got_id # 0 means, doesn't exist
278 id = elements id_hash
289 # vim: expandtab shiftwidth=4 ft=pir: