Skip to content

Commit 6cc9c51

Browse files
committed
repl improvements
1 parent e34b8cb commit 6cc9c51

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

src/main/kotlin/novah/cli/command/ReplCommand.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ReplCommand : CliktCommand(name = "repl", help = "start a repl for the cur
4242
input = input.drop(2).trimStart()
4343
def = true
4444
while (true) {
45-
val more = prompt("", promptSuffix = "", default = "")
45+
val more = prompt(">>", promptSuffix = " ", default = "")
4646
if (more == null || more == "") break
4747
input += "\n$more"
4848
}

src/main/kotlin/novah/cli/repl/Backend.kt

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package novah.cli.repl
33
import novah.data.Err
44
import novah.data.Ok
55
import novah.data.Result
6+
import novah.frontend.error.CompilerProblem
67
import novah.main.*
78
import java.io.File
89
import java.io.IOException
@@ -12,14 +13,15 @@ import kotlin.io.path.Path
1213

1314
class Backend(
1415
private val echo: (String) -> Unit,
15-
private val classpath: String,
16-
private val sourcepath: String,
16+
private val classpath: String?,
17+
private val sourcepath: String?,
1718
output: String
1819
) {
1920

2021
private var imports = LinkedList<String>()
2122
private var code = LinkedList<String>()
2223
private var eval = "()"
24+
private var replType: String? = ""
2325

2426
private val folder = File(output)
2527
private val options = Options(verbose = false, devMode = true)
@@ -37,16 +39,18 @@ class Backend(
3739
private fun clear() {
3840
imports.clear()
3941
code.clear()
42+
eval = "()"
4043
}
4144

4245
fun help() = """
43-
:help -> shows this help
44-
:clear -> resets the repl
45-
:q -> quits the repl
46-
:> -> starts a definition (value or function). Won't stop until an empty new line is reached
47-
:test <suite> -> runs the specified test suite using novah.test.runTests
46+
:help -> shows this help
47+
:clear -> resets the repl
48+
:q, ctrl+c -> quits the repl
49+
:> -> starts a definition. Won't stop until an empty new line is reached
50+
:test <suite> -> runs the specified test suite using novah.test.runTests
51+
:t, :type <exp> -> shows the type of the given expression
4852
import <module> -> adds an import to the repl
49-
<expression> -> evaluates the expression
53+
<expression> -> evaluates the expression
5054
""".trimIndent()
5155

5256
fun execute(input: String, def: Boolean = false) {
@@ -67,13 +71,20 @@ class Backend(
6771
echo(res.err)
6872
}
6973
}
70-
} else if (input.startsWith(":test")) {
74+
} else if (input.startsWith(":test ")) {
7175
val suite = input.replace(Regex("^:test\\s+"), "")
7276
eval = "runTests [$suite]"
7377
when (val res = build()) {
7478
is Ok -> run()
7579
is Err -> echo(res.err)
7680
}
81+
} else if (input.startsWith(":type ") || input.startsWith(":t ")) {
82+
val exp = input.replace(Regex("^:t\\w*\\s+"), "")
83+
eval = exp
84+
when (val res = build()) {
85+
is Ok -> echo("$exp : $replType")
86+
is Err -> echo(res.err)
87+
}
7788
} else if (input.startsWith(":")) {
7889
echo("error: invalid command `$input`")
7990
} else if (def) {
@@ -99,37 +110,39 @@ class Backend(
99110
}
100111

101112
private fun build(): Result<FullModuleEnv, String> {
102-
val scode = """module repl1
113+
val scode = """module _repl1
103114
|
104115
|${imports.joinToString("\n\n")}
105116
|
106117
|${code.joinToString("\n\n")}
107118
|
119+
|_repl_res = $eval
120+
|
108121
|pub
109122
|main : Array String -> Unit
110-
|main _ =
111-
| let _res = $eval
112-
| println _res
123+
|main _ = println _repl_res
113124
""".trimMargin()
114125

115-
val sources = sequenceOf(Source.SString(Path("repl1"), scode))
126+
val sources = sequenceOf(Source.SString(Path("_repl1"), scode))
116127
val env = Environment(classpath, sourcepath, options)
117128
return try {
118129
env.parseSources(sources)
119130
env.generateCode(folder)
120131

121-
val errs = env.errors().filter { it.isErrorOrFatal() }
132+
val errs = env.errors().filter(::errFilter)
122133
if (errs.isNotEmpty()) {
123134
Err(errs.joinToString("\n\n") { it.msg })
124135
} else {
125-
Ok(env.modules()["repl1"]!!)
136+
val environment = env.modules()["_repl1"]!!
137+
replType = environment.env.decls["_repl_res"]?.type?.show(typeVarsMap = environment.typeVarsMap)
138+
Ok(environment)
126139
}
127140
} catch (_: CompilationError) {
128-
env.errors().filter { it.isErrorOrFatal() }.joinToString("\n\n") { it.msg }.let { Err(it) }
141+
env.errors().filter(::errFilter).joinToString("\n\n") { it.msg }.let { Err(it) }
129142
}
130143
}
131144

132-
val pbuilder = ProcessBuilder("java", "-cp", ".", "repl1.\$Module")
145+
private val pbuilder = ProcessBuilder("java", "-cp", ".", "_repl1.\$Module")
133146
.directory(folder)
134147
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
135148
.redirectError(ProcessBuilder.Redirect.INHERIT)
@@ -144,4 +157,9 @@ class Backend(
144157
1
145158
}
146159
}
160+
161+
companion object {
162+
private fun errFilter(err: CompilerProblem): Boolean =
163+
err.isErrorOrFatal() && err.msg != "Undefined variable _repl_res."
164+
}
147165
}

src/main/kotlin/novah/main/Compiler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import java.nio.file.Path
2424

2525
class Compiler(private val sources: Sequence<Source>, classpath: String?, sourcepath: String?, opts: Options) {
2626

27-
private val env = Environment(classpath, sourcepath, opts)
27+
val env = Environment(classpath, sourcepath, opts)
2828

2929
fun compile(): Map<String, FullModuleEnv> = env.parseSources(sources)
3030

src/test/kotlin/novah/frontend/TestUtil.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ object TestUtil {
8080
return Compiler(sources, null, null, Options(verbose, devMode))
8181
}
8282

83-
fun compileCode(code: String, verbose: Boolean = false): FullModuleEnv {
83+
fun compileCode(code: String, verbose: Boolean = false, moduleName: String = "test"): FullModuleEnv {
8484
val compiler = compilerForCode(code, verbose)
8585
compiler.run(File("."), dryRun = true)
8686
if (compiler.errors().isNotEmpty()) {
8787
compiler.errors().forEach { println(it.formatToConsole()) }
8888
}
89-
return compiler.getModules()["test"]!!
89+
return compiler.getModules()[moduleName]!!
9090
}
9191

9292
fun compileAndOptimizeCode(code: String, verbose: Boolean = false): OModule {

0 commit comments

Comments
 (0)