• No results found

The Pint language also offers the programmer the pleasure of making a declaration. The SGML/XML document type declaration which is described in chapter 4.1 on page 22 is not strictly a part of the Pint language, even though it is required for every source file.

Imported program declarations A Pint program may incorporate other programs such as library templates and element declarations using one of the following dec-larations

• import name where name is the name of an entity recorded in an ENTITY declaration in the OASIS catalogue. The corresponding file identified by the catalogue is to be imported.

• importfpi where fpi is a formal public identifier recorded in a PUBLIC declara-tion in the OASIS catalogue. The corresponding file defined by the catalogue is to be imported.

For example

141 import "-//Pint//DTD Input output library//EN"

17The character ¶ is Unicode character U+00B6 which is octal 266 and decimal 182.

4.8 Declarations 33

will call for a lookup of PUBLIC "-//Pint//DTD Input output library//EN" in the catalogue, and the corresponding file, possibly ./lib/io.dtd will be imported.

Imported files may import other files. It is not an error to try to import a file twice.

Pint remembers that the file is already imported and skips the second importation.

Whever this happens you will receive a warning on the console and in the log file.

For example:

142 58:55 Skipping -//Pint//DTD Input output library//EN:

143 already imported.

This behaviour is useful for providing default declarations which may, optionally, be over-ridden by an import declaration in a user program. The import declara-tion in a user’s program will be the first seen by the translator, if it is placed at the head of theimportlist. SGML experts and XML specialists will be reminded of the effect of entity declarations in the internal subset [Gol90, 9.4.4.1] [GP02, 55.2].

import declarations must appear at the head of the program, before any other Pint declaration.

New path declarations The π-calculus operator ν used in (νx)P and read as “new x in P ” is written new x and introduces a new path x for the remainder of the scope of the declaration. This x is different from any other x. For example

144 let new x

145 out ( alu.int.+!{2 2 x}

146 || x ? i=io.format.itouni ! <Itouni <DefaultFpp> i c>

147 )

148 end

The declaration new x ensures that the path on which the ALU returns the sum is different to all other paths.

The general syntax is newhnamei[:htypei]. See chapter 5.3 for a discussion of the optional type annotation.

Names introduced by ν in the π-calculus may be for any purpose, but Pint restricts thenewdeclaration to introducing new path names which will have typeτ. If you need a variable to carry something which is not a path, use a template argument.

For a constant which is not a path, use the valdeclaration.

New prole path declarations In a nutshell: A channel assigned to a prole path is always garbage collected when the template instance in which it was assigned dies. A path x may be extruded from a local process or local value. However when the containing template has completed its work, and the attached paths are abandoned to the garbage collector, paths which are extruded must be protected from the unwanted garbage collection.

In order to protect an extruded path x, it will automatically be “promoted” and will be placed in an outer box18 to protect it from the premature garbage collection.

18More exactly: an extruded path will be placed in the smallest outer box that will prevent it from premature garbage collection.

This is a conservative approach, and the programmer may not want such protection to occur. To prevent this promotion, write new prole x instead of new x. The prole paths are flagged as such by the translator in the log file. For example:

149 X480 gc2 - Prole var gc2, format[567·46]

Both the “-” and the hint flag gc2 as a restricted, prole path which will be garbage collected with its containing template instance. Paths which are not proles are flagged “+”.

If you try to “proletize” a path which is not extruded, you will receive an error message.19

Value declarations With the declarationvalhpatterni=hvaluei you may give a name to a value. See chapter 4.6 for a discussion of patterns. For example:

150 val i=0

151 val greeting = {am="Good morning" pm="Good afternoon"}

152 val a as {am pm} = greeting

The val declaration introduces new names in the same way that the new decla-ration does. Since the hpatterni includes optional type annotations you can write declarations such as

153 val emptyList : bool list = []

which asserts that emptyList is a list of booleans.

