mirror of
https://github.com/gbdev/rgbds.git
synced 2026-06-12 19:52:12 +00:00
Optimize skipToLeadingKeyword for the common ViewedContent case (#1968)
This commit is contained in:
+74
-20
@@ -2082,6 +2082,49 @@ finish: // Can't `break` out of a nested `for`-`switch`
|
|||||||
return Token(T_(YYEOF));
|
return Token(T_(YYEOF));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Token skipToLeadingKeyword(
|
||||||
|
InvocableR<int> auto peekFn,
|
||||||
|
Procedure<> auto shiftFn,
|
||||||
|
Procedure<> auto nextLineFn,
|
||||||
|
Procedure<> auto finalizeFn
|
||||||
|
) {
|
||||||
|
for (;;) {
|
||||||
|
int c = peekFn();
|
||||||
|
if (lexerState->atLineStart) {
|
||||||
|
lexerState->atLineStart = false;
|
||||||
|
while (isBlankSpace(c)) {
|
||||||
|
shiftFn();
|
||||||
|
c = peekFn();
|
||||||
|
}
|
||||||
|
if (c == EOF) {
|
||||||
|
return Token(T_(YYEOF));
|
||||||
|
} else if (isLetter(c)) {
|
||||||
|
std::string keyword(1, c);
|
||||||
|
shiftFn();
|
||||||
|
for (c = peekFn(); continuesIdentifier(c); c = peekFn()) {
|
||||||
|
keyword += c;
|
||||||
|
shiftFn();
|
||||||
|
}
|
||||||
|
if (auto search = keywords.find(keyword); search != keywords.end()) {
|
||||||
|
finalizeFn();
|
||||||
|
return Token(search->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shiftFn();
|
||||||
|
if (c == EOF) {
|
||||||
|
return Token(T_(YYEOF));
|
||||||
|
} else if (isNewline(c)) {
|
||||||
|
// Like `handleCRLF` but calling generic `shiftFn`
|
||||||
|
if (c == '\r' && peekFn() == '\n') {
|
||||||
|
shiftFn();
|
||||||
|
}
|
||||||
|
nextLineFn();
|
||||||
|
lexerState->atLineStart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This function is called when capturing `REPT`/`FOR` loops and `MACRO` bodies,
|
// This function is called when capturing `REPT`/`FOR` loops and `MACRO` bodies,
|
||||||
// and when skipping unexecuted `IF`/`ELIF`/`ELSE` blocks and `REPT`/`FOR` loops.
|
// and when skipping unexecuted `IF`/`ELIF`/`ELSE` blocks and `REPT`/`FOR` loops.
|
||||||
// It expects that these constructs' `ENDC`/`ENDR`/`ENDM` closing tokens are only
|
// It expects that these constructs' `ENDC`/`ENDR`/`ENDM` closing tokens are only
|
||||||
@@ -2098,28 +2141,39 @@ finish: // Can't `break` out of a nested `for`-`switch`
|
|||||||
static Token skipToLeadingKeyword() {
|
static Token skipToLeadingKeyword() {
|
||||||
assume(!lexerState->enableExpansions);
|
assume(!lexerState->enableExpansions);
|
||||||
|
|
||||||
for (;;) {
|
if (std::holds_alternative<ViewedContent>(lexerState->content)
|
||||||
if (lexerState->atLineStart) {
|
&& lexerState->expansionStack.empty()) {
|
||||||
lexerState->atLineStart = false;
|
// Optimize the common case (a fully-read assembly file without ongoing
|
||||||
if (int c = skipChars(isBlankSpace); c == EOF) {
|
// expansions) to avoid the bookkeeping of `peek` and `shiftChar`.
|
||||||
return Token(T_(YYEOF));
|
auto &view = std::get<ViewedContent>(lexerState->content);
|
||||||
} else if (isLetter(c)) {
|
char const *ptr = view.span.ptr.get();
|
||||||
std::string keyword(1, c);
|
auto quickPeek = [&]() { return view.offset < view.span.size ? ptr[view.offset] : EOF; };
|
||||||
for (c = nextChar(); continuesIdentifier(c); c = nextChar()) {
|
auto quickNextLine = []() { ++lexerState->lineNo; };
|
||||||
keyword += c;
|
auto quickFinalize = []() {
|
||||||
}
|
// When `skipToLeadingKeyword` returns a token, there has been one more
|
||||||
if (auto search = keywords.find(keyword); search != keywords.end()) {
|
// call to `quickPeek` than to `quickNextLine`. Unlike `peek` and `shiftChar`,
|
||||||
return Token(search->second);
|
// the optimized functions do not update `lexerState->expansionScanDistance`,
|
||||||
}
|
// so it must be incrementedif it was previously zero.
|
||||||
|
if (lexerState->expansionScanDistance == 0) {
|
||||||
|
++lexerState->expansionScanDistance;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if (lexerState->capturing) {
|
||||||
|
assume(lexerState->captureBuf == nullptr);
|
||||||
|
auto quickCaptureShiftChar = [&]() {
|
||||||
|
++view.offset;
|
||||||
|
++lexerState->captureSize;
|
||||||
|
};
|
||||||
|
return skipToLeadingKeyword(
|
||||||
|
quickPeek, quickCaptureShiftChar, quickNextLine, quickFinalize
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
auto quickShiftChar = [&]() { ++view.offset; };
|
||||||
|
return skipToLeadingKeyword(quickPeek, quickShiftChar, quickNextLine, quickFinalize);
|
||||||
}
|
}
|
||||||
if (int c = bumpChar(); c == EOF) {
|
} else {
|
||||||
return Token(T_(YYEOF));
|
auto finalize = []() {};
|
||||||
} else if (isNewline(c)) {
|
return skipToLeadingKeyword(peek, shiftChar, nextLine, finalize);
|
||||||
handleCRLF(c);
|
|
||||||
nextLine();
|
|
||||||
lexerState->atLineStart = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user