Charles.Forsyth20060303a828770d19 years agoHistory
863 lines · 18.7 KB · Brainfuck
RawDownload
exec(ex: ref Exec, code: ref Code): Completion{	ssp := ex.sp; 	r := estmt(ex, code, 0, code.npc); 	if(r.kind == CThrow)		ex.sp = ssp; 	if(ssp != ex.sp)		runtime(ex, InternalError, "internal error: exec stack not balanced"); 	if(r.lab != nil)		runtime(ex, InternalError, "internal error: label out of stack");	return r;} estmt(ex: ref Exec, code: ref Code, pc, epc: int): Completion{	e: ref Ref;	ev: ref Val;	k, apc, pc2, apc2, pc3, apc3, c: int;	lab: string;	labs: list of string; 	osp := ex.sp; {	v : ref Val = nil;	k1 := CNormal;	while(pc < epc){		v1 : ref Val = nil; 		labs = nil;		op := int code.ops[pc++];		while(op == Llabel){			(pc, c) = getconst(code.ops, pc);			labs = code.strs[c] :: labs;			op = int code.ops[pc++];		}		if(debug['e'] > 1)			print("estmt(pc %d, sp %d) %s\n", pc-1, ex.sp, tokname(op));		case op {		Lbreak =>			return (CBreak, v, nil);		Lcontinue =>			return (CContinue, v, nil);		Lbreaklab =>			(pc, c) = getconst(code.ops, pc);			return (CBreak, v, code.strs[c]);		Lcontinuelab =>			(pc, c) = getconst(code.ops, pc);			return (CContinue, v, code.strs[c]);		Lreturn =>			(pc, v) = eexpval(ex, code, pc, code.npc);			return (CReturn, v, nil);		'{' =>			(pc, apc) = getjmp(code.ops, pc);			(k1, v1, lab) = estmt(ex, code, pc, apc);			pc = apc;		Lif =>			(pc, apc) = getjmp(code.ops, pc);			(pc, ev) = eexpval(ex, code, pc, apc);			(pc, apc) = getjmp(code.ops, pc);			(pc2, apc2) = getjmp(code.ops, apc);			if(toBoolean(ex, ev) != false)				(k1, v1, lab) = estmt(ex, code, pc, apc);			else if(pc2 != apc2)				(k1, v1, lab) = estmt(ex, code, pc2, apc2);			pc = apc2;		Lwhile =>			(pc, apc) = getjmp(code.ops, pc);			(pc2, apc2) = getjmp(code.ops, apc);			for(;;){				(nil, ev) = eexpval(ex, code, pc, apc);				if(toBoolean(ex, ev) == false)					break;				(k, v1, lab) = estmt(ex, code, pc2, apc2);				if(v1 != nil)					v = v1;				if(k == CBreak || k == CContinue){					if(initlabs(lab, labs)){						if(k == CBreak)							break;						else							continue;					}					else						return (k, v1, lab);				}				if(k == CReturn || k == CThrow)					return (k, v1, nil);			}			pc = apc2;		Ldo =>			(pc, apc) = getjmp(code.ops, pc);			(pc2, apc2) = getjmp(code.ops, apc);			for(;;){				(k, v1, lab) = estmt(ex, code,  pc, apc);				if(v1 != nil)					v = v1;				if(k == CBreak || k == CContinue){					if(initlabs(lab, labs)){						if(k == CBreak)							break;						else							continue;					}					else						return (k, v1, lab);				}				if(k == CReturn || k == CThrow)					return (k, v1, nil);				(nil, ev) = eexpval(ex, code, pc2, apc2);				if(toBoolean(ex, ev) == false)					break;			}			pc = apc2;		Lfor or		Lforvar =>			(pc, apc) = getjmp(code.ops, pc);			(pc, nil) = eexpval(ex, code, pc, apc);			(pc, apc) = getjmp(code.ops, pc);			(pc2, apc2) = getjmp(code.ops, apc);			(pc3, apc3) = getjmp(code.ops, apc2);			for(;;){				(nil, e) = eexp(ex, code, pc, apc);				if(e != nil && toBoolean(ex, getValue(ex, e)) == false)					break;				(k, v1, lab) = estmt(ex, code, pc3, apc3);				if(v1 != nil)					v = v1;				if(k == CBreak || k == CContinue){					if(initlabs(lab, labs)){						if(k == CBreak)							break;						else							continue;					}					else						return (k, v1, lab);				}				if(k == CReturn || k == CThrow)					return (k, v1, nil);				eexpval(ex, code, pc2, apc2);			}			pc = apc3;		Lforin or		Lforvarin =>			(pc, apc) = getjmp(code.ops, pc);			(pc2, apc2) = getjmp(code.ops, apc);			(pc3, apc3) = getjmp(code.ops, apc2);			if(op == Lforvarin){				(nil, nil) = eexp(ex, code, pc, apc);				# during for only evaluate the id, not the initializer				apc = pc + 1;			}			(nil, ev) = eexpval(ex, code, pc2, apc2);			bo := toObject(ex, ev); 			#			# note this won't enumerate host properties			#			enum:			for(o := bo; o != nil; o = o.prototype){				if(o.host != nil && o.host != me)					continue;				for(i := 0; i < len o.props; i++){					if(o.props[i] == nil					|| (o.props[i].attr & DontEnum)					|| propshadowed(bo, o, o.props[i].name))						continue;					(nil, e) = eexp(ex, code, pc, apc);					putValue(ex, e, strval(o.props[i].name));					(k, v1, lab) = estmt(ex, code, pc3, apc3);					if(v1 != nil)						v = v1;					if(k == CBreak || k == CContinue){						if(initlabs(lab, labs)){							if(k == CBreak)								break enum;							else								continue enum;						}						else							return (k, v1, lab);					}					if(k == CReturn || k == CThrow)						return (k, v1, nil);				}			}			pc = apc3;		Lwith =>			(pc, apc) = getjmp(code.ops, pc);			(pc, ev) = eexpval(ex, code, pc, apc);			pushscope(ex, toObject(ex, ev));			(pc, apc) = getjmp(code.ops, pc);			(k1, v1, lab) = estmt(ex, code, pc, apc);			popscope(ex);			pc = apc;		';' =>			;		Lvar =>			(pc, apc) = getjmp(code.ops, pc);			(pc, nil) = eexp(ex, code, pc, apc);		Lswitch =>			(pc, apc) = getjmp(code.ops, pc);			(pc, ev) = eexpval(ex, code, pc, apc);			(pc, apc) = getjmp(code.ops, pc);			(k1, v1, lab) = ecaseblk(ex, code, ev, pc, apc, labs);			pc = apc;		Lthrow =>			(pc, v) = eexpval(ex, code, pc, code.npc);			ex.error = toString(ex, v);			return (CThrow, v, nil);		Lprint =>			(pc, v1) = eexpval(ex, code, pc, code.npc);			print("%s\n", toString(ex, v1));		Ltry =>			(pc, apc) = getjmp(code.ops, pc);			(k1, v1, lab) = estmt(ex, code,  pc, apc);			(kc, vc) := (k1, v1);			(pc, apc) = getjmp(code.ops, apc);			if(pc != apc){				(pc, c) = getconst(code.ops, ++pc);				if(k1 == CThrow){					o := mkobj(ex.objproto, "Object");					valinstant(o, DontDelete, code.strs[c], v1);					pushscope(ex, o);					(k1, v1, lab) = estmt(ex, code, pc, apc);					popscope(ex);					if(k1 != CNormal)						(kc, vc) = (k1, v1);				}			}			(pc, apc) = getjmp(code.ops, apc);			if(pc != apc){				(k, v, lab) = estmt(ex, code, pc, apc);				if(k == CNormal)					(k1, v1) = (kc, vc);				else					(k1, v1) = (k, v);			}			pc = apc;		* =>			(pc, e) = eexp(ex, code, pc-1, code.npc);			if(e != nil)				v1 = getValue(ex, e);			if(debug['v'])				print("%s\n", toString(ex, v1));		} 		if(v1 != nil)			v = v1;		if(k1 == CBreak && lab != nil && inlabs(lab, labs))			(k1, lab) = (CNormal, nil);		if(k1 != CNormal)			return (k1, v, lab);	}	return (CNormal, v, nil);}exception{	"throw" =>		ex.sp = osp;		return (CThrow, ex.errval, nil);}} ecaseblk(ex : ref Exec, code : ref Code, sv : ref Val, pc, epc : int, labs: list of string) : Completion{	defpc, nextpc, clausepc, apc : int;	ev : ref Val;	lab: string; 	k := CNormal;	v := undefined;	matched := 0; 	(pc, defpc) = getjmp(code.ops, pc);	clausepc = pc;	(pc, nextpc) = getjmp(code.ops, pc);	for (; pc <= epc; (clausepc, (pc, nextpc)) = (nextpc, getjmp(code.ops, nextpc))) {		if (nextpc == epc) {			if (matched || defpc == epc)				break;			# do the default			matched = 1;			nextpc = defpc;			continue;		}		if (!matched && clausepc == defpc)			# skip default case - still scanning guards			continue;		if (clausepc != defpc) {			# only case clauses have guard exprs			(pc, apc) = getjmp(code.ops, pc);			if (matched)				pc = apc;			else {				(pc, ev) = eexpval(ex, code, pc, apc);				if (identical(sv, ev))					matched = 1;				else					continue;			}		}		(k, v, lab) = estmt(ex, code, pc, nextpc);		if(k == CBreak && initlabs(lab, labs))			return (CNormal, v, nil);		if(k == CBreak || k == CContinue || k == CReturn || k == CThrow)			return (k, v, lab);	}	return (k, v, lab);} identical(v1, v2 : ref Val) : int{	if (v1.ty != v2.ty)		return 0;	ret := 0;	case v1.ty{	TUndef or	TNull =>		ret = 1;	TNum =>		if(v1.num == v2.num)			ret = 1;	TBool =>		if(v1 == v2)			ret = 1;	TStr =>		if(v1.str == v2.str)			ret = 1;	TObj =>		if(v1.obj == v2.obj)			ret = 1;	TRegExp =>		if(v1.rev == v2.rev)			ret = 1;	}	return ret;} eexpval(ex: ref Exec, code: ref Code, pc, epc: int): (int, ref Val){	e: ref Ref; 	(pc, e) = eexp(ex, code, pc, epc);	if(e == nil)		v := undefined;	else		v = getValue(ex, e);	return (pc, v);} eexp(ex: ref Exec, code: ref Code, pc, epc: int): (int, ref Ref){	o, th: ref Obj;	a1: ref Ref;	v, v1, v2: ref Val;	s: string;	r1, r2: real;	c, apc, i1, i2: int; 	savesp := ex.sp;out:	while(pc < epc){		op := int code.ops[pc++];		if(debug['e'] > 1){			case op{			Lid or			Lstr or			Lregexp =>				(nil, c) = getconst(code.ops, pc);				print("eexp(pc %d, sp %d) %s '%s'\n", pc-1, ex.sp, tokname(op), code.strs[c]);			Lnum =>				(nil, c) = getconst(code.ops, pc);				print("eexp(pc %d, sp %d) %s '%g'\n", pc-1, ex.sp, tokname(op), code.nums[c]);			* =>				print("eexp(pc %d, sp %d) %s\n", pc-1, ex.sp, tokname(op));			}		}		case op{		Lthis =>			v1 = objval(ex.this);		Lnum =>			(pc, c) = getconst(code.ops, pc);			v1 = numval(code.nums[c]);		Lstr =>			(pc, c) = getconst(code.ops, pc);			v1 = strval(code.strs[c]);		Lregexp =>			(pc, c) = getconst(code.ops, pc);			(p, f) := rsplit(code.strs[c]);			o = nregexp(ex, nil, array[] of { strval(p), strval(f) });			v1 = objval(o);			# v1 = regexpval(p, f, 0);		Lid =>			(pc, c) = getconst(code.ops, pc);			epush(ex, esprimid(ex, code.strs[c]));			continue;		Lnoval =>			v1 = undefined;		'.' =>			a1 = epop(ex);			v1 = epopval(ex);			epush(ex, ref Ref(1, nil, toObject(ex, v1), a1.name));			continue;		'[' =>			v2 = epopval(ex);			v1 = epopval(ex);			epush(ex, ref Ref(1, nil, toObject(ex, v1), toString(ex, v2)));			continue;		Lpostinc or		Lpostdec =>			a1 = epop(ex);			r1 = toNumber(ex, getValue(ex, a1));			v1 = numval(r1);			if(op == Lpostinc)				r1++;			else				r1--;			putValue(ex, a1, numval(r1));		Linc or		Ldec or		Lpreadd or		Lpresub =>			a1 = epop(ex);			r1 = toNumber(ex, getValue(ex, a1));			case op{			Linc =>				r1++;			Ldec =>				r1--;			Lpresub =>				r1 = -r1;			}			v1 = numval(r1);			if(op == Linc || op == Ldec)				putValue(ex, a1, v1);		'~' =>			v = epopval(ex);			i1 = toInt32(ex, v);			i1 = ~i1;			v1 = numval(real i1);		'!' =>			v = epopval(ex);			v1 = toBoolean(ex, v);			if(v1 == true)				v1 = false;			else				v1 = true;		Ltypeof =>			a1 = epop(ex);			if(a1.isref && getBase(ex, a1) == nil)				s = "undefined";			else case (v1 = getValue(ex, a1)).ty{			TUndef =>				s = "undefined";			TNull =>				s = "object";			TBool =>				s = "boolean";			TNum =>				s = "number";			TStr =>				s = "string";			TObj =>				if(v1.obj.call != nil)					s = "function";				else					s = "object";			TRegExp =>				s = "regexp";			}			v1 = strval(s);		Ldelete =>			a1 = epop(ex);			o = getBase(ex, a1);			s = getPropertyName(ex, a1);			if(o != nil)				esdelete(ex, o, s, 0);			v1 = undefined;		Lvoid =>			epopval(ex);			v = undefined;		'*' or		'/' or		'%' or		'-' =>			v2 = epopval(ex);			a1 = epop(ex);			r1 = toNumber(ex, getValue(ex, a1));			r2 = toNumber(ex, v2);			case op{			'*' =>				r1 = r1 * r2;			'/' =>				r1 = r1 / r2;			'%' =>				r1 = fmod(r1, r2);			'-' =>

Lines 1–500 of 863.