; ---------------------------------------------------------------------------- ;
;  Type                                                                        ;
; ---------------------------------------------------------------------------- ;

Type
	= Atomic [Union / Intersection]
	/ Nullable

ParenthesizedType
	= Atomic [Union / Intersection / Conditional]
	/ Nullable

Union
	= 1*(TokenUnion Atomic)

Intersection
	= 1*(TokenIntersection Atomic)

Conditional
    = 1*ByteHorizontalWs TokenIs [TokenNot] Atomic TokenNullable Type TokenColon ParenthesizedType

Nullable
	= TokenNullable Atomic

Atomic
	= TokenIdentifier [Generic / Callable / Array]
	/ TokenThisVariable
	/ TokenParenthesesOpen ParenthesizedType TokenParenthesesClose [Array]

Generic
	= TokenAngleBracketOpen GenericTypeArgument *(TokenComma GenericTypeArgument) TokenAngleBracketClose

GenericTypeArgument
    = [TokenContravariant / TokenCovariant] Type
    / TokenWildcard

Callable
	= [CallableTemplate] TokenParenthesesOpen [CallableParameters] TokenParenthesesClose TokenColon CallableReturnType

CallableTemplate
	= TokenAngleBracketOpen CallableTemplateArgument *(TokenComma CallableTemplateArgument) TokenAngleBracketClose

CallableTemplateArgument
    = TokenIdentifier [1*ByteHorizontalWs TokenOf Type]

CallableParameters
	= CallableParameter *(TokenComma CallableParameter)

CallableParameter
	= Type [CallableParameterIsReference] [CallableParameterIsVariadic] [CallableParameterName] [CallableParameterIsOptional]

CallableParameterIsReference
	= TokenIntersection

CallableParameterIsVariadic
	= TokenVariadic

CallableParameterName
	= TokenVariable

CallableParameterIsOptional
	= TokenEqualSign

CallableReturnType
	= TokenIdentifier [Generic]
	/ Nullable
	/ TokenParenthesesOpen Type TokenParenthesesClose

Array
	= 1*(TokenSquareBracketOpen TokenSquareBracketClose)

ArrayShape
    = TokenCurlyBracketOpen ArrayShapeItem *(TokenComma ArrayShapeItem) TokenCurlyBracketClose

ArrayShapeItem
    = (ConstantString / ConstantInt / TokenIdentifier) TokenNullable TokenColon Type
    / Type

; ---------------------------------------------------------------------------- ;
;  ConstantExpr                                                                ;
; ---------------------------------------------------------------------------- ;

ConstantExpr
	= ConstantFloat *ByteHorizontalWs
	/ ConstantInt *ByteHorizontalWs
	/ ConstantTrue *ByteHorizontalWs
	/ ConstantFalse *ByteHorizontalWs
	/ ConstantNull *ByteHorizontalWs
	/ ConstantString *ByteHorizontalWs
	/ ConstantArray *ByteHorizontalWs
	/ ConstantFetch *ByteHorizontalWs

ConstantFloat
	= [ByteNumberSign] 1*ByteDecDigit *("_" 1*ByteDecDigit) "." [1*ByteDecDigit *("_" 1*ByteDecDigit)] [ConstantFloatExp]
	/ [ByteNumberSign] 1*ByteDecDigit *("_" 1*ByteDecDigit) ConstantFloatExp
	/ [ByteNumberSign] "." 1*ByteDecDigit *("_" 1*ByteDecDigit) [ConstantFloatExp]

ConstantFloatExp
	= "e" [ByteNumberSign] 1*ByteDecDigit *("_" 1*ByteDecDigit)

ConstantInt
	= [ByteNumberSign] "0b" 1*ByteBinDigit *("_" 1*ByteBinDigit)
	/ [ByteNumberSign] "0o" 1*ByteOctDigit *("_" 1*ByteOctDigit)
	/ [ByteNumberSign] "0x" 1*ByteHexDigit *("_" 1*ByteHexDigit)
	/ [ByteNumberSign] 1*ByteDecDigit *("_" 1*ByteDecDigit)

ConstantTrue
	= "true"

ConstantFalse
	= "false"

ConstantNull
	= "null"

ConstantString
	= ByteSingleQuote *(ByteBackslash ByteNotEol / ByteNotEolAndNotBackslashAndNotSingleQuote) ByteSingleQuote
	/ ByteDoubleQuote *(ByteBackslash ByteNotEol / ByteNotEolAndNotBackslashAndNotDoubleQuote) ByteDoubleQuote

