Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 3 | # Copyright 2012 the V8 project authors. All rights reserved. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 4 | # Redistribution and use in source and binary forms, with or without |
| 5 | # modification, are permitted provided that the following conditions are |
| 6 | # met: |
| 7 | # |
| 8 | # * Redistributions of source code must retain the above copyright |
| 9 | # notice, this list of conditions and the following disclaimer. |
| 10 | # * Redistributions in binary form must reproduce the above |
| 11 | # copyright notice, this list of conditions and the following |
| 12 | # disclaimer in the documentation and/or other materials provided |
| 13 | # with the distribution. |
| 14 | # * Neither the name of Google Inc. nor the names of its |
| 15 | # contributors may be used to endorse or promote products derived |
| 16 | # from this software without specific prior written permission. |
| 17 | # |
| 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | |
| 30 | # This is a utility for converting JavaScript source code into C-style |
| 31 | # char arrays. It is used for embedded JavaScript code in the V8 |
| 32 | # library. |
| 33 | |
| 34 | import os, re, sys, string |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 35 | import optparse |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 36 | import jsmin |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 37 | import bz2 |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 38 | import textwrap |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 39 | |
| 40 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 41 | class Error(Exception): |
| 42 | def __init__(self, msg): |
| 43 | Exception.__init__(self, msg) |
| 44 | |
| 45 | |
| 46 | def ToCArray(byte_sequence): |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 47 | result = [] |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 48 | for chr in byte_sequence: |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 49 | result.append(str(ord(chr))) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 50 | joined = ", ".join(result) |
| 51 | return textwrap.fill(joined, 80) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 52 | |
| 53 | |
| 54 | def RemoveCommentsAndTrailingWhitespace(lines): |
| 55 | lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments |
| 56 | lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments. |
| 57 | lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace |
| 58 | return lines |
| 59 | |
| 60 | |
| 61 | def ReadFile(filename): |
| 62 | file = open(filename, "rt") |
| 63 | try: |
| 64 | lines = file.read() |
| 65 | finally: |
| 66 | file.close() |
| 67 | return lines |
| 68 | |
| 69 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 70 | EVAL_PATTERN = re.compile(r'\beval\s*\(') |
| 71 | WITH_PATTERN = re.compile(r'\bwith\s*\(') |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 72 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 73 | def Validate(lines): |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 74 | # Because of simplified context setup, eval and with is not |
| 75 | # allowed in the natives files. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 76 | if EVAL_PATTERN.search(lines): |
| 77 | raise Error("Eval disallowed in natives.") |
| 78 | if WITH_PATTERN.search(lines): |
| 79 | raise Error("With statements disallowed in natives.") |
| 80 | |
| 81 | # Pass lines through unchanged. |
| 82 | return lines |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 83 | |
| 84 | |
| 85 | def ExpandConstants(lines, constants): |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 86 | for key, value in constants: |
| 87 | lines = key.sub(str(value), lines) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 88 | return lines |
| 89 | |
| 90 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 91 | def ExpandMacroDefinition(lines, pos, name_pattern, macro, expander): |
| 92 | pattern_match = name_pattern.search(lines, pos) |
| 93 | while pattern_match is not None: |
| 94 | # Scan over the arguments |
| 95 | height = 1 |
| 96 | start = pattern_match.start() |
| 97 | end = pattern_match.end() |
| 98 | assert lines[end - 1] == '(' |
| 99 | last_match = end |
| 100 | arg_index = [0] # Wrap state into array, to work around Python "scoping" |
| 101 | mapping = { } |
| 102 | def add_arg(str): |
| 103 | # Remember to expand recursively in the arguments |
| 104 | replacement = expander(str.strip()) |
| 105 | mapping[macro.args[arg_index[0]]] = replacement |
| 106 | arg_index[0] += 1 |
| 107 | while end < len(lines) and height > 0: |
| 108 | # We don't count commas at higher nesting levels. |
| 109 | if lines[end] == ',' and height == 1: |
| 110 | add_arg(lines[last_match:end]) |
| 111 | last_match = end + 1 |
| 112 | elif lines[end] in ['(', '{', '[']: |
| 113 | height = height + 1 |
| 114 | elif lines[end] in [')', '}', ']']: |
| 115 | height = height - 1 |
| 116 | end = end + 1 |
| 117 | # Remember to add the last match. |
| 118 | add_arg(lines[last_match:end-1]) |
| 119 | result = macro.expand(mapping) |
| 120 | # Replace the occurrence of the macro with the expansion |
| 121 | lines = lines[:start] + result + lines[end:] |
| 122 | pattern_match = name_pattern.search(lines, start + len(result)) |
| 123 | return lines |
| 124 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 125 | def ExpandMacros(lines, macros): |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 126 | # We allow macros to depend on the previously declared macros, but |
| 127 | # we don't allow self-dependecies or recursion. |
| 128 | for name_pattern, macro in reversed(macros): |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 129 | def expander(s): |
| 130 | return ExpandMacros(s, macros) |
| 131 | lines = ExpandMacroDefinition(lines, 0, name_pattern, macro, expander) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 132 | return lines |
| 133 | |
| 134 | class TextMacro: |
| 135 | def __init__(self, args, body): |
| 136 | self.args = args |
| 137 | self.body = body |
| 138 | def expand(self, mapping): |
| 139 | result = self.body |
| 140 | for key, value in mapping.items(): |
| 141 | result = result.replace(key, value) |
| 142 | return result |
| 143 | |
| 144 | class PythonMacro: |
| 145 | def __init__(self, args, fun): |
| 146 | self.args = args |
| 147 | self.fun = fun |
| 148 | def expand(self, mapping): |
| 149 | args = [] |
| 150 | for arg in self.args: |
| 151 | args.append(mapping[arg]) |
| 152 | return str(self.fun(*args)) |
| 153 | |
| 154 | CONST_PATTERN = re.compile(r'^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$') |
| 155 | MACRO_PATTERN = re.compile(r'^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$') |
| 156 | PYTHON_MACRO_PATTERN = re.compile(r'^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$') |
| 157 | |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 158 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 159 | def ReadMacros(lines): |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 160 | constants = [] |
| 161 | macros = [] |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 162 | for line in lines.split('\n'): |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 163 | hash = line.find('#') |
| 164 | if hash != -1: line = line[:hash] |
| 165 | line = line.strip() |
| 166 | if len(line) is 0: continue |
| 167 | const_match = CONST_PATTERN.match(line) |
| 168 | if const_match: |
| 169 | name = const_match.group(1) |
| 170 | value = const_match.group(2).strip() |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 171 | constants.append((re.compile("\\b%s\\b" % name), value)) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 172 | else: |
| 173 | macro_match = MACRO_PATTERN.match(line) |
| 174 | if macro_match: |
| 175 | name = macro_match.group(1) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 176 | args = [match.strip() for match in macro_match.group(2).split(',')] |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 177 | body = macro_match.group(3).strip() |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 178 | macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body))) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 179 | else: |
| 180 | python_match = PYTHON_MACRO_PATTERN.match(line) |
| 181 | if python_match: |
| 182 | name = python_match.group(1) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 183 | args = [match.strip() for match in python_match.group(2).split(',')] |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 184 | body = python_match.group(3).strip() |
| 185 | fun = eval("lambda " + ",".join(args) + ': ' + body) |
Leon Clarke | ac95265 | 2010-07-15 11:15:24 +0100 | [diff] [blame] | 186 | macros.append((re.compile("\\b%s\\(" % name), PythonMacro(args, fun))) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 187 | else: |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 188 | raise Error("Illegal line: " + line) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 189 | return (constants, macros) |
| 190 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 191 | INLINE_MACRO_PATTERN = re.compile(r'macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\n') |
| 192 | INLINE_MACRO_END_PATTERN = re.compile(r'endmacro\s*\n') |
| 193 | |
| 194 | def ExpandInlineMacros(lines): |
| 195 | pos = 0 |
| 196 | while True: |
| 197 | macro_match = INLINE_MACRO_PATTERN.search(lines, pos) |
| 198 | if macro_match is None: |
| 199 | # no more macros |
| 200 | return lines |
| 201 | name = macro_match.group(1) |
| 202 | args = [match.strip() for match in macro_match.group(2).split(',')] |
| 203 | end_macro_match = INLINE_MACRO_END_PATTERN.search(lines, macro_match.end()); |
| 204 | if end_macro_match is None: |
| 205 | raise Error("Macro %s unclosed" % name) |
| 206 | body = lines[macro_match.end():end_macro_match.start()] |
| 207 | |
| 208 | # remove macro definition |
| 209 | lines = lines[:macro_match.start()] + lines[end_macro_match.end():] |
| 210 | name_pattern = re.compile("\\b%s\\(" % name) |
| 211 | macro = TextMacro(args, body) |
| 212 | |
| 213 | # advance position to where the macro defintion was |
| 214 | pos = macro_match.start() |
| 215 | |
| 216 | def non_expander(s): |
| 217 | return s |
| 218 | lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander) |
| 219 | |
| 220 | |
| 221 | INLINE_CONSTANT_PATTERN = re.compile(r'const\s+([a-zA-Z0-9_]+)\s*=\s*([^;\n]+)[;\n]') |
| 222 | |
| 223 | def ExpandInlineConstants(lines): |
| 224 | pos = 0 |
| 225 | while True: |
| 226 | const_match = INLINE_CONSTANT_PATTERN.search(lines, pos) |
| 227 | if const_match is None: |
| 228 | # no more constants |
| 229 | return lines |
| 230 | name = const_match.group(1) |
| 231 | replacement = const_match.group(2) |
| 232 | name_pattern = re.compile("\\b%s\\b" % name) |
| 233 | |
| 234 | # remove constant definition and replace |
| 235 | lines = (lines[:const_match.start()] + |
| 236 | re.sub(name_pattern, replacement, lines[const_match.end():])) |
| 237 | |
| 238 | # advance position to where the constant defintion was |
| 239 | pos = const_match.start() |
| 240 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 241 | |
| 242 | HEADER_TEMPLATE = """\ |
Ben Murdoch | 257744e | 2011-11-30 15:57:28 +0000 | [diff] [blame] | 243 | // Copyright 2011 Google Inc. All Rights Reserved. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 244 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 245 | // This file was generated from .js source files by GYP. If you |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 246 | // want to make changes to this file you should either change the |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 247 | // javascript source files or the GYP script. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 248 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 249 | #include "src/v8.h" |
| 250 | #include "src/natives.h" |
| 251 | #include "src/utils.h" |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 252 | |
| 253 | namespace v8 { |
| 254 | namespace internal { |
| 255 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 256 | %(sources_declaration)s\ |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 257 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 258 | template <> |
| 259 | int NativesCollection<%(type)s>::GetBuiltinsCount() { |
| 260 | return %(builtin_count)i; |
| 261 | } |
| 262 | |
| 263 | template <> |
Andrei Popescu | 3100271 | 2010-02-23 13:46:05 +0000 | [diff] [blame] | 264 | int NativesCollection<%(type)s>::GetDebuggerCount() { |
| 265 | return %(debugger_count)i; |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | template <> |
| 269 | int NativesCollection<%(type)s>::GetIndex(const char* name) { |
| 270 | %(get_index_cases)s\ |
| 271 | return -1; |
| 272 | } |
| 273 | |
| 274 | template <> |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 275 | Vector<const char> NativesCollection<%(type)s>::GetScriptSource(int index) { |
| 276 | %(get_script_source_cases)s\ |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 277 | return Vector<const char>("", 0); |
| 278 | } |
| 279 | |
| 280 | template <> |
| 281 | Vector<const char> NativesCollection<%(type)s>::GetScriptName(int index) { |
| 282 | %(get_script_name_cases)s\ |
| 283 | return Vector<const char>("", 0); |
| 284 | } |
| 285 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 286 | template <> |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 287 | Vector<const char> NativesCollection<%(type)s>::GetScriptsSource() { |
| 288 | return Vector<const char>(sources, %(total_length)i); |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 289 | } |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 290 | } // internal |
| 291 | } // v8 |
| 292 | """ |
| 293 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 294 | SOURCES_DECLARATION = """\ |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 295 | static const char sources[] = { %s }; |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 296 | """ |
| 297 | |
| 298 | |
| 299 | GET_INDEX_CASE = """\ |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 300 | if (strcmp(name, "%(id)s") == 0) return %(i)i; |
| 301 | """ |
| 302 | |
| 303 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 304 | GET_SCRIPT_SOURCE_CASE = """\ |
| 305 | if (index == %(i)i) return Vector<const char>(sources + %(offset)i, %(source_length)i); |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 306 | """ |
| 307 | |
| 308 | |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 309 | GET_SCRIPT_NAME_CASE = """\ |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 310 | if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i); |
| 311 | """ |
| 312 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 313 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 314 | def BuildFilterChain(macro_filename): |
| 315 | """Build the chain of filter functions to be applied to the sources. |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 316 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 317 | Args: |
| 318 | macro_filename: Name of the macro file, if any. |
Ben Murdoch | 3fb3ca8 | 2011-12-02 17:19:32 +0000 | [diff] [blame] | 319 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 320 | Returns: |
| 321 | A function (string -> string) that reads a source file and processes it. |
| 322 | """ |
| 323 | filter_chain = [ReadFile] |
| 324 | |
| 325 | if macro_filename: |
| 326 | (consts, macros) = ReadMacros(ReadFile(macro_filename)) |
| 327 | filter_chain.append(lambda l: ExpandConstants(l, consts)) |
| 328 | filter_chain.append(lambda l: ExpandMacros(l, macros)) |
| 329 | |
| 330 | filter_chain.extend([ |
| 331 | RemoveCommentsAndTrailingWhitespace, |
| 332 | ExpandInlineMacros, |
| 333 | ExpandInlineConstants, |
| 334 | Validate, |
| 335 | jsmin.JavaScriptMinifier().JSMinify |
| 336 | ]) |
| 337 | |
| 338 | def chain(f1, f2): |
| 339 | return lambda x: f2(f1(x)) |
| 340 | |
| 341 | return reduce(chain, filter_chain) |
| 342 | |
| 343 | |
| 344 | class Sources: |
| 345 | def __init__(self): |
| 346 | self.names = [] |
| 347 | self.modules = [] |
| 348 | self.is_debugger_id = [] |
| 349 | |
| 350 | |
| 351 | def IsDebuggerFile(filename): |
| 352 | return filename.endswith("-debugger.js") |
| 353 | |
| 354 | def IsMacroFile(filename): |
| 355 | return filename.endswith("macros.py") |
| 356 | |
| 357 | |
| 358 | def PrepareSources(source_files): |
| 359 | """Read, prepare and assemble the list of source files. |
| 360 | |
| 361 | Args: |
| 362 | sources: List of Javascript-ish source files. A file named macros.py |
| 363 | will be treated as a list of macros. |
| 364 | |
| 365 | Returns: |
| 366 | An instance of Sources. |
| 367 | """ |
| 368 | macro_file = None |
| 369 | macro_files = filter(IsMacroFile, source_files) |
| 370 | assert len(macro_files) in [0, 1] |
| 371 | if macro_files: |
| 372 | source_files.remove(macro_files[0]) |
| 373 | macro_file = macro_files[0] |
| 374 | |
| 375 | filters = BuildFilterChain(macro_file) |
| 376 | |
| 377 | # Sort 'debugger' sources first. |
| 378 | source_files = sorted(source_files, |
| 379 | lambda l,r: IsDebuggerFile(r) - IsDebuggerFile(l)) |
| 380 | |
| 381 | result = Sources() |
| 382 | for source in source_files: |
| 383 | try: |
| 384 | lines = filters(source) |
| 385 | except Error as e: |
| 386 | raise Error("In file %s:\n%s" % (source, str(e))) |
| 387 | |
| 388 | result.modules.append(lines); |
| 389 | |
| 390 | is_debugger = IsDebuggerFile(source) |
| 391 | result.is_debugger_id.append(is_debugger); |
| 392 | |
| 393 | name = os.path.basename(source)[:-3] |
| 394 | result.names.append(name if not is_debugger else name[:-9]); |
| 395 | return result |
| 396 | |
| 397 | |
| 398 | def BuildMetadata(sources, source_bytes, native_type): |
| 399 | """Build the meta data required to generate a libaries file. |
| 400 | |
| 401 | Args: |
| 402 | sources: A Sources instance with the prepared sources. |
| 403 | source_bytes: A list of source bytes. |
| 404 | (The concatenation of all sources; might be compressed.) |
| 405 | native_type: The parameter for the NativesCollection template. |
| 406 | |
| 407 | Returns: |
| 408 | A dictionary for use with HEADER_TEMPLATE. |
| 409 | """ |
| 410 | total_length = len(source_bytes) |
| 411 | raw_sources = "".join(sources.modules) |
| 412 | |
| 413 | # The sources are expected to be ASCII-only. |
| 414 | assert not filter(lambda value: ord(value) >= 128, raw_sources) |
| 415 | |
| 416 | # Loop over modules and build up indices into the source blob: |
| 417 | get_index_cases = [] |
| 418 | get_script_name_cases = [] |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 419 | get_script_source_cases = [] |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 420 | offset = 0 |
| 421 | for i in xrange(len(sources.modules)): |
| 422 | native_name = "native %s.js" % sources.names[i] |
| 423 | d = { |
| 424 | "i": i, |
| 425 | "id": sources.names[i], |
| 426 | "name": native_name, |
| 427 | "length": len(native_name), |
| 428 | "offset": offset, |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 429 | "source_length": len(sources.modules[i]), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 430 | } |
| 431 | get_index_cases.append(GET_INDEX_CASE % d) |
| 432 | get_script_name_cases.append(GET_SCRIPT_NAME_CASE % d) |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 433 | get_script_source_cases.append(GET_SCRIPT_SOURCE_CASE % d) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 434 | offset += len(sources.modules[i]) |
| 435 | assert offset == len(raw_sources) |
| 436 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 437 | metadata = { |
| 438 | "builtin_count": len(sources.modules), |
| 439 | "debugger_count": sum(sources.is_debugger_id), |
| 440 | "sources_declaration": SOURCES_DECLARATION % ToCArray(source_bytes), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 441 | "total_length": total_length, |
| 442 | "get_index_cases": "".join(get_index_cases), |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 443 | "get_script_source_cases": "".join(get_script_source_cases), |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 444 | "get_script_name_cases": "".join(get_script_name_cases), |
| 445 | "type": native_type, |
| 446 | } |
| 447 | return metadata |
| 448 | |
| 449 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 450 | def PutInt(blob_file, value): |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 451 | assert(value >= 0 and value < (1 << 28)) |
| 452 | if (value < 1 << 6): |
| 453 | size = 1 |
| 454 | elif (value < 1 << 14): |
| 455 | size = 2 |
| 456 | elif (value < 1 << 22): |
| 457 | size = 3 |
| 458 | else: |
| 459 | size = 4 |
| 460 | value_with_length = (value << 2) | (size - 1) |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 461 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 462 | byte_sequence = bytearray() |
| 463 | for i in xrange(size): |
| 464 | byte_sequence.append(value_with_length & 255) |
| 465 | value_with_length >>= 8; |
| 466 | blob_file.write(byte_sequence) |
| 467 | |
| 468 | |
| 469 | def PutStr(blob_file, value): |
| 470 | PutInt(blob_file, len(value)); |
| 471 | blob_file.write(value); |
| 472 | |
| 473 | |
| 474 | def WriteStartupBlob(sources, startup_blob): |
| 475 | """Write a startup blob, as expected by V8 Initialize ... |
| 476 | TODO(vogelheim): Add proper method name. |
| 477 | |
| 478 | Args: |
| 479 | sources: A Sources instance with the prepared sources. |
| 480 | startup_blob_file: Name of file to write the blob to. |
| 481 | """ |
| 482 | output = open(startup_blob, "wb") |
| 483 | |
| 484 | debug_sources = sum(sources.is_debugger_id); |
| 485 | PutInt(output, debug_sources) |
| 486 | for i in xrange(debug_sources): |
| 487 | PutStr(output, sources.names[i]); |
| 488 | PutStr(output, sources.modules[i]); |
| 489 | |
| 490 | PutInt(output, len(sources.names) - debug_sources) |
| 491 | for i in xrange(debug_sources, len(sources.names)): |
| 492 | PutStr(output, sources.names[i]); |
| 493 | PutStr(output, sources.modules[i]); |
| 494 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 495 | output.close() |
| 496 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 497 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 498 | def JS2C(source, target, native_type, raw_file, startup_blob): |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 499 | sources = PrepareSources(source) |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 500 | sources_bytes = "".join(sources.modules) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 501 | metadata = BuildMetadata(sources, sources_bytes, native_type) |
| 502 | |
| 503 | # Optionally emit raw file. |
| 504 | if raw_file: |
| 505 | output = open(raw_file, "w") |
| 506 | output.write(sources_bytes) |
| 507 | output.close() |
| 508 | |
| 509 | if startup_blob: |
| 510 | WriteStartupBlob(sources, startup_blob); |
| 511 | |
| 512 | # Emit resulting source file. |
| 513 | output = open(target, "w") |
| 514 | output.write(HEADER_TEMPLATE % metadata) |
| 515 | output.close() |
| 516 | |
| 517 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 518 | def main(): |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 519 | parser = optparse.OptionParser() |
| 520 | parser.add_option("--raw", action="store", |
| 521 | help="file to write the processed sources array to.") |
| 522 | parser.add_option("--startup_blob", action="store", |
| 523 | help="file to write the startup blob to.") |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 524 | parser.set_usage("""js2c out.cc type sources.js ... |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 525 | out.cc: C code to be generated. |
| 526 | type: type parameter for NativesCollection template. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 527 | sources.js: JS internal sources or macros.py.""") |
| 528 | (options, args) = parser.parse_args() |
| 529 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 530 | JS2C(args[2:], args[0], args[1], options.raw, options.startup_blob) |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 531 | |
Steve Block | a7e24c1 | 2009-10-30 11:49:00 +0000 | [diff] [blame] | 532 | |
| 533 | if __name__ == "__main__": |
| 534 | main() |