Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / GenerateReservedWords.py
blob078f8bf833c000c77de15925da1b4a6f91ded05f
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 import re
6 import sys
9 def read_reserved_word_list(filename, enable_decorators):
10 macro_pat = re.compile(r"MACRO\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?")
12 reserved_word_list = []
13 index = 0
14 with open(filename, "r") as f:
15 for line in f:
16 m = macro_pat.search(line)
17 if m:
18 reserved_word = m.group(1)
19 if reserved_word == "accessor" and not enable_decorators:
20 continue
21 reserved_word_list.append((index, reserved_word))
22 index += 1
24 assert len(reserved_word_list) != 0
26 return reserved_word_list
29 def line(opt, s):
30 opt["output"].write("{}{}\n".format(" " * opt["indent_level"], s))
33 def indent(opt):
34 opt["indent_level"] += 1
37 def dedent(opt):
38 opt["indent_level"] -= 1
41 def span_and_count_at(reserved_word_list, column):
42 assert len(reserved_word_list) != 0
44 chars_dict = {}
45 for index, word in reserved_word_list:
46 chars_dict[ord(word[column])] = True
48 chars = sorted(chars_dict.keys())
49 return chars[-1] - chars[0] + 1, len(chars)
52 def optimal_switch_column(opt, reserved_word_list, columns, unprocessed_columns):
53 assert len(reserved_word_list) != 0
54 assert unprocessed_columns != 0
56 min_count = 0
57 min_span = 0
58 min_count_index = 0
59 min_span_index = 0
61 for index in range(0, unprocessed_columns):
62 span, count = span_and_count_at(reserved_word_list, columns[index])
63 assert span != 0
65 if span == 1:
66 assert count == 1
67 return 1, True
69 assert count != 1
70 if index == 0 or min_span > span:
71 min_span = span
72 min_span_index = index
74 if index == 0 or min_count > count:
75 min_count = count
76 min_count_index = index
78 if min_count <= opt["use_if_threshold"]:
79 return min_count_index, True
81 return min_span_index, False
84 def split_list_per_column(reserved_word_list, column):
85 assert len(reserved_word_list) != 0
87 column_dict = {}
88 for item in reserved_word_list:
89 index, word = item
90 per_column = column_dict.setdefault(word[column], [])
91 per_column.append(item)
93 return sorted(column_dict.items())
96 def generate_letter_switch(opt, unprocessed_columns, reserved_word_list, columns=None):
97 assert len(reserved_word_list) != 0
99 if not columns:
100 columns = range(0, unprocessed_columns)
102 if len(reserved_word_list) == 1:
103 index, word = reserved_word_list[0]
105 if unprocessed_columns == 0:
106 line(opt, "JSRW_GOT_MATCH({}) /* {} */".format(index, word))
107 return
109 if unprocessed_columns > opt["char_tail_test_threshold"]:
110 line(opt, "JSRW_TEST_GUESS({}) /* {} */".format(index, word))
111 return
113 conds = []
114 for column in columns[0:unprocessed_columns]:
115 quoted = repr(word[column])
116 conds.append("JSRW_AT({})=={}".format(column, quoted))
118 line(opt, "if ({}) {{".format(" && ".join(conds)))
120 indent(opt)
121 line(opt, "JSRW_GOT_MATCH({}) /* {} */".format(index, word))
122 dedent(opt)
124 line(opt, "}")
125 line(opt, "JSRW_NO_MATCH()")
126 return
128 assert unprocessed_columns != 0
130 optimal_column_index, use_if = optimal_switch_column(
131 opt, reserved_word_list, columns, unprocessed_columns
133 optimal_column = columns[optimal_column_index]
135 # Make a copy to avoid breaking passed list.
136 columns = list(columns)
137 columns[optimal_column_index] = columns[unprocessed_columns - 1]
139 list_per_column = split_list_per_column(reserved_word_list, optimal_column)
141 if not use_if:
142 line(opt, "switch (JSRW_AT({})) {{".format(optimal_column))
144 for char, reserved_word_list_per_column in list_per_column:
145 quoted = repr(char)
146 if use_if:
147 line(opt, "if (JSRW_AT({}) == {}) {{".format(optimal_column, quoted))
148 else:
149 line(opt, " case {}:".format(quoted))
151 indent(opt)
152 generate_letter_switch(
153 opt, unprocessed_columns - 1, reserved_word_list_per_column, columns
155 dedent(opt)
157 if use_if:
158 line(opt, "}")
160 if not use_if:
161 line(opt, "}")
163 line(opt, "JSRW_NO_MATCH()")
166 def split_list_per_length(reserved_word_list):
167 assert len(reserved_word_list) != 0
169 length_dict = {}
170 for item in reserved_word_list:
171 index, word = item
172 per_length = length_dict.setdefault(len(word), [])
173 per_length.append(item)
175 return sorted(length_dict.items())
178 def generate_switch(opt, reserved_word_list):
179 assert len(reserved_word_list) != 0
181 line(opt, "/*")
182 line(
183 opt,
184 " * Generating switch for the list of {} entries:".format(
185 len(reserved_word_list)
188 for index, word in reserved_word_list:
189 line(opt, " * {}".format(word))
190 line(opt, " */")
192 list_per_length = split_list_per_length(reserved_word_list)
194 use_if = False
195 if len(list_per_length) < opt["use_if_threshold"]:
196 use_if = True
198 if not use_if:
199 line(opt, "switch (JSRW_LENGTH()) {")
201 for length, reserved_word_list_per_length in list_per_length:
202 if use_if:
203 line(opt, "if (JSRW_LENGTH() == {}) {{".format(length))
204 else:
205 line(opt, " case {}:".format(length))
207 indent(opt)
208 generate_letter_switch(opt, length, reserved_word_list_per_length)
209 dedent(opt)
211 if use_if:
212 line(opt, "}")
214 if not use_if:
215 line(opt, "}")
216 line(opt, "JSRW_NO_MATCH()")
219 def main(output, reserved_words_h, enable_decorators=False):
220 reserved_word_list = read_reserved_word_list(reserved_words_h, enable_decorators)
222 opt = {
223 "indent_level": 1,
224 "use_if_threshold": 3,
225 "char_tail_test_threshold": 4,
226 "output": output,
228 generate_switch(opt, reserved_word_list)
231 if __name__ == "__main__":
232 main(sys.stdout, *sys.argv[1:])