xref: /inferno-os/module/ecmascript.m (revision 46439007cf417cbd9ac8049bb4122c890097a0fa)
1ESHostobj: module
2{
3	#
4	# extensible interface for adding host objects
5	#
6	# any implementation must obey the rules of the interpreter.
7	# it is an error to return bogus values, and may cause
8	# the interpreter to crash.
9	#
10	# get/put must return/set the value of property in o
11	#
12	# canput and hasproperty return es->true or es->false
13	#
14	# defaultval must return a primitive (non-object) value.
15	#	this means it can't return a String object, etc.
16	#
17	# call gets the caller's execution context in ex.
18	# the new this value is passed as an argument,
19	# but no new scopechain is allocated
20	# it returns a reference, which is typically just a value
21	#
22	# construct should make up a new object
23	#
24	get:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
25	put:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string, val: ref Ecmascript->Val);
26	canput:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
27	hasproperty:	fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
28	delete:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string);
29	defaultval:	fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, tyhint: int): ref Ecmascript->Val;
30	call:		fn(ex: ref Ecmascript->Exec, func, this: ref Ecmascript->Obj, args: array of ref Ecmascript->Val, eval: int): ref Ecmascript->Ref;
31	construct:	fn(ex: ref Ecmascript->Exec, func: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Obj;
32};
33
34#
35# calls to init and mkexec do the following
36#	math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
37#
38Ecmascript: module
39{
40	PATH:	con "/dis/lib/ecmascript.dis";
41
42	#
43	# an execution context
44	#
45	Exec: adt
46	{
47		#
48		# well known glop
49		#
50		objproto:	cyclic ref Obj;
51		funcproto:	cyclic ref Obj;
52		strproto:	cyclic ref Obj;
53		numproto:	cyclic ref Obj;
54		boolproto:	cyclic ref Obj;
55		arrayproto:	cyclic ref Obj;
56		dateproto:	cyclic ref Obj;
57		regexpproto:	cyclic ref Obj;
58		errproto:		cyclic ref Obj;
59		evlerrproto:		cyclic ref Obj;
60		ranerrproto:		cyclic ref Obj;
61		referrproto:		cyclic ref Obj;
62		synerrproto:		cyclic ref Obj;
63		typerrproto:		cyclic ref Obj;
64		urierrproto:		cyclic ref Obj;
65		interrproto:		cyclic ref Obj;
66
67		global:		cyclic ref Obj;
68		this:		cyclic ref Obj;
69		scopechain:	cyclic list of ref Obj;
70
71		error:		string;
72		errval:		cyclic ref Val;
73
74		#
75		# private, keep out
76		#
77		stack:		cyclic array of ref Ref;
78		sp:	int;
79	};
80
81	#
82	# must be called at the dawn of time
83	# returns error string
84	init:	fn(): string;
85
86	#
87	# initialize a new global execution context
88	# if go is supplied, it's the global object
89	# if not, one is made up automatically
90	#
91	mkexec:		fn(go: ref Obj): ref Exec;
92
93	#
94	# throw a runtime error
95	# msg ends up in ex.error, and an
96	# "ecmascript runtime error" is raised
97	#
98	RUNTIME:	con "ecmascript runtime error";
99	runtime:	fn(ex: ref Exec, o: ref Obj, msg: string);
100
101	# runtime errors
102	EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, InternalError: ref Obj;
103
104	#
105	# debug flags: array of 256 indexed by char
106	#
107	# e	print ops as they are executed
108	# f	abort on an internal error
109	# p	print parsed code
110	# r	abort on any runtime error
111	# v	print value of expression statements
112	#
113	debug: array of int;
114
115	#
116	# parse and runt the source string
117	#
118	eval:	fn(ex: ref Exec, src: string): Completion;
119
120	Re: type ref Arena;
121
122	# the fundamental data structure
123	Obj: adt
124	{
125		props:		cyclic array of ref Prop;
126		prototype:	cyclic ref Obj;		# some builtin properties
127		val:		cyclic ref Val;
128		call:		cyclic ref Call;
129		construct:	cyclic ref Call;
130		class:		string;
131		host:		ESHostobj;		# method suite for host objects
132		re:		Re;				# compiled regexp for RegExp objects
133	};
134
135	Call: adt
136	{
137		params:		array of string;
138		code:		cyclic ref Code;
139		ex:		cyclic ref Exec;
140	};
141
142	# attributes
143	ReadOnly, DontEnum, DontDelete: con 1 << iota;
144	Prop: adt
145	{
146		attr:		int;
147		name:		string;
148		val:		cyclic ref RefVal;
149	};
150
151	# an extra level of indirection, because sometimes properties are aliased
152	RefVal: adt
153	{
154		val:		cyclic ref Val;
155	};
156
157	# types of js values
158	TUndef, TNull, TBool, TNum, TStr, TObj, TRegExp, NoHint: con iota;
159	Val: adt
160	{
161		ty:		int;
162		num:		real;
163		str:		string;
164		obj:		cyclic ref Obj;
165		rev:		ref REval;
166	};
167
168	# regular expression
169	REval: adt
170	{
171		p: string;
172		f: string;
173		i: int;
174	};
175
176	# intermediate result of expression evaluation
177	Ref: adt
178	{
179		isref:		int;
180		val:		ref Val;
181		base:		ref Obj;
182		name:		string;				# name of property within base
183	};
184
185	# completion values of statements
186	CNormal, CBreak, CContinue, CReturn, CThrow: con iota;
187	Completion: adt
188	{
189		kind:		int;
190		val:		ref Val;
191		lab:		string;
192	};
193
194	Code: adt
195	{
196		ops:		array of byte;			# all instructions
197		npc:		int;				# end of active portion of ops
198		vars:		cyclic array of ref Prop;	# variables defined in the code
199		ids:		array of string;		# ids used in the code
200		strs:		array of string;		# string literal
201		nums:		array of real;			# numerical literals
202		fexps:	cyclic array of ref Obj;	# function expressions
203	};
204
205	#
206	# stuff for adding host objects
207	#
208	# ecmascript is also a host object;
209	get:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
210	put:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string, val: ref Ecmascript->Val);
211	canput:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
212	hasproperty:	fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
213	delete:		fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string);
214	defaultval:	fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, tyhint: int): ref Ecmascript->Val;
215	call:		fn(ex: ref Ecmascript->Exec, func, this: ref Ecmascript->Obj, args: array of ref Ecmascript->Val, eval: int): ref Ecmascript->Ref;
216	construct:	fn(ex: ref Ecmascript->Exec, func: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Obj;
217
218	#
219	# return the named variable from the scope chain sc
220	#
221	bivar:		fn(ex: ref Exec, sc: list of ref Obj, s: string): ref Val;
222
223	#
224	# return the nth argument value, or undefined if too far
225	#
226	biarg:		fn(args: array of ref Val, n: int): ref Val;
227
228	#
229	# make up a new object
230	# most often called as mkobj(ex.objproto, "Object")
231	#
232	mkobj:		fn(proto: ref Obj, class: string): ref Obj;
233
234	#
235	# object installation helpers
236	#
237	Builtin: adt
238	{
239		name:	string;
240		val:	string;
241		params:	array of string;
242		length:	int;
243	};
244	biinst:		fn(o: ref Obj, bi: Builtin, proto: ref Obj, h: ESHostobj): ref Obj;
245	biminst:	fn(o: ref Obj, bis: array of Builtin, proto: ref Obj, h: ESHostobj);
246
247	#
248	# instantiate a new variable inside an object
249	#
250	varinstant:	fn(in: ref Obj, attr: int, name: string, val: ref RefVal);
251
252	#
253	# various constructors
254	#
255	objval:		fn(o: ref Obj): ref Val;
256	strval:		fn(s: string): ref Val;
257	numval:		fn(r: real): ref Val;
258	valref:		fn(v: ref Val): ref Ref;
259
260	#
261	# conversion routines defined in section 9
262	#
263	toPrimitive:	fn(ex: ref Exec, v: ref Val, ty: int): ref Val;
264	toBoolean:	fn(ex: ref Exec, v: ref Val): ref Val;
265	toNumber:	fn(ex: ref Exec, v: ref Val): real;
266	toInteger:	fn(ex: ref Exec, v: ref Val): real;
267	toInt32:	fn(ex: ref Exec, v: ref Val): int;
268	toUint32:	fn(ex: ref Exec, v: ref Val): big;
269	toUint16:	fn(ex: ref Exec, v: ref Val): int;
270	toString:	fn(ex: ref Exec, v: ref Val): string;
271	toObject:	fn(ex: ref Exec, v: ref Val): ref Obj;
272
273	#
274	# simple coercion routines to force
275	# Boolean, String, and Number values to objects and vice versa
276	#
277	coerceToObj:	fn(ex: ref Exec, v: ref Val): ref Val;
278	coerceToVal:	fn(v: ref Val): ref Val;
279
280	#
281	# object/value kind checkers
282	#
283	isstrobj:	fn(o: ref Obj): int;
284	isnumobj:	fn(o: ref Obj): int;
285	isboolobj:	fn(o: ref Obj): int;
286	isdateobj:	fn(o: ref Obj): int;
287	isregexpobj: fn(o: ref Obj): int;
288	isarray:	fn(o: ref Obj): int;
289	isstr:		fn(v: ref Val): int;
290	isnum:		fn(v: ref Val): int;
291	isbool:		fn(v: ref Val): int;
292	isobj:		fn(v: ref Val): int;
293
294	#
295	# well-known ecmascript primitive values
296	#
297	undefined:	ref Val;
298	true:		ref Val;
299	false:		ref Val;
300	null:		ref Val;
301
302	# regexp data structures
303
304	refRex: type int;	# used instead of ref Rex to avoid circularity
305
306	Set: adt {				# character class
307		neg: int;			# 0 or 1
308		ascii: array of int;		# ascii members, bit array
309		unicode: list of (int,int);	# non-ascii char ranges
310		subset: cyclic list of ref Set;
311	};
312
313	Nstate: adt{
314		m: int;
315		n: int;
316	};
317
318	Rex: adt {		# node in parse of regex, or state of fsm
319		kind: int;	# kind of node: char or ALT, CAT, etc
320		left: refRex;	# left descendant
321		right: refRex;	# right descendant, or next state
322		set: ref Set;	# character class
323		pno: int;
324		greedy: int;
325		ns: ref Nstate;
326	};
327
328	Arena: adt {		# free store from which nodes are allocated
329		rex: array of Rex;
330		ptr: refRex;	# next available space
331		start: refRex;	# root of parse, or start of fsm
332		pno: int;
333	};
334};
335