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:
16
tests/language/numeric/truth_value_arithmetic.bas
Normal file
16
tests/language/numeric/truth_value_arithmetic.bas
Normal file
@@ -0,0 +1,16 @@
|
||||
10 REM A truth value carries its payload in boolvalue, not floatval. The three
|
||||
20 REM numeric operators were `if ( INTEGER ) ... else <treat as float>`, and
|
||||
30 REM that else was a catch-all rather than a float branch -- so a truth value
|
||||
40 REM on the LEFT computed 0 - 1 into a field nothing reads, kept its BOOLEAN
|
||||
50 REM type, and printed `true` instead of -2. Silent, and wrong twice over.
|
||||
60 A# = 1
|
||||
70 PRINT (A# == 1)
|
||||
80 REM On the RIGHT it stays legal and stays -1, which is the same property that
|
||||
90 REM lets AND and OR double as logical operators. Refusing it here would have
|
||||
100 REM broken every condition in the language.
|
||||
110 PRINT 5 - (A# == 1)
|
||||
120 PRINT 5 * (A# == 1)
|
||||
130 PRINT 5 + (A# == 1)
|
||||
140 PRINT 4 - (A# == 2)
|
||||
150 REM And on the left it is refused by name rather than computed.
|
||||
160 PRINT (A# == 1) - 1
|
||||
7
tests/language/numeric/truth_value_arithmetic.txt
Normal file
7
tests/language/numeric/truth_value_arithmetic.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
true
|
||||
6
|
||||
-5
|
||||
4
|
||||
4
|
||||
? 160 : RUNTIME ERROR Cannot perform subtraction on a truth value
|
||||
|
||||
Reference in New Issue
Block a user