|
| 1 | +[ |
| 2 | + { |
| 3 | + "id": "arithmetic-precedence", |
| 4 | + "note": "+ * - precedence", |
| 5 | + "source": "x = 2 + 3 * 4 - 1\nprint(x)", |
| 6 | + "expected": { "kind": "ok", "text": "13" }, |
| 7 | + "expect": "parity" |
| 8 | + }, |
| 9 | + { |
| 10 | + "id": "int-div-mod-pow", |
| 11 | + "note": "floor div, modulo, power on ints", |
| 12 | + "source": "print(17 // 5)\nprint(17 % 5)\nprint(2 ** 10)", |
| 13 | + "expected": { "kind": "ok", "text": "3\n2\n1024" }, |
| 14 | + "expect": "parity" |
| 15 | + }, |
| 16 | + { |
| 17 | + "id": "floor-div-neg", |
| 18 | + "note": "floor division / modulo follow Python (floor) semantics, not C", |
| 19 | + "source": "print(-7 // 2)\nprint(-7 % 2)", |
| 20 | + "expected": { "kind": "ok", "text": "-4\n1" }, |
| 21 | + "expect": "parity" |
| 22 | + }, |
| 23 | + { |
| 24 | + "id": "float-div", |
| 25 | + "note": "true division yields a float", |
| 26 | + "source": "print(7 / 2)", |
| 27 | + "expected": { "kind": "ok", "text": "3.5" }, |
| 28 | + "expect": "parity" |
| 29 | + }, |
| 30 | + { |
| 31 | + "id": "unary-minus", |
| 32 | + "note": "unary minus binds tighter than *", |
| 33 | + "source": "print(-5)\nx = -2\nprint(x * 3)", |
| 34 | + "expected": { "kind": "ok", "text": "-5\n-6" }, |
| 35 | + "expect": "parity" |
| 36 | + }, |
| 37 | + { |
| 38 | + "id": "comparison", |
| 39 | + "note": "ordered and equality comparisons return booleans", |
| 40 | + "source": "print(3 < 5)\nprint(3 == 4)\nprint(5 >= 5)", |
| 41 | + "expected": { "kind": "ok", "text": "True\nFalse\nTrue" }, |
| 42 | + "expect": "parity" |
| 43 | + }, |
| 44 | + { |
| 45 | + "id": "string-concat-repeat", |
| 46 | + "note": "str + str concatenates; str * int repeats", |
| 47 | + "source": "print('ab' + 'cd')\nprint('ab' * 3)", |
| 48 | + "expected": { "kind": "ok", "text": "abcd\nababab" }, |
| 49 | + "expect": "parity" |
| 50 | + }, |
| 51 | + { |
| 52 | + "id": "list-mutate-len", |
| 53 | + "note": "list.append mutates in place; len reflects it", |
| 54 | + "source": "a = [1, 2]\na.append(3)\nprint(a)\nprint(len(a))", |
| 55 | + "expected": { "kind": "ok", "text": "[1, 2, 3]\n3" }, |
| 56 | + "expect": "parity" |
| 57 | + }, |
| 58 | + { |
| 59 | + "id": "dict-setitem", |
| 60 | + "note": "dict item assignment; repr matches CPython", |
| 61 | + "source": "d = {'k': 1}\nd['k'] = 2\nprint(d)", |
| 62 | + "expected": { "kind": "ok", "text": "{'k': 2}" }, |
| 63 | + "expect": "parity" |
| 64 | + }, |
| 65 | + { |
| 66 | + "id": "string-methods", |
| 67 | + "note": ".upper() / .lower()", |
| 68 | + "source": "s = 'Hello'\nprint(s.upper())\nprint(s.lower())", |
| 69 | + "expected": { "kind": "ok", "text": "HELLO\nhello" }, |
| 70 | + "expect": "parity" |
| 71 | + }, |
| 72 | + { |
| 73 | + "id": "for-range-accumulate", |
| 74 | + "note": "for over range accumulates", |
| 75 | + "source": "total = 0\nfor i in range(1, 5):\n total = total + i\nprint(total)", |
| 76 | + "expected": { "kind": "ok", "text": "10" }, |
| 77 | + "expect": "parity" |
| 78 | + }, |
| 79 | + { |
| 80 | + "id": "while-break", |
| 81 | + "note": "while True + break; nested if", |
| 82 | + "source": "n = 0\nwhile True:\n n = n + 1\n if n >= 3:\n break\nprint(n)", |
| 83 | + "expected": { "kind": "ok", "text": "3" }, |
| 84 | + "expect": "parity" |
| 85 | + }, |
| 86 | + { |
| 87 | + "id": "if-elif-else", |
| 88 | + "note": "elif ladder picks the first true branch", |
| 89 | + "source": "score = 72\nif score >= 90:\n print('A')\nelif score >= 70:\n print('B')\nelse:\n print('C')", |
| 90 | + "expected": { "kind": "ok", "text": "B" }, |
| 91 | + "expect": "parity" |
| 92 | + }, |
| 93 | + { |
| 94 | + "id": "function-return", |
| 95 | + "note": "def + positional call + return", |
| 96 | + "source": "def f(a, b):\n return a + b\nprint(f(2, 3))", |
| 97 | + "expected": { "kind": "ok", "text": "5" }, |
| 98 | + "expect": "parity" |
| 99 | + }, |
| 100 | + { |
| 101 | + "id": "conversions", |
| 102 | + "note": "bool / int / str builtins match CPython", |
| 103 | + "source": "print(bool(1))\nprint(bool(0))\nprint(int(5.9))\nprint(str(10))", |
| 104 | + "expected": { "kind": "ok", "text": "True\nFalse\n5\n10" }, |
| 105 | + "expect": "parity" |
| 106 | + }, |
| 107 | + { |
| 108 | + "id": "membership-in", |
| 109 | + "note": "in over a list", |
| 110 | + "source": "xs = [10, 20, 30]\nprint(20 in xs)\nprint(99 in xs)", |
| 111 | + "expected": { "kind": "ok", "text": "True\nFalse" }, |
| 112 | + "expect": "parity" |
| 113 | + }, |
| 114 | + { |
| 115 | + "id": "tuple-len", |
| 116 | + "note": "tuple repr and len", |
| 117 | + "source": "t = (1, 2, 3)\nprint(t)\nprint(len(t))", |
| 118 | + "expected": { "kind": "ok", "text": "(1, 2, 3)\n3" }, |
| 119 | + "expect": "parity" |
| 120 | + }, |
| 121 | + { |
| 122 | + "id": "abs-min-max", |
| 123 | + "note": "abs / min / max over a list", |
| 124 | + "source": "print(abs(-4))\nprint(min([3, 1, 2]))\nprint(max([3, 1, 2]))", |
| 125 | + "expected": { "kind": "ok", "text": "4\n1\n3" }, |
| 126 | + "expect": "parity" |
| 127 | + }, |
| 128 | + { |
| 129 | + "id": "drift-iadd", |
| 130 | + "note": "CPython list.__iadd__ extends in place, so the alias b sees [1, 2]; the simulator rebinds a to a new list, so b stays [1]. (Phase 3: __iadd__/__imul__)", |
| 131 | + "source": "a = [1]\nb = a\na += [2]\nprint(b)", |
| 132 | + "expected": { "kind": "ok", "text": "[1, 2]" }, |
| 133 | + "expect": "drift" |
| 134 | + }, |
| 135 | + { |
| 136 | + "id": "drift-unbound", |
| 137 | + "note": "CPython pre-scopes x as local inside bump() (assigned, not declared global), so reading x before that assignment raises UnboundLocalError. The simulator has no local pre-scope (lookupName walks all frames), so the read falls through to the module x and prints 1. (Phase 2: scope)", |
| 138 | + "source": "x = 1\ndef bump():\n print(x)\n x = 2\nbump()", |
| 139 | + "expected": { "kind": "exc", "excType": "UnboundLocalError" }, |
| 140 | + "expect": "drift" |
| 141 | + } |
| 142 | +] |
0 commit comments