OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright 2014 the V8 project authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import js2c |
| 7 import os |
| 8 import re |
| 9 import sys |
| 10 |
| 11 FILENAME = "src/runtime.cc" |
| 12 FUNCTION = re.compile("^RUNTIME_FUNCTION\(Runtime_(\w+)") |
| 13 FUNCTIONEND = "}\n" |
| 14 MACRO = re.compile(r"^#define ([^ ]+)\(([^)]*)\) *([^\\]*)\\?\n$") |
| 15 FIRST_WORD = re.compile("^\s*(.*?)[\s({\[]") |
| 16 |
| 17 # Expand these macros, they define further runtime functions. |
| 18 EXPAND_MACROS = [ |
| 19 "BUFFER_VIEW_GETTER", |
| 20 "DATA_VIEW_GETTER", |
| 21 "DATA_VIEW_SETTER", |
| 22 "ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION", |
| 23 "FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION", |
| 24 "RUNTIME_UNARY_MATH", |
| 25 "TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION", |
| 26 ] |
| 27 |
| 28 |
| 29 class Function(object): |
| 30 def __init__(self, match): |
| 31 self.name = match.group(1) |
| 32 |
| 33 |
| 34 class Macro(object): |
| 35 def __init__(self, match): |
| 36 self.name = match.group(1) |
| 37 self.args = [s.strip() for s in match.group(2).split(",")] |
| 38 self.lines = [] |
| 39 self.indentation = 0 |
| 40 self.AddLine(match.group(3)) |
| 41 |
| 42 def AddLine(self, line): |
| 43 if not line: return |
| 44 if not self.lines: |
| 45 # This is the first line, detect indentation. |
| 46 self.indentation = len(line) - len(line.lstrip()) |
| 47 line = line.rstrip("\\\n ") |
| 48 if not line: return |
| 49 assert len(line[:self.indentation].strip()) == 0, \ |
| 50 ("expected whitespace: '%s', full line: '%s'" % |
| 51 (line[:self.indentation], line)) |
| 52 line = line[self.indentation:] |
| 53 if not line: return |
| 54 self.lines.append(line + "\n") |
| 55 |
| 56 def Finalize(self): |
| 57 for arg in self.args: |
| 58 pattern = re.compile(r"(##|\b)%s(##|\b)" % arg) |
| 59 for i in range(len(self.lines)): |
| 60 self.lines[i] = re.sub(pattern, "%%(%s)s" % arg, self.lines[i]) |
| 61 |
| 62 def FillIn(self, arg_values): |
| 63 filler = {} |
| 64 assert len(arg_values) == len(self.args) |
| 65 for i in range(len(self.args)): |
| 66 filler[self.args[i]] = arg_values[i] |
| 67 result = [] |
| 68 for line in self.lines: |
| 69 result.append(line % filler) |
| 70 return result |
| 71 |
| 72 |
| 73 def ReadFileAndExpandMacros(filename): |
| 74 found_macros = {} |
| 75 expanded_lines = [] |
| 76 with open(filename, "r") as f: |
| 77 found_macro = None |
| 78 for line in f: |
| 79 if found_macro is not None: |
| 80 found_macro.AddLine(line) |
| 81 if not line.endswith("\\\n"): |
| 82 found_macro.Finalize() |
| 83 found_macro = None |
| 84 continue |
| 85 |
| 86 match = MACRO.match(line) |
| 87 if match: |
| 88 found_macro = Macro(match) |
| 89 if found_macro.name in EXPAND_MACROS: |
| 90 found_macros[found_macro.name] = found_macro |
| 91 else: |
| 92 found_macro = None |
| 93 continue |
| 94 |
| 95 match = FIRST_WORD.match(line) |
| 96 if match: |
| 97 first_word = match.group(1) |
| 98 if first_word in found_macros: |
| 99 MACRO_CALL = re.compile("%s\(([^)]*)\)" % first_word) |
| 100 match = MACRO_CALL.match(line) |
| 101 assert match |
| 102 args = [s.strip() for s in match.group(1).split(",")] |
| 103 expanded_lines += found_macros[first_word].FillIn(args) |
| 104 continue |
| 105 |
| 106 expanded_lines.append(line) |
| 107 return expanded_lines |
| 108 |
| 109 |
| 110 # Detects runtime functions by parsing FILENAME. |
| 111 def FindRuntimeFunctions(): |
| 112 functions = [] |
| 113 expanded_lines = ReadFileAndExpandMacros(FILENAME) |
| 114 function = None |
| 115 partial_line = "" |
| 116 for line in expanded_lines: |
| 117 # Multi-line definition support, ignoring macros. |
| 118 if line.startswith("RUNTIME_FUNCTION") and not line.endswith("{\n"): |
| 119 if line.endswith("\\\n"): continue |
| 120 partial_line = line.rstrip() |
| 121 continue |
| 122 if partial_line: |
| 123 partial_line += " " + line.strip() |
| 124 if partial_line.endswith("{"): |
| 125 line = partial_line |
| 126 partial_line = "" |
| 127 else: |
| 128 continue |
| 129 |
| 130 match = FUNCTION.match(line) |
| 131 if match: |
| 132 function = Function(match) |
| 133 continue |
| 134 if function is None: continue |
| 135 |
| 136 if line == FUNCTIONEND: |
| 137 if function is not None: |
| 138 functions.append(function) |
| 139 function = None |
| 140 return functions |
| 141 |
| 142 |
| 143 class Builtin(object): |
| 144 def __init__(self, match): |
| 145 self.name = match.group(1) |
| 146 |
| 147 |
| 148 def FindJSNatives(): |
| 149 PATH = "src" |
| 150 fileslist = [] |
| 151 for (root, dirs, files) in os.walk(PATH): |
| 152 for f in files: |
| 153 if f.endswith(".js"): |
| 154 fileslist.append(os.path.join(root, f)) |
| 155 natives = [] |
| 156 regexp = re.compile("^function (\w+)\s*\((.*?)\) {") |
| 157 matches = 0 |
| 158 for filename in fileslist: |
| 159 with open(filename, "r") as f: |
| 160 file_contents = f.read() |
| 161 file_contents = js2c.ExpandInlineMacros(file_contents) |
| 162 lines = file_contents.split("\n") |
| 163 partial_line = "" |
| 164 for line in lines: |
| 165 if line.startswith("function") and not '{' in line: |
| 166 partial_line += line.rstrip() |
| 167 continue |
| 168 if partial_line: |
| 169 partial_line += " " + line.strip() |
| 170 if '{' in line: |
| 171 line = partial_line |
| 172 partial_line = "" |
| 173 else: |
| 174 continue |
| 175 match = regexp.match(line) |
| 176 if match: |
| 177 natives.append(Builtin(match)) |
| 178 return natives |
| 179 |
| 180 |
| 181 def Main(): |
| 182 functions = FindRuntimeFunctions() |
| 183 natives = FindJSNatives() |
| 184 errors = 0 |
| 185 runtime_map = {} |
| 186 for f in functions: |
| 187 runtime_map[f.name] = 1 |
| 188 for b in natives: |
| 189 if b.name in runtime_map: |
| 190 print("JS_Native/Runtime_Function name clash: %s" % b.name) |
| 191 errors += 1 |
| 192 |
| 193 if errors > 0: |
| 194 return 1 |
| 195 print("Runtime/Natives name clashes: checked %d/%d functions, all good." % |
| 196 (len(functions), len(natives))) |
| 197 return 0 |
| 198 |
| 199 |
| 200 if __name__ == "__main__": |
| 201 sys.exit(Main()) |
OLD | NEW |