shithub: mc

ref: 152a1b90e2f9cb2f8afd51223c1bcd40b41a899b
dir: /interp.myr/

View raw version
use std

use "types.use"

pkg regex =
	const exec	: (re : regex#, str : byte[:] -> bool)
;;

const exec = {re, str
	var i

	re.str = str
	re.strp = 0
	re.matched = `std.None
	mkthread(re, 0)
	while re.nthr > 0
		for i = 0; i < re.nthr; i++
			std.put("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:
		std.put("\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++
			std.put("\t\tmatched %b with %b\n", b, str[re.strp])
		;;
		;;
	`Irange (start, end):
		std.put("\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:
		std.put("\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):
		std.put("\t%i:\tFork (%z, %z)\n", thr.ip, rip, lip)
		jmp(re, tid, rip)
		spawn(re, lip)
		;;
	`Ijmp ip:
		std.put("\t%i:\tJmp %z\n", thr.ip, ip)
		jmp(re, tid, ip)
		;;
	`Imatch:
		std.put("\t%i:\tMatch\n", thr.ip)
		finish(re, tid)
		;;
	;;
}

const jmp = {re, tid, ip
	re.thr[tid].ip = ip
	step(re, tid)
}

const steptrace = {
	std.put("\t\tStepping\n")
}

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
	*/
	std.put("\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
	std.put("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
}