Repository navigation
feat: math functions and function names with digits (3.7.13) - #699
Merged
Merged
Conversation
NLP++ had only logten, abs, mod, factorial and randomint for math. Add the rounding family and the remaining core C/C++ math functions: floor(num) NUM round down, toward -infinity ceiling(num) NUM round up, toward +infinity round(num) NUM nearest whole number, halfway away from zero truncate(num) NUM discard the fraction, toward zero sqrt(num) FLOAT square root, errors on a negative argument pow(base,exp) FLOAT errors when the result is NaN or out of float range log(num) FLOAT natural (base e) log, argument must be positive The four rounding functions take a float and return a whole number, which is what callers actually want; floor and truncate deliberately differ on negatives (floor(-3.7) = -4, truncate(-3.7) = -3). Registered in the parallel funcs.h / func_defs.h tables (kept in sync, 340 entries each), declared in fn.h, dispatched and implemented in fn.cpp. Compiled analyzers need matching runtime entry points: codegen in iaction.cpp emits Arun::<fnname> for every builtin, so each function also gets Arun overloads in fnrun.cpp and declarations in Arun.h, including the four RFASem/float combinations for the two-argument pow. The global C functions are called with the :: qualifier so the new Arun members do not recurse into themselves. Help: seven new pages under visualtext/Help/helps modeled on logten.htm, TOC entries in Help.hhc, and Table_of_Math_Functions.htm rebuilt. That table previously listed logten alone, so abs, factorial, mod and randomint are now documented there as well. Verified against a live analyzer: all values correct, including the floor/truncate split on negatives and round(-3.5) = -4. Note that negative literals as arguments (e.g. floor(-3.2)) fail to parse, but that is a pre-existing NLP++ limitation -- abs(-5), mod(-7,3) and logten(-1.0) fail the same way; passing a negative variable works. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 26, 2026
The math-function commit named 3.7.13 in its subject but left the #define at 3.7.12, so nlp --version would have under-reported the build. Note that this #define is what --version actually prints; the generated Version() from version.cpp is commented out at the callsite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ddehilster
force-pushed
the
feat/nlpxx-math-functions
branch
from
July 26, 2026 13:02
46db686 to
da93da0
Compare
A user function whose name contained a digit (Round2, Clamp01, Fixed2) or an
underscore (Round_2) never compiled. The rule-file tokenizer built _LIT from a
single _xALPHA token, so "Round2" arrived at the function grammar as
_LIT("Round") + _NUM(2) and never matched "_FNCALLLIST <- _LIT \(" in
gram2.nlp. The diagnostic was "[Warning: Missing ';']" + "[Syntax error.]" on a
function header that is itself valid, which sends you looking at the previous
statement instead of at the name.
Take the fix the issue prefers -- accept the digits -- rather than reporting a
better error, since digits have always been legal in L() variable names.
bigtok.nlp: glom adjacent alpha/numeric/underscore tokens into one _LIT, but
only when they are immediately followed by an UNESCAPED "(", ie a function
definition header or a call. That gate is what keeps the change contained:
@rules literals must write "\(" and key=(val) pairs put "=" before the paren,
so element literals ("covid19" stays two elements) and pair values tokenize
exactly as before. The second element is [plus], so single-token names never
reach the rule and the keyword rules (if/while/return/L/N/X/G/P/s) still win.
postrfa.cpp: rfaname() gains a two-arg form that gathers the covered text
across a range of collects; the one-arg form is untouched. The name still
starts at an _xALPHA, so the identifiers Ifunc::genDecls emits into generated
C++ stay legal.
Verified: all forms from the issue table now run (Round2, R2ound, x2Round,
Round_2, Clamp01, plus Round_Two). parse-en-us final.tree is byte-identical to
the CI baseline, and an A/B run of all 15 tutorial/nlpfix/corporate analyzers
against the unpatched grammar shows zero drift.
Adds .github/workflows/tests/fnname-digits plus a step in the Windows and Linux
builds next to the existing #669 regression. The step asserts out.txt rather
than the exit code -- the engine exits 0 even when the analyzer fails to build.
Confirmed the step fails on the unpatched grammar.
No version bump: this rides along with 3.7.13 so both changes ship in one build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Linux jobs went red on the new step even though the analyzer built fine
("[Loaded analyzer: 0.005928 sec]", no errors). Windows always leaves a
logs/make_ana.log behind, but Linux only writes one when the build had
something to report, so an unconditional `cat` hit "No such file or directory"
and `set -e` killed the step.
Print the log only when it exists, and add an explicit "no out.txt -- the
analyzer did not build" guard so a genuine build failure still fails loudly
instead of tripping over a missing file. Verified both ways locally: green with
the fix (with and without a logs dir), and red against the pre-fix grammar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two changes shipping in one build as 3.7.13.
Fixes #698
1. Function names containing digits or underscores (#698)
A user function whose name contained a digit (
Round2,Clamp01,Fixed2) or an underscore (Round_2) never compiled. The rule-file tokenizer built_LITfrom a single_xALPHAtoken, soRound2reached the function grammar as_LIT("Round")+_NUM(2)and never matched_FNCALLLIST <- _LIT \(ingram2.nlp. The diagnostic was[Warning: Missing ';']+[Syntax error.]on a function header that is itself valid — which sends you looking at the previous statement instead of at the name.Takes the fix the issue prefers — accept the digits — rather than just reporting a better error, since digits have always been legal in
L()variable names.bigtok.nlpgloms adjacent alpha/numeric/underscore tokens into one_LIT, but only when immediately followed by an unescaped(— a function definition header or a call. That gate is what keeps the change contained:@RULESliterals must write\(andkey=(val)pairs put=before the paren, so element literals (covid19stays two elements) and pair values tokenize exactly as before. The second element is[plus], so single-token names never reach the rule and the keyword rules (if/while/return/L/N/X/G/P/s) still win.postrfa.cppgivesrfaname()a two-arg form that gathers covered text across a range of collects; the one-arg form is untouched. The name still starts at an_xALPHA, so identifiersIfunc::genDeclsemits into generated C++ stay legal.Verified: all forms from the issue table now run (
Round2,R2ound,x2Round,Round_2,Clamp01,Round_Two).parse-en-usfinal.treeis byte-identical to the CI baseline, and an A/B run of all 15 tutorial/nlpfix/corporate analyzers against the unpatched grammar shows zero drift.Adds
.github/workflows/tests/fnname-digitsplus a step in the Windows and Linux builds next to the existing #669 regression. The step assertsout.txtrather than the exit code — the engine exits 0 even when the analyzer fails to build. Confirmed the step fails on the unpatched grammar.2. NLP++ math functions
NLP++ had only
logten,abs,mod,factorialandrandomint. This adds the rounding family and the remaining core C/C++ math functions.floor(num)ceiling(num)round(num)truncate(num)sqrt(num)pow(base,exp)log(num)The four rounding functions take a float and return a whole number, which is what callers actually want.
floorandtruncatedeliberately differ on negatives.Registered in the parallel
funcs.h/func_defs.htables (verified in sync — 340 entries each), declared infn.h, dispatched and implemented infn.cpp.Compiled analyzers: codegen in
iaction.cppemitsArun::<fnname>for every builtin, so each function also getsArunoverloads infnrun.cppand declarations inArun.h— including the fourRFASem/floatcombinations for the two-argumentpow. The global C functions are called with the::qualifier so the newArunmembers don't recurse into themselves.Help: seven new pages under
visualtext/Help/helpsmodeled onlogten.htm, TOC entries inHelp.hhc, andTable_of_Math_Functions.htmrebuilt. That table previously listedlogtenalone, soabs,factorial,modandrandomintare now documented there too.Testing — built clean and verified against a live analyzer:
sqrtof a negative andlog(0)are rejected rather than propagating NaN.Version
NLP_ENGINE_VERSIONinnlp/main.cppbumped to 3.7.13 — that#defineis what--versionprints, since the generatedVersion()is commented out at the callsite. Confirmednlp --versionreports3.7.13.Notes for review
floor(-3.2)) fail to parse. Pre-existing, not introduced here —abs(-5),mod(-7,3)andlogten(-1.0)fail identically. Passing a negative variable works. Worth noting the existingabshelp page documentsabs(-7), which does not actually run.abs,modandrandominthave noArun::overloads, so they are broken in compiled analyzers today. Not fixed here to keep scope contained — happy to follow up.min/maxdeliberately omitted. NLP++ distinguishes NUM from FLOAT and these are the only functions in the set with a genuinely ambiguous return type (a float-basedmin(2,3)could print2.000000). Worth deciding explicitly rather than picking silently.Companion PRs: VisualText/vscode-nlp#1112 (editor support), VisualText/visualtext-files#197 (help docs)
🤖 Generated with Claude Code