Refuse an operand the numeric path cannot read
math_minus, math_multiply and math_divide were `if ( INTEGER ) ... else <treat
as float>`, and that else was a catch-all rather than a float branch: it read
floatval from whatever it was handed. A truth value keeps its payload in
boolvalue and leaves floatval zero, so a truth value on the left computed into a
field nothing reads and kept its BOOLEAN type --
(A# == 1) - 1 printed true, should be -2
(A# == 1) * 3 printed true, should be -3
(A# == 1) + 1 correctly refused
wrong in value and in type, and silent. math_plus escaped only because it
enumerates its cases and ends in an error.
The three now share one require_numeric() guard, so a type added later is
refused by all of them at once instead of quietly taking the float branch in
each. The two operands have different rules and that asymmetry is the point: the
left one picks the branch and must be a number, while the right is read through
rval_as_int(), which handles -1/0 deliberately. `5 - (A# == 1)` is 6, and that
is the same property that lets AND and OR double as logical operators, so
refusing a truth value on the right would have broken every condition in the
language.
Found by asking what a structure operand would do to this path, which is where
AKBASIC_TYPE_STRUCT is about to arrive. The structures work did not create the
defect; it made an already-reachable one worth chasing.
Two stale comments went with it. src/value.c's header and a duplicate block
above rval_as_int both cited "TODO.md section 12", which does not exist -- the
defect list is section 6 -- and the duplicate described the summing behaviour
item 5 had already removed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
36
TODO.md
36
TODO.md
@@ -1527,6 +1527,42 @@ the reference's semantics reproduced faithfully; the third is the port's own.
|
||||
listings read it there. Same known-failing test as item 19; the fix is a scoping decision
|
||||
about where a loop counter is created, not an ordering one.
|
||||
|
||||
### Found while auditing `akbasic_value_clone()` for the structures work
|
||||
|
||||
22. ~~**The numeric operators' `else` was a catch-all, not a float branch.**~~ **Fixed.**
|
||||
`math_minus`, `math_multiply` and `math_divide` were `if ( INTEGER ) … else <treat as
|
||||
float>`, and that `else` read `floatval` from whatever it was handed. A truth value
|
||||
keeps its payload in `boolvalue` and leaves `floatval` zero, so a truth value on the
|
||||
*left* computed into a field nothing reads and kept its `BOOLEAN` type:
|
||||
|
||||
```
|
||||
(A# == 1) - 1 printed true should be -2
|
||||
(A# == 1) * 3 printed true should be -3
|
||||
(A# == 1) + 1 correctly refused
|
||||
```
|
||||
|
||||
Wrong in value and in type, and silent. `math_plus` escaped only because it enumerates
|
||||
its cases and ends in an error; the other three now share one `require_numeric()` guard
|
||||
so a type added later is refused by all of them at once instead of quietly taking the
|
||||
float branch in each.
|
||||
|
||||
**The two operands have different rules, deliberately.** The left one picks the branch
|
||||
and must be a number. The right one is read through `rval_as_int()`, which handles a
|
||||
truth value on purpose — `5 - (A# == 1)` is 6, and that is the same property that lets
|
||||
`AND` and `OR` double as logical operators. Refusing it on the right would have broken
|
||||
every condition in the language, and `tests/language/numeric/truth_value_arithmetic.bas`
|
||||
pins both halves.
|
||||
|
||||
**Found by asking what a structure operand would do**, since `AKBASIC_TYPE_STRUCT` would
|
||||
have taken exactly this path and read a `floatval` it does not carry. The structures
|
||||
work did not create this defect; it made an already-reachable one worth chasing. Same
|
||||
shape as item 5 and fixed the same way, with the assertions against the value API where
|
||||
the bad value can actually be constructed.
|
||||
|
||||
Two stale comments went with it: `src/value.c`'s file header and a duplicate block above
|
||||
`rval_as_int()` both cited "TODO.md section 12", which does not exist — the defect list
|
||||
is §6 — and the duplicate described the summing behaviour item 5 had already removed.
|
||||
|
||||
### Found while writing the error-code appendix
|
||||
|
||||
21. **A dependency's status code reaches `ER#` where the interpreter has one of its own.**
|
||||
|
||||
Reference in New Issue
Block a user