ECMAScript 4 Netscape Proposal
Rationale
Units
|
Friday, September 20, 2002
Units derived from the Spice proposals had originally been part of the ECMAScript 4 proposal but were deferred to a future version of the language in order to keep ECMAScript 4 small. If implemented, units might behave as described in this section.
A unit expression usually consists of a number followed by a unit name with no intervening white space, as in 7cm
.
The unit name can be quoted (for example, 7 "cm"
), in which case white space is permitted between
the number and the unit and the unit name can instead be a unit pattern (for example, 7 "Kg*cm^2/s"
).
When a numeric literal is immediately followed by an identifier, the lexer converts the identifier to a string literal. The parser then treats the number and string as a unit expression. The identifier cannot start with an underscore, but there are no reserved word restrictions on the identifier; any identifier that begins with a letter will work, even if it is a reserved word.
For example, 3in
is converted to 3 "in"
. 5xena
is converted to 5 "xena"
.
On the other hand, 0xena
is converted to 0xe "na"
. It is unwise to define unit names that begin
with the letters e
or E
either alone or followed by a decimal digit, or x
or X
followed by a hexadecimal digit because of potential ambiguities with exponential or hexadecimal notation.
null
true
false
public
this
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 pattern 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 idi in the system unit
namespace. If ei is 1, let Fi
= Vi; otherwise, let Fi = Vi.public::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.public::pow(2)*
unit::s.public::pow(–2)*
unit::q.public::pow(–1)
,
where unit is the system unit
namespace (the distinction between unit and the name unit
is only relevant for perverse code that has a local definition named unit
; the presence of such a local definition
doesn’t affect unit lookup).
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.public::pow(2)*
unit::s.public::pow(–2)*
unit::q.public::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"))
.
Units are defined by placing them in the unit
namespace, which is predefined by the system. Unit
expressions are implicitly qualified using the unit
namespace. The unit namespace is not use
d
by default, so a program needs to explicitly qualify identifiers with unit::
to access existing unit definitions..
The easiest way to define new units is to scale, multiply, or divide existing ones. 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
.
If class extensions were also added to the language, the class extension
mechanism could be used instead of a unit
namespace to define units. This way units could be designated as internal
,
private
, etc.
The unit
attribute would be defined as though
const unit = extend(Unit);
were evaluated at the top level. Unit
would be the class that holds the definitions of unit names.
Waldemar Horwat Last modified Friday, September 20, 2002 |