signature : "instance" method_signature <END>
          | method_signature <END>
          | type <END>
          ;

method_signature : type type "::" <ID> opt_method_generic_types "(" opt_types ")"
                 ;

qualified_name : <ID> qualified_name_tail
               ;

qualified_name_tail : "." <ID> qualified_name_tail
                    | /* empty */
                    ;

type : primitive_type opt_array_tail
     | class_type opt_array_tail
     | generic_type opt_array_tail
     ;

opt_array_tail : "[" "]" opt_array_tail
               | /* empty */
               ;

opt_types : types
          | /* empty */
          ;

types : type opt_type_tail
      ;

opt_type_tail : "," type opt_type_tail
              | /* empty */
              ;

primitive_type : "object"
               | "void"
               | "bool"
               | "int"
               | "long"
               | "string"
               ;

generic_type : "!" <INT>   # class generic
             | "!!" <INT>  # method generic
             ;

class_type : "class" class_name
           | "class" assembly_name class_name
           ;

class_name : qualified_name opt_class_generic_types
           | qualified_name "/" <ID> opt_generic_types
           ;

assembly_name : "[" qualified_name "]"
              ;

opt_method_generic_types : "<" types ">"
                         | /* empty */
                         ;

#
# Length of `types` must be equal to the <INT> value.
#
opt_class_generic_types : "`" <INT> "<" types ">"
                        | /* empty */
                        ;

#
# ID = [a-zA-Z_][a-zA-Z0-9_\.]+
# INT = [0-9]+
# END = EOF
#

