#
# This file is derived from
#
# https://github.com/varlink/rust/blob/master/varlink_parser/src/varlink_grammar.rustpeg
#
# Using the file in MIT License is allowed in https://github.com/varlink/rust/issues/20.
#
########################################################################
#
# MIT License
#
# Copyright (c) 2016 - 2018 Red Hat, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
########################################################################
#
# This module contains PEG grammer and functions for generating tags
# for varlink IDL:
#
# * https://github.com/varlink
# * https://varlink.org/Interface-Definition
#
# varlink_grammar.rustpeg uses ** and ++ extended operators.
# peg processor written in Rust can understand the operators.
# However, packcc doesn't do. So ** and ++ are replaced with
# rules without ** and ++ operators.
#
# This parser is the test-bed for using packcc in ctags.
#
# TODO
#
# * revise scope field for field value
# * implement typeref and signature fields
#

#
# To avoid conflicting names in code generated by packcc and code written manually,
# add "p" as prefix to names in generated code.
#
%prefix "pvarlink"

%auxil	"struct parserCtx *"

%header {
	struct parserCtx;
}

%source {
#include "varlink_pre.h"
}

#
# Packcc tries to apply the first grammer rule in the input.
#
interface
    <- _* "interface" _+ interface_name eol ( member_list ) _*

# Modeled after ECMA-262, 5th ed., 7.2. \v\f removed
whitespace
    <- [ \t\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000]

# Modeled after ECMA-262, 5th ed., 7.3.
eol_r
  <- "\n"
  / "\r\n"
  / "\r"
  / "\u2028"
  / "\u2029"

comment
    <- "#" [^\n\r\u2028\u2029]* eol_r

eol
    <- whitespace* eol_r
    / comment

_
    <- whitespace / comment / eol_r

field_name
    <- < [A-Za-z]('_'?[A-Za-z0-9])* > {
    makeVarlikTag(auxil, $1, $1s);
}

field_name_list
    <- field_name (_* ',' _* field_name)*

name
    <- < [A-Z][A-Za-z0-9]* > {
    if (peekKind(auxil) != KIND_GHOST_INDEX)
	auxil->scope_cork_index = makeVarlikTag(auxil, $1, $1s);
}

interface_name
    <- < [a-z]([-]* [a-z0-9])* ( '.' [a-z0-9]([-]*[a-z0-9])* )+ > {
    auxil->scope_cork_index = makeVarlikTag(auxil, $1, $1s);
}

dict
    <- "[string]"

array
    <- "[]"

maybe
    <- "?"

element_type
    <- "bool"
    / "int"
    / "float"
    / "string"
    / "object"
    / { pushKind (auxil, KIND_GHOST_INDEX); } name { popKind (auxil, false); }
    / venum
    / vstruct

type
    <- element_type
    / maybe element_type
    / array type
    / dict type
    / maybe array type
    / maybe dict type

venum
    <- { pushKind (auxil, K_ENUMERATION); } '(' _* field_name_list? _* ')' { popKind (auxil, false); }

argument
    <- _* field_name _* ':' _* type

argument_list
    <- argument (_* ',' _* argument)*

vstruct
    <- { pushKindContextual (auxil); } '(' _* argument_list? _* ')' { popKind (auxil, false); }

vtypedef
    <- "type" { pushKind (auxil, K_STRUCT); } _+ name _* vstruct { popKind (auxil, true); }
    / "type" { pushKind (auxil, K_ENUM); } _+ name _* venum { popKind (auxil, true); }

error
    <- "error" { pushKind (auxil, K_ERROR); } _+ name _* vstruct { popKind (auxil, true); }

method
    <- "method" {
       pushKind(auxil, K_METHOD); setMethodParamState (auxil, METHOD_PARAM_INPUT);
    } _+ name _* vstruct _* {
       setMethodParamState (auxil, METHOD_PARAM_OUTPUT);
    } "->" _* vstruct { popKind (auxil, true); }

member
    <- _* m:method
    / _* t:vtypedef
    / _* e:error

member_list
   <- member (eol member)*

%%
#include "varlink_post.h"
