aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py')
-rw-r--r--sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py458
1 files changed, 0 insertions, 458 deletions
diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
deleted file mode 100644
index 2053c3e9d..000000000
--- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+++ /dev/null
@@ -1,458 +0,0 @@
-#############################################################################
-##
-## Copyright (C) 2019 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of Qt for Python.
-##
-## $QT_BEGIN_LICENSE:LGPL$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 3 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL3 included in the
-## packaging of this file. Please review the following information to
-## ensure the GNU Lesser General Public License version 3 requirements
-## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 2.0 or (at your option) the GNU General
-## Public license version 3 or any later version approved by the KDE Free
-## Qt Foundation. The licenses are as published by the Free Software
-## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-2.0.html and
-## https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-from __future__ import print_function, absolute_import
-
-import sys
-import re
-import warnings
-import types
-import keyword
-import functools
-from shibokensupport.signature.mapping import (type_map, update_mapping,
- namespace, typing, _NotCalled, ResultVariable, ArrayLikeVariable)
-from shibokensupport.signature.lib.tool import (SimpleNamespace,
- build_brace_pattern)
-
-_DEBUG = False
-LIST_KEYWORDS = False
-
-"""
-parser.py
-
-This module parses the signature text and creates properties for the
-signature objects.
-
-PySide has a new function 'CppGenerator::writeSignatureInfo()'
-that extracts the gathered information about the function arguments
-and defaults as good as it can. But what PySide generates is still
-very C-ish and has many constants that Python doesn't understand.
-
-The function 'try_to_guess()' below understands a lot of PySide's
-peculiar way to assume local context. If it is able to do the guess,
-then the result is inserted into the dict, so the search happens
-not again. For everything that is not covered by these automatic
-guesses, we provide an entry in 'type_map' that resolves it.
-
-In effect, 'type_map' maps text to real Python objects.
-"""
-
-def dprint(*args, **kw):
- if _DEBUG:
- import pprint
- for arg in args:
- pprint.pprint(arg)
- sys.stdout.flush()
-
-
-_cache = {}
-
-def _parse_arglist(argstr):
- # The following is a split re. The string is broken into pieces which are
- # between the recognized strings. Because the re has groups, both the
- # strings and the separators are returned, where the strings are not
- # interesting at all: They are just the commata.
- key = "_parse_arglist"
- if key not in _cache:
- regex = build_brace_pattern(level=3, separators=",")
- _cache[key] = re.compile(regex, flags=re.VERBOSE)
- split = _cache[key].split
- # Note: this list is interspersed with "," and surrounded by ""
- return [x.strip() for x in split(argstr) if x.strip() not in ("", ",")]
-
-
-def _parse_line(line):
- line_re = r"""
- ((?P<multi> ([0-9]+)) : )? # the optional multi-index
- (?P<funcname> \w+(\.\w+)*) # the function name
- \( (?P<arglist> .*?) \) # the argument list
- ( -> (?P<returntype> .*) )? # the optional return type
- $
- """
- ret = SimpleNamespace(**re.match(line_re, line, re.VERBOSE).groupdict())
- # PYSIDE-1095: Handle arbitrary default expressions
- argstr = ret.arglist.replace("->", ".deref.")
- arglist = _parse_arglist(argstr)
- args = []
- for arg in arglist:
- name, ann = arg.split(":")
- if name in keyword.kwlist:
- if LIST_KEYWORDS:
- print("KEYWORD", ret)
- name = name + "_"
- if "=" in ann:
- ann, default = ann.split("=", 1)
- tup = name, ann, default
- else:
- tup = name, ann
- args.append(tup)
- ret.arglist = args
- multi = ret.multi
- if multi is not None:
- ret.multi = int(multi)
- funcname = ret.funcname
- parts = funcname.split(".")
- if parts[-1] in keyword.kwlist:
- ret.funcname = funcname + "_"
- return vars(ret)
-
-
-def make_good_value(thing, valtype):
- try:
- if thing.endswith("()"):
- thing = 'Default("{}")'.format(thing[:-2])
- else:
- ret = eval(thing, namespace)
- if valtype and repr(ret).startswith("<"):
- thing = 'Instance("{}")'.format(thing)
- return eval(thing, namespace)
- except Exception:
- pass
-
-
-def try_to_guess(thing, valtype):
- if "." not in thing and "(" not in thing:
- text = "{}.{}".format(valtype, thing)
- ret = make_good_value(text, valtype)
- if ret is not None:
- return ret
- typewords = valtype.split(".")
- valwords = thing.split(".")
- braceless = valwords[0] # Yes, not -1. Relevant is the overlapped word.
- if "(" in braceless:
- braceless = braceless[:braceless.index("(")]
- for idx, w in enumerate(typewords):
- if w == braceless:
- text = ".".join(typewords[:idx] + valwords)
- ret = make_good_value(text, valtype)
- if ret is not None:
- return ret
- return None
-
-def get_name(thing):
- if isinstance(thing, type):
- return getattr(thing, "__qualname__", thing.__name__)
- else:
- return thing.__name__
-
-def _resolve_value(thing, valtype, line):
- if thing in ("0", "None") and valtype:
- if valtype.startswith("PySide2.") or valtype.startswith("typing."):
- return None
- map = type_map[valtype]
- # typing.Any: '_SpecialForm' object has no attribute '__name__'
- name = get_name(map) if hasattr(map, "__name__") else str(map)
- thing = "zero({})".format(name)
- if thing in type_map:
- return type_map[thing]
- res = make_good_value(thing, valtype)
- if res is not None:
- type_map[thing] = res
- return res
- res = try_to_guess(thing, valtype) if valtype else None
- if res is not None:
- type_map[thing] = res
- return res
- warnings.warn("""pyside_type_init:
-
- UNRECOGNIZED: {!r}
- OFFENDING LINE: {!r}
- """.format(thing, line), RuntimeWarning)
- return thing
-
-
-def _resolve_arraytype(thing, line):
- search = re.search(r"\[(\d*)\]$", thing)
- thing = thing[:search.start()]
- if thing.endswith("]"):
- thing = _resolve_arraytype(thing, line)
- if search.group(1):
- # concrete array, use a tuple
- nelem = int(search.group(1))
- thing = ", ".join([thing] * nelem)
- thing = "Tuple[" + thing + "]"
- else:
- thing = "QList[" + thing + "]"
- return thing
-
-
-def to_string(thing):
- if isinstance(thing, str):
- return thing
- if hasattr(thing, "__name__"):
- dot = "." in str(thing)
- name = get_name(thing)
- return thing.__module__ + "." + name if dot else name
- # Note: This captures things from the typing module:
- return str(thing)
-
-
-matrix_pattern = "PySide2.QtGui.QGenericMatrix"
-
-def handle_matrix(arg):
- n, m, typstr = tuple(map(lambda x:x.strip(), arg.split(",")))
- assert typstr == "float"
- result = "PySide2.QtGui.QMatrix{n}x{m}".format(**locals())
- return eval(result, namespace)
-
-
-debugging_aid = """
-from inspect import currentframe
-
-def lno(level):
- lineno = currentframe().f_back.f_lineno
- spaces = level * " "
- return "{lineno}{spaces}".format(**locals())
-"""
-
-
-def _resolve_type(thing, line, level, var_handler):
- # Capture total replacements, first. Happens in
- # "PySide2.QtCore.QCborStreamReader.StringResult[PySide2.QtCore.QByteArray]"
- if thing in type_map:
- return type_map[thing]
- # Now the nested structures are handled.
- if "[" in thing:
- # handle primitive arrays
- if re.search(r"\[\d*\]$", thing):
- thing = _resolve_arraytype(thing, line)
- # Handle a container return type. (see PYSIDE-921 in cppgenerator.cpp)
- contr, thing = re.match(r"(.*?)\[(.*?)\]$", thing).groups()
- # Special case: Handle the generic matrices.
- if contr == matrix_pattern:
- return handle_matrix(thing)
- contr = var_handler(_resolve_type(contr, line, level+1, var_handler))
- if isinstance(contr, _NotCalled):
- raise SystemError("Container types must exist:", repr(contr))
- contr = to_string(contr)
- pieces = []
- for part in _parse_arglist(thing):
- part = var_handler(_resolve_type(part, line, level+1, var_handler))
- if isinstance(part, _NotCalled):
- # fix the tag (i.e. "Missing") by repr
- part = repr(part)
- pieces.append(to_string(part))
- thing = ", ".join(pieces)
- result = "{contr}[{thing}]".format(**locals())
- return eval(result, namespace)
- return _resolve_value(thing, None, line)
-
-
-def _handle_generic(obj, repl):
- """
- Assign repl if obj is an ArrayLikeVariable
-
- This is a neat trick. Example:
-
- obj repl result
- ---------------------- -------- ---------
- ArrayLikeVariable List List
- ArrayLikeVariable(str) List List[str]
- ArrayLikeVariable Sequence Sequence
- ArrayLikeVariable(str) Sequence Sequence[str]
- """
- if isinstance(obj, ArrayLikeVariable):
- return repl[obj.type]
- if isinstance(obj, type) and issubclass(obj, ArrayLikeVariable):
- # was "if obj is ArrayLikeVariable"
- return repl
- return obj
-
-
-def handle_argvar(obj):
- """
- Decide how array-like variables are resolved in arguments
-
- Currently, the best approximation is types.Sequence.
- We want to change that to types.Iterable in the near future.
- """
- return _handle_generic(obj, typing.Sequence)
-
-
-def handle_retvar(obj):
- """
- Decide how array-like variables are resolved in results
-
- This will probably stay typing.List forever.
- """
- return _handle_generic(obj, typing.List)
-
-
-def calculate_props(line):
- parsed = SimpleNamespace(**_parse_line(line.strip()))
- arglist = parsed.arglist
- annotations = {}
- _defaults = []
- for idx, tup in enumerate(arglist):
- name, ann = tup[:2]
- if ann == "...":
- name = "*args" if name.startswith("arg_") else "*" + name
- # copy the pathed fields back
- ann = 'nullptr' # maps to None
- tup = name, ann
- arglist[idx] = tup
- annotations[name] = _resolve_type(ann, line, 0, handle_argvar)
- if len(tup) == 3:
- default = _resolve_value(tup[2], ann, line)
- _defaults.append(default)
- defaults = tuple(_defaults)
- returntype = parsed.returntype
- if returntype is not None:
- annotations["return"] = _resolve_type(returntype, line, 0, handle_retvar)
- props = SimpleNamespace()
- props.defaults = defaults
- props.kwdefaults = {}
- props.annotations = annotations
- props.varnames = varnames = tuple(tup[0] for tup in arglist)
- funcname = parsed.funcname
- props.fullname = funcname
- shortname = funcname[funcname.rindex(".")+1:]
- props.name = shortname
- props.multi = parsed.multi
- fix_variables(props, line)
- return vars(props)
-
-
-def fix_variables(props, line):
- annos = props.annotations
- if not any(isinstance(ann, (ResultVariable, ArrayLikeVariable))
- for ann in annos.values()):
- return
- retvar = annos.get("return", None)
- if retvar and isinstance(retvar, (ResultVariable, ArrayLikeVariable)):
- # Special case: a ResultVariable which is the result will always be an array!
- annos["return"] = retvar = typing.List[retvar.type]
- fullname = props.fullname
- varnames = list(props.varnames)
- defaults = list(props.defaults)
- diff = len(varnames) - len(defaults)
-
- safe_annos = annos.copy()
- retvars = [retvar] if retvar else []
- deletions = []
- for idx, name in enumerate(varnames):
- ann = safe_annos[name]
- if isinstance(ann, ArrayLikeVariable):
- ann = typing.Sequence[ann.type]
- annos[name] = ann
- if not isinstance(ann, ResultVariable):
- continue
- # We move the variable to the end and remove it.
- retvars.append(ann.type)
- deletions.append(idx)
- del annos[name]
- for idx in reversed(deletions):
- # varnames: 0 1 2 3 4 5 6 7
- # defaults: 0 1 2 3 4
- # diff: 3
- del varnames[idx]
- if idx >= diff:
- del defaults[idx - diff]
- else:
- diff -= 1
- if retvars:
- rvs = []
- retvars = list(handle_retvar(rv) if isinstance(rv, ArrayLikeVariable) else rv
- for rv in retvars)
- if len(retvars) == 1:
- returntype = retvars[0]
- else:
- typestr = "typing.Tuple[{}]".format(", ".join(map(to_string, retvars)))
- returntype = eval(typestr, namespace)
- props.annotations["return"] = returntype
- props.varnames = tuple(varnames)
- props.defaults = tuple(defaults)
-
-
-def fixup_multilines(lines):
- """
- Multilines can collapse when certain distinctions between C++ types
- vanish after mapping to Python.
- This function fixes this by re-computing multiline-ness.
- """
- res = []
- multi_lines = []
- for line in lines:
- multi = re.match(r"([0-9]+):", line)
- if multi:
- idx, rest = int(multi.group(1)), line[multi.end():]
- multi_lines.append(rest)
- if idx > 0:
- continue
- # remove duplicates
- multi_lines = sorted(set(multi_lines))
- # renumber or return a single line
- nmulti = len(multi_lines)
- if nmulti > 1:
- for idx, line in enumerate(multi_lines):
- res.append("{}:{}".format(nmulti-idx-1, line))
- else:
- res.append(multi_lines[0])
- multi_lines = []
- else:
- res.append(line)
- return res
-
-
-def pyside_type_init(type_key, sig_strings):
- dprint()
- dprint("Initialization of type key '{}'".format(type_key))
- update_mapping()
- lines = fixup_multilines(sig_strings)
- ret = {}
- multi_props = []
- for line in lines:
- props = calculate_props(line)
- shortname = props["name"]
- multi = props["multi"]
- if multi is None:
- ret[shortname] = props
- dprint(props)
- else:
- multi_props.append(props)
- if multi > 0:
- continue
- fullname = props.pop("fullname")
- multi_props = {"multi": multi_props, "fullname": fullname}
- ret[shortname] = multi_props
- dprint(multi_props)
- multi_props = []
- return ret
-
-# end of file