Types
The primitive types in Silver are:
String
Boolean
Integer
Float
IO
For more information on these primitive types, see the corresponding sections on expressions for Booleans, Numeric Operations, Strings, and IO.)
Functions and production have types that look similar to their signatures, but with the names removed:
(<Type> ::= <Type> ...)
Example: The following function signature:
function pluck
String ::= lst::String index::Integer
has type
(String ::= String Integer)
Lists are given a special syntax for types:
[ <Type> ]
See Lists for more information on lists.
Example: The map function would have the following signature:
function map
[b] ::= (b ::= a) [a]
Nonterminal declarations create a type (as do terminal declarations.) All type names must be capitalized, as lower case names are considered type variables (see Type Variables.)
Example: The following nonterminal declaration:
nonterminal Expr;
creates the type
Expr
.
Note: Attributes with a nonterminal type are often called
higher-order attributes
in the attribute grammar literature\cite{vogt89}. For example:
synthesized attribute transformed :: Expr;
is a “higher-order attribute.”
Nonterminals additionally have a “decorated” form, whose type is simply prefixed
with the keyword Decorated
. See Decorated vs Undecorated for more information.
Example:
Expr
Decorated Expr
Each of these lines is a valid, and importantly different, type.
Note: Attributes with a decorated nonterminal type are often called reference attributes in the attribute grammar literature\cite{hedin00}. For example:
synthesized attribute declaration :: Decorated Dcl;
is a “reference attribute.”
Lower case type names are considered to be type variables. Type variables are declared in a function or production signature only (using a new type variable name elsewhere will result in an ``undefined type" error.)
Example:
function reverse
[a] ::= l::[a] -- 'a' is a new type variable
{
local attribute foo:[b]; -- ERROR: 'b' is not in scope
}
Type variables are always held abstract where they are in scope. Once something
is declared to be of type a
, that cannot be refined to, for example,
Integer
as long as a
is in scope.
Example:
function reverse
[a] ::= l::[a]
{
return [1,2]; -- ERROR: 'a' is not Integer
}
Example: But, the following is perfectly okay:
global foo :: [Integer] = reverse([1,2,3]);