Difference between pages "Extending the Rodin database (How to extend Rodin Tutorial)" and "Extending the Static Checker"

From Event-B
(Difference between pages)
Jump to navigationJump to search
imported>Pascal
 
imported>Renato
 
Line 1: Line 1:
{{Navigation|Previous= [[Extend_Rodin_database_(How_to_extend_Rodin_Tutorial)|Extend the database]]|Next=[[Extend_Rodin_Structured_Editor_(How_to_extend_Rodin_Tutorial)|Extend the structured editor]] | Up= [[Plug-in_Tutorial|How to extend Rodin Tutorial (Index)]]}}
+
{{TOCright}}
 +
= Introduction =
 +
The purpose of this page is to describe how to extend the static checker. It covers on the one hand, the definition of the extension, and on the other hand its implementation.
  
=== In this part ===
+
The useful extension points are listed below; they offer the possibility to contribute to the static checker:
We will explain how to add a new attribute to events elements and add a new element in the database.
+
* <tt>org.rodinp.core.autoTools</tt>
Here are the steps we will detail :
+
* <tt>org.eventb.core.configurations</tt>
# add dependencies to the plugins providing the extension services and interfaces we want to use,
+
* <tt>org.eventb.core.scModuleTypes</tt>
# add the extensions point we will use, and define our extensions,
+
* <tt>org.eventb.core.scStateTypes</tt>
# implement required classes to specify newly added elements,
 
# create an interface using Eclipse content assist
 
For more information about the database extension, please refer to :  [[Extending_the_Rodin_Database| Extending the Rodin Database]]
 
  
=== Step 1 ===
+
= Before Starting =
When one wants to use extension points provided by a plugin, one has to add a dependency to this plugin.
 
We will use 2 extension points to extend the database, so we need to add a dependency to the plugin <tt>org.rodinp.core</tt> which defines them.
 
Moreover, as we want to manipulate event-b elements, we will manipulate interfaces and public classes provided by the event-B plugin.
 
We will then add a dependency to the plugin <tt>org.eventb.core</tt>
 
To do this, open the MANIFEST.MF file in the forlder META-INF of our plugin to get the following:
 
  
[[Image:Extend_Rodin_Tuto_1_5_Manifest_dependencies.png|500px]]
+
It is necessary to define the static checked elements that are similar to the unchecked elements. We will use as an example the ''decompositionFile'' that is defined as follows:
  
1. Click on the "Dependencies" Tab, <br>
+
*decompositionFile
2. Click on the Add button.<br>
+
**decompositionRoot
A dialog appears, start to enter <tt>org.rodinp.core</tt> and select this plugin, press "OK" to add it to the dependencies.<br>
+
***Component(machine to be decomposed)
The dependency to <tt>org.rodinp.core</tt> has been added.
+
***Configuration(''style'':shared event/shared variables;''newProjectOption'':decompose in the same project/different projects;''decomposeContextOption'':noDecomposition/minimal decomposition)
Re-do the above operations to add <tt>org.eventb.core</tt>.
+
***SubComponent(resulting decomposed parts)
 +
****SubComponentElement(elements used to decompose:variables for    shared event and events for shared variable)
  
You should now have the following dependencies added to the plugin :
+
[[Image:Decomp file pretty print.png]]
  
[[Image:Extend_Rodin_Tuto_1_5_Added_Dependencies.png|200px]]
+
To extend the static checker, it is necessary to add a new contentType (org.eclipse.core.contenttype.contentTypes) containing the checked version of the decompositionFile:
  
=== Step 2 ===
+
      <content-type
We will add now the Extensions Points that we want to use, and define extensions using them.
+
          base-type="org.rodinp.core.rodin"
 +
          file-extensions="dcc,dcc_tmp"
 +
          id="scDcpFile"
 +
          name="Event-B Statically Checked Decomposition File"
 +
          priority="normal">
 +
    </content-type>
  
[[Image:Extend_Rodin_Tuto_1_6_Add_Extension_Point.png|400px]]
+
and the respective fileAssociation (org.rodinp.core.fileAssociations):
  
1. Click on the "Extensions" Tab, <br>
+
    <fileAssociation
2. and click on the "Add" button.
+
          content-type-id="ch.ethz.eventb.decomposition.core.scDcpFile"  
 +
          root-element-type="ch.ethz.eventb.decomposition.core.scDcpFile">
 +
    </fileAssociation>
 +
     
 +
The respective static checked elements must be added as internalElements using the extension ‘org.rodinp.core.internalElementTypes‘:
  
[[Image:Extend_Rodin_Tuto_1_6_Extension_Point_Selection.png|440px]]
+
<extension
 +
        point="org.rodinp.core.internalElementTypes">
 +
    <internalElementType
 +
          class="ch.ethz.eventb.decomposition.core.basis.DecompositionRoot"
 +
          id="dcpFile"
 +
          name="%eventBdcpFile">
 +
    </internalElementType>
 +
    <internalElementType
 +
          class="ch.ethz.eventb.decomposition.core.basis.SCDecompositionRoot"
 +
          id="scDcpFile"
 +
          name="Event-B Statically Checked Decomposition Root">
 +
    </internalElementType>
 +
    <internalElementType
 +
          class="ch.ethz.eventb.decomposition.core.basis.DecompositionConfiguration"
 +
          id="configuration"
 +
          name="%eventBDecompositionConfiguration">
 +
    </internalElementType>
 +
    <internalElementType
 +
          class="ch.ethz.eventb.decomposition.core.basis.SCDecompositionConfiguration"
 +
          id="scConfiguration"
 +
          name="Event-B Statically Checked Decomposition Configuration">
 +
    </internalElementType>
 +
</extension>
  
As we will start by extending the database by adding the attribute "probabilistic", we will create an extension for <tt>org.rodinp.core.attributeTypes</tt> extension point. Hence, we need to add this extension point first before creating an extension with it.
+
In the above, the first internalElementType is the unckecked internalElement and the second is the same internalElement but in the checked version. Having the checked elements define, we can start to extend the static checker for our file and respective elements.
To do so... on the wizard that appeared (see picture above):<br>
 
