3225 lines · 67.6 KB · Brainfuck
RawDownload
fndecls:	ref Decl;labstack:	array of ref Node;maxlabdep:	int;inexcept:	ref Node;nexc: int;fndec: ref Decl; increfs(id: ref Decl){	for( ; id != nil; id = id.link)		id.refs++;} fninline(d: ref Decl): int{	left, right: ref Node; 	n := d.init;	if(dontinline || d.inline == byte -1 || d.locals != nil || ispoly(d) || n.ty.tof.kind == Tnone || nodes(n) >= 100)		return 0;	n = n.right;	if(n.op == Oseq && n.right == nil)		n = n.left;	# 	# 	inline	# 		(a) return e;	# 		(b) if(c) return e1; else return e2;	# 		(c) if(c) return e1; return e2;	# 	case(n.op){	Oret =>		break;	Oif =>		right = n.right;		if(right.right == nil || right.left.op != Oret || right.right.op != Oret || !tequal(right.left.left.ty, right.right.left.ty))			return 0;		break;	Oseq =>		left = n.left;		right = n.right;		if(left.op != Oif || left.right.right != nil || left.right.left.op != Oret || right.op != Oseq || right.right != nil || right.left.op != Oret || !tequal(left.right.left.left.ty, right.left.left.ty))			return 0;		break;	* =>		return 0;	}	if(occurs(d, n) || hasasgns(n))		return 0;	if(n.op == Oseq){		left.right.right = right.left;		n = left;		right = n.right;		d.init.right.right = nil;	}	if(n.op == Oif){		n.ty = right.ty = right.left.left.ty;		right.left = right.left.left;		right.right = right.right.left;		d.init.right.left = mkunary(Oret, n);	}	return 1;} rewind(n: ref Node){	r, nn: ref Node; 	r = n;	nn = n.left;	for(n = n.right; n != nil; n = n.right){		if(n.right == nil){			r.left = nn;			r.right = n.left;		}		else			nn = mkbin(Oindex, nn, n.left);	}} ckmod(n: ref Node, id: ref Decl){	t: ref Type;	d, idc: ref Decl;	mod: ref Node; 	if(id == nil)		fatal("can't find function: " + nodeconv(n));	idc = nil;	mod = nil;	if(n.op == Oname){		idc = id;		mod = id.eimport;	}	else if(n.op == Omdot)		mod = n.left;	else if(n.op == Odot){		idc = id.dot;		t = n.left.ty;		if(t.kind == Tref)			t = t.tof;		if(t.kind == Tadtpick)			t = t.decl.dot.ty;		d = t.decl;		while(d != nil && d.link != nil)			d = d.link;		if(d != nil && d.timport != nil)			mod = d.timport.eimport;		n.right.left = mod;	}	if(mod != nil && mod.ty.kind != Tmodule){		nerror(n, "cannot use " + expconv(n) + " as a function reference");		return;	}	if(mod != nil){		if(valistype(mod)){			nerror(n, "cannot use " + expconv(n) + " as a function reference because " + expconv(mod) + " is a module interface");			return;		}	}else if(idc != nil && idc.dot != nil && !isimpmod(idc.dot.sym)){		nerror(n, "cannot use " + expconv(n) + " without importing " + idc.sym.name + " from a variable");		return;	}	if(mod != nil)		modrefable(n.ty);} addref(n: ref Node){	nn: ref Node; 	nn = mkn(0, nil, nil);	*nn = *n;	n.op = Oref;	n.left = nn;	n.right = nil;	n.decl = nil;	n.ty = usetype(mktype(n.src.start, n.src.stop, Tref, nn.ty, nil));} fnref(n: ref Node, id: ref Decl){	id.inline = byte -1;	ckmod(n, id);	addref(n);	while(id.link != nil)		id = id.link;	if(ispoly(id) && encpolys(id) != nil)		nerror(n, "cannot have a polymorphic adt function reference " + id.sym.name);} typecheck(checkimp: int): ref Decl{	entry, d, m: ref Decl; 	if(errors)		return nil; 	#	# generate the set of all functions	# compile one function at a time	#	gdecl(tree);	gbind(tree);	fns = array[nfns] of ref Decl;	i := gcheck(tree, fns, 0);	if(i != nfns)		fatal("wrong number of functions found in gcheck"); 	maxlabdep = 0;	for(i = 0; i < nfns; i++){		d = fns[i];		if(d != nil)			fndec = d;		if(d != nil)			fncheck(d);		fndec = nil;	} 	if(errors)		return nil; 	entry = nil;	if(checkimp){		im: ref Decl;		dm: ref Dlist; 		if(impmods == nil){			yyerror("no implementation module");			return nil;		}		for(im = impmods; im != nil; im = im.next){			for(dm = impdecls; dm != nil; dm = dm.next)				if(dm.d.sym == im.sym)					break;			if(dm == nil || dm.d.ty == nil){				yyerror("no definition for implementation module "+im.sym.name);				return nil;			}		} 		#		# can't check the module spec until all types and imports are determined,		# which happens in scheck		#		for(dm = impdecls; dm != nil; dm = dm.next){			im = dm.d;			im.refs++;			im.ty = usetype(im.ty);			if(im.store != Dtype || im.ty.kind != Tmodule){				error(im.src.start, "cannot implement "+declconv(im));				return nil;			}		}			# now check any multiple implementations		impdecl = modimp(impdecls, impmods); 		s := enter("init", 0);		for(dm = impdecls; dm != nil; dm = dm.next){			im = dm.d;			for(m = im.ty.ids; m != nil; m = m.next){				m.ty = usetype(m.ty);				m.refs++;					if(m.sym == s && m.ty.kind == Tfn && entry == nil)					entry = m;					if(m.store == Dglobal || m.store == Dfn)					modrefable(m.ty);					if(m.store == Dtype && m.ty.kind == Tadt){					for(d = m.ty.ids; d != nil; d = d.next){						d.ty = usetype(d.ty);						modrefable(d.ty);						d.refs++;					}				}			}			checkrefs(im.ty.ids);		}	}	if(errors)		return nil;	gsort(tree);	tree = nil;	return entry;}## introduce all global declarations# also adds all fields to adts and modules# note the complications due to nested Odas expressions#gdecl(n: ref Node){	for(;;){		if(n == nil)			return;		if(n.op != Oseq)			break;		gdecl(n.left);		n = n.right;	}	case n.op{	Oimport =>		importdecled(n);		gdasdecl(n.right);	Oadtdecl =>		adtdecled(n);	Ocondecl =>		condecled(n);		gdasdecl(n.right);	Oexdecl =>		exdecled(n);	Omoddecl =>		moddecled(n);	Otypedecl =>		typedecled(n);	Ovardecl =>		vardecled(n);	Ovardecli =>		vardecled(n.left);		gdasdecl(n.right);	Ofunc =>		fndecled(n);	Oas or	Odas or	Onothing =>		gdasdecl(n);	* =>		fatal("can't deal with "+opconv(n.op)+" in gdecl");	}} ## bind all global type ids,# including those nested inside modules# this needs to be done, since we may use such# a type later in a nested scope, so if we bound# the type ids then, the type could get bound# to a nested declaration#gbind(n: ref Node){	ids: ref Decl; 	for(;;){		if(n == nil)			return;		if(n.op != Oseq)			break;		gbind(n.left);		n = n.right;	}	case n.op{	Oas or	Ocondecl or	Odas or	Oexdecl or	Ofunc or	Oimport or	Onothing or	Ovardecl or	Ovardecli =>		break;	Ofielddecl =>		bindtypes(n.decl.ty);	Otypedecl =>		bindtypes(n.decl.ty);		if(n.left != nil)			gbind(n.left);	Opickdecl =>		gbind(n.left);		d := n.right.left.decl;		bindtypes(d.ty);		repushids(d.ty.ids);		gbind(n.right.right);		# get new ids for undefined types; propagate outwards		ids = popids(d.ty.ids);		if(ids != nil)			installids(Dundef, ids);	Oadtdecl or	Omoddecl =>		bindtypes(n.ty);		if(n.ty.polys != nil)			repushids(n.ty.polys);		repushids(n.ty.ids);		gbind(n.left);		# get new ids for undefined types; propagate outwards		ids = popids(n.ty.ids);		if(ids != nil)			installids(Dundef, ids);		if(n.ty.polys != nil)			popids(n.ty.polys);	* =>		fatal("can't deal with "+opconv(n.op)+" in gbind");	}} ## check all of the global declarations# bind all type ids referred to within types at the global level# record decls for defined functions#gcheck(n: ref Node, fns: array of ref Decl, nfns: int): int{	ok, allok: int; 	for(;;){		if(n == nil)			return nfns;		if(n.op != Oseq)			break;		nfns = gcheck(n.left, fns, nfns);		n = n.right;	} 	case n.op{	Ofielddecl =>		if(n.decl.ty.eraises != nil)			raisescheck(n.decl.ty);	Onothing or	Opickdecl =>		break;	Otypedecl =>		tcycle(n.ty);	Oadtdecl or	Omoddecl =>		if(n.ty.polys != nil)			repushids(n.ty.polys);		repushids(n.ty.ids);		if(gcheck(n.left, nil, 0))			fatal("gcheck fn decls nested in modules or adts");		if(popids(n.ty.ids) != nil)			fatal("gcheck installs new ids in a module or adt");		if(n.ty.polys != nil)			popids(n.ty.polys);	Ovardecl =>		varcheck(n, 1);	Ocondecl =>		concheck(n, 1);	Oexdecl =>		excheck(n, 1);	Oimport =>		importcheck(n, 1);	Ovardecli =>		varcheck(n.left, 1);		(ok, allok) = echeck(n.right, 0, 1, nil);		if(ok){			if(allok)				n.right = fold(n.right);			globalas(n.right.left, n.right.right, allok);		}	Oas or	Odas =>		(ok, allok) = echeck(n, 0, 1, nil);		if(ok){			if(allok)				n = fold(n);			globalas(n.left, n.right, allok);		}	Ofunc =>		(ok, allok) = echeck(n.left, 0, 1, n);		if(ok && n.ty.eraises != nil)			raisescheck(n.ty);		d : ref Decl = nil;		if(ok)			d = fnchk(n);		fns[nfns++] = d;	* =>		fatal("can't deal with "+opconv(n.op)+" in gcheck");	}	return nfns;} ## check for unused expression results# make sure the any calculated expression has# a destination#checkused(n: ref Node): ref Node{	#	# only nil; and nil = nil; should have type tany	#	if(n.ty == tany){		if(n.op == Oname)			return n;		if(n.op == Oas)			return checkused(n.right);		fatal("line "+lineconv(n.src.start)+" checkused "+nodeconv(n));	} 	if(n.op == Ocall && n.left.ty.kind == Tfn && n.left.ty.tof != tnone){		n = mkunary(Oused, n);		n.ty = n.left.ty;		return n;	}	if(n.op == Ocall && isfnrefty(n.left.ty)){		if(n.left.ty.tof.tof != tnone){			n = mkunary(Oused, n);			n.ty = n.left.ty;		}		return n;	}	if(isused[n.op] && (n.op != Ocall || n.left.ty.kind == Tfn))		return n;	t := n.ty;	if(t.kind == Tfn)		nerror(n, "function "+expconv(n)+" not called");	else if(t.kind == Tadt && t.tags != nil || t.kind == Tadtpick)		nerror(n, "expressions cannot have type "+typeconv(t));	else if(n.op == Otuple){		for(nn := n.left; nn != nil; nn = nn.right)			checkused(nn.left);	}	else		nwarn(n, "result of expression "+expconv(n)+" not used");	n = mkunary(Oused, n);	n.ty = n.left.ty;	return n;} fncheck(d: ref Decl){	n := d.init;	if(debug['t'])		print("typecheck tree: %s\n", nodeconv(n)); 	fndecls = nil;	adtp := outerpolys(n.left);	if(n.left.op == Odot)		repushids(adtp);	if(d.ty.polys != nil)		repushids(d.ty.polys);	repushids(d.ty.ids); 	labdep = 0;	labstack = array[maxlabdep] of ref Node;	n.right = scheck(n.right, d.ty.tof, Sother);	if(labdep != 0)

Lines 1–500 of 3225.