Core Discus Fragment¶
Core Discus is a fragment of the DDC Core language that represents desugared Source Discus programs. The fragment includes the following primitives:
Primitive Types¶
Type Kind Values Notes
----- ---- ------ -----
Void# Data (no values)
Bool# Data true#, false#
Nat# Data 0#, 1#, 2# ... [1]
Int# Data ... -1i#, 0i#, 1i# ... [2]
Size# Data 0s#, 1s#, 2s# ... [3]
WordN# Data 0w8#, 1056w32# N ∈ { 8, 16, 32, 64 }
FloatN# Data 3.141f32# N ∈ { 32, 64 }
Addr# Data (no literals) [4]
Ptr# Region -> Data (no literals)
TextLit# Data "hello"#
TupleN# .. -> Data (x, y) (x, y, z)
Vector# Region -> Data -> Data (no literals)
U# Data -> Data Represents an unboxed type during compilation [5].
F# Data -> Data Represents a function closure during compilation [6].
[1] The Nat
type has enough precision to count the maximum number of objects allocatable in the Discus heap, but not necessarally enough precision to count every addressable byte.
[2] The Int
type has enough precision to represent numbers in the range [-N .. +N], where N is the maximum number of objects allocatable in the Discus heap.
[3] The Size
type has enough precision to count every addressable byte in memory.
[4] The Addr
type can hold the address of any addressable byte in memory.
[5] The U#
constructor is used to represent the type of an unboxed value during the Unbox transformation.
[6] The F#
constructor is used to represent the type of a closure during the Curry transformation.
Arithmetic Operators¶
Name Type Valid Description
---- ----- ----- -----------
and# Bool# -> Bool# -> Bool# boolean and
or# Bool# -> Bool# -> Bool# boolean or
shl# a -> a -> a [I] bitwise shift left
shr# a -> a -> a [I] bitwise shift right
band# a -> a -> a [I] bitwise boolean and
bor# a -> a -> a [I] bitwise boolean or
bxor# a -> a -> a [I] bitwise boolean exclusive or
neg# a -> a [I, F] negation
add# a -> a -> a [I, F] addition
sub# a -> a -> a [I, F] subtraction
mul# a -> a -> a [I, F] multiplication
div# a -> a -> a [I, F] division
mod# a -> a -> a [I, F] modulus
rem# a -> a -> a [I, F] remainder
eq# a -> a -> Bool# [I, F] equality
neq# a -> a -> Bool# [I, F] negated equality
gt# a -> a -> Bool# [I, F] greater than
ge# a -> a -> Bool# [I, F] greater than or equal
lt# a -> a -> Bool# [I, F] less than
le# a -> a -> Bool# [I, F] less than or equal
Although the arithmetic operators are given indicative polymorphic types for convenience, the object code generator only supports subset of possible instantiations. The ‘Valid’ column in the above table lists whether the operator works on both [I]ntegral and [F]loating point types, or just [I]ntegral. The sets of integral and floating point types are:
[I] Integral = { Bool#, Nat#, Int#, Size#, WordN#, Addr#, Ptr# a }
[F] Floating = { FloatN# }
Cast Operators¶
Name Type Description
---- ---- -----------
convert# {@a b: Data} -> b -> a Convert value to a type of the same precision.
promote# {@a b: Data} -> b -> a Promote value to a type of the same or greater precision.
truncate# {@a b: Data} -> b -> a Truncate value to a type of the same or lower precison.
The cast operators convert numeric values between types. As with the arithmetic operators, although the conversion operators are given polymorphic types the object code generator only supports a subset of possible instantiations.
The cast operators can be used to convert unsigned to signed values, integral to floating point values, address to word values and so on. The available instantiations are platform dependent, for example Addr# can be converted to a Word32# on a 32-bit system, but not on a 64-bit system.
Note that the order of forall quantifiers in the types of these primitive is opposite relative to the order in which the type variables appear in the body of the type. We do this so that it’s easier to specify the desired result type. For example, one can write convert# [Word32#] thing
to indicate that a result of type Word32#
is desired, and the second type argument will be inferred based on the type of thing
.
Vector Operators¶
Name Type / Description
---- ------------------
vectorAlloc# Nat# -> S (Alloc r) (Vector# r a)
Allocate a vector of primitive values, initializing them all to 0.
vectorLength# Vector# r a -> Nat#
Allocate a vector of primitive values, initializing them all to 0.
vectorRead# Vector# r a -> Nat# -> S (Read r) a
Read the value at the given index from a vector.
Attempting to access an out-of-bounds index will cause a runtime exception.
vectorWrite# Vector# r a -> Nat# -> a -> S (Write r) Unit
Write to the value at the given index of a vector.
Attempting to access an out-of-bounds index will cause a runtime exception.
At runtime, vectors are represented as flat arrays of unboxed values. Vector values cannot be polymorphic in the element type. Every use of a vector operator must instantiate the element type variable a
to a primitive numeric type.
Error Operators¶
Name Type / Description
---- ------------------
default# TextLit# -> Nat# -> a
Abort the program, signalling that there was an inexhaustive case match
at the given source file and line number.
The default#
operator is inserted when desugaring Source Discus down to Core Discus.
Closure Operators¶
Name Type/Description
---- ----------------
reify# {@a b: Data} -> (a -> b) -> F# (a -> b)
Reify a function value into an explicit closure value.
curryN# {@aN .. a1 a0: Data} -> F# (aN .. -> a1 -> a0) -> aN .. -> a1 -> a0
Apply N more arguments to the given function closure.
apply# {@aN .. a1 a0: Data} -> (aN .. -> a1 -> a0) -> aN .. -> a1 -> a0
Apply N more arguments to the given function.
The closure operators are inserted by the Curry transformation when converting Core Discus code to Core Salt. They are not normally inserted into client programs.