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