name_index.py (4881B)
1 #!/usr/bin/env python3 2 """Rebuild the current index; check complete results, persistence and demand. 3 4 Optional --unit selects an artifact-only stable module compiler for independent 5 source outcomes and complete comparisons with --reference (published by default). 6 No compiler generation, publication or acceptance is performed here. 7 """ 8 import argparse 9 import hashlib 10 import json 11 from pathlib import Path 12 import subprocess 13 from bundle_dag import merge_bundles 14 from pattern_lowering import audit 15 from shipped_compiler import verify 16 from source_equation_cases import cases, quoted 17 18 ROOT = Path(__file__).resolve().parent.parent 19 20 21 def main(): 22 p = argparse.ArgumentParser(description=__doc__) 23 p.add_argument('tricu', type=Path) 24 p.add_argument('--directory', type=Path, required=True) 25 p.add_argument('--unit', type=Path) 26 p.add_argument('--reference', type=Path, default=ROOT/'test/fixtures/compiler-library.arboricx') 27 args = p.parse_args() 28 out = args.directory.resolve(); out.mkdir(parents=True, exist_ok=False) 29 ws = out/'workspace'; ws.mkdir(); (ws/'tricu.workspace').write_text('tricu.workspace.v1\n') 30 host = args.tricu.resolve(); compiler = verify(); sha = lambda p: hashlib.sha256(p.read_bytes()).hexdigest() 31 report = dict(complete=False, compiler_sha256=compiler['sha256'], runtime_sha256=sha(host), commands=[]) 32 33 def run(argv, seconds=300, reject=False): 34 command = list(map(str, argv)) 35 r = subprocess.run(command, capture_output=True, text=True, cwd=ROOT, timeout=seconds) 36 report['commands'].append(dict(argv=command, code=r.returncode, stdout=r.stdout, stderr=r.stderr)) 37 (out/'report.json').write_text(json.dumps(report, indent=2)+'\n') 38 if reject: 39 assert r.returncode and 'first-binding mismatch' in r.stderr, r 40 elif r.returncode: 41 raise RuntimeError(r.stdout[-4000:]+r.stderr[-4000:]) 42 43 paths = dict(source_index='lib/source/index.tri', prelude='lib/prelude.tri', base='lib/base.tri', 44 bytes='lib/bytes.tri', conversions='lib/conversions.tri', native_math='lib/math/native.tri') 45 for alias, path in paths.items(): (ws/(alias+'.tri')).write_bytes((ROOT/path).read_bytes()) 46 report['sources'] = {path: sha(ROOT/path) for path in paths.values()} 47 48 def compile(alias): 49 output = out/(alias+'.arboricx') 50 run([host, 'arboricx', 'compile', '--file', ws/(alias+'.tri'), '--store', out/'store', 51 '--output', output, '--compile-timeout', '240', '+RTS', '-N1', '-M8192m', '-RTS']) 52 return output 53 54 index = compile('source_index') 55 report['modules'] = audit(ws, out/'store', compiler['sha256'], {}) 56 expr = ('let f=builtins.getFlake "git+file://'+str(ROOT)+'";' 57 'p=f.inputs.nixpkgs.legacyPackages.x86_64-linux;' 58 'in p.haskellPackages.ghcWithPackages(h:[h.cryptonite h.memory h.base16-bytestring h.vector])') 59 60 def build(name): 61 exe = out/name 62 run(['nix', 'shell', '--impure', '--expr', expr, '--command', 'ghc', '-O2', '-rtsopts', 63 '-XOverloadedStrings', '-XLambdaCase', '-XMultiWayIf', '-XScopedTypeVariables', 64 '-isrc', '-outputdir', out/(name+'-objects'), ROOT/'test'/(name+'.hs'), '-o', exe]) 65 return exe 66 67 checks = build('NameIndex'); run([checks, index, '+RTS', '-M2048m', '-RTS']) 68 (ws/'wrong.tri').write_text('!export wrong\nwrong index key = t\n') 69 bad = compile('wrong'); wrong = out/'wrong-index.arboricx' 70 merge_bundles(wrong, [(index, [('sourceIndexBuild','sourceIndexBuild'), ('sourceIndexPut','sourceIndexPut')]), 71 (bad, [('wrong','sourceIndexGet')])], prune_unreachable=True) 72 run([checks, wrong, '+RTS', '-M2048m', '-RTS'], reject=True) 73 report['wrong_subject_rejected'] = True 74 if args.unit: 75 (ws/'parser.tri').write_bytes((ROOT/'lib/parser.tri').read_bytes()) 76 rows = ['(pair '+quoted(label)+' (pair '+('true' if truth else 'false')+' (pair '+env+ 77 ' (pair '+quoted(source)+' '+expected+'))))' for label,source,expected,env,truth in cases] 78 (ws/'corpus.tri').write_text('!import prelude *\n!import parser *\n!export fixtures\nfixtures = [\n'+ 79 '\n'.join(rows)+'\n]\n') 80 corpus = compile('corpus'); checker = build('NameIndexUnit') 81 run([checker, args.reference.resolve(), args.unit.resolve(), corpus, '+RTS', '-M8192m', '-RTS']) 82 report['unit'] = dict(sha256=sha(args.unit), reference_sha256=sha(args.reference), 83 cases=len(cases), complete_results=True, environment_controls=6) 84 report.update(complete=True, index_sha256=sha(index)) 85 (out/'report.json').write_text(json.dumps(report, indent=2)+'\n') 86 print('PASS name index: complete model, persistence, demand, wrong-subject and source provenance') 87 88 89 if __name__ == '__main__': main()