tricu

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

basic-examples-probe.mjs (6175B)


      1 const el=id=>document.getElementById(id),delay=ms=>new Promise(r=>setTimeout(r,ms));
      2 const assert=(ok,message)=>{if(!ok)throw Error(message);};
      3 const input=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('input'));};
      4 const change=(id,value)=>{el(id).value=value;el(id).dispatchEvent(new Event('change'));};
      5 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('result').textContent);}
      6 export async function run(control,backend='haskell-wasm'){
      7  await status('Ready');
      8  const groups=[...el('program-picker').querySelectorAll('optgroup')];
      9  assert(groups.map(g=>g.label).join('|')==='Basic Examples|Practical Examples|Language & Runtime Explorations|Libraries','Purposeful selector groups');
     10  const basics=['names-values','arithmetic','functions','lists','transform-list','choices'];
     11  assert([...groups[0].children].map(o=>o.value).join('|')===basics.map(n=>'demo:'+n).join('|'),'Basic progression');
     12  assert(groups[2].firstElementChild.value==='demo:language-reference','Reference leads explorations');
     13  assert(![...el('program-picker').options].some(o=>o.value==='demo:intro'||o.value==='package:intro'),'Start Here retired from selector');
     14  assert(el('program-picker').value==='demo:names-values'&&el('expression-editor').value==='greeting'&&el('output-type').value==='string','Beginner arrival is ready to evaluate');
     15  assert(el('result').textContent===''&&el('terminal').textContent==='','Arrival waits for Evaluate');
     16  change('runtime-backend',backend);await status('Ready');
     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  const visible=[...groups[3].children],manifests=visible.map(o=>releases.find(r=>r.name===o.value.slice(8))?.manifest);
     20  assert(new Set(manifests).size===manifests.length,'One selector row per module identity');
     21  assert(visible.every(o=>!o.textContent.startsWith('tricu-')),'Friendly library labels');
     22  assert(visible.some(o=>o.value==='package:tricu-lib-native-math')&&!visible.some(o=>o.value==='package:tricu-math'),'Complete library publication preferred');
     23  const select=async name=>{change('program-picker','demo:'+name);await status('Ready');};
     24  const evaluate=async(expression,output,expected)=>{input('expression-editor',expression);change('output-type',output);el('run').click();await status('Finished');assert(el('result').textContent===expected,expression+' expected '+expected+' got '+el('result').textContent);};
     25  const defaults=[['greeting','string','Hello, world!'],['total','number','12'],['double 6','number','12'],['count','number','3'],['total','number','24'],['message 0','string','Your basket is empty.']];
     26  for(let i=0;i<basics.length;i++){
     27   await select(basics[i]);assert(el('expression-editor').value===defaults[i][0]&&el('output-type').value===defaults[i][1],'Default expression/settings '+basics[i]);
     28   el('run').click();await status('Finished');assert(el('result').textContent===defaults[i][2],'Default result '+basics[i]);
     29   const original=el('source-editor').value;
     30   if(i===0){input('source-editor',original.replace('answer = 42','answer = 7'));await status('Compiled');await evaluate('answer','number','7');}
     31   if(i===1){input('source-editor',original.replace('Math.add 5 7','Math.add 8 9'));await status('Compiled');await evaluate('total','number','17');}
     32   if(i===2){input('source-editor',original.replace('double number = Math.multiply number 2','triple number = Math.multiply number 3'));await status('Compiled');await evaluate('triple 6','number','18');}
     33   if(i===3){input('source-editor',original.replace('numbers = [2 4 6]','numbers = [2 4 6 8]'));await status('Compiled');await evaluate('count','number','4');await evaluate('total','number','20');input('source-editor',original.replace('numbers = [2 4 6]','numbers = []'));await status('Compiled');await evaluate('count','number','0');await evaluate('total','number','0');}
     34   if(i===4){input('source-editor',original.replace('Math.multiply number 2','Math.multiply number 3'));await status('Compiled');await evaluate('total','number','36');}
     35   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.');}
     36   el('restore-source').click();await status('Ready');assert(el('source-editor').value===original,'Restore '+basics[i]);
     37  }
     38  await select('language-reference');
     39  // Each preset goes through the actual published page (before editing), so the
     40  // examples must work using the public interface rather than hidden imports.
     41  const catalogue=await(await fetch(new URL('catalogue.json',base))).json();
     42  const reference=catalogue.find(d=>d.id==='language-reference');
     43  for(const name of Object.keys(reference.presets)){
     44   change('export',name);el('run').click();await status('Finished');assert(el('result').textContent.length>0,'Reference preset '+name);
     45  }
     46  await evaluate('describe (t t)','string','true');await evaluate('describe "hi"','string','greeting');await evaluate('firstOr 99 []','number','99');
     47  input('source-editor',reference.source+'\n-- my reference notes');await status('Compiled');await evaluate('sequenced 9','number','9');
     48  // A retired example's immutable publication still loads through its old share link.
     49  const old=releases.find(r=>r.name==='intro'&&r.version==='0.2.0');
     50  location.hash=new URLSearchParams({bundle:old.hash,demo:'intro',export:'answer'}).toString();await delay(50);await status('Ready');
     51  assert(el('program-picker').value==='hash','Retired link remains a direct bundle selection');await evaluate('answer','number','42');
     52  await select('names-values');
     53  return {userAgent:navigator.userAgent,checks:['beginner default; grouped selector; identity-based library deduplication; all six lesson defaults and exercises; restoration; all reference presets before editing; editable reference; retained historical link'],backend};
     54 }