Brad Arant 8483618012 Scope custom <tag> definitions to their enclosing invocation - and fix
two real, previously-latent bugs found while building this

Custom tag definitions used to be entirely flat: every <tag name="..."> -
regardless of where in the script it appeared - registered into a single
global.tags map, visible everywhere for the rest of the script. Now a
<tag> defined directly inside another custom tag's own invocation (i.e.
nested inside a __dotag instance's own expansion, not just sitting inside
an <if>/<for>/<while> that happens to be there - those remain transparent)
is scoped to that invocation: visible only for the rest of that specific
expansion, gone once it finishes. Definitions at the true top level (or
inside control-flow tags that are themselves at the top level) still
register globally, unchanged.

Implementation: Tag gained isCustomTagBoundary (true only on __dotag
instances) and localTags (populated only on boundary instances) - both
public rather than protected, since __tag.cpp needs to read/write them
through an arbitrary ancestor Tag* found by walking parent, and C++
protected access doesn't extend to another object reached through a
base-typed pointer. findTagDefinition() walks from `this` up through
`parent` looking for the nearest boundary whose localTags has the name,
falling back to global.tags - used by both ifTagDefined() (is <name>
visible right here?) and __dotag's own constructor (fetch the definition
to expand). __tag.cpp's registration does the mirror walk starting from
`parent` (skip self, a <tag> definition is never itself a boundary).

Two real bugs found and fixed along the way, neither introduced by this
feature, both confirmed via a hung/broken real jet-2.0 run before
diagnosis rather than assumed:

1. __tag.cpp's own base Tag(...) call passed (this, this) as its own
   parent/local instead of the parent/local it actually received - made
   the new scope-walk loop on itself forever (since <tag>'s own `parent`
   would just point at itself). Fixed to pass through the real received
   parent/local; nothing else in this class depended on the old
   self-referential values (a <tag> definition's own container is never
   evaluated at definition time - evaluate=false - so parent/local were
   never used for anything else here).
2. __dotag never overrode hasContainer, which Tag::processContainer gates
   real rendering on - and the base constructor sets hasContainer from
   whether THIS INVOCATION was self-closing (<name /> vs <name>...</name>),
   which is the right question for capturing an invocation's own nested
   content, but the wrong one for whether the tag's OWN DEFINITION should
   render. Net effect, confirmed via a real run: <name /> always silently
   rendered nothing for ANY custom tag - only the <name></name> form ever
   worked. Fixed by forcing hasContainer=true in __dotag's constructor -
   by the time it's constructed a valid definition is guaranteed (dispatch
   only builds __dotag after ifTagDefined() already confirmed one exists),
   so there's always something to render regardless of invocation syntax.

<dump> updated to match: its "DEFINED TAGS" section now renders the real
tree currently in effect (global at the root, each enclosing custom-tag
invocation nested one level deeper, outermost first) instead of a single
flat list - if there's no active local scope, that's just the root with
nothing nested under it.

Verified via real jet-2.0 runs, not just compilation: a tag defined inside
another tag's body is invokable from within that body and correctly NOT
recognized (falls through to literal-text echo) outside it; the same
holds through 3 levels of nesting; the dump tree correctly shows nested
levels indented under their own "(inside X)" header. Full regression pass
on <try>/<catch>, <if>/<else>, <while>, and dump's own flat top-level
output - all still work unchanged.
2026-08-26 09:39:36 -07:00
2024-12-02 15:46:49 -08:00
2025-05-06 07:33:04 -07:00
2025-05-06 07:33:04 -07:00
2025-01-09 07:49:11 -08:00
2025-02-07 19:29:18 -08:00
2025-02-07 19:29:18 -08:00
2025-12-09 12:29:39 -08:00
2025-01-09 08:02:38 -08:00
2025-01-09 08:02:38 -08:00
2025-02-07 16:10:13 -08:00
2025-11-21 19:15:48 -08:00
2025-11-21 19:15:48 -08:00
2025-12-04 17:05:57 -08:00
2025-05-06 07:33:04 -07:00
2025-11-21 19:15:48 -08:00
2025-11-21 19:15:48 -08:00
2025-11-21 19:15:48 -08:00
2025-11-21 19:15:48 -08:00
2025-11-21 19:15:48 -08:00
2025-11-21 19:15:48 -08:00
S
Description
JET 2.0 core library.
40 MiB
0 Stars 0 Watchers 0 Forks
Languages
HTML 50.2%
TeX 18.7%
C++ 15%
JavaScript 7.5%
CSS 4.4%
Other 4.2%