# HG changeset patch # User Paul Boddie # Date 1548353790 -3600 # Node ID ef74fed1f5c4f4c488e2ed833a74a89234302cfd # Parent d2c64260113c9c96ab3e2ab1e5243a51f02cc83a# Parent cd0d6f9991fb5d0c43e6cef6c513dc5c883a6a72 Merged the tuple-optimisations branch into the default branch. diff -r d2c64260113c -r ef74fed1f5c4 common.py --- a/common.py Thu Jan 24 19:12:29 2019 +0100 +++ b/common.py Thu Jan 24 19:16:30 2019 +0100 @@ -461,8 +461,11 @@ for i, node in enumerate(n.nodes): statements.append( - compiler.ast.Assign([node], compiler.ast.Subscript( - compiler.ast.Name(temp), "OP_APPLY", [compiler.ast.Const(i, str(i))])) + compiler.ast.Assign([node], compiler.ast.CallFunc( + compiler.ast.Getattr(compiler.ast.Name(temp), + "__get_single_item_unchecked__", + privileged=True), + [compiler.ast.Const(i, str(i))])) ) return self.process_structure_node(compiler.ast.Stmt(statements)) @@ -1597,6 +1600,10 @@ predefined_constants = "False", "None", "NotImplemented", "True" +privileged_attributes = [ + "__get_single_item_unchecked__", + ] + unary_operator_functions = { # Unary operations. diff -r d2c64260113c -r ef74fed1f5c4 compiler/ast.py --- a/compiler/ast.py Thu Jan 24 19:12:29 2019 +0100 +++ b/compiler/ast.py Thu Jan 24 19:16:30 2019 +0100 @@ -868,11 +868,15 @@ return "%s %s" % (self.expr, " ".join(map(str, self.quals))) class Getattr(Node): - def __init__(self, expr, attrname, lineno=None): + def __init__(self, expr, attrname, lineno=None, privileged=False): self.expr = expr self.attrname = attrname self.lineno = lineno + # Support privileged internal accesses. + + self.privileged = privileged + def getChildren(self): return self.expr, self.attrname diff -r d2c64260113c -r ef74fed1f5c4 inspector.py --- a/inspector.py Thu Jan 24 19:12:29 2019 +0100 +++ b/inspector.py Thu Jan 24 19:16:30 2019 +0100 @@ -21,7 +21,8 @@ """ from branching import BranchTracker -from common import CommonModule, get_argnames, init_item, predefined_constants +from common import CommonModule, get_argnames, init_item, \ + predefined_constants, privileged_attributes from modules import BasicModule, CacheWritingModule, InspectionNaming from errors import InspectError from referencing import Reference @@ -358,6 +359,16 @@ "Process the given attribute access node 'n'." + path = self.get_namespace_path() + + # Test for access to special privileged attributes. + + if isinstance(n, compiler.ast.Getattr) and \ + n.attrname in privileged_attributes and not n.privileged: + + raise InspectError("Attribute %s is accessed by an unprivileged operation." % + n.attrname, path, n) + # Obtain any completed chain and return the reference to it. name_ref = self.process_attribute_chain(n) @@ -372,8 +383,6 @@ # either being name-based and thus an access rooted on a name, or being # based on some other node and thus an anonymous access of some kind. - path = self.get_namespace_path() - # Start with the the full attribute chain. remaining = self.attrs diff -r d2c64260113c -r ef74fed1f5c4 lib/__builtins__/list.py --- a/lib/__builtins__/list.py Thu Jan 24 19:12:29 2019 +0100 +++ b/lib/__builtins__/list.py Thu Jan 24 19:16:30 2019 +0100 @@ -3,7 +3,7 @@ """ List objects. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -20,11 +20,11 @@ """ from __builtins__.iteration.iterator import itemiterator -from __builtins__.sequence import sequence, _get_absolute_index +from __builtins__.sequence import unpackable, _get_absolute_index from native import list_append, list_concat, list_element, list_init, \ list_len, list_nonempty, list_setelement, list_setsize -class list(sequence): +class list(unpackable): "Implementation of list." diff -r d2c64260113c -r ef74fed1f5c4 lib/__builtins__/sequence.py --- a/lib/__builtins__/sequence.py Thu Jan 24 19:12:29 2019 +0100 +++ b/lib/__builtins__/sequence.py Thu Jan 24 19:16:30 2019 +0100 @@ -20,7 +20,7 @@ """ from __builtins__.int import maxint -from native import isinstance as _isinstance, is_int +from native import isinstance as _isinstance, is_int, list_element class itemaccess: @@ -255,6 +255,22 @@ # __iter__(self) +class unpackable(sequence): + + "Class for list and tuple unpacking." + + def __get_single_item_unchecked__(self, index): + + """ + This method is provided by a privileged attribute recorded in the common + module in the toolchain. Normal programs should not be able to access + it. + """ + + # NOTE: This uses implementation-specific access. + + return list_element(self.__data__, index) + def _get_absolute_index(index, length): """ diff -r d2c64260113c -r ef74fed1f5c4 lib/__builtins__/tuple.py --- a/lib/__builtins__/tuple.py Thu Jan 24 19:12:29 2019 +0100 +++ b/lib/__builtins__/tuple.py Thu Jan 24 19:16:30 2019 +0100 @@ -20,12 +20,12 @@ """ from __builtins__.iteration.iterator import itemiterator -from __builtins__.sequence import hashable, sequence +from __builtins__.sequence import hashable, unpackable from native import tuple_init, \ list_element, list_len, list_setsize, list_setelement, \ isinstance as _isinstance -class tuple(sequence, hashable): +class tuple(unpackable, hashable): "Implementation of tuple." @@ -66,7 +66,7 @@ 'step'. """ - return tuple(get_using(sequence.__getslice__, self)(start, end, step)) + return tuple(get_using(unpackable.__getslice__, self)(start, end, step)) def __len__(self): diff -r d2c64260113c -r ef74fed1f5c4 tests/tuple_unpack_bad.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tuple_unpack_bad.py Thu Jan 24 19:16:30 2019 +0100 @@ -0,0 +1,9 @@ +def good(t): + a, b, c = t + +def bad(t): + a = t.__get_single_item_unchecked__(0) + +t = 1, 2, 3 +good(t) +bad(t)