• No results found

Semantic Rules

In document Tool specification with GTSL (Page 159-163)

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.4 Semantic Rules

Attributes and semantic relationships are concepts that can be used for dening data structures for static semantics and inter-document consistency constraints. Changes of attribute values and the creation or deletion of semantic relationships will be dened in tool command de- nitions by invoking methods. These changes, however, usually require a number of follow-on activities in order to check static semantic constraints for related increments.

As an example, consider the creation of a new type import increment in the Groupie module interface tool specication. A command will invoke a method which creates a new type import increment, scans a given string and inserts the type import increment into an import list increment. Then it must be checked to see whether the type import matches with an exported type in the respective imported module. In that case the semantic relationship ImpFrom/ExpTo

must be established between the two increments, otherwise the type import must be considered wrong and an error attribute of the type import increment should include a respective error descriptor. By accessing this error attribute, the tool command can decide if the type import is correct or not. If not, it might then dene whether to tolerate or to reject the error. If the type import is correct or the tool command tolerates the error, the import now extends the set of declared types and the symbol table attribute DefinedNamesof the module must be

updated. This, in turn, might require checking using type increments such as parameter types or function result types. They could have become correct by the change if their lexical value is identical to that of the type import. Then their error attributes will have to be updated in order to reect the correction of this error.

If we did not dene any other concept than methods, tool builders would have to nd valid execution orders to perform the required follow-on actions for all potential attribute and se- mantic relationship changes. We strongly consider this to be at the wrong level of abstraction. Tool builders require instead a declarative concept for dening the correctness of the various static semantic and inter-document consistency constraints. This concept should, in partic- ular, relieve them from worrying about the order in which evaluations are performed. The new concept should also support our structuring paradigm and be dened in terms of incre- ment classes. In addition, the concept must enable the ecient evaluation of static semantic constraints to be carried out as this has to be done on-line, i.e. during the execution of user commands. It must, therefore, meet the time restrictions required in Section 2.3.3. We now dene semantic rules that will meet the above requirements.

Each semantic rule consists of a list of statements called action that is bound to a condition. The condition is specied after the ON clause and the action is dened between ACTION and END ACTIONkeywords. Temporal predicates may be used to specify conditions, namelyCHANGED

and DELETED. A CHANGED predicate becomesTRUEif its argument has been created or changed

since the last execution of the semantic rule. The DELETED expression becomes TRUE if its

argument is about to be removed. Arguments of a CHANGED or DELETED expression may be

attributes or semantic relationships of any other increments. Path expressions are used to determine attributes or semantic relationships of remote increments. A name of an attribute may only occur as the last name in a path expression. Compound conditions can be built by using the OR operator. An EXISTS operator is used in the usual sense of rst order logic to

specify that the rule has to be executed as soon as some other condition holds for an element in a multi-valued syntax component or a multi-valued semantic relationship. This predicate, in fact, resolves the situation for semantic rules that intermediate steps in path expressions cannot be multi-valued.

INCREMENT SPECIFICATION TypeImport; ...

SEMANTIC RULES // Rule 1

ON CHANGED(father.ImpFrom.DefinedNames) OR CHANGED(value)

// symbol table of imported module or lexical value of type import changed VAR i: Increment;

ACTION

i := father.ImpFrom.DefinedNames.increment_at(value);

IF (i == NIL) // Name undefined?

THEN ImpFrom:= NIL; // Type Import not o.k.

ELSE

IF (i.IS_OF_CLASS("TypeName")) // Is Defined Name a TypeName?

THEN ImpFrom := <TypeName>i; // o.k: establish semantic relationship ELSE ImpFrom := NIL; // Type Import not o.k.

ENDIF; ENDIF; END ACTION;

Figure 6.9: Semantic Rule in ClassTypeImport

As a rst example, consider a semantic rule from class TypeImport of the Groupie interface

editor specication that is displayed in Figure 6.9. The condition of this rule denes that the rule will be executed if either the value of attribute DefinedNamesin the symbol table of the

imported module or the lexical value of the type import itself has been changed.

If the condition of a rule becomes true, the list of GTSL statements given in the action is se- quentially executed before attributes and links that are modied by the rule are accessed the next time. The available statements for semantic rule actions are assignments of expressions to attribute values, invocation of methods reading or modifying attribute values, creation of relationships and control ow primitives such asIForFOREACHstatements. In order to facili-

tate encapsulation and avoid side eects, semantic rules of a class may only modify attributes or relationships dened or inherited by that class. Note that actions must, therefore, not invoke methods via path expressions that would modify attributes of remote increments. This is excluded by a static semantic constraint

The purpose of the action in the rst semantic rule in the above example is to determine the existence of semantic relationship ImpFrom. The rst statement reads the DefinedNames

attribute in order to obtain the increment that is associated with the lexical value of the

TypeImport. If there is no such association, then the semantic relationship should not exist

and NIL is assigned to ImpFrom, otherwise the rule checks whether the dynamic type of the

increment really is a type name in order to prevent the import of some other resource, such as an operation that might be exported under the same name. If the association denotes a type name, we can specialise the static type using the cast operator and establish the semantic relationship ImpFrom/ExpTobetween the import and the corresponding export, otherwise the

relationship should not exist, since the increment that is dened in the symbol table is not a type name. A very similar rule is dened for class OpImportin Figure 6.10. It establishes the ImpFrom/ExpTorelationship between operation imports and the respective exported operation.

The two classesTypeImportandOpImportshare the common characteristic that the increments

are considered erroneous whenever the semantic relationship between import and export does not exist. This common behaviour is dened in the common super classImportas displayed in

INCREMENT SPECIFICATION OpImport; ...

SEMANTIC RULES // Rule 1

ON CHANGED(father.ImpFrom.DefinedNames) OR CHANGED(value)

