summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/compile.c23
-rw-r--r--tests/basics/for2.py8
-rw-r--r--tests/misc/features.py159
3 files changed, 183 insertions, 7 deletions
diff --git a/py/compile.c b/py/compile.c
index 43253a926b..25830eb6f9 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1534,35 +1534,41 @@ void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
// TODO preload end and step onto stack if they are not constants
-// TODO check if step is negative and do opposite test
+// Note that, as per semantics of for .. range, the final failing value should not be stored in the loop variable
+// And, if the loop never runs, the loop variable should never be assigned
void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, mp_parse_node_t pn_start, mp_parse_node_t pn_end, mp_parse_node_t pn_step, mp_parse_node_t pn_body, mp_parse_node_t pn_else) {
START_BREAK_CONTINUE_BLOCK
int top_label = comp_next_label(comp);
int entry_label = comp_next_label(comp);
- // compile: var = start
+ // compile: start, duplicated on stack
compile_node(comp, pn_start);
- c_assign(comp, pn_var, ASSIGN_STORE);
+ EMIT(dup_top);
EMIT_ARG(jump, entry_label);
EMIT_ARG(label_assign, top_label);
+ // at this point we actually have 1 less element on the stack
+ EMIT_ARG(set_stack_size, EMIT(get_stack_size) - 1);
+
+ // store next value to var
+ c_assign(comp, pn_var, ASSIGN_STORE);
+
// compile body
compile_node(comp, pn_body);
EMIT_ARG(label_assign, continue_label);
- // compile: var += step
- c_assign(comp, pn_var, ASSIGN_AUG_LOAD);
+ // compile: var + step, duplicated on stack
+ compile_node(comp, pn_var);
compile_node(comp, pn_step);
EMIT_ARG(binary_op, MP_BINARY_OP_INPLACE_ADD);
- c_assign(comp, pn_var, ASSIGN_AUG_STORE);
+ EMIT(dup_top);
EMIT_ARG(label_assign, entry_label);
// compile: if var <cond> end: goto top
- compile_node(comp, pn_var);
compile_node(comp, pn_end);
assert(MP_PARSE_NODE_IS_SMALL_INT(pn_step));
if (MP_PARSE_NODE_LEAF_SMALL_INT(pn_step) >= 0) {
@@ -1572,6 +1578,9 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var,
}
EMIT_ARG(pop_jump_if_true, top_label);
+ // discard final value of var that failed the loop condition
+ EMIT(pop_top);
+
// break/continue apply to outer loop (if any) in the else block
END_BREAK_CONTINUE_BLOCK
diff --git a/tests/basics/for2.py b/tests/basics/for2.py
new file mode 100644
index 0000000000..62f056e760
--- /dev/null
+++ b/tests/basics/for2.py
@@ -0,0 +1,8 @@
+i = 'init'
+for i in range(0):
+ pass
+print(i) # should not have been modified
+
+for i in range(10):
+ pass
+print(i) # should be last successful value of loop
diff --git a/tests/misc/features.py b/tests/misc/features.py
new file mode 100644
index 0000000000..d2fd8865c3
--- /dev/null
+++ b/tests/misc/features.py
@@ -0,0 +1,159 @@
+# mad.py
+# Alf Clement 27-Mar-2014
+#
+zero=0
+three=3
+print("1")
+print("2")
+print(three)
+print("{}".format(4))
+five=25/5
+print(int(five))
+j=0
+for i in range(4):
+ j += i
+print(j)
+print(3+4)
+try:
+ a=4/zero
+except:
+ print(8)
+print("xxxxxxxxx".count("x"))
+def ten():
+ return 10
+print(ten())
+a=[]
+for i in range(13):
+ a.append(i)
+print(a[11])
+print(a[-1])
+str="0123456789"
+print(str[1]+str[3])
+def p(s):
+ print(s)
+p("14")
+p(15)
+class A:
+ def __init__(self):
+ self.a=16
+ def print(self):
+ print(self.a)
+ def set(self,b):
+ self.a=b
+a=A()
+a.print()
+a.set(17)
+a.print()
+b=A()
+b.set(a.a + 1)
+b.print()
+for i in range(20):
+ pass
+print(i)
+if 20 > 30:
+ a="1"
+else:
+ a="2"
+if 0 < 4:
+ print(a+"0")
+else:
+ print(a+"1")
+a=[20,21,22,23,24]
+for i in a:
+ if i < 21:
+ continue
+ if i > 21:
+ break
+ print(i)
+b=[a,a,a]
+print(b[1][2])
+print(161//7)
+a=24
+while True:
+ try:
+ def gcheck():
+ global a
+ print(a)
+ gcheck()
+ class c25():
+ x=25
+ x=c25()
+ print(x.x)
+ raise
+ except:
+ print(26)
+ print(27+zero)
+ break
+print(28)
+k=29
+def f():
+ global k
+ k = yield k
+print(next(f()))
+while True:
+ k+= 1
+ if k < 30:
+ continue
+ break
+print(k)
+for i in [1,2,3]:
+ class A():
+ def __init__(self, c):
+ self.a = i+10*c
+ b = A(3)
+ print(b.a)
+print(34)
+p=0
+for i in range(35, -1, -1):
+ print(i)
+ p = p + 1
+ if p > 0:
+ break
+p=36
+while p == 36:
+ print(p)
+ p=37
+print(p)
+for i in [38]:
+ print(i)
+print(int(exec("def foo(): return 38") == None)+foo())
+d = {}
+exec("def bar(): return 40", d)
+print(d["bar"]())
+def fib2(n):
+ result = []
+ a, b = 0, 1
+ while a < n:
+ result.append(a)
+ a, b = b, a+b
+ return result
+print(fib2(100)[-2]-14)
+Answer={}
+Answer["ForAll"]=42
+print(Answer["ForAll"])
+i = 43
+def f(i=i):
+ print(i)
+i = 44
+f()
+print(i)
+while True:
+ try:
+ if None != True:
+ print(45)
+ break
+ else:
+ print(0)
+ except:
+ print(0)
+print(46)
+print(46+1)
+def u(p):
+ if p > 3:
+ return 3*p
+ else:
+ return u(2*p)-3*u(p)
+print(u(16))
+def u49():
+ return 49
+print(u49())