#! /usr/bin/env python3 import sys, os, re, urllib.request default_issue_list_path = 'cwg_index.html' issue_list_url = "https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_index.html" output = 'cxx_dr_status.html' dr_test_dir = '../test/CXX/drs' class DR: def __init__(self, section, issue, url, status, title): self.section, self.issue, self.url, self.status, self.title = \ section, issue, url, status, title def __repr__(self): return '%s (%s): %s' % (self.issue, self.status, self.title) def parse(dr): try: section, issue_link, status, liaison, title = [ col.split('>', 1)[1].split('')[0] for col in dr.split('', 1)[0].split('', 1)[1].split('<', 1)[0]) title = title.replace('', '').replace('', '').replace('\r\n', '\n').strip() return DR(section, issue, url, status, title) def collect_tests(): status_re = re.compile(r'\bdr([0-9]+): (.*)') status_map = {} for test_cpp in os.listdir(dr_test_dir): if not test_cpp.endswith('.cpp'): continue test_cpp = os.path.join(dr_test_dir, test_cpp) found_any = False; for match in re.finditer(status_re, open(test_cpp, 'r').read()): status_map[int(match.group(1))] = match.group(2) found_any = True if not found_any: print("warning:%s: no '// dr123: foo' comments in this file" % test_cpp, file=sys.stderr) return status_map def get_issues(path): buffer = None if not path and os.path.exists(default_issue_list_path): path = default_issue_list_path try: if path is None: print('Fetching issue list from {}'.format(issue_list_url)) with urllib.request.urlopen(issue_list_url) as f: buffer = f.read().decode('utf-8') else: print('Opening issue list from file {}'.format(path)) with open(path, 'r') as f: buffer = f.read() except Exception as ex: print('Unable to read the core issue list', file=sys.stderr) print(ex, file=sys.stderr) sys.exit(1) return sorted((parse(dr) for dr in buffer.split('')[2:]), key = lambda dr: dr.issue) issue_list_path = None if len(sys.argv) == 1: pass elif len(sys.argv) == 2: issue_list_path = sys.argv[1] else: print('Usage: {} []'.format(sys.argv[0]), file=sys.stderr) sys.exit(1) status_map = collect_tests() drs = get_issues(issue_list_path) out_file = open(output, 'w') out_file.write('''\ Clang - C++ Defect Report Status

C++ Defect Report Support in Clang

C++ defect report implementation status

This page tracks which C++ defect reports are implemented within Clang.

''') latest_release = 15 def availability(issue): status = status_map.get(issue, 'unknown') unresolved_status = '' if status.endswith(' open'): status = status[:-5] unresolved_status = 'open' elif status.endswith(' drafting'): status = status[:-9] unresolved_status = 'drafting' elif status.endswith(' review'): status = status[:-7] unresolved_status = 'review' avail_suffix = '' if status.endswith(' c++11'): status = status[:-6] avail_suffix = ' (C++11 onwards)' elif status.endswith(' c++14'): status = status[:-6] avail_suffix = ' (C++14 onwards)' elif status.endswith(' c++17'): status = status[:-6] avail_suffix = ' (C++17 onwards)' elif status.endswith(' c++20'): status = status[:-6] avail_suffix = ' (C++20 onwards)' if status == 'unknown': avail = 'Unknown' avail_style = ' class="none"' elif re.match('^[0-9]+\.?[0-9]*', status): avail = 'Clang %s' % status if float(status) > latest_release: avail_style = ' class="unreleased"' else: avail_style = ' class="full"' elif status == 'yes': avail = 'Yes' avail_style = ' class="full"' elif status == 'partial': avail = 'Partial' avail_style = ' class="partial"' elif status == 'no': avail = 'No' avail_style = ' class="none"' elif status == 'na': avail = 'N/A' avail_style = ' class="na"' elif status == 'na lib': avail = 'N/A (Library DR)' avail_style = ' class="na"' elif status == 'na abi': avail = 'N/A (ABI constraint)' avail_style = ' class="na"' elif status.startswith('sup '): dup = status.split(' ', 1)[1] if dup.startswith('P'): avail = 'Superseded by %s' % (dup, dup) avail_style = ' class="na"' else: avail = 'Superseded by %s' % (dup, dup) try: _, avail_style, _ = availability(int(dup)) except: print("issue %s marked as sup %s" % (issue, dup), file=sys.stderr) avail_style = ' class="none"' elif status.startswith('dup '): dup = int(status.split(' ', 1)[1]) avail = 'Duplicate of %s' % (dup, dup) _, avail_style, _ = availability(dup) else: assert False, 'unknown status %s for issue %s' % (status, dr.issue) return (avail + avail_suffix, avail_style, unresolved_status) count = {} for dr in drs: if dr.status in ('concepts',): # This refers to the old ("C++0x") concepts feature, which was not part # of any C++ International Standard or Technical Specification. continue elif dr.status == 'extension': row_style = ' class="open"' avail = 'Extension' avail_style = '' elif dr.status in ('open', 'drafting', 'review'): row_style = ' class="open"' avail, avail_style, unresolved_status = availability(dr.issue) if avail == 'Unknown': avail = 'Not resolved' avail_style = '' else: assert unresolved_status == dr.status, \ "Issue %s is marked '%s', which differs from CWG index status '%s'" \ % (dr.issue, unresolved_status, dr.status) else: row_style = '' avail, avail_style, unresolved_status = availability(dr.issue) assert not unresolved_status, \ "Issue %s is marked '%s', even though it is resolved in CWG index" \ % (dr.issue, unresolved_status) if not avail.startswith('Sup') and not avail.startswith('Dup'): count[avail] = count.get(avail, 0) + 1 out_file.write(''' %s ''' % (row_style, dr.issue, dr.issue, dr.issue, dr.status, dr.title, avail_style, avail)) for status, num in sorted(count.items()): print("%s: %s" % (status, num), file=sys.stderr) out_file.write('''\
Number Status Issue title Available in Clang?
%s %s %s
''') out_file.close()