1. start to type the extension point name <tt>org.rodinp.core.attributeTypes</tt>, to reveal it in the list of available extension points,<br>
 
2. select it in the list, and click on "Finish" to add it.
 
  
The extension point <tt>org.rodinp.core.attributeTypes</tt> now appears in the list on the "Extensions" page of the MANIFEST.MF of our plugin.
+
= AutoTools =
  
=== Step 3 ===
+
The static checker it is a tool that runs automatically. In order to implement the tool, it is necessary to define the following extension point <tt>org.rodinp.core.autoTools</tt>. This extension point allows tools to run automatically when changes to the Rodin database are committed. To implement the reactive model of Rodin, automatic tools run only when one of their input files has changed. As such, for each automatic tool, plugin developers must provide two kinds of contributions:
We will now add the attribute "probabilistic" in the database, creating an extension for <tt>org.rodinp.core.attributeTypes</tt>.
 
Right click on the extension point, select <tt>New > attributeType</tt> as in the picture below :
 
  
[[Image:Extend_Rodin_Tuto_1_7_Add_Attibute_Extension.png|440px]]
+
* some dependency extractors
 +
* the tool itself
  
A new extension <tt>attributeType</tt> has been added. We will edit it to add our "probabilistic" attribute.<br>
+
== Declaration ==
As an event can be probabilistic or not, we set the kind of this attribute to <tt>boolean</tt>.
 
Give a unique ID to this attribute (here <tt>probabilistic</tt>) and a name (here <tt>Event-B Probabilistic Attribute</tt>).
 
You should now have something similar to what appears in the picture below :
 
  
[[Image:Extend_Rodin_Tuto_1_7_Add_Attibute_Extension2.png]]
+
The autoTools extension-point allows tool writers to register their tool implementation under a symbolic name that is then used by the Rodin platform to find and run the tool. The symbolic name is the id of the tool extension. An example of the implementation of a static checker can be seen as follows:
  
=== Step 4 ===
+
<extension
 +
        point="org.rodinp.core.autoTools">
 +
    <tool
 +
          class="ch.ethz.eventb.decomposition.internal.core.sc.DecompositionStaticChecker"
 +
          id="decompositionSC"
 +
          name="Decomposition Static Checker">
 +
        <extractor
 +
              class="ch.ethz.eventb.decomposition.internal.core.sc.DecompositionStaticChecker"
 +
              name="Decomposition Extractor of Static Checker">
 +
          <inputType
 +
                id="ch.ethz.eventb.decomposition.core.dcpFile">
 +
          </inputType>
 +
        </extractor>
 +
    </tool>
 +
  </extension>
  
We will now add a new element "'''Bound'''" to set the upper bound of the probabilistic variant.<br>
+
We defined a static checker tool that will run for the inputType defined (<tt>ch.ethz.eventb.decomposition.core.dcpFile</tt>). The class provided for extractors must implement the <tt>org.rodinp.core.builder.IExtractor</tt> interface, while the class provided for tools themselves must implement <tt>org.rodinp.core.builder.IAutomaticTool</tt>. The Rodin platform itself does not provide any automatic tools. These are provided by additional features such as the Event-B modelling environment (see plugin <tt>org.eventb.core</tt>).
Repeat the step 2, to add the extension point : <tt>org.rodinp.core.internalElementTypes</tt>.<br>
 
Create an extension to specify our new element "'''Bound'''" using the right click as previously.<br>
 
You shall now specify the details for this new extension element :
 
  
[[Image:Extend_Rodin_Tuto_1_7_Bound_Extension.png]]
+
== Programmatic usage ==
  
As in the picture above :<br>
+
The class to be implement usually extends the class <tt>org.eventb.core.sc.StaticChecker</tt>
1. give the element a unique ID (here <tt>bound</tt>)<br>
+
and needs to implement the abstract method ‘extract()‘ from the interface <tt>org.rodinp.core.builder.IExtractor</tt>:
2. give a name to this element (here Event-B Bound Element)<br>
 
3. now things differ, as this extension point (<tt>org.rodinp.core.internalElementTypes</tt>) requires us to provide a class describing the element.<br>
 
Click on the "class*:" link to open a wizard that will help us to create this class.
 
  
The following wizard appears :
+
<tt>
 +
    public void extract(IFile file, IGraph graph, IProgressMonitor monitor)throws CoreException {
 +
        try {
 +
              monitor.beginTask(Messages.bind(Messages.build_extracting, file.getName()), 1);
 +
              IRodinFile source = RodinCore.valueOf(file);
 +
              IDecompositionRoot root = (IDecompositionRoot) source.getRoot();
 +
              IRodinFile target = root.getSCDecompositionRoot().getRodinFile();
 +
              graph.addTarget(target.getResource());
 +
              graph.addToolDependency(source.getResource(), target.getResource(),true);
 +
            } finally {
 +
              monitor.done();
 +
            }
 +
    }
 +
</tt>
  
[[Image:Extend_Rodin_Tuto_1_7_Bound_Extension_New_Java_Class_Bound.png|400px]]
+
An <tt>org.rodinp.core.builder.IGraph</tt> interface is used by the extractors registers with the builder to manipulate the dependency graph of all Rodin resources of a Rodin project. It is a Facade to the more complicated ways of manipulating the dependency graph inside the builder. Some information is cached in the corresponding object so the contents of the facade must be synchronised with the graph at the end of an extraction. Requests to add nodes to the graph must be made explicitly by methods addNode(). Dependencies are managed by the facade. This saves clients from having to compute dependency graph deltas themselves.  
  
1. First specify a package where you want this class to be stored. As we want to organise a bit the project, we will say that all elements that we add will be part of a new package called <tt>fr.systerel.rodinextension.sample.basis</tt>,<br>
+
We have already defined the static check tool and the target for which it will run. Now, we need to configure the static checker tool. It is necessary to define the checks that are required for each element and that is done by adding an extension-point of <tt>org.eventb.core.configurations</tt>.
2. Give the name of the class : "Bound",<br>
 
3. We see that the superclass of this element is <tt>org.rodinp.core.basis.InternalElement</tt> but we know that we will implement an element specific to Event-B, so we put here <tt>org.eventb.core.basis.EventBElement</tt>,<br>
 
