1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5from __future__ import absolute_import 6import re 7import textwrap 8import string 9 10comment_re = re.compile(r"//[^\n]*\n|/\*.*\*/", re.S) 11decl_re = re.compile( 12 r"""^(.+)\s+ # type 13 (\w+)\s* # name 14 (?:\((.*)\))?$ # optional param tys 15 """, 16 re.X | re.S, 17) 18 19 20def read_decls(filename): 21 """Parse & yield C-style decls from an input file""" 22 with open(filename, "r") as fd: 23 # Strip comments from the source text. 24 text = comment_re.sub("", fd.read()) 25 26 # Parse individual declarations. 27 raw_decls = [d.strip() for d in text.split(";") if d.strip()] 28 for raw in raw_decls: 29 match = decl_re.match(raw) 30 if match is None: 31 raise "Invalid decl: %s" % raw 32 33 ty, name, params = match.groups() 34 if params is not None: 35 params = [a.strip() for a in params.split(",") if a.strip()] 36 yield ty, name, params 37 38 39def generate(fd, consts_path, unicodes_path, template_path, compiler): 40 # Parse the template 41 with open(template_path, "r") as template_fd: 42 template = string.Template(template_fd.read()) 43 44 decls = "" 45 46 # Each constant should be saved to a temporary, and then re-assigned to a 47 # constant with the correct name, allowing the value to be determined by 48 # the actual definition. 49 for ty, name, args in read_decls(consts_path): 50 assert args is None, "parameters in const decl!" 51 52 decls += textwrap.dedent( 53 """ 54 #ifdef {name} 55 constexpr {ty} _tmp_{name} = {name}; 56 #undef {name} 57 constexpr {ty} {name} = _tmp_{name}; 58 #endif 59 """.format( 60 ty=ty, name=name 61 ) 62 ) 63 64 # Each unicode declaration defines a static inline function with the 65 # correct types which calls the 'A' or 'W'-suffixed versions of the 66 # function. Full types are required here to ensure that '0' to 'nullptr' 67 # coersions are preserved. 68 for ty, name, args in read_decls(unicodes_path): 69 assert args is not None, "argument list required for unicode decl" 70 71 # Parameter & argument string list 72 params = ", ".join("%s a%d" % (ty, i) for i, ty in enumerate(args)) 73 args = ", ".join("a%d" % i for i in range(len(args))) 74 75 decls += textwrap.dedent( 76 """ 77 #ifdef {name} 78 #undef {name} 79 static inline {ty} WINAPI 80 {name}({params}) 81 #ifdef UNICODE 82 {{ 83 return {name}W({args}); 84 }} 85 #else 86 = delete; 87 #endif 88 #endif 89 """.format( 90 ty=ty, name=name, params=params, args=args 91 ) 92 ) 93 94 # Write out the resulting file 95 fd.write(template.substitute(decls=decls)) 96