If you declare the same variable more than once in a value declaration, e.g.val i as i = 7, the two occurrences of i are two different variables. The second over-shadows the first and you will receive a warning that the first occurrence is never used.

Technically, the assignment corresponds to the assignment of actual parameters to formal parameters in a function call or template activation. There may be more than one argument, and the arguments may take paths as values, for example

154 new lie new obfuscate

155 val {policy1:∧a{} policy2:∧a{}} = {lie obfuscate}

The names declared on the left hand side of the “=” are not available for use in the hvaluei part of the declaration on the right hand side.

valdeclarations are useful for providing short aliases for long URL’s. For example:

156 new url x-pi://[email protected]/joes_prog#listen 157 val url_joe = x-pi://[email protected]/joes_prog#listen It is also possible to use thevaldeclaration to change the userid, host or domain.

19“Why?”, you may ask, is it possible in some cases to write eithernewx ornew prolex and receive no warning. The answer is that x is subject to an extrusion constraint, but the constraint solver is able to satisfy the constraint without changing the garbage collection box to which path x is assigned. Thus x is “extruded” but to the box is was in originally. Specifyingproledoes not change the outcome.

4.8 Declarations 35

Prole value declarations not allowed If avaldeclaration is used to define a path which is liable to scope extrusion, you may be tempted to inhibit the automatic

“promotion” of the path to an outer box with a restricting prole declaration, as in:

158 val {prole policy1 prole policy2}

159 = {lie obfuscate}

This is not allowed in Pint. Paths policy1 and policy2 are considered to be arguments to a template20 and the arguments, i.e. the formal parameters, cannot be proletized. Only the actual values substituted for the formal parameters can be proletized.

In the example given, you might want to consider proletizing lie and obfuscate.

Offered process declaration A process may be offered to the hardware for execution using the syntaxofferhprocessi. For example:

160 import "-//Pint//DTD Input output library//EN"

161 new e new k

162 offer io.file.uwrite!<Uwrite stdOut "Hello world\n" k e>

Use of the declarationofferhprocessi in no way guarantees that the process will be executed. This is why the Pict declaration run hprocessi has been replaced by offer hprocessi. The effective execution depends on the state of the network of paths and the existence of both hvaluei and habstractioni needed for the π-calculus reduction.

Template declaration Input processes, see chapter 4.7 on page 31, may be made permanent and given names. Such a named process is known as a template process and is written21 def hnamei[:htypei] habstractioni, where the type annotation is optional, see chapter 5.3. For a discussion of the habstractioni, see chapter 4.5. For example:

163 def print {s k e} =

164 io.file.uwrite!<Uwrite stdOut s k e>

The hnamei is a path which receives values and supports reductions, but unlike regular paths does not disappear after the reduction. Such a declaration makes it possible to write the further declarations:

165 new k new e

166 offer ( print!{"Hello World\n" k e}

167 || k?_ = ¶fin

168 || e?_ = ¶postmortem

169 )

20The template body is the rest of the program.

21It might be clearer to use a slightly different syntax such asdefhnamei[:htypei] ? habstractioni but the current syntax is compatible with Pict.

The template print offers an element of type io containing the phrase “Hello World” to the library pathio.file.uwrite. The path print is not destroyed by the ensuing reduction and remains available for futher printing.

A common use for templates is as a looping mechanism:

170 def spammer {victim spam} =

171 ( victim!spam || spammer!{victim spam} )

We have seen an example of this in the template fac declared on line 17 on page 4. Looping is discussed in more detail in chapter 9.2 on page 63.

Garbage collection in Pint is closely tied to the declaration of templates.

If you run the program fac and then look in the log file, you will see that in the listing of the program, the template has a box drawn around it and numbered 13. At translation time, each template is associated with a numbered box and the paths used in the program are assigned to the translate-time boxes. Later, as the program runs, and instances of the template are created, run-time box es are created for each instance, and the channels which are assigned to carry the paths are placed in the run-time box es associated with the template instances. When a template instance dies as a result of the ¶fin process, the garbage collector recovers the channels in the associated run-time box.22

