ref: d916a4c3823f55227ffae35738c2497256e307b5
dir: /module/ecmascript.m/
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;
};
};