.sh 1 "Types and Declarations"
.(b
type  ::=  |1basic_type   #   type_definition   #   type_identifier   #
           /1component_identifier  .  type_identifier
.)b
.(b
basic_type  ::=  @bool@   #   @char@   #   @int@   #   @string@  (  integer_expression  )
.)b
.(b
declaration  ::=  |1type_declaration   #   constant_declaration   #   variable_declaration   #
                  /1optype_declaration   #  operation_declaration
.)b
.lp
The SR types consist of ordered types and structured types.
The ordered types are boolean, character, integer, and enumeration types.
The structured types are strings, records, capabilities, and pointers.\**
.(f
\**Reals and unions are not yet supported but will be added
in the near future.
.)f
Enumeration and structured types may be defined
in type declarations and subsequently referenced by means
of the type identifier.
Such types may also be defined anonymously by simply being
defined at any point a type is required.
For example, a variable can be specified to have a record
type either by using the name of a previously defined record type
or by defining the record structure in the variable's declaration.
.pp
Declarations describe user-defined data types, constants,
variables, operation types, and operations.
Declarations may contain expressions,
which can reference previously declared objects,
including global ones.
Thus, as a block is executed,
declarations are at least conceptually evaluated
as they are encountered.
.sh 2 "Type Declarations"
.(b
type_declaration  ::=  @type@  type_identifier  =  type_definition  type_restriction{{o}}
.)b
.(b
type_definition  ::=  |1enumeration_definition   #   string_definition   #   record_definition   # 
                      /1pointer_definition   #   capability_definition
.)b
.(b
type_restriction  ::=  {  public  }   #   {  private  }
.)b
.(b
enumeration_definition  ::=  @enum@  (  enumeration_literal  @,@{{+}}  )
.)b
.(b
string_definition  ::=  @string@  (  integer_expression  )
.)b
.(b
record_definition  ::=  @rec@  (  field_definition{{+}}  )
.)b
.(b
field_definition  ::=  variable_name  @,@{{+}}  :  type
.)b
.(b
pointer_definition  ::=  @ptr@  type   #   @ptr any@
.)b
.(b
capability_definition  ::=  |1@cap@  resource_or_operation_or_optype_identifier   #
                            /1@cap@  component_identifier . operation_or_optype_identifier  #
                            /1@cap@  operation_specification
.)b
.lp
A type declaration introduces a new identifier that is a
synonym for the declared type.
Types are used in declarations of variables,
record fields, and parameters.
.pp
Enumeration types define symbolic literals.
The literals have an implicit order that is the order
in which they are declared
and an implicit mapping to integer values
with the first literal being mapped to zero, the second
to one, and so on.
Enumeration literals can be cast to their
integer equivalent using the pre-defined function @int@.
Enumeration literals, unlike identifiers,
cannot be redeclared in nested blocks;
each such literal must belong to exactly one enumeration type.
Furthermore, enumeration literals cannot be hidden by declaring
other objects of the same name.
.pp
String types define variable-length strings of characters.
The minimum length of the value in a string variable is zero;
the maximum length is the value of the expression in
the corresponding string definition.
The length of a string variable changes when a new
value is assigned to the variable.
.pp
Record types define collections of data values.
Fields in records are declared like variables,
but may not have initial values.
.pp
Pointer types define references to data values.
Their use is not restricted, but care should
be taken to avoid the possibility
of a pointer referencing a value in a different virtual
machine and hence in a different address space
(see Sec. 6.3).
The special case @ptr any@ is a generic pointer type that
can reference a value of any type.
Such a pointer can be assigned to and copied,
but cannot be dereferenced.
Generic pointers can be used, for example, to construct
mutually recursive record types.
.pp
Capability types define references to resources and operations.
A capability for a resource has one implicit field for each
operation the resource exports.
Thus, a resource capability is like a record of
operation capabilities.
However, a resource capability also has one implicit
field that permits the associated resource to be destroyed.
A resource capability may be bound to an instance
of the named resource or to any resource that exports
the same number of operations with the same parameterization.
An operation capability, or field of a resource capability,
can be bound to any operation having the same parameterization,
assuming the operation restriction of the capability is a
subset of the restriction on the operation to which
the capability is bound (see Sec. 3.4).
When parameterization is compared, only the signatures of
formals and return values matter; formal and return
identifiers are ignored (see Sec. 7.6).
The capability literals @null@ and @noop@ (see Sec. 7.2)
can be assigned to any resource or operation capability.
.pp
The optional type restriction on a type declaration
indicates how objects of the type may be used.
The default is `public', which imposes no restriction.
The other option is `private'.
Use of a private type is unrestricted
in the component in which the type is declared.
However, objects of a private type may only appear in declarations
and expressions in other components.
In particular, such objects may not be assigned to.
This allows a resource to export a type,
while ensuring that only instances of the resource
can alter objects of that type.
Note that it makes no sense to attach a private restriction to
a type declared in a global component since that would render
the type unusable.
.PS L
%Examples:
.sp .5
	type primary_color = enum(red, blue, yellow)
	type person = rec(name : string(20); age : int)
	type stack_cap = cap Stack
	type File_Desc = rec(read : cap Read;  write : cap Write
	                     seek : cap Seek; close : cap Close)
	type r1 = rec(a : int; p2 : ptr any)    # p2 can point to type r2
	type r2 = rec(b : int; p1 : ptr r1)
