Exercise 3: Tracing _is_equal for "3.0 == 3" vs. "true == 1" — Possible Solution ==================================================================== THE CODE BEING TRACED ------------------------------ def _is_equal(self, left, right): if type(left) is not type(right): return False return left == right TRACE 1 — 'print 3.0 == 3;' ------------------------------ Both '3.0' and '3' are tokenized as NUMBER tokens by the lexer -- Wisp's grammar has no separate integer literal syntax at all. primary() converts BOTH through the identical line: return Literal(float(tok[1])) So by the time _is_equal runs: left = 3.0 (a Python float) right = 3.0 (a Python float -- float('3') == float('3.0')) type(left) is float type(right) is float type(left) is not type(right) -> False (the guard does NOT trigger) left == right -> 3.0 == 3.0 -> True Result: true TRACE 2 — 'print true == 1;' ------------------------------ 'true' is a keyword, matched by primary()'s `if self.match('TRUE')` branch, producing Literal(True) -- a Python bool. '1' is a NUMBER token, producing Literal(float('1')) = Literal(1.0) -- a Python float. left = True (a Python bool) right = 1.0 (a Python float) type(left) is bool type(right) is float type(left) is not type(right) -> True (the guard DOES trigger) -> return False immediately, left == right is never even evaluated Result: false WHY THIS WORKS AS AN ANSWER ------------------------------ The two cases only look similar on the surface -- "3.0 and 3 are both numbers really" reads the same as "true and 1 are both numbers really" if you're thinking about VALUES. But _is_equal checks Wisp's own TYPES, not numeric value. 3.0 and 3 are equal because Wisp's parser produces the exact same Python type (float) for both, regardless of which literal spelling was used -- the type check is genuinely comparing "same Wisp type" in that case, and passes. true and 1 are NOT equal because Wisp's parser produces two deliberately different Python types for them (bool vs. float) -- the type check is doing its actual job in that case, blocking a value-level coincidence (Python's own True == 1.0 quirk from bool being an int subclass) from ever being consulted at all. The guard doesn't ask "would these be value-equal if I skipped it" -- it asks "are these even the same kind of thing," and answers that question before value equality gets a chance to run.