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
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)