Extract SMNP core from 'app' module to 'core' module

This commit is contained in:
2020-03-29 12:56:52 +02:00
parent 0ccc169b58
commit d9f29a95ad
157 changed files with 19 additions and 8 deletions

View File

@@ -1,10 +1,5 @@
dependencies {
compile project(':api')
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.3.61'
compile group: 'org.pf4j', name: 'pf4j', version: '3.2.0'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.1'
compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '2.0.0-alpha1'
compile project(':core')
compile "com.xenomachina:kotlin-argparser:2.0.7"
}

View File

@@ -1,39 +0,0 @@
package io.smnp.callable.function
import io.smnp.callable.util.FunctionEnvironmentProvider
import io.smnp.callable.util.FunctionSignatureParser
import io.smnp.dsl.ast.model.node.FunctionDefinitionArgumentsNode
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.evaluation.evaluator.BlockEvaluator
import io.smnp.evaluation.model.exception.Return
import io.smnp.type.model.Value
object CustomFunction {
fun create(node: FunctionDefinitionNode): Function {
val identifier = (node.identifier as IdentifierNode).token.rawValue
return object : Function(identifier) {
override fun define(new: FunctionDefinitionTool) {
val (_, argumentsNode, bodyNode) = node
val signature = FunctionSignatureParser.parseSignature(argumentsNode as FunctionDefinitionArgumentsNode)
val evaluator = BlockEvaluator(dedicatedScope = false)
new function signature body { env, args ->
val boundArguments = FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env)
try {
env.pushScope(boundArguments.toMutableMap())
evaluator.evaluate(bodyNode, env)
} catch(value: Return) {
return@body value.value
} finally {
env.popScope()
}
Value.void()
}
}
}
}
}

View File

@@ -1,42 +0,0 @@
package io.smnp.callable.method
import io.smnp.callable.util.FunctionEnvironmentProvider
import io.smnp.callable.util.FunctionSignatureParser
import io.smnp.dsl.ast.model.node.FunctionDefinitionArgumentsNode
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.evaluation.evaluator.BlockEvaluator
import io.smnp.evaluation.model.exception.Return
import io.smnp.type.matcher.Matcher
import io.smnp.type.model.Value
object CustomMethod {
fun create(type: Matcher, node: FunctionDefinitionNode): Method {
val identifier = (node.identifier as IdentifierNode).token.rawValue
return object : Method(type, identifier) {
override fun define(new: MethodDefinitionTool) {
val (_, argumentsNode, bodyNode) = node
val signature = FunctionSignatureParser.parseSignature(argumentsNode as FunctionDefinitionArgumentsNode)
val evaluator = BlockEvaluator(dedicatedScope = false)
new method signature body { env, obj, args ->
val boundArguments =
FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env).toMutableMap()
boundArguments["this"] = obj
try {
env.pushScope(boundArguments)
evaluator.evaluate(bodyNode, env)
} catch (value: Return) {
return@body value.value
} finally {
env.popScope()
}
Value.void()
}
}
}
}
}

View File

@@ -1,44 +0,0 @@
package io.smnp.callable.util
import io.smnp.dsl.ast.model.node.FunctionDefinitionArgumentsNode
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.ast.model.node.OptionalFunctionDefinitionArgumentNode
import io.smnp.dsl.ast.model.node.RegularFunctionDefinitionArgumentNode
import io.smnp.environment.Environment
import io.smnp.error.ShouldNeverReachThisLineException
import io.smnp.evaluation.evaluator.ExpressionEvaluator
import io.smnp.type.model.Value
object FunctionEnvironmentProvider {
private val evaluator = ExpressionEvaluator()
fun provideEnvironment(
signature: FunctionDefinitionArgumentsNode,
actualArgs: List<Value>,
environment: Environment
): Map<String, Value> {
return signature.items.mapIndexed { index, node ->
when (node) {
is RegularFunctionDefinitionArgumentNode -> regularArgument(node, actualArgs, index)
is OptionalFunctionDefinitionArgumentNode -> optionalArgument(node, environment, actualArgs, index)
else -> throw ShouldNeverReachThisLineException()
}
}.toMap()
}
private fun regularArgument(
node: RegularFunctionDefinitionArgumentNode,
actualArgs: List<Value>,
index: Int
) = (node.identifier as IdentifierNode).token.rawValue to actualArgs[index]
private fun optionalArgument(
node: OptionalFunctionDefinitionArgumentNode,
environment: Environment,
actualArgs: List<Value>,
index: Int
) = (node.identifier as IdentifierNode).token.rawValue to
if (index < actualArgs.size) actualArgs[index]
else evaluator.evaluate(node.defaultValue, environment).value
}

View File

