Skip to content

fix: getValue/inDayTimeRange/toNum — 3 glm-hunt bugs (#90 #91 #92) - #93

Merged
opaopa6969 merged 1 commit into
masterfrom
fix/issue-90-getvalue-cast
Aug 29, 2026
Merged

fix: getValue/inDayTimeRange/toNum — 3 glm-hunt bugs (#90 #91 #92)#93
opaopa6969 merged 1 commit into
masterfrom
fix/issue-90-getvalue-cast

Conversation

@opaopa6969

Copy link
Copy Markdown
Owner

Summary

Fixes three [glm-hunt] issues reported in the previous stage. Each is a small, independent, reversible bug fix; bundled into one PR because the touch points do not overlap and splitting would only add CI/merge overhead.

Closes #90
Closes #91
Closes #92

Why one PR

The three bugs live in two files (AbstractCalculationContext.java, P4TypedAstEvaluator.java) and do not interact. Each fix is minimal and locally reversible (revert the relevant hunk only). Bundling avoids three CI runs and three merge commits for what is effectively a single bug-hunt pass.

Changes

#90getValue() ClassCastException on non-Float Number

AbstractCalculationContext.getValue(String) did (Float) valueByName.get(name), but set(String, Number) stores arbitrary Number subtypes (Double/Integer/BigInteger...). Reading such a value via getValue threw ClassCastException, affecting e.g. inTimeRange/getValue("nowHour") after a set(String, Number) declaration.

Fix: read as Number; if not already Float, convert via number.floatValue(). Float values are preserved exactly (no extra boxing). Empty map → Optional.empty() as before.

#91toNum() ClassCastException + missing castToNumberType

P4TypedAstEvaluator.evalToNumExpr returned a raw Double (ignoring the configured numberType) and cast the default value via (Number) eval(...), so a non-Number default (toNum('abc','xyz'), toNum('abc', true)) threw ClassCastException. Other number functions (sin/sqrt/abs...) already route through castToNumberType; only toNum was inconsistent. The JavaCode backend rejects non-Number defaults at parse time, so this also improves cross-backend parity (AST no longer crashes at eval time).

Fix: route both the parsed value and the default through castToNumberType(double); when the default is not a Number, fall back to 0.0 instead of throwing. This is the minimal safe option; tightening the grammar to reject non-Number defaults at parse time is a larger change left for a follow-up if desired.

#92inDayTimeRange always false for same-day midnight span

inDayTimeRange(MONDAY, 22, MONDAY, 6) (same day, fromHour > toHour) always returned false, while EmbeddedFunction.inTimeRange(22, 6) treats fromHour > toHour as a midnight span and returns true for 23/3. User intent ("Monday 22:00 → Tuesday 06:00" expressed intra-day) was silently dropped.

Fix: when the from/to days are equal and fromHour > toHour, evaluate as a midnight span (nowHour >= fromHour || nowHour < toHour), mirroring inTimeRange. Normal same-day ranges are unchanged.

Tests

  • Issue90GetValueCastTestset(String, Number) with Double/Integer/BigInteger; getValue returns the floatValue(); Float path exact; absent → empty.
  • Issue91ToNumTest — non-Number defaults no longer throw; toNum('3.14', 0) returns Float for numberType=_float and Double for numberType=_double; default value is cast through numberType.
  • Issue92InDayTimeRangeTest — same-day midnight span includes 23/3/22, excludes 6 (boundary) and 12 (gap); consistency with inTimeRange; normal same-day range still works.

Full suite: 703 tests, 0 failures (9 pre-existing skips).

Risk / revert

All changes are additive/safe-conversion paths; no public API signature changes. Revert is git revert <commit> (single commit) or per-hunk.

…nsistent, toNum() cast through numberType

Fix three glm-hunt bugs in CalculationContext / P4TypedAstEvaluator:

#90: AbstractCalculationContext.getValue() did an unchecked (Float) cast on
    valueByName, so set(String, Number) with Double/Integer/BigInteger etc.
    caused ClassCastException on read. Convert via Number.floatValue() when
    the stored value is not already a Float; Float values are preserved as-is.

#91: P4TypedAstEvaluator.evalToNumExpr() returned a raw Double and cast the
    default value via (Number), causing ClassCastException for non-Number
    defaults (e.g. toNum('abc','xyz')) and ignoring the configured numberType.
    Route both the parsed value and the default through castToNumberType so
    the result honors numberType, and fall back to 0.0 when the default is
    not a Number instead of throwing.

#92: AbstractCalculationContext.inDayTimeRange() returned false for a
    same-day range with fromHour > toHour (a midnight-spanning range),
    inconsistent with EmbeddedFunction.inTimeRange(). When fromHour >
    toHour on the same day, evaluate as a midnight span
    (nowHour >= fromHour || nowHour < toHour), matching inTimeRange().

Each bug is covered by a dedicated regression test (Issue90/91/92*Test).
Full test suite passes (703 tests, 0 failures).
@opaopa6969
opaopa6969 merged commit 5ae6675 into master Aug 29, 2026
1 check passed
@opaopa6969
opaopa6969 deleted the fix/issue-90-getvalue-cast branch August 29, 2026 18:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment