From 6ceae48b48dbd3c615278fb70d566266e25cfe3e Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Thu, 9 Apr 2026 01:23:25 +0200 Subject: [PATCH 1/2] Add :compile and :watch commands to REPL --- effekt/jvm/src/main/scala/effekt/Repl.scala | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/effekt/jvm/src/main/scala/effekt/Repl.scala b/effekt/jvm/src/main/scala/effekt/Repl.scala index f47263429c..b789a1ba5f 100644 --- a/effekt/jvm/src/main/scala/effekt/Repl.scala +++ b/effekt/jvm/src/main/scala/effekt/Repl.scala @@ -10,6 +10,8 @@ import effekt.util.Version.effektVersion import kiama.util.{Console, REPL, Range, Source, StringSource} import kiama.parsing.{NoSuccess, ParseResult, Success, Input} +import java.nio.file.Paths + class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] { private implicit lazy val context: Context with IOModuleDB = driver.context @@ -83,6 +85,8 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] { |:status show the current REPL environment |:type (:t) show the type of an expression |:imports list all current imports + |:compile compile program with current flags + |:watch watch path and all its dependencies |:reset reset the REPL state |:help (:h) print this help message |:quit (:q) quit this REPL""".stripMargin @@ -115,6 +119,34 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] { } } + /** + * Command `:compile` -- compiles given file with current effekt config + */ + def compile(filename: String, config: EffektConfig): Unit = + driver.compileFile(filename, config) + + /** + * Command `:watch` -- watches the given file and compiles with current effekt config + */ + def watch(filename: String, config: EffektConfig): Unit = { + var files = List(filename) + var timestamps = Map.empty[String, Long] + while (!Thread.currentThread().isInterrupted) { + Thread.sleep(100) + timestamps = files.map { f => + val current = Paths.get(f).toFile.lastModified + val last = timestamps.getOrElse(f, 0L) + if (current != last && last != 0L) { + println(s"\n--- ${f} changed: running ${filename} ---") + driver.compileFile(filename, config) + files = driver.sources.keys.toList // TODO: doesn't include dependencies + // println(s"listening on ${files}") + } + f -> current + }.toMap + } + } + /** * Command `:type` -- runs the frontend (and typechecker) on the given expression */ @@ -163,6 +195,14 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] { case Command(":quit", _) | Command(":q", _) => None + case Command(cmd, filename) if cmd == ":compile" || cmd == ":c" => + compile(filename, config) + Some(config) + + case Command(cmd, filename) if cmd == ":watch" || cmd == ":w" => + watch(filename, config) + Some(config) + case Command(cmd, expr) if cmd == ":type" || cmd == ":t" => typecheck(StringSource(expr, source.name), config) Some(config) From 0dd7da730620cd262482481e1b988f473834fadc Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Fri, 10 Apr 2026 13:41:34 +0200 Subject: [PATCH 2/2] Collect some dependencies at least --- effekt/jvm/src/main/scala/effekt/Driver.scala | 8 ++++++++ effekt/jvm/src/main/scala/effekt/Repl.scala | 1 + 2 files changed, 9 insertions(+) diff --git a/effekt/jvm/src/main/scala/effekt/Driver.scala b/effekt/jvm/src/main/scala/effekt/Driver.scala index 745ba06532..9f52fb1d62 100644 --- a/effekt/jvm/src/main/scala/effekt/Driver.scala +++ b/effekt/jvm/src/main/scala/effekt/Driver.scala @@ -177,4 +177,12 @@ trait Driver { outer => config.output().emitln(e.getMessage) } } + + def collectDependencies(filename: String, config: EffektConfig, encoding: String = "UTF-8")(implicit C: Context): List[String] = { + val source = FileSource(filename, encoding) + C.compiler.runFrontend(source) + val moduleOpt = C.compiler.getAST(source) + if (moduleOpt.isEmpty) return Nil + moduleOpt.get.includes.map(_.path) + } } diff --git a/effekt/jvm/src/main/scala/effekt/Repl.scala b/effekt/jvm/src/main/scala/effekt/Repl.scala index b789a1ba5f..473a281e4c 100644 --- a/effekt/jvm/src/main/scala/effekt/Repl.scala +++ b/effekt/jvm/src/main/scala/effekt/Repl.scala @@ -139,6 +139,7 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] { if (current != last && last != 0L) { println(s"\n--- ${f} changed: running ${filename} ---") driver.compileFile(filename, config) + println(driver.collectDependencies(filename, config)) files = driver.sources.keys.toList // TODO: doesn't include dependencies // println(s"listening on ${files}") }