Index: tools/js2c.py |
diff --git a/tools/js2c.py b/tools/js2c.py |
old mode 100644 |
new mode 100755 |
index 9492b0030c0dbf56f91f78208230e3aa89db300e..f67d053ad26360c07cf190fefea4c7cb73ce6ab6 |
--- a/tools/js2c.py |
+++ b/tools/js2c.py |
@@ -116,41 +116,47 @@ def ExpandConstants(lines, constants): |
return lines |
+def ExpandMacroDefinition(lines, pos, name_pattern, macro, expander): |
+ pattern_match = name_pattern.search(lines, pos) |
+ while pattern_match is not None: |
+ # Scan over the arguments |
+ height = 1 |
+ start = pattern_match.start() |
+ end = pattern_match.end() |
+ assert lines[end - 1] == '(' |
+ last_match = end |
+ arg_index = [0] # Wrap state into array, to work around Python "scoping" |
+ mapping = { } |
+ def add_arg(str): |
+ # Remember to expand recursively in the arguments |
+ replacement = expander(str.strip()) |
+ mapping[macro.args[arg_index[0]]] = replacement |
+ arg_index[0] += 1 |
+ while end < len(lines) and height > 0: |
+ # We don't count commas at higher nesting levels. |
+ if lines[end] == ',' and height == 1: |
+ add_arg(lines[last_match:end]) |
+ last_match = end + 1 |
+ elif lines[end] in ['(', '{', '[']: |
+ height = height + 1 |
+ elif lines[end] in [')', '}', ']']: |
+ height = height - 1 |
+ end = end + 1 |
+ # Remember to add the last match. |
+ add_arg(lines[last_match:end-1]) |
+ result = macro.expand(mapping) |
+ # Replace the occurrence of the macro with the expansion |
+ lines = lines[:start] + result + lines[end:] |
+ pattern_match = name_pattern.search(lines, start + len(result)) |
+ return lines |
+ |
def ExpandMacros(lines, macros): |
# We allow macros to depend on the previously declared macros, but |
# we don't allow self-dependecies or recursion. |
for name_pattern, macro in reversed(macros): |
- pattern_match = name_pattern.search(lines, 0) |
- while pattern_match is not None: |
- # Scan over the arguments |
- height = 1 |
- start = pattern_match.start() |
- end = pattern_match.end() |
- assert lines[end - 1] == '(' |
- last_match = end |
- arg_index = [0] # Wrap state into array, to work around Python "scoping" |
- mapping = { } |
- def add_arg(str): |
- # Remember to expand recursively in the arguments |
- replacement = ExpandMacros(str.strip(), macros) |
- mapping[macro.args[arg_index[0]]] = replacement |
- arg_index[0] += 1 |
- while end < len(lines) and height > 0: |
- # We don't count commas at higher nesting levels. |
- if lines[end] == ',' and height == 1: |
- add_arg(lines[last_match:end]) |
- last_match = end + 1 |
- elif lines[end] in ['(', '{', '[']: |
- height = height + 1 |
- elif lines[end] in [')', '}', ']']: |
- height = height - 1 |
- end = end + 1 |
- # Remember to add the last match. |
- add_arg(lines[last_match:end-1]) |
- result = macro.expand(mapping) |
- # Replace the occurrence of the macro with the expansion |
- lines = lines[:start] + result + lines[end:] |
- pattern_match = name_pattern.search(lines, start + len(result)) |
+ def expander(s): |
+ return ExpandMacros(s, macros) |
+ lines = ExpandMacroDefinition(lines, 0, name_pattern, macro, expander) |
return lines |
class TextMacro: |
@@ -210,6 +216,34 @@ def ReadMacros(lines): |
raise ("Illegal line: " + line) |
return (constants, macros) |
+INLINE_MACRO_PATTERN = re.compile(r'macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*\n') |
+INLINE_MACRO_END_PATTERN = re.compile(r'endmacro\s*\n') |
+ |
+def ExpandInlineMacros(lines, filename): |
+ pos = 0 |
+ while True: |
+ macro_match = INLINE_MACRO_PATTERN.search(lines, pos) |
+ if macro_match is None: |
+ # no more macros |
+ return lines |
+ name = macro_match.group(1) |
+ args = [match.strip() for match in macro_match.group(2).split(',')] |
+ end_macro_match = INLINE_MACRO_END_PATTERN.search(lines, macro_match.end()); |
+ if end_macro_match is None: |
+ raise ("Macro %s unclosed in %s" % (name, filename)) |
+ body = lines[macro_match.end():end_macro_match.start()] |
+ |
+ # remove macro definition |
+ lines = lines[:macro_match.start()] + lines[end_macro_match.end():] |
+ name_pattern = re.compile("\\b%s\\(" % name) |
+ macro = TextMacro(args, body) |
+ |
+ # advance position to where the macro defintion was |
+ pos = macro_match.start() |
+ |
+ def non_expander(s): |
+ return s |
+ lines = ExpandMacroDefinition(lines, pos, name_pattern, macro, non_expander) |
HEADER_TEMPLATE = """\ |
// Copyright 2011 Google Inc. All Rights Reserved. |
@@ -325,6 +359,8 @@ def JS2C(source, target, env): |
lines = ReadFile(filename) |
lines = ExpandConstants(lines, consts) |
lines = ExpandMacros(lines, macros) |
+ lines = RemoveCommentsAndTrailingWhitespace(lines) |
+ lines = ExpandInlineMacros(lines, filename) |
Validate(lines, filename) |
lines = minifier.JSMinify(lines) |
id = (os.path.split(filename)[1])[:-3] |