diff options
Diffstat (limited to 'module/ecmascript.m')
| -rw-r--r-- | module/ecmascript.m | 334 |
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; + }; +}; |
