Package: src/packages/core_scalar_types.fdoc

key file
__init__.flx share/lib/std/scalar/__init__.flx
scalar.flx share/lib/std/scalar/ctypedefs.flx

Core Scalar Types

Language features.

In these definitions, we introduce basic types into Felix with bindings to C. These are expressed by the type statement, which gives the Felix name of the type, and then the C name in quotes.

Note very particularly each type is distinct, type names such as size_t in C and C++ are merely aliases for some other integer type, in Felix these types are completely distinct.

The adjective pod stands for <em>plain old datatype</em> and tells the system that the type has a trivial destructor and does not require finalisation.

The adjective _gc_pointer tells the system the abstract primitive is in fact a pointer and the garbage collector must follow it.

The requires clause, if specified, tells the system that the named floating insertion must be emitted into the generated C++ code. We will use the names of code fragments specifying header files defined in the <strong>cheaders</strong> package.

Synopsis

//[__init__.flx]

include "std/scalar/ctypedefs";

include "std/scalar/address";
include "std/scalar/memory";
include "std/scalar/bool";
include "std/scalar/int";
include "std/scalar/real";
include "std/scalar/number";
include "std/scalar/char";

include "std/scalar/float_format";
include "std/scalar/float_math";
include "std/scalar/quaternion";

include "std/kind/staticbool";

Character type

A basic 8 bit character type.

//[scalar.flx]
pod type char = "char";

Efficient Integer types

These types correspond to C99 integer types. Note that Felix mandates the existence of the long long types.

Note we also require the C99 intmax_t and uintmax_t types. These will usually be signed and unsigned long long, however they may be an even larger type if the C implementor desires.

We also map C89 size_t and the less useful C99 ssize_t, a signed variant of size_t. These are used for array lengths and in particular can span byte arrays as large as can be addressed.

//[scalar.flx]
pod type tiny = "signed char" requires index TYPE_tiny;
pod type short = "short" requires index TYPE_short;
pod type int = "int" requires index TYPE_int;
pod type long = "long" requires index TYPE_long;
pod type vlong = "long long" requires index TYPE_vlong;
pod type utiny = "unsigned char" requires index TYPE_utiny;
pod type ushort = "unsigned short" requires index TYPE_ushort;
pod type uint = "unsigned int" requires index TYPE_uint;
pod type ulong = "unsigned long" requires index TYPE_ulong;
pod type uvlong = "unsigned long long" requires index TYPE_uvlong;

pod type intmax = "intmax_t" requires C99_headers::stdint_h, index TYPE_intmax;
pod type uintmax = "uintmax_t" requires C99_headers::stdint_h, index TYPE_uintmax;
pod type size = "size_t" requires C89_headers::stddef_h, index TYPE_size;
pod type ssize = "ssize_t" requires C89_headers::stddef_h, index TYPE_ssize;

/* for concordance, required to generated loops */
class PervasiveInts {
  private const zero: int = "0" requires index CONST_zero;
  private fun isneg:  int -> 2 = "$1<0" requires index FUN_isneg;
  private fun isnonneg:  int -> 2= "$1>=0" requires index FUN_isnonneg;
  private proc decr:  &int = "--*$1;" requires index PROC_decr;
}

// Shouldn't really be here!
class PervasiveLogic {
  private fun land: bool * bool -> bool = "$1&&$2" requires index FUN_land;
  private fun lor: bool * bool -> bool = "$1||$2" requires index FUN_lor;
  private fun lnot: bool * bool -> bool = "!$1" requires index FUN_lnot;
}

Exact Integer types

Here are the usual exact integer types. Note that Felix mandates the existence of the stdint.h header file from C99, and that all the exact types are defined. This includes 64 bit signed and unsigned integers, even on a 32 bit machine.

//[scalar.flx]
pod type int8 = "int8_t" requires C99_headers::stdint_h, index TYPE_int8;
pod type int16 = "int16_t" requires C99_headers::stdint_h, index TYPE_int16;
pod type int32 = "int32_t" requires C99_headers::stdint_h, index TYPE_int32;
pod type int64 = "int64_t" requires C99_headers::stdint_h, index TYPE_int64;
pod type uint8 = "uint8_t" requires C99_headers::stdint_h, index TYPE_uint8;
pod type uint16 = "uint16_t" requires C99_headers::stdint_h, index TYPE_uint16;
pod type uint32 = "uint32_t" requires C99_headers::stdint_h, index TYPE_uint32;
pod type uint64 = "uint64_t" requires C99_headers::stdint_h, index TYPE_uint64;

Raw Memory

