Lichen

Changeset

870:8f6ea88d0845
2019-01-24 Paul Boddie raw files shortlog changelog graph Merged changes from the default branch. trailing-data
     1.1 --- a/common.py	Thu Jan 17 14:23:38 2019 +0100
     1.2 +++ b/common.py	Thu Jan 24 22:20:33 2019 +0100
     1.3 @@ -3,8 +3,8 @@
     1.4  """
     1.5  Common functions.
     1.6  
     1.7 -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013,
     1.8 -              2014, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     1.9 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
    1.10 +              2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
    1.11  
    1.12  This program is free software; you can redistribute it and/or modify it under
    1.13  the terms of the GNU General Public License as published by the Free Software
    1.14 @@ -461,8 +461,11 @@
    1.15  
    1.16          for i, node in enumerate(n.nodes):
    1.17              statements.append(
    1.18 -                compiler.ast.Assign([node], compiler.ast.Subscript(
    1.19 -                    compiler.ast.Name(temp), "OP_APPLY", [compiler.ast.Const(i, str(i))]))
    1.20 +                compiler.ast.Assign([node], compiler.ast.CallFunc(
    1.21 +                    compiler.ast.Getattr(compiler.ast.Name(temp),
    1.22 +                                         "__get_single_item_unchecked__",
    1.23 +                                         privileged=True),
    1.24 +                    [compiler.ast.Const(i, str(i))]))
    1.25                  )
    1.26  
    1.27          return self.process_structure_node(compiler.ast.Stmt(statements))
    1.28 @@ -579,9 +582,13 @@
    1.29              # <t2> = <t1>.next
    1.30              # try:
    1.31              #     while True:
    1.32 -            #         <var>... = <t2>()
    1.33 -            #         ...
    1.34 -            # except StopIteration:
    1.35 +            #         try:
    1.36 +            #             <var>... = <t2>()
    1.37 +            #         except StopIteration:
    1.38 +            #             raise LoopExit
    1.39 +            #         {n.body}
    1.40 +            # except LoopExit:
    1.41 +            #     {n.else_}
    1.42              #     pass
    1.43  
    1.44              compiler.ast.Assign(
    1.45 @@ -592,15 +599,18 @@
    1.46                  compiler.ast.While(
    1.47                      compiler.ast.Name("True"),
    1.48                      compiler.ast.Stmt([
    1.49 -                        compiler.ast.Assign(
    1.50 -                            [n.assign],
    1.51 -                            compiler.ast.CallFunc(
    1.52 -                                compiler.ast.Name(t2),
    1.53 -                                []
    1.54 -                                )),
    1.55 +                        compiler.ast.TryExcept(
    1.56 +                            compiler.ast.Assign(
    1.57 +                                [n.assign],
    1.58 +                                compiler.ast.CallFunc(
    1.59 +                                    compiler.ast.Name(t2),
    1.60 +                                    [])),
    1.61 +                            [(compiler.ast.Name("StopIteration"), None,
    1.62 +                              compiler.ast.Raise(compiler.ast.Name("LoopExit")))],
    1.63 +                            None),
    1.64                          n.body]),
    1.65                      None),
    1.66 -                [(compiler.ast.Name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Pass()]))],
    1.67 +                [(compiler.ast.Name("LoopExit"), None, n.else_ or compiler.ast.Pass())],
    1.68                  None)
    1.69              ])
    1.70  
    1.71 @@ -1590,6 +1600,10 @@
    1.72  
    1.73  predefined_constants = "False", "None", "NotImplemented", "True"
    1.74  
    1.75 +privileged_attributes = [
    1.76 +    "__get_single_item_unchecked__",
    1.77 +    ]
    1.78 +
    1.79  unary_operator_functions = {
    1.80  
    1.81      # Unary operations.
     2.1 --- a/compiler/ast.py	Thu Jan 17 14:23:38 2019 +0100
     2.2 +++ b/compiler/ast.py	Thu Jan 24 22:20:33 2019 +0100
     2.3 @@ -868,11 +868,15 @@
     2.4          return "%s %s" % (self.expr, " ".join(map(str, self.quals)))
     2.5  
     2.6  class Getattr(Node):
     2.7 -    def __init__(self, expr, attrname, lineno=None):
     2.8 +    def __init__(self, expr, attrname, lineno=None, privileged=False):
     2.9          self.expr = expr
    2.10          self.attrname = attrname
    2.11          self.lineno = lineno
    2.12  
    2.13 +        # Support privileged internal accesses.
    2.14 +
    2.15 +        self.privileged = privileged
    2.16 +
    2.17      def getChildren(self):
    2.18          return self.expr, self.attrname
    2.19  
    2.20 @@ -1249,7 +1253,7 @@
    2.21          return "print %s" % ", ".join(map(str, dest + self.nodes))
    2.22  
    2.23  class Raise(Node):
    2.24 -    def __init__(self, expr1, expr2, expr3, lineno=None):
    2.25 +    def __init__(self, expr1, expr2=None, expr3=None, lineno=None):
    2.26          self.expr1 = expr1
    2.27          self.expr2 = expr2
    2.28          self.expr3 = expr3
     3.1 --- a/inspector.py	Thu Jan 17 14:23:38 2019 +0100
     3.2 +++ b/inspector.py	Thu Jan 24 22:20:33 2019 +0100
     3.3 @@ -21,7 +21,8 @@
     3.4  """
     3.5  
     3.6  from branching import BranchTracker
     3.7 -from common import CommonModule, get_argnames, init_item, predefined_constants
     3.8 +from common import CommonModule, get_argnames, init_item, \
     3.9 +                   predefined_constants, privileged_attributes
    3.10  from modules import BasicModule, CacheWritingModule, InspectionNaming
    3.11  from errors import InspectError
    3.12  from referencing import Reference
    3.13 @@ -358,6 +359,16 @@
    3.14  
    3.15          "Process the given attribute access node 'n'."
    3.16  
    3.17 +        path = self.get_namespace_path()
    3.18 +
    3.19 +        # Test for access to special privileged attributes.
    3.20 +
    3.21 +        if isinstance(n, compiler.ast.Getattr) and \
    3.22 +           n.attrname in privileged_attributes and not n.privileged:
    3.23 +
    3.24 +            raise InspectError("Attribute %s is accessed by an unprivileged operation." %
    3.25 +                               n.attrname, path, n)
    3.26 +
    3.27          # Obtain any completed chain and return the reference to it.
    3.28  
    3.29          name_ref = self.process_attribute_chain(n)
    3.30 @@ -372,8 +383,6 @@
    3.31          # either being name-based and thus an access rooted on a name, or being
    3.32          # based on some other node and thus an anonymous access of some kind.
    3.33  
    3.34 -        path = self.get_namespace_path()
    3.35 -
    3.36          # Start with the the full attribute chain.
    3.37  
    3.38          remaining = self.attrs
     4.1 --- a/lib/__builtins__/__init__.py	Thu Jan 17 14:23:38 2019 +0100
     4.2 +++ b/lib/__builtins__/__init__.py	Thu Jan 24 22:20:33 2019 +0100
     4.3 @@ -3,7 +3,7 @@
     4.4  """
     4.5  Simple built-in classes and functions.
     4.6  
     4.7 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     4.8 +Copyright (C) 2015, 2016, 2017, 2019 Paul Boddie <paul@boddie.org.uk>
     4.9  
    4.10  This program is free software; you can redistribute it and/or modify it under
    4.11  the terms of the GNU General Public License as published by the Free Software
    4.12 @@ -35,6 +35,7 @@
    4.13      IndentationError,
    4.14      IndexError,
    4.15      IOError,
    4.16 +    LoopExit,
    4.17      KeyError,
    4.18      KeyboardInterrupt,
    4.19      NotImplementedError,
     5.1 --- a/lib/__builtins__/exception/__init__.py	Thu Jan 17 14:23:38 2019 +0100
     5.2 +++ b/lib/__builtins__/exception/__init__.py	Thu Jan 24 22:20:33 2019 +0100
     5.3 @@ -3,7 +3,7 @@
     5.4  """
     5.5  Exception objects.
     5.6  
     5.7 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     5.8 +Copyright (C) 2015, 2016, 2017, 2019 Paul Boddie <paul@boddie.org.uk>
     5.9  
    5.10  This program is free software; you can redistribute it and/or modify it under
    5.11  the terms of the GNU General Public License as published by the Free Software
    5.12 @@ -25,6 +25,7 @@
    5.13  
    5.14  from __builtins__.exception.base import (
    5.15      IndexError,
    5.16 +    LoopExit,
    5.17      KeyError,
    5.18      NotImplementedError,
    5.19      RuntimeError,
     6.1 --- a/lib/__builtins__/exception/base.py	Thu Jan 17 14:23:38 2019 +0100
     6.2 +++ b/lib/__builtins__/exception/base.py	Thu Jan 24 22:20:33 2019 +0100
     6.3 @@ -3,7 +3,7 @@
     6.4  """
     6.5  Base exception objects. See __builtins__.core for the core exceptions.
     6.6  
     6.7 -Copyright (C) 2015, 2016, 2018 Paul Boddie <paul@boddie.org.uk>
     6.8 +Copyright (C) 2015, 2016, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
     6.9  
    6.10  This program is free software; you can redistribute it and/or modify it under
    6.11  the terms of the GNU General Public License as published by the Free Software
    6.12 @@ -61,6 +61,12 @@
    6.13  
    6.14          pass
    6.15  
    6.16 +class LoopExit(Exception):
    6.17 +
    6.18 +    "An exception signalling the end of iteration in a loop."
    6.19 +
    6.20 +    pass
    6.21 +
    6.22  class StopIteration(Exception):
    6.23  
    6.24      "An exception signalling the end of iteration."
     7.1 --- a/lib/__builtins__/list.py	Thu Jan 17 14:23:38 2019 +0100
     7.2 +++ b/lib/__builtins__/list.py	Thu Jan 24 22:20:33 2019 +0100
     7.3 @@ -3,7 +3,7 @@
     7.4  """
     7.5  List objects.
     7.6  
     7.7 -Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
     7.8 +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
     7.9  
    7.10  This program is free software; you can redistribute it and/or modify it under
    7.11  the terms of the GNU General Public License as published by the Free Software
    7.12 @@ -20,11 +20,11 @@
    7.13  """
    7.14  
    7.15  from __builtins__.iteration.iterator import itemiterator
    7.16 -from __builtins__.sequence import sequence, _get_absolute_index
    7.17 +from __builtins__.sequence import unpackable, _get_absolute_index
    7.18  from native import list_append, list_concat, list_element, list_init, \
    7.19                     list_len, list_nonempty, list_setelement, list_setsize
    7.20  
    7.21 -class list(sequence):
    7.22 +class list(unpackable):
    7.23  
    7.24      "Implementation of list."
    7.25  
     8.1 --- a/lib/__builtins__/sequence.py	Thu Jan 17 14:23:38 2019 +0100
     8.2 +++ b/lib/__builtins__/sequence.py	Thu Jan 24 22:20:33 2019 +0100
     8.3 @@ -20,7 +20,7 @@
     8.4  """
     8.5  
     8.6  from __builtins__.int import maxint
     8.7 -from native import isinstance as _isinstance, is_int
     8.8 +from native import isinstance as _isinstance, is_int, list_element
     8.9  
    8.10  class itemaccess:
    8.11  
    8.12 @@ -255,6 +255,22 @@
    8.13  
    8.14      # __iter__(self)
    8.15  
    8.16 +class unpackable(sequence):
    8.17 +
    8.18 +    "Class for list and tuple unpacking."
    8.19 +
    8.20 +    def __get_single_item_unchecked__(self, index):
    8.21 +
    8.22 +        """
    8.23 +        This method is provided by a privileged attribute recorded in the common
    8.24 +        module in the toolchain. Normal programs should not be able to access
    8.25 +        it.
    8.26 +        """
    8.27 +
    8.28 +        # NOTE: This uses implementation-specific access.
    8.29 +
    8.30 +        return list_element(self.__data__, index)
    8.31 +
    8.32  def _get_absolute_index(index, length):
    8.33  
    8.34      """
     9.1 --- a/lib/__builtins__/tuple.py	Thu Jan 17 14:23:38 2019 +0100
     9.2 +++ b/lib/__builtins__/tuple.py	Thu Jan 24 22:20:33 2019 +0100
     9.3 @@ -20,12 +20,12 @@
     9.4  """
     9.5  
     9.6  from __builtins__.iteration.iterator import itemiterator
     9.7 -from __builtins__.sequence import hashable, sequence
     9.8 +from __builtins__.sequence import hashable, unpackable
     9.9  from native import tuple_init, \
    9.10                     list_element, list_len, list_setsize, list_setelement, \
    9.11                     isinstance as _isinstance
    9.12  
    9.13 -class tuple(sequence, hashable):
    9.14 +class tuple(unpackable, hashable):
    9.15  
    9.16      "Implementation of tuple."
    9.17  
    9.18 @@ -66,7 +66,7 @@
    9.19          'step'.
    9.20          """
    9.21  
    9.22 -        return tuple(get_using(sequence.__getslice__, self)(start, end, step))
    9.23 +        return tuple(get_using(unpackable.__getslice__, self)(start, end, step))
    9.24  
    9.25      def __len__(self):
    9.26  
    10.1 --- a/templates/Makefile	Thu Jan 17 14:23:38 2019 +0100
    10.2 +++ b/templates/Makefile	Thu Jan 24 22:20:33 2019 +0100
    10.3 @@ -4,7 +4,7 @@
    10.4  
    10.5  SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c
    10.6  OBJ = $(SRC:.c=.o)
    10.7 -CFLAGS += -Wall -I. -finput-charset=UTF-8
    10.8 +CFLAGS += -Wall -Wno-maybe-uninitialized -I. -finput-charset=UTF-8
    10.9  LDFLAGS += -lm -lgc
   10.10  
   10.11  ifdef ARCH
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tests/for.py	Thu Jan 24 22:20:33 2019 +0100
    11.3 @@ -0,0 +1,34 @@
    11.4 +l = [1, 2, 3]
    11.5 +
    11.6 +# Test else clause.
    11.7 +
    11.8 +for i in l:
    11.9 +    print i             # 1
   11.10 +                        # 2
   11.11 +                        # 3
   11.12 +else:
   11.13 +    print 4             # 4
   11.14 +
   11.15 +# Test break versus else clause.
   11.16 +
   11.17 +for i in l:
   11.18 +    print i             # 1
   11.19 +                        # 2
   11.20 +    if i == 2:
   11.21 +        break
   11.22 +else:
   11.23 +    print 3
   11.24 +
   11.25 +# Test StopIteration in loop.
   11.26 +
   11.27 +try:
   11.28 +    for i in l:
   11.29 +        print i         # 1
   11.30 +                        # 2
   11.31 +        if i == 2:
   11.32 +            raise StopIteration
   11.33 +    else:
   11.34 +        print 3
   11.35 +
   11.36 +except StopIteration:
   11.37 +    print "stopped"     # stopped
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/tests/tuple_unpack_bad.py	Thu Jan 24 22:20:33 2019 +0100
    12.3 @@ -0,0 +1,9 @@
    12.4 +def good(t):
    12.5 +    a, b, c = t
    12.6 +
    12.7 +def bad(t):
    12.8 +    a = t.__get_single_item_unchecked__(0)
    12.9 +
   12.10 +t = 1, 2, 3
   12.11 +good(t)
   12.12 +bad(t)