diff --git a/src/main/antlr/SimpleLanguage.g4 b/src/main/antlr/SimpleLanguage.g4 index 43025e0..667a407 100644 --- a/src/main/antlr/SimpleLanguage.g4 +++ b/src/main/antlr/SimpleLanguage.g4 @@ -12,7 +12,7 @@ statement | expression NEWLINE # expressionStmt | functionDefinition NEWLINE # functionDefinitionStmt | classDefinition NEWLINE # classDefinitionStmt - | IF LPAREN expression RPAREN thenBlock=block (ELSE elseBlock=block)? NEWLINE # ifStmt + | IF LPAREN ifExpression=expression RPAREN ifThenBlock=block (ELSE IF LPAREN elseIfExpression=expression RPAREN elseIfThenBlock=block)* (ELSE elseBlock=block)? NEWLINE # ifStmt | WHILE LPAREN expression RPAREN body=block NEWLINE # whileStmt | RETURN expression NEWLINE # returnStatement | NEWLINE # newlineStmt diff --git a/src/main/kotlin/ast/AstNodes.kt b/src/main/kotlin/ast/AstNodes.kt index 7416962..76c6157 100644 --- a/src/main/kotlin/ast/AstNodes.kt +++ b/src/main/kotlin/ast/AstNodes.kt @@ -45,11 +45,13 @@ data class FunctionDeclarationStatement( } data class IfStatement( - val condition: Expression, - val thenBlock: Block, + val ifCondition: Expression, + val elseIfConditions: List?, + val ifThenBlock: Block, + val elseIfThenBlocks: List?, val elseBlock: Block? ) : Statement { - override val children = listOfNotNull(condition, thenBlock, elseBlock) + override val children = listOfNotNull(ifCondition, ifThenBlock, elseBlock) + elseIfConditions.orEmpty() + elseIfThenBlocks.orEmpty() override fun acceptVisitor(visitor: AstVisitor): T = visitor.visitIfStatement(this) } diff --git a/src/main/kotlin/codegen/dsl/ControlFlow.kt b/src/main/kotlin/codegen/dsl/ControlFlow.kt index b6fd4d7..288bd47 100644 --- a/src/main/kotlin/codegen/dsl/ControlFlow.kt +++ b/src/main/kotlin/codegen/dsl/ControlFlow.kt @@ -3,12 +3,12 @@ package codegen.dsl import codegen.ChunkBuilder import codegen.Code -fun ChunkBuilder.ifStatement(condition: Code, thenCode: Code, elseCode: Code = {}) { +fun ChunkBuilder.ifStatement(ifCondition: Code, thenCode: Code, elseCode: Code = {}) { val afterThen = looseLabel("after then") val afterIf = looseLabel("after if") // IF - +condition // CONDITION + +ifCondition // CONDITION jumpForwardIfFalse(afterThen) // THEN pop() // pop CONDITION @@ -23,6 +23,42 @@ fun ChunkBuilder.ifStatement(condition: Code, thenCode: Code, elseCode: Code = { putLabel(afterIf) } +fun ChunkBuilder.ifStatement(ifConditions: List, thenCodes: List, elseCode: Code = {}) { + val afterAllThen = looseLabel("after then") + val afterAllIf = looseLabel("after all if") + val afterIf = mutableListOf() + + for ((index, condition) in ifConditions.withIndex()) { + afterIf.add(looseLabel("after $index if")) + } + + var currentAfterCondition: ChunkBuilder.Label? = null + + for ((index, condition) in ifConditions.withIndex()) { + currentAfterCondition = looseLabel("after $index") + +condition + jumpForwardIfFalse(afterIf[index]) + pop() + +thenCodes[index] + jumpTo(afterAllIf) + putLabel(afterIf[index]) + } + +// +ifCondition +// jumpForwardIfFalse(afterAllThen) +// +// pop() +// +thenCode +// +// jumpTo(afterIf) + + putLabel(afterAllThen) + pop() + +elseCode + + putLabel(afterAllIf) +} + fun ChunkBuilder.whileLoop(condition: Code, body: Code) { val beforeLoop = looseLabel("before loop") val afterBody = looseLabel("after body") diff --git a/src/main/kotlin/compiler/Compiler.kt b/src/main/kotlin/compiler/Compiler.kt index 6cfc73d..d605d88 100644 --- a/src/main/kotlin/compiler/Compiler.kt +++ b/src/main/kotlin/compiler/Compiler.kt @@ -8,6 +8,7 @@ import codegen.instructions.SetFieldInstruction import resolve.* import stdlib.BuiltInFunction import stdlib.addBuiltInFunction +import java.util.concurrent.locks.Condition fun compile( builtInFunctions: List, @@ -116,10 +117,28 @@ private class CompilerVisitor(builtInFunctions: List, private v } override fun visitIfStatement(ifStatement: IfStatement): Code = { - val condition = visit(ifStatement.condition) - val thenCode = visit(ifStatement.thenBlock) + val ifCondition = visit(ifStatement.ifCondition) + val elseIfConditions = ifStatement.elseIfConditions?.map { visit(it) } + val ifThenCode = visit(ifStatement.ifThenBlock) + val elseIfThenCodes = ifStatement.elseIfThenBlocks?.map { visit(it) } val elseCode = ifStatement.elseBlock?.let { visit(it) } ?: {} - ifStatement(condition, thenCode, elseCode) + + val conditions: MutableList + if (elseIfConditions != null) { + conditions = elseIfConditions.toMutableList() + conditions.add(0, ifCondition) + } else { + conditions = mutableListOf(ifCondition) + } + + val thenCodes: MutableList + if (elseIfThenCodes != null) { + thenCodes = elseIfThenCodes.toMutableList() + thenCodes.add(0, ifThenCode) + } else { + thenCodes = mutableListOf(ifThenCode) + } + ifStatement(conditions, thenCodes, elseCode) } override fun visitWhileStatement(whileStatement: WhileStatement): Code = { diff --git a/src/main/kotlin/parsing/AstBuilder.kt b/src/main/kotlin/parsing/AstBuilder.kt index e82af31..cf7605a 100644 --- a/src/main/kotlin/parsing/AstBuilder.kt +++ b/src/main/kotlin/parsing/AstBuilder.kt @@ -40,10 +40,20 @@ class AstBuilder : SimpleLanguageBaseVisitor() { } override fun visitIfStmt(ctx: SimpleLanguageParser.IfStmtContext?): IfStatement { - val condition = visit(ctx!!.expression()) as Expression - val thenBlock = visitBlock(ctx.thenBlock) +// val condition = visit(ctx!!.expression()) as Expression +// val thenBlock = visitBlock(ctx.thenBlock) +// val elseBlock = ctx.elseBlock?.let { visitBlock(it) } +// return IfStatement(condition, thenBlock, elseBlock) + + val ifCondition = visit(ctx!!.ifExpression) as Expression + val elseIfConditionContexts = ctx.expression().drop(1) + val elseIfConditions = elseIfConditionContexts.map { visit(it) as Expression } + val ifThenBlock = visitBlock(ctx.ifThenBlock) + val elseIfThenBlockContexts = ctx.block().drop(1) + val elseIfThenBlocks = elseIfThenBlockContexts.map { visitBlock(it) } val elseBlock = ctx.elseBlock?.let { visitBlock(it) } - return IfStatement(condition, thenBlock, elseBlock) + + return IfStatement(ifCondition, elseIfConditions, ifThenBlock, elseIfThenBlocks, elseBlock) } override fun visitWhileStmt(ctx: SimpleLanguageParser.WhileStmtContext?): AstNode { diff --git a/src/main/kotlin/stdlib/BuiltInFunctions.kt b/src/main/kotlin/stdlib/BuiltInFunctions.kt index 2644b53..96da065 100644 --- a/src/main/kotlin/stdlib/BuiltInFunctions.kt +++ b/src/main/kotlin/stdlib/BuiltInFunctions.kt @@ -25,7 +25,7 @@ object FactFunction : BuiltInFunction { override val arity: Int = 1 override val code: Code = { ifStatement( - condition = { + ifCondition = { equal({ getLocalVariable(1) }, { literal(1) }) }, thenCode = {