April 2002 Draft
JavaScript 2.0
Core Language

Tuesday, December 18, 2001

Most of the behavior of expressions is the same as in JavaScript 1.5. Differences are highlighted below. One general difference is that most expression operators can be overridden.



|  get
|  set
|  exclude
|  include
|  named

The above keywords are not reserved and may be used in identifiers.

Qualified Identifiers

|  public
|  private
|  Qualifier :: Identifier
ExpressionQualifiedIdentifier  ParenExpression :: Identifier
|  ExpressionQualifiedIdentifier

Just like in ECMAScript Edition 3, an identifier evaluates to an internal data structure called a reference. However, JavaScript 2.0 references can be qualified by a qualifier, which, in the general syntax, is a ParenExpression that must be a compile-time constant expression that evaluates to a namespace. For convenience, if the ParenExpression consists of a single identifier, the parentheses may be omitted: (a)::m may be written as a::m.

The reserved words public and private may also be used as qualifiers. public evaluates to the public namespace. internal (which is not a reserved word) evaluates to the containing package’s anonymous namespace. private can only be used inside a class and evaluates to the containing class’s anonymous namespace.

See the name lookup section for more information on the :: operator.

Unit Expressions

|  Number [no line break] String
|  UnitExpression [no line break] String

A Number literal, ParenListExpression, or UnitExpression followed by a String literal is a unit expression, which is evaluated as follows:

Evaluate the String literal to obtain a string S. Parse that string according to the unit grammar and semantics to obtain a list of identifiers and exponents [id1e1, id2e2, ..., idnen]. If the parse fails, signal a syntax error. If the list is empty, let U be the function nullUnit, which accepts one required and one optional argument and returns its first argument, ignoring the optional argument.

If the list is not empty, for each i between 1 and n, let Vi be the value of looking up the class property idi of the Unit class. If ei is 1, let Fi = Vi; otherwise, let Fi = Vi.pow(ei). Then let U = F1*F2*...*Fn. For example, if S is "Kg*m^2/s^2*q", then U is the value of Unit.Kg*Unit.m.pow(2)*Unit.s.pow(–2)*Unit.q.pow(–1).

The result U should be callable as a function that accepts one required and one optional argument. The unit expression calls U, providing the numeric value of the Number literal, ParenListExpression, or UnitExpression as the first argument. The second argument is present only for the UnitExpression  Number [no line break] String production, in which case it is the original Number literal expressed as a string. Continuing the example above, the unit expression 32.50 "Kg*m^2/s^2*q", evaluates to the result of (Unit.Kg*Unit.m.pow(2)*Unit.s.pow(–2)*Unit.q.pow(–1))(32.5, "32.50").

U’s second argument allows user-defined unit classes to define extended syntaxes for numbers. For instance, a long-integer package might define a unit called "L" that treats the Number literal as a full 64-bit number without rounding it to a float64 first. Such a unit can be combined with other units by listing the units one after another; note that the lexer allows the first unit to be unquoted if it directly follows the number: 3L "cm" is the same as 3 "L" "cm" and evaluates to the result of Unit.cm(Unit.L(3, "3")).

The Unit class is predefined by the system. A program can define additional units by using a class extension. The unit attribute is conveniently provided to make a definition into a class extension. For example:

unit const µm = Unit.m/1e6;
unit const Å = Unit.m/1e10;
unit const dm = Unit.m/10;
unit const \_in = Unit.m*0.0254;
unit const liter = Unit.dm.pow(3);

\_ must be used to define the unit in because in is a reserved word. However, the unit in may be used without quoting it, as in the expression 3in + 5cm.

Primary Expressions

|  true
|  false
|  public
|  Number
|  String
|  this
|  RegularExpression
|  UnitExpression
|  ArrayLiteral
|  ObjectLiteral
|  FunctionExpression
ParenExpression  ( AssignmentExpressionallowIn )
|  ( ListExpressionallowIn , AssignmentExpressionallowIn )

public evaluates to the public namespace.

this may only be used in methods, constructors, or functions with the prototype attribute set.

Function Expressions

   function FunctionSignature Block
|  function Identifier FunctionSignature Block

A FunctionExpression creates and returns an anonymous function.

Object Literals

   { }
|  { FieldList }
|  FieldList , LiteralField
LiteralField  FieldName : AssignmentExpressionallowIn
|  String
|  Number

A ParenExpression must evaluate to a string.

Array Literals

ArrayLiteral  [ ElementList ]
|  ElementList , LiteralElement
|  AssignmentExpressionallowIn

Super Expressions

|  FullSuperExpression
FullSuperExpression  super ParenExpression

super, which may only be used inside a class C, can be applied to a subexpression that evaluates to an instance v of C. That subexpression can be either a ParenExpression or omitted, in which case it defaults to this.

