From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- js/src/jsautokw.py | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 js/src/jsautokw.py (limited to 'js/src/jsautokw.py') diff --git a/js/src/jsautokw.py b/js/src/jsautokw.py new file mode 100644 index 000000000..fa4b872b5 --- /dev/null +++ b/js/src/jsautokw.py @@ -0,0 +1,213 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import re +import sys + +def read_keyword_list(filename): + macro_pat = re.compile(r"^\s*macro\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?$") + + keyword_list = [] + index = 0 + with open(filename, 'r') as f: + for line in f: + m = macro_pat.search(line) + if m: + keyword_list.append((index, m.group(1))) + index += 1 + + assert(len(keyword_list) != 0) + + return keyword_list + +def line(opt, s): + opt['output'].write('{}{}\n'.format(' ' * opt['indent_level'], s)) + +def indent(opt): + opt['indent_level'] += 1 + +def dedent(opt): + opt['indent_level'] -= 1 + +def span_and_count_at(keyword_list, column): + assert(len(keyword_list) != 0); + + chars_dict = {} + for index, keyword in keyword_list: + chars_dict[ord(keyword[column])] = True + + chars = sorted(chars_dict.keys()) + return chars[-1] - chars[0] + 1, len(chars) + +def optimal_switch_column(opt, keyword_list, columns, unprocessed_columns): + assert(len(keyword_list) != 0); + assert(unprocessed_columns != 0); + + min_count = 0 + min_span = 0 + min_count_index = 0 + min_span_index = 0 + + for index in range(0, unprocessed_columns): + span, count = span_and_count_at(keyword_list, columns[index]) + assert(span != 0) + + if span == 1: + assert(count == 1) + return 1, True + + assert(count != 1) + if index == 0 or min_span > span: + min_span = span + min_span_index = index + + if index == 0 or min_count > count: + min_count = count + min_count_index = index + + if min_count <= opt['use_if_threshold']: + return min_count_index, True + + return min_span_index, False + +def split_list_per_column(keyword_list, column): + assert(len(keyword_list) != 0); + + column_dict = {} + for item in keyword_list: + index, keyword = item + per_column = column_dict.setdefault(keyword[column], []) + per_column.append(item) + + return sorted(column_dict.items(), key=lambda (char, keyword): ord(char)) + +def generate_letter_switch(opt, unprocessed_columns, keyword_list, + columns=None): + assert(len(keyword_list) != 0); + + if not columns: + columns = range(0, unprocessed_columns) + + if len(keyword_list) == 1: + index, keyword = keyword_list[0] + + if unprocessed_columns == 0: + line(opt, 'JSKW_GOT_MATCH({}) /* {} */'.format(index, keyword)) + return + + if unprocessed_columns > opt['char_tail_test_threshold']: + line(opt, 'JSKW_TEST_GUESS({}) /* {} */'.format(index, keyword)) + return + + conds = [] + for column in columns[0:unprocessed_columns]: + quoted = repr(keyword[column]) + conds.append('JSKW_AT({})=={}'.format(column, quoted)) + + line(opt, 'if ({}) {{'.format(' && '.join(conds))) + + indent(opt) + line(opt, 'JSKW_GOT_MATCH({}) /* {} */'.format(index, keyword)) + dedent(opt) + + line(opt, '}') + line(opt, 'JSKW_NO_MATCH()') + return + + assert(unprocessed_columns != 0); + + optimal_column_index, use_if = optimal_switch_column(opt, keyword_list, + columns, + unprocessed_columns) + optimal_column = columns[optimal_column_index] + + # Make a copy to avoid breaking passed list. + columns = columns[:] + columns[optimal_column_index] = columns[unprocessed_columns - 1] + + list_per_column = split_list_per_column(keyword_list, optimal_column) + + if not use_if: + line(opt, 'switch (JSKW_AT({})) {{'.format(optimal_column)) + + for char, keyword_list_per_column in list_per_column: + quoted = repr(char) + if use_if: + line(opt, 'if (JSKW_AT({}) == {}) {{'.format(optimal_column, + quoted)) + else: + line(opt, ' case {}:'.format(quoted)) + + indent(opt) + generate_letter_switch(opt, unprocessed_columns - 1, + keyword_list_per_column, columns) + dedent(opt) + + if use_if: + line(opt, '}') + + if not use_if: + line(opt, '}') + + line(opt, 'JSKW_NO_MATCH()') + +def split_list_per_length(keyword_list): + assert(len(keyword_list) != 0); + + length_dict = {} + for item in keyword_list: + index, keyword = item + per_length = length_dict.setdefault(len(keyword), []) + per_length.append(item) + + return sorted(length_dict.items(), key=lambda (length, keyword): length) + +def generate_switch(opt, keyword_list): + assert(len(keyword_list) != 0); + + line(opt, '/*') + line(opt, ' * Generating switch for the list of {} entries:'.format(len(keyword_list))) + for index, keyword in keyword_list: + line(opt, ' * {}'.format(keyword)) + line(opt, ' */') + + list_per_length = split_list_per_length(keyword_list) + + use_if = False + if len(list_per_length) < opt['use_if_threshold']: + use_if = True + + if not use_if: + line(opt, 'switch (JSKW_LENGTH()) {') + + for length, keyword_list_per_length in list_per_length: + if use_if: + line(opt, 'if (JSKW_LENGTH() == {}) {{'.format(length)) + else: + line(opt, ' case {}:'.format(length)) + + indent(opt) + generate_letter_switch(opt, length, keyword_list_per_length) + dedent(opt) + + if use_if: + line(opt, '}') + + if not use_if: + line(opt, '}') + line(opt, 'JSKW_NO_MATCH()') + +def main(output, keywords_h): + keyword_list = read_keyword_list(keywords_h) + + opt = { + 'indent_level': 1, + 'use_if_threshold': 3, + 'char_tail_test_threshold': 4, + 'output': output + } + generate_switch(opt, keyword_list) + +if __name__ == '__main__': + main(sys.stdout, *sys.argv[1:]) -- cgit v1.2.3