The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / js2c.py @ 90fc8d36

History | View | Annotate | Download (9.56 KB)

1 63a9cd38 Ryan
#!/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
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
35
import jsmin
36
37
38
def ToCArray(lines):
39
  result = []
40
  for chr in lines:
41
    value = ord(chr)
42
    assert value < 128
43
    result.append(str(value))
44
  result.append("0")
45
  return ", ".join(result)
46
47
48
def CompressScript(lines, do_jsmin):
49
  # If we're not expecting this code to be user visible, we can run it through
50
  # a more aggressive minifier.
51
  if do_jsmin:
52
    return jsmin.jsmin(lines)
53
54
  # Remove stuff from the source that we don't want to appear when
55
  # people print the source code using Function.prototype.toString().
56
  # Note that we could easily compress the scripts mode but don't
57
  # since we want it to remain readable.
58
  #lines = re.sub('//.*\n', '\n', lines) # end-of-line comments
59
  #lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments.
60
  #lines = re.sub('\s+\n+', '\n', lines) # trailing whitespace
61
  return lines
62
63
64
def ReadFile(filename):
65
  file = open(filename, "rt")
66
  try:
67
    lines = file.read()
68
  finally:
69
    file.close()
70
  return lines
71
72
73
def ReadLines(filename):
74
  result = []
75
  for line in open(filename, "rt"):
76
    if '#' in line:
77
      line = line[:line.index('#')]
78
    line = line.strip()
79
    if len(line) > 0:
80
      result.append(line)
81
  return result
82
83
84
def LoadConfigFrom(name):
85
  import ConfigParser
86
  config = ConfigParser.ConfigParser()
87
  config.read(name)
88
  return config
89
90
91
def ParseValue(string):
92
  string = string.strip()
93
  if string.startswith('[') and string.endswith(']'):
94
    return string.lstrip('[').rstrip(']').split()
95
  else:
96
    return string
97
98
99
def ExpandConstants(lines, constants):
100
  for key, value in constants.items():
101
    lines = lines.replace(key, str(value))
102
  return lines
103
104
105
def ExpandMacros(lines, macros):
106
  for name, macro in macros.items():
107
    start = lines.find(name + '(', 0)
108
    while start != -1:
109
      # Scan over the arguments
110
      assert lines[start + len(name)] == '('
111
      height = 1
112
      end = start + len(name) + 1
113
      last_match = end
114
      arg_index = 0
115
      mapping = { }
116
      def add_arg(str):
117
        # Remember to expand recursively in the arguments
118
        replacement = ExpandMacros(str.strip(), macros)
119
        mapping[macro.args[arg_index]] = replacement
120
      while end < len(lines) and height > 0:
121
        # We don't count commas at higher nesting levels.
122
        if lines[end] == ',' and height == 1:
123
          add_arg(lines[last_match:end])
124
          last_match = end + 1
125
        elif lines[end] in ['(', '{', '[']:
126
          height = height + 1
127
        elif lines[end] in [')', '}', ']']:
128
          height = height - 1
129
        end = end + 1
130
      # Remember to add the last match.
131
      add_arg(lines[last_match:end-1])
132
      result = macro.expand(mapping)
133
      # Replace the occurrence of the macro with the expansion
134
      lines = lines[:start] + result + lines[end:]
135
      start = lines.find(name + '(', end)
136
  return lines
137
138
class TextMacro:
139
  def __init__(self, args, body):
140
    self.args = args
141
    self.body = body
142
  def expand(self, mapping):
143
    result = self.body
144
    for key, value in mapping.items():
145
        result = result.replace(key, value)
146
    return result
147
148
class PythonMacro:
149
  def __init__(self, args, fun):
150
    self.args = args
151
    self.fun = fun
152
  def expand(self, mapping):
153
    args = []
154
    for arg in self.args:
155
      args.append(mapping[arg])
156
    return str(self.fun(*args))
