The Pascal parser allocates a string per identifier token to throw it away
This ticket is a characterised job, not a request to do it. It exists so that on some later day the work is an afternoon rather than a rediscovery.
The shape
GetTokenStr(idx) calls GetTokenStrFromRaw, which does SetLength(s, len)
and a copy — a heap allocation. CaseEqual(a, b) then rejects on length in its
first two lines. So the cheap reject happens after the expensive part. Every
identifier token a scan passes costs an allocation, a copy, a comparison and a
free, in order to answer a question an integer comparison settles.
The remedy, already written and already proven
TokenCaseEqual(idx, nm) in ast_syminfer.inc compares TokChars in place
after Tokens[idx].SLen <> Length(nm) rejects. Semantics are identical,
edges included — an out-of-range index and an empty token both yield '' from
GetTokenStr, and CaseEqual('', nm) is true exactly when nm is empty, which
the replacement reproduces explicitly rather than by accident.
It carries -dPXX_TCE_CROSSCHECK (computes both ways, reports disagreements)
and -dPXX_TCE_BREAK (deliberately wrong, to prove the crosscheck fires). On
lekkerzeilen those read 0 and 67. So a converter does not have to trust the
substitution; they can measure it in two builds.
The rewrite is mechanical: CaseEqual(GetTokenStr(X), Y) -> TokenCaseEqual(X, Y),
and every occurrence in pyparser.inc had a simple index expression with no
nested parentheses.
What is NOT claimed
Pascal parse time has never been profiled. The NilPy win came from routines that scan the whole token array per definition, where that array holds every imported module — a shape the Pascal frontend may simply not have. A reader who assumes 12.4% transfers is reasoning from an unmeasured analogy.
Before opening this, profile a large Pascal build. If GetTokenStrFromRaw or
the allocator is not in the top few symbols, close this as not worth it and say
so here.