summaryrefslogtreecommitdiff
path: root/module/ecmascript.m
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 20:52:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 20:52:35 +0000
commit46439007cf417cbd9ac8049bb4122c890097a0fa (patch)
tree6fdb25e5f3a2b6d5657eb23b35774b631d4d97e4 /module/ecmascript.m
parent37da2899f40661e3e9631e497da8dc59b971cbd0 (diff)
20060303-partial
Diffstat (limited to 'module/ecmascript.m')
-rw-r--r--module/ecmascript.m334
1 files changed, 334 insertions, 0 deletions
diff --git a/module/ecmascript.m b/module/ecmascript.m
new file mode 100644
index 00000000..27856d9a
--- /dev/null
+++ b/module/ecmascript.m
@@ -0,0 +1,334 @@
+ESHostobj: module
+{
+ #
+ # extensible interface for adding host objects
+ #
+ # any implementation must obey the rules of the interpreter.
+ # it is an error to return bogus values, and may cause
+ # the interpreter to crash.
+ #
+ # get/put must return/set the value of property in o
+ #
+ # canput and hasproperty return es->true or es->false
+ #
+ # defaultval must return a primitive (non-object) value.
+ # this means it can't return a String object, etc.
+ #
+ # call gets the caller's execution context in ex.
+ # the new this value is passed as an argument,
+ # but no new scopechain is allocated
+ # it returns a reference, which is typically just a value
+ #
+ # construct should make up a new object
+ #
+ get: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
+ put: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string, val: ref Ecmascript->Val);
+ canput: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
+ hasproperty: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
+ delete: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string);
+ defaultval: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, tyhint: int): ref Ecmascript->Val;
+ call: fn(ex: ref Ecmascript->Exec, func, this: ref Ecmascript->Obj, args: array of ref Ecmascript->Val, eval: int): ref Ecmascript->Ref;
+ construct: fn(ex: ref Ecmascript->Exec, func: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Obj;
+};
+
+#
+# calls to init and mkexec do the following
+# math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
+#
+Ecmascript: module
+{
+ PATH: con "/dis/lib/ecmascript.dis";
+
+ #
+ # an execution context
+ #
+ Exec: adt
+ {
+ #
+ # well known glop
+ #
+ objproto: cyclic ref Obj;
+ funcproto: cyclic ref Obj;
+ strproto: cyclic ref Obj;
+ numproto: cyclic ref Obj;
+ boolproto: cyclic ref Obj;
+ arrayproto: cyclic ref Obj;
+ dateproto: cyclic ref Obj;
+ regexpproto: cyclic ref Obj;
+ errproto: cyclic ref Obj;
+ evlerrproto: cyclic ref Obj;
+ ranerrproto: cyclic ref Obj;
+ referrproto: cyclic ref Obj;
+ synerrproto: cyclic ref Obj;
+ typerrproto: cyclic ref Obj;
+ urierrproto: cyclic ref Obj;
+ interrproto: cyclic ref Obj;
+
+ global: cyclic ref Obj;
+ this: cyclic ref Obj;
+ scopechain: cyclic list of ref Obj;
+
+ error: string;
+ errval: cyclic ref Val;
+
+ #
+ # private, keep out
+ #
+ stack: cyclic array of ref Ref;
+ sp: int;
+ };
+
+ #
+ # must be called at the dawn of time
+ # returns error string
+ init: fn(): string;
+
+ #
+ # initialize a new global execution context
+ # if go is supplied, it's the global object
+ # if not, one is made up automatically
+ #
+ mkexec: fn(go: ref Obj): ref Exec;
+
+ #
+ # throw a runtime error
+ # msg ends up in ex.error, and an
+ # "ecmascript runtime error" is raised
+ #
+ RUNTIME: con "ecmascript runtime error";
+ runtime: fn(ex: ref Exec, o: ref Obj, msg: string);
+
+ # runtime errors
+ EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, InternalError: ref Obj;
+
+ #
+ # debug flags: array of 256 indexed by char
+ #
+ # e print ops as they are executed
+ # f abort on an internal error
+ # p print parsed code
+ # r abort on any runtime error
+ # v print value of expression statements
+ #
+ debug: array of int;
+
+ #
+ # parse and runt the source string
+ #
+ eval: fn(ex: ref Exec, src: string): Completion;
+
+ Re: type ref Arena;
+
+ # the fundamental data structure
+ Obj: adt
+ {
+ props: cyclic array of ref Prop;
+ prototype: cyclic ref Obj; # some builtin properties
+ val: cyclic ref Val;
+ call: cyclic ref Call;
+ construct: cyclic ref Call;
+ class: string;
+ host: ESHostobj; # method suite for host objects
+ re: Re; # compiled regexp for RegExp objects
+ };
+
+ Call: adt
+ {
+ params: array of string;
+ code: cyclic ref Code;
+ ex: cyclic ref Exec;
+ };
+
+ # attributes
+ ReadOnly, DontEnum, DontDelete: con 1 << iota;
+ Prop: adt
+ {
+ attr: int;
+ name: string;
+ val: cyclic ref RefVal;
+ };
+
+ # an extra level of indirection, because sometimes properties are aliased
+ RefVal: adt
+ {
+ val: cyclic ref Val;
+ };
+
+ # types of js values
+ TUndef, TNull, TBool, TNum, TStr, TObj, TRegExp, NoHint: con iota;
+ Val: adt
+ {
+ ty: int;
+ num: real;
+ str: string;
+ obj: cyclic ref Obj;
+ rev: ref REval;
+ };
+
+ # regular expression
+ REval: adt
+ {
+ p: string;
+ f: string;
+ i: int;
+ };
+
+ # intermediate result of expression evaluation
+ Ref: adt
+ {
+ isref: int;
+ val: ref Val;
+ base: ref Obj;
+ name: string; # name of property within base
+ };
+
+ # completion values of statements
+ CNormal, CBreak, CContinue, CReturn, CThrow: con iota;
+ Completion: adt
+ {
+ kind: int;
+ val: ref Val;
+ lab: string;
+ };
+
+ Code: adt
+ {
+ ops: array of byte; # all instructions
+ npc: int; # end of active portion of ops
+ vars: cyclic array of ref Prop; # variables defined in the code
+ ids: array of string; # ids used in the code
+ strs: array of string; # string literal
+ nums: array of real; # numerical literals
+ fexps: cyclic array of ref Obj; # function expressions
+ };
+
+ #
+ # stuff for adding host objects
+ #
+ # ecmascript is also a host object;
+ get: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
+ put: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string, val: ref Ecmascript->Val);
+ canput: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
+ hasproperty: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val;
+ delete: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string);
+ defaultval: fn(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, tyhint: int): ref Ecmascript->Val;
+ call: fn(ex: ref Ecmascript->Exec, func, this: ref Ecmascript->Obj, args: array of ref Ecmascript->Val, eval: int): ref Ecmascript->Ref;
+ construct: fn(ex: ref Ecmascript->Exec, func: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Obj;
+
+ #
+ # return the named variable from the scope chain sc
+ #
+ bivar: fn(ex: ref Exec, sc: list of ref Obj, s: string): ref Val;
+
+ #
+ # return the nth argument value, or undefined if too far
+ #
+ biarg: fn(args: array of ref Val, n: int): ref Val;
+
+ #
+ # make up a new object
+ # most often called as mkobj(ex.objproto, "Object")
+ #
+ mkobj: fn(proto: ref Obj, class: string): ref Obj;
+
+ #
+ # object installation helpers
+ #
+ Builtin: adt
+ {
+ name: string;
+ val: string;
+ params: array of string;
+ length: int;
+ };
+ biinst: fn(o: ref Obj, bi: Builtin, proto: ref Obj, h: ESHostobj): ref Obj;
+ biminst: fn(o: ref Obj, bis: array of Builtin, proto: ref Obj, h: ESHostobj);
+
+ #
+ # instantiate a new variable inside an object
+ #
+ varinstant: fn(in: ref Obj, attr: int, name: string, val: ref RefVal);
+
+ #
+ # various constructors
+ #
+ objval: fn(o: ref Obj): ref Val;
+ strval: fn(s: string): ref Val;
+ numval: fn(r: real): ref Val;
+ valref: fn(v: ref Val): ref Ref;
+
+ #
+ # conversion routines defined in section 9
+ #
+ toPrimitive: fn(ex: ref Exec, v: ref Val, ty: int): ref Val;
+ toBoolean: fn(ex: ref Exec, v: ref Val): ref Val;
+ toNumber: fn(ex: ref Exec, v: ref Val): real;
+ toInteger: fn(ex: ref Exec, v: ref Val): real;
+ toInt32: fn(ex: ref Exec, v: ref Val): int;
+ toUint32: fn(ex: ref Exec, v: ref Val): big;
+ toUint16: fn(ex: ref Exec, v: ref Val): int;
+ toString: fn(ex: ref Exec, v: ref Val): string;
+ toObject: fn(ex: ref Exec, v: ref Val): ref Obj;
+
+ #
+ # simple coercion routines to force
+ # Boolean, String, and Number values to objects and vice versa
+ #
+ coerceToObj: fn(ex: ref Exec, v: ref Val): ref Val;
+ coerceToVal: fn(v: ref Val): ref Val;
+
+ #
+ # object/value kind checkers
+ #
+ isstrobj: fn(o: ref Obj): int;
+ isnumobj: fn(o: ref Obj): int;
+ isboolobj: fn(o: ref Obj): int;
+ isdateobj: fn(o: ref Obj): int;
+ isregexpobj: fn(o: ref Obj): int;
+ isarray: fn(o: ref Obj): int;
+ isstr: fn(v: ref Val): int;
+ isnum: fn(v: ref Val): int;
+ isbool: fn(v: ref Val): int;
+ isobj: fn(v: ref Val): int;
+
+ #
+ # well-known ecmascript primitive values
+ #
+ undefined: ref Val;
+ true: ref Val;
+ false: ref Val;
+ null: ref Val;
+
+ # regexp data structures
+
+ refRex: type int; # used instead of ref Rex to avoid circularity
+
+ Set: adt { # character class
+ neg: int; # 0 or 1
+ ascii: array of int; # ascii members, bit array
+ unicode: list of (int,int); # non-ascii char ranges
+ subset: cyclic list of ref Set;
+ };
+
+ Nstate: adt{
+ m: int;
+ n: int;
+ };
+
+ Rex: adt { # node in parse of regex, or state of fsm
+ kind: int; # kind of node: char or ALT, CAT, etc
+ left: refRex; # left descendant
+ right: refRex; # right descendant, or next state
+ set: ref Set; # character class
+ pno: int;
+ greedy: int;
+ ns: ref Nstate;
+ };
+
+ Arena: adt { # free store from which nodes are allocated
+ rex: array of Rex;
+ ptr: refRex; # next available space
+ start: refRex; # root of parse, or start of fsm
+ pno: int;
+ };
+};