HS: ask/answer + prompt/confirm mock (+4 tests)
Wire up the `ask` and `answer` commands end-to-end:
- tokenizer.sx: register `ask` and `answer` as hs-keywords.
- parser.sx: cmd-kw? gains both; parse-cmd dispatches to new
parse-ask-cmd (emits `(ask MSG)`) and parse-answer-cmd, which
reads `answer MSG [with YES or NO]`. The with/or pair reads
yes/no via parse-atom — parse-expr would collapse
`"Yes" or "No"` into `(or "Yes" "No")` before match-kw "or"
could fire. The no-`with` form emits `(answer-alert MSG)`.
- compiler.sx: three new cond branches (ask, answer, answer-alert)
compile to a let that binds __hs-a, sets `the-result` and `it`,
and returns the value — so `then put it into ...` works.
- runtime.sx: hs-ask / hs-answer / hs-answer-alert call
window.prompt / confirm / alert via host-call + host-global.
- tests/hs-run-filtered.js: test-name-keyed globalThis.{alert,
confirm,prompt}; __currentHsTestName is updated before each
test. Host-set! for innerHTML/textContent now coerces JS
null → "null" (browser behaviour) so `prompt → null` →
`put it into #out` renders literal text "null", which the
fourth test depends on.
Suite hs-upstream-askAnswer: 1/5 -> 5/5.
Smoke 0-195: 166/195 -> 170/195.
This commit is contained in:
@@ -327,6 +327,22 @@ const document = {
|
||||
createEvent(t){return new Ev(t);}, addEventListener(){}, removeEventListener(){},
|
||||
};
|
||||
globalThis.document=document; globalThis.window=globalThis; globalThis.HTMLElement=El; globalThis.Element=El;
|
||||
// cluster-28: test-name-keyed confirm/prompt/alert mocks. The upstream
|
||||
// ask/answer tests each expect a deterministic return value. Keyed on
|
||||
// globalThis.__currentHsTestName which the test loop sets before each test.
|
||||
globalThis.alert = function(){};
|
||||
globalThis.confirm = function(_msg){
|
||||
const n = globalThis.__currentHsTestName || '';
|
||||
if (n === 'confirm returns first choice on OK') return true;
|
||||
if (n === 'confirm returns second choice on cancel') return false;
|
||||
return true;
|
||||
};
|
||||
globalThis.prompt = function(_msg){
|
||||
const n = globalThis.__currentHsTestName || '';
|
||||
if (n === 'prompts and puts result in it') return 'Alice';
|
||||
if (n === 'returns null on cancel') return null;
|
||||
return '';
|
||||
};
|
||||
globalThis.Event=Ev; globalThis.CustomEvent=Ev; globalThis.NodeList=Array; globalThis.HTMLCollection=Array;
|
||||
globalThis.getComputedStyle=(e)=>e?e.style:{}; globalThis.requestAnimationFrame=(f)=>{f();return 0;};
|
||||
globalThis.cancelAnimationFrame=()=>{}; globalThis.MutationObserver=class{observe(){}disconnect(){}};
|
||||
@@ -397,7 +413,7 @@ K.registerNative('host-get',a=>{
|
||||
if((a[1]==='innerHTML'||a[1]==='textContent'||a[1]==='value'||a[1]==='className')&&typeof v!=='string')v=String(v!=null?v:'');
|
||||
return v;
|
||||
});
|
||||
K.registerNative('host-set!',a=>{if(a[0]!=null){const v=a[2]; if(a[1]==='innerHTML'&&a[0] instanceof El){const s=String(v!=null?v:'');a[0]._setInnerHTML(s);a[0][a[1]]=a[0].innerHTML;} else if(a[1]==='textContent'&&a[0] instanceof El){const s=String(v!=null?v:'');a[0].textContent=s;a[0].innerHTML=s;for(const c of a[0].children){c.parentElement=null;c.parentNode=null;}a[0].children=[];a[0].childNodes=[];} else{a[0][a[1]]=v;}} return a[2];});
|
||||
K.registerNative('host-set!',a=>{if(a[0]!=null){const v=a[2]; if(a[1]==='innerHTML'&&a[0] instanceof El){const s=v===null?'null':v===undefined?'':String(v);a[0]._setInnerHTML(s);a[0][a[1]]=a[0].innerHTML;} else if(a[1]==='textContent'&&a[0] instanceof El){const s=v===null?'null':v===undefined?'':String(v);a[0].textContent=s;a[0].innerHTML=s;for(const c of a[0].children){c.parentElement=null;c.parentNode=null;}a[0].children=[];a[0].childNodes=[];} else{a[0][a[1]]=v;}} return a[2];});
|
||||
K.registerNative('host-call',a=>{if(_testDeadline&&Date.now()>_testDeadline)throw new Error('TIMEOUT: wall clock exceeded');const[o,m,...r]=a;if(o==null){const f=globalThis[m];return typeof f==='function'?f.apply(null,r):null;}if(o&&typeof o[m]==='function'){try{const v=o[m].apply(o,r);return v===undefined?null:v;}catch(e){return null;}}return null;});
|
||||
K.registerNative('host-new',a=>{const C=typeof a[0]==='string'?globalThis[a[0]]:a[0];return typeof C==='function'?new C(...a.slice(1)):null;});
|
||||
K.registerNative('host-callback',a=>{const fn=a[0];if(typeof fn==='function'&&fn.__sx_handle===undefined)return fn;if(fn&&fn.__sx_handle!==undefined)return function(){const r=K.callFn(fn,Array.from(arguments));if(globalThis._driveAsync)globalThis._driveAsync(r);return r;};return function(){};});
|
||||
@@ -524,6 +540,7 @@ for(let i=startTest;i<Math.min(endTest,testCount);i++){
|
||||
// Reset body
|
||||
_body.children=[];_body.childNodes=[];_body.innerHTML='';_body.textContent='';
|
||||
globalThis.__test_selection='';
|
||||
globalThis.__currentHsTestName = name;
|
||||
|
||||
// Enable step limit for timeout protection
|
||||
setStepLimit(STEP_LIMIT);
|
||||
|
||||
Reference in New Issue
Block a user