/// <summary> /// Copy constructor helper. /// </summary> /// <param name="dataSource">The LGSPGraph object to get the data from</param> /// <param name="newName">Name of the copied graph.</param> /// <param name="oldToNewMap">A map of the old elements to the new elements after cloning, /// just forget about it if you don't need it.</param> private void Copy(LGSPGraph dataSource, String newName, out IDictionary<IGraphElement, IGraphElement> oldToNewMap) { model = dataSource.model; name = newName; InitializeGraph(); model.CreateAndBindIndexSet(this); if(dataSource.backend != null) { backend = dataSource.backend; modelAssemblyName = dataSource.modelAssemblyName; } oldToNewMap = new Dictionary<IGraphElement, IGraphElement>(); for(int i = 0; i < dataSource.nodesByTypeHeads.Length; i++) { for(LGSPNode head = dataSource.nodesByTypeHeads[i], node = head.lgspTypePrev; node != head; node = node.lgspTypePrev) { LGSPNode newNode = (LGSPNode) node.Clone(); AddNodeWithoutEvents(newNode, node.lgspType.TypeID); oldToNewMap[node] = newNode; } } for(int i = 0; i < dataSource.edgesByTypeHeads.Length; i++) { for(LGSPEdge head = dataSource.edgesByTypeHeads[i], edge = head.lgspTypePrev; edge != head; edge = edge.lgspTypePrev) { LGSPEdge newEdge = (LGSPEdge) edge.Clone((INode) oldToNewMap[edge.lgspSource], (INode) oldToNewMap[edge.lgspTarget]); AddEdgeWithoutEvents(newEdge, newEdge.lgspType.TypeID); oldToNewMap[edge] = newEdge; } } /* TODO: remove when cloning of graph variables was implemented * foreach(KeyValuePair<IGraphElement, LinkedList<Variable>> kvp in dataSource.ElementMap) { IGraphElement newElem = oldToNewMap[kvp.Key]; foreach(Variable var in kvp.Value) SetVariableValue(var.Name, newElem); }*/ model.FillIndexSetAsClone(this, dataSource, oldToNewMap); statistics = new LGSPGraphStatistics(this.Model); statistics.Copy(dataSource); }
/// <summary> /// Constructs an LGSPGraph object with the given model, backend, and name. /// </summary> /// <param name="grmodel">The graph model.</param> /// <param name="lgspBackend">The responsible backend object, needed for import from the sequences.</param> /// <param name="grname">The name for the graph.</param> public LGSPGraph(IGraphModel grmodel, LGSPBackend lgspBackend, String grname) : this(grmodel, grname) { backend = lgspBackend; }
/// <summary> /// Constructs an LGSPGraph object. /// Deprecated. /// </summary> /// <param name="lgspBackend">The responsible backend object.</param> /// <param name="grmodel">The graph model.</param> /// <param name="grname">The name for the graph.</param> /// <param name="modelassemblyname">The name of the model assembly.</param> public LGSPGraph(LGSPBackend lgspBackend, IGraphModel grmodel, String grname, String modelassemblyname) : this(grmodel, grname) { backend = lgspBackend; modelAssemblyName = modelassemblyname; }
static void Main(string[] args) { bool verbose = false, onlyNew = false, append = false; int filesStart = -1; if(args.Length > 0) { for(int i = 0; i < args.Length; i++) { if(args[i][0] == '-') { switch(args[i]) { case "-a": append = true; break; case "-c": Console.Write("Cleaning ..."); foreach(String dir in Directory.GetDirectories(".")) { foreach(String subdir in Directory.GetDirectories(dir, "*_out")) Directory.Delete(subdir, true); } Console.WriteLine(" OK"); return; case "-d": ShowDiff(); return; case "-n": onlyNew = true; break; case "-v": verbose = true; break; case "--help": case "-?": case "/?": Usage(); return; default: Console.WriteLine("Unknown option: " + args[i] + "\n"); Usage(); return; } } else { filesStart = i; break; } } } List<String> files = new List<string>(); if(filesStart == -1) { files.AddRange(Directory.GetFiles("should_pass", "*.grg")); files.AddRange(Directory.GetFiles("should_warn", "*.grg")); files.AddRange(Directory.GetFiles("should_fail", "*.grg")); } else { for(int i = filesStart; i < args.Length; i++) files.Add(args[i]); } LGSPBackend backend = new LGSPBackend(); using(StreamWriter logFile = new StreamWriter("summary.log", append)) { foreach(String file in files) { if(!file.EndsWith(".grg")) { Console.WriteLine("Error: Filename does not end with \".grg\": " + file); continue; } if(!File.Exists(file)) { Console.WriteLine("Error: File does not exist: " + file); continue; } String outDir = file.Replace(".grg", "_out"); String fileForLog = file.Replace('\\', '/'); if(Directory.Exists(outDir)) { if(onlyNew && Directory.GetLastWriteTime(outDir) > Directory.GetLastWriteTime(file)) continue; Directory.Delete(outDir, true); } Directory.CreateDirectory(outDir); TextWriter oldOut = Console.Out; Console.Write("===> TEST " + fileForLog); StringWriter log = new StringWriter(); Console.SetError(log); Console.SetOut(log); bool failed = false; try { backend.ProcessSpecification(file, outDir + Path.DirectorySeparatorChar, outDir, null, ProcessSpecFlags.KeepGeneratedFiles); } catch(Exception ex) { failed = true; log.Write(ex.Message); } Console.SetOut(oldOut); String javaOutput = null; String logStr = log.ToString(); if(logStr.Contains("Exception in thread")) { Console.WriteLine(" ... ABEND"); logFile.WriteLine("ABEND " + fileForLog); } else if(logStr.Contains("ERROR")) { Console.WriteLine(" ... ERROR"); logFile.WriteLine("ERROR " + fileForLog); } else if(logStr.Contains("Illegal model") || logStr.Contains("Illegal actions")) { Console.WriteLine(" ... FAILED"); logFile.WriteLine("FAILED " + fileForLog); } else if(!failed) { if(logStr.Contains("WARNING")) { Console.WriteLine(" ... WARNED"); logFile.WriteLine("WARNED " + fileForLog); } else if(File.Exists(outDir + Path.DirectorySeparatorChar + "printOutput.txt")) { using(StreamReader sr = new StreamReader(outDir + Path.DirectorySeparatorChar + "printOutput.txt")) javaOutput = sr.ReadToEnd(); if(javaOutput.Contains("WARNING")) { Console.WriteLine(" ... WARNED"); logFile.WriteLine("WARNED " + fileForLog); } else { javaOutput = null; Console.WriteLine(" ... OK"); logFile.WriteLine("OK " + fileForLog); } } else { Console.WriteLine(" ... OK"); logFile.WriteLine("OK " + fileForLog); } } else { Console.WriteLine(" ... ABEND"); logFile.WriteLine("ABEND " + fileForLog); } if(verbose) { if(javaOutput != null) Console.WriteLine(javaOutput); Console.WriteLine(log.ToString()); } } } ShowDiff(); }
/// <summary> /// Constructs an LGSPGraph object with the given model and backend, and an automatically generated name. /// </summary> /// <param name="grmodel">The graph model.</param> /// <param name="lgspBackend">The responsible backend object, needed for import from the sequences.</param> public LGSPGraph(IGraphModel grmodel, LGSPBackend lgspBackend) : this(grmodel, lgspBackend, GetNextGraphName()) { }
/// <summary> /// Constructs an LGSPNamedGraph object with the given model, backend, name, and capacity. /// </summary> /// <param name="grmodel">The graph model.</param> /// <param name="backend">The backend.</param> /// <param name="grname">The name for the graph.</param> /// <param name="capacity">The initial capacity for the name maps (performance optimization, use 0 if unsure).</param> public LGSPNamedGraph(IGraphModel grmodel, LGSPBackend backend, String grname, int capacity) : base(grmodel, backend, grname) { NameToElem = new Dictionary <String, IGraphElement>(capacity); ElemToName = new Dictionary <IGraphElement, String>(capacity); }
void DoIt() { // create the LibGr Search Plan backend we want to use LGSPBackend backend = new LGSPBackend(); // the graph model we'll use JavaProgramGraphsGraphModel model = new JavaProgramGraphsGraphModel(); // the actions object for the rules we'll to use IActions ba; // import the instance graph we created with gxl2grs, using the the .gm we created by hand // (can't use import gxl for the program graph, because the given .gxl is severly rotten) // we throw away the named graph cause we don't need names here and they require about the same amount of memory as the graph itself; INamedGraph importedNamedGraph = (INamedGraph)Porter.Import("InstanceGraph.grs", backend, model, out ba); LGSPGraph graph = new LGSPGraph((LGSPNamedGraph)importedNamedGraph, "unnamed"); importedNamedGraph = null; // get the actions object for the rules we want to use JavaProgramGraphsActions actions = ba!=null ? (JavaProgramGraphsActions)ba : new JavaProgramGraphsActions(graph); // the graph processing environment we'll use LGSPGraphProcessingEnvironment procEnv = new LGSPGraphProcessingEnvironment(graph, actions); // the instance graph script uses variables to build up the graph, // we query some of them here, to get the elements to refactor // (instead of variables one could use the element names) Class src = (Class)procEnv.GetNodeVarValue("I176"); // class Node Class tgt = (Class)procEnv.GetNodeVarValue("I194"); // class Packet - use if parameter is used in moving method //Class tgt = (Class)graph.GetNodeVarValue("I617"); // class String - use if instance variable is used in moving method MethodBody mb = (MethodBody)procEnv.GetNodeVarValue("I409"); // method body of send // get operation for method body by: // get action, match action pattern with given parameters, apply rewrite filling given out parameters IMatchesExact<Rule_getOperation.IMatch_getOperation> matches = actions.getOperation.Match(procEnv, 1, mb); IOperation op; actions.getOperation.Modify(procEnv, matches.FirstExact, out op); // iterated application of action marking the body of the expression // (shows second way of getting action) int visitedFlagId = graph.AllocateVisitedFlag(); Debug.Assert(visitedFlagId==0); IGraphElement[] param = new LGSPNode[1]; param[0] = mb; IMatches matchesInexact; while((matchesInexact = actions.GetAction("markExpressionOfBody").Match(procEnv, 1, param)).Count == 1) { actions.GetAction("markExpressionOfBody").Modify(procEnv, matchesInexact.First); } // application of a graph rewrite sequence procEnv.SetVariableValue("src", src); procEnv.SetVariableValue("tgt", tgt); procEnv.SetVariableValue("mb", mb); procEnv.SetVariableValue("op", op); procEnv.ApplyGraphRewriteSequence( @"(p)=someParameterOfTargetType(mb,tgt) && !callToSuperExists && !isStatic(mb) && !methodNameExists(mb,tgt) && (!thisIsAccessed || thisIsAccessed && (srcparam)=addSourceParameter(op,src) && useSourceParameter(srcparam)*) && relinkOperationAndMethodBody(op,mb,src,tgt) && ( (call,pe)=getUnprocessedCallWithActualParameter(op,p) && ((def(srcparam) && addSourceToCall(call,srcparam)) || true) && (replaceAccess_Parameter_AccessWithoutLink(c,pe) || replaceAccess_Parameter_AccessWithLinkToExpression(c,pe)) )*"); Console.WriteLine(procEnv.PerformanceInfo.MatchesFound + " matches found."); procEnv.PerformanceInfo.Reset(); // unmark the body of the expression by searching all occurences and modifying them actions.unmarkExpression.ApplyAll(0, procEnv); graph.FreeVisitedFlag(visitedFlagId); // export changed graph (alternatively you may export it as InstanceGraphAfter.gxl) // if we'd use a NamedGraph we'd get the graph exported with its persistent names; so we get it exported with some hash names List<String> exportParameters = new List<string>(); exportParameters.Add("InstanceGraphAfter.grs"); Porter.Export(graph, exportParameters); }
/// <summary> /// Constructs an LGSPNamedGraph object. /// Deprecated. /// </summary> /// <param name="lgspBackend">The responsible backend object.</param> /// <param name="grmodel">The graph model.</param> /// <param name="grname">The name for the graph.</param> /// <param name="modelassemblyname">The name of the model assembly.</param> /// <param name="capacity">The initial capacity for the name maps (performance optimization, use 0 if unsure).</param> public LGSPNamedGraph(LGSPBackend lgspBackend, IGraphModel grmodel, String grname, String modelassemblyname, int capacity) : base(lgspBackend, grmodel, grname, modelassemblyname) { NameToElem = new Dictionary <String, IGraphElement>(capacity); ElemToName = new Dictionary <IGraphElement, String>(capacity); }
/// <summary> /// Constructs an LGSPNamedGraph object with the given model, backend, name, and capacity. /// </summary> /// <param name="grmodel">The graph model.</param> /// <param name="backend">The backend.</param> /// <param name="grname">The name for the graph.</param> /// <param name="capacity">The initial capacity for the name maps (performance optimization, use 0 if unsure).</param> public LGSPNamedGraph(IGraphModel grmodel, LGSPBackend backend, String grname, int capacity) : base(grmodel, backend, grname) { NameToElem = new Dictionary<String, IGraphElement>(capacity); ElemToName = new Dictionary<IGraphElement, String>(capacity); }
/// <summary> /// Constructs an LGSPNamedGraph object. /// Deprecated. /// </summary> /// <param name="lgspBackend">The responsible backend object.</param> /// <param name="grmodel">The graph model.</param> /// <param name="grname">The name for the graph.</param> /// <param name="modelassemblyname">The name of the model assembly.</param> /// <param name="capacity">The initial capacity for the name maps (performance optimization, use 0 if unsure).</param> public LGSPNamedGraph(LGSPBackend lgspBackend, IGraphModel grmodel, String grname, String modelassemblyname, int capacity) : base(lgspBackend, grmodel, grname, modelassemblyname) { NameToElem = new Dictionary<String, IGraphElement>(capacity); ElemToName = new Dictionary<IGraphElement, String>(capacity); }
static int Main(string[] args) { String specFile = null; String dirname = null; String destDir = null; ProcessSpecFlags flags = ProcessSpecFlags.UseNoExistingFiles; IBackend backend = null; List<String> externalAssemblies = new List<String>(); String statisticsPath = null; for(int i = 0; i < args.Length; i++) { if(args[i][0] == '-') { switch(args[i]) { case "-o": if(i + 1 >= args.Length) { Console.Error.WriteLine("Missing parameter for -o option!"); specFile = null; // show usage break; } destDir = args[++i]; if(!Directory.Exists(destDir)) { Console.Error.WriteLine("Specified output directory does not exist!"); return 1; } if(destDir[destDir.Length - 1] != Path.DirectorySeparatorChar) destDir += Path.DirectorySeparatorChar; break; case "-b": if(i + 1 >= args.Length) { Console.Error.WriteLine("Missing parameter for -b option!"); specFile = null; // show usage break; } backend = LoadBackend(args[++i]); if(backend == null) return 1; Console.WriteLine("Using backend \"" + backend.Name + "\"."); break; case "-r": if (i + 1 >= args.Length) { Console.Error.WriteLine("Missing parameter for -r option!"); specFile = null; // show usage break; } externalAssemblies.Add(args[++i]); break; case "-keep": flags |= ProcessSpecFlags.KeepGeneratedFiles; if(specFile != null) // specFile already specified? { if(i + 1 >= args.Length) // yes. is there another parameter? break; } else if(i + 2 >= args.Length) // no. are there two more parameters? break; if(args[i + 1][0] == '-') // is the next parameter an option? break; dirname = args[++i]; // no, use it as a gen-dir break; case "-use": if(i + 1 >= args.Length) { Console.Error.WriteLine("Missing parameter for -use option!"); specFile = null; // show usage break; } if(dirname != null) { Console.Error.WriteLine("The -d option may not specify a directory if -use is used!"); specFile = null; break; } dirname = args[++i]; flags |= ProcessSpecFlags.UseJavaGeneratedFiles; if(!Directory.Exists(dirname)) { Console.Error.WriteLine("Illegal directory specified! It does not exist!"); return 1; } break; case "-usefull": if(i + 1 >= args.Length) { Console.Error.WriteLine("Missing parameter for -usefull option!"); specFile = null; // show usage break; } if(dirname != null) { Console.Error.WriteLine("The -d option may not specify a directory if -usefull is used!"); specFile = null; break; } dirname = args[++i]; flags |= ProcessSpecFlags.UseAllGeneratedFiles; if(!Directory.Exists(dirname)) { Console.Error.WriteLine("Illegal directory specified! It does not exist!"); return 1; } break; case "-debug": flags |= ProcessSpecFlags.CompileWithDebug; break; case "-noevents": flags |= ProcessSpecFlags.NoEvents; flags |= ProcessSpecFlags.NoDebugEvents; break; case "-nodebugevents": flags |= ProcessSpecFlags.NoDebugEvents; break; case "-lazynic": flags |= ProcessSpecFlags.LazyNIC; break; case "-noinline": flags |= ProcessSpecFlags.Noinline; break; case "-statistics": if(i + 1 >= args.Length) { Console.Error.WriteLine("Missing parameter for -statistics option!"); specFile = null; // show usage break; } statisticsPath = args[++i]; if(!File.Exists(statisticsPath)) { Console.Error.WriteLine("Specified statistics file \"" + statisticsPath + "\" does not exist!"); return 1; } break; case "-profile": flags |= ProcessSpecFlags.Profile; break; default: Console.Error.WriteLine("Illegal option: " + args[i]); specFile = null; i = args.Length; // leave for loop break; } } else if(specFile != null) { Console.Error.WriteLine("Two rule specification files specified: \"" + specFile + "\" and \"" + args[i] + "\""); specFile = null; break; } else specFile = args[i]; } // flags |= ProcessSpecFlags.Profile; // uncomment to test profiling if(specFile == null) { Console.WriteLine( "Usage: GrGen [OPTIONS] <grg-file>[.grg]\n" + "Options:\n" + " -o <output-dir> Output directory for the generated assemblies\n" + " -keep [<gen-dir>] Don't delete generated files making it possible\n" + " to use the files in a C# project directly.\n" + " This way you can also debug non-matching rules.\n" + " Optionally you can specify a destination directory.\n" + " -debug Compiles the assemblies with debug information\n" + " -r <assembly-path> Assembly path to reference, i.e. link into\n" + " the generated assembly\n" + " -statistics <path> Build matchers based on the graph statistics\n" + " contained in the specified file\n" + " -use <existing-dir> Use old C# files generated by the Java frontend\n" + " using the -keep option in the specified directory\n" + " -usefull <exist-dir> Use all old C# files generated using the -keep option\n" + " in the specified directory\n" + " -b <backend-dll> Use the specified backend library\n" + " (default: LGSPBackend)\n" + " -lazynic Negatives, Independents, and Conditions are only\n" + " executed at the end of matching (normally asap)\n" + " -noinline disables subpattern and independent inlining\n" + "Optimizing options:\n" + " -nodebugevents Do not fire debug events in the generated code.\n" + " Mostly action events, impacts debugging.\n" + " -noevents Do not fire events in the generated code.\n" + " Mostly attribute change events.\n" + " Impacts transactions, recording, debugging.\n" + " -noperfinfo Do not try to update the performance info object\n" + " counting number of matches and rewrites."); return 1; } if(!File.Exists(specFile)) { if(File.Exists(specFile + ".grg")) specFile += ".grg"; else { Console.Error.WriteLine("The GRG-file \"" + specFile + "\" does not exist!"); return 1; } } specFile = FixDirectorySeparators(specFile); String specDir; int index = specFile.LastIndexOf(Path.DirectorySeparatorChar); if(index == -1) specDir = ""; else { specDir = specFile.Substring(0, index + 1); if(!Directory.Exists(specDir)) { Console.Error.WriteLine("Something is wrong with the directory of the specification file:\n\"" + specDir + "\" does not exist!"); return 1; } } if(destDir == null) destDir = specDir; if(dirname == null) { int id = 0; do { dirname = specDir + "tmpgrgen" + id + ""; id++; } while(Directory.Exists(dirname)); } if(!Directory.Exists(dirname)) { try { Directory.CreateDirectory(dirname); } catch(Exception) { Console.Error.WriteLine("Unable to create temporary directory \"" + dirname + "\"!"); return 1; } } if((flags & ProcessSpecFlags.KeepGeneratedFiles) != 0) Console.WriteLine("The generated files will be kept in: " + dirname); if(backend == null) backend = new LGSPBackend(); int ret = 0; try { backend.ProcessSpecification(specFile, destDir, dirname, statisticsPath, flags, externalAssemblies.ToArray()); } catch(Exception ex) { Console.Error.WriteLine((flags & ProcessSpecFlags.CompileWithDebug) != 0 ? ex.ToString() : ex.Message); ret = 1; } if((flags & ProcessSpecFlags.KeepGeneratedFiles) == 0 && (flags & ProcessSpecFlags.UseExistingMask) == ProcessSpecFlags.UseNoExistingFiles) Directory.Delete(dirname, true); return ret; }
static void Main(string[] args) { if(args.Length < 2 || args.Length > 3) { Console.WriteLine("usage: MovieDatabaseBenchmarker <name of rule to apply> <name of grs file to import or number of creation iterations of synthetic graph> [\"sequence to execute\"]"); Console.WriteLine("example: MovieDatabaseBenchmarker findCouplesOpt imdb-0005000-50176.movies.xmi.grs"); Console.WriteLine("example: MovieDatabaseBenchmarker findCliquesOf3Opt imdb-0130000-712130.movies.xmi.grs \"[cliques3WithRating\\orderDescendingBy<avgRating>\\keepFirst(15)] ;> [cliques3WithRating\\orderDescendingBy<numMovies>\\keepFirst(15)]\""); return; } // the graph we'll work on LGSPGraph graph; // the actions we'll use MovieDatabaseActions actions; // the graph processing environment we'll use LGSPGraphProcessingEnvironment procEnv; int dummy; if(Int32.TryParse(args[1], out dummy)) { Console.WriteLine("Synthesizing test graph with iteration count " + args[1] + " ..."); graph = new MovieDatabaseModelGraph(); actions = new MovieDatabaseActions(graph); procEnv = new LGSPGraphProcessingEnvironment(graph, actions); int startTimeSynth = Environment.TickCount; procEnv.ApplyGraphRewriteSequence("createExample(" + args[1] + ")"); Console.WriteLine("...needed " + (Environment.TickCount - startTimeSynth) + "ms for synthesizing"); } else { Console.WriteLine("Importing " + args[1] + " ..."); // the libGr search plan backend we'll use LGSPBackend backend = new LGSPBackend(); // the graph model we'll use MovieDatabaseModelGraphModel model = new MovieDatabaseModelGraphModel(); // import the graph, result (of grs import) will be a named graph IActions ba; INamedGraph importedNamedGraph = (INamedGraph)Porter.Import(args[1], backend, model, out ba); // we throw away the named graph cause we don't need names here and they require a huge amount of memory graph = new LGSPGraph((LGSPNamedGraph)importedNamedGraph, "unnamed"); importedNamedGraph = null; GC.Collect(); actions = ba != null ? (MovieDatabaseActions)ba : new MovieDatabaseActions(graph); procEnv = new LGSPGraphProcessingEnvironment(graph, actions); } // calculate search plans to optimize performance (I'm not going to fiddle with loading saved analysis data here) graph.AnalyzeGraph(); actions.GenerateActions(args[0]); Console.WriteLine("Number of Movie: " + graph.nodesByTypeCounts[graph.Model.NodeModel.GetType("Movie").TypeID]); Console.WriteLine("Number of Actor: " + graph.nodesByTypeCounts[graph.Model.NodeModel.GetType("Actor").TypeID]); Console.WriteLine("Number of Actress: " + graph.nodesByTypeCounts[graph.Model.NodeModel.GetType("Actress").TypeID]); Console.WriteLine("Number of personToMovie: " + graph.edgesByTypeCounts[graph.Model.EdgeModel.GetType("personToMovie").TypeID]); Console.WriteLine("Start matching " + args[0] + " ..."); int startTime = Environment.TickCount; // get action, search for all matches, apply rewrite IAction ruleToApply = actions.GetAction(args[0]); IMatches matches = ruleToApply.Match(procEnv, 0, new object[0]); Console.WriteLine("...needed " + (Environment.TickCount - startTime) + "ms for finding the matches"); Console.WriteLine("...continue with rewriting..."); ruleToApply.ModifyAll(procEnv, matches); Console.WriteLine("...needed " + (Environment.TickCount - startTime) + "ms for finding the matches and adding the couples/cliques"); Console.WriteLine("Number of Couple: " + graph.nodesByTypeCounts[graph.Model.NodeModel.GetType("Couple").TypeID]); Console.WriteLine("Number of Clique: " + graph.nodesByTypeCounts[graph.Model.NodeModel.GetType("Clique").TypeID]); Console.WriteLine("Number of commonMovies: " + graph.edgesByTypeCounts[graph.Model.EdgeModel.GetType("commonMovies").TypeID]); if(args.Length == 3) { procEnv.ApplyGraphRewriteSequence(args[2]); } }