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))
;;
}