tricu

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

basic-examples-probe.mjs (6219B)


      1 import {evaluateSource,inspect} from './source-probe-helpers.mjs';
      2 const el=id=>document.getElementById(id),delay=ms=>new Promise(r=>setTimeout(r,ms));
      3 const assert=(ok,message)=>{if(!ok)throw Error(message);};
      4 const input=(id,value)=>{if(id==='source-editor'){globalThis.__sourceEditor.replaceSource(value,true);return;}el(id).value=value;el(id).dispatchEvent(new Event('input'));};
      5 const change=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('change'));};
      6 async function status(want){for(let i=0;i<4500;i++){if(el('status').textContent===want)return;await delay(20);}throw Error(want+': '+el('status').textContent+' / '+el('compile-diagnostic').textContent+' / '+el('operation-diagnostic').textContent);}
      7 export async function run(control,backend='haskell-wasm'){
      8  await status('Ready');
      9  const groups=[...el('program-picker').querySelectorAll('optgroup')];
     10  assert(groups.map(g=>g.label).join('|')==='Basic Examples|Practical Examples|Language & Runtime Explorations','Purposeful selector groups');
     11  const basics=['names-values','arithmetic','functions','lists','transform-list','choices'];
     12  assert([...groups[0].children].map(o=>o.value).join('|')===basics.map(n=>'demo:'+n).join('|'),'Basic progression');
     13  assert(groups[2].firstElementChild.value==='demo:language-reference','Reference leads explorations');
     14  assert(![...el('program-picker').options].some(o=>o.value==='demo:intro'||o.value==='package:intro'),'Start Here retired from selector');
     15  assert(el('program-picker').value==='demo:names-values'&&!el('expression-editor'),'Beginner arrival is source-first');
     16  assert(document.querySelector('.definition-card').hidden,'Arrival waits for explicit inspection');
     17  const base=new URL('../',document.querySelector('script[type=module][src]').src);
     18  const releases=(await(await fetch(new URL('packages.json',base))).json()).releases;
     19  assert(![...el('program-picker').options].some(o=>o.value.startsWith('package:')),'Libraries are discovered in the explorer, not a giant selector list');
     20  assert(el('add-import').textContent==='Explore libraries…','Prominent library explorer');
     21  const select=async name=>{change('program-picker','demo:'+name);await status('Ready');};
     22  const evaluate=async(expression,output,expected)=>assert(await evaluateSource(expression,output)===expected,expression+' expected '+expected);
     23  const defaults=[['greeting','string','Hello, world!'],['total','number','12'],['sixDoubled','number','12'],['itemCount','number','3'],['total','number','24'],['emptyBasket','string','Your basket is empty.']];
     24  for(let i=0;i<basics.length;i++){
     25   await select(basics[i]);const original=globalThis.__sourceEditor.getSource();
     26   assert(await inspect(...defaults[i].slice(0,2))===defaults[i][2],'Published lesson result '+basics[i]);
     27   if(i===0)assert(await inspect('greetAndAnswer','values')==='["Hello, world!" 42]','Intro list is published and inspectable');
     28   if(i===2){assert(await inspect('nineDoubled','number')==='18','Second function call');assert(await inspect('area','number')==='28','Two-parameter function');}
     29   if(i===4){assert(await inspect('doubled','values')==='[4 8 12]','Mapped list');assert(await inspect('numbers','values')==='[2 4 6]','Original list preserved');}
     30   if(i===5){assert(await inspect('oneItem','string')==='You have one item.','Specific match');assert(await inspect('fullBasket','string')==='You have several items.','Fallback match');}
     31   if(!el('restore-source').hidden){el('restore-source').click();await status('Ready');}
     32   if(i===0){input('source-editor',original.replace('answer = 42','answer = 7'));await status('Compiled');await evaluate('answer','number','7');}
     33   if(i===1){input('source-editor',original.replace('add 5 7','add 8 9'));await status('Compiled');await evaluate('total','number','17');}
     34   if(i===2){input('source-editor',original.replace('mul number 2','mul number 3').replace(/\bdouble\b/g,'triple'));await status('Compiled');await evaluate('sixDoubled','number','18');await evaluate('nineDoubled','number','27');}
     35   if(i===3){input('source-editor',original.replace('numbers = [2 4 6]','numbers = [2 4 6 8]'));await status('Compiled');await evaluate('itemCount','number','4');await evaluate('total','number','20');input('source-editor',original.replace('numbers = [2 4 6]','numbers = []'));await status('Compiled');await evaluate('itemCount','number','0');await evaluate('total','number','0');}
     36   if(i===4){input('source-editor',original.replace('mul number 2','mul number 3'));await status('Compiled');await evaluate('total','number','36');}
     37   if(i===5){input('source-editor',original.replace('message _ =','message 2 = "You have two items."\nmessage _ ='));await status('Compiled');await evaluate('message 2','string','You have two items.');await evaluate('message 4','string','You have several items.');}
     38   el('restore-source').click();await status('Ready');assert(globalThis.__sourceEditor.getSource()===original,'Restore '+basics[i]);
     39  }
     40  await select('language-reference');
     41  const catalogue=await(await fetch(new URL('catalogue.json',base))).json();
     42  const reference=catalogue.find(d=>d.id==='language-reference');
     43  assert(await inspect('leaf','tricu')==='t','Published reference root without compilation');
     44  await evaluate('describe (t t)','string','true');await evaluate('describe "hi"','string','greeting');await evaluate('firstOr 99 []','number','99');
     45  input('source-editor',reference.source+'\n-- my reference notes');await status('Compiled');await evaluate('sequenced 9','number','9');
     46  // A retired example's immutable publication still loads through its old share link.
     47  const old=releases.find(r=>r.name==='intro'&&r.version==='0.2.0');
     48  location.hash=new URLSearchParams({bundle:old.hash,demo:'intro',export:'answer'}).toString();await delay(50);await status('Ready');
     49  assert(el('program-picker').value==='hash','Retired link remains a direct bundle selection');await evaluate('answer','number','42');
     50  await select('names-values');
     51  return {userAgent:navigator.userAgent,checks:['beginner default; grouped selector; library exploration separated from example selection; all six lesson defaults and exercises; restoration; published reference root; editable reference; retained historical link'],backend};
     52 }