tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

local-module-native.py (3612B)


      1 #!/usr/bin/env python3
      2 """Verify browser-produced exports with the native CLI and shipped compiler.
      3 
      4 Input is a local-module browser probe JSON report (BENCHMARK_REPORT).
      5 Expected identities come from independent native compilation using a Nix-built host.
      6 """
      7 import argparse
      8 import json
      9 from pathlib import Path
     10 import re
     11 import subprocess
     12 import sys
     13 import tempfile
     14 ROOT = Path(__file__).resolve().parents[3]
     15 SITE = ROOT / 'ext/demo-site'
     16 sys.path.insert(0, str(ROOT / 'test'))
     17 from shipped_compiler import verify
     18 from bundle_dag import read
     19 
     20 
     21 def main():
     22     parser = argparse.ArgumentParser(description=__doc__)
     23     parser.add_argument('tricu', type=Path)
     24     parser.add_argument('reports', nargs='+', type=Path)
     25     args = parser.parse_args()
     26     metadata = verify()
     27     releases = json.loads((SITE / 'packages.json').read_text())['releases']
     28     identities = set()
     29     with tempfile.TemporaryDirectory(prefix='tricu-local-export-') as temporary:
     30         work = Path(temporary)
     31         (work / 'tricu.workspace').write_text('tricu.workspace.v1\n')
     32         def run(*words):
     33             reply = subprocess.run([str(args.tricu.resolve()), *map(str, words), '+RTS', '-N1', '-M2048m', '-RTS'],
     34                                    cwd=work, capture_output=True, timeout=120)
     35             assert reply.returncode == 0, (reply.stdout + reply.stderr).decode()
     36             return reply.stdout.decode().strip()
     37         def imported(file, store):
     38             return re.search(r'Created module alias .* -> ([0-9a-f]{64})', run('arboricx', 'import', '--indexed', '--file', file, '--store', store))[1]
     39         compiler = imported(ROOT / metadata['bundle'], work / 'tools')
     40         for report in args.reports:
     41             data = json.loads(report.read_text())
     42             file = work / 'browser.arboricx'
     43             file.write_bytes(bytes(data['bytes']))
     44             manifest = imported(file, work / 'consumer')
     45             assert manifest == data['manifest']
     46             assert list(read(file)[3]) == ['echo', 'plus', 'value']
     47             def natural(n): return (b'\x02' + (b'\x01\x00' if n % 2 else b'\x00') + natural(n // 2)) if n else b'\x00'
     48             for name, number, expected in [('plus', 33, '42'), ('value', None, '42'), ('echo', 17, '17')]:
     49                 arguments = []
     50                 if number is not None:
     51                     arg = work / 'argument.tree'; arg.write_bytes(natural(number))
     52                     arguments = ['--arg-tree-file', arg]
     53                 assert run('arboricx', 'run', '--module', manifest, '--store', work / 'consumer', '--name', name, *arguments, '--format', 'number') == expected
     54             for ref in re.findall(r'^!import ([0-9a-f]{64}) ', data['source'], re.M):
     55                 release = next(r for r in releases if r['manifest'] == ref)
     56                 assert imported(SITE / 'bundles' / (release['hash'] + '.arboricx'), work / 'build') == ref
     57             source = work / 'original.tri'; source.write_text(data['source'])
     58             native = work / 'native.arboricx'
     59             run('arboricx', 'compile', '--file', source, '--store', work / 'build', '--toolchain', compiler,
     60                 '--tool-store', work / 'tools', '--output', native, '--compile-timeout', '110')
     61             assert imported(native, work / 'native-consumer') == manifest, 'Native compiled interface/tree identities differ'
     62             identities.add(manifest)
     63     assert len(identities) == 1, 'Backend export identities differ'
     64     print('Native import/run and independently compiled complete module identity agree for', len(args.reports), 'browser reports')
     65 
     66 
     67 if __name__ == '__main__':
     68     main()