399 lines · 6.7 KB · Text
RawDownload
use std use "types.use"use "util.use"use "opts.use"use "fsel.use" pkg bld =	const parse	: (p : parser#	-> bool);; const failparse = {p : parser#, msg, args : ...	var buf : byte[1024]	var ap	var n 	ap = std.vastart(&args)	n = std.bfmtv(buf[:], msg, ap)	std.fput(1, "%s:%i: %s", p.fname, p.line, buf[:n])	std.exit(1)} const parse = {p	while true		skipspace(p)		if !target(p)			break		;;	;;	skipspace(p)	if p.rest.len > 0		failparse(p, "junk in file near %s\n", p.rest[:std.min(p.rest.len, 10)])		-> false	else		-> true	;;} const target = {p : parser#	match word(p)	| `std.Some "bin":	bintarget(p)	| `std.Some "test":	testtarget(p)	| `std.Some "lib":	libtarget(p)	| `std.Some "gen":	gentarget(p)	| `std.Some "sub":	subtarget(p)	| `std.Some "man":	mantarget(p)	| `std.Some targtype:	failparse(p, "unknown targtype type %s\n", targtype)	| `std.None:	-> false	;;	-> true} /* bintarget: myrtarget */const bintarget = {p	p.targs = std.slpush(p.targs, `Bin myrtarget(p, "bin"))} /* testtarget: myrtarget */const testtarget = {p	p.targs = std.slpush(p.targs, `Test myrtarget(p, "test"))} /* libtarget: myrtarget */const libtarget = {p	p.targs = std.slpush(p.targs, `Lib myrtarget(p, "lib"))} /* subtarget : anontarget */const subtarget = {p	p.targs = std.slpush(p.targs, `Sub anontarget(p, "sub"))} /* mantarget: anontarget */const mantarget = {p	p.targs = std.slpush(p.targs, `Man anontarget(p, "man"))} /* gentarget: wordlist = wordlist ;; */const gentarget = {p	var outlist, cmdlist	var gt 	match wordlist(p)	| `std.None:	failparse(p, "gen target missing output files\n")	| `std.Some out:		outlist = out	;; 	skipspace(p)	if !matchc(p, '=')		failparse(p, "expected '=' after '%s %s'\n", cmdlist, outlist[outlist.len-1])	;; 	match wordlist(p)	| `std.None:	failparse(p, "gen target missing command\n")	| `std.Some cmd:		cmdlist = cmd	;; 	if !matchc(p, ';') || !matchc(p, ';')		failparse(p, "expected ';;' terminating genfile command, got %c\n", peekc(p))	;; 	gt = std.mk([.out = outlist, .cmd=cmdlist])	for o in outlist		std.htput(p.gensrc, o, gt)	;;	p.targs = std.slpush(p.targs, `Gen gt)} /*myrtarget: name '=' inputlist ';;'	| name attrlist = inputlist ';;'*/const myrtarget = {p, targ	var ldscript, runtime, inst, incpath	var name, inputs, libdeps, attrs	var fsel 	match word(p)	| `std.Some n:	name = n	| `std.None:	failparse(p, "expected target name after '%s'\n", targ)	;; 	skipspace(p)	if matchc(p, '{')		match attrlist(p)		| `std.Some al:	attrs = al		| `std.None:	failparse(p, "invalid attr list for %s %s\n", targ, name)		;;	else		attrs = [][:]	;; 	skipspace(p)	if !matchc(p, '=')		failparse(p, "expected '=' after '%s %s'\n", targ, name)	;; 	match inputlist(p)	| `std.Some (wl, libs): 		fsel = mkfsel()		libdeps = libs		for w in wl			fseladd(fsel, w)		;;		inputs = fselfin(fsel)		std.slfree(wl)	| `std.None: failparse(p, "expected list of file names after '%s %s'\n", targ, name)	;; 	skipspace(p)	if !matchc(p, ';') || !matchc(p, ';')		failparse(p, "expected ';;' terminating input list, got %c\n", peekc(p))	;; 	inst = true	ldscript = ""	runtime = ""	incpath = [][:]	for elt in attrs		match elt		| ("ldscript", lds):	ldscript = std.sldup(lds)		| ("runtime", rt):	runtime = std.sldup(rt)		| ("inc", path):	incpath = std.slpush(incpath, std.sldup(path))		| ("noinst", val):			if val.len != 0				failparse(p, "noinst attr does not take argument\n")			;;			inst = false		| (invalid, _):			std.fatal(1, "got invalid attr '%s'\n", invalid)		;;	;;	-> std.mk([		.name=name,		.inputs=inputs,		.libdeps=libdeps,		.install=inst,		.ldscript=ldscript,		.runtime=runtime,		.incpath=incpath,		.built=false	])} /* anontarget: '=' wordlist ';;' */const anontarget = {p, targ	var inputs 	inputs = [][:]	skipspace(p)	if !matchc(p, '=')		failparse(p, "expected '=' after '%s' target\n", targ)	;; 	match wordlist(p)	| `std.None:	failparse(p, "expected list of file names after '%s' target\n", targ)	| `std.Some wl:	inputs = wl	;;	skipspace(p)	if !matchc(p, ';') || !matchc(p, ';')		failparse(p, "expected ';;' terminating input list\n")	;;	-> inputs} /*attrlist: attrs '}' attrs	: EMPTY	| attrs attr attr	: name	| name '=' name*/const attrlist = {p	var al 	al = [][:]	while true		match word(p)		| `std.Some k:			skipspace(p)			if matchc(p, '=')				match word(p)				| `std.Some v:					al = std.slpush(al, (k, v))				| `std.None:					failparse(p, "invalid attr in attribute list\n")				;;			else				al = std.slpush(al, (k, [][:]))			;;			if !matchc(p, ',')				break			;;		| `std.None:	break		;;	;;	if !matchc(p, '}')		failparse(p, "expected '}' at end of attr list, got '%c'\n", peekc(p))	;;	if al.len == 0		-> `std.None	else		-> `std.Some al	;;} /*inputlist: EMPTY	| inputlist input input	: word	| "lib" word*/const inputlist = {p	var wl, libs 	wl = [][:]	libs = [][:]	while true		match word(p)		| `std.Some "lib":			match word(p)			| `std.Some l:	libs = std.slpush(libs, l)			| `std.None:	failparse(p, "expected lib name after 'lib'\n")			;;		| `std.Some w:	wl = std.slpush(wl, w)		| `std.None:	break		;;	;;	if wl.len == 0		-> `std.None	else		-> `std.Some (wl, libs)	;;} /* wordlist: EMPTY | wordlist word */const wordlist = {p	var wl 	wl = [][:]	while true		match word(p)		| `std.Some w:	wl = std.slpush(wl, w)		| `std.None:	break		;;	;;	if wl.len == 0		-> `std.None	else		-> `std.Some wl	;;} /* word: /wordchar*/const word = {p : parser#	var c, n	var start 	skipspace(p) 	c = peekc(p)	if c == '"'		n = 0		nextc(p)		start = p.rest		while p.rest.len > 0			c = peekc(p)			if c == '"'				nextc(p)				goto done			elif c == '\\'				c = nextc(p)			;;			nextc(p)			n += std.charlen(c)		;;		failparse(p, "input ended within quoted word\n")	else		n = 0		start = p.rest		while p.rest.len > 0			c = peekc(p)			if wordchar(c)				nextc(p)				n += std.charlen(c)			else				break			;;		;;	;;:done	if n > 0		-> `std.Some std.sldup(start[:n])	else		-> `std.None	;;} const wordchar = {c	-> std.isalnum(c) || \		c == '.' || c == '_' || c == '$' || c == '-' || \		c == '/' || c == ':' || c == '!' || c == '~' || \		c == '+'} const skipspace = {p : parser#	var c, r 	r = p.rest	while r.len > 0		c = peekc(p)		match c		| ' ':	nextc(p)		| '\t':	nextc(p)		| '\n':			nextc(p)			p.line++		| '#':			while p.rest.len > 0 && peekc(p) != '\n'				nextc(p)			;;		| _:			break		;;	;;} const matchc = {p, c	var chr, s 	if p.rest.len == 0		-> false	;;	(chr, s) = std.striter(p.rest)	if c == chr		p.rest = s		-> true	else		-> false	;;} const peekc = {p	-> std.decode(p.rest)} const nextc = {p	var c, s 	(c, s) = std.striter(p.rest)	p.rest = s	-> c}