From a7990f70c422d3cf2eb779188e883b4d8de14599 Mon Sep 17 00:00:00 2001 From: Takahiro Ueda Date: Fri, 9 Jan 2026 15:02:01 +0900 Subject: [PATCH 1/6] feat: relax ordering constraints for $-variable ModuleOptions --- sources/compiler.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/sources/compiler.c b/sources/compiler.c index dcaa3c0e..8532f2a0 100644 --- a/sources/compiler.c +++ b/sources/compiler.c @@ -43,6 +43,7 @@ */ #include "form3.h" +#include "comtool.h" /* com1commands are the commands of which only part of the word has to @@ -617,8 +618,28 @@ int CompileStatement(UBYTE *in) } else if ( k->type == MIXED2 ) {} else if ( k->type > AC.compiletype ) { - if ( StrCmp((UBYTE *)(k->name),(UBYTE *)"format") != 0 ) - AC.compiletype = k->type; + /* + * We intentionally do NOT update "compiletype" for: + * - Format statements (type = TOOUTPUT) + * - ModuleOption statements (type = ATENDOFMODULE) + * with sum/maximum/minimum/local (i.e., $-variable-related options) + * + * This relaxes the ordering constraint, allowing statements with + * type >= the current "compiletype" to follow. + */ + if ( StrCmp((UBYTE *)(k->name),(UBYTE *)"format") == 0 ) + goto NoUpdateCompileType; + if ( StrCmp((UBYTE *)(k->name),(UBYTE *)"moduleoption") == 0 ) { + UBYTE *ss = s; + SkipSpaces(&ss); + if ( ConsumeOption(&ss,"sum") + || ConsumeOption(&ss,"maximum") + || ConsumeOption(&ss,"minimum") + || ConsumeOption(&ss,"local") ) goto NoUpdateCompileType; + } + AC.compiletype = k->type; +NoUpdateCompileType: + ; } else if ( k->type < AC.compiletype ) { switch ( k->type ) { From 2f13c3271c0669e6f904fdba8becefeda132aef4 Mon Sep 17 00:00:00 2001 From: Takahiro Ueda Date: Tue, 13 Jan 2026 17:54:25 +0900 Subject: [PATCH 2/6] fix: remove unintended & in warnings (#766) Close #766. --- sources/module.c | 2 +- sources/names.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sources/module.c b/sources/module.c index f9aa7453..a5a64115 100644 --- a/sources/module.c +++ b/sources/module.c @@ -672,7 +672,7 @@ UBYTE * DoModDollar(UBYTE *s, int type) number = GetDollar(name); if ( number < 0 ) { number = AddDollar(s,0,0,0); - Warning("&Undefined $-variable in module statement"); + Warning("Undefined $-variable in module statement"); } md = (MODOPTDOLLAR *)FromList(&AC.ModOptDolList); md->number = number; diff --git a/sources/names.c b/sources/names.c index b22d0c73..d8184aff 100644 --- a/sources/names.c +++ b/sources/names.c @@ -1526,7 +1526,7 @@ illegsym: *s = cc; else goto illegsym; *s = cc; if ( *s != ')' || ( s[1] && s[1] != ',' && s[1] != '<' ) ) { - Warning("&Excess information in symmetric properties currently ignored"); + Warning("Excess information in symmetric properties currently ignored"); s = SkipField(s,1); } else s++; @@ -1547,7 +1547,7 @@ retry:; if ( ( StrICont(par,(UBYTE *)"arguments") == 0 ) || ( StrICont(par,(UBYTE *)"args") == 0 ) ) {} else { - Warning("&Illegal information in number of arguments properties currently ignored"); + Warning("Illegal information in number of arguments properties currently ignored"); error = 1; } *s = cc; @@ -1571,7 +1571,7 @@ retry:; if ( ( StrICont(par,(UBYTE *)"arguments") == 0 ) || ( StrICont(par,(UBYTE *)"args") == 0 ) ) {} else { - Warning("&Illegal information in number of arguments properties currently ignored"); + Warning("Illegal information in number of arguments properties currently ignored"); error = 1; } *s = cc; From c28a66d23e312e918c981c387ef39807201785f2 Mon Sep 17 00:00:00 2001 From: Takahiro Ueda Date: Tue, 13 Jan 2026 17:34:17 +0900 Subject: [PATCH 3/6] docs: statement ordering exceptions Provide a more precise description of mixed statements. Add descriptions for Format and ModuleOption. --- doc/manual/module.tex | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/doc/manual/module.tex b/doc/manual/module.tex index 425f22d6..fc7abf10 100644 --- a/doc/manual/module.tex +++ b/doc/manual/module.tex @@ -31,7 +31,7 @@ \chapter{Modules} \item [Definitions\index{definitions}] These define new expressions. \item [Executable\index{executable statements} statements] The operations on all active expressions. -\item [OutputSpecifications\index{output specifications}] These specify the +\item [Output specifications\index{output specifications}] These specify the output representation. \item [End-of-module specifications\index{end of module specifications}] Extra settings that are for this module only. @@ -39,11 +39,34 @@ \chapter{Modules} classes. Most notably the print statement. \end{description} Statements must occur in such an order that no statement follows a -statement of a later category. The only exception is formed by the mixed -statements, which can occur anywhere. This is different from earlier +statement of a later category, except as described bellow. +This is different from earlier versions of \FORM\ in which the order of the statements was not fixed. This did cause a certain amount of confusion about the workings of \FORM\@. +The exceptions are: +\begin{itemize} +\item Mixed statements are permitted in the executable statements, + output specifications, and end-of-module specifications parts of a module. +\item \texttt{Format}\index{format} statements are permitted anywhere. +\item \texttt{ModuleOption}\index{moduleoption} statements that control how \$-variables are handled + during parallel execution are permitted anywhere. +\end{itemize} +The last exception allows such \texttt{ModuleOption} statements to appear inside procedures +that use \$-variables and do not contain a \texttt{.sort}. +For example, the following structure is valid: +\begin{verbatim} + #procedure SortlessProc + $procLocalDollar = ... + ModuleOption local $procLocalDollar; + * more executable statements here + #endprocedure + + #call SortlessProc + * more executable statements here + .sort +\end{verbatim} + There are several types of modules. \begin{description} \item[.sort\index{.sort}] \label{instrsort} The general end-of-module. From 96c3adc45166f0f2f475c62a7f9e390aa5c659c9 Mon Sep 17 00:00:00 2001 From: Takahiro Ueda Date: Tue, 13 Jan 2026 18:57:50 +0900 Subject: [PATCH 4/6] tmp: test: add test (766) --- check/fixes.frm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/check/fixes.frm b/check/fixes.frm index fcb6ea75..d818cc9c 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -4437,6 +4437,13 @@ assert result("testCF1") =~ expr("putfirst_(f,2,mu1)*putfirst_(e,2,mu1)*putfirst assert result("testCF2") =~ expr("d(mu2,mu1)*e(mu2,mu1)*f(mu2,mu1)") assert result("testCF3") =~ expr("d(mu2,mu1,mu3)*e(mu2,mu1,mu3)*f(mu2,mu1,mu3)") *--#] Issue750 : +*--#[ Issue766 : +CF f(s,s); +ModuleOption local,$a; +.end +assert warning?("Excess information in symmetric properties") +assert warning?("Undefined $-variable") +*--#] Issue766 : *--#[ PullReq535 : * This test requires more than the specified 50K workspace. #:maxtermsize 200 From c70a85f3cb6013648bc4bf1d05df952963b4ffc9 Mon Sep 17 00:00:00 2001 From: Takahiro Ueda Date: Tue, 13 Jan 2026 19:08:07 +0900 Subject: [PATCH 5/6] tmp: test: add test (762) --- check/features.frm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/check/features.frm b/check/features.frm index a1b91032..c31efefa 100644 --- a/check/features.frm +++ b/check/features.frm @@ -2233,6 +2233,19 @@ assert stdout =~ exact_pattern("Generated terms = 1001 ( 1 K )") assert stdout =~ exact_pattern("Terms in output = 1001 ( 1 K )") assert stdout =~ exact_pattern("Bytes used = 199172 (199 KiB)") *--#] humanstats : +*--#[ ModuleOption_dollar_order : +$a = 0; +ModuleOption sum,$a; +$b = 0; +ModuleOption maximum,$b; +$c = 0; +ModuleOption minimum,$c; +$d = 0; +ModuleOption local,$d; +discard; +.end +assert succeeded? +*--#] ModuleOption_dollar_order : *--#[ Issue49 : * Add mul_ function for polynomial multiplications Symbols x,y,z; From c5f6faade73905b4370ad85e0d721e29282b8f56 Mon Sep 17 00:00:00 2001 From: Takahiro Ueda Date: Tue, 13 Jan 2026 21:49:57 +0900 Subject: [PATCH 6/6] tmp: fix: hacky impl --- sources/module.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sources/module.c b/sources/module.c index a5a64115..975635f6 100644 --- a/sources/module.c +++ b/sources/module.c @@ -502,7 +502,14 @@ Error2:; AR.PolyFunExp = 0; AC.PolyRatFunChanged = 1; *t = c; - if ( *t == '+' ) { + if ( *t == '+' || *t == ',' ) { + if ( *t == ',' ) { + /* + * Somehow "+" is not checked by CoModuleOption, and the word + * after "+" is ignored. We take advantage of this. + */ + *t = '+'; + } t++; s = t; t = EndOfToken(s); c = *t; *t = 0;