@@ -1,155 +0,0 @@
package io.smnp.callable.util
import io.smnp.callable.signature.Signature
import io.smnp.dsl.ast.model.node.*
import io.smnp.error.InvalidSignatureException
import io.smnp.error.ShouldNeverReachThisLineException
import io.smnp.type.enumeration.DataType
import io.smnp.type.matcher.Matcher
import io.smnp.type.matcher.Matcher.Companion.anyType
import io.smnp.type.matcher.Matcher.Companion.listOfMatchers
import io.smnp.type.matcher.Matcher.Companion.mapOfMatchers
import io.smnp.type.matcher.Matcher.Companion.ofType
import io.smnp.type.matcher.Matcher.Companion.oneOf
import io.smnp.type.matcher.Matcher.Companion.optional
object FunctionSignatureParser {
private data class SignatureMetadata(val hasRegular: Boolean, val hasOptional: Boolean, val hasVararg: Boolean)
fun parseSignature(signature: FunctionDefinitionArgumentsNode): Signature {
val (_, _, hasVararg) = assertArgumentsPositions(signature)
assertArgumentsNames(signature)
val matchers = signature.items.map {
when (it) {
is RegularFunctionDefinitionArgumentNode -> matcherForUnionTypeNode(it.type as UnionTypeNode)
is OptionalFunctionDefinitionArgumentNode -> optional(matcherForUnionTypeNode(it.type as UnionTypeNode))
else -> throw ShouldNeverReachThisLineException()
}
}
return if (hasVararg) Signature.vararg(
matchers.last(),
*matchers.dropLast(1).toTypedArray()
) else Signature.simple(*matchers.toTypedArray())
}
private fun assertArgumentsNames(signature: FunctionDefinitionArgumentsNode) {
signature.items.groupingBy {
when (it) {
is RegularFunctionDefinitionArgumentNode -> (it.identifier as IdentifierNode).token.rawValue
is OptionalFunctionDefinitionArgumentNode -> (it.identifier as IdentifierNode).token.rawValue
else -> throw ShouldNeverReachThisLineException()
}
}.eachCount().forEach {
if (it.value > 1) {
throw InvalidSignatureException("Duplicated argument name of '${it.key}'")
}
}
}
private fun assertArgumentsPositions(signature: FunctionDefinitionArgumentsNode): SignatureMetadata {
val firstOptional = signature.items.indexOfFirst { it is OptionalFunctionDefinitionArgumentNode }
val lastRegular = signature.items.indexOfLast { it is RegularFunctionDefinitionArgumentNode }
val vararg =
signature.items.indexOfFirst { it is RegularFunctionDefinitionArgumentNode && it.vararg != Node.NONE }
val metadata = SignatureMetadata(
lastRegular != -1,
firstOptional != -1,
vararg != -1
)
if (metadata.hasVararg && metadata.hasOptional) {
throw InvalidSignatureException("Optional arguments and vararg cannot be mixed in same signature")
}
if (metadata.hasRegular && metadata.hasOptional && firstOptional < lastRegular) {
throw InvalidSignatureException("Optional arguments should be at the very end of arguments list")
}
if (metadata.hasVararg && vararg != signature.items.size - 1) {
throw InvalidSignatureException("Vararg arguments should be at the very end of arguments list")
}
return metadata
}
private fun matcherForUnionTypeNode(unionTypeNode: UnionTypeNode): Matcher {
if (unionTypeNode.items.isEmpty()) {
return anyType()
}
if (unionTypeNode.items.size == 1) {
return matcherForSingleTypeNode(
unionTypeNode.items[0] as SingleTypeNode
)
}
return oneOf(*unionTypeNode.items.map {
matcherForSingleTypeNode(
it as SingleTypeNode
)
}.toTypedArray())
}
fun matcherForSingleTypeNode(singleTypeNode: SingleTypeNode): Matcher {
// TODO
val type = DataType.valueOf((singleTypeNode.type as IdentifierNode).token.rawValue.toUpperCase())
if (singleTypeNode.specifiers == Node.NONE) {
return ofType(type)
} else if (type == DataType.LIST && singleTypeNode.specifiers.children.size == 1) {
return listSpecifier(singleTypeNode.specifiers.children[0] as TypeSpecifierNode)
} else if (type == DataType.MAP && singleTypeNode.specifiers.children.size == 2) {
return mapSpecifier(
singleTypeNode.specifiers.children[0] as TypeSpecifierNode,
singleTypeNode.specifiers.children[1] as TypeSpecifierNode
)
}
throw ShouldNeverReachThisLineException()
}
private fun listSpecifier(listSpecifierNode: TypeSpecifierNode): Matcher {
val types = mutableListOf<Matcher>()
if (listSpecifierNode.items.isEmpty()) {
types.add(anyType())
}
listSpecifierNode.items.forEach { types.add(
matcherForSingleTypeNode(
it as SingleTypeNode
)
) }
return listOfMatchers(*types.toTypedArray())
}
private fun mapSpecifier(keySpecifierNode: TypeSpecifierNode, valueSpecifierNode: TypeSpecifierNode): Matcher {
val keys = mutableListOf<Matcher>()
val values = mutableListOf<Matcher>()
if (keySpecifierNode.items.isEmpty()) {
keys.add(anyType())
}
if (valueSpecifierNode.items.isEmpty()) {
values.add(anyType())
}
keySpecifierNode.items.forEach { keys.add(
matcherForSingleTypeNode(
it as SingleTypeNode
)
) }
valueSpecifierNode.items.forEach { values.add(
matcherForSingleTypeNode(
it as SingleTypeNode
)
) }
return mapOfMatchers(keys, values)
}
}

View File

@@ -1,20 +0,0 @@
package io.smnp.dsl.ast.model.entity
import io.smnp.dsl.ast.model.enumeration.ParsingResult
import io.smnp.dsl.ast.model.node.Node
class ParserOutput private constructor(val result: ParsingResult, val node: Node) {
fun map(mapper: (Node) -> Node): ParserOutput {
return if(result == ParsingResult.OK) ok(mapper(node)) else fail()
}
companion object {
fun ok(node: Node): ParserOutput {
return ParserOutput(ParsingResult.OK, node)
}
fun fail(): ParserOutput {
return ParserOutput(ParsingResult.FAILED, Node.NONE)
}
}
}

View File

@@ -1,6 +0,0 @@
package io.smnp.dsl.ast.model.enumeration
enum class ParsingResult {
OK,
FAILED
}

View File

@@ -1,8 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
abstract class AbstractIterableNode(items: List<Node>, position: TokenPosition) : Node(items, position) {
val items: List<Node>
get() = children
}

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class AccessOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class AssignmentOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,11 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
abstract class AtomAbstractNode(val token: Token) : Node(1, token.position) {
override fun pretty(prefix: String, last: Boolean, first: Boolean) {
println(prefix + (if (first) "" else if (last) "└─" else "├─") + this::class.simpleName + " " + position)
println(prefix + (if (last) " " else "") + "" + token)
}
}