As specified in the grammar below, the SuperExpression must be embedded as an operand to one of the following operators:

super changes the behavior of the operator in which it is embedded by limiting its property search to definitions inherited from class C’s superclass. See property lookup and operator dispatch.

Postfix Expressions

|  FullPostfixExpression
|  ShortNewExpression
|  SuperExpression
|  AttributeExpression MemberOperator
|  AttributeExpression Arguments
|  ExpressionQualifiedIdentifier
|  FullNewExpression
|  FullPostfixExpression MemberOperator
|  SuperExpression DotOperator
|  FullPostfixExpression Arguments
|  FullSuperExpression Arguments
|  PostfixExpressionOrSuper [no line break] ++
|  PostfixExpressionOrSuper [no line break] --
   new FullNewSubexpression Arguments
|  new FullSuperExpression Arguments
|  QualifiedIdentifier
|  FullNewExpression
|  FullNewSubexpression MemberOperator
|  SuperExpression DotOperator
   new ShortNewSubexpression
|  new SuperExpression
|  ShortNewExpression

A SimpleQualifiedIdentifier or ExpressionQualifiedIdentifier expression id resolves to the binding of id in the innermost enclosing scope that has a visible binding of id. If a qualifier q is present before the id, then the QualifiedIdentifier expression resolves to the binding of id in the innermost enclosing scope that has a visible binding of id in the namespace q.

Member Operators

|  . ParenExpression
   . QualifiedIdentifier
|  Brackets

The . operator accepts a QualifiedIdentifier as the second operand and performs a property lookup.

The [] operator can take multiple (or even named) arguments. This allows programmers to define data structures such as multidimensional arrays via operator overriding.

Unless the [] operator is overridden for an object o, the expression o[m] explicitly coerces m to a String s and returns the result of o.s, limiting the name lookup to the public indexable properties of o. See property lookup.

   [ ]
|  [ ListExpressionallowIn ]
|  [ NamedArgumentList ]
|  ( NamedArgumentList )
   ( )
|  ParenListExpression
|  ListExpressionallowIn , LiteralField
|  NamedArgumentList , LiteralField

A list of arguments can contain both positional and named arguments. The positional arguments are the subexpressions separated by commas within the ListExpressionallowIn. Named arguments use the same syntax as object literals. All strings except those consisting entirely of digits are legal for argument names. No two arguments may have the same name. The order of named arguments is immaterial.

Unary Operators

|  delete PostfixExpression
|  void UnaryExpression
|  typeof UnaryExpression
|  ++ PostfixExpressionOrSuper
|  -- PostfixExpressionOrSuper
|  + UnaryExpressionOrSuper
|  - UnaryExpressionOrSuper
|  ~ UnaryExpressionOrSuper
|  ! UnaryExpression
|  SuperExpression

The typeof operator is deprecated. It returns a string as in JavaScript 1.5. To get the type of an object x, use x.class instead.

Multiplicative Operators

|  MultiplicativeExpressionOrSuper * UnaryExpressionOrSuper
|  MultiplicativeExpressionOrSuper / UnaryExpressionOrSuper
|  MultiplicativeExpressionOrSuper % UnaryExpressionOrSuper
|  SuperExpression

Additive Operators

|  AdditiveExpressionOrSuper + MultiplicativeExpressionOrSuper
|  AdditiveExpressionOrSuper - MultiplicativeExpressionOrSuper
|  SuperExpression

Bitwise Shift Operators

|  ShiftExpressionOrSuper << AdditiveExpressionOrSuper
|  ShiftExpressionOrSuper >> AdditiveExpressionOrSuper
|  ShiftExpressionOrSuper >>> AdditiveExpressionOrSuper
|  SuperExpression

Relational Operators

|  RelationalExpressionOrSuperallowIn < ShiftExpressionOrSuper
|  RelationalExpressionOrSuperallowIn > ShiftExpressionOrSuper
|  RelationalExpressionOrSuperallowIn <= ShiftExpressionOrSuper
|  RelationalExpressionOrSuperallowIn >= ShiftExpressionOrSuper
|  RelationalExpressionallowIn is ShiftExpression
|  RelationalExpressionallowIn as ShiftExpression
|  RelationalExpressionallowIn in ShiftExpressionOrSuper
|  RelationalExpressionallowIn instanceof ShiftExpression
|  RelationalExpressionOrSupernoIn < ShiftExpressionOrSuper
|  RelationalExpressionOrSupernoIn > ShiftExpressionOrSuper
|  RelationalExpressionOrSupernoIn <= ShiftExpressionOrSuper
|  RelationalExpressionOrSupernoIn >= ShiftExpressionOrSuper
|  RelationalExpressionnoIn is ShiftExpression
|  RelationalExpressionnoIn as ShiftExpression
|  RelationalExpressionnoIn instanceof ShiftExpression
|  SuperExpression

