PageRenderTime 198ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/external/v8/tools/js2c.py

https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk
Python | 396 lines | 329 code | 27 blank | 40 comment | 28 complexity | fdae1bddd6b0ce363e041d30b504150e MD5 | raw file
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2006-2008 the V8 project authors. All rights reserved.
  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. # This is a utility for converting JavaScript source code into C-style
  30. # char arrays. It is used for embedded JavaScript code in the V8
  31. # library.
  32. import os, re, sys, string
  33. import jsmin
  34. import bz2
  35. def ToCAsciiArray(lines):
  36. result = []
  37. for chr in lines:
  38. value = ord(chr)
  39. assert value < 128
  40. result.append(str(value))
  41. return ", ".join(result)
  42. def ToCArray(lines):
  43. result = []
  44. for chr in lines:
  45. result.append(str(ord(chr)))
  46. return ", ".join(result)
  47. def RemoveCommentsAndTrailingWhitespace(lines):
  48. lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments
  49. lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments.
  50. lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace
  51. return lines
  52. def ReadFile(filename):
  53. file = open(filename, "rt")
  54. try:
  55. lines = file.read()
  56. finally:
  57. file.close()
  58. return lines
  59. def ReadLines(filename):
  60. result = []
  61. for line in open(filename, "rt"):
  62. if '#' in line:
  63. line = line[:line.index('#')]
  64. line = line.strip()
  65. if len(line) > 0:
  66. result.append(line)
  67. return result
  68. def LoadConfigFrom(name):
  69. import ConfigParser
  70. config = ConfigParser.ConfigParser()
  71. config.read(name)
  72. return config
  73. def ParseValue(string):
  74. string = string.strip()
  75. if string.startswith('[') and string.endswith(']'):
  76. return string.lstrip('[').rstrip(']').split()
  77. else:
  78. return string
  79. EVAL_PATTERN = re.compile(r'\beval\s*\(')
  80. WITH_PATTERN = re.compile(r'\bwith\s*\(')
  81. def Validate(lines, file):
  82. lines = RemoveCommentsAndTrailingWhitespace(lines)
  83. # Because of simplified context setup, eval and with is not
  84. # allowed in the natives files.
  85. eval_match = EVAL_PATTERN.search(lines)
  86. if eval_match:
  87. raise ("Eval disallowed in natives: %s" % file)
  88. with_match = WITH_PATTERN.search(lines)
  89. if with_match:
  90. raise ("With statements disallowed in natives: %s" % file)
  91. def ExpandConstants(lines, constants):
  92. for key, value in constants:
  93. lines = key.sub(str(value), lines)
  94. return lines
  95. def ExpandMacros(lines, macros):
  96. # We allow macros to depend on the previously declared macros, but
  97. # we don't allow self-dependecies or recursion.
  98. for name_pattern, macro in reversed(macros):
  99. pattern_match = name_pattern.search(lines, 0)
  100. while pattern_match is not None:
  101. # Scan over the arguments
  102. height = 1
  103. start = pattern_match.start()
  104. end = pattern_match.end()
  105. assert lines[end - 1] == '('
  106. last_match = end
  107. arg_index = [0] # Wrap state into array, to work around Python "scoping"
  108. mapping = { }
  109. def add_arg(str):
  110. # Remember to expand recursively in the arguments
  111. replacement = ExpandMacros(str.strip(), macros)
  112. mapping[macro.args[arg_index[0]]] = replacement
  113. arg_index[0] += 1
  114. while end < len(lines) and height > 0:
  115. # We don't count commas at higher nesting levels.
  116. if lines[end] == ',' and height == 1:
  117. add_arg(lines[last_match:end])
  118. last_match = end + 1
  119. elif lines[end] in ['(', '{', '[']:
  120. height = height + 1
  121. elif lines[end] in [')', '}', ']']:
  122. height = height - 1
  123. end = end + 1
  124. # Remember to add the last match.
  125. add_arg(lines[last_match:end-1])
  126. result = macro.expand(mapping)
  127. # Replace the occurrence of the macro with the expansion
  128. lines = lines[:start] + result + lines[end:]
  129. pattern_match = name_pattern.search(lines, start + len(result))
  130. return lines
  131. class TextMacro:
  132. def __init__(self, args, body):
  133. self.args = args
  134. self.body = body
  135. def expand(self, mapping):
  136. result = self.body
  137. for key, value in mapping.items():
  138. result = result.replace(key, value)
  139. return result
  140. class PythonMacro:
  141. def __init__(self, args, fun):
  142. self.args = args
  143. self.fun = fun
  144. def expand(self, mapping):
  145. args = []
  146. for arg in self.args:
  147. args.append(mapping[arg])
  148. return str(self.fun(*args))
  149. CONST_PATTERN = re.compile(r'^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$')
  150. MACRO_PATTERN = re.compile(r'^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
  151. PYTHON_MACRO_PATTERN = re.compile(r'^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
  152. def ReadMacros(lines):
  153. constants = []
  154. macros = []
  155. for line in lines:
  156. hash = line.find('#')
  157. if hash != -1: line = line[:hash]
  158. line = line.strip()
  159. if len(line) is 0: continue
  160. const_match = CONST_PATTERN.match(line)
  161. if const_match:
  162. name = const_match.group(1)
  163. value = const_match.group(2).strip()
  164. constants.append((re.compile("\\b%s\\b" % name), value))
  165. else:
  166. macro_match = MACRO_PATTERN.match(line)
  167. if macro_match:
  168. name = macro_match.group(1)
  169. args = map(string.strip, macro_match.group(2).split(','))
  170. body = macro_match.group(3).strip()
  171. macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body)))
  172. else:
  173. python_match = PYTHON_MACRO_PATTERN.match(line)
  174. if python_match:
  175. name = python_match.group(1)
  176. args = map(string.strip, python_match.group(2).split(','))
  177. body = python_match.group(3).strip()
  178. fun = eval("lambda " + ",".join(args) + ': ' + body)
  179. macros.append((re.compile("\\b%s\\(" % name), PythonMacro(args, fun)))
  180. else:
  181. raise ("Illegal line: " + line)
  182. return (constants, macros)
  183. HEADER_TEMPLATE = """\
  184. // Copyright 2011 Google Inc. All Rights Reserved.
  185. // This file was generated from .js source files by SCons. If you
  186. // want to make changes to this file you should either change the
  187. // javascript source files or the SConstruct script.
  188. #include "v8.h"
  189. #include "natives.h"
  190. #include "utils.h"
  191. namespace v8 {
  192. namespace internal {
  193. static const byte sources[] = { %(sources_data)s };
  194. %(raw_sources_declaration)s\
  195. template <>
  196. int NativesCollection<%(type)s>::GetBuiltinsCount() {
  197. return %(builtin_count)i;
  198. }
  199. template <>
  200. int NativesCollection<%(type)s>::GetDebuggerCount() {
  201. return %(debugger_count)i;
  202. }
  203. template <>
  204. int NativesCollection<%(type)s>::GetIndex(const char* name) {
  205. %(get_index_cases)s\
  206. return -1;
  207. }
  208. template <>
  209. int NativesCollection<%(type)s>::GetRawScriptsSize() {
  210. return %(raw_total_length)i;
  211. }
  212. template <>
  213. Vector<const char> NativesCollection<%(type)s>::GetRawScriptSource(int index) {
  214. %(get_raw_script_source_cases)s\
  215. return Vector<const char>("", 0);
  216. }
  217. template <>
  218. Vector<const char> NativesCollection<%(type)s>::GetScriptName(int index) {
  219. %(get_script_name_cases)s\
  220. return Vector<const char>("", 0);
  221. }
  222. template <>
  223. Vector<const byte> NativesCollection<%(type)s>::GetScriptsSource() {
  224. return Vector<const byte>(sources, %(total_length)i);
  225. }
  226. template <>
  227. void NativesCollection<%(type)s>::SetRawScriptsSource(Vector<const char> raw_source) {
  228. ASSERT(%(raw_total_length)i == raw_source.length());
  229. raw_sources = raw_source.start();
  230. }
  231. } // internal
  232. } // v8
  233. """
  234. RAW_SOURCES_COMPRESSION_DECLARATION = """\
  235. static const char* raw_sources = NULL;
  236. """
  237. RAW_SOURCES_DECLARATION = """\
  238. static const char* raw_sources = reinterpret_cast<const char*>(sources);
  239. """
  240. GET_INDEX_CASE = """\
  241. if (strcmp(name, "%(id)s") == 0) return %(i)i;
  242. """
  243. GET_RAW_SCRIPT_SOURCE_CASE = """\
  244. if (index == %(i)i) return Vector<const char>(raw_sources + %(offset)i, %(raw_length)i);
  245. """
  246. GET_SCRIPT_NAME_CASE = """\
  247. if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
  248. """
  249. def JS2C(source, target, env):
  250. ids = []
  251. debugger_ids = []
  252. modules = []
  253. # Locate the macros file name.
  254. consts = []
  255. macros = []
  256. for s in source:
  257. if 'macros.py' == (os.path.split(str(s))[1]):
  258. (consts, macros) = ReadMacros(ReadLines(str(s)))
  259. else:
  260. modules.append(s)
  261. minifier = jsmin.JavaScriptMinifier()
  262. module_offset = 0
  263. all_sources = []
  264. for module in modules:
  265. filename = str(module)
  266. debugger = filename.endswith('-debugger.js')
  267. lines = ReadFile(filename)
  268. lines = ExpandConstants(lines, consts)
  269. lines = ExpandMacros(lines, macros)
  270. Validate(lines, filename)
  271. lines = minifier.JSMinify(lines)
  272. id = (os.path.split(filename)[1])[:-3]
  273. if debugger: id = id[:-9]
  274. raw_length = len(lines)
  275. if debugger:
  276. debugger_ids.append((id, raw_length, module_offset))
  277. else:
  278. ids.append((id, raw_length, module_offset))
  279. all_sources.append(lines)
  280. module_offset += raw_length
  281. total_length = raw_total_length = module_offset
  282. if env['COMPRESSION'] == 'off':
  283. raw_sources_declaration = RAW_SOURCES_DECLARATION
  284. sources_data = ToCAsciiArray("".join(all_sources))
  285. else:
  286. raw_sources_declaration = RAW_SOURCES_COMPRESSION_DECLARATION
  287. if env['COMPRESSION'] == 'bz2':
  288. all_sources = bz2.compress("".join(all_sources))
  289. total_length = len(all_sources)
  290. sources_data = ToCArray(all_sources)
  291. # Build debugger support functions
  292. get_index_cases = [ ]
  293. get_raw_script_source_cases = [ ]
  294. get_script_name_cases = [ ]
  295. i = 0
  296. for (id, raw_length, module_offset) in debugger_ids + ids:
  297. native_name = "native %s.js" % id
  298. get_index_cases.append(GET_INDEX_CASE % { 'id': id, 'i': i })
  299. get_raw_script_source_cases.append(GET_RAW_SCRIPT_SOURCE_CASE % {
  300. 'offset': module_offset,
  301. 'raw_length': raw_length,
  302. 'i': i
  303. })
  304. get_script_name_cases.append(GET_SCRIPT_NAME_CASE % {
  305. 'name': native_name,
  306. 'length': len(native_name),
  307. 'i': i
  308. })
  309. i = i + 1
  310. # Emit result
  311. output = open(str(target[0]), "w")
  312. output.write(HEADER_TEMPLATE % {
  313. 'builtin_count': len(ids) + len(debugger_ids),
  314. 'debugger_count': len(debugger_ids),
  315. 'sources_data': sources_data,
  316. 'raw_sources_declaration': raw_sources_declaration,
  317. 'raw_total_length': raw_total_length,
  318. 'total_length': total_length,
  319. 'get_index_cases': "".join(get_index_cases),
  320. 'get_raw_script_source_cases': "".join(get_raw_script_source_cases),
  321. 'get_script_name_cases': "".join(get_script_name_cases),
  322. 'type': env['TYPE']
  323. })
  324. output.close()
  325. def main():
  326. natives = sys.argv[1]
  327. type = sys.argv[2]
  328. compression = sys.argv[3]
  329. source_files = sys.argv[4:]
  330. JS2C(source_files, [natives], { 'TYPE': type, 'COMPRESSION': compression })
  331. if __name__ == "__main__":
  332. main()