OLD | NEW |
(Empty) | |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """Utility functions (file reading, simple IDL parsing by regexes) for IDL build
.""" |
| 6 |
| 7 import os |
| 8 import cPickle as pickle |
| 9 import re |
| 10 import string |
| 11 |
| 12 |
| 13 class IdlBadFilenameError(Exception): |
| 14 """Raised if an IDL filename disagrees with the interface name in the file."
"" |
| 15 pass |
| 16 |
| 17 |
| 18 ################################################################################ |
| 19 # Basic file reading/writing |
| 20 ################################################################################ |
| 21 |
| 22 def get_file_contents(filename): |
| 23 with open(filename) as f: |
| 24 return ''.join(f.readlines()) |
| 25 |
| 26 |
| 27 def write_file(new_lines, destination_filename, only_if_changed): |
| 28 if only_if_changed and os.path.isfile(destination_filename): |
| 29 with open(destination_filename) as destination_file: |
| 30 if destination_file.readlines() == new_lines: |
| 31 return |
| 32 with open(destination_filename, 'w') as destination_file: |
| 33 destination_file.write(''.join(new_lines)) |
| 34 |
| 35 |
| 36 def write_pickle_file(pickle_filename, data, only_if_changed): |
| 37 if only_if_changed and os.path.isfile(pickle_filename): |
| 38 with open(pickle_filename) as pickle_file: |
| 39 if pickle.load(pickle_file) == data: |
| 40 return |
| 41 with open(pickle_filename, 'w') as pickle_file: |
| 42 pickle.dump(data, pickle_file) |
| 43 |
| 44 |
| 45 ################################################################################ |
| 46 # IDL parsing |
| 47 # |
| 48 # We use regular expressions for parsing; this is incorrect (Web IDL is not a |
| 49 # regular language), but simple and sufficient in practice. |
| 50 # Leading and trailing context (e.g. following '{') used to avoid false matches. |
| 51 ################################################################################ |
| 52 |
| 53 def get_partial_interface_name_from_idl(file_contents): |
| 54 match = re.search(r'partial\s+interface\s+(\w+)\s*{', file_contents) |
| 55 return match and match.group(1) |
| 56 |
| 57 |
| 58 def get_implemented_interfaces_from_idl(file_contents, interface_name): |
| 59 # Rule is: identifier-A implements identifier-B; |
| 60 # http://www.w3.org/TR/WebIDL/#idl-implements-statements |
| 61 def get_implemented(left_identifier, right_identifier): |
| 62 # identifier-A must be the current interface |
| 63 if left_identifier != interface_name: |
| 64 raise IdlBadFilenameError("Identifier on the left of the 'implements
' statement should be %s in %s.idl, but found %s" % (interface_name, interface_n
ame, left_identifier)) |
| 65 return right_identifier |
| 66 |
| 67 implements_re = (r'^\s*' |
| 68 r'(\w+)\s+' |
| 69 r'implements\s+' |
| 70 r'(\w+)\s*' |
| 71 r';') |
| 72 implements_matches = re.finditer(implements_re, file_contents, re.MULTILINE) |
| 73 implements_pairs = [(match.group(1), match.group(2)) |
| 74 for match in implements_matches] |
| 75 return [get_implemented(left, right) for left, right in implements_pairs] |
| 76 |
| 77 |
| 78 def is_callback_interface_from_idl(file_contents): |
| 79 match = re.search(r'callback\s+interface\s+\w+\s*{', file_contents) |
| 80 return bool(match) |
| 81 |
| 82 |
| 83 def get_parent_interface(file_contents): |
| 84 match = re.search(r'interface\s+' |
| 85 r'\w+\s*' |
| 86 r':\s*(\w+)\s*' |
| 87 r'{', |
| 88 file_contents) |
| 89 return match and match.group(1) |
| 90 |
| 91 |
| 92 def get_interface_extended_attributes_from_idl(file_contents): |
| 93 match = re.search(r'\[(.*)\]\s*' |
| 94 r'((callback|partial)\s+)?' |
| 95 r'(interface|exception)\s+' |
| 96 r'\w+\s*' |
| 97 r'(:\s*\w+\s*)?' |
| 98 r'{', |
| 99 file_contents, flags=re.DOTALL) |
| 100 if not match: |
| 101 return {} |
| 102 # Strip comments |
| 103 # re.compile needed b/c Python 2.6 doesn't support flags in re.sub |
| 104 single_line_comment_re = re.compile(r'//.*$', flags=re.MULTILINE) |
| 105 block_comment_re = re.compile(r'/\*.*?\*/', flags=re.MULTILINE | re.DOTALL) |
| 106 extended_attributes_string = re.sub(single_line_comment_re, '', match.group(
1)) |
| 107 extended_attributes_string = re.sub(block_comment_re, '', extended_attribute
s_string) |
| 108 extended_attributes = {} |
| 109 # FIXME: this splitting is WRONG: it fails on ExtendedAttributeArgList like |
| 110 # 'NamedConstructor=Foo(a, b)' |
| 111 parts = [extended_attribute.strip() |
| 112 for extended_attribute in extended_attributes_string.split(',') |
| 113 # Discard empty parts, which may exist due to trailing comma |
| 114 if extended_attribute.strip()] |
| 115 for part in parts: |
| 116 name, _, value = map(string.strip, part.partition('=')) |
| 117 extended_attributes[name] = value |
| 118 return extended_attributes |
| 119 |
| 120 |
| 121 def get_put_forward_interfaces_from_idl(file_contents): |
| 122 put_forwards_pattern = (r'\[[^\]]*PutForwards=[^\]]*\]\s+' |
| 123 r'readonly\s+' |
| 124 r'attribute\s+' |
| 125 r'(\w+)') |
| 126 return sorted(set(match.group(1) |
| 127 for match in re.finditer(put_forwards_pattern, |
| 128 file_contents, |
| 129 flags=re.DOTALL))) |
OLD | NEW |