View File

@@ -1,22 +0,0 @@
package io.smnp.dsl.ast.model.node
abstract class BinaryOperatorAbstractNode(lhs: Node, operator: Node, rhs: Node) : Node(3, operator.position) {
operator fun component1() = children[0]
operator fun component2() = children[1]
operator fun component3() = children[2]
val lhs: Node
get() = children[0]
val operator: Node
get() = children[1]
val rhs: Node
get() = children[2]
init {
children[0] = lhs
children[1] = operator
children[2] = rhs
}
}

View File

@@ -1,10 +0,0 @@
package io.smnp.dsl.ast.model.node
class BlockNode(begin: Node, statements: List<Node>, end: Node) : Node(statements, begin.position) {
val statements: List<Node>
get() = children
init {
children = statements.toMutableList()
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class BoolLiteralNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,22 +0,0 @@
package io.smnp.dsl.ast.model.node
class ConditionNode(trueBranchToken: Node, condition: Node, trueBranch: Node, falseBranchToken: Node, falseBranch: Node) : Node(3, trueBranchToken.position) {
operator fun component1(): Node = children[0]
operator fun component2(): Node = children[1]
operator fun component3(): Node = children[2]
val condition: Node
get() = children[0]
val trueBranch: Node
get() = children[1]
val falseBranch: Node
get() = children[2]
init {
children[0] = condition
children[1] = trueBranch
children[2] = falseBranch
}
}

View File

@@ -1,19 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class ExtendNode(type: Node, functions: Node, position: TokenPosition) : Node(2, position) {
operator fun component1(): Node = children[0]
operator fun component2(): Node = children[1]
val type: Node
get() = children[0]
val functions: Node
get() = children[1]
init {
children[0] = type
children[1] = functions
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class FloatLiteralNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class FunctionCallArgumentsNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,17 +0,0 @@
package io.smnp.dsl.ast.model.node
class FunctionCallNode(identifier: Node, arguments: Node) : Node(2, identifier.position) {
operator fun component1() = children[0]
operator fun component2() = children[1]
val identifier: Node
get() = children[0]
val arguments: Node
get() = children[1]
init {
children[0] = identifier
children[1] = arguments
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class FunctionDefinitionArgumentsNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,24 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class FunctionDefinitionNode(identifier: Node, arguments: Node, body: Node, position: TokenPosition) : Node(3, position) {
operator fun component1() = children[0]
operator fun component2() = children[1]
operator fun component3() = children[2]
val identifier: Node
get() = children[0]
val arguments: Node
get() = children[1]
val body: Node
get() = children[2]
init {
children[0] = identifier
children[1] = arguments
children[2] = body
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class IdentifierNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,8 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class ImportNode(path: List<Node>, position: TokenPosition) : Node(path, position) {
val path: List<Node>
get() = children
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class IntegerLiteralNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class ListNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class LogicOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,27 +0,0 @@
package io.smnp.dsl.ast.model.node
class LoopNode(iterator: Node, parameters: Node, operator: Node, statement: Node, filter: Node): Node(4, operator.position) {
operator fun component1() = children[0]
operator fun component2() = children[1]
operator fun component3() = children[2]
operator fun component4() = children[3]
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
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class LoopParametersNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,14 +0,0 @@
package io.smnp.dsl.ast.model.node
class MapEntryNode(key: Node, operator: Node, value: Node) : Node(2, operator.position) {
val key: Node
get() = children[0]
val value: Node
get() = children[1]
init {
children[0] = key
children[1] = value
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class MapNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class MeasureNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class MinusOperatorNode(operator: Node, operand: Node) : UnaryOperatorAbstractNode(operator, operand)

View File

@@ -1,35 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
abstract class Node(numberOfChildren: Int, val position: TokenPosition) {
var children: MutableList<Node> = MutableList(numberOfChildren) { NONE }
protected set
constructor(children: List<Node>, position: TokenPosition) : this(children.size, position) {
this.children = children.toMutableList()
}
operator fun get(index: Int) = children[index]
operator fun set(index: Int, value: Node) {
children[index] = value
}
open fun pretty(prefix: String = "", last: Boolean = true, first: Boolean = true) {
var newPrefix = prefix
var newLast = last
val nodeName = this::class.simpleName ?: "<anonymous>"
println(newPrefix + (if (first) "" else if (newLast) "└─" else "├─") + nodeName + " " + position)
newPrefix += if (newLast) " " else ""
for ((index, child) in children.withIndex()) {
newLast = index == children.size - 1
child.pretty(newPrefix, newLast, false)
}
}
companion object {
val NONE = NoneNode()
}
}

View File

@@ -1,7 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class NoneNode : Node(0,
TokenPosition.NONE
)

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class NotOperatorNode(operator: Node, operand: Node) : UnaryOperatorAbstractNode(operator, operand)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class NoteLiteralNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,18 +0,0 @@
package io.smnp.dsl.ast.model.node
class OptionalFunctionDefinitionArgumentNode(identifier: Node, type: Node, defaultValue: Node) : Node(3, identifier.position) {
val identifier: Node
get() = children[0]
val type: Node
get() = children[1]
val defaultValue: Node
get() = children[2]
init {
children[0] = identifier
children[1] = type
children[2] = defaultValue
}
}

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class PowerOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class ProductOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,18 +0,0 @@
package io.smnp.dsl.ast.model.node
class RegularFunctionDefinitionArgumentNode(identifier: Node, type: Node, vararg: Node) : Node(3, identifier.position) {
val identifier
get() = children[0]
val type
get() = children[1]
val vararg
get() = children[2]
init {
children[0] = identifier
children[1] = type
children[2] = vararg
}
}

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class RelationOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.model.node
class ReturnNode(value: Node) : Node(1, value.position) {
operator fun component1() = children[0]
val value: Node
get() = children[0]
init {
children[0] = value
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class RootNode(nodes: List<Node>, position: TokenPosition) : Node(nodes, position)

View File

@@ -1,14 +0,0 @@
package io.smnp.dsl.ast.model.node
class SingleTypeNode(type: Node, specifiers: Node) : Node(2, type.position) {
val type: Node
get() = children[0]
val specifiers: Node
get() = children[1]
init {
children[0] = type
children[1] = specifiers
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class StaffNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class StringLiteralNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,3 +0,0 @@
package io.smnp.dsl.ast.model.node
class SumOperatorNode(lhs: Node, operator: Node, rhs: Node) : BinaryOperatorAbstractNode(lhs, operator, rhs)

View File

@@ -1,10 +0,0 @@
package io.smnp.dsl.ast.model.node
class ThrowNode(value: Node) : Node(1, value.position) {
val value: Node
get() = children[0]
init {
children[0] = value
}
}

View File

@@ -1,14 +0,0 @@
package io.smnp.dsl.ast.model.node
class TimeSignatureNode(numerator: Node, denominator: Node) : Node(2, numerator.position) {
val numerator: Node
get() = children[0]
val denominator: Node
get() = children[1]
init {
children[0] = numerator
children[1] = denominator
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.Token
class TokenNode(token: Token) : AtomAbstractNode(token)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class TypeSpecifierNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class TypeSpecifiersNode(specifiers: List<Node>, position: TokenPosition) : Node(specifiers, position)

View File

@@ -1,17 +0,0 @@
package io.smnp.dsl.ast.model.node
abstract class UnaryOperatorAbstractNode(operator: Node, operand: Node) : Node(2, operator.position) {
operator fun component1() = children[0]
operator fun component2() = children[1]
val operator: Node
get() = children[0]
val operand: Node
get() = children[1]
init {
children[0] = operator
children[1] = operand
}
}

View File

@@ -1,5 +0,0 @@
package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class UnionTypeNode(items: List<Node>, position: TokenPosition) : AbstractIterableNode(items, position)

View File

@@ -1,42 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.entity.TokenPosition
import io.smnp.dsl.token.model.enumeration.TokenType
abstract class AbstractIterableParser(
private val beginTokenType: TokenType,
private val itemParser: Parser,
private val endTokenType: TokenType,
private val separator: TokenType = TokenType.COMMA,
private val createNode: (List<Node>, TokenPosition) -> Node
) : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val emptyIterableParser = allOf(
terminal(beginTokenType),
terminal(endTokenType)
) { (beginToken) -> createNode(listOf(), beginToken.position) }
val nonEmptyIterableParser = allOf(
terminal(beginTokenType),
allOf(
itemParser,
optional(repeat(allOf(
terminal(separator),
itemParser
) { (_, item) -> item }) { list, position -> object : Node(list, position) {} }
)) { (firstItem, otherAggregatedItems) ->
object : Node(listOf(firstItem) + otherAggregatedItems.children, TokenPosition.NONE) {}
},
terminal(endTokenType)
) { (beginToken, aggregatedItems) -> createNode(aggregatedItems.children.toList(), beginToken.position) }
return oneOf(
emptyIterableParser,
nonEmptyIterableParser
).parse(input)
}
}

View File

@@ -1,16 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.AssignmentOperatorNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class AssignmentOperatorParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
SimpleIdentifierParser(),
terminal(TokenType.ASSIGN),
assert(ExpressionParser(), "expression")
) { (target, assignToken, value) -> AssignmentOperatorNode(target, assignToken, value) }.parse(input)
}
}

View File

@@ -1,26 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class AtomParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val parenthesesParser = allOf(
terminal(TokenType.OPEN_PAREN),
ExpressionParser(),
terminal(TokenType.CLOSE_PAREN)
) { (_, expression) -> expression }
val literalParser = oneOf(
parenthesesParser,
ComplexIdentifierParser(),
StaffParser(),
ListParser(),
LiteralParser(),
MapParser()
)
return literalParser.parse(input)
}
}

View File

@@ -1,18 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.BlockNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class BlockParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return loop(
terminal(TokenType.OPEN_CURLY),
assert(StatementParser(), "statement or }"),
terminal(TokenType.CLOSE_CURLY)
) { begin, list, end ->
BlockNode(begin, list, end)
}.parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.BoolLiteralNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class BoolLiteralParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return terminal(TokenType.BOOL) { BoolLiteralNode(it) }.parse(input)
}
}

View File

@@ -1,14 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.token.model.entity.TokenList
class ComplexIdentifierParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return oneOf(
AssignmentOperatorParser(),
FunctionCallParser(),
SimpleIdentifierParser()
).parse(input)
}
}

View File

@@ -1,42 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.ConditionNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class ConditionParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val ifStatementParser = allOf(
terminal(TokenType.IF),
terminal(TokenType.OPEN_PAREN),
assert(SubexpressionParser(), "expression"),
terminal(TokenType.CLOSE_PAREN),
assert(StatementParser(), "statement")
) { (ifToken, _, condition, _, trueBranch) ->
ConditionNode(ifToken, condition, trueBranch, Node.NONE, Node.NONE)
}
val ifElseStatementParser = allOf(
terminal(TokenType.IF),
terminal(TokenType.OPEN_PAREN),
assert(SubexpressionParser(), "expression"),
terminal(TokenType.CLOSE_PAREN),
assert(StatementParser(), "statement"),
terminal(TokenType.ELSE),
assert(StatementParser(), "statement")
) { (ifToken, _, condition, _, trueBranch, elseToken, falseBranch) ->
ConditionNode(ifToken, condition, trueBranch, elseToken, falseBranch)
}
return oneOf(
ifElseStatementParser,
ifStatementParser
).parse(input)
}
}
// It is required for destructing list of nodes in ifElseStatementParser object
private operator fun <E> List<E>.component6() = this[5];
private operator fun <E> List<E>.component7() = this[6];

View File

@@ -1,13 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.token.model.entity.TokenList
class ExpressionParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return oneOf(
LoopParser(),
SubexpressionParser()
).parse(input)
}
}

View File

@@ -1,45 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.BlockNode
import io.smnp.dsl.ast.model.node.ExtendNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class ExtendParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val simpleExtendParser = allOf(
terminal(TokenType.EXTEND),
assert(SingleTypeParser(), "type to be extended"),
terminal(TokenType.WITH),
assert(
mapNode(FunctionDefinitionParser()) { BlockNode(Node.NONE, listOf(it), Node.NONE) },
"method definition"
)
) { (extendToken, targetType, _, method) ->
ExtendNode(targetType, method, extendToken.position)
}
val complexExtendParser = allOf(
terminal(TokenType.EXTEND),
assert(SingleTypeParser(), "type to be extended"),
assert(
loop(
terminal(TokenType.OPEN_CURLY),
assert(FunctionDefinitionParser(), "method definition or }"),
terminal(TokenType.CLOSE_CURLY)
) { begin, methods, end ->
BlockNode(begin, methods, end)
}, "block with methods' definitions or 'with' keyword with single method definition"
)
) { (extendToken, targetType, methods) ->
ExtendNode(targetType, methods, extendToken.position)
}
return oneOf(
simpleExtendParser,
complexExtendParser
).parse(input)
}
}

View File

@@ -1,27 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.NotOperatorNode
import io.smnp.dsl.ast.model.node.PowerOperatorNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class FactorParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val factorParser = leftAssociativeOperator(
UnitParser(),
listOf(TokenType.DOUBLE_ASTERISK),
assert(UnitParser(), "expression")
) { lhs, operator, rhs -> PowerOperatorNode(lhs, operator, rhs) }
val notOperatorParser = allOf(
terminal(TokenType.NOT),
assert(factorParser, "expression")
) { (notToken, expression) -> NotOperatorNode(notToken, expression) }
return oneOf(
notOperatorParser,
factorParser
).parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.FloatLiteralNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class FloatLiteralParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return terminal(TokenType.FLOAT) { FloatLiteralNode(it) }.parse(input)
}
}

