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

Add Support for Documenting Modules #1900

Merged
merged 5 commits into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Enso Next

## Interpreter/Runtime

- Added support for documenting modules directly
([#1900](https://github.com/enso-org/enso/pull/1900)).

# Enso 0.2.16 (2021-07-23)

## Interpreter/Runtime
Expand Down
4 changes: 4 additions & 0 deletions docs/syntax/comments.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ for more information). By way of example:
until I unindent again.
```

Documentation blocks are associated with the _next_ entity in the file, except
for if they occur as the _very first_ entity in the file. In this case, they are
treated as the module's documentation.

Documentation comments are _not_ allowed inside textual interpolations.

The tool that generates this documentation aims to be fairly robust, and tries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ object Suggestions {

val module: Suggestion.Module = Suggestion.Module(
module = "Test.Main",
documentation = None,
documentationHtml = None
documentation = Some("Module doc"),
documentationHtml = Some("<html></html>")
)

val atom: Suggestion.Atom = Suggestion.Atom(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,13 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
}

val builder: TreeBuilder = Vector.newBuilder
builder += Tree.Node(buildModule(module), Vector())
builder += Tree.Node(
buildModule(
module,
ir.getMetadata(DocumentationComments).map(_.documentation)
),
Vector()
)

Tree.Root(
go(builder, Scope(ir.children, ir.location))
Expand Down Expand Up @@ -205,11 +211,14 @@ final class SuggestionBuilder[A: IndexedSource](val source: A) {
}

/** Build an atom suggestion representing a module. */
private def buildModule(module: QualifiedName): Suggestion =
private def buildModule(
module: QualifiedName,
doc: Option[String]
): Suggestion =
Suggestion.Module(
module = module.toString,
documentation = None,
documentationHtml = None,
documentation = doc,
documentationHtml = doc.map(DocParserWrapper.runOnPureDoc),
reexport = None
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import org.enso.compiler.pass.IRPass
import org.enso.compiler.pass.desugar.{ComplexType, GenerateMethodBodies}

/** Associates doc comments with the commented entities as metadata.
*
* If the first module definition is a documentation comment, it is treated as
* the module documentation.
*
* This pass has no configuration.
*
Expand Down Expand Up @@ -159,7 +162,12 @@ case object DocumentationComments extends IRPass {
* @return `ir`, with any doc comments associated with nodes as metadata
*/
private def resolveModule(ir: IR.Module): IR.Module = {
val newBindings = resolveList(ir.bindings).map(resolveDefinition)
val newBindings = (ir.bindings.headOption match {
case Some(doc: IR.Comment.Documentation) =>
ir.updateMetadata(this -->> Doc(doc.doc))
resolveList(ir.bindings.drop(1))
case _ => resolveList(ir.bindings)
}).map(resolveDefinition)
ir.copy(bindings = newBindings)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.enso.compiler.test.context

import java.util.UUID

import org.enso.compiler.Passes
import org.enso.compiler.context.{
FreshNameSupply,
Expand All @@ -11,10 +9,13 @@ import org.enso.compiler.context.{
import org.enso.compiler.core.IR
import org.enso.compiler.pass.PassManager
import org.enso.compiler.test.CompilerTest
import org.enso.docs.generator.DocParserWrapper
import org.enso.pkg.QualifiedName
import org.enso.polyglot.Suggestion
import org.enso.polyglot.data.Tree

import java.util.UUID

class SuggestionBuilderTest extends CompilerTest {

implicit val passManager: PassManager = new Passes(defaultConfig).passManager
Expand All @@ -29,6 +30,16 @@ class SuggestionBuilderTest extends CompilerTest {
),
Vector()
)
private val moduleDoc = "Module doc"
private val DoccedModuleNode = Tree.Node(
Suggestion.Module(
module = Module.toString,
documentation = Some(" " + moduleDoc),
documentationHtml = Some(DocParserWrapper.runOnPureDoc(moduleDoc)),
reexport = None
),
Vector()
)

private def htmlDoc(inner: String): String = {
"<html><body><div class=\"doc\" style=\"font-size: 13px;\"><div><div class=\"\">" + inner + "</div></div></div></body></html>"
Expand Down Expand Up @@ -68,13 +79,15 @@ class SuggestionBuilderTest extends CompilerTest {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""## The foo
"""## Module doc
|
|## The foo
|foo = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
DoccedModuleNode,
Tree.Node(
Suggestion.Method(
externalId = None,
Expand All @@ -98,14 +111,16 @@ class SuggestionBuilderTest extends CompilerTest {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""## The foo
"""## Module doc
|
|## The foo
|foo : Number
|foo = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
DoccedModuleNode,
Tree.Node(
Suggestion.Method(
externalId = None,
Expand Down Expand Up @@ -1084,13 +1099,15 @@ class SuggestionBuilderTest extends CompilerTest {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""## My sweet type
"""## Module doc
|
|## My sweet type
|type MyType a b""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
DoccedModuleNode,
Tree.Node(
Suggestion.Atom(
externalId = None,
Expand Down Expand Up @@ -1207,7 +1224,9 @@ class SuggestionBuilderTest extends CompilerTest {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""## When in doubt
"""## Module doc
|
|## When in doubt
|type Maybe
| ## Nothing here
| type Nothing
Expand All @@ -1217,7 +1236,7 @@ class SuggestionBuilderTest extends CompilerTest {

build(code, module) shouldEqual Tree.Root(
Vector(
ModuleNode,
DoccedModuleNode,
Tree.Node(
Suggestion.Atom(
externalId = None,
Expand Down Expand Up @@ -1808,6 +1827,47 @@ class SuggestionBuilderTest extends CompilerTest {
)
}

"build module with documentation" in {
implicit val moduleContext: ModuleContext = freshModuleContext

val code =
"""## Module doc
|
|## The foo
|foo = 42""".stripMargin
val module = code.preprocessModule

build(code, module) shouldEqual Tree.Root(
Vector(
Tree.Node(
Suggestion.Module(
"Unnamed.Test",
Some(" Module doc"),
Some(
"<html><body><div class=\"doc\" style=\"font-size: 13px;\"><div><div class=\"\"><p>Module doc</p></div></div></div></body></html>"
iamrecursion marked this conversation as resolved.
Show resolved Hide resolved
),
None
),
Vector()
),
Tree.Node(
Suggestion.Method(
externalId = None,
module = "Unnamed.Test",
name = "foo",
arguments = Seq(
Suggestion.Argument("this", "Unnamed.Test", false, false, None)
),
selfType = "Unnamed.Test",
returnType = SuggestionBuilder.Any,
documentation = Some(" The foo"),
documentationHtml = Some(htmlDoc("<p>The foo</p>"))
),
Vector()
)
)
)
}
}

private def build(source: String, ir: IR.Module): Tree.Root[Suggestion] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ class FunctionBindingTest extends CompilerTest {

"retain documentation comments and annotations associated with them" in {
val ir =
s"""
s"""## Module doc
|
|## My documentation for this conversion.
|@My_Annotation
|My_Type.$from (that : Value) = that
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,24 +80,47 @@ class DocumentationCommentsTest extends CompilerTest with Inside {
// === The Tests ============================================================

"Documentation comments in the top scope" should {
implicit val moduleContext: ModuleContext = mkModuleContext
val ir =
"""
|## My module documentation
|
|## This is doc for My_Atom
|type My_Atom a b c
|
|## This is doc for my_method
|MyAtom.my_method x = x + this
|
|""".stripMargin.preprocessModule.resolve

"be associated with atoms and methods" in {
ir.bindings.length shouldEqual 2
ir.bindings(0) shouldBe an[IR.Module.Scope.Definition.Atom]
ir.bindings(1) shouldBe an[IR.Module.Scope.Definition.Method]

getDoc(ir.bindings(0)) shouldEqual " This is doc for My_Atom"
getDoc(ir.bindings(1)) shouldEqual " This is doc for my_method"
}

"be associated with modules" in {
getDoc(ir) shouldEqual " My module documentation"
}

"not be associated with modules when not the first entity" in {
implicit val moduleContext: ModuleContext = mkModuleContext
val ir =
"""
"""from Standard.Base import al
|
|## My module documentation
|
|## This is doc for My_Atom
|type My_Atom a b c
|
|## This is doc for my_method
|MyAtom.my_method x = x + this
|
|""".stripMargin.preprocessModule.resolve

ir.bindings.length shouldEqual 2
ir.bindings(0) shouldBe an[IR.Module.Scope.Definition.Atom]
ir.bindings(1) shouldBe an[IR.Module.Scope.Definition.Method]

getDoc(ir.bindings(0)) shouldEqual " This is doc for My_Atom"
getDoc(ir.bindings(1)) shouldEqual " This is doc for my_method"
ir.getMetadata(DocumentationComments) should not be defined
}
}

Expand Down Expand Up @@ -174,7 +197,8 @@ class DocumentationCommentsTest extends CompilerTest with Inside {
implicit val moduleContext: ModuleContext = mkModuleContext
"assign docs to all entities" in {
val ir =
"""
"""## My Module documentation
|
|## the type Foo
|type Foo
| ## the constructor Bar
Expand Down Expand Up @@ -212,7 +236,9 @@ class DocumentationCommentsTest extends CompilerTest with Inside {
buildModuleContext(freshNameSupply = Some(new FreshNameSupply))

val module =
"""## The foo
"""## Module docs
|
|## The foo
|foo : Integer
|foo = 42""".stripMargin.preprocessModule
val foo = module.bindings.head
Expand All @@ -227,7 +253,8 @@ class DocumentationCommentsTest extends CompilerTest with Inside {
buildModuleContext(freshNameSupply = Some(new FreshNameSupply))

val ir =
"""
"""## Module Docs
|
|## the type Foo
|type Foo
| ## the constructor Bar
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ class GenerateDocumentationTest extends CompilerTest with Inside {
"be associated with atoms and methods" in {
implicit val moduleContext: ModuleContext = mkModuleContext
val ir =
"""
"""## Module Docs
|
|## This is doc for My_Atom
|type My_Atom a b c
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ class TypeSignaturesTest extends CompilerTest {

"reattach documentation to method definitions" in {
val ir =
"""## My bar
"""## Module doc
|
|## My bar
|bar : Number -> Number -> Number
|bar a b = a + b
|""".stripMargin.preprocessModule.resolve
Expand Down