4. You can optionnaly add comments automatically to the created class, if you set them in "Preferences > Java > Code Style > Code Templates",<br>
 
5. Click on "Finish" to create the class.
 
  
The class ''Bound.java'' has now been created. We can open it and review its contents that we anyway shall modify now.
+
= Configuration =
  
=== Step 5 ===
+
Configuration is used to define which modules are used by the static checker tool. Similarly in can be used for the proof obligation generator (POG).
We now opened the class ''Bound.java'' and see that we need to implement the method <tt>getElementType()</tt> inherited from the superclass.<br>
 
As the type of element might be needed from outside, and is common to all Bound element, we will create a constanst in a new interface IBound that we have to create.<br>
 
Enter in the method body the following code :
 
return IBound.ELEMENT_TYPE;
 
  
[[Image:Extend_Rodin_Tuto_1_7_Create_Interface_Menu.png|400px]]
+
== Declaration ==
  
Then use the quick assist (while you go over IBound underlined in red), to create the interface IBound.
+
<!ELEMENT configuration ((config | pogModule | scModule))+>
The following wizard appears :
+
  <!ATTLIST configuration
+
  id  CDATA #REQUIRED
[[Image:Extend_Rodin_Tuto_1_7_Create_Interface_Wizard.png|400px]]
+
  name CDATA #REQUIRED
 +
  >
 +
  id - the identifier for this attribute type (simple id token, unique for attribute types within the extension namespace). The token cannot contain dot (.) or whitespace.
 +
  name - the human-readable name of this attribute type
  
Use here the "Extended Interfaces" field to specify that the element '''Bound''' should be commented (thus shall implement ICommentedElement) and will carry an expression (thus shall implement IExpressionElement) for the value of the bound.
+
For static checks, we use scModule and config elements. Below we show an example of using the configuration:
  
  public interface IBound extends ICommentedElement, IExpressionElement {
+
  <extension
IInternalElementType<IBound> ELEMENT_TYPE = RodinCore
+
        point="org.eventb.core.configurations">
.getInternalElementType(QualProbPlugin.PLUGIN_ID + ".bound");
+
      <configuration
}
+
            id="dcmpSC"
 +
            name="Decomposition Static Checker Root Module">
 +
        <scModule
 +
              id="ch.ethz.eventb.decomposition.core.decompositionModule">
 +
        </scModule>
 +
      </configuration>
 +
      <configuration
 +
            id="dcmpBaseSC"
 +
            name="Decomposition Static Checker Base Module">
 +
        <config
 +
              id="ch.ethz.eventb.decomposition.core.dcmpSC">
 +
        </config>
 +
        <scModule
 +
              id="ch.ethz.eventb.decomposition.core.componentModule">
 +
        </scModule>
 +
        <scModule
 +
            id="ch.ethz.eventb.decomposition.core.decompositionConfigurationModule">
 +
        </scModule>
 +
        <scModule
 +
              id="ch.ethz.eventb.decomposition.core.subComponentModule">
 +
        </scModule>
 +
        <scModule
 +
              id="ch.ethz.eventb.decomposition.core.subComponentElementModule">
 +
        </scModule>
 +
      </configuration>
 +
      <configuration
 +
            id="dcmp"
 +
            name="Decomposition Configuration">
 +
        <config
 +
              id="ch.ethz.eventb.decomposition.core.dcmpBaseSC">
 +
        </config>
 +
      </configuration>
 +
  </extension>
  
Modify the class <tt>Bound.java</tt> to add <tt>implements IBound</tt>.<br>
+
Although not necessary, we structure the configuration in different levels:
At this point of the development, you should have the following extensions :
 
  
[[Image:Extend_Rodin_Tuto_1_7_Used_Extensions.png]]
+
* The ‘Decomposition Configuration’ is defined by a base static checker module that contains the ‘Decomposition Static Checker Base Module‘.
 +
* Inside the last one are the static check modules for all elements (decompositionComponentModule,decompositionConfigurationModule,...) in the decompositionFile including decompositionRoot (id=dcmpSC).  
  
and you should have the following contents in your plugin :
+
The id field in the scModule tags must exist already. They will correspond to the static checker modules defined using the extension ‘org.eventb.core.scModuleTypes‘. These are used to process the necessary operations for each element inside a static checked file.
  
[[Image:Extend_Rodin_Tuto_1_7_ProjectExplorer2.png.png]]
+
== Programmatic usage ==
  
The sources of the plugin at this point can be downloaded here : // FIXME attach sources here.
+
= Modules =
 +
== Filter ==
  
=== In Brief ===
+
Filter are used to validate inserted elements. After the successful validation of all elements, they can be processed and stored in the static checked file. In order to implement a filter, we define the following extension-point:
  
We saw how to use Eclipse to add extension points that will be used in our plugin and created our extensions using some helpful Eclipse automatic actions (wizard, content assist...).
+
<!ELEMENT filterType (prereq)*>
As we had a detailed view (captures) of all the actions further needed, the next parts of this tutorial will focus only on the extensions.
+
  <!ATTLIST filterType
+
  id    CDATA #REQUIRED
{{Navigation|Previous= [[Extend_Rodin_database_(How_to_extend_Rodin_Tutorial)|Extend the database]]|Next= [[Extend_Rodin_Structured_Editor_(How_to_extend_Rodin_Tutorial)|Extend the structured editor]] | Up= [[Plug-in_Tutorial|How to extend Rodin Tutorial (Index)]]}}
+
  name  CDATA #REQUIRED
 +
  parent CDATA #REQUIRED
 +
  class  CDATA #REQUIRED
 +
  >
 +
  id - the identifier for this filter type (simple id token, unique for (filter/processor/root) types within the extension namespace).  
 +
  The token cannot contain dot (.) or whitespace.
 +
  name - the human-readable name of this filter module
 +
  parent - the optional parent (processor) module. Root modules must leave the attribute undefined. It is not allowed to choose a filter module as parent.
 +
  class - the fully-qualified name of a subclass of org.eventb.core.sc.SCFilterModule
  
