shithub: mc

Download patch

ref: ac297020506255ca01cde01c14145f3203d1a155
parent: 8bc429fb93070938b8bc5d459da4f2664c00abae
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Jan 7 20:19:36 EST 2016

Start of parsing files.

--- /dev/null
+++ b/mparse/ast.myr
@@ -1,0 +1,10 @@
+use std
+
+use "types.use"
+use "tokdefs.use"
+use "tok.use"
+use "util.use"
+
+pkg parse =
+;;
+
--- a/mparse/bld.proj
+++ b/mparse/bld.proj
@@ -1,7 +1,11 @@
 bin tok =
+	ast.myr
+	dump.myr
 	main.myr
-	types.myr
+	parse.myr
+	stab.myr
 	tok.myr
 	tokdefs.myr
+	types.myr
 	util.myr
 ;;
--- /dev/null
+++ b/mparse/dump.myr
@@ -1,0 +1,185 @@
+use std
+
+use "types.use"
+use "util.use"
+
+pkg parse =
+;;
+
+const __init__ = {
+	var f : file
+	var d : dcl
+	var st : stab
+	var e : expr
+
+	std.fmtinstall(std.typeof(&f), fmtfile, [][:])
+	std.fmtinstall(std.typeof(&d), fmtdcl, [][:])
+	/*std.fmtinstall(std.typeof(&n), fmtnode, [][:])*/
+	std.fmtinstall(std.typeof(&e), fmtexpr, [][:])
+	std.fmtinstall(std.typeof(&st), fmtstab, [][:])
+}
+
+/*
+const fmtnode = {sb, ap, opts
+	var f : node#
+	f = std.vanext(ap)
+	nodedump(sb, f, 0)
+}
+*/
+
+generic fmtfile = {sb, ap, opts
+	var f : file#
+	f = std.vanext(ap)
+	filedump(sb, f, 0)
+}
+
+const fmtdcl = {sb, ap, opts
+	var f : dcl#
+	f = std.vanext(ap)
+	dcldump(sb, f, 0)
+}
+
+const fmtstab = {sb, ap, opts
+	var f : stab#
+	f = std.vanext(ap)
+	stabdump(sb, f, 0)
+}
+
+const fmtexpr = {sb, ap, opts
+	var f : expr#
+	f = std.vanext(ap)
+	exprdump(sb, f)
+}
+
+
+const filedump = {sb, f, ind
+	ifmt(sb, ind, "file: {}\n", f.path)
+	for u in f.uses
+		match u
+		| `Ulocal l:	ifmt(sb, ind + 1, "local-use:\t{}\n", l)
+		| `Ulib l:	ifmt(sb, ind + 1, "lib-use:\t{}\n", l)
+		;;
+	;;
+	ifmt(sb, ind, "libs: {}\n", f.extlibs)
+	ifmt(sb, ind, "extlibs: {}\n", f.extlibs)
+
+	for i in f.extinit
+		dcldump(sb, i, ind + 1)
+	;;
+
+	match f.init
+	| `std.Some d:	dcldump(sb, d, ind + 1)
+	| `std.None:
+	;;
+
+	stabdump(sb, f.builtin, ind + 1)
+	stabdump(sb, f.globls, ind + 1)
+
+	for s in f.dcls
+		dcldump(sb, s, ind + 1)
+	;;
+}
+
+const dcldump = {sb, dcl, ind
+	ifmt(sb, ind, "{}: {} {}: {}\t", dcl.id, dcl.vis, dcl.name, dcl.ty)
+	ifmt(sb, ind + 2, "globl:{}, const:{}, noret:{}, init:{}, exportinit:{}\n", \
+		dcl.isglobl, dcl.isconst, dcl.isnoret, dcl.isinit, dcl.isexportinit)
+	ifmt(sb, ind + 2, "extern:{}, import:{}, hidden:{}, pkglocal:{}, generic:{}\n", \
+		dcl.isextern, dcl.isimport, dcl.ishidden, dcl.ispkglocal, dcl.isgeneric)
+	ifmt(sb, ind + 1, "{}", dcl.init)
+}
+
+const exprdump = {sb, e
+	match e#
+	| [.e = `Oadd (a, b)]:	std.sbfmt(sb, "{} + {}", a, b)
+	| [.e = `Osub (a, b)]:	std.sbfmt(sb, "{} - {}", a, b)
+	| [.e = `Omul (a, b)]:	std.sbfmt(sb, "{} * {}", a, b)
+	| [.e = `Odiv (a, b)]:	std.sbfmt(sb, "{} / {}", a, b)
+	| [.e = `Omod (a, b)]:	std.sbfmt(sb, "{} % {}", a, b)
+	| [.e = `Oneg exp]:	std.sbfmt(sb, "-{}", exp)
+	| [.e = `Obor (a, b)]:	std.sbfmt(sb, "{} | {}", a, b)
+	| [.e = `Oband (a, b)]:	std.sbfmt(sb, "{} & {}", a, b)
+	| [.e = `Obxor (a, b)]:	std.sbfmt(sb, "{} ^ {}", a, b)
+	| [.e = `Obsl (a, b)]:	std.sbfmt(sb, "{} << {}", a, b)
+	| [.e = `Obsr (a, b)]:	std.sbfmt(sb, "{} >> {}", a, b)
+	| [.e = `Obnot exp]:	std.sbfmt(sb, "~{}", exp)
+	| [.e = `Opreinc exp]:	std.sbfmt(sb, "++{}", exp)
+	| [.e = `Opostinc exp]:	std.sbfmt(sb, "{}++", exp)
+	| [.e = `Opredec exp]:	std.sbfmt(sb, "++{}", exp)
+	| [.e = `Opostdec exp]:	std.sbfmt(sb, "{}--", exp)
+	| [.e = `Oaddr exp]:	std.sbfmt(sb, "&{}", exp)
+	| [.e = `Oderef exp]:	std.sbfmt(sb, "{}#", exp)
+	| [.e = `Olor (a, b)]:	std.sbfmt(sb, "{} || {}", a, b)
+	| [.e = `Oland (a, b)]:	std.sbfmt(sb, "{} && {}", a, b)
+	| [.e = `Olnot exp]:	std.sbfmt(sb, "!{}", exp)
+	| [.e = `Oeq (a, b)]:	std.sbfmt(sb, "{} == {}", a, b)
+	| [.e = `One (a, b)]:	std.sbfmt(sb, "{} != {}", a, b)
+	| [.e = `Ogt (a, b)]:	std.sbfmt(sb, "{} > {}", a, b)
+	| [.e = `Oge (a, b)]:	std.sbfmt(sb, "{} >= {}", a, b)
+	| [.e = `Olt (a, b)]:	std.sbfmt(sb, "{} < {}", a, b)
+	| [.e = `Ole (a, b)]:	std.sbfmt(sb, "{} <= {}", a, b)
+	| [.e = `Oasn (a, b)]:	std.sbfmt(sb, "{} = {}", a, b)
+	| [.e = `Oaddeq (a, b)]:	std.sbfmt(sb, "{} += {}", a, b)
+	| [.e = `Osubeq (a, b)]:	std.sbfmt(sb, "{} -= {}", a, b)
+	| [.e = `Omuleq (a, b)]:	std.sbfmt(sb, "{} *= {}", a, b)
+	| [.e = `Odiveq (a, b)]:	std.sbfmt(sb, "{} /= {}", a, b)
+	| [.e = `Omodeq (a, b)]:	std.sbfmt(sb, "{} %= {}", a, b)
+	| [.e = `Oboreq (a, b)]:	std.sbfmt(sb, "{} |= {}", a, b)
+	| [.e = `Obandeq (a, b)]:	std.sbfmt(sb, "{} &= {}", a, b)
+	| [.e = `Obxoreq (a, b)]:	std.sbfmt(sb, "{} ^= {}", a, b)
+	| [.e = `Obsleq (a, b)]:	std.sbfmt(sb, "{} <<= {}", a, b)
+	| [.e = `Obsreq (a, b)]:	std.sbfmt(sb, "{} >>= {}", a, b)
+	| [.e = `Oidx (a, b)]:	std.sbfmt(sb, "{}[{}]", a, b)
+	| [.e = `Oslice (a, b, c)]:	std.sbfmt(sb, "{}[{} : {}]", a, b, c)
+	| [.e = `Omemb (a, memb)]:	std.sbfmt(sb, "{}.{}", a, memb)
+	| [.e = `Osize ty]:	std.sbfmt(sb, "sizeof({})", ty)
+	| [.e = `Ocast exp]:	std.sbfmt(sb, "{} castto({})", exp)
+	| [.e = `Oret exp]:	std.sbfmt(sb, "-> {}", exp)
+	| [.e = `Ojmp name]:	std.sbfmt(sb, "goto {}", name)
+	| [.e = `Obreak]:		std.sbfmt(sb, "break")
+	| [.e = `Ocontinue]:	std.sbfmt(sb, "continue")
+	| [.e = `Ovar name]:	std.sbfmt(sb, "{}", name)
+	| [.e = `Ogap]:		std.sbfmt(sb, "_")
+	| [.e = `Olit lit]:	std.sbfmt(sb, "{}", lit)
+	| [.e = `Ocall (f, args)]:	std.sbfmt(sb, "{}({})", f, args)
+	| [.e = `Oucon (t, `std.Some v)]:
+		std.sbfmt(sb, "{} {}", t, v)
+	| [.e = `Oucon (t, `std.None)]:
+		std.sbfmt(sb, "{}", t)
+	| [.e = `Otup al]:
+		std.sbfmt(sb, "{}", al)
+	| [.e = `Ostruct ml]:
+		std.sbfmt(sb, "{}", ml)
+	| [.e = `Oarr il]:
+		std.sbfmt(sb, "{}", il)
+	| [.e = `Oidxlen]:
+		std.sbfmt(sb, "$")
+	;;
+}
+
+const stabdump = {sb, st, ind
+	var keys
+
+	if st.name.len != 0
+		ifmt(sb, ind, "ns: {}", st.name)
+	;;
+	keys = std.htkeys(st.syms)
+	for k in keys
+		match std.get(std.htget(st.syms, k))
+		| `Dcl d:	ifmt(sb, ind, "{} : {}\n", k, d.ty)
+		| `Ucon uc:	ifmt(sb, ind, "{} : {}\n", k, uc.ety)
+		;;
+	;;
+	std.slfree(keys)
+
+	keys = std.htkeys(st.types)
+	for k in keys
+		match std.get(std.htget(st.types, k))
+		| `Tyfwd:	ifmt(sb, ind, "type {} [PROTO]", k)
+		| `Trfwd:	ifmt(sb, ind, "trait {} [PROTO]", k)
+		| `Tydef d:	ifmt(sb, ind, "type {} = {}\n", k, d)
+		| `Trdef tr:	ifmt(sb, ind, "trait {} = ...\n", k)
+		;;
+	;;
+	std.slfree(keys)
+}
--- a/mparse/main.myr
+++ b/mparse/main.myr
@@ -1,15 +1,11 @@
 use std
 
 use "tok.use"
+use "parse.use"
 
 const main = {
 	var ts
 
 	ts = parse.tokinitf(0)
-	while true
-		match parse.toknext(ts)
-		| `parse.Teof:	break
-		| tok:	std.put("{}\n", tok)
-		;;
-	;;
+	parse.tsfile(ts)
 }
--- /dev/null
+++ b/mparse/parse.myr
@@ -1,0 +1,92 @@
+use std
+
+use "ast.use"
+use "stab.use"
+use "types.use"
+use "tokdefs.use"
+use "tok.use"
+use "util.use"
+
+pkg parse =
+	const tsfile	: (ts : tokstream# -> file#)
+;;
+
+const tsfile = {ts
+	var f
+
+	f = std.mk([
+		.uses = [][:],
+		.libs = [][:],
+		.extlibs = [][:],
+		.stmts = [][:],
+		.extinit = [][:],
+		.init = `std.None,
+		.globls = mkstab(),
+		.builtin = mkstab(),
+	])
+	f.globls.super = `std.Some f.builtin
+	while true
+		match tokpeek(ts)
+		| (loc, `Teof):	
+			break
+		| (loc, `Tendln):
+			continue
+
+		| (loc, `Tuse):
+			usestmt(ts, f)
+		| (loc, `Tpkg):
+			pkgdef(ts, f)
+		| (loc, `Ttrait):
+			traitdef(ts, f)
+		| (loc, `Ttype):
+			tydef(ts, f)
+		| _:	
+			decl(ts, ts)
+		;;
+	;;
+	-> f
+}
+
+const usestmt = {ts, f
+}
+
+const pkgdef = {ts, f
+	match toknext(ts)
+	| (loc, `Tpkg):	/* ok */
+	| (loc, t):	err(loc, "unexpected token in pkg {}\n", t)
+	;;
+
+	match toknext(ts)
+	| (loc, `Tident id):	setpkg(f, f.globls, id)
+	| (loc, `Tgap):	/* pkg _ */
+	| (loc, t):	err(loc, "invalid package name {}\n", t)
+	;;
+
+	match toknext(ts)
+	| (loc, `Tasn):	/* ok */
+	| (loc, t):	err(loc, "expected '=' after pkg name, got {}\n", t)
+	;;
+
+	pkgbody(ts, f)
+
+	expectendblk(ts, f)
+}
+
+const pkgbody = {ts, f
+}
+
+const traitdef = {ts, f
+}
+
+const tydef = {ts, f
+}
+
+const decl = {ts, f
+}
+
+const expectendblk = {ts, f
+	match toknext(ts)
+	| (loc, `Tendblk):	/* ok */
+	| (loc, t):	err(loc, "expected ;; after block, got {}\n", t)
+	;;
+}
--- /dev/null
+++ b/mparse/stab.myr
@@ -1,0 +1,39 @@
+use std
+
+use "types.use"
+use "tokdefs.use"
+use "tok.use"
+use "util.use"
+
+pkg parse =
+	const setpkg	: (f : file#, st : stab#, name : byte[:]-> void)
+	const mkstab	: (-> stab#)
+;;
+
+const mkstab = {
+	-> std.mk([
+		.super = `std.None,
+		.name = "",
+		.isfunc = false,
+		.syms = std.mkht(stnamehash, stnameeq),
+		.impls = std.mkht(stnamehash, stnameeq),
+		.env = std.mkht(stnamehash, stnameeq),
+	])
+}
+
+const setpkg = {f, st, name
+	if st.name.len != 0
+		std.fatal("package name already set for pkg {}\n", st.name)
+	;;
+	st.name = name
+	std.htput(f.ns, name, st)
+}
+
+const stnamehash = {n : name#
+	-> std.strhash(n.name)
+}
+
+const stnameeq = {a, b
+	-> std.streq(a.name, b.name)
+}
+
--- a/mparse/tok.myr
+++ b/mparse/tok.myr
@@ -6,7 +6,7 @@
 
 pkg parse =
 	type tokstream = struct
-		next	: std.option(tok)
+		next	: std.option((srcloc, tok))
 		rest	: byte[:]
 		data	: byte[:]
 		loc	: srcloc
@@ -16,8 +16,8 @@
 	const tokinitf	: (path : std.fd	-> tokstream#)
 	const tokclose	: (ts : tokstream#	-> void)
 
-	const toknext	: (ts : tokstream#	-> tok)
-	const tokpeek	: (ts : tokstream#	-> tok)
+	const toknext	: (ts : tokstream#	-> (srcloc, tok))
+	const tokpeek	: (ts : tokstream#	-> (srcloc, tok))
 ;;
 
 const Eof = std.Badchar
@@ -46,11 +46,9 @@
 	match ts.next
 	| `std.Some tok:
 		ts.next = `std.None
-		std.put("tok: {}\n", tok)
 		-> tok
 	| `std.None:
 		t = tokread(ts)
-		std.put("t: {}\n", t)
 		-> t
 	;;
 }
@@ -68,30 +66,31 @@
 	;;
 }
 
-const tokread : (ts : tokstream# -> tok) = {ts
-	var c
+const tokread = {ts
+	var c, loc
 
 	skipspace(ts)
+	loc = ts.loc
 	c = peekc(ts)
 	if ts.rest.len == 0
-		-> `Teof
+		-> (loc, `Teof)
 	elif c == '\n'
 		takec(ts)
 		ts.loc.line++
 		ts.loc.col = 1
-		-> `Tendln
+		-> (loc, `Tendln)
 	elif c == '\''
-		-> chrlit(ts)
+		-> (loc, chrlit(ts))
 	elif c == '"'
-		-> strlit(ts)
+		-> (loc, strlit(ts))
 	elif c == '@'
-		-> typaram(ts)
-	elif isident(c)
-		-> kwident(ts)
+		-> (loc, typaram(ts))
 	elif std.isdigit(c)
-		-> numlit(ts)
+		-> (loc, numlit(ts))
+	elif isident(c)
+		-> (loc, kwident(ts))
 	else
-		-> oper(ts)
+		-> (loc, oper(ts))
 	;;
 }
 
@@ -267,12 +266,13 @@
 const numlit = {ts
 	var t
 
+	std.put("parsing number: {}\n", ts.rest[:10])
 	if matchc(ts, '0')
 		if matchc(ts, 'x')
 			t = number(ts, 16)
 		elif matchc(ts, 'b')
 			t = number(ts, 2)
-		elif matchc('o')
+		elif matchc(ts, 'o')
 			t = number(ts, 8)
 		else
 			t = number(ts, 10)
@@ -283,6 +283,7 @@
 	-> t
 }
 
+
 /*
 only deals with the body of the number. if we reach
 this code, then it's guaranteed that we already have
@@ -289,7 +290,54 @@
 a numerical value.
 */
 const number = {ts, base
+	var buf, nbuf
+	var isfloat, issigned
+	var v, bits
 
+	buf = ts.rest
+	nbuf = 0
+	isfloat = false
+	for var c = peekc(ts); std.isxdigit(c) || c == '.' || c == '_'; c = peekc(ts)
+		takec(ts)
+		if c == '_'
+			continue
+		elif c == '.'
+			isfloat = true
+		else 
+			v = std.charval(c, base)
+			if v < 0
+				err(ts.loc, "digit {} out of range of base {}\n", c, base)
+			;;
+		;;
+		nbuf++
+	;;
+
+	if isfloat
+		if base != 10
+			err(ts.loc, "floats must be in base 10\n")
+		;;
+		std.fatal("unable to parse floats: fuck me\n")
+		/*
+		-> `Tfltlit std.flt64parse(buf[:n])
+		*/
+	else
+		issigned = true
+		if peekc(ts) == 'u'
+			takec(ts)
+			issigned = false
+		;;
+
+		match peekc(ts)
+		| 'l':	bits = 64
+		| 'i':	bits = 32
+		| 's':	bits = 16
+		| 'b':	bits = 8
+		| _:	bits = 0
+		;;
+		v = std.get(std.intparsebase(buf[:nbuf], base))
+		/* guaranteed to be ok */
+		-> `Tintlit (v, bits, issigned)
+	;;
 }
 
 const kwident = {ts
@@ -332,7 +380,6 @@
 	var t, chr
 
 	chr = takec(ts)
-	std.put("c = '{}'\n", chr)
 	t = `Tobrace
 	match chr
 	| '{': t = `Tobrace
--- a/mparse/tokdefs.myr
+++ b/mparse/tokdefs.myr
@@ -66,7 +66,7 @@
 		`Tbreak   /* break */
 		`Tcontinue   /* continue */
 	
-		`Tintlit int64
+		`Tintlit (int64, int, bool) /* val, sz, sign */
 		`Tstrlit byte[:]
 		`Tfltlit flt64
 		`Tchrlit char
--- a/mparse/types.myr
+++ b/mparse/types.myr
@@ -1,3 +1,5 @@
+use std
+
 pkg parse =
 	type srcloc = struct
 		file	: byte[:]
@@ -9,5 +11,280 @@
 		`Attrpkglocal
 		`Attrextern
 		`Attrnoret
+	;;
+
+	type file = struct
+		path	: byte[:]
+		uses	: usefile[:]
+		libs	: byte[:][:]
+		extlibs	: byte[:][:]
+		extinit	: dcl#[:]
+		init	: std.option(dcl#)
+		builtin	: stab#
+		globls	: stab#
+		ns	: std.htab(byte[:], node#)#
+		dcls	: dcl#[:]
+	;;
+
+	type node = union
+		`Nexpr	expr
+		`Nlit	lit
+		`Nloop	loopstmt
+		`Niter	iterstmt
+		`Nif	ifstmt
+		`Nmatch matchstmt
+		`Ncase	matchcase
+		`Ndcl	dcl#
+		`Nfunc	func
+		`Ntrait traitdef
+		`Nimpl	impldef
+	;;
+
+	type tydef = struct
+		ty	: ty
+		id	: int32
+		loc	: srcloc
+		fixed	: bool
+		found	: bool
+		traits	: std.bitset#
+	;;
+		
+	type ty = union
+		`Tyvoid
+		`Tybool
+		/* integers */
+		`Tyint8
+		`Tyint16
+		`Tyint32
+		`Tyint
+		/* unsigned integers */
+		`Tychar
+		`Tybyte
+		`Tyint64
+		`Tyuint8
+		`Tyuint16
+		`Tyuint32
+		`Tyuint
+		`Tyuint64
+		/*floats */
+		`Tyflt32
+		`Tyflt64
+		/* a bit odd.. */
+		`Tyvalist
+		/* compound types */
+		`Tyslice tydef#
+		`Typtr tydef#
+		`Tyarray (tydef#, node#)
+		`Tystruct (dcl#[:])
+		`Tyunion (ucon#[:])
+		/* user defined types */
+		`Tygeneric (tydef#[:], tydef#)
+		`Tyname	(tydef#[:], tydef#)
+		`Typaram byte[:]
+		`Tyvar int64
+	;;
+
+	type ucon = struct
+		loc	: srcloc
+		name	: name#
+		uty	: tydef#
+		ety	: std.option(tydef#)
+	;;
+
+	type impldef = struct
+		vis	: vis
+		tr	: name#
+		ty	: tydef#
+		aux	: tydef#[:]
+		dcls	: dcl#[:]
+		isimport	: bool
+	;;
+
+	type expr = struct
+		ty	: tydef#
+		loc	: srcloc
+		e	: union
+			`Oadd	(node#, node#)
+			`Osub	(node#, node#)
+			`Omul	(node#, node#)
+			`Odiv	(node#, node#)
+			`Omod	(node#, node#)
+			`Oneg	node#
+			`Obor	(node#, node#)
+			`Oband	(node#, node#)
+			`Obxor	(node#, node#)
+			`Obsl	(node#, node#)
+			`Obsr	(node#, node#)
+			`Obnot	node#
+			`Opreinc	node#
+			`Opostinc	node#
+			`Opredec	node#
+			`Opostdec	node#
+			`Oaddr	node#
+			`Oderef	node#
+			`Olor	(node#, node#)
+			`Oland	(node#, node#)
+			`Olnot	node#
+			`Oeq	(node#, node#)
+			`One	(node#, node#)
+			`Ogt	(node#, node#)
+			`Oge	(node#, node#)
+			`Olt	(node#, node#)
+			`Ole	(node#, node#)
+			`Oasn	(node#, node#)
+			`Oaddeq	(node#, node#)
+			`Osubeq	(node#, node#)
+			`Omuleq	(node#, node#)
+			`Odiveq	(node#, node#)
+			`Omodeq	(node#, node#)
+			`Oboreq	(node#, node#)
+			`Obandeq	(node#, node#)
+			`Obxoreq	(node#, node#)
+			`Obsleq	(node#, node#)
+			`Obsreq	(node#, node#)
+			`Oidx	(node#, node#)
+			`Oslice	(node#, node#, node#)
+			`Omemb	(node#, byte[:])
+			`Osize	ty#
+			`Ocall	(node#, node#[:])
+			`Ocast	node#
+			`Oret	node#
+			`Ojmp	name#
+			`Obreak
+			`Ocontinue
+			`Ovar	name#
+			`Ogap
+			`Olit	lit
+			`Oucon	(name#, std.option(node#))
+			`Otup	node#[:]
+			`Ostruct	(name#, node#)[:]
+			`Oarr	(node#, node#)[:]
+			`Oidxlen
+		;;
+	;;
+
+	type dcl = struct
+		id	: int32
+		name	: name
+		vis	: vis
+
+		ty	: tydef#
+		init	: expr#
+		tr	: traitdef#
+		impls	: std.htab(tydef#, dcl#)
+
+		isglobl	: bool
+		isconst	: bool
+		isnoret	: bool
+		isinit	: bool
+		isexportinit	: bool
+		isextern	: bool
+		isimport	: bool
+		ishidden	: bool
+		ispkglocal	: bool
+		isgeneric	: bool
+	;;
+
+	type loopstmt = struct
+		init	: expr#
+		cond	: expr#
+		step	: expr#
+		body	: block#
+		scope	: stab#
+	;;
+
+	type iterstmt = struct
+		elt	: expr#
+		seq	: expr#
+		body	: block#
+	;;
+
+	type ifstmt = struct
+		cond	: expr#
+		iftrue	: block#
+		iffalse	: block#
+	;;
+
+	type block = struct
+		stab	: stab#
+		stmts	: node#[:]
+	;;
+
+	type matchstmt = struct
+		val	: expr#
+		matches	: matchcase#[:]
+	;;
+
+	type matchcase = struct
+		expr	: node#
+		blk	: block#
+	;;
+
+	type lit = union
+		`Lint	uint64
+		`Lflt	flt64
+		`Lchr	char
+		`Lstr	byte[:]
+		`Llbl	byte[:]
+		`Lbool	bool
+		`Lvoid
+	;;
+
+	type traitdef = struct
+		id	: int32
+		loc	: srcloc
+		vis	: vis
+		name	: name
+		param	: tydef#
+		aux	: tydef#[:]
+		memb	: dcl#[:]
+		funcs	: dcl#[:]
+	;;
+
+	type usefile = union
+		`Ulocal	byte[:]
+		`Ulib	byte[:]
+	;;
+
+	type func = struct
+		stab	: stab#
+		ty	: tydef#
+		args	: dcl#[:]
+		body	: block#
+	;;
+
+	type stab = struct
+		super	: std.option(stab#)
+		name	: byte[:]
+		isfunc	: bool
+
+		syms	: std.htab(name, sym)#
+		types	: std.htab(name, tysym)#
+		impls	: std.htab(name, node#)#
+		env	: std.htab(name, node#)#
+	;;
+
+	type sym = union
+		`Dcl	dcl#
+		`Ucon	ucon#
+	;;
+
+	type tysym = union
+		`Tyfwd
+		`Trfwd
+		`Tydef	tydef#
+		`Trdef	traitdef#
+	;;
+
+	type name = struct
+		ns	: byte[:]
+		name	: byte[:]
+	;;
+
+	type vis = union
+		`Visintern
+		`Vishidden
+		`Visexport
+		`Visbuiltin
 	;;
 ;;
--- a/mparse/util.myr
+++ b/mparse/util.myr
@@ -3,12 +3,34 @@
 use "types.use"
 
 pkg parse =
+	const ifmt	: (sb : std.strbuf#, ind : int, fmt : byte[:], args : ... -> void)
 	$noret const err	: (loc : srcloc, msg : byte[:], args : ... -> void)
-	$noret const verr	: (loc : srcloc, msg : byte[:], args : std.valist -> void)
+	$noret const verr	: (loc : srcloc, msg : byte[:], args : std.valist# -> void)
 ;;
 
 const err = {loc, msg, args
+	var ap
+	
+	ap = std.vastart(&args)
+	verr(loc, msg, &ap)
 }
 
 const verr = {loc, msg, ap
+	var sb, ln
+
+	sb = std.mksb()
+	std.sbfmtv(sb, msg, ap)
+	ln = std.sbfin(sb)
+	std.fatal("{}:{}:{}: {}\n", loc.file, loc.line, loc.col, ln)
+	std.slfree(ln)
+}
+
+const ifmt = {sb, ind, fmt, args : ...
+	var ap
+
+	ap = std.vastart(&args)
+	for var i = 0; i < ind; i++
+		std.sbputs(sb, "  ")
+	;;
+	std.sbfmtv(sb, fmt, &ap)
 }
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -224,8 +224,7 @@
 			size_t nextlibs;
 			Node **stmts; /* all top level statements */
 			size_t nstmts;
-			Node
-				**init; /* a list of all __init__ function names of our deps. NB, this
+			Node **init; /* a list of all __init__ function names of our deps. NB, this
 					   is a Nname, not an Ndecl */
 			size_t ninit;
 			Node *localinit; /* and the local one, if any */
@@ -334,13 +333,6 @@
 			char isexportinit;
 			char isinit;
 		} decl;
-
-		struct {
-			long uid;
-			Node *name;
-			Type *elt;
-			Type *alt;
-		} uelt;
 
 		struct {
 			Stab *scope;
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -645,7 +645,7 @@
 			continue;
 		if (c == '.')
 			isfloat = 1;
-		else if (hexval(c) < 0 || hexval(c) > base)
+		else if (hexval(c) < 0 || hexval(c) >= base)
 			lfatal(curloc, "Integer digit '%c' outside of base %d", c, base);
 		if (nbuf >= sizeof buf - 1) {
 			buf[nbuf - 1] = '\0';