Welcome to the GrGen.NET v6.7 API documentation |
This is an introduction into the Application Programming Interface of the GrGen.NET v6.7 system, i.e. the libGr and the assemblies generated from the model and rule specifications. We'll have a look at the
Note |
---|
If you work on the API level it is helpful to keep the generated source code which normally is thrown away after it was compiled into the assemblies lgsp-FooModel.dll and lgsp-FooActions.dll. Use the -keep option when you call grgen.exe to do so. |
The generated FooModel.cs opens the namespace de.unika.ipd.grGen.Model_Foo containing all the generated entities. It contains for every node or edge class Bar an interface IBar, which offers C# properties giving access to the attributes, and is inheriting in the same way as specified in the model file. This builds the exact interface of the model, it is implemented by a sealed class Bar with generated code and with code from the lgsp backend. Furtheron the namespace contains a model class FooGraphModel implementing the interface de.unika.ipd.grGen.libGr.IGraphModel, which supports iteration over the entities defined in the model using further, generic(i.e. inexact) interfaces from libGr. Finally, the namespace contains a class FooGraph which defines an LGSPGraph of a model equivalent to FooGraphModel; it contains convenience functions to easily create nodes and edges of exact type in the graph. In addition, a class FooNamedGraph is available, which defines an LGSPNamedGraph of a model equivalent to FooGraphModel; the named graph offers persistent names for all its graph elements, otherwise it is identical to an LGSPGraph. The naming requires about the same memory as an unnamed graph, but under normal circumstances the named graph is the recommended one to use (and is the one which will be used if employed by the shell). The graphs require an IGlobalVariables input upon creation, you have to construct and supply an LGSPGlobalVariables object towards this goal.
Note |
---|
If you want to use the type-safe interface, use the interface IBar, and the CreateNodeBar-methods of FooGraph or the CreateNode-method of Bar. If you want to use the generic interface, your entry point is the IGraphModel, with INodeModel.GetType("Bar") returning a NodeType, used in IGraph.AddNode(NodeType) returning an INode. |
The generated file FooActions.cs opens the namespace de.unika.ipd.grGen.Action_Foo containing all the generated entities. It contains for every rule or test bar
Note |
---|
If you want to use the type-safe interface, your entry point is the member bar of type IAction_bar from FooActions (or Action_bar.Instance). Actions are used with named parameters of exact types. If you want to use the generic interface, your entry point is the method GetAction("bar") of the interface BaseActions implemented by FooActions returning an IAction. Actions are used with object-arrays for parameter passing. |
The interface IGraphProcessingEnvironment implemented by the LGSPGraphProcessingEnvironment class offers all the additional functionality of GrGen.NET exceeding what is offered by the graph and the actions. It is constructed as LGSPGraphProcessingEnvironment given the graph and the actions. It offers execution of the sequences, combining actions into transformations (the former regarding control flow, the latter regarding data flow). Further on, the environment offers driver or helper objects for transaction management, deferred sequence execution, graph change recording, and emitting.
The GraphViewer offers the functionality to display a graph continuously, following its changes, as well as to just render a snapshot of it. The Debugger allows you to execute sequences stepwise under debugger control (in a console window). They are contained in the graphViewerAndSequencesDebugger project; in the libGrShell project do you find the GrShell that allows you to employ GrShell-functionality from your own code (once it was generated).
There are several examples available in the examples-api folder of the GrGen.NET-distribution:
Normally you want to use the type-safe interface of the generated code as it is much more convenient. Only if your application must get along with models and actions unknown before it is compiled you have to fall back to the generic interface. An extensive example showing how to cope with the latter is shipped with GrGen.NET in form of the GrShell. Here we'll show a short example on how to use GrGen.NET with the type-safe API; further examples are given in the examples-api folder of the GrGen.NET-distribution. We'll start with including the namespaces of the libGr and the lgsp backend shipped with GrGen.NET, plus the namespaces of our actions and models, generated from Foo.grg.
using de.unika.ipd.grGen.libGr; using de.unika.ipd.grGen.lgsp; using de.unika.ipd.grGen.Action_Foo; using de.unika.ipd.grGen.Model_Foo;
FooGraph graph = new FooGraph(new LGSPGlobalVariables()); FooActions actions = new FooActions(graph); Bar b = graph.CreateNodeBar(); actions.bar.Apply(graph, b, ref b); // input of type Bar, output of type Bar
FooNamedGraph graph = new FooNamedGraph(new LGSPGlobalVariables());
This is an example doing mostly the same as the previous example, in a slightly more complicated way allowing for more control. Here we create the model separate from the graph, then the graph with a model not bound at generation time. We create the actions to apply on the graph, and a single node of type Bar in the graph, which we assign again to a variable b. Then we get the action from the actions and save it to an action variable bar; afterwards we use the action for finding all available matches of bar with input b -- which is different from the first version -- and remember the found matches in the matches variable with its exact type. Finally we take the first match from the matches and execute the rewrite with it. We could have inspected the nodes and edges of the match or their attributes before (using element names prefixed with node_/edge_ or attribute names to get exactly typed entities).
IGraphModel model = new FooGraphModel(); LGSPGraph graph = new LGSPGraph(model, new LGSPGlobalVariables()); FooActions actions = new FooActions(graph); Bar b = Bar.CreateNode(graph); IAction_bar bar = Action_bar.Instance; IMatchesExact<Rule_bar.IMatch_bar matches> = bar.Match(graph, 0, b); bar.Modify(graph, matches.First);
LGSPGraph graph = new LGSPNamedGraph(model, new LGSPGlobalVariables());
While C# allows input arguments values to be of a subtype of the declared interface parameter type (OO), it requires that the argument variables for the out parameters are of exactly the type declared (non-OO). Although a variable of a supertype would be fully sufficient -- the variable is only assigned. So for node class Bla extends Bar; and action bar(Bar x) : (Bla) from the rules file rules Foo.grg we can't use a desired target variable of type Bar as out-argument, but are forced to introduce a temporary variable of type Bla and assign this variable to the desired target variable after the call.
using de.unika.ipd.grGen.libGr; using de.unika.ipd.grGen.lgsp; using de.unika.ipd.grGen.Action_Foo; using de.unika.ipd.grGen.Model_Foo; FooGraph graph = new FooGraph(new LGSPGlobalVariables()); FooActions actions = new FooActions(graph); Bar b = graph.CreateNodeBar(); IMatchesExact<Rule_bar.IMatch_bar> matches = actions.bar.Match(graph, 1, b); //actions.bar.Modify(graph, matches.First, out b); // wont work, needed: Bla bla = null; actions.bar.Modify(graph, matches.First, out bla); b = bla;
For all but the simplest transformations you'll end up constructing a graph processing environment from the graph and the actions constructed until now, executing a graph rewrite sequence on the graph processing environment:
LGSPGraphProcessingEnvironment procEnv = new LGSPGraphProcessingEnvironment(graph, actions); procEnv.ApplyGraphRewriteSequence("<(::x)=foo && (::y)=bar(::x) | bla(::y)>");