[[Category:Developer documentation|*Index]]
+
For the filterType, the classes usually extend the abstract class <tt>org.eventb.core.sc.SCFilterModule</tt>. It also contains three methods:
[[Category:Rodin Platform|*Index]]
+
 
[[Category:Tutorial|*Index]]
+
* <tt>public abstract boolean accept(IRodinElement element, ISCStateRepository repository, IProgressMonitor monitor) throws CoreException;</tt>: runs the static checker module. Returns whether the element should be accepted. If an error marker was associated with the element the returned value should usually be '''false'''. Exceptions from this rule are possible, in particular, if the element has been already marked with an error.
 +
 
 +
* <tt>public abstract void initModule(ISCStateRepository repository,IProgressMonitor monitor) throws CoreException;</tt>:Initialisation code for the module
 +
 
 +
* <tt>public abstract void endModule(ISCStateRepository repository,IProgressMonitor monitor) throws CoreException;</tt>: Termination code for the module
 +
 
 +
== Processor ==
 +
 
 +
Processor literally process the elements, storing them in the static checked file, running sub-processors and adding states to the repository if required. To implement a processor, it is required to define the following extension-point:
 +
 
 +
  <!ELEMENT processorType (prereq)*>
 +
  <!ATTLIST processorType
 +
  id    CDATA #REQUIRED
 +
  name  CDATA #REQUIRED
 +
  parent CDATA #REQUIRED
 +
  class  CDATA #REQUIRED
 +
  >
 +
  id - the identifier for this processor type (simple id token, unique for (filter/processor/root) types within the extension namespace).
 +
  The token cannot contain dot (.) or whitespace.
 +
  name - the human-readable name of this processor module
 +
  parent - the optional parent (processor) module. Root modules must leave the attribute undefined. It is not allowed to choose a filter module as parent.
 +
  class - the fully-qualified name of a subclass of <tt>org.eventb.core.sc.SCProcessorModule</tt>
 +
 
 +
The classes that implement the rootType and processorType usually extend the abstract class <tt>org.eventb.core.sc.SCProcessorModule</tt>. They contain a constant called <tt>MODULE_TYPE</tt> that identifies the scModule. An example is:
 +
 
 +
public static final IModuleType<DecompositionModule> MODULE_TYPE = SCCore.getModuleType(DecompositionCorePlugin.PLUGIN_ID + ".decompositionModule");
 +
 
 +
that identifies the Decomposition Root Module. Moreover this classes should implement the three methods that are part of the interface <tt>org.eventb.internal.core.tool.types.ISCProcessorModule</tt>:
 +
 
 +
* <tt>public abstract void initModule(IRodinElement element,ISCStateRepository repository,IProgressMonitor monitor) throws CoreException;</tt> : Initialisation code for the module. Used to initialise the global variables of the class.
 +
* <tt>public abstract void process(IRodinElement element,IInternalElement target, ISCStateRepository repository, IProgressMonitor monitor) throws CoreException;</tt>: Runs the static checker module: process the element. The element itself has already been accepted. If this element has children, then the children modules should be called here (see for example ‘ch.ethz.eventb.decomposition.core.sc.modules.DecompositionSubComponentModule‘).
 +
* <tt>public abstract void endModule(IRodinElement element,ISCStateRepository repository,IProgressMonitor monitor) throws CoreException;</tt> : Termination code for the module. Used to clean up memory (global variables) before finishing the module call.
 +
 
 +
== Sequencing ==
 +
 
 +
 
 +
=== Parent ===
 +
 
 +
Similar to processor by applied to the root of the file. The extension that need to be implemented in defined below:
 +
 
 +
<!ELEMENT rootType EMPTY>
 +
  <!ATTLIST rootType
 +
  id    CDATA #REQUIRED
 +
  name  CDATA #REQUIRED
 +
  input CDATA #REQUIRED
 +
  class CDATA #REQUIRED
 +
  >
 +
  id - the identifier for this root type (simple id token, unique for (filter/processor/root) types within the extension namespace). The token cannot contain dot (.) or whitespace.
 +
  name - the human-readable name of this root module
 +
  input - identifier of the input file element type for this root module.
 +
  class - the fully-qualified name of a subclass of org.eventb.core.sc.SCProcessorModule
 +
 
 +
=== Prerequisite ===
 +
 
 +
Some static checks rely on already done static checks so they work as pre-requirements. For instance, if a concrete event is refined it is necessary to know the abstract machine defined in the refine machine section. So the refine machine is a static check pre-requirement of the refinement an event. To implement a pre-requirement, it is necessary to define the following extension-point:
 +
 
 +
<!ELEMENT prereq EMPTY>
 +
  <!ATTLIST prereq
 +
  id CDATA #REQUIRED
 +
  >
 +
  id - the full ids of all (filter and processor) modules that must be run before this module
 +
 
 +
== Example ==
 +
 
 +
An example of defining a scModule of type rootType, filterType and pre-requirement is defined below:
 +
 
 +
  <extension
 +
          point="org.eventb.core.scModuleTypes">
 +
        <rootType
 +
              class="ch.ethz.eventb.decomposition.core.sc.modules.DecompositionModule"
 +
              id="decompositionModule"
 +
              input="ch.ethz.eventb.decomposition.core.dcpFile"
 +
              name="Decomposition SC Root Module">
 +
        </rootType>
 +
        <processorType
 +
              class="ch.ethz.eventb.decomposition.core.sc.modules.DecompositionComponentModule"
 +
              id="decompositionComponentModule"
 +
              name="Decomposition SC Component Module"
 +
              parent="ch.ethz.eventb.decomposition.core.decompositionModule">
 +
        </processorType>
 +
        .
 +
        .
 +
        .
 +
        <filterType
 +
              class="ch.ethz.eventb.decomposition.core.sc.modules.DecompositionSubComponentElementFilterModule"
 +
              id="decompositionSubComponentElementFilterModule"
 +
              name="Decomposition SC SubComponentElement Filter Module"
 +
              parent="ch.ethz.eventb.decomposition.core.decompositionCommitSubComponentElementModule">
 +
          <prereq
 +
                id="ch.ethz.eventb.decomposition.core.decompositionConfigurationModule">
 +
          </prereq>
 +
          <prereq
 +
                id="ch.ethz.eventb.decomposition.core.decompositionComponentModule">
 +
          </prereq>
 +
        </filterType>
 +
    </extension>
 +
 
 +
