ref: 3eb19da0ab48e2040438dee79a5a2c578516f30c
dir: /interp.myr/
use std use "types.use" pkg regex = const exec : (re : regex#, str : byte[:] -> bool) ;; const exec = {re, str var i re.debug = true re.str = str re.strp = 0 re.matched = `std.None mkthread(re, 0) while re.nthr > 0 for i = 0; i < re.nthr; i++ trace(re, "tid=%z, ip=%z, c=b\n", re.thr[i].uid, re.thr[i].ip, str[re.strp]) step(re, i) ;; if re.nthr > 0 re.strp++ ;; ;; match re.matched `std.Some thr: -> re.strp == str.len;; `std.None: -> false;; ;; } const step = {re, tid var thr var str thr = re.thr[tid] str = re.str match re.prog[thr.ip] /* Char matching. Consume exactly one byte from the string. */ `Ibyte b: trace(re, "\t%i:\tByte %b\n", thr.ip, b) if !in(re, str) kill(re, tid, "end of string") elif b != str[re.strp] kill(re, tid, "not right char") else thr.ip++ trace(re, "\t\tmatched %b with %b\n", b, str[re.strp]) ;; ;; `Irange (start, end): trace(re, "\t%i:\tRange (%b, %b)\t", thr.ip, start, end) if !in(re, str) || start > str[re.strp] || end < str[re.strp] kill(re, tid, "bad range") else thr.ip++ ;; ;; `Idot: trace(re, "\t%i:\tDot\n", thr.ip) if in(re, str) kill(re, tid, "past end") else thr.ip++ ;; ;; /* Control flow. All of these recursively call step() until exactly one byte is consumed from the string. */ `Ifork (lip, rip): trace(re, "\t%i:\tFork (%z, %z)\n", thr.ip, rip, lip) jmp(re, tid, rip) spawn(re, lip) ;; `Ijmp ip: trace(re, "\t%i:\tJmp %z\n", thr.ip, ip) jmp(re, tid, ip) ;; `Imatch: trace(re, "\t%i:\tMatch\n", thr.ip) finish(re, tid) ;; ;; } const jmp = {re, tid, ip re.thr[tid].ip = ip step(re, tid) } var uid = 0 const mkthread = {re, ip var thr : rethread# var tid tid = re.nthr if re.nthr >= re.thr.len re.thr = std.slgrow(re.thr, std.max(1, re.nthr * 2)) ;; thr = std.alloc() thr.ip = ip thr.uid = uid++ re.thr[re.nthr] = thr re.nthr++ -> tid } const spawn = {re, ip step(re, mkthread(re, ip)) } const kill = {re, tid, msg /* free the dying thread, and shuffle the last thread into the it's place in the thread list */ trace(re, "\t\tkill %z: %s\n", re.thr[tid].uid, msg) std.free(re.thr[tid]) re.thr[tid] = re.thr[re.nthr - 1] re.nthr-- } const finish = {re, tid trace(re, "finish\n", tid) match re.matched `std.Some thr: std.free(thr);; `std.None: ;; ;; re.matched = `std.Some re.thr[tid] re.thr[tid] = re.thr[re.nthr - 1] re.nthr-- } const in = {re, str -> re.strp < str.len } const trace : (re : regex#, msg : byte[:], args : ...) = {re, msg, args if re.debug std.putv(msg, std.vastart(&args)) ;; }