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 "An RSVP code generator." 30 31 def __init__(self): 32 33 "Initialise the visitor." 34 35 Visitor.__init__(self) 36 self.assemblers = [] 37 self.current_assemblers = [] 38 39 # Satisfy visitor issues. 40 41 self.visitor = self 42 43 def get_code(self): 44 return rsvp.get_image(*self.assemblers) 45 46 def assembler(self): 47 return self.current_assemblers[-1] 48 49 def process(self, module): 50 51 """ 52 Process the given 'module', creating RSVP assemblers to store code and 53 data. 54 """ 55 56 self.module = module 57 58 main = rsvp.RSVPAssembler(1) 59 self.current_assemblers.append(main) 60 61 # Store constants. 62 63 for name, const in module.simplifier.constants.items(): 64 main.label("const$%s$%s" % (self.module.name, name)) 65 main.add(const.value) 66 67 # Reserve the namespace. 68 69 for name in module.namespace.keys(): 70 main.label("global$%s$%s" % (self.module.name, name)) 71 main.add(None) 72 73 # Generate subprograms. 74 75 for subprogram in module.simplifier.subprograms: 76 if not subprogram.internal: 77 78 # Generate specific subprograms. 79 80 for specialisation in subprogram.specialisations(): 81 self.process_subprogram(specialisation) 82 83 # Generate the initialisation. 84 85 self.dispatch(module) 86 87 # Remember the assembler used. 88 89 self.current_assemblers.pop() 90 self.assemblers.append(main) 91 92 def default(self, node, *args): 93 if hasattr(node, "code"): 94 self.dispatches(node.code) 95 96 def visitInvoke(self, invoke): 97 98 "Process the given 'invoke' node." 99 100 sub = self.assembler() 101 102 # NOTE: Generate arguments in a way compatible with subprogram 103 # NOTE: consumption as parameters. 104 105 for subprogram in invoke.invocations: 106 consumed_args = invoke.consumed_args[subprogram] 107 108 # NOTE: Generate switch table. 109 110 # Save the current frame. 111 112 sub.add("SCF") 113 114 # Extend the stack for the arguments. 115 116 nparams = len(consumed_args) 117 if not invoke.share_locals: 118 sub.add("ESF", nparams) 119 120 # For each argument, evaluate the expression. 121 122 for arg in invoke.args: 123 if arg is None: 124 continue 125 126 self.dispatch(arg) 127 128 # Then, save the argument to the correct part of the arguments 129 # frame. 130 131 pos = self.arg_position(consumed_args, arg) 132 sub.add("MVA", pos) 133 134 # Reserve the namespace. 135 136 sub.add("NSF", nparams) 137 138 sub.add("JAS", "sub$%s$%s" % (subprogram.module.name, subprogram.full_name())) 139 140 if not invoke.share_locals: 141 sub.add("PSF") # previous stack frame 142 143 visitInvokeFunction = visitInvoke 144 visitInvokeRef = visitInvoke 145 146 def visitModule(self, module): 147 148 "Process the given 'module'." 149 150 self.dispatches(module.code) 151 152 def visitSubprogram(self, subprogram): 153 154 "Process the 'subprogram'." 155 156 if subprogram.internal: 157 self.process_subprogram(subprogram) 158 159 def process_subprogram(self, subprogram): 160 161 sub = rsvp.RSVPAssembler(1) 162 self.current_assemblers.append(sub) 163 164 sub.label("sub$%s$%s" % (self.module.name, subprogram.full_name())) 165 166 locals = subprogram.namespace.keys() 167 params = subprogram.paramtypes.keys() 168 nparams = len(params) 169 non_params = len(locals) - nparams 170 171 if non_params > 0: 172 sub.add("ESF", non_params) # extend stack frame for locals 173 174 # Produce the standard end of subprogram return. 175 176 sub.add("RAC") # return 177 178 self.current_assemblers.pop() 179 self.assemblers.append(sub) 180 181 def arg_position(self, consumed_args, arg): 182 183 """ 184 Return, for the specified 'consumed_args', the position of 'arg' in the 185 list, handling keyword arguments appropriately. 186 """ 187 188 if isinstance(arg, Keyword): 189 arg = arg.expr 190 return consumed_args.index(arg) 191 192 # Convenience functions. 193 194 def generate(module): 195 generator = Generator() 196 generator.process(module) 197 return generator.get_code() 198 199 # vim: tabstop=4 expandtab shiftwidth=4