Give jetc a dedicated, fully inert <comment> handler at compile time
<comment> had no special-case in jetc's compiler at all - it fell through to parseFallback(), the generic unknown-tag path, which hunts for a tag's own closing tag via scanBody()/skipQuotedValue(), the same quote-aware, backslash-escape-interpreting scanning real Jet attribute syntax needs. A comment containing an explanatory " sequence (a JSON example in prose, say) or a literal <else>/<if>-looking word - both already confirmed, separately, to corrupt jetc when they turn up inside a JS // comment - hit the exact same corruption here too, just triggered from inside a <comment> block instead. Added skipCommentTag(), which only tracks same-tag-name nesting depth via the existing case-insensitive matchTagOpen/matchTagClose and otherwise ignores every character - no quote tracking, no other-tag recognition, nothing a comment's own body could ever trip over. Wired into parseNodes() alongside the other recognized top-level tags; unlike those, it pushes no node at all; the comment contributes nothing to the compiled output, matching the runtime interpreters own __comment behavior but now safe at compile time too. Verified directly: a scratch .jet with five <comment> blocks (plain, a bare quote, a backslash-quote JSON example, literal <else>/<if> text, and nested comments with their own quotes) all compiled clean and left zero trace in the generated code, with the <if> immediately following them compiling correctly too - confirming nothing after a tricky comment gets corrupted either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b8f7793773
commit
867ace3cb3
2 files changed
+52
No files matched your search
@@ -162,6 +162,48 @@ namespace jetc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Advances p from '<' of "<comment" (any case - matchTagOpen already
|
||||||
|
// confirmed the match before this is called) past the whole
|
||||||
|
// <comment>...</comment> construct, including any nested <comment>
|
||||||
|
// tags, counted the same case-insensitive way everything else in this
|
||||||
|
// file matches tag names. Deliberately does NOT call skipOpenTag/
|
||||||
|
// skipQuotedValue/skipEmbeddedTag or any other quote- or tag-aware
|
||||||
|
// scanning on the body text - a comment containing an explanatory '"'
|
||||||
|
// or '\"' (about the code itself, say) previously fell through to
|
||||||
|
// parseFallback()'s generic path, which DOES apply those rules while
|
||||||
|
// hunting for this same closing tag, and silently mislocated it
|
||||||
|
// exactly like the already-documented JS-comment-corrupts-jetc bug
|
||||||
|
// class, just triggered from inside a <comment> instead of a //
|
||||||
|
// comment. This only ever advances past '<'/'>' boundaries it
|
||||||
|
// recognizes as comment open/close - nothing inside can affect it.
|
||||||
|
void Parser::skipCommentTag(size_t &p) {
|
||||||
|
p += 8; // "<comment" (8 chars regardless of case)
|
||||||
|
bool selfClosing = false;
|
||||||
|
while (p < s.size() && s[p] != '>') {
|
||||||
|
if (s[p] == '/' && p + 1 < s.size() && s[p + 1] == '>') selfClosing = true;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (p < s.size()) p++; // past '>'
|
||||||
|
if (selfClosing) return;
|
||||||
|
int depth = 1;
|
||||||
|
while (p < s.size()) {
|
||||||
|
if (matchTagOpen("comment", p)) {
|
||||||
|
depth++;
|
||||||
|
p++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (matchTagClose("comment", p)) {
|
||||||
|
p += 2; // "</"
|
||||||
|
while (p < s.size() && isNameChar(s[p])) p++;
|
||||||
|
if (p < s.size() && s[p] == '>') p++;
|
||||||
|
depth--;
|
||||||
|
if (depth == 0) return;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Parser::skipOpenTag(size_t &p) {
|
bool Parser::skipOpenTag(size_t &p) {
|
||||||
p++; // '<'
|
p++; // '<'
|
||||||
while (p < s.size() && isNameChar(s[p])) p++;
|
while (p < s.size() && isNameChar(s[p])) p++;
|
||||||
@@ -555,6 +597,7 @@ namespace jetc {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (matchTagOpen("container", pos)) { flush(); nodes.push_back(parseContainerSlot()); continue; }
|
if (matchTagOpen("container", pos)) { flush(); nodes.push_back(parseContainerSlot()); continue; }
|
||||||
|
if (matchTagOpen("comment", pos)) { flush(); skipCommentTag(pos); continue; }
|
||||||
if (topLevel && matchTagOpen("tag", pos)) { flush(); nodes.push_back(parseTagDef()); continue; }
|
if (topLevel && matchTagOpen("tag", pos)) { flush(); nodes.push_back(parseTagDef()); continue; }
|
||||||
flush();
|
flush();
|
||||||
nodes.push_back(parseFallback());
|
nodes.push_back(parseFallback());
|
||||||
|
|||||||
@@ -61,6 +61,15 @@ namespace jetc {
|
|||||||
void skipQuotedValue(size_t &p);
|
void skipQuotedValue(size_t &p);
|
||||||
void skipEmbeddedTag(size_t &p);
|
void skipEmbeddedTag(size_t &p);
|
||||||
|
|
||||||
|
// <comment>...</comment> must be fully inert regardless of what's
|
||||||
|
// inside it - unlike the generic parseFallback/scanBody path this
|
||||||
|
// tag used to fall through to (which applies the same quote/
|
||||||
|
// backslash-escape and nested-tag scanning real Jet syntax needs),
|
||||||
|
// this tracks only same-tag-name nesting depth via matchTagOpen/
|
||||||
|
// matchTagClose and otherwise ignores every character. See its own
|
||||||
|
// definition for the quote-corruption bug this specifically closes.
|
||||||
|
void skipCommentTag(size_t &p);
|
||||||
|
|
||||||
std::map<std::string, std::string> parseAttrs(bool &hasContainer);
|
std::map<std::string, std::string> parseAttrs(bool &hasContainer);
|
||||||
|
|
||||||
// Scans forward from bodyStart (just after the opening tag's '>') for
|
// Scans forward from bodyStart (just after the opening tag's '>') for
|
||||||
|
|||||||
Reference in new issue
Block a user