View File

@@ -1,13 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.FunctionCallArgumentsNode
import io.smnp.dsl.token.model.enumeration.TokenType
class FunctionCallArgumentsParser :
AbstractIterableParser(
TokenType.OPEN_PAREN,
ExpressionParser(),
TokenType.CLOSE_PAREN,
createNode = { list, tokenPosition ->
FunctionCallArgumentsNode(list, tokenPosition)
})

View File

@@ -1,14 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.FunctionCallNode
import io.smnp.dsl.token.model.entity.TokenList
class FunctionCallParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
SimpleIdentifierParser(),
FunctionCallArgumentsParser()
) { (identifier, arguments) -> FunctionCallNode(identifier, arguments) }.parse(input)
}
}

View File

@@ -1,13 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.token.model.entity.TokenList
class FunctionDefinitionArgumentParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return assert(oneOf(
OptionalFunctionDefinitionArgumentParser(),
RegularFunctionDefinitionArgumentParser()
), "optional or regular argument definition").parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.FunctionDefinitionArgumentsNode
import io.smnp.dsl.token.model.enumeration.TokenType
class FunctionDefinitionArgumentsParser : AbstractIterableParser(
TokenType.OPEN_PAREN,
FunctionDefinitionArgumentParser(),
TokenType.CLOSE_PAREN,
createNode = { list, tokenPosition ->
FunctionDefinitionArgumentsNode(list, tokenPosition)
})

