tricu

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

compiler.js (3811B)


      1 import { bundleHash } from './bundle.js';
      2 import { text, readText, readList, readNatural } from './codecs.js';
      3 export const COMPILER_EXPORT = 'source_unit.compileStableModuleDefinitions';
      4 export function compilerDescriptor(raw) {
      5     if (!raw || typeof raw !== 'object' || Array.isArray(raw))
      6         throw new Error('Invalid compiler descriptor');
      7     const descriptor = raw;
      8     if (descriptor['schema'] !== 1 || descriptor['backend'] !== 'stable' || descriptor['export'] !== COMPILER_EXPORT)
      9         throw new Error('Invalid stable compiler descriptor');
     10     return { hash: bundleHash(descriptor['hash']) };
     11 }
     12 export const COMPILER_COLLECTION = Object.freeze({ threshold: 250_000 });
     13 export const SOURCE_LIMIT = 16_384;
     14 export function sourceText(source) {
     15     if (typeof source !== 'string' || !source.trim())
     16         throw new Error('Enter a source unit or native module');
     17     if (source.length > SOURCE_LIMIT * 2)
     18         throw new Error('Source limit exceeded');
     19     let count = 0;
     20     for (const char of source) {
     21         if (++count > SOURCE_LIMIT)
     22             throw new Error('Source limit exceeded');
     23         const scalar = char.codePointAt(0);
     24         if (scalar >= 0xd800 && scalar <= 0xdfff)
     25             throw new Error('Unpaired source surrogate');
     26     }
     27     return source;
     28 }
     29 export function sourceLiteral(graph, source) {
     30     return text(graph, sourceText(source), SOURCE_LIMIT);
     31 }
     32 export function compilerDiagnostic(graph, payload) {
     33     const [diagnostic] = graph.pair(payload, 'compiler error payload');
     34     const [code, tail] = graph.pair(diagnostic, 'diagnostic code');
     35     const [expected, fields] = graph.pair(tail, 'diagnostic expected');
     36     const [, locationFields] = graph.pair(fields, 'diagnostic found');
     37     const [location] = graph.pair(locationFields, 'diagnostic location');
     38     let where = '';
     39     if (graph.observe(location).node.kind !== 'leaf') {
     40         const [line, rest] = graph.pair(location, 'source position'), [column] = graph.pair(rest, 'source column');
     41         where = ` at ${readNatural(graph, line)}:${readNatural(graph, column)}`;
     42     }
     43     // Expected can be a token-kind number or a label; found/context/remainder
     44     // may be arbitrary trees. Decode only the compiler's known diagnostic profile.
     45     const number = readNatural(graph, code);
     46     const label = number === 2n ? `: expected token kind ${readNatural(graph, expected)}`
     47         : number === 20n ? `: unresolved name ${JSON.stringify(readText(graph, expected, 512))}`
     48             : number >= 30n ? `: expected ${JSON.stringify(readText(graph, expected, 512))}` : '';
     49     return `Compiler diagnostic ${number}${where}${label}`;
     50 }
     51 // Decode only the result spine/names. Compiled program trees remain lazy handles.
     52 // Do not normalize/serialize them merely to populate an export selector.
     53 export function compiledDefinitions(graph, result, allowEmpty = false) {
     54     const [tag, payload] = graph.pair(result, 'compiler result');
     55     const flag = graph.observe(tag).node;
     56     if (flag.kind === 'leaf')
     57         throw new Error(compilerDiagnostic(graph, payload));
     58     if (flag.kind !== 'stem' || graph.observe(flag.child).node.kind !== 'leaf')
     59         throw new Error('Invalid compiler result tag');
     60     const [definitions] = graph.pair(payload, 'compiler definitions payload');
     61     const bindings = readList(graph, definitions, 16), exports = new Map();
     62     for (const binding of bindings) {
     63         const [nameTree, program] = graph.pair(binding, 'compiled binding');
     64         const name = readText(graph, nameTree, 128);
     65         if (!name || exports.has(name))
     66             throw new Error('Empty/duplicate compiled definition name');
     67         exports.set(name, program);
     68     }
     69     if (!exports.size && !allowEmpty)
     70         throw new Error('Source unit produced no definitions');
     71     return exports;
     72 }