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/.
9 def read_reserved_word_list(filename
, enable_decorators
):
10 macro_pat
= re
.compile(r
"MACRO\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?")
12 reserved_word_list
= []
14 with
open(filename
, "r") as f
:
16 m
= macro_pat
.search(line
)
18 reserved_word
= m
.group(1)
19 if reserved_word
== "accessor" and not enable_decorators
:
21 reserved_word_list
.append((index
, reserved_word
))
24 assert len(reserved_word_list
) != 0
26 return reserved_word_list
30 opt
["output"].write("{}{}\n".format(" " * opt
["indent_level"], s
))
34 opt
["indent_level"] += 1
38 opt
["indent_level"] -= 1
41 def span_and_count_at(reserved_word_list
, column
):
42 assert len(reserved_word_list
) != 0
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
61 for index
in range(0, unprocessed_columns
):
62 span
, count
= span_and_count_at(reserved_word_list
, columns
[index
])
70 if index
== 0 or min_span
> span
:
72 min_span_index
= index
74 if index
== 0 or 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
88 for item
in reserved_word_list
:
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
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
))
109 if unprocessed_columns
> opt
["char_tail_test_threshold"]:
110 line(opt
, "JSRW_TEST_GUESS({}) /* {} */".format(index
, word
))
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
)))
121 line(opt
, "JSRW_GOT_MATCH({}) /* {} */".format(index
, word
))
125 line(opt
, "JSRW_NO_MATCH()")
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
)
142 line(opt
, "switch (JSRW_AT({})) {{".format(optimal_column
))
144 for char
, reserved_word_list_per_column
in list_per_column
:
147 line(opt
, "if (JSRW_AT({}) == {}) {{".format(optimal_column
, quoted
))
149 line(opt
, " case {}:".format(quoted
))
152 generate_letter_switch(
153 opt
, unprocessed_columns
- 1, reserved_word_list_per_column
, columns
163 line(opt
, "JSRW_NO_MATCH()")
166 def split_list_per_length(reserved_word_list
):
167 assert len(reserved_word_list
) != 0
170 for item
in reserved_word_list
:
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
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
))
192 list_per_length
= split_list_per_length(reserved_word_list
)
195 if len(list_per_length
) < opt
["use_if_threshold"]:
199 line(opt
, "switch (JSRW_LENGTH()) {")
201 for length
, reserved_word_list_per_length
in list_per_length
:
203 line(opt
, "if (JSRW_LENGTH() == {}) {{".format(length
))
205 line(opt
, " case {}:".format(length
))
208 generate_letter_switch(opt
, length
, reserved_word_list_per_length
)
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
)
224 "use_if_threshold": 3,
225 "char_tail_test_threshold": 4,
228 generate_switch(opt
, reserved_word_list
)
231 if __name__
== "__main__":
232 main(sys
.stdout
, *sys
.argv
[1:])