Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Documenting Dafny Entities (Adding Docstring) #3756

Merged
merged 15 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion Source/DafnyCore/AST/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace Microsoft.Dafny;

public class Function : MemberDecl, TypeParameter.ParentType, ICallable, ICanFormat {
public class Function : MemberDecl, TypeParameter.ParentType, ICallable, ICanFormat, IHasDocstring {
public override string WhatKind => "function";

public string GetFunctionDeclarationKeywords(DafnyOptions options) {
Expand Down Expand Up @@ -437,4 +437,23 @@ public void Resolve(Resolver resolver) {

resolver.Options.WarnShadowing = warnShadowingOption; // restore the original warnShadowing value
}

protected override string GetTriviaContainingDocstring() {
if (Body == null) {
if (EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

if (StartToken.LeadingTrivia.Trim() != "") {
return StartToken.LeadingTrivia;
}
} else if (Body.StartToken.Prev.Prev is var tokenWhereTrailingIsDocstring &&
tokenWhereTrailingIsDocstring.TrailingTrivia.Trim() != "") {
return tokenWhereTrailingIsDocstring.TrailingTrivia;
} else if (StartToken is var tokenWhereLeadingIsDocstring &&
tokenWhereLeadingIsDocstring.LeadingTrivia.Trim() != "") {
return tokenWhereLeadingIsDocstring.LeadingTrivia;
}
return null;
}
}
4 changes: 2 additions & 2 deletions Source/DafnyCore/AST/Grammar/TriviaFormatterHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public static bool EndsWithNewline(string s) {
return EndsWithNewlineRegex.IsMatch(s);
}

private static readonly string AnyNewline = @"\r?\n|\r(?!\n)";
public static readonly string AnyNewline = @"\r?\n|\r(?!\n)";

private static readonly string NoCommentDelimiter = @"(?:(?!/\*|\*/)[\s\S])*";

private static readonly string MultilineCommentContent =
public static readonly string MultilineCommentContent =
$@"(?:{NoCommentDelimiter}(?:(?'Open'/\*)|(?'-Open'\*/)))*{NoCommentDelimiter}";

public static readonly Regex NewlineRegex =
Expand Down
18 changes: 17 additions & 1 deletion Source/DafnyCore/AST/IteratorDecl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Microsoft.Dafny;

public class IteratorDecl : ClassDecl, IMethodCodeContext {
public class IteratorDecl : ClassDecl, IMethodCodeContext, IHasDocstring {
public override string WhatKind { get { return "iterator"; } }
public readonly List<Formal> Ins;
public readonly List<Formal> Outs;
Expand Down Expand Up @@ -480,4 +480,20 @@ public void Resolve(Resolver resolver) {
Members.Add(moveNext);
}
}


protected override string GetTriviaContainingDocstring() {
IToken lastClosingParenthesis = null;
foreach (var token in OwnedTokens) {
if (token.val == ")") {
lastClosingParenthesis = token;
}
}

if (lastClosingParenthesis != null && lastClosingParenthesis.TrailingTrivia.Trim() != "") {
return lastClosingParenthesis.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}
10 changes: 9 additions & 1 deletion Source/DafnyCore/AST/MemberDecls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public virtual string FullSanitizedName {
public virtual IEnumerable<Expression> SubExpressions => Enumerable.Empty<Expression>();
}

public class Field : MemberDecl, ICanFormat {
public class Field : MemberDecl, ICanFormat, IHasDocstring {
public override string WhatKind => "field";
public readonly bool IsMutable; // says whether or not the field can ever change values
public readonly bool IsUserMutable; // says whether or not code is allowed to assign to the field (IsUserMutable implies IsMutable)
Expand Down Expand Up @@ -173,6 +173,14 @@ public bool SetIndent(int indentBefore, TokenNewIndentCollector formatter) {

return true;
}

protected override string GetTriviaContainingDocstring() {
if (EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return GetTriviaContainingDocstringFromStartTokeOrNull();
return GetTriviaContainingDocstringFromStartTokenOrNull();

And anywhere else this name is used

}
}

public class SpecialFunction : Function, ICallable {
Expand Down
17 changes: 16 additions & 1 deletion Source/DafnyCore/AST/Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Microsoft.Dafny;

public class Method : MemberDecl, TypeParameter.ParentType, IMethodCodeContext, ICanFormat {
public class Method : MemberDecl, TypeParameter.ParentType, IMethodCodeContext, ICanFormat, IHasDocstring {
public override IEnumerable<Node> Children => new Node[] { Body, Decreases }.
Where(x => x != null).Concat(Ins).Concat(Outs).Concat<Node>(TypeArgs).
Concat(Req).Concat(Ens).Concat(Mod.Expressions);
Expand Down Expand Up @@ -336,4 +336,19 @@ public void Resolve(Resolver resolver) {
resolver.currentMethod = null;
}
}

protected override string GetTriviaContainingDocstring() {
IToken lastClosingParenthesis = null;
foreach (var token in OwnedTokens) {
if (token.val == ")") {
lastClosingParenthesis = token;
}
}

if (lastClosingParenthesis != null && lastClosingParenthesis.TrailingTrivia.Trim() != "") {
return lastClosingParenthesis.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}
142 changes: 135 additions & 7 deletions Source/DafnyCore/AST/TopLevelDeclarations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ public static Dictionary<TypeParameter, Type> SubstitutionMap(List<TypeParameter
}

// Represents a submodule declaration at module level scope
public abstract class ModuleDecl : TopLevelDecl {
public abstract class ModuleDecl : TopLevelDecl, IHasDocstring {
public override string WhatKind { get { return "module"; } }
[FilledInDuringResolution] public ModuleSignature Signature; // filled in topological order.
public virtual ModuleSignature AccessibleSignature(bool ignoreExports) {
Expand Down Expand Up @@ -375,6 +375,27 @@ public override bool IsEssentiallyEmpty() {
// A module or import is considered "essentially empty" to its parents, but the module is going to be resolved by itself.
return true;
}

protected override string GetTriviaContainingDocstring() {
IToken candidate = null;
var tokens = OwnedTokens.Any() ?
OwnedTokens :
PreResolveChildren.Any() ? PreResolveChildren.First().OwnedTokens : Enumerable.Empty<IToken>();
foreach (var token in tokens) {
if (token.val == "{") {
candidate = token.Prev;
if (candidate.TrailingTrivia.Trim() != "") {
return candidate.TrailingTrivia;
}
}
}

if (candidate == null && EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}
// Represents module X { ... }
public class LiteralModuleDecl : ModuleDecl, ICanFormat {
Expand Down Expand Up @@ -587,6 +608,14 @@ public bool SetIndent(int indentBefore, TokenNewIndentCollector formatter) {

return true;
}

protected override string GetTriviaContainingDocstring() {
if (Tok.TrailingTrivia.Trim() != "") {
return Tok.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

public class ExportSignature : TokenNode, IHasUsages {
Expand Down Expand Up @@ -1349,7 +1378,7 @@ public override IEnumerable<AssumptionDescription> Assumptions() {
}
}

public class ClassDecl : TopLevelDeclWithMembers, RevealableTypeDecl, ICanFormat {
public class ClassDecl : TopLevelDeclWithMembers, RevealableTypeDecl, ICanFormat, IHasDocstring {
public override string WhatKind { get { return "class"; } }
public override bool CanBeRevealed() { return true; }
[FilledInDuringResolution] public bool HasConstructor; // filled in (early) during resolution; true iff there exists a member that is a Constructor
Expand Down Expand Up @@ -1472,6 +1501,24 @@ public virtual bool SetIndent(int indentBefore, TokenNewIndentCollector formatte

return true;
}

protected override string GetTriviaContainingDocstring() {
IToken candidate = null;
foreach (var token in OwnedTokens) {
if (token.val == "{") {
candidate = token.Prev;
if (candidate.TrailingTrivia.Trim() != "") {
return candidate.TrailingTrivia;
}
}
}

if (candidate == null && EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

public class DefaultClassDecl : ClassDecl {
Expand Down Expand Up @@ -1524,7 +1571,7 @@ public ArrowTypeDecl(List<TypeParameter> tps, Function req, Function reads, Modu
}
}

public abstract class DatatypeDecl : TopLevelDeclWithMembers, RevealableTypeDecl, ICallable, ICanFormat {
public abstract class DatatypeDecl : TopLevelDeclWithMembers, RevealableTypeDecl, ICallable, ICanFormat, IHasDocstring {
public override bool CanBeRevealed() { return true; }
public readonly List<DatatypeCtor> Ctors;

Expand Down Expand Up @@ -1682,6 +1729,16 @@ public bool SetIndent(int indent, TokenNewIndentCollector formatter) {

return true;
}

protected override string GetTriviaContainingDocstring() {
foreach (var token in OwnedTokens) {
if (token.val == "=" && token.TrailingTrivia.Trim() != "") {
return token.TrailingTrivia;
}
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

public class IndDatatypeDecl : DatatypeDecl {
Expand Down Expand Up @@ -1772,7 +1829,7 @@ public Type CreateType(List<Type> typeArgs) {
}
}

public class DatatypeCtor : Declaration, TypeParameter.ParentType {
public class DatatypeCtor : Declaration, TypeParameter.ParentType, IHasDocstring {
public readonly bool IsGhost;
public readonly List<Formal> Formals;
[ContractInvariantMethod]
Expand Down Expand Up @@ -1808,6 +1865,14 @@ public string FullName {
return "#" + EnclosingDatatype.FullName + "." + Name;
}
}

protected override string GetTriviaContainingDocstring() {
if (EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

/// <summary>
Expand Down Expand Up @@ -1880,6 +1945,7 @@ public CallableWrapper(ICallable callable, bool isGhostContext)

protected ICallable cwInner => (ICallable)inner;
public IToken Tok => cwInner.Tok;

public string WhatKind => cwInner.WhatKind;
public string NameRelativeToModule => cwInner.NameRelativeToModule;
public Specification<Expression> Decreases => cwInner.Decreases;
Expand All @@ -1903,6 +1969,10 @@ public class DontUseICallable : ICallable {
public string FullSanitizedName { get { throw new cce.UnreachableException(); } }
public bool AllowsNontermination { get { throw new cce.UnreachableException(); } }
public IToken Tok { get { throw new cce.UnreachableException(); } }
public string GetDocstring(DafnyOptions options) {
throw new cce.UnreachableException();
}

public string NameRelativeToModule { get { throw new cce.UnreachableException(); } }
public Specification<Expression> Decreases { get { throw new cce.UnreachableException(); } }
public bool InferredDecreases {
Expand Down Expand Up @@ -1939,7 +2009,7 @@ public NoContext(ModuleDefinition module) {
public bool AllowsAllocation => true;
}

public class OpaqueTypeDecl : TopLevelDeclWithMembers, TypeParameter.ParentType, RevealableTypeDecl, ICanFormat {
public class OpaqueTypeDecl : TopLevelDeclWithMembers, TypeParameter.ParentType, RevealableTypeDecl, ICanFormat, IHasDocstring {
public override string WhatKind { get { return "opaque type"; } }
public override bool CanBeRevealed() { return true; }
public readonly TypeParameter.TypeParameterCharacteristics Characteristics;
Expand Down Expand Up @@ -2020,6 +2090,25 @@ public bool SetIndent(int indentBefore, TokenNewIndentCollector formatter) {

return true;
}

protected override string GetTriviaContainingDocstring() {
IToken openingBlock = null;
foreach (var token in OwnedTokens) {
if (token.val == "{") {
openingBlock = token;
}
}

if (openingBlock != null && openingBlock.Prev.TrailingTrivia.Trim() != "") {
return openingBlock.Prev.TrailingTrivia;
}

if (openingBlock == null && EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

public interface RedirectingTypeDecl : ICallable {
Expand Down Expand Up @@ -2091,7 +2180,7 @@ public interface RevealableTypeDecl {
TypeDeclSynonymInfo SynonymInfo { get; set; }
}

public class NewtypeDecl : TopLevelDeclWithMembers, RevealableTypeDecl, RedirectingTypeDecl {
public class NewtypeDecl : TopLevelDeclWithMembers, RevealableTypeDecl, RedirectingTypeDecl, IHasDocstring {
public override string WhatKind { get { return "newtype"; } }
public override bool CanBeRevealed() { return true; }
public Type BaseType { get; set; } // null when refining
Expand Down Expand Up @@ -2177,9 +2266,27 @@ public override bool IsEssentiallyEmpty() {
// A "newtype" is not considered "essentially empty", because it always has a parent type to be resolved.
return false;
}

protected override string GetTriviaContainingDocstring() {
IToken candidate = null;
foreach (var token in OwnedTokens) {
if (token.val == "{") {
candidate = token.Prev;
if (candidate.TrailingTrivia.Trim() != "") {
return candidate.TrailingTrivia;
}
}
}

if (candidate == null && EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

public abstract class TypeSynonymDeclBase : TopLevelDecl, RedirectingTypeDecl {
public abstract class TypeSynonymDeclBase : TopLevelDecl, RedirectingTypeDecl, IHasDocstring {
public override string WhatKind { get { return "type synonym"; } }
public TypeParameter.TypeParameterCharacteristics Characteristics; // the resolver may change the .EqualitySupport component of this value from Unspecified to InferredRequired (for some signatures that may immediately imply that equality support is required)
public bool SupportsEquality {
Expand Down Expand Up @@ -2273,6 +2380,27 @@ public override bool IsEssentiallyEmpty() {
// A synonym/subset type is not considered "essentially empty", because it always has a parent type to be resolved.
return false;
}



protected override string GetTriviaContainingDocstring() {
IToken openingBlock = null;
foreach (var token in OwnedTokens) {
if (token.val == "{") {
openingBlock = token;
}
}

if (openingBlock != null && openingBlock.Prev.TrailingTrivia.Trim() != "") {
return openingBlock.Prev.TrailingTrivia;
}

if (openingBlock == null && EndToken.TrailingTrivia.Trim() != "") {
return EndToken.TrailingTrivia;
}

return GetTriviaContainingDocstringFromStartTokeOrNull();
}
}

public class TypeSynonymDecl : TypeSynonymDeclBase, RevealableTypeDecl {
Expand Down
Loading