github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/runtime/ppapi/mkzfile.py (about) 1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 # Copyright 2014 The Go Authors. All rights reserved. 5 # Use of this source code is governed by a BSD-style 6 # license that can be found in the LICENSE file. 7 8 """This is a code generator. It reads configuration information that 9 describes types, functions, and enums; and it uses the info to expand 10 code templates. The config contains lines of the following form: 11 12 Enumeration: <type> is the Go type name, and <pattern> is a regular expression 13 for finding constants in the PPAPI header files. 14 15 //enum <type> <pattern> 16 17 For example, the following defines a type Error containing all constants 18 matching the pattern PP_ERROR_. 19 20 //enum Error PP_ERROR_ 21 22 Types: define a type <type> with a machine representation <mtype>. The machine 23 types includes the usual integer types int32, int64; floats float32 and float64; 24 pointers *; and structs with size in bytes struct[16]. 25 26 //type <type> <mtype> 27 28 //type pp_Bool int32 29 //type pp_Var struct[16] 30 31 Callbacks: specify a callback with the given parameters. 32 33 //callback f(a1 t1, ..., aN, tN) returnType 34 35 //callback ppp_did_create(instance pp_Instance, argc uint32, argn **byte, argv **byte) pp_Bool 36 37 Functions: specify a function call with the given parameters. This is a call 38 into PPAPI. 39 40 //func f(a1 t1, ..., aN, tN) returnType = interface[index] 41 42 //func ppb_var_from_utf8(data *byte, len uint32) pp_Var = PPB_VAR[2] 43 44 To run this, you will need a copy of the NaCl SDK, downloadable from 45 https://developer.chrome.com/native-client/sdk/download. 46 47 Let $NACL_SDK be the location of the NaCl SDK, and $PEPPER be the version of 48 pepper (e.g. pepper_34). This script scans the header files in that package and 49 performs a template expansion. The following command can be used to extract the 50 PPAPI constants. 51 52 ./mkzfile.py --include=$NACL_SDK/$PEPPER/include/ppapi/c consts.got > zconsts.go 53 """ 54 55 __author__ = 'jyh@google.com (Jason Hickey)' 56 57 import argparse 58 import fileinput 59 import glob 60 import re 61 import string 62 import sys 63 from jinja2 import Environment, Template 64 65 parser = argparse.ArgumentParser(description='Process some integers.') 66 parser.add_argument('--include', nargs=1, help='PPAPI include directory from the NaCl SDK') 67 parser.add_argument('template', nargs='+', help='template files') 68 69 # Size/align for machine kinds. 70 sizes = { 71 'void': (0, 0), 72 'int32': (4, 4), 73 'int64': (8, 8), 74 'float32': (4, 4), 75 'float64': (8, 8), 76 '*': (4, 4), 77 } 78 79 # align aligns an address to the next larger boundary. 80 def align(addr, n): 81 return (addr + n - 1) & ~(n - 1) 82 83 # sizeof returns a triple of the kind name, the number of bytes needed to 84 # represent a value of that kind, and the alignment. 85 def sizeof(kind): 86 if kind.startswith('*'): 87 return ('*', 4, 4) 88 elif kind.startswith('struct'): 89 m = re.search(r'struct\[(\w+)(,(\w+))?\]', kind) 90 if m == None: 91 raise Exception("Malformed struct type: " + kind) 92 a = 4 93 if m.group(3) != None: 94 a = int(m.group(3)) 95 return ('struct', int(m.group(1)), a) 96 else: 97 n, a = sizes[kind] 98 return (kind, n, a) 99 100 # Type represents a type, where <name> is the name of the type, <kind> is the 101 # machine kind, and <size> is the sizeof that type. 102 class Type: 103 """Type represents base type""" 104 def __init__(self, name, kind, builtin=False): 105 self.name = name 106 self.kind, self.size, self.align = sizeof(kind) 107 self.builtin = builtin 108 109 # Arg represents a function parameter, including the name and the type. 110 class Arg: 111 """Argument""" 112 def __init__(self, n, ty): 113 self.name = n 114 self.type = ty 115 116 # Func represents a function declaration, declared in the input file. 117 class Func: 118 """Func represents a function description""" 119 def __init__(self, name, args, result, interface, index): 120 self.name = name 121 self.args = args 122 self.result = result 123 self.goresult = result.name 124 self.interface = interface 125 self.index = index 126 self.structReturn = False 127 128 # builtin_types is a dictionary containing the predefined base types. 129 def builtin_types(): 130 return { 131 '': Type('void', 'void', True), 132 'void': Type('void', 'void', True), 133 'bool': Type('bool', 'int32', True), 134 'int16': Type('int16', 'int32', True), 135 'uint16': Type('uint16', 'int32', True), 136 'int32': Type('int32', 'int32', True), 137 'uint32': Type('uint32', 'int32', True), 138 'int64': Type('int64', 'int64', True), 139 'uint64': Type('uint64', 'int64', True), 140 'uintptr': Type('uintptr', 'int32', True), 141 'float32': Type('float32', 'float32', True), 142 'float64': Type('float64', 'float64', True), 143 } 144 145 class Processor: 146 """Processor scans the header and template files and performs the template expansion""" 147 148 # Const definitions scanned from the include files. 149 consts = {} 150 151 # Scanned configuration info. 152 enums = {} 153 types = builtin_types() 154 callbacks = [] 155 functions = [] 156 157 # typeof returns the type for a name. 158 def typeof(self, ty): 159 if ty.startswith('*'): 160 return Type(ty, '*') 161 if ty not in self.types: 162 raise Exception("undefined type: " + ty) 163 return self.types[ty] 164 165 # parseArg parses an argument into a pair (name, type). 166 def parseArg(self, arg, line): 167 parts = arg.split() 168 if len(parts) != 2: 169 raise Exception("Argument should have the form 'name type': " + arg + " : " + line) 170 return Arg(parts[0], self.typeof(parts[1])) 171 172 # parseArgs splits the parameter list for a function. 173 def parseArgs(self, args, line): 174 if args == "": 175 return [] 176 return [self.parseArg(arg.strip(), line) for arg in string.split(args, ',')] 177 178 # framesize returns the total size for all arguments. 179 def framesize(self, func): 180 size = 0 181 for arg in func.args: 182 if arg.type.align > 0: 183 size = align(size, arg.type.align) 184 size += arg.type.size 185 return size 186 187 # updateStructReturn converts the function definition when the return value is 188 # a struct that is larger than 8 bytes. If so, the result is passed by 189 # reference as the first arg. 190 def updateStructReturn(self, func): 191 if func.result.kind == 'struct': 192 func.args.insert(0, Arg('return_struct', Type('*' + func.result.name, '*'))) 193 func.goresult = 'void' 194 func.structReturn = True 195 196 # findEnumType finds the type for a const. 197 def findEnumType(self, c): 198 for r, ty in self.enums.items(): 199 m = re.match(r, c) 200 if m: 201 return ty 202 203 # scanIncludeFiles collect the constants from the include files. 204 def scanIncludeFiles(self, files): 205 for line in fileinput.input(files): 206 m = re.search(r'(PP\w*)\s*=\s*([^,\n\r]+),?\s*$', line) 207 if m: 208 self.consts[m.group(1)] = m.group(2) 209 210 # scanArch reads the architecture from the files. 211 def scanArch(self, files): 212 for line in fileinput.input(files): 213 if line.startswith('//sizeof'): 214 # //enum regex typename 215 m = re.search(r'^//sizeof\s+(\w+)\s+(\d+)\s+(\d+)$', line) 216 if m == None: 217 raise Exception('Malformed //sizeof: ' + line) 218 sizes[m.group(1)] = (int(m.group(2)), int(m.group(3))) 219 self.types = builtin_types() 220 221 # scanConfig reads the configuration from a set of files. 222 def scanConfig(self, files): 223 for line in fileinput.input(files): 224 if line.startswith('//enum'): 225 # //enum regex typename 226 m = re.search(r'^//enum\s+(\w+)\s+(.*)$', line) 227 if m == None: 228 raise Exception('Malformed //enum: ' + line) 229 self.enums[m.group(2)] = m.group(1) 230 self.types[m.group(1)] = Type(m.group(1), 'int32') 231 232 elif line.startswith('//type'): 233 # //type name name 234 m = re.search(r'^//type\s+(\w+)\s+([][,\w*]+)\s*(\w*)\s*$', line) 235 if m == None: 236 raise Exception('Malformed //type: ' + line) 237 self.types[m.group(1)] = Type(m.group(1), m.group(2), m.group(3) <> '') 238 239 elif line.startswith('//func'): 240 # //func name(a1 t1, a2 t2, ..., aN tN) ty = x[i] 241 m = re.search(r'^//func\s+(\w+)[(]([\w\s,*]*)[)]\s*([\w*]*)\s*=\s*(\w+)\s*\[\s*(\w+)\s*\]\s*$', line) 242 if m == None: 243 raise Exception("Malformed function: " + line) 244 func = Func(m.group(1), self.parseArgs(m.group(2), line), self.typeof(m.group(3)), m.group(4), m.group(5)) 245 self.updateStructReturn(func) 246 self.functions.append(func) 247 248 elif line.startswith('//callback'): 249 # //callback name(a1 t1, a2 t2, ..., aN tN) ty 250 m = re.search(r'^//callback\s+(\w+)[(]([\w\s,*]*)[)]\s*([\w*]*)\s*$', line) 251 if m == None: 252 raise Exception("Malformed function: " + line) 253 func = Func(m.group(1), self.parseArgs(m.group(2), line), self.typeof(m.group(3)), None, None) 254 self.callbacks.append(func) 255 256 # compile returns the dictionary used by the templates. 257 def compile(self): 258 enums = [] 259 for ty in self.enums.values(): 260 enums.append(ty) 261 consts = [] 262 for c, v in self.consts.items(): 263 ty = self.findEnumType(c) 264 if ty: 265 consts.append((c, ty, v)) 266 return { 'callbacks': self.callbacks, 267 'functions': self.functions, 268 'consts': consts, 269 'enums': enums, 270 'types': self.types, 271 } 272 273 # printTemplates expands and prints all template files. 274 def printTemplates(self, templates): 275 state = self.compile() 276 for file in templates: 277 text = '' 278 with open(file) as f: 279 text = f.read() 280 text = text.decode('utf-8') 281 tmpl = Template(text) 282 tmpl.globals['framesize'] = self.framesize 283 tmpl.globals['max'] = max 284 tmpl.globals['align'] = align 285 text = tmpl.render(**state) 286 print text.encode('utf-8') 287 288 # Preprocess the input files. 289 def main(): 290 args = parser.parse_args() 291 print '//', string.join(sys.argv) 292 print '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT' 293 print 294 p = Processor() 295 if args.include != None: 296 for dir in args.include: 297 p.scanIncludeFiles(glob.glob(dir + '/*.h')) 298 p.scanArch(args.template) 299 p.scanConfig(args.template) 300 p.printTemplates(args.template) 301 302 # This is the standard boilerplate that calls the main() function. 303 if __name__ == '__main__': 304 main()