glib (2.79.0)

(root)/
share/
glib-2.0/
codegen/
parser.py
       1  # -*- Mode: Python -*-
       2  
       3  # GDBus - GLib D-Bus Library
       4  #
       5  # Copyright (C) 2008-2011 Red Hat, Inc.
       6  #
       7  # This library is free software; you can redistribute it and/or
       8  # modify it under the terms of the GNU Lesser General Public
       9  # License as published by the Free Software Foundation; either
      10  # version 2.1 of the License, or (at your option) any later version.
      11  #
      12  # This library is distributed in the hope that it will be useful,
      13  # but WITHOUT ANY WARRANTY; without even the implied warranty of
      14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15  # Lesser General Public License for more details.
      16  #
      17  # You should have received a copy of the GNU Lesser General
      18  # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19  #
      20  # Author: David Zeuthen <davidz@redhat.com>
      21  
      22  import xml.parsers.expat
      23  import textwrap
      24  
      25  from . import dbustypes
      26  from .utils import print_error
      27  
      28  
      29  class ESC[4;38;5;81mDBusXMLParser:
      30      STATE_TOP = "top"
      31      STATE_NODE = "node"
      32      STATE_INTERFACE = "interface"
      33      STATE_METHOD = "method"
      34      STATE_SIGNAL = "signal"
      35      STATE_PROPERTY = "property"
      36      STATE_ARG = "arg"
      37      STATE_ANNOTATION = "annotation"
      38      STATE_IGNORED = "ignored"
      39  
      40      def __init__(self, xml_data, h_type_implies_unix_fd=True):
      41          self._parser = xml.parsers.expat.ParserCreate()
      42          self._parser.CommentHandler = self.handle_comment
      43          self._parser.CharacterDataHandler = self.handle_char_data
      44          self._parser.StartElementHandler = self.handle_start_element
      45          self._parser.EndElementHandler = self.handle_end_element
      46  
      47          self.parsed_interfaces = []
      48          self._cur_object = None
      49  
      50          self.state = DBusXMLParser.STATE_TOP
      51          self.state_stack = []
      52          self._cur_object = None
      53          self._cur_object_stack = []
      54  
      55          self.doc_comment_last_symbol = ""
      56  
      57          self._h_type_implies_unix_fd = h_type_implies_unix_fd
      58  
      59          self._parser.Parse(xml_data)
      60  
      61      COMMENT_STATE_BEGIN = "begin"
      62      COMMENT_STATE_PARAMS = "params"
      63      COMMENT_STATE_BODY = "body"
      64      COMMENT_STATE_SKIP = "skip"
      65  
      66      def handle_comment(self, data):
      67          comment_state = DBusXMLParser.COMMENT_STATE_BEGIN
      68          lines = textwrap.dedent(data).split("\n")
      69          symbol = ""
      70          body = ""
      71          in_para = False
      72          params = {}
      73          for line in lines:
      74              if comment_state == DBusXMLParser.COMMENT_STATE_BEGIN:
      75                  if len(line) > 0:
      76                      colon_index = line.find(": ")
      77                      if colon_index == -1:
      78                          if line.endswith(":"):
      79                              symbol = line[0 : len(line) - 1]
      80                              comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
      81                          else:
      82                              comment_state = DBusXMLParser.COMMENT_STATE_SKIP
      83                      else:
      84                          symbol = line[0:colon_index]
      85                          rest_of_line = line[colon_index + 2 :].strip()
      86                          if len(rest_of_line) > 0:
      87                              body += f"{rest_of_line}\n"
      88                          comment_state = DBusXMLParser.COMMENT_STATE_PARAMS
      89              elif comment_state == DBusXMLParser.COMMENT_STATE_PARAMS:
      90                  if line.startswith("@"):
      91                      colon_index = line.find(": ")
      92                      if colon_index == -1:
      93                          comment_state = DBusXMLParser.COMMENT_STATE_BODY
      94                          if not in_para:
      95                              body += "\n"
      96                              in_para = True
      97                          body += f"{line}\n"
      98                      else:
      99                          param = line[1:colon_index]
     100                          docs = line[colon_index + 2 :]
     101                          params[param] = docs
     102                  else:
     103                      comment_state = DBusXMLParser.COMMENT_STATE_BODY
     104                      if len(line) > 0:
     105                          if not in_para:
     106                              body += "\n"
     107                              in_para = True
     108                          body += line + "\n"
     109              elif comment_state == DBusXMLParser.COMMENT_STATE_BODY:
     110                  if len(line) > 0:
     111                      if not in_para:
     112                          in_para = True
     113                      body += line + "\n"
     114                  else:
     115                      if in_para:
     116                          body += "\n"
     117                          in_para = False
     118          if in_para:
     119              body += "\n"
     120  
     121          if symbol != "":
     122              self.doc_comment_last_symbol = symbol
     123              self.doc_comment_params = params
     124              self.doc_comment_body = body
     125  
     126      def handle_char_data(self, data):
     127          # print 'char_data=%s'%data
     128          pass
     129  
     130      def handle_start_element(self, name, attrs):
     131          old_state = self.state
     132          old_cur_object = self._cur_object
     133          if self.state == DBusXMLParser.STATE_IGNORED:
     134              self.state = DBusXMLParser.STATE_IGNORED
     135          elif self.state == DBusXMLParser.STATE_TOP:
     136              if name == DBusXMLParser.STATE_NODE:
     137                  self.state = DBusXMLParser.STATE_NODE
     138              else:
     139                  self.state = DBusXMLParser.STATE_IGNORED
     140          elif self.state == DBusXMLParser.STATE_NODE:
     141              if name == DBusXMLParser.STATE_INTERFACE:
     142                  self.state = DBusXMLParser.STATE_INTERFACE
     143                  iface = dbustypes.Interface(attrs["name"])
     144                  self._cur_object = iface
     145                  self.parsed_interfaces.append(iface)
     146              elif name == DBusXMLParser.STATE_ANNOTATION:
     147                  self.state = DBusXMLParser.STATE_ANNOTATION
     148                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     149                  self._cur_object.annotations.append(anno)
     150                  self._cur_object = anno
     151              else:
     152                  self.state = DBusXMLParser.STATE_IGNORED
     153  
     154              # assign docs, if any
     155              if "name" in attrs and self.doc_comment_last_symbol == attrs["name"]:
     156                  self._cur_object.doc_string = self.doc_comment_body
     157                  if "short_description" in self.doc_comment_params:
     158                      short_description = self.doc_comment_params["short_description"]
     159                      self._cur_object.doc_string_brief = short_description
     160                  if "since" in self.doc_comment_params:
     161                      self._cur_object.since = self.doc_comment_params["since"].strip()
     162  
     163          elif self.state == DBusXMLParser.STATE_INTERFACE:
     164              if name == DBusXMLParser.STATE_METHOD:
     165                  self.state = DBusXMLParser.STATE_METHOD
     166                  method = dbustypes.Method(
     167                      attrs["name"], h_type_implies_unix_fd=self._h_type_implies_unix_fd
     168                  )
     169                  self._cur_object.methods.append(method)
     170                  self._cur_object = method
     171              elif name == DBusXMLParser.STATE_SIGNAL:
     172                  self.state = DBusXMLParser.STATE_SIGNAL
     173                  signal = dbustypes.Signal(attrs["name"])
     174                  self._cur_object.signals.append(signal)
     175                  self._cur_object = signal
     176              elif name == DBusXMLParser.STATE_PROPERTY:
     177                  self.state = DBusXMLParser.STATE_PROPERTY
     178                  prop = dbustypes.Property(attrs["name"], attrs["type"], attrs["access"])
     179                  self._cur_object.properties.append(prop)
     180                  self._cur_object = prop
     181              elif name == DBusXMLParser.STATE_ANNOTATION:
     182                  self.state = DBusXMLParser.STATE_ANNOTATION
     183                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     184                  self._cur_object.annotations.append(anno)
     185                  self._cur_object = anno
     186              else:
     187                  self.state = DBusXMLParser.STATE_IGNORED
     188  
     189              # assign docs, if any
     190              if "name" in attrs and self.doc_comment_last_symbol == attrs["name"]:
     191                  self._cur_object.doc_string = self.doc_comment_body
     192                  if "since" in self.doc_comment_params:
     193                      self._cur_object.since = self.doc_comment_params["since"].strip()
     194  
     195          elif self.state == DBusXMLParser.STATE_METHOD:
     196              if name == DBusXMLParser.STATE_ARG:
     197                  self.state = DBusXMLParser.STATE_ARG
     198                  arg_name = None
     199                  if "name" in attrs:
     200                      arg_name = attrs["name"]
     201                  arg = dbustypes.Arg(arg_name, attrs["type"])
     202                  direction = attrs.get("direction", "in")
     203                  if direction == "in":
     204                      self._cur_object.in_args.append(arg)
     205                  elif direction == "out":
     206                      self._cur_object.out_args.append(arg)
     207                  else:
     208                      print_error('Invalid direction "{}"'.format(direction))
     209                  self._cur_object = arg
     210              elif name == DBusXMLParser.STATE_ANNOTATION:
     211                  self.state = DBusXMLParser.STATE_ANNOTATION
     212                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     213                  self._cur_object.annotations.append(anno)
     214                  self._cur_object = anno
     215              else:
     216                  self.state = DBusXMLParser.STATE_IGNORED
     217  
     218              # assign docs, if any
     219              if self.doc_comment_last_symbol == old_cur_object.name:
     220                  if "name" in attrs and attrs["name"] in self.doc_comment_params:
     221                      doc_string = self.doc_comment_params[attrs["name"]]
     222                      if doc_string is not None:
     223                          self._cur_object.doc_string = doc_string
     224                      if "since" in self.doc_comment_params:
     225                          self._cur_object.since = self.doc_comment_params[
     226                              "since"
     227                          ].strip()
     228  
     229          elif self.state == DBusXMLParser.STATE_SIGNAL:
     230              if name == DBusXMLParser.STATE_ARG:
     231                  self.state = DBusXMLParser.STATE_ARG
     232                  arg_name = None
     233                  if "name" in attrs:
     234                      arg_name = attrs["name"]
     235                  arg = dbustypes.Arg(arg_name, attrs["type"])
     236                  self._cur_object.args.append(arg)
     237                  self._cur_object = arg
     238              elif name == DBusXMLParser.STATE_ANNOTATION:
     239                  self.state = DBusXMLParser.STATE_ANNOTATION
     240                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     241                  self._cur_object.annotations.append(anno)
     242                  self._cur_object = anno
     243              else:
     244                  self.state = DBusXMLParser.STATE_IGNORED
     245  
     246              # assign docs, if any
     247              if self.doc_comment_last_symbol == old_cur_object.name:
     248                  if "name" in attrs and attrs["name"] in self.doc_comment_params:
     249                      doc_string = self.doc_comment_params[attrs["name"]]
     250                      if doc_string is not None:
     251                          self._cur_object.doc_string = doc_string
     252                      if "since" in self.doc_comment_params:
     253                          self._cur_object.since = self.doc_comment_params[
     254                              "since"
     255                          ].strip()
     256  
     257          elif self.state == DBusXMLParser.STATE_PROPERTY:
     258              if name == DBusXMLParser.STATE_ANNOTATION:
     259                  self.state = DBusXMLParser.STATE_ANNOTATION
     260                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     261                  self._cur_object.annotations.append(anno)
     262                  self._cur_object = anno
     263              else:
     264                  self.state = DBusXMLParser.STATE_IGNORED
     265  
     266          elif self.state == DBusXMLParser.STATE_ARG:
     267              if name == DBusXMLParser.STATE_ANNOTATION:
     268                  self.state = DBusXMLParser.STATE_ANNOTATION
     269                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     270                  self._cur_object.annotations.append(anno)
     271                  self._cur_object = anno
     272              else:
     273                  self.state = DBusXMLParser.STATE_IGNORED
     274  
     275          elif self.state == DBusXMLParser.STATE_ANNOTATION:
     276              if name == DBusXMLParser.STATE_ANNOTATION:
     277                  self.state = DBusXMLParser.STATE_ANNOTATION
     278                  anno = dbustypes.Annotation(attrs["name"], attrs["value"])
     279                  self._cur_object.annotations.append(anno)
     280                  self._cur_object = anno
     281              else:
     282                  self.state = DBusXMLParser.STATE_IGNORED
     283  
     284          else:
     285              print_error(
     286                  'Unhandled state "{}" while entering element with name "{}"'.format(
     287                      self.state, name
     288                  )
     289              )
     290  
     291          self.state_stack.append(old_state)
     292          self._cur_object_stack.append(old_cur_object)
     293  
     294      def handle_end_element(self, name):
     295          self.state = self.state_stack.pop()
     296          self._cur_object = self._cur_object_stack.pop()
     297  
     298  
     299  def parse_dbus_xml(xml_data, h_type_implies_unix_fd):
     300      parser = DBusXMLParser(xml_data, h_type_implies_unix_fd)
     301      return parser.parsed_interfaces