/// <summary> /// Populate methods and classes dictionaries from content lines /// </summary> /// <param name="contentLines"> /// A <see cref="System.String[]"/>: Each line of file content /// </param> /// <remarks> /// Maintain a stack of lines that increase the scope, /// then pop as the scope is decreased. /// Use scope begin/end for region/fold population. /// </remarks> /// <returns> /// A <see cref="System.Boolean"/>: Success/failure /// </returns> bool RunStack(string[] contentLines) { Stack<KeyValuePair<int,RubyDeclaration>> stack = new Stack<KeyValuePair<int,RubyDeclaration>> (); int i = 1; Match match; foreach (string aline in contentLines) { string line = aline.Trim (); if (line.StartsWith ("end", StringComparison.Ordinal) && (3 == line.Length || !char.IsLetterOrDigit (line[3]))) { if (0 == stack.Count){ // Console.WriteLine ("RubyDocumentParser: Popping empty stack at {0}", i); return false; }// stack imbalance KeyValuePair<int,RubyDeclaration> poppedPair = stack.Pop (); if (!string.IsNullOrEmpty (poppedPair.Value.name)) { // Console.WriteLine ("Got {0} {1} from {2} to {3}", methods.ContainsKey(poppedPair.Key)? "method": "class", poppedPair.Value, poppedPair.Key, i); if (methods.ContainsKey (poppedPair.Key)) { methods[poppedPair.Key].endLine = i; }// end of method definition if (classes.ContainsKey (poppedPair.Key)) { classes[poppedPair.Key].endLine = i; }// end of class definition if (modules.ContainsKey (poppedPair.Key)) { modules[poppedPair.Key].endLine = i; }// end of module definition }// only care about method and class definitions }// Scope decrease foreach (string sb in scopeBeginners) { if (line.StartsWith (sb, StringComparison.Ordinal) && !line.EndsWith ("end", StringComparison.Ordinal) && (line.Length == sb.Length || char.IsWhiteSpace (line[sb.Length]) || char.IsPunctuation (line[sb.Length]))) { stack.Push (new KeyValuePair<int,RubyDeclaration> (i, new RubyDeclaration (i, aline.Length, i, string.Empty, line))); break; } }// check for unimportant scope increase if (null != (match = doEndBlock.Match (line)) && match.Success && !match.Groups["end"].Success) { stack.Push (new KeyValuePair<int,RubyDeclaration> (i, new RubyDeclaration (i, aline.Length, i, string.Empty, line))); }// check for do/end-scoped block with inline do else if (null != (match = methodDefinition.Match (line)) && match.Success) { RubyDeclaration method = methods[i] = new RubyDeclaration (i, aline.Length, i, match.Groups["name"].Value, line); stack.Push (new KeyValuePair<int,RubyDeclaration> (i, method)); }// begin method definition else if (null != (match = classDefinition.Match (line)) && match.Success) { if (match.Groups["module"].Success && !string.IsNullOrEmpty (match.Groups["module"].Value)) { modules[i] = new RubyDeclaration (i, line.Length+1, i, match.Groups["module"].Value, line); } RubyDeclaration klass = classes[i] = new RubyDeclaration (i, aline.Length, i, match.Groups["name"].Value, line); stack.Push (new KeyValuePair<int,RubyDeclaration> (i, klass)); }// begin class definition else if (null != (match = moduleDefinition.Match (line)) && match.Success) { RubyDeclaration module = modules[i] = new RubyDeclaration (i, aline.Length, i, match.Groups["name"].Value, line); stack.Push (new KeyValuePair<int,RubyDeclaration> (i, module)); }// begin module definition ++i; }// parse line return (0 == stack.Count); }
/// <summary> /// Populate a module with classes /// </summary> void PopulateClasses(CompilationUnit cu, RubyDeclaration parent) { List<int> removal = new List<int> (); foreach (KeyValuePair<int,RubyDeclaration> mpair in classes) { if (mpair.Key >= parent.beginLine && mpair.Key <= parent.endLine) { DomType myclass = new DomType (cu, ClassType.Class, mpair.Value.name, new DomLocation (mpair.Value.beginLine, 1), parent.name, new DomRegion (mpair.Value.beginLine, mpair.Value.beginColumn+1, mpair.Value.endLine, int.MaxValue), new List<IMember> ()); PopulateMethods (myclass); cu.Add (myclass); removal.Add (mpair.Key); }// Add classes that are declared within the parent's scope }// Check detected classes // Remove used classes from map foreach (int key in removal){ classes.Remove (key); } }