Terminals
General tokens: Identifier NegatedMinLong Number RegularExpression String VirtualSemicolon
Punctuation tokens: ! != !== % %= & && &&= &= ( ) * *= + ++ += , - -- -= . ... / /= : :: ; < << <<= <= = == === > >= >> >>= >>> >>>= ? [ ] ^ ^= ^^ ^^= { | |= || ||= } ~
Reserved words: as break case catch class const continue default delete do else export extends false finally for function if import in instanceof is namespace new null package private public return super switch this throw true try typeof use var void while with
Future reserved words: abstract debugger enum goto implements interface native protected synchronized throws transient volatile
Non-reserved words: get include set
Data Model
Semantic Exceptions
tuple Break
value: Object,
label: Label
end tuple;
tuple Continue
value: Object,
label: Label
end tuple;
tuple Return
value: Object
end tuple;
ControlTransfer = Break  Continue  Return;
SemanticException = Object  ControlTransfer;
Extended integers and rationals
tag +zero;
tag –zero;
tag +∞;
tag –∞;
tag NaN;
ExtendedRational = (Rational – {0})  {+zero, –zero, +∞, –∞, NaN};
ExtendedInteger = Integer  {+∞, –∞, NaN};
Objects
tag none;
tag ok;
tag reject;
Object = Undefined  Null  Boolean  Long  ULong  Float32  Float64  Char16  String  Namespace  CompoundAttribute  Class  SimpleInstance  MethodClosure  Date  RegExp  Package;
PrimitiveObject = Undefined  Null  Boolean  Long  ULong  Float32  Float64  Char16  String;
NonprimitiveObject = Namespace  CompoundAttribute  Class  SimpleInstance  MethodClosure  Date  RegExp  Package;
BindingObject = Class  SimpleInstance  RegExp  Date  Package;
ObjectOpt = Object  {none};
BooleanOpt = Boolean  {none};
IntegerOpt = Integer  {none};
Undefined
tag undefined;
Undefined = {undefined};
Null
tag null;
Null = {null};
Strings
StringOpt = String  {none};
Namespaces
record Namespace
name: String
end record;
Qualified Names
tuple QualifiedName
namespace: Namespace,
id: String
end tuple;
The notation ns::id is a shorthand for QualifiedNamenamespace: ns, id: id.
Multiname = QualifiedName{};
Attributes
tag static;
tag virtual;
tag final;
PropertyCategory = {none, static, virtual, final};
OverrideModifier = {none, true, false, undefined};
tuple CompoundAttribute
namespaces: Namespace{},
explicit: Boolean,
enumerable: Boolean,
dynamic: Boolean,
category: PropertyCategory,
overrideMod: OverrideModifier,
prototype: Boolean,
unused: Boolean
end tuple;
Attribute = Boolean  Namespace  CompoundAttribute;
AttributeOptNotFalse = {none, true}  Namespace  CompoundAttribute;
Classes
record Class
localBindings: LocalBinding{},
instanceProperties: InstanceProperty{},
super: ClassOpt,
prototype: ObjectOpt,
complete: Boolean,
name: String,
typeofString: String,
privateNamespace: Namespace,
dynamic: Boolean,
final: Boolean,
defaultValue: ObjectOpt,
defaultHint: Hint,
hasProperty: Object  Class  Object  Boolean  Phase  Boolean,
bracketRead: Object  Class  Object[]  Boolean  Phase  ObjectOpt,
bracketWrite: Object  Class  Object[]  Object  Boolean  {run}  {none, ok},
bracketDelete: Object  Class  Object[]  {run}  BooleanOpt,
read: Object  Class  Multiname  EnvironmentOpt  Boolean  Phase  ObjectOpt,
write: Object  Class  Multiname  EnvironmentOpt  Object  Boolean  {run}  {none, ok},
delete: Object  Class  Multiname  EnvironmentOpt  {run}  BooleanOpt,
enumerate: Object  Object{},
call: Object  Class  Object[]  Phase  Object,
construct: Class  Object[]  Phase  Object,
init: (SimpleInstance  Object[]  {run}  ())  {none},
is: Object  Class  Boolean,
coerce: Object  Class  ObjectOpt
end record;
ClassOpt = Class  {none};
Simple Instances
record SimpleInstance
localBindings: LocalBinding{},
archetype: ObjectOpt,
sealed: Boolean,
type: Class,
slots: Slot{},
call: (Object  SimpleInstance  Object[]  Phase  Object)  {none},
construct: (SimpleInstance  Object[]  Phase  Object)  {none},
env: EnvironmentOpt
end record;
Slots
record Slot
id: InstanceVariable,
value: ObjectOpt
end record;
Uninstantiated Functions
record UninstantiatedFunction
type: Class,
length: Integer,
call: (Object  SimpleInstance  Object[]  Phase  Object)  {none},
construct: (SimpleInstance  Object[]  Phase  Object)  {none},
instantiations: SimpleInstance{}
end record;
Method Closures
tuple MethodClosure
this: Object,
method: InstanceMethod,
slots: Slot{}
end tuple;
Dates
record Date
localBindings: LocalBinding{},
archetype: ObjectOpt,
sealed: Boolean,
timeValue: Integer
end record;
Regular Expressions
record RegExp
localBindings: LocalBinding{},
archetype: ObjectOpt,
sealed: Boolean,
source: String,
lastIndex: Integer,
global: Boolean,
ignoreCase: Boolean,
multiline: Boolean
end record;
Packages
record Package
localBindings: LocalBinding{},
archetype: ObjectOpt,
name: String,
initialize: (()  ())  {none, busy},
sealed: Boolean,
internalNamespace: Namespace
end record;
Objects with Limits
instance must be an instance of one of limit’s descendants.
tuple LimitedInstance
instance: Object,
limit: Class
end tuple;
ObjOptionalLimit = Object  LimitedInstance;
References
tuple LexicalReference
env: Environment,
variableMultiname: Multiname,
strict: Boolean
end tuple;
tuple DotReference
base: Object,
limit: Class,
multiname: Multiname
end tuple;
tuple BracketReference
base: Object,
limit: Class,
args: Object[]
end tuple;
Reference = LexicalReference  DotReference  BracketReference;
ObjOrRef = Object  Reference;
Modes of expression evaluation
tag compile;
tag run;
Phase = {compile, run};
Contexts
record Context
strict: Boolean,
openNamespaces: Namespace{}
end record;
Labels
tag default;
Label = String  {default};
tuple JumpTargets
breakTargets: Label{},
continueTargets: Label{}
end tuple;
Function Support
tag normal;
tag get;
tag set;
Handling = {normal, get, set};
tag plainFunction;
tag uncheckedFunction;
tag prototypeFunction;
tag instanceFunction;
tag constructorFunction;
StaticFunctionKind = {plainFunction, uncheckedFunction, prototypeFunction};
FunctionKind = {plainFunction, uncheckedFunction, prototypeFunction, instanceFunction, constructorFunction};
Environments
An Environment is a list of two or more frames. Each frame corresponds to a scope. More specific frames are listed first—each frame’s scope is directly contained in the following frame’s scope. The last frame is always a Package. A WithFrame is always preceded by a LocalFrame, so the first frame is never a WithFrame.
Environment = Frame[];
EnvironmentOpt = Environment  {none};
Frame = NonWithFrame  WithFrame;
NonWithFrame = Package  ParameterFrame  Class  LocalFrame;
record ParameterFrame
localBindings: LocalBinding{},
kind: FunctionKind,
handling: Handling,
callsSuperconstructor: Boolean,
superconstructorCalled: Boolean,
this: ObjectOpt,
parameters: Parameter[],
rest: VariableOpt,
returnType: Class
end record;
ParameterFrameOpt = ParameterFrame  {none};
tuple Parameter
var: Variable  DynamicVar,
default: ObjectOpt
end tuple;
record LocalFrame
localBindings: LocalBinding{}
end record;
record WithFrame
value: ObjectOpt
end record;
Properties
tag read;
tag write;
tag readWrite;
Access = {read, write};
AccessSet = {read, write, readWrite};
tuple LocalBinding
qname: QualifiedName,
accesses: AccessSet,
explicit: Boolean,
enumerable: Boolean,
content: SingletonProperty
end tuple;
tag forbidden;
SingletonProperty = {forbidden}  Variable  DynamicVar  Getter  Setter;
SingletonPropertyOpt = SingletonProperty  {none};
VariableValue = {none}  Object  UninstantiatedFunction;
tag busy;
Initializer = Environment  Phase  Object;
InitializerOpt = Initializer  {none};
record Variable
type: Class,
value: VariableValue,
immutable: Boolean,
setup: (()  ClassOpt)  {none, busy},
initializer: Initializer  {none, busy},
initializerEnv: Environment
end record;
VariableOpt = Variable  {none};
record DynamicVar
value: Object  UninstantiatedFunction,
sealed: Boolean
end record;
record Getter
call: Environment  Phase  Object,
env: EnvironmentOpt
end record;
record Setter
call: Object  Environment  Phase  (),
env: EnvironmentOpt
end record;
InstanceProperty = InstanceVariable  InstanceMethod  InstanceGetter  InstanceSetter;
InstancePropertyOpt = InstanceProperty  {none};
record InstanceVariable
multiname: Multiname,
final: Boolean,
enumerable: Boolean,
type: Class,
defaultValue: ObjectOpt,
immutable: Boolean
end record;
InstanceVariableOpt = InstanceVariable  {none};
record InstanceMethod
multiname: Multiname,
final: Boolean,
enumerable: Boolean,
signature: ParameterFrame,
length: Integer,
call: Object  Object[]  Phase  Object
end record;
record InstanceGetter
multiname: Multiname,
final: Boolean,
enumerable: Boolean,
signature: ParameterFrame,
call: Object  Phase  Object
end record;
record InstanceSetter
multiname: Multiname,
final: Boolean,
enumerable: Boolean,
signature: ParameterFrame,
call: Object  Object  Phase  ()
end record;
PropertyOpt = SingletonProperty  InstanceProperty  {none};
Miscellaneous
tag hintString;
tag hintNumber;
Hint = {hintString, hintNumber};
HintOpt = Hint  {none};
tag less;
tag equal;
tag greater;
tag unordered;
Order = {less, equal, greater, unordered};
Data Operations
Numeric Utilities
unsignedWrap32(i) returns i converted to a value between 0 and 232–1 inclusive, wrapping around modulo 232 if necessary.
proc unsignedWrap32(i: Integer): {0 ... 232 – 1}
return bitwiseAnd(i, 0xFFFFFFFF)
end proc;
signedWrap32(i) returns i converted to a value between –231 and 231–1 inclusive, wrapping around modulo 232 if necessary.
proc signedWrap32(i: Integer): {–231 ... 231 – 1}
j: Integer  bitwiseAnd(i, 0xFFFFFFFF);
if j ≥ 231 then j  j – 232 end if;
return j
end proc;
unsignedWrap64(i) returns i converted to a value between 0 and 264–1 inclusive, wrapping around modulo 264 if necessary.
proc unsignedWrap64(i: Integer): {0 ... 264 – 1}
return bitwiseAnd(i, 0xFFFFFFFFFFFFFFFF)
end proc;
signedWrap64(i) returns i converted to a value between –263 and 263–1 inclusive, wrapping around modulo 264 if necessary.
proc signedWrap64(i: Integer): {–263 ... 263 – 1}
j: Integer  bitwiseAnd(i, 0xFFFFFFFFFFFFFFFF);
if j ≥ 263 then j  j – 264 end if;
return j
end proc;
truncateToInteger(x) returns x converted to an integer by rounding towards zero. If x is an infinity or a NaN, the result is 0.
proc truncateToInteger(x: GeneralNumber): Integer
case x of
{NaNf32, NaNf64, +∞f32, +∞f64, –∞f32, –∞f64} do return 0;
FiniteFloat32 do return truncateFiniteFloat32(x);
FiniteFloat64 do return truncateFiniteFloat64(x);
Long  ULong do return x.value
end case
end proc;
pinExtendedInteger(i, limit, negativeFromEnd) returns i pinned to the set {0 ... limit}, where limit is a nonnegative integer. If negativeFromEnd is true, then negative values of i from –limit through –1 are treated as 0 through limit – 1 respectively.
proc pinExtendedInteger(i: ExtendedInteger, limit: Integer, negativeFromEnd: Boolean): Integer
case i of
{NaN} do throw a RangeError exception;
{–∞} do return 0;
{+∞} do return limit;
Integer do
j: Integer  i;
if j > limit then j  limit end if;
if negativeFromEnd and j < 0 then j  j + limit end if;
if j < 0 then j  0 end if;
note	0 ≤ j ≤ limit;
return j
end case
end proc;
checkInteger(x) returns x converted to an integer if its mathematical value is, in fact, an integer. If x is an infinity or a NaN or has a fractional part, the result is none.
proc checkInteger(x: GeneralNumber): IntegerOpt
case x of
{NaNf32, NaNf64, +∞f32, +∞f64, –∞f32, –∞f64} do return none;
{+zerof32, +zerof64, –zerof32, –zerof64} do return 0;
Long  ULong do return x.value;
NonzeroFiniteFloat32  NonzeroFiniteFloat64 do
r: Rational  x.value;
if r  Integer then return none end if;
return r
end case
end proc;
integerToLong(i) converts i to the first of the types Long, ULong, or Float64 that can contain the value i. If necessary, the Float64 result may be rounded or converted to an infinity using the IEEE 754 “round to nearest” mode.
proc integerToLong(i: Integer): GeneralNumber
if –263 ≤ i ≤ 263 – 1 then return ilong
elsif 263 ≤ i ≤ 264 – 1 then return iulong
else return if64
end if
end proc;
integerToULong(i) converts i to the first of the types ULong, Long, or Float64 that can contain the value i. If necessary, the Float64 result may be rounded or converted to an infinity using the IEEE 754 “round to nearest” mode.
proc integerToULong(i: Integer): GeneralNumber
if 0 ≤ i ≤ 264 – 1 then return iulong
elsif –263 ≤ i ≤ –1 then return ilong
else return if64
end if
end proc;
rationalToLong(q) converts q to one of the types Long, ULong, or Float64, whichever one can come the closest to representing the true value of q. If several of these types can come equally close to the value of q, then one of them is chosen according to the algorithm below.
proc rationalToLong(q: Rational): GeneralNumber
if q  Integer then return integerToLong(q)
elsif |q| ≤ 253 then return qf64
elsif q < –263 – 1/2 or q ≥ 264 – 1/2 then return qf64
else
Let i be the integer closest to q. If q is halfway between two integers, pick i so that it is even.
note	–263 ≤ i ≤ 264 – 1;
if i < 263 then return ilong else return iulong end if
end if
end proc;
rationalToULong(q) converts q to one of the types ULong, Long, or Float64, whichever one can come the closest to representing the true value of q. If several of these types can come equally close to the value of q, then one of them is chosen according to the algorithm below.
proc rationalToULong(q: Rational): GeneralNumber
if q  Integer then return integerToULong(q)
elsif |q| ≤ 253 then return qf64
elsif q < –263 – 1/2 or q ≥ 264 – 1/2 then return qf64
else
Let i be the integer closest to q. If q is halfway between two integers, pick i so that it is even.
note	–263 ≤ i ≤ 264 – 1;
if i ≥ 0 then return iulong else return ilong end if
end if
end proc;
proc extendedRationalToFloat32(q: ExtendedRational): Float32
case q of
Rational do return qf32;
{+zero} do return +zerof32;
{–zero} do return –zerof32;
{+∞} do return +∞f32;
{–∞} do return –∞f32;
{NaN} do return NaNf32
end case
end proc;
proc extendedRationalToFloat64(q: ExtendedRational): Float64
case q of
Rational do return qf64;
{+zero} do return +zerof64;
{–zero} do return –zerof64;
{+∞} do return +∞f64;
{–∞} do return –∞f64;
{NaN} do return NaNf64
end case
end proc;
toRational(x) returns the exact Rational value of x.
proc toRational(x: FiniteGeneralNumber): Rational
case x of
{+zerof32, +zerof64, –zerof32, –zerof64} do return 0;
NonzeroFiniteFloat32  NonzeroFiniteFloat64  Long  ULong do return x.value
end case
end proc;
toFloat32(x) converts x to a Float32, using the IEEE 754 “round to nearest” mode.
proc toFloat32(x: GeneralNumber): Float32
case x of
Long  ULong do return (x.value)f32;
Float32 do return x;
{–∞f64} do return –∞f32;
{–zerof64} do return –zerof32;
{+zerof64} do return +zerof32;
{+∞f64} do return +∞f32;
{NaNf64} do return NaNf32;
NonzeroFiniteFloat64 do return (x.value)f32
end case
end proc;
toFloat64(x) converts x to a Float64, using the IEEE 754 “round to nearest” mode.
proc toFloat64(x: GeneralNumber): Float64
case x of
Long  ULong do return (x.value)f64;
Float32 do return float32ToFloat64(x);
Float64 do return x
end case
end proc;
generalNumberCompare(x, y) compares x with y using the IEEE 754 rules and returns less if x<y, equal if x=y, greater if x>y, or unordered if either x or y is a NaN. The comparison is done using the exact values of x and y, even if they have different types. Positive infinities compare equal to each other and greater than any other non-NaN values. Negative infinities compare equal to each other and less than any other non-NaN values. Positive and negative zeroes compare equal to each other.
proc generalNumberCompare(x: GeneralNumber, y: GeneralNumber): Order
if x  {NaNf32, NaNf64} or y  {NaNf32, NaNf64} then return unordered
elsif x  {+∞f32, +∞f64} and y  {+∞f32, +∞f64} then return equal
elsif x  {–∞f32, –∞f64} and y  {–∞f32, –∞f64} then return equal
elsif x  {+∞f32, +∞f64} or y  {–∞f32, –∞f64} then return greater
elsif x  {–∞f32, –∞f64} or y  {+∞f32, +∞f64} then return less
else
xr: Rational  toRational(x);
yr: Rational  toRational(y);
if xr < yr then return less
elsif xr > yr then return greater
else return equal
end if
end if
end proc;
Character Utilities
proc integerToUTF16(i: {0 ... 0x10FFFF}): String
if 0 ≤ i ≤ 0xFFFF then return [integerToChar16(i)]
else
j: {0 ... 0xFFFFF}  i – 0x10000;
high: Char16  integerToChar16(0xD800 + bitwiseShift(j, –10));
low: Char16  integerToChar16(0xDC00 + bitwiseAnd(j, 0x3FF));
return [high, low]
end if
end proc;
proc char21ToUTF16(ch: Char21): String
return integerToUTF16(char21ToInteger(ch))
end proc;
proc surrogatePairToSupplementaryChar(h: Char16, l: Char16): SupplementaryChar
codePoint: {0x10000 ... 0x10FFFF}  0x10000 + (char16ToInteger(h) – 0xD800)0x400 + char16ToInteger(l) – 0xDC00;
return integerToSupplementaryChar(codePoint)
end proc;
proc stringToUTF32(s: String): Char21[]
i: Integer  0;
result: Char21[]  [];
while i ≠ |s| do
ch: Char21;
if s[i]  {‘«uD800»’ ... ‘«uDBFF»’} and i + 1 ≠ |s| and s[i + 1]  {‘«uDC00»’ ... ‘«uDFFF»’} then
ch  surrogatePairToSupplementaryChar(s[i], s[i + 1]);
i  i + 2
else ch  s[i]; i  i + 1
end if;
result  result  [ch]
end while;
return result
end proc;
proc charToLowerFull(ch: Char21): String
return ch converted to a lower case character using the Unicode full, locale-independent case mapping. A single character may be converted to multiple characters. If ch has no lower case equivalent, then the result is the string char21ToUTF16(ch).
end proc;
proc charToLowerLocalized(ch: Char21): String
return ch converted to a lower case character using the Unicode full case mapping in the host environment’s current locale. A single character may be converted to multiple characters. If ch has no lower case equivalent, then the result is the string char21ToUTF16(ch).
end proc;
proc charToUpperFull(ch: Char21): String
return ch converted to a upper case character using the Unicode full, locale-independent case mapping. A single character may be converted to multiple characters. If ch has no upper case equivalent, then the result is the string char21ToUTF16(ch).
end proc;
proc charToUpperLocalized(ch: Char21): String
return ch converted to a upper case character using the Unicode full case mapping in the host environment’s current locale. A single character may be converted to multiple characters. If ch has no upper case equivalent, then the result is the string char21ToUTF16(ch).
end proc;
Object Utilities
Object Class Inquiries
objectType(o) returns an Object o’s most specific type. Although objectType is used internally throughout this specification, in order to allow one programmer-visible class to be implemented as an ensemble of implementation-specific classes, no way is provided for a user program to directly obtain the result of calling objectType on an object.
proc objectType(o: Object): Class
case o of
Undefined do return Void;
Null do return Null;
Boolean do return Boolean;
Long do return long;
ULong do return ulong;
Float32 do return float;
Float64 do return Number;
Char16 do return char;
String do return String;
Namespace do return Namespace;
CompoundAttribute do return Attribute;
Class do return Class;
SimpleInstance do return o.type;
MethodClosure do return Function;
Date do return Date;
RegExp do return RegExp;
Package do return Package
end case
end proc;
is(o, c) returns true if o is an instance of class c or one of its subclasses.
proc is(o: Object, c: Class): Boolean
return c.is(o, c)
end proc;
ordinaryIs(o, c) is the implementation of is for a native class unless specified otherwise in the class’s definition. Host classes may either also use ordinaryIs or define a different procedure to perform this test.
proc ordinaryIs(o: Object, c: Class): Boolean
return isAncestor(c, objectType(o))
end proc;
Return an ordered list of class c’s ancestors, including c itself.
proc ancestors(c: Class): Class[]
s: ClassOpt  c.super;
if s = none then return [c] else return ancestors(s)  [c] end if
end proc;
Return true if c is d or an ancestor of d.
proc isAncestor(c: Class, d: Class): Boolean
if c = d then return true
else
s: ClassOpt  d.super;
if s = none then return false end if;
return isAncestor(c, s)
end if
end proc;
Object to Boolean Conversion
objectToBoolean(o) returns o converted to a Boolean.
proc objectToBoolean(o: Object): Boolean
case o of
Undefined  Null do return false;
Boolean do return o;
Long  ULong do return o.value ≠ 0;
Float32 do return o  {+zerof32, –zerof32, NaNf32};
Float64 do return o  {+zerof64, –zerof64, NaNf64};
String do return o ≠ “”;
Char16  Namespace  CompoundAttribute  Class  SimpleInstance  MethodClosure  Date  RegExp  Package do
return true
end case
end proc;
Object to Primitive Conversion
proc objectToPrimitive(o: Object, hint: HintOpt, phase: Phase): PrimitiveObject
if o  PrimitiveObject then return o end if;
c: Class  objectType(o);
h: Hint;
if hint  Hint then h  hint else h  c.defaultHint end if;
case h of
{hintString} do
toStringMethod: ObjectOpt  c.read(o, c, {public::“toString”}, none, false, phase);
if toStringMethod ≠ none then
r: Object  call(o, toStringMethod, [], phase);
if r  PrimitiveObject then return r end if
end if;
valueOfMethod: ObjectOpt  c.read(o, c, {public::“valueOf”}, none, false, phase);
if valueOfMethod ≠ none then
r: Object  call(o, valueOfMethod, [], phase);
if r  PrimitiveObject then return r end if
end if;
{hintNumber} do
valueOfMethod: ObjectOpt  c.read(o, c, {public::“valueOf”}, none, false, phase);
if valueOfMethod ≠ none then
r: Object  call(o, valueOfMethod, [], phase);
if r  PrimitiveObject then return r end if
end if;
toStringMethod: ObjectOpt  c.read(o, c, {public::“toString”}, none, false, phase);
if toStringMethod ≠ none then
r: Object  call(o, toStringMethod, [], phase);
if r  PrimitiveObject then return r end if
end if
end case;
throw a TypeError exception — cannot convert this object to a primitive
end proc;
Object to Number Conversions
objectToGeneralNumber(o, phase) returns o converted to a GeneralNumber. If phase is compile, only constant conversions are permitted.
proc objectToGeneralNumber(o: Object, phase: Phase): GeneralNumber
a: PrimitiveObject  objectToPrimitive(o, hintNumber, phase);
case a of
Undefined do return NaNf64;
Null  {false} do return +zerof64;
{true} do return 1f64;
GeneralNumber do return a;
Char16  String do return stringToFloat64(toString(a))
end case
end proc;
objectToFloat32(o, phase) returns o converted to a Float32. If phase is compile, only constant conversions are permitted.
proc objectToFloat32(o: Object, phase: Phase): Float32
a: PrimitiveObject  objectToPrimitive(o, hintNumber, phase);
case a of
Undefined do return NaNf32;
Null  {false} do return +zerof32;
{true} do return 1f32;
GeneralNumber do return toFloat32(a);
Char16  String do return stringToFloat32(toString(a))
end case
end proc;
objectToFloat64(o, phase) returns o converted to a Float64. If phase is compile, only constant conversions are permitted.
proc objectToFloat64(o: Object, phase: Phase): Float64
return toFloat64(objectToGeneralNumber(o, phase))
end proc;
objectToExtendedInteger(o, phase) returns o converted to an ExtendedInteger. An error occurs if o has a fractional part or is a NaN. If o is a string, then it is converted exactly. If phase is compile, only constant conversions are permitted.
proc objectToExtendedInteger(o: Object, phase: Phase): ExtendedInteger
a: PrimitiveObject  objectToPrimitive(o, hintNumber, phase);
case a of
Null  {false} do return 0;
{true} do return 1;
{undefined, NaNf32, NaNf64} do return NaN;
{+∞f32, +∞f64} do return +∞;
{–∞f32, –∞f64} do return –∞;
{+zerof32, +zerof64, –zerof32, –zerof64} do return 0;
Long  ULong do return a.value;
NonzeroFiniteFloat32  NonzeroFiniteFloat64 do
r: Rational  a.value;
if r  Integer then
throw a RangeError exception — the value a is not an integer
end if;
return r;
Char16  String do return stringToExtendedInteger(toString(a))
end case
end proc;
objectToInteger(o, phase) returns o converted to an Integer. An error occurs if o has a fractional part or is not finite. If o is a string, then it is converted exactly. If phase is compile, only constant conversions are permitted.
proc objectToInteger(o: Object, phase: Phase): Integer
i: ExtendedInteger  objectToExtendedInteger(o, phase);
case i of
{+∞, –∞, NaN} do throw a RangeError exception — i is not an integer;
Integer do return i
end case
end proc;
proc stringToFloat32(s: String): Float32
Apply the lexer grammar with the start symbol StringNumericLiteral to the string s.
if the grammar cannot interpret the entire string as an expansion of StringNumericLiteral then
return NaNf32
else
q: ExtendedRational  the value of the action Lex applied to the obtained expansion of the nonterminal StringNumericLiteral;
return extendedRationalToFloat32(q)
end if
end proc;
proc stringToFloat64(s: String): Float64
Apply the lexer grammar with the start symbol StringNumericLiteral to the string s.
if the grammar cannot interpret the entire string as an expansion of StringNumericLiteral then
return NaNf64
else
q: ExtendedRational  the value of the action Lex applied to the obtained expansion of the nonterminal StringNumericLiteral;
return extendedRationalToFloat64(q)
end if
end proc;
proc stringToExtendedInteger(s: String): ExtendedInteger
Apply the lexer grammar with the start symbol StringNumericLiteral to the string s.
if the grammar cannot interpret the entire string as an expansion of StringNumericLiteral then
throw a TypeError exception — the string s does not contain a number
else
q: ExtendedRational  the value of the action Lex applied to the obtained expansion of the nonterminal StringNumericLiteral;
case q of
{+zero, –zero} do return 0;
{+∞, –∞, NaN} do return q;
Rational do
if q  Integer then return q
else throw a RangeError exception — the value should be an integer
end if
end case
end if
end proc;
Object to String Conversions
objectToString(o, phase) returns o converted to a String. If phase is compile, only constant conversions are permitted.
proc objectToString(o: Object, phase: Phase): String
a: PrimitiveObject  objectToPrimitive(o, hintString, phase);
case a of
Undefined do return “undefined”;
Null do return “null”;
{false} do return “false”;
{true} do return “true”;
GeneralNumber do return generalNumberToString(a);
Char16 do return [a];
String do return a
end case
end proc;
proc toString(o: Char16  String): String
case o of
Char16 do return [o];
String do return o
end case
end proc;
proc generalNumberToString(x: GeneralNumber): String
case x of
Long  ULong do return integerToString(x.value);
Float32 do return float32ToString(x);
Float64 do return float64ToString(x)
end case
end proc;
integerToString(i) converts an integer i to a string of one or more decimal digits. If i is negative, the string is preceded by a minus sign.
proc integerToString(i: Integer): String
if i < 0 then return [‘-’]  integerToString(–i) end if;
q: Integer  i/10;
r: Integer  i – q10;
c: Char16  integerToChar16(r + char16ToInteger(‘0’));
if q = 0 then return [c] else return integerToString(q)  [c] end if
end proc;
integerToStringWithSign(i) is the same as integerToString(i) except that the resulting string always begins with a plus or minus sign.
proc integerToStringWithSign(i: Integer): String
if i ≥ 0 then return [‘+’]  integerToString(i)
else return [‘-’]  integerToString(–i)
end if
end proc;
proc exponentialNotationString(digits: String, e: Integer): String
mantissa: String;
if |digits| = 1 then mantissa  digits
else mantissa  [digits[0]]  “.”  digits[1 ...]
end if;
return mantissa  “e”  integerToStringWithSign(e)
end proc;
float32ToString(x) converts a Float32 x to a string using fixed-point notation if the absolute value of x is between 10–6 inclusive and 1021 exclusive, and exponential notation otherwise. The result has the fewest significant digits possible while still ensuring that converting the string back into a Float32 value would result in the same value x (except that –zerof32 would become +zerof32).
proc float32ToString(x: Float32): String
case x of
{NaNf32} do return “NaN”;
{+zerof32, –zerof32} do return “0”;
{+∞f32} do return “Infinity”;
{–∞f32} do return “-Infinity”;
NonzeroFiniteFloat32 do
r: Rational  x.value;
if r < 0 then return “-”  float32ToString(float32Negate(x))
else
Let e, k, and s be integers such that k ≥ 1, 10k–1 ≤ s ≤ 10k, (s10e+1–k)f32 = x, and k is as small as possible.
note	k is the number of digits in the decimal representation of s, s is not divisible by 10, and the least significant digit of s is not necessarily uniquely determined by the above criteria.
When there are multiple possibilities for s according to the rules above, implementations are encouraged but not required to select the one according to the following rule: Select the value of s for which s10e+1–k is closest in value to r; if there are two such possible values of s, choose the one that is even.
digits: String  integerToString(s)
if k – 1 ≤ e ≤ 20 then return digits  repeat(‘0’, e + 1 – k)
elsif 0 ≤ e ≤ 20 then return digits[0 ... e]  “.”  digits[e + 1 ...]
elsif –6 ≤ e < 0 then return “0.”  repeat(‘0’, –(e + 1))  digits
else return exponentialNotationString(digits, e)
end if
end if
end case
end proc;
float64ToString(x) converts a Float64 x to a string using fixed-point notation if the absolute value of x is between 10–6 inclusive and 1021 exclusive, and exponential notation otherwise. The result has the fewest significant digits possible while still ensuring that converting the string back into a Float64 value would result in the same value x (except that –zerof64 would become +zerof64).
proc float64ToString(x: Float64): String
case x of
{NaNf64} do return “NaN”;
{+zerof64, –zerof64} do return “0”;
{+∞f64} do return “Infinity”;
{–∞f64} do return “-Infinity”;
NonzeroFiniteFloat64 do
r: Rational  x.value;
if r < 0 then return “-”  float64ToString(float64Negate(x))
else
Let e, k, and s be integers such that k ≥ 1, 10k–1 ≤ s ≤ 10k, (s10e+1–k)f64 = x, and k is as small as possible.
note	k is the number of digits in the decimal representation of s, s is not divisible by 10, and the least significant digit of s is not necessarily uniquely determined by the above criteria.
When there are multiple possibilities for s according to the rules above, implementations are encouraged but not required to select the one according to the following rule: Select the value of s for which s10e+1–k is closest in value to r; if there are two such possible values of s, choose the one that is even.
digits: String  integerToString(s)
if k – 1 ≤ e ≤ 20 then return digits  repeat(‘0’, e + 1 – k)
elsif 0 ≤ e ≤ 20 then return digits[0 ... e]  “.”  digits[e + 1 ...]
elsif –6 ≤ e < 0 then return “0.”  repeat(‘0’, –(e + 1))  digits
else return exponentialNotationString(digits, e)
end if
end if
end case
end proc;
Object to Qualified Name Conversion
objectToQualifiedName(o, phase) coerces an object o to a qualified name. If phase is compile, only constant conversions are permitted.
proc objectToQualifiedName(o: Object, phase: Phase): QualifiedName
return public::(objectToString(o, phase))
end proc;
Object to Class Conversion
objectToClass(o) returns o converted to a non-null Class.
proc objectToClass(o: Object): Class
if o  Class then return o else throw a TypeError exception end if
end proc;
Object to Attribute Conversion
objectToAttribute(o) returns o converted to an attribute.
proc objectToAttribute(o: Object, phase: Phase): Attribute
if o  Attribute then return o
else
note	If o is not an attribute, try to call it with no arguments.
a: Object  call(null, o, [], phase);
if a  Attribute then return a else throw a TypeError exception end if
end if
end proc;
Implicit Coercions
coerce(o, c) attempts to implicitly coerce o to class c. If the coercion succeeds, coerce returns the coerced value. If not, coerce throws a TypeError.
The coercion always succeeds and returns o unchanged if o is already a member of class c. The value returned from coerce always is a member of class c.
proc coerce(o: Object, c: Class): Object
result: ObjectOpt  c.coerce(o, c);
if result ≠ none then return result
else throw a TypeError exception — coercion failed
end if
end proc;
coerceOrNull(o, c) attempts to implicitly coerce o to class c. If the coercion succeeds, coerceOrNull returns the coerced value. If not, then coerceOrNull returns null if null is a member of type c; otherwise, coerceOrNull throws a TypeError.
The coercion always succeeds and returns o unchanged if o is already a member of class c. The value returned from coerceOrNull always is a member of class c.
proc coerceOrNull(o: Object, c: Class): Object
result: ObjectOpt  c.coerce(o, c);
if result ≠ none then return result
elsif c.coerce(null, c) = null then return null
else throw a TypeError exception — coercion failed
end if
end proc;
coerceNonNull(o, c) attempts to implicitly coerce o to class c. If the coercion succeeds and the result is not null, then coerceNonNull returns the coerced value. If not, coerceNonNull throws a TypeError.
proc coerceNonNull(o: Object, c: Class): Object
result: ObjectOpt  c.coerce(o, c);
if result  {none, null} then return result
else throw a TypeError exception — coercion failed
end if
end proc;
ordinaryCoerce(o, c) is the implementation of coercion for a native class unless specified otherwise in the class’s definition. Host classes may define a different procedure to perform this coercion.
proc ordinaryCoerce(o: Object, c: Class): ObjectOpt
if o = null or is(o, c) then return o else return none end if
end proc;
Attributes
combineAttributes(a, b) returns the attribute that results from concatenating the attributes a and b.
proc combineAttributes(a: AttributeOptNotFalse, b: Attribute): Attribute
if b = false then return false
elsif a  {none, true} then return b
elsif b = true then return a
elsif a  Namespace then
if a = b then return a
elsif b  Namespace then
return CompoundAttributenamespaces: {a, b}, explicit: false, enumerable: false, dynamic: false, category: none, overrideMod: none, prototype: false, unused: false
else return CompoundAttributenamespaces: b.namespaces  {a}, other fields from b
end if
elsif b  Namespace then
return CompoundAttributenamespaces: a.namespaces  {b}, other fields from a
else
note	At this point both a and b are compound attributes.
if (a.category ≠ none and b.category ≠ none and a.category ≠ b.category) or (a.overrideMod ≠ none and b.overrideMod ≠ none and a.overrideMod ≠ b.overrideMod) then
throw an AttributeError exception — attributes a and b have conflicting contents
else
return CompoundAttributenamespaces: a.namespaces  b.namespaces, explicit: a.explicit or b.explicit, enumerable: a.enumerable or b.enumerable, dynamic: a.dynamic or b.dynamic, category: a.category ≠ none ? a.category : b.category, overrideMod: a.overrideMod ≠ none ? a.overrideMod : b.overrideMod, prototype: a.prototype or b.prototype, unused: a.unused or b.unused
end if
end if
end proc;
toCompoundAttribute(a) returns a converted to a CompoundAttribute even if it was a simple namespace, true, or none.
proc toCompoundAttribute(a: AttributeOptNotFalse): CompoundAttribute
case a of
{none, true} do
return CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: none, overrideMod: none, prototype: false, unused: false;
Namespace do
return CompoundAttributenamespaces: {a}, explicit: false, enumerable: false, dynamic: false, category: none, overrideMod: none, prototype: false, unused: false;
CompoundAttribute do return a
end case
end proc;
Access Utilities
accessesOverlap(accesses1, accesses2) returns true if the two AccessSets have a nonempty intersection.
proc accessesOverlap(accesses1: AccessSet, accesses2: AccessSet): Boolean
return accesses1 = accesses2 or accesses1 = readWrite or accesses2 = readWrite
end proc;
proc archetype(o: Object): ObjectOpt
case o of
Undefined  Null do return none;
Boolean do return Boolean.prototype;
Long do return long.prototype;
ULong do return ulong.prototype;
Float32 do return float.prototype;
Float64 do return Number.prototype;
Char16 do return char.prototype;
String do return String.prototype;
Namespace do return Namespace.prototype;
CompoundAttribute do return Attribute.prototype;
MethodClosure do return Function.prototype;
Class do return Class.prototype;
SimpleInstance  RegExp  Date  Package do return o.archetype
end case
end proc;
archetypes(o) returns the set of o’s archetypes, not including o itself.
proc archetypes(o: Object): Object{}
a: ObjectOpt  archetype(o);
if a = none then return {} end if;
return {a}  archetypes(a)
end proc;
o is an object that is known to have slot id. findSlot(o, id) returns that slot.
proc findSlot(o: Object, id: InstanceVariable): Slot
note	o must be a SimpleInstance or a MethodClosure in order to have slots.
matchingSlots: Slot{}  {s | s  o.slots such that s.id = id};
return the one element of matchingSlots
end proc;
setupVariable(v) runs Setup and initialises the type of the variable v, making sure that Setup is done at most once and does not reenter itself.
proc setupVariable(v: Variable)
setup: (()  ClassOpt)  {none, busy}  v.setup;
case setup of
()  ClassOpt do
v.setup  busy;
type: ClassOpt  setup();
if type = none then type  Object end if;
v.type  type;
v.setup  none;
{none} do nothing;
{busy} do
throw a ConstantError exception — a constant’s type or initialiser cannot depend on the value of that constant
end case
end proc;
writeVariable(v, newValue, clearInitializer) writes the value newValue into the mutable or immutable variable v. newValue is coerced to v’s type. If the clearInitializer flag is set, then the caller  has just evaluated v’s initialiser and is supplying its result in newValue. In this case writeVariable atomically clears v.initializer while writing v.value. In all other cases the presence of an initialiser or an existing value will prevent an immutable variable’s value from being written.
proc writeVariable(v: Variable, newValue: Object, clearInitializer: Boolean): Object
coercedValue: Object  coerce(newValue, v.type);
if clearInitializer then v.initializer  none end if;
if v.immutable and (v.value ≠ none or v.initializer ≠ none) then
throw a ReferenceError exception — cannot initialise a const variable twice
end if;
v.value  coercedValue;
return coercedValue
end proc;
Environmental Utilities
If env is from within a class’s body, getEnclosingClass(env) returns the innermost such class; otherwise, it returns none.
proc getEnclosingClass(env: Environment): ClassOpt
if some c  env satisfies c  Class then
Let c be the first element of env that is a Class.
return c
end if;
return none
end proc;
If env is from within a function’s body, getEnclosingParameterFrame(env) returns the ParameterFrame for the innermost such function; otherwise, it returns none.
proc getEnclosingParameterFrame(env: Environment): ParameterFrameOpt
for each frame  env do
case frame of
LocalFrame  WithFrame do nothing;
ParameterFrame do return frame;
Package  Class do return none
end case
end for each;
return none
end proc;
getRegionalEnvironment(env) returns all frames in env up to and including the first regional frame. A regional frame is either any frame other than a with frame or local block frame, a local block frame directly enclosed in a class, or a local block frame directly enclosed in a with frame directly enclosed in a class.
proc getRegionalEnvironment(env: Environment): Frame[]
i: Integer  0;
while env[i]  LocalFrame  WithFrame do i  i + 1 end while;
if env[i]  Class then while i ≠ 0 and env[i]  LocalFrame do i  i – 1 end while
end if;
return env[0 ... i]
end proc;
getRegionalFrame(env) returns the most specific regional frame in env.
proc getRegionalFrame(env: Environment): Frame
regionalEnv: Frame[]  getRegionalEnvironment(env);
return regionalEnv[|regionalEnv| – 1]
end proc;
getPackageFrame(env) returns the innermost package frame in env.
proc getPackageFrame(env: Environment): Package
i: Integer  0;
while env[i]  Package do i  i + 1 end while;
note	Every environment ends with a Package frame, so one will always be found.
return env[i]
end proc;
Property Lookup
findLocalSingletonProperty(o, multiname, access) looks in o for a local singleton property with one of the names in multiname and access that includes access. If there is no such property, findLocalSingletonProperty returns none. If there is exactly one such property, findLocalSingletonProperty returns it. If there is more than one such property, findLocalSingletonProperty throws an error.
proc findLocalSingletonProperty(o: NonWithFrame  SimpleInstance  RegExp  Date, multiname: Multiname, access: Access): SingletonPropertyOpt
matchingLocalBindings: LocalBinding{}  {b | b  o.localBindings such that b.qname  multiname and accessesOverlap(b.accesses, access)};
note	If the same property was found via several different bindings b, then it will appear only once in the set matchingProperties.
matchingProperties: SingletonProperty{}  {b.content | b  matchingLocalBindings};
if matchingProperties = {} then return none
elsif |matchingProperties| = 1 then return the one element of matchingProperties
else
throw a ReferenceError exception — this access is ambiguous because the bindings it found belong to several different local properties
end if
end proc;
instancePropertyAccesses(m) returns instance property’s AccessSet.
proc instancePropertyAccesses(m: InstanceProperty): AccessSet
case m of
InstanceVariable  InstanceMethod do return readWrite;
InstanceGetter do return read;
InstanceSetter do return write
end case
end proc;
findLocalInstanceProperty(c, multiname, accesses) looks in class c for a local instance property with one of the names in multiname and accesses that have a nonempty intersection with accesses. If there is no such property, findLocalInstanceProperty returns none. If there is exactly one such property, findLocalInstanceProperty returns it. If there is more than one such property, findLocalInstanceProperty throws an error.
proc findLocalInstanceProperty(c: Class, multiname: Multiname, accesses: AccessSet): InstancePropertyOpt
matches: InstanceProperty{}  {m | m  c.instanceProperties such that m.multiname  multiname ≠ {} and accessesOverlap(instancePropertyAccesses(m), accesses)};
if matches = {} then return none
elsif |matches| = 1 then return the one element of matches
else
throw a ReferenceError exception — this access is ambiguous because it found several different instance properties in the same class
end if
end proc;
findArchetypeProperty(o, multiname, access, flat) looks in object o for any local or inherited property with one of the names in multiname and access that includes access. If flat is true, then properties inherited from the archetype are not considered in the search. If it finds no property, findArchetypeProperty returns none. If it finds one property, findArchetypeProperty returns it. If it finds more than one property, findArchetypeProperty prefers the more local one in the list of o’s superclasses or archetypes; if two or more properties remain, the singleton one is preferred; if two or more properties still remain, findArchetypeProperty throws an error.
Note that findArchetypeProperty(o, multiname, access, flat) searches o itself rather than o’s class for properties. findArchetypeProperty will not find instance properties unless o is a class.
proc findArchetypeProperty(o: Object, multiname: Multiname, access: Access, flat: Boolean): PropertyOpt
m: PropertyOpt;
case o of
Undefined  Null  Boolean  Long  ULong  Float32  Float64  Char16  String  Namespace  CompoundAttribute  MethodClosure do
m  none;
SimpleInstance  RegExp  Date  Package do
m  findLocalSingletonProperty(o, multiname, access);
Class do m  findClassProperty(o, multiname, access)
end case;
if m ≠ none then return m end if;
if flat then return none end if;
a: ObjectOpt  archetype(o);
if a = none then return none end if;
return findArchetypeProperty(a, multiname, access, flat)
end proc;
proc findClassProperty(c: Class, multiname: Multiname, access: Access): PropertyOpt
m: PropertyOpt  findLocalSingletonProperty(c, multiname, access);
if m = none then
m  findLocalInstanceProperty(c, multiname, access);
if m = none then
super: ClassOpt  c.super;
if super ≠ none then m  findClassProperty(super, multiname, access) end if
end if
end if;
return m
end proc;
findBaseInstanceProperty(c, multiname, accesses) looks in class c and its ancestors for an instance property with one of the names in multiname and accesses that have a nonempty intersection with accesses. If there is no such property, findBaseInstanceProperty returns none. If there is exactly one such property, findBaseInstanceProperty returns it. If there is more than one such property, findBaseInstanceProperty prefers the one defined in the least specific class; if two or more properties still remain, findBaseInstanceProperty throws an error.
proc findBaseInstanceProperty(c: Class, multiname: Multiname, accesses: AccessSet): InstancePropertyOpt
note	Start from the root class (Object) and proceed through more specific classes that are ancestors of c.
for each s  ancestors(c) do
m: InstancePropertyOpt  findLocalInstanceProperty(s, multiname, accesses);
if m ≠ none then return m end if
end for each;
return none
end proc;
getDerivedInstanceProperty(c, mBase, accesses) returns the most derived instance property whose name includes that of mBase and whose accesses that have a nonempty intersection with accesses. The caller of getDerivedInstanceProperty ensures that such an instance property always exists. If accesses is readWrite then it is possible that this search could find both a getter and a setter defined in the same class; in this case either the getter or the setter is returned at the implementation’s discretion.
proc getDerivedInstanceProperty(c: Class, mBase: InstanceProperty, accesses: AccessSet): InstanceProperty
if some m  c.instanceProperties satisfies mBase.multiname  m.multiname and accessesOverlap(instancePropertyAccesses(m), accesses) then
return m
else return getDerivedInstanceProperty(c.super, mBase, accesses)
end if
end proc;
readImplicitThis(env) returns the value of implicit this to be used to access instance properties within a class’s scope without using the . operator. An implicit this is well-defined only inside instance methods and constructors; readImplicitThis throws an error if there is no well-defined implicit this value or if an attempt is made to read it before it has been initialised.
proc readImplicitThis(env: Environment): Object
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
if frame = none then
throw a ReferenceError exception — can’t access instance properties outside an instance method without supplying an instance object
end if;
this: ObjectOpt  frame.this;
if this = none then
throw a ReferenceError exception — can’t access instance properties inside a non-instance method without supplying an instance object
end if;
if frame.kind  {instanceFunction, constructorFunction} then
throw a ReferenceError exception — can’t access instance properties inside a non-instance method without supplying an instance object
end if;
if not frame.superconstructorCalled then
throw an UninitializedError exception — can’t access instance properties from within a constructor before the superconstructor has been called
end if;
return this
end proc;
hasProperty(o, property, flat, phase) returns true if o has a readable or writable property named property. If flat is true, then properties inherited from the archetype are not considered.
proc hasProperty(o: Object, property: Object, flat: Boolean, phase: Phase): Boolean
c: Class  objectType(o);
return c.hasProperty(o, c, property, flat, phase)
end proc;
hasProperty(o, c, property, flat, phase) is the implementation of hasProperty for a native class unless specified otherwise in the class’s definition. Host classes may either also use ordinaryHasProperty or define a different procedure to perform this test. c is o’s type.
proc ordinaryHasProperty(o: Object, c: Class, property: Object, flat: Boolean, phase: Phase): Boolean
qname: QualifiedName  objectToQualifiedName(property, phase);
return findBaseInstanceProperty(c, {qname}, read) ≠ none or findBaseInstanceProperty(c, {qname}, write) ≠ none or findArchetypeProperty(o, {qname}, read, flat) ≠ none or findArchetypeProperty(o, {qname}, write, flat) ≠ none
end proc;
Reading
If r is an Object, readReference(r, phase) returns it unchanged.  If r is a Reference, readReference reads r and returns the result. If phase is compile, only constant expressions can be evaluated in the process of reading r.
proc readReference(r: ObjOrRef, phase: Phase): Object
result: ObjectOpt;
case r of
Object do result  r;
LexicalReference do result  lexicalRead(r.env, r.variableMultiname, phase);
DotReference do
result  r.limit.read(r.base, r.limit, r.multiname, none, true, phase);
BracketReference do
result  r.limit.bracketRead(r.base, r.limit, r.args, true, phase)
end case;
if result ≠ none then return result
else
throw a ReferenceError exception — property not found, and no default value is available
end if
end proc;
dotRead(o, multiname, phase) reads and returns the value of the multiname property of o. dotRead throws an error if the property does not exist and no default value was available for it.
proc dotRead(o: Object, multiname: Multiname, phase: Phase): Object
limit: Class  objectType(o);
result: ObjectOpt  limit.read(o, limit, multiname, none, true, phase);
if result = none then
throw a ReferenceError exception — property not found, and no default value is available
end if;
return result
end proc;
readLength(o, phase) reads and returns the value of the length property of o, ensuring that it is an integer between 0 and arrayLimit inclusive.
proc readLength(o: Object, phase: Phase): Integer
value: Object  dotRead(o, {public::“length”}, phase);
if value  GeneralNumber then throw a TypeError exception — length not an integer
end if;
length: IntegerOpt  checkInteger(value);
if length = none then throw a RangeError exception — length not an integer
elsif 0 ≤ length ≤ arrayLimit then return length
else throw a RangeError exception — length out of range
end if
end proc;
indexRead(o, i, phase) returns the value of o[i] or none if no such property was found; unlike dotRead, indexRead does not return a default value for missing properties. i should always be a valid array index.
proc indexRead(o: Object, i: Integer, phase: Phase): ObjectOpt
note	0 ≤ i < arrayLimit;
limit: Class  objectType(o);
x: Float64  if64;
result: ObjectOpt  limit.bracketRead(o, limit, [x], false, phase);
if result ≠ none and not hasProperty(o, x, true, phase) then
At the implementation’s discretion either do nothing, set result to none, or throw a ReferenceError.
end if;
return result
end proc;
ordinaryBracketRead(o, limit, args, undefinedIfMissing, phase) evaluates the expression o[args] when o is a native object. Host objects may either also use ordinaryBracketRead or choose a different procedure P to evaluate o[args] by writing P into objectType(o).bracketRead.
limit is used to handle the expression super(o)[args], in which case limit is the superclass of the class inside which the super expression appears. Otherwise, limit is set to objectType(o).
proc ordinaryBracketRead(o: Object, limit: Class, args: Object[], undefinedIfMissing: Boolean, phase: Phase): ObjectOpt
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
qname: QualifiedName  objectToQualifiedName(args[0], phase);
return limit.read(o, limit, {qname}, none, undefinedIfMissing, phase)
end proc;
proc lexicalRead(env: Environment, multiname: Multiname, phase: Phase): Object
i: Integer  0;
while i < |env| do
frame: Frame  env[i];
result: ObjectOpt  none;
case frame of
Package  Class do
limit: Class  objectType(frame);
result  limit.read(frame, limit, multiname, env, false, phase);
ParameterFrame  LocalFrame do
m: SingletonPropertyOpt  findLocalSingletonProperty(frame, multiname, read);
if m ≠ none then result  readSingletonProperty(m, phase) end if;
WithFrame do
value: ObjectOpt  frame.value;
if value = none then
case phase of
{compile} do
throw a ConstantError exception — cannot read a with statement’s frame from a constant expression;
{run} do
throw an UninitializedError exception — cannot read a with statement’s frame before that statement’s expression has been evaluated
end case
end if;
limit: Class  objectType(value);
result  limit.read(value, limit, multiname, env, false, phase)
end case;
if result ≠ none then return result end if;
i  i + 1
end while;
throw a ReferenceError exception — no property found with the name multiname
end proc;
proc ordinaryRead(o: Object, limit: Class, multiname: Multiname, env: EnvironmentOpt, undefinedIfMissing: Boolean, phase: Phase): ObjectOpt
mBase: InstancePropertyOpt  findBaseInstanceProperty(limit, multiname, read);
if mBase ≠ none then return readInstanceProperty(o, limit, mBase, phase) end if;
if limit ≠ objectType(o) then return none end if;
flat: Boolean  env ≠ none and o  Class;
m: PropertyOpt  findArchetypeProperty(o, multiname, read, flat);
case m of
{none} do
if undefinedIfMissing and o  SimpleInstance  Date  RegExp  Package and not o.sealed then
case phase of
{compile} do
throw a ConstantError exception — a constant expression cannot read dynamic properties;
{run} do return undefined
end case
else return none
end if;
SingletonProperty do return readSingletonProperty(m, phase);
InstanceProperty do
if o  Class or env = none then
throw a ReferenceError exception — cannot read an instance property without supplying an instance
end if;
this: Object  readImplicitThis(env);
return readInstanceProperty(this, objectType(this), m, phase)
end case
end proc;
readInstanceProperty(o, qname, phase) is a simplified interface to ordinaryRead used to read instance slots that are known to exist.
proc readInstanceSlot(o: Object, qname: QualifiedName, phase: Phase): Object
c: Class  objectType(o);
mBase: InstancePropertyOpt  findBaseInstanceProperty(c, {qname}, read);
note	readInstanceProperty is only called in cases where the instance property is known to exist, so mBase cannot be none here.
return readInstanceProperty(o, c, mBase, phase)
end proc;
proc readInstanceProperty(this: Object, c: Class, mBase: InstanceProperty, phase: Phase): Object
m: InstanceProperty  getDerivedInstanceProperty(c, mBase, read);
case m of
InstanceVariable do
if phase = compile and not m.immutable then
throw a ConstantError exception — a constant expression cannot read mutable variables
end if;
v: ObjectOpt  findSlot(this, m).value;
if v = none then
case phase of
{compile} do
throw a ConstantError exception — cannot read uninitalised const variables from a constant expression;
{run} do
throw an UninitializedError exception — cannot read a const instance variable before it is initialised
end case
end if;
return v;
InstanceMethod do
slots: Slot{}  {new Slotid: ivarFunctionLength, value: (m.length)f64};
return MethodClosurethis: this, method: m, slots: slots;
InstanceGetter do return m.call(this, phase);
InstanceSetter do
m cannot be an InstanceSetter because these are only represented as write-only properties.
end case
end proc;
proc readSingletonProperty(m: SingletonProperty, phase: Phase): Object
case m of
{forbidden} do
throw a ReferenceError exception — cannot access a property defined in a scope outside the current region if any block inside the current region shadows it;
DynamicVar do
if phase = compile then
throw a ConstantError exception — a constant expression cannot read mutable variables
end if;
value: Object  UninstantiatedFunction  m.value;
note	value can be an UninstantiatedFunction only during the compile phase, which was ruled out above.
return value;
Variable do
if phase = compile and not m.immutable then
throw a ConstantError exception — a constant expression cannot read mutable variables
end if;
value: VariableValue  m.value;
case value of
Object do return value;
{none} do
if not m.immutable then throw an UninitializedError exception end if;
note	Try to run a const variable’s initialiser if there is one.
Evaluate setupVariable(m) and ignore its result;
initializer: Initializer  {none, busy}  m.initializer;
if initializer  {none, busy} then
case phase of
{compile} do
throw a ConstantError exception — a constant expression cannot access a constant with a missing or recursive initialiser;
{run} do throw an UninitializedError exception
end case
end if;
m.initializer  busy;
coercedValue: Object;
try
newValue: Object  initializer(m.initializerEnv, compile);
coercedValue  writeVariable(m, newValue, true)
catch x: SemanticException do
note	If initialisation failed, restore m.initializer to its original value so it can be tried later.
m.initializer  initializer;
throw x
end try;
return coercedValue;
UninstantiatedFunction do
note	An uninstantiated function can only be found when phase = compile.
throw a ConstantError exception — an uninstantiated function is not a constant expression
end case;
Getter do
env: EnvironmentOpt  m.env;
if env = none then
note	An uninstantiated getter can only be found when phase = compile.
throw a ConstantError exception — an uninstantiated getter is not a constant expression
end if;
return m.call(env, phase);
Setter do
m cannot be a Setter because these are only represented as write-only properties.
end case
end proc;
Writing
If r is a reference, writeReference(r, newValue) writes newValue into r. An error occurs if r is not a reference. writeReference is never called from a constant expression.
proc writeReference(r: ObjOrRef, newValue: Object, phase: {run})
result: {none, ok};
case r of
Object do
throw a ReferenceError exception — a non-reference is not a valid target of an assignment;
LexicalReference do
Evaluate lexicalWrite(r.env, r.variableMultiname, newValue, not r.strict, phase) and ignore its result;
result  ok;
DotReference do
result  r.limit.write(r.base, r.limit, r.multiname, none, newValue, true, phase);
BracketReference do
result  r.limit.bracketWrite(r.base, r.limit, r.args, newValue, true, phase)
end case;
if result = none then
throw a ReferenceError exception — property not found and could not be created
end if
end proc;
dotWrite(o, multiname, newValue, phase) is a simplified interface to write newValue into the multiname property of o.
proc dotWrite(o: Object, multiname: Multiname, newValue: Object, phase: {run})
limit: Class  objectType(o);
result: {none, ok}  limit.write(o, limit, multiname, none, newValue, true, phase);
if result = none then
throw a ReferenceError exception — property not found and could not be created
end if
end proc;
writeLength(o, length, phase) ensures that length is between 0 and arrayLimit inclusive and then writes it into the length property of o. Note that if o is an Array, the act of writing its length property will invoke the Array_setLength setter.
proc writeLength(o: Object, length: Integer, phase: {run})
if length < 0 or length > arrayLimit then
throw a RangeError exception — length out of range
end if;
Evaluate dotWrite(o, {public::“length”}, lengthf64, phase) and ignore its result
end proc;
proc indexWrite(o: Object, i: Integer, newValue: ObjectOpt, phase: {run})
if i < 0 or i ≥ arrayLimit then throw a RangeError exception — index out of range
end if;
limit: Class  objectType(o);
if newValue = none then
deleteResult: BooleanOpt  limit.bracketDelete(o, limit, [if64], phase);
if deleteResult = false then
throw a ReferenceError exception — cannot delete element
end if
else
writeResult: {none, ok}  limit.bracketWrite(o, limit, [if64], newValue, true, phase);
if writeResult = none then
throw a ReferenceError exception — element not found and could not be created
end if
end if
end proc;
proc ordinaryBracketWrite(o: Object, limit: Class, args: Object[], newValue: Object, createIfMissing: Boolean, phase: {run}): {none, ok}
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
qname: QualifiedName  objectToQualifiedName(args[0], phase);
return limit.write(o, limit, {qname}, none, newValue, createIfMissing, phase)
end proc;
proc lexicalWrite(env: Environment, multiname: Multiname, newValue: Object, createIfMissing: Boolean, phase: {run})
i: Integer  0;
while i < |env| do
frame: Frame  env[i];
result: {none, ok}  none;
case frame of
Package  Class do
limit: Class  objectType(frame);
result  limit.write(frame, limit, multiname, env, newValue, false, phase);
ParameterFrame  LocalFrame do
m: SingletonPropertyOpt  findLocalSingletonProperty(frame, multiname, write);
if m ≠ none then
Evaluate writeSingletonProperty(m, newValue, phase) and ignore its result;
result  ok
end if;
WithFrame do
value: ObjectOpt  frame.value;
if value = none then
throw an UninitializedError exception — cannot read a with statement’s frame before that statement’s expression has been evaluated
end if;
limit: Class  objectType(value);
result  limit.write(value, limit, multiname, env, newValue, false, phase)
end case;
if result = ok then return end if;
i  i + 1
end while;
if createIfMissing then
pkg: Package  getPackageFrame(env);
note	Try to write the variable into pkg again, this time allowing new dynamic bindings to be created dynamically.
limit: Class  objectType(pkg);
result: {none, ok}  limit.write(pkg, limit, multiname, env, newValue, true, phase);
if result = ok then return end if
end if;
throw a ReferenceError exception — no existing property found with the name multiname and one could not be created
end proc;
proc ordinaryWrite(o: Object, limit: Class, multiname: Multiname, env: EnvironmentOpt, newValue: Object, createIfMissing: Boolean, phase: {run}): {none, ok}
mBase: InstancePropertyOpt  findBaseInstanceProperty(limit, multiname, write);
if mBase ≠ none then
Evaluate writeInstanceProperty(o, limit, mBase, newValue, phase) and ignore its result;
return ok
end if;
if limit ≠ objectType(o) then return none end if;
m: PropertyOpt  findArchetypeProperty(o, multiname, write, true);
case m of
{none} do
if createIfMissing and o  SimpleInstance  Date  RegExp  Package and not o.sealed and (some qname  multiname satisfies qname.namespace = public) then
note	Before trying to create a new dynamic property named qname, check that there is no read-only fixed property with the same name.
if findBaseInstanceProperty(objectType(o), {qname}, read) = none and findArchetypeProperty(o, {qname}, read, true) = none then
Evaluate createDynamicProperty(o, qname, false, true, newValue) and ignore its result;
return ok
end if
end if;
return none;
SingletonProperty do
Evaluate writeSingletonProperty(m, newValue, phase) and ignore its result;
return ok;
InstanceProperty do
if o  Class or env = none then
throw a ReferenceError exception — cannot write an instance property without supplying an instance
end if;
this: Object  readImplicitThis(env);
Evaluate writeInstanceProperty(this, objectType(this), m, newValue, phase) and ignore its result;
return ok
end case
end proc;
The caller must make sure that the created property does not already exist and does not conflict with any other property.
proc createDynamicProperty(o: SimpleInstance  Date  RegExp  Package, qname: QualifiedName, sealed: Boolean, enumerable: Boolean, newValue: Object)
dv: DynamicVar  new DynamicVarvalue: newValue, sealed: sealed;
o.localBindings  o.localBindings  {LocalBindingqname: qname, accesses: readWrite, explicit: false, enumerable: enumerable, content: dv}
end proc;
proc writeInstanceProperty(this: Object, c: Class, mBase: InstanceProperty, newValue: Object, phase: {run})
m: InstanceProperty  getDerivedInstanceProperty(c, mBase, write);
case m of
InstanceVariable do
s: Slot  findSlot(this, m);
coercedValue: Object  coerce(newValue, m.type);
if m.immutable and s.value ≠ none then
throw a ReferenceError exception — cannot initialise a const instance variable twice
end if;
s.value  coercedValue;
InstanceMethod do
throw a ReferenceError exception — cannot write to an instance method;
InstanceGetter do
m cannot be an InstanceGetter because these are only represented as read-only properties.
InstanceSetter do Evaluate m.call(this, newValue, phase) and ignore its result
end case
end proc;
proc writeSingletonProperty(m: SingletonProperty, newValue: Object, phase: {run})
case m of
{forbidden} do
throw a ReferenceError exception — cannot access a property defined in a scope outside the current region if any block inside the current region shadows it;
Variable do Evaluate writeVariable(m, newValue, false) and ignore its result;
DynamicVar do m.value  newValue;
Getter do
m cannot be a Getter because these are only represented as read-only properties.
Setter do
env: EnvironmentOpt  m.env;
note	All instances are resolved for the run phase, so env ≠ none.
Evaluate m.call(newValue, env, phase) and ignore its result
end case
end proc;
Deleting
If r is a Reference, deleteReference(r) deletes it. If r is an Object, this function signals an error in strict mode or returns true in non-strict mode. deleteReference is never called from a constant expression.
proc deleteReference(r: ObjOrRef, strict: Boolean, phase: {run}): Boolean
result: BooleanOpt;
case r of
Object do
if strict then
throw a ReferenceError exception — a non-reference is not a valid target for delete in strict mode
else result  true
end if;
LexicalReference do result  lexicalDelete(r.env, r.variableMultiname, phase);
DotReference do
result  r.limit.delete(r.base, r.limit, r.multiname, none, phase);
BracketReference do
result  r.limit.bracketDelete(r.base, r.limit, r.args, phase)
end case;
if result ≠ none then return result else return true end if
end proc;
proc ordinaryBracketDelete(o: Object, limit: Class, args: Object[], phase: {run}): BooleanOpt
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
qname: QualifiedName  objectToQualifiedName(args[0], phase);
return limit.delete(o, limit, {qname}, none, phase)
end proc;
proc lexicalDelete(env: Environment, multiname: Multiname, phase: {run}): Boolean
i: Integer  0;
while i < |env| do
frame: Frame  env[i];
result: BooleanOpt  none;
case frame of
Package  Class do
limit: Class  objectType(frame);
result  limit.delete(frame, limit, multiname, env, phase);
ParameterFrame  LocalFrame do
if findLocalSingletonProperty(frame, multiname, write) ≠ none then
result  false
end if;
WithFrame do
value: ObjectOpt  frame.value;
if value = none then
throw an UninitializedError exception — cannot read a with statement’s frame before that statement’s expression has been evaluated
end if;
limit: Class  objectType(value);
result  limit.delete(value, limit, multiname, env, phase)
end case;
if result ≠ none then return result end if;
i  i + 1
end while;
return true
end proc;
proc ordinaryDelete(o: Object, limit: Class, multiname: Multiname, env: EnvironmentOpt, phase: {run}): BooleanOpt
if findBaseInstanceProperty(limit, multiname, write) ≠ none then return false end if;
if limit ≠ objectType(o) then return none end if;
m: PropertyOpt  findArchetypeProperty(o, multiname, write, true);
case m of
{none} do return none;
{forbidden} do
throw a ReferenceError exception — cannot access a property defined in a scope outside the current region if any block inside the current region shadows it;
Variable  Getter  Setter do return false;
DynamicVar do
if m.sealed then return false
else
o.localBindings  {b | b  o.localBindings such that b.qname  multiname or b.content ≠ m};
return true
end if;
InstanceProperty do
if o  Class or env = none then return false end if;
Evaluate readImplicitThis(env) and ignore its result;
return false
end case
end proc;
Enumerating
proc ordinaryEnumerate(o: Object): Object{}
e1: Object{}  enumerateInstanceProperties(objectType(o));
e2: Object{}  enumerateArchetypeProperties(o);
return e1  e2
end proc;
proc enumerateInstanceProperties(c: Class): Object{}
e: Object{}  {};
for each m  c.instanceProperties do
if m.enumerable then
e  e  {qname.id | qname  m.multiname such that qname.namespace = public}
end if
end for each;
super: ClassOpt  c.super;
if super = none then return e
else return e  enumerateInstanceProperties(super)
end if
end proc;
proc enumerateArchetypeProperties(o: Object): Object{}
e: Object{}  {};
for each a  {o}  archetypes(o) do
if a  BindingObject then e  e  enumerateSingletonProperties(a) end if
end for each;
return e
end proc;
proc enumerateSingletonProperties(o: BindingObject): Object{}
e: Object{}  {};
for each b  o.localBindings do
if b.enumerable and b.qname.namespace = public then e  e  {b.qname.id} end if
end for each;
if o  Class then
super: ClassOpt  o.super;
if super ≠ none then e  e  enumerateSingletonProperties(super) end if
end if;
return e
end proc;
Calling Instances
proc call(this: Object, a: Object, args: Object[], phase: Phase): Object
case a of
Undefined  Null  Boolean  GeneralNumber  Char16  String  Namespace  CompoundAttribute  Date  RegExp  Package do
throw a TypeError exception;
Class do return a.call(this, a, args, phase);
SimpleInstance do
f: (Object  SimpleInstance  Object[]  Phase  Object)  {none}  a.call;
if f = none then throw a TypeError exception end if;
return f(this, a, args, phase);
MethodClosure do
m: InstanceMethod  a.method;
return m.call(a.this, args, phase)
end case
end proc;
proc ordinaryCall(this: Object, c: Class, args: Object[], phase: Phase): Object
note	This function can be used in a constant expression.
if not c.complete then
throw a ConstantError exception — cannot call a class before its definition has been compiled
end if;
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
return coerce(args[0], c)
end proc;
proc sameAsConstruct(this: Object, c: Class, args: Object[], phase: Phase): Object
return construct(c, args, phase)
end proc;
Creating Instances
proc construct(a: Object, args: Object[], phase: Phase): Object
case a of
Undefined  Null  Boolean  GeneralNumber  Char16  String  Namespace  CompoundAttribute  MethodClosure  Date  RegExp  Package do
throw a TypeError exception;
Class do return a.construct(a, args, phase);
SimpleInstance do
f: (SimpleInstance  Object[]  Phase  Object)  {none}  a.construct;
if f = none then throw a TypeError exception end if;
return f(a, args, phase)
end case
end proc;
proc ordinaryConstruct(c: Class, args: Object[], phase: Phase): Object
if not c.complete then
throw a ConstantError exception — cannot construct an instance of a class before its definition has been compiled
end if;
if phase = compile then
throw a ConstantError exception — a class constructor call is not a constant expression because it evaluates to a new object each time it is evaluated
end if;
this: SimpleInstance  createSimpleInstance(c, c.prototype, none, none, none);
Evaluate callInit(this, c, args, phase) and ignore its result;
return this
end proc;
proc createSimpleInstance(c: Class, archetype: ObjectOpt, call: (Object  SimpleInstance  Object[]  Phase  Object)  {none}, construct: (SimpleInstance  Object[]  Phase  Object)  {none}, env: EnvironmentOpt): SimpleInstance
slots: Slot{}  {};
for each s  ancestors(c) do
for each m  s.instanceProperties do
if m  InstanceVariable then
slot: Slot  new Slotid: m, value: m.defaultValue;
slots  slots  {slot}
end if
end for each
end for each;
return new SimpleInstancelocalBindings: {}, archetype: archetype, sealed: not c.dynamic, type: c, slots: slots, call: call, construct: construct, env: env
end proc;
proc callInit(this: SimpleInstance, c: ClassOpt, args: Object[], phase: {run})
init: (SimpleInstance  Object[]  {run}  ())  {none}  none;
if c ≠ none then init  c.init end if;
if init ≠ none then Evaluate init(this, args, phase) and ignore its result
else
if args ≠ [] then
throw an ArgumentError exception — the default constructor does not take any arguments
end if
end if
end proc;
Adding Local Definitions
proc defineSingletonProperty(env: Environment, id: String, namespaces: Namespace{}, overrideMod: OverrideModifier, explicit: Boolean, accesses: AccessSet, m: SingletonProperty): Multiname
innerFrame: NonWithFrame  env[0];
if overrideMod ≠ none then
throw an AttributeError exception — a local definition cannot have the override attribute
end if;
if explicit and innerFrame  Package then
throw an AttributeError exception — the explicit attribute can only be used at the top level of a package
end if;
namespaces2: Namespace{}  namespaces;
if namespaces2 = {} then namespaces2  {public} end if;
multiname: Multiname  {ns::id | ns  namespaces2};
regionalEnv: Frame[]  getRegionalEnvironment(env);
if some b  innerFrame.localBindings satisfies b.qname  multiname and accessesOverlap(b.accesses, accesses) then
throw a DefinitionError exception — duplicate definition in the same scope
end if;
if innerFrame  Class and id = innerFrame.name then
throw a DefinitionError exception — a static property of a class cannot have the same name as the class, regardless of the namespace
end if;
for each frame  regionalEnv[1 ...] do
if frame  WithFrame and (some b  frame.localBindings satisfies b.qname  multiname and accessesOverlap(b.accesses, accesses) and b.content ≠ forbidden) then
throw a DefinitionError exception — this definition would shadow a property defined in an outer scope within the same region
end if
end for each;
newBindings: LocalBinding{}  {LocalBindingqname: qname, accesses: accesses, explicit: explicit, enumerable: true, content: m | qname  multiname};
innerFrame.localBindings  innerFrame.localBindings  newBindings;
note	Mark the bindings of multiname as forbidden in all non-innermost frames in the current region if they haven’t been marked as such already.
newForbiddenBindings: LocalBinding{}  {LocalBindingqname: qname, accesses: accesses, explicit: true, enumerable: true, content: forbidden | qname  multiname};
for each frame  regionalEnv[1 ...] do
note	Since frame  Class here, a Class frame never gets a forbidden binding.
if frame  WithFrame then
frame.localBindings  frame.localBindings  newForbiddenBindings
end if
end for each;
return multiname
end proc;
defineHoistedVar(env, id, initialValue) defines a hoisted variable with the name id in the environment env. Hoisted variables are hoisted to the package or enclosing function scope. Multiple hoisted variables may be defined in the same scope, but they may not coexist with non-hoisted variables with the same name. A hoisted variable can be defined using either a var or a function statement. If it is defined using var, then initialValue is always undefined (if the var statement has an initialiser, then the variable’s value will be written later when the var statement is executed). If it is defined using function, then initialValue must be a function instance or open instance. A var hoisted variable may be hoisted into the ParameterFrame if there is already a parameter with the same name; a function hoisted variable is never hoisted into the ParameterFrame and will shadow a parameter with the same name for compatibility with ECMAScript Edition 3. If there are multiple function definitions, the initial value is the last function definition.
proc defineHoistedVar(env: Environment, id: String, initialValue: Object  UninstantiatedFunction): DynamicVar
qname: QualifiedName  public::id;
regionalEnv: Frame[]  getRegionalEnvironment(env);
regionalFrame: Frame  regionalEnv[|regionalEnv| – 1];
note	env is either a Package or a ParameterFrame because hoisting only occurs into package or function scope.
existingBindings: LocalBinding{}  {b | b  regionalFrame.localBindings such that b.qname = qname};
if (existingBindings = {} or initialValue ≠ undefined) and regionalFrame  ParameterFrame and |regionalEnv| ≥ 2 then
regionalFrame  regionalEnv[|regionalEnv| – 2];
existingBindings  {b | b  regionalFrame.localBindings such that b.qname = qname}
end if;
if existingBindings = {} then
v: DynamicVar  new DynamicVarvalue: initialValue, sealed: true;
regionalFrame.localBindings  regionalFrame.localBindings  {LocalBindingqname: qname, accesses: readWrite, explicit: false, enumerable: true, content: v};
return v
elsif |existingBindings| ≠ 1 then
throw a DefinitionError exception — a hoisted definition conflicts with a non-hoisted one
else
b: LocalBinding  the one element of existingBindings;
m: SingletonProperty  b.content;
if b.accesses ≠ readWrite or m  DynamicVar then
throw a DefinitionError exception — a hoisted definition conflicts with a non-hoisted one
end if;
note	At this point a hoisted binding of the same var already exists, so there is no need to create another one. Overwrite its initial value if the new definition is a function definition.
if initialValue ≠ undefined then m.value  initialValue end if;
m.sealed  true;
regionalFrame.localBindings  regionalFrame.localBindings – {b};
regionalFrame.localBindings  regionalFrame.localBindings  {LocalBindingenumerable: true, other fields from b};
return m
end if
end proc;
Adding Instance Definitions
proc searchForOverrides(c: Class, multiname: Multiname, accesses: AccessSet): InstancePropertyOpt
mBase: InstancePropertyOpt  none;
s: ClassOpt  c.super;
if s ≠ none then
for each qname  multiname do
m: InstancePropertyOpt  findBaseInstanceProperty(s, {qname}, accesses);
if mBase = none then mBase  m
elsif m ≠ none and m ≠ mBase then
throw a DefinitionError exception — cannot override two separate superclass methods at the same time
end if
end for each
end if;
return mBase
end proc;
proc defineInstanceProperty(c: Class, cxt: Context, id: String, namespaces: Namespace{}, overrideMod: OverrideModifier, explicit: Boolean, m: InstanceProperty): InstancePropertyOpt
if explicit then
throw an AttributeError exception — the explicit attribute can only be used at the top level of a package
end if;
accesses: AccessSet  instancePropertyAccesses(m);
requestedMultiname: Multiname  {ns::id | ns  namespaces};
openMultiname: Multiname  {ns::id | ns  cxt.openNamespaces};
definedMultiname: Multiname;
searchedMultiname: Multiname;
if requestedMultiname = {} then
definedMultiname  {public::id};
searchedMultiname  openMultiname;
note	definedMultiname  searchedMultiname because the public namespace is always open.
else definedMultiname  requestedMultiname; searchedMultiname  requestedMultiname
end if;
mBase: InstancePropertyOpt  searchForOverrides(c, searchedMultiname, accesses);
mOverridden: InstancePropertyOpt  none;
if mBase ≠ none then
mOverridden  getDerivedInstanceProperty(c, mBase, accesses);
definedMultiname  mOverridden.multiname;
if not (requestedMultiname  definedMultiname) then
throw a DefinitionError exception — cannot extend the set of a property’s namespaces when overriding it
end if;
goodKind: Boolean;
case m of
InstanceVariable do goodKind  mOverridden  InstanceVariable;
InstanceGetter do
goodKind  mOverridden  InstanceVariable  InstanceGetter;
InstanceSetter do
goodKind  mOverridden  InstanceVariable  InstanceSetter;
InstanceMethod do goodKind  mOverridden  InstanceMethod
end case;
if not goodKind then
throw a DefinitionError exception — a method can override only another method, a variable can override only another variable, a getter can override only a getter or a variable, and a setter can override only a setter or a variable
end if;
if mOverridden.final then
throw a DefinitionError exception — cannot override a final property
end if
end if;
if some m2  c.instanceProperties satisfies m2.multiname  definedMultiname ≠ {} and accessesOverlap(instancePropertyAccesses(m2), accesses) then
throw a DefinitionError exception — duplicate definition in the same scope
end if;
case overrideMod of
{none} do
if mBase ≠ none then
throw a DefinitionError exception — a definition that overrides a superclass’s property must be marked with the override attribute
end if;
if searchForOverrides(c, openMultiname, accesses) ≠ none then
throw a DefinitionError exception — this definition is hidden by one in a superclass when accessed without a namespace qualifier; in the rare cases where this is intentional, use the override(false) attribute
end if;
{false} do
if mBase ≠ none then
throw a DefinitionError exception — this definition is marked with override(false) but it overrides a superclass’s property
end if;
{true} do
if mBase = none then
throw a DefinitionError exception — this definition is marked with override or override(true) but it doesn’t override a superclass’s property
end if;
{undefined} do nothing
end case;
m.multiname  definedMultiname;
c.instanceProperties  c.instanceProperties  {m};
return mOverridden
end proc;
Instantiation
proc instantiateFunction(uf: UninstantiatedFunction, env: Environment): SimpleInstance
c: Class  uf.type;
i: SimpleInstance  createSimpleInstance(c, c.prototype, uf.call, uf.construct, env);
Evaluate dotWrite(i, {public::“length”}, (uf.length)f64, run) and ignore its result;
if c = PrototypeFunction then
prototype: Object  construct(Object, [], run);
Evaluate dotWrite(prototype, {public::“constructor”}, i, run) and ignore its result;
Evaluate dotWrite(i, {public::“prototype”}, prototype, run) and ignore its result
end if;
instantiations: SimpleInstance{}  uf.instantiations;
if instantiations ≠ {} then
Suppose that instantiateFunction were to choose at its discretion some element i2 of instantiations, assign i2.env  env, and return i. If the behaviour of doing that assignment were observationally indistinguishable by the rest of the program from the behaviour of returning i without modifying i2.env, then the implementation may, but does not have to, return i2 now, discarding (or not even bothering to create) the value of i.
note	The above rule allows an implementation to avoid creating a fresh closure each time a local function is instantiated if it can show that the closures would behave identically. This optimisation is not transparent to the programmer because the instantiations will be === to each other and share one set of properties (including the prototype property, if applicable) rather than each having its own. ECMAScript programs should not rely on this distinction.
end if;
uf.instantiations  instantiations  {i};
return i
end proc;
proc instantiateProperty(m: SingletonProperty, env: Environment): SingletonProperty
case m of
{forbidden} do return m;
Variable do
note	m.setup = none because Setup must have been called on a frame before that frame can be instantiated.
value: VariableValue  m.value;
if value  UninstantiatedFunction then
value  instantiateFunction(value, env)
end if;
return new Variabletype: m.type, value: value, immutable: m.immutable, setup: none, initializer: m.initializer, initializerEnv: env;
DynamicVar do
value: Object  UninstantiatedFunction  m.value;
if value  UninstantiatedFunction then
value  instantiateFunction(value, env)
end if;
return new DynamicVarvalue: value, sealed: m.sealed;
Getter do
case m.env of
Environment do return m;
{none} do return new Gettercall: m.call, env: env
end case;
Setter do
case m.env of
Environment do return m;
{none} do return new Settercall: m.call, env: env
end case
end case
end proc;
tuple PropertyTranslation
from: SingletonProperty,
to: SingletonProperty
end tuple;
proc instantiateLocalFrame(frame: LocalFrame, env: Environment): LocalFrame
instantiatedFrame: LocalFrame  new LocalFramelocalBindings: {};
properties: SingletonProperty{}  {b.content | b  frame.localBindings};
propertyTranslations: PropertyTranslation{}  {PropertyTranslationfrom: m, to: instantiateProperty(m, [instantiatedFrame]  env) | m  properties};
proc translateProperty(m: SingletonProperty): SingletonProperty
mi: PropertyTranslation  the one element mi  propertyTranslations that satisfies mi.from = m;
return mi.to
end proc;
instantiatedFrame.localBindings  {LocalBindingcontent: translateProperty(b.content), other fields from b | b  frame.localBindings};
return instantiatedFrame
end proc;
proc instantiateParameterFrame(frame: ParameterFrame, env: Environment, singularThis: ObjectOpt): ParameterFrame
note	frame.superconstructorCalled must be true if and only if frame.kind is not constructorFunction.
instantiatedFrame: ParameterFrame  new ParameterFramelocalBindings: {}, kind: frame.kind, handling: frame.handling, callsSuperconstructor: frame.callsSuperconstructor, superconstructorCalled: frame.superconstructorCalled, this: singularThis, returnType: frame.returnType;
note	properties will contain the set of all SingletonProperty records found in the frame.
properties: SingletonProperty{}  {b.content | b  frame.localBindings};
note	If any of the parameters (including the rest parameter) are anonymous, their bindings will not be present in frame.localBindings. In this situation, the following steps add their SingletonProperty records to properties.
for each p  frame.parameters do properties  properties  {p.var} end for each;
rest: VariableOpt  frame.rest;
if rest ≠ none then properties  properties  {rest} end if;
propertyTranslations: PropertyTranslation{}  {PropertyTranslationfrom: m, to: instantiateProperty(m, [instantiatedFrame]  env) | m  properties};
proc translateProperty(m: SingletonProperty): SingletonProperty
mi: PropertyTranslation  the one element mi  propertyTranslations that satisfies mi.from = m;
return mi.to
end proc;
instantiatedFrame.localBindings  {LocalBindingcontent: translateProperty(b.content), other fields from b | b  frame.localBindings};
instantiatedFrame.parameters  [Parametervar: translateProperty(op.var), default: op.default | op  frame.parameters];
if rest = none then instantiatedFrame.rest  none
else instantiatedFrame.rest  translateProperty(rest)
end if;
return instantiatedFrame
end proc;
Sealing
proc sealObject(o: Object)
if o  SimpleInstance  RegExp  Date  Package then o.sealed  true end if
end proc;
proc sealAllLocalProperties(o: Object)
if o  BindingObject then
for each b  o.localBindings do
m: SingletonProperty  b.content;
if m  DynamicVar then m.sealed  true end if
end for each
end if
end proc;
proc sealLocalProperty(o: Object, qname: QualifiedName)
c: Class  objectType(o);
if findBaseInstanceProperty(c, {qname}, read) = none and findBaseInstanceProperty(c, {qname}, write) = none and o  BindingObject then
matchingProperties: SingletonProperty{}  {b.content | b  o.localBindings such that b.qname = qname};
for each m  matchingProperties do
if m  DynamicVar then m.sealed  true end if
end for each
end if
end proc;
Standard Class Utilities
proc defaultArg(args: Object[], n: Integer, default: Object): Object
if n ≥ |args| then return default end if;
arg: Object  args[n];
if arg = undefined then return default else return arg end if
end proc;
proc stdConstBinding(qname: QualifiedName, type: Class, value: Object): LocalBinding
return LocalBindingqname: qname, accesses: readWrite, explicit: false, enumerable: false, content: new Variabletype: type, value: value, immutable: true, setup: none, initializer: none
end proc;
proc stdExplicitConstBinding(qname: QualifiedName, type: Class, value: Object): LocalBinding
return LocalBindingqname: qname, accesses: readWrite, explicit: true, enumerable: false, content: new Variabletype: type, value: value, immutable: true, setup: none, initializer: none
end proc;
proc stdVarBinding(qname: QualifiedName, type: Class, value: Object): LocalBinding
return LocalBindingqname: qname, accesses: readWrite, explicit: false, enumerable: false, content: new Variabletype: type, value: value, immutable: false, setup: none, initializer: none
end proc;
proc stdFunction(qname: QualifiedName, call: Object  SimpleInstance  Object[]  Phase  Object, length: Integer): LocalBinding
slots: Slot{}  {new Slotid: ivarFunctionLength, value: lengthf64};
f: SimpleInstance  new SimpleInstancelocalBindings: {}, archetype: FunctionPrototype, sealed: true, type: Function, slots: slots, call: call, construct: none, env: none;
return LocalBindingqname: qname, accesses: readWrite, explicit: false, enumerable: false, content: new Variabletype: Function, value: f, immutable: true, setup: none, initializer: none
end proc;
stdReserve(qname, archetype) is used during the creation of system objects. It returns an alias of the local binding of qname in archetype, which should be the archetype of the object being created. The alias that stdReserve defines serves to prevent qname from being later redefined by users in the object being created while at the same time retaining the definition of qname that would normally be inherited from archetype.
proc stdReserve(qname: QualifiedName, archetype: SimpleInstance): LocalBinding
matchingBindings: LocalBinding{}  {b | b  archetype.localBindings such that b.qname = qname};
return the one element of matchingBindings
end proc;
Expressions
Syntax
  {allowIn, noIn}
Terminal Actions
Name[Identifier]: String;
Value[Number]: GeneralNumber;
Value[String]: String;
Body[RegularExpression]: String;
Flags[RegularExpression]: String;
Identifiers
Syntax
Identifier 
	Identifier
|	get
|	set
|	include
Semantics
Name[Identifier]: String;
Name[Identifier  Identifier] = Name[Identifier];
Name[Identifier  get] = “get”;
Name[Identifier  set] = “set”;
Name[Identifier  include] = “include”;
Qualified Identifiers
Syntax
SimpleQualifiedIdentifier 
	Identifier
|	Identifier :: Identifier
|	ReservedNamespace :: Identifier
ExpressionQualifiedIdentifier  ParenExpression :: Identifier
QualifiedIdentifier 
	SimpleQualifiedIdentifier
|	ExpressionQualifiedIdentifier
Validation
OpenNamespaces[SimpleQualifiedIdentifier]: Namespace{};
Strict[SimpleQualifiedIdentifier]: Boolean;
proc Validate[SimpleQualifiedIdentifier] (cxt: Context, env: Environment)
[SimpleQualifiedIdentifier  Identifier] do
OpenNamespaces[SimpleQualifiedIdentifier]  cxt.openNamespaces;
Strict[SimpleQualifiedIdentifier]  cxt.strict;
[SimpleQualifiedIdentifier  Identifier :: Identifier] do
OpenNamespaces[SimpleQualifiedIdentifier]  cxt.openNamespaces;
[SimpleQualifiedIdentifier  ReservedNamespace :: Identifier] do
Evaluate Validate[ReservedNamespace](cxt, env) and ignore its result
end proc;
Strict[ExpressionQualifiedIdentifier]: Boolean;
proc Validate[ExpressionQualifiedIdentifier  ParenExpression :: Identifier] (cxt: Context, env: Environment)
Strict[ExpressionQualifiedIdentifier]  cxt.strict;
Evaluate Validate[ParenExpression](cxt, env) and ignore its result
end proc;
Strict[QualifiedIdentifier]: Boolean;
proc Validate[QualifiedIdentifier] (cxt: Context, env: Environment)
[QualifiedIdentifier  SimpleQualifiedIdentifier] do
Strict[QualifiedIdentifier]  cxt.strict;
Evaluate Validate[SimpleQualifiedIdentifier](cxt, env) and ignore its result;
[QualifiedIdentifier  ExpressionQualifiedIdentifier] do
Strict[QualifiedIdentifier]  cxt.strict;
Evaluate Validate[ExpressionQualifiedIdentifier](cxt, env) and ignore its result
end proc;
Setup
proc Setup[SimpleQualifiedIdentifier] ()
[SimpleQualifiedIdentifier  Identifier] do nothing;
[SimpleQualifiedIdentifier  Identifier :: Identifier] do nothing;
[SimpleQualifiedIdentifier  ReservedNamespace :: Identifier] do
Evaluate Setup[ReservedNamespace]() and ignore its result
end proc;
proc Setup[ExpressionQualifiedIdentifier  ParenExpression :: Identifier] ()
Evaluate Setup[ParenExpression]() and ignore its result
end proc;
Setup[QualifiedIdentifier] () propagates the call to Setup to nonterminals in the expansion of QualifiedIdentifier.
Evaluation
proc Eval[SimpleQualifiedIdentifier] (env: Environment, phase: Phase): Multiname
[SimpleQualifiedIdentifier  Identifier] do
return {ns::(Name[Identifier]) | ns  OpenNamespaces[SimpleQualifiedIdentifier]};
[SimpleQualifiedIdentifier  Identifier1 :: Identifier2] do
multiname: Multiname  {ns::(Name[Identifier1]) | ns  OpenNamespaces[SimpleQualifiedIdentifier]};
a: Object  lexicalRead(env, multiname, phase);
if a  Namespace then
throw a TypeError exception — the qualifier must be a namespace
end if;
return {a::(Name[Identifier2])};
[SimpleQualifiedIdentifier  ReservedNamespace :: Identifier] do
q: Namespace  Eval[ReservedNamespace](env, phase);
return {q::(Name[Identifier])}
end proc;
proc Eval[ExpressionQualifiedIdentifier  ParenExpression :: Identifier] (env: Environment, phase: Phase): Multiname
q: Object  readReference(Eval[ParenExpression](env, phase), phase);
if q  Namespace then throw a TypeError exception — the qualifier must be a namespace
end if;
return {q::(Name[Identifier])}
end proc;
Eval[QualifiedIdentifier] (env: Environment, phase: Phase): Multiname propagates the call to Eval to nonterminals in the expansion of QualifiedIdentifier.
Primary Expressions
Syntax
PrimaryExpression 
	null
|	true
|	false
|	Number
|	String
|	this
|	RegularExpression
|	ReservedNamespace
|	ParenListExpression
|	ArrayLiteral
|	ObjectLiteral
|	FunctionExpression
ReservedNamespace 
	public
|	private
ParenExpression  ( AssignmentExpressionallowIn )
ParenListExpression 
	ParenExpression
|	( ListExpressionallowIn , AssignmentExpressionallowIn )
Validation
proc Validate[PrimaryExpression] (cxt: Context, env: Environment)
[PrimaryExpression  null] do nothing;
[PrimaryExpression  true] do nothing;
[PrimaryExpression  false] do nothing;
[PrimaryExpression  Number] do nothing;
[PrimaryExpression  String] do nothing;
[PrimaryExpression  this] do
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
if frame = none then
if cxt.strict then
throw a SyntaxError exception — this can be used outside a function only in non-strict mode
end if
elsif frame.kind = plainFunction then
throw a SyntaxError exception — this function does not define this
end if;
[PrimaryExpression  RegularExpression] do nothing;
[PrimaryExpression  ReservedNamespace] do
Evaluate Validate[ReservedNamespace](cxt, env) and ignore its result;
[PrimaryExpression  ParenListExpression] do
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
[PrimaryExpression  ArrayLiteral] do
Evaluate Validate[ArrayLiteral](cxt, env) and ignore its result;
[PrimaryExpression  ObjectLiteral] do
Evaluate Validate[ObjectLiteral](cxt, env) and ignore its result;
[PrimaryExpression  FunctionExpression] do
Evaluate Validate[FunctionExpression](cxt, env) and ignore its result
end proc;
proc Validate[ReservedNamespace] (cxt: Context, env: Environment)
[ReservedNamespace  public] do nothing;
[ReservedNamespace  private] do
if getEnclosingClass(env) = none then
throw a SyntaxError exception — private is meaningful only inside a class
end if
end proc;
Validate[ParenExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ParenExpression.
Validate[ParenListExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ParenListExpression.
Setup
Setup[PrimaryExpression] () propagates the call to Setup to nonterminals in the expansion of PrimaryExpression.
proc Setup[ReservedNamespace] ()
[ReservedNamespace  public] do nothing;
[ReservedNamespace  private] do nothing
end proc;
Setup[ParenExpression] () propagates the call to Setup to nonterminals in the expansion of ParenExpression.
Setup[ParenListExpression] () propagates the call to Setup to nonterminals in the expansion of ParenListExpression.
Evaluation
proc Eval[PrimaryExpression] (env: Environment, phase: Phase): ObjOrRef
[PrimaryExpression  null] do return null;
[PrimaryExpression  true] do return true;
[PrimaryExpression  false] do return false;
[PrimaryExpression  Number] do return Value[Number];
[PrimaryExpression  String] do return Value[String];
[PrimaryExpression  this] do
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
if frame = none then return getPackageFrame(env) end if;
note	Validate ensured that frame.kind ≠ plainFunction at this point.
this: ObjectOpt  frame.this;
if this = none then
note	If Validate passed, this can be uninitialised only when phase = compile.
throw a ConstantError exception — a constant expression cannot read an uninitialised this parameter
end if;
if not frame.superconstructorCalled then
throw an UninitializedError exception — can’t access this from within a constructor before the superconstructor has been called
end if;
return this;
[PrimaryExpression  RegularExpression] do
return Body[RegularExpression]  “#”  Flags[RegularExpression];
[PrimaryExpression  ReservedNamespace] do
return Eval[ReservedNamespace](env, phase);
[PrimaryExpression  ParenListExpression] do
return Eval[ParenListExpression](env, phase);
[PrimaryExpression  ArrayLiteral] do return Eval[ArrayLiteral](env, phase);
[PrimaryExpression  ObjectLiteral] do return Eval[ObjectLiteral](env, phase);
[PrimaryExpression  FunctionExpression] do
return Eval[FunctionExpression](env, phase)
end proc;
proc Eval[ReservedNamespace] (env: Environment, phase: Phase): Namespace
[ReservedNamespace  public] do return public;
[ReservedNamespace  private] do
c: ClassOpt  getEnclosingClass(env);
note	Validate already ensured that c ≠ none.
return c.privateNamespace
end proc;
Eval[ParenExpression] (env: Environment, phase: Phase): ObjOrRef propagates the call to Eval to nonterminals in the expansion of ParenExpression.
proc Eval[ParenListExpression] (env: Environment, phase: Phase): ObjOrRef
[ParenListExpression  ParenExpression] do return Eval[ParenExpression](env, phase);
[ParenListExpression  ( ListExpressionallowIn , AssignmentExpressionallowIn )] do
Evaluate readReference(Eval[ListExpressionallowIn](env, phase), phase) and ignore its result;
return readReference(Eval[AssignmentExpressionallowIn](env, phase), phase)
end proc;
proc EvalAsList[ParenListExpression] (env: Environment, phase: Phase): Object[]
[ParenListExpression  ParenExpression] do
elt: Object  readReference(Eval[ParenExpression](env, phase), phase);
return [elt];
[ParenListExpression  ( ListExpressionallowIn , AssignmentExpressionallowIn )] do
elts: Object[]  EvalAsList[ListExpressionallowIn](env, phase);
elt: Object  readReference(Eval[AssignmentExpressionallowIn](env, phase), phase);
return elts  [elt]
end proc;
Function Expressions
Syntax
FunctionExpression 
	function FunctionCommon
|	function Identifier FunctionCommon
Validation
F[FunctionExpression]: UninstantiatedFunction;
proc Validate[FunctionExpression] (cxt: Context, env: Environment)
[FunctionExpression  function FunctionCommon] do
kind: StaticFunctionKind  plainFunction;
if not cxt.strict and Plain[FunctionCommon] then kind  uncheckedFunction
end if;
F[FunctionExpression]  ValidateStaticFunction[FunctionCommon](cxt, env, kind);
[FunctionExpression  function Identifier FunctionCommon] do
v: Variable  new Variabletype: Function, value: none, immutable: true, setup: none, initializer: busy;
b: LocalBinding  LocalBindingqname: public::(Name[Identifier]), accesses: readWrite, explicit: false, enumerable: true, content: v;
compileFrame: LocalFrame  new LocalFramelocalBindings: {b};
kind: StaticFunctionKind  plainFunction;
if not cxt.strict and Plain[FunctionCommon] then kind  uncheckedFunction
end if;
F[FunctionExpression]  ValidateStaticFunction[FunctionCommon](cxt, [compileFrame]  env, kind)
end proc;
Setup
proc Setup[FunctionExpression] ()
[FunctionExpression  function FunctionCommon] do
Evaluate Setup[FunctionCommon]() and ignore its result;
[FunctionExpression  function Identifier FunctionCommon] do
Evaluate Setup[FunctionCommon]() and ignore its result
end proc;
Evaluation
proc Eval[FunctionExpression] (env: Environment, phase: Phase): ObjOrRef
[FunctionExpression  function FunctionCommon] do
if phase = compile then
throw a ConstantError exception — a function expression is not a constant expression because it can evaluate to different values
end if;
return instantiateFunction(F[FunctionExpression], env);
[FunctionExpression  function Identifier FunctionCommon] do
if phase = compile then
throw a ConstantError exception — a function expression is not a constant expression because it can evaluate to different values
end if;
v: Variable  new Variabletype: Function, value: none, immutable: true, setup: none, initializer: none;
b: LocalBinding  LocalBindingqname: public::(Name[Identifier]), accesses: readWrite, explicit: false, enumerable: true, content: v;
runtimeFrame: LocalFrame  new LocalFramelocalBindings: {b};
f: SimpleInstance  instantiateFunction(F[FunctionExpression], [runtimeFrame]  env);
v.value  f;
return f
end proc;
Object Literals
Syntax
ObjectLiteral  { FieldList }
FieldList 
	«empty»
|	NonemptyFieldList
NonemptyFieldList 
	LiteralField
|	LiteralField , NonemptyFieldList
LiteralField  FieldName : AssignmentExpressionallowIn
FieldName 
	QualifiedIdentifier
|	String
|	Number
|	ParenExpression
Validation
Validate[ObjectLiteral] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ObjectLiteral.
Validate[FieldList] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of FieldList.
Validate[NonemptyFieldList] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of NonemptyFieldList.
Validate[LiteralField] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of LiteralField.
Validate[FieldName] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of FieldName.
Setup
Setup[ObjectLiteral] () propagates the call to Setup to nonterminals in the expansion of ObjectLiteral.
Setup[FieldList] () propagates the call to Setup to nonterminals in the expansion of FieldList.
Setup[NonemptyFieldList] () propagates the call to Setup to nonterminals in the expansion of NonemptyFieldList.
Setup[LiteralField] () propagates the call to Setup to nonterminals in the expansion of LiteralField.
Setup[FieldName] () propagates the call to Setup to nonterminals in the expansion of FieldName.
Evaluation
proc Eval[ObjectLiteral  { FieldList }] (env: Environment, phase: Phase): ObjOrRef
if phase = compile then
throw a ConstantError exception — an object literal is not a constant expression because it evaluates to a new object each time it is evaluated
end if;
o: Object  construct(Object, [], phase);
Evaluate Eval[FieldList](env, o, phase) and ignore its result;
return o
end proc;
Eval[FieldList] (env: Environment, o: Object, phase: {run}) propagates the call to Eval to nonterminals in the expansion of FieldList.
Eval[NonemptyFieldList] (env: Environment, o: Object, phase: {run}) propagates the call to Eval to nonterminals in the expansion of NonemptyFieldList.
proc Eval[LiteralField  FieldName : AssignmentExpressionallowIn] (env: Environment, o: Object, phase: {run})
multiname: Multiname  Eval[FieldName](env, phase);
value: Object  readReference(Eval[AssignmentExpressionallowIn](env, phase), phase);
Evaluate dotWrite(o, multiname, value, phase) and ignore its result
end proc;
proc Eval[FieldName] (env: Environment, phase: Phase): Multiname
[FieldName  QualifiedIdentifier] do return Eval[QualifiedIdentifier](env, phase);
[FieldName  String] do return {objectToQualifiedName(Value[String], phase)};
[FieldName  Number] do return {objectToQualifiedName(Value[Number], phase)};
[FieldName  ParenExpression] do
a: Object  readReference(Eval[ParenExpression](env, phase), phase);
return {objectToQualifiedName(a, phase)}
end proc;
Array Literals
Syntax
ArrayLiteral  [ ElementList ]
ElementList 
	«empty»
|	LiteralElement
|	, ElementList
|	LiteralElement , ElementList
LiteralElement  AssignmentExpressionallowIn
Validation
Validate[ArrayLiteral] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ArrayLiteral.
Validate[ElementList] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ElementList.
Validate[LiteralElement] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of LiteralElement.
Setup
Setup[ArrayLiteral] () propagates the call to Setup to nonterminals in the expansion of ArrayLiteral.
Setup[ElementList] () propagates the call to Setup to nonterminals in the expansion of ElementList.
Setup[LiteralElement] () propagates the call to Setup to nonterminals in the expansion of LiteralElement.
Evaluation
proc Eval[ArrayLiteral  [ ElementList ]] (env: Environment, phase: Phase): ObjOrRef
if phase = compile then
throw a ConstantError exception — an array literal is not a constant expression because it evaluates to a new object each time it is evaluated
end if;
o: Object  construct(Array, [], phase);
length: Integer  Eval[ElementList](env, 0, o, phase);
Evaluate writeArrayPrivateLength(o, length, phase) and ignore its result;
return o
end proc;
proc Eval[ElementList] (env: Environment, length: Integer, o: Object, phase: {run}): Integer
[ElementList  «empty»] do return length;
[ElementList  LiteralElement] do
Evaluate Eval[LiteralElement](env, length, o, phase) and ignore its result;
return length + 1;
[ElementList0  , ElementList1] do
return Eval[ElementList1](env, length + 1, o, phase);
[ElementList0  LiteralElement , ElementList1] do
Evaluate Eval[LiteralElement](env, length, o, phase) and ignore its result;
return Eval[ElementList1](env, length + 1, o, phase)
end proc;
proc Eval[LiteralElement  AssignmentExpressionallowIn] (env: Environment, length: Integer, o: Object, phase: {run})
value: Object  readReference(Eval[AssignmentExpressionallowIn](env, phase), phase);
Evaluate indexWrite(o, length, value, phase) and ignore its result
end proc;
Super Expressions
Syntax
SuperExpression 
	super
|	super ParenExpression
Validation
proc Validate[SuperExpression] (cxt: Context, env: Environment)
[SuperExpression  super] do
c: ClassOpt  getEnclosingClass(env);
if c = none then
throw a SyntaxError exception — a super expression is meaningful only inside a class
end if;
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
if frame = none or frame.kind  StaticFunctionKind then
throw a SyntaxError exception — a super expression without an argument is meaningful only inside an instance method or a constructor
end if;
if c.super = none then
throw a SyntaxError exception — a super expression is meaningful only if the enclosing class has a superclass
end if;
[SuperExpression  super ParenExpression] do
c: ClassOpt  getEnclosingClass(env);
if c = none then
throw a SyntaxError exception — a super expression is meaningful only inside a class
end if;
if c.super = none then
throw a SyntaxError exception — a super expression is meaningful only if the enclosing class has a superclass
end if;
Evaluate Validate[ParenExpression](cxt, env) and ignore its result
end proc;
Setup
Setup[SuperExpression] () propagates the call to Setup to nonterminals in the expansion of SuperExpression.
Evaluation
proc Eval[SuperExpression] (env: Environment, phase: Phase): ObjOptionalLimit
[SuperExpression  super] do
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
note	Validate ensured that frame ≠ none and frame.kind  StaticFunctionKind at this point.
this: ObjectOpt  frame.this;
if this = none then
note	If Validate passed, this can be uninitialised only when phase = compile.
throw a ConstantError exception — a constant expression cannot read an uninitialised this parameter
end if;
if not frame.superconstructorCalled then
throw an UninitializedError exception — can’t access super from within a constructor before the superconstructor has been called
end if;
return makeLimitedInstance(this, getEnclosingClass(env), phase);
[SuperExpression  super ParenExpression] do
r: ObjOrRef  Eval[ParenExpression](env, phase);
return makeLimitedInstance(r, getEnclosingClass(env), phase)
end proc;
proc makeLimitedInstance(r: ObjOrRef, c: Class, phase: Phase): ObjOptionalLimit
o: Object  readReference(r, phase);
limit: ClassOpt  c.super;
note	Validate ensured that limit cannot be none at this point.
coerced: Object  coerce(o, limit);
if coerced = null then return null end if;
return LimitedInstanceinstance: coerced, limit: limit
end proc;
Postfix Expressions
Syntax
PostfixExpression 
	AttributeExpression
|	FullPostfixExpression
|	ShortNewExpression
AttributeExpression 
	SimpleQualifiedIdentifier
|	AttributeExpression PropertyOperator
|	AttributeExpression Arguments
FullPostfixExpression 
	PrimaryExpression
|	ExpressionQualifiedIdentifier
|	FullNewExpression
|	FullPostfixExpression PropertyOperator
|	SuperExpression PropertyOperator
|	FullPostfixExpression Arguments
|	PostfixExpression [no line break] ++
|	PostfixExpression [no line break] --
FullNewExpression  new FullNewSubexpression Arguments
FullNewSubexpression 
	PrimaryExpression
|	QualifiedIdentifier
|	FullNewExpression
|	FullNewSubexpression PropertyOperator
|	SuperExpression PropertyOperator
ShortNewExpression  new ShortNewSubexpression
ShortNewSubexpression 
	FullNewSubexpression
|	ShortNewExpression
Validation
Validate[PostfixExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of PostfixExpression.
Validate[AttributeExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of AttributeExpression.
Validate[FullPostfixExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of FullPostfixExpression.
Validate[FullNewExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of FullNewExpression.
Validate[FullNewSubexpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of FullNewSubexpression.
Validate[ShortNewExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ShortNewExpression.
Validate[ShortNewSubexpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ShortNewSubexpression.
Setup
Setup[PostfixExpression] () propagates the call to Setup to nonterminals in the expansion of PostfixExpression.
Setup[AttributeExpression] () propagates the call to Setup to nonterminals in the expansion of AttributeExpression.
Setup[FullPostfixExpression] () propagates the call to Setup to nonterminals in the expansion of FullPostfixExpression.
Setup[FullNewExpression] () propagates the call to Setup to nonterminals in the expansion of FullNewExpression.
Setup[FullNewSubexpression] () propagates the call to Setup to nonterminals in the expansion of FullNewSubexpression.
Setup[ShortNewExpression] () propagates the call to Setup to nonterminals in the expansion of ShortNewExpression.
Setup[ShortNewSubexpression] () propagates the call to Setup to nonterminals in the expansion of ShortNewSubexpression.
Evaluation
Eval[PostfixExpression] (env: Environment, phase: Phase): ObjOrRef propagates the call to Eval to nonterminals in the expansion of PostfixExpression.
proc Eval[AttributeExpression] (env: Environment, phase: Phase): ObjOrRef
[AttributeExpression  SimpleQualifiedIdentifier] do
m: Multiname  Eval[SimpleQualifiedIdentifier](env, phase);
return LexicalReferenceenv: env, variableMultiname: m, strict: Strict[SimpleQualifiedIdentifier];
[AttributeExpression0  AttributeExpression1 PropertyOperator] do
a: Object  readReference(Eval[AttributeExpression1](env, phase), phase);
return Eval[PropertyOperator](env, a, phase);
[AttributeExpression0  AttributeExpression1 Arguments] do
r: ObjOrRef  Eval[AttributeExpression1](env, phase);
f: Object  readReference(r, phase);
base: Object;
case r of
Object  LexicalReference do base  null;
DotReference  BracketReference do base  r.base
end case;
args: Object[]  Eval[Arguments](env, phase);
return call(base, f, args, phase)
end proc;
proc Eval[FullPostfixExpression] (env: Environment, phase: Phase): ObjOrRef
[FullPostfixExpression  PrimaryExpression] do
return Eval[PrimaryExpression](env, phase);
[FullPostfixExpression  ExpressionQualifiedIdentifier] do
m: Multiname  Eval[ExpressionQualifiedIdentifier](env, phase);
return LexicalReferenceenv: env, variableMultiname: m, strict: Strict[ExpressionQualifiedIdentifier];
[FullPostfixExpression  FullNewExpression] do
return Eval[FullNewExpression](env, phase);
[FullPostfixExpression0  FullPostfixExpression1 PropertyOperator] do
a: Object  readReference(Eval[FullPostfixExpression1](env, phase), phase);
return Eval[PropertyOperator](env, a, phase);
[FullPostfixExpression  SuperExpression PropertyOperator] do
a: ObjOptionalLimit  Eval[SuperExpression](env, phase);
return Eval[PropertyOperator](env, a, phase);
[FullPostfixExpression0  FullPostfixExpression1 Arguments] do
r: ObjOrRef  Eval[FullPostfixExpression1](env, phase);
f: Object  readReference(r, phase);
base: Object;
case r of
Object  LexicalReference do base  null;
DotReference  BracketReference do base  r.base
end case;
args: Object[]  Eval[Arguments](env, phase);
return call(base, f, args, phase);
[FullPostfixExpression  PostfixExpression [no line break] ++] do
if phase = compile then
throw a ConstantError exception — ++ cannot be used in a constant expression
end if;
r: ObjOrRef  Eval[PostfixExpression](env, phase);
a: Object  readReference(r, phase);
b: Object  plus(a, phase);
c: Object  add(b, 1f64, phase);
Evaluate writeReference(r, c, phase) and ignore its result;
return b;
[FullPostfixExpression  PostfixExpression [no line break] --] do
if phase = compile then
throw a ConstantError exception — -- cannot be used in a constant expression
end if;
r: ObjOrRef  Eval[PostfixExpression](env, phase);
a: Object  readReference(r, phase);
b: Object  plus(a, phase);
c: Object  subtract(b, 1f64, phase);
Evaluate writeReference(r, c, phase) and ignore its result;
return b
end proc;
proc Eval[FullNewExpression  new FullNewSubexpression Arguments] (env: Environment, phase: Phase): ObjOrRef
f: Object  readReference(Eval[FullNewSubexpression](env, phase), phase);
args: Object[]  Eval[Arguments](env, phase);
return construct(f, args, phase)
end proc;
proc Eval[FullNewSubexpression] (env: Environment, phase: Phase): ObjOrRef
[FullNewSubexpression  PrimaryExpression] do
return Eval[PrimaryExpression](env, phase);
[FullNewSubexpression  QualifiedIdentifier] do
m: Multiname  Eval[QualifiedIdentifier](env, phase);
return LexicalReferenceenv: env, variableMultiname: m, strict: Strict[QualifiedIdentifier];
[FullNewSubexpression  FullNewExpression] do
return Eval[FullNewExpression](env, phase);
[FullNewSubexpression0  FullNewSubexpression1 PropertyOperator] do
a: Object  readReference(Eval[FullNewSubexpression1](env, phase), phase);
return Eval[PropertyOperator](env, a, phase);
[FullNewSubexpression  SuperExpression PropertyOperator] do
a: ObjOptionalLimit  Eval[SuperExpression](env, phase);
return Eval[PropertyOperator](env, a, phase)
end proc;
proc Eval[ShortNewExpression  new ShortNewSubexpression] (env: Environment, phase: Phase): ObjOrRef
f: Object  readReference(Eval[ShortNewSubexpression](env, phase), phase);
return construct(f, [], phase)
end proc;
Eval[ShortNewSubexpression] (env: Environment, phase: Phase): ObjOrRef propagates the call to Eval to nonterminals in the expansion of ShortNewSubexpression.
Property Operators
Syntax
PropertyOperator 
	. QualifiedIdentifier
|	Brackets
Brackets 
	[ ]
|	[ ListExpressionallowIn ]
|	[ ExpressionsWithRest ]
Arguments 
	( )
|	ParenListExpression
|	( ExpressionsWithRest )
ExpressionsWithRest 
	RestExpression
|	ListExpressionallowIn , RestExpression
RestExpression  ... AssignmentExpressionallowIn
Validation
Validate[PropertyOperator] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of PropertyOperator.
Validate[Brackets] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of Brackets.
Validate[Arguments] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of Arguments.
Validate[ExpressionsWithRest] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ExpressionsWithRest.
Validate[RestExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of RestExpression.
Setup
Setup[PropertyOperator] () propagates the call to Setup to nonterminals in the expansion of PropertyOperator.
Setup[Brackets] () propagates the call to Setup to nonterminals in the expansion of Brackets.
Setup[Arguments] () propagates the call to Setup to nonterminals in the expansion of Arguments.
Setup[ExpressionsWithRest] () propagates the call to Setup to nonterminals in the expansion of ExpressionsWithRest.
Setup[RestExpression] () propagates the call to Setup to nonterminals in the expansion of RestExpression.
Evaluation
proc Eval[PropertyOperator] (env: Environment, base: ObjOptionalLimit, phase: Phase): ObjOrRef
[PropertyOperator  . QualifiedIdentifier] do
m: Multiname  Eval[QualifiedIdentifier](env, phase);
case base of
Object do
return DotReferencebase: base, limit: objectType(base), multiname: m;
LimitedInstance do
return DotReferencebase: base.instance, limit: base.limit, multiname: m
end case;
[PropertyOperator  Brackets] do
args: Object[]  Eval[Brackets](env, phase);
case base of
Object do
return BracketReferencebase: base, limit: objectType(base), args: args;
LimitedInstance do
return BracketReferencebase: base.instance, limit: base.limit, args: args
end case
end proc;
proc Eval[Brackets] (env: Environment, phase: Phase): Object[]
[Brackets  [ ]] do return [];
[Brackets  [ ListExpressionallowIn ]] do
return EvalAsList[ListExpressionallowIn](env, phase);
[Brackets  [ ExpressionsWithRest ]] do return Eval[ExpressionsWithRest](env, phase)
end proc;
proc Eval[Arguments] (env: Environment, phase: Phase): Object[]
[Arguments  ( )] do return [];
[Arguments  ParenListExpression] do
return EvalAsList[ParenListExpression](env, phase);
[Arguments  ( ExpressionsWithRest )] do
return Eval[ExpressionsWithRest](env, phase)
end proc;
proc Eval[ExpressionsWithRest] (env: Environment, phase: Phase): Object[]
[ExpressionsWithRest  RestExpression] do return Eval[RestExpression](env, phase);
[ExpressionsWithRest  ListExpressionallowIn , RestExpression] do
args1: Object[]  EvalAsList[ListExpressionallowIn](env, phase);
args2: Object[]  Eval[RestExpression](env, phase);
return args1  args2
end proc;
proc Eval[RestExpression  ... AssignmentExpressionallowIn] (env: Environment, phase: Phase): Object[]
a: Object  readReference(Eval[AssignmentExpressionallowIn](env, phase), phase);
length: Integer  readLength(a, phase);
i: Integer  0;
args: Object[]  [];
while i ≠ length do
arg: ObjectOpt  indexRead(a, i, phase);
if arg = none then
An implementation may, at its discretion, either throw a ReferenceError or treat the hole as a missing argument, substituting the called function’s default parameter value if there is one, undefined if the called function is unchecked, or throwing an ArgumentError exception otherwise. An implementation must not replace such a hole with undefined except when the called function is unchecked or happens to have undefined as its default parameter value.
end if;
args  args  [arg];
i  i + 1
end while;
return args
end proc;
Unary Operators
Syntax
UnaryExpression 
	PostfixExpression
|	delete PostfixExpression
|	void UnaryExpression
|	typeof UnaryExpression
|	++ PostfixExpression
|	-- PostfixExpression
|	+ UnaryExpression
|	- UnaryExpression
|	- NegatedMinLong
|	~ UnaryExpression
|	! UnaryExpression
Validation
Strict[UnaryExpression]: Boolean;
proc Validate[UnaryExpression] (cxt: Context, env: Environment)
[UnaryExpression  PostfixExpression] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
[UnaryExpression  delete PostfixExpression] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
Strict[UnaryExpression]  cxt.strict;
[UnaryExpression0  void UnaryExpression1] do
Evaluate Validate[UnaryExpression1](cxt, env) and ignore its result;
[UnaryExpression0  typeof UnaryExpression1] do
Evaluate Validate[UnaryExpression1](cxt, env) and ignore its result;
[UnaryExpression  ++ PostfixExpression] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
[UnaryExpression  -- PostfixExpression] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
[UnaryExpression0  + UnaryExpression1] do
Evaluate Validate[UnaryExpression1](cxt, env) and ignore its result;
[UnaryExpression0  - UnaryExpression1] do
Evaluate Validate[UnaryExpression1](cxt, env) and ignore its result;
[UnaryExpression  - NegatedMinLong] do nothing;
[UnaryExpression0  ~ UnaryExpression1] do
Evaluate Validate[UnaryExpression1](cxt, env) and ignore its result;
[UnaryExpression0  ! UnaryExpression1] do
Evaluate Validate[UnaryExpression1](cxt, env) and ignore its result
end proc;
Setup
Setup[UnaryExpression] () propagates the call to Setup to nonterminals in the expansion of UnaryExpression.
Evaluation
proc Eval[UnaryExpression] (env: Environment, phase: Phase): ObjOrRef
[UnaryExpression  PostfixExpression] do return Eval[PostfixExpression](env, phase);
[UnaryExpression  delete PostfixExpression] do
if phase = compile then
throw a ConstantError exception — delete cannot be used in a constant expression
end if;
r: ObjOrRef  Eval[PostfixExpression](env, phase);
return deleteReference(r, Strict[UnaryExpression], phase);
[UnaryExpression0  void UnaryExpression1] do
Evaluate readReference(Eval[UnaryExpression1](env, phase), phase) and ignore its result;
return undefined;
[UnaryExpression0  typeof UnaryExpression1] do
a: Object  readReference(Eval[UnaryExpression1](env, phase), phase);
c: Class  objectType(a);
return c.typeofString;
[UnaryExpression  ++ PostfixExpression] do
if phase = compile then
throw a ConstantError exception — ++ cannot be used in a constant expression
end if;
r: ObjOrRef  Eval[PostfixExpression](env, phase);
a: Object  readReference(r, phase);
b: Object  plus(a, phase);
c: Object  add(b, 1f64, phase);
Evaluate writeReference(r, c, phase) and ignore its result;
return c;
[UnaryExpression  -- PostfixExpression] do
if phase = compile then
throw a ConstantError exception — -- cannot be used in a constant expression
end if;
r: ObjOrRef  Eval[PostfixExpression](env, phase);
a: Object  readReference(r, phase);
b: Object  plus(a, phase);
c: Object  subtract(b, 1f64, phase);
Evaluate writeReference(r, c, phase) and ignore its result;
return c;
[UnaryExpression0  + UnaryExpression1] do
a: Object  readReference(Eval[UnaryExpression1](env, phase), phase);
return plus(a, phase);
[UnaryExpression0  - UnaryExpression1] do
a: Object  readReference(Eval[UnaryExpression1](env, phase), phase);
return minus(a, phase);
[UnaryExpression  - NegatedMinLong] do return (–263)long;
[UnaryExpression0  ~ UnaryExpression1] do
a: Object  readReference(Eval[UnaryExpression1](env, phase), phase);
return bitNot(a, phase);
[UnaryExpression0  ! UnaryExpression1] do
a: Object  readReference(Eval[UnaryExpression1](env, phase), phase);
return logicalNot(a, phase)
end proc;
plus(a, phase) returns the value of the unary expression +a. If phase is compile, only constant operations are permitted.
proc plus(a: Object, phase: Phase): Object
return objectToGeneralNumber(a, phase)
end proc;
minus(a, phase) returns the value of the unary expression -a. If phase is compile, only constant operations are permitted.
proc minus(a: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
return generalNumberNegate(x)
end proc;
proc generalNumberNegate(x: GeneralNumber): GeneralNumber
case x of
Long do return integerToLong(–x.value);
ULong do return integerToULong(–x.value);
Float32 do return float32Negate(x);
Float64 do return float64Negate(x)
end case
end proc;
proc bitNot(a: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
case x of
Long do i: {–263 ... 263 – 1}  x.value; return (bitwiseXor(i, –1))long;
ULong do
i: {0 ... 264 – 1}  x.value;
return (bitwiseXor(i, 0xFFFFFFFFFFFFFFFF))ulong;
Float32  Float64 do
i: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(x));
return (bitwiseXor(i, –1))f64
end case
end proc;
logicalNot(a, phase) returns the value of the unary expression !a. If phase is compile, only constant operations are permitted.
proc logicalNot(a: Object, phase: Phase): Object
return not objectToBoolean(a)
end proc;
Multiplicative Operators
Syntax
MultiplicativeExpression 
	UnaryExpression
|	MultiplicativeExpression * UnaryExpression
|	MultiplicativeExpression / UnaryExpression
|	MultiplicativeExpression % UnaryExpression
Validation
Validate[MultiplicativeExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of MultiplicativeExpression.
Setup
Setup[MultiplicativeExpression] () propagates the call to Setup to nonterminals in the expansion of MultiplicativeExpression.
Evaluation
proc Eval[MultiplicativeExpression] (env: Environment, phase: Phase): ObjOrRef
[MultiplicativeExpression  UnaryExpression] do
return Eval[UnaryExpression](env, phase);
[MultiplicativeExpression0  MultiplicativeExpression1 * UnaryExpression] do
a: Object  readReference(Eval[MultiplicativeExpression1](env, phase), phase);
b: Object  readReference(Eval[UnaryExpression](env, phase), phase);
return multiply(a, b, phase);
[MultiplicativeExpression0  MultiplicativeExpression1 / UnaryExpression] do
a: Object  readReference(Eval[MultiplicativeExpression1](env, phase), phase);
b: Object  readReference(Eval[UnaryExpression](env, phase), phase);
return divide(a, b, phase);
[MultiplicativeExpression0  MultiplicativeExpression1 % UnaryExpression] do
a: Object  readReference(Eval[MultiplicativeExpression1](env, phase), phase);
b: Object  readReference(Eval[UnaryExpression](env, phase), phase);
return remainder(a, b, phase)
end proc;
proc multiply(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: IntegerOpt  checkInteger(x);
j: IntegerOpt  checkInteger(y);
if i ≠ none and j ≠ none then
k: Integer  ij;
if x  ULong or y  ULong then return integerToULong(k)
else return integerToLong(k)
end if
end if
end if;
return float64Multiply(toFloat64(x), toFloat64(y))
end proc;
proc divide(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: IntegerOpt  checkInteger(x);
j: IntegerOpt  checkInteger(y);
if i ≠ none and j ≠ none and j ≠ 0 then
q: Rational  i/j;
if x  ULong or y  ULong then return rationalToULong(q)
else return rationalToLong(q)
end if
end if
end if;
return float64Divide(toFloat64(x), toFloat64(y))
end proc;
proc remainder(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: IntegerOpt  checkInteger(x);
j: IntegerOpt  checkInteger(y);
if i ≠ none and j ≠ none and j ≠ 0 then
q: Rational  i/j;
k: Integer  q ≥ 0 ? q : q;
r: Integer  i – jk;
if x  ULong or y  ULong then return integerToULong(r)
else return integerToLong(r)
end if
end if
end if;
return float64Remainder(toFloat64(x), toFloat64(y))
end proc;
Additive Operators
Syntax
AdditiveExpression 
	MultiplicativeExpression
|	AdditiveExpression + MultiplicativeExpression
|	AdditiveExpression - MultiplicativeExpression
Validation
Validate[AdditiveExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of AdditiveExpression.
Setup
Setup[AdditiveExpression] () propagates the call to Setup to nonterminals in the expansion of AdditiveExpression.
Evaluation
proc Eval[AdditiveExpression] (env: Environment, phase: Phase): ObjOrRef
[AdditiveExpression  MultiplicativeExpression] do
return Eval[MultiplicativeExpression](env, phase);
[AdditiveExpression0  AdditiveExpression1 + MultiplicativeExpression] do
a: Object  readReference(Eval[AdditiveExpression1](env, phase), phase);
b: Object  readReference(Eval[MultiplicativeExpression](env, phase), phase);
return add(a, b, phase);
[AdditiveExpression0  AdditiveExpression1 - MultiplicativeExpression] do
a: Object  readReference(Eval[AdditiveExpression1](env, phase), phase);
b: Object  readReference(Eval[MultiplicativeExpression](env, phase), phase);
return subtract(a, b, phase)
end proc;
proc add(a: Object, b: Object, phase: Phase): Object
ap: PrimitiveObject  objectToPrimitive(a, none, phase);
bp: PrimitiveObject  objectToPrimitive(b, none, phase);
if ap  Char16  String or bp  Char16  String then
return objectToString(ap, phase)  objectToString(bp, phase)
end if;
x: GeneralNumber  objectToGeneralNumber(ap, phase);
y: GeneralNumber  objectToGeneralNumber(bp, phase);
if x  Long  ULong or y  Long  ULong then
i: IntegerOpt  checkInteger(x);
j: IntegerOpt  checkInteger(y);
if i ≠ none and j ≠ none then
k: Integer  i + j;
if x  ULong or y  ULong then return integerToULong(k)
else return integerToLong(k)
end if
end if
end if;
return float64Add(toFloat64(x), toFloat64(y))
end proc;
proc subtract(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: IntegerOpt  checkInteger(x);
j: IntegerOpt  checkInteger(y);
if i ≠ none and j ≠ none then
k: Integer  i – j;
if x  ULong or y  ULong then return integerToULong(k)
else return integerToLong(k)
end if
end if
end if;
return float64Subtract(toFloat64(x), toFloat64(y))
end proc;
Bitwise Shift Operators
Syntax
ShiftExpression 
	AdditiveExpression
|	ShiftExpression << AdditiveExpression
|	ShiftExpression >> AdditiveExpression
|	ShiftExpression >>> AdditiveExpression
Validation
Validate[ShiftExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ShiftExpression.
Setup
Setup[ShiftExpression] () propagates the call to Setup to nonterminals in the expansion of ShiftExpression.
Evaluation
proc Eval[ShiftExpression] (env: Environment, phase: Phase): ObjOrRef
[ShiftExpression  AdditiveExpression] do
return Eval[AdditiveExpression](env, phase);
[ShiftExpression0  ShiftExpression1 << AdditiveExpression] do
a: Object  readReference(Eval[ShiftExpression1](env, phase), phase);
b: Object  readReference(Eval[AdditiveExpression](env, phase), phase);
return shiftLeft(a, b, phase);
[ShiftExpression0  ShiftExpression1 >> AdditiveExpression] do
a: Object  readReference(Eval[ShiftExpression1](env, phase), phase);
b: Object  readReference(Eval[AdditiveExpression](env, phase), phase);
return shiftRight(a, b, phase);
[ShiftExpression0  ShiftExpression1 >>> AdditiveExpression] do
a: Object  readReference(Eval[ShiftExpression1](env, phase), phase);
b: Object  readReference(Eval[AdditiveExpression](env, phase), phase);
return shiftRightUnsigned(a, b, phase)
end proc;
proc shiftLeft(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
count: Integer  truncateToInteger(objectToGeneralNumber(b, phase));
case x of
Float32  Float64 do
count  bitwiseAnd(count, 0x1F);
i: {–231 ... 231 – 1}  signedWrap32(bitwiseShift(truncateToInteger(x), count));
return if64;
Long do
count  bitwiseAnd(count, 0x3F);
i: {–263 ... 263 – 1}  signedWrap64(bitwiseShift(x.value, count));
return ilong;
ULong do
count  bitwiseAnd(count, 0x3F);
i: {0 ... 264 – 1}  unsignedWrap64(bitwiseShift(x.value, count));
return iulong
end case
end proc;
proc shiftRight(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
count: Integer  truncateToInteger(objectToGeneralNumber(b, phase));
case x of
Float32  Float64 do
i: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(x));
count  bitwiseAnd(count, 0x1F);
i  bitwiseShift(i, –count);
return if64;
Long do
count  bitwiseAnd(count, 0x3F);
i: {–263 ... 263 – 1}  bitwiseShift(x.value, –count);
return ilong;
ULong do
count  bitwiseAnd(count, 0x3F);
i: {–263 ... 263 – 1}  bitwiseShift(signedWrap64(x.value), –count);
return (unsignedWrap64(i))ulong
end case
end proc;
proc shiftRightUnsigned(a: Object, b: Object, phase: Phase): Object
x: GeneralNumber  objectToGeneralNumber(a, phase);
count: Integer  truncateToInteger(objectToGeneralNumber(b, phase));
case x of
Float32  Float64 do
i: {0 ... 232 – 1}  unsignedWrap32(truncateToInteger(x));
count  bitwiseAnd(count, 0x1F);
i  bitwiseShift(i, –count);
return if64;
Long do
count  bitwiseAnd(count, 0x3F);
i: {0 ... 264 – 1}  bitwiseShift(unsignedWrap64(x.value), –count);
return (signedWrap64(i))long;
ULong do
count  bitwiseAnd(count, 0x3F);
i: {0 ... 264 – 1}  bitwiseShift(x.value, –count);
return iulong
end case
end proc;
Relational Operators
Syntax
RelationalExpressionallowIn 
	ShiftExpression
|	RelationalExpressionallowIn < ShiftExpression
|	RelationalExpressionallowIn > ShiftExpression
|	RelationalExpressionallowIn <= ShiftExpression
|	RelationalExpressionallowIn >= ShiftExpression
|	RelationalExpressionallowIn is ShiftExpression
|	RelationalExpressionallowIn as ShiftExpression
|	RelationalExpressionallowIn in ShiftExpression
|	RelationalExpressionallowIn instanceof ShiftExpression
RelationalExpressionnoIn 
	ShiftExpression
|	RelationalExpressionnoIn < ShiftExpression
|	RelationalExpressionnoIn > ShiftExpression
|	RelationalExpressionnoIn <= ShiftExpression
|	RelationalExpressionnoIn >= ShiftExpression
|	RelationalExpressionnoIn is ShiftExpression
|	RelationalExpressionnoIn as ShiftExpression
|	RelationalExpressionnoIn instanceof ShiftExpression
Validation
Validate[RelationalExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of RelationalExpression.
Setup
Setup[RelationalExpression] () propagates the call to Setup to nonterminals in the expansion of RelationalExpression.
Evaluation
proc Eval[RelationalExpression] (env: Environment, phase: Phase): ObjOrRef
[RelationalExpression  ShiftExpression] do
return Eval[ShiftExpression](env, phase);
[RelationalExpression0  RelationalExpression1 < ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
return isLess(a, b, phase);
[RelationalExpression0  RelationalExpression1 > ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
return isLess(b, a, phase);
[RelationalExpression0  RelationalExpression1 <= ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
return isLessOrEqual(a, b, phase);
[RelationalExpression0  RelationalExpression1 >= ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
return isLessOrEqual(b, a, phase);
[RelationalExpression0  RelationalExpression1 is ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
c: Class  objectToClass(b);
return is(a, c);
[RelationalExpression0  RelationalExpression1 as ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
c: Class  objectToClass(b);
return coerceOrNull(a, c);
[RelationalExpressionallowIn0  RelationalExpressionallowIn1 in ShiftExpression] do
a: Object  readReference(Eval[RelationalExpressionallowIn1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
return hasProperty(b, a, false, phase);
[RelationalExpression0  RelationalExpression1 instanceof ShiftExpression] do
a: Object  readReference(Eval[RelationalExpression1](env, phase), phase);
b: Object  readReference(Eval[ShiftExpression](env, phase), phase);
if b  Class then return is(a, b)
elsif is(b, PrototypeFunction) then
prototype: Object  dotRead(b, {public::“prototype”}, phase);
return prototype  archetypes(a)
else throw a TypeError exception
end if
end proc;
proc isLess(a: Object, b: Object, phase: Phase): Boolean
ap: PrimitiveObject  objectToPrimitive(a, hintNumber, phase);
bp: PrimitiveObject  objectToPrimitive(b, hintNumber, phase);
if ap  Char16  String and bp  Char16  String then
return toString(ap) < toString(bp)
end if;
return generalNumberCompare(objectToGeneralNumber(ap, phase), objectToGeneralNumber(bp, phase)) = less
end proc;
proc isLessOrEqual(a: Object, b: Object, phase: Phase): Boolean
ap: PrimitiveObject  objectToPrimitive(a, hintNumber, phase);
bp: PrimitiveObject  objectToPrimitive(b, hintNumber, phase);
if ap  Char16  String and bp  Char16  String then
return toString(ap) ≤ toString(bp)
end if;
return generalNumberCompare(objectToGeneralNumber(ap, phase), objectToGeneralNumber(bp, phase))  {less, equal}
end proc;
Equality Operators
Syntax
EqualityExpression 
	RelationalExpression
|	EqualityExpression == RelationalExpression
|	EqualityExpression != RelationalExpression
|	EqualityExpression === RelationalExpression
|	EqualityExpression !== RelationalExpression
Validation
Validate[EqualityExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of EqualityExpression.
Setup
Setup[EqualityExpression] () propagates the call to Setup to nonterminals in the expansion of EqualityExpression.
Evaluation
proc Eval[EqualityExpression] (env: Environment, phase: Phase): ObjOrRef
[EqualityExpression  RelationalExpression] do
return Eval[RelationalExpression](env, phase);
[EqualityExpression0  EqualityExpression1 == RelationalExpression] do
a: Object  readReference(Eval[EqualityExpression1](env, phase), phase);
b: Object  readReference(Eval[RelationalExpression](env, phase), phase);
return isEqual(a, b, phase);
[EqualityExpression0  EqualityExpression1 != RelationalExpression] do
a: Object  readReference(Eval[EqualityExpression1](env, phase), phase);
b: Object  readReference(Eval[RelationalExpression](env, phase), phase);
return not isEqual(a, b, phase);
[EqualityExpression0  EqualityExpression1 === RelationalExpression] do
a: Object  readReference(Eval[EqualityExpression1](env, phase), phase);
b: Object  readReference(Eval[RelationalExpression](env, phase), phase);
return isStrictlyEqual(a, b, phase);
[EqualityExpression0  EqualityExpression1 !== RelationalExpression] do
a: Object  readReference(Eval[EqualityExpression1](env, phase), phase);
b: Object  readReference(Eval[RelationalExpression](env, phase), phase);
return not isStrictlyEqual(a, b, phase)
end proc;
proc isEqual(a: Object, b: Object, phase: Phase): Boolean
case a of
Undefined  Null do return b  Undefined  Null;
Boolean do
if b  Boolean then return a = b
else return isEqual(objectToGeneralNumber(a, phase), b, phase)
end if;
GeneralNumber do
bp: PrimitiveObject  objectToPrimitive(b, none, phase);
case bp of
Undefined  Null do return false;
Boolean  GeneralNumber  Char16  String do
return generalNumberCompare(a, objectToGeneralNumber(bp, phase)) = equal
end case;
Char16  String do
bp: PrimitiveObject  objectToPrimitive(b, none, phase);
case bp of
Undefined  Null do return false;
Boolean  GeneralNumber do
return generalNumberCompare(objectToGeneralNumber(a, phase), objectToGeneralNumber(bp, phase)) = equal;
Char16  String do return toString(a) = toString(bp)
end case;
Namespace  CompoundAttribute  Class  MethodClosure  SimpleInstance  Date  RegExp  Package do
case b of
Undefined  Null do return false;
Namespace  CompoundAttribute  Class  MethodClosure  SimpleInstance  Date  RegExp  Package do
return isStrictlyEqual(a, b, phase);
Boolean  GeneralNumber  Char16  String do
ap: PrimitiveObject  objectToPrimitive(a, none, phase);
return isEqual(ap, b, phase)
end case
end case
end proc;
proc isStrictlyEqual(a: Object, b: Object, phase: Phase): Boolean
if a  GeneralNumber and b  GeneralNumber then
return generalNumberCompare(a, b) = equal
else return a = b
end if
end proc;
Binary Bitwise Operators
Syntax
BitwiseAndExpression 
	EqualityExpression
|	BitwiseAndExpression & EqualityExpression
BitwiseXorExpression 
	BitwiseAndExpression
|	BitwiseXorExpression ^ BitwiseAndExpression
BitwiseOrExpression 
	BitwiseXorExpression
|	BitwiseOrExpression | BitwiseXorExpression
Validation
Validate[BitwiseAndExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of BitwiseAndExpression.
Validate[BitwiseXorExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of BitwiseXorExpression.
Validate[BitwiseOrExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of BitwiseOrExpression.
Setup
Setup[BitwiseAndExpression] () propagates the call to Setup to nonterminals in the expansion of BitwiseAndExpression.
Setup[BitwiseXorExpression] () propagates the call to Setup to nonterminals in the expansion of BitwiseXorExpression.
Setup[BitwiseOrExpression] () propagates the call to Setup to nonterminals in the expansion of BitwiseOrExpression.
Evaluation
proc Eval[BitwiseAndExpression] (env: Environment, phase: Phase): ObjOrRef
[BitwiseAndExpression  EqualityExpression] do
return Eval[EqualityExpression](env, phase);
[BitwiseAndExpression0  BitwiseAndExpression1 & EqualityExpression] do
a: Object  readReference(Eval[BitwiseAndExpression1](env, phase), phase);
b: Object  readReference(Eval[EqualityExpression](env, phase), phase);
return bitAnd(a, b, phase)
end proc;
proc Eval[BitwiseXorExpression] (env: Environment, phase: Phase): ObjOrRef
[BitwiseXorExpression  BitwiseAndExpression] do
return Eval[BitwiseAndExpression](env, phase);
[BitwiseXorExpression0  BitwiseXorExpression1 ^ BitwiseAndExpression] do
a: Object  readReference(Eval[BitwiseXorExpression1](env, phase), phase);
b: Object  readReference(Eval[BitwiseAndExpression](env, phase), phase);
return bitXor(a, b, phase)
end proc;
proc Eval[BitwiseOrExpression] (env: Environment, phase: Phase): ObjOrRef
[BitwiseOrExpression  BitwiseXorExpression] do
return Eval[BitwiseXorExpression](env, phase);
[BitwiseOrExpression0  BitwiseOrExpression1 | BitwiseXorExpression] do
a: Object  readReference(Eval[BitwiseOrExpression1](env, phase), phase);
b: Object  readReference(Eval[BitwiseXorExpression](env, phase), phase);
return bitOr(a, b, phase)
end proc;
proc bitAnd(a: Object, b: Object, phase: Phase): GeneralNumber
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: {–263 ... 263 – 1}  signedWrap64(truncateToInteger(x));
j: {–263 ... 263 – 1}  signedWrap64(truncateToInteger(y));
k: {–263 ... 263 – 1}  bitwiseAnd(i, j);
if x  ULong or y  ULong then return (unsignedWrap64(k))ulong
else return klong
end if
else
i: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(x));
j: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(y));
return (bitwiseAnd(i, j))f64
end if
end proc;
proc bitXor(a: Object, b: Object, phase: Phase): GeneralNumber
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: {–263 ... 263 – 1}  signedWrap64(truncateToInteger(x));
j: {–263 ... 263 – 1}  signedWrap64(truncateToInteger(y));
k: {–263 ... 263 – 1}  bitwiseXor(i, j);
if x  ULong or y  ULong then return (unsignedWrap64(k))ulong
else return klong
end if
else
i: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(x));
j: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(y));
return (bitwiseXor(i, j))f64
end if
end proc;
proc bitOr(a: Object, b: Object, phase: Phase): GeneralNumber
x: GeneralNumber  objectToGeneralNumber(a, phase);
y: GeneralNumber  objectToGeneralNumber(b, phase);
if x  Long  ULong or y  Long  ULong then
i: {–263 ... 263 – 1}  signedWrap64(truncateToInteger(x));
j: {–263 ... 263 – 1}  signedWrap64(truncateToInteger(y));
k: {–263 ... 263 – 1}  bitwiseOr(i, j);
if x  ULong or y  ULong then return (unsignedWrap64(k))ulong
else return klong
end if
else
i: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(x));
j: {–231 ... 231 – 1}  signedWrap32(truncateToInteger(y));
return (bitwiseOr(i, j))f64
end if
end proc;
Binary Logical Operators
Syntax
LogicalAndExpression 
	BitwiseOrExpression
|	LogicalAndExpression && BitwiseOrExpression
LogicalXorExpression 
	LogicalAndExpression
|	LogicalXorExpression ^^ LogicalAndExpression
LogicalOrExpression 
	LogicalXorExpression
|	LogicalOrExpression || LogicalXorExpression
Validation
Validate[LogicalAndExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of LogicalAndExpression.
Validate[LogicalXorExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of LogicalXorExpression.
Validate[LogicalOrExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of LogicalOrExpression.
Setup
Setup[LogicalAndExpression] () propagates the call to Setup to nonterminals in the expansion of LogicalAndExpression.
Setup[LogicalXorExpression] () propagates the call to Setup to nonterminals in the expansion of LogicalXorExpression.
Setup[LogicalOrExpression] () propagates the call to Setup to nonterminals in the expansion of LogicalOrExpression.
Evaluation
proc Eval[LogicalAndExpression] (env: Environment, phase: Phase): ObjOrRef
[LogicalAndExpression  BitwiseOrExpression] do
return Eval[BitwiseOrExpression](env, phase);
[LogicalAndExpression0  LogicalAndExpression1 && BitwiseOrExpression] do
a: Object  readReference(Eval[LogicalAndExpression1](env, phase), phase);
if objectToBoolean(a) then
return readReference(Eval[BitwiseOrExpression](env, phase), phase)
else return a
end if
end proc;
proc Eval[LogicalXorExpression] (env: Environment, phase: Phase): ObjOrRef
[LogicalXorExpression  LogicalAndExpression] do
return Eval[LogicalAndExpression](env, phase);
[LogicalXorExpression0  LogicalXorExpression1 ^^ LogicalAndExpression] do
a: Object  readReference(Eval[LogicalXorExpression1](env, phase), phase);
b: Object  readReference(Eval[LogicalAndExpression](env, phase), phase);
ba: Boolean  objectToBoolean(a);
bb: Boolean  objectToBoolean(b);
return ba xor bb
end proc;
proc Eval[LogicalOrExpression] (env: Environment, phase: Phase): ObjOrRef
[LogicalOrExpression  LogicalXorExpression] do
return Eval[LogicalXorExpression](env, phase);
[LogicalOrExpression0  LogicalOrExpression1 || LogicalXorExpression] do
a: Object  readReference(Eval[LogicalOrExpression1](env, phase), phase);
if objectToBoolean(a) then return a
else return readReference(Eval[LogicalXorExpression](env, phase), phase)
end if
end proc;
Conditional Operator
Syntax
ConditionalExpression 
	LogicalOrExpression
|	LogicalOrExpression ? AssignmentExpression : AssignmentExpression
NonAssignmentExpression 
	LogicalOrExpression
|	LogicalOrExpression ? NonAssignmentExpression : NonAssignmentExpression
Validation
Validate[ConditionalExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ConditionalExpression.
Validate[NonAssignmentExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of NonAssignmentExpression.
Setup
Setup[ConditionalExpression] () propagates the call to Setup to nonterminals in the expansion of ConditionalExpression.
Setup[NonAssignmentExpression] () propagates the call to Setup to nonterminals in the expansion of NonAssignmentExpression.
Evaluation
proc Eval[ConditionalExpression] (env: Environment, phase: Phase): ObjOrRef
[ConditionalExpression  LogicalOrExpression] do
return Eval[LogicalOrExpression](env, phase);
[ConditionalExpression  LogicalOrExpression ? AssignmentExpression1 : AssignmentExpression2] do
a: Object  readReference(Eval[LogicalOrExpression](env, phase), phase);
if objectToBoolean(a) then
return readReference(Eval[AssignmentExpression1](env, phase), phase)
else return readReference(Eval[AssignmentExpression2](env, phase), phase)
end if
end proc;
proc Eval[NonAssignmentExpression] (env: Environment, phase: Phase): ObjOrRef
[NonAssignmentExpression  LogicalOrExpression] do
return Eval[LogicalOrExpression](env, phase);
[NonAssignmentExpression0  LogicalOrExpression ? NonAssignmentExpression1 : NonAssignmentExpression2] do
a: Object  readReference(Eval[LogicalOrExpression](env, phase), phase);
if objectToBoolean(a) then
return readReference(Eval[NonAssignmentExpression1](env, phase), phase)
else return readReference(Eval[NonAssignmentExpression2](env, phase), phase)
end if
end proc;
Assignment Operators
Syntax
AssignmentExpression 
	ConditionalExpression
|	PostfixExpression = AssignmentExpression
|	PostfixExpression CompoundAssignment AssignmentExpression
|	PostfixExpression LogicalAssignment AssignmentExpression
CompoundAssignment 
	*=
|	/=
|	%=
|	+=
|	-=
|	<<=
|	>>=
|	>>>=
|	&=
|	^=
|	|=
LogicalAssignment 
	&&=
|	^^=
|	||=
Semantics
tag andEq;
tag xorEq;
tag orEq;
Validation
proc Validate[AssignmentExpression] (cxt: Context, env: Environment)
[AssignmentExpression  ConditionalExpression] do
Evaluate Validate[ConditionalExpression](cxt, env) and ignore its result;
[AssignmentExpression0  PostfixExpression = AssignmentExpression1] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
Evaluate Validate[AssignmentExpression1](cxt, env) and ignore its result;
[AssignmentExpression0  PostfixExpression CompoundAssignment AssignmentExpression1] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
Evaluate Validate[AssignmentExpression1](cxt, env) and ignore its result;
[AssignmentExpression0  PostfixExpression LogicalAssignment AssignmentExpression1] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
Evaluate Validate[AssignmentExpression1](cxt, env) and ignore its result
end proc;
Setup
proc Setup[AssignmentExpression] ()
[AssignmentExpression  ConditionalExpression] do
Evaluate Setup[ConditionalExpression]() and ignore its result;
[AssignmentExpression0  PostfixExpression = AssignmentExpression1] do
Evaluate Setup[PostfixExpression]() and ignore its result;
Evaluate Setup[AssignmentExpression1]() and ignore its result;
[AssignmentExpression0  PostfixExpression CompoundAssignment AssignmentExpression1] do
Evaluate Setup[PostfixExpression]() and ignore its result;
Evaluate Setup[AssignmentExpression1]() and ignore its result;
[AssignmentExpression0  PostfixExpression LogicalAssignment AssignmentExpression1] do
Evaluate Setup[PostfixExpression]() and ignore its result;
Evaluate Setup[AssignmentExpression1]() and ignore its result
end proc;
Evaluation
proc Eval[AssignmentExpression] (env: Environment, phase: Phase): ObjOrRef
[AssignmentExpression  ConditionalExpression] do
return Eval[ConditionalExpression](env, phase);
[AssignmentExpression0  PostfixExpression = AssignmentExpression1] do
if phase = compile then
throw a ConstantError exception — assignment cannot be used in a constant expression
end if;
ra: ObjOrRef  Eval[PostfixExpression](env, phase);
b: Object  readReference(Eval[AssignmentExpression1](env, phase), phase);
Evaluate writeReference(ra, b, phase) and ignore its result;
return b;
[AssignmentExpression0  PostfixExpression CompoundAssignment AssignmentExpression1] do
if phase = compile then
throw a ConstantError exception — assignment cannot be used in a constant expression
end if;
rLeft: ObjOrRef  Eval[PostfixExpression](env, phase);
oLeft: Object  readReference(rLeft, phase);
oRight: Object  readReference(Eval[AssignmentExpression1](env, phase), phase);
result: Object  Op[CompoundAssignment](oLeft, oRight, phase);
Evaluate writeReference(rLeft, result, phase) and ignore its result;
return result;
[AssignmentExpression0  PostfixExpression LogicalAssignment AssignmentExpression1] do
if phase = compile then
throw a ConstantError exception — assignment cannot be used in a constant expression
end if;
rLeft: ObjOrRef  Eval[PostfixExpression](env, phase);
oLeft: Object  readReference(rLeft, phase);
bLeft: Boolean  objectToBoolean(oLeft);
result: Object  oLeft;
case Operator[LogicalAssignment] of
{andEq} do
if bLeft then
result  readReference(Eval[AssignmentExpression1](env, phase), phase)
end if;
{xorEq} do
bRight: Boolean  objectToBoolean(readReference(Eval[AssignmentExpression1](env, phase), phase));
result  bLeft xor bRight;
{orEq} do
if not bLeft then
result  readReference(Eval[AssignmentExpression1](env, phase), phase)
end if
end case;
Evaluate writeReference(rLeft, result, phase) and ignore its result;
return result
end proc;
Op[CompoundAssignment]: Object  Object  Phase  Object;
Op[CompoundAssignment  *=] = multiply;
Op[CompoundAssignment  /=] = divide;
Op[CompoundAssignment  %=] = remainder;
Op[CompoundAssignment  +=] = add;
Op[CompoundAssignment  -=] = subtract;
Op[CompoundAssignment  <<=] = shiftLeft;
Op[CompoundAssignment  >>=] = shiftRight;
Op[CompoundAssignment  >>>=] = shiftRightUnsigned;
Op[CompoundAssignment  &=] = bitAnd;
Op[CompoundAssignment  ^=] = bitXor;
Op[CompoundAssignment  |=] = bitOr;
Operator[LogicalAssignment]: {andEq, xorEq, orEq};
Operator[LogicalAssignment  &&=] = andEq;
Operator[LogicalAssignment  ^^=] = xorEq;
Operator[LogicalAssignment  ||=] = orEq;
Comma Expressions
Syntax
ListExpression 
	AssignmentExpression
|	ListExpression , AssignmentExpression
Validation
Validate[ListExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ListExpression.
Setup
Setup[ListExpression] () propagates the call to Setup to nonterminals in the expansion of ListExpression.
Evaluation
proc Eval[ListExpression] (env: Environment, phase: Phase): ObjOrRef
[ListExpression  AssignmentExpression] do
return Eval[AssignmentExpression](env, phase);
[ListExpression0  ListExpression1 , AssignmentExpression] do
Evaluate readReference(Eval[ListExpression1](env, phase), phase) and ignore its result;
return readReference(Eval[AssignmentExpression](env, phase), phase)
end proc;
proc EvalAsList[ListExpression] (env: Environment, phase: Phase): Object[]
[ListExpression  AssignmentExpression] do
elt: Object  readReference(Eval[AssignmentExpression](env, phase), phase);
return [elt];
[ListExpression0  ListExpression1 , AssignmentExpression] do
elts: Object[]  EvalAsList[ListExpression1](env, phase);
elt: Object  readReference(Eval[AssignmentExpression](env, phase), phase);
return elts  [elt]
end proc;
Type Expressions
Syntax
TypeExpression  NonAssignmentExpression
Validation
Validate[TypeExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of TypeExpression.
Setup and Evaluation
proc SetupAndEval[TypeExpression  NonAssignmentExpression] (env: Environment): Class
Evaluate Setup[NonAssignmentExpression]() and ignore its result;
o: Object  readReference(Eval[NonAssignmentExpression](env, compile), compile);
return objectToClass(o)
end proc;
Statements
Syntax
  {abbrev, noShortIf, full}
Statement 
	ExpressionStatement Semicolon
|	SuperStatement Semicolon
|	Block
|	LabeledStatement
|	IfStatement
|	SwitchStatement
|	DoStatement Semicolon
|	WhileStatement
|	ForStatement
|	WithStatement
|	ContinueStatement Semicolon
|	BreakStatement Semicolon
|	ReturnStatement Semicolon
|	ThrowStatement Semicolon
|	TryStatement
Substatement 
	EmptyStatement
|	Statement
|	SimpleVariableDefinition Semicolon
|	Attributes [no line break] { Substatements }
Substatements 
	«empty»
|	SubstatementsPrefix Substatementabbrev
SubstatementsPrefix 
	«empty»
|	SubstatementsPrefix Substatementfull
Semicolonabbrev 
	;
|	VirtualSemicolon
|	«empty»
SemicolonnoShortIf 
	;
|	VirtualSemicolon
|	«empty»
Semicolonfull 
	;
|	VirtualSemicolon
Validation
proc Validate[Statement] (cxt: Context, env: Environment, sl: Label{}, jt: JumpTargets, preinst: Boolean)
[Statement  ExpressionStatement Semicolon] do
Evaluate Validate[ExpressionStatement](cxt, env) and ignore its result;
[Statement  SuperStatement Semicolon] do
Evaluate Validate[SuperStatement](cxt, env) and ignore its result;
[Statement  Block] do
Evaluate Validate[Block](cxt, env, jt, preinst) and ignore its result;
[Statement  LabeledStatement] do
Evaluate Validate[LabeledStatement](cxt, env, sl, jt) and ignore its result;
[Statement  IfStatement] do
Evaluate Validate[IfStatement](cxt, env, jt) and ignore its result;
[Statement  SwitchStatement] do
Evaluate Validate[SwitchStatement](cxt, env, jt) and ignore its result;
[Statement  DoStatement Semicolon] do
Evaluate Validate[DoStatement](cxt, env, sl, jt) and ignore its result;
[Statement  WhileStatement] do
Evaluate Validate[WhileStatement](cxt, env, sl, jt) and ignore its result;
[Statement  ForStatement] do
Evaluate Validate[ForStatement](cxt, env, sl, jt) and ignore its result;
[Statement  WithStatement] do
Evaluate Validate[WithStatement](cxt, env, jt) and ignore its result;
[Statement  ContinueStatement Semicolon] do
Evaluate Validate[ContinueStatement](jt) and ignore its result;
[Statement  BreakStatement Semicolon] do
Evaluate Validate[BreakStatement](jt) and ignore its result;
[Statement  ReturnStatement Semicolon] do
Evaluate Validate[ReturnStatement](cxt, env) and ignore its result;
[Statement  ThrowStatement Semicolon] do
Evaluate Validate[ThrowStatement](cxt, env) and ignore its result;
[Statement  TryStatement] do
Evaluate Validate[TryStatement](cxt, env, jt) and ignore its result
end proc;
Enabled[Substatement]: Boolean;
proc Validate[Substatement] (cxt: Context, env: Environment, sl: Label{}, jt: JumpTargets)
[Substatement  EmptyStatement] do nothing;
[Substatement  Statement] do
Evaluate Validate[Statement](cxt, env, sl, jt, false) and ignore its result;
[Substatement  SimpleVariableDefinition Semicolon] do
Evaluate Validate[SimpleVariableDefinition](cxt, env) and ignore its result;
[Substatement  Attributes [no line break] { Substatements }] do
Evaluate Validate[Attributes](cxt, env) and ignore its result;
Evaluate Setup[Attributes]() and ignore its result;
attr: Attribute  Eval[Attributes](env, compile);
if attr  Boolean then
throw a TypeError exception — attributes other than true and false may be used in a statement but not a substatement
end if;
Enabled[Substatement]  attr;
if attr then Evaluate Validate[Substatements](cxt, env, jt) and ignore its result
end if
end proc;
proc Validate[Substatements] (cxt: Context, env: Environment, jt: JumpTargets)
[Substatements  «empty»] do nothing;
[Substatements  SubstatementsPrefix Substatementabbrev] do
Evaluate Validate[SubstatementsPrefix](cxt, env, jt) and ignore its result;
Evaluate Validate[Substatementabbrev](cxt, env, {}, jt) and ignore its result
end proc;
proc Validate[SubstatementsPrefix] (cxt: Context, env: Environment, jt: JumpTargets)
[SubstatementsPrefix  «empty»] do nothing;
[SubstatementsPrefix0  SubstatementsPrefix1 Substatementfull] do
Evaluate Validate[SubstatementsPrefix1](cxt, env, jt) and ignore its result;
Evaluate Validate[Substatementfull](cxt, env, {}, jt) and ignore its result
end proc;
Setup
Setup[Statement] () propagates the call to Setup to nonterminals in the expansion of Statement.
proc Setup[Substatement] ()
[Substatement  EmptyStatement] do nothing;
[Substatement  Statement] do Evaluate Setup[Statement]() and ignore its result;
[Substatement  SimpleVariableDefinition Semicolon] do
Evaluate Setup[SimpleVariableDefinition]() and ignore its result;
[Substatement  Attributes [no line break] { Substatements }] do
if Enabled[Substatement] then
Evaluate Setup[Substatements]() and ignore its result
end if
end proc;
Setup[Substatements] () propagates the call to Setup to nonterminals in the expansion of Substatements.
Setup[SubstatementsPrefix] () propagates the call to Setup to nonterminals in the expansion of SubstatementsPrefix.
proc Setup[Semicolon] ()
[Semicolon  ;] do nothing;
[Semicolon  VirtualSemicolon] do nothing;
[Semicolonabbrev  «empty»] do nothing;
[SemicolonnoShortIf  «empty»] do nothing
end proc;
Evaluation
proc Eval[Statement] (env: Environment, d: Object): Object
[Statement  ExpressionStatement Semicolon] do
return Eval[ExpressionStatement](env);
[Statement  SuperStatement Semicolon] do return Eval[SuperStatement](env);
[Statement  Block] do return Eval[Block](env, d);
[Statement  LabeledStatement] do return Eval[LabeledStatement](env, d);
[Statement  IfStatement] do return Eval[IfStatement](env, d);
[Statement  SwitchStatement] do return Eval[SwitchStatement](env, d);
[Statement  DoStatement Semicolon] do return Eval[DoStatement](env, d);
[Statement  WhileStatement] do return Eval[WhileStatement](env, d);
[Statement  ForStatement] do return Eval[ForStatement](env, d);
[Statement  WithStatement] do return Eval[WithStatement](env, d);
[Statement  ContinueStatement Semicolon] do
return Eval[ContinueStatement](env, d);
[Statement  BreakStatement Semicolon] do return Eval[BreakStatement](env, d);
[Statement  ReturnStatement Semicolon] do return Eval[ReturnStatement](env);
[Statement  ThrowStatement Semicolon] do return Eval[ThrowStatement](env);
[Statement  TryStatement] do return Eval[TryStatement](env, d)
end proc;
proc Eval[Substatement] (env: Environment, d: Object): Object
[Substatement  EmptyStatement] do return d;
[Substatement  Statement] do return Eval[Statement](env, d);
[Substatement  SimpleVariableDefinition Semicolon] do
return Eval[SimpleVariableDefinition](env, d);
[Substatement  Attributes [no line break] { Substatements }] do
if Enabled[Substatement] then return Eval[Substatements](env, d)
else return d
end if
end proc;
proc Eval[Substatements] (env: Environment, d: Object): Object
[Substatements  «empty»] do return d;
[Substatements  SubstatementsPrefix Substatementabbrev] do
o: Object  Eval[SubstatementsPrefix](env, d);
return Eval[Substatementabbrev](env, o)
end proc;
proc Eval[SubstatementsPrefix] (env: Environment, d: Object): Object
[SubstatementsPrefix  «empty»] do return d;
[SubstatementsPrefix0  SubstatementsPrefix1 Substatementfull] do
o: Object  Eval[SubstatementsPrefix1](env, d);
return Eval[Substatementfull](env, o)
end proc;
Empty Statement
Syntax
EmptyStatement  ;
Expression Statement
Syntax
ExpressionStatement  [lookahead{function, {}] ListExpressionallowIn
Validation
Validate[ExpressionStatement] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ExpressionStatement.
Setup
Setup[ExpressionStatement] () propagates the call to Setup to nonterminals in the expansion of ExpressionStatement.
Evaluation
proc Eval[ExpressionStatement  [lookahead{function, {}] ListExpressionallowIn] (env: Environment): Object
return readReference(Eval[ListExpressionallowIn](env, run), run)
end proc;
Super Statement
Syntax
SuperStatement  super Arguments
Validation
proc Validate[SuperStatement  super Arguments] (cxt: Context, env: Environment)
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
if frame = none or frame.kind ≠ constructorFunction then
throw a SyntaxError exception — a super statement is meaningful only inside a constructor
end if;
Evaluate Validate[Arguments](cxt, env) and ignore its result;
frame.callsSuperconstructor  true
end proc;
Setup
Setup[SuperStatement] () propagates the call to Setup to nonterminals in the expansion of SuperStatement.
Evaluation
proc Eval[SuperStatement  super Arguments] (env: Environment): Object
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
note	Validate already ensured that frame ≠ none and frame.kind = constructorFunction.
args: Object[]  Eval[Arguments](env, run);
if frame.superconstructorCalled = true then
throw a ReferenceError exception — the superconstructor cannot be called twice
end if;
c: Class  getEnclosingClass(env);
this: ObjectOpt  frame.this;
note	this  SimpleInstance;
Evaluate callInit(this, c.super, args, run) and ignore its result;
frame.superconstructorCalled  true;
return this
end proc;
Block Statement
Syntax
Block  { Directives }
Validation
CompileFrame[Block]: LocalFrame;
Preinstantiate[Block]: Boolean;
proc ValidateUsingFrame[Block  { Directives }] (cxt: Context, env: Environment, jt: JumpTargets, preinst: Boolean, frame: Frame)
localCxt: Context  new Contextstrict: cxt.strict, openNamespaces: cxt.openNamespaces;
Evaluate Validate[Directives](localCxt, [frame]  env, jt, preinst, none) and ignore its result
end proc;
proc Validate[Block  { Directives }] (cxt: Context, env: Environment, jt: JumpTargets, preinst: Boolean)
compileFrame: LocalFrame  new LocalFramelocalBindings: {};
CompileFrame[Block]  compileFrame;
Preinstantiate[Block]  preinst;
Evaluate ValidateUsingFrame[Block](cxt, env, jt, preinst, compileFrame) and ignore its result
end proc;
Setup
Setup[Block] () propagates the call to Setup to nonterminals in the expansion of Block.
Evaluation
proc Eval[Block  { Directives }] (env: Environment, d: Object): Object
compileFrame: LocalFrame  CompileFrame[Block];
runtimeFrame: LocalFrame;
if Preinstantiate[Block] then runtimeFrame  compileFrame
else runtimeFrame  instantiateLocalFrame(compileFrame, env)
end if;
return Eval[Directives]([runtimeFrame]  env, d)
end proc;
proc EvalUsingFrame[Block  { Directives }] (env: Environment, frame: Frame, d: Object): Object
return Eval[Directives]([frame]  env, d)
end proc;
Labeled Statements
Syntax
LabeledStatement  Identifier : Substatement
Validation
proc Validate[LabeledStatement  Identifier : Substatement] (cxt: Context, env: Environment, sl: Label{}, jt: JumpTargets)
name: String  Name[Identifier];
if name  jt.breakTargets then
throw a SyntaxError exception — nesting labeled statements with the same label is not permitted
end if;
jt2: JumpTargets  JumpTargetsbreakTargets: jt.breakTargets  {name}, continueTargets: jt.continueTargets;
Evaluate Validate[Substatement](cxt, env, sl  {name}, jt2) and ignore its result
end proc;
Setup
proc Setup[LabeledStatement  Identifier : Substatement] ()
Evaluate Setup[Substatement]() and ignore its result
end proc;
Evaluation
proc Eval[LabeledStatement  Identifier : Substatement] (env: Environment, d: Object): Object
try return Eval[Substatement](env, d)
catch x: SemanticException do
if x  Break and x.label = Name[Identifier] then return x.value
else throw x
end if
end try
end proc;
If Statement
Syntax
IfStatementabbrev 
	if ParenListExpression Substatementabbrev
|	if ParenListExpression SubstatementnoShortIf else Substatementabbrev
IfStatementfull 
	if ParenListExpression Substatementfull
|	if ParenListExpression SubstatementnoShortIf else Substatementfull
IfStatementnoShortIf  if ParenListExpression SubstatementnoShortIf else SubstatementnoShortIf
Validation
proc Validate[IfStatement] (cxt: Context, env: Environment, jt: JumpTargets)
[IfStatementabbrev  if ParenListExpression Substatementabbrev] do
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
Evaluate Validate[Substatementabbrev](cxt, env, {}, jt) and ignore its result;
[IfStatementfull  if ParenListExpression Substatementfull] do
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
Evaluate Validate[Substatementfull](cxt, env, {}, jt) and ignore its result;
[IfStatement  if ParenListExpression SubstatementnoShortIf1 else Substatement2] do
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
Evaluate Validate[SubstatementnoShortIf1](cxt, env, {}, jt) and ignore its result;
Evaluate Validate[Substatement2](cxt, env, {}, jt) and ignore its result
end proc;
Setup
Setup[IfStatement] () propagates the call to Setup to nonterminals in the expansion of IfStatement.
Evaluation
proc Eval[IfStatement] (env: Environment, d: Object): Object
[IfStatementabbrev  if ParenListExpression Substatementabbrev] do
o: Object  readReference(Eval[ParenListExpression](env, run), run);
if objectToBoolean(o) then return Eval[Substatementabbrev](env, d)
else return d
end if;
[IfStatementfull  if ParenListExpression Substatementfull] do
o: Object  readReference(Eval[ParenListExpression](env, run), run);
if objectToBoolean(o) then return Eval[Substatementfull](env, d)
else return d
end if;
[IfStatement  if ParenListExpression SubstatementnoShortIf1 else Substatement2] do
o: Object  readReference(Eval[ParenListExpression](env, run), run);
if objectToBoolean(o) then return Eval[SubstatementnoShortIf1](env, d)
else return Eval[Substatement2](env, d)
end if
end proc;
Switch Statement
Semantics
tuple SwitchKey
key: Object
end tuple;
SwitchGuard = SwitchKey  {default}  Object;
Syntax
SwitchStatement  switch ParenListExpression { CaseElements }
CaseElements 
	«empty»
|	CaseLabel
|	CaseLabel CaseElementsPrefix CaseElementabbrev
CaseElementsPrefix 
	«empty»
|	CaseElementsPrefix CaseElementfull
CaseElement 
	Directive
|	CaseLabel
CaseLabel 
	case ListExpressionallowIn :
|	default :
Validation
CompileFrame[SwitchStatement]: LocalFrame;
proc Validate[SwitchStatement  switch ParenListExpression { CaseElements }] (cxt: Context, env: Environment, jt: JumpTargets)
if NDefaults[CaseElements] > 1 then
throw a SyntaxError exception — a case statement may have at most one default clause
end if;
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
jt2: JumpTargets  JumpTargetsbreakTargets: jt.breakTargets  {default}, continueTargets: jt.continueTargets;
compileFrame: LocalFrame  new LocalFramelocalBindings: {};
CompileFrame[SwitchStatement]  compileFrame;
localCxt: Context  new Contextstrict: cxt.strict, openNamespaces: cxt.openNamespaces;
Evaluate Validate[CaseElements](localCxt, [compileFrame]  env, jt2) and ignore its result
end proc;
NDefaults[CaseElements]: Integer;
NDefaults[CaseElements  «empty»] = 0;
NDefaults[CaseElements  CaseLabel] = NDefaults[CaseLabel];
NDefaults[CaseElements  CaseLabel CaseElementsPrefix CaseElementabbrev] = NDefaults[CaseLabel] + NDefaults[CaseElementsPrefix] + NDefaults[CaseElementabbrev];
Validate[CaseElements] (cxt: Context, env: Environment, jt: JumpTargets) propagates the call to Validate to nonterminals in the expansion of CaseElements.
NDefaults[CaseElementsPrefix]: Integer;
NDefaults[CaseElementsPrefix  «empty»] = 0;
NDefaults[CaseElementsPrefix0  CaseElementsPrefix1 CaseElementfull] = NDefaults[CaseElementsPrefix1] + NDefaults[CaseElementfull];
Validate[CaseElementsPrefix] (cxt: Context, env: Environment, jt: JumpTargets) propagates the call to Validate to nonterminals in the expansion of CaseElementsPrefix.
NDefaults[CaseElement]: Integer;
NDefaults[CaseElement  Directive] = 0;
NDefaults[CaseElement  CaseLabel] = NDefaults[CaseLabel];
proc Validate[CaseElement] (cxt: Context, env: Environment, jt: JumpTargets)
[CaseElement  Directive] do
Evaluate Validate[Directive](cxt, env, jt, false, none) and ignore its result;
[CaseElement  CaseLabel] do
Evaluate Validate[CaseLabel](cxt, env, jt) and ignore its result
end proc;
NDefaults[CaseLabel]: Integer;
NDefaults[CaseLabel  case ListExpressionallowIn :] = 0;
NDefaults[CaseLabel  default :] = 1;
proc Validate[CaseLabel] (cxt: Context, env: Environment, jt: JumpTargets)
[CaseLabel  case ListExpressionallowIn :] do
Evaluate Validate[ListExpressionallowIn](cxt, env) and ignore its result;
[CaseLabel  default :] do nothing
end proc;
Setup
Setup[SwitchStatement] () propagates the call to Setup to nonterminals in the expansion of SwitchStatement.
Setup[CaseElements] () propagates the call to Setup to nonterminals in the expansion of CaseElements.
Setup[CaseElementsPrefix] () propagates the call to Setup to nonterminals in the expansion of CaseElementsPrefix.
Setup[CaseElement] () propagates the call to Setup to nonterminals in the expansion of CaseElement.
Setup[CaseLabel] () propagates the call to Setup to nonterminals in the expansion of CaseLabel.
Evaluation
proc Eval[SwitchStatement  switch ParenListExpression { CaseElements }] (env: Environment, d: Object): Object
key: Object  readReference(Eval[ParenListExpression](env, run), run);
compileFrame: LocalFrame  CompileFrame[SwitchStatement];
runtimeFrame: LocalFrame  instantiateLocalFrame(compileFrame, env);
runtimeEnv: Environment  [runtimeFrame]  env;
result: SwitchGuard  Eval[CaseElements](runtimeEnv, SwitchKeykey: key, d);
if result  Object then return result end if;
note	result = SwitchKeykey: key;
result  Eval[CaseElements](runtimeEnv, default, d);
if result  Object then return result end if;
note	result = default;
return d
end proc;
proc Eval[CaseElements] (env: Environment, guard: SwitchGuard, d: Object): SwitchGuard
[CaseElements  «empty»] do return guard;
[CaseElements  CaseLabel] do return Eval[CaseLabel](env, guard, d);
[CaseElements  CaseLabel CaseElementsPrefix CaseElementabbrev] do
guard2: SwitchGuard  Eval[CaseLabel](env, guard, d);
guard3: SwitchGuard  Eval[CaseElementsPrefix](env, guard2, d);
return Eval[CaseElementabbrev](env, guard3, d)
end proc;
proc Eval[CaseElementsPrefix] (env: Environment, guard: SwitchGuard, d: Object): SwitchGuard
[CaseElementsPrefix  «empty»] do return guard;
[CaseElementsPrefix0  CaseElementsPrefix1 CaseElementfull] do
guard2: SwitchGuard  Eval[CaseElementsPrefix1](env, guard, d);
return Eval[CaseElementfull](env, guard2, d)
end proc;
proc Eval[CaseElement] (env: Environment, guard: SwitchGuard, d: Object): SwitchGuard
[CaseElement  Directive] do
case guard of
SwitchKey  {default} do return guard;
Object do return Eval[Directive](env, guard)
end case;
[CaseElement  CaseLabel] do return Eval[CaseLabel](env, guard, d)
end proc;
proc Eval[CaseLabel] (env: Environment, guard: SwitchGuard, d: Object): SwitchGuard
[CaseLabel  case ListExpressionallowIn :] do
case guard of
{default}  Object do return guard;
SwitchKey do
label: Object  readReference(Eval[ListExpressionallowIn](env, run), run);
if isStrictlyEqual(guard.key, label, run) then return d
else return guard
end if
end case;
[CaseLabel  default :] do
case guard of
SwitchKey  Object do return guard;
{default} do return d
end case
end proc;
Do-While Statement
Syntax
DoStatement  do Substatementabbrev while ParenListExpression
Validation
Labels[DoStatement]: Label{};
proc Validate[DoStatement  do Substatementabbrev while ParenListExpression] (cxt: Context, env: Environment, sl: Label{}, jt: JumpTargets)
continueLabels: Label{}  sl  {default};
Labels[DoStatement]  continueLabels;
jt2: JumpTargets  JumpTargetsbreakTargets: jt.breakTargets  {default}, continueTargets: jt.continueTargets  continueLabels;
Evaluate Validate[Substatementabbrev](cxt, env, {}, jt2) and ignore its result;
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result
end proc;
Setup
Setup[DoStatement] () propagates the call to Setup to nonterminals in the expansion of DoStatement.
Evaluation
proc Eval[DoStatement  do Substatementabbrev while ParenListExpression] (env: Environment, d: Object): Object
try
d1: Object  d;
while true do
try d1  Eval[Substatementabbrev](env, d1)
catch x: SemanticException do
if x  Continue and x.label  Labels[DoStatement] then d1  x.value
else throw x
end if
end try;
o: Object  readReference(Eval[ParenListExpression](env, run), run);
if not objectToBoolean(o) then return d1 end if
end while
catch x: SemanticException do
if x  Break and x.label = default then return x.value else throw x end if
end try
end proc;
While Statement
Syntax
WhileStatement  while ParenListExpression Substatement
Validation
Labels[WhileStatement]: Label{};
proc Validate[WhileStatement  while ParenListExpression Substatement] (cxt: Context, env: Environment, sl: Label{}, jt: JumpTargets)
continueLabels: Label{}  sl  {default};
Labels[WhileStatement]  continueLabels;
jt2: JumpTargets  JumpTargetsbreakTargets: jt.breakTargets  {default}, continueTargets: jt.continueTargets  continueLabels;
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
Evaluate Validate[Substatement](cxt, env, {}, jt2) and ignore its result
end proc;
Setup
Setup[WhileStatement] () propagates the call to Setup to nonterminals in the expansion of WhileStatement.
Evaluation
proc Eval[WhileStatement  while ParenListExpression Substatement] (env: Environment, d: Object): Object
try
d1: Object  d;
while objectToBoolean(readReference(Eval[ParenListExpression](env, run), run)) do
try d1  Eval[Substatement](env, d1)
catch x: SemanticException do
if x  Continue and x.label  Labels[WhileStatement] then
d1  x.value
else throw x
end if
end try
end while;
return d1
catch x: SemanticException do
if x  Break and x.label = default then return x.value else throw x end if
end try
end proc;
For Statements
Syntax
ForStatement 
	for ( ForInitializer ; OptionalExpression ; OptionalExpression ) Substatement
|	for ( ForInBinding in ListExpressionallowIn ) Substatement
ForInitializer 
	«empty»
|	ListExpressionnoIn
|	VariableDefinitionnoIn
|	Attributes [no line break] VariableDefinitionnoIn
ForInBinding 
	PostfixExpression
|	VariableDefinitionKind VariableBindingnoIn
|	Attributes [no line break] VariableDefinitionKind VariableBindingnoIn
OptionalExpression 
	ListExpressionallowIn
|	«empty»
Validation
Labels[ForStatement]: Label{};
CompileLocalFrame[ForStatement]: LocalFrame;
proc Validate[ForStatement] (cxt: Context, env: Environment, sl: Label{}, jt: JumpTargets)
[ForStatement  for ( ForInitializer ; OptionalExpression1 ; OptionalExpression2 ) Substatement] do
continueLabels: Label{}  sl  {default};
Labels[ForStatement]  continueLabels;
jt2: JumpTargets  JumpTargetsbreakTargets: jt.breakTargets  {default}, continueTargets: jt.continueTargets  continueLabels;
compileLocalFrame: LocalFrame  new LocalFramelocalBindings: {};
CompileLocalFrame[ForStatement]  compileLocalFrame;
compileEnv: Environment  [compileLocalFrame]  env;
Evaluate Validate[ForInitializer](cxt, compileEnv) and ignore its result;
Evaluate Validate[OptionalExpression1](cxt, compileEnv) and ignore its result;
Evaluate Validate[OptionalExpression2](cxt, compileEnv) and ignore its result;
Evaluate Validate[Substatement](cxt, compileEnv, {}, jt2) and ignore its result;
[ForStatement  for ( ForInBinding in ListExpressionallowIn ) Substatement] do
continueLabels: Label{}  sl  {default};
Labels[ForStatement]  continueLabels;
jt2: JumpTargets  JumpTargetsbreakTargets: jt.breakTargets  {default}, continueTargets: jt.continueTargets  continueLabels;
Evaluate Validate[ListExpressionallowIn](cxt, env) and ignore its result;
compileLocalFrame: LocalFrame  new LocalFramelocalBindings: {};
CompileLocalFrame[ForStatement]  compileLocalFrame;
compileEnv: Environment  [compileLocalFrame]  env;
Evaluate Validate[ForInBinding](cxt, compileEnv) and ignore its result;
Evaluate Validate[Substatement](cxt, compileEnv, {}, jt2) and ignore its result
end proc;
Enabled[ForInitializer]: Boolean;
proc Validate[ForInitializer] (cxt: Context, env: Environment)
[ForInitializer  «empty»] do nothing;
[ForInitializer  ListExpressionnoIn] do
Evaluate Validate[ListExpressionnoIn](cxt, env) and ignore its result;
[ForInitializer  VariableDefinitionnoIn] do
Evaluate Validate[VariableDefinitionnoIn](cxt, env, none) and ignore its result;
[ForInitializer  Attributes [no line break] VariableDefinitionnoIn] do
Evaluate Validate[Attributes](cxt, env) and ignore its result;
Evaluate Setup[Attributes]() and ignore its result;
attr: Attribute  Eval[Attributes](env, compile);
Enabled[ForInitializer]  attr ≠ false;
if attr ≠ false then
Evaluate Validate[VariableDefinitionnoIn](cxt, env, attr) and ignore its result
end if
end proc;
proc Validate[ForInBinding] (cxt: Context, env: Environment)
[ForInBinding  PostfixExpression] do
Evaluate Validate[PostfixExpression](cxt, env) and ignore its result;
[ForInBinding  VariableDefinitionKind VariableBindingnoIn] do
Evaluate Validate[VariableBindingnoIn](cxt, env, none, Immutable[VariableDefinitionKind], true) and ignore its result;
[ForInBinding  Attributes [no line break] VariableDefinitionKind VariableBindingnoIn] do
Evaluate Validate[Attributes](cxt, env) and ignore its result;
Evaluate Setup[Attributes]() and ignore its result;
attr: Attribute  Eval[Attributes](env, compile);
if attr = false then
throw an AttributeError exception — the false attribute canot be applied to a for-in variable definition
end if;
Evaluate Validate[VariableBindingnoIn](cxt, env, attr, Immutable[VariableDefinitionKind], true) and ignore its result
end proc;
Validate[OptionalExpression] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of OptionalExpression.
Setup
Setup[ForStatement] () propagates the call to Setup to nonterminals in the expansion of ForStatement.
proc Setup[ForInitializer] ()
[ForInitializer  «empty»] do nothing;
[ForInitializer  ListExpressionnoIn] do
Evaluate Setup[ListExpressionnoIn]() and ignore its result;
[ForInitializer  VariableDefinitionnoIn] do
Evaluate Setup[VariableDefinitionnoIn]() and ignore its result;
[ForInitializer  Attributes [no line break] VariableDefinitionnoIn] do
if Enabled[ForInitializer] then
Evaluate Setup[VariableDefinitionnoIn]() and ignore its result
end if
end proc;
proc Setup[ForInBinding] ()
[ForInBinding  PostfixExpression] do
Evaluate Setup[PostfixExpression]() and ignore its result;
[ForInBinding  VariableDefinitionKind VariableBindingnoIn] do
Evaluate Setup[VariableBindingnoIn]() and ignore its result;
[ForInBinding  Attributes [no line break] VariableDefinitionKind VariableBindingnoIn] do
Evaluate Setup[VariableBindingnoIn]() and ignore its result
end proc;
Setup[OptionalExpression] () propagates the call to Setup to nonterminals in the expansion of OptionalExpression.
Evaluation
proc Eval[ForStatement] (env: Environment, d: Object): Object
[ForStatement  for ( ForInitializer ; OptionalExpression1 ; OptionalExpression2 ) Substatement] do
runtimeLocalFrame: LocalFrame  instantiateLocalFrame(CompileLocalFrame[ForStatement], env);
runtimeEnv: Environment  [runtimeLocalFrame]  env;
try
Evaluate Eval[ForInitializer](runtimeEnv) and ignore its result;
d1: Object  d;
while objectToBoolean(readReference(Eval[OptionalExpression1](runtimeEnv, run), run)) do
try d1  Eval[Substatement](runtimeEnv, d1)
catch x: SemanticException do
if x  Continue and x.label  Labels[ForStatement] then
d1  x.value
else throw x
end if
end try;
Evaluate readReference(Eval[OptionalExpression2](runtimeEnv, run), run) and ignore its result
end while;
return d1
catch x: SemanticException do
if x  Break and x.label = default then return x.value else throw x end if
end try;
[ForStatement  for ( ForInBinding in ListExpressionallowIn ) Substatement] do
try
o: Object  readReference(Eval[ListExpressionallowIn](env, run), run);
c: Class  objectType(o);
oldIndices: Object{}  c.enumerate(o);
remainingIndices: Object{}  oldIndices;
d1: Object  d;
while remainingIndices ≠ {} do
runtimeLocalFrame: LocalFrame  instantiateLocalFrame(CompileLocalFrame[ForStatement], env);
runtimeEnv: Environment  [runtimeLocalFrame]  env;
index: Object  any element of remainingIndices;
remainingIndices  remainingIndices – {index};
Evaluate WriteBinding[ForInBinding](runtimeEnv, index) and ignore its result;
try d1  Eval[Substatement](runtimeEnv, d1)
catch x: SemanticException do
if x  Continue and x.label  Labels[ForStatement] then
d1  x.value
else throw x
end if
end try;
newIndices: Object{}  c.enumerate(o);
if newIndices ≠ oldIndices then
The implementation may, at its discretion, add none, some, or all of the objects in the set difference newIndices – oldIndices to remainingIndices;
The implementation may, at its discretion, remove none, some, or all of the objects in the set difference oldIndices – newIndices from remainingIndices;
end if;
oldIndices  newIndices
end while;
return d1
catch x: SemanticException do
if x  Break and x.label = default then return x.value else throw x end if
end try
end proc;
proc Eval[ForInitializer] (env: Environment)
[ForInitializer  «empty»] do nothing;
[ForInitializer  ListExpressionnoIn] do
Evaluate readReference(Eval[ListExpressionnoIn](env, run), run) and ignore its result;
[ForInitializer  VariableDefinitionnoIn] do
Evaluate Eval[VariableDefinitionnoIn](env, undefined) and ignore its result;
[ForInitializer  Attributes [no line break] VariableDefinitionnoIn] do
if Enabled[ForInitializer] then
Evaluate Eval[VariableDefinitionnoIn](env, undefined) and ignore its result
end if
end proc;
proc WriteBinding[ForInBinding] (env: Environment, newValue: Object)
[ForInBinding  PostfixExpression] do
r: ObjOrRef  Eval[PostfixExpression](env, run);
Evaluate writeReference(r, newValue, run) and ignore its result;
[ForInBinding  VariableDefinitionKind VariableBindingnoIn] do
Evaluate WriteBinding[VariableBindingnoIn](env, newValue) and ignore its result;
[ForInBinding  Attributes [no line break] VariableDefinitionKind VariableBindingnoIn] do
Evaluate WriteBinding[VariableBindingnoIn](env, newValue) and ignore its result
end proc;
proc Eval[OptionalExpression] (env: Environment, phase: Phase): ObjOrRef
[OptionalExpression  ListExpressionallowIn] do
return Eval[ListExpressionallowIn](env, phase);
[OptionalExpression  «empty»] do return true
end proc;
With Statement
Syntax
WithStatement  with ParenListExpression Substatement
Validation
CompileLocalFrame[WithStatement]: LocalFrame;
proc Validate[WithStatement  with ParenListExpression Substatement] (cxt: Context, env: Environment, jt: JumpTargets)
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
compileWithFrame: WithFrame  new WithFramevalue: none;
compileLocalFrame: LocalFrame  new LocalFramelocalBindings: {};
CompileLocalFrame[WithStatement]  compileLocalFrame;
compileEnv: Environment  [compileLocalFrame]  [compileWithFrame]  env;
Evaluate Validate[Substatement](cxt, compileEnv, {}, jt) and ignore its result
end proc;
Setup
Setup[WithStatement] () propagates the call to Setup to nonterminals in the expansion of WithStatement.
Evaluation
proc Eval[WithStatement  with ParenListExpression Substatement] (env: Environment, d: Object): Object
value: Object  readReference(Eval[ParenListExpression](env, run), run);
runtimeWithFrame: WithFrame  new WithFramevalue: value;
runtimeLocalFrame: LocalFrame  instantiateLocalFrame(CompileLocalFrame[WithStatement], [runtimeWithFrame]  env);
runtimeEnv: Environment  [runtimeLocalFrame]  [runtimeWithFrame]  env;
return Eval[Substatement](runtimeEnv, d)
end proc;
Continue and Break Statements
Syntax
ContinueStatement 
	continue
|	continue [no line break] Identifier
BreakStatement 
	break
|	break [no line break] Identifier
Validation
proc Validate[ContinueStatement] (jt: JumpTargets)
[ContinueStatement  continue] do
if default  jt.continueTargets then
throw a SyntaxError exception — there is no enclosing statement to which to continue
end if;
[ContinueStatement  continue [no line break] Identifier] do
if Name[Identifier]  jt.continueTargets then
throw a SyntaxError exception — there is no enclosing labeled statement to which to continue
end if
end proc;
proc Validate[BreakStatement] (jt: JumpTargets)
[BreakStatement  break] do
if default  jt.breakTargets then
throw a SyntaxError exception — there is no enclosing statement to which to break
end if;
[BreakStatement  break [no line break] Identifier] do
if Name[Identifier]  jt.breakTargets then
throw a SyntaxError exception — there is no enclosing labeled statement to which to break
end if
end proc;
Setup
proc Setup[ContinueStatement] ()
[ContinueStatement  continue] do nothing;
[ContinueStatement  continue [no line break] Identifier] do nothing
end proc;
proc Setup[BreakStatement] ()
[BreakStatement  break] do nothing;
[BreakStatement  break [no line break] Identifier] do nothing
end proc;
Evaluation
proc Eval[ContinueStatement] (env: Environment, d: Object): Object
[ContinueStatement  continue] do throw Continuevalue: d, label: default;
[ContinueStatement  continue [no line break] Identifier] do
throw Continuevalue: d, label: Name[Identifier]
end proc;
proc Eval[BreakStatement] (env: Environment, d: Object): Object
[BreakStatement  break] do throw Breakvalue: d, label: default;
[BreakStatement  break [no line break] Identifier] do
throw Breakvalue: d, label: Name[Identifier]
end proc;
Return Statement
Syntax
ReturnStatement 
	return
|	return [no line break] ListExpressionallowIn
Validation
proc Validate[ReturnStatement] (cxt: Context, env: Environment)
[ReturnStatement  return] do
if getEnclosingParameterFrame(env) = none then
throw a SyntaxError exception — a return statement must be located inside a function
end if;
[ReturnStatement  return [no line break] ListExpressionallowIn] do
frame: ParameterFrameOpt  getEnclosingParameterFrame(env);
if frame = none then
throw a SyntaxError exception — a return statement must be located inside a function
end if;
if cannotReturnValue(frame) then
throw a SyntaxError exception — a return statement inside a setter or constructor cannot return a value
end if;
Evaluate Validate[ListExpressionallowIn](cxt, env) and ignore its result
end proc;
Setup
Setup[ReturnStatement] () propagates the call to Setup to nonterminals in the expansion of ReturnStatement.
Evaluation
proc Eval[ReturnStatement] (env: Environment): Object
[ReturnStatement  return] do throw Returnvalue: undefined;
[ReturnStatement  return [no line break] ListExpressionallowIn] do
a: Object  readReference(Eval[ListExpressionallowIn](env, run), run);
throw Returnvalue: a
end proc;
cannotReturnValue(frame) returns true if the function represented by frame cannot return a value because it is a setter or constructor.
proc cannotReturnValue(frame: ParameterFrame): Boolean
return frame.kind = constructorFunction or frame.handling = set
end proc;
Throw Statement
Syntax
ThrowStatement  throw [no line break] ListExpressionallowIn
Validation
Validate[ThrowStatement] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of ThrowStatement.
Setup
Setup[ThrowStatement] () propagates the call to Setup to nonterminals in the expansion of ThrowStatement.
Evaluation
proc Eval[ThrowStatement  throw [no line break] ListExpressionallowIn] (env: Environment): Object
a: Object  readReference(Eval[ListExpressionallowIn](env, run), run);
throw a
end proc;
Try Statement
Syntax
TryStatement 
	try Block CatchClauses
|	try Block CatchClausesOpt finally Block
CatchClausesOpt 
	«empty»
|	CatchClauses
CatchClauses 
	CatchClause
|	CatchClauses CatchClause
CatchClause  catch ( Parameter ) Block
Validation
proc Validate[TryStatement] (cxt: Context, env: Environment, jt: JumpTargets)
[TryStatement  try Block CatchClauses] do
Evaluate Validate[Block](cxt, env, jt, false) and ignore its result;
Evaluate Validate[CatchClauses](cxt, env, jt) and ignore its result;
[TryStatement  try Block1 CatchClausesOpt finally Block2] do
Evaluate Validate[Block1](cxt, env, jt, false) and ignore its result;
Evaluate Validate[CatchClausesOpt](cxt, env, jt) and ignore its result;
Evaluate Validate[Block2](cxt, env, jt, false) and ignore its result
end proc;
Validate[CatchClausesOpt] (cxt: Context, env: Environment, jt: JumpTargets) propagates the call to Validate to nonterminals in the expansion of CatchClausesOpt.
Validate[CatchClauses] (cxt: Context, env: Environment, jt: JumpTargets) propagates the call to Validate to nonterminals in the expansion of CatchClauses.
CompileEnv[CatchClause]: Environment;
CompileFrame[CatchClause]: LocalFrame;
proc Validate[CatchClause  catch ( Parameter ) Block] (cxt: Context, env: Environment, jt: JumpTargets)
compileFrame: LocalFrame  new LocalFramelocalBindings: {};
compileEnv: Environment  [compileFrame]  env;
CompileFrame[CatchClause]  compileFrame;
CompileEnv[CatchClause]  compileEnv;
Evaluate Validate[Parameter](cxt, compileEnv, compileFrame) and ignore its result;
Evaluate Validate[Block](cxt, compileEnv, jt, false) and ignore its result
end proc;
Setup
Setup[TryStatement] () propagates the call to Setup to nonterminals in the expansion of TryStatement.
Setup[CatchClausesOpt] () propagates the call to Setup to nonterminals in the expansion of CatchClausesOpt.
Setup[CatchClauses] () propagates the call to Setup to nonterminals in the expansion of CatchClauses.
proc Setup[CatchClause  catch ( Parameter ) Block] ()
Evaluate Setup[Parameter](CompileEnv[CatchClause], CompileFrame[CatchClause], none) and ignore its result;
Evaluate Setup[Block]() and ignore its result
end proc;
Evaluation
proc Eval[TryStatement] (env: Environment, d: Object): Object
[TryStatement  try Block CatchClauses] do
try return Eval[Block](env, d)
catch x: SemanticException do
if x  ControlTransfer then throw x
else
r: Object  {reject}  Eval[CatchClauses](env, x);
if r ≠ reject then return r else throw x end if
end if
end try;
[TryStatement  try Block1 CatchClausesOpt finally Block2] do
result: ObjectOpt  none;
exception: SemanticException  {none}  none;
try result  Eval[Block1](env, d)
catch x: SemanticException do exception  x
end try;
note	At this point exactly one of result and exception has a non-none value.
if exception  Object then
try
r: Object  {reject}  Eval[CatchClausesOpt](env, exception);
if r ≠ reject then
note	The exception has been handled, so clear it.
result  r;
exception  none
end if
catch x: SemanticException do
note	The catch clause threw another exception or ControlTransfer x, so replace the original exception with x.
exception  x
end try
end if;
note	The finally clause is executed even if the original block exited due to a ControlTransfer (break, continue, or return).
note	The finally clause is not inside a try-catch semantic statement, so if it throws another exception or ControlTransfer, then the original exception or ControlTransfer exception is dropped.
Evaluate Eval[Block2](env, undefined) and ignore its result;
note	At this point exactly one of result and exception has a non-none value.
if exception ≠ none then throw exception else return result end if
end proc;
proc Eval[CatchClausesOpt] (env: Environment, exception: Object): Object  {reject}
[CatchClausesOpt  «empty»] do return reject;
[CatchClausesOpt  CatchClauses] do return Eval[CatchClauses](env, exception)
end proc;
proc Eval[CatchClauses] (env: Environment, exception: Object): Object  {reject}
[CatchClauses  CatchClause] do return Eval[CatchClause](env, exception);
[CatchClauses0  CatchClauses1 CatchClause] do
r: Object  {reject}  Eval[CatchClauses1](env, exception);
if r ≠ reject then return r else return Eval[CatchClause](env, exception) end if
end proc;
proc Eval[CatchClause  catch ( Parameter ) Block] (env: Environment, exception: Object): Object  {reject}
compileFrame: LocalFrame  CompileFrame[CatchClause];
runtimeFrame: LocalFrame  instantiateLocalFrame(compileFrame, env);
runtimeEnv: Environment  [runtimeFrame]  env;
qname: QualifiedName  public::(Name[Parameter]);
v: SingletonPropertyOpt  findLocalSingletonProperty(runtimeFrame, {qname}, write);
note	Validate created one local variable with the name in qname, so v  Variable.
if is(exception, v.type) then
Evaluate writeSingletonProperty(v, exception, run) and ignore its result;
return Eval[Block](runtimeEnv, undefined)
else return reject
end if
end proc;
Directives
Syntax
Directive 
	EmptyStatement
|	Statement
|	AnnotatableDirective
|	Attributes [no line break] AnnotatableDirective
|	Attributes [no line break] { Directives }
|	IncludeDirective Semicolon
|	Pragma Semicolon
AnnotatableDirective 
	VariableDefinitionallowIn Semicolon
|	FunctionDefinition
|	ClassDefinition
|	NamespaceDefinition Semicolon
|	ImportDirective Semicolon
|	ExportDefinition Semicolon
|	UseDirective Semicolon
Directives 
	«empty»
|	DirectivesPrefix Directiveabbrev
DirectivesPrefix 
	«empty»
|	DirectivesPrefix Directivefull
Validation
Enabled[Directive]: Boolean;
proc Validate[Directive] (cxt: Context, env: Environment, jt: JumpTargets, preinst: Boolean, attr: AttributeOptNotFalse)
[Directive  EmptyStatement] do nothing;
[Directive  Statement] do
if attr  {none, true} then
throw an AttributeError exception — an ordinary statement only permits the attributes true and false
end if;
Evaluate Validate[Statement](cxt, env, {}, jt, preinst) and ignore its result;
[Directive  AnnotatableDirective] do
Evaluate Validate[AnnotatableDirective](cxt, env, preinst, attr) and ignore its result;
[Directive  Attributes [no line break] AnnotatableDirective] do
Evaluate Validate[Attributes](cxt, env) and ignore its result;
Evaluate Setup[Attributes]() and ignore its result;
attr2: Attribute  Eval[Attributes](env, compile);
attr3: Attribute  combineAttributes(attr, attr2);
if attr3 = false then Enabled[Directive]  false
else
Enabled[Directive]  true;
Evaluate Validate[AnnotatableDirective](cxt, env, preinst, attr3) and ignore its result
end if;
[Directive  Attributes [no line break] { Directives }] do
Evaluate Validate[Attributes](cxt, env) and ignore its result;
Evaluate Setup[Attributes]() and ignore its result;
attr2: Attribute  Eval[Attributes](env, compile);
attr3: Attribute  combineAttributes(attr, attr2);
if attr3 = false then Enabled[Directive]  false
else
Enabled[Directive]  true;
localCxt: Context  new Contextstrict: cxt.strict, openNamespaces: cxt.openNamespaces;
Evaluate Validate[Directives](localCxt, env, jt, preinst, attr3) and ignore its result
end if;
[Directive  IncludeDirective Semicolon] do
if attr  {none, true} then Evaluate ???? and ignore its result
else
throw an AttributeError exception — an include directive only permits the attributes true and false
end if;
[Directive  Pragma Semicolon] do
if attr  {none, true} then Evaluate Validate[Pragma](cxt) and ignore its result
else
throw an AttributeError exception — a pragma directive only permits the attributes true and false
end if
end proc;
proc Validate[AnnotatableDirective] (cxt: Context, env: Environment, preinst: Boolean, attr: AttributeOptNotFalse)
[AnnotatableDirective  VariableDefinitionallowIn Semicolon] do
Evaluate Validate[VariableDefinitionallowIn](cxt, env, attr) and ignore its result;
[AnnotatableDirective  FunctionDefinition] do
Evaluate Validate[FunctionDefinition](cxt, env, preinst, attr) and ignore its result;
[AnnotatableDirective  ClassDefinition] do
Evaluate Validate[ClassDefinition](cxt, env, preinst, attr) and ignore its result;
[AnnotatableDirective  NamespaceDefinition Semicolon] do
Evaluate Validate[NamespaceDefinition](cxt, env, preinst, attr) and ignore its result;
[AnnotatableDirective  ImportDirective Semicolon] do
Evaluate Validate[ImportDirective](cxt, env, preinst, attr) and ignore its result;
[AnnotatableDirective  ExportDefinition Semicolon] do
Evaluate ???? and ignore its result;
[AnnotatableDirective  UseDirective Semicolon] do
if attr  {none, true} then
Evaluate Validate[UseDirective](cxt, env) and ignore its result
else
throw an AttributeError exception — a use directive only permits the attributes true and false
end if
end proc;
Validate[Directives] (cxt: Context, env: Environment, jt: JumpTargets, preinst: Boolean, attr: AttributeOptNotFalse) propagates the call to Validate to nonterminals in the expansion of Directives.
Validate[DirectivesPrefix] (cxt: Context, env: Environment, jt: JumpTargets, preinst: Boolean, attr: AttributeOptNotFalse) propagates the call to Validate to nonterminals in the expansion of DirectivesPrefix.
Setup
proc Setup[Directive] ()
[Directive  EmptyStatement] do nothing;
[Directive  Statement] do Evaluate Setup[Statement]() and ignore its result;
[Directive  AnnotatableDirective] do
Evaluate Setup[AnnotatableDirective]() and ignore its result;
[Directive  Attributes [no line break] AnnotatableDirective] do
if Enabled[Directive] then
Evaluate Setup[AnnotatableDirective]() and ignore its result
end if;
[Directive  Attributes [no line break] { Directives }] do
if Enabled[Directive] then Evaluate Setup[Directives]() and ignore its result
end if;
[Directive  IncludeDirective Semicolon] do Evaluate ???? and ignore its result;
[Directive  Pragma Semicolon] do nothing
end proc;
proc Setup[AnnotatableDirective] ()
[AnnotatableDirective  VariableDefinitionallowIn Semicolon] do
Evaluate Setup[VariableDefinitionallowIn]() and ignore its result;
[AnnotatableDirective  FunctionDefinition] do
Evaluate Setup[FunctionDefinition]() and ignore its result;
[AnnotatableDirective  ClassDefinition] do
Evaluate Setup[ClassDefinition]() and ignore its result;
[AnnotatableDirective  NamespaceDefinition Semicolon] do nothing;
[AnnotatableDirective  ImportDirective Semicolon] do nothing;
[AnnotatableDirective  ExportDefinition Semicolon] do
Evaluate ???? and ignore its result;
[AnnotatableDirective  UseDirective Semicolon] do nothing
end proc;
Setup[Directives] () propagates the call to Setup to nonterminals in the expansion of Directives.
Setup[DirectivesPrefix] () propagates the call to Setup to nonterminals in the expansion of DirectivesPrefix.
Evaluation
proc Eval[Directive] (env: Environment, d: Object): Object
[Directive  EmptyStatement] do return d;
[Directive  Statement] do return Eval[Statement](env, d);
[Directive  AnnotatableDirective] do return Eval[AnnotatableDirective](env, d);
[Directive  Attributes [no line break] AnnotatableDirective] do
if Enabled[Directive] then return Eval[AnnotatableDirective](env, d)
else return d
end if;
[Directive  Attributes [no line break] { Directives }] do
if Enabled[Directive] then return Eval[Directives](env, d) else return d end if;
[Directive  IncludeDirective Semicolon] do Evaluate ???? and ignore its result;
[Directive  Pragma Semicolon] do return d
end proc;
proc Eval[AnnotatableDirective] (env: Environment, d: Object): Object
[AnnotatableDirective  VariableDefinitionallowIn Semicolon] do
return Eval[VariableDefinitionallowIn](env, d);
[AnnotatableDirective  FunctionDefinition] do return d;
[AnnotatableDirective  ClassDefinition] do return Eval[ClassDefinition](env, d);
[AnnotatableDirective  NamespaceDefinition Semicolon] do return d;
[AnnotatableDirective  ImportDirective Semicolon] do return d;
[AnnotatableDirective  ExportDefinition Semicolon] do
Evaluate ???? and ignore its result;
[AnnotatableDirective  UseDirective Semicolon] do return d
end proc;
proc Eval[Directives] (env: Environment, d: Object): Object
[Directives  «empty»] do return d;
[Directives  DirectivesPrefix Directiveabbrev] do
o: Object  Eval[DirectivesPrefix](env, d);
return Eval[Directiveabbrev](env, o)
end proc;
proc Eval[DirectivesPrefix] (env: Environment, d: Object): Object
[DirectivesPrefix  «empty»] do return d;
[DirectivesPrefix0  DirectivesPrefix1 Directivefull] do
o: Object  Eval[DirectivesPrefix1](env, d);
return Eval[Directivefull](env, o)
end proc;
Attributes
Syntax
Attributes 
	Attribute
|	AttributeCombination
AttributeCombination  Attribute [no line break] Attributes
Attribute 
	AttributeExpression
|	true
|	false
|	ReservedNamespace
Validation
Validate[Attributes] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of Attributes.
Validate[AttributeCombination] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of AttributeCombination.
Validate[Attribute] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of Attribute.
Setup
Setup[Attributes] () propagates the call to Setup to nonterminals in the expansion of Attributes.
Setup[AttributeCombination] () propagates the call to Setup to nonterminals in the expansion of AttributeCombination.
Setup[Attribute] () propagates the call to Setup to nonterminals in the expansion of Attribute.
Evaluation
proc Eval[Attributes] (env: Environment, phase: Phase): Attribute
[Attributes  Attribute] do return Eval[Attribute](env, phase);
[Attributes  AttributeCombination] do return Eval[AttributeCombination](env, phase)
end proc;
proc Eval[AttributeCombination  Attribute [no line break] Attributes] (env: Environment, phase: Phase): Attribute
a: Attribute  Eval[Attribute](env, phase);
if a = false then return false end if;
b: Attribute  Eval[Attributes](env, phase);
return combineAttributes(a, b)
end proc;
proc Eval[Attribute] (env: Environment, phase: Phase): Attribute
[Attribute  AttributeExpression] do
a: Object  readReference(Eval[AttributeExpression](env, phase), phase);
return objectToAttribute(a, phase);
[Attribute  true] do return true;
[Attribute  false] do return false;
[Attribute  ReservedNamespace] do return Eval[ReservedNamespace](env, phase)
end proc;
Use Directive
Syntax
UseDirective  use namespace ParenListExpression
Validation
proc Validate[UseDirective  use namespace ParenListExpression] (cxt: Context, env: Environment)
Evaluate Validate[ParenListExpression](cxt, env) and ignore its result;
Evaluate Setup[ParenListExpression]() and ignore its result;
values: Object[]  EvalAsList[ParenListExpression](env, compile);
namespaces: Namespace{}  {};
for each v  values do
if v  Namespace then throw a TypeError exception end if;
namespaces  namespaces  {v}
end for each;
cxt.openNamespaces  cxt.openNamespaces  namespaces
end proc;
Import Directive
Syntax
ImportDirective 
	import PackageName
|	import Identifier = PackageName
Validation
proc Validate[ImportDirective] (cxt: Context, env: Environment, preinst: Boolean, attr: AttributeOptNotFalse)
[ImportDirective  import PackageName] do
if not preinst then
throw a SyntaxError exception — a package may be imported only in a preinstantiated scope
end if;
frame: Frame  env[0];
if frame  Package then
throw a SyntaxError exception — a package may be imported only into a package scope
end if;
if attr  {none, true} then
throw an AttributeError exception — an unnamed import directive only permits the attributes true and false
end if;
pkgName: String  Name[PackageName];
pkg: Package  locatePackage(pkgName);
Evaluate importPackageInto(pkg, frame) and ignore its result;
[ImportDirective  import Identifier = PackageName] do
if not preinst then
throw a SyntaxError exception — a package may be imported only in a preinstantiated scope
end if;
frame: Frame  env[0];
if frame  Package then
throw a SyntaxError exception — a package may be imported only into a package scope
end if;
a: CompoundAttribute  toCompoundAttribute(attr);
if a.dynamic then
throw an AttributeError exception — a package definition cannot have the dynamic attribute
end if;
if a.prototype then
throw an AttributeError exception — a package definition cannot have the prototype attribute
end if;
pkgName: String  Name[PackageName];
pkg: Package  locatePackage(pkgName);
v: Variable  new Variabletype: Package, value: pkg, immutable: true, setup: none, initializer: none;
Evaluate defineSingletonProperty(env, Name[Identifier], a.namespaces, a.overrideMod, a.explicit, readWrite, v) and ignore its result;
Evaluate importPackageInto(pkg, frame) and ignore its result
end proc;
proc locatePackage(name: String): Package
Look for a package bound to name in the implementation’s list of available packages. If one is found, let pkg: Package be that package; otherwise, throw an implementation-defined error.
initialize: (()  ())  {none, busy}  pkg.initialize;
case initialize of
{none} do nothing;
{busy} do throw an UninitializedError exception — circular package dependency;
()  () do
Evaluate initialize() and ignore its result;
note	pkg.initialize = none;
end case;
return pkg
end proc;
proc importPackageInto(source: Package, destination: Package)
for each b  source.localBindings do
if not (b.explicit or b.content = forbidden or (some d  destination.localBindings satisfies b.qname = d.qname and accessesOverlap(b.accesses, d.accesses))) then
destination.localBindings  destination.localBindings  {b}
end if
end for each
end proc;
Include Directive
Syntax
IncludeDirective  include [no line break] String
Pragma
Syntax
Pragma  use PragmaItems
PragmaItems 
	PragmaItem
|	PragmaItems , PragmaItem
PragmaItem 
	PragmaExpr
|	PragmaExpr ?
PragmaExpr 
	Identifier
|	Identifier ( PragmaArgument )
PragmaArgument 
	true
|	false
|	Number
|	- Number
|	- NegatedMinLong
|	String
Validation
Validate[Pragma] (cxt: Context) propagates the call to Validate to nonterminals in the expansion of Pragma.
Validate[PragmaItems] (cxt: Context) propagates the call to Validate to nonterminals in the expansion of PragmaItems.
proc Validate[PragmaItem] (cxt: Context)
[PragmaItem  PragmaExpr] do
Evaluate Validate[PragmaExpr](cxt, false) and ignore its result;
[PragmaItem  PragmaExpr ?] do
Evaluate Validate[PragmaExpr](cxt, true) and ignore its result
end proc;
proc Validate[PragmaExpr] (cxt: Context, optional: Boolean)
[PragmaExpr  Identifier] do
Evaluate processPragma(cxt, Name[Identifier], undefined, optional) and ignore its result;
[PragmaExpr  Identifier ( PragmaArgument )] do
arg: Object  Value[PragmaArgument];
Evaluate processPragma(cxt, Name[Identifier], arg, optional) and ignore its result
end proc;
Value[PragmaArgument]: Object;
Value[PragmaArgument  true] = true;
Value[PragmaArgument  false] = false;
Value[PragmaArgument  Number] = Value[Number];
Value[PragmaArgument  - Number] = generalNumberNegate(Value[Number]);
Value[PragmaArgument  - NegatedMinLong] = (–263)long;
Value[PragmaArgument  String] = Value[String];
proc processPragma(cxt: Context, name: String, value: Object, optional: Boolean)
if name = “strict” then
if value  {true, undefined} then cxt.strict  true; return end if;
if value = false then cxt.strict  false; return end if
end if;
if name = “ecmascript” then
if value  {undefined, 4f64} then return end if;
if value  {1f64, 2f64, 3f64} then
An implementation may optionally modify cxt to disable features not available in ECMAScript Edition value other than subsequent pragmas.
return
end if
end if;
if not optional then throw a SyntaxError exception end if
end proc;
Definitions
Export Definition
Syntax
ExportDefinition  export ExportBindingList
ExportBindingList 
	ExportBinding
|	ExportBindingList , ExportBinding
ExportBinding 
	FunctionName
|	FunctionName = FunctionName
Variable Definition
Syntax
VariableDefinition  VariableDefinitionKind VariableBindingList
VariableDefinitionKind 
	var
|	const
VariableBindingList 
	VariableBinding
|	VariableBindingList , VariableBinding
VariableBinding  TypedIdentifier VariableInitialisation
VariableInitialisation 
	«empty»
|	= VariableInitializer
VariableInitializer 
	AssignmentExpression
|	AttributeCombination
TypedIdentifier 
	Identifier
|	Identifier : TypeExpression
Validation
proc Validate[VariableDefinition  VariableDefinitionKind VariableBindingList] (cxt: Context, env: Environment, attr: AttributeOptNotFalse)
Evaluate Validate[VariableBindingList](cxt, env, attr, Immutable[VariableDefinitionKind], false) and ignore its result
end proc;
Immutable[VariableDefinitionKind]: Boolean;
Immutable[VariableDefinitionKind  var] = false;
Immutable[VariableDefinitionKind  const] = true;
Validate[VariableBindingList] (cxt: Context, env: Environment, attr: AttributeOptNotFalse, immutable: Boolean, noInitializer: Boolean) propagates the call to Validate to nonterminals in the expansion of VariableBindingList.
CompileEnv[VariableBinding]: Environment;
CompileVar[VariableBinding]: Variable  DynamicVar  InstanceVariable;
OverriddenVar[VariableBinding]: InstanceVariableOpt;
Multiname[VariableBinding]: Multiname;
proc Validate[VariableBinding  TypedIdentifier VariableInitialisation] (cxt: Context, env: Environment, attr: AttributeOptNotFalse, immutable: Boolean, noInitializer: Boolean)
Evaluate Validate[TypedIdentifier](cxt, env) and ignore its result;
Evaluate Validate[VariableInitialisation](cxt, env) and ignore its result;
CompileEnv[VariableBinding]  env;
name: String  Name[TypedIdentifier];
if not cxt.strict and getRegionalFrame(env)  Package  ParameterFrame and not immutable and attr = none and Plain[TypedIdentifier] then
qname: QualifiedName  public::name;
Multiname[VariableBinding]  {qname};
CompileVar[VariableBinding]  defineHoistedVar(env, name, undefined)
else
a: CompoundAttribute  toCompoundAttribute(attr);
if a.dynamic then
throw an AttributeError exception — a variable definition cannot have the dynamic attribute
end if;
if a.prototype then
throw an AttributeError exception — a variable definition cannot have the prototype attribute
end if;
category: PropertyCategory  a.category;
if env[0]  Class then if category = none then category  final end if
else
if category ≠ none then
throw an AttributeError exception — non-class variables cannot have a static, virtual, or final attribute
end if
end if;
case category of
{none, static} do
initializer: InitializerOpt  Initializer[VariableInitialisation];
if noInitializer and initializer ≠ none then
throw a SyntaxError exception — a for-in statement’s variable definition must not have an initialiser
end if;
proc variableSetup(): ClassOpt
type: ClassOpt  SetupAndEval[TypedIdentifier](env);
Evaluate Setup[VariableInitialisation]() and ignore its result;
return type
end proc;
v: Variable  new Variablevalue: none, immutable: immutable, setup: variableSetup, initializer: initializer, initializerEnv: env;
multiname: Multiname  defineSingletonProperty(env, name, a.namespaces, a.overrideMod, a.explicit, readWrite, v);
Multiname[VariableBinding]  multiname;
CompileVar[VariableBinding]  v;
{virtual, final} do
note	not noInitializer;
c: Class  env[0];
v: InstanceVariable  new InstanceVariablefinal: category = final, immutable: immutable;
vOverridden: InstanceVariableOpt  defineInstanceProperty(c, cxt, name, a.namespaces, a.overrideMod, a.explicit, v);
enumerable: Boolean  a.enumerable;
if vOverridden ≠ none and vOverridden.enumerable then enumerable  true
end if;
v.enumerable  enumerable;
OverriddenVar[VariableBinding]  vOverridden;
CompileVar[VariableBinding]  v
end case
end if
end proc;
Validate[VariableInitialisation] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of VariableInitialisation.
Validate[VariableInitializer] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of VariableInitializer.
Name[TypedIdentifier]: String;
Name[TypedIdentifier  Identifier] = Name[Identifier];
Name[TypedIdentifier  Identifier : TypeExpression] = Name[Identifier];
Plain[TypedIdentifier]: Boolean;
Plain[TypedIdentifier  Identifier] = true;
Plain[TypedIdentifier  Identifier : TypeExpression] = false;
proc Validate[TypedIdentifier] (cxt: Context, env: Environment)
[TypedIdentifier  Identifier] do nothing;
[TypedIdentifier  Identifier : TypeExpression] do
Evaluate Validate[TypeExpression](cxt, env) and ignore its result
end proc;
Setup
proc Setup[VariableDefinition  VariableDefinitionKind VariableBindingList] ()
Evaluate Setup[VariableBindingList]() and ignore its result
end proc;
Setup[VariableBindingList] () propagates the call to Setup to nonterminals in the expansion of VariableBindingList.
proc Setup[VariableBinding  TypedIdentifier VariableInitialisation] ()
env: Environment  CompileEnv[VariableBinding];
v: Variable  DynamicVar  InstanceVariable  CompileVar[VariableBinding];
case v of
Variable do
Evaluate setupVariable(v) and ignore its result;
if not v.immutable then
defaultValue: ObjectOpt  v.type.defaultValue;
if defaultValue = none then
throw an UninitializedError exception — Cannot declare a mutable variable of type Never
end if;
v.value  defaultValue
end if;
DynamicVar do Evaluate Setup[VariableInitialisation]() and ignore its result;
InstanceVariable do
t: ClassOpt  SetupAndEval[TypedIdentifier](env);
if t = none then
overriddenVar: InstanceVariableOpt  OverriddenVar[VariableBinding];
if overriddenVar ≠ none then t  overriddenVar.type
else t  Object
end if
end if;
v.type  t;
Evaluate Setup[VariableInitialisation]() and ignore its result;
initializer: InitializerOpt  Initializer[VariableInitialisation];
defaultValue: ObjectOpt  none;
if initializer ≠ none then defaultValue  initializer(env, compile)
elsif not v.immutable then
defaultValue  t.defaultValue;
if defaultValue = none then
throw an UninitializedError exception — Cannot declare a mutable instance variable of type Never
end if
end if;
v.defaultValue  defaultValue
end case
end proc;
Setup[VariableInitialisation] () propagates the call to Setup to nonterminals in the expansion of VariableInitialisation.
Setup[VariableInitializer] () propagates the call to Setup to nonterminals in the expansion of VariableInitializer.
Evaluation
proc Eval[VariableDefinition  VariableDefinitionKind VariableBindingList] (env: Environment, d: Object): Object
Evaluate Eval[VariableBindingList](env) and ignore its result;
return d
end proc;
Eval[VariableBindingList] (env: Environment) propagates the call to Eval to nonterminals in the expansion of VariableBindingList.
proc Eval[VariableBinding  TypedIdentifier VariableInitialisation] (env: Environment)
case CompileVar[VariableBinding] of
Variable do
innerFrame: NonWithFrame  env[0];
properties: SingletonProperty{}  {b.content | b  innerFrame.localBindings such that b.qname  Multiname[VariableBinding]};
note	The properties set consists of exactly one Variable element because innerFrame was constructed with that Variable inside Validate.
v: Variable  the one element of properties;
initializer: Initializer  {none, busy}  v.initializer;
case initializer of
{none} do nothing;
{busy} do throw a ReferenceError exception;
Initializer do
v.initializer  busy;
value: Object  initializer(v.initializerEnv, run);
Evaluate writeVariable(v, value, true) and ignore its result
end case;
DynamicVar do
initializer: InitializerOpt  Initializer[VariableInitialisation];
if initializer ≠ none then
value: Object  initializer(env, run);
Evaluate lexicalWrite(env, Multiname[VariableBinding], value, false, run) and ignore its result
end if;
InstanceVariable do nothing
end case
end proc;
proc WriteBinding[VariableBinding  TypedIdentifier VariableInitialisation] (env: Environment, newValue: Object)
case CompileVar[VariableBinding] of
Variable do
innerFrame: NonWithFrame  env[0];
properties: SingletonProperty{}  {b.content | b  innerFrame.localBindings such that b.qname  Multiname[VariableBinding]};
note	The properties set consists of exactly one Variable element because innerFrame was constructed with that Variable inside Validate.
v: Variable  the one element of properties;
Evaluate writeVariable(v, newValue, false) and ignore its result;
DynamicVar do
Evaluate lexicalWrite(env, Multiname[VariableBinding], newValue, false, run) and ignore its result
end case
end proc;
Initializer[VariableInitialisation]: InitializerOpt;
Initializer[VariableInitialisation  «empty»] = none;
Initializer[VariableInitialisation  = VariableInitializer] = Eval[VariableInitializer];
proc Eval[VariableInitializer] (env: Environment, phase: Phase): Object
[VariableInitializer  AssignmentExpression] do
return readReference(Eval[AssignmentExpression](env, phase), phase);
[VariableInitializer  AttributeCombination] do
return Eval[AttributeCombination](env, phase)
end proc;
proc SetupAndEval[TypedIdentifier] (env: Environment): ClassOpt
[TypedIdentifier  Identifier] do return none;
[TypedIdentifier  Identifier : TypeExpression] do
return SetupAndEval[TypeExpression](env)
end proc;
Simple Variable Definition
Syntax
A SimpleVariableDefinition represents the subset of VariableDefinition expansions that may be used when the variable definition is used as a Substatement instead of a Directive in non-strict mode. In strict mode variable definitions may not be used as substatements.
SimpleVariableDefinition  var UntypedVariableBindingList
UntypedVariableBindingList 
	UntypedVariableBinding
|	UntypedVariableBindingList , UntypedVariableBinding
UntypedVariableBinding  Identifier VariableInitialisationallowIn
Validation
proc Validate[SimpleVariableDefinition  var UntypedVariableBindingList] (cxt: Context, env: Environment)
if cxt.strict or getRegionalFrame(env)  Package  ParameterFrame then
throw a SyntaxError exception — a variable may not be defined in a substatement except inside a non-strict function or non-strict top-level code; to fix this error, place the definition inside a block
end if;
Evaluate Validate[UntypedVariableBindingList](cxt, env) and ignore its result
end proc;
Validate[UntypedVariableBindingList] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of UntypedVariableBindingList.
proc Validate[UntypedVariableBinding  Identifier VariableInitialisationallowIn] (cxt: Context, env: Environment)
Evaluate Validate[VariableInitialisationallowIn](cxt, env) and ignore its result;
Evaluate defineHoistedVar(env, Name[Identifier], undefined) and ignore its result
end proc;
Setup
Setup[SimpleVariableDefinition] () propagates the call to Setup to nonterminals in the expansion of SimpleVariableDefinition.
Setup[UntypedVariableBindingList] () propagates the call to Setup to nonterminals in the expansion of UntypedVariableBindingList.
proc Setup[UntypedVariableBinding  Identifier VariableInitialisationallowIn] ()
Evaluate Setup[VariableInitialisationallowIn]() and ignore its result
end proc;
Evaluation
proc Eval[SimpleVariableDefinition  var UntypedVariableBindingList] (env: Environment, d: Object): Object
Evaluate Eval[UntypedVariableBindingList](env) and ignore its result;
return d
end proc;
Eval[UntypedVariableBindingList] (env: Environment) propagates the call to Eval to nonterminals in the expansion of UntypedVariableBindingList.
proc Eval[UntypedVariableBinding  Identifier VariableInitialisationallowIn] (env: Environment)
initializer: InitializerOpt  Initializer[VariableInitialisationallowIn];
if initializer ≠ none then
value: Object  initializer(env, run);
qname: QualifiedName  public::(Name[Identifier]);
Evaluate lexicalWrite(env, {qname}, value, false, run) and ignore its result
end if
end proc;
Function Definition
Syntax
FunctionDefinition  function FunctionName FunctionCommon
FunctionName 
	Identifier
|	get [no line break] Identifier
|	set [no line break] Identifier
FunctionCommon  ( Parameters ) Result Block
Validation
OverriddenProperty[FunctionDefinition]: InstancePropertyOpt;
proc ValidateStatic[FunctionDefinition  function FunctionName FunctionCommon] (cxt: Context, env: Environment, preinst: Boolean, a: CompoundAttribute, unchecked: Boolean, hoisted: Boolean)
name: String  Name[FunctionName];
handling: Handling  Handling[FunctionName];
case handling of
{normal} do
kind: StaticFunctionKind;
if unchecked then kind  uncheckedFunction
elsif a.prototype then kind  prototypeFunction
else kind  plainFunction
end if;
f: SimpleInstance  UninstantiatedFunction  ValidateStaticFunction[FunctionCommon](cxt, env, kind);
if preinst then f  instantiateFunction(f, env) end if;
if hoisted then Evaluate defineHoistedVar(env, name, f) and ignore its result
else
v: Variable  new Variabletype: Function, value: f, immutable: true, setup: none, initializer: none;
Evaluate defineSingletonProperty(env, name, a.namespaces, a.overrideMod, a.explicit, readWrite, v) and ignore its result
end if;
{get, set} do
if a.prototype then
throw an AttributeError exception — a getter or setter cannot have the prototype attribute
end if;
note	not (unchecked or hoisted);
Evaluate Validate[FunctionCommon](cxt, env, plainFunction, handling) and ignore its result;
boundEnv: EnvironmentOpt  none;
if preinst then boundEnv  env end if;
case handling of
{get} do
getter: Getter  new Gettercall: EvalStaticGet[FunctionCommon], env: boundEnv;
Evaluate defineSingletonProperty(env, name, a.namespaces, a.overrideMod, a.explicit, read, getter) and ignore its result;
{set} do
setter: Setter  new Settercall: EvalStaticSet[FunctionCommon], env: boundEnv;
Evaluate defineSingletonProperty(env, name, a.namespaces, a.overrideMod, a.explicit, write, setter) and ignore its result
end case
end case;
OverriddenProperty[FunctionDefinition]  none
end proc;
proc ValidateInstance[FunctionDefinition  function FunctionName FunctionCommon] (cxt: Context, env: Environment, c: Class, a: CompoundAttribute, final: Boolean)
if a.prototype then
throw an AttributeError exception — an instance method cannot have the prototype attribute
end if;
handling: Handling  Handling[FunctionName];
Evaluate Validate[FunctionCommon](cxt, env, instanceFunction, handling) and ignore its result;
signature: ParameterFrame  CompileFrame[FunctionCommon];
m: InstanceProperty;
case handling of
{normal} do
m  new InstanceMethodfinal: final, signature: signature, length: signatureLength(signature), call: EvalInstanceCall[FunctionCommon];
{get} do
m  new InstanceGetterfinal: final, signature: signature, call: EvalInstanceGet[FunctionCommon];
{set} do
m  new InstanceSetterfinal: final, signature: signature, call: EvalInstanceSet[FunctionCommon]
end case;
mOverridden: InstancePropertyOpt  defineInstanceProperty(c, cxt, Name[FunctionName], a.namespaces, a.overrideMod, a.explicit, m);
enumerable: Boolean  a.enumerable;
if mOverridden ≠ none and mOverridden.enumerable then enumerable  true end if;
m.enumerable  enumerable;
OverriddenProperty[FunctionDefinition]  mOverridden
end proc;
proc ValidateConstructor[FunctionDefinition  function FunctionName FunctionCommon] (cxt: Context, env: Environment, c: Class, a: CompoundAttribute)
if a.prototype then
throw an AttributeError exception — a class constructor cannot have the prototype attribute
end if;
if Handling[FunctionName]  {get, set} then
throw a SyntaxError exception — a class constructor cannot be a getter or a setter
end if;
Evaluate Validate[FunctionCommon](cxt, env, constructorFunction, normal) and ignore its result;
if c.init ≠ none then
throw a DefinitionError exception — duplicate constructor definition
end if;
c.init  EvalInstanceInit[FunctionCommon];
OverriddenProperty[FunctionDefinition]  none
end proc;
proc Validate[FunctionDefinition  function FunctionName FunctionCommon] (cxt: Context, env: Environment, preinst: Boolean, attr: AttributeOptNotFalse)
a: CompoundAttribute  toCompoundAttribute(attr);
if a.dynamic then
throw an AttributeError exception — a function cannot have the dynamic attribute
end if;
frame: Frame  env[0];
if frame  Class then
note	preinst;
case a.category of
{static} do
Evaluate ValidateStatic[FunctionDefinition](cxt, env, preinst, a, false, false) and ignore its result;
{none} do
if Name[FunctionName] = frame.name then
Evaluate ValidateConstructor[FunctionDefinition](cxt, env, frame, a) and ignore its result
else
Evaluate ValidateInstance[FunctionDefinition](cxt, env, frame, a, false) and ignore its result
end if;
{virtual} do
Evaluate ValidateInstance[FunctionDefinition](cxt, env, frame, a, false) and ignore its result;
{final} do
Evaluate ValidateInstance[FunctionDefinition](cxt, env, frame, a, true) and ignore its result
end case
else
if a.category ≠ none then
throw an AttributeError exception — non-class functions cannot have a static, virtual, or final attribute
end if;
unchecked: Boolean  not cxt.strict and Handling[FunctionName] = normal and Plain[FunctionCommon];
hoisted: Boolean  unchecked and attr = none and (frame  Package or (frame  LocalFrame and env[1]  ParameterFrame));
Evaluate ValidateStatic[FunctionDefinition](cxt, env, preinst, a, unchecked, hoisted) and ignore its result
end if
end proc;
Handling[FunctionName]: Handling;
Handling[FunctionName  Identifier] = normal;
Handling[FunctionName  get [no line break] Identifier] = get;
Handling[FunctionName  set [no line break] Identifier] = set;
Name[FunctionName]: String;
Name[FunctionName  Identifier] = Name[Identifier];
Name[FunctionName  get [no line break] Identifier] = Name[Identifier];
Name[FunctionName  set [no line break] Identifier] = Name[Identifier];
Plain[FunctionCommon  ( Parameters ) Result Block]: Boolean = Plain[Parameters] and Plain[Result];
CompileEnv[FunctionCommon]: Environment;
CompileFrame[FunctionCommon]: ParameterFrame;
proc Validate[FunctionCommon  ( Parameters ) Result Block] (cxt: Context, env: Environment, kind: FunctionKind, handling: Handling)
localCxt: Context  new Contextstrict: cxt.strict, openNamespaces: cxt.openNamespaces;
superconstructorCalled: Boolean  kind ≠ constructorFunction;
compileFrame: ParameterFrame  new ParameterFramelocalBindings: {}, kind: kind, handling: handling, callsSuperconstructor: false, superconstructorCalled: superconstructorCalled, this: none, parameters: [], rest: none;
compileEnv: Environment  [compileFrame]  env;
CompileFrame[FunctionCommon]  compileFrame;
CompileEnv[FunctionCommon]  compileEnv;
if kind = uncheckedFunction then
Evaluate defineHoistedVar(compileEnv, “arguments”, undefined) and ignore its result
end if;
Evaluate Validate[Parameters](localCxt, compileEnv, compileFrame) and ignore its result;
Evaluate Validate[Result](localCxt, compileEnv) and ignore its result;
Evaluate Validate[Block](localCxt, compileEnv, JumpTargetsbreakTargets: {}, continueTargets: {}, false) and ignore its result
end proc;
proc ValidateStaticFunction[FunctionCommon  ( Parameters ) Result Block] (cxt: Context, env: Environment, kind: StaticFunctionKind): UninstantiatedFunction
Evaluate Validate[FunctionCommon](cxt, env, kind, normal) and ignore its result;
length: Integer  ParameterCount[Parameters];
case kind of
{plainFunction} do
return new UninstantiatedFunctiontype: Function, length: length, call: EvalStaticCall[FunctionCommon], construct: none, instantiations: {};
{uncheckedFunction, prototypeFunction} do
return new UninstantiatedFunctiontype: PrototypeFunction, length: length, call: EvalStaticCall[FunctionCommon], construct: EvalPrototypeConstruct[FunctionCommon], instantiations: {}
end case
end proc;
Setup
proc Setup[FunctionDefinition  function FunctionName FunctionCommon] ()
overriddenProperty: InstancePropertyOpt  OverriddenProperty[FunctionDefinition];
case overriddenProperty of
{none} do Evaluate Setup[FunctionCommon]() and ignore its result;
InstanceMethod  InstanceGetter  InstanceSetter do
Evaluate SetupOverride[FunctionCommon](overriddenProperty.signature) and ignore its result;
InstanceVariable do
overriddenSignature: ParameterFrame;
case Handling[FunctionName] of
{normal} do
This cannot happen because ValidateInstance already ensured that a function cannot override an instance variable.
{get} do
overriddenSignature  new ParameterFramelocalBindings: {}, kind: instanceFunction, handling: get, callsSuperconstructor: false, superconstructorCalled: false, this: none, parameters: [], rest: none, returnType: overriddenProperty.type;
{set} do
v: Variable  new Variabletype: overriddenProperty.type, value: none, immutable: false, setup: none, initializer: none;
parameters: Parameter[]  [Parametervar: v, default: none];
overriddenSignature  new ParameterFramelocalBindings: {}, kind: instanceFunction, handling: set, callsSuperconstructor: false, superconstructorCalled: false, this: none, parameters: parameters, rest: none, returnType: Void
end case;
Evaluate SetupOverride[FunctionCommon](overriddenSignature) and ignore its result
end case
end proc;
proc Setup[FunctionCommon  ( Parameters ) Result Block] ()
compileEnv: Environment  CompileEnv[FunctionCommon];
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
Evaluate Setup[Parameters](compileEnv, compileFrame) and ignore its result;
Evaluate checkAccessorParameters(compileFrame) and ignore its result;
Evaluate Setup[Result](compileEnv, compileFrame) and ignore its result;
Evaluate Setup[Block]() and ignore its result
end proc;
proc SetupOverride[FunctionCommon  ( Parameters ) Result Block] (overriddenSignature: ParameterFrame)
compileEnv: Environment  CompileEnv[FunctionCommon];
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
Evaluate SetupOverride[Parameters](compileEnv, compileFrame, overriddenSignature) and ignore its result;
Evaluate checkAccessorParameters(compileFrame) and ignore its result;
Evaluate SetupOverride[Result](compileEnv, compileFrame, overriddenSignature) and ignore its result;
Evaluate Setup[Block]() and ignore its result
end proc;
Evaluation
proc EvalStaticCall[FunctionCommon  ( Parameters ) Result Block] (this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call user-defined functions
end if;
runtimeEnv: Environment  f.env;
runtimeThis: ObjectOpt  none;
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
if compileFrame.kind  {uncheckedFunction, prototypeFunction} then
if this  PrimitiveObject then runtimeThis  getPackageFrame(runtimeEnv)
else runtimeThis  this
end if
end if;
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, runtimeEnv, runtimeThis);
Evaluate assignArguments(runtimeFrame, f, args, phase) and ignore its result;
result: Object;
try
Evaluate Eval[Block]([runtimeFrame]  runtimeEnv, undefined) and ignore its result;
result  undefined
catch x: SemanticException do
if x  Return then result  x.value else throw x end if
end try;
return coerce(result, runtimeFrame.returnType)
end proc;
proc EvalStaticGet[FunctionCommon  ( Parameters ) Result Block] (runtimeEnv: Environment, phase: Phase): Object
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call user-defined getters
end if;
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, runtimeEnv, none);
Evaluate assignArguments(runtimeFrame, none, [], phase) and ignore its result;
result: Object;
try
Evaluate Eval[Block]([runtimeFrame]  runtimeEnv, undefined) and ignore its result;
throw a SyntaxError exception — a getter must return a value and may not return by falling off the end of its code
catch x: SemanticException do
if x  Return then result  x.value else throw x end if
end try;
return coerce(result, runtimeFrame.returnType)
end proc;
proc EvalStaticSet[FunctionCommon  ( Parameters ) Result Block] (newValue: Object, runtimeEnv: Environment, phase: Phase)
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call setters
end if;
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, runtimeEnv, none);
Evaluate assignArguments(runtimeFrame, none, [newValue], phase) and ignore its result;
try
Evaluate Eval[Block]([runtimeFrame]  runtimeEnv, undefined) and ignore its result
catch x: SemanticException do if x  Return then throw x end if
end try
end proc;
proc EvalInstanceCall[FunctionCommon  ( Parameters ) Result Block] (this: Object, args: Object[], phase: Phase): Object
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call user-defined functions
end if;
note	Class frames are always preinstantiated, so the run environment is the same as compile environment.
env: Environment  CompileEnv[FunctionCommon];
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, env, this);
Evaluate assignArguments(runtimeFrame, none, args, phase) and ignore its result;
result: Object;
try
Evaluate Eval[Block]([runtimeFrame]  env, undefined) and ignore its result;
result  undefined
catch x: SemanticException do
if x  Return then result  x.value else throw x end if
end try;
return coerce(result, runtimeFrame.returnType)
end proc;
proc EvalInstanceGet[FunctionCommon  ( Parameters ) Result Block] (this: Object, phase: Phase): Object
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call user-defined getters
end if;
note	Class frames are always preinstantiated, so the run environment is the same as compile environment.
env: Environment  CompileEnv[FunctionCommon];
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, env, this);
Evaluate assignArguments(runtimeFrame, none, [], phase) and ignore its result;
result: Object;
try
Evaluate Eval[Block]([runtimeFrame]  env, undefined) and ignore its result;
throw a SyntaxError exception — a getter must return a value and may not return by falling off the end of its code
catch x: SemanticException do
if x  Return then result  x.value else throw x end if
end try;
return coerce(result, runtimeFrame.returnType)
end proc;
proc EvalInstanceSet[FunctionCommon  ( Parameters ) Result Block] (this: Object, newValue: Object, phase: Phase)
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call setters
end if;
note	Class frames are always preinstantiated, so the run environment is the same as compile environment.
env: Environment  CompileEnv[FunctionCommon];
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, env, this);
Evaluate assignArguments(runtimeFrame, none, [newValue], phase) and ignore its result;
try Evaluate Eval[Block]([runtimeFrame]  env, undefined) and ignore its result
catch x: SemanticException do if x  Return then throw x end if
end try
end proc;
proc EvalInstanceInit[FunctionCommon  ( Parameters ) Result Block] (this: SimpleInstance, args: Object[], phase: {run})
note	Class frames are always preinstantiated, so the run environment is the same as compile environment.
env: Environment  CompileEnv[FunctionCommon];
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, env, this);
Evaluate assignArguments(runtimeFrame, none, args, phase) and ignore its result;
if not runtimeFrame.callsSuperconstructor then
c: Class  getEnclosingClass(env);
Evaluate callInit(this, c.super, [], run) and ignore its result;
runtimeFrame.superconstructorCalled  true
end if;
try Evaluate Eval[Block]([runtimeFrame]  env, undefined) and ignore its result
catch x: SemanticException do if x  Return then throw x end if
end try;
if not runtimeFrame.superconstructorCalled then
throw an UninitializedError exception — the superconstructor must be called before returning normally from a constructor
end if
end proc;
proc EvalPrototypeConstruct[FunctionCommon  ( Parameters ) Result Block] (f: SimpleInstance, args: Object[], phase: Phase): Object
note	The check that phase ≠ compile also ensures that Setup has been called.
if phase = compile then
throw a ConstantError exception — a constant expression cannot call user-defined prototype constructors
end if;
runtimeEnv: Environment  f.env;
archetype: Object  dotRead(f, {public::“prototype”}, phase);
if archetype  {null, undefined} then archetype  ObjectPrototype
elsif objectType(archetype) ≠ Object then
throw a TypeError exception — bad prototype value
end if;
o: Object  createSimpleInstance(Object, archetype, none, none, none);
compileFrame: ParameterFrame  CompileFrame[FunctionCommon];
runtimeFrame: ParameterFrame  instantiateParameterFrame(compileFrame, runtimeEnv, o);
Evaluate assignArguments(runtimeFrame, f, args, phase) and ignore its result;
result: Object;
try
Evaluate Eval[Block]([runtimeFrame]  runtimeEnv, undefined) and ignore its result;
result  undefined
catch x: SemanticException do
if x  Return then result  x.value else throw x end if
end try;
coercedResult: Object  coerce(result, runtimeFrame.returnType);
if coercedResult  PrimitiveObject then return o else return coercedResult end if
end proc;
proc checkAccessorParameters(frame: ParameterFrame)
parameters: Parameter[]  frame.parameters;
rest: VariableOpt  frame.rest;
case frame.handling of
{normal} do nothing;
{get} do
if parameters ≠ [] or rest ≠ none then
throw a SyntaxError exception — a getter cannot take any parameters
end if;
{set} do
if |parameters| ≠ 1 or rest ≠ none then
throw a SyntaxError exception — a setter must take exactly one parameter
end if;
if parameters[0].default ≠ none then
throw a SyntaxError exception — a setter’s parameter cannot be optional
end if
end case
end proc;
proc assignArguments(runtimeFrame: ParameterFrame, f: SimpleInstance  {none}, args: Object[], phase: {run})
This procedure performs a number of checks on the arguments, including checking their count, names, and values. Although this procedure performs these checks in a specific order for expository purposes, an implementation may perform these checks in a different order, which could have the effect of reporting a different error if there are multiple errors. For example, if a function only allows between 2 and 4 arguments, the first of which must be a Number and is passed five arguments the first of which is a String, then the implementation may throw an exception either about the argument count mismatch or about the type coercion error in the first argument.
argumentsObject: ObjectOpt  none;
if runtimeFrame.kind = uncheckedFunction then
argumentsObject  construct(Array, [], phase);
Evaluate createDynamicProperty(argumentsObject, public::“callee”, false, false, f) and ignore its result;
Evaluate writeArrayPrivateLength(argumentsObject, |args|, phase) and ignore its result
end if;
restObject: ObjectOpt  none;
rest: Variable  {none}  runtimeFrame.rest;
if rest ≠ none then restObject  construct(Array, [], phase) end if;
parameters: Parameter[]  runtimeFrame.parameters;
i: Integer  0;
j: Integer  0;
for each arg  args do
if i < |parameters| then
parameter: Parameter  parameters[i];
default: ObjectOpt  parameter.default;
argOrDefault: Object  arg;
if argOrDefault = undefined and default ≠ none then argOrDefault  default
end if;
v: DynamicVar  Variable  parameter.var;
Evaluate writeSingletonProperty(v, argOrDefault, phase) and ignore its result;
if argumentsObject ≠ none then
note	Create an alias of v as the ith entry of the arguments object.
note	v  DynamicVar;
qname: QualifiedName  objectToQualifiedName(if64, phase);
argumentsObject.localBindings  argumentsObject.localBindings  {LocalBindingqname: qname, accesses: readWrite, explicit: false, enumerable: false, content: v}
end if
elsif restObject ≠ none then
if j ≥ arrayLimit then throw a RangeError exception end if;
Evaluate indexWrite(restObject, j, arg, phase) and ignore its result;
note	argumentsObject = none because a function can't have both a rest parameter and an arguments object.
j  j + 1
elsif argumentsObject ≠ none then
Evaluate indexWrite(argumentsObject, i, arg, phase) and ignore its result
else
throw an ArgumentError exception — more arguments than parameters were supplied, and the called function does not have a ... parameter and is not unchecked.
end if;
i  i + 1
end for each;
while i < |parameters| do
parameter: Parameter  parameters[i];
default: ObjectOpt  parameter.default;
if default = none then
if argumentsObject ≠ none then default  undefined
else
throw an ArgumentError exception — fewer arguments than parameters were supplied, and the called function does not supply default values for the missing parameters and is not unchecked.
end if
end if;
Evaluate writeSingletonProperty(parameter.var, default, phase) and ignore its result;
i  i + 1
end while
end proc;
proc signatureLength(signature: ParameterFrame): Integer
return |signature.parameters|
end proc;
Syntax
Parameters 
	«empty»
|	NonemptyParameters
NonemptyParameters 
	ParameterInit
|	ParameterInit , NonemptyParameters
|	RestParameter
Parameter  ParameterAttributes TypedIdentifierallowIn
ParameterAttributes 
	«empty»
|	const
ParameterInit 
	Parameter
|	Parameter = AssignmentExpressionallowIn
RestParameter 
	...
|	... ParameterAttributes Identifier
Result 
	«empty»
|	: TypeExpressionallowIn
Validation
Plain[Parameters]: Boolean;
Plain[Parameters  «empty»] = true;
Plain[Parameters  NonemptyParameters] = Plain[NonemptyParameters];
ParameterCount[Parameters]: Integer;
ParameterCount[Parameters  «empty»] = 0;
ParameterCount[Parameters  NonemptyParameters] = ParameterCount[NonemptyParameters];
Validate[Parameters] (cxt: Context, env: Environment, compileFrame: ParameterFrame) propagates the call to Validate to nonterminals in the expansion of Parameters.
Plain[NonemptyParameters]: Boolean;
Plain[NonemptyParameters  ParameterInit] = Plain[ParameterInit];
Plain[NonemptyParameters0  ParameterInit , NonemptyParameters1] = Plain[ParameterInit] and Plain[NonemptyParameters1];
Plain[NonemptyParameters  RestParameter] = false;
ParameterCount[NonemptyParameters]: Integer;
ParameterCount[NonemptyParameters  ParameterInit] = 1;
ParameterCount[NonemptyParameters0  ParameterInit , NonemptyParameters1] = 1 + ParameterCount[NonemptyParameters1];
ParameterCount[NonemptyParameters  RestParameter] = 0;
Validate[NonemptyParameters] (cxt: Context, env: Environment, compileFrame: ParameterFrame) propagates the call to Validate to nonterminals in the expansion of NonemptyParameters.
Name[Parameter  ParameterAttributes TypedIdentifierallowIn]: String = Name[TypedIdentifierallowIn];
Plain[Parameter  ParameterAttributes TypedIdentifierallowIn]: Boolean = Plain[TypedIdentifierallowIn] and not HasConst[ParameterAttributes];
CompileVar[Parameter]: DynamicVar  Variable;
proc Validate[Parameter  ParameterAttributes TypedIdentifierallowIn] (cxt: Context, env: Environment, compileFrame: ParameterFrame  LocalFrame)
Evaluate Validate[TypedIdentifierallowIn](cxt, env) and ignore its result;
immutable: Boolean  HasConst[ParameterAttributes];
name: String  Name[TypedIdentifierallowIn];
v: DynamicVar  Variable;
if compileFrame  ParameterFrame and compileFrame.kind = uncheckedFunction then
note	not immutable;
v  defineHoistedVar(env, name, undefined)
else
v  new Variablevalue: none, immutable: immutable, setup: none, initializer: none;
Evaluate defineSingletonProperty(env, name, {public}, none, false, readWrite, v) and ignore its result
end if;
CompileVar[Parameter]  v
end proc;
HasConst[ParameterAttributes]: Boolean;
HasConst[ParameterAttributes  «empty»] = false;
HasConst[ParameterAttributes  const] = true;
Plain[ParameterInit]: Boolean;
Plain[ParameterInit  Parameter] = Plain[Parameter];
Plain[ParameterInit  Parameter = AssignmentExpressionallowIn] = false;
proc Validate[ParameterInit] (cxt: Context, env: Environment, compileFrame: ParameterFrame)
[ParameterInit  Parameter] do
Evaluate Validate[Parameter](cxt, env, compileFrame) and ignore its result;
[ParameterInit  Parameter = AssignmentExpressionallowIn] do
Evaluate Validate[Parameter](cxt, env, compileFrame) and ignore its result;
Evaluate Validate[AssignmentExpressionallowIn](cxt, env) and ignore its result
end proc;
proc Validate[RestParameter] (cxt: Context, env: Environment, compileFrame: ParameterFrame)
[RestParameter  ...] do
note	compileFrame.kind ≠ uncheckedFunction;
v: Variable  new Variabletype: Array, value: none, immutable: true, setup: none, initializer: none;
compileFrame.rest  v;
[RestParameter  ... ParameterAttributes Identifier] do
note	compileFrame.kind ≠ uncheckedFunction;
v: Variable  new Variabletype: Array, value: none, immutable: HasConst[ParameterAttributes], setup: none, initializer: none;
compileFrame.rest  v;
name: String  Name[Identifier];
Evaluate defineSingletonProperty(env, name, {public}, none, false, readWrite, v) and ignore its result
end proc;
Plain[Result]: Boolean;
Plain[Result  «empty»] = true;
Plain[Result  : TypeExpressionallowIn] = false;
Validate[Result] (cxt: Context, env: Environment) propagates the call to Validate to nonterminals in the expansion of Result.
Setup
Setup[Parameters] (compileEnv: Environment, compileFrame: ParameterFrame) propagates the call to Setup to nonterminals in the expansion of Parameters.
proc SetupOverride[Parameters] (compileEnv: Environment, compileFrame: ParameterFrame, overriddenSignature: ParameterFrame)
[Parameters  «empty»] do
if overriddenSignature.parameters ≠ [] or overriddenSignature.rest ≠ none then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
[Parameters  NonemptyParameters] do
Evaluate SetupOverride[NonemptyParameters](compileEnv, compileFrame, overriddenSignature, overriddenSignature.parameters) and ignore its result
end proc;
proc Setup[NonemptyParameters] (compileEnv: Environment, compileFrame: ParameterFrame)
[NonemptyParameters  ParameterInit] do
Evaluate Setup[ParameterInit](compileEnv, compileFrame) and ignore its result;
[NonemptyParameters0  ParameterInit , NonemptyParameters1] do
Evaluate Setup[ParameterInit](compileEnv, compileFrame) and ignore its result;
Evaluate Setup[NonemptyParameters1](compileEnv, compileFrame) and ignore its result;
[NonemptyParameters  RestParameter] do nothing
end proc;
proc SetupOverride[NonemptyParameters] (compileEnv: Environment, compileFrame: ParameterFrame, overriddenSignature: ParameterFrame, overriddenParameters: Parameter[])
[NonemptyParameters  ParameterInit] do
if overriddenParameters = [] then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
Evaluate SetupOverride[ParameterInit](compileEnv, compileFrame, overriddenParameters[0]) and ignore its result;
if |overriddenParameters| ≠ 1 or overriddenSignature.rest ≠ none then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
[NonemptyParameters0  ParameterInit , NonemptyParameters1] do
if overriddenParameters = [] then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
Evaluate SetupOverride[ParameterInit](compileEnv, compileFrame, overriddenParameters[0]) and ignore its result;
Evaluate SetupOverride[NonemptyParameters1](compileEnv, compileFrame, overriddenSignature, overriddenParameters[1 ...]) and ignore its result;
[NonemptyParameters  RestParameter] do
if overriddenParameters ≠ [] then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
overriddenRest: Variable  {none}  overriddenSignature.rest;
if overriddenRest = none or overriddenRest.type ≠ Array then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if
end proc;
proc Setup[Parameter  ParameterAttributes TypedIdentifierallowIn] (compileEnv: Environment, compileFrame: ParameterFrame  LocalFrame, default: ObjectOpt)
if compileFrame  ParameterFrame and default = none and (some p2  compileFrame.parameters satisfies p2.default ≠ none) then
throw a SyntaxError exception — a required parameter cannot follow an optional one
end if;
v: DynamicVar  Variable  CompileVar[Parameter];
case v of
DynamicVar do nothing;
Variable do
type: ClassOpt  SetupAndEval[TypedIdentifierallowIn](compileEnv);
if type = none then type  Object end if;
v.type  type
end case;
if compileFrame  ParameterFrame then
p: Parameter  Parametervar: v, default: default;
compileFrame.parameters  compileFrame.parameters  [p]
end if
end proc;
proc SetupOverride[Parameter  ParameterAttributes TypedIdentifierallowIn] (compileEnv: Environment, compileFrame: ParameterFrame, default: ObjectOpt, overriddenParameter: Parameter)
newDefault: ObjectOpt  default;
if newDefault = none then newDefault  overriddenParameter.default end if;
if default = none and (some p2  compileFrame.parameters satisfies p2.default ≠ none) then
throw a SyntaxError exception — a required parameter cannot follow an optional one
end if;
v: DynamicVar  Variable  CompileVar[Parameter];
note	v  DynamicVar;
type: ClassOpt  SetupAndEval[TypedIdentifierallowIn](compileEnv);
if type = none then type  Object end if;
if type ≠ overriddenParameter.var.type then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
v.type  type;
p: Parameter  Parametervar: v, default: newDefault;
compileFrame.parameters  compileFrame.parameters  [p]
end proc;
proc Setup[ParameterInit] (compileEnv: Environment, compileFrame: ParameterFrame)
[ParameterInit  Parameter] do
Evaluate Setup[Parameter](compileEnv, compileFrame, none) and ignore its result;
[ParameterInit  Parameter = AssignmentExpressionallowIn] do
Evaluate Setup[AssignmentExpressionallowIn]() and ignore its result;
default: Object  readReference(Eval[AssignmentExpressionallowIn](compileEnv, compile), compile);
Evaluate Setup[Parameter](compileEnv, compileFrame, default) and ignore its result
end proc;
proc SetupOverride[ParameterInit] (compileEnv: Environment, compileFrame: ParameterFrame, overriddenParameter: Parameter)
[ParameterInit  Parameter] do
Evaluate SetupOverride[Parameter](compileEnv, compileFrame, none, overriddenParameter) and ignore its result;
[ParameterInit  Parameter = AssignmentExpressionallowIn] do
Evaluate Setup[AssignmentExpressionallowIn]() and ignore its result;
default: Object  readReference(Eval[AssignmentExpressionallowIn](compileEnv, compile), compile);
Evaluate SetupOverride[Parameter](compileEnv, compileFrame, default, overriddenParameter) and ignore its result
end proc;
proc Setup[Result] (compileEnv: Environment, compileFrame: ParameterFrame)
[Result  «empty»] do
defaultReturnType: Class  Object;
if cannotReturnValue(compileFrame) then defaultReturnType  Void end if;
compileFrame.returnType  defaultReturnType;
[Result  : TypeExpressionallowIn] do
if cannotReturnValue(compileFrame) then
throw a SyntaxError exception — a setter or constructor cannot define a return type
end if;
compileFrame.returnType  SetupAndEval[TypeExpressionallowIn](compileEnv)
end proc;
proc SetupOverride[Result] (compileEnv: Environment, compileFrame: ParameterFrame, overriddenSignature: ParameterFrame)
[Result  «empty»] do compileFrame.returnType  overriddenSignature.returnType;
[Result  : TypeExpressionallowIn] do
t: Class  SetupAndEval[TypeExpressionallowIn](compileEnv);
if overriddenSignature.returnType ≠ t then
throw a DefinitionError exception — mismatch with the overridden method’s signature
end if;
compileFrame.returnType  t
end proc;
Class Definition
Syntax
ClassDefinition  class Identifier Inheritance Block
Inheritance 
	«empty»
|	extends TypeExpressionallowIn
Validation
Class[ClassDefinition]: Class;
proc Validate[ClassDefinition  class Identifier Inheritance Block] (cxt: Context, env: Environment, preinst: Boolean, attr: AttributeOptNotFalse)
if not preinst then
throw a SyntaxError exception — a class may be defined only in a preinstantiated scope
end if;
super: Class  Validate[Inheritance](cxt, env);
if not super.complete then
throw a ConstantError exception — cannot override a class before its definition has been compiled
end if;
if super.final then throw a DefinitionError exception — can’t override a final class
end if;
a: CompoundAttribute  toCompoundAttribute(attr);
if a.prototype then
throw an AttributeError exception — a class definition cannot have the prototype attribute
end if;
final: Boolean;
case a.category of
{none} do final  false;
{static} do
if env[0]  Class then
throw an AttributeError exception — non-class property definitions cannot have a static attribute
end if;
final  false;
{final} do final  true;
{virtual} do
throw an AttributeError exception — a class definition cannot have the virtual attribute
end case;
privateNamespace: Namespace  new Namespacename: “private”;
dynamic: Boolean  a.dynamic or (super.dynamic and super ≠ Object);
c: Class  new ClasslocalBindings: {}, instanceProperties: {}, super: super, prototype: super.prototype, complete: false, name: Name[Identifier], typeofString: “object”, privateNamespace: privateNamespace, dynamic: dynamic, final: final, defaultValue: null, defaultHint: hintNumber, hasProperty: super.hasProperty, bracketRead: super.bracketRead, bracketWrite: super.bracketWrite, bracketDelete: super.bracketDelete, read: super.read, write: super.write, delete: super.delete, enumerate: super.enumerate, call: ordinaryCall, construct: ordinaryConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
Class[ClassDefinition]  c;
v: Variable  new Variabletype: Class, value: c, immutable: true, setup: none, initializer: none;
Evaluate defineSingletonProperty(env, Name[Identifier], a.namespaces, a.overrideMod, a.explicit, readWrite, v) and ignore its result;
innerCxt: Context  new Contextstrict: cxt.strict, openNamespaces: cxt.openNamespaces  {privateNamespace};
Evaluate ValidateUsingFrame[Block](innerCxt, env, JumpTargetsbreakTargets: {}, continueTargets: {}, preinst, c) and ignore its result;
if c.init = none then c.init  super.init end if;
c.complete  true
end proc;
proc Validate[Inheritance] (cxt: Context, env: Environment): Class
[Inheritance  «empty»] do return Object;
[Inheritance  extends TypeExpressionallowIn] do
Evaluate Validate[TypeExpressionallowIn](cxt, env) and ignore its result;
return SetupAndEval[TypeExpressionallowIn](env)
end proc;
Setup
proc Setup[ClassDefinition  class Identifier Inheritance Block] ()
Evaluate Setup[Block]() and ignore its result
end proc;
Evaluation
proc Eval[ClassDefinition  class Identifier Inheritance Block] (env: Environment, d: Object): Object
c: Class  Class[ClassDefinition];
return EvalUsingFrame[Block](env, c, d)
end proc;
Namespace Definition
Syntax
NamespaceDefinition  namespace Identifier
Validation
proc Validate[NamespaceDefinition  namespace Identifier] (cxt: Context, env: Environment, preinst: Boolean, attr: AttributeOptNotFalse)
if not preinst then
throw a SyntaxError exception — a namespace may be defined only in a preinstantiated scope
end if;
a: CompoundAttribute  toCompoundAttribute(attr);
if a.dynamic then
throw an AttributeError exception — a namespace definition cannot have the dynamic attribute
end if;
if a.prototype then
throw an AttributeError exception — a namespace definition cannot have the prototype attribute
end if;
case a.category of
{none} do nothing;
{static} do
if env[0]  Class then
throw an AttributeError exception — non-class property definitions cannot have a static attribute
end if;
{virtual, final} do
throw an AttributeError exception — a namespace definition cannot have the virtual or final attribute
end case;
name: String  Name[Identifier];
ns: Namespace  new Namespacename: name;
v: Variable  new Variabletype: Namespace, value: ns, immutable: true, setup: none, initializer: none;
Evaluate defineSingletonProperty(env, name, a.namespaces, a.overrideMod, a.explicit, readWrite, v) and ignore its result
end proc;
Programs
Syntax
Program 
	Directives
|	PackageDefinition Program
Processing
Process[Program]: Object;
Process[Program  Directives]
begin
cxt: Context  new Contextstrict: false, openNamespaces: {public, internal};
initialEnvironment: Environment  [createGlobalObject()];
Evaluate Validate[Directives](cxt, initialEnvironment, JumpTargetsbreakTargets: {}, continueTargets: {}, true, none) and ignore its result;
Evaluate Setup[Directives]() and ignore its result;
return Eval[Directives](initialEnvironment, undefined)
end;
Process[Program0  PackageDefinition Program1]
begin
Evaluate Process[PackageDefinition] and ignore its result;
return Process[Program1]
end;
Package Definition
Syntax
PackageDefinition  package PackageNameOpt Block
PackageNameOpt 
	«empty»
|	PackageName
PackageName 
	String
|	PackageIdentifiers
PackageIdentifiers 
	Identifier
|	PackageIdentifiers . Identifier
Processing
Process[PackageDefinition  package PackageNameOpt Block]: Void
begin
name: String  Name[PackageNameOpt];
cxt: Context  new Contextstrict: false, openNamespaces: {public, internal};
globalObject: Package  createGlobalObject();
pkgInternal: Namespace  new Namespacename: “internal”;
pkg: Package  new PackagelocalBindings: {stdExplicitConstBinding(internal::“internal”, Namespace, internal)}, archetype: ObjectPrototype, name: name, initialize: busy, sealed: true, internalNamespace: pkgInternal;
initialEnvironment: Environment  [pkg, globalObject];
Evaluate Validate[Block](cxt, initialEnvironment, JumpTargetsbreakTargets: {}, continueTargets: {}, true) and ignore its result;
Evaluate Setup[Block]() and ignore its result;
proc evalPackage()
pkg.initialize  busy;
Evaluate Eval[Block](initialEnvironment, undefined) and ignore its result;
pkg.initialize  none
end proc;
pkg.initialize  evalPackage;
Bind name to package pkg in the system’s list of packages in an implementation-defined manner.
end;
Name[PackageNameOpt]: String;
Name[PackageNameOpt  «empty»] = an implementation-supplied name;
Name[PackageNameOpt  PackageName] = Name[PackageName];
Name[PackageName]: String;
Name[PackageName  String] = Value[String] processed in an implementation-defined manner;
Name[PackageName  PackageIdentifiers] = Names[PackageIdentifiers] processed in an implementation-defined manner;
Names[PackageIdentifiers]: String[];
Names[PackageIdentifiers  Identifier] = [Name[Identifier]];
Names[PackageIdentifiers0  PackageIdentifiers1 . Identifier] = Names[PackageIdentifiers1]  [Name[Identifier]];
packageDatabase: Package{}  {};
Predefined Identifiers
proc createGlobalObject(): Package
return new PackagelocalBindings: {
stdExplicitConstBinding(internal::“internal”, Namespace, internal),
stdConstBinding(public::“explicit”, Attribute, global_explicit),
stdConstBinding(public::“enumerable”, Attribute, global_enumerable),
stdConstBinding(public::“dynamic”, Attribute, global_dynamic),
stdConstBinding(public::“static”, Attribute, global_static),
stdConstBinding(public::“virtual”, Attribute, global_virtual),
stdConstBinding(public::“final”, Attribute, global_final),
stdConstBinding(public::“prototype”, Attribute, global_prototype),
stdConstBinding(public::“unused”, Attribute, global_unused),
stdFunction(public::“override”, global_override, 1),
stdConstBinding(public::“NaN”, Number, NaNf64),
stdConstBinding(public::“Infinity”, Number, +∞f64),
stdConstBinding(public::“fNaN”, float, NaNf32),
stdConstBinding(public::“fInfinity”, float, +∞f32),
stdConstBinding(public::“undefined”, Void, undefined),
stdFunction(public::“eval”, global_eval, 1),
stdFunction(public::“parseInt”, global_parseint, 2),
stdFunction(public::“parseLong”, global_parselong, 2),
stdFunction(public::“parseFloat”, global_parsefloat, 1),
stdFunction(public::“isNaN”, global_isnan, 1),
stdFunction(public::“isFinite”, global_isfinite, 1),
stdFunction(public::“decodeURI”, global_decodeuri, 1),
stdFunction(public::“decodeURIComponent”, global_decodeuricomponent, 1),
stdFunction(public::“encodeURI”, global_encodeuri, 1),
stdFunction(public::“encodeURIComponent”, global_encodeuricomponent, 1),
stdConstBinding(public::“Object”, Class, Object),
stdConstBinding(public::“Never”, Class, Never),
stdConstBinding(public::“Void”, Class, Void),
stdConstBinding(public::“Null”, Class, Null),
stdConstBinding(public::“Boolean”, Class, Boolean),
stdConstBinding(public::“GeneralNumber”, Class, GeneralNumber),
stdConstBinding(public::“long”, Class, long),
stdConstBinding(public::“ulong”, Class, ulong),
stdConstBinding(public::“float”, Class, float),
stdConstBinding(public::“Number”, Class, Number),
stdConstBinding(public::“sbyte”, Class, sbyte),
stdConstBinding(public::“byte”, Class, byte),
stdConstBinding(public::“short”, Class, short),
stdConstBinding(public::“ushort”, Class, ushort),
stdConstBinding(public::“int”, Class, int),
stdConstBinding(public::“uint”, Class, uint),
stdConstBinding(public::“char”, Class, char),
stdConstBinding(public::“String”, Class, String),
stdConstBinding(public::“Array”, Class, Array),
stdConstBinding(public::“Namespace”, Class, Namespace),
stdConstBinding(public::“Attribute”, Class, Attribute),
stdConstBinding(public::“Date”, Class, Date),
stdConstBinding(public::“RegExp”, Class, RegExp),
stdConstBinding(public::“Class”, Class, Class),
stdConstBinding(public::“Function”, Class, Function),
stdConstBinding(public::“PrototypeFunction”, Class, PrototypeFunction),
stdConstBinding(public::“Package”, Class, Package),
stdConstBinding(public::“Error”, Class, Error),
stdConstBinding(public::“ArgumentError”, Class, ArgumentError),
stdConstBinding(public::“AttributeError”, Class, AttributeError),
stdConstBinding(public::“ConstantError”, Class, ConstantError),
stdConstBinding(public::“DefinitionError”, Class, DefinitionError),
stdConstBinding(public::“EvalError”, Class, EvalError),
stdConstBinding(public::“RangeError”, Class, RangeError),
stdConstBinding(public::“ReferenceError”, Class, ReferenceError),
stdConstBinding(public::“SyntaxError”, Class, SyntaxError),
stdConstBinding(public::“TypeError”, Class, TypeError),
stdConstBinding(public::“UninitializedError”, Class, UninitializedError),
stdConstBinding(public::“URIError”, Class, URIError)},
archetype: ObjectPrototype, name: “”, initialize: none, sealed: false, internalNamespace: internal
end proc;
Built-in Namespaces
public: Namespace = new Namespacename: “public”;
internal: Namespace = new Namespacename: “internal”;
Built-in Attributes
global_explicit: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: true, enumerable: false, dynamic: false, category: none, overrideMod: none, prototype: false, unused: false;
global_enumerable: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: true, dynamic: false, category: none, overrideMod: none, prototype: false, unused: false;
global_dynamic: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: true, category: none, overrideMod: none, prototype: false, unused: false;
global_static: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: static, overrideMod: none, prototype: false, unused: false;
global_virtual: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: virtual, overrideMod: none, prototype: false, unused: false;
global_final: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: final, overrideMod: none, prototype: false, unused: false;
global_prototype: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: none, overrideMod: none, prototype: true, unused: false;
global_unused: CompoundAttribute = CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: none, overrideMod: none, prototype: false, unused: true;
proc global_override(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function does not check phase and therefore can be used in a constant expression.
overrideMod: OverrideModifier;
if args = [] then overrideMod  true
elsif |args| = 1 then
arg: Object  args[0];
if arg  {true, false, undefined} then throw a TypeError exception end if;
overrideMod  arg
else throw an ArgumentError exception — too many arguments supplied
end if;
return CompoundAttributenamespaces: {}, explicit: false, enumerable: false, dynamic: false, category: none, overrideMod: overrideMod, prototype: false, unused: false
end proc;
Built-in Functions
proc global_eval(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
proc global_parseint(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if the arguments can be converted to primitives in constant expressions.
if |args|  {1, 2} then
throw an ArgumentError exception — at least one and at most two arguments must be supplied
end if;
s: String  objectToString(args[0], phase);
radix: Integer  objectToInteger(defaultArg(args, 1, +zerof64), phase);
i: (Integer – {0})  {+zero, –zero, NaN}  stringPrefixToInteger(s, radix);
return extendedRationalToFloat64(i)
end proc;
proc stringPrefixToInteger(s: String, radix: Integer): (Integer – {0})  {+zero, –zero, NaN}
r: Integer  radix;
if r  {0, 2 ... 36} then throw a RangeError exception — radix out of range end if;
i: Integer  0;
while i < |s| and the nonterminal WhiteSpaceOrLineTerminatorChar can expand into [s[i]] do
i  i + 1
end while;
sign: {–1, 1}  1;
if i < |s| then
if s[i] = ‘+’ then i  i + 1 elsif s[i] = ‘-’ then sign  –1; i  i + 1 end if
end if;
if r  {0, 16} and i + 2 ≤ |s| and s[i ... i + 1]  {“0x”, “0X”} then
r  16;
i  i + 2
end if;
if r = 0 then r  10 end if;
n: Integer  0;
start: Integer  i;
digit: IntegerOpt  0;
while i < |s| and digit ≠ none do
ch: Char16  s[i];
if ch  {‘0’ ... ‘9’} then digit  char16ToInteger(ch) – char16ToInteger(‘0’)
elsif ch  {‘A’ ... ‘Z’} then
digit  char16ToInteger(ch) – char16ToInteger(‘A’) + 10
elsif ch  {‘a’ ... ‘z’} then
digit  char16ToInteger(ch) – char16ToInteger(‘a’) + 10
else digit  none
end if;
if digit ≠ none and digit ≥ r then digit  none end if;
if digit ≠ none then n  nr + digit; i  i + 1 end if
end while;
if i = start then return NaN end if;
if n ≠ 0 then return nsign
elsif sign > 0 then return +zero
else return –zero
end if
end proc;
proc global_parselong(this: Object, f: SimpleInstance, args: Object[], phase: Phase): GeneralNumber
note	This function can be used in a constant expression if the arguments can be converted to primitives in constant expressions.
if |args|  {1, 2} then
throw an ArgumentError exception — at least one and at most two arguments must be supplied
end if;
s: String  objectToString(args[0], phase);
radix: Integer  objectToInteger(defaultArg(args, 1, +zerof64), phase);
i: (Integer – {0})  {+zero, –zero, NaN}  stringPrefixToInteger(s, radix);
case i of
{+zero, –zero} do return 0long;
Integer do return integerToLong(i);
{NaN} do return NaNf64
end case
end proc;
proc global_parsefloat(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if its argument can be converted to a primitive in a constant expression.
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
s: String  objectToString(args[0], phase);
Apply the lexer grammar with the start symbol StringDecimalLiteral to the string s. If the grammar can interpret neither s nor any prefix of s as an expansion of StringDecimalLiteral, then return NaNf64. Otherwise, let p be the longest prefix of s (possibly s itself) such that p is an expansion of StringDecimalLiteral.
q: ExtendedRational  the value of the action Lex applied to p’s expansion of the nonterminal StringDecimalLiteral;
return extendedRationalToFloat64(q)
end proc;
proc global_isnan(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Boolean
note	This function can be used in a constant expression if its argument can be converted to a primitive in a constant expression.
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
x: GeneralNumber  objectToGeneralNumber(args[0], phase);
return x  {NaNf32, NaNf64}
end proc;
proc global_isfinite(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Boolean
note	This function can be used in a constant expression if its argument can be converted to a primitive in a constant expression.
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
x: GeneralNumber  objectToGeneralNumber(args[0], phase);
return x  {NaNf32, NaNf64, +∞f32, +∞f64, –∞f32, –∞f64}
end proc;
proc global_decodeuri(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
proc global_decodeuricomponent(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
proc global_encodeuri(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
proc global_encodeuricomponent(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
Built-in Classes
proc dummyCall(this: Object, c: Class, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
proc dummyConstruct(c: Class, args: Object[], phase: Phase): Object
Evaluate ???? and ignore its result
end proc;
prototypesSealed: Boolean = false;
Object
Object: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: none, prototype: ObjectPrototype, complete: true, name: “Object”, typeofString: “object”, dynamic: true, final: false, defaultValue: undefined, defaultHint: hintNumber, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: callObject, construct: constructObject, init: none, is: ordinaryIs, coerce: coerceObject;
proc callObject(this: Object, c: Class, args: Object[], phase: Phase): Object
note	This function does not check phase and therefore can be used in a constant expression.
if |args| = 0 then return undefined
elsif |args| = 1 then return args[0]
else throw an ArgumentError exception — at most one argument can be supplied
end if
end proc;
proc constructObject(c: Class, args: Object[], phase: Phase): Object
note	This function does not check phase and therefore can be used in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
o: Object  defaultArg(args, 0, undefined);
if o  {null, undefined} then
return createSimpleInstance(Object, ObjectPrototype, none, none, none)
else return o
end if
end proc;
proc coerceObject(o: Object, c: Class): ObjectOpt
return o
end proc;
ObjectPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, Object),
stdFunction(public::“toString”, Object_toString, 0),
stdFunction(public::“toLocaleString”, Object_toLocaleString, 0),
stdFunction(public::“valueOf”, Object_valueOf, 0),
stdFunction(public::“hasOwnProperty”, Object_hasOwnProperty, 1),
stdFunction(public::“isPrototypeOf”, Object_isPrototypeOf, 1),
stdFunction(public::“propertyIsEnumerable”, Object_propertyIsEnumerable, 1),
stdFunction(public::“sealProperty”, Object_sealProperty, 1)},
archetype: none, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc Object_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function does not check phase and therefore can be used in a constant expression.
note	This function ignores any arguments passed to it in args.
c: Class  objectType(this);
return “[object ”  c.name  “]”
end proc;
proc Object_toLocaleString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — toLocaleString cannot be called from a constant expression
end if;
toStringMethod: Object  dotRead(this, {public::“toString”}, phase);
return call(this, toStringMethod, args, phase)
end proc;
proc Object_valueOf(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function does not check phase and therefore can be used in a constant expression.
note	This function ignores any arguments passed to it in args.
return this
end proc;
proc Object_hasOwnProperty(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Boolean
if phase = compile then
throw a ConstantError exception — hasOwnProperty cannot be called from a constant expression
end if;
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
return hasProperty(this, args[0], true, phase)
end proc;
proc Object_isPrototypeOf(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Boolean
if phase = compile then
throw a ConstantError exception — isPrototypeOf cannot be called from a constant expression
end if;
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
o: Object  args[0];
return this  archetypes(o)
end proc;
proc Object_propertyIsEnumerable(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Boolean
if phase = compile then
throw a ConstantError exception — propertyIsEnumerable cannot be called from a constant expression
end if;
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
qname: QualifiedName  objectToQualifiedName(args[0], phase);
c: Class  objectType(this);
mBase: InstancePropertyOpt  findBaseInstanceProperty(c, {qname}, read);
if mBase ≠ none then
m: InstanceProperty  getDerivedInstanceProperty(c, mBase, read);
if m.enumerable then return true end if
end if;
mBase  findBaseInstanceProperty(c, {qname}, write);
if mBase ≠ none then
m: InstanceProperty  getDerivedInstanceProperty(c, mBase, write);
if m.enumerable then return true end if
end if;
if this  BindingObject then return false end if;
return some b  this.localBindings satisfies b.qname = qname and b.enumerable
end proc;
proc Object_sealProperty(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Undefined
if phase = compile then
throw a ConstantError exception — sealProperty cannot be called from a constant expression
end if;
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, true);
if arg = false then Evaluate sealObject(this) and ignore its result
elsif arg = true then
Evaluate sealObject(this) and ignore its result;
Evaluate sealAllLocalProperties(this) and ignore its result
elsif arg  Char16  String then
if not hasProperty(this, arg, true, phase) then
throw a ReferenceError exception — property not found
end if;
qname: QualifiedName  objectToQualifiedName(arg, phase);
Evaluate sealLocalProperty(this, qname) and ignore its result
end if;
return undefined
end proc;
Never
Never: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: none, complete: true, name: “Never”, typeofString: “”, dynamic: false, final: true, defaultValue: none, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructNever, init: none, is: ordinaryIs, coerce: coerceNever;
proc constructNever(c: Class, args: Object[], phase: Phase): Object
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
throw a TypeError exception — no coercions to Never are possible
end proc;
proc coerceNever(o: Object, c: Class): {none}
return none
end proc;
Void
Void: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: none, complete: true, name: “Void”, typeofString: “undefined”, dynamic: false, final: true, defaultValue: undefined, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: callVoid, construct: constructVoid, init: none, is: ordinaryIs, coerce: coerceVoid;
proc callVoid(this: Object, c: Class, args: Object[], phase: Phase): Undefined
note	This function does not check phase and therefore can be used in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
return undefined
end proc;
proc constructVoid(c: Class, args: Object[], phase: Phase): Undefined
note	This function does not check phase and therefore can be used in a constant expression.
if |args| ≠ 0 then throw an ArgumentError exception — no arguments can be supplied
end if;
return undefined
end proc;
proc coerceVoid(o: Object, c: Class): {undefined, none}
if o  Null  Undefined then return undefined else return none end if
end proc;
Null
Null: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: none, complete: true, name: “Null”, typeofString: “object”, dynamic: false, final: true, defaultValue: null, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: callNull, construct: constructNull, init: none, is: ordinaryIs, coerce: coerceNull;
proc callNull(this: Object, c: Class, args: Object[], phase: Phase): Null
note	This function does not check phase and therefore can be used in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
return null
end proc;
proc constructNull(c: Class, args: Object[], phase: Phase): Null
note	This function does not check phase and therefore can be used in a constant expression.
if |args| ≠ 0 then throw an ArgumentError exception — no arguments can be supplied
end if;
return null
end proc;
proc coerceNull(o: Object, c: Class): {null, none}
if o = null then return o else return none end if
end proc;
Boolean
Boolean: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: BooleanPrototype, complete: true, name: “Boolean”, typeofString: “boolean”, dynamic: false, final: true, defaultValue: false, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructBoolean, init: none, is: ordinaryIs, coerce: coerceBoolean;
proc constructBoolean(c: Class, args: Object[], phase: Phase): Boolean
note	This function does not check phase and therefore can be used in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
return objectToBoolean(defaultArg(args, 0, false))
end proc;
proc coerceBoolean(o: Object, c: Class): BooleanOpt
if o  Boolean then return o else return none end if
end proc;
BooleanPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, Boolean),
stdFunction(public::“toString”, Boolean_toString, 0),
stdReserve(public::“valueOf”, ObjectPrototype)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc Boolean_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression.
note	This function ignores any arguments passed to it in args.
a: Boolean  objectToBoolean(this);
return objectToString(a, phase)
end proc;
GeneralNumber
GeneralNumber: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: GeneralNumberPrototype, complete: true, name: “GeneralNumber”, typeofString: “object”, dynamic: false, final: true, defaultValue: NaNf64, defaultHint: hintNumber, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructGeneralNumber, init: none, is: ordinaryIs, coerce: coerceGeneralNumber;
proc constructGeneralNumber(c: Class, args: Object[], phase: Phase): GeneralNumber
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| = 0 then return +zerof64
elsif |args| = 1 then return objectToGeneralNumber(args[0], phase)
else throw an ArgumentError exception — at most one argument can be supplied
end if
end proc;
proc coerceGeneralNumber(o: Object, c: Class): GeneralNumber  {none}
if o  GeneralNumber then return o else return none end if
end proc;
GeneralNumberPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, GeneralNumber),
stdFunction(public::“toString”, GeneralNumber_toString, 1),
stdReserve(public::“valueOf”, ObjectPrototype),
stdFunction(public::“toFixed”, GeneralNumber_toFixed, 1),
stdFunction(public::“toExponential”, GeneralNumber_toExponential, 1),
stdFunction(public::“toPrecision”, GeneralNumber_toPrecision, 1)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc GeneralNumber_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a general number.
x: GeneralNumber  objectToGeneralNumber(this, phase);
radix: Integer  objectToInteger(defaultArg(args, 0, 10f64), phase);
if radix < 2 or radix > 36 then throw a RangeError exception — bad radix end if;
if radix = 10 then return generalNumberToString(x)
else
return x converted to a string containing a base-radix number in an implementation-defined manner
end if
end proc;
precisionLimit: Integer = an implementation-defined integer not less than 20;
proc GeneralNumber_toFixed(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a general number.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
x: GeneralNumber  objectToGeneralNumber(this, phase);
fractionDigits: Integer  objectToInteger(defaultArg(args, 0, +zerof64), phase);
if fractionDigits < 0 or fractionDigits > precisionLimit then
throw a RangeError exception
end if;
if x  FiniteGeneralNumber then return generalNumberToString(x) end if;
r: Rational  toRational(x);
if |r| ≥ 1021 then return generalNumberToString(x) end if;
sign: String  “”;
if r < 0 then sign  “-”; r  –r end if;
n: Integer  r10fractionDigits + 1/2;
digits: String  integerToString(n);
if fractionDigits = 0 then return sign  digits
else
if |digits| ≤ fractionDigits then
digits  repeat(‘0’, fractionDigits + 1 – |digits|)  digits
end if;
k: Integer  |digits| – fractionDigits;
return sign  digits[0 ... k – 1]  “.”  digits[k ...]
end if
end proc;
proc GeneralNumber_toExponential(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a general number.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
x: GeneralNumber  objectToGeneralNumber(this, phase);
fractionDigits: ExtendedInteger  objectToExtendedInteger(defaultArg(args, 0, NaNf64), phase);
if fractionDigits  {+∞, –∞} or (fractionDigits ≠ NaN and (fractionDigits < 0 or fractionDigits > precisionLimit)) then
throw a RangeError exception
end if;
if x  FiniteGeneralNumber then return generalNumberToString(x) end if;
r: Rational  toRational(x);
sign: String  “”;
if r < 0 then sign  “-”; r  –r end if;
digits: String;
e: Integer;
if fractionDigits ≠ NaN then
if r = 0 then digits  repeat(‘0’, fractionDigits + 1); e  0
else
e  log10(r);
n: Integer  r10fractionDigits–e + 1/2;
note	At this point 10fractionDigits ≤ n ≤ 10fractionDigits+1
if n = 10fractionDigits+1 then n  n/10; e  e + 1 end if;
digits  integerToString(n)
end if;
note	At this point the string digits has exactly fractionDigits + 1 digits
elsif r = 0 then digits  “0”; e  0
elsif x  Long  ULong then
digits  integerToString(r);
e  |digits| – 1;
while digits[|digits| – 1] = ‘0’ do digits  digits[0 ... |digits| – 2]
end while
else
k: Integer;
s: Integer;
case x of
NonzeroFiniteFloat32 do
Let e, k, and s be integers such that k ≥ 1, 10k–1 ≤ s ≤ 10k, (s10e+1–k)f32 = x, and k is as small as possible.
NonzeroFiniteFloat64 do
Let e, k, and s be integers such that k ≥ 1, 10k–1 ≤ s ≤ 10k, (s10e+1–k)f64 = x, and k is as small as possible.
end case;
note	k is the number of digits in the decimal representation of s, s is not divisible by 10, and the least significant digit of s is not necessarily uniquely determined by the above criteria.
When there are multiple possibilities for s according to the rules above, implementations are encouraged but not required to select the one according to the following rules: Select the value of s for which s10e+1–k is closest in value to r; if there are two such possible values of s, choose the one that is even.
digits  integerToString(s)
end if;
return sign  exponentialNotationString(digits, e)
end proc;
proc GeneralNumber_toPrecision(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a general number.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
x: GeneralNumber  objectToGeneralNumber(this, phase);
precision: ExtendedInteger  objectToExtendedInteger(defaultArg(args, 0, NaNf64), phase);
if precision = NaN then return generalNumberToString(x) end if;
if precision  {+∞, –∞} or precision < 1 or precision > precisionLimit + 1 then
throw a RangeError exception
end if;
if x  FiniteGeneralNumber then return generalNumberToString(x) end if;
r: Rational  toRational(x);
sign: String  “”;
if r < 0 then sign  “-”; r  –r end if;
digits: String;
e: Integer;
if r = 0 then digits  repeat(‘0’, precision); e  0
else
e  log10(r);
n: Integer  r10precision–1–e + 1/2;
note	At this point 10precision–1 ≤ n ≤ 10precision
if n = 10precision then n  n/10; e  e + 1 end if;
digits  integerToString(n)
end if;
note	At this point the string digits has exactly precision digits
if e < –6 or e ≥ precision then return sign  exponentialNotationString(digits, e)
elsif e = precision – 1 then return sign  digits
elsif e ≥ 0 then return sign  digits[0 ... e]  “.”  digits[e + 1 ...]
else return sign  “0.”  repeat(‘0’, –(e + 1))  digits
end if
end proc;
long
long: Class = new ClasslocalBindings: {
stdConstBinding(public::“MAX_VALUE”, ulong, (263 – 1)long),
stdConstBinding(public::“MIN_VALUE”, ulong, (–263)long)},
instanceProperties: {}, super: GeneralNumber, prototype: longPrototype, complete: true, name: “long”, typeofString: “long”, dynamic: false, final: true, defaultValue: 0long, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructLong, init: none, is: ordinaryIs, coerce: coerceLong;
proc constructLong(c: Class, args: Object[], phase: Phase): Long
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, +zerof64);
i: Integer  objectToInteger(arg, phase);
if –263 ≤ i ≤ 263 – 1 then return ilong
else throw a RangeError exception — i is out of the Long range
end if
end proc;
proc coerceLong(o: Object, c: Class): Long  {none}
if o  GeneralNumber then return none end if;
i: IntegerOpt  checkInteger(o);
if i ≠ none and –263 ≤ i ≤ 263 – 1 then return ilong
else throw a RangeError exception — i is out of the Long range
end if
end proc;
longPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, long),
stdReserve(public::“toString”, GeneralNumberPrototype),
stdReserve(public::“valueOf”, GeneralNumberPrototype)},
archetype: GeneralNumberPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
ulong
ulong: Class = new ClasslocalBindings: {
stdConstBinding(public::“MAX_VALUE”, ulong, (264 – 1)ulong),
stdConstBinding(public::“MIN_VALUE”, ulong, 0ulong)},
instanceProperties: {}, super: GeneralNumber, prototype: ulongPrototype, complete: true, name: “ulong”, typeofString: “ulong”, dynamic: false, final: true, defaultValue: 0ulong, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructULong, init: none, is: ordinaryIs, coerce: coerceULong;
proc constructULong(c: Class, args: Object[], phase: Phase): ULong
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, +zerof64);
i: Integer  objectToInteger(arg, phase);
if 0 ≤ i ≤ 264 – 1 then return iulong
else throw a RangeError exception — i is out of the ULong range
end if
end proc;
proc coerceULong(o: Object, c: Class): ULong  {none}
if o  GeneralNumber then return none end if;
i: IntegerOpt  checkInteger(o);
if i ≠ none and 0 ≤ i ≤ 264 – 1 then return iulong
else throw a RangeError exception — i is out of the ULong range
end if
end proc;
ulongPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, ulong),
stdReserve(public::“toString”, GeneralNumberPrototype),
stdReserve(public::“valueOf”, GeneralNumberPrototype)},
archetype: GeneralNumberPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
float
float: Class = new ClasslocalBindings: {
stdConstBinding(public::“MAX_VALUE”, float, (3.40282351038)f32),
stdConstBinding(public::“MIN_VALUE”, float, (10–45)f32),
stdConstBinding(public::“NaN”, float, NaNf32),
stdConstBinding(public::“NEGATIVE_INFINITY”, float, –∞f32),
stdConstBinding(public::“POSITIVE_INFINITY”, float, +∞f32)},
instanceProperties: {}, super: GeneralNumber, prototype: floatPrototype, complete: true, name: “float”, typeofString: “float”, dynamic: false, final: true, defaultValue: NaNf32, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructFloat, init: none, is: ordinaryIs, coerce: coerceFloat;
proc constructFloat(c: Class, args: Object[], phase: Phase): Float32
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| = 0 then return +zerof32
elsif |args| = 1 then return objectToFloat32(args[0], phase)
else throw an ArgumentError exception — at most one argument can be supplied
end if
end proc;
proc coerceFloat(o: Object, c: Class): Float32  {none}
if o  GeneralNumber then return toFloat32(o) else return none end if
end proc;
floatPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, float),
stdReserve(public::“toString”, GeneralNumberPrototype),
stdReserve(public::“valueOf”, GeneralNumberPrototype)},
archetype: GeneralNumberPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
Number
Number: Class = new ClasslocalBindings: {
stdConstBinding(public::“MAX_VALUE”, Number, (1.797693134862315710308)f64),
stdConstBinding(public::“MIN_VALUE”, Number, (510–324)f64),
stdConstBinding(public::“NaN”, Number, NaNf64),
stdConstBinding(public::“NEGATIVE_INFINITY”, Number, –∞f64),
stdConstBinding(public::“POSITIVE_INFINITY”, Number, +∞f64)},
instanceProperties: {}, super: GeneralNumber, prototype: NumberPrototype, complete: true, name: “Number”, typeofString: “number”, dynamic: false, final: true, defaultValue: NaNf64, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructNumber, init: none, is: ordinaryIs, coerce: coerceNumber;
proc constructNumber(c: Class, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| = 0 then return +zerof64
elsif |args| = 1 then return objectToFloat64(args[0], phase)
else throw an ArgumentError exception — at most one argument can be supplied
end if
end proc;
proc coerceNumber(o: Object, c: Class): Float64  {none}
if o  GeneralNumber then return toFloat64(o) else return none end if
end proc;
NumberPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, Number),
stdReserve(public::“toString”, GeneralNumberPrototype),
stdReserve(public::“valueOf”, GeneralNumberPrototype)},
archetype: GeneralNumberPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc makeBuiltInIntegerClass(name: String, low: Integer, high: Integer): Class
proc construct(c: Class, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, +zerof64);
x: Float64  objectToFloat64(arg, phase);
i: IntegerOpt  checkInteger(x);
if i ≠ none and low ≤ i ≤ high then
note	–zerof64 is coerced to +zerof64.
return if64
end if;
throw a RangeError exception
end proc;
proc is(o: Object, c: Class): Boolean
if o  Float64 then return false end if;
i: IntegerOpt  checkInteger(o);
return i ≠ none and low ≤ i ≤ high
end proc;
proc coerce(o: Object, c: Class): Float64  {none}
if o  GeneralNumber then return none end if;
i: IntegerOpt  checkInteger(o);
if i ≠ none and low ≤ i ≤ high then
note	–zerof32, +zerof32, and –zerof64 are all coerced to +zerof64.
return if64
end if;
throw a RangeError exception
end proc;
return new ClasslocalBindings: {
stdConstBinding(public::“MAX_VALUE”, Number, highf64),
stdConstBinding(public::“MIN_VALUE”, Number, lowf64)},
instanceProperties: {}, super: Number, prototype: Number.prototype, complete: true, name: name, typeofString: “number”, dynamic: false, final: true, defaultValue: +zerof64, hasProperty: Number.hasProperty, bracketRead: Number.bracketRead, bracketWrite: Number.bracketWrite, bracketDelete: Number.bracketDelete, read: Number.read, write: Number.write, delete: Number.delete, enumerate: Number.enumerate, call: sameAsConstruct, construct: construct, init: none, is: is, coerce: coerce
end proc;
sbyte: Class = makeBuiltInIntegerClass(“sbyte”, –128, 127);
byte: Class = makeBuiltInIntegerClass(“byte”, 0, 255);
short: Class = makeBuiltInIntegerClass(“short”, –32768, 32767);
ushort: Class = makeBuiltInIntegerClass(“ushort”, 0, 65535);
int: Class = makeBuiltInIntegerClass(“int”, –2147483648, 2147483647);
uint: Class = makeBuiltInIntegerClass(“uint”, 0, 4294967295);
char
char: Class = new ClasslocalBindings: {stdFunction(public::“fromCharCode”, char_fromCharCode, 1)}, instanceProperties: {}, super: Object, prototype: charPrototype, complete: true, name: “char”, typeofString: “char”, dynamic: false, final: true, defaultValue: ‘«NUL»’, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructChar, init: none, is: ordinaryIs, coerce: coerceChar;
proc callChar(this: Object, c: Class, args: Object[], phase: Phase): Char16
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
s: String  objectToString(args[0], phase);
if |s| ≠ 1 then throw a RangeError exception — only one character may be given end if;
return s[0]
end proc;
proc constructChar(c: Class, args: Object[], phase: Phase): Char16
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, undefined);
if arg = undefined then return ‘«NUL»’
elsif arg  Char16 then return arg
else
s: String  objectToString(args[0], phase);
if |s| ≠ 1 then throw a RangeError exception — only one character may be given
end if;
return s[0]
end if
end proc;
proc coerceChar(o: Object, c: Class): Char16  {none}
if o  Char16 then return o else return none end if
end proc;
proc char_fromCharCode(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
i: Integer  objectToInteger(args[0], phase);
if 0 ≤ i ≤ 0xFFFF then return integerToChar16(i)
else throw a RangeError exception — character code out of range
end if
end proc;
charPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, char),
stdReserve(public::“toString”, StringPrototype),
stdReserve(public::“valueOf”, StringPrototype)},
archetype: StringPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
String
String: Class = new ClasslocalBindings: {stdFunction(public::“fromCharCode”, String_fromCharCode, 1)}, instanceProperties: {
new InstanceGettermultiname: {public::“length”}, final: true, enumerable: false, call: String_length},
super: Object, prototype: StringPrototype, complete: true, name: “String”, typeofString: “string”, dynamic: false, final: true, defaultValue: null, hasProperty: stringHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: readString, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: constructString, init: none, is: ordinaryIs, coerce: coerceString;
proc stringHasProperty(o: Object, c: Class, property: Object, flat: Boolean, phase: Phase): Boolean
note	o  String because stringHasProperty is only called on instances of class String.
qname: QualifiedName  objectToQualifiedName(property, phase);
i: IntegerOpt  multinameToUnsignedInteger({qname});
if i ≠ none then return i < |o|
else
return findBaseInstanceProperty(c, {qname}, read) ≠ none or findBaseInstanceProperty(c, {qname}, write) ≠ none or findArchetypeProperty(o, {qname}, read, flat) ≠ none or findArchetypeProperty(o, {qname}, write, flat) ≠ none
end if
end proc;
proc readString(o: Object, limit: Class, multiname: Multiname, env: EnvironmentOpt, undefinedIfMissing: Boolean, phase: Phase): ObjectOpt
note	o  String because readString is only called on instances of class String.
if limit = String then
i: IntegerOpt  multinameToUnsignedInteger(multiname);
if i ≠ none then
if i < |o| then return o[i]
elsif undefinedIfMissing then return undefined
else return none
end if
end if
end if;
return ordinaryRead(o, limit, multiname, env, undefinedIfMissing, phase)
end proc;
proc constructString(c: Class, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if the argument can be converted to a primitive in a constant expression.
if |args| = 0 then return “”
elsif |args| = 1 then return objectToString(args[0], phase)
else throw an ArgumentError exception — at most one argument can be supplied
end if
end proc;
proc coerceString(o: Object, c: Class): String  Null  {none}
if o  Null  String then return o
elsif o  Char16 then return [o]
else return none
end if
end proc;
proc String_length(this: Object, phase: Phase): Object
note	this  String because this getter cannot be extracted from the String class.
length: Integer  |this|;
return lengthf64
end proc;
proc String_fromCharCode(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function can be used in a constant expression if the arguments can be converted to primitives in constant expressions.
s: String  “”;
for each arg  args do
i: Integer  objectToInteger(arg, phase);
if 0 ≤ i ≤ 0x10FFFF then s  s  integerToUTF16(i)
else throw a RangeError exception — character code out of range
end if
end for each;
return s
end proc;
StringPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, String),
stdFunction(public::“toString”, String_toString, 0),
stdReserve(public::“valueOf”, ObjectPrototype),
stdFunction(public::“charAt”, String_charAt, 1),
stdFunction(public::“charCodeAt”, String_charCodeAt, 1),
stdFunction(public::“concat”, String_concat, 1),
stdFunction(public::“indexOf”, String_indexOf, 1),
stdFunction(public::“lastIndexOf”, String_lastIndexOf, 1),
stdFunction(public::“localeCompare”, String_localeCompare, 1),
stdFunction(public::“match”, String_match, 1),
stdFunction(public::“replace”, String_replace, 1),
stdFunction(public::“search”, String_search, 1),
stdFunction(public::“slice”, String_slice, 2),
stdFunction(public::“split”, String_split, 2),
stdFunction(public::“substring”, String_substring, 2),
stdFunction(public::“toLowerCase”, String_toLowerCase, 0),
stdFunction(public::“toLocaleLowerCase”, String_toLocaleLowerCase, 0),
stdFunction(public::“toUpperCase”, String_toUpperCase, 0),
stdFunction(public::“toLocaleUpperCase”, String_toLocaleUpperCase, 0)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc String_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this can be converted to a primitive in a constant expression.
note	This function is generic and can be applied even if this is not a string.
note	This function ignores any arguments passed to it in args.
return objectToString(this, phase)
end proc;
proc String_charAt(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
s: String  objectToString(this, phase);
position: ExtendedInteger  objectToExtendedInteger(defaultArg(args, 0, +zerof64), phase);
if position = NaN then throw a RangeError exception
elsif position  {+∞, –∞} and 0 ≤ position < |s| then return [s[position]]
else return “”
end if
end proc;
proc String_charCodeAt(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
s: String  objectToString(this, phase);
position: ExtendedInteger  objectToExtendedInteger(defaultArg(args, 0, +zerof64), phase);
if position = NaN then throw a RangeError exception
elsif position  {+∞, –∞} and 0 ≤ position < |s| then
return (char16ToInteger(s[position]))f64
else return NaNf64
end if
end proc;
proc String_concat(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the argument can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
s: String  objectToString(this, phase);
for each arg  args do s  s  objectToString(arg, phase) end for each;
return s
end proc;
proc String_indexOf(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if this and the arguments can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
if |args|  {1, 2} then
throw an ArgumentError exception — at least one and at most two arguments must be supplied
end if;
s: String  objectToString(this, phase);
pattern: String  objectToString(args[0], phase);
arg: Object  defaultArg(args, 1, +zerof64);
position: Integer  pinExtendedInteger(objectToExtendedInteger(arg, phase), |s|, false);
while position + |pattern| ≤ |s| do
if s[position ... position + |pattern| – 1] = pattern then return positionf64
end if;
position  position + 1
end while;
return (–1)f64
end proc;
proc String_lastIndexOf(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
note	This function can be used in a constant expression if this and the arguments can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
if |args|  {1, 2} then
throw an ArgumentError exception — at least one and at most two arguments must be supplied
end if;
s: String  objectToString(this, phase);
pattern: String  objectToString(args[0], phase);
arg: Object  defaultArg(args, 1, +∞f64);
position: Integer  pinExtendedInteger(objectToExtendedInteger(arg, phase), |s|, false);
if position + |pattern| > |s| then position  |s| – |pattern| end if;
while position ≥ 0 do
if s[position ... position + |pattern| – 1] = pattern then return positionf64
end if;
position  position – 1
end while;
return (–1)f64
end proc;
proc String_localeCompare(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — localeCompare cannot be called from a constant expression
end if;
if |args| < 1 then
throw an ArgumentError exception — at least one argument must be supplied
end if;
s1: String  objectToString(this, phase);
s2: String  objectToString(args[0], phase);
Let result: Object be a value of type Number that is the result of a locale-sensitive string comparison of s1 and s2. The two strings are compared in an implementation-defined fashion. The result is intended to order strings in the sort order specified by the system default locale, and will be negative, zero, or positive, depending on whether s1 comes before s2 in the sort order, they are equal, or s1 comes after s2 in the sort order, respectively. The result shall not be NaNf64. The comparison shall be a consistent comparison function on the set of all strings.
return result
end proc;
proc String_match(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — match cannot be called from a constant expression
end if;
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
s: String  objectToString(this, phase);
Evaluate ???? and ignore its result
end proc;
proc String_replace(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — replace cannot be called from a constant expression
end if;
if |args| ≠ 2 then
throw an ArgumentError exception — exactly two arguments must be supplied
end if;
s: String  objectToString(this, phase);
Evaluate ???? and ignore its result
end proc;
proc String_search(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — search cannot be called from a constant expression
end if;
if |args| ≠ 1 then
throw an ArgumentError exception — exactly one argument must be supplied
end if;
s: String  objectToString(this, phase);
Evaluate ???? and ignore its result
end proc;
proc String_slice(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the arguments can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
if |args| > 2 then
throw an ArgumentError exception — at most two arguments can be supplied
end if;
s: String  objectToString(this, phase);
startArg: Object  defaultArg(args, 0, +zerof64);
endArg: Object  defaultArg(args, 1, +∞f64);
start: Integer  pinExtendedInteger(objectToExtendedInteger(startArg, phase), |s|, true);
end: Integer  pinExtendedInteger(objectToExtendedInteger(endArg, phase), |s|, true);
if start < end then return s[start ... end – 1] else return “” end if
end proc;
proc String_split(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — split cannot be called from a constant expression
end if;
if |args| > 2 then
throw an ArgumentError exception — at most two arguments can be supplied
end if;
s: String  objectToString(this, phase);
Evaluate ???? and ignore its result
end proc;
proc String_substring(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this and the arguments can be converted to primitives in constant expressions.
note	This function is generic and can be applied even if this is not a string.
if |args| > 2 then
throw an ArgumentError exception — at most two arguments can be supplied
end if;
s: String  objectToString(this, phase);
startArg: Object  defaultArg(args, 0, +zerof64);
endArg: Object  defaultArg(args, 1, +∞f64);
start: Integer  pinExtendedInteger(objectToExtendedInteger(startArg, phase), |s|, false);
end: Integer  pinExtendedInteger(objectToExtendedInteger(endArg, phase), |s|, false);
if start ≤ end then return s[start ... end – 1]
else return s[end ... start – 1]
end if
end proc;
proc String_toLowerCase(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this can be converted to a primitive in a constant expression.
note	This function is generic and can be applied even if this is not a string.
s: String  objectToString(this, phase);
s32: Char21[]  stringToUTF32(s);
r: String  “”;
for each ch  s32 do r  r  charToLowerFull(ch) end for each;
return r
end proc;
proc String_toLocaleLowerCase(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — toLocaleLowerCase cannot be called from a constant expression
end if;
s: String  objectToString(this, phase);
s32: Char21[]  stringToUTF32(s);
r: String  “”;
for each ch  s32 do r  r  charToLowerLocalized(ch) end for each;
return r
end proc;
proc String_toUpperCase(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function can be used in a constant expression if this can be converted to a primitive in a constant expression.
note	This function is generic and can be applied even if this is not a string.
s: String  objectToString(this, phase);
s32: Char21[]  stringToUTF32(s);
r: String  “”;
for each ch  s32 do r  r  charToUpperFull(ch) end for each;
return r
end proc;
proc String_toLocaleUpperCase(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function is generic and can be applied even if this is not a string.
if phase = compile then
throw a ConstantError exception — toLocaleUpperCase cannot be called from a constant expression
end if;
s: String  objectToString(this, phase);
s32: Char21[]  stringToUTF32(s);
r: String  “”;
for each ch  s32 do r  r  charToUpperLocalized(ch) end for each;
return r
end proc;
Array
Array: Class = new ClasslocalBindings: {}, instanceProperties: {
new InstanceVariablemultiname: {arrayPrivate::“length”}, final: true, enumerable: false, type: Number, defaultValue: +zerof64, immutable: false,
new InstanceGettermultiname: {public::“length”}, final: true, enumerable: false, call: Array_getLength,
new InstanceSettermultiname: {public::“length”}, final: true, enumerable: false, call: Array_setLength},
super: Object, prototype: ArrayPrototype, complete: true, name: “Array”, typeofString: “object”, privateNamespace: arrayPrivate, dynamic: true, final: true, defaultValue: null, defaultHint: hintNumber, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: writeArray, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: sameAsConstruct, construct: ordinaryConstruct, init: initArray, is: ordinaryIs, coerce: ordinaryCoerce;
arrayLimit: Integer = an implementation-defined integer value between 232 – 1 and 253 inclusive;
arrayPrivate: Namespace = new Namespacename: “private”;
proc writeArray(o: Object, limit: Class, multiname: Multiname, env: EnvironmentOpt, newValue: Object, createIfMissing: Boolean, phase: {run}): {none, ok}
result: {none, ok}  ordinaryWrite(o, limit, multiname, env, newValue, createIfMissing, phase);
if result = ok then
i: IntegerOpt  multinameToUnsignedInteger(multiname);
if i ≠ none then
if i ≥ arrayLimit then throw a RangeError exception — array index out of range
end if;
length: Integer  readArrayPrivateLength(o, phase);
if i ≥ length then
length  i + 1;
Evaluate writeArrayPrivateLength(o, length, phase) and ignore its result
end if
end if
end if;
return result
end proc;
readArrayPrivateLength(array, phase) returns an Array’s private length. See also readLength, which can work on non-Array objects.
proc readArrayPrivateLength(array: Object, phase: Phase): Integer
length: Float64  readInstanceSlot(array, arrayPrivate::“length”, phase);
note	length  {NaNf64, +∞f64, –∞f64};
n: Rational  toRational(length);
note	n  Integer and 0 ≤ n ≤ arrayLimit;
return n
end proc;
writeArrayPrivateLength(array, length, phase) sets an Array’s private length to length after ensuring that length is between 0 and arrayLimit inclusive. See also writeLength, which can work on non-Array objects.
proc writeArrayPrivateLength(array: Object, length: Integer, phase: {run})
if length < 0 or length > arrayLimit then
throw a RangeError exception — array length out of range
end if;
Evaluate dotWrite(array, {arrayPrivate::“length”}, lengthf64, phase) and ignore its result
end proc;
proc multinameToUnsignedInteger(multiname: Multiname): IntegerOpt
if |multiname| ≠ 1 then return none end if;
qname: QualifiedName  the one element of multiname;
if qname.namespace ≠ public then return none end if;
name: String  qname.id;
if name ≠ [] then
if name = “0” then return 0
elsif name[0] ≠ ‘0’ and (every ch  name satisfies ch  {‘0’ ... ‘9’}) then
return stringToExtendedInteger(name)
end if
end if;
return none
end proc;
proc initArray(this: SimpleInstance, args: Object[], phase: {run})
if |args| = 1 then
arg: Object  args[0];
if arg  GeneralNumber then
length: IntegerOpt  checkInteger(arg);
if length = none then
throw a RangeError exception — array length must be an integer
end if;
Evaluate writeArrayPrivateLength(this, length, phase) and ignore its result;
return
end if
end if;
i: Integer  0;
for each arg  args do
Evaluate indexWrite(this, i, arg, phase) and ignore its result;
i  i + 1
end for each;
note	The call to indexWrite above also set the array’s length to i.
end proc;
proc Array_getLength(this: Object, phase: Phase): Float64
note	is(this, Array) because this getter cannot be extracted from the Array class.
note	An array’s length is mutable, so reading it will throw ConstantError when phase = compile.
return readInstanceSlot(this, arrayPrivate::“length”, phase)
end proc;
proc Array_setLength(this: Object, length: Object, phase: Phase)
note	is(this, Array) because this setter cannot be extracted from the Array class.
if phase = compile then
throw a ConstantError exception — an array’s length cannot be set from a constant expression
end if;
newLength: IntegerOpt  checkInteger(objectToGeneralNumber(length, phase));
if newLength = none or newLength < 0 or newLength > arrayLimit then
throw a RangeError exception — array length out of range or not an integer
end if;
oldLength: Integer  readArrayPrivateLength(this, phase);
if newLength < oldLength then
note	Delete all indexed properties greater than or equal to the new length
proc qnameInDeletedRange(qname: QualifiedName): Boolean
i: IntegerOpt  multinameToUnsignedInteger({qname});
return i ≠ none and newLength ≤ i < oldLength
end proc;
this.localBindings  {b | b  this.localBindings such that not qnameInDeletedRange(b.qname)}
end if;
Evaluate writeArrayPrivateLength(this, newLength, phase) and ignore its result
end proc;
ArrayPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, Array),
stdFunction(public::“toString”, Array_toString, 0),
stdFunction(public::“toLocaleString”, Array_toLocaleString, 0),
stdFunction(public::“concat”, Array_concat, 1),
stdFunction(public::“join”, Array_join, 1),
stdFunction(public::“pop”, Array_pop, 0),
stdFunction(public::“push”, Array_push, 1),
stdFunction(public::“reverse”, Array_reverse, 0),
stdFunction(public::“shift”, Array_shift, 0),
stdFunction(public::“slice”, Array_slice, 2),
stdFunction(public::“sort”, Array_sort, 1),
stdFunction(public::“splice”, Array_splice, 2),
stdFunction(public::“unshift”, Array_unshift, 1)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc Array_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
if phase = compile then
throw a ConstantError exception — toString cannot be called on an Array from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
note	This function ignores any arguments passed to it in args.
return internalJoin(this, “,”, phase)
end proc;
proc Array_toLocaleString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
if phase = compile then
throw a ConstantError exception — toLocaleString cannot be called on an Array from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
note	This function passes any arguments passed to it in args to toLocaleString applied to the elements of the array.
separator: String  the list-separator string appropriate for the host’s current locale, derived in an implementation-defined way;
length: Integer  readLength(this, phase);
result: String  “”;
i: Integer  0;
while i ≠ length do
elt: ObjectOpt  indexRead(this, i, phase);
if elt  {undefined, null, none} then
toLocaleStringMethod: Object  dotRead(elt, {public::“toLocaleString”}, phase);
s: Object  call(elt, toLocaleStringMethod, args, phase);
if s  Char16  String then
throw a TypeError exception — toLocaleString should return a string
end if;
result  result  toString(s)
end if;
i  i + 1;
if i ≠ length then result  result  separator end if
end while;
return result
end proc;
proc Array_concat(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — concat cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
constituents: Object[]  [this]  args;
array: Object  construct(Array, [], phase);
i: Integer  0;
for each o  constituents do
if is(o, Array) then
oLength: Integer  readLength(o, phase);
k: Integer  0;
while k ≠ oLength do
elt: ObjectOpt  indexRead(o, k, phase);
if elt ≠ none then
Evaluate indexWrite(array, i, elt, phase) and ignore its result
end if;
k  k + 1;
i  i + 1
end while
else Evaluate indexWrite(array, i, o, phase) and ignore its result; i  i + 1
end if
end for each;
Evaluate writeArrayPrivateLength(array, i, phase) and ignore its result;
return array
end proc;
proc Array_join(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
if phase = compile then
throw a ConstantError exception — join cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, undefined);
separator: String  “,”;
if arg ≠ undefined then separator  objectToString(arg, phase) end if;
return internalJoin(this, separator, phase)
end proc;
proc internalJoin(this: Object, separator: String, phase: {run}): String
length: Integer  readLength(this, phase);
result: String  “”;
i: Integer  0;
while i ≠ length do
elt: ObjectOpt  indexRead(this, i, phase);
if elt  {undefined, null, none} then
result  result  objectToString(elt, phase)
end if;
i  i + 1;
if i ≠ length then result  result  separator end if
end while;
return result
end proc;
proc Array_pop(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — pop cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| ≠ 0 then throw an ArgumentError exception — no arguments can be supplied
end if;
length: Integer  readLength(this, phase);
result: Object  undefined;
if length ≠ 0 then
length  length – 1;
elt: ObjectOpt  indexRead(this, length, phase);
if elt ≠ none then
result  elt;
Evaluate indexWrite(this, length, none, phase) and ignore its result
end if
end if;
Evaluate writeLength(this, length, phase) and ignore its result;
return result
end proc;
proc Array_push(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — push cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
length: Integer  readLength(this, phase);
for each arg  args do
Evaluate indexWrite(this, length, arg, phase) and ignore its result;
length  length + 1
end for each;
Evaluate writeLength(this, length, phase) and ignore its result;
return lengthf64
end proc;
proc Array_reverse(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — reverse cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| ≠ 0 then throw an ArgumentError exception — no arguments can be supplied
end if;
length: Integer  readLength(this, phase);
lo: Integer  0;
hi: Integer  length – 1;
while lo < hi do
loElt: ObjectOpt  indexRead(this, lo, phase);
hiElt: ObjectOpt  indexRead(this, hi, phase);
Evaluate indexWrite(this, lo, hiElt, phase) and ignore its result;
Evaluate indexWrite(this, hi, loElt, phase) and ignore its result;
lo  lo + 1;
hi  hi – 1
end while;
return this
end proc;
proc Array_shift(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — shift cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| ≠ 0 then throw an ArgumentError exception — no arguments can be supplied
end if;
length: Integer  readLength(this, phase);
result: Object  undefined;
if length ≠ 0 then
elt: ObjectOpt  indexRead(this, 0, phase);
if elt ≠ none then result  elt end if;
i: Integer  1;
while i ≠ length do
elt  indexRead(this, i, phase);
Evaluate indexWrite(this, i – 1, elt, phase) and ignore its result;
i  i + 1
end while;
length  length – 1;
Evaluate indexWrite(this, length, none, phase) and ignore its result
end if;
Evaluate writeLength(this, length, phase) and ignore its result;
return result
end proc;
proc Array_slice(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — slice cannot be called on an Array from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| > 2 then
throw an ArgumentError exception — at most two arguments can be supplied
end if;
length: Integer  readLength(this, phase);
startArg: Object  defaultArg(args, 0, +zerof64);
endArg: Object  defaultArg(args, 1, +∞f64);
start: Integer  pinExtendedInteger(objectToExtendedInteger(startArg, phase), length, true);
end: Integer  pinExtendedInteger(objectToExtendedInteger(endArg, phase), length, true);
return makeArraySlice(this, start, end, phase)
end proc;
proc makeArraySlice(array: Object, start: Integer, end: Integer, phase: {run}): Object
slice: Object  construct(Array, [], phase);
i: Integer  start;
j: Integer  0;
while i < end do
elt: ObjectOpt  indexRead(array, i, phase);
Evaluate indexWrite(slice, j, elt, phase) and ignore its result;
i  i + 1;
j  j + 1
end while;
Evaluate writeLength(slice, j, phase) and ignore its result;
return slice
end proc;
proc Array_sort(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — sort cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
Evaluate ???? and ignore its result
end proc;
proc Array_splice(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Object
if phase = compile then
throw a ConstantError exception — splice cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
if |args| < 2 then
throw an ArgumentError exception — at least two arguments must be supplied
end if;
length: Integer  readLength(this, phase);
startArg: Object  defaultArg(args, 0, +zerof64);
deleteCountArg: Object  defaultArg(args, 1, +zerof64);
start: Integer  pinExtendedInteger(objectToExtendedInteger(startArg, phase), length, true);
deleteCount: Integer  pinExtendedInteger(objectToExtendedInteger(deleteCountArg, phase), length – start, false);
deletedSlice: Object  makeArraySlice(this, start, start + deleteCount, phase);
newElts: Object[]  args[2 ...];
newEltCount: Integer  |newElts|;
countDiff: Integer  newEltCount – deleteCount;
i: Integer;
if countDiff < 0 then
i  start + deleteCount;
while i ≠ length do
elt: ObjectOpt  indexRead(this, i, phase);
Evaluate indexWrite(this, i + countDiff, elt, phase) and ignore its result;
i  i + 1
end while;
i  0;
while i ≠ countDiff do
i  i – 1;
Evaluate indexWrite(this, length + i, none, phase) and ignore its result
end while
elsif countDiff > 0 then
i  length;
while i ≠ start + deleteCount do
i  i – 1;
elt: ObjectOpt  indexRead(this, i, phase);
Evaluate indexWrite(this, i + countDiff, elt, phase) and ignore its result
end while
end if;
Evaluate writeLength(this, length + countDiff, phase) and ignore its result;
i  start;
for each arg  newElts do
Evaluate indexWrite(this, i, arg, phase) and ignore its result;
i  i + 1
end for each;
return deletedSlice
end proc;
proc Array_unshift(this: Object, f: SimpleInstance, args: Object[], phase: Phase): Float64
if phase = compile then
throw a ConstantError exception — unshift cannot be called from a constant expression
end if;
note	This function is generic and can be applied even if this is not an Array.
i: Integer  readLength(this, phase);
nArgs: Integer  |args|;
newLength: Integer  nArgs + i;
if nArgs = 0 then
At the implementation’s discretion, either do nothing or return newLengthf64
end if;
Evaluate writeLength(this, newLength, phase) and ignore its result;
while i ≠ 0 do
i  i – 1;
elt: ObjectOpt  indexRead(this, i, phase);
Evaluate indexWrite(this, i + nArgs, elt, phase) and ignore its result
end while;
for each arg  args do
Evaluate indexWrite(this, i, arg, phase) and ignore its result;
i  i + 1
end for each;
return newLengthf64
end proc;
Namespace
Namespace: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: NamespacePrototype, complete: true, name: “Namespace”, typeofString: “namespace”, dynamic: false, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: ordinaryCall, construct: constructNamespace, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
proc constructNamespace(c: Class, args: Object[], phase: Phase): Namespace
note	This function can be used in a constant expression if its argument is a string.
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, undefined);
if arg  Null  Undefined then
if phase = compile then
throw a ConstantError exception — a constant expression cannot construct new anonymous namespaces
end if;
return new Namespacename: “anonymous”
elsif arg  Char16  String then
name: String  toString(arg);
if name = “” then return public
elsif some ns  namedNamespaces satisfies ns.name = name then return ns
else
ns2: Namespace  new Namespacename: name;
namedNamespaces  namedNamespaces  {ns2};
return ns2
end if
else throw a TypeError exception
end if
end proc;
namedNamespaces: Namespace{}  {};
NamespacePrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdFunction(public::“toString”, Namespace_toString, 0),
stdReserve(public::“valueOf”, ObjectPrototype)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc Namespace_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function does not check phase and therefore can be used in a constant expression.
note	This function ignores any arguments passed to it in args.
if this  Namespace then throw a TypeError exception end if;
return this.name
end proc;
Attribute
Attribute: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: ObjectPrototype, complete: true, name: “Attribute”, typeofString: “object”, dynamic: false, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
Date
Date: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: DatePrototype, complete: true, name: “Date”, typeofString: “object”, dynamic: true, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
DatePrototype: SimpleInstance = new SimpleInstancelocalBindings: {}, archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
RegExp
RegExp: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: RegExpPrototype, complete: true, name: “RegExp”, typeofString: “object”, dynamic: true, final: true, defaultValue: null, defaultHint: hintNumber, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
RegExpPrototype: SimpleInstance = new SimpleInstancelocalBindings: {}, archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
Class
Class: Class = new ClasslocalBindings: {}, instanceProperties: {classPrototypeGetter}, super: Object, prototype: ClassPrototype, complete: true, name: “Class”, typeofString: “function”, dynamic: false, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
classPrototypeGetter: InstanceGetter = new InstanceGettermultiname: {public::“prototype”}, final: true, enumerable: false, call: Class_prototype;
proc Class_prototype(this: Object, phase: Phase): Object
note	this  Class because this getter cannot be extracted from the Class class.
prototype: ObjectOpt  this.prototype;
if prototype = none then return undefined else return prototype end if
end proc;
ClassPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, Class),
stdFunction(public::“toString”, Class_toString, 0),
stdReserve(public::“valueOf”, ObjectPrototype),
stdConstBinding(public::“length”, Number, 1f64)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc Class_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
note	This function does not check phase and therefore can be used in a constant expression.
note	This function ignores any arguments passed to it in args.
c: Class  objectToClass(this);
return “[class ”  c.name  “]”
end proc;
Function
Function: Class = new ClasslocalBindings: {}, instanceProperties: {ivarFunctionLength}, super: Object, prototype: FunctionPrototype, complete: true, name: “Function”, typeofString: “function”, dynamic: false, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
ivarFunctionLength: InstanceVariable = new InstanceVariablemultiname: {public::“length”}, final: true, enumerable: false, type: Number, defaultValue: none, immutable: true;
FunctionPrototype: SimpleInstance = new SimpleInstancelocalBindings: {}, archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
PrototypeFunction
PrototypeFunction: Class = new ClasslocalBindings: {}, instanceProperties: {new InstanceVariablemultiname: {public::“prototype”}, final: true, enumerable: false, type: Object, defaultValue: undefined, immutable: false}, super: Function, prototype: FunctionPrototype, complete: true, name: “Function”, typeofString: “function”, dynamic: true, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
Package
Package: Class = new ClasslocalBindings: {}, instanceProperties: {}, super: Object, prototype: ObjectPrototype, complete: true, name: “Package”, typeofString: “object”, dynamic: true, final: true, defaultValue: null, defaultHint: hintString, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: dummyCall, construct: dummyConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
Error
Error: Class = new ClasslocalBindings: {}, instanceProperties: {
new InstanceVariablemultiname: {public::“name”}, final: false, enumerable: true, type: String, defaultValue: null, immutable: false,
new InstanceVariablemultiname: {public::“message”}, final: false, enumerable: true, type: String, defaultValue: null, immutable: false},
super: Object, prototype: ErrorPrototype, complete: true, name: “Error”, typeofString: “object”, dynamic: true, final: false, defaultValue: null, defaultHint: hintNumber, hasProperty: ordinaryHasProperty, bracketRead: ordinaryBracketRead, bracketWrite: ordinaryBracketWrite, bracketDelete: ordinaryBracketDelete, read: ordinaryRead, write: ordinaryWrite, delete: ordinaryDelete, enumerate: ordinaryEnumerate, call: callError, construct: ordinaryConstruct, init: initError, is: ordinaryIs, coerce: ordinaryCoerce;
proc callError(this: Object, c: Class, args: Object[], phase: Phase): Object
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, undefined);
if arg = null or is(arg, Error) then return arg
else return construct(c, args, phase)
end if
end proc;
proc initError(this: SimpleInstance, args: Object[], phase: {run})
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
name: String  Null  dotRead(ErrorPrototype, {public::“name”}, phase);
Evaluate dotWrite(this, {public::“name”}, name, phase) and ignore its result;
arg: Object  defaultArg(args, 0, undefined);
message: String  Null;
if arg = undefined then
message  dotRead(ErrorPrototype, {public::“message”}, phase)
else message  objectToString(arg, phase)
end if;
Evaluate dotWrite(this, {public::“message”}, message, phase) and ignore its result
end proc;
ErrorPrototype: SimpleInstance = new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, Error),
stdFunction(public::“toString”, Error_toString, 1),
stdVarBinding(public::“name”, String, “Error”),
stdVarBinding(public::“message”, String, an implementation-defined string)},
archetype: ObjectPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc Error_toString(this: Object, f: SimpleInstance, args: Object[], phase: Phase): String
if phase = compile then
throw a ConstantError exception — toString cannot be called on an Error from a constant expression
end if;
note	This function ignores any arguments passed to it in args.
err: Object  coerceNonNull(this, Error);
name: String  Null  dotRead(err, {public::“name”}, phase);
message: String  Null  dotRead(err, {public::“message”}, phase);
return an implementation-defined string derived from name, message, and optionally other properties of err
end proc;
proc systemError(e: Class, msg: String  Undefined): Object
return construct(e, [msg], run)
end proc;
Error Subclasses
proc makeBuiltInErrorSubclass(name: String): Class
proc call(this: Object, c: Class, args: Object[], phase: Phase): Object
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
arg: Object  defaultArg(args, 0, undefined);
if arg = null or is(arg, Error) then return coerce(arg, c)
else return construct(c, args, phase)
end if
end proc;
c: Class  new ClasslocalBindings: {}, instanceProperties: {}, super: Error, complete: false, name: name, typeofString: “object”, dynamic: true, final: false, defaultValue: null, defaultHint: hintNumber, hasProperty: Error.hasProperty, bracketRead: Error.bracketRead, bracketWrite: Error.bracketWrite, bracketDelete: Error.bracketDelete, read: Error.read, write: Error.write, delete: Error.delete, enumerate: Error.enumerate, call: call, construct: ordinaryConstruct, init: none, is: ordinaryIs, coerce: ordinaryCoerce;
prototype: SimpleInstance  new SimpleInstancelocalBindings: {
stdConstBinding(public::“constructor”, Class, c),
stdVarBinding(public::“name”, String, name),
stdVarBinding(public::“message”, String, an implementation-defined string)},
archetype: ErrorPrototype, sealed: prototypesSealed, type: Object, slots: {}, call: none, construct: none, env: none;
proc init(this: SimpleInstance, args: Object[], phase: {run})
if |args| > 1 then
throw an ArgumentError exception — at most one argument can be supplied
end if;
name2: String  Null  dotRead(prototype, {public::“name”}, phase);
Evaluate dotWrite(this, {public::“name”}, name2, phase) and ignore its result;
arg: Object  defaultArg(args, 0, undefined);
message: String  Null;
if arg = undefined then message  dotRead(prototype, {public::“message”}, phase)
else message  objectToString(arg, phase)
end if;
Evaluate dotWrite(this, {public::“message”}, message, phase) and ignore its result
end proc;
c.prototype  prototype;
c.init  init;
c.complete  true;
return c
end proc;
ArgumentError: Class = makeBuiltInErrorSubclass(“ArgumentError”);
AttributeError: Class = makeBuiltInErrorSubclass(“AttributeError”);
ConstantError: Class = makeBuiltInErrorSubclass(“ConstantError”);
DefinitionError: Class = makeBuiltInErrorSubclass(“DefinitionError”);
EvalError: Class = makeBuiltInErrorSubclass(“EvalError”);
RangeError: Class = makeBuiltInErrorSubclass(“RangeError”);
ReferenceError: Class = makeBuiltInErrorSubclass(“ReferenceError”);
SyntaxError: Class = makeBuiltInErrorSubclass(“SyntaxError”);
TypeError: Class = makeBuiltInErrorSubclass(“TypeError”);
UninitializedError: Class = makeBuiltInErrorSubclass(“UninitializedError”);
URIError: Class = makeBuiltInErrorSubclass(“URIError”);
Index
Nonterminals
Update fields to generate this index
Tags
Update fields to generate this index
Semantic Domains
Update fields to generate this index
Globals
Update fields to generate this index