public virtual Differences VisitTypeNodeList(TypeNodeList list1, TypeNodeList list2, out TypeNodeList changes, out TypeNodeList deletions, out TypeNodeList insertions){ changes = list1 == null ? null : list1.Clone(); deletions = list1 == null ? null : list1.Clone(); insertions = list1 == null ? new TypeNodeList() : list1.Clone(); //^ assert insertions != null; Differences differences = new Differences(); //Compare definitions that have matching key attributes TrivialHashtable matchingPosFor = new TrivialHashtable(); TrivialHashtable matchedNodes = new TrivialHashtable(); for (int j = 0, n = list2 == null ? 0 : list2.Count; j < n; j++){ //^ assert list2 != null; TypeNode nd2 = list2[j]; if (nd2 == null || nd2.Name == null) continue; string fullName = nd2.FullName; if (fullName == null) continue; matchingPosFor[Identifier.For(fullName).UniqueIdKey] = j; insertions.Add(null); } for (int i = 0, n = list1 == null ? 0 : list1.Count; i < n; i++){ //^ assert list1 != null && changes != null && deletions != null; TypeNode nd1 = list1[i]; if (nd1 == null || nd1.Name == null) continue; string fullName = nd1.FullName; if (fullName == null) continue; object pos = matchingPosFor[Identifier.For(fullName).UniqueIdKey]; if (!(pos is int)) continue; //^ assert pos != null; //^ assume list2 != null; //since there was entry int matchingPosFor int j = (int)pos; TypeNode nd2 = list2[j]; //^ assume nd2 != null; //nd1 and nd2 have the same key attributes and are therefore treated as the same entity matchedNodes[nd1.UniqueKey] = nd1; matchedNodes[nd2.UniqueKey] = nd2; //nd1 and nd2 may still be different, though, so find out how different Differences diff = this.VisitTypeNode(nd1, nd2); if (diff == null){Debug.Assert(false); continue;} if (diff.NumberOfDifferences != 0){ changes[i] = diff.Changes as TypeNode; deletions[i] = diff.Deletions as TypeNode; insertions[i] = diff.Insertions as TypeNode; insertions[n+j] = nd1; //Records the position of nd2 in list2 in case the change involved a permutation //Debug.Assert(diff.Changes == changes[i] && diff.Deletions == deletions[i] && diff.Insertions == insertions[i]); differences.NumberOfDifferences += diff.NumberOfDifferences; differences.NumberOfSimilarities += diff.NumberOfSimilarities; if (nd1.DeclaringModule == this.OriginalModule || (nd1.DeclaringType != null && nd1.DeclaringType.DeclaringModule == this.OriginalModule)){ if (this.MembersThatHaveChanged == null) this.MembersThatHaveChanged = new MemberList(); this.MembersThatHaveChanged.Add(nd1); } continue; } changes[i] = null; deletions[i] = null; insertions[i] = null; insertions[n+j] = nd1; //Records the position of nd2 in list2 in case the change involved a permutation } //Find deletions for (int i = 0, n = list1 == null ? 0 : list1.Count; i < n; i++){ //^ assert list1 != null && changes != null && deletions != null; TypeNode nd1 = list1[i]; if (nd1 == null) continue; if (matchedNodes[nd1.UniqueKey] != null) continue; changes[i] = null; deletions[i] = nd1; insertions[i] = null; differences.NumberOfDifferences += 1; if (nd1.DeclaringModule == this.OriginalModule || (nd1.DeclaringType != null && nd1.DeclaringType.DeclaringModule == this.OriginalModule)){ if (this.MembersThatHaveChanged == null) this.MembersThatHaveChanged = new MemberList(); this.MembersThatHaveChanged.Add(nd1); } } //Find insertions for (int j = 0, n = list1 == null ? 0 : list1.Count, m = list2 == null ? 0 : list2.Count; j < m; j++){ //^ assert list2 != null; TypeNode nd2 = list2[j]; if (nd2 == null) continue; if (matchedNodes[nd2.UniqueKey] != null) continue; insertions[n+j] = nd2; //Records nd2 as an insertion into list1, along with its position in list2 differences.NumberOfDifferences += 1; //REVIEW: put the size of the tree here? } if (differences.NumberOfDifferences == 0){ changes = null; deletions = null; insertions = null; } return differences; }
private InterfaceList ParseInterfaceList(TokenSet followers, bool expectLeftBrace){ InterfaceList ilist = new InterfaceList(); TokenSet followersOrComma = followers|Token.Comma; for(;;){ Expression id = this.scanner.GetIdentifier(); switch(this.currentToken){ case Token.Bool: case Token.Decimal: case Token.Sbyte: case Token.Byte: case Token.Short: case Token.Ushort: case Token.Int: case Token.Uint: case Token.Long: case Token.Ulong: case Token.Char: case Token.Float: case Token.Double: case Token.Object: case Token.String: case Token.Void: TypeExpression texpr = this.TypeExpressionFor(this.currentToken); this.GetNextToken(); ilist.Add(new InterfaceExpression(texpr.Expression, texpr.SourceContext)); goto lookForComma; default: bool idOK = Parser.IdentifierOrNonReservedKeyword[this.currentToken]; if (idOK){ this.GetNextToken(); if (this.currentToken == Token.DoubleColon){ this.GetNextToken(); Identifier id2 = this.scanner.GetIdentifier(); id2.Prefix = (Identifier)id; id2.SourceContext.StartPos = id.SourceContext.StartPos; this.SkipIdentifierOrNonReservedKeyword(); id = id2; } if (this.currentToken == Token.Dot) id = this.ParseQualifiedIdentifier(id, followersOrComma|Token.LessThan); }else{ int col = this.scanner.endPos; this.SkipIdentifierOrNonReservedKeyword(Error.TypeExpected); if (col == this.scanner.endPos && this.currentToken != Token.EndOfFile){ //Did not consume a token, but just gave an error if (!followersOrComma[this.currentToken]) this.GetNextToken(); if (followers[this.currentToken]) return ilist; if (this.currentToken != Token.Comma){ if (Parser.IdentifierOrNonReservedKeyword[this.currentToken]) continue; break; } this.GetNextToken(); continue; } if (this.currentToken == Token.Dot) id = this.ParseQualifiedIdentifier(id, followersOrComma|Token.LessThan); if (!idOK) goto lookForComma; } break; } //I really want an Identifier here for StartName if (this.sink != null) { Identifier name = id as Identifier; if (id is QualifiedIdentifier) { name = ((QualifiedIdentifier)id).Identifier; } if (name != null) { this.sink.StartName(name); } } InterfaceExpression ifaceExpr = new InterfaceExpression(id, id.SourceContext); if (this.currentToken == Token.LessThan){ yetAnotherTypeArgumentList: this.GetNextToken(); TypeNodeList arguments = new TypeNodeList(); for(;;){ TypeNode t = this.ParseTypeExpression(null, followers|Token.Comma|Token.GreaterThan); arguments.Add(t); if (this.currentToken != Token.Comma) break; this.GetNextToken(); } ifaceExpr.TemplateArguments = arguments; ifaceExpr.TemplateArgumentExpressions = arguments.Clone(); ifaceExpr.SourceContext.EndPos = this.scanner.endPos; this.Skip(Token.GreaterThan); if (this.currentToken == Token.Dot) { TemplateInstance tempInst = new TemplateInstance(ifaceExpr.Expression, ifaceExpr.TemplateArguments); tempInst.TypeArgumentExpressions = ifaceExpr.TemplateArguments == null ? null : ifaceExpr.TemplateArguments.Clone(); tempInst.SourceContext = ifaceExpr.SourceContext; ifaceExpr.Expression = this.ParseQualifiedIdentifier(tempInst, followersOrComma|Token.LessThan); ifaceExpr.TemplateArguments = null; ifaceExpr.TemplateArgumentExpressions = null; if (ifaceExpr.Expression != null) ifaceExpr.SourceContext = ifaceExpr.Expression.SourceContext; if (this.currentToken == Token.LessThan) goto yetAnotherTypeArgumentList; } } ilist.Add(ifaceExpr); lookForComma: if (Parser.TypeOperator[this.currentToken] && !(expectLeftBrace && this.currentToken == Token.LeftBrace)){ this.HandleError(Error.BadBaseType); this.GetNextToken(); if (this.currentToken == Token.RightBracket || this.currentToken == Token.RightBrace) this.GetNextToken(); this.SkipTo(followersOrComma, Error.None); }else if (!followersOrComma[this.currentToken]) this.SkipTo(followersOrComma, Error.TypeExpected); if (this.currentToken == Token.Comma){ if (followers[Token.Comma] && followers[Token.GreaterThan]) break; //Parsing the constraint of a type parameter this.GetNextToken(); if (expectLeftBrace && (this.currentToken == Token.Class || this.currentToken == Token.Struct || this.currentToken == Token.New)) break; }else if (!Parser.TypeStart[this.currentToken] || this.currentToken == Token.Where) break; else if (Parser.ContractStart[this.currentToken]) break; } return ilist; }