tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

editable-conformance.mjs (4072B)


      1 // Opt-in real demo compilation with explicit native manifest imports. No host
      2 // recompilation; expected results are retained independent Haskell captures.
      3 import assert from 'node:assert/strict';
      4 import {readFile} from 'node:fs/promises';
      5 import {createHash} from 'node:crypto';
      6 import {Graph} from '../dist/graph.js';
      7 import {decodeBundle,loadBundle,COMPILER_BUNDLE_LIMIT} from '../dist/bundle.js';
      8 import {compiledDefinitions,sourceLiteral,COMPILER_EXPORT} from '../dist/compiler.js';
      9 import {stageModule,selectModuleExports} from '../dist/module-stage.js';
     10 import {moduleIdentity} from '../dist/module-identity.js';
     11 import {list,text,readText} from '../dist/codecs.js';
     12 // Pure reference execution only; IO goldens run through native browser probes.
     13 const root=new URL('../',import.meta.url);
     14 const catalogue=JSON.parse(await readFile(new URL('catalogue.json',root)));
     15 const environments=JSON.parse(await readFile(new URL('environments.json',root)));
     16 const goldens=JSON.parse(await readFile(new URL('demos.json',root)));
     17 async function bundle(hash,limit){
     18  const bytes=await readFile(new URL('bundles/'+hash+'.arboricx',root));
     19  assert.equal(createHash('sha256').update(bytes).digest('hex'),hash);
     20  return decodeBundle(bytes,limit);
     21 }
     22 for(const id of ['parser','lexer'])goldens.demos[id]=JSON.parse(await readFile(new URL(id+'-demo.json',root)));
     23 const releases=JSON.parse(await readFile(new URL('packages.json',root))).releases;
     24 const compiler=await bundle(environments.compiler,COMPILER_BUNDLE_LIMIT);
     25 for(const entry of catalogue.filter(e=>!process.argv[2]||e.id===process.argv[2])){
     26  if(entry.mode==='io'){console.log('NATIVE ONLY',entry.id,'IO execution is checked by module/inline/full-golden browser probes');continue;}
     27  const started=performance.now();
     28  const g=new Graph({nodes:6_000_000,fuel:Infinity,stack:100_000},{threshold:250_000});
     29  const library=loadBundle(g,compiler),stage=stageModule(g,library,entry.source+'\n-- Edited locally\n');
     30  assert.ok(stage.native);
     31  // Header strings/shapes now live in JS; release native parsing temporaries.
     32  g.collect(library.values());
     33  const modules=new Map(),scope=new Map();
     34  const roots=()=>[...library.values(),...[...modules.values()].flatMap(m=>[...m.values()])];
     35  let qualifiedCount=0;
     36  for(const [ref,qualifier] of stage.imports){
     37   if(!modules.has(ref)){
     38    const release=releases.find(r=>r.manifest===ref);assert.ok(release);
     39    const decoded=await bundle(release.hash);assert.equal(await moduleIdentity(decoded),ref);
     40    modules.set(ref,loadBundle(g,decoded));
     41   }
     42   for(const [name,value] of modules.get(ref)){
     43    const qualified=readText(g,g.apply(library.get('source_module.sourceModuleQualified'),[text(g,qualifier),text(g,name)]),512);
     44    assert.ok(!scope.has(qualified));scope.set(qualified,value);
     45    if(++qualifiedCount%32===0)g.collect(roots());
     46   }
     47  }
     48  g.collect(roots());
     49  const bindings=[...scope].map(([name,value])=>g.fork(text(g,name),value));
     50  const locals=compiledDefinitions(g,g.apply(library.get(COMPILER_EXPORT),[list(g,bindings),sourceLiteral(g,stage.body)]));
     51  for(const name of locals.keys())assert.ok(!scope.has(name));
     52  const definitions=selectModuleExports(stage,locals,modules);
     53  g.collect(definitions.values());
     54  console.log(entry.id,'compile ms',Math.round(performance.now()-started),'stats',JSON.stringify(g.stats));
     55  // Exactly apply the default published export using the first Haskell capture
     56  // for that export; evaluating the draft must reproduce the independent tree.
     57  const expected=goldens.demos[entry.id].haskellCases.find(c=>c.export===entry.export);
     58  assert.ok(expected);
     59  g.beginOperation();
     60  let result=g.apply(definitions.get(entry.export),expected.arguments.map(a=>g.fromTernary(a)));
     61  let terminal='';
     62  const actual=g.toTernary(result);
     63  // Compare small digests rather than permitting gigantic diagnostic diffs.
     64  const sha=s=>createHash('sha256').update(s).digest('hex');
     65  assert.equal(sha(actual),sha(expected.result),entry.id+' result');assert.equal(terminal,expected.terminal);
     66  console.log('PASS',entry.id,'draft equals independent Haskell result');
     67 }