• No results found

Path Expressions

In document Tool specification with GTSL (Page 155-157)

Static Semantics and Inter-Document Consistency Constraints: Tool specications must dene static semantics such as scoping and type compatibility rules of a language More-

6.5 Class Specications

6.5.2 Path Expressions

The purpose of a path expression8 is to statically, i.e. on a type level of abstraction, dene a

navigation from an increment of a particular class along syntactic and semantic relationships to remote increments. Before we actually dene path expressions in detail, we discuss a number of properties that tool builders will require from primitives for dening navigation paths.

Expressiveness:

Path expressions must serve as a concise primitive for searching, from a given increment, for other semantically related increments. We, therefore, require traver- sal primitives such as navigating to abstract syntax children, the abstract syntax father or following links of semantic relationships. Furthermore, our language supports the con- cept of structured attributes for storing semantic information and, in particular, symbol tables. The contents of these attributes will also have to be accessed for searching seman- tically related increments. Path expressions must, therefore, be dened in such a way that they can include attribute accesses and, in particular, symbol table lookups. Then a number of operators for path expressions in graph grammars [ELS87, Sch91a], such as iterations, unions or intersections, become obsolete. Increments can then be located by symbol table lookups rather than by graph traversals that visit a huge amount of nodes.

8The path expressions dened in this thesis should not be confused with those dened in [CH74]. That

Safeness:

The notion for path expressions should exclude denitions of invalid navigation paths. We consider a path to be invalid if it can never exist in a given structure denition of the underlying syntax graph.

Eciency:

Path expressions should dene navigation paths in such a way that it can be eciently decided whether the path exists. If the path exists, the increment or the set of increments that are addressed by the path should be eciently computable from the path expression.

A path expression in our language consists of a sequence of steps delimited by a dot. A step, in turn, can be a navigation to an abstract syntax child, to the abstract syntax father or along a link of a semantic relationship. A step can also be a method call. This supports structuring path expressions, since subpaths can then be dened in methods. As methods can call themselves recursively, path expressions can be recursive as well.

We do not support intermediate steps in a path expression that are multi-valued abstract syntax children or links. These multi-valued steps are not required because below we will introduce the dedicated operators FOREACH and EXISTSthat can be used to split multi-valued

path expressions. As we will see, this restriction to single-valued intermediate steps will increase performance during evaluation of path expressions and contributes to meeting the safeness requirement, which we consider now.

Path expressions are statically dened in the context of some increment classes

c

. The rst step in the path expression has to denote a property of the class or SELF. SELF denotes the

object for which a path expression is currently being executed. Note that this might be an instance of a subclass of

c

due to polymorphism. Each step

s

of a path expression is associated with a static type. For the rst step, this is the type of the property identied by the step or

c

if the rst step is SELF. Due to the single-value requirement, the type of

s

is a class if

s

has a successor step

s

0. For the correctness of

s

0, we then require the name of the step to

be either an abstract syntax child, the abstract syntax father, a semantic relationship link or a method of the class denoted by the previous step

s

. In that way, we ensure that the path expression can always exist. We are able to highlight specication errors if path expressions do not conform to the underlying abstract syntax graph structure.

Due to polymorphism, steps may lead to increments of more specic types than dened by the static type of the respective property or method used in the step. Sometimes a tool builder has to exploit knowledge about dynamic types and specialise the static type in the path expression. We include a cast operator for that purpose. This is inherently unsafe. Therefore, [Mey92] suggests \No such thing [as a type cast] exists in Eiel. This is essential if we want to have any trust in our software". Although it is unsafe, we require type casts. As an example consider the general purpose class Incrementthat will be contained in a library of reusable increment

classes (c.f. Appendix B). Increment implements a path expression to the root increment of

a document in terms of a method get doc. The result type of this method is the abstract

increment classDocument, which is again contained in the library of reusable increment classes

and models the common properties of root increments of an abstract syntax tree. Each tool specication will, therefore, dene a root increment class as a subclass of Document. Any

execution ofget docwill return instances of these subclasses, since abstract increment classes

cannot be instantiated. In order to access properties or invoke methods from these results, however, the static type ofget doc needs to be specialised. This can be done with covariant

redenition or assignments against the polymorphism rule. For covariant redenition, an additional subclass ofIncrement, which covariantly redenes theget doc method, would have

to be dened. This is reasonable if the method is applied on enough occasions to justify the introduction of a new class. Therefore, GTSL includes covariant redenitions. Another option would be to redene get doc in all classes. Then, however, we do not reuse methods but, on

the contrary, have to multiply them in the specication. Meyer also admits the need for type specialisations and has included the ?=operator in the most recent Eiel language denition.

The polymorphism rule is abandoned for this operator. The assignment is performed if the dynamic types are compatible, otherwise the operator assignsNIL. This approach has two main

disadvantages. First, it is as unsafe as type casts due to the unsafeness of invoking a feature on NIL. Moreover, requiring assignments for performing a specialisation would run contrary

to expressive path expressions. A tool builder would then have to declare additional local variables and split path expressions in order to apply the ?=operator. We, therefore, include

type casts in GTSL. Unlike casts in C or C++, however, we severely restrict their applicability. We require that the static type can only be specialised, whereas in C++ arbitrary casts, even between atomic types, are allowed. In addition, the language includes a number of operators, such asIS OF CLASSorIS KIND OF, that implement inquiries on the dynamic type of a property

or method result. These operators can then be used for safeguarding the use of type casts. Moreover, the type data ow analysis technique discussed during covariant method redenition can be applied to ensure the safe use of type casts [CLZ94]. As examples, consider the following path expressions that are taken from the Groupie interface denition.

INCREMENT SPECIFICATION ImportList; ...

fromModule.ImpFrom.father ...

INCREMENT SPECIFICATION UsingType; ...

(<Module>SELF.my_op().father.father).DefinedNames ...

Note how understanding these path expressions is simplied by considering the entity relation- ship diagrams in Figures 6.5 and 6.6 on Page 130. The rst path expression is dened in the context of classImportList. It traverses to theImpModuleand then follows an explicit semantic

relationship link to aModName to obtain the document by traversing along the abstract syntax

father. The reference might then be assigned to the explicit link ImpFromin class ImportList

in order to establish the semantic relationship. The second path expression is dened in the context of class UsingTypein order to obtain the increment that declares the type. Therefore,

it traverses to the operation increment that includes the using type by method my op, and tra-

verses twice along syntactic fathers in order to obtain the root increment. It then specialises the static type with a cast to become Module. Only then is it valid to access the symbol table

attribute DefinedNames dened in class Module. The attribute may then be used further to

perform a symbol table lookup to the increment that is associated with the lexical value of the using type increment.

In document Tool specification with GTSL (Page 155-157)