View File

@@ -1,19 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class FunctionDefinitionParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
terminal(TokenType.FUNCTION),
assert(SimpleIdentifierParser(), "function/method name"),
assert(FunctionDefinitionArgumentsParser(), "function/method arguments list"),
assert(BlockParser(), "function/method body")
) { (functionToken, identifier, arguments, body) ->
FunctionDefinitionNode(identifier, arguments, body, functionToken.position)
}.parse(input)
}
}

View File

@@ -1,30 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.ImportNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class ImportParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val pathParser = allOf(
SimpleIdentifierParser(),
optional(repeat(allOf(
terminal(TokenType.DOT),
SimpleIdentifierParser()
) { (_, child) -> child }) { segments, position ->
object : Node(segments, position) {}
})) { (firstSegment, otherSegments) ->
object : Node(listOf(firstSegment) + otherSegments.children, firstSegment.position) {}
}
return allOf(
terminal(TokenType.IMPORT),
assert(pathParser, "module canonical name")
) { (import, path) ->
ImportNode(path.children, import.position)
}.parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.IntegerLiteralNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class IntegerLiteralParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return terminal(TokenType.INTEGER) { IntegerLiteralNode(it) }.parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.ListNode
import io.smnp.dsl.token.model.enumeration.TokenType
class ListParser : AbstractIterableParser(
TokenType.OPEN_SQUARE,
assert(ExpressionParser(), "expression"),
TokenType.CLOSE_SQUARE,
createNode = { list, tokenPosition ->
ListNode(list, tokenPosition)
})

View File

