tricu

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

compiler.test.mjs (4361B)


      1 import test from 'node:test';
      2 import assert from 'node:assert/strict';
      3 import {readFile} from 'node:fs/promises';
      4 import {createHash} from 'node:crypto';
      5 import {Graph} from '../dist/graph.js';
      6 import {natural,text,list,readText} from '../dist/codecs.js';
      7 import {compiledDefinitions,sourceLiteral,sourceText,SOURCE_LIMIT} from '../dist/compiler.js';
      8 test('compiler shipped pin matches authenticated reference and Haskell golden provenance',async()=>{
      9   const descriptor=JSON.parse(await readFile(new URL('../compiler.json',import.meta.url)));
     10   const goldens=JSON.parse(await readFile(new URL('./compiler-conformance.json',import.meta.url)));
     11   const shipped=await readFile(new URL('../bundles/'+descriptor.hash+'.arboricx',import.meta.url));
     12   assert.equal(createHash('sha256').update(shipped).digest('hex'),descriptor.hash);
     13   assert.equal(goldens.compilerBundleSha256,descriptor.hash);
     14   assert.match(descriptor.referenceCommit,/^[0-9a-f]{40}$/);
     15   // The site's accepted compiler is intentionally pinned independently of HEAD.
     16   // Authenticate it against its retained publication metadata below, not the
     17   // current compiler-library fixture. Never ask assert to diff megabyte buffers.
     18   const metadata=(await readFile(new URL('../compiler-reference.v1',import.meta.url),'utf8')).trim().split('\n');
     19   assert.equal(metadata[0],'tricu.compiler-library-fixture.v1');
     20   const fixtureDigest=createHash('sha256').update('tricu.compiler-library-fixture.v1\0').update(shipped).digest('hex');
     21   assert.deepEqual(metadata.filter(row=>row.startsWith('bundle\t')),['bundle\t'+fixtureDigest]);
     22   const sources=metadata.filter(row=>row.startsWith('module\t'));
     23   assert.equal(sources.length,28);
     24   assert.ok(sources.every(row=>row.split('\t')[2]!=='patterns'));
     25   for(const row of sources){
     26     const pin=row.split('\t')[4];assert.match(pin,/^[0-9a-f]{64}$/);
     27     const source=await readFile(new URL('../../../test/fixtures/reference-source/'+pin+'.tri',import.meta.url));
     28     assert.equal(createHash('sha256').update('arboricx.source.v1\0').update(source).digest('hex'),pin);
     29   }
     30   assert.equal(descriptor.export,'source_unit.compileStableModuleDefinitions');
     31 });
     32 test('bounded compiler result decoder preserves lazy program handles',()=>{
     33   const g=new Graph({fuel:5000}),q=g.fromTernary('212110021100'),loop=g.app(q,q);
     34   const binding=g.fork(text(g,'loop'),loop);
     35   const success=defs=>g.fork(g.stem(g.leaf),g.fork(defs,g.leaf));
     36   const exports=compiledDefinitions(g,success(list(g,[binding])));
     37   assert.equal(exports.get('loop'),loop); // No forcing/expansion of code to name exports.
     38   assert.throws(()=>compiledDefinitions(g,success(list(g,[binding,binding]))),/duplicate/);
     39   assert.throws(()=>compiledDefinitions(g,success(list(g,Array(17).fill(binding)))),/limit/);
     40   assert.throws(()=>compiledDefinitions(g,success(g.leaf)),/no definitions/);
     41   assert.throws(()=>compiledDefinitions(g,g.fork(g.stem(g.stem(g.leaf)),g.leaf)),/tag/);
     42   assert.throws(()=>sourceLiteral(g,'x'.repeat(SOURCE_LIMIT+1)),/limit/);
     43   assert.throws(()=>sourceLiteral(g,''),/Enter/);
     44   assert.throws(()=>sourceLiteral(g,'\ud800'),/surrogate/);
     45 });
     46 test('structured compiler diagnostics ignore arbitrary found/context/remainder trees',()=>{
     47   const g=new Graph({fuel:5000}),q=g.fromTernary('212110021100'),loop=g.app(q,q);
     48   const location=g.fork(natural(g,2n),g.fork(natural(g,3n),loop));
     49   const diagnostic=g.fork(natural(g,2n),g.fork(natural(g,7n),g.fork(loop,g.fork(location,loop))));
     50   const failure=g.fork(g.leaf,g.fork(diagnostic,loop));
     51   assert.throws(()=>compiledDefinitions(g,failure),/^Error: Compiler diagnostic 2 at 2:3: expected token kind 7$/);
     52   assert.ok(g.stats.work<1000);
     53 });
     54 
     55 test('16,384 scalar source validation and Worker encoding have no hidden 256/main-heap cap',()=>{
     56  assert.equal(SOURCE_LIMIT,16384);
     57  const ascii='x'.repeat(SOURCE_LIMIT), unicode='🙂'.repeat(SOURCE_LIMIT);
     58  assert.equal(sourceText(ascii),ascii);assert.equal(sourceText(unicode),unicode);
     59  assert.throws(()=>sourceText(unicode+'x'),/limit/);
     60  assert.throws(()=>sourceText(ascii+'x'),/limit/);
     61  assert.throws(()=>sourceText(' \n '),/Enter/);
     62  assert.throws(()=>sourceText('x\udc00'),/surrogate/);
     63  const g=new Graph({nodes:1_000_000,fuel:2_000_000});
     64  const encoded=sourceLiteral(g,unicode);
     65  assert.ok(g.stats.nodes>250000);assert.equal(readText(g,encoded,SOURCE_LIMIT),unicode);
     66 });