From dc7bc74ceccf158b4a7856b0d419e0a95c34ddca Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Tue, 25 Aug 2026 14:16:41 +0100 Subject: [PATCH 1/3] fix: clean up repeated expression replacements When an expression is replaced more than once in a module, maintain the replacement chain such that the intermediate replacements can all be cleaned up. Note that it is important that the expression name points at the original definition for the duration of the module. Fixes #882 --- check/fixes.frm | 104 ++++++++++++++++++++++++++++++++++++++++------ sources/comexpr.c | 15 ++++--- sources/execute.c | 7 +++- 3 files changed, 106 insertions(+), 20 deletions(-) diff --git a/check/fixes.frm b/check/fixes.frm index fa21fc7b0..a673a135d 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -4575,6 +4575,18 @@ assert stdout =~ exact_pattern(<<'EOF') sumpow: 129 EOF *--#] Issue796c : +*--#[ Issue808 : +#do i=0,9 +Global E`i' = `i'; +#enddo +.store +#do i=1,80 +Global F1 = E{`i' % 10}*E2*E3*E4; +#enddo +.sort +.end +assert succeeded? +*--#] Issue808 : *--#[ Issue833_1 : #- #: TermsInSmall 1024 @@ -4761,6 +4773,86 @@ assert result("test4") =~ expr("16384*f(4)^4") assert result("htest4") =~ expr("16*g(4)^8") assert result("ihtest4") =~ expr("4096*h(4)^12") *--#] Issue856 : +*--#[ Issue882_1 : +Off statistics; +Symbol x; +Local test = 1+x; +Local test = 1+2*x; +Local test = 1+3*x; +.sort +Identify x=x^2; +.sort +Hide test; +.sort +Print; +.end +assert succeeded? +assert result("test") !~ expr("1+2*x^2") +*--#] Issue882_1 : +*--#[ Issue882_2 : +Off statistics; +Symbol x; +Local test = 1+x; +Local test = 1+2*x; +Local test = 1+3*x; +.sort +Print; +.end +assert succeeded? +assert result("test") !~ expr("1+x") +assert result("test") !~ expr("1+2*x") +assert result("test") =~ expr("1+3*x") +*--#] Issue882_2 : +*--#[ Issue882_3 : +Off statistics; +Symbol x; +Local test = 1+x; +Local test = 2*test; +.sort +Print; +.end +assert succeeded? +assert result("test") =~ expr("2+2*x") +*--#] Issue882_3 : +*--#[ Issue882_4 : +Off statistics; +Symbol x; +Local test = 1+x; +.sort +Local test = 2*test; +.sort +Print; +.end +assert succeeded? +assert result("test") =~ expr("2+2*x") +*--#] Issue882_4 : +*--#[ Issue882_5 : +Off statistics; +Symbol x; +Local test = 1+x; +.sort +Local test = 2*test; +Local test = 3*test; +.sort +Print; +.end +assert succeeded? +assert result("test") =~ expr("3+3*x") +*--#] Issue882_5 : +*--#[ Issue882_6 : +Off statistics; +Symbol x; +Local test = 1+x; +.sort +Local test = 2*test; +Local test = 3*test; +Local test = 4*test; +.sort +Print; +.end +assert succeeded? +assert result("test") =~ expr("4+4*x") +*--#] Issue882_6 : *--#[ PullReq535 : * This test requires more than the specified 50K workspace. #:maxtermsize 200 @@ -5129,15 +5221,3 @@ Print; assert succeeded? assert result("test") =~ expr("0") *--#] PullReq860_3 : -*--#[ Issue808 : -#do i=0,9 -Global E`i' = `i'; -#enddo -.store -#do i=1,80 -Global F1 = E{`i' % 10}*E2*E3*E4; -#enddo -.sort -.end -assert succeeded? -*--#] Issue808 : diff --git a/sources/comexpr.c b/sources/comexpr.c index 2d608f8b8..bcb71a269 100644 --- a/sources/comexpr.c +++ b/sources/comexpr.c @@ -98,7 +98,7 @@ int DoExpr(UBYTE *inp, int type, int par) GETIDENTITY int error = 0; UBYTE *p, *q, c; - WORD *w, i, j = 0, c1, c2, *OldWork = AT.WorkPointer, osize; + WORD *w, i, j = 0, c1, c2, c3, *OldWork = AT.WorkPointer, osize; WORD jold = 0; POSITION pos; while ( *inp == ',' ) inp++; @@ -132,8 +132,11 @@ int DoExpr(UBYTE *inp, int type, int par) StrCmp(inp,AO.OptimizeResult.nameofexpr) == 0 ) { ClearOptimize(); } - if ( Expressions[c2].status != DROPPEDEXPRESSION ) { - w = &(Expressions[c2].status); + c3 = c2; + while ( Expressions[c3].replace >= 0 ) + c3 = Expressions[c3].replace; + if ( Expressions[c3].status != DROPPEDEXPRESSION ) { + w = &(Expressions[c3].status); if ( *w == LOCALEXPRESSION || *w == SKIPLEXPRESSION ) *w = DROPLEXPRESSION; else if ( *w == GLOBALEXPRESSION || *w == SKIPGEXPRESSION ) @@ -143,10 +146,10 @@ int DoExpr(UBYTE *inp, int type, int par) else if ( *w == HIDDENGEXPRESSION ) *w = DROPHGEXPRESSION; } - AC.TransEname = Expressions[c2].name; + AC.TransEname = Expressions[c3].name; j = EntVar(CEXPRESSION,0,type,0,0,0); - Expressions[j].node = Expressions[c2].node; - Expressions[c2].replace = j; + Expressions[j].node = Expressions[c3].node; + Expressions[c3].replace = j; } } else { diff --git a/sources/execute.c b/sources/execute.c index f23bd332e..a523bb342 100644 --- a/sources/execute.c +++ b/sources/execute.c @@ -518,8 +518,11 @@ void TestDrop(void) ClearBracketIndex(j); e->bracketinfo = e->newbracketinfo; e->newbracketinfo = 0; if ( e->replace >= 0 ) { - Expressions[e->replace].replace = REGULAREXPRESSION; - AC.exprnames->namenode[e->node].number = e->replace; + WORD replacement = e->replace; + while ( Expressions[replacement].replace >= 0 ) + replacement = Expressions[replacement].replace; + Expressions[replacement].replace = REGULAREXPRESSION; + AC.exprnames->namenode[e->node].number = replacement; e->replace = REGULAREXPRESSION; } else { From 4076dd2127f913dc0e1075114b37d247b73fc53c Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Tue, 25 Aug 2026 15:42:54 +0100 Subject: [PATCH 2/3] fix: products of vector wildcards Correctly handle products of vector wildcards: previously they were taken to be index wildcards, producing malformed term data. Fixes #665 --- check/fixes.frm | 12 ++++++++++++ sources/pattern.c | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/check/fixes.frm b/check/fixes.frm index a673a135d..7bfa2844c 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -4186,6 +4186,18 @@ Evaluate 1; #pend_if wordsize == 2 assert compile_error?("should be a built in function that can be evaluated numerically.") *--#] Issue664 : +*--#[ Issue665 : +CFunction f,g; +Vector p1,p2; +Local test = p1*p2 + f(p1*p2) + p1*f(p2); +Identify p1?*p2? = g(1,p1,p2); +Identify f(p1?*p2?) = g(2,p1,p2); +Identify p1?*f(p2?) = g(3,p1,p2); +Print; +.end +assert succeeded? +assert result("test") =~ expr("g(1,p1,p2) + g(2,p1,p2) + g(3,p1,p2)") +*--#] Issue665 : *--#[ Issue666 : #- #$repcount = 1; diff --git a/sources/pattern.c b/sources/pattern.c index 07b1cbc12..bb1d98750 100644 --- a/sources/pattern.c +++ b/sources/pattern.c @@ -1032,7 +1032,28 @@ SubsL5: fill += nq; if ( *m == *t ) { m += 1; t += 1; } - else if ( *m >= (AM.OffsetIndex+WILDOFFSET) ) { + else if ( ( *m >= (AM.OffsetVector+WILDOFFSET) ) + && ( *m < (AM.OffsetVector+2*WILDOFFSET) ) ) { + while ( t < xstop ) *fill++ = *t++; + nq = WORDDIF(fill,subterm); + fill = subterm; + do { + if ( !CheckWild(BHEAD *m-WILDOFFSET,VECTOVEC,*fill,&newval3) ) + break; + fill++; + nq--; + } while ( nq > 0 ); + if ( nq <= 0 ) { + m++; + continue; + } + nq--; + q = fill + 1; + if ( nq > 0 ) { NCOPY(fill,q,nq); } + m++; + } + else if ( ( *m >= (AM.OffsetIndex+WILDOFFSET) ) + && ( *m < (AM.OffsetIndex+2*WILDOFFSET) ) ) { while ( t < xstop ) *fill++ = *t++; nq = WORDDIF(fill, subterm); fill = subterm; From 8b0a7a3b2abc6b835262094ce3d5216975cad7ad Mon Sep 17 00:00:00 2001 From: Josh Davies Date: Thu, 27 Aug 2026 22:53:20 +0100 Subject: [PATCH 3/3] fix: InExpression and if(expression()) for redefined expressions These must check if expressions have been redefined, and follow the redefinition chain to the most recently-defined expression. Otherwise they act on stale redefined expressions, which are not processed in the module. Fixes #103 --- check/fixes.frm | 24 ++++++++++++++++++++++++ sources/compcomm.c | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/check/fixes.frm b/check/fixes.frm index 7bfa2844c..a067f447c 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -1095,6 +1095,30 @@ assert result("OK2") =~ expr("f(t(p1,p2),x,1)") assert result("OK3") =~ expr("f(t(p1,p2,p3),x,1)") assert result("BAD") =~ expr("f(t(p1,p2,p3,p4),x,1)") *--#] Issue97_2 : +*--#[ Issue103 : +#- +Symbol x,y,z; +Local test1 = x; +Local test3 = x; +.sort +Local test1 = y; +Local test2 = test1; +Local test1 = z; +Local test3 = y; +InExpression test1; + Multiply 2; +EndInExpression; +If ( expression(test3) ); + Multiply 3; +EndIf; +Identify y = z; +Print; +.end +assert succeeded? +assert result("test1") =~ expr("2*z") +assert result("test2") =~ expr("x") +assert result("test3") =~ expr("3*z") +*--#] Issue103 : *--#[ Issue104 : * Leading zeroes in rational numbers not handled consistently Local test1 = 0001; diff --git a/sources/compcomm.c b/sources/compcomm.c index cf0b68068..4b57915a5 100644 --- a/sources/compcomm.c +++ b/sources/compcomm.c @@ -3408,6 +3408,9 @@ int CoInExpression(UBYTE *s) } c = *s; *s = 0; if ( GetName(AC.exprnames,t,&number,NOAUTO) == CEXPRESSION ) { + while ( Expressions[number].replace >= 0 ) { + number = Expressions[number].replace; + } *w++ = number; } else if ( GetName(AC.varnames,t,&number,NOAUTO) != NAMENOTFOUND ) { @@ -4561,6 +4564,9 @@ NoGood: MesPrint("&Unrecognized word: %s",inp); } c = *p; *p = 0; if ( GetName(AC.exprnames,pp,&number,NOAUTO) == CEXPRESSION ) { + while ( Expressions[number].replace >= 0 ) { + number = Expressions[number].replace; + } *w++ = number; } else if ( GetName(AC.varnames,pp,&number,NOAUTO) != NAMENOTFOUND ) {