Skip to content

Commit

Permalink
Fix - Unit keyword (and probably others) cannot be used in enum values
Browse files Browse the repository at this point in the history
  • Loading branch information
jerrevanveluw committed Jan 9, 2025
1 parent 103392c commit c347ac0
Show file tree
Hide file tree
Showing 26 changed files with 275 additions and 322 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ import community.flock.wirespec.compiler.core.tokenize.tokenize
import community.flock.wirespec.compiler.core.validate.validate
import community.flock.wirespec.compiler.utils.Logger


fun LanguageSpec.parse(source: String): (Logger) -> Either<NonEmptyList<WirespecException>, AST> =
{ logger ->
tokenize(source)
.also((TOKENIZED::report)(logger))
.optimize()
.optimize(customType.types)
.also((VALIDATED::report)(logger))
.let { Parser(logger).parse(it) }
.also((PARSED::report)(logger))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,50 +1,51 @@
package community.flock.wirespec.compiler.core

import community.flock.wirespec.compiler.core.tokenize.types.Arrow
import community.flock.wirespec.compiler.core.tokenize.types.Brackets
import community.flock.wirespec.compiler.core.tokenize.types.Character
import community.flock.wirespec.compiler.core.tokenize.types.Colon
import community.flock.wirespec.compiler.core.tokenize.types.Comma
import community.flock.wirespec.compiler.core.tokenize.types.CustomType
import community.flock.wirespec.compiler.core.tokenize.types.CustomValue
import community.flock.wirespec.compiler.core.tokenize.types.Equals
import community.flock.wirespec.compiler.core.tokenize.types.ForwardSlash
import community.flock.wirespec.compiler.core.tokenize.types.Hash
import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.types.Method
import community.flock.wirespec.compiler.core.tokenize.types.NewLine
import community.flock.wirespec.compiler.core.tokenize.types.Path
import community.flock.wirespec.compiler.core.tokenize.types.Pipe
import community.flock.wirespec.compiler.core.tokenize.types.QuestionMark
import community.flock.wirespec.compiler.core.tokenize.types.RightCurly
import community.flock.wirespec.compiler.core.tokenize.types.StatusCode
import community.flock.wirespec.compiler.core.tokenize.types.TokenType
import community.flock.wirespec.compiler.core.tokenize.types.WhiteSpaceExceptNewLine
import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean
import community.flock.wirespec.compiler.core.tokenize.types.WsBytes
import community.flock.wirespec.compiler.core.tokenize.types.WsChannelDef
import community.flock.wirespec.compiler.core.tokenize.types.WsComment
import community.flock.wirespec.compiler.core.tokenize.types.WsEndpointDef
import community.flock.wirespec.compiler.core.tokenize.types.WsEnumTypeDef
import community.flock.wirespec.compiler.core.tokenize.types.WsInteger
import community.flock.wirespec.compiler.core.tokenize.types.WsNumber
import community.flock.wirespec.compiler.core.tokenize.types.WsString
import community.flock.wirespec.compiler.core.tokenize.types.WsTypeDef
import community.flock.wirespec.compiler.core.tokenize.types.WsUnit
import community.flock.wirespec.compiler.core.tokenize.Arrow
import community.flock.wirespec.compiler.core.tokenize.Brackets
import community.flock.wirespec.compiler.core.tokenize.ChannelDefinition
import community.flock.wirespec.compiler.core.tokenize.Character
import community.flock.wirespec.compiler.core.tokenize.Colon
import community.flock.wirespec.compiler.core.tokenize.Comma
import community.flock.wirespec.compiler.core.tokenize.Comment
import community.flock.wirespec.compiler.core.tokenize.CustomType
import community.flock.wirespec.compiler.core.tokenize.CustomValue
import community.flock.wirespec.compiler.core.tokenize.EndpointDefinition
import community.flock.wirespec.compiler.core.tokenize.EnumTypeDefinition
import community.flock.wirespec.compiler.core.tokenize.Equals
import community.flock.wirespec.compiler.core.tokenize.ForwardSlash
import community.flock.wirespec.compiler.core.tokenize.Hash
import community.flock.wirespec.compiler.core.tokenize.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.Method
import community.flock.wirespec.compiler.core.tokenize.NewLine
import community.flock.wirespec.compiler.core.tokenize.Path
import community.flock.wirespec.compiler.core.tokenize.Pipe
import community.flock.wirespec.compiler.core.tokenize.QuestionMark
import community.flock.wirespec.compiler.core.tokenize.RightCurly
import community.flock.wirespec.compiler.core.tokenize.StatusCode
import community.flock.wirespec.compiler.core.tokenize.TokenType
import community.flock.wirespec.compiler.core.tokenize.TypeDefinition
import community.flock.wirespec.compiler.core.tokenize.WhiteSpaceExceptNewLine
import community.flock.wirespec.compiler.core.tokenize.WsBoolean
import community.flock.wirespec.compiler.core.tokenize.WsBytes
import community.flock.wirespec.compiler.core.tokenize.WsInteger
import community.flock.wirespec.compiler.core.tokenize.WsNumber
import community.flock.wirespec.compiler.core.tokenize.WsString
import community.flock.wirespec.compiler.core.tokenize.WsUnit

typealias TokenMatcher = Pair<Regex, TokenType>

interface LanguageSpec {
val customType: CustomType
val orderedMatchers: List<TokenMatcher>
}

object WirespecSpec : LanguageSpec {
@Suppress("RegExpRedundantEscape")
override val customType = WsCustomType
override val orderedMatchers = listOf(
Regex("^type") to WsTypeDef,
Regex("^enum") to WsEnumTypeDef,
Regex("^endpoint") to WsEndpointDef,
Regex("^channel") to WsChannelDef,
Regex("^type") to TypeDefinition,
Regex("^enum") to EnumTypeDefinition,
Regex("^endpoint") to EndpointDefinition,
Regex("^channel") to ChannelDefinition,
Regex("^[^\\S\\r\\n]+") to WhiteSpaceExceptNewLine,
Regex("^[\\r\\n]") to NewLine,
Regex("^\\{") to LeftCurly,
Expand All @@ -57,21 +58,26 @@ object WirespecSpec : LanguageSpec {
Regex("^\\?") to QuestionMark,
Regex("^#") to Hash,
Regex("^\\[\\]") to Brackets,
Regex("^String") to WsString,
Regex("^Bytes") to WsBytes,
Regex("^Integer32") to WsInteger,
Regex("^Integer") to WsInteger,
Regex("^Number32") to WsNumber,
Regex("^Number") to WsNumber,
Regex("^Boolean") to WsBoolean,
Regex("^Unit") to WsUnit,
Regex("^GET|^POST|^PUT|^DELETE|^OPTIONS|^HEAD|^PATCH|^TRACE") to Method,
Regex("^[1-5][0-9][0-9]") to StatusCode,
Regex("^[a-z`][a-zA-Z0-9_`]*") to CustomValue,
Regex("^[A-Z][a-zA-Z0-9_]*") to CustomType,
Regex("^[A-Z][a-zA-Z0-9_]*") to customType,
Regex("^/[a-zA-Z0-9-_]+") to Path,
Regex("^\\/\\*(\\*(?!\\/)|[^*])*\\*\\/") to WsComment,
Regex("^\\/\\*(\\*(?!\\/)|[^*])*\\*\\/") to Comment,
Regex("^/") to ForwardSlash,
Regex("^.") to Character // Catch all regular expression if none of the above matched
)
}

data object WsCustomType : CustomType {
override val types = mapOf(
"Boolean" to WsBoolean,
"Bytes" to WsBytes,
"Integer" to WsInteger,
"Integer32" to WsInteger,
"Number" to WsNumber,
"Number32" to WsNumber,
"String" to WsString,
"Unit" to WsUnit,
)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package community.flock.wirespec.compiler.core.exceptions

import community.flock.wirespec.compiler.core.tokenize.Token
import community.flock.wirespec.compiler.core.tokenize.types.TokenType
import community.flock.wirespec.compiler.core.tokenize.types.name
import community.flock.wirespec.compiler.core.tokenize.TokenType
import community.flock.wirespec.compiler.core.tokenize.name
import kotlin.reflect.KClass

sealed class WirespecException(message: String, val coordinates: Token.Coordinates) : RuntimeException(message) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
package community.flock.wirespec.compiler.core.optimize

import arrow.core.NonEmptyList
import community.flock.wirespec.compiler.core.tokenize.CustomType
import community.flock.wirespec.compiler.core.tokenize.SpecificType
import community.flock.wirespec.compiler.core.tokenize.Token
import community.flock.wirespec.compiler.core.tokenize.Tokens

fun NonEmptyList<Token>.optimize(): NonEmptyList<Token> = this
fun Tokens.optimize(specificTypes: Map<String, SpecificType>): Tokens = map { it.specify(specificTypes) }

private fun Token.specify(entries: Map<String, SpecificType>) = when (type) {
is CustomType -> entries[value]
?.let { copy(type = it) }
?: this

else -> this
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import arrow.core.Either
import arrow.core.raise.either
import community.flock.wirespec.compiler.core.exceptions.WirespecException
import community.flock.wirespec.compiler.core.exceptions.WirespecException.CompilerException.ParserException.WrongTokenException
import community.flock.wirespec.compiler.core.tokenize.types.Arrow
import community.flock.wirespec.compiler.core.tokenize.types.Colon
import community.flock.wirespec.compiler.core.tokenize.types.CustomType
import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.types.QuestionMark
import community.flock.wirespec.compiler.core.tokenize.types.RightCurly
import community.flock.wirespec.compiler.core.tokenize.types.WirespecType
import community.flock.wirespec.compiler.core.tokenize.Arrow
import community.flock.wirespec.compiler.core.tokenize.Colon
import community.flock.wirespec.compiler.core.tokenize.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.QuestionMark
import community.flock.wirespec.compiler.core.tokenize.RightCurly
import community.flock.wirespec.compiler.core.tokenize.WirespecType
import community.flock.wirespec.compiler.utils.Logger

class ChannelParser(logger: Logger) : AbstractParser(logger) {
Expand All @@ -21,8 +20,8 @@ class ChannelParser(logger: Logger) : AbstractParser(logger) {
eatToken().bind()
token.log()
when (token.type) {
is CustomType -> parseChannelDefinition(comment, DefinitionIdentifier(token.value)).bind()
else -> raise(WrongTokenException<CustomType>(token).also { eatToken().bind() })
is WirespecType -> parseChannelDefinition(comment, DefinitionIdentifier(token.value)).bind()
else -> raise(WrongTokenException<WirespecType>(token).also { eatToken().bind() })
}
}

Expand Down Expand Up @@ -52,7 +51,7 @@ class ChannelParser(logger: Logger) : AbstractParser(logger) {
}
}

else -> raise(WrongTokenException<CustomType>(token).also { eatToken().bind() })
else -> raise(WrongTokenException<WirespecType>(token).also { eatToken().bind() })
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import arrow.core.Either
import arrow.core.raise.either
import community.flock.wirespec.compiler.core.exceptions.WirespecException
import community.flock.wirespec.compiler.core.exceptions.WirespecException.CompilerException.ParserException.WrongTokenException
import community.flock.wirespec.compiler.core.tokenize.types.Arrow
import community.flock.wirespec.compiler.core.tokenize.types.Brackets
import community.flock.wirespec.compiler.core.tokenize.types.Colon
import community.flock.wirespec.compiler.core.tokenize.types.CustomType
import community.flock.wirespec.compiler.core.tokenize.types.CustomValue
import community.flock.wirespec.compiler.core.tokenize.types.ForwardSlash
import community.flock.wirespec.compiler.core.tokenize.types.Hash
import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.types.Method
import community.flock.wirespec.compiler.core.tokenize.types.Path
import community.flock.wirespec.compiler.core.tokenize.types.QuestionMark
import community.flock.wirespec.compiler.core.tokenize.types.RightCurly
import community.flock.wirespec.compiler.core.tokenize.types.StatusCode
import community.flock.wirespec.compiler.core.tokenize.types.WirespecType
import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean
import community.flock.wirespec.compiler.core.tokenize.types.WsBytes
import community.flock.wirespec.compiler.core.tokenize.types.WsInteger
import community.flock.wirespec.compiler.core.tokenize.types.WsNumber
import community.flock.wirespec.compiler.core.tokenize.types.WsString
import community.flock.wirespec.compiler.core.tokenize.types.WsUnit
import community.flock.wirespec.compiler.core.tokenize.Arrow
import community.flock.wirespec.compiler.core.tokenize.Brackets
import community.flock.wirespec.compiler.core.tokenize.Colon
import community.flock.wirespec.compiler.core.tokenize.CustomType
import community.flock.wirespec.compiler.core.tokenize.CustomValue
import community.flock.wirespec.compiler.core.tokenize.ForwardSlash
import community.flock.wirespec.compiler.core.tokenize.Hash
import community.flock.wirespec.compiler.core.tokenize.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.Method
import community.flock.wirespec.compiler.core.tokenize.Path
import community.flock.wirespec.compiler.core.tokenize.QuestionMark
import community.flock.wirespec.compiler.core.tokenize.RightCurly
import community.flock.wirespec.compiler.core.tokenize.StatusCode
import community.flock.wirespec.compiler.core.tokenize.WirespecType
import community.flock.wirespec.compiler.core.tokenize.WsBoolean
import community.flock.wirespec.compiler.core.tokenize.WsBytes
import community.flock.wirespec.compiler.core.tokenize.WsInteger
import community.flock.wirespec.compiler.core.tokenize.WsNumber
import community.flock.wirespec.compiler.core.tokenize.WsString
import community.flock.wirespec.compiler.core.tokenize.WsUnit
import community.flock.wirespec.compiler.utils.Logger

class EndpointParser(logger: Logger) : AbstractParser(logger) {
Expand All @@ -34,8 +34,8 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) {
eatToken().bind()
token.log()
when (token.type) {
is CustomType -> parseEndpointDefinition(comment, DefinitionIdentifier(token.value)).bind()
else -> raise(WrongTokenException<CustomType>(token).also { eatToken().bind() })
is WirespecType -> parseEndpointDefinition(comment, DefinitionIdentifier(token.value)).bind()
else -> raise(WrongTokenException<WirespecType>(token).also { eatToken().bind() })
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import arrow.core.Either
import arrow.core.raise.either
import community.flock.wirespec.compiler.core.exceptions.WirespecException
import community.flock.wirespec.compiler.core.exceptions.WirespecException.CompilerException.ParserException.WrongTokenException
import community.flock.wirespec.compiler.core.tokenize.types.Comma
import community.flock.wirespec.compiler.core.tokenize.types.CustomType
import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.types.RightCurly
import community.flock.wirespec.compiler.core.tokenize.Comma
import community.flock.wirespec.compiler.core.tokenize.LeftCurly
import community.flock.wirespec.compiler.core.tokenize.RightCurly
import community.flock.wirespec.compiler.core.tokenize.WirespecType
import community.flock.wirespec.compiler.utils.Logger

class EnumParser(logger: Logger) : AbstractParser(logger) {
Expand All @@ -16,8 +16,8 @@ class EnumParser(logger: Logger) : AbstractParser(logger) {
eatToken().bind()
token.log()
when (token.type) {
is CustomType -> parseEnumTypeDefinition(comment, DefinitionIdentifier(token.value)).bind()
else -> raise(WrongTokenException<CustomType>(token).also { eatToken().bind() })
is WirespecType -> parseEnumTypeDefinition(comment, DefinitionIdentifier(token.value)).bind()
else -> raise(WrongTokenException<WirespecType>(token).also { eatToken().bind() })
}
}

Expand All @@ -44,19 +44,19 @@ class EnumParser(logger: Logger) : AbstractParser(logger) {
eatToken().bind()
token.log()
when (token.type) {
is CustomType -> mutableListOf<String>().apply {
is WirespecType -> mutableListOf<String>().apply {
add(token.value)
eatToken().bind()
while (token.type == Comma) {
eatToken().bind()
when (token.type) {
is CustomType -> add(token.value).also { eatToken().bind() }
else -> raise(WrongTokenException<CustomType>(token).also { eatToken().bind() })
is WirespecType -> add(token.value).also { eatToken().bind() }
else -> raise(WrongTokenException<WirespecType>(token).also { eatToken().bind() })
}
}
}

else -> raise(WrongTokenException<CustomType>(token).also { eatToken().bind() })
else -> raise(WrongTokenException<WirespecType>(token).also { eatToken().bind() })
}.toSet()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import arrow.core.nel
import arrow.core.raise.either
import community.flock.wirespec.compiler.core.exceptions.WirespecException
import community.flock.wirespec.compiler.core.exceptions.WirespecException.CompilerException.ParserException.WrongTokenException
import community.flock.wirespec.compiler.core.tokenize.ChannelDefinition
import community.flock.wirespec.compiler.core.tokenize.Comment
import community.flock.wirespec.compiler.core.tokenize.EndpointDefinition
import community.flock.wirespec.compiler.core.tokenize.EnumTypeDefinition
import community.flock.wirespec.compiler.core.tokenize.Token
import community.flock.wirespec.compiler.core.tokenize.Tokens
import community.flock.wirespec.compiler.core.tokenize.TypeDefinition
import community.flock.wirespec.compiler.core.tokenize.WirespecDefinition
import community.flock.wirespec.compiler.core.tokenize.removeWhiteSpace
import community.flock.wirespec.compiler.core.tokenize.types.WirespecDefinition
import community.flock.wirespec.compiler.core.tokenize.types.WsChannelDef
import community.flock.wirespec.compiler.core.tokenize.types.WsComment
import community.flock.wirespec.compiler.core.tokenize.types.WsEndpointDef
import community.flock.wirespec.compiler.core.tokenize.types.WsEnumTypeDef
import community.flock.wirespec.compiler.core.tokenize.types.WsTypeDef
import community.flock.wirespec.compiler.utils.Logger

typealias AST = List<Node>
Expand Down Expand Up @@ -45,15 +45,15 @@ class Parser(logger: Logger) : AbstractParser(logger) {
private fun TokenProvider.parseDefinition() = either {
token.log()
val comment = when (token.type) {
is WsComment -> Comment(token.value).also { eatToken().bind() }
is Comment -> Comment(token.value).also { eatToken().bind() }
else -> null
}
when (token.type) {
is WirespecDefinition -> when (token.type as WirespecDefinition) {
is WsTypeDef -> with(typeParser) { parseType(comment) }.bind()
is WsEnumTypeDef -> with(enumParser) { parseEnum(comment) }.bind()
is WsEndpointDef -> with(endpointParser) { parseEndpoint(comment) }.bind()
is WsChannelDef -> with(channelParser) { parseChannel(comment) }.bind()
is TypeDefinition -> with(typeParser) { parseType(comment) }.bind()
is EnumTypeDefinition -> with(enumParser) { parseEnum(comment) }.bind()
is EndpointDefinition -> with(endpointParser) { parseEndpoint(comment) }.bind()
is ChannelDefinition -> with(channelParser) { parseChannel(comment) }.bind()
}

else -> raise(WrongTokenException<WirespecDefinition>(token).also { eatToken().bind() })
Expand Down
Loading

0 comments on commit c347ac0

Please sign in to comment.