Skip to content

Instantly share code, notes, and snippets.

@tangentstorm
Created February 19, 2024 06:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tangentstorm/054de51c34eae8739528ccfca4906006 to your computer and use it in GitHub Desktop.
Save tangentstorm/054de51c34eae8739528ccfca4906006 to your computer and use it in GitHub Desktop.
javascript parser combinators ( https://youtube.com/live/ZfjORjtkDpI )
let set=(o,k,v)=>{let r={...o}; r[k]=v; return r}
let gs=k=>(x,y)=> y===undefined ? x[k] : set(y,k,x)
let mb=gs('mb'), // match bit
ib=gs('ib'), // input buffer
ix=gs('ix'), // index into input buffer
ch=gs('ch'), // current character (ib[ix])
mk=gs('mk'); // start index of current token
let s0=()=>({mb:0,ib:'',ch:'',ix:-1,mk:-1})
on=s=>ix(0,ch(s[0],ib(s,s0())))
m1=s=>mb(1,s) // match
m0=s=>mb(0,s) // fail
let nx=s=>{let i=1+ix(s),b=ib(s); return ch(b[i], ix(i, s))}
fw=(n,s)=>{for(let i=0;i<n;i++)s=nx(s); return s}
emp=m1 // always matches, consumes nothing
fwm=(n,s)=>mb(+n, fw(+n,s))
any=s=>fwm(ix(s)<ib(s).length, s)
neg=p=>s=>mb(1-mb(p(s)),s)
end=neg(any)
chr=c=>s=>fwm(c==ib(s)[ix(s)],s)
chs=cs=>s=>fwm(cs.includes(ib(s)[ix(s)]),s)
seq=ps=>s=>{let r=s;for(p of ps){r=p(r);if(!mb(r))return m0(s)}return r}
alt=ps=>s=>{for(p of ps){let r=p(s);if(mb(r))return r} return m0(s)}
opt=p=>alt([p,emp])
lit=cs=>seq([...cs].map(chr))
rep=p=>s=>{let r=m1(s);while(mb(r)){r=p(r)}return mb(+(ix(s)<ix(r)),r)}
orp=p=>alt([rep(p), emp])
not=p=>seq([neg(p),any])
sep=(p,d)=>seq([p, orp(seq([d, p]))])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment