TiddlyWiki / TiddlyWiki5

A self-contained JavaScript wiki for the browser, Node.js, AWS Lambda etc.
https://tiddlywiki.com/
Other
7.97k stars 1.18k forks source link

[BUG] Nested Macro: Variable Substitution Does Not Work #7006

Closed kookma closed 9 months ago

kookma commented 1 year ago

From https://github.com/Jermolene/TiddlyWiki5/pull/7004#issuecomment-1287892029

Issue: Variable substitution from parent in child macros does not work.

Case i: Non Nested Macro Structure

The below WIkiText works.

\define child01()

* This is child01. This is `$(var-from-parent)$`: $(var-from-parent)$.
* This is child01. This is `<<var-from-parent>>`: <<var-from-parent>>.
\end child01

\define parent()

<$let var-from-parent="120">

Call child01:

<<child01>>
</$let>
\end parent

<<parent>>

Case ii: Nested Macro Structure

The below WIkiText does not works.

\define parent()

\define child01()

* This is child01. This is `$(var-from-parent)$`: $(var-from-parent)$.
* This is child01. This is `<<var-from-parent>>`: <<var-from-parent>>.
\end child01

<$let var-from-parent="120">

Call child01:

<<child01>>
</$let>
\end parent

<<parent>>

None of $(var-from-parent)$ or <<var-from-parent>> work.

kookma commented 1 year ago

NOTE:

From https://github.com/Jermolene/TiddlyWiki5/pull/7004#issuecomment-1287892029

Consider below code

\define parent()

\define child01()
This is child01. This is `$(var-from-parent)$`: $(var-from-parent)$.
\end child01

<$let var-from-parent="120">
<<child01>>
</$let>
\end parent

<<parent>>

It produces

This is child01. This is : .

Something goes wrong with parsing when substituion does not work!

Jermolene commented 1 year ago

Hi @kookma in the second example the variable substitution first takes place when <<parent>> is invoked. At that point the values of the variables haven't been set, and so are not substituted.

kookma commented 1 year ago

At that point the values of the variables haven't been set, and so are not substituted.

Does this mean, one cannot use variable substitution from parent macro?

Jermolene commented 1 year ago

Does this mean, one cannot use variable substitution from parent macro?

I think the reverse: it will try to do the variable substitution to the first macro encountered. Macros contained within that one will therefore have the variable substitution markers removed.

kookma commented 1 year ago

Thank you! I keep this issue open to do more experiments.

It produces

This is child01. This is : .

What about this? Note that

\define child01()
This is child01. This is `$(var-from-parent)$`: $(var-from-parent)$ ddddd 

\end child01

will produce This is child01. This is : ddddd which is not correct! everything by "\end" will parsed as code.

Jermolene commented 1 year ago

Hi @kookma I think it's the same issue: the textual subsitution of variables occurs at the first opportunity. Once it has happened, the markers are gone, and so it won't happen again if the same text is fed through a macro again.

These nested definitions are much more useful with the procedures and widgets of #6666, where there is no textual substitution occurring.

kookma commented 1 year ago

Thank you! Should I close this issue?

Jermolene commented 1 year ago

Hi @kookma perhaps we should address it via some documentation updates? I've added a very brief docs update to Macro Definitions in WikiText but it might be worth pulling out a separate Nested Macro Definitions tiddlers?

kookma commented 1 year ago

perhaps we should address it via some documentation updates?

Absolutely! TBH, for me this is confusing and just after your explanation I understood what is going on behind the scenes! So yes. I will be available for any test!

AnthonyMuscio commented 1 year ago

@kookma Just as an aside; tested your examples on tiddlywiki.com

\define parent() <$let var-from-parent="120">

Call child01:

<> </$let> \end

<>

* In your second example I understood you could only define one macro in another if the inner macros were single line with no `\end`

So I restated the problem a little;

\define parent()

\define child01() This is child01. This is $(var-from-parent)$: <> - "$(var-from-parent2)$" : <> <$let var-from-parent2="60"> Call child01:

<> </$let> \end <$let var-from-parent="120"> <> </$let>


and this works as expected, If I place the $let in the parent macro only (below the single line `\define child01` )  `<<var-from-parent>>` and worked `$(var-from-parent)$`. As with the let in the tiddler body, above, both work as expected.

Conclusions:
* Sub macros can only be one line ?
* `$(var-from-parent)$` is not valid when used in a a macro which is a sub macro regardless of where it is set.

Regards
Tony.
Jermolene commented 1 year ago

Hi @AnthonyMuscio it is not very clear but this ticket relates to the proposed \end <macroname> syntax changes in #7004, and so the examples do not work on the prerelease.

pmario commented 9 months ago

@kookma -- Is this still an issue with v5.3.1?

kookma commented 9 months ago

No, the issue is not solved in 5.3.2

AnthonyMuscio commented 9 months ago

Interesting I never tried to nest the define but a parent procedure works;

\procedure parent()

\define child01()
This is child01. This is `$(var-from-parent)$`: $(var-from-parent)$.
<<var-from-parent>>!
\end child01

<$let var-from-parent="120">
<<child01>>
</$let>
\end parent

<<parent>>
Jermolene commented 9 months ago

Hi @kookma if we're talking about this code, then the reason why it doesn't work is that all the variable and parameter substitution occurs when the macro parent is executed. Part of its execution is to define the macro child01, but that definition won't be subject to any further parameter or variable substitution.

\define parent()

\define child01()

* This is child01. This is `$(var-from-parent)$`: $(var-from-parent)$.
* This is child01. This is `<<var-from-parent>>`: <<var-from-parent>>.
\end child01

<$let var-from-parent="120">

Call child01:

<<child01>>
</$let>
\end parent

<<parent>>
kookma commented 9 months ago

@Jermolene Thank you for clarification. While procedures replacing macros and recommendation is to not use text substitution, I think your explanation above worth to be added into official documentation.

Jermolene commented 9 months ago

Thanks @kookma I made a docs update here, improvements welcome.