The expression a is b takes an expression that must evaluate to a type as its second operand b. When a is not null, the expression a is b returns true if a is a member of type b and false otherwise; this is equivalent to testing whether a can be stored in a variable of type b without coercion. When a is null, a is b behaves analogously to method dispatch and returns true if b is either Object or Null and false otherwise. As a special case, when a is –0.0 and b is sbyte, byte, short, ushort, int, or uint, a is b returns true.

The expression a as b returns a if a is a member of type b. Otherwise, if a can be implicitly coerced to type b, then the result is the result of that implicit coercion. Otherwise, a as b returns null if null is a member of type b or throws an exception otherwise. In any case b must evaluate to a type.

The instanceof operator is deprecated and behaves in the same way as in JavaScript 1.5 — a instanceof b follows a’s prototype chain.

Equality Operators

|  EqualityExpressionOrSuper == RelationalExpressionOrSuper
|  EqualityExpressionOrSuper != RelationalExpressionOrSuper
|  EqualityExpressionOrSuper === RelationalExpressionOrSuper
|  EqualityExpressionOrSuper !== RelationalExpressionOrSuper
|  SuperExpression

Binary Bitwise Operators

|  BitwiseAndExpressionOrSuper & EqualityExpressionOrSuper
|  BitwiseXorExpressionOrSuper ^ BitwiseAndExpressionOrSuper
|  BitwiseOrExpressionOrSuper | BitwiseXorExpressionOrSuper
|  SuperExpression
|  SuperExpression
|  SuperExpression

Binary Logical Operators

|  LogicalAndExpression && BitwiseOrExpression
|  LogicalXorExpression ^^ LogicalAndExpression

The ^^ operator is a logical exclusive-or operator. It evaluates both operands. If they both convert to true or both convert to false, then ^^ returns false; otherwise ^^ returns the unconverted value of whichever argument converted to true.

|  LogicalOrExpression || LogicalXorExpression

Conditional Operator

|  LogicalOrExpression ? AssignmentExpression : AssignmentExpression
|  LogicalOrExpression ? NonAssignmentExpression : NonAssignmentExpression

Assignment Operators

|  PostfixExpression = AssignmentExpression
|  PostfixExpressionOrSuper CompoundAssignment AssignmentExpression
|  PostfixExpressionOrSuper CompoundAssignment SuperExpression
|  PostfixExpression LogicalAssignment AssignmentExpression
|  /=
|  %=
|  +=
|  -=
|  <<=
|  >>=
|  >>>=
|  &=
|  ^=
|  |=
|  ^^=
|  ||=

Comma Expressions

|  ListExpression , AssignmentExpression
|  «empty»

Type Expressions

TypeExpression  NonAssignmentExpression

Compile-Time Constant Expressions

A compile-time constant expression is an expression that either produces an error or evaluates to a value that can be determined at compile time.

The reason that a compile-time constant expression is not guaranteed to always evaluate successfully at run time is that global name lookup cannot be guaranteed to succeed. It is possible for a program to import a package P that defines a global constant P::A that can be accessed as A and then dynamically define another top-level variable Q::A that collides with A. It does not appear to be practical to restrict compile-time constant expressions to only qualified names to eliminate the possibility of such collisions.

A compile-time expression can consist of the following:

A pure function cannot have any read or write side effects or create any objects. A pure function’s result depends only on its arguments. A JavaScript host embedding may define some pure functions. Currently there is no way for a script to define any such functions, but a future language extension may permit that.

A reference R to a definition D of a compile-time constant is allowed inside a compile-time constant expression as long as the conditions below are met. If D was imported from another package, then the location of D is considered to be the location of the import directive. If D is visible to R by virtue of an intervening use directive U, then the conditions below have to be satisfied both with respect to D and R and with respect to U and R.

Some compile-time constant expressions only allow references to definitions that are textually prior to the point of the reference. Other compile-time constant expressions allow forward references to later compile-time constant definitions.


JavaScript 2.0 imposes the following restrictions:

A statement A dominates statement B if any of the following conditions are met:

Note that the above definition is conservative. If statement A dominates statement B, then it is guaranteed that, if B is executed then A must have been executed earlier; however, there may be some other statements A' that also are guaranteed to have been executed before B but which do not dominate B by the above definition.

A statement A is dead if any of the following conditions are met:

Note that the above definition is conservative. If a statement is dead, then it is guaranteed that it cannot be executed; however, there may be statements that cannot be executed that are not dead by the above definition.

A statement is live if it is not dead.

Waldemar Horwat
Last modified Tuesday, December 18, 2001