Below is an example of the call of the three processor/root methods in the class <tt>ch.ethz.eventb.decomposition.core.sc.modules.DecompositionModule</tt>:
 +
 
 +
        @Override
 +
        public void initModule(IRodinElement element,ISCStateRepository repository,  IProgressMonitor monitor) throws CoreException {
 +
                accuracyInfo = new DecompositionAccuracyInfo();
 +
                final IDecompositionLabelSymbolTable labelSymbolTable = new DecompositionLabelSymbolTable(LABEL_SYMTAB_SIZE);
 +
                repository.setState(labelSymbolTable);
 +
                repository.setState(accuracyInfo);
 +
                initProcessorModules(element, repository, monitor);
 +
        }
 +
 
 +
        public void process(IRodinElement element, IInternalElement target,ISCStateRepository repository, IProgressMonitor monitor)throws CoreException {
 +
                scRoot = (ISCDecompositionRoot) target;
 +
              processModules(element, target, repository, monitor);
 +
        }
 +
 +
        @Override
 +
        public void endModule(IRodinElement element,ISCStateRepository repository, IProgressMonitor monitor) throws CoreException {
 +
                scRoot.setAccuracy(accuracyInfo.isAccurate(), monitor);
 +
              endProcessorModules(element, repository, monitor);
 +
        }
 +
 +
Whenever a problem is encountered by the static checker, it is possible to raise a warning or an error, highlighting the respective element using the method <tt>org.eventb.core.sc.SCModule#createProblemMarker</tt>. An example can be seen below:
 +
 
 +
        public void process(IRodinElement element, IInternalElement target,ISCStateRepository repository, IProgressMonitor monitor)throws CoreException {
 +
                monitor.subTask(Messages.bind(Messages.progress_DecompositionComponent));
 +
                IComponent[] decompositionComponents = decompositionFile.getDecompositionComponents();
 +
                if (decompositionComponents.length > 1) {
 +
                        for (int k = 1; k < decompositionComponents.length; k++) {
 +
                                createProblemMarker(decompositionComponents[k], DecompositionConfigurationAttributes.TARGET_ATTRIBUTE,
 +
                                                              DecompositionGraphProblem.TooManyComponentsError);
 +
                        }
 +
              }
 +
              ...
 +
              repository.setState(new ComponentMachineInfo(scComponentMachineRoot,component));
 +
              ...
 +
              monitor.worked(1);
 +
      }
 +
 
 +
In this particular case, if the number of IComponent elements is >1, then an error will be generated for the respective IComponent element:
 +
 
 +
[[Image:More_than_one_component_error.png]]
 +
 
 +
=States=
 +
 
 +
The static check of the elements in a file are independent of each other (different and independent modules). Nevertheless there are some information that is dependent on other elements. For instance, for label elements it is necessary to know which labels have been used already before checking the elements. Since the elements checks are independent, the solution is to ‘share data‘ through scStates implemented using the extension-point <tt>org.eventb.core.scStateTypes</tt>. These are used to dynamically store data that will be used by dependencies (scModules) inside the static checked elements. The data is stored in a SCStateRepository and contains a key and respective content (value).
 +
 
 +
==Declaration==
 +
 
 +
<!ELEMENT stateType EMPTY>
 +
  <!ATTLIST stateType
 +
  id    CDATA #REQUIRED
 +
  name  CDATA #REQUIRED
 +
  class CDATA #REQUIRED
 +
  >
 +
  id - the identifier for this attribute type (simple id token, unique for attribute types within the extension namespace). The token cannot contain dot (.) or whitespace.
 +
  name - the human-readable name of this attribute type
 +
  class - the fully-qualified name of a subclass of org.eventb.core.sc.state.ISCState
 +
 
 +
==Programatic Usage==
 +
 
 +
To store data, we need to call the method
 +
 
 +
<tt>void setState(I state)</tt> [I extends IState]
 +
 
 +
part of the interface <tt>org.eventb.core.tool.IStateRepository</tt> (See method <tt>initModule</tt> above). To retrieve a state, you call the method:
 +
 
 +
</tt>I getState(IStateType<? extends I> stateType) throws CoreException;</tt>
 +
 
 +
In order to use the state, it is necessary to define the ‘key‘ in the extension point <tt>stateType</tt>.
 +
 
 +
==Example==
 +
 
 +
An example of the use of states can be seen below:
 +
 
 +
<extension
 +
          point="org.eventb.core.scStateTypes">
 +
        <stateType
 +
              class="ch.ethz.eventb.decomposition.core.sc.state.IDecompositionAccuracyInfo"
 +
              id="decompositionAccuracyInfo"
 +
              name="Decomposition Accuracy Info">
 +
        </stateType>
 +
        <stateType
 +
              class="ch.ethz.eventb.decomposition.core.sc.state.IDecompositionLabelSymbolTable"
 +
              id="decompositionLabelSymbolTable"
 +
              name="Decomposition Label-Symbol Table">
 +
        </stateType>
 +
        <stateType
 +
              class="ch.ethz.eventb.decomposition.core.sc.state.IComponentAccuracyInfo"
 +
              id="componentDecompositionInfo"
 +
              name="Decomposition Component Machine Information">
 +
        </stateType>
 +
        <stateType
 +
              class="ch.ethz.eventb.decomposition.core.sc.state.IDecompositionStyle"
 +
              id="style"
 +
              name="Decomposition Style">
 +
        </stateType>
 +
    </extension>
 +
 
 +
For instance, the last stateType defined above is ''Decomposition Style''. It is required for checking which kind of ''subComponentElements'' are expected:
 +
 
 +
* if ''style''= shared event => ''subComponentElement'' type must be ''variables''.
 +
* if ''style''= shared variable => ''subComponentElement'' type must be ''events''.
 +
 
 +
 
 +
[[Category:Developer documentation]]
 +
[[Category:Work in progress]]

Revision as of 10:19, 21 May 2010

Introduction

The purpose of this page is to describe how to extend the static checker. It covers on the one hand, the definition of the extension, and on the other hand its implementation.