.PE
.sh 2 "Variables and Constants"
.(b
variable_declaration  ::=  @var@  variable_definition  @,@{{+}}
.)b
.(b
constant_declaration  ::=  @const@  initialized_variable  @,@{{+}}
.)b
.(b
variable_definition  ::=  initialized_variable   #   uninitialized_variable
.)b
.(b
initialized_variable  ::=  variable_name  type_part{{o}}  @:=@  expression
.)b
.(b
uninitialized_variable  ::=  variable_name  @,@{{+}}  :  type
.)b
.(b
variable_name  ::=  variable_identifier  subscripts{{o}}
.)b
.(b
subscripts  ::=  @[@  range  @]@   #   @[@  range  @,@  range  @]@
.)b
.(b
range  ::=  integer_expression   #   expression  @:@  expression
.)b
.(b
type_part  ::=  @:@  type
.)b
.lp
A variable declaration introduces one or more new variables,
their types, and optionally their initial values.
A constant declaration introduces one or more read-only
variables and always specifies their initial values.
.pp
The declaration of an initialized variable (or constant)
contains an initialization expression.
If this expression's value is a single element of a
basic type\(emor a vector of values of a basic type\(emthe type
part of the declaration may be omitted since it can be inferred.
However, the declaration of an uninitialized variable always specifies the
variable's type.
In this case a list of identifiers can
be declared to have the same type.
The initial value of an uninitialized variable is undefined.
.pp
A variable without subscripts is called a #simple #variable;
it is used to hold one value of the declared type.
A variable with subscripts is called a #subscripted #variable or #array;
it is used to hold a collection of values of the declared type.
Arrays can have one or two ranges (dimensions).
A one-dimensional array is called a vector;
a two-dimensional array is called a matrix.
.pp
A range can be specified by giving expressions
for both the lower and upper bounds.
These expressions must yield values of the
same ordered type;
an array has no elements if the value
of any upper bound is smaller than that of the corresponding lower bound.
Alternatively, a range can be specified by giving just
one integer-valued expression;
in this case the implicit lower bound is 1.
As in all declarations,
these expressions can reference previously declared objects;
hence, the size of an array can vary between block activations.
.PS L
%Examples:
.sp .5
	const N := 100, twoN := 2*N
	const error_msg := "boom: fatal error"   # type is string(17)
	var count := 0, front := 0, rear := 0   # types are int
	var sc : stack_cap
	var name : string(20) := ""     # initially empty
	var boolean_matrix[1:N,1:N] : bool := ([N*N] false)
	var int_vector[1:10] := ([10] 0)
	var me : person
	var char_count[char(0):char(127)] : int
	var fd[1:3] : File_Desc
.PE
.sh 2 "Operation-Type Declarations"
.(b
optype_declaration  ::=  @optype@  optype_identifier  @=@{{o}}  operation_specification
.)b
.lp
An @optype@ declaration introduces a new identifier that is a synonym
for the specified type of operation.
Operation types are used in operation and capability declarations.
They are to operations what type declarations are to variables:
they declare patterns that will be used more than once.
.PS L
%Examples:
.sp .5
	optype answer(res result : int)  {send}
	optype Write(buf[0:*] : char; cnt : int) returns actual_cnt : int
.PE
.sh 2 "Operation Declarations"
.(b
operation_declaration  ::=  |1@op@  operation_definition  @,@{{+}}   #
                            /1@op@  operation_name  @,@{{+}}  @:@{{o}}  optype_identifier   #
                            /1@sem@  operation_name  @,@{{+}}
.)b
.(b
operation_definition  ::=  operation_name  operation_specification
.)b
.(b
operation_name  ::=  operation_identifier  subscripts{{o}}
.)b
.(b
operation_specification  ::=  (  parameter_spec{{*}}  )  return_spec{{o}}  op_restriction{{o}}
.)b
.(b
parameter_spec  ::=  parameter_kind{{o}}  variable_name  @,@{{+}}  :  type
.)b
.(b
return_spec  ::=  @returns@  variable_name  @:@  type
.)b
.(b
op_restriction  ::=  @{call}@   #   @{send}@   #   @{call, send}@\
   #   @{send, call}@
.)b
.(b
parameter_kind  ::=  @var@   #   @val@   #   @res@
.)b
.lp
An operation declaration defines one or more simple or subscripted
operation headers.
Every operation must be declared in an operation declaration
before being invoked or implemented.
.pp
Each operation is implemented either by one @proc@,
or by input (@in@) or @receive@ statements.
Subscripted operations may be implemented only by input
or @receive@ statements.
Operations provide the sole means by which processes in different
resources interact.
.pp
An operation may have parameters and/or a result.
Parameters are passed by copying, as is the result.
Value parameters (@val@) are copied in,
result parameters (@res@) and the return value are copied out,
and variable parameters (@var@) are copied both in and out.
The default parameter kind is @val@.
.pp
Unlike normal variables, the sizes of string and
array parameters may depend on the arguments of an invocation.
This is denoted by the use of `*' for the string
size or one of the range bounds.
When the operation is invoked, the implicit value of `*'
becomes whatever is required to match the corresponding attribute
of the actual parameter.
This value can be determined
by means of the pre-defined functions, @length@, @lb@, and @ub@.
.pp
Operations are invoked by explicit @call@ or @send@ statements, or by
implicit calls.
The operation restriction indicates whether the invocation
can be by @call@, by @send@, or by either.
The default is no restriction.
.pp
A semaphore is a special kind of operation introduced by a @sem@ declaration.
Semaphores can be accessed by the @P@ and @V@ statements, which
are simply abbreviations for @receive@ and @send@ respectively.
Semaphores provide no additional functionality over normal operations
but can sometimes allow a clearer expression of the programmer's intentions.
Diagnostics are in terms of the underlying implementation as special operations.
The initial value of each semaphore is zero;
an appropriate number of @V@ statements must be executed to initialize
a semaphore to another value.
.PS L
%Examples:
.sp .5
	op insert(item : person)
	op my_answer, your_answer : answer    # uses optype answer
	op differ(s1, s2 : string(*)) returns place : int {call}
	op signals[1:4]() {send}
	op tty_write(c : char) {call, send}
	op query(key : int; reply_channel : cap answer) {send}
	op left(i : int) returns lft : int
	sem mutex, fork[1:5]
.PE
