xref: /inferno-os/appl/lib/ecmascript/ecmascript.b (revision 46439007cf417cbd9ac8049bb4122c890097a0fa)
1implement Ecmascript;
2
3include "sys.m";
4include "math.m";
5include "string.m";
6include "daytime.m";
7include "ecmascript.m";
8
9include "pprint.b";
10include "obj.b";
11include "exec.b";
12include "date.b";
13include "builtin.b";
14include "regexp.b";
15include "uri.b";
16
17FF: con '\u000c';
18LS: con '\u2028';
19PS: con '\u2029';
20
21islt(c: int): int
22{
23	return c == '\n' || c == '\r' || c == LS || c == PS;
24}
25
26me: ESHostobj;
27
28sys: Sys;
29print, sprint: import sys;
30stdout: ref Sys->FD;
31
32math: Math;
33	isnan, floor, copysign, fabs, fmod, NaN, Infinity: import math;
34
35str: String;
36
37daytime: Daytime;
38	Tm: import daytime;
39
40labrec: adt{
41	s: string;	# name
42	k: int;	# kind
43};
44
45HashSize:	con 1024;
46
47Parser: adt
48{
49	ex:		ref Exec;
50
51	code:		ref Code;
52
53	inloop:		int;		# parser state
54	incase:		int;
55	infunc:		int;
56	lastnl:		int;		# parser state for inserting ;
57	notin:		int;		# don't allow `in' in expression
58
59	token:		int;		# lexical token
60	token1:		int;		# lexical token
61	id:		int;		# associated value
62	lineno:		int;
63
64	src:		string;		# lexical input state
65	esrc:		int;
66	srci:		int;
67
68	errors: int;
69	labs:		list of ref labrec;
70};
71
72Keywd: adt
73{
74	name:	string;
75	token:	int;
76};
77
78#
79#	lexical tokens and ops
80#
81	Lbase:	con 128;
82
83	Leos,
84
85	Landas,
86	Loras,
87	Lxoras,
88	Llshas,
89	Lrshas,
90	Lrshuas,
91	Laddas,
92	Lsubas,
93	Lmulas,
94	Ldivas,
95	Lmodas,
96	Loror,
97	Landand,
98	Leq,
99	Lneq,
100	Lleq,
101	Lgeq,
102	Llsh,
103	Lrsh,
104	Lrshu,
105	Linc,
106	Ldec,
107	Lnum,
108	Lid,
109	Lstr,
110	Lthis,
111	Ltypeof,
112	Ldelete,
113	Lvoid,
114	Lwhile,
115	Lfor,
116	Lbreak,
117	Lcontinue,
118	Lwith,
119	Lreturn,
120	Lfunction,
121	Lvar,
122	Lif,
123	Lelse,
124	Lin,
125	Lnew,
126	Lcase,
127	Ldefault,
128	Lswitch,
129	Ldo,
130	Linstanceof,
131	Lcatch,
132	Lfinally,
133	Lthrow,
134	Ltry,
135	Lregexp,
136	Lseq,
137	Lsne,
138	Lprint,
139
140	Lpostinc,		# ops that aren't lexical tokens
141	Lpostdec,
142	Lpresub,
143	Lpreadd,
144	Lcall,
145	Lnewcall,
146	Lgetval,
147	Las,
148	Lasop,
149	Lforin,
150	Lforvar,
151	Lforvarin,
152	Larrinit,
153	Lobjinit,
154	Lnoval,
155	Llabel,
156	Lbreaklab,
157	Lcontinuelab,
158
159	#
160	# reserved words
161	#
162	Labstract,
163	Lboolean,
164	Lbyte,
165	Lchar,
166	Lclass,
167	Lconst,
168	Ldebugger,
169	Ldouble,
170	Lenum,
171	Lexport,
172	Lextends,
173	Lfinal,
174	Lfloat,
175	Lgoto,
176	Limplements,
177	Limport,
178	Lint,
179	Linterface,
180	Llong,
181	Lnative,
182	Lpackage,
183	Lprivate,
184	Lprotected,
185	Lpublic,
186	Lshort,
187	Lstatic,
188	Lsuper,
189	Lsynchronized,
190	Lthrows,
191	Ltransient,
192	Lvolatile:	con Lbase + iota;
193
194
195#
196# internals
197#
198
199Mlower, Mupper, Munder, Mdigit, Msign, Mexp, Mhex, Moct: con byte 1 << iota;
200Malpha:	con Mupper|Mlower|Munder;
201map :=		array[256] of
202{
203	'_' or '$'		=> Munder,
204	'-' or '+'		=> Msign,
205	'a' to 'd' or 'f'	=> Mlower | Mhex,
206	'e'			=> Mlower | Mhex | Mexp,
207	'g' to 'z'		=> Mlower,
208	'A' to 'D' or 'F'	=> Mupper | Mhex,
209	'E'			=> Mupper | Mhex | Mexp,
210	'G' to 'Z'		=> Mupper,
211	'0' to '7'		=> Mdigit | Mhex | Moct,
212	'8' to '9'		=> Mdigit | Mhex,
213	*			=> byte 0
214};
215
216maxerr:		int;
217toterrors:	int;
218fabort:		int;
219
220escmap :=	array[] of
221{
222	'\'' =>		byte '\'',
223	'"' =>		byte '"',
224	'\\' =>		byte '\\',
225	'b' =>		byte '\b',
226	'f' =>		byte FF,
227	'n' =>		byte '\n',
228	'r' =>		byte '\r',
229	't' =>		byte '\t',
230	'v' =>	byte FF,
231
232	* =>		byte 255
233};
234
235#
236# must be sorted
237#
238keywords := array [] of
239{
240	Keywd("abstract",	Labstract),
241	Keywd("boolean",	Lboolean),
242	Keywd("byte",		Lbyte),
243	Keywd("break",		Lbreak),
244	Keywd("case",		Lcase),
245	Keywd("catch",		Lcatch),
246	Keywd("char",		Lchar),
247	Keywd("class",		Lclass),
248	Keywd("const",		Lconst),
249	Keywd("continue",	Lcontinue),
250	Keywd("debugger",	Ldebugger),
251	Keywd("default",	Ldefault),
252	Keywd("delete",		Ldelete),
253	Keywd("do",		Ldo),
254	Keywd("double",	Ldouble),
255	Keywd("else",		Lelse),
256	Keywd("enum",		Lenum),
257	Keywd("export",		Lexport),
258	Keywd("extends	",	Lextends),
259	Keywd("final",		Lfinal),
260	Keywd("finally",	Lfinally),
261	Keywd("float",		Lfloat),
262	Keywd("for",		Lfor),
263	Keywd("function",	Lfunction),
264	Keywd("goto",		Lgoto),
265	Keywd("if",		Lif),
266	Keywd("implements",	Limplements),
267	Keywd("import",		Limport),
268	Keywd("in",		Lin),
269	Keywd("instanceof",	Linstanceof),
270	Keywd("int",		Lint),
271	Keywd("interface",	Linterface),
272	Keywd("long",		Llong),
273	Keywd("native",	Lnative),
274	Keywd("new",		Lnew),
275	Keywd("package",	Lpackage),
276	# Keywd("print",		Lprint),
277	Keywd("private",	Lprivate),
278	Keywd("protected",	Lprotected),
279	Keywd("public",		Lpublic),
280	Keywd("return",		Lreturn),
281	Keywd("short",		Lshort),
282	Keywd("static",		Lstatic),
283	Keywd("super",		Lsuper),
284	Keywd("switch",		Lswitch),
285	Keywd("synchronized",	Lsynchronized),
286	Keywd("this",		Lthis),
287	Keywd("throw",		Lthrow),
288	Keywd("throws",	Lthrows),
289	Keywd("transient",	Ltransient),
290	Keywd("try",		Ltry),
291	Keywd("typeof",		Ltypeof),
292	Keywd("var",		Lvar),
293	Keywd("void",		Lvoid),
294	Keywd("volatile",	Lvolatile),
295	Keywd("while",		Lwhile),
296	Keywd("with",		Lwith),
297};
298
299debug = array[256] of {* => 0};
300
301glbuiltins := array[] of
302{
303	Builtin("eval", "eval", array[] of {"src"}, 1),
304	Builtin("parseInt", "parseInt", array[] of {"string", "radix"}, 2),
305	Builtin("parseFloat", "parseFloat", array[] of {"string"}, 1),
306	Builtin("escape", "escape", array[] of {"string"}, 1),
307	Builtin("unescape", "unescape", array[] of {"string"}, 1),
308	Builtin("isNaN", "isNaN", array[] of {"number"}, 1),
309	Builtin("isFinite", "isFinite", array[] of {"number"}, 1),
310	Builtin("decodeURI", "decodeURI", array[] of {"string"}, 1),
311	Builtin("decodeURIComponent", "decodeURIComponent", array[] of {"string"}, 1),
312	Builtin("encodeURI", "encodeURI", array[] of {"string"}, 1),
313	Builtin("encodeURIComponent", "encodeURIComponent", array[] of {"string"}, 1),
314};
315
316biobj := Builtin("Object", "Object", array[] of {"value"}, 1);
317biobjproto := array[] of
318{
319	Builtin("toString", "Object.prototype.toString", nil, 0),
320	Builtin("toLocaleString", "Object.prototype.toLocaleString", nil, 0),
321	Builtin("valueOf", "Object.prototype.valueOf", nil, 0),
322	Builtin("hasOwnProperty", "Object.prototype.hasOwnProperty", array[] of {"V"}, 1),
323	Builtin("isPrototypeOf", "Object.prototype.isPrototypeOf", array[] of {"V"}, 1),
324	Builtin("propertyisEnumerable", "Object.prototype.propertyisEnumerable", array[] of {"V"}, 1),
325};
326
327bifunc := Builtin("Function", "Function", array[] of {"body"}, 1);
328bifuncproto := array[] of
329{
330	Builtin("toString", "Function.prototype.toString", nil, 0),
331	Builtin("apply", "Function.prototype.apply", array[] of {"this", "array"}, 2),
332	Builtin("call", "Function.prototype.call", array[] of {"this", "arg"}, 1),
333};
334
335bierr := Builtin("Error", "Error", array[] of {"message"}, 1);
336bierrproto := array[] of
337{
338	Builtin("toString", "Error.prototype.toString", nil , 0),
339};
340
341biarray := Builtin("Array", "Array", array[] of {"length"}, 1);
342biarrayproto := array[] of
343{
344	Builtin("toString", "Array.prototype.toString", nil, 0),
345	Builtin("toLocaleString", "Array.prototype.toLocaleString", nil, 0),
346	Builtin("concat", "Array.prototype.concat", array[] of {"item"}, 1),
347	Builtin("join", "Array.prototype.join", array[] of {"separator"}, 1),
348	Builtin("pop", "Array.prototype.pop", nil, 0),
349	Builtin("push", "Array.prototype.push", array[] of {"item"} , 1),
350	Builtin("reverse", "Array.prototype.reverse", nil, 0),
351	Builtin("shift", "Array.prototype.shift", nil, 0),
352	Builtin("slice", "Array.prototype.slice", array[] of {"start", "end"}, 2),
353	Builtin("splice", "Array.prototype.splice", array[] of {"start", "delcnt", "item"}, 2),
354	Builtin("sort", "Array.prototype.sort", array[] of {"comparefunc"}, 1),
355	Builtin("unshift", "Array.prototype.unshift", array[] of {"item"}, 1),
356};
357
358bistr := Builtin("String", "String", array[] of {"value"}, 1);
359bistrproto := array[] of
360{
361	Builtin("toString", "String.prototype.toString", nil, 0),
362	Builtin("valueOf", "String.prototype.valueOf", nil, 0),
363	Builtin("charAt", "String.prototype.charAt", array[] of {"pos"}, 1),
364	Builtin("charCodeAt", "String.prototype.charCodeAt", array[] of {"pos"}, 1),
365	Builtin("concat", "String.prototype.concat", array[] of {"string"}, 1),
366	Builtin("indexOf", "String.prototype.indexOf", array[] of {"string", "pos"}, 2),
367	Builtin("lastIndexOf", "String.prototype.lastIndexOf", array[] of {"string", "pos"}, 2),
368	Builtin("localeCompare", "String.prototype.localeCompare", array[] of {"that"}, 1),
369	Builtin("slice", "String.prototype.slice", array[] of {"start", "end"}, 2),
370	Builtin("split", "String.prototype.split", array[] of {"separator"}, 2),
371	Builtin("substr", "String.prototype.substr", array[] of {"start", "length"}, 2),
372	Builtin("substring", "String.prototype.substring", array[] of {"start", "end"}, 2),
373	Builtin("toLowerCase", "String.prototype.toLowerCase", nil, 0),
374	Builtin("toUpperCase", "String.prototype.toUpperCase", nil, 0),
375	Builtin("toLocaleLowerCase", "String.prototype.toLocaleLowerCase", nil, 0),
376	Builtin("toLocaleUpperCase", "String.prototype.toLocaleUpperCase", nil, 0),
377# JavaScript 1.0
378	Builtin("anchor", "String.prototype.anchor", array[] of {"name"}, 1),
379	Builtin("big", "String.prototype.big", nil, 0),
380	Builtin("blink", "String.prototype.blink", nil, 0),
381	Builtin("bold", "String.prototype.bold", nil, 0),
382	Builtin("fixed", "String.prototype.fixed", nil, 0),
383	Builtin("fontcolor", "String.prototype.fontcolor", array[] of {"color"}, 1),
384	Builtin("fontsize", "String.prototype.fontsize", array[] of {"size"}, 1),
385	Builtin("italics", "String.prototype.italics", nil, 0),
386	Builtin("link", "String.prototype.link", array[] of {"href"}, 1),
387	Builtin("small", "String.prototype.small", nil, 0),
388	Builtin("strike", "String.prototype.strike", nil, 0),
389	Builtin("sub", "String.prototype.sub", nil, 0),
390	Builtin("sup", "String.prototype.sup", nil, 0),
391	Builtin("match", "String.prototype.match", array[] of {"regexp"}, 1),
392	Builtin("replace", "String.prototype.replace", array[] of {"searchval", "replaceval"}, 2),
393	Builtin("search", "String.prototype.search", array[] of {"regexp"}, 1),
394};
395bistrctor := Builtin("fromCharCode", "String.fromCharCode", array[] of {"characters"}, 1);
396
397bibool := Builtin("Boolean", "Boolean", array[] of {"value"}, 1);
398biboolproto := array[] of
399{
400	Builtin("toString", "Boolean.prototype.toString", nil, 0),
401	Builtin("valueOf", "Boolean.prototype.valueOf", nil, 0),
402};
403
404binum := Builtin("Number", "Number", array[] of {"value"}, 1);
405binumproto := array[] of
406{
407	Builtin("toString", "Number.prototype.toString", nil, 0),
408	Builtin("toLocaleString", "Number.prototype.toLocaleString", nil, 0),
409	Builtin("valueOf", "Number.prototype.valueOf", nil, 0),
410	Builtin("toFixed", "Number.prototype.toFixed", array[] of {"digits"}, 1),
411	Builtin("toExponential", "Number.prototype.toExponential", array[] of {"digits"}, 1),
412	Builtin("toPrecision", "Number.prototype.toPrecision", array[] of {"digits"}, 1),
413};
414
415biregexp := Builtin("RegExp", "RegExp", array[] of {"pattern", "flags"}, 2);
416biregexpproto := array[] of
417{
418	Builtin("exec", "RegExp.prototype.exec", array[] of {"string"}, 1),
419	Builtin("test", "RegExp.prototype.test", array[] of {"string"}, 1),
420	Builtin("toString", "RegExp.prototype.toString", nil, 0),
421};
422
423bidate := Builtin("Date", "Date", array[] of {"value"}, 1);
424bidateproto := array[] of
425{
426	Builtin("toString", "Date.prototype.toString", nil, 0),
427	Builtin("toDateString", "Date.prototype.toDateString", nil, 0),
428	Builtin("toTimeString", "Date.prototype.toTimeString", nil, 0),
429	Builtin("toLocaleString", "Date.prototype.toLocalString", nil, 0),
430	Builtin("toLocaleDateString", "Date.prototype.toLocaleDateString", nil, 0),
431	Builtin("toLocaleTimeString", "Date.prototype.toLocaleTimeString", nil, 0),
432	Builtin("valueOf", "Date.prototype.valueOf", nil, 0),
433	Builtin("getTime", "Date.prototype.getTime", nil, 0),
434	Builtin("getYear", "Date.prototype.getYear", nil, 0),
435	Builtin("getFullYear", "Date.prototype.getFullYear", nil, 0),
436	Builtin("getUTCFullYear", "Date.prototype.getUTCFullYear", nil, 0),
437	Builtin("getMonth", "Date.prototype.getMonth", nil, 0),
438	Builtin("getUTCMonth", "Date.prototype.getUTCMonth", nil, 0),
439	Builtin("getDate", "Date.prototype.getDate", nil, 0),
440	Builtin("getUTCDate", "Date.prototype.getUTCDate", nil, 0),
441	Builtin("getDay", "Date.prototype.getDay", nil, 0),
442	Builtin("getUTCDay", "Date.prototype.getUTCDay", nil, 0),
443	Builtin("getHours", "Date.prototype.getHours", nil, 0),
444	Builtin("getUTCHours", "Date.prototype.getUTCHours", nil, 0),
445	Builtin("getMinutes", "Date.prototype.getMinutes", nil, 0),
446	Builtin("getUTCMinutes", "Date.prototype.getUTCMinutes", nil, 0),
447	Builtin("getSeconds", "Date.prototype.getSeconds", nil, 0),
448	Builtin("getUTCSeconds", "Date.prototype.getUTCSeconds", nil, 0),
449	Builtin("getMilliseconds", "Date.prototype.getMilliseconds", nil, 0),
450	Builtin("getUTCMilliseconds", "Date.prototype.getUTCMilliseconds", nil, 0),
451	Builtin("getTimezoneOffset", "Date.prototype.getTimezoneOffset", nil, 0),
452	Builtin("setTime", "Date.prototype.setTime", array[] of {"time"}, 1),
453	Builtin("setMilliseconds", "Date.prototype.setMilliseconds", array[] of {"ms"}, 1),
454	Builtin("setUTCMilliseconds", "Date.prototype.setUTCMilliseconds", array[] of {"ms"}, 1),
455	Builtin("setSeconds", "Date.prototype.setSeconds", array[] of {"sec", "ms"}, 2),
456	Builtin("setUTCSeconds", "Date.prototype.setUTCSeconds", array[] of {"sec", "ms"}, 2),
457	Builtin("setMinutes", "Date.prototype.setMinutes", array[] of {"min", "sec", "ms"}, 3),
458	Builtin("setUTCMinutes", "Date.prototype.setUTCMinutes", array[] of {"min", "sec", "ms"}, 3),
459	Builtin("setHours", "Date.prototype.setHours", array[] of {"hour", "min", "sec", "ms"}, 4),
460	Builtin("setUTCHours", "Date.prototype.setUTCHours", array[] of {"hour", "min", "sec", "ms"}, 4),
461	Builtin("setDate", "Date.prototype.setDate", array[] of {"date"}, 1),
462	Builtin("setUTCDate", "Date.prototype.setUTCDate", array[] of {"date"}, 1),
463	Builtin("setMonth", "Date.prototype.setMonth", array[] of {"mon", "date"}, 2),
464	Builtin("setUTCMonth", "Date.prototype.setUTCMonth", array[] of {"mon", "date"}, 2),
465	Builtin("setFullYear", "Date.prototype.setFullYear", array[] of {"year", "mon", "date"}, 3),
466	Builtin("setUTCFullYear", "Date.prototype.setUTCFullYear", array[] of {"year", "mon", "date"}, 3),
467	Builtin("setYear", "Date.prototype.setYear", array[] of {"year"}, 1),
468	Builtin("toLocaleString", "Date.prototype.toLocaleString", nil, 0),
469	Builtin("toUTCString", "Date.prototype.toUTCString", nil, 0),
470	Builtin("toGMTString", "Date.prototype.toGMTString", nil, 0),
471};
472bidatector := array[] of
473{
474	Builtin("parse", "Date.parse", array[] of {"string"}, 1),
475	Builtin("UTC", "Date.UTC", array[] of {"year", "month", "date", "hours", "minutes", "seconds", "ms"}, 7),
476};
477
478bimath := array[] of
479{
480	Builtin("abs", "Math.abs", array[] of {"x"}, 1),
481	Builtin("acos", "Math.acos", array[] of {"x"}, 1),
482	Builtin("asin", "Math.asin", array[] of {"x"}, 1),
483	Builtin("atan", "Math.atan", array[] of {"x"}, 1),
484	Builtin("atan2", "Math.atan2", array[] of {"y", "x"}, 2),
485	Builtin("ceil", "Math.ceil", array[] of {"x"}, 1),
486	Builtin("cos", "Math.cos", array[] of {"x"}, 1),
487	Builtin("exp", "Math.exp", array[] of {"x"}, 1),
488	Builtin("floor", "Math.floor", array[] of {"x"}, 1),
489	Builtin("log", "Math.log", array[] of {"x"}, 1),
490	Builtin("max", "Math.max", array[] of {"x", "y"}, 2),
491	Builtin("min", "Math.min", array[] of {"x", "y"}, 2),
492	Builtin("pow", "Math.pow", array[] of {"x", "y"}, 2),
493	Builtin("random", "Math.random", nil, 0),
494	Builtin("round", "Math.round", array[] of {"x"}, 1),
495	Builtin("sin", "Math.sin", array[] of {"x"}, 1),
496	Builtin("sqrt", "Math.sqrt", array[] of {"x"}, 1),
497	Builtin("tan", "Math.tan", array[] of {"x"}, 1),
498};
499
500init(): string
501{
502	sys = load Sys Sys->PATH;
503	math = load Math Math->PATH;
504	if(math == nil)
505		return sys->sprint("can't load module %s: %r", Math->PATH);
506
507	str = load String String->PATH;
508	if(str == nil)
509		return sys->sprint("can't load module %s: %r", String->PATH);
510
511	daytime = load Daytime Daytime->PATH;
512	if(daytime == nil)
513		return sys->sprint("can't load module %s: %r", Daytime->PATH);
514
515	me = load ESHostobj SELF;
516	if(me == nil)
517		return "can't load builtin functions";
518
519	randinit(big sys->millisec());
520	stdout = sys->fildes(1);
521	#
522	# maximum number of syntax errors reported
523	#
524	maxerr = 1;
525
526	undefined = ref Val(TUndef, 0., nil, nil, nil);
527	null =	ref Val(TNull, 0., nil, nil, nil);
528	true = ref Val(TBool, 1., nil, nil, nil);
529	false = ref Val(TBool, 0., nil, nil, nil);
530	return "";
531}
532
533mkcall(ex : ref Exec, p: array of string): ref Call
534{
535	return ref Call(p, nil, ex);
536}
537
538mkbiobj(ex: ref Exec, meth: Builtin, proto: ref Obj): ref Obj
539{
540	o := biinst(ex.global, meth, ex.funcproto, me);
541	o.construct = o.call;
542	valinstant(o, DontEnum|DontDelete|ReadOnly, "prototype", objval(proto));
543	valinstant(proto, DontEnum, "constructor", objval(o));
544	return o;
545}
546
547mkexec(go: ref Obj): ref Exec
548{
549	o: ref Obj;
550	if(go == nil)
551		go = mkobj(nil, "global");
552	ex := ref Exec;
553	ex.this = go;
554	ex.scopechain = go :: nil;
555	ex.stack = array[4] of ref Ref;
556	ex.sp = 0;
557	ex.global = go;
558
559	#
560	# builtin object prototypes
561	#
562	ex.objproto = mkobj(nil, "Object");
563	ex.funcproto = mkobj(ex.objproto, "Function");
564	ex.arrayproto = mkobj(ex.objproto, "Array");
565	ex.strproto = mkobj(ex.objproto, "String");
566	ex.numproto = mkobj(ex.objproto, "Number");
567	ex.boolproto = mkobj(ex.objproto, "Boolean");
568	ex.dateproto = mkobj(ex.objproto, "Date");
569	ex.regexpproto = mkobj(ex.objproto, "RegExp");
570	ex.errproto = mkobj(ex.objproto, "Error");
571
572	biminst(ex.objproto, biobjproto, ex.funcproto, me);
573
574	biminst(ex.funcproto, bifuncproto, ex.funcproto, me);
575	ex.funcproto.call = mkcall(ex, nil);
576	ex.funcproto.val = strval("Function.prototype");
577	valinstant(ex.funcproto, DontEnum|DontDelete|ReadOnly, "length", numval(real 0));
578
579	biminst(ex.arrayproto, biarrayproto, ex.funcproto, me);
580	valinstant(ex.arrayproto, DontEnum|DontDelete, "length", numval(real 0));
581
582	biminst(ex.errproto, bierrproto, ex.funcproto, me);
583	ex.errproto.val = strval("");
584	valinstant(ex.errproto, DontEnum|DontDelete, "length", numval(real 0));
585	valinstant(ex.errproto, DontEnum|DontDelete, "name", strval(""));
586	valinstant(ex.errproto, DontEnum|DontDelete, "message", strval("Error"));
587
588	biminst(ex.strproto, bistrproto, ex.funcproto, me);
589	ex.strproto.val = strval("");
590	valinstant(ex.strproto, DontEnum|DontDelete|ReadOnly, "length", numval(real 0));
591
592	biminst(ex.boolproto, biboolproto, ex.funcproto, me);
593	ex.boolproto.val = false;
594
595	biminst(ex.numproto, binumproto, ex.funcproto, me);
596	ex.numproto.val = numval(real +0);
597
598	biminst(ex.regexpproto, biregexpproto, ex.funcproto, me);
599	ex.regexpproto.val = strval("");
600	valinstant(ex.regexpproto, DontEnum|DontDelete|ReadOnly, "length", numval(real 2));
601	valinstant(ex.regexpproto, DontEnum|DontDelete|ReadOnly, "source", strval(""));
602	valinstant(ex.regexpproto, DontEnum|DontDelete|ReadOnly, "global", false);
603	valinstant(ex.regexpproto, DontEnum|DontDelete|ReadOnly, "ignoreCase", false);
604	valinstant(ex.regexpproto, DontEnum|DontDelete|ReadOnly, "multiline", false);
605	valinstant(ex.regexpproto, DontEnum|DontDelete, "lastIndex", numval(real 0));
606
607	biminst(ex.dateproto, bidateproto, ex.funcproto, me);
608	ex.dateproto.val = numval(Math->NaN);
609	valinstant(ex.dateproto, DontEnum|DontDelete|ReadOnly, "length", numval(real 7));
610
611	#
612	# simple builtin functions and values
613	#
614	valinstant(go, DontEnum, "NaN", numval(Math->NaN));
615	valinstant(go, DontEnum, "Infinity", numval(Math->Infinity));
616
617	biminst(go, glbuiltins, ex.funcproto, me);
618
619	#
620	# builtin objects, and cross-link them to their prototypes
621	#
622	mkbiobj(ex, biobj, ex.objproto);
623	mkbiobj(ex, bifunc, ex.funcproto);
624	mkbiobj(ex, biarray, ex.arrayproto);
625	o = mkbiobj(ex, bistr, ex.strproto);
626	biinst(o, bistrctor, ex.funcproto, me);
627	mkbiobj(ex, bibool, ex.boolproto);
628	o = mkbiobj(ex, binum, ex.numproto);
629	mkbiobj(ex, biregexp, ex.regexpproto);
630	mkbiobj(ex, bierr, ex.errproto);
631
632	math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
633
634	valinstant(o, DontEnum|DontDelete|ReadOnly, "MAX_VALUE", numval(math->nextafter(Math->Infinity, 0.)));
635	valinstant(o, DontEnum|DontDelete|ReadOnly, "MIN_VALUE", numval(math->nextafter(0., 1.)));
636	valinstant(o, DontEnum|DontDelete|ReadOnly, "NaN", numval(Math->NaN));
637	valinstant(o, DontEnum|DontDelete|ReadOnly, "NEGATIVE_INFINITY", numval(-Math->Infinity));
638	valinstant(o, DontEnum|DontDelete|ReadOnly, "POSITIVE_INFINITY", numval(+Math->Infinity));
639	o = mkbiobj(ex, bidate, ex.dateproto);
640	biminst(o, bidatector, ex.funcproto, me);
641
642	#
643	# the math object is a little different
644	#
645	o = mkobj(ex.objproto, "Object");
646	valinstant(go, DontEnum, "Math", objval(o));
647	biminst(o, bimath, ex.funcproto, me);
648
649	#
650	# these are computed so they are consistent with numbers ecma might calculate
651	#
652	mathe := math->exp(1.);
653	valinstant(o, DontEnum|DontDelete|ReadOnly, "E", numval(mathe));
654	valinstant(o, DontEnum|DontDelete|ReadOnly, "LN10", numval(math->log(10.)));
655	valinstant(o, DontEnum|DontDelete|ReadOnly, "LN2", numval(math->log(2.)));
656	valinstant(o, DontEnum|DontDelete|ReadOnly, "LOG2E", numval(1./math->log(2.)));
657	valinstant(o, DontEnum|DontDelete|ReadOnly, "LOG10E", numval(1./math->log(10.)));
658	valinstant(o, DontEnum|DontDelete|ReadOnly, "PI", numval(Math->Pi));
659	valinstant(o, DontEnum|DontDelete|ReadOnly, "SQRT1_2", numval(math->sqrt(1./2.)));
660	valinstant(o, DontEnum|DontDelete|ReadOnly, "SQRT2", numval(math->sqrt(2.)));
661
662	(EvalError, ex.evlerrproto) = mkerr(ex, "EvalError");
663	(RangeError, ex.ranerrproto) = mkerr(ex, "RangeError");
664	(ReferenceError, ex.referrproto) = mkerr(ex, "ReferenceError");
665	(SyntaxError, ex.synerrproto) = mkerr(ex, "SyntaxError");
666	(TypeError, ex.typerrproto) = mkerr(ex, "TypeError");
667	(URIError, ex.urierrproto) = mkerr(ex, "URIError");
668	(InternalError, ex.interrproto) = mkerr(ex, "InternalError");
669
670	return ex;
671}
672
673mkerr(ex: ref Exec, e: string): (ref Obj, ref Obj)
674{
675	errproto := mkobj(ex.objproto, e);
676	biminst(errproto, array[] of { Builtin("toString", e+".prototype.toString", nil, 0) }, ex.funcproto, me);
677	errproto.val = strval("");
678	valinstant(errproto, DontEnum|DontDelete, "length", numval(real 0));
679	valinstant(errproto, DontEnum|DontDelete, "name", strval(e));
680	valinstant(errproto, DontEnum|DontDelete, "message", strval(e));
681	eo := mkbiobj(ex, Builtin(e, e, array[] of {"message"}, 1), errproto);
682	# return (eo, errproto);
683	return (nerr(ex, eo, array[] of {strval(e)}, errproto), errproto);
684}
685
686mkparser(ex: ref Exec, src: string): ref Parser
687{
688	p := ref Parser;
689	p.ex = ex;
690	p.src = src;
691	p.esrc = len src;
692	p.srci = 0;
693	p.errors = 0;
694	p.lineno = 1;
695	p.token = -1;
696	p.token1 = -1;
697	p.lastnl = 0;
698	p.inloop = 0;
699	p.incase = 0;
700	p.infunc = 0;
701	p.notin = 0;
702	p.code = mkcode();
703	return p;
704}
705
706eval(ex: ref Exec, src: string): Completion
707{
708	{
709		p := mkparser(ex, src);
710
711		if(debug['t'])
712			parset := sys->millisec();
713
714		prog(ex, p);
715
716		toterrors += p.errors;
717
718		if(p.errors)
719			runtime(ex, SyntaxError, ex.error);
720		if(debug['p']){
721			s := array of byte pprint(ex, p.code, "");
722			if(len s)
723				sys->write(stdout, s, len s);
724		}
725
726		if(debug['t'])
727			xect := sys->millisec();
728
729		globalinstant(hd ex.scopechain, p.code.vars);
730		c := exec(ex, p.code);
731
732		if(debug['t'])
733			print("parse time %d exec time %d\n", xect - parset, sys->millisec() - xect);
734
735		return c;
736	}exception{
737		"throw" =>
738			return (CThrow, ex.errval, nil);
739	}
740}
741
742#prog	: selems
743#	;
744#
745#selems	: selem
746#	| selems selem
747#	;
748#selem	: stmt
749#	| fundecl
750#	;
751prog(ex: ref Exec, p: ref Parser)
752{
753	while(look(p) != Leos)
754		if(look(p) == Lfunction)
755			fundecl(ex, p, 0);
756		else
757			stmt(p);
758}
759
760#fundecl	: Lfunction Lid '(' zplist ')' '{' stmts '}'
761#	;
762#zplist	:
763#	| plist
764#	;
765#
766#plist	: Lid
767#	| plist ',' Lid
768#	;
769fundecl(ex: ref Exec, p: ref Parser, expr: int): ref Obj
770{
771	jp: ref Prop;
772
773	c := p.code;
774	labs := p.labs;
775	p.labs = nil;
776	mustbe(p, Lfunction);
777	if(!expr || look(p) == Lid){
778		mustbe(p, Lid);
779		jp = codevar(p, expr);
780	}
781	p.code = mkcode();
782	mustbe(p, '(');
783	if(look(p) != ')'){
784		for(;;){
785			mustbe(p, Lid);
786			codevar(p, 1);
787			if(look(p) == ')')
788				break;
789			mustbe(p, ',');
790		}
791	}
792	params := p.code.vars;
793	p.code.vars = nil;
794	mustbe(p, ')');
795	mustbe(p, '{');
796	p.infunc++;
797	stmts(p);
798	p.infunc--;
799	mustbe(p, '}');
800
801	#
802	# override any existing value,
803	# as per sec. 10.1.3 Variable instantiation
804	#
805	sparams := array[len params] of string;
806	for(i := 0; i < len sparams; i++)
807		sparams[i] = params[i].name;
808
809	#
810	# construct a function object;
811	# see section 15.3.21
812	o := mkobj(ex.funcproto, "Function");
813	o.call = ref Call(sparams, p.code, ex);
814	o.construct = o.call;
815	if(jp != nil)
816		o.val = strval(jp.name);
817	else
818		o.val = strval("");
819	valinstant(o, DontDelete|DontEnum|ReadOnly, "length", numval(real len sparams));
820	po := nobj(ex, nil, nil);
821	valinstant(o, DontEnum, "prototype", objval(po));
822	valinstant(po, DontEnum, "constructor", objval(o));
823	valinstant(o, DontDelete|DontEnum|ReadOnly, "arguments", null);
824	if(jp != nil)
825		jp.val.val = objval(o);
826
827	if(debug['p']){
828		s := array of byte (funcprint(ex, o) + "\n");
829		sys->write(stdout, s, len s);
830	}
831
832	p.code = c;
833	p.labs = labs;
834	if(expr && jp != nil)
835		popvar(p);
836	return o;
837}
838
839#
840# install a variable for the id just lexed
841#
842codevar(p: ref Parser, forcenew: int): ref Prop
843{
844	name := p.code.strs[p.id];
845	vs := p.code.vars;
846	i : int;
847	if(!forcenew){
848		for(i = 0; i < len vs; i++)
849			if(vs[i].name == name)
850				return vs[i];
851	}else{
852		i = len vs;
853	}
854	vs = array[i+1] of ref Prop;
855	vs[:] = p.code.vars;
856	p.code.vars = vs;
857	vs[i] = ref Prop(0, name, ref RefVal(undefined));
858	return vs[i];
859}
860
861popvar(p: ref Parser)
862{
863	vs := p.code.vars;
864	p.code.vars = vs[0: len vs - 1];
865}
866
867#stmts	:
868#	| stmts stmt
869#	;
870stmts(p: ref Parser)
871{
872	while((op := look(p)) != '}' && op != Leos)
873		stmt(p);
874}
875
876#stmt	: '{' stmts '}'
877#	| Lvar varlist ';'
878#	| exp ';'
879#	| ';'
880#	| Lif '(' exp ')' stmt
881#	| Lif '(' exp ')' stmt Lelse stmt
882#	| Lwhile '(' exp ')' stmt
883#	| Ldo stmt Lwhile '(' exp ')'
884#	| Lfor '(' zexp-notin ';' zexp ';' zexp ')' stmt
885#	| Lfor '(' Lvar varlist-notin ';' zexp ';' zexp ')' stmt
886#	| Lfor '(' lhsexp Lin exp ')' stmt
887#	| Lfor '(' Lvar Lid [init] Lin exp ')' stmt
888#	| Lcontinue ';'
889#	| Lbreak ';'
890#	| Lreturn zexp ';'	# no line term after return
891#	| Lwith '(' exp ')' stmt
892#	| Lswitch '(' exp ')' '{' caseblk '}'
893#	| Lthrow exp ';'
894#	| Ltry block Lcatch '(' Lid ')' block
895#	| Ltry block finally block
896#	| Ltry block Lcatch '(' Lid ')' block finally block
897#	;
898stmt(p: ref Parser)
899{
900	pc: int;
901
902	seenlabs := 0;
903	while(look(p) == Lid && look2(p) == ':'){
904		pushlab(p, p.code.strs[p.id]);
905		emitconst(p, Llabel, p.id);
906		lex(p);
907		lex(p);
908		seenlabs++;
909	}
910
911	op := look(p);
912	if(seenlabs)
913		setkindlab(p, op, seenlabs);
914	case op{
915	';' =>
916		lexemit(p);
917	'{' =>
918		if(seenlabs == 0){
919			lex(p);
920			stmts(p);
921		}
922		else{
923			lexemit(p);
924			pc = epatch(p);
925			stmts(p);
926			patch(p, pc);
927		}
928		mustbe(p, '}');
929	Lvar =>
930		lexemit(p);
931		pc = epatch(p);
932		varlist(p);
933		semi(p);
934		patch(p, pc);
935	* =>
936		exp(p);
937		semi(p);
938		emit(p, ';');
939	Lif =>
940		lexemit(p);
941		pc = epatch(p);
942		mustbe(p, '(');
943		exp(p);
944		mustbe(p, ')');
945		patch(p, pc);
946		pc = epatch(p);
947		stmt(p);
948		patch(p, pc);
949		pc = epatch(p);
950		if(look(p) == Lelse){
951			lex(p);
952			stmt(p);
953		}
954		patch(p, pc);
955	Lwhile or
956	Lwith =>
957		lexemit(p);
958		pc = epatch(p);
959		mustbe(p, '(');
960		exp(p);
961		mustbe(p, ')');
962		patch(p, pc);
963		if(op == Lwhile)
964			p.inloop++;
965		pc = epatch(p);
966		stmt(p);
967		patch(p, pc);
968		if(op == Lwhile)
969			p.inloop--;
970	Ldo =>
971		p.inloop++;
972		lexemit(p);
973		pc = epatch(p);
974		stmt(p);
975		patch(p, pc);
976		mustbe(p, Lwhile);
977		mustbe(p, '(');
978		pc = epatch(p);
979		exp(p);
980		patch(p, pc);
981		mustbe(p, ')');
982		mustbe(p, ';');
983		p.inloop--;
984	Lfor =>
985		fpc := p.code.npc;
986		lexemit(p);
987		mustbe(p, '(');
988		p.notin++;
989		if(look(p) == Lvar){
990			lex(p);
991			pc = epatch(p);
992			varlist(p);
993			patch(p, pc);
994			p.notin--;
995			if(look(p) == Lin){
996				check1var(p);
997				p.code.ops[fpc] = byte Lforvarin;
998				lex(p);
999				pc = epatch(p);
1000				exp(p);
1001				patch(p, pc);
1002			}else{
1003				p.code.ops[fpc] = byte Lforvar;
1004				mustbe(p, ';');
1005				pc = epatch(p);
1006				zexp(p);
1007				patch(p, pc);
1008				mustbe(p, ';');
1009				pc = epatch(p);
1010				zexp(p);
1011				patch(p, pc);
1012			}
1013		}else{
1014			pc = epatch(p);
1015			lhspc := p.code.npc;
1016			zexp(p);
1017			patch(p, pc);
1018			p.notin--;
1019			if(look(p) == Lin){
1020				p.code.ops[fpc] = byte Lforin;
1021				checklhsexp(p, lhspc);
1022				lex(p);
1023				pc = epatch(p);
1024				exp(p);
1025				patch(p, pc);
1026			}else{
1027				mustbe(p, ';');
1028				pc = epatch(p);
1029				zexp(p);
1030				patch(p, pc);
1031				mustbe(p, ';');
1032				pc = epatch(p);
1033				zexp(p);
1034				patch(p, pc);
1035			}
1036		}
1037		mustbe(p, ')');
1038		p.inloop++;
1039		pc = epatch(p);
1040		stmt(p);
1041		patch(p, pc);
1042		p.inloop--;
1043	Lcontinue or
1044	Lbreak =>
1045		lex(p);
1046		lab := 0;
1047		if(look(p) == Lid){
1048			if((lr := findlab(p, p.code.strs[p.id])) == nil)
1049				error(p, "missing label");
1050			if(op == Lcontinue && !itstmt(lr.k))
1051				error(p, "continue label not on iteration statement");
1052			if(op == Lbreak)
1053				nop := Lbreaklab;
1054			else
1055				nop = Lcontinuelab;
1056			if(!inlocallabs(p, lr, seenlabs))	# otherwise noop
1057				emitconst(p, nop, p.id);
1058			lex(p);
1059			lab = 1;
1060		}
1061		else
1062			emit(p, op);
1063		semi(p);
1064		if(op == Lbreak && !lab && !p.inloop && !p.incase)
1065			error(p, "break not in a do or for or while or case");
1066		if(op == Lcontinue && !p.inloop)
1067			error(p, "continue not in a do or for or while");
1068	Lreturn =>
1069		lexemit(p);
1070		nextop := look(p);
1071		if(nextop != ';' && nextop != '}' && !p.lastnl)
1072			exp(p);
1073		semi(p);
1074		emit(p, ';');
1075		if(!p.infunc)
1076			error(p, tokname(op)+" not in a function");
1077	Lswitch =>
1078		lexemit(p);
1079		mustbe(p, '(');
1080		pc = epatch(p);
1081		exp(p);
1082		patch(p, pc);
1083		mustbe(p, ')');
1084		mustbe(p, '{');
1085		pc = epatch(p);
1086		caseblk(p);
1087		patch(p, pc);
1088		mustbe(p, '}');
1089	Lthrow =>
1090		lexemit(p);
1091		nextop := look(p);
1092		if(!p.lastnl)
1093			exp(p);
1094		mustbe(p, ';');
1095		emit(p, ';');
1096	Lprint =>
1097		lexemit(p);
1098		nextop := look(p);
1099		if(!p.lastnl)
1100			exp(p);
1101		mustbe(p, ';');
1102		emit(p, ';');
1103	Ltry =>
1104		lexemit(p);
1105		pc = epatch(p);
1106		block(p);
1107		patch(p, pc);
1108		pc = epatch(p);
1109		if(look(p) == Lcatch){
1110			lex(p);
1111			mustbe(p, '(');
1112			mustbe(p, Lid);
1113			emitconst(p, Lid, p.id);
1114			mustbe(p, ')');
1115			block(p);
1116		}
1117		patch(p, pc);
1118		pc = epatch(p);
1119		if(look(p) == Lfinally){
1120			lex(p);
1121			block(p);
1122		}
1123		patch(p, pc);
1124	}
1125	while(--seenlabs >= 0)
1126		poplab(p);
1127}
1128
1129block(p : ref Parser)
1130{
1131	mustbe(p, '{');
1132	stmts(p);
1133	mustbe(p, '}');
1134}
1135
1136caseblk(p : ref Parser)
1137{
1138	pc, defaultpc, clausepc : int;
1139	gotdef := 0;
1140	p.incase++;
1141
1142	defaultpc = epatch(p);
1143	while((op := look(p)) != '}' && op != Leos) {
1144		if (op != Lcase && op != Ldefault) {
1145			err := "expected " + tokname(Lcase)
1146				+ " or " + tokname(Ldefault)
1147				+ " found " + tokname(op);
1148			error(p, err);
1149		}
1150		if (op == Ldefault) {
1151			if (gotdef)
1152				error(p, "default case already defined");
1153			gotdef = 1;
1154
1155			patch(p, defaultpc);
1156		}
1157		lex(p);
1158		clausepc = epatch(p);
1159		if (op == Lcase) {
1160			pc = epatch(p);
1161			exp(p);
1162			patch(p, pc);
1163		}
1164		mustbe(p, ':');
1165		casestmts(p);
1166		patch(p, clausepc);
1167	}
1168	clausepc = epatch(p);
1169	patch(p, clausepc);
1170	if (!gotdef)
1171		patch(p, defaultpc);
1172	p.incase--;
1173}
1174
1175casestmts(p : ref Parser)
1176{
1177	while((op := look(p)) != '}' && op != Lcase && op != Ldefault && op != Leos)
1178		stmt(p);
1179}
1180
1181semi(p: ref Parser)
1182{
1183	op := look(p);
1184	if(op == ';'){
1185		lex(p);
1186		return;
1187	}
1188	if(op == '}' || op == Leos || p.lastnl)
1189		return;
1190	mustbe(p, ';');
1191}
1192
1193#varlist	: vardecl
1194#	| varlist ',' vardecl
1195#	;
1196#
1197#vardecl	: Lid init
1198#	;
1199#
1200#init	:
1201#	| '=' asexp
1202#	;
1203varlist(p: ref Parser)
1204{
1205	#
1206	# these declaration aren't supposed
1207	# to override current definitions
1208	#
1209	mustbe(p, Lid);
1210	codevar(p, 0);
1211	emitconst(p, Lid, p.id);
1212	if(look(p) == '='){
1213		lex(p);
1214		asexp(p);
1215		emit(p, '=');
1216	}
1217	if(look(p) != ',')
1218		return;
1219	emit(p, Lgetval);
1220	lex(p);
1221	varlist(p);
1222	emit(p, ',');
1223}
1224
1225#
1226# check that only 1 id is declared in the var list
1227#
1228check1var(p: ref Parser)
1229{
1230	if(p.code.ops[p.code.npc-1] == byte ',')
1231		error(p, "only one identifier allowed");
1232}
1233
1234#zexp	:
1235#	| exp
1236#	;
1237zexp(p: ref Parser)
1238{
1239	op := look(p);
1240	if(op == ';' || op == ')')
1241		return;
1242	exp(p);
1243}
1244
1245#exp	: asexp
1246#	| exp ',' asexp
1247#	;
1248exp(p: ref Parser)
1249{
1250	asexp(p);
1251	while(look(p) == ','){
1252		lex(p);
1253		emit(p, Lgetval);
1254		asexp(p);
1255		emit(p, ',');
1256	}
1257}
1258
1259#asexp	: condexp
1260#	| lhsexp asop asexp
1261#	;
1262#
1263#asop	: '=' | Lmulas | Ldivas | Lmodas | Laddas | Lsubas
1264#		| Llshas | Lrshas | Lrshuas | Landas | Lxoras | Loras
1265#	;
1266asops := array[] of { '=', Lmulas, Ldivas, Lmodas, Laddas, Lsubas,
1267		Llshas, Lrshas, Lrshuas, Landas, Lxoras, Loras };
1268asbaseops := array[] of { '=', '*', '/', '%', '+', '-',
1269		Llsh, Lrsh, Lrshu, '&', '^', '|' };
1270asexp(p: ref Parser)
1271{
1272	lhspc := p.code.npc;
1273	condexp(p);
1274	i := inops(look(p), asops);
1275	if(i >= 0){
1276		op := lex(p);
1277		checklhsexp(p, lhspc);
1278		if(op != '=')
1279			emit(p, Lasop);
1280		asexp(p);
1281		emit(p, asbaseops[i]);
1282		if(op != '=')
1283			emit(p, Las);
1284	}
1285}
1286
1287#condexp	: ororexp
1288#	| ororexp '?' asexp ':' asexp
1289#	;
1290condexp(p: ref Parser)
1291{
1292	ororexp(p);
1293	if(look(p) == '?'){
1294		lexemit(p);
1295		pc := epatch(p);
1296		asexp(p);
1297		mustbe(p, ':');
1298		patch(p, pc);
1299		pc = epatch(p);
1300		asexp(p);
1301		patch(p, pc);
1302	}
1303}
1304
1305#ororexp	: andandexp
1306#	| ororexp op andandexp
1307#	;
1308ororexp(p: ref Parser)
1309{
1310	andandexp(p);
1311	while(look(p) == Loror){
1312		lexemit(p);
1313		pc := epatch(p);
1314		andandexp(p);
1315		patch(p, pc);
1316	}
1317}
1318
1319#andandexp	: laexp
1320#	| andandexp op laexp
1321#	;
1322andandexp(p: ref Parser)
1323{
1324	laexp(p, 0);
1325	while(look(p) == Landand){
1326		lexemit(p);
1327		pc := epatch(p);
1328		laexp(p, 0);
1329		patch(p, pc);
1330	}
1331}
1332
1333#laexp	: unexp
1334#	| laexp op laexp
1335#	;
1336prectab := array[] of
1337{
1338	array[] of { '|' },
1339	array[] of { '^' },
1340	array[] of { '&' },
1341	array[] of { Leq, Lneq, Lseq, Lsne },
1342	array[] of { '<', '>', Lleq, Lgeq, Lin, Linstanceof },
1343	array[] of { Llsh, Lrsh, Lrshu },
1344	array[] of { '+', '-' },
1345	array[] of { '*', '/', '%' },
1346};
1347laexp(p: ref Parser, prec: int)
1348{
1349	unexp(p);
1350	for(pr := len prectab - 1; pr >= prec; pr--){
1351		while(inops(look(p), prectab[pr]) >= 0){
1352			emit(p, Lgetval);
1353			op := lex(p);
1354			laexp(p, pr + 1);
1355			emit(p, op);
1356		}
1357	}
1358}
1359
1360#unexp	: postexp
1361#	| Ldelete unexp
1362#	| Lvoid unexp
1363#	| Ltypeof unexp
1364#	| Linc unexp
1365#	| Ldec unexp
1366#	| '+' unexp
1367#	| '-' unexp
1368#	| '~' unexp
1369#	| '!' unexp
1370#	;
1371preops := array[] of { Ldelete, Lvoid, Ltypeof, Linc, Ldec, '+', '-', '~', '!' };
1372unexp(p: ref Parser)
1373{
1374	if(inops(look(p), preops) >= 0){
1375		op := lex(p);
1376		unexp(p);
1377		if(op == '-')
1378			op = Lpresub;
1379		else if(op == '+')
1380			op = Lpreadd;
1381		emit(p, op);
1382		return;
1383	}
1384	postexp(p);
1385}
1386
1387#postexp	: lhsexp
1388#	| lhsexp Linc	# no line terminators before Linc or Ldec
1389#	| lhsexp Ldec
1390#	;
1391postexp(p: ref Parser)
1392{
1393	lhsexp(p, 0);
1394	if(p.lastnl)
1395		return;
1396	op := look(p);
1397	if(op == Linc || op == Ldec){
1398		if(op == Linc)
1399			op = Lpostinc;
1400		else
1401			op = Lpostdec;
1402		lex(p);
1403		emit(p, op);
1404	}
1405}
1406
1407#
1408# verify that the last expression is actually a lhsexp
1409#
1410checklhsexp(p: ref Parser, pc: int)
1411{
1412
1413	case int p.code.ops[p.code.npc-1]{
1414	Lthis or
1415	')' or
1416	'.' or
1417	'[' or
1418	Lcall or
1419	Lnew or
1420	Lnewcall =>
1421		return;
1422	}
1423
1424	case int p.code.ops[pc]{
1425	Lid or
1426	Lnum or
1427	Lstr or
1428	Lregexp =>
1429		npc := pc + 1;
1430		(npc, nil) = getconst(p.code.ops, npc);
1431		if(npc == p.code.npc)
1432			return;
1433	}
1434
1435	(nil, e) := pexp(mkpprint(p.ex, p.code), pc, p.code.npc);
1436	error(p, "only left-hand-side expressions allowed: "+e);
1437}
1438
1439#lhsexp	: newexp
1440#	| callexp
1441#	;
1442#callexp: memexp args
1443#	| callexp args
1444#	| callexp '[' exp ']'
1445#	| callexp '.' Lid
1446#	;
1447#newexp	: memexp
1448#	| Lnew newexp
1449#	;
1450#memexp	: primexp
1451#	| Lfunction id(opt) '(' zplist ')' '{' stmts '}'
1452#	| memexp '[' exp ']'
1453#	| memexp '.' Lid
1454#	| Lnew memexp args
1455#	;
1456lhsexp(p: ref Parser, hasnew: int): int
1457{
1458	a: int;
1459	if(look(p) == Lnew){
1460		lex(p);
1461		hasnew = lhsexp(p, hasnew + 1);
1462		if(hasnew){
1463			emit(p, Lnew);
1464			hasnew--;
1465		}
1466		return hasnew;
1467	}
1468	if(look(p) == Lfunction){
1469		o := fundecl(p.ex, p, 1);
1470		emitconst(p, Lfunction, fexplook(p, o));
1471		return 0;
1472	}
1473	primexp(p);
1474	for(;;){
1475		op := look(p);
1476		if(op == '('){
1477			op = Lcall;
1478			if(hasnew){
1479				hasnew--;
1480				#
1481				# stupid different order of evaluation
1482				#
1483				emit(p, Lgetval);
1484				op = Lnewcall;
1485			}
1486			a = args(p);
1487			emitconst(p, op, a);
1488		}else if(op == '['){
1489			emit(p, Lgetval);
1490			lex(p);
1491			exp(p);
1492			mustbe(p, ']');
1493			emit(p, '[');
1494		}else if(op == '.'){
1495			lex(p);
1496			mustbe(p, Lid);
1497			emitconst(p, Lid, p.id);
1498			emit(p, '.');
1499		}else
1500			return hasnew;
1501	}
1502}
1503
1504#primexp	: Lthis
1505#	| Lid
1506#	| Lnum
1507#	| Lstr
1508#	| Lregexp
1509#	| '(' exp ')'
1510#	| '[' array initializer ']'
1511#	| '{' propandval '}'
1512#	;
1513primexp(p: ref Parser)
1514{
1515	case t := lex(p){
1516	Lthis =>
1517		emit(p, t);
1518	Lid or
1519	Lnum or
1520	Lstr =>
1521		emitconst(p, t, p.id);
1522	'/' =>
1523		lexregexp(p);
1524		emitconst(p, Lregexp, p.id);
1525	'(' =>
1526		emit(p, '(');
1527		exp(p);
1528		mustbe(p, ')');
1529		emit(p, ')');
1530	'[' =>
1531		a := 0;
1532		if(look(p) == ']')
1533			lex(p);
1534		else{
1535			for(;;){
1536				if(look(p) == ']'){
1537					lex(p);
1538					break;
1539				}
1540				if(look(p) == ',')
1541					emit(p, Lnoval);
1542				else
1543					asexp(p);
1544				emit(p, Lgetval);
1545				a++;
1546				if(look(p) == ']'){
1547					lex(p);
1548					break;
1549				}
1550				mustbe(p, ',');
1551			}
1552		}
1553		emitconst(p, Larrinit, a);
1554	'{' =>
1555		a := 0;
1556		if(look(p) == '}')
1557			lex(p);
1558		else{
1559			for(;;){
1560				case(tt := lex(p)){
1561				Lid =>
1562					emitconst(p, Lstr, p.id);
1563				Lnum or
1564				Lstr =>
1565					emitconst(p, tt, p.id);
1566				* =>
1567					error(p, "expected identifier, number or string");
1568				}
1569				mustbe(p, ':');
1570				asexp(p);
1571				emit(p, Lgetval);
1572				a++;
1573				if(look(p) == '}'){
1574					lex(p);
1575					break;
1576				}
1577				mustbe(p, ',');
1578			}
1579		}
1580		emitconst(p, Lobjinit, a);
1581	* =>
1582		error(p, "expected an expression");
1583	}
1584}
1585
1586#args	: '(' ')'
1587#	| '(' arglist ')'
1588#	;
1589#
1590#arglist	: asexp
1591#	| arglist ',' asexp
1592#	;
1593args(p: ref Parser): int
1594{
1595	mustbe(p, '(');
1596	if(look(p) == ')'){
1597		lex(p);
1598		return 0;
1599	}
1600	a := 0;
1601	for(;;){
1602		asexp(p);
1603		emit(p, Lgetval);
1604		a++;
1605		if(look(p) == ')'){
1606			lex(p);
1607			return a;
1608		}
1609		mustbe(p, ',');
1610	}
1611}
1612
1613inops(tok: int, ops: array of int): int
1614{
1615	for(i := 0; i < len ops; i++)
1616		if(tok == ops[i])
1617			return i;
1618	return -1;
1619}
1620
1621mustbe(p: ref Parser, t: int)
1622{
1623	tt := lex(p);
1624	if(tt != t)
1625		error(p, "expected "+tokname(t)+" found "+tokname(tt));
1626}
1627
1628toknames := array[] of
1629{
1630	Leos-Lbase =>		"end of input",
1631	Landas-Lbase =>		"&=",
1632	Loras-Lbase =>		"|=",
1633	Lxoras-Lbase =>		"^=",
1634	Llshas-Lbase =>		"<<=",
1635	Lrshas-Lbase =>		">>=",
1636	Lrshuas-Lbase =>	">>>=",
1637	Laddas-Lbase =>		"+=",
1638	Lsubas-Lbase =>		"-=",
1639	Lmulas-Lbase =>		"*=",
1640	Ldivas-Lbase =>		"/=",
1641	Lmodas-Lbase =>		"%=",
1642	Loror-Lbase =>		"||",
1643	Landand-Lbase =>	"&&",
1644	Leq-Lbase =>		"==",
1645	Lneq-Lbase =>		"!=",
1646	Lleq-Lbase =>		"<=",
1647	Lgeq-Lbase =>		">=",
1648	Llsh-Lbase =>		"<<",
1649	Lrsh-Lbase =>		">>",
1650	Lrshu-Lbase =>		">>>",
1651	Linc-Lbase =>		"++",
1652	Ldec-Lbase =>		"--",
1653	Lnum-Lbase =>		"a number",
1654	Lid-Lbase =>		"an identifier",
1655	Lstr-Lbase =>		"a string",
1656	Lthis-Lbase =>		"this",
1657	Ltypeof-Lbase =>	"typeof",
1658	Ldelete-Lbase =>	"delete",
1659	Lvoid-Lbase =>		"void",
1660	Lwhile-Lbase =>		"while",
1661	Lfor-Lbase =>		"for",
1662	Lbreak-Lbase =>		"break",
1663	Lcontinue-Lbase =>	"continue",
1664	Lwith-Lbase =>		"with",
1665	Lreturn-Lbase =>	"return",
1666	Lfunction-Lbase =>	"function",
1667	Lvar-Lbase =>		"var",
1668	Lif-Lbase =>		"if",
1669	Lelse-Lbase =>		"else",
1670	Lin-Lbase =>		"in",
1671	Lnew-Lbase =>		"new",
1672
1673	Lpreadd-Lbase =>	"+",
1674	Lpresub-Lbase =>	"-",
1675	Lpostinc-Lbase =>	"++",
1676	Lpostdec-Lbase =>	"--",
1677	Lcall-Lbase =>		"call",
1678	Lnewcall-Lbase =>	"newcall",
1679	Lgetval-Lbase =>	"[[GetValue]]",
1680	Las-Lbase =>		"[[as]]",
1681	Lasop-Lbase =>		"[[asop]]",
1682	Lforin-Lbase =>		"forin",
1683	Lforvar-Lbase =>	"forvar",
1684	Lforvarin-Lbase =>	"forvarin",
1685	Lcase-Lbase =>		"case",
1686	Labstract-Lbase =>	"abstract",
1687	Lboolean-Lbase =>	"boolean",
1688	Lbyte-Lbase =>	"byte",
1689	Lcatch-Lbase =>		"catch",
1690	Lchar-Lbase =>	"char",
1691	Lclass-Lbase =>		"class",
1692	Lconst-Lbase =>		"const",
1693	Ldebugger-Lbase =>	"debugger",
1694	Ldefault-Lbase =>	"default",
1695	Ldo-Lbase =>		"do",
1696	Ldouble-Lbase =>	"double",
1697	Lenum-Lbase =>		"enum",
1698	Lexport-Lbase =>	"export",
1699	Lextends-Lbase =>	"extends",
1700	Lfinal-Lbase =>	"final",
1701	Lfinally-Lbase =>	"finally",
1702	Lfloat-Lbase =>	"float",
1703	Lgoto-Lbase =>	"goto",
1704	Limplements-Lbase =>	"implements",
1705	Limport-Lbase =>	"import",
1706	Linstanceof-Lbase =>	"instanceof",
1707	Lint-Lbase =>		"int",
1708	Linterface-Lbase =>	"interface",
1709	Llong-Lbase =>	"long",
1710	Lnative-Lbase =>	"native",
1711	Lpackage-Lbase =>	"package",
1712	Lprint-Lbase =>	"print",
1713	Lprivate-Lbase =>	"private",
1714	Lprotected-Lbase =>	"protected",
1715	Lpublic-Lbase =>	"public",
1716	Lregexp-Lbase =>	"regexp",
1717	Lseq-Lbase =>	"===",
1718	Lsne-Lbase =>	"!==",
1719	Lshort-Lbase =>	"short",
1720	Lstatic-Lbase =>	"static",
1721	Lsuper-Lbase =>		"super",
1722	Lswitch-Lbase =>	"switch",
1723	Lsynchronized-Lbase =>	"synchronized",
1724	Lthrow-Lbase =>		"throw",
1725	Lthrows-Lbase =>	"throws",
1726	Ltransient-Lbase =>	"transient",
1727	Ltry-Lbase=>		"try",
1728	Lvolatile-Lbase =>	"volatile",
1729	Larrinit-Lbase =>	"arrayinit",
1730	Lobjinit-Lbase =>	"objinit",
1731	Lnoval-Lbase =>	"novalue",
1732	Llabel-Lbase =>	"label",
1733	Lbreaklab-Lbase =>	"break",
1734	Lcontinuelab-Lbase =>	"continue",
1735};
1736
1737tokname(t: int): string
1738{
1739	if(t < Lbase){
1740		s := "";
1741		s[0] = t;
1742		return s;
1743	}
1744	if(t-Lbase >= len toknames || toknames[t-Lbase] == "")
1745		return sprint("<%d>", t);
1746	return toknames[t-Lbase];
1747}
1748
1749lexemit(p: ref Parser)
1750{
1751	emit(p, lex(p));
1752	if(debug['s'])
1753		sys->print("%d: %s\n", p.code.npc-1, tokname(int p.code.ops[p.code.npc-1]));
1754}
1755
1756emit(p: ref Parser, t: int)
1757{
1758	if(t > 255)
1759		fatal(p.ex, sprint("emit too big: %d\n", t));
1760	if(p.code.npc >= len p.code.ops){
1761		ops := array[2 * len p.code.ops] of byte;
1762		ops[:] = p.code.ops;
1763		p.code.ops = ops;
1764	}
1765	p.code.ops[p.code.npc++] = byte t;
1766}
1767
1768emitconst(p: ref Parser, op, c: int)
1769{
1770	emit(p, op);
1771	if(c < 0)
1772		fatal(p.ex, "emit negative constant");
1773	if(c >= 255){
1774		if(c >= 65536)
1775			fatal(p.ex, "constant too large");
1776		emit(p, 255);
1777		emit(p, c & 16rff);
1778		c >>= 8;
1779	}
1780	emit(p, c);
1781}
1782
1783epatch(p: ref Parser): int
1784{
1785	pc := p.code.npc;
1786	emit(p, 0);
1787	emit(p, 0);
1788	return pc;
1789}
1790
1791patch(p: ref Parser, pc: int)
1792{
1793	val := p.code.npc - pc;
1794	if(val >= 65536)
1795		fatal(p.ex, "patch constant too large");
1796	p.code.ops[pc] = byte val;
1797	p.code.ops[pc+1] = byte(val >> 8);
1798}
1799
1800getconst(ops: array of byte, pc: int): (int, int)
1801{
1802	c := int ops[pc++];
1803	if(c == 255){
1804		c = int ops[pc] + (int ops[pc+1] << 8);
1805		pc += 2;
1806	}
1807	return (pc, c);
1808}
1809
1810getjmp(ops: array of byte, pc: int): (int, int)
1811{
1812	c := int ops[pc] + (int ops[pc+1] << 8) + pc;
1813	pc += 2;
1814	return (pc, c);
1815}
1816
1817mkcode(): ref Code
1818{
1819	return ref Code(array[16] of byte, 0, nil, nil, nil, nil, nil);
1820}
1821
1822look(p: ref Parser): int
1823{
1824	if(p.token == -1)
1825		p.token = lex(p);
1826	if(p.notin && p.token == Lin)
1827		return ~Lin;
1828	return p.token;
1829}
1830
1831look2(p: ref Parser): int
1832{
1833	look(p);
1834	if(p.token1 == -1){
1835		# fool lex()
1836		t := p.token;
1837		p.token = -1;
1838		p.token1 = lex(p);
1839		p.token = t;
1840	}
1841	return  p.token1;
1842}
1843
1844lex(p: ref Parser): int
1845{
1846	t := lex0(p);
1847	if(0)
1848		sys->print("tok=%d %s\n", t, tokname(t));
1849	return t;
1850}
1851
1852lex0(p: ref Parser): int
1853{
1854	t := p.token;
1855	if(t != -1){
1856		p.token = p.token1;
1857		p.token1 = -1;
1858		return t;
1859	}
1860
1861	p.lastnl = 0;
1862	while(p.srci < p.esrc){
1863		c := p.src[p.srci++];
1864		case c{
1865		'\r' or LS or PS =>
1866			p.lastnl = 1;
1867		'\n' =>
1868			p.lineno++;
1869			p.lastnl = 1;
1870		' ' or
1871		'\t' or
1872		'\v' or
1873		FF or		# form feed
1874		'\u00a0' =>	# no-break space
1875			;
1876		'"' or
1877		'\''=>
1878			return lexstring(p, c);
1879		'(' or
1880		')' or
1881		'[' or
1882		']' or
1883		'{' or
1884		'}' or
1885		',' or
1886		';' or
1887		'~' or
1888		'?' or
1889		':' =>
1890			return c;
1891		'.' =>
1892			if(p.srci < p.esrc && (map[p.src[p.srci]] & Mdigit) != byte 0){
1893				p.srci--;
1894				return lexnum(p);
1895			}
1896			return '.';
1897		'^' =>
1898			if(p.srci < p.esrc && p.src[p.srci] == '='){
1899				p.srci++;
1900				return Lxoras;
1901			}
1902			return '^';
1903		'*' =>
1904			if(p.srci < p.esrc && p.src[p.srci] == '='){
1905				p.srci++;
1906				return Lmulas;
1907			}
1908			return '*';
1909		'%' =>
1910			if(p.srci < p.esrc && p.src[p.srci] == '='){
1911				p.srci++;
1912				return Lmodas;
1913			}
1914			return '%';
1915		'=' =>
1916			if(p.srci < p.esrc && p.src[p.srci] == '='){
1917				p.srci++;
1918				if(p.srci < p.esrc && p.src[p.srci] == '='){
1919					p.srci++;
1920					return Lseq;
1921				}
1922				return Leq;
1923			}
1924			return '=';
1925		'!' =>
1926			if(p.srci < p.esrc && p.src[p.srci] == '='){
1927				p.srci++;
1928				if(p.srci < p.esrc && p.src[p.srci] == '='){
1929					p.srci++;
1930					return Lsne;
1931				}
1932				return Lneq;
1933			}
1934			return '!';
1935		'+' =>
1936			if(p.srci < p.esrc){
1937				c = p.src[p.srci];
1938				if(c == '='){
1939					p.srci++;
1940					return Laddas;
1941				}
1942				if(c == '+'){
1943					p.srci++;
1944					return Linc;
1945				}
1946			}
1947			return '+';
1948		'-' =>
1949			if(p.srci < p.esrc){
1950				c = p.src[p.srci];
1951				if(c == '='){
1952					p.srci++;
1953					return Lsubas;
1954				}
1955				if(c == '-'){
1956					p.srci++;
1957					return Ldec;
1958				}
1959			}
1960			return '-';
1961		'|' =>
1962			if(p.srci < p.esrc){
1963				c = p.src[p.srci];
1964				if(c == '='){
1965					p.srci++;
1966					return Loras;
1967				}
1968				if(c == '|'){
1969					p.srci++;
1970					return Loror;
1971				}
1972			}
1973			return '|';
1974		'&' =>
1975			if(p.srci < p.esrc){
1976				c = p.src[p.srci];
1977				if(c == '='){
1978					p.srci++;
1979					return Landas;
1980				}
1981				if(c == '&'){
1982					p.srci++;
1983					return Landand;
1984				}
1985			}
1986			return '&';
1987		'/' =>
1988			if(p.srci < p.esrc){
1989				c = p.src[p.srci];
1990				if(c == '='){
1991					p.srci++;
1992					return Ldivas;
1993				}
1994				if(c == '/'){
1995					p.srci++;
1996					if(lexcom(p) < 0)
1997						return Leos;
1998					break;
1999				}
2000				if(c == '*'){
2001					p.srci++;
2002					if(lexmcom(p) < 0)
2003						return Leos;
2004					break;
2005				}
2006			}
2007			return '/';
2008		'>' =>
2009			if(p.srci < p.esrc){
2010				c = p.src[p.srci];
2011				if(c == '='){
2012					p.srci++;
2013					return Lgeq;
2014				}
2015				if(c == '>'){
2016					p.srci++;
2017					if (p.srci < p.esrc) {
2018						c = p.src[p.srci];
2019						if(c == '='){
2020							p.srci++;
2021							return Lrshas;
2022						}
2023						if(c == '>'){
2024							p.srci++;
2025							c = p.src[p.srci];
2026							if(c == '='){
2027								p.srci++;
2028								return Lrshuas;
2029							}
2030							return Lrshu;
2031						}
2032					}
2033					return Lrsh;
2034				}
2035			}
2036			return '>';
2037		'<' =>
2038			if(p.srci < p.esrc){
2039				c = p.src[p.srci];
2040				case c {
2041				'=' =>
2042					p.srci++;
2043					return Lleq;
2044				'<' =>
2045					p.srci++;
2046					if (p.srci < p.esrc) {
2047						c = p.src[p.srci];
2048						if(c == '='){
2049							p.srci++;
2050							return Llshas;
2051						}
2052					}
2053					return Llsh;
2054				'!' =>
2055					# HTML comment - consume to end of line or end of comment
2056					# No way of having the HTML parser do this
2057					if (p.srci+2 >= p.esrc)
2058						return Leos;
2059
2060					if (p.src[p.srci+1] != '-' || p.src[p.srci+2] != '-')
2061						# don't treat as a comment, let the parser report syntax error
2062						return '<';
2063					# consume "!--"
2064					p.srci += 3;
2065					if(lexhtmlcom(p) < 0)
2066						return Leos;
2067					continue;
2068				}
2069			}
2070			return '<';
2071		'0' to '9' =>
2072			p.srci--;
2073			return lexnum(p);
2074		'\\' =>
2075			return lexid(p);
2076		* =>
2077			if((map[c] & Malpha) != byte 0)
2078				return lexid(p);
2079			s := "";
2080			s[0] = c;
2081			error(p, "unknown character '"+s+"'");
2082		}
2083	}
2084	return Leos;
2085}
2086
2087#
2088# single line comment
2089#
2090lexcom(p: ref Parser): int
2091{
2092	while(p.srci < p.esrc){
2093		c := p.src[p.srci];
2094		if(islt(c))
2095			return 0;
2096		p.srci++;
2097	}
2098	return -1;
2099}
2100
2101#
2102# multi-line comment
2103#
2104lexmcom(p: ref Parser): int
2105{
2106	star := 0;
2107	while(p.srci < p.esrc){
2108		c := p.src[p.srci++];
2109		if(c == '/' && star)
2110			return 0;
2111		star = c == '*';
2112	}
2113	return -1;
2114}
2115
2116# HTML comment
2117# consume to end of line or end of comment (-->), whichever we see first.
2118# [not strict HTML comment semantics because of
2119# the way in which HTML comments are used in JavaScript]
2120#
2121lexhtmlcom(p: ref Parser): int
2122{
2123	nmin := 0;
2124	for (;p.srci < p.esrc;) {
2125		c := p.src[p.srci++];
2126		if (c == '-') {
2127			nmin++;
2128			continue;
2129		}
2130		if (c == '>' && nmin >= 2)
2131			return 0;
2132		if (islt(c))
2133			return 0;
2134		nmin = 0;
2135	}
2136	return -1;
2137}
2138
2139lexid(p: ref Parser): int
2140{
2141	p.srci--;
2142	id := "";
2143	ch := "Z";
2144	while(p.srci < p.esrc){
2145		c := p.src[p.srci];
2146		if(c == '\\'){
2147			p.srci++;
2148			c = uniescchar(p);
2149			if(c == -1)
2150				error(p, "malformed unicode escape sequence in identifier");
2151			else
2152				;
2153		}
2154		else{
2155			if(c >= 0 && c < 256 && (map[c] & (Malpha|Mdigit)) == byte 0)
2156			# if(c >= 256 || (map[c] & (Malpha|Mdigit)) == byte 0)
2157				break;
2158			p.srci++;
2159		}
2160		ch[0] = c;
2161		id += ch;
2162	}
2163	# id := p.src[srci:p.srci];
2164	t := keywdlook(id);
2165	if(t != -1)
2166		return t;
2167	p.id = strlook(p, id);
2168	return Lid;
2169}
2170
2171ParseReal, ParseHex, ParseOct, ParseTrim, ParseEmpty: con 1 << iota;
2172
2173#
2174# parse a numeric identifier
2175# format [0-9]+(r[0-9A-Za-z]+)?
2176# or ([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][+-]?[0-9]+)?
2177#
2178lexnum(p: ref Parser): int
2179{
2180	v: real;
2181	(p.srci, v) = parsenum(p.ex, p.src, p.srci, ParseReal|ParseHex|ParseOct);
2182	p.id = numlook(p, v);
2183	return Lnum;
2184}
2185
2186parsenum(ex: ref Exec, s: string, si, how: int): (int, real)
2187{
2188	Inf: con "Infinity";
2189
2190	osi := si;
2191	lens := len s;
2192	if (how & ParseTrim) {
2193		while(si < lens && iswhite(s[si]))
2194			si++;
2195	}
2196	if(si >= lens) {
2197		if (how & ParseEmpty)
2198			return (si, 0.);
2199		return (osi, Math->NaN);
2200	}
2201	c := s[si];
2202	neg := 0;
2203	if(c == '+')
2204		si++;
2205	else if(c == '-'){
2206		si++;
2207		neg = 1;
2208	}
2209	v := 0.;
2210	if((how & ParseReal) && si + len Inf <= lens && s[si:si+len Inf] == Inf){
2211		si += len Inf;
2212		v = Math->Infinity;
2213	}else{
2214		nsi := si;
2215		(si, v) = parsenumval(ex, s, si, how);
2216		if(si == nsi)
2217			return (osi, Math->NaN);
2218	}
2219	if(neg)
2220		v = -v;
2221	if (how & ParseTrim) {
2222		while(si < lens && iswhite(s[si]))
2223			si++;
2224	}
2225	return (si, v);
2226}
2227
2228#
2229# parse a bunch of difference subsets of numbers
2230#
2231parsenumval(ex: ref Exec, s: string, si, how: int): (int, real)
2232{
2233	Int, Oct, Hex, FracSeen, Frac, ExpSeen, ExpSignSeen, Exp: con iota;
2234
2235	lens := len s;
2236	if(si >= lens)
2237		return (si, Math->NaN);
2238	ssi := si;
2239	c := s[si];
2240	state := Int;
2241	if(c == '.' && (how & ParseReal)){
2242		state = FracSeen;
2243		si++;
2244	}else if(c == '0'){
2245		if(si+1 >= lens)
2246			return (si+1, 0.);
2247		c = s[si+1];
2248		if(c == '.' && (how & ParseReal)){
2249			state = Frac;
2250			si += 2;
2251		}else if((c == 'x' || c == 'X') && (how & ParseHex)){
2252			state = Hex;
2253			ssi += 2;
2254			si += 2;
2255		}else if(how & ParseOct)
2256			state = Oct;
2257	}
2258
2259done:	while(si < lens){
2260		c = s[si];
2261		case state{
2262		Int =>
2263			if((map[c] & Mdigit) != byte 0)
2264				break;
2265			if((map[c] & Mexp) != byte 0 && (how & ParseReal))
2266				state = ExpSeen;
2267			else if(c == '.' && (how & ParseReal))
2268				state = Frac;
2269			else
2270				break done;
2271		Hex =>
2272			if((map[c] & Mhex) == byte 0)
2273				break done;
2274		Oct =>
2275			if((map[c] & Moct) == byte 0)
2276				break done;
2277		FracSeen or
2278		Frac =>
2279			if((map[c] & Mdigit) != byte 0)
2280				state = Frac;
2281			else if((map[c] & Mexp) != byte 0)
2282				state = ExpSeen;
2283			else
2284				break done;
2285		ExpSeen =>
2286			if((map[c] & Msign) != byte 0)
2287				state = ExpSignSeen;
2288			else if((map[c] & Mdigit) != byte 0)
2289				state = Exp;
2290			else
2291				break done;
2292		ExpSignSeen or
2293		Exp =>
2294			if((map[c] & Mdigit) != byte 0)
2295				state = Exp;
2296			else
2297				break done;
2298		}
2299		si++;
2300	}
2301
2302	esi := si;
2303	if(state == FracSeen)
2304		return (si - 1, Math->NaN);
2305	if(state == ExpSeen){
2306		state = Frac;
2307		esi--;
2308	}else if(state == ExpSignSeen){
2309		state = Frac;
2310		esi -= 2;
2311	}
2312	buf := s[ssi:esi];
2313	v: real;
2314	case state{
2315	* =>
2316		# only if the above lexing code is wrong
2317		fatal(ex, "bad parse of numerical constant '"+buf+"'");
2318		v = 0.;
2319	Oct =>
2320		v = strtoi(ex, buf, 8);
2321	Hex =>
2322		v = strtoi(ex, buf, 16);
2323	Int or
2324	Frac or
2325	Exp =>
2326		v = real buf;
2327	}
2328	return (si, v);
2329}
2330
2331#
2332# called only from parsenumval
2333# can never fatal error if that routine works correctly
2334#
2335strtoi(ex: ref Exec, t: string, base: int): real
2336{
2337	if(len t == 0)
2338		return Math->NaN;
2339
2340	v := 0.;
2341	for(i := 0; i < len t; i++){
2342		c := t[i];
2343		if(c >= '0' && c <= '9')
2344			c -= '0';
2345		else if(c >= 'a' && c <= 'z')
2346			c -= 'a' - 10;
2347		else
2348			c -= 'A' - 10;
2349		if(c >= base){
2350			fatal(ex, "digit '"+t[i:i+1]+"' is not radix "+string base);
2351			return Math->NaN;
2352		}
2353		v = v * real base + real c;
2354	}
2355	return v;
2356}
2357
2358lexstring(p: ref Parser, end: int): int
2359{
2360	s := "";
2361	i := 0;
2362	for(;;){
2363		if(p.srci >= p.esrc){
2364			error(p, "end of file in string constant");
2365			break;
2366		}
2367		c := p.src[p.srci];
2368		if(islt(c)){
2369			error(p, "newline in string constant");
2370			break;
2371		}
2372		p.srci++;
2373		if(c == end)
2374			break;
2375		if(c == '\\'){
2376			c = escchar(p);
2377			if(c == Leos)
2378				continue;
2379		}
2380		s[i++] = c;
2381	}
2382	p.id = strlook(p, s);
2383	return Lstr;
2384}
2385
2386lexregexp(p: ref Parser): int
2387{
2388	c := esc := 0;
2389	s := "";
2390	i := 0;
2391	s[i++] = '/';
2392	for(;;){
2393		if(p.srci >= p.esrc){
2394			error(p, "end of file in regexp constant");
2395			break;
2396		}
2397		c = p.src[p.srci];
2398		if(islt(c)){
2399			error(p, "newline in regexp constant");
2400			break;
2401		}
2402		p.srci++;
2403		s[i++] = c;
2404		if(!esc && c == '/')
2405			break;
2406		esc = !esc && c == '\\';
2407	}
2408	if(esc)
2409		error(p, "missing escaped character");
2410	if(i == 2)
2411		error(p, "missing regexp");
2412	while(p.srci < p.esrc){
2413		c = p.src[p.srci];
2414		if(c >= 256 || (map[c] & (Malpha|Mdigit)) == byte 0)
2415			break;
2416		p.srci++;
2417		s[i++] = c;
2418	}
2419	p.id = strlook(p, s);
2420	return Lregexp;
2421}
2422
2423uniescchar(p: ref Parser): int
2424{
2425	if(p.srci >= p.esrc)
2426		return -1;
2427	c := p.src[p.srci++];
2428	if(c != 'u')
2429		return -1;
2430	v := 0;
2431	for(i := 0; i < 4; i++){
2432		if(p.srci >= p.esrc || (map[c = p.src[p.srci]] & (Mdigit|Mhex)) == byte 0)
2433			return -1;
2434		p.srci++;
2435		if((map[c] & Mdigit) != byte 0)
2436			c -= '0';
2437		else if((map[c] & Mlower) != byte 0)
2438			c = c - 'a' + 10;
2439		else if((map[c] & Mupper) != byte 0)
2440			c = c - 'A' + 10;
2441		v = v * 16 + c;
2442	}
2443	return v;
2444}
2445
2446escchar(p: ref Parser): int
2447{
2448	v: int;
2449	if(p.srci >= p.esrc)
2450		return Leos;
2451	c := p.src[p.srci++];
2452	if(c == 'u' || c == 'x'){
2453		d := 2;
2454		if(c == 'u')
2455			d = 4;
2456		v = 0;
2457		for(i := 0; i < d; i++){
2458			if(p.srci >= p.esrc || (map[c = p.src[p.srci]] & (Mdigit|Mhex)) == byte 0){
2459				error(p, "malformed hex escape sequence");
2460				break;
2461			}
2462			p.srci++;
2463			if((map[c] & Mdigit) != byte 0)
2464				c -= '0';
2465			else if((map[c] & Mlower) != byte 0)
2466				c = c - 'a' + 10;
2467			else if((map[c] & Mupper) != byte 0)
2468				c = c - 'A' + 10;
2469			v = v * 16 + c;
2470		}
2471		return v;
2472	}
2473	if(c >= '0' && c <= '7'){
2474		v = c - '0';
2475		if(p.srci < p.esrc && (c = p.src[p.srci]) >= '0' && c <= '7'){
2476			p.srci++;
2477			v = v * 8 + c - '0';
2478			if(v <= 8r37 && p.srci < p.esrc && (c = p.src[p.srci]) >= '0' && c <= '7'){
2479				p.srci++;
2480				v = v * 8 + c - '0';
2481			}
2482		}
2483		return v;
2484	}
2485
2486	if(c < len escmap && (v = int escmap[c]) < 255)
2487		return v;
2488	return c;
2489}
2490
2491keywdlook(s: string): int
2492{
2493	m: int;
2494	l := 1;
2495	r := len keywords - 1;
2496	while(l <= r){
2497		m = (r + l) >> 1;
2498		if(keywords[m].name <= s)
2499			l = m + 1;
2500		else
2501			r = m - 1;
2502	}
2503	m = l - 1;
2504	if(keywords[m].name == s)
2505		return keywords[m].token;
2506	return -1;
2507}
2508
2509strlook(p: ref Parser, s: string): int
2510{
2511	for(i := 0; i < len p.code.strs; i++)
2512		if(p.code.strs[i] == s)
2513			return i;
2514	strs := array[i + 1] of string;
2515	strs[:] = p.code.strs;
2516	strs[i] = s;
2517	p.code.strs = strs;
2518	return i;
2519}
2520
2521numlook(p: ref Parser, r: real): int
2522{
2523	for(i := 0; i < len p.code.nums; i++)
2524		if(p.code.nums[i] == r)
2525			return i;
2526	nums := array[i + 1] of real;
2527	nums[:] = p.code.nums;
2528	nums[i] = r;
2529	p.code.nums = nums;
2530	return i;
2531}
2532
2533fexplook(p: ref Parser, o: ref Obj): int
2534{
2535	i := len p.code.fexps;
2536	fexps := array[i+1] of ref Obj;
2537	fexps[:] = p.code.fexps;
2538	fexps[i] = o;
2539	p.code.fexps = fexps;
2540	return i;
2541}
2542
2543iswhite(c: int): int
2544{
2545	if(islt(c))
2546		return 1;
2547	case c {
2548	' ' or
2549	'\t' or
2550	'\v' or
2551	FF or			# form feed
2552	'\u00a0' =>	# no-break space
2553		return 1;
2554	}
2555	return 0;
2556}
2557
2558error(p: ref Parser, s: string)
2559{
2560	p.errors++;
2561	p.ex.error += sys->sprint("%d: syntax error: %s\n", p.lineno, s);
2562	if(p.errors >= maxerr)
2563		runtime(p.ex, SyntaxError, p.ex.error);
2564}
2565
2566fatal(ex: ref Exec, msg: string)
2567{
2568	if(debug['f']){
2569		print("fatal ecmascript error: %s\n", msg);
2570		if(""[5] == -1);	# abort
2571	}
2572	runtime(ex, InternalError, "unrecoverable internal ecmascript error: "+ msg);
2573}
2574
2575# scanb(p: ref Parser, s: string): int
2576# {
2577# 	n := len s;
2578# 	for(i := p.srci; i+n > p.esrc || p.src[i: i+n] != s; --i)
2579# 		;
2580# 	return i;
2581# }
2582
2583setkindlab(p: ref Parser, op: int, n: int)
2584{
2585	l := p.labs;
2586	for(i := 0; i < n; i++){
2587		(hd l).k = op;
2588		l = tl l;
2589	}
2590}
2591
2592inlocallabs(p: ref Parser, lr: ref labrec, n: int): int
2593{
2594	l := p.labs;
2595	for(i := 0; i < n; i++){
2596		if(hd l == lr)
2597			return 1;
2598		l = tl l;
2599	}
2600	return 0;
2601}
2602
2603findlab(p: ref Parser, s: string): ref labrec
2604{
2605	for(l := p.labs; l != nil; l = tl l)
2606		if((hd l).s == s)
2607			return hd l;
2608	return nil;
2609}
2610
2611pushlab(p: ref Parser, s: string)
2612{
2613	if(findlab(p, s) != nil)
2614		error(p, "duplicate labels");
2615	p.labs = ref labrec(s, 0) :: p.labs;
2616}
2617
2618poplab(p: ref Parser)
2619{
2620	p.labs = tl p.labs;
2621}
2622
2623itstmt(k: int): int
2624{
2625	return k == Lwhile || k == Ldo || k == Lfor;
2626}
2627