Skip to content

Commit 0decaa0

Browse files
marvinbornerBinderDavidtimsueberkrueb
authored
Generate documentation (#930)
- annotate doc comments in Tree - right now this is only implemented as a POC (and breaks some Effekt code), we should combine this with the current efforts of annotating the tree with positions and types - add flags `show-documentation` and `write-documentation` for generating JSONs of documented nodes - these JSONs can be later used to generate API documentation for the website --------- Co-authored-by: David Binder <[email protected]> Co-authored-by: Tim Süberkrüb <[email protected]>
1 parent cf2c47c commit 0decaa0

25 files changed

+1036
-202
lines changed

effekt/jvm/src/main/scala/effekt/Driver.scala

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kiama.parsing.ParseResult
1111
import kiama.util.{ IO, Source }
1212
import effekt.util.messages.{ BufferedMessaging, CompilerPanic, EffektError, EffektMessaging, FatalPhaseError }
1313
import effekt.util.paths.file
14-
import effekt.util.{ AnsiColoredMessaging, MarkdownSource, getOrElseAborting }
14+
import effekt.util.{ JSONDocumentationGenerator, AnsiColoredMessaging, MarkdownSource, getOrElseAborting }
1515

1616
import scala.sys.process.Process
1717

@@ -66,8 +66,9 @@ trait Driver extends kiama.util.Compiler[EffektConfig, EffektError] { outer =>
6666
}
6767
}
6868

69-
// we are in one of three exclusive modes: LSPServer, Compile, Run
70-
if (config.server()) { compiler.runFrontend(src) }
69+
// we are in one of four exclusive modes: Documenter, LSPServer, Compile, Run
70+
if (config.documenter()) { documenter(source, config)(context) }
71+
else if (config.server()) { compiler.runFrontend(src) }
7172
else if (config.interpret()) { compile() foreach runner.eval }
7273
else if (config.build()) { compile() foreach runner.build }
7374
else if (config.compile()) { compile() }
@@ -126,6 +127,25 @@ trait Driver extends kiama.util.Compiler[EffektConfig, EffektError] { outer =>
126127
}
127128
}
128129

130+
def generateDocumentation(ast: ModuleDecl, source: Source)(using C: Context): String =
131+
JSONDocumentationGenerator(ast, source.name).content
132+
133+
def showDocumentation(ast: ModuleDecl, source: Source)(using C: Context): Unit =
134+
println(generateDocumentation(ast, source))
135+
136+
def writeDocumentation(ast: ModuleDecl, source: Source, output: String)(using C: Context): Unit =
137+
val name = source.name.split("/").last + ".json"
138+
IO.createFile((output / name).unixPath, generateDocumentation(ast, source))
139+
140+
def documenter(source: Source, config: EffektConfig)(implicit C: Context): Unit =
141+
C.compiler.runFrontend(source)
142+
val astOpt = C.compiler.getAST(source)
143+
if (astOpt.isEmpty) return
144+
145+
val out = config.outputPath().getAbsolutePath
146+
if (config.writeDocumentation()) writeDocumentation(astOpt.get, source, out)
147+
if (config.showDocumentation()) showDocumentation(astOpt.get, source)
148+
129149
/**
130150
* Overridden in [[Server]] to also publish core and js compilation results to VSCode
131151
*/

effekt/jvm/src/main/scala/effekt/EffektConfig.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,24 @@ class EffektConfig(args: Seq[String]) extends REPLConfig(args.takeWhile(_ != "--
155155
group = debugging
156156
)
157157

158+
val showDocumentation: ScallopOption[Boolean] = toggle(
159+
"show-documentation",
160+
descrYes = "Show all documented statements as a JSON",
161+
default = Some(false),
162+
noshort = true,
163+
prefix = "no-",
164+
group = debugging
165+
)
166+
167+
val writeDocumentation: ScallopOption[Boolean] = toggle(
168+
"write-documentation",
169+
descrYes = "Write all documented statements to a JSON in the output directory",
170+
default = Some(false),
171+
noshort = true,
172+
prefix = "no-",
173+
group = debugging
174+
)
175+
158176
val time: ScallopOption[String] = choice(
159177
choices = Seq("text", "json"),
160178
name = "time",
@@ -232,6 +250,8 @@ class EffektConfig(args: Seq[String]) extends REPLConfig(args.takeWhile(_ != "--
232250

233251
def repl(): Boolean = filenames().isEmpty && !server() && !compile()
234252

253+
def documenter(): Boolean = showDocumentation() || writeDocumentation()
254+
235255
def timed(): Boolean = time.isSupplied && !server()
236256

237257
validateFilesIsDirectory(includePath)

effekt/jvm/src/main/scala/effekt/Repl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
316316
val fullSpan = Span(source, 0, source.content.length, origin = Origin.Synthesized)
317317
ModuleDecl("interactive", includes,
318318
definitions :+ FunDef(IdDef("main", fakeSpan), Many.empty(fakeSpan), Many.empty(fakeSpan), Many.empty(fakeSpan), Maybe.None(fakeSpan),
319-
body, fullSpan), fullSpan)
319+
body, None, fullSpan), None, fullSpan)
320320
}
321321

322322
def makeEval(source: Source, expr: Term): ModuleDecl = {

effekt/jvm/src/test/scala/effekt/LSPTests.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,9 +1188,11 @@ class LSPTests extends FunSuite {
11881188
| Span(StringSource(def main() = <>, file://test.effekt), 13, 15, Real())
11891189
| )
11901190
| ),
1191+
| None(),
11911192
| Span(StringSource(def main() = <>, file://test.effekt), 0, 15, Real())
11921193
| )
11931194
| ),
1195+
| None(),
11941196
| Span(StringSource(def main() = <>, file://test.effekt), 0, 15, Real())
11951197
|)""".stripMargin
11961198

@@ -1244,6 +1246,7 @@ class LSPTests extends FunSuite {
12441246
| List(foo_whatever)
12451247
|)""".stripMargin
12461248

1249+
12471250
val receivedIRContent = client.receivedIR()
12481251
assertEquals(receivedIRContent.length, 1)
12491252
assertIREquals(receivedIRContent.head.content, expectedIRContents)

0 commit comments

Comments
 (0)