# HG changeset patch # User Paul Boddie # Date 1548364833 -3600 # Node ID 8f6ea88d08455f674cd9407cd9703be83f448b4a # Parent 7783f93f470487a1a12fba122f0e93bf0b89f0f0# Parent ef74fed1f5c4f4c488e2ed833a74a89234302cfd Merged changes from the default branch. diff -r 7783f93f4704 -r 8f6ea88d0845 common.py --- a/common.py Thu Jan 17 14:23:38 2019 +0100 +++ b/common.py Thu Jan 24 22:20:33 2019 +0100 @@ -3,8 +3,8 @@ """ Common functions. -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, - 2014, 2015, 2016, 2017, 2018 Paul Boddie +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, + 2017, 2018, 2019 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 @@ -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)) @@ -579,9 +582,13 @@ # = .next # try: # while True: - # ... = () - # ... - # except StopIteration: + # try: + # ... = () + # except StopIteration: + # raise LoopExit + # {n.body} + # except LoopExit: + # {n.else_} # pass compiler.ast.Assign( @@ -592,15 +599,18 @@ compiler.ast.While( compiler.ast.Name("True"), compiler.ast.Stmt([ - compiler.ast.Assign( - [n.assign], - compiler.ast.CallFunc( - compiler.ast.Name(t2), - [] - )), + compiler.ast.TryExcept( + compiler.ast.Assign( + [n.assign], + compiler.ast.CallFunc( + compiler.ast.Name(t2), + [])), + [(compiler.ast.Name("StopIteration"), None, + compiler.ast.Raise(compiler.ast.Name("LoopExit")))], + None), n.body]), None), - [(compiler.ast.Name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Pass()]))], + [(compiler.ast.Name("LoopExit"), None, n.else_ or compiler.ast.Pass())], None) ]) @@ -1590,6 +1600,10 @@ predefined_constants = "False", "None", "NotImplemented", "True" +privileged_attributes = [ + "__get_single_item_unchecked__", + ] + unary_operator_functions = { # Unary operations. diff -r 7783f93f4704 -r 8f6ea88d0845 compiler/ast.py --- a/compiler/ast.py Thu Jan 17 14:23:38 2019 +0100 +++ b/compiler/ast.py Thu Jan 24 22:20:33 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 @@ -1249,7 +1253,7 @@ return "print %s" % ", ".join(map(str, dest + self.nodes)) class Raise(Node): - def __init__(self, expr1, expr2, expr3, lineno=None): + def __init__(self, expr1, expr2=None, expr3=None, lineno=None): self.expr1 = expr1 self.expr2 = expr2 self.expr3 = expr3 diff -r 7783f93f4704 -r 8f6ea88d0845 inspector.py --- a/inspector.py Thu Jan 17 14:23:38 2019 +0100 +++ b/inspector.py Thu Jan 24 22:20:33 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 7783f93f4704 -r 8f6ea88d0845 lib/__builtins__/__init__.py --- a/lib/__builtins__/__init__.py Thu Jan 17 14:23:38 2019 +0100 +++ b/lib/__builtins__/__init__.py Thu Jan 24 22:20:33 2019 +0100 @@ -3,7 +3,7 @@ """ Simple built-in classes and functions. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2019 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 @@ -35,6 +35,7 @@ IndentationError, IndexError, IOError, + LoopExit, KeyError, KeyboardInterrupt, NotImplementedError, diff -r 7783f93f4704 -r 8f6ea88d0845 lib/__builtins__/exception/__init__.py --- a/lib/__builtins__/exception/__init__.py Thu Jan 17 14:23:38 2019 +0100 +++ b/lib/__builtins__/exception/__init__.py Thu Jan 24 22:20:33 2019 +0100 @@ -3,7 +3,7 @@ """ Exception objects. -Copyright (C) 2015, 2016, 2017 Paul Boddie +Copyright (C) 2015, 2016, 2017, 2019 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 @@ -25,6 +25,7 @@ from __builtins__.exception.base import ( IndexError, + LoopExit, KeyError, NotImplementedError, RuntimeError, diff -r 7783f93f4704 -r 8f6ea88d0845 lib/__builtins__/exception/base.py --- a/lib/__builtins__/exception/base.py Thu Jan 17 14:23:38 2019 +0100 +++ b/lib/__builtins__/exception/base.py Thu Jan 24 22:20:33 2019 +0100 @@ -3,7 +3,7 @@ """ Base exception objects. See __builtins__.core for the core exceptions. -Copyright (C) 2015, 2016, 2018 Paul Boddie +Copyright (C) 2015, 2016, 2018, 2019 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 @@ -61,6 +61,12 @@ pass +class LoopExit(Exception): + + "An exception signalling the end of iteration in a loop." + + pass + class StopIteration(Exception): "An exception signalling the end of iteration." diff -r 7783f93f4704 -r 8f6ea88d0845 lib/__builtins__/list.py --- a/lib/__builtins__/list.py Thu Jan 17 14:23:38 2019 +0100 +++ b/lib/__builtins__/list.py Thu Jan 24 22:20:33 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 7783f93f4704 -r 8f6ea88d0845 lib/__builtins__/sequence.py --- a/lib/__builtins__/sequence.py Thu Jan 17 14:23:38 2019 +0100 +++ b/lib/__builtins__/sequence.py Thu Jan 24 22:20:33 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 7783f93f4704 -r 8f6ea88d0845 lib/__builtins__/tuple.py --- a/lib/__builtins__/tuple.py Thu Jan 17 14:23:38 2019 +0100 +++ b/lib/__builtins__/tuple.py Thu Jan 24 22:20:33 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 7783f93f4704 -r 8f6ea88d0845 templates/Makefile --- a/templates/Makefile Thu Jan 17 14:23:38 2019 +0100 +++ b/templates/Makefile Thu Jan 24 22:20:33 2019 +0100 @@ -4,7 +4,7 @@ SRC += calls.c exceptions.c main.c ops.c progops.c progtypes.c OBJ = $(SRC:.c=.o) -CFLAGS += -Wall -I. -finput-charset=UTF-8 +CFLAGS += -Wall -Wno-maybe-uninitialized -I. -finput-charset=UTF-8 LDFLAGS += -lm -lgc ifdef ARCH diff -r 7783f93f4704 -r 8f6ea88d0845 tests/for.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/for.py Thu Jan 24 22:20:33 2019 +0100 @@ -0,0 +1,34 @@ +l = [1, 2, 3] + +# Test else clause. + +for i in l: + print i # 1 + # 2 + # 3 +else: + print 4 # 4 + +# Test break versus else clause. + +for i in l: + print i # 1 + # 2 + if i == 2: + break +else: + print 3 + +# Test StopIteration in loop. + +try: + for i in l: + print i # 1 + # 2 + if i == 2: + raise StopIteration + else: + print 3 + +except StopIteration: + print "stopped" # stopped diff -r 7783f93f4704 -r 8f6ea88d0845 tests/tuple_unpack_bad.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/tuple_unpack_bad.py Thu Jan 24 22:20:33 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)