@@ -1,16 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.token.model.entity.TokenList
class LiteralParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return oneOf(
BoolLiteralParser(),
FloatLiteralParser(),
IntegerLiteralParser(),
NoteLiteralParser(),
StringLiteralParser()
).parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.LoopParametersNode
import io.smnp.dsl.token.model.enumeration.TokenType
class LoopParametersParser : AbstractIterableParser(
TokenType.OPEN_PAREN,
assert(SimpleIdentifierParser(), "identifier"),
TokenType.CLOSE_PAREN,
createNode = { list, tokenPosition ->
LoopParametersNode(list, tokenPosition)
})

View File

@@ -1,34 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.LoopNode
import io.smnp.dsl.ast.model.node.LoopParametersNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class LoopParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val loopParametersParser = allOf(
terminal(TokenType.AS),
assert(oneOf(
mapNode(SimpleIdentifierParser()) { LoopParametersNode(listOf(it), it.position) },
LoopParametersParser()
), "loop parameters")
) { (_, parameters) -> parameters }
val loopFilterParser = allOf(
terminal(TokenType.PERCENT),
assert(SubexpressionParser(), "filter as bool expression")
) { (_, filter) -> filter }
return allOf(
SubexpressionParser(),
optional(loopParametersParser),
terminal(TokenType.CARET),
assert(StatementParser(), "statement"),
optional(loopFilterParser)
) { (iterator, parameters, caretToken, statement, filter) ->
LoopNode(iterator, parameters, caretToken, statement, filter)
}.parse(input)
}
}

View File

@@ -1,21 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.MapEntryNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class MapEntryParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val keyParser = oneOf(
LiteralParser(),
SimpleIdentifierParser()
)
return allOf(
keyParser,
terminal(TokenType.ARROW),
assert(SubexpressionParser(), "expression")
) { (key, arrowToken, value) -> MapEntryNode(key, arrowToken, value) }.parse(input)
}
}

View File

@@ -1,13 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.MapNode
import io.smnp.dsl.token.model.enumeration.TokenType
class MapParser :
AbstractIterableParser(
TokenType.OPEN_CURLY,
MapEntryParser(),
TokenType.CLOSE_CURLY,
createNode = { list, tokenPosition ->
MapNode(list, tokenPosition)
})

View File

@@ -1,17 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.MeasureNode
import io.smnp.dsl.token.model.entity.TokenList
class MeasureParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return repeat(
oneOf(
TimeSignatureParser(),
ExpressionParser()
)
) { items, position -> MeasureNode(items, position) }.parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.NoteLiteralNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class NoteLiteralParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return terminal(TokenType.NOTE) { NoteLiteralNode(it) }.parse(input)
}
}

View File

@@ -1,24 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.OptionalFunctionDefinitionArgumentNode
import io.smnp.dsl.ast.model.node.UnionTypeNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.entity.TokenPosition
import io.smnp.dsl.token.model.enumeration.TokenType
class OptionalFunctionDefinitionArgumentParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
SimpleIdentifierParser(),
optional(allOf(
terminal(TokenType.COLON),
assert(TypeParser(), "type name")
) { (_, type) -> type }) { UnionTypeNode(emptyList(), TokenPosition.NONE) },
terminal(TokenType.ASSIGN),
assert(ExpressionParser(), "expression")
) { (identifier, type, _, defaultValue) ->
OptionalFunctionDefinitionArgumentNode(identifier, type, defaultValue)
}.parse(input)
}
}

View File