The useful extension points are listed below; they offer the possibility to contribute to the static checker:

  • org.rodinp.core.autoTools
  • org.eventb.core.configurations
  • org.eventb.core.scModuleTypes
  • org.eventb.core.scStateTypes

Before Starting

It is necessary to define the static checked elements that are similar to the unchecked elements. We will use as an example the decompositionFile that is defined as follows:

  • decompositionFile
    • decompositionRoot
      • Component(machine to be decomposed)
      • Configuration(style:shared event/shared variables;newProjectOption:decompose in the same project/different projects;decomposeContextOption:noDecomposition/minimal decomposition)
      • SubComponent(resulting decomposed parts)
        • SubComponentElement(elements used to decompose:variables for shared event and events for shared variable)

Decomp file pretty print.png

To extend the static checker, it is necessary to add a new contentType (org.eclipse.core.contenttype.contentTypes) containing the checked version of the decompositionFile:

     <content-type
          base-type="org.rodinp.core.rodin"
          file-extensions="dcc,dcc_tmp"
          id="scDcpFile"
          name="Event-B Statically Checked Decomposition File"
          priority="normal">
    </content-type>

and the respective fileAssociation (org.rodinp.core.fileAssociations):

    <fileAssociation 
         content-type-id="ch.ethz.eventb.decomposition.core.scDcpFile" 
         root-element-type="ch.ethz.eventb.decomposition.core.scDcpFile">
   </fileAssociation>
     

The respective static checked elements must be added as internalElements using the extension ‘org.rodinp.core.internalElementTypes‘:

<extension
       point="org.rodinp.core.internalElementTypes">
    <internalElementType
          class="ch.ethz.eventb.decomposition.core.basis.DecompositionRoot"
          id="dcpFile"
          name="%eventBdcpFile">
    </internalElementType>
    <internalElementType
          class="ch.ethz.eventb.decomposition.core.basis.SCDecompositionRoot"
          id="scDcpFile"
          name="Event-B Statically Checked Decomposition Root">
    </internalElementType>
    <internalElementType
          class="ch.ethz.eventb.decomposition.core.basis.DecompositionConfiguration"
          id="configuration"
          name="%eventBDecompositionConfiguration">
    </internalElementType>
    <internalElementType
          class="ch.ethz.eventb.decomposition.core.basis.SCDecompositionConfiguration"
          id="scConfiguration"
          name="Event-B Statically Checked Decomposition Configuration">
    </internalElementType>
</extension>

In the above, the first internalElementType is the unckecked internalElement and the second is the same internalElement but in the checked version. Having the checked elements define, we can start to extend the static checker for our file and respective elements.

AutoTools

The static checker it is a tool that runs automatically. In order to implement the tool, it is necessary to define the following extension point org.rodinp.core.autoTools. This extension point allows tools to run automatically when changes to the Rodin database are committed. To implement the reactive model of Rodin, automatic tools run only when one of their input files has changed. As such, for each automatic tool, plugin developers must provide two kinds of contributions:

  • some dependency extractors
  • the tool itself

Declaration

The autoTools extension-point allows tool writers to register their tool implementation under a symbolic name that is then used by the Rodin platform to find and run the tool. The symbolic name is the id of the tool extension. An example of the implementation of a static checker can be seen as follows:

<extension
       point="org.rodinp.core.autoTools">
    <tool
          class="ch.ethz.eventb.decomposition.internal.core.sc.DecompositionStaticChecker"
          id="decompositionSC"
          name="Decomposition Static Checker">
       <extractor
             class="ch.ethz.eventb.decomposition.internal.core.sc.DecompositionStaticChecker"
             name="Decomposition Extractor of Static Checker">
          <inputType
                id="ch.ethz.eventb.decomposition.core.dcpFile">
          </inputType>
       </extractor>
    </tool>
 </extension>

We defined a static checker tool that will run for the inputType defined (ch.ethz.eventb.decomposition.core.dcpFile). The class provided for extractors must implement the org.rodinp.core.builder.IExtractor interface, while the class provided for tools themselves must implement org.rodinp.core.builder.IAutomaticTool. The Rodin platform itself does not provide any automatic tools. These are provided by additional features such as the Event-B modelling environment (see plugin org.eventb.core).

Programmatic usage

The class to be implement usually extends the class org.eventb.core.sc.StaticChecker and needs to implement the abstract method ‘extract()‘ from the interface org.rodinp.core.builder.IExtractor:

    public void extract(IFile file, IGraph graph, IProgressMonitor monitor)throws CoreException {
        try {
              monitor.beginTask(Messages.bind(Messages.build_extracting, file.getName()), 1);
              IRodinFile source = RodinCore.valueOf(file);
              IDecompositionRoot root = (IDecompositionRoot) source.getRoot();
              IRodinFile target = root.getSCDecompositionRoot().getRodinFile();
              graph.addTarget(target.getResource());
              graph.addToolDependency(source.getResource(), target.getResource(),true);
           } finally {
              monitor.done();
           }
    }

An org.rodinp.core.builder.IGraph interface is used by the extractors registers with the builder to manipulate the dependency graph of all Rodin resources of a Rodin project. It is a Facade to the more complicated ways of manipulating the dependency graph inside the builder. Some information is cached in the corresponding object so the contents of the facade must be synchronised with the graph at the end of an extraction. Requests to add nodes to the graph must be made explicitly by methods addNode(). Dependencies are managed by the facade. This saves clients from having to compute dependency graph deltas themselves.

We have already defined the static check tool and the target for which it will run. Now, we need to configure the static checker tool. It is necessary to define the checks that are required for each element and that is done by adding an extension-point of org.eventb.core.configurations.

Configuration

Configuration is used to define which modules are used by the static checker tool. Similarly in can be used for the proof obligation generator (POG).

Declaration

<!ELEMENT configuration ((config | pogModule | scModule))+>
 <!ATTLIST configuration
 id   CDATA #REQUIRED
 name CDATA #REQUIRED
 >
 id - the identifier for this attribute type (simple id token, unique for attribute types within the extension namespace). The token cannot contain dot (.) or whitespace.
 name - the human-readable name of this attribute type

