1 #!/usr/bin/env python 2 3 """ 4 Generate RSVP code from simplified nodes. 5 6 Copyright (C) 2007 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from simplify.simplified import * 23 import rsvp 24 25 # Classes. 26 27 class Generator(Visitor): 28 29 """ 30 An RSVP code generator. 31 32 Covered: 33 34 Missing: Assign, CheckType, Conditional, Constant, Global, Import, 35 InvokeRef, InvokeFunction, LoadAttr, LoadExc, LoadName, LoadRef, 36 LoadTemp, Module, Not, Pass, Raise, ReleaseTemp, ReturnFromBlock, 37 ReturnFromFunction, StoreAttr, StoreName, StoreTemp, Subprogram, 38 Try. 39 """ 40 41 def __init__(self, debug=0): 42 43 "Initialise the visitor." 44 45 self.debug = debug 46 Visitor.__init__(self) 47 self.assemblers = [] 48 self.current_assemblers = [] 49 50 # Satisfy visitor issues. 51 52 self.visitor = self 53 54 def get_code(self): 55 return rsvp.get_merged(*self.assemblers) 56 57 def assembler(self): 58 return self.current_assemblers[-1] 59 60 def process(self, module): 61 62 """ 63 Process the given 'module', creating RSVP assemblers to store code and 64 data. 65 """ 66 67 self.module = module 68 69 main = rsvp.RSVPAssembler(self.debug) 70 self.current_assemblers.append(main) 71 72 # Store constants. 73 74 for name, const in module.simplifier.constants.items(): 75 main.label("const$%s$%s" % (self.module.name, name)) 76 main.add(const.value) 77 78 # Reserve the namespace. 79 80 for name in module.namespace.keys(): 81 main.label("global$%s$%s" % (self.module.name, name)) 82 main.add(None) 83 84 # Generate subprograms. 85 86 for subprogram in module.simplifier.subprograms: 87 if not subprogram.internal: 88 89 # Generate specific subprograms. 90 91 for specialisation in subprogram.specialisations(): 92 self.process_subprogram(specialisation) 93 94 # Generate the initialisation. 95 96 self.dispatch(module) 97 98 # Remember the assembler used. 99 100 self.current_assemblers.pop() 101 self.assemblers.append(main) 102 103 def default(self, node, *args): 104 if hasattr(node, "code"): 105 self.dispatches(node.code) 106 107 def visitInvoke(self, invoke): 108 109 "Process the given 'invoke' node." 110 111 sub = self.assembler() 112 113 # NOTE: Generate arguments in a way compatible with subprogram 114 # NOTE: consumption as parameters. 115 116 for subprogram in invoke.invocations: 117 prepare_args = not isinstance(invoke, InvokeRef) and not invoke.share_locals 118 if prepare_args: 119 consumed_args = invoke.consumed_args[subprogram] 120 121 # NOTE: Generate switch table. 122 123 # Save the current frame. 124 125 sub.add("SCF") 126 127 # Extend the stack for the arguments. 128 129 nparams = len(consumed_args) 130 sub.add("ESF", nparams) 131 132 # For each argument, evaluate the expression. 133 134 for arg in invoke.args: 135 if arg is None: 136 continue 137 138 self.dispatch(arg) 139 140 # Then, save the argument to the correct part of the arguments 141 # frame. 142 143 pos = self.arg_position(consumed_args, arg) 144 sub.add("MVA", pos) 145 146 # Reserve the namespace. 147 148 sub.add("NSF", nparams) 149 150 sub.add("JAS", "sub$%s$%s" % (subprogram.module.name, subprogram.full_name())) 151 152 if prepare_args: 153 sub.add("PSF") # previous stack frame 154 155 visitInvokeFunction = visitInvoke 156 visitInvokeRef = visitInvoke 157 158 def visitModule(self, module): 159 160 "Process the given 'module'." 161 162 self.dispatches(module.code) 163 164 def visitSubprogram(self, subprogram): 165 166 "Process the 'subprogram'." 167 168 if subprogram.internal: 169 self.process_subprogram(subprogram) 170 171 def process_subprogram(self, subprogram): 172 173 sub = rsvp.RSVPAssembler(self.debug) 174 self.current_assemblers.append(sub) 175 176 sub.label("sub$%s$%s" % (self.module.name, subprogram.full_name())) 177 178 locals = subprogram.namespace.keys() 179 params = subprogram.paramtypes.keys() 180 nparams = len(params) 181 non_params = len(locals) - nparams 182 183 if non_params > 0: 184 sub.add("ESF", non_params) # extend stack frame for locals 185 186 # Produce the standard end of subprogram return. 187 188 sub.add("RAC") # return 189 190 self.current_assemblers.pop() 191 self.assemblers.append(sub) 192 193 def arg_position(self, consumed_args, arg): 194 195 """ 196 Return, for the specified 'consumed_args', the position of 'arg' in the 197 list, handling keyword arguments appropriately. 198 """ 199 200 if isinstance(arg, Keyword): 201 arg = arg.expr 202 return consumed_args.index(arg) 203 204 # Convenience functions. 205 206 def get_attribute_table(importer): 207 208 """ 209 Return an attribute table for all structures known to the given 'importer'. 210 """ 211 212 master_table = {} 213 for module in importer.get_modules(): 214 for structure in module.simplifier.structures: 215 classname = structure.fully_qualified_name() 216 master_table[classname] = [] 217 218 # NOTE: Assume enquiries of class attribute items produce the same 219 # NOTE: ordering every time. 220 221 positions = {} 222 for name, (defining_cls, defs) in structure.get_visible_class_attributes().items(): 223 first = 1 224 for attr in defs: 225 if not first: 226 print "Ambiguous attribute '%s' in '%s'." % (name, classname) 227 break 228 if not positions.has_key(defining_cls): 229 positions[defining_cls] = 1 230 master_table[classname].append((name, (name, "A", defining_cls.fully_qualified_name(), positions[defining_cls]))) 231 positions[defining_cls] += 1 232 first = 0 233 234 i = 1 235 for name in structure.get_instance_attribute_names(): 236 master_table[classname].append((name, (name, "A", "I", i))) 237 i += 1 238 239 return master_table 240 241 def generate(module): 242 generator = Generator() 243 generator.process(module) 244 return generator.get_code() 245 246 # vim: tabstop=4 expandtab shiftwidth=4