Charles.Forsyth20060303a828770d19 years agoHistory
1286 lines · 26.3 KB · Brainfuck
RawDownload
strhas(s: string, c: int): ref Val{	for(i := 0; i < len s; i++)		if(s[i] == c)			return true;	return false;} rsplit(r: string): (string, string){	esc := 0;	i := 1;	# skip '/'	for(;;){		c := r[i++];		if(!esc && c == '/')			break;		esc = !esc && c == '\\';	}	return (r[1: i-1], r[i: ]);}		badflags(f: string): int{	g := i := m := 0;	for(j := 0; j < len f; j++){		case(f[j]){			'g' =>				g++;			'i' =>				i++;			'm' =>				m++;			* =>				return 1;		}	}	return g > 1 || i > 1 || m > 1;} regexpvals(ex: ref Exec, v: ref Val, o: ref Ecmascript->Obj): (string, string, int){	if(v != nil){		if(v.ty == TRegExp)			return (v.rev.p, v.rev.f, v.rev.i);		o = v.obj;	}	p := toString(ex, esget(ex, o, "source", 0));	f := "";	if(toBoolean(ex, esget(ex, o, "global", 0)) == true)		f += "g";	if(toBoolean(ex, esget(ex, o, "ignoreCase", 0)) == true)		f += "i";	if(toBoolean(ex, esget(ex, o, "multiline", 0)) == true)		f += "m";	i := toInt32(ex, esget(ex, o, "lastIndex", 0));	return (p, f, i);} nregexp(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj{	pat := biarg(args, 0);	flags := biarg(args, 1);	(p, f) := ("", "");	if(isregexp(pat)){		if(flags == undefined)			(p, f, nil) = regexpvals(ex, pat, nil);		else			runtime(ex, TypeError, "flags defined");	}	else{		if(pat == undefined)			p = "";		else			p = toString(ex, pat);		if(flags == undefined)			f = "";		else			f = toString(ex, flags);	}	o := nobj(ex, nil, array[] of { regexpval(p, f, 0) });	if(badflags(f))		runtime(ex, SyntaxError, "bad regexp flags");	regex = ex;	(re, err) := compile(p, 1);	if(re == nil || err != nil)		runtime(ex, SyntaxError, "bad regexp pattern");	o.re = re;	return o;} cregexp(ex: ref Exec, f, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val{	pat := biarg(args, 0);	flags := biarg(args, 1);	if(isregexp(pat) && flags == undefined)		return pat;	return objval(nregexp(ex, f, args));} cregexpprotoexec(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val): ref Val{	m: array of (int, int); 	regexpcheck(ex, this, f);	s := toString(ex, biarg(args, 0));	l := len s;	i := toInt32(ex, esget(ex, this, "lastIndex", 0));	e := 0;	glob := esget(ex, this, "global", 0);	multiline := esget(ex, this, "multiline", 0);	ignorecase := esget(ex, this, "ignoreCase", 0);	if(glob == false)		i = 0;	for(;;){		if(i < 0 || i >= l){			esput(ex, this, "lastIndex", numval(real 0), 0);			return null;		}		regex = ex;		m = executese(this.re, s, (i, len s), i == 0, 1, multiline == true, ignorecase == true);		if(m != nil)			break;		i++;		i = -1;	# no need to loop with executese	}	(i, e) = m[0];	if(glob == true)		esput(ex, this, "lastIndex", numval(real e), 0);	n := len m;	av := array[n] of ref Val;	for(j := 0; j < n; j++){		(a, b) := m[j];		if(a < 0)			av[j] = undefined;		else			av[j] = strval(s[a: b]);	}	a := narray(ex, nil, av);	esput(ex, a, "index", numval(real i), 0);	esput(ex, a, "input", strval(s), 0);	return objval(a);} cregexpprototest(ex: ref Exec, f, this: ref Ecmascript->Obj, args: array of ref Val): ref Val{	regexpcheck(ex, this, f);	v := cregexpprotoexec(ex, f, this, args);	if(!isnull(v))		return true;	return false;} cregexpprototoString(ex: ref Exec, f, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val{	regexpcheck(ex, this, f);	(p, fl, nil) := regexpvals(ex, nil, this);	return strval("/" + p + "/" + fl);} regexpcheck(ex: ref Exec, o: ref Ecmascript->Obj, f: ref Obj){	if(f == nil)		s := "exec";	else		s = f.val.str;	if(!isregexpobj(o))		runtime(ex, TypeError, "RegExp.prototype." + s + " called on non-RegExp object");} cstrprotomatch(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val{	v := biarg(args, 0);	if(!isregexp(v))		re := nregexp(ex, nil, args);	else if(v.ty == TObj)		re = v.obj;	else		re = nobj(ex, nil, args);	s := toString(ex, this.val);	glob := esget(ex, re, "global", 0);	av := array[1] of ref Val;	av[0] = strval(s);	if(glob == false)		return cregexpprotoexec(ex, nil, re, av);	li := 0;	esput(ex, re, "lastIndex", numval(real li), 0);	ms: list of ref Val;	for(;;){		v = cregexpprotoexec(ex, nil, re, av);		if(isnull(v))			break;		ms = esget(ex, v.obj, "0", 0) :: ms;		ni := int toUint32(ex, esget(ex, re, "lastIndex", 0));		if(ni == li)			esput(ex, re, "lastIndex", numval(real ++li), 0);		else			li = ni;	}		n := len ms;	av = array[n] of ref Val;	for(j := n-1; j >= 0; j--){		av[j] = hd ms;		ms = tl ms;	}	return objval(narray(ex, nil, av));} cstrprotoreplace(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val{	re: ref Ecmascript->Obj; 	v := biarg(args, 0);	rege := isregexp(v);	if(!rege){		if(args == nil)			re = nregexp(ex, nil, args);		else			re = nregexp(ex, nil, args[0:1]);	}	else if(v.ty == TObj)		re = v.obj;	else		re = nobj(ex, nil, args);	s := toString(ex, this.val);	if(rege)		glob := esget(ex, re, "global", 0);	else		glob = false;	av := array[1] of ref Val;	av[0] = strval(s);	ms: list of ref Val;	li := 0;	if(glob == true)		esput(ex, re, "lastIndex", numval(real li), 0);	for(;;){		v = cregexpprotoexec(ex, nil, re, av);		if(!isnull(v))			ms = v :: ms;		if(isnull(v) || glob == false)			break;		ni := int toUint32(ex, esget(ex, re, "lastIndex", 0));		if(ni == li)			esput(ex, re, "lastIndex", numval(real ++li), 0);		else			li = ni;	}	if(ms == nil)		return strval(s);	ms = rev(ms);	if(rege)		lcp := int toUint32(ex, esget(ex, (hd ms).obj, "length", 0))-1;	else		lcp = 0;	v = biarg(args, 1);	if(isobj(v) && isfuncobj(v.obj)){		ns := s;		n := len ms;		args = array[lcp+3] of ref Val;		o := inc := 0;		for(i := 0; i < n; i++){			a := (hd ms).obj;			ms = tl ms;			for(j := 0; j <= lcp; j++)				args[j] = esget(ex, a, string j, 0);			ss := toString(ex, args[0]);			o = offset(ss, s, o);			args[lcp+1] = numval(real o);			args[lcp+2] = strval(s);			rs := toString(ex, getValue(ex, escall(ex, v.obj, nil, args, 0)));			ns = repl(ns, o+inc, o+inc+len ss, rs);			o += len ss;			inc += len rs - len ss;		}		return strval(ns);	}	else{		ps := toString(ex, v);		lps := len ps;		ns := s;		n := len ms;		o := inc := 0;		for(i := 0; i < n; i++){			a := (hd ms).obj;			ms = tl ms;			ss := toString(ex, esget(ex, a, "0", 0));			o = offset(ss, s, o);			rs := "";			for(j := 0; j < lps; j++){				if(ps[j] == '$' && j < lps-1){					j++;					case(c := ps[j]){						'$' =>							rs += "$";						'&' =>							rs += ss;						'`' =>							rs += s[0: o];						''' =>							rs += s[o+len ss: ];						'0' to '9' =>							if(j < lps-1 && isdigit(ps[j+1]))								c = 10*(c-'0')+ps[++j]-'0';							else								c = c-'0';							if(c >= 1 && c <= lcp)								rs += toString(ex, esget(ex, a, string c, 0));					}				}				else					rs += ps[j: j+1];			}			ns = repl(ns, o+inc, o+inc+len ss, rs);			o += len ss;			inc += len rs - len ss;		}		return strval(ns);	}} cstrprotosearch(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val{	v := biarg(args, 0);	if(!isregexp(v))		re := nregexp(ex, nil, args);	else if(v.ty == TObj)		re = v.obj;	else		re = nobj(ex, nil, args);	s := toString(ex, this.val);	glob := esget(ex, re, "global", 0);	esput(ex, re, "global", false, 0);	av := array[1] of ref Val;	av[0] = strval(s);	v = cregexpprotoexec(ex, nil, re, av);	if(isnull(v))		r := -1;	else{		ss := toString(ex, esget(ex, v.obj, "0", 0));		r = offset(ss, s, 0);	}	esput(ex, re, "global", glob, 0);	return numval(real r);} offset(ss: string, s: string, m: int): int{	nn := len ss;	n := len s;	for(i := m; i <= n-nn; i++){		if(s[i: i+nn] == ss)			return i;	}	return -1;} repl(s: string, a: int, b: int, ns: string): string{	return s[0: a] + ns + s[b: ];} rev(ls: list of ref Val): list of ref Val{	ns: list of ref Val; 	for( ; ls != nil; ls = tl ls)		ns = hd ls :: ns;	return ns;} ########################################################################## regex.b originally # normally imported identifiers # internal identifiers, not normally imported ALT, CAT, DOT, SET, HAT, DOL, NUL, PCLO, CLO, OPT, LPN, RPN, LPN0, RPN0, LPN1, RPN1, LPN2, RPN2, BEET, BEEF, MNCLO, LCP, IDLE: con (1<<16)+iota; # syntax # RE	ALT		regular expression#	NUL# ALT	CAT		alternation# 	CAT | ALT## CAT	DUP		catenation# 	DUP CAT## DUP	PRIM		possibly duplicated primary# 	PCLO# 	CLO# 	OPT## PCLO	PRIM +		1 or more# CLO	PRIM *		0 or more# OPT	PRIM ?		0 or 1## PRIM	( RE )#	()# 	DOT		any character# 	CHAR		a single character#	ESC		escape sequence# 	[ SET ]		character set# 	NUL		null string# 	HAT		beginning of string# 	DOL		end of string# regex: ref Exec; NIL : con -1;		# a refRex constantNONE: con -2;		# ditto, for an un-set valueBAD: con 1<<16;		# a non-character HUGE: con (1<<31) - 1; # the data structures of re.m would like to be ref-linked, but are# circular (see fn walk), thus instead of pointers we use indexes# into an array (arena) of nodes of the syntax tree of a regular expression.# from a storage-allocation standpoint, this replaces many small# allocations of one size with one big one of variable size. ReStr: adt {	s : string;	i : int;	# cursor postion	n : int;	# number of chars left; -1 on error	peek : fn(s: self ref ReStr): int;	next : fn(s: self ref ReStr): int;	unput: fn(s: self ref ReStr);}; ReStr.peek(s: self ref ReStr): int{	if(s.n <= 0)		return BAD;	return s.s[s.i];} ReStr.next(s: self ref ReStr): int{	if(s.n <= 0)		syntax("bad regular expression");	s.n--;	return s.s[s.i++];} ReStr.unput(s: self ref ReStr){	s.n++;	s.i--;} newRe(kind: int, left, right: refRex, set: ref Set, ar: ref Arena, pno: int, greedy: int): refRex{	ar.rex[ar.ptr] = Rex(kind, left, right, set, pno, greedy, nil);	return ar.ptr++;} # parse a regex by recursive descent to get a syntax tree re(s: ref ReStr, ar: ref Arena): refRex{	left := cat(s, ar);	if(left==NIL || s.peek()!='|')		return left;	s.next();	right := re(s, ar);	if(right == NIL)		return NIL;	return newRe(ALT, left, right, nil, ar, 0, 0);} cat(s: ref ReStr, ar: ref Arena): refRex{	left := dup(s, ar);	if(left == NIL)		return left;	right := cat(s, ar);	if(right == NIL)		return left;	return newRe(CAT, left, right, nil, ar, 0, 0);} dup(s: ref ReStr, ar: ref Arena): refRex{	n1, n2: int; 	case s.peek() {	BAD or ')' or ']' or '|' or '?' or '*' or '+' =>		return NIL;	}	prim: refRex;	case kind:=s.next() {	'(' =>	if(ar.pno < 0) {			if(s.peek() == ')') {				s.next();				prim = newRe(NUL, NONE, NONE, nil, ar, 0, 0);			} else {				prim = re(s, ar);				if(prim==NIL || s.next()!=')')					syntax("( with no )");

Lines 1–500 of 1286.