Raw memory operations provide an uninterpreted byte and two address types.

We also provide a mapping of ptrdiff_t which is a signed type holding the result of subtracting two pointers or addresses of the same type.

Finally, we provide signed and unsigned integers of the same size as addresses and pointers which can be used to perform arbitrary integer operations.

//[scalar.flx]
pod type byte = "unsigned char" requires index TYPE_byte;
type caddress = "void *";
_gc_pointer type address = "void *" requires index TYPE_address;

pod type ptrdiff = "ptrdiff_t" requires C89_headers::stddef_h, index TYPE_ptrdiff;

pod type intptr = "intptr_t" requires C99_headers::stdint_h, index TYPE_intptr;
pod type uintptr = "uintptr_t" requires C99_headers::stdint_h, index TYPE_uintptr;

Integer literal constructors.

In Felix, integer types are lifted from C in the library. Therefore, constructors for these types must also be defined in the library, including literals.

In Felix, internally, all literals are represented opaquely. There are three components to a literal: the Felix type, the string value of the lexeme decoded by the parser, and a string representing the C++ value to be emitted by the compiler back end.

The grammar specification consists of regular definitions used to recognize the literal, and decoding routines written in Scheme used to produce the triple required by the compiler.

Floating types

Note that Felix requires the long double type from C99. Also note that the complex types are taken from C++ and not C!

//[scalar.flx]
pod type float = "float" requires index TYPE_float;
pod type double = "double" requires index TYPE_double;
pod type ldouble = "long double" requires index TYPE_ldouble;
pod type fcomplex = "::std::complex<float>" requires Cxx_headers::complex, index TYPE_fcomplex;
pod type dcomplex = "::std::complex<double>" requires Cxx_headers::complex, index TYPE_dcomplex;
pod type lcomplex = "::std::complex<long double>" requires Cxx_headers::complex, index TYPE_lcomplex;

Groupings of the types.

We can define sets of types so they may be used in in function bindings to avoid a lot of repetition.

The typesetof operator takes a comma separated list of parenthesised type names, and represents a finite set of types.

The \(\cup\) operator, spelled \cup, can be used to find the setwise union of two typesets.

//[scalar.flx]
//$ Types associated with raw address calculations.
typedef addressing = typesetof (
  byte,
  address,
  caddress
);

//$ Character types.
typedef chars = typesetof (char);

Integers

//[scalar.flx]
//$ "natural" sized signed integer types.
//$ These correspond to C/C++ core types.
typedef fast_sints = typesetof (tiny, short, int, long, vlong);

//$ Exact sized signed integer types.
//$ In C these are typedefs.
//$ In Felix they're distinct types.
typedef exact_sints = typesetof(int8,int16,int32,int64);

//$ "natural" sized unsigned integer types.
//$ These correspond to C/C++ core types.
typedef fast_uints = typesetof (utiny, ushort, uint, ulong,uvlong);

//$ Exact sized unsigned integer types.
//$ In C these are typedefs.
//$ In Felix they're distinct types.
typedef exact_uints = typesetof (uint8,uint16,uint32,uint64);

//$ Weirdo signed integers types corresponding to
//$ typedefs in C.
typedef weird_sints = typesetof (ptrdiff, ssize, intmax, intptr);

//$ Weirdo unsigned integers types corresponding to
//$ typedefs in C.
typedef weird_uints = typesetof (size, uintmax, uintptr);

//$ All the signed integers.
typedef sints = fast_sints \cup exact_sints \cup weird_sints;

//$ All the usigned integers.
typedef uints = fast_uints \cup exact_uints \cup weird_uints;

//$ All the fast integers.
typedef fast_ints = fast_sints \cup fast_uints;

//$ All the exact integers.
typedef exact_ints = exact_sints \cup exact_uints;

//$ All the integers.
typedef ints = sints \cup uints;

Floats

//[scalar.flx]
//$ All the core floating point types.
typedef floats = typesetof (float, double, ldouble);

//$ All the core approximations to real types.
typedef reals = ints \cup floats;

//$ All the core approximations to complex types.
typedef complexes = typesetof (fcomplex,dcomplex,lcomplex);

//$ All the core approximations to numbers.
typedef numbers = reals \cup complexes;

All Scalars.

//[scalar.flx]
//$ All the basic scalar types.
typedef basic_types = bool \cup numbers \cup chars \cup addressing;

// we define this now, we will open it later...
instance [t in basic_types] Eq[t] {
  fun == : t * t -> bool = "$1==$2";
}

// we open this now even though we haven't developed
// the instances yet....
open[T in basic_types] Show[T];