grammar Aidl;

@members {
    int oneway = 0;
}

aidl: 
    packageStatement? (
        parcelableStatement | 
        importStatement* interfaceStatement
    )?;

packageStatement: 
    PACKAGE name SE;

parcelableStatement: 
    PARCELABLE id SE;

importStatement: 
    IMPORT path SE;

interfaceStatement:
    {oneway = 0;}
    (ONEWAY {oneway = 1;})? 
    INTERFACE id LC interfaceSubStatement* RC;

interfaceSubStatement: 
    methodStatement | constStatement;

methodStatement:
    {oneway &= 1;}
    (ONEWAY {oneway |= 2;})? 
    methodReturnType id LP paramList? RP (EQ INT)? SE;

constStatement: 
    CONST INT id EQ INTEGER SE |
    CONST STRING id EQ LITERALSTRING SE;

methodReturnType:
    {oneway==0}? (NULLABLE? type) | VOID;

paramList:
    param (CO param)*;

param:
	NULLABLE? paramTag? paramType[$paramTag.text] id;

paramTag:
    IN | 
    {oneway==0}? (OUT | INOUT);

paramType[String tag]
locals [int tid = 0]:
    {$tag==null}? (
        (PRIMITIVE | STRING | interfaceName {$tid = 1;})
    ) | {$tag!=null}? (
        MAP 
        | CHARSEQUENCE
        | list 
        | (
            name {$tid = -1;}
            | type {$tid = $type.tid;}
        ) {$tag.equals("in")}?
        | className {$tid = 2;}
        | type LB RB
    );

type
returns [int tid = 0]: 
    (PRIMITIVE | STRING | CHARSEQUENCE | MAP | list | className {$tid = 2;}) (LB RB)*;
list: LIST (LA type RA)?;
interfaceName: IBINDER | name;
className: name;
name: ID | PATH;
path: PATH;
id: ID;

PRIMITIVE: BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | BOOLEAN | CHAR;
BYTE: 'byte';
SHORT: 'short';
INT: 'int';
LONG: 'long';
FLOAT: 'float';
DOUBLE: 'double';
BOOLEAN: 'boolean';
CHAR: 'char';
PACKAGE: 'package';
PARCELABLE: 'parcelable';
IMPORT: 'import';
INTERFACE: 'interface';
ONEWAY: 'oneway';
VOID: 'void';
CONST: 'const';
NULLABLE: '@nullable';
INOUT: 'inout';
IN: 'in';
OUT: 'out';
STRING: 'String';
CHARSEQUENCE: 'CharSequence';
MAP: 'Map';
LIST: 'List';
IBINDER: 'IBinder';

LP: '(';
RP: ')';
LC: '{';
RC: '}';
LB: '[';
RB: ']';
LA: '<';
RA: '>';
DOT: '.';
CO: ',';
SE: ';';
EQ: '=';

PATH: ID (DOT ID)+;
ID: [_a-zA-Z][_a-zA-Z0-9]*;
INTEGER: [0-9]+;
LITERALSTRING: '"' (ESC | .)*? '"';
fragment ESC: '\\"' | '\\\\';

WS: [ \t\r\n]+ -> channel(1);
COMMENT_BLOCK: '/*' .*? '*/' -> channel(2);
COMMENT_LINE: '//' .*? EL -> channel(2);
fragment EL: '\r\n' | '\n' | '\n\r' | EOF;