@@ -1,209 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.enumeration.ParsingResult
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.ast.model.node.TokenNode
import io.smnp.dsl.token.model.entity.Token
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.entity.TokenPosition
import io.smnp.dsl.token.model.enumeration.TokenType
import io.smnp.error.InvalidSyntaxException
import io.smnp.error.PositionException
abstract class Parser {
fun parse(input: TokenList): ParserOutput {
val snapshot = input.snapshot()
val output = tryToParse(input)
if (output.result == ParsingResult.FAILED) {
input.restore(snapshot)
}
return output
}
protected abstract fun tryToParse(input: TokenList): ParserOutput
companion object {
// a -> A
fun terminal(terminal: TokenType, createNode: (Token) -> Node = { TokenNode(it) }): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
if (input.hasCurrent() && input.current.type == terminal) {
val token = input.current
input.ahead()
return ParserOutput.ok(createNode(token))
}
return ParserOutput.fail()
}
}
}
// oneOf -> a | b | c | ...
fun oneOf(vararg parsers: Parser): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
if (parsers.isEmpty()) {
throw RuntimeException("Provide one parser at least")
}
for (parser in parsers) {
val output = parser.parse(input)
if (output.result == ParsingResult.OK) {
return output
}
}
return ParserOutput.fail()
}
}
}
// a -> A | B | C | ...
fun terminals(vararg terminals: TokenType, createNode: (Token) -> Node = { TokenNode(it) }): Parser {
return oneOf(*terminals.map { terminal(it, createNode) }.toTypedArray())
}
// allOf -> a b c ...
fun allOf(vararg parsers: Parser, createNode: (List<Node>) -> Node): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
if (parsers.isEmpty()) {
throw RuntimeException("Provide one parser at least")
}
val nodes = mutableListOf<Node>()
for (parser in parsers) {
val output = parser.parse(input)
if (output.result == ParsingResult.FAILED) {
return ParserOutput.fail()
}
nodes += output.node
}
return ParserOutput.ok(createNode(nodes))
}
}
}
// leftAssociative -> left | left OP right
fun leftAssociativeOperator(
lhsParser: Parser,
allowedOperators: List<TokenType>,
rhsParser: Parser,
createNode: (lhs: Node, operator: Node, rhs: Node) -> Node
): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val opParser = terminals(*allowedOperators.toTypedArray())
var lhs = lhsParser.parse(input)
if (lhs.result == ParsingResult.OK) {
var op = opParser.parse(input)
while (op.result == ParsingResult.OK) {
val rhs = rhsParser.parse(input)
if (rhs.result == ParsingResult.FAILED) { // Todo: Not sure if it should be here
return ParserOutput.fail()
}
lhs = ParserOutput.ok(createNode(lhs.node, op.node, rhs.node))
op = opParser.parse(input)
}
return lhs
}
return ParserOutput.fail()
}
}
}
// repeat -> item*
fun repeat(itemParser: Parser, createNode: (List<Node>, TokenPosition) -> Node): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val items = mutableListOf<Node>()
while (true) {
val output = itemParser.parse(input)
if (output.result == ParsingResult.OK) {
items += output.node
} else if (items.isEmpty()) {
return ParserOutput.fail()
} else {
return ParserOutput.ok(createNode(items, items.first().position))
}
}
}
}
}
// loop -> begin item* end
fun loop(
beginParser: Parser,
itemParser: Parser,
endParser: Parser,
createNode: (Node, List<Node>, Node) -> Node
): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val items = mutableListOf<Node>()
val begin = beginParser.parse(input)
if (begin.result == ParsingResult.OK) {
while (true) {
val end = endParser.parse(input)
if (end.result == ParsingResult.OK) {
return ParserOutput.ok(createNode(begin.node, items, end.node))
}
val item = itemParser.parse(input)
if (item.result == ParsingResult.FAILED) {
return ParserOutput.fail()
}
items += item.node
}
}
return ParserOutput.fail()
}
}
}
fun assert(parser: Parser, expected: String): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val output = parser.parse(input)
if (output.result == ParsingResult.FAILED) {
throw PositionException(InvalidSyntaxException("Expected $expected, got '${input.current.rawValue}'"), input.currentPos())
}
return output
}
}
}
// optional -> a?
fun optional(parser: Parser, createFallbackNode: () -> Node = { Node.NONE }): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val output = parser.parse(input)
return if (output.result == ParsingResult.OK) output else ParserOutput.ok(createFallbackNode())
}
}
}
fun mapNode(parser: Parser, mapper: (Node) -> Node): Parser {
return object : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return parser.parse(input).map(mapper)
}
}
}
}
}

View File

@@ -1,23 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.RegularFunctionDefinitionArgumentNode
import io.smnp.dsl.ast.model.node.UnionTypeNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.entity.TokenPosition
import io.smnp.dsl.token.model.enumeration.TokenType
class RegularFunctionDefinitionArgumentParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
optional(terminal(TokenType.DOTS)),
SimpleIdentifierParser(),
optional(allOf(
terminal(TokenType.COLON),
assert(TypeParser(), "type name")
) { (_, type) -> type }) { UnionTypeNode(emptyList(), TokenPosition.NONE) }
) { (vararg, identifier, type) ->
RegularFunctionDefinitionArgumentNode(identifier, type, vararg)
}.parse(input)
}
}

View File

@@ -1,17 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.ReturnNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class ReturnParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
terminal(TokenType.RETURN),
optional(assert(ExpressionParser(), "expression"))
) { (_, value) ->
ReturnNode(value)
}.parse(input)
}
}

View File

@@ -1,21 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.RootNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class RootParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return assert(repeat(
oneOf(
allOf(ImportParser(), optional(terminal(TokenType.SEMICOLON))) { (import, _) -> import },
FunctionDefinitionParser(),
ExtendParser(),
StatementParser()
)
) { list, tokenPosition ->
RootNode(list, tokenPosition)
}, "import statement, function definition, extend statement or any other statement").parse(input)
}
}

View File

@@ -1,16 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class SimpleIdentifierParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val identifierParser = terminal(TokenType.IDENTIFIER) { IdentifierNode(it) }
return oneOf(
identifierParser
).parse(input)
}
}

View File

@@ -1,15 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.SingleTypeNode
import io.smnp.dsl.ast.model.node.TypeSpecifiersNode
import io.smnp.dsl.token.model.entity.TokenList
class SingleTypeParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
SimpleIdentifierParser(),
optional(repeat(TypeSpecifierParser()) { list, tokenPosition -> TypeSpecifiersNode(list, tokenPosition) })
) { (identifier, specifiers) -> SingleTypeNode(identifier, specifiers) }.parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.StaffNode
import io.smnp.dsl.token.model.enumeration.TokenType
class StaffParser : AbstractIterableParser(
TokenType.DOLLAR,
MeasureParser(),
TokenType.DOUBLE_PIPE,
TokenType.PIPE,
{ items, position -> StaffNode(items, position) }
)

View File

@@ -1,20 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class StatementParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
oneOf(
ConditionParser(),
ExpressionParser(),
BlockParser(),
ReturnParser(),
ThrowParser()
),
optional(terminal(TokenType.SEMICOLON))
) { (statement) -> statement }.parse(input)
}
}

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.StringLiteralNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class StringLiteralParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return terminal(TokenType.STRING) { StringLiteralNode(it) }.parse(input)
}
}

View File

