diff --git a/src/main/kotlin/org/yakou/lang/compilation/CompilationSession.kt b/src/main/kotlin/org/yakou/lang/compilation/CompilationSession.kt index f4e8b2e..17cafa3 100644 --- a/src/main/kotlin/org/yakou/lang/compilation/CompilationSession.kt +++ b/src/main/kotlin/org/yakou/lang/compilation/CompilationSession.kt @@ -14,7 +14,7 @@ import org.yakou.lang.util.Constants class CompilationSession(val preference: AbstractPreference) { val table: Table = Table() private val sourceFile: File? = preference.sourceFile - private val unitProcessResult: MutableMap> = mutableMapOf() + private val unitProcessResult: MutableMap> = mutableMapOf() fun compile() { if (sourceFile == null || !sourceFile.exists()) { @@ -32,10 +32,7 @@ class CompilationSession(val preference: AbstractPreference) { val statusPadding = if (preference.enableColor) 10 else 1 for ((unitName, result) in unitProcessResult) { - val status = when (result.first) { - true -> if (preference.useAscii) "V" else "✔" - false -> if (preference.useAscii) "X" else "✖" - } + val status = result.first.stateLiteral println( "%-${unitNamePadding}s %s status: %-${statusPadding}s | elapsed time: %d ms".format( @@ -44,14 +41,18 @@ class CompilationSession(val preference: AbstractPreference) { if (preference.enableColor) { Ansi.colorize( status, - if (result.first) Attribute.GREEN_BACK() else Attribute.RED_BACK(), - Attribute.BLACK_TEXT() + when (result.first) { + UnitProcessResult.PASSED -> Attribute.GREEN_BACK() + UnitProcessResult.FAILED -> Attribute.RED_BACK() + UnitProcessResult.SKIPPED -> Attribute.BRIGHT_BLACK_BACK() + }, + Attribute.BLACK_TEXT(), ) } else { status }, - result.second - ) + result.second, + ), ) } } @@ -65,52 +66,63 @@ class CompilationSession(val preference: AbstractPreference) { // PHASE I: LEXICAL ANALYSIS unitProcessResult["lexical analysis"] = measureTime { - compilationUnits.all(CompilationUnit::lex) + compilationUnits.processAll(CompilationUnit::lex) } - if (!unitProcessResult["lexical analysis"]!!.first) { + if (!unitProcessResult["lexical analysis"]!!.first.ok()) { return } // PHASE II: SYNTACTIC ANALYSIS unitProcessResult["syntactic analysis"] = measureTime { - compilationUnits.all(CompilationUnit::parse) + compilationUnits.processAll(CompilationUnit::parse) } - if (!unitProcessResult["syntactic analysis"]!!.first) { + if (!unitProcessResult["syntactic analysis"]!!.first.ok()) { return } - // PHASE III: TYPE BINDING - unitProcessResult["type binding"] = measureTime { - val declarationBinding = compilationUnits.all(CompilationUnit::bind) - - declarationBinding && compilationUnits.all(CompilationUnit::postBind) + // PHASE III: DECLARATION BINDING + unitProcessResult["declaration binding"] = measureTime { + compilationUnits.processAll(CompilationUnit::bind) } - if (!unitProcessResult["type binding"]!!.first) { + if (!unitProcessResult["declaration binding"]!!.first.ok()) { return } - // PHASE III: SEMANTIC CHECKING - unitProcessResult["semantic checking"] = measureTime { - compilationUnits.all(CompilationUnit::check) + // PHASE IV: TYPE BINDING + unitProcessResult["type binding"] = measureTime { + compilationUnits.processAll(CompilationUnit::postBind) } - if (!unitProcessResult["semantic checking"]!!.first) { + if (!unitProcessResult["type binding"]!!.first.ok()) { return } - // PHASE IV: CODE OPTIMIZATION - unitProcessResult["code optimization"] = measureTime { - compilationUnits.all(CompilationUnit::optimize) + // PHASE V: SEMANTIC CHECKING + unitProcessResult["semantic checking"] = measureTime { + compilationUnits.processAll(CompilationUnit::check) } - if (!unitProcessResult["code optimization"]!!.first) { + if (!unitProcessResult["semantic checking"]!!.first.ok()) { return } - // PHASE V: CODE GENERATION + // PHASE VI: CODE OPTIMIZATION + if (!preference.noOpt) { + unitProcessResult["code optimization"] = measureTime { + compilationUnits.processAll(CompilationUnit::optimize) + } + + if (!unitProcessResult["code optimization"]!!.first.ok()) { + return + } + } else { + unitProcessResult["code optimization"] = UnitProcessResult.SKIPPED to 0 + } + + // PHASE VII: CODE GENERATION unitProcessResult["code generation"] = measureTime { val generator = JvmBytecodeGenerator(this) @@ -119,7 +131,7 @@ class CompilationSession(val preference: AbstractPreference) { generator.finalize() - true + UnitProcessResult.PASSED } } @@ -129,54 +141,70 @@ class CompilationSession(val preference: AbstractPreference) { // PHASE I: LEXICAL ANALYZE unitProcessResult["lexical analysis"] = measureTime(compilationUnit::lex) - if (!unitProcessResult["lexical analysis"]!!.first) { + if (!unitProcessResult["lexical analysis"]!!.first.ok()) { return } // PHASE II: SYNTACTIC ANALYSIS unitProcessResult["syntactic analysis"] = measureTime(compilationUnit::parse) - if (!unitProcessResult["syntactic analysis"]!!.first) { + if (!unitProcessResult["syntactic analysis"]!!.first.ok()) { return } - // PHASE III: TYPE BINDING - unitProcessResult["type binding"] = measureTime { - compilationUnit.bind() && compilationUnit.postBind() + // PHASE III: DECLARATION BINDING + unitProcessResult["declaration binding"] = measureTime(compilationUnit::bind) + + if (!unitProcessResult["declaration binding"]!!.first.ok()) { + return } - if (!unitProcessResult["type binding"]!!.first) { + // PHASE IV: TYPE BINDING + unitProcessResult["type binding"] = measureTime(compilationUnit::postBind) + + if (!unitProcessResult["type binding"]!!.first.ok()) { return } - // PHASE III: SEMANTIC CHECKING + // PHASE V: SEMANTIC CHECKING unitProcessResult["semantic checking"] = measureTime(compilationUnit::check) - if (!unitProcessResult["semantic checking"]!!.first) { + if (!unitProcessResult["semantic checking"]!!.first.ok()) { return } - // PHASE IV: SEMANTIC CHECKING - unitProcessResult["code optimization"] = measureTime(compilationUnit::optimize) + // PHASE VI: CODE OPTIMIZATION + if (!preference.noOpt) { + unitProcessResult["code optimization"] = measureTime(compilationUnit::optimize) - if (!unitProcessResult["code optimization"]!!.first) { - return + if (!unitProcessResult["code optimization"]!!.first.ok()) { + return + } + } else { + unitProcessResult["code optimization"] = UnitProcessResult.SKIPPED to 0 } - // PHASE V: CODE GENERATION + // PHASE VII: CODE GENERATION unitProcessResult["code generation"] = measureTime { val generator = JvmBytecodeGenerator(this) generator.gen(compilationUnit) generator.finalize() - true + UnitProcessResult.PASSED } } - private inline fun measureTime(crossinline process: () -> Boolean): Pair { + private inline fun measureTime(crossinline process: () -> UnitProcessResult): Pair { val before = Instant.now() val result = process() val after = Instant.now() return result to Duration.between(before, after).toMillis() } + + private inline fun List.processAll(crossinline process: CompilationUnit.() -> UnitProcessResult): UnitProcessResult = + if (map(process).any { it == UnitProcessResult.FAILED }) { + UnitProcessResult.FAILED + } else { + UnitProcessResult.PASSED + } } diff --git a/src/main/kotlin/org/yakou/lang/compilation/CompilationUnit.kt b/src/main/kotlin/org/yakou/lang/compilation/CompilationUnit.kt index 04e110e..9fdc1b2 100644 --- a/src/main/kotlin/org/yakou/lang/compilation/CompilationUnit.kt +++ b/src/main/kotlin/org/yakou/lang/compilation/CompilationUnit.kt @@ -31,40 +31,40 @@ class CompilationUnit(val sourceFile: File, val session: CompilationSession) : U override fun maxLineCount(): Int = SourceCache.INSTANCE.getOrAdd(sourceFile).size - fun lex(): Boolean { + fun lex(): UnitProcessResult { tokens = Lexer(this).lex() return dumpReportStatus() } - fun parse(): Boolean { + fun parse(): UnitProcessResult { ykFile = Parser(this).parse() return dumpReportStatus() } - fun bind(): Boolean { + fun bind(): UnitProcessResult { binder = Binder(this) binder.bind() return dumpReportStatus() } - fun postBind(): Boolean { + fun postBind(): UnitProcessResult { binder.bindSecondary() return dumpReportStatus() } - fun check(): Boolean { + fun check(): UnitProcessResult { Checker(this).check() return dumpReportStatus() } - fun optimize(): Boolean { + fun optimize(): UnitProcessResult { Optimizer(this).optimize() return dumpReportStatus() } - private fun dumpReportStatus(): Boolean { + private fun dumpReportStatus(): UnitProcessResult { val hasError = reportBuilder.containsError() reportBuilder.dump(preference().outputStream) - return !hasError + return if (!hasError) UnitProcessResult.PASSED else UnitProcessResult.FAILED } } diff --git a/src/main/kotlin/org/yakou/lang/compilation/UnitProcessResult.kt b/src/main/kotlin/org/yakou/lang/compilation/UnitProcessResult.kt new file mode 100644 index 0000000..b7fabb9 --- /dev/null +++ b/src/main/kotlin/org/yakou/lang/compilation/UnitProcessResult.kt @@ -0,0 +1,9 @@ +package org.yakou.lang.compilation + +enum class UnitProcessResult(val stateLiteral: String) { + PASSED("passed"), + FAILED("failed"), + SKIPPED("skipped"); + + fun ok(): Boolean = this != FAILED +} \ No newline at end of file