def compile(graph, target): ''' Compilation is a two-step process that supports (1) pre-computation of values and (2) rapid access to other nodes. A compiled node is a function that takes no arguments and returns the next compiled node for evaluation (the end of the process is signalled to the engine via the `.match()` and `.no_match()` callbacks above). It's non-trivial (I think?) to make an efficient closure that includes loops, so the compilation avoids this. Instead, indices into an array of nodes are used. So the compilation process works as follows: 1. - The `.compile()` method is passed the engine (`BaseMatchTarget` above) and numbered. It returns a "compiler" function. 2. - The compiler function is called with the map from nodes to indices and the (future) table of compiled nodes by index. This converts any node references to indices and returns the "compiled" node, which is stored in the table. At run-time, when the compiled node is called it must: 3. - Call the target interface as necessary. 4. - Return the next node. To obtain the next node it will use the indices generated above to lookup the node from the table. Note that the state (position in the input text, matched groups, etc) is managed by the engine itself. The nodes simply trigger the correct processing. ''' compilers = [(node, node.compile(target)) for node in node_iterator(graph)] node_index = dict( (node, index) for (index, (node, _compiler)) in enumerate(compilers)) table = [] for (node, compiler) in compilers: table.append(compiler(node_index, table)) return table
def compile(graph, target): ''' Compilation is a two-step process that supports (1) pre-computation of values and (2) rapid access to other nodes. A compiled node is a function that takes no arguments and returns the next compiled node for evaluation (the end of the process is signalled to the engine via the `.match()` and `.no_match()` callbacks above). It's non-trivial (I think?) to make an efficient closure that includes loops, so the compilation avoids this. Instead, indices into an array of nodes are used. So the compilation process works as follows: 1. - The `.compile()` method is passed the engine (`BaseMatchTarget` above) and numbered. It returns a "compiler" function. 2. - The compiler function is called with the map from nodes to indices and the (future) table of compiled nodes by index. This converts any node references to indices and returns the "compiled" node, which is stored in the table. At run-time, when the compiled node is called it must: 3. - Call the target interface as necessary. 4. - Return the next node. To obtain the next node it will use the indices generated above to lookup the node from the table. Note that the state (position in the input text, matched groups, etc) is managed by the engine itself. The nodes simply trigger the correct processing. ''' compilers = [(node, node.compile(target)) for node in node_iterator(graph)] node_index = dict((node, index) for (index, (node, _compiler)) in enumerate(compilers)) table = [] for (node, compiler) in compilers: table.append(compiler(node_index, table)) return table
def post_process(graph, actions): map = {} for (type_, function) in actions: if type_ not in map: map[type_] = function else: raise RxpyError('Conflicting actions for ' + str(type_)) for node in node_iterator(graph): map.get(type(node), lambda x: None)(node) return graph