grammar TrinoType;

trinotype
    : identifier                                                                  #base
    | identifier LPARENS typeParameter (COMMA typeParameter)* RPARENS             #parameterized
    | ROW LPARENS identifier trinotype (COMMA identifier trinotype)* RPARENS      #row
    | TIMESTAMP WITHOUT_TIME_ZONE                                                 #timestamp
    | TIMESTAMP LPARENS precision = INTEGER_VALUE RPARENS (WITHOUT_TIME_ZONE)?    #timestampPrecision
    | TIMESTAMP WITH_TIME_ZONE                                                    #timestamptz
    | TIMESTAMP LPARENS precision = INTEGER_VALUE RPARENS WITH_TIME_ZONE          #timestamptzPrecision
    | TIME WITHOUT_TIME_ZONE                                                      #time
    | TIME LPARENS precision = INTEGER_VALUE RPARENS (WITHOUT_TIME_ZONE)?         #timePrecision
    | TIME WITH_TIME_ZONE                                                         #timetz
    | INTERVAL YEAR_TO_MONTH                                                      #intervalYearToMonth
    | INTERVAL DAY_TO_SECOND                                                      #intervalDayToSecond
    ;

identifier
    : IDENTIFIER             #unquotedIdentifier
    | nonReserved            #unquotedIdentifier
    ;

// This is trick stolen from the Trino SqlBase grammar.
//
// IMPORTANT: this rule must only contain tokens. Nested rules are not supported.
//            See SqlParser.exitNonReserved
nonReserved
    // IMPORTANT: this rule must only contain tokens. Nested rules are not supported. See SqlParser.exitNonReserved
    : INTERVAL | ROW | TIME | TIMESTAMP | WITHOUT_TIME_ZONE | WITH_TIME_ZONE |
        YEAR_TO_MONTH | DAY_TO_SECOND | INTERVAL | UNKNOWN
    ;

typeParameter
    : INTEGER_VALUE | trinotype
    ;

//
// Extra phrases
//
ROW: 'row' | 'ROW';
TIME: 'time' | 'TIME';
TIMESTAMP: 'timestamp' | 'TIMESTAMP';
WITHOUT_TIME_ZONE: 'without time zone' | 'WITHOUT TIME ZONE';
WITH_TIME_ZONE: 'with time zone' | 'WITH TIME ZONE';
YEAR_TO_MONTH: 'year to month' | 'YEAR TO MONTH';
DAY_TO_SECOND: 'day to second' | 'DAY TO SECOND';
INTERVAL: 'interval' | 'INTERVAL';
UNKNOWN: 'unknown' | 'UNKNOWN';

//
// Symbols
//

COMMA: ',';
LPARENS: '(';
RPARENS: ')';

//
// Literals
//

INTEGER_VALUE
    : DECIMAL_INTEGER
    ;

IDENTIFIER
    : [a-zA-Z_][a-zA-Z_0-9]*
    ;

fragment DECIMAL_INTEGER
    : DIGIT ('_'? DIGIT)*
    ;

fragment DIGIT
    : [0-9]
    ;

//
// Whitespace
//

WS
    : [ \r\n\t]+ -> channel(HIDDEN)
    ;
