/*
 * Grammar rules for type names generated by rustc for the debug info.
 *
 * For the details about debug info type names, see:
 * https://github.com/rust-lang/rust/blob/9da4644d5685aa0c4daa4aea6ddc9eb834ae51cc/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
 * https://github.com/rust-lang/rust/blob/9da4644d5685aa0c4daa4aea6ddc9eb834ae51cc/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
*/

grammar RsTypeName;

@header {
package org.rust.debugger.lang;
}

parseTypeName : typeName EOF ;

typeName
    : msvcTypeName
    | commonTypeName
    ;

msvcTypeName
    : msvcStr
    | msvcNever
    | msvcTuple
    | msvcPtr_const
    | msvcPtr_mut
    | msvcRef
    | msvcRef_mut
    | msvcArray
    | msvcSlice
    | msvcEnum
    | msvcEnum2
    ;

msvcStr: STR ;

msvcNever: NEVER ;

msvcTuple
    : TUPLE LT items=commaSeparatedList? GT
    ;

msvcPtr_const
    : PTR_CONST LT type=typeName GT
    ;

msvcPtr_mut
    : PTR_MUT LT type=typeName GT
    ;

msvcRef
    : REF LT type=typeName GT
    ;

msvcRef_mut
    : REF_MUT LT type=typeName GT
    ;

msvcArray
    : ARRAY LT type=typeName COMMA length=WORD GT
    ;

msvcSlice
    : SLICE LT type=typeName GT
    ;

//BACKCOMPAT: Rust 1.64
msvcEnum
    : ENUM LT type=typeName GT
    | ENUM LT type=typeName COMMA variant=WORD GT
    | ENUM LT type=typeName COMMA typeName COMMA typeName COMMA variant=WORD GT
    ;

// Since Rust 1.65, introduced in https://github.com/rust-lang/rust/pull/98393
msvcEnum2
    : ENUM2 LT type=typeName GT
    ;


commonTypeName
    : str
    | never
    | tuple
    | ptrConst
    | ptrMut
    | ref
    | refMut
    | array
    | slice
    | qualifiedName
    ;

str: AND STR ;

never : EXCL ;

tuple
    : LPAREN items=commaSeparatedList? RPAREN
    ;

ptrConst
    : MUL CONST type=typeName
    ;

ptrMut
    : MUL MUT type=typeName
    ;

ref
    : AND type=typeName
    ;

refMut
    : AND MUT type=typeName
    ;

array
    : LBRACK type=typeName SEMICOLON length=WORD  RBRACK
    ;

slice
    : LBRACK type=typeName RBRACK
    ;

qualifiedName
    : ( namespaceSegments+=qualifiedNameSegment COLONCOLON )* namespaceSegments+=qualifiedNameSegment
    ;

qualifiedNameSegment
    : name=WORD (LT items=commaSeparatedList GT)?
    ;

commaSeparatedList
    : items+=typeName ( COMMA items+=typeName )*
    ;

STR : 'str' ;
NEVER: 'never$' ;
TUPLE : 'tuple$' ;
PTR_CONST: 'ptr_const$' ;
PTR_MUT: 'ptr_mut$' ;
REF: 'ref$' ;
REF_MUT: 'ref_mut$' ;
ARRAY : 'array$' ;
SLICE : 'slice$' ;
ENUM: 'enum$' ;
ENUM2: 'enum2$' ;

// Currently not fully supported
DYN: 'dyn$' ;
IMPL: 'impl$' ;
ASSOC: 'assoc$' ;
ASYNC_BLOCK_ENV: 'async_block_env$' ;
ASYNC_FN_ENV: 'async_fn_env$' ;
GENERATOR_FN_ENV: 'generator_env$' ;
CLOSURE_FN_ENV: 'closure_env$' ;

LT: '<' ;
GT: '>' ;
LPAREN: '(' ;
RPAREN: ')' ;
LBRACK: '[' ;
RBRACK: ']' ;
COMMA: ',' ;
EQ: '=' ;
ARROW: '->' ;
EXCL: '!' ;
COLONCOLON: '::' ;
SEMICOLON: ';' ;
AND: '&' ;
MUL: '*' ;
CONST: 'const' ;
MUT: 'mut' ;

WORD : (LETTER | DIGIT)+ ;
fragment LETTER : 'a'..'z' | 'A'..'Z' | '_' ;
fragment DIGIT : '0'..'9' ;

WS : [ \t]+ -> skip ;
