fix(generator): normalize float literal emission and handle INF/NAN constants - #33
Conversation
81f93bd to
e9aa012
Compare
matyhtf
left a comment
There was a problem hiding this comment.
Thank you for consolidating the float literal generation paths. The overall direction is correct, and the new tests cover ordinary runtime expression lowering well.
I found two implementation issues that need to be addressed before merging.
- The persistent declaration path in
gen_stub.phpstill emits floats throughstrval().
EvaluatedValue::getCExpr() currently contains:
} elseif ($this->type->isInt() or $this->type->isFloat()) {
return strval($this->value);
}As a result, class constants and property defaults still generate raw special-value tokens:
ZVAL_DOUBLE(&const_POSITIVE_value, INF);
ZVAL_DOUBLE(&const_NEGATIVE_value, -INF);
ZVAL_DOUBLE(&const_NOT_A_NUMBER_value, NAN);Finite values in the same path also remain dependent on the host precision setting. With precision=14, M_E still generates:
ZVAL_DOUBLE(&const_E_value, 2.718281828459);
ZVAL_DOUBLE(&property_e_default_value, 2.718281828459);This means the PR does not yet completely fix either #31 or #34. Please route float values emitted by EvaluatedValue::getCExpr() through the same canonical float literal formatter. This may require making the formatter accessible to gen_stub.php, or moving it to a shared stateless helper.
sprintf('%.17g', ...)is locale-dependent and can silently generate incorrect C++.
PHP's %g conversion uses the decimal separator from LC_NUMERIC. For example, under the available en_DK.utf8 locale:
sprintf('%.17g', 1.5) // "1,5"The PR then generates:
return php::toFloat(1,5.0);This is parsed as a C++ comma expression and evaluates to 5.0, so it is a semantic miscompile rather than only a syntax issue.
Please use PHP's locale-independent %h conversion instead, for example:
$text = sprintf('%.17h', $value);The existing exponent/decimal preservation logic can remain the same.
After consolidation, CompilerBase::$floatPrecision also appears to have no remaining readers. Removing it would avoid retaining dead configuration, though this cleanup is not a merge blocker.
I reproduced both blocking cases on the PR head. The current focused PHPUnit tests pass, but they do not exercise declaration metadata or a locale with a comma decimal separator.
|
On a personal note, I was deeply saddened to hear about the devastating flash floods and landslides affecting Nepal and communities along the Nepal–China border. My heartfelt condolences go to everyone who has lost family members, friends, and loved ones. My thoughts are also with those who remain missing, those who have been injured or displaced, and the rescue workers and volunteers facing extraordinarily difficult conditions. I sincerely hope that you, your family, and your friends are safe. May those who lost their lives rest in peace, and may the affected communities find strength, support, and recovery in the difficult days ahead. |
…onstants
Consolidate float-to-C++ literal generation into Utils::genFloatLiteral().
Previously:
- genCValue() stringified floats directly via (string), emitting 'INF', '-INF', 'NAN', or losing the floating-point decimal point for whole numbers like 1.0 -> '1'.
- BinaryOpTrait::genFloatLiteral() used sprintf('%.17g') without handling INF or NAN.
Now all float code generation paths delegate to Utils::genFloatLiteral(), mapping INF/-INF/NAN to std::numeric_limits<double> and ensuring whole numbers retain .0.
e9aa012 to
2d81626
Compare
|
Thank you @matyhtf for the thorough review and catch! I have addressed all the feedback in the latest update:
And thank you so much for your kind words and thoughts regarding the situation in Nepal. It means a lot. Everyone in our family is safe. Wishing you all the best as well! |
matyhtf
left a comment
There was a problem hiding this comment.
Thank you for addressing all previous review findings. I verified that the persistent declaration path now uses the canonical formatter, the locale-independent float format is used, and the dead precision configuration has been removed. I also compiled the new declaration fixture with precision=14; the generated C++ builds and runs successfully.
There is a small isolation issue in the new locale test: setlocale returns the newly selected locale rather than the previous one, so the test does not restore the original locale. This does not affect the generator fix, and we will correct the test on master in a follow-up commit. The implementation itself is approved.
|
Thank you for the merge and the follow-up locale fix, the LC_NUMERIC-only approach with the skip guard is much cleaner than what I had. Appreciate you taking the time to tidy that up. Really glad this contribution made it in. Looking forward to digging deeper into the codebase and contributing more where I can. |
Summary
Consolidates float literal generation into
Utils::genFloatLiteral()so all float-to-C++ codegen paths handle precision, locale independence, and special values consistently.Fixes #31
Fixes #34
Details
genCValue()andgen_stub.php(EvaluatedValue::getCExpr()) previously stringified floats directly, which:precisionini (default 14) instead of full 17 digits (Float constants are truncated to the host's precision ini and baked into the binary #31).INF/-INF/NANas raw invalid C++ tokens in expressions, class constants, and property defaults (Constant expressions evaluating to INF, -INF, or NAN generate invalid C++ syntax #34).1.0as"1", losing floating-point type identity in C++.%gto PHP's locale-independent%hspecifier (%.17h) to avoid comma decimal separators under European locales.genFloatLiteral()is now the single public helper underTypePhp\Generator\Utils, mapping special values tostd::numeric_limits<double>and preserving.0on whole numbers.$floatPrecisionproperty fromCompilerBase.OperatorTestfor runtime expressions, class constant/property declaration metadata, and locale independence.