Pint even allows mutually recursive templates — woo hoo!

It is sometimes necessary for templates to refer to one another, for example in a mutual recursion. The declarationdef· · ·and· · ·and· · · does this. For example:

172 def even {n keven kodd} =

173 let new nlt0 new ngt0 new kn1

174 out (alu.int.comp!{n 0 nlt0 keven ngt0}

175 || nlt0?{} =

176 ( alu.int.+!{n 1 kn1}

177 || kn1?n1 = odd!{n1 keven kodd}

178 )

179 || ngt0?{} =

180 ( alu.int.-!{n 1 kn1}

181 || kn1?n1 = odd!{n1 keven kodd}

182 )

183 )

184 end

22If you look at the postmortem dump produced by a Pint program, you will see the translate-time and run-time boxes. The run time boxes are in the “Run time box dictionary BoxHeap”. The run-time boxes are assigned by the openBox service of the box_mgr server which runs in parallel with the user’s program. Each run-time box is addressed by the pair {b,GUN}, where b is the translate-time box number, and GUN is a guaranteed unique number assigned by Erlang’s make_ref/0.

4.8 Declarations 37

185 and odd {n keven kodd} =

186 let new nlt0 new ngt0 new kn1

187 out (alu.int.comp!{n 0 nlt0 kodd ngt0}

188 || nlt0?{} =

189 ( alu.int.+!{n 1 kn1}

190 || kn1?n1 = even!{n1 keven kodd}

191 )

192 || ngt0?{} =

193 ( alu.int.-!{n 1 kn1}

194 || kn1?n1 = even!{n1 keven kodd}

195 )

196 )

197 end

In this program, templates even and odd each receive an integer n in the first argument and send a handclap on the paths given by the other arguments according as n is even or odd. Note on line 177 the forward reference to template odd.

This na¨ıve program has a potentially unbounded footprint. It consumes 6 extra paths on each loop. See chapter 9.2 on page 63 for a version which has a constant footprint.

Prole template declaration In a nutshell: A channel assigned to a prole template instance is always garbage collected when the outer template instance in which it was declared dies. A template t may be extruded from a local process or local value.

If this happens then the path t will automatically be “promoted” and will be placed in an outer box to protect it from premature garbage collection. The program-mer may prevent this promotion by using the syntax def prole hnamei[:htypei]

habstractioni. The prole templates are flagged as such by the translator in the log file.

If you try to “proletize” a template which is not extruded, you will receive an error message. The formal arguments of a template may not be proletized. See paragraph 4.8 on page 35.

Element type declaration Pint’s element type declaration does not follow the syntax of SGML/XML. It is similar to an ML datatype declaration and provides a recur-sive element and attribute structure. Good old SGML [Gol90] and it’s more recent XML [YBP+04] subset provide element declaration [8879, prod 116], element type declaration [XML, prod 45], attribute definition list declaration [8879, prod 141]

and attribute-list declaration [XML, prod 52] syntax to define the types inhab-ited by elements such as <img src="me.jpg">. Pint simplifies and generalises these declarations and integrates them into the language’s type system, which is discussed in chapter 5 on page 40. The principal changes are:

1. In SGML, the generic identifier [8879, prod 30] and the element type [8879, prod 117] it identifies are most often the same name. In XML the name [XML, prod 5] which appears in the element type declaration [XML, prod 45] gives the element’s type. These two notions of the element’s type and the identifier in the element instance are distinguished in Pint.

2. Attribute values may be marked up.

3. Elements and attributes are declared using the same declaration.

4. Pint makes no distinction between attribute and content, since both appear between the “<” and the “>”. A Pint element may have multiple contents.

5. All the attributes must be present, and in the order specified by the elatt declaration.23

6. There is no equivalent of SGML’s markup minimization in Pint.

The declaration

