// Copyright 2022 Jeff Kim <hiking90@gmail.com>
// SPDX-License-Identifier: Apache-2.0
document = _{ SOI ~ package? ~ imports* ~ decls ~ EOI }
package = { "package" ~ qualified_name ~ ";" }
imports = { import+ }
import = _{ "import" ~ qualified_name ~ ";" }
decls = _{ decl+ }
decl = { annotation_list* ~ unannotated_decl }
annotation_list = { annotation+ }
unannotated_decl = _{ parcelable_decl | interface_decl | enum_decl | union_decl }
optional_unstructured_headers = {
CPP_HEADER ~ C_STR |
NDK_HEADER ~ C_STR |
RUST_TYPE ~ C_STR
}
parcelable_decl = {
PARCELABLE ~ qualified_name ~ optional_type_params ~ "{" ~ parcelable_members* ~ "}" |
PARCELABLE ~ qualified_name ~ optional_type_params ~ optional_unstructured_headers* ~ ";"
}
interface_decl = {
INTERFACE ~ qualified_name ~ ";" |
ONEWAY* ~ INTERFACE ~ qualified_name ~ "{" ~ interface_members? ~ "}"
}
interface_members = {
method_decl ~ interface_members* |
constant_decl ~ interface_members* |
decl ~ interface_members*
}
constant_decl = {
annotation_list* ~ CONST ~ type ~ identifier ~ "=" ~ const_expr ~ ";"
}
generic_type1 = {
"<" ~ type_args ~ "," ~ non_array_type ~ "<" ~ type_args ~ RSHIFT
}
generic_type2 = {
"<" ~ non_array_type ~ "<" ~ type_args ~ RSHIFT
}
generic_type3 = {
"<" ~ type_args ~ ">"
}
// annotation_list is removed from non_array_type and array_type and then moved to type.
non_array_type = {
qualified_name ~
(
generic_type1 | generic_type2 | generic_type3
)?
}
array_type = {
"[" ~ const_expr? ~ "]"
}
type = {
annotation_list* ~ non_array_type ~ array_type*
}
type_args = { type ~ ("," ~ type)* }
method_decl = {
annotation_list* ~ ONEWAY? ~ type ~ identifier ~ "(" ~ arg_list* ~ ")" ~ ";" |
annotation_list* ~ ONEWAY? ~ type ~ identifier ~ "(" ~ arg_list* ~ ")" ~ "=" ~ INTVALUE ~ ";"
}
direction = @{ (INOUT | IN | OUT) ~ &WHITESPACE }
arg = {
direction* ~ type ~ identifier
}
arg_list = { arg ~ ("," ~ arg)* }
enumerator = {
identifier ~ "=" ~ const_expr |
identifier
}
enumerators = _{ enumerator ~ ("," ~ enumerator)* }
enum_decl_body = _{
"{" ~ enumerators ~ "}" |
"{" ~ enumerators ~ "," ~ "}"
}
enum_decl = { ENUM ~ qualified_name ~ enum_decl_body }
union_decl = { UNION ~ qualified_name ~ optional_type_params ~ "{" ~ parcelable_members* ~ "}" }
optional_type_params = { ("<" ~ identifier ~ ("," ~ identifier)* ~ ">")? }
variable_decl = {
type ~ identifier ~ "=" ~ const_expr ~ ";" |
type ~ identifier ~ ";"
}
parcelable_members = { (variable_decl | constant_decl | decl)+ }
keywords = @{
(
INTERFACE | ONEWAY | CONST | INOUT | IN | OUT | ENUM | UNION | CPP_HEADER | NDK_HEADER | RUST_TYPE | PARCELABLE |
TRUE_LITERAL | FALSE_LITERAL
) ~ &WHITESPACE
}
parameter = { identifier ~ "=" ~ const_expr }
parameter_list = { parameter ~ ("," ~ parameter)* }
annotation = {
ANNOTATION ~ "(" ~ const_expr ~ ")" |
ANNOTATION ~ "(" ~ parameter_list* ~ ")" |
ANNOTATION
}
qualified_name = @{ identifier ~ ("." ~ identifier)* }
identifier = { !keywords ~ (IDENTIFIER | CPP_HEADER | NDK_HEADER | RUST_TYPE) }
constant_value_list = { const_expr ~ ("," ~ const_expr)* ~ ","? }
const_expr = {
"{" ~ constant_value_list? ~ "}" |
CHARVALUE | expression | string_expr
}
string_expr = { string_term ~ ("+" ~ string_term)* }
string_term = { C_STR | qualified_name }
expression = { logical_or ~ (logical_or_op ~ logical_or)* }
logical_or_op = { LOGICAL_OR }
logical_or = { logical_and ~ (logical_and_op ~ logical_and)* }
logical_and_op = { LOGICAL_AND }
logical_and = { equality ~ (equality_op ~ equality)* }
equality_op = { EQUALITY | NEQ }
equality = { comparison ~ (comparison_op ~ comparison)* }
comparison_op = { LEQ | GEQ | LT | GT }
comparison = { bitwise_or ~ (bitwise_or_op ~ bitwise_or)* }
// In Android's AIDL parser, bitwise operators have lower precedence than comparison operators.
// However, in rsbinder, bitwise operators are defined to have higher precedence,
// consistent with other programming languages.
bitwise_or_op = { "|" }
bitwise_or = { bitwise_xor ~ (bitwise_xor_op ~ bitwise_xor)* }
bitwise_xor_op = { "^" }
bitwise_xor = { bitwise_and ~ (bitwise_and_op ~ bitwise_and)* }
bitwise_and_op = { "&" }
bitwise_and = { shift ~ (shift_op ~ shift)* }
shift_op = { LSHIFT | RSHIFT }
shift = { arith ~ (arith_op ~ arith)* }
arith_op = { "+" | "-" }
arith = { factor ~ (factor_op ~ factor)* }
factor_op = { "*" | "/" | "%" }
factor = { "(" ~ expression ~ ")" | unary | value }
unary = { unary_op ~ factor }
unary_op = { "+" | "-" | "!" | "~" }
value = {
TRUE_LITERAL | FALSE_LITERAL | HEXVALUE | FLOATVALUE | INTVALUE |
qualified_name
}
ANNOTATION = @{ "@" ~ identifier }
INTERFACE = _{ "interface" }
ONEWAY = { "oneway" }
CONST = _{ "const" }
RSHIFT = { ">>" }
LSHIFT = { "<<" }
IN = { "in" }
OUT = { "out" }
INOUT = { "inout" }
ENUM = _{ "enum" }
UNION = _{ "union" }
CPP_HEADER = { "cpp_header" }
NDK_HEADER = { "ndk_header" }
RUST_TYPE = { "rust_type" }
PARCELABLE = _{ "parcelable" }
IDENTIFIER = @{ ("_" | ASCII_ALPHA)+ ~ ("_" | ASCII_ALPHA | ASCII_DIGIT)* }
TRUE_LITERAL = { "true" }
FALSE_LITERAL = { "false" }
// CHARVALUE = @{ !"\n" ~ ANY }
// CHARVALUE = @{ "'" ~ (!("'" | "\n") ~ ANY) ~ "'" }
CHARVALUE = @{ "'" ~ ("\\" ~ ANY | !"'" ~ ANY) ~ "'" }
INTVALUE = @{ ASCII_DIGIT+ ~ ("l" | "L" | "u8")? }
// int_value = @{ ASCII_DIGIT+ }
// int_suffix = @{ ("l" | "L") | "u8" }
// FLOATVALUE = @{ float_value ~ float_suffix? }
// float_value = @{ ASCII_DIGIT* ~ "."? ~ ASCII_DIGIT+ ~ (("e" | "E") ~ ("-" | "+")? ~ ASCII_DIGIT+)? }
// float_suffix = @{ "f" }
FLOATVALUE = @{ ASCII_DIGIT* ~ "."? ~ ASCII_DIGIT+ ~ (("e" | "E") ~ ("-" | "+")? ~ ASCII_DIGIT+)? ~ "f"? }
HEXVALUE = @{ "0" ~ ("x" | "X") ~ (ASCII_DIGIT | 'a'..'f' | 'A'..'F')+ ~ ("l" | "L" | "u8")? }
// HEXVALUE = @{ hex_value ~ int_suffix? }
// hex_value = @{ "0" ~ ("x" | "X") ~ (ASCII_DIGIT | 'a'..'f' | 'A'..'F')+ }
C_STR = @{ "\"" ~ ( !("\"") ~ ANY | "\\" ~ ANY)* ~ "\"" }
LOGICAL_OR = { "||" }
LOGICAL_AND = { "&&" }
EQUALITY = { "==" }
NEQ = { "!=" }
LEQ = { "<=" }
GEQ = { ">=" }
LT = @{ !"<<" ~ "<" }
GT = @{ !">>" ~ ">" }
LONG_COMMENT = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" }
LINE_COMMENT = _{ "//" ~ (!"\n" ~ ANY)* ~ "\n" }
COMMENT = _{ LONG_COMMENT | LINE_COMMENT }
WHITESPACE = _{ (" " | "\t" | "\r" | "\n")+ }
rust_derive = { (IDENTIFIER ~ "=" ~ (TRUE_LITERAL | FALSE_LITERAL) ~ ","?)+ }