fpp/docs/spec/Evaluation.adoc
2025-09-04 11:07:17 -07:00

147 lines
5.3 KiB
Plaintext

== Evaluation
*Evaluation* is the process of transforming an <<Expressions,expression>> into
a <<Values,value>>.
In FPP, all evaluation happens during
<<Analysis-and-Translation_Analysis,analysis>>,
in resolving expressions to compile-time constant values.
=== Evaluating Expressions
Evaluation of expressions occurs as stated in the
<<Expressions,expression descriptions>>. Evaluation of integer
expressions occurs at type <<Types_Internal-Types_Integer,_Integer_>>,
using enough bits to represent the result without overflow.
Evaluation of floating-point expressions occurs using 64-bit floating-point
arithmetic.
=== Type Conversion
The following rules govern the conversion of a value stem:[v_1] of canonical type
stem:[T_1]
to a value stem:[v_2] of canonical type stem:[T_2].
==== Unsigned Primitive Integer Values
. If stem:[T_1] and stem:[T_2] are both unsigned primitive integer types and
stem:[T_2] is
narrower than stem:[T_1], then construct stem:[v_2] by truncating the
unsigned
binary representation of stem:[v_1] to the width of stem:[v_2]. For
example, converting `0x1234: U16` to `U8` yields `0x34: U8`.
. Otherwise if stem:[T_1] and stem:[T_2] are both unsigned primitive integer
types, then
stem:[v_2] is the integer value of stem:[v_1] at the type of
stem:[v_2]. For example,
converting `0x12: U8` to `U16` yields `0x12: U16`.
==== Signed Primitive Integer Values
. If stem:[T_1] and stem:[T_2] are both signed primitive integer types and
stem:[T_2] is narrower than stem:[T_1], then construct stem:[v_2] by truncating
the two's complement binary representation of stem:[v_1] to the width of
stem:[v_2]. For example, converting `-0x1234: I16` to `I8` yields `-0x34:
I8`.
. Otherwise if stem:[T_1] and stem:[T_2] are both signed primitive integer
types, then stem:[v_2]
is the integer value of stem:[v_1] at the type of stem:[v_2]. For
example, converting `-0x12: I8` to `I16` yields `-0x12: I16`.
==== Primitive Integer Values of Mixed Sign
If stem:[T_1] and stem:[T_2] are primitive integer types with one signed and
one unsigned,
then do the following:
. Construct the value stem:[v] by converting stem:[v_1] to the type
stem:[T], where
stem:[T] is signed if stem:[T_1] is signed and unsigned if
stem:[T_1] is unsigned, and
stem:[T] has the same width as stem:[T_2].
. Construct stem:[v_2] by converting stem:[v] to stem:[T_2].
For example converting `-1: I8` to `U16` yields `0xFFFF: U16`
==== Primitive and Non-Primitive Integer Values
If stem:[T_1] is _Integer_ and stem:[T_2] is a primitive integer type, then
proceed as if stem:[T_1] were a signed primitive integer
type of the narrowest bit width that will hold stem:[v_1].
For example, converting `-0x1234` to `I8` yields `-0x34: I8`.
If stem:[T_1] is a primitive integer type and stem:[T_2] is
_Integer_, then stem:[v_2] is the integer value of stem:[v_1]
at type _Integer_. For example, converting
`0xFFFF: U32` to _Integer_ yields `0xFFFF:` _Integer_.
==== Floating-Point Values
We use the standard rules for IEEE floating-point values to convert
among integer values to and from floating-point values and
floating-point values to and from each other.
==== String Values
If stem:[T_1] is a string type and stem:[T_2] is a string type,
then let stem:[v_2 = v_1].
As noted in the section on <<Values_String-Values,string values>>, if the size
of type stem:[T_2] is less than the length of value stem:[v_1], then string
truncation may occur.
Any such truncation is handled by the generated code.
The FPP type system does not perform any truncation.
==== Array Values
If stem:[T_2] is an array type and stem:[T_1 = T_2], then
let stem:[v_2 = v_1].
Otherwise if stem:[T_1] is
a numeric type, Boolean type, enum type, or string type
and stem:[T_2] is an anonymous array type or array type with stem:[n]
elements, then
. Let stem:[T'_2] be the element type of stem:[T_2].
. Let stem:[w] be the result of converting stem:[v_1] to type stem:[T'_2].
. Let stem:[v_2] be the unique array value of type stem:[T_2]
with value stem:[w] at each element.
Otherwise if stem:[T_1] is an anonymous array type and stem:[T_2] is an
anonymous array type or array type, both with stem:[n] elements, then
. Let stem:[T'_2] be the element type of stem:[T_2].
. For each stem:[i in [0,n-1\]], let stem:[w_i] be the result of converting
element stem:[i] of stem:[v_1] to type stem:[T'_2].
. Let stem:[v_2] be the unique array value of type stem:[T_2]
with value stem:[w_i] at each element stem:[i].
Otherwise the conversion is not valid.
==== Structure Values
If stem:[T_2] is a struct type and stem:[T_1 = T_2], then
let stem:[v_2 = v_1].
Otherwise if stem:[T_1] is an anonymous struct type and stem:[T_2] is
an anonymous struct type or struct type
such that for each member stem:[m] `:` stem:[v_m] of stem:[T_1] there is a member
stem:[m] `:` stem:[T_m] in stem:[T_2], then use the value of stem:[T_2] with
the following members:
. For each member stem:[m] `:` stem:[T_m] of stem:[T_2] such that there is a member
stem:[m] `:` stem:[v_m] in stem:[v_1], add the member stem:[m] `:` stem:[v'_m],
where stem:[v'_m] is the result of converting stem:[v_m] to stem:[T_m].
. For each member stem:[m] `:` stem:[T_m] of stem:[T_2] such that there is no member
stem:[m] `:` stem:[v_m] in stem:[v_1], add the member stem:[m] `:` stem:[v'_m],
where stem:[v'_m] is the <<Types_Default-Values,default value>> at type stem:[T_m].
Otherwise the conversion is invalid.