@@ -1,46 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.LogicOperatorNode
import io.smnp.dsl.ast.model.node.RelationOperatorNode
import io.smnp.dsl.ast.model.node.SumOperatorNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class SubexpressionParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val expr1Parser = leftAssociativeOperator(
TermParser(),
listOf(TokenType.PLUS, TokenType.MINUS),
assert(TermParser(), "expression")
) { lhs, operator, rhs ->
SumOperatorNode(lhs, operator, rhs)
}
val expr2Parser = leftAssociativeOperator(
expr1Parser,
listOf(TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE),
assert(expr1Parser, "expression")
) { lhs, operator, rhs ->
RelationOperatorNode(lhs, operator, rhs)
}
val expr3Parser = leftAssociativeOperator(
expr2Parser,
listOf(TokenType.AND),
assert(expr2Parser, "expression")
) { lhs, operator, rhs ->
LogicOperatorNode(lhs, operator, rhs)
}
val expr4Parser = leftAssociativeOperator(
expr3Parser,
listOf(TokenType.OR),
assert(expr3Parser, "expression")
) { lhs, operator, rhs ->
LogicOperatorNode(lhs, operator, rhs)
}
return expr4Parser.parse(input)
}
}

View File

@@ -1,18 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.ProductOperatorNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class TermParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return leftAssociativeOperator(
FactorParser(),
listOf(TokenType.ASTERISK, TokenType.SLASH),
assert(FactorParser(), "expression")
) { lhs, operator, rhs ->
ProductOperatorNode(lhs, operator, rhs)
}.parse(input)
}
}

View File

@@ -1,15 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.ThrowNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class ThrowParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
terminal(TokenType.THROW),
optional(SubexpressionParser())
) { (_, value) -> ThrowNode(value) }.parse(input)
}
}

View File

@@ -1,17 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.TimeSignatureNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class TimeSignatureParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return allOf(
IntegerLiteralParser(),
terminal(TokenType.SLASH),
IntegerLiteralParser()
) { (numerator, _, denominator) -> TimeSignatureNode(numerator, denominator) }.parse(input)
}
}

View File

@@ -1,17 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.SingleTypeNode
import io.smnp.dsl.ast.model.node.UnionTypeNode
import io.smnp.dsl.token.model.entity.TokenList
class TypeParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
return mapNode(oneOf(
SingleTypeParser(),
UnionTypeParser()
)) {
node -> if(node is SingleTypeNode) UnionTypeNode(listOf(node), node.position) else node
}.parse(input)
}
}

View File

@@ -1,13 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.TypeSpecifierNode
import io.smnp.dsl.token.model.enumeration.TokenType
class TypeSpecifierParser :
AbstractIterableParser(
TokenType.OPEN_ANGLE,
SingleTypeParser(),
TokenType.CLOSE_ANGLE,
createNode = { list, tokenPosition ->
TypeSpecifierNode(list, tokenPosition)
})

View File

@@ -1,12 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.node.UnionTypeNode
import io.smnp.dsl.token.model.enumeration.TokenType
class UnionTypeParser : AbstractIterableParser(
TokenType.OPEN_ANGLE,
SingleTypeParser(),
TokenType.CLOSE_ANGLE,
createNode = { list, tokenPosition ->
UnionTypeNode(list, tokenPosition)
})

View File

@@ -1,27 +0,0 @@
package io.smnp.dsl.ast.parser
import io.smnp.dsl.ast.model.entity.ParserOutput
import io.smnp.dsl.ast.model.node.AccessOperatorNode
import io.smnp.dsl.ast.model.node.MinusOperatorNode
import io.smnp.dsl.token.model.entity.TokenList
import io.smnp.dsl.token.model.enumeration.TokenType
class UnitParser : Parser() {
override fun tryToParse(input: TokenList): ParserOutput {
val minusOperatorParser = allOf(
terminal(TokenType.MINUS),
assert(AtomParser(), "expression")
) { (minusToken, expression) -> MinusOperatorNode(minusToken, expression) }
val atom2 = oneOf(
minusOperatorParser,
AtomParser()
)
return leftAssociativeOperator(
atom2,
listOf(TokenType.DOT),
assert(atom2, "property or method call")
) { lhs, operator, rhs -> AccessOperatorNode(lhs, operator, rhs) }.parse(input)
}
}

View File

@@ -1,19 +0,0 @@
package io.smnp.dsl.token.model.entity
import io.smnp.dsl.token.model.enumeration.TokenType
data class Token(val type: TokenType, val value: Any, val rawValue: String, val position: TokenPosition) {
constructor(type: TokenType, value: String, position: TokenPosition): this(type, value, value, position)
fun mapValue(mapper: (Any) -> Any): Token {
return Token(type, mapper(value), rawValue, position)
}
companion object {
val NONE = Token(TokenType.NONE, "", TokenPosition.NONE)
}
override fun toString(): String {
return "($type, »$rawValue«, $position)"
}
}

View File

@@ -1,60 +0,0 @@
package io.smnp.dsl.token.model.entity
class TokenList(val tokens: List<Token>, val lines: List<String>) {
private var cursor = 0
private var snap = 0
operator fun get(index: Int): Token {
return tokens[index]
}
val current: Token
get() {
if (!hasCurrent()) {
throw RuntimeException("Cursor points to not existing token! Cursor = ${cursor}, length = ${tokens.size}")
}
return tokens[cursor]
}
fun currentPos(): TokenPosition {
return current.position
}
fun hasCurrent(): Boolean {
return cursor < tokens.size
}
fun hasMore(count: Int = 1): Boolean {
return cursor + count < tokens.size
}
fun next(number: Int = 1): Token {
return tokens[cursor + number]
}
fun prev(number: Int = 1): Token {
return tokens[cursor - number]
}
fun ahead() {
cursor += 1
}
fun snapshot(): Int {
return cursor
}
fun restore(snapshot: Int) {
cursor = snapshot
}
fun reset() {
cursor = 0
}
override fun toString(): String {
val currentStr = if(hasCurrent()) "current: ${cursor} -> ${current}" else "<all tokens consumed>"
return "size: ${tokens.size}\n${currentStr}\nall: ${tokens}"
}
}

Some files were not shown because too many files have changed in this diff Show More