Create FunctionSignatureParser
This commit is contained in:
@@ -0,0 +1,132 @@
|
|||||||
|
package io.smnp.callable.function
|
||||||
|
|
||||||
|
import io.smnp.callable.signature.Signature
|
||||||
|
import io.smnp.dsl.ast.model.node.*
|
||||||
|
import io.smnp.error.ShouldNeverReachThisLineException
|
||||||
|
import io.smnp.type.enumeration.DataType
|
||||||
|
import io.smnp.type.matcher.Matcher
|
||||||
|
import io.smnp.type.matcher.Matcher.Companion.allTypes
|
||||||
|
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 RuntimeException("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 RuntimeException("Optional arguments and vararg cannot be mixed in same signature")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.hasRegular && metadata.hasOptional && firstOptional < lastRegular) {
|
||||||
|
throw RuntimeException("Optional arguments should be at the very end of arguments list")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.hasVararg && vararg != signature.items.size - 1) {
|
||||||
|
throw RuntimeException("Vararg arguments should be at the very end of arguments list")
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun matcherForUnionTypeNode(unionTypeNode: UnionTypeNode): Matcher {
|
||||||
|
if (unionTypeNode.items.isEmpty()) {
|
||||||
|
return allTypes()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unionTypeNode.items.size == 1) {
|
||||||
|
return matcherForSingleTypeNode(unionTypeNode.items[0] as SingleTypeNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oneOf(*unionTypeNode.items.map { matcherForSingleTypeNode(it as SingleTypeNode) }.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 RuntimeException("Unknown type")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listSpecifier(listSpecifierNode: TypeSpecifierNode): Matcher {
|
||||||
|
val types = mutableListOf<Matcher>()
|
||||||
|
|
||||||
|
if (listSpecifierNode.items.isEmpty()) {
|
||||||
|
types.add(allTypes())
|
||||||
|
}
|
||||||
|
|
||||||
|
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(allTypes())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueSpecifierNode.items.isEmpty()) {
|
||||||
|
values.add(allTypes())
|
||||||
|
}
|
||||||
|
|
||||||
|
keySpecifierNode.items.forEach { keys.add(matcherForSingleTypeNode(it as SingleTypeNode)) }
|
||||||
|
valueSpecifierNode.items.forEach { values.add(matcherForSingleTypeNode(it as SingleTypeNode)) }
|
||||||
|
|
||||||
|
return mapOfMatchers(keys, values)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.smnp.dsl.ast.model.node
|
package io.smnp.dsl.ast.model.node
|
||||||
|
|
||||||
class TypeNode(type: Node, specifiers: Node) : Node(2, type.position) {
|
class SingleTypeNode(type: Node, specifiers: Node) : Node(2, type.position) {
|
||||||
val type: Node
|
val type: Node
|
||||||
get() = children[0]
|
get() = children[0]
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
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)
|
||||||
@@ -11,7 +11,7 @@ class ExtendParser : Parser() {
|
|||||||
override fun tryToParse(input: TokenList): ParserOutput {
|
override fun tryToParse(input: TokenList): ParserOutput {
|
||||||
val simpleExtendParser = allOf(
|
val simpleExtendParser = allOf(
|
||||||
terminal(TokenType.EXTEND),
|
terminal(TokenType.EXTEND),
|
||||||
assert(TypeParser(), "type to be extended"),
|
assert(SingleTypeParser(), "type to be extended"),
|
||||||
assert(terminal(TokenType.AS), "'as' keyword with identifier"),
|
assert(terminal(TokenType.AS), "'as' keyword with identifier"),
|
||||||
assert(SimpleIdentifierParser(), "identifier"),
|
assert(SimpleIdentifierParser(), "identifier"),
|
||||||
terminal(TokenType.WITH),
|
terminal(TokenType.WITH),
|
||||||
@@ -22,7 +22,7 @@ class ExtendParser : Parser() {
|
|||||||
|
|
||||||
val complexExtendParser = allOf(
|
val complexExtendParser = allOf(
|
||||||
terminal(TokenType.EXTEND),
|
terminal(TokenType.EXTEND),
|
||||||
assert(TypeParser(), "type to be extended"),
|
assert(SingleTypeParser(), "type to be extended"),
|
||||||
assert(terminal(TokenType.AS), "'as' keyword with identifier"),
|
assert(terminal(TokenType.AS), "'as' keyword with identifier"),
|
||||||
assert(SimpleIdentifierParser(), "identifier"),
|
assert(SimpleIdentifierParser(), "identifier"),
|
||||||
assert(loop(terminal(TokenType.OPEN_CURLY), assert(FunctionDefinitionParser(), "method definition or }"), terminal(TokenType.CLOSE_CURLY)) {
|
assert(loop(terminal(TokenType.OPEN_CURLY), assert(FunctionDefinitionParser(), "method definition or }"), terminal(TokenType.CLOSE_CURLY)) {
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package io.smnp.dsl.ast.parser
|
|||||||
|
|
||||||
import io.smnp.dsl.ast.model.entity.ParserOutput
|
import io.smnp.dsl.ast.model.entity.ParserOutput
|
||||||
import io.smnp.dsl.ast.model.node.OptionalFunctionDefinitionArgumentNode
|
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.TokenList
|
||||||
|
import io.smnp.dsl.token.model.entity.TokenPosition
|
||||||
import io.smnp.dsl.token.model.enumeration.TokenType
|
import io.smnp.dsl.token.model.enumeration.TokenType
|
||||||
|
|
||||||
class OptionalFunctionDefinitionArgumentParser : Parser() {
|
class OptionalFunctionDefinitionArgumentParser : Parser() {
|
||||||
@@ -12,7 +14,7 @@ class OptionalFunctionDefinitionArgumentParser : Parser() {
|
|||||||
optional(allOf(
|
optional(allOf(
|
||||||
terminal(TokenType.COLON),
|
terminal(TokenType.COLON),
|
||||||
TypeParser()
|
TypeParser()
|
||||||
) { it[1] }),
|
) { it[1] }) { UnionTypeNode(emptyList(), TokenPosition.NONE) },
|
||||||
terminal(TokenType.ASSIGN),
|
terminal(TokenType.ASSIGN),
|
||||||
assert(ExpressionParser(), "expression")
|
assert(ExpressionParser(), "expression")
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -187,11 +187,11 @@ abstract class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// optional -> a?
|
// optional -> a?
|
||||||
fun optional(parser: Parser): Parser {
|
fun optional(parser: Parser, createFallbackNode: () -> Node = { Node.NONE }): Parser {
|
||||||
return object : Parser() {
|
return object : Parser() {
|
||||||
override fun tryToParse(input: TokenList): ParserOutput {
|
override fun tryToParse(input: TokenList): ParserOutput {
|
||||||
val output = parser.parse(input)
|
val output = parser.parse(input)
|
||||||
return if (output.result == ParsingResult.OK) output else ParserOutput.ok(Node.NONE)
|
return if (output.result == ParsingResult.OK) output else ParserOutput.ok(createFallbackNode())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package io.smnp.dsl.ast.parser
|
|||||||
|
|
||||||
import io.smnp.dsl.ast.model.entity.ParserOutput
|
import io.smnp.dsl.ast.model.entity.ParserOutput
|
||||||
import io.smnp.dsl.ast.model.node.RegularFunctionDefinitionArgumentNode
|
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.TokenList
|
||||||
|
import io.smnp.dsl.token.model.entity.TokenPosition
|
||||||
import io.smnp.dsl.token.model.enumeration.TokenType
|
import io.smnp.dsl.token.model.enumeration.TokenType
|
||||||
|
|
||||||
class RegularFunctionDefinitionArgumentParser : Parser() {
|
class RegularFunctionDefinitionArgumentParser : Parser() {
|
||||||
@@ -13,9 +15,9 @@ class RegularFunctionDefinitionArgumentParser : Parser() {
|
|||||||
optional(allOf(
|
optional(allOf(
|
||||||
terminal(TokenType.COLON),
|
terminal(TokenType.COLON),
|
||||||
TypeParser()
|
TypeParser()
|
||||||
) { it[1] })
|
) { it[1] }) { UnionTypeNode(emptyList(), TokenPosition.NONE) }
|
||||||
) {
|
) { (vararg, identifier, type) ->
|
||||||
RegularFunctionDefinitionArgumentNode(it[1], it[2], it[0])
|
RegularFunctionDefinitionArgumentNode(identifier, type, vararg)
|
||||||
}.parse(input)
|
}.parse(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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) })
|
||||||
|
) {
|
||||||
|
SingleTypeNode(it[0], it[1])
|
||||||
|
}.parse(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package io.smnp.dsl.ast.parser
|
package io.smnp.dsl.ast.parser
|
||||||
|
|
||||||
import io.smnp.dsl.ast.model.entity.ParserOutput
|
import io.smnp.dsl.ast.model.entity.ParserOutput
|
||||||
import io.smnp.dsl.ast.model.node.TypeNode
|
import io.smnp.dsl.ast.model.node.SingleTypeNode
|
||||||
import io.smnp.dsl.ast.model.node.TypeSpecifiersNode
|
import io.smnp.dsl.ast.model.node.UnionTypeNode
|
||||||
import io.smnp.dsl.token.model.entity.TokenList
|
import io.smnp.dsl.token.model.entity.TokenList
|
||||||
|
|
||||||
class TypeParser : Parser() {
|
class TypeParser : Parser() {
|
||||||
override fun tryToParse(input: TokenList): ParserOutput {
|
override fun tryToParse(input: TokenList): ParserOutput {
|
||||||
return allOf(
|
return mapNode(oneOf(
|
||||||
SimpleIdentifierParser(),
|
SingleTypeParser(),
|
||||||
optional(repeat(TypeSpecifierParser()) { list, tokenPosition -> TypeSpecifiersNode(list, tokenPosition) })
|
UnionTypeParser()
|
||||||
) {
|
)) {
|
||||||
TypeNode(it[0], it[1])
|
node -> if(node is SingleTypeNode) UnionTypeNode(listOf(node), node.position) else node
|
||||||
}.parse(input)
|
}.parse(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,6 @@ import io.smnp.dsl.ast.model.node.TypeSpecifierNode
|
|||||||
import io.smnp.dsl.token.model.enumeration.TokenType
|
import io.smnp.dsl.token.model.enumeration.TokenType
|
||||||
|
|
||||||
class TypeSpecifierParser :
|
class TypeSpecifierParser :
|
||||||
AbstractIterableParser(TokenType.OPEN_ANGLE, TypeParser(), TokenType.CLOSE_ANGLE, { list, tokenPosition ->
|
AbstractIterableParser(TokenType.OPEN_ANGLE, SingleTypeParser(), TokenType.CLOSE_ANGLE, { list, tokenPosition ->
|
||||||
TypeSpecifierNode(list, tokenPosition)
|
TypeSpecifierNode(list, tokenPosition)
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
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, { list, tokenPosition ->
|
||||||
|
UnionTypeNode(list, tokenPosition)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user