From ad7e82573996b4c658e1e9d660ba605dac13cc40 Mon Sep 17 00:00:00 2001
From: James Clark Strings
-There are five basic types of structured value. First, there are three container -basic types: list, mapping and table. Second, there is the xml basic type and -the error basic type, which are both special in different ways. +There are five basic types of structured value. First, there are two container +basic types: list and mapping. Second, there are the table, xml and error basic +types, which are each special in different ways.
Values of the container basic types are containers for other values, which are @@ -761,6 +761,14 @@
+Each member has a key that uniquely identifies it within the container. The +member type for a key type K in a container type T consists of all +shapes v such that there is a shape in T with key in K and shape v. A type K is +an optional member type for T if there is a shape v in T and a key k in +K such that v does not have a member k; a member type that is not optional is +required. +
structured-type-descriptor := @@ -776,7 +784,7 @@Structured values
- | Integer index | +Integer key | String key | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Type descriptor | +Filler value | +When available | +
---|---|---|
() |
+() |
++ |
boolean |
+false |
++ |
int |
+0 |
++ |
float |
++0.0f |
++ |
decimal |
++0.0d |
++ |
string |
+"" |
++ |
list type descriptor | +[] |
+if that is a valid constructor for the type | +
mapping type descriptor | +{ } |
+if that is a valid constructor for the type | +
table | +empty table (with no rows) | ++ |
object | +new T() |
+if this is valid and its static type does not include error, where
+T is the object type descriptor (an abstract object type will not
+have a filler value) |
+
xml |
+xml`` |
++ |
stream<T> |
+new stream<T> |
++ |
singleton | +the single value used to specify the type | ++ |
union | +() |
+if () is a member of the union |
+
the filler value for basic type B | +if all members of the union belong to a single basic type B, +and the filler value for B also belongs to the union | +|
T? |
+() |
++ |
any |
+() |
++ |
anydata |
+() |
++ |
byte |
+0 |
++ |
json |
+() |
++ |
Freeze(v) is defined for any pure value v. The result of Freeze(v) is always v. @@ -2045,7 +2175,7 @@
-Some members of a list can be filled in automatically. A member can be filled in -automatically if its type descriptor, as determined by the inherent type of the -list, provides a way to create a filler value. The following table -specifies the filler value for each kind of type descriptor that provides one. -
-Type descriptor | -Filler value | -When provided | -
---|---|---|
() |
-() |
-- |
boolean |
-false |
-- |
int |
-0 |
-- |
float |
-+0.0f |
-- |
decimal |
-+0.0d |
-- |
string |
-"" |
-- |
list type descriptor | -[] |
-if that is a valid constructor for the type | -
mapping type descriptor | -{ } |
-if that is a valid constructor for the type | -
table | -empty table (with no rows) | -- |
object | -new T() |
-if this is valid and its static type does not include error, where
-T is the object type descriptor (an abstract object type will not
-have a filler value) |
-
xml |
-xml`` |
-- |
stream<T> |
-new stream<T> |
-- |
singleton | -the single value used to specify the type | -- |
union | -() |
-if () is a member of the union |
-
the filler value for basic type B | -if all members of the union belong to a single basic type B, -and the filler value for B also belongs to the union | -|
T? |
-() |
-- |
any |
-() |
-- |
anydata |
-() |
-- |
byte |
-0 |
-- |
json |
-() |
-- |
-The inherent type of a list establishes either a fixed length for the list or -just a minimum length for the list, which may be zero. In the latter case, for -each j greater than m, where m is the minimum -length of the list, the inherent type of the list must be such that -j-th member can be filled in automatically. In either case, a list -constructor may specify only the first k members, provided that for -each i from k + 1 up to the fixed length of the list, the -i-th member can be filled in automatically. +A member of a list can be filled in automatically if the FillMember abstract operation would succeed on it. The +inherent type of a list establishes either a fixed length for the list or just a +minimum length for the list, which may be zero. In the latter case, for each +j greater than m, where m is the minimum length +of the list, the inherent type of the list must be such that j-th +member can be filled in automatically. In either case, a list constructor may +specify only the first k members, provided that for each i +from k + 1 up to the fixed length of the list, the i-th +member can be filled in automatically.
annot-access-expr
is T? where T is the type
of the annotation tag.
-index-expr := expression[
expression]
+class="grammar">member-access-expr := expression[
expression]
{MISSING}
-Evaluation of an index-expr that attempts to accessing a list with an out of +Evaluation of a member-access-expr that attempts to access a list with an out of bounds index will complete abruptly with a panic.
simple-const-expr
must be a subtype of
string.
-+There are three kinds of assignment statement: +
++The first two of these build on the concept of an lvalue, whereas the +last one builds on the concept of a binding pattern. +
+ ++An lvalue is what the left hand side of an assignment evaluates to. An lvalue +refers to a storage location which is one of the following: +
++An lvalue that is both defined and initialized refers to a storage location that +holds a value: +
+__init
method returnsassignment-stmt := lhs+ +=
action-or-expr;
-lhs := - variable-reference - | lhs.
field-name - | lhs[
expression]
- | lhs@
+class="grammar">lvexpr := + variable-reference-lvexpr + | field-access-lvexpr + | member-access-lvexpr
+The left hand side of an assignment is syntactically a restricted type of +expression, called an lvexpr. When the evaluation of an lvexpr completes +normally, its result is an lvalue. The evaluation of an lvexpr can also complete +abruptly, with a panic or check-fail, just as with the evaluation of an +expression. +
-An lhs
evaluates to a storage location, into which a value can be
-stored and from which a value can be fetched.
+The compiler determines a static type for each lvexpr just as it does for
+expressions, but the meaning is slightly different. For an lvexpr L to have
+static type T means that if the runtime evaluation of L completes normally
+resulting in an lvalue x, then if x is defined and initialized, it refers to a
+storage location that holds a value belonging to type T. In addition to a type,
+the compiler determines for each lvexpr whether it is potentially undefined and
+whether it is potentially uninitialized.
-When a list value has an inherent type that is not fixed length. then attempting -to write a member of a list at an index i that is greater than or equal -to the current length of the list will first increase the length of the list to -i + 1, with the newly added members of the array being filled in -automatically. +An lvalue supports three operations: store, read and filling-read.
-The type of lhs provides the contextually expected type for action-or-expr. +The fundamental operation on an lvalue is to store a value in the storage +location it refers to. This operation does not required the lvalue to be defined +or initialized; a successful store operation on an undefined lvalue will result +in the addition of a member to the container; a store on an uninitialized lvalue +will initialize it. When an lvalue refers to a variable, it is possible to +determine at compile-time whether the store of a value is permissible based on +the declaration of the variable and the static type of the value to be stored. +However, when the lvalue refers to a member of a container, this is not in +general possible for three reasons. +
++The first of these reasons also applies to lvalues that refer to fields of +objects. Accordingly, stores to lvalues other than lvalues that refer to +variables must be verified at runtime to ensure that they are not impermissible +for any of the above three reasons. An attempt to perform an impermissible store +results in a panic at runtime. +
++List values maintain the invariant that there is a unique integer n, the length +of the list, such that a member k of the list is defined if and only if k is a +non-negative integer less than n. When a store is performed on an lvalue +referring to a member k of a list value and the length of the list is n and k is +> n, then each member with index i for each <= i < k is filled in, by +using the FillMember abstract operation. The FillMember abstract operation may +fail; in particular it will fail if the list is a fixed-length array. If the +FillMember operation fails, then the attempt to store will panic. +
++An lvalue also allows a read operation, which is used by the compound assignment +statement. Unlike a store operation, a read operation cannot result in a runtime +panic. A read operation cannot be performed on an lvalue that is undefined or +uninitialized. +
++Finally, a lvalue supports a filling-read operation, which is used to support +chained assignment. A filling-read is performed only an lvalue with a static +type that is a container type. It differs from a read operation only when it is +performed on a potentially undefined lvalue. If the lvalue is undefined at +runtime, then the filling-read will use the FillMember abstract operation on the +member that the lvalue refers to. If the FillMember operation fails, then the +filling-read panics. Unlike the read operation, the filling-read operation can +be performed on an undefined lvalue; it cannot, however, be performed on an +uninitialized lvalue. +
++The evaluation of an lvexpr is specified in terms of the evaluation of its +subexpressions, the evaluation of its sub-lvexprs, and store and +filling-read operations on lvalues. If any of these result in a panic, then +the evaluation of the lvexpr completes abruptly with a panic.
-variable-reference-lvexpr := variable-reference ++
+The result of evaluating variable-reference-lvexpr is an lvalue referring to a +variable. Its static type is the declared or inferred type of the variable. The +lvexpr is potentially uninitialized if it is possible for execution to have +reached this point without initializing the referenced variable. +
+ +field-access-lvexpr := lvexpr .
field-name
+
+
++The static type of lvexpr must be either a subtype of the mapping basic type +or a subtype of the object basic type. +
++In the case where the static type of lvexpr is a subtype of the object basic +type, the object type must have a field with the specified name, and the +resulting lvalue refers to that object field. +
++In the case where the static type of lvexpr is a subtype of the mapping basic +type, the semantics are as follows. +
+field-name
as an individual-type-descriptor (if
+lvexpr is a union, then this requirement applies to every member of the union);
+lvexpr must not be potentially uninitialized, but may be potentially
+undefined.member-access-lvexpr := lvexpr+[
expression]
+
+The static type of lvexpr must be either a subtype of the mapping basic type or +a subtype of the list basic type. In the former case, the contextually expected +type of expression must be string and it is an error if the static type of +expression is not string; in the latter case, the contextually expected type of +expression must be int and it is an error if the static type of expression is +not int. +
+It is evaluated as follows: ++The static type of the member-access-expr is the member type for the key type K +in T, where T is the static type of the lvexpr and K is the static type type of +expression; the member-access-expr is potentially undefined if K is an optional +member type for T. +
+ +assignment-stmt := lvexpr+=
action-or-expr;
+
+The static type of action-or-expr must be a subtype of the static type of +lvexpr. The static type of lvexpr provides the contextually expected type for +action-or-expr. It is not an error for lvexpr to be potentially undefined or +potentially uninitialized. +
++It is executed at as follows: +
+compound-assignment-stmt := - lhs CompoundAssignmentOperator action-or-expr;
+class="grammar">compound-assignment-stmt := lvexpr CompoundAssignmentOperator action-or-expr;
CompoundAssignmentOperator := BinaryOperator=
-BinaryOperator :=+
|-
|*
|/
|&
||
|^
|<<
|>>
|>>>
+BinaryOperator :=+
|-
|*
|/
|&
||
|^
|<<
|>>
|>>>
-These statements update the value of the LHS variable to the value that results -from applying the corresponding binary operator to the value of the variable and -the value of the expression. +It is a compile error if lvexpr is potentially undefined unless the static type +of lvexpr is a subtype of the list basic type. It is a compile error if lvexpr +is potentially uninitialized.
-+Let T1 be the static type of lvexpr, and let T2 be the static type of +action-expr. Then let T3 be the static type of an expression E1 BinaryOp E2 +where E1 has type T1 and E2 has type T2. It is a compile error if T3 is not a +subtype of T1. +
++It is executed as follows: +
+destructure-assignment-stmt :=