For static checks, we use scModule and config elements. Below we show an example of using the configuration:

<extension
        point="org.eventb.core.configurations">
     <configuration
           id="dcmpSC"
           name="Decomposition Static Checker Root Module">
        <scModule
              id="ch.ethz.eventb.decomposition.core.decompositionModule">
        </scModule>
     </configuration>
     <configuration
           id="dcmpBaseSC"
           name="Decomposition Static Checker Base Module">
        <config
              id="ch.ethz.eventb.decomposition.core.dcmpSC">
        </config>
        <scModule
              id="ch.ethz.eventb.decomposition.core.componentModule">
        </scModule>
        <scModule
           id="ch.ethz.eventb.decomposition.core.decompositionConfigurationModule">
        </scModule>
        <scModule
              id="ch.ethz.eventb.decomposition.core.subComponentModule">
        </scModule>
        <scModule
              id="ch.ethz.eventb.decomposition.core.subComponentElementModule">
        </scModule>
     </configuration>
     <configuration
           id="dcmp"
           name="Decomposition Configuration">
        <config
              id="ch.ethz.eventb.decomposition.core.dcmpBaseSC">
        </config>
     </configuration>
  </extension>

Although not necessary, we structure the configuration in different levels:

  • The ‘Decomposition Configuration’ is defined by a base static checker module that contains the ‘Decomposition Static Checker Base Module‘.
  • Inside the last one are the static check modules for all elements (decompositionComponentModule,decompositionConfigurationModule,...) in the decompositionFile including decompositionRoot (id=dcmpSC).

The id field in the scModule tags must exist already. They will correspond to the static checker modules defined using the extension ‘org.eventb.core.scModuleTypes‘. These are used to process the necessary operations for each element inside a static checked file.

Programmatic usage

Modules

Filter

Filter are used to validate inserted elements. After the successful validation of all elements, they can be processed and stored in the static checked file. In order to implement a filter, we define the following extension-point:

<!ELEMENT filterType (prereq)*>
 <!ATTLIST filterType
 id     CDATA #REQUIRED
 name   CDATA #REQUIRED
 parent CDATA #REQUIRED
 class  CDATA #REQUIRED
 >
 id - the identifier for this filter type (simple id token, unique for (filter/processor/root) types within the extension namespace). 
 The token cannot contain dot (.) or whitespace.
 name - the human-readable name of this filter module
 parent - the optional parent (processor) module. Root modules must leave the attribute undefined. It is not allowed to choose a filter module as parent.
 class - the fully-qualified name of a subclass of org.eventb.core.sc.SCFilterModule

For the filterType, the classes usually extend the abstract class org.eventb.core.sc.SCFilterModule. It also contains three methods:

  • public abstract boolean accept(IRodinElement element, ISCStateRepository repository, IProgressMonitor monitor) throws CoreException;: runs the static checker module. Returns whether the element should be accepted. If an error marker was associated with the element the returned value should usually be false. Exceptions from this rule are possible, in particular, if the element has been already marked with an error.
  • public abstract void initModule(ISCStateRepository repository,IProgressMonitor monitor) throws CoreException;:Initialisation code for the module
  • public abstract void endModule(ISCStateRepository repository,IProgressMonitor monitor) throws CoreException;: Termination code for the module

Processor

Processor literally process the elements, storing them in the static checked file, running sub-processors and adding states to the repository if required. To implement a processor, it is required to define the following extension-point:

 <!ELEMENT processorType (prereq)*>
 <!ATTLIST processorType
 id     CDATA #REQUIRED
 name   CDATA #REQUIRED
 parent CDATA #REQUIRED
 class  CDATA #REQUIRED
 >
 id - the identifier for this processor type (simple id token, unique for (filter/processor/root) types within the extension namespace). 
 The token cannot contain dot (.) or whitespace.
 name - the human-readable name of this processor module
 parent - the optional parent (processor) module. Root modules must leave the attribute undefined. It is not allowed to choose a filter module as parent.
 class - the fully-qualified name of a subclass of org.eventb.core.sc.SCProcessorModule

The classes that implement the rootType and processorType usually extend the abstract class org.eventb.core.sc.SCProcessorModule. They contain a constant called MODULE_TYPE that identifies the scModule. An example is:

public static final IModuleType<DecompositionModule> MODULE_TYPE = SCCore.getModuleType(DecompositionCorePlugin.PLUGIN_ID + ".decompositionModule");

that identifies the Decomposition Root Module. Moreover this classes should implement the three methods that are part of the interface org.eventb.internal.core.tool.types.ISCProcessorModule:

  • public abstract void initModule(IRodinElement element,ISCStateRepository repository,IProgressMonitor monitor) throws CoreException; : Initialisation code for the module. Used to initialise the global variables of the class.
  • public abstract void process(IRodinElement element,IInternalElement target, ISCStateRepository repository, IProgressMonitor monitor) throws CoreException;: Runs the static checker module: process the element. The element itself has already been accepted. If this element has children, then the children modules should be called here (see for example ‘ch.ethz.eventb.decomposition.core.sc.modules.DecompositionSubComponentModule‘).
  • public abstract void endModule(IRodinElement element,ISCStateRepository repository,IProgressMonitor monitor) throws CoreException; : Termination code for the module. Used to clean up memory (global variables) before finishing the module call.

Sequencing

Parent

Similar to processor by applied to the root of the file. The extension that need to be implemented in defined below:

<!ELEMENT rootType EMPTY>
 <!ATTLIST rootType
 id    CDATA #REQUIRED
 name  CDATA #REQUIRED
 input CDATA #REQUIRED
 class CDATA #REQUIRED
 >
 id - the identifier for this root type (simple id token, unique for (filter/processor/root) types within the extension namespace). The token cannot contain dot (.) or whitespace.
 name - the human-readable name of this root module
 input - identifier of the input file element type for this root module.
 class - the fully-qualified name of a subclass of org.eventb.core.sc.SCProcessorModule

Prerequisite

Some static checks rely on already done static checks so they work as pre-requirements. For instance, if a concrete event is refined it is necessary to know the abstract machine defined in the refine machine section. So the refine machine is a static check pre-requirement of the refinement an event. To implement a pre-requirement, it is necessary to define the following extension-point:

