Types

Primitive data types

Primitive data type are the building blocks of which other more complex types are derived from. Each primitive type has the following 3 attributes:

  1. Type: Indicates the name for the type
  2. Width: How many bits it takes up
  3. Intended interpretation: How it should be interpreted

Integral types

Type Width Intended interpretation
byte 8 signed byte (two’s complement)
ubyte 8 unsigned byte
short 16 signed short (two’s complement)
ushort 16 unsigned short
int 32 signed int (two’s complement)
uint 32 unsigned int
long 64 signed long (two’s complement)
ulong 64 unsigned long

There are also some types aliases to be aware of:

Type Width Intended interpretation
size_t Value of config entry types:max_width unsigned
ssize_t Value of config entry types:max_width signed byte (two’s complement)

Decimal

TODO: Add this


Rules

There are a few rules that the type system abides by and which one should know about when dealing with types in T.

Promotion

T has the concept of type promotion meaning that certain types when used in expressions with other different types will have some kind of automatic conversion take place.

Promotion takes place for integral types, below we have an example where a smaller type (byte) is automatically coerced to the bigger type (the long) when assigned to the variable of the type long:

module simple_coerce_literal_good_stdalone_ass;

void function()
{
    byte i = 1UL;
    long i1;

    i1 = i;
}

No explicit cast was required for the statement il = 1

This example is available as part of the test suite.

Literals

There is one case whereby automatic conversion (known as “coercion”) is applied and that is with the usage of numeric literals. Firstly, however, we must discuss the default encoding scheme.

Below we have a table of ranges of values (literal values) and the types they can be coerced to. By this we mean that if you had a statement where you were, for example, assigning one of these literals to a variable of type T that you would infact be able to assign such a value to said type T. That “type T” is what we have in the Coercible-to column:

Range Coercible-to
0255 ubyte, ushort, uint, ulong
065_535 ushort, uint, ulong
04_294_967_295 uint, ulong
018_446_744_073_709_551_615 ulong
0127 byte, ubyte, short, ushort, int, uint, long, ulong
032_7676 short, ushort, int, uint, long, ulong
02_147_483_647 int, uint, long, ulong
09_223_372_036_854_775_807 long, ulong

If the expression being assigned is not a literal but rather a composed expression such as a “negated literal” (a UnaryOpExpression with an operation of - and a embedded LiteralValue) then the following table applies:

Range Coercible-to
-128127 byte, short, int, long
-32_76832_767 short, int, long
-2_147_483_6482_147_483_647 int, long
-9_223_372_036_854_775_8089_223_372_036_854_775_807 long
  1. TODO: Sign/zero extension
    • TODO: Mention that this is something the code emitter will have to do by comparing the CastedValueInstruction’s toType and the getInstrType() of the embedded Value-based instruction
    • It should, however, follow a predictable/lang-specc’d procedure