// symbol table of imported module or lexical value of op import changed VAR i: Increment;

ACTION

i := father.ImpFrom.DefinedNames.increment_at(value);

IF (i == NIL) // Name undefined?

THEN ImpFrom:= NIL; // Operation Import not o.k.

ELSE

IF (i.IS_OF_CLASS("OpName")) // Is Defined Name an OpName?

THEN ImpFrom := <OpName>i; // o.k: establish semantic relationship ELSE ImpFrom := NIL; // Type Import not o.k.

ENDIF; ENDIF; END ACTION;

Figure 6.10: Semantic Rule in Class OpImport

INCREMENT SPECIFICATION Import; ...

SEMANTIC RULES // Rule 1

ON CHANGED(ImpFrom) // If link has changed

ACTION

IF (ImpFrom == NIL) // See whether it (still) exists

THEN Errors.append_error(#NotAValidExport);// add respective error ELSE Errors.clear_error(#NotAValidExport); // delete error

ENDIF; END ACTION; END SEMANTIC RULES;

Figure 6.11: Semantic Rule in Abstract ClassImport

Figure 6.11. The rule is, therefore, inherited by both subclasses. The value ofErrorsdepends

on the existence of semantic relationship ImpFrom/ExpTo. The condition of the rule in class Import, therefore, includes a CHANGED expression with the link ImpFrom as the argument. To

be able to dene it this way, we have to dene the link ImpFrom in class Import. It is then

covariantly redened in subclasses to lead to OpName or TypeName, respectively. The rule's

precondition becomes TRUE, if for example the rst semantic rule has modied the link. In

this case, a check is made whether the link exists. If it does not exist then the import is wrong and an error message is added to the Errorsset, otherwise the import is correct. The

corresponding error message is removed because the import might have been incorrect before. Note that we explicitly dene the dependencies between rules and attributes. As with import interfaces, these dependencies might be inferred by some static analysis tool. It is, however, im- portant that the tool builder is aware of the dependencies. As with imports these dependencies should be minimised. The rationale here is to facilitate ecient rule evaluation. Moreover, the explicit declaration of dependencies, as with imports, simplies the impact analysis if attribute or relationship declarations are changed.

As a further example consider the rules below that modify and access theDefinedNamessymbol

table in an ADTModulewhenever elements of the export are changed. These changes must be

reected in the symbol table in order to keep imports consistent. The rst rule enters a type name into the symbol table whenever the value of the exported type is changed. The second rule uses the EXISTS predicate in order to update the symbol table DefinedNames, whenever

the lexical value of an operation name changes. Then the methodassociateof the predened

non-syntactic classSymbolTableis invoked in order to store the operation as an entry with its

new name as the key. If necessary the old key is deleted.

INCREMENT SPECIFICATION ADTModule ... // Rule 1 SEMANTIC RULES ON CHANGED (type.value) ACTION DefinedNames.associate(type.name, type.name.value); END; // Rule 2 ON EXISTS op in opl.op_list:CHANGED(op.name.value) ACTION DefinedNames.associate(op.name, op.name.value); END ACTION; ...

Figure 6.12: Semantic Rule in ClassADTModule

The next rule is dened in class OpNameand uses the symbol table DefinedNames of its root

increment in order to check for the uniqueness of operation names. If the symbol table contains another increment such as a type name under the same key, then an error message is added to theErrorsset, otherwise the message is deleted.

INCREMENT SPECIFICATION OpName; ... // Rule OpName::1 ON CHANGED father.father.father.DefinedNames ACTION IF father.father.father.DefinedNames.is_duplicate(value) THEN Errors.append_error(#NameAlreadyDefined) ELSE Errors.remove_error(#NameAlreadyDefined) ENDIF END ACTION; ...

Figure 6.13: Semantic Rule in Class OpName

The dynamic semantics of semantic rules is informally dened as follows. Rule evaluation is, in fact, divided into two phases. The rst phase is a propagation phase where attributes and semantic relationships are stamped as dirty whenever they are modied. All semantic rules that read dirty attributes or relationships are also stamped as dirty. Then the property of being dirty is transitively propagated to all attributes or relationships that are modied by dirty rules. The propagation phase ends when all aected rules, attributes and relationships have been marked dirty. The second phase evaluates rules and it starts whenever a dirty attribute

or relationship is about to be accessed (e.g. during unparsing). Then all rules are executed according to the propagation path dened in the propagation phase. This execution brings the attribute or relationship back into state clean. Only then is the attribute or relationship really accessed.

The conditions of semantic rules specify static dependencies between dierent semantic rules. We do not want to enable computations or even modications to be dened in these condi- tions. Such modications could produce serious side eects and lead to situations where the rules can no longer be understood by the tool builder. In particular, the tool builder had to know the order in which change predicates are evaluated and it was the main motivation for semantic rules to relieve the tool builder from this burden. Path expressions as dened above include steps that may invoke methods and in these methods side eects could be produced. Method invocations would be required to determine recursive path expressions as they occur, for instance, during specication of nested scoping blocks. Upon increment creation, however, recursive path expressions can always be materialised within auxilliary semantic relationships. Then these relationships can be used in semantic rule conditions. We can, therefore, disable method invocations to occur in steps of path expressions of semantic rule conditions.

In short, we have dened a declarative language for the denition of static semantics and inter- document consistency constraints. Note that we have not dened any execution order between the dierent semantic rules that we have discussed. A valid execution order will be inferred statically from the dependencies between rules, attributes and relationships. Semantic rules enforce well-structured static semantics and inter-document consistency constraint denitions because the language does not enable rule actions to modify attributes or relationships that do not belong to the class. Moreover, subclasses inherit semantic rules from super classes.

In document Tool specification with GTSL (Page 159-163)