ConstantArray
	= TokenSquareBracketOpen [ConstantArrayItems] TokenSquareBracketClose
	/ "array" TokenParenthesesOpen [ConstantArrayItems] TokenParenthesesClose

ConstantArrayItems
	= ConstantArrayItem *(TokenComma ConstantArrayItem) [TokenComma]

ConstantArrayItem
	= ConstantExpr [TokenDoubleArrow ConstantExpr]

ConstantFetch
	= TokenIdentifier [TokenDoubleColon ByteIdentifierFirst *ByteIdentifierSecond *ByteHorizontalWs]


; ---------------------------------------------------------------------------- ;
;  Tokens                                                                      ;
; ---------------------------------------------------------------------------- ;

TokenUnion
	= "|" *ByteHorizontalWs

TokenIntersection
	= "&" *ByteHorizontalWs

TokenNullable
	= "?" *ByteHorizontalWs

TokenParenthesesOpen
	= "(" *ByteHorizontalWs

TokenParenthesesClose
	= ")" *ByteHorizontalWs

TokenAngleBracketOpen
	= "<" *ByteHorizontalWs

TokenAngleBracketClose
	= ">" *ByteHorizontalWs

TokenSquareBracketOpen
	= "[" *ByteHorizontalWs

TokenSquareBracketClose
	= "]" *ByteHorizontalWs

TokenCurlyBracketOpen
    = "{" *ByteHorizontalWs

TokenCurlyBracketClose
    = "}" *ByteHorizontalWs

TokenComma
	= "," *ByteHorizontalWs

TokenColon
	= ":" *ByteHorizontalWs

TokenVariadic
	= "..." *ByteHorizontalWs

TokenEqualSign
	= "=" *ByteHorizontalWs

TokenVariable
	= "$" ByteIdentifierFirst *ByteIdentifierSecond *ByteHorizontalWs

TokenDoubleArrow
	= "=>" *ByteHorizontalWs

TokenDoubleColon
	= "::" *ByteHorizontalWs

TokenThisVariable
	= %s"$this" *ByteHorizontalWs

TokenIs
	= %s"is" 1*ByteHorizontalWs

TokenNot
	= %s"not" 1*ByteHorizontalWs

TokenOf
	= %s"of" 1*ByteHorizontalWs

TokenContravariant
    = %s"contravariant" 1*ByteHorizontalWs

TokenCovariant
    = %s"covariant" 1*ByteHorizontalWs

TokenWildcard
	= "*" *ByteHorizontalWs

TokenIdentifier
	= [ByteBackslash] ByteIdentifierFirst *ByteIdentifierSecond *(ByteBackslash ByteIdentifierFirst *ByteIdentifierSecond) *ByteHorizontalWs


; ---------------------------------------------------------------------------- ;
;  Bytes                                                                       ;
; ---------------------------------------------------------------------------- ;

ByteHorizontalWs
	= %x09 ; horizontal tab
	/ " "

ByteNumberSign
	= "+"
	/ "-"

ByteBinDigit
	= %x30-31 ; 0-1

ByteOctDigit
	= %x30-37 ; 0-7

ByteDecDigit
	= %x30-39 ; 0-9

ByteHexDigit
	= %x30-39 ; 0-9
	/ %x41-46 ; A-F
	/ %x61-66 ; a-f

ByteIdentifierFirst
	= %x41-5A ; A-Z
	/ "_"
	/ %x61-7A ; a-z
	/ %x80-FF

ByteIdentifierSecond
	= ByteIdentifierFirst
	/ %x30-39 ; 0-9

ByteSingleQuote
	= %x27    ; '

ByteDoubleQuote
	= %x22    ; "

ByteBackslash
	= %x5C    ; \

ByteNotEol
	= %x00-09 ; skip LF
	/ %x0B-0C ; skip CR
	/ %x0E-FF

ByteNotEolAndNotBackslashAndNotSingleQuote
	= %x00-09 ; skip LF
	/ %x0B-0C ; skip CR
	/ %x0E-26 ; skip single quote
	/ %x28-5B ; skip backslash
	/ %x5D-FF

ByteNotEolAndNotBackslashAndNotDoubleQuote
	= %x00-09 ; skip LF
	/ %x0B-0C ; skip CR
	/ %x0E-21 ; skip double quote
	/ %x23-5B ; skip backslash
	/ %x5D-FF
