-
Notifications
You must be signed in to change notification settings - Fork 2
Language Specification (10) : Syntax Binding
Syntax Binding is the process of mapping library defined procedures to built-in syntax. A library defined procedure is bound to a given built-in syntax form by including a binding specifier within the procedure’s header. The binding specifier determines to which syntax form the procedure is bound, and it must be included in both the procedure’s definition and declaration.
procedureHeader :=
PROCEDURE ( '[' bindingSpecifier ']')? procedureSignature ;
bindingSpecifier :=
NEW ( ARGLIST | CAPACITY )? | RETAIN | RELEASE |
READ NEW? | WRITE ( '#' )? | bindableIdent ;
bindableIdent := Pervasive | Primitive ;
A syntax form to which library defined procedures may be bound is said to be bindable. Procedures bound to it are called its bindings. While bindable syntax forms are type agnostic, their bindings are type specific, that is to say, each binding supports arguments of a specific type. For each type to be supported by a bindable syntax form, a binding specific to arguments of the type is required.
A bindable syntax form S
is said to have a binding for type T
when a library procedure p
that supports arguments of T
has been bound to S
. Procedure p
is said to be bound to S
in respect of T
.
Bindable syntax forms act as Wirthian macros. A syntax form S
with binding p
for type T
, an occurrence of S
with a primary argument or argument list a
of type T
is resolved into a procedure call to p
, passing a
.
S a ...
⟶ T.p(a...)
Statement NEW
has three bindable syntax forms.
An ADT module Foo
with a binding
PROCEDURE [NEW] New ( VAR p : Foo );
binds ADT library procedure Foo.New()
to the NEW
statement in respect of type Foo
.
Any use of the NEW
statement with a designator of type Foo
and without initialiser nor capacity specifier is then
replaced by a call to procedure Foo.New()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
a statement of the form
NEW foo;
is resolved into a library call
Foo.New(foo);
An ADT module Foo
with the binding
PROCEDURE [NEW ARGLIST] NewWithArgs ( VAR p : Foo; initVal : ARGLIST OF Value );
bind ADT library procedure Foo.NewWithArgs()
to the NEW
statement in respect of type Foo
.
Any use of the NEW
statement with a designator of type Foo
and an initialiser is then resolved into a call to
procedure Foo.NewWithArgs()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
a statement of the form
NEW foo := { a, b, c };
is resolved into a library call
Foo.NewWithArgs(foo, a, b, c);
An ADT module Foo
with a binding
PROCEDURE [NEW CAPACITY] NewWithCapacity ( VAR p : Foo; capacity : LONGCARD );
binds ADT library procedure Foo.NewWithCapacity()
to the NEW
statements in respect of type Foo
.
Any use of the NEW
statement with a designator of type Foo
and a capacity specifier is then resolved into a call to procedure Foo.NewWithCapacity()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
a statement of the form
NEW foo CAPACITY n;
is resolved into a library call
Foo.NewWithCapacity(foo, n);
An ADT module Foo with a binding
PROCEDURE [RETAIN] Retain ( p : Foo );
binds ADT library procedure Retain()
to the RETAIN
statement in respect of type Foo
.
Any use of RETAIN
with a designator of type Foo
is then resolved into a call to procedure Foo.Retain()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
a statement of the form
RETAIN foo;
is resolved into a library cal
Foo.Retain(foo);
An ADT module Foo
with a binding
PROCEDURE [RELEASE] Release ( VAR p : Foo );
binds ADT library procedure Release()
to the RELEASE
statement in respect of type Foo
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
a statement of the form
RELEASE foo;
is resolved into a library cal
Foo.Release(foo);
Statement READ
has two associated bindings.
-
[READ]
bindings are used to generate calls for plain designators in aREAD
statement -
[READ NEW]
bindings are used to generate calls forNEW
-prefixed designators in aREAD
statement
An IO module FooIO
with a binding
PROCEDURE [READ] Read ( chan : IOChannel; VAR value : Foo );
binds IO library procedure Read()
to the READ
statement in respect of type Foo
.
Any plain designator of type Foo
within a READ
statement will then generate a call to procedure FooIO.Read()
.
An IO module FooIO
with a binding
PROCEDURE [READ NEW] ReadNew ( chan : IOChannel; VAR ptr : Foo ); (* Foo is a pointer type *)
binds IO library procedure ReadNew()
to the READ
statement in respect of pointer type Foo
.
Any NEW
-prefixed designator of pointer type Foo
within a READ
statement will then generate a call to procedure FooIO.ReadNew()
.
Given the following imports and declaration within a client module
IMPORT Foo, FooIO, IOChannel; VAR foo : Foo; file : IOChannel;
- a statement of the form
READ @file : foo
is resolved into a library callFooIO.Read(file, foo)
- a statement of the form
READ @file : NEW foo
is resolved into a library callFooIO.ReadNew(file, foo)
If the IO channel argument is omitted, default input channel primitive STDIN
is automatically inserted. In order to resolve STDIN
an appropriate IO library must be imported to bind an input channel to STDIN
and make it visible within the current module scope. Import of module StdIO
binds StdIO.in()
to STDIN
.
Given the following imports and declaration within a client module
IMPORT Foo, FooIO, StdIO; VAR foo : Foo;
- a statement of the form
READ foo
is resolved into a library callFooIO.Read(StdIO.in(), foo)
- a statement of the form
READ NEW foo
is resolved into a library callFooIO.ReadNew(StdIO.in(), foo)
Given modules Foo
, Bar
, Baz
and Bam
, their respective IO modules FooIO
, BarIO
, BazIO
and BamIO
with bindings to for their respective types and the following imports and declaration within a client module
IMPORT Foo, FooIO, Bar, BarIO, Baz, BazIO, Bam, BamIO, StdIO;
VAR foo : Foo; bar : Bar; baz : Baz; bam : Bam;
a statement of the form
READ foo, NEW bar, baz, NEW bam;
is resolved into a statement sequence
FooIO.Read(StdIO.in(), foo); BarIO.ReadNew(StdIO.in(), bar);
BazIO.Read(StdIO.in(), baz); BamIO.ReadNew(StdIO.in(), bam);
Statement WRITE
has two associated bindings.
-
[WRITE]
bindings are used to generate calls for unformatted output values in aWRITE
statement -
[WRITE #]
bindings are used to generate calls for formatted output values in aWRITE
statement
An IO module FooIO
with a binding
PROCEDURE [WRITE] Write ( chan : IOChannel; value : Foo );
binds IO library procedure Write()
to the WRITE
statement in respect of type Foo
.
Any unformatted output value of type Foo
within a WRITE
statement will then generate a call to procedure
FooIO.Write()
.
An IO module FooIO
with a binding
PROCEDURE [WRITE #] WriteF ( chan : IOChannel; CONST fmtStr : ARRAY OF CHAR; value : Foo );
binds IO library procedure WriteF()
to the WRITE
statement in respect of type Foo
.
Any formatted output value of type Foo
within a WRITE
statement will then generate a call to procedure
FooIO.WriteF()
.
Given the following imports and declaration within a client module
IMPORT Foo, FooIO, IOChannel; VAR foo : Foo; file : IOChannel;
- a statement of the form
WRITE @file : foo
is resolved into a library calFooIO.Write(file, foo)
- a statement of the form
WRITE @file : #(fmt, foo)
is resolved into a library callFooIO.WriteF(file, fmt, foo)
If the IO channel argument is omitted, default output channel primitive STDOUT
is automatically inserted. In order to resolve STDOUT
an appropriate IO library must be imported to bind an output channel to STDOUT
and make it visible within the current module scope. Import of module StdIO
binds StdIO.out()
to STDOUT
.
Given the following imports and declaration within a client module
- a statement of the form
WRITE foo
is resolved into a library callFooIO.Write(StdIO.out(), foo)
- a statement of the form
WRITE #(fmt, foo)
is resolved into a callFooIO.WriteF(StdIO.out(), fmt, foo)
Given modules Foo
, Bar
, Baz
and Bam
, their respective IO modules FooIO
, BarIO
, BazIO
and BamIO
with bindings to for their respective types and the following imports and declaration within a client module
IMPORT Foo, FooIO, Bar, BarIO, Baz, BazIO, Bam, BamIO, StdIO;
VAR foo : Foo; bar : Bar; baz : Baz; bam : Bam;
a statement of the form
WRITE foo, #(fmt1, bar), baz, #(fmt2, bam);
is resolved into a statement sequence
FooIO.Write(StdIO.out(), foo); BarIO.WriteF(StdIO.out(), fmt1, bar);
BazIO.Write(StdIO.out(), baz); BarIO.WriteF(StdIO.out(), fmt2, bam);
An ADT module Foo
with a binding
PROCEDURE [APPEND] Append ( VAR a : Foo; values : ARGLIST OF Value );
binds ADT library procedure Foo.Append()
to pervasive procedure APPEND()
in respect of type Foo
.
Any call to APPEND()
with a first argument of type Foo
is then resolved into a call to procedure Foo.Append()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
an invocation of the form APPEND(foo, v1, v2, v3)
is resolved into a library call Foo.Append(foo, v1, v2, v3)
.
An ADT module Foo
with a binding
PROCEDURE [REMOVE] Remove ( VAR a : Foo; keys : ARGLIST OF Keys );
binds ADT library procedure Foo.Remove()
to pervasive procedure REMOVE()
in respect of type Foo
.
Any call to REMOVE()
with a first argument of type Foo
is then resolved into a call to procedure Foo.Remove()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
an invocation of the form REMOVE(foo, k1, k2, k3)
is resolved into a library call Foo.Append(foo, k1, k2, k3)
.
An ADT module Foo
with a binding
PROCEDURE [COUNT] count ( VAR a : Foo ) : LONGCARD;
binds ADT library function Foo.count()
to pervasive function COUNT()
in respect of type Foo
.
Any invocation of COUNT()
with an argument of type Foo
is then resolved into a call to function Foo.count()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
an invocation of the form COUNT(foo)
is resolved into a library call Foo.count(foo)
.
Within any given ADT module, bindings to COUNT
and LENGTH
are mutually exclusive.
An ADT module Foo
with a binding
PROCEDURE [LENGTH] length ( VAR a : Foo ) : LONGCARD;
binds ADT library function Foo.length()
to pervasive function LENGTH()
in respect of type Foo
.
Any invocation of LENGTH()
with an argument of type Foo
is then resolved into a call to function Foo.length()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
an invocation of the form LENGTH(foo)
is resolved into a library call Foo.length(foo)
.
Within any given ADT module, bindings to COUNT
and LENGTH
are mutually exclusive.
An ADT module Foo
with a binding
PROCEDURE [FIRST] firstKey ( a : Foo ) : KeyType (* of Foo *);
binds ADT library function Foo.firstKey()
to pervasive function FIRST()
in respect of type Foo
.
Any invocation of FIRST()
with an argument of type Foo
is then resolved into a call to function Foo.firstKey()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
an invocation of the form FIRST(foo)
is resolved into a library call Foo.firstKey(foo)
.
An ADT module Foo
with a binding
PROCEDURE [LAST] lastKey ( a : Foo ) : KeyType (* of Foo *);
binds ADT library function Foo.lastKey()
to pervasive function LAST()
in respect of type Foo
.
Any invocation of LAST()
with an argument of type Foo
is then resolved into a call to function Foo.lastKey()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo;
an invocation of the form LAST(foo)
is resolved into a library call Foo.lastKey(foo)
.
An ADT module Foo
with a binding
PROCEDURE [PREV] prevKey ( VAR a : Foo; key : Key ) : Key;
binds ADT library function Foo.prevKey()
to pervasive function PREV()
in respect of type Foo
.
Any invocation of PREV()
with an argument of type Foo
is then resolved into a call to function Foo.prevKey()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo; key : Foo.Key;
an invocation of the form PREV(foo, key)
is resolved into a library call Foo.prevKey(foo, key)
.
An ADT module Foo
with a binding
PROCEDURE [NEXT] nextKey ( VAR a : Foo; key : Key ) : Key;
binds ADT library function Foo.nextKey()
to pervasive function NEXT()
in respect of type Foo
.
Any invocation of NEXT()
with an argument of type Foo
is then resolved into a call to function Foo.nextKey()
.
Given the following import and declaration within a client module
IMPORT Foo; VAR foo : Foo; key : Foo.Key;
an invocation of the form NEXT(foo, key)
is resolved into a library call Foo.nextKey(foo, key)
.
An ADT module Foo
with a binding
CONST [TLIMIT] Capacity = 1000;
binds library constant Foo.Capacity
to pervasive macro TLIMIT()
in respect of type Foo
.
Given an import directive IMPORT Foo;
within a client module,
an expression of the form TLIMIT(Foo)
is replaced by library constant Foo.Capacity
.
A library module may bind an array constant to the language processor’s internal collation table.
CONST [COLLATION] Order = { index0, index1, index2, ... index94 };
where value Order[i]
defines the collation index of character CHR(i+32)
for i
in range [0..94]
.
Such a library is called a collation library. Import of a collation library causes pervasive function COLLATION()
and thereby all string comparisons to use the library defined order within the scope of the importing module.
An ADT module Foo
with a binding
PROCEDURE [VALUE] valueForKey ( VAR a : Foo; key : Key ) : Value;
binds function Foo.valueForKey()
to primitive VALUE
in respect of type Foo
.
Any (internal) use of primitive VALUE
with a first argument of type Foo
is then resolved into a library call to
function Foo.valueForKey()
during translation of syntax forms that are synthesised using primitive VALUE
.
An ADT module Foo
with a binding
PROCEDURE [ATVALUE] valueAtIndex ( VAR a : Foo; atIndex : LONGCARD ) : Value;
binds function Foo.valueAtIndex()
to primitive ATVALUE
in respect of type Foo
.
Any (internal) use of primitive ATVALUE
with a first argument of type Foo
is then resolved into a library call to
function Foo.valueAtIndex()
during translation of syntax forms that are synthesised using primitive ATVALUE
.
An ADT module Foo
with a binding
PROCEDURE [STORE] StoreKeyValue ( VAR a : Foo; key : Key; value : Value );
binds procedure Foo.StoreKeyValue
to primitive STORE
in respect of type Foo
.
Any (internal) use of primitive STORE
with a first argument of type Foo
is then resolved into a library call to
procedure Foo.StoreKeyValue
during translation of syntax forms that are synthesised using primitive STORE
.
An ADT module Foo
with a binding
PROCEDURE [ATSTORE] StoreAtIndex ( VAR a : Foo; atIndex : LONGCARD; value : Value );
binds procedure Foo.StoreAtIndex
to primitive ATSTORE
in respect of type Foo
.
Any (internal) use of primitive ATSTORE
with a first argument of type Foo
is then resolved into a library call to
procedure Foo.StoreAtIndex
during translation of syntax forms that are synthesised using primitive ATSTORE
.
An ADT module Foo
with a binding
PROCEDURE [ATINSERT] AtInsert ( VAR a : Foo; atIndex : LONGCARD; values : ARGLIST OF Value );
binds procedure Foo.AtInsert
to primitive ATINSERT
in respect of type Foo
.
Any (internal) use of primitive ATINSERT
with a first argument of type Foo
is then resolved into a library call to
procedure Foo.AtInsert
during translation of syntax forms that are synthesised using primitive ATINSERT
.
An ADT module Foo
with a binding
PROCEDURE [ATREMOVE] AtRemove ( VAR a : Foo; startIndex, endIndex : LONGCARD );
binds procedure Foo.AtRemove
to primitive ATREMOVE
in respect of type Foo
.
Any (internal) use of primitive ATREMOVE
with a first argument of type Foo
is then resolved into a library call to
procedure Foo.AtRemove
during translation of syntax forms that are synthesised using primitive ATREMOVE
.
A storage library module MyStorage
with a binding
PROCEDURE [ALLOC] Allocate ( VAR p : CAST ADDRESS; size : LONGCARD );
binds procedure MyStorage.Allocate
to primitive ALLOC
.
Any (internal) use of primitive ALLOC
is then resolved into a library call to procedure MyStorage.Allocate
during translation of NEW
statements for types that do not provide type specific bindings to NEW
.
A storage library module MyStorage
with a binding
PROCEDURE [DEALLOC] Deallocate ( VAR p : CAST ADDRESS );
binds procedure MyStorage.Deallocate
to primitive DEALLOC
.
Any (internal) use of primitive DEALLOC
is then resolved into a library call to procedure MyStorage.Deallocate
during translation of RELEASE
statements for types that do not provide type specific bindings to RELEASE
.
An IO module MyIO
with a binding
PROCEDURE [STDIN] stdIn : ArbitraryIOChannelType;
binds MyIO.stdIn()
to primitive STDIN
. (Internal) use of STDIN
is then resolved to MyIO.stdIn()
.
An IO module MyIO
with a binding
PROCEDURE [STDOUT] stdOut : ArbitraryIOChannelType;
binds MyIO.stdOut()
to primitive STDOUT
. (Internal) use of STDOUT
is then resolved to MyIO.stdOut()
.
Copyright © 2015-2018 Modula-2 Software Foundation