OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
6 # met: | 6 # met: |
7 # | 7 # |
8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
(...skipping 14 matching lines...) Expand all Loading... |
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 # This is a utility for converting JavaScript source code into C-style | 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 | 31 # char arrays. It is used for embedded JavaScript code in the V8 |
32 # library. | 32 # library. |
33 | 33 |
34 import os, re, sys, string | 34 import os, re, sys, string |
| 35 import optparse |
35 import jsmin | 36 import jsmin |
36 import bz2 | 37 import bz2 |
| 38 import textwrap |
37 | 39 |
38 | 40 |
39 def ToCAsciiArray(lines): | 41 class Error(Exception): |
40 result = [] | 42 def __init__(self, msg): |
41 for chr in lines: | 43 Exception.__init__(self, msg) |
42 value = ord(chr) | |
43 assert value < 128 | |
44 result.append(str(value)) | |
45 return ", ".join(result) | |
46 | 44 |
47 | 45 |
48 def ToCArray(lines): | 46 def ToCArray(byte_sequence): |
49 result = [] | 47 result = [] |
50 for chr in lines: | 48 for chr in byte_sequence: |
51 result.append(str(ord(chr))) | 49 result.append(str(ord(chr))) |
52 return ", ".join(result) | 50 joined = ", ".join(result) |
| 51 return textwrap.fill(joined, 80) |
53 | 52 |
54 | 53 |
55 def RemoveCommentsAndTrailingWhitespace(lines): | 54 def RemoveCommentsAndTrailingWhitespace(lines): |
56 lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments | 55 lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments |
57 lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments. | 56 lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments. |
58 lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace | 57 lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace |
59 return lines | 58 return lines |
60 | 59 |
61 | 60 |
62 def ReadFile(filename): | 61 def ReadFile(filename): |
63 file = open(filename, "rt") | 62 file = open(filename, "rt") |
64 try: | 63 try: |
65 lines = file.read() | 64 lines = file.read() |
66 finally: | 65 finally: |
67 file.close() | 66 file.close() |
68 return lines | 67 return lines |
69 | 68 |
70 | 69 |
71 def ReadLines(filename): | |
72 result = [] | |
73 for line in open(filename, "rt"): | |
74 if '#' in line: | |
75 line = line[:line.index('#')] | |
76 line = line.strip() | |
77 if len(line) > 0: | |
78 result.append(line) | |
79 return result | |
80 | |
81 | |
82 def LoadConfigFrom(name): | |
83 import ConfigParser | |
84 config = ConfigParser.ConfigParser() | |
85 config.read(name) | |
86 return config | |
87 | |
88 | |
89 def ParseValue(string): | |
90 string = string.strip() | |
91 if string.startswith('[') and string.endswith(']'): | |
92 return string.lstrip('[').rstrip(']').split() | |
93 else: | |
94 return string | |
95 | |
96 | |
97 EVAL_PATTERN = re.compile(r'\beval\s*\(') | 70 EVAL_PATTERN = re.compile(r'\beval\s*\(') |
98 WITH_PATTERN = re.compile(r'\bwith\s*\(') | 71 WITH_PATTERN = re.compile(r'\bwith\s*\(') |
99 | 72 |
100 | 73 def Validate(lines): |
101 def Validate(lines, file): | |
102 lines = RemoveCommentsAndTrailingWhitespace(lines) | |
103 # Because of simplified context setup, eval and with is not | 74 # Because of simplified context setup, eval and with is not |
104 # allowed in the natives files. | 75 # allowed in the natives files. |
105 eval_match = EVAL_PATTERN.search(lines) | 76 if EVAL_PATTERN.search(lines): |
106 if eval_match: | 77 raise Error("Eval disallowed in natives.") |
107 raise ("Eval disallowed in natives: %s" % file) | 78 if WITH_PATTERN.search(lines): |
108 with_match = WITH_PATTERN.search(lines) | 79 raise Error("With statements disallowed in natives.") |
109 if with_match: | 80 |
110 raise ("With statements disallowed in natives: %s" % file) | 81 # Pass lines through unchanged. |
| 82 return lines |
111 | 83 |
112 | 84 |
113 def ExpandConstants(lines, constants): | 85 def ExpandConstants(lines, constants): |
114 for key, value in constants: | 86 for key, value in constants: |
115 lines = key.sub(str(value), lines) | 87 lines = key.sub(str(value), lines) |
116 return lines | 88 return lines |
117 | 89 |
118 | 90 |
119 def ExpandMacroDefinition(lines, pos, name_pattern, macro, expander): | 91 def ExpandMacroDefinition(lines, pos, name_pattern, macro, expander): |
120 pattern_match = name_pattern.search(lines, pos) | 92 pattern_match = name_pattern.search(lines, pos) |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 return str(self.fun(*args)) | 152 return str(self.fun(*args)) |
181 | 153 |
182 CONST_PATTERN = re.compile(r'^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$') | 154 CONST_PATTERN = re.compile(r'^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$') |
183 MACRO_PATTERN = re.compile(r'^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*
);$') | 155 MACRO_PATTERN = re.compile(r'^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*
);$') |
184 PYTHON_MACRO_PATTERN = re.compile(r'^python\s+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*([^;]*);$') |
185 | 157 |
186 | 158 |
187 def ReadMacros(lines): | 159 def ReadMacros(lines): |
188 constants = [] | 160 constants = [] |
189 macros = [] | 161 macros = [] |
190 for line in lines: | 162 for line in lines.split('\n'): |
191 hash = line.find('#') | 163 hash = line.find('#') |
192 if hash != -1: line = line[:hash] | 164 if hash != -1: line = line[:hash] |
193 line = line.strip() | 165 line = line.strip() |
194 if len(line) is 0: continue | 166 if len(line) is 0: continue |
195 const_match = CONST_PATTERN.match(line) | 167 const_match = CONST_PATTERN.match(line) |
196 if const_match: | 168 if const_match: |
197 name = const_match.group(1) | 169 name = const_match.group(1) |
198 value = const_match.group(2).strip() | 170 value = const_match.group(2).strip() |
199 constants.append((re.compile("\\b%s\\b" % name), value)) | 171 constants.append((re.compile("\\b%s\\b" % name), value)) |
200 else: | 172 else: |
201 macro_match = MACRO_PATTERN.match(line) | 173 macro_match = MACRO_PATTERN.match(line) |
202 if macro_match: | 174 if macro_match: |
203 name = macro_match.group(1) | 175 name = macro_match.group(1) |
204 args = [match.strip() for match in macro_match.group(2).split(',')] | 176 args = [match.strip() for match in macro_match.group(2).split(',')] |
205 body = macro_match.group(3).strip() | 177 body = macro_match.group(3).strip() |
206 macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body))) | 178 macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body))) |
207 else: | 179 else: |
208 python_match = PYTHON_MACRO_PATTERN.match(line) | 180 python_match = PYTHON_MACRO_PATTERN.match(line) |
209 if python_match: | 181 if python_match: |
210 name = python_match.group(1) | 182 name = python_match.group(1) |
211 args = [match.strip() for match in python_match.group(2).split(',')] | 183 args = [match.strip() for match in python_match.group(2).split(',')] |
212 body = python_match.group(3).strip() | 184 body = python_match.group(3).strip() |
213 fun = eval("lambda " + ",".join(args) + ': ' + body) | 185 fun = eval("lambda " + ",".join(args) + ': ' + body) |
214 macros.append((re.compile("\\b%s\\(" % name), PythonMacro(args, fun))) | 186 macros.append((re.compile("\\b%s\\(" % name), PythonMacro(args, fun))) |
215 else: | 187 else: |
216 raise ("Illegal line: " + line) | 188 raise Error("Illegal line: " + line) |
217 return (constants, macros) | 189 return (constants, macros) |
218 | 190 |
219 INLINE_MACRO_PATTERN = re.compile(r'macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\n') | 191 INLINE_MACRO_PATTERN = re.compile(r'macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\n') |
220 INLINE_MACRO_END_PATTERN = re.compile(r'endmacro\s*\n') | 192 INLINE_MACRO_END_PATTERN = re.compile(r'endmacro\s*\n') |
221 | 193 |
222 def ExpandInlineMacros(lines, filename): | 194 def ExpandInlineMacros(lines): |
223 pos = 0 | 195 pos = 0 |
224 while True: | 196 while True: |
225 macro_match = INLINE_MACRO_PATTERN.search(lines, pos) | 197 macro_match = INLINE_MACRO_PATTERN.search(lines, pos) |
226 if macro_match is None: | 198 if macro_match is None: |
227 # no more macros | 199 # no more macros |
228 return lines | 200 return lines |
229 name = macro_match.group(1) | 201 name = macro_match.group(1) |
230 args = [match.strip() for match in macro_match.group(2).split(',')] | 202 args = [match.strip() for match in macro_match.group(2).split(',')] |
231 end_macro_match = INLINE_MACRO_END_PATTERN.search(lines, macro_match.end()); | 203 end_macro_match = INLINE_MACRO_END_PATTERN.search(lines, macro_match.end()); |
232 if end_macro_match is None: | 204 if end_macro_match is None: |
233 raise ("Macro %s unclosed in %s" % (name, filename)) | 205 raise Error("Macro %s unclosed" % name) |
234 body = lines[macro_match.end():end_macro_match.start()] | 206 body = lines[macro_match.end():end_macro_match.start()] |
235 | 207 |
236 # remove macro definition | 208 # remove macro definition |
237 lines = lines[:macro_match.start()] + lines[end_macro_match.end():] | 209 lines = lines[:macro_match.start()] + lines[end_macro_match.end():] |
238 name_pattern = re.compile("\\b%s\\(" % name) | 210 name_pattern = re.compile("\\b%s\\(" % name) |
239 macro = TextMacro(args, body) | 211 macro = TextMacro(args, body) |
240 | 212 |
241 # advance position to where the macro defintion was | 213 # advance position to where the macro defintion was |
242 pos = macro_match.start() | 214 pos = macro_match.start() |
243 | 215 |
244 def non_expander(s): | 216 def non_expander(s): |
245 return s | 217 return s |
246 lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander) | 218 lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander) |
247 | 219 |
| 220 |
248 HEADER_TEMPLATE = """\ | 221 HEADER_TEMPLATE = """\ |
249 // Copyright 2011 Google Inc. All Rights Reserved. | 222 // Copyright 2011 Google Inc. All Rights Reserved. |
250 | 223 |
251 // This file was generated from .js source files by GYP. If you | 224 // This file was generated from .js source files by GYP. If you |
252 // want to make changes to this file you should either change the | 225 // want to make changes to this file you should either change the |
253 // javascript source files or the GYP script. | 226 // javascript source files or the GYP script. |
254 | 227 |
255 #include "v8.h" | 228 #include "v8.h" |
256 #include "natives.h" | 229 #include "natives.h" |
257 #include "utils.h" | 230 #include "utils.h" |
258 | 231 |
259 namespace v8 { | 232 namespace v8 { |
260 namespace internal { | 233 namespace internal { |
261 | 234 |
262 static const byte sources[] = { %(sources_data)s }; | 235 %(sources_declaration)s\ |
263 | 236 |
264 %(raw_sources_declaration)s\ | 237 %(raw_sources_declaration)s\ |
265 | 238 |
266 template <> | 239 template <> |
267 int NativesCollection<%(type)s>::GetBuiltinsCount() { | 240 int NativesCollection<%(type)s>::GetBuiltinsCount() { |
268 return %(builtin_count)i; | 241 return %(builtin_count)i; |
269 } | 242 } |
270 | 243 |
271 template <> | 244 template <> |
272 int NativesCollection<%(type)s>::GetDebuggerCount() { | 245 int NativesCollection<%(type)s>::GetDebuggerCount() { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 template <> | 277 template <> |
305 void NativesCollection<%(type)s>::SetRawScriptsSource(Vector<const char> raw_s
ource) { | 278 void NativesCollection<%(type)s>::SetRawScriptsSource(Vector<const char> raw_s
ource) { |
306 ASSERT(%(raw_total_length)i == raw_source.length()); | 279 ASSERT(%(raw_total_length)i == raw_source.length()); |
307 raw_sources = raw_source.start(); | 280 raw_sources = raw_source.start(); |
308 } | 281 } |
309 | 282 |
310 } // internal | 283 } // internal |
311 } // v8 | 284 } // v8 |
312 """ | 285 """ |
313 | 286 |
| 287 SOURCES_DECLARATION = """\ |
| 288 static const byte sources[] = { %s }; |
| 289 """ |
| 290 |
314 | 291 |
315 RAW_SOURCES_COMPRESSION_DECLARATION = """\ | 292 RAW_SOURCES_COMPRESSION_DECLARATION = """\ |
316 static const char* raw_sources = NULL; | 293 static const char* raw_sources = NULL; |
317 """ | 294 """ |
318 | 295 |
319 | 296 |
320 RAW_SOURCES_DECLARATION = """\ | 297 RAW_SOURCES_DECLARATION = """\ |
321 static const char* raw_sources = reinterpret_cast<const char*>(sources); | 298 static const char* raw_sources = reinterpret_cast<const char*>(sources); |
322 """ | 299 """ |
323 | 300 |
324 | 301 |
325 GET_INDEX_CASE = """\ | 302 GET_INDEX_CASE = """\ |
326 if (strcmp(name, "%(id)s") == 0) return %(i)i; | 303 if (strcmp(name, "%(id)s") == 0) return %(i)i; |
327 """ | 304 """ |
328 | 305 |
329 | 306 |
330 GET_RAW_SCRIPT_SOURCE_CASE = """\ | 307 GET_RAW_SCRIPT_SOURCE_CASE = """\ |
331 if (index == %(i)i) return Vector<const char>(raw_sources + %(offset)i, %(ra
w_length)i); | 308 if (index == %(i)i) return Vector<const char>(raw_sources + %(offset)i, %(ra
w_length)i); |
332 """ | 309 """ |
333 | 310 |
334 | 311 |
335 GET_SCRIPT_NAME_CASE = """\ | 312 GET_SCRIPT_NAME_CASE = """\ |
336 if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i); | 313 if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i); |
337 """ | 314 """ |
338 | 315 |
339 def JS2C(source, target, env): | 316 |
340 ids = [] | 317 def BuildFilterChain(macro_filename): |
341 debugger_ids = [] | 318 """Build the chain of filter functions to be applied to the sources. |
342 modules = [] | 319 |
343 # Locate the macros file name. | 320 Args: |
344 consts = [] | 321 macro_filename: Name of the macro file, if any. |
345 macros = [] | 322 |
346 for s in source: | 323 Returns: |
347 if 'macros.py' == (os.path.split(str(s))[1]): | 324 A function (string -> string) that reads a source file and processes it. |
348 (consts, macros) = ReadMacros(ReadLines(str(s))) | 325 """ |
349 else: | 326 filter_chain = [ReadFile] |
350 modules.append(s) | 327 |
351 | 328 if macro_filename: |
352 minifier = jsmin.JavaScriptMinifier() | 329 (consts, macros) = ReadMacros(ReadFile(macro_filename)) |
353 | 330 filter_chain.append(lambda l: ExpandConstants(l, consts)) |
354 module_offset = 0 | 331 filter_chain.append(lambda l: ExpandMacros(l, macros)) |
355 all_sources = [] | 332 |
356 for module in modules: | 333 filter_chain.extend([ |
357 filename = str(module) | 334 RemoveCommentsAndTrailingWhitespace, |
358 debugger = filename.endswith('-debugger.js') | 335 ExpandInlineMacros, |
359 lines = ReadFile(filename) | 336 Validate, |
360 lines = ExpandConstants(lines, consts) | 337 jsmin.JavaScriptMinifier().JSMinify |
361 lines = ExpandMacros(lines, macros) | 338 ]) |
362 lines = RemoveCommentsAndTrailingWhitespace(lines) | 339 |
363 lines = ExpandInlineMacros(lines, filename) | 340 def chain(f1, f2): |
364 Validate(lines, filename) | 341 return lambda x: f2(f1(x)) |
365 lines = minifier.JSMinify(lines) | 342 |
366 id = (os.path.split(filename)[1])[:-3] | 343 return reduce(chain, filter_chain) |
367 if debugger: id = id[:-9] | 344 |
368 raw_length = len(lines) | 345 |
369 if debugger: | 346 class Sources: |
370 debugger_ids.append((id, raw_length, module_offset)) | 347 def __init__(self): |
371 else: | 348 self.names = [] |
372 ids.append((id, raw_length, module_offset)) | 349 self.modules = [] |
373 all_sources.append(lines) | 350 self.is_debugger_id = [] |
374 module_offset += raw_length | 351 |
375 total_length = raw_total_length = module_offset | 352 |
376 | 353 def IsDebuggerFile(filename): |
377 if env['COMPRESSION'] == 'off': | 354 return filename.endswith("-debugger.js") |
378 raw_sources_declaration = RAW_SOURCES_DECLARATION | 355 |
379 sources_data = ToCAsciiArray("".join(all_sources)) | 356 def IsMacroFile(filename): |
| 357 return filename.endswith("macros.py") |
| 358 |
| 359 |
| 360 def PrepareSources(source_files): |
| 361 """Read, prepare and assemble the list of source files. |
| 362 |
| 363 Args: |
| 364 sources: List of Javascript-ish source files. A file named macros.py |
| 365 will be treated as a list of macros. |
| 366 |
| 367 Returns: |
| 368 An instance of Sources. |
| 369 """ |
| 370 macro_file = None |
| 371 macro_files = filter(IsMacroFile, source_files) |
| 372 assert len(macro_files) in [0, 1] |
| 373 if macro_files: |
| 374 source_files.remove(macro_files[0]) |
| 375 macro_file = macro_files[0] |
| 376 |
| 377 filters = BuildFilterChain(macro_file) |
| 378 |
| 379 # Sort 'debugger' sources first. |
| 380 source_files = sorted(source_files, |
| 381 lambda l,r: IsDebuggerFile(r) - IsDebuggerFile(l)) |
| 382 |
| 383 result = Sources() |
| 384 for source in source_files: |
| 385 try: |
| 386 lines = filters(source) |
| 387 except Error as e: |
| 388 raise Error("In file %s:\n%s" % (source, str(e))) |
| 389 |
| 390 result.modules.append(lines); |
| 391 |
| 392 is_debugger = IsDebuggerFile(source) |
| 393 result.is_debugger_id.append(is_debugger); |
| 394 |
| 395 name = os.path.basename(source)[:-3] |
| 396 result.names.append(name if not is_debugger else name[:-9]); |
| 397 return result |
| 398 |
| 399 |
| 400 def BuildMetadata(sources, source_bytes, native_type, omit): |
| 401 """Build the meta data required to generate a libaries file. |
| 402 |
| 403 Args: |
| 404 sources: A Sources instance with the prepared sources. |
| 405 source_bytes: A list of source bytes. |
| 406 (The concatenation of all sources; might be compressed.) |
| 407 native_type: The parameter for the NativesCollection template. |
| 408 omit: bool, whether we should omit the sources in the output. |
| 409 |
| 410 Returns: |
| 411 A dictionary for use with HEADER_TEMPLATE. |
| 412 """ |
| 413 total_length = len(source_bytes) |
| 414 raw_sources = "".join(sources.modules) |
| 415 |
| 416 # The sources are expected to be ASCII-only. |
| 417 assert not filter(lambda value: ord(value) >= 128, raw_sources) |
| 418 |
| 419 # Loop over modules and build up indices into the source blob: |
| 420 get_index_cases = [] |
| 421 get_script_name_cases = [] |
| 422 get_raw_script_source_cases = [] |
| 423 offset = 0 |
| 424 for i in xrange(len(sources.modules)): |
| 425 native_name = "native %s.js" % sources.names[i] |
| 426 d = { |
| 427 "i": i, |
| 428 "id": sources.names[i], |
| 429 "name": native_name, |
| 430 "length": len(native_name), |
| 431 "offset": offset, |
| 432 "raw_length": len(sources.modules[i]), |
| 433 } |
| 434 get_index_cases.append(GET_INDEX_CASE % d) |
| 435 get_script_name_cases.append(GET_SCRIPT_NAME_CASE % d) |
| 436 get_raw_script_source_cases.append(GET_RAW_SCRIPT_SOURCE_CASE % d) |
| 437 offset += len(sources.modules[i]) |
| 438 assert offset == len(raw_sources) |
| 439 |
| 440 # If we have the raw sources we can declare them accordingly. |
| 441 have_raw_sources = source_bytes == raw_sources and not omit |
| 442 raw_sources_declaration = (RAW_SOURCES_DECLARATION |
| 443 if have_raw_sources else RAW_SOURCES_COMPRESSION_DECLARATION) |
| 444 |
| 445 metadata = { |
| 446 "builtin_count": len(sources.modules), |
| 447 "debugger_count": sum(sources.is_debugger_id), |
| 448 "sources_declaration": SOURCES_DECLARATION % ToCArray(source_bytes), |
| 449 "sources_data": ToCArray(source_bytes) if not omit else "", |
| 450 "raw_sources_declaration": raw_sources_declaration, |
| 451 "raw_total_length": sum(map(len, sources.modules)), |
| 452 "total_length": total_length, |
| 453 "get_index_cases": "".join(get_index_cases), |
| 454 "get_raw_script_source_cases": "".join(get_raw_script_source_cases), |
| 455 "get_script_name_cases": "".join(get_script_name_cases), |
| 456 "type": native_type, |
| 457 } |
| 458 return metadata |
| 459 |
| 460 |
| 461 def CompressMaybe(sources, compression_type): |
| 462 """Take the prepared sources and generate a sequence of bytes. |
| 463 |
| 464 Args: |
| 465 sources: A Sources instance with the prepared sourced. |
| 466 compression_type: string, describing the desired compression. |
| 467 |
| 468 Returns: |
| 469 A sequence of bytes. |
| 470 """ |
| 471 sources_bytes = "".join(sources.modules) |
| 472 if compression_type == "off": |
| 473 return sources_bytes |
| 474 elif compression_type == "bz2": |
| 475 return bz2.compress(sources_bytes) |
380 else: | 476 else: |
381 raw_sources_declaration = RAW_SOURCES_COMPRESSION_DECLARATION | 477 raise Error("Unknown compression type %s." % compression_type) |
382 if env['COMPRESSION'] == 'bz2': | 478 |
383 all_sources = bz2.compress("".join(all_sources)) | 479 |
384 total_length = len(all_sources) | 480 def JS2C(source, target, native_type, compression_type, raw_file, omit): |
385 sources_data = ToCArray(all_sources) | 481 sources = PrepareSources(source) |
386 | 482 sources_bytes = CompressMaybe(sources, compression_type) |
387 # Build debugger support functions | 483 metadata = BuildMetadata(sources, sources_bytes, native_type, omit) |
388 get_index_cases = [ ] | 484 |
389 get_raw_script_source_cases = [ ] | 485 # Optionally emit raw file. |
390 get_script_name_cases = [ ] | 486 if raw_file: |
391 | 487 output = open(raw_file, "w") |
392 i = 0 | 488 output.write(sources_bytes) |
393 for (id, raw_length, module_offset) in debugger_ids + ids: | 489 output.close() |
394 native_name = "native %s.js" % id | 490 |
395 get_index_cases.append(GET_INDEX_CASE % { 'id': id, 'i': i }) | 491 # Emit resulting source file. |
396 get_raw_script_source_cases.append(GET_RAW_SCRIPT_SOURCE_CASE % { | 492 output = open(target, "w") |
397 'offset': module_offset, | 493 output.write(HEADER_TEMPLATE % metadata) |
398 'raw_length': raw_length, | |
399 'i': i | |
400 }) | |
401 get_script_name_cases.append(GET_SCRIPT_NAME_CASE % { | |
402 'name': native_name, | |
403 'length': len(native_name), | |
404 'i': i | |
405 }) | |
406 i = i + 1 | |
407 | |
408 # Emit result | |
409 output = open(str(target[0]), "w") | |
410 output.write(HEADER_TEMPLATE % { | |
411 'builtin_count': len(ids) + len(debugger_ids), | |
412 'debugger_count': len(debugger_ids), | |
413 'sources_data': sources_data, | |
414 'raw_sources_declaration': raw_sources_declaration, | |
415 'raw_total_length': raw_total_length, | |
416 'total_length': total_length, | |
417 'get_index_cases': "".join(get_index_cases), | |
418 'get_raw_script_source_cases': "".join(get_raw_script_source_cases), | |
419 'get_script_name_cases': "".join(get_script_name_cases), | |
420 'type': env['TYPE'] | |
421 }) | |
422 output.close() | 494 output.close() |
423 | 495 |
| 496 |
424 def main(): | 497 def main(): |
425 natives = sys.argv[1] | 498 parser = optparse.OptionParser() |
426 type = sys.argv[2] | 499 parser.add_option("--raw", action="store", |
427 compression = sys.argv[3] | 500 help="file to write the processed sources array to.") |
428 source_files = sys.argv[4:] | 501 parser.add_option("--omit", dest="omit", action="store_true", |
429 JS2C(source_files, [natives], { 'TYPE': type, 'COMPRESSION': compression }) | 502 help="Omit the raw sources from the generated code.") |
| 503 parser.set_usage("""js2c out.cc type compression sources.js ... |
| 504 out.cc: C code to be generated. |
| 505 type: type parameter for NativesCollection template. |
| 506 compression: type of compression used. [off|bz2] |
| 507 sources.js: JS internal sources or macros.py.""") |
| 508 (options, args) = parser.parse_args() |
| 509 |
| 510 JS2C(args[3:], args[0], args[1], args[2], options.raw, options.omit) |
| 511 |
430 | 512 |
431 if __name__ == "__main__": | 513 if __name__ == "__main__": |
432 main() | 514 main() |
OLD | NEW |