From 984732bf267a30a4648a73ff65b9153dc5d4f2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Fri, 6 Mar 2020 18:24:30 +0100 Subject: [PATCH] Migrate loop parser to Kotlin --- src/main/kotlin/SMNP.kt | 2 +- .../dsl/ast/model/entity/ParserOutput.kt | 6 +-- .../kotlin/dsl/ast/model/node/LoopNode.kt | 22 +++++++++ .../dsl/ast/model/node/LoopParametersNode.kt | 5 ++ .../kotlin/dsl/ast/parser/ConditionParser.kt | 4 +- .../kotlin/dsl/ast/parser/ExpressionParser.kt | 41 ++--------------- src/main/kotlin/dsl/ast/parser/ListParser.kt | 2 +- .../dsl/ast/parser/LoopParametersParser.kt | 8 ++++ src/main/kotlin/dsl/ast/parser/LoopParser.kt | 34 ++++++++++++++ .../kotlin/dsl/ast/parser/MapEntryParser.kt | 2 +- src/main/kotlin/dsl/ast/parser/Parser.kt | 9 ++++ .../kotlin/dsl/ast/parser/ReturnParser.kt | 2 +- .../dsl/ast/parser/SubexpressionParser.kt | 46 +++++++++++++++++++ src/main/kotlin/dsl/ast/parser/ThrowParser.kt | 2 +- 14 files changed, 136 insertions(+), 49 deletions(-) create mode 100644 src/main/kotlin/dsl/ast/model/node/LoopNode.kt create mode 100644 src/main/kotlin/dsl/ast/model/node/LoopParametersNode.kt create mode 100644 src/main/kotlin/dsl/ast/parser/LoopParametersParser.kt create mode 100644 src/main/kotlin/dsl/ast/parser/LoopParser.kt create mode 100644 src/main/kotlin/dsl/ast/parser/SubexpressionParser.kt diff --git a/src/main/kotlin/SMNP.kt b/src/main/kotlin/SMNP.kt index 2d4204d..31ff7b1 100644 --- a/src/main/kotlin/SMNP.kt +++ b/src/main/kotlin/SMNP.kt @@ -2,5 +2,5 @@ import interpreter.Interpreter fun main(args: Array) { val interpreter = Interpreter() - interpreter.run("if (true) { return 2; 2*2; { 3+3; 1*2**3.@c:14 == (2 > not false) } throw \"Hello, world\" } else { false }") + interpreter.run("{ [2, 3, 4] as (i, j, k) ^ { x y z } % i == 2 [1, xyz, [true, { 1 -> false, 2 -> { @c -> @d, @e -> false } }, [@c], 4, \"h\"]] 2 @c @d * 3.14 }") } \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/model/entity/ParserOutput.kt b/src/main/kotlin/dsl/ast/model/entity/ParserOutput.kt index 3a71123..926cbd8 100644 --- a/src/main/kotlin/dsl/ast/model/entity/ParserOutput.kt +++ b/src/main/kotlin/dsl/ast/model/entity/ParserOutput.kt @@ -5,11 +5,7 @@ import dsl.ast.model.node.Node data class ParserOutput private constructor(val result: ParsingResult, val node: Node) { fun map(mapper: (Node) -> Node): ParserOutput { - if(result == ParsingResult.FAILED) { - throw RuntimeException("Mapping operation is not allowed for failed parsing output") - } - - return ok(mapper(node)) + return if(result == ParsingResult.OK) ok(mapper(node)) else fail() } companion object { diff --git a/src/main/kotlin/dsl/ast/model/node/LoopNode.kt b/src/main/kotlin/dsl/ast/model/node/LoopNode.kt new file mode 100644 index 0000000..91198a2 --- /dev/null +++ b/src/main/kotlin/dsl/ast/model/node/LoopNode.kt @@ -0,0 +1,22 @@ +package dsl.ast.model.node + +class LoopNode(iterator: Node, parameters: Node, operator: Node, statement: Node, filter: Node): Node(4, operator.position) { + val iterator: Node + get() = children[0] + + val parameters: Node + get() = children[1] + + val statement: Node + get() = children[2] + + val filter: Node + get() = children[3] + + init { + children[0] = iterator + children[1] = parameters + children[2] = statement + children[3] = filter + } +} \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/model/node/LoopParametersNode.kt b/src/main/kotlin/dsl/ast/model/node/LoopParametersNode.kt new file mode 100644 index 0000000..b17ed2d --- /dev/null +++ b/src/main/kotlin/dsl/ast/model/node/LoopParametersNode.kt @@ -0,0 +1,5 @@ +package dsl.ast.model.node + +import dsl.token.model.entity.TokenPosition + +class LoopParametersNode(items: List, position: TokenPosition) : AbstractIterableNode(items, position) \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/ConditionParser.kt b/src/main/kotlin/dsl/ast/parser/ConditionParser.kt index f8873d9..6904c8c 100644 --- a/src/main/kotlin/dsl/ast/parser/ConditionParser.kt +++ b/src/main/kotlin/dsl/ast/parser/ConditionParser.kt @@ -11,7 +11,7 @@ class ConditionParser : Parser() { val ifStatementParser = allOf(listOf( terminal(TokenType.IF), terminal(TokenType.OPEN_PAREN), - ExpressionParser(), + SubexpressionParser(), terminal(TokenType.CLOSE_PAREN), StatementParser() )) { @@ -21,7 +21,7 @@ class ConditionParser : Parser() { val ifElseStatementParser = allOf(listOf( terminal(TokenType.IF), terminal(TokenType.OPEN_PAREN), - ExpressionParser(), + SubexpressionParser(), terminal(TokenType.CLOSE_PAREN), StatementParser(), terminal(TokenType.ELSE), diff --git a/src/main/kotlin/dsl/ast/parser/ExpressionParser.kt b/src/main/kotlin/dsl/ast/parser/ExpressionParser.kt index bd4ff34..f80882d 100644 --- a/src/main/kotlin/dsl/ast/parser/ExpressionParser.kt +++ b/src/main/kotlin/dsl/ast/parser/ExpressionParser.kt @@ -1,46 +1,13 @@ package dsl.ast.parser import dsl.ast.model.entity.ParserOutput -import dsl.ast.model.node.LogicOperatorNode -import dsl.ast.model.node.RelationOperatorNode -import dsl.ast.model.node.SumOperatorNode import dsl.token.model.entity.TokenList -import dsl.token.model.enumeration.TokenType class ExpressionParser : Parser() { override fun tryToParse(input: TokenList): ParserOutput { - val expr1Parser = leftAssociativeOperator( - TermParser(), - listOf(TokenType.PLUS, TokenType.MINUS), - TermParser() - ) { - lhs, operator, rhs -> SumOperatorNode(lhs, operator, rhs) - } - - val expr2Parser = leftAssociativeOperator( - expr1Parser, - listOf(TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE), - expr1Parser - ) { - lhs, operator, rhs -> RelationOperatorNode(lhs, operator, rhs) - } - - val expr3Parser = leftAssociativeOperator( - expr2Parser, - listOf(TokenType.AND), - expr2Parser - ) { - lhs, operator, rhs -> LogicOperatorNode(lhs, operator, rhs) - } - - val expr4Parser = leftAssociativeOperator( - expr3Parser, - listOf(TokenType.OR), - expr3Parser - ) { - lhs, operator, rhs -> LogicOperatorNode(lhs, operator, rhs) - } - - return expr4Parser.parse(input) + return oneOf(listOf( + LoopParser(), + SubexpressionParser() + )).parse(input) } } \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/ListParser.kt b/src/main/kotlin/dsl/ast/parser/ListParser.kt index a94e692..c53a8c8 100644 --- a/src/main/kotlin/dsl/ast/parser/ListParser.kt +++ b/src/main/kotlin/dsl/ast/parser/ListParser.kt @@ -3,6 +3,6 @@ package dsl.ast.parser import dsl.ast.model.node.ListNode import dsl.token.model.enumeration.TokenType -class ListParser : AbstractIterableParser(TokenType.OPEN_SQUARE, ExpressionParser(), TokenType.CLOSE_SQUARE, { +class ListParser : AbstractIterableParser(TokenType.OPEN_SQUARE, SubexpressionParser(), TokenType.CLOSE_SQUARE, { list, tokenPosition -> ListNode(list, tokenPosition) }) \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/LoopParametersParser.kt b/src/main/kotlin/dsl/ast/parser/LoopParametersParser.kt new file mode 100644 index 0000000..d26e210 --- /dev/null +++ b/src/main/kotlin/dsl/ast/parser/LoopParametersParser.kt @@ -0,0 +1,8 @@ +package dsl.ast.parser + +import dsl.ast.model.node.LoopParametersNode +import dsl.token.model.enumeration.TokenType + +class LoopParametersParser : AbstractIterableParser(TokenType.OPEN_PAREN, IdentifierParser(), TokenType.CLOSE_PAREN, { + list, tokenPosition -> LoopParametersNode(list, tokenPosition) +}) \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/LoopParser.kt b/src/main/kotlin/dsl/ast/parser/LoopParser.kt new file mode 100644 index 0000000..e6a3ecc --- /dev/null +++ b/src/main/kotlin/dsl/ast/parser/LoopParser.kt @@ -0,0 +1,34 @@ +package dsl.ast.parser + +import dsl.ast.model.entity.ParserOutput +import dsl.ast.model.node.LoopNode +import dsl.ast.model.node.LoopParametersNode +import dsl.token.model.entity.TokenList +import dsl.token.model.enumeration.TokenType + +class LoopParser : Parser() { + override fun tryToParse(input: TokenList): ParserOutput { + val loopParametersParser = allOf(listOf( + terminal(TokenType.AS), + oneOf(listOf( + mapNode(IdentifierParser()) { LoopParametersNode(listOf(it), it.position) }, + LoopParametersParser() + )) + )) { it[1] } + + val loopFilterParser = allOf(listOf( + terminal(TokenType.PERCENT), + assert(SubexpressionParser(), "filter as bool expression") + )) { it[1] } + + return allOf(listOf( + SubexpressionParser(), + optional(loopParametersParser), + terminal(TokenType.CARET), + StatementParser(), + optional(loopFilterParser) + )) { + LoopNode(it[0], it[1], it[2], it[3], it[4]) + }.parse(input) + } +} \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/MapEntryParser.kt b/src/main/kotlin/dsl/ast/parser/MapEntryParser.kt index 93e2c9f..01b52f0 100644 --- a/src/main/kotlin/dsl/ast/parser/MapEntryParser.kt +++ b/src/main/kotlin/dsl/ast/parser/MapEntryParser.kt @@ -15,7 +15,7 @@ class MapEntryParser : Parser() { return allOf(listOf( keyParser, terminal(TokenType.ARROW), - assert(ExpressionParser(), "expression") + assert(SubexpressionParser(), "expression") )) { MapEntryNode(it[0], it[1], it[2]) }.parse(input) diff --git a/src/main/kotlin/dsl/ast/parser/Parser.kt b/src/main/kotlin/dsl/ast/parser/Parser.kt index 588fed7..5078e44 100644 --- a/src/main/kotlin/dsl/ast/parser/Parser.kt +++ b/src/main/kotlin/dsl/ast/parser/Parser.kt @@ -184,5 +184,14 @@ abstract class Parser { } } } + + fun mapNode(parser: Parser, mapper: (Node) -> Node) : Parser { + return object : Parser() { + override fun tryToParse(input: TokenList): ParserOutput { + return parser.parse(input).map(mapper) + } + + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/ReturnParser.kt b/src/main/kotlin/dsl/ast/parser/ReturnParser.kt index 05420a0..92c30e6 100644 --- a/src/main/kotlin/dsl/ast/parser/ReturnParser.kt +++ b/src/main/kotlin/dsl/ast/parser/ReturnParser.kt @@ -9,7 +9,7 @@ class ReturnParser : Parser() { override fun tryToParse(input: TokenList): ParserOutput { return allOf(listOf( terminal(TokenType.RETURN), - optional(ExpressionParser()) + optional(SubexpressionParser()) )) { ReturnNode(it[1]) }.parse(input) diff --git a/src/main/kotlin/dsl/ast/parser/SubexpressionParser.kt b/src/main/kotlin/dsl/ast/parser/SubexpressionParser.kt new file mode 100644 index 0000000..8171fbb --- /dev/null +++ b/src/main/kotlin/dsl/ast/parser/SubexpressionParser.kt @@ -0,0 +1,46 @@ +package dsl.ast.parser + +import dsl.ast.model.entity.ParserOutput +import dsl.ast.model.node.LogicOperatorNode +import dsl.ast.model.node.RelationOperatorNode +import dsl.ast.model.node.SumOperatorNode +import dsl.token.model.entity.TokenList +import dsl.token.model.enumeration.TokenType + +class SubexpressionParser : Parser() { + override fun tryToParse(input: TokenList): ParserOutput { + val expr1Parser = leftAssociativeOperator( + TermParser(), + listOf(TokenType.PLUS, TokenType.MINUS), + TermParser() + ) { + lhs, operator, rhs -> SumOperatorNode(lhs, operator, rhs) + } + + val expr2Parser = leftAssociativeOperator( + expr1Parser, + listOf(TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE), + expr1Parser + ) { + lhs, operator, rhs -> RelationOperatorNode(lhs, operator, rhs) + } + + val expr3Parser = leftAssociativeOperator( + expr2Parser, + listOf(TokenType.AND), + expr2Parser + ) { + lhs, operator, rhs -> LogicOperatorNode(lhs, operator, rhs) + } + + val expr4Parser = leftAssociativeOperator( + expr3Parser, + listOf(TokenType.OR), + expr3Parser + ) { + lhs, operator, rhs -> LogicOperatorNode(lhs, operator, rhs) + } + + return expr4Parser.parse(input) + } +} \ No newline at end of file diff --git a/src/main/kotlin/dsl/ast/parser/ThrowParser.kt b/src/main/kotlin/dsl/ast/parser/ThrowParser.kt index 766e4e9..170e6a6 100644 --- a/src/main/kotlin/dsl/ast/parser/ThrowParser.kt +++ b/src/main/kotlin/dsl/ast/parser/ThrowParser.kt @@ -9,7 +9,7 @@ class ThrowParser : Parser() { override fun tryToParse(input: TokenList): ParserOutput { return allOf(listOf( terminal(TokenType.THROW), - optional(ExpressionParser()) + optional(SubexpressionParser()) )) { ThrowNode(it[1]) }.parse(input)