Lichen

Changeset

842:3fda355ec392
2018-07-05 Paul Boddie raw files shortlog changelog graph Merged changes from the default branch. tuple-optimisations
     1.1 --- a/deducer.py	Tue Jul 03 16:02:02 2018 +0200
     1.2 +++ b/deducer.py	Thu Jul 05 19:36:14 2018 +0200
     1.3 @@ -651,7 +651,8 @@
     1.4              referenced_attrs = self.referenced_attrs[location]
     1.5  
     1.6              if not referenced_attrs:
     1.7 -                raise DeduceError("In %s, access via %s to attribute %s (occurrence %d) cannot be identified." % location)
     1.8 +                raise DeduceError("In %s, access via %s to attribute %s (occurrence %d) cannot be identified." %
     1.9 +                    (location.path, location.name, location.get_attrname(), location.access_number))
    1.10  
    1.11              # Record attribute information for each name used on the
    1.12              # accessor.
    1.13 @@ -2135,6 +2136,17 @@
    1.14          if constrained:
    1.15              self.accessor_constrained.add(location)
    1.16  
    1.17 +        # Complain about situations where no types are valid but where a
    1.18 +        # specific, known accessor type has been indicated. This absence of
    1.19 +        # suitable types is likely to occur when the presence of invocations
    1.20 +        # filters out the accessor type.
    1.21 +
    1.22 +        if not class_only_types and not instance_types and not module_types and \
    1.23 +           invocations and constrained_specific:
    1.24 +
    1.25 +            raise DeduceError("In %s, methods of class %s cannot be called directly." %
    1.26 +                (path, name))
    1.27 +
    1.28      def update_provider_types(self, location, class_types, instance_types, module_types):
    1.29  
    1.30          """
     2.1 --- a/encoders.py	Tue Jul 03 16:02:02 2018 +0200
     2.2 +++ b/encoders.py	Thu Jul 05 19:36:14 2018 +0200
     2.3 @@ -78,6 +78,13 @@
     2.4  
     2.5      return "%s:%s:%s:%d" % (t.path, t.name or "{}", t.attrnames or "{}", t.access_number)
     2.6  
     2.7 +def decode_access_location(s):
     2.8 +
     2.9 +    "Decode the access location 's'."
    2.10 +
    2.11 +    path, name, attrnames, access_number = s.split(":")
    2.12 +    return path, name, attrnames, access_number
    2.13 +
    2.14  def encode_alias_location(t, invocation=False):
    2.15  
    2.16      "Encode the alias location 't'."
     3.1 --- a/tests/contexts.py	Tue Jul 03 16:02:02 2018 +0200
     3.2 +++ b/tests/contexts.py	Thu Jul 05 19:36:14 2018 +0200
     3.3 @@ -5,6 +5,8 @@
     3.4          self.x = x
     3.5          self.y = 3
     3.6          self.z = "zebra libre"
     3.7 +    def __len__(self):
     3.8 +        return len(self.z)
     3.9  
    3.10  c = C([1])
    3.11  x = c.x
    3.12 @@ -45,3 +47,11 @@
    3.13  print b             # zebra libre
    3.14  print i             # __builtins__.str.basestring.__len__
    3.15  print i()           # 11
    3.16 +
    3.17 +j = C.__len__
    3.18 +k = get_using(j, c)
    3.19 +try:
    3.20 +    print j()
    3.21 +except UnboundMethodInvocation:
    3.22 +    print "j(): invocation of method with class context"
    3.23 +print k()           # 11
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tests/methods_unbound_bad.py	Thu Jul 05 19:36:14 2018 +0200
     4.3 @@ -0,0 +1,12 @@
     4.4 +class C:
     4.5 +    def __init__(self, x, y, z):
     4.6 +        self.x = x
     4.7 +        self.y = y
     4.8 +        self.z = z
     4.9 +
    4.10 +    def c(self):
    4.11 +        return self.x
    4.12 +
    4.13 +c = C(1, 2, 3)
    4.14 +print c.c() # 1
    4.15 +print C.c() # bad
     5.1 --- a/tools/showalias.py	Tue Jul 03 16:02:02 2018 +0200
     5.2 +++ b/tools/showalias.py	Thu Jul 05 19:36:14 2018 +0200
     5.3 @@ -1,6 +1,6 @@
     5.4  #!/usr/bin/env python
     5.5  
     5.6 -from os.path import abspath, split
     5.7 +from os.path import abspath, exists, join, split
     5.8  import sys
     5.9  
    5.10  # Find the modules.
    5.11 @@ -15,12 +15,18 @@
    5.12  from encoders import decode_alias_location
    5.13  
    5.14  if len(sys.argv) < 3:
    5.15 -    print >>sys.stderr, "Usage: %s <filename> <alias>" % sys.argv[0]
    5.16 +    print >>sys.stderr, "Usage: %s <directory> <alias>" % sys.argv[0]
    5.17      sys.exit(1)
    5.18  
    5.19 -filename = sys.argv[1]
    5.20 +dirname = sys.argv[1]
    5.21  alias = sys.argv[2]
    5.22  
    5.23 +filename = join(dirname, "_deduced", "aliases")
    5.24 +
    5.25 +if not exists(filename):
    5.26 +    print >>sys.stderr, "Directory %s does not provide file %s." % (dirname, filename)
    5.27 +    sys.exit(1)
    5.28 +
    5.29  f = open(filename)
    5.30  try:
    5.31      for line in f.xreadlines():
     6.1 --- a/tools/showplan.py	Tue Jul 03 16:02:02 2018 +0200
     6.2 +++ b/tools/showplan.py	Thu Jul 05 19:36:14 2018 +0200
     6.3 @@ -1,14 +1,32 @@
     6.4  #!/usr/bin/env python
     6.5  
     6.6 +from os.path import abspath, exists, join, split
     6.7  import sys
     6.8  
     6.9 +# Find the modules.
    6.10 +
    6.11 +try:
    6.12 +    import encoders
    6.13 +except ImportError:
    6.14 +    parent = abspath(split(split(__file__)[0])[0])
    6.15 +    if split(parent)[1] == "Lichen":
    6.16 +        sys.path.append(parent)
    6.17 +
    6.18 +from encoders import decode_access_location
    6.19 +
    6.20  if len(sys.argv) < 3:
    6.21 -    print >>sys.stderr, "Usage: %s <filename> <access>" % sys.argv[0]
    6.22 +    print >>sys.stderr, "Usage: %s <directory> <access>" % sys.argv[0]
    6.23      sys.exit(1)
    6.24  
    6.25 -filename = sys.argv[1]
    6.26 +dirname = sys.argv[1]
    6.27  access = sys.argv[2]
    6.28  
    6.29 +filename = join(dirname, "_deduced", "attribute_plans")
    6.30 +
    6.31 +if not exists(filename):
    6.32 +    print >>sys.stderr, "Directory %s does not provide file %s." % (dirname, filename)
    6.33 +    sys.exit(1)
    6.34 +
    6.35  f = open(filename)
    6.36  try:
    6.37      for line in f.xreadlines():
    6.38 @@ -17,17 +35,21 @@
    6.39              continue
    6.40  
    6.41          location, name, test, test_type, base, traversed, traversal_modes, \
    6.42 -        attrnames, context, context_test, first_method, final_method, attr, \
    6.43 -        accessor_kinds = columns
    6.44 +        traversal_attrnames, context, context_test, \
    6.45 +        first_method, final_method, attr, accessor_kinds = columns
    6.46 +
    6.47 +        path, _name, attrnames, access_number = decode_access_location(location)
    6.48  
    6.49          print "Location:", location
    6.50          print "Name:", name
    6.51 +        print "Attribute names:", attrnames
    6.52 +        print "Access number:", access_number
    6.53          print "Test:", test
    6.54          print "Test type:", test_type
    6.55          print "Base:", base
    6.56          print "Traversed:", traversed
    6.57          print "Traversal modes:", traversal_modes
    6.58 -        print "Attribute names:", attrnames
    6.59 +        print "Traversed attributes:", traversal_attrnames
    6.60          print "Context:", context
    6.61          print "Context test:", context_test
    6.62          print "First method:", first_method
     7.1 --- a/translator.py	Tue Jul 03 16:02:02 2018 +0200
     7.2 +++ b/translator.py	Thu Jul 05 19:36:14 2018 +0200
     7.3 @@ -1403,12 +1403,14 @@
     7.4  
     7.5          elif function:
     7.6              if context_required:
     7.7 +
     7.8 +                # With context_verified or context_identity...
     7.9 +
    7.10                  if have_access_context:
    7.11 -                    if context_verified:
    7.12 -                        emit("__get_function_member(%s)" % target_expr)
    7.13 -                    else:
    7.14 -                        emit("__get_function(%s, %s)" % (
    7.15 -                            context_identity, target_expr))
    7.16 +                    emit("__get_function_member(%s)" % target_expr)
    7.17 +
    7.18 +                # Otherwise, test the context for the function/method.
    7.19 +
    7.20                  else:
    7.21                      emit("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % (
    7.22                          target_var, target_expr))
    7.23 @@ -1420,7 +1422,7 @@
    7.24          elif known_parameters:
    7.25              context_arg = context_required and args[0] or "__NULL"
    7.26              if self.always_callable(refs):
    7.27 -                if context_verified:
    7.28 +                if context_verified or context_identity:
    7.29                      emit("__get_function_member(%s)" % target_expr)
    7.30                  else:
    7.31                      emit("__get_function(%s, %s)" % (context_arg, target_expr))