<!ELEMENT prereq EMPTY>
 <!ATTLIST prereq
 id CDATA #REQUIRED
 >
 id - the full ids of all (filter and processor) modules that must be run before this module

Example

An example of defining a scModule of type rootType, filterType and pre-requirement is defined below:

 <extension
          point="org.eventb.core.scModuleTypes">
       <rootType
             class="ch.ethz.eventb.decomposition.core.sc.modules.DecompositionModule"
             id="decompositionModule"
             input="ch.ethz.eventb.decomposition.core.dcpFile"
             name="Decomposition SC Root Module">
       </rootType>
       <processorType
             class="ch.ethz.eventb.decomposition.core.sc.modules.DecompositionComponentModule"
             id="decompositionComponentModule"
             name="Decomposition SC Component Module"
             parent="ch.ethz.eventb.decomposition.core.decompositionModule">
       </processorType>
       .
       .
       .
       <filterType
             class="ch.ethz.eventb.decomposition.core.sc.modules.DecompositionSubComponentElementFilterModule"
             id="decompositionSubComponentElementFilterModule"
             name="Decomposition SC SubComponentElement Filter Module"
             parent="ch.ethz.eventb.decomposition.core.decompositionCommitSubComponentElementModule">
          <prereq
                id="ch.ethz.eventb.decomposition.core.decompositionConfigurationModule">
          </prereq>
          <prereq
                id="ch.ethz.eventb.decomposition.core.decompositionComponentModule">
          </prereq>
       </filterType>
    </extension>

Below is an example of the call of the three processor/root methods in the class ch.ethz.eventb.decomposition.core.sc.modules.DecompositionModule:

       @Override
       public void initModule(IRodinElement element,ISCStateRepository repository,  IProgressMonitor monitor) throws CoreException {
               accuracyInfo = new DecompositionAccuracyInfo();
               final IDecompositionLabelSymbolTable labelSymbolTable = new DecompositionLabelSymbolTable(LABEL_SYMTAB_SIZE);
               repository.setState(labelSymbolTable);
               repository.setState(accuracyInfo);
               initProcessorModules(element, repository, monitor);
       }
       public void process(IRodinElement element, IInternalElement target,ISCStateRepository repository, IProgressMonitor monitor)throws CoreException {
               scRoot = (ISCDecompositionRoot) target;
              processModules(element, target, repository, monitor);
       }
       @Override
       public void endModule(IRodinElement element,ISCStateRepository repository, IProgressMonitor monitor) throws CoreException {
               scRoot.setAccuracy(accuracyInfo.isAccurate(), monitor);
              endProcessorModules(element, repository, monitor);
       }

Whenever a problem is encountered by the static checker, it is possible to raise a warning or an error, highlighting the respective element using the method org.eventb.core.sc.SCModule#createProblemMarker. An example can be seen below:

       public void process(IRodinElement element, IInternalElement target,ISCStateRepository repository, IProgressMonitor monitor)throws CoreException {
               monitor.subTask(Messages.bind(Messages.progress_DecompositionComponent));
               IComponent[] decompositionComponents = decompositionFile.getDecompositionComponents();
               if (decompositionComponents.length > 1) {
                       for (int k = 1; k < decompositionComponents.length; k++) {
                               createProblemMarker(decompositionComponents[k], DecompositionConfigurationAttributes.TARGET_ATTRIBUTE,
                                                             DecompositionGraphProblem.TooManyComponentsError);
                       }
              }
              ...
              repository.setState(new ComponentMachineInfo(scComponentMachineRoot,component));
              ...
             monitor.worked(1);
      }

In this particular case, if the number of IComponent elements is >1, then an error will be generated for the respective IComponent element:

More than one component error.png

States

The static check of the elements in a file are independent of each other (different and independent modules). Nevertheless there are some information that is dependent on other elements. For instance, for label elements it is necessary to know which labels have been used already before checking the elements. Since the elements checks are independent, the solution is to ‘share data‘ through scStates implemented using the extension-point org.eventb.core.scStateTypes. These are used to dynamically store data that will be used by dependencies (scModules) inside the static checked elements. The data is stored in a SCStateRepository and contains a key and respective content (value).

Declaration

<!ELEMENT stateType EMPTY>
 <!ATTLIST stateType
 id    CDATA #REQUIRED
 name  CDATA #REQUIRED
 class CDATA #REQUIRED
 >
 id - the identifier for this attribute type (simple id token, unique for attribute types within the extension namespace). The token cannot contain dot (.) or whitespace.
 name - the human-readable name of this attribute type
 class - the fully-qualified name of a subclass of org.eventb.core.sc.state.ISCState

Programatic Usage

To store data, we need to call the method

void setState(I state) [I extends IState]

part of the interface org.eventb.core.tool.IStateRepository (See method initModule above). To retrieve a state, you call the method:

I getState(IStateType<? extends I> stateType) throws CoreException;

In order to use the state, it is necessary to define the ‘key‘ in the extension point stateType.

Example

An example of the use of states can be seen below:

<extension
          point="org.eventb.core.scStateTypes">
       <stateType
             class="ch.ethz.eventb.decomposition.core.sc.state.IDecompositionAccuracyInfo"
             id="decompositionAccuracyInfo"
             name="Decomposition Accuracy Info">
       </stateType>
       <stateType
             class="ch.ethz.eventb.decomposition.core.sc.state.IDecompositionLabelSymbolTable"
             id="decompositionLabelSymbolTable"
             name="Decomposition Label-Symbol Table">
       </stateType>
       <stateType
             class="ch.ethz.eventb.decomposition.core.sc.state.IComponentAccuracyInfo"
             id="componentDecompositionInfo"
             name="Decomposition Component Machine Information">
       </stateType>
       <stateType
             class="ch.ethz.eventb.decomposition.core.sc.state.IDecompositionStyle"
             id="style"
             name="Decomposition Style">
       </stateType>
   </extension>

For instance, the last stateType defined above is Decomposition Style. It is required for checking which kind of subComponentElements are expected:

  • if style= shared event => subComponentElement type must be variables.
  • if style= shared variable => subComponentElement type must be events.