# Defines a type A that is an alias of U32
+type A = U32
+
+# Defines a struct type B whose member x has type A
+struct B {
+ x: A
+ y: F32
+} default { y = 1 }
+diff --git a/docs/fpp-spec.html b/docs/fpp-spec.html index a181fe582..a1558e9e6 100644 --- a/docs/fpp-spec.html +++ b/docs/fpp-spec.html @@ -465,84 +465,91 @@
An alias type definition associates a name with a type +that is defined elsewhere.
+type
identifier = type-name
The identifier is the name N of the type.
+The definition associates the name N with
+the type T specified after the =
symbol.
+Elsewhere in the model, the name N may be used as alias of (i.e., an
+alternate name for) the type T.
# Defines a type A that is an alias of U32
+type A = U32
+
+# Defines a struct type B whose member x has type A
+struct B {
+ x: A
+ y: F32
+} default { y = 1 }
+An array definition defines a new array type and associates a name with it.
array
identifier =
[
expression ]
type-name
@@ -1671,7 +1719,7 @@
The identifier is the name N of the new type. The first expression must evaluate to a compile-time constant numeric value n @@ -1696,7 +1744,7 @@
# Defines an array type A of 3 U8 elements with default value [ 0, 0, 0 ]
@@ -1721,7 +1769,7 @@ 5.2.3. Examples
A component definition defines an F Prime component. A component is a unit of function in the F Prime framework. @@ -1729,7 +1777,7 @@
component-kind component
identifier
@@ -1830,7 +1878,7 @@
The identifier is the name of the component. The definitions inside the body of the component are @@ -1941,7 +1989,7 @@
@ Receives commands from the ground or from a sequencer
@@ -2196,7 +2244,7 @@ 5.3.3. Examples
A component instance definition defines an instance of a @@ -2205,7 +2253,7 @@
instance commandDispatcher: Svc.CommandDispatcher \
@@ -2405,14 +2453,14 @@ 5.4.3. Examples
A constant definition associates a name with a compile-time constant value. You can use the name in place of the value elsewhere in the model.
constant a = 0 # a has value 0
@@ -2444,7 +2492,7 @@ 5.5.3. Examples
An enum definition does two things:
The enumerated constants have the enum type defined in the enum definition. During @@ -2509,14 +2557,14 @@
If type-name does not appear after the identifier, then
the implied representation type is I32
.
If type-name appears after the identifier, then the semantic analyzer does the following:
@@ -2535,7 +2583,7 @@The following example shows two definitions. In the first one, the implied
representation type is I32
.
@@ -2572,7 +2620,7 @@
An enumerated constant definition is an element of an
enum
@@ -2583,7 +2631,7 @@ 5.7. Enumerated Constant De
in the enum definition.
If present, expression must evaluate @@ -2625,7 +2673,7 @@
A module definition provides a named scope that encloses and qualifies other definitions, including other module definitions. It is similar to a namespace in C++ or a package in Java or Scala.
A module definition D qualifies the names of all the definitions inside it with its own name. Inside D, you can refer to definitions in @@ -2715,7 +2763,7 @@
module M {
@@ -2730,13 +2778,13 @@ 5.8.3. Example
An port definition defines an F Prime port. A port is the endpoint of a connection between F Prime components.
@ Port 1
@@ -2803,7 +2851,7 @@ 5.9.3. Examples
A state machine definition defines a state machine.
state machine
identifier
[ {
state-machine-member-sequence }
]
An internal state machine M has the following runtime behavior:
state machine MonitorSm {
@@ -3227,13 +3275,13 @@ 5.10.4. Examples
A struct definition defines a new structure type and associates a name with it.
struct
identifier
{
struct-type-member-sequence }
@@ -3257,10 +3305,10 @@
The identifier is the name N of the type. The definition associates the name -N with a +
The identifier is the name N of the type. +The definition associates the name N with a struct type T representing a structure with named members, each of the specified type. Each identifier appearing in the struct type member sequence must be distinct.
@@ -3295,7 +3343,7 @@# Defines a struct type A with members x and y
@@ -3330,7 +3378,7 @@ 5.11.3. Examples
A topology definition defines an F Prime topology, that is, a set of component instances and the connections @@ -3344,7 +3392,7 @@
A topology definition D must be resolvable to a topology T, according to the following algorithm:
@@ -3755,7 +3803,7 @@Example 1.
An alias type is a type associated with an +alias type definition. +There is one alias type per alias type definition. +An alias type is written using its +unique qualified +name.
+Internal types do not have syntactic names in FPP source models. The compiler assigns these types to expressions during type checking.
The type Integer represents all integer values, without regard to bit width.
Integer together with the primitive integer types are called @@ -9494,7 +9554,7 @@
Integer together with the primitive numeric types are called @@ -9502,7 +9562,7 @@
The type [ n ] T, where n is an integer and T is a type, represents an array of n elements, @@ -9510,7 +9570,7 @@
The type { \$m_1\$ : \$T_1, ...,\$ \$m_n\$ : \$T_n\$ }, where each \$m_i\$ is an identifier and each \$T_i\$ is a type, @@ -9524,9 +9584,35 @@
A type is a displayable type if it is one of the following:
+A type is a canonical type if it is not an alias type.
+The underlying type of a type T is the canonical type +associated with T.
+If T is a canonical type, then the underlying type of T is T.
+Otherwise T is an alias type. +In this case, the underlying type of T is the underlying type of the type +associated with T in the definition of T.
+A displayable type is a type that the F Prime ground data system can display. +It is one of the following:
A struct type whose member types are all displayable types.
An alias type whose underlying +type is a displayable type.
+A type has numeric members if it is one of the following:
+A type has numeric members if its underlying type +is one of the following:
Every type T with a syntactic name in FPP has an associated default value. @@ -9634,6 +9725,12 @@
The default value associated with an +alias type T is the +default value of its +underlying type.
+Each of \$T_1\$ and \$T_2\$ is an +abstract type, +alias type, array type, enum type, or struct type, @@ -10000,6 +10099,13 @@
If either \$T_1\$ or \$T_2\$ or both is an +alias type, then \$T_1\$ +may be converted to \$T_2\$ if the underlying +type of \$T_1\$ may be converted to +the underlying type of \$T_2\$.
+Any string type may be converted to any other string type.
Otherwise if \$T_1\$ or \$T_2\$ or both are alias +types, then replace +each alias type with its underlying type +and reapply these rules.
+Otherwise if \$T_1\$ and \$T_2\$ are both numeric types, then do the following:
\$T_1\$ and \$T_2\$ are identical types.
Either or both of \$T_1\$ and \$T_2\$ is an alias +type, +and Some \$T'_1\$ may be converted to Some \$T'_2\$, where +\$T'_1\$ is the underlying type of \$T_1\$, +and +\$T'_2\$ is the underlying type of \$T_2\$.
+\$T_1\$ and \$T_2\$ are both signed primitive integer types, and \$T_2\$ is at least as wide as \$T_1\$.
@@ -10294,6 +10414,11 @@Otherwise if either \$T_1\$ or \$T_2\$ is an alias type, +then replace each alias type with its underlying type +and reapply these rules.
+Otherwise if \$T_1\$ and \$T_2\$ are both signed primitive integer types, then let \$T\$ be the wider of the two types.
@@ -10395,13 +10520,35 @@Every value belongs to exactly one type.
+Every value v belongs to exactly one canonical type +T, except as follows:
+Every string value belongs to the type string
and to
+all types string
n, for any n.
Every value that belongs to type T also belongs to every +alias type whose +underlying type is T.
+When a value v belongs to a type T, we say that v is a value +of type T.
+In the following subsections, we describe each kind of value and +its associated canonical types.
A primitive integer value is an ordinary (mathematical) integer value -together with a +together with its canonical type, which is a primitive integer type. Formally, the set of primitive integer values is the disjoint union over the integer types of the values @@ -10422,7 +10569,8 @@
We represent a primitive integer value as an expression followed by a colon and a type. +
We represent a primitive integer value as an expression followed by a colon and
+a primitive integer type.
For example, we write the value 1 at type U32
as 1: U32
. The value 1:
U32
is distinct from the value 1: U8
.
An integer value is an ordinary (mathematical) integer value.
-It has type Integer.
+Its canonical type is Integer.
We represent an integer value as an integer number, with no explicit type.
For example, 1
is an integer value.
We write a floating-point values analogously to primitive integer values. For
-example, we write the value 1.0 at type F32
as 1.0: F32
.
F32
as 1.0: F32
.
+The canonical type of a floating-point value is F32
or F64
.
A Boolean value is one of the values true
and false
.
-Its type is bool
.
bool
.
"abc"
.
-Its type is string
.
+A string value belongs to the following canonical types:
+string
string
n for any n
An abstract type value is a value associated with an abstract
type.
-There is one value associated with each abstract type \$T\$.
+For each abstract type \$T\$, there is one
+value with canonical type \$T\$.
+This value is not represented explicitly in the model, but it
+may be represented in the generated code, e.g., as an object
+with default initialization.
We write the value value of type
\$T\$.
[
\$v_1\$ ,
\$...\$ ,
+an anonymous array value \$v\$ has the form [
\$v_1\$ ,
\$...\$
+,
\$v_n\$ ]
, where for each \$i in [1,n\$], \$v_i\$ is a value of type
-\$T\$ for some \$T\$.
-The type of the value is [ \$n\$ ] \$T\$.
+\$T\$ for some canonical type \$T\$.
+The canonical type of \$v\$ is [ \$n\$ ] \$T\$.
+Note that for an anonymous array value \$v\$ to be well-formed, the member +values must have identical types. +If an array expression appearing in the source syntax has +member values with non-identical types, then one or more members must be +converted to a different type before forming \$v\$.
For each \$i in [1,n\$], \$v_i\$ is a value of type \$T\$.
+For each \$i in [1,n\$], \$v_i\$ is a value of type \$T\$.
+Note that \$T\$ need not be a canonical type.
+For example, it is permissible for \$T\$ to be T
, for
+T
to be an alias of U32
, and for \$v\$ to be the value [ 1: U32, 2: U32 ]
.
+In this case 1: U32
and 2: U32
are values of type T
, as required.
The type of the value is \$Q\$.
+The canonical type of the value is \$Q\$.
{
\$m_1\$ =
\$v_1\$ ,
\$...\$ ,
\$m_n\$ =
\$v_n\$ }
,
where for each \$i in [1,n\$], \$v_i\$ is a value of type \$T_i\$.
-The type of \$v\$ is { \$m_1\$ : \$T_1\$ , \$...\$ ,
-\$m_n\$ : \$T_n\$ }.
+Each type \$T_i\$ must be a canonical type.
+The canonical type of the value is { \$m_1\$ : \$T_1\$ , \$...\$
+, \$m_n\$ : \$T_n\$ }.
The members of \$Q\$ are \$m_i\$ :
\$T_i\$ for \$i in [1,n]\$.
For each \$i in [1,n\$], \$v_i\$ is a value of type \$T_i\$.
+For each \$i in [1,n\$], \$v_i\$ is a value of type \$T_i\$.
+Note that \$T_i\$ need not be a canonical type.
+For example, it is permissible for \$T_1\$ to be T
, for
+T
to be an alias of U32
, and for \$v_1\$ to be the value 1: U32
.
+In this case 1: U32
is a value of type T
, as required.
All the members must be explicitly assigned values.
+Each member of the struct value must have an explicit value. +The canonical type of the struct value is \$Q\$.
If T is a +alias type, then apply these rules to its +underlying type.
+