tricu

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

reference.py (8367B)


      1 #!/usr/bin/env python3
      2 """Build static agent references and picker metadata from published interfaces."""
      3 import argparse
      4 import hashlib
      5 import json
      6 from pathlib import Path
      7 import re
      8 import sys
      9 
     10 
     11 def generate(root, output):
     12     site = root / 'ext/demo-site'
     13     sys.path.insert(0, str(root / 'test'))
     14     from bundle_dag import read
     15     reference = output / 'reference'
     16     reference.mkdir(parents=True, exist_ok=True)
     17     def write(name, text):
     18         path = reference / name
     19         path.parent.mkdir(parents=True, exist_ok=True)
     20         path.write_text(text)
     21     write('LICENSE.txt', (root / 'LICENSE').read_text())
     22     notes = json.loads((site / 'reference-input/libraries.json').read_text())
     23     releases = json.loads((site / 'packages.json').read_text())['releases']
     24     rows = []
     25     # Keep all releases. Browser-side SemVer ordering chooses the initial view.
     26     for release in releases:
     27         if not release['name'].startswith('tricu-lib-'):
     28             continue
     29         short = release['name'].removeprefix('tricu-lib-')
     30         bundle = site / 'bundles' / (release['hash'] + '.arboricx')
     31         assert hashlib.sha256(bundle.read_bytes()).hexdigest() == release['hash']
     32         names = list(read(bundle)[3])
     33         note = notes.get(short, {}) if release['version'] == '0.1.0' else {}
     34         alias = note.get('alias', ''.join(word.capitalize() for word in short.split('-')))
     35         description = note.get('description', f'{short.replace("-", " ").capitalize()} library; inspect its complete interface and source reference below.')
     36         filename = release['name'] + '-' + release['version'] + '.md'
     37         rows.append(dict(release, title=short, description=description, alias=alias,
     38                          names=names, reference='libraries/' + filename, **({'usage': note['usage']} if 'usage' in note else {})))
     39         source = (root / release['title']).resolve()
     40         assert source.is_relative_to(root / 'lib') and source.is_file()
     41         relative = source.relative_to(root).as_posix()
     42         # Source is a labelled checkout reference; export membership comes from
     43         # the immutable published bundle, including inherited/reexported names.
     44         write('source/' + relative + '.txt', source.read_text())
     45         write('libraries/' + filename,
     46               f'# {short} · {release["version"]}\n\n{description}\n\n'
     47               f'```tricu\n!import {release["manifest"]} as {alias}\n```\n\n'
     48               f'Package: `{release["name"]}`\n\nManifest: `{release["manifest"]}`\n\n'
     49               f'Bundle SHA-256: `{release["hash"]}`\n\n'
     50               f'[Download bundle](https://arbori.cx/_arboricx/bundle/hash/{release["hash"]})\n\n'
     51               '## Calling conventions\n\n' + note.get('usage', 'Consult the source and protocol guides for argument order, encoding and effects.') + '\n\n'
     52               '[Complete examples](../examples.md) · [Language features](../language-features.md) · [Contracts](../contracts.md) · [Host ABI](../host-abi.md) · [Parser protocol](../parser.md)\n\n'
     53               f'## Complete published interface ({len(names)} exports)\n\n```text\n' + '\n'.join(names) + '\n```\n\n'
     54               f'## Source reference\n\n[Repository source](../source/{relative}.txt) from this site build. '
     55               f'Source SHA-256: `{hashlib.sha256(source.read_bytes()).hexdigest()}`. '
     56               'The export list above describes the selected published bundle; repository source is provided for implementation context. '
     57               'Workspace import names in source resolve through the [library directory](../libraries.md) when adapting code for the playground.\n')
     58     write('libraries.md', '# Published tricu libraries\n\nChoose a release to get its complete exports, manifest import and calling conventions. '
     59           'The playground picker initially shows the newest version of each library; all releases are listed here. '
     60           '[Start with the playground guide](getting-started.md).\n\n' + '\n'.join(
     61               f'- [{r["title"]} {r["version"]}]({r["reference"]}) — {r["description"]}' for r in rows) + '\n')
     62     # Publish readable source and language/protocol contracts at ordinary HTTP URLs.
     63     for path in (root / 'lib').rglob('*.tri'):
     64         write('source/' + path.relative_to(root).as_posix() + '.txt', path.read_text())
     65     for path in (root / 'docs').glob('*.md'):
     66         text = path.read_text().replace('.md.html', '.md')
     67         text = re.sub(r'\]\(\.\./lib/([^)]*?\.tri)(#[^)]*)?\)', lambda m: '](source/lib/' + m[1] + '.txt' + (m[2] or '') + ')', text)
     68         text = re.sub(r'\]\(\.\./([^)]*)\)', r'](https://git.eversole.co/James/tricu/file/\1)', text)
     69         write(path.name, text)
     70     write('getting-started.md', (site / 'reference-input/getting-started.md').read_text())
     71     # Examples pin explicit release versions; adding a publication cannot silently
     72     # change their program meaning or independent expected results.
     73     pins = {r['name'].removeprefix('tricu-lib-'): r['manifest'] for r in rows if r['version'] == '0.1.0'}
     74     examples = json.loads((site / 'reference-input/examples.json').read_text())
     75     for example in examples:
     76         example['source'] = re.sub(r'\{\{([^}]+)\}\}', lambda m: pins[m[1]], example['source'])
     77     for row in rows:
     78         example = next((e for e in examples if row['manifest'] in e['source']), None)
     79         if example:
     80             row['example'] = example['source'] + '\nExpression: ' + example['expression'] + '\nInterpretation: ' + dict(number='Natural number', string='Text')[example['output']] + '\nExecution: ' + ('Pure value' if example['mode'] == 'pure' else 'Text / line IO') + '\nExpected result: ' + example['expected']
     81     write('libraries.json', json.dumps(dict(schema=1, releases=rows), indent=2) + '\n')
     82     write('examples.json', json.dumps(examples, indent=2) + '\n')
     83     write('examples.md', '# Playground examples\n\nReplace Source with a complete module below. Wait for Compiled, enter its expression, choose its settings and Evaluate.\n\n' + '\n'.join(
     84         f'## {e["title"]}\n\n```tricu\n{e["source"]}```\n\nExpression: `{e["expression"]}`. '
     85         f'Output: **Evaluated result**. Interpretation: **{dict(number="Natural number", string="Text")[e["output"]]}**. '
     86         f'Execution: **{"Pure value" if e["mode"] == "pure" else "Text / line IO"}**.\n\n'
     87         f'Expected result: `{e["expected"]}`.\n\n' + (f'Terminal output:\n\n```text\n{e["terminal"]}```\n\n' if e['terminal'] else '') for e in examples))
     88     (output / 'llms.txt').write_text('''# Arboricx and tricu
     89 
     90 > tricu is a programming language built on Tree Calculus. Arboricx carries compiled programs between hosts. This site is the language homepage and browser playground.
     91 
     92 ## Write programs
     93 
     94 - [Playground guide](./reference/getting-started.md): source, expressions, imports, output settings, IO, diagnostics and sharing.
     95 - [Library directory](./reference/libraries.md): complete published interfaces, versions, exact manifest imports and calling conventions.
     96 - [Machine-readable library index](./reference/libraries.json): the same metadata used by Add import.
     97 - [Language features](./reference/language-features.md): patterns, recursion, local bindings, sequencing and library protocols.
     98 - [Language contract](./reference/language.md): source syntax and semantics.
     99 - [Worked examples](./reference/examples.md): complete programs, settings and expected results.
    100 - [Modules and packages](./reference/modules.md): source modules and portable bundle identities.
    101 
    102 ## Protocols and boundaries
    103 
    104 - [Contracts](./reference/contracts.md): input validation and Result protocols.
    105 - [Parser combinators](./reference/parser.md): replies, progress and rollback.
    106 - [Host ABI](./reference/host-abi.md): IO actions and host capabilities.
    107 - [Native CLI](./reference/build-and-run.md): run and package programs outside the browser.
    108 - [License](./reference/LICENSE.txt): source and documentation licensing.
    109 
    110 Start with the playground guide, then fetch the relevant library release pages. Static references are available without executing WebAssembly.
    111 ''')
    112 
    113 
    114 if __name__ == '__main__':
    115     parser = argparse.ArgumentParser(description=__doc__)
    116     parser.add_argument('--root', type=Path, required=True)
    117     parser.add_argument('--output', type=Path, required=True)
    118     args = parser.parse_args()
    119     generate(args.root.resolve(), args.output.resolve())