1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-11 17:29:14 +00:00
millfork/docs/lang/types.md

152 lines
5.1 KiB
Markdown
Raw Normal View History

2018-04-02 22:21:26 +00:00
[< back to index](../index.md)
2018-01-18 21:35:25 +00:00
# Types
Millfork puts extra limitations on which types can be used in which contexts.
## Numeric types
* `byte` 1-byte value of undefined signedness, defaulting to unsigned
* `word` 2-byte value of undefined signedness, defaulting to unsigned
(alias: `int16`)
2018-01-18 21:35:25 +00:00
* `int24` 3-byte value of undefined signedness, defaulting to unsigned
(alias: `farword`; this alias is deprecated and might be removed in the future)
2018-05-14 00:16:46 +00:00
2018-01-18 21:35:25 +00:00
* `long` 4-byte value of undefined signedness, defaulting to unsigned
(alias: `int32`)
* `int40`, `int48`,... `int128` even larger types
2018-01-18 21:35:25 +00:00
* `sbyte` signed 1-byte value
* `ubyte` unsigned 1-byte value
* `pointer` the same as `word`, but variables of this type default to be zero-page-allocated
2018-01-31 21:25:06 +00:00
and you can index `pointer` variables (not arbitrary `pointer`-typed expressions though, `f()[0]` won't compile)
2018-08-03 11:00:52 +00:00
You can create pointer values by suffixing `.addr` to the name of a variable, function or array.
**Work in progress**:
There's no reason to make a function return `pointer` yet, since currently to dereference it,
2018-05-14 00:16:46 +00:00
you need to put it in a variable first anyway.
2018-01-18 21:35:25 +00:00
2018-08-03 11:00:52 +00:00
You can access single bytes of variables by using the following notations:
* for 2-byte-sized variables: `.lo` for the least significant byte and `.hi` for the most significant byte
* for larger variables: `.b0` for the least significant byte and then `.b1`, `.b2` and so on
You can also access words that are parts of variables:
* for 3-byte-sized variables: `.loword` is the word formed from `.b1` and `.b0` and `.hiword` is the word formed from `.b2` and `.b1`
* for 4-byte-sized variables: `.loword` is the word formed from `.b1` and `.b0` and `.hiword` is the word formed from `.b3` and `.b2`
2018-01-18 21:35:25 +00:00
Numeric types can be converted automatically:
* from a smaller type to a bigger type (`byte`→`word`)
* from a type of undefined signedness to a type of defined signedness (`byte`→`sbyte`)
* from a type of defined signedness to a type of undefined signedness (`sbyte`→`byte`)
## Typed pointers
For every type `T`, there is a pointer type defined called `pointer.T`.
Unlike raw pointers, they are not subject to arithmetic.
Examples:
pointer.t p
p.raw // expression of type pointer, pointing to the same location in memory as 'p'
p.lo // equivalent to 'p.raw.lo'
p.hi // equivalent to 'p.raw.lo'
p[0] // valid only if the type 't' is of size 1 or 2, accesses the pointed element
p[i] // valid only if the type 't' is of size 1, equivalent to 't(p.raw[i])'
p->x // valid only if the type 't' has a field called 'x', accesses the field 'x' of the pointed element
p->x.y->z // you can stack it
2018-01-18 21:35:25 +00:00
## Boolean types
TODO
## Special types
* `void` a unit type containing no information, can be only used as a return type for a function.
## Enumerations
Enumeration is a 1-byte type that represents a set of values:
enum <name> { <variants, separated by commas or newlines> }
The first variant has value 0. Every next variant has a value increased by 1 compared to a previous one.
Alternatively, a variant can be given a custom constant value, which will change the sequence.
If there is at least one variant and no variant is given a custom constant value,
then the enumeration is considered _plain_. Plain enumeration types can be used as array keys.
For plain enumerations, a constant `<name>.count` is defined,
equal to the number of variants in the enumeration.
Assigment between numeric types and enumerations is not possible without an explicit type cast:
enum E {}
byte b
E e
e = b // won't compile
b = e // won't compile
b = byte(e) // ok
e = E(b) // ok
Plain enumerations have their variants equal to `byte(0)` to `byte(<name>.count - 1)`.
Tip: You can use an enumeration with no variants as a strongly checked alternative byte type,
as there are no checks no values when converting bytes to enumeration values and vice versa.
2019-04-14 23:58:51 +00:00
## Structs
Struct is a compound type containing multiple fields of various types:
struct <name> { <field definitions (type and name), separated by commas or newlines>}
A struct is represented in memory as a contiguous area of variables laid out one after another.
Struct can have a maximum size of 255 bytes. Larger structs are not supported.
You can access a field of a struct with the dot:
struct point { word x, word y }
point p
p.x = 3
p.y.lo = 4
Offsets are available as `structname.fieldname.offset`:
pointer ptr
ptr = p.addr
ptr += point.y.offset
// ptr points now at p.y
// alternatively:
ptr = p.y.addr
## Unions
union <name> { <field definitions (type and name), separated by commas or newlines>}
Unions are pretty similar to structs, with the difference that all fields of the union
start at the same point in memory and therefore overlap each other.
struct point { byte x, byte y }
union point_or_word { point p, word w }
point_or_word u
u.p.x = 0
u.p.y = 0
if u.w == 0 { ok() }
Offset constants are also available, but they're obviously all zero.