default namespace core = "http://www.gtk.org/introspection/core/1.0"
namespace c = "http://www.gtk.org/introspection/c/1.0"
namespace glib = "http://www.gtk.org/introspection/glib/1.0"

grammar {
  start = Repository

  Repository =
    element repository {
      attribute version { xsd:string }?,
      attribute c:identifier-prefixes { xsd:string }?,
      attribute c:symbol-prefixes { xsd:string }?,

      (Include*
       & CInclude*
       & Package*
       & Namespace*)
    }

  Namespace =
    element namespace {
      attribute name { xsd:string }?,
      attribute version { xsd:string }?,
      attribute c:identifier-prefixes { xsd:string }?,
      attribute c:symbol-prefixes { xsd:string }?,
      attribute c:prefix { xsd:string }?,
      attribute shared-library { xsd:string }?,

      (Alias*
       & Class*
       & Interface*
       & Record*
       & Enum*
       & Function*
       & Union*
       & BitField*
       & Callback*
       & Constant*
       & Annotation*
       & Boxed*)
    }

  Annotation =
    element attribute {
      attribute name { xsd:string },
      attribute value { xsd:string }
    }

  CInclude =
    element c:include {
      attribute name { xsd:string },

      empty
    }

  Include =
    element include {
      attribute name { xsd:string },
      attribute version { xsd:string }?,

      empty
    }

  Package =
    element package {
      attribute name { xsd:string },

      empty
    }

  Alias =
    element alias {
      Info.attrs,
      attribute name { xsd:string },
      attribute c:type { xsd:string },

      (Info.elements
       & Type)
    }

  Interface =
    element interface {
      Info.attrs,
      attribute name { xsd:string },
      attribute glib:type-name { xsd:string },
      attribute glib:get-type { xsd:string },

      attribute c:symbol-prefix { xsd:string }?,
      attribute c:type { xsd:string }?,
      attribute glib:type-struct { xsd:string }?,

      (Info.elements
       & Prerequisite*
       & Implements*
       & Function*
       & Constructor?
       & Method*
       & VirtualMethod*
       & Field*
       & Property*
       & Signal*
       & Callback*
       & Constant*)
    }

  Class =
    element class {
      Info.attrs,
      attribute name { xsd:string },
      attribute glib:type-name { xsd:string },
      attribute glib:get-type { xsd:string },

      attribute parent { xsd:string }?,
      attribute glib:type-struct { xsd:string }?,
      attribute glib:ref-func { xsd:string }?,
      attribute glib:unref-func { xsd:string }?,
      attribute glib:set-value-func { xsd:string }?,
      attribute glib:get-value-func { xsd:string }?,
      attribute c:type { xsd:string }?,
      attribute c:symbol-prefix { xsd:string }?,
      attribute abstract { "0" | "1" }?,
      attribute glib:fundamental { "0" | "1" }?,

      (Info.elements
       & Implements*
       & Constructor*
       & Method*
       & Function*
       & VirtualMethod*
       & Field*
       & Property*
       & Signal*
       & Union*
       & Constant*
       & Record*
       & Callback*)
    }

  Boxed =
    element glib:boxed {
      Info.attrs,
      attribute glib:name { xsd:string },

      attribute c:symbol-prefix { xsd:string }?,
      attribute glib:type-name { xsd:string }?,
      attribute glib:get-type { xsd:string }?,

      (Info.elements
       & Function*)
    }

  Record =
    element record {
      Info.attrs,
      attribute name { xsd:string },

      attribute c:type { xsd:string }?,
      attribute disguised { "0" | "1" }?,
      attribute glib:type-name { xsd:string }?,
      attribute glib:get-type { xsd:string }?,
      attribute c:symbol-prefix { xsd:string }?,
      attribute foreign { "0" | "1" }?,
      attribute glib:is-gtype-struct-for { xsd:string }?,

      (Info.elements
       & Field*
       & Function*
       & Union*
       & Method*
       & Constructor*
       & Property*)
    }

  Info.attrs = (
    attribute introspectable { "0" | "1" }?,
    attribute deprecated { xsd:string }?,
    attribute deprecated-version { xsd:string }?,
    attribute version { xsd:string }?,
    attribute stability { xsd:string }?
  )

  DocElements = (
    element doc-version {
      attribute xml:space { "preserve" }?,
      attribute xml:whitespace { "preserve" }?,

      text
    }?
    & element doc-stability {
      attribute xml:space { "preserve" }?,
      attribute xml:whitespace { "preserve" }?,

      text
    }?
    & element doc {
      attribute xml:space { "preserve" }?,
      attribute xml:whitespace { "preserve" }?,
      attribute filename { xsd:string },
      attribute line { xsd:string },
      attribute column { xsd:string },

      text
    }?
    & element doc-deprecated {
      attribute xml:space { "preserve" }?,
      attribute xml:whitespace { "preserve" }?,

      text
    }?
    & element source-position {
      attribute filename { xsd:string },
      attribute line { xsd:string },
      attribute column { xsd:string },
    }?
  )

  Info.elements = (
    DocElements
    & Annotation*
  )

  Constant =
    element constant {
        Info.attrs,
        attribute name { xsd:string },
        attribute value { xsd:string },
        attribute c:type { xsd:string }?,
        attribute c:identifier { xsd:string }?,

        (Info.elements
         & AnyType?)
    }

  Property =
    element property {
      Info.attrs,
      attribute name { xsd:string },

      attribute writable { "0" | "1" }?,
      attribute readable { "0" | "1" }?,
      attribute construct { "0" | "1" }?,
      attribute construct-only { "0" | "1" }?,
      TransferOwnership?,

      (Info.elements
       & AnyType)
    }

  Signal =
    element glib:signal {
      Info.attrs,
      attribute name { xsd:string },

      attribute detailed { "0" | "1" }?,
      attribute when { "first" | "last" | "cleanup" }?,
      attribute action { "0" | "1" }?,
      attribute no-hooks { "0" | "1" }?,
      attribute no-recurse { "0" | "1" }?,

      (Info.elements
       & Callable.params?
       & Callable.return?)
    }

  Field =
    element field {
      Info.attrs,
      attribute name { xsd:string },

      attribute writable { "0" | "1" }?,
      attribute readable { "0" | "1" }?,
      attribute private { "0" | "1" }?,
      attribute bits { xsd:integer }?,

      (Info.elements
       & (Callback | AnyType))
    }

  Callback =
    element callback {
      Info.attrs,
      attribute name { xsd:string },

      attribute c:type { xsd:string }?,
      attribute throws { "0" | "1" }?,

      (Info.elements
       & Callable.params?
       & Callable.return?)
    }

  Implements  =
    element implements {
      attribute name { xsd:string }
    }

  Prerequisite  =
    element prerequisite {
      attribute name { xsd:string }
    }

  AnyType = (Type | ArrayType)

  Type =
    element type {
      attribute name { xsd:string }?,
      attribute c:type { xsd:string }?,
      attribute introspectable { xsd:string }?,

      (DocElements & AnyType*)
    }

  ArrayType =
    element array {
      attribute name { xsd:string }?,
      attribute zero-terminated { "0" | "1" }?,
      attribute fixed-size { xsd:integer }?,
      attribute introspectable { xsd:string }?,
      attribute length { xsd:integer }?,
      attribute c:type { xsd:string }?,

      AnyType
    }

  TransferOwnership =
    attribute transfer-ownership { "none" | "container" | "full" }

  Constructor =
    element constructor {
      Callable.attrs,

      (Info.elements
       & Callable.params?
       & Callable.return?)
    }

  Callable.attrs = (
    Info.attrs,
    attribute name { xsd:string },

    attribute c:identifier { xsd:string }?,
    attribute shadowed-by { xsd:string }?,
    attribute shadows { xsd:string }?,
    attribute throws { "0" | "1" }?,
    attribute moved-to { xsd:string }?
  )

  VarArgs =
    element varargs {
      empty
    }

  Callable.params =
    element parameters {
      element parameter {
        attribute name { xsd:string }?,
        attribute nullable { "0" | "1" }?,
        attribute allow-none { "0" | "1" }?,
        attribute introspectable { "0" | "1" }?,
        attribute closure { xsd:integer }?,
        attribute destroy { xsd:integer }?,
        attribute scope { "notified" | "async" | "call" }?,
        attribute direction { "out" | "in" | "inout" }?,
        attribute caller-allocates { "0" | "1" }?,
        attribute optional { "0" | "1" }?,
        attribute skip { "0" | "1" }?,
        TransferOwnership?,

        (DocElements
         & (AnyType | VarArgs))
      }*

      & element instance-parameter {
        attribute name { xsd:string },

        attribute nullable { "0" | "1" }?,
        attribute allow-none { "0" | "1" }?,
        attribute direction { "out" | "in" | "inout" }?,
        attribute caller-allocates { "0" | "1" }?,
        TransferOwnership?,

        (DocElements
         & Type)
      }?
    }

  Callable.return =
    element return-value {
      attribute introspectable { xsd:string }?,
      attribute nullable { "0" | "1" }?,
      attribute closure { xsd:integer }?,
      attribute scope { "notified" | "async" | "call" }?,
      attribute destroy { xsd:integer }?,
      attribute skip { "0" | "1" }?,
      attribute allow-none { "0" | "1" }?,
      TransferOwnership?,

      (DocElements
       & AnyType)
    }

  Function =
    element function {
      Callable.attrs,

      (Callable.params?
       & Callable.return?
       & DocElements)
    }

  Method =
    element method {
      Callable.attrs,

      (Info.elements
       & Callable.params?
       & Callable.return?)
    }

  VirtualMethod =
    element virtual-method {
      Callable.attrs,
      attribute invoker { xsd:string }?,

      (Info.elements
       & Callable.params?
       & Callable.return?)
    }

  Union =
    element union {
      Info.attrs,
      attribute name { xsd:string }?,
      attribute c:type { xsd:string }?,
      attribute c:symbol-prefix { xsd:string }?,
      attribute glib:get-type { xsd:string }?,
      attribute glib:type-name { xsd:string }?,

      (Info.elements
       & Field*
       & Constructor*
       & Method*
       & Function*
       & Record*)
    }

  BitField =
    element bitfield {
      Info.attrs,
      attribute name { xsd:string },
      attribute c:type { xsd:string },

      attribute glib:type-name { xsd:string }?,
      attribute glib:get-type { xsd:string }?,

      (Info.elements
       & Member*
       & Function*)
    }

  Enum =
    element enumeration {
      Info.attrs,
      attribute name { xsd:string },
      attribute c:type { xsd:string },

      attribute glib:type-name { xsd:string }?,
      attribute glib:get-type { xsd:string }?,
      attribute glib:error-domain { xsd:string }?,

      (Info.elements
       & Member*
       & Function*)
    }

  Member =
    element member {
      Info.attrs,
      attribute name { xsd:string },
      attribute value { xsd:string },
      attribute c:identifier { xsd:string },

      attribute glib:nick { xsd:string }?,

      Info.elements
    }
}
