idl =
    ws
  / control_section
  / metadata_section
  / shape_section

ws =
    *(sp / newline / line_comment) ; whitespace

sp =
    *(%x20  / %x09) ; " " and \t

br =
    sp (line_comment / newline) sp ; break

newline =
    %x0A / %x0D.0A ; \n and \r\n

line_comment =
     "//" *not_newline newline

not_newline =
     %x09 / %x20-10FFFF ; Any character except newline

documentation_comment =
    "///" *not_newline br

control_section =
    *(control_statement)

control_statement =
    "$" ws node_object_key ws ":" ws node_value br

version_string =
    1*DIGIT [ "." 1*DIGIT ]

shape_id =
    root_shape_id [shape_id_member]

root_shape_id =
    absolute_root_shape_id / identifier

absolute_root_shape_id =
    namespace "#" identifier

namespace =
    identifier *("." identifier)

identifier =
    (ALPHA / "_") *(ALPHA / DIGIT / "_")

shape_id_member =
    "$" identifier

node_value =
    node_array
  / node_object
  / number
  / node_keywords
  / shape_id
  / text_block
  / quoted_text

node_array =
    empty_node_array / populated_node_array

empty_node_array =
    "[" ws "]"

populated_node_array =
    "[" ws node_value ws
         *(comma node_value ws)
         trailing_comma "]"

trailing_comma =
    [comma]

comma =
    "," ws

node_object =
    empty_node_object / populated_node_object

empty_node_object =
    "{" ws "}"

populated_node_object =
    "{" ws node_object_kvp ws
         *(comma node_object_kvp ws)
         trailing_comma "}"

node_object_kvp =
    node_object_key ws ":" ws node_value

node_object_key =
    quoted_text / identifier

number =
    [minus] int [frac] [exp]

decimal_point =
    %x2E ; .

digit1_9 =
    %x31-39 ; 1-9

e =
    %x65 / %x45 ; e E

exp =
    e [minus / plus] 1*DIGIT

frac =
    decimal_point 1*DIGIT

int =
    zero / (digit1_9 *DIGIT)

minus =
    %x2D ; -

plus =
    %x2B ; +

zero =
    %x30 ; 0

node_keywords =
     "true" / "false" / "null"

quoted_text =
    DQUOTE *quoted_char DQUOTE

quoted_char =
    %x20-21        ; space - "!"
  / %x23-5B        ; "#" - "["
  / %x5D-10FFFF    ; "]"+
  / escaped_char
  / preserved_double

escaped_char =
    escape (escape / "'" / DQUOTE / "b" / "f" / "n" / "r" / "t" / "/" / unicode_escape)

unicode_escape =
    "u" hex hex hex hex

hex =
     DIGIT / %x41-46 / %x61-66

preserved_double =
    escape (%x20-21 / %x23-5B / %x5D-10FFFF)

escape =
    %x5C ; backslash

text_block =
    three_dquotes br *quoted_char three_dquotes

three_dquotes =
    DQUOTE DQUOTE DQUOTE

shape_section =
    [namespace_statement [use_section] [shape_statements]]

namespace_statement =
    "namespace" ws namespace br

use_section =
    *(use_statement)

use_statement =
    "use" ws absolute_root_shape_id br

shape_statements =
    *(shape_statement / apply_statement)

shape_statement =
    [shape_documentation_comments ws]
    trait_statements
    shape_body br

shape_documentation_comments =
    *(documentation_comment)

shape_body =
    simple_shape_statement
  / list_statement
  / set_statement
  / map_statement
  / structure_statement
  / union_statement
  / service_statement
  / operation_statement
  / resource_statement

simple_shape_statement =
    simple_type_name ws identifier

simple_type_name =
    "blob" / "boolean" / "document" / "string"
  / "byte" / "short" / "integer" / "long"
  / "float" / "double" / "bigInteger"
  / "bigDecimal" / "timestamp"

shape_members =
    empty_shape_members / populated_shape_members

empty_shape_members =
    "{" ws "}"

populated_shape_members =
    "{" ws shape_member_kvp
    *(comma shape_member_kvp ws) trailing_comma "}"

shape_member_kvp =
    [shape_documentation_comments]
    trait_statements
    identifier ws ":" ws shape_id

list_statement =
    "list" ws identifier ws shape_members

set_statement =
    "set" ws identifier ws shape_members

map_statement =
    "map" ws identifier ws shape_members

structure_statement =
    "structure" ws identifier ws shape_members

union_statement =
    "union" ws identifier ws shape_members

service_statement =
    "service" ws identifier ws node_object

operation_statement =
    "operation" ws identifier ws node_object

resource_statement =
    "resource" ws identifier ws node_object

apply_statement =
    "apply" ws shape_id ws trait br

trait_statements =
     *(ws trait) ws

trait =
    "@" shape_id [trait_body]

trait_body =
    "(" ws trait_body_value ws ")"

trait_body_value =
    trait_structure / node_value

trait_structure =
    trait_structure_kvp *(ws comma trait_structure_kvp)

trait_structure_kvp =
    node_object_key ws ":" ws node_value

metadata_section =
    *(metadata_statement)

metadata_statement =
    "metadata" ws node_object_key ws "=" ws node_value br