elatt hnamei=F of [l1:]htypei1∗ . . . ∗ [ln:]htypein n ≥ 0

introduces a type functionF which “tags” the elements that inhabit the new type calledhnamei. F is a Pint name. The typeshtypei1. . .htypeinmay be built-in types or types defined by elattdeclarations, see chapter 5.3. If n = 0 the keyword of is to be omitted. The optional labels li are Pint names and if present in theelatt declaration must also be present in all the corresponding element instances. Note that in anelattdeclaration, the labels are attached to the type with a colon “:”, but in an element instance, the labels are attached to the corresponding values with equals symbols “=”.

elatt declarations may be spread throughout a program or set of programs, but they are all deemed to occur24 at the head of the first program, even if they were placed in local declarations. Thus there is no such thing as a local elatt declaration, thus avoiding the problem of extrusion of type names [MTHM97, ch.

G.7].

Several type functions may map to the same defined type:

elatt T =F of [l1 :]σ1∗ . . . ∗ [ln:]σn n ≥ 0 elatt T =G of [l1 :]τ1∗ . . . ∗ [lm:]τm m ≥ 0 and a simplified syntax allows you to write this as

elatt T =F of [l1 :]σ1∗ . . . ∗ [ln:]σn n ≥ 0

| G of [l1:]τ1∗ . . . ∗ [lm :]τm m ≥ 0 For example

198 elatt number = Int of int

199 | Real of real

200 | Complex of real:real * imag:real

where defined typeT isnumber, and the type functions areInt,RealandComplex.

Note the convention of writing type functions with an initial capital letter. This also avoids confusion with the built-in type.

If two separated elatt declarations have the same defined type T, they are con-sidered to be parts of the same declaration. For example, the following declaration says the same as the one at line 198:

23“Wow!”, you might say, “This is a step backwards.” Remember that Pint is a low level language akin to microprogramming. Shuffling and forgetting attributes is for high level languages, which might be compiled into low-level languages such as Pint. The compiler should replace the shuffling and omission by order and completion.

24A phase of the translator walks through the code looking forelatts and moves them to the head of the program before any work is done on type recovery.

4.8 Declarations 39

201 elatt number = Complex of real:real * imag:real 202 . . .

203 elatt number = Real of real 204 . . .

205 elatt number = Int of int

The three elatt declaration could even be in three different source files. Don’t worry about the untidiness of having the elatt declarations spread throughout your source files. If you look in the log file, you will find a complete listing of the accumulated DTD.

Here are two examples of elements of typenumber: Int1,<Complexreal=0.0 imag=∼1.0>.

5 Types

Pint integrates document elements and attributes with a programming language. This chapter addresses some of the issues raised.

You have to provide a DTD (Document Type Definition) for all the elements that you use, but you do not need to specify the types of your variables. In most cases the Pint translator can detect the variable’s type automatically. The translator will also check that there are no inconsistencies.

5.1 Introduction — the syntactic gap

In SGML/XML the type of an element is a purely syntactic issue. The SGML/XML element declaration [8879, prod 116] provides a mechanism for specifying the syntax of an element. Within this syntax, the element type [8879, prod 117] is purely syntactic, and is usually a generic identifier [8879, prod 30]. Validation of typing in SGML/XML requires validation of a syntax. The validator is a parser such as James Clark’s SP [Cla97].

In general the syntaxes defined with SGML/XML are not the same as the syntaxes of the programs which manipulate the documents. The syntactic gap between documents and application programs is bridged in practical applications with the introduction of a common syntactic interface which parsers and application programs agree to. An example is the World Wide Web Consortium’s DOM [W+98] which generates further syntax having informal semantics.

An effect of the syntactic gap is that the parser which validates an SGML/XML document validates only the document, and not the document with its application pro-gram. Many possible type errors are therefore not addressed. There is no equivalent in SGML/XML of type validation of a document against a program.

Pint takes a different point of view, and addresses document typing as a typing issue rather than a question of syntax.