157
158
CONST_PATTERN = re.compile('^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$')
159
MACRO_PATTERN = re.compile('^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
160
PYTHON_MACRO_PATTERN = re.compile('^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
161
162
def ReadMacros(lines):
163
  constants = { }
164
  macros = { }
165
  for line in lines:
166
    hash = line.find('#')
167
    if hash != -1: line = line[:hash]
168
    line = line.strip()
169
    if len(line) is 0: continue
170
    const_match = CONST_PATTERN.match(line)
171
    if const_match:
172
      name = const_match.group(1)
173
      value = const_match.group(2).strip()
174
      constants[name] = value
175
    else:
176
      macro_match = MACRO_PATTERN.match(line)
177
      if macro_match:
178
        name = macro_match.group(1)
179
        args = map(string.strip, macro_match.group(2).split(','))
180
        body = macro_match.group(3).strip()
181
        macros[name] = TextMacro(args, body)
182
      else:
183
        python_match = PYTHON_MACRO_PATTERN.match(line)
184
        if python_match:
185
          name = python_match.group(1)
186
          args = map(string.strip, python_match.group(2).split(','))
187
          body = python_match.group(3).strip()
188
          fun = eval("lambda " + ",".join(args) + ': ' + body)
189
          macros[name] = PythonMacro(args, fun)
190
        else:
191
          raise ("Illegal line: " + line)
192
  return (constants, macros)
193
194
195
HEADER_TEMPLATE = """\
196
#ifndef node_natives_h
197
#define node_natives_h
198
namespace node {
199

200
%(source_lines)s\
201

202
}
203
#endif
204
"""
205
206
207
SOURCE_DECLARATION = """\
208
  static const char native_%(id)s[] = { %(data)s };
209
"""
210
211
212
GET_DELAY_INDEX_CASE = """\
213
    if (strcmp(name, "%(id)s") == 0) return %(i)i;
214
"""
215
216
217
GET_DELAY_SCRIPT_SOURCE_CASE = """\
218
    if (index == %(i)i) return Vector<const char>(%(id)s, %(length)i);
219
"""
220
221
222
GET_DELAY_SCRIPT_NAME_CASE = """\
223
    if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
224
"""
225
226
def JS2C(source, target):
227
  ids = []
228
  delay_ids = []
229
  modules = []
230
  # Locate the macros file name.
231
  consts = {}
232
  macros = {}
233
  for s in source:
234
    if 'macros.py' == (os.path.split(str(s))[1]):
235
      (consts, macros) = ReadMacros(ReadLines(str(s)))
236
    else:
237
      modules.append(s)
238
239
  # Build source code lines
240
  source_lines = [ ]
241
  source_lines_empty = []
242
  for s in modules:
243
    delay = str(s).endswith('-delay.js')
244
    lines = ReadFile(str(s))
245
    do_jsmin = lines.find('// jsminify this file, js2c: jsmin') != -1
246
    lines = ExpandConstants(lines, consts)
247
    lines = ExpandMacros(lines, macros)
248
    lines = CompressScript(lines, do_jsmin)
249
    data = ToCArray(lines)
250
    id = (os.path.split(str(s))[1])[:-3]
251
    if delay: id = id[:-6]
252
    if delay:
253
      delay_ids.append((id, len(lines)))
254
    else:
255
      ids.append((id, len(lines)))
256
    source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data })
257
    source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': 0 })
258
  
259
  # Build delay support functions
260
  get_index_cases = [ ]
261
  get_script_source_cases = [ ]
262
  get_script_name_cases = [ ]
263
264
  i = 0
265
  for (id, length) in delay_ids:
266
    native_name = "native %s.js" % id
267
    get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
268
    get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
269
      'id': id,
270
      'length': length,
271
      'i': i
272
    })
273
    get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
274
      'name': native_name,
275
      'length': len(native_name),
276
      'i': i
277
    });
278
    i = i + 1
279
280
  for (id, length) in ids:
281
    native_name = "native %s.js" % id
282
    get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
283
    get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
284
      'id': id,
285
      'length': length,
286
      'i': i
287
    })
288
    get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
289
      'name': native_name,
290
      'length': len(native_name),
291
      'i': i
292
    });
293
    i = i + 1
294
295
  # Emit result
296
  output = open(str(target[0]), "w")
297
  output.write(HEADER_TEMPLATE % {
298
    'builtin_count': len(ids) + len(delay_ids),
299
    'delay_count': len(delay_ids),
300
    'source_lines': "\n".join(source_lines),
301
    'get_index_cases': "".join(get_index_cases),
302
    'get_script_source_cases': "".join(get_script_source_cases),
303
    'get_script_name_cases': "".join(get_script_name_cases)
304
  })
305
  output.close()
306
307
  if len(target) > 1:
308
    output = open(str(target[1]), "w")
309
    output.write(HEADER_TEMPLATE % {
310
      'builtin_count': len(ids) + len(delay_ids),
311
      'delay_count': len(delay_ids),
312
      'source_lines': "\n".join(source_lines_empty),
313
      'get_index_cases': "".join(get_index_cases),
314
      'get_script_source_cases': "".join(get_script_source_cases),
315
      'get_script_name_cases': "".join(get_script_name_cases)
316
    })
317
    output.close()