Skip to content

style: Add macro preprocessing to fix tree-sitter parse errors#2559

Closed
bobtista wants to merge 5 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/macro-hints-core
Closed

style: Add macro preprocessing to fix tree-sitter parse errors#2559
bobtista wants to merge 5 commits intoTheSuperHackers:mainfrom
bobtista:bobtista/feat/macro-hints-core

Conversation

@bobtista
Copy link
Copy Markdown

@bobtista bobtista commented Apr 9, 2026

Summary

  • Add macro preprocessing to the tree-sitter formatting script
  • Fixes 14 additional lines across 4 files in Core/

Builds on #2554 (Core mixed-whitespace PR). All C++ changes are whitespace-only.

What this does

Adds a preprocessing step that expands known macros (GCALL, CALLBACK, WINAPI,
IN, OUT, RO, NEW, W3DNEW, __RPC_FAR, __asm, etc.) before passing source to
tree-sitter for parsing. This fixes parse errors that caused the tool to skip
lines it couldn't confidently reindent.

The expansions are same-length replacements to preserve byte offsets, and are
only used for parsing — the original source content is preserved in output.

After #2554 merges to main, this PR should be rebased onto main so the diff
only shows the Phase 2 delta (5 files changed).

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 9, 2026

Greptile Summary

This PR adds a macro-preprocessing step to the tree-sitter–based convert_leading_spaces_to_tabs.py script, replacing known Windows/game-engine macros (CALLBACK, GCALL, WINAPI, IN, OUT, etc.) with same-length space sequences before parsing so tree-sitter can handle them without errors. The 498 C++ file changes are purely whitespace (spaces → tabs), generated by running the updated script.

Confidence Score: 5/5

Safe to merge — all C++ changes are whitespace-only and the script changes are additive and low-risk

Only P2 findings remain: one dead clause in the block-comment guard (functionally harmless, correctness is preserved by the first clause of the or) and a minor PEP 8 blank-line nit. Neither blocks merge.

scripts/cpp/convert_leading_spaces_to_tabs.py (minor block-comment logic dead code)

Vulnerabilities

No security concerns identified. The script is a local formatting tool with no network access, no execution of external data, and no sensitive input handling.

Important Files Changed

Filename Overview
scripts/cpp/convert_leading_spaces_to_tabs.py New tree-sitter based tool that preprocesses C++ macros before parsing to fix indentation; one dead clause in block-comment detection and minor style nit
Core/GameEngine/Include/Common/GameAudio.h Whitespace-only: mixed-spaces indentation on several virtual method declarations corrected to tabs
Core/GameEngine/Include/Common/FileSystem.h Whitespace-only: two private member declarations corrected from space-indented to tab-indented

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Read file as cp1252] --> B[Encode to UTF-8 bytes]
    B --> C[preprocess_for_parsing\nexpand CALLBACK/GCALL/WINAPI/IN/OUT/etc.\nwith same-length space replacements]
    C --> D[tree-sitter parse\npreprocessed bytes]
    D --> E{Top-level ERROR\nnodes > 10?}
    E -- Yes --> F[Skip file entirely]
    E -- No --> G[For each line with leading spaces]
    G --> H{In block comment\nor macro continuation?}
    H -- Yes --> I[Preserve line as-is]
    H -- No --> J[Find AST node at\nfirst non-whitespace col]
    J --> K{ERROR ancestor\nor continuation line?}
    K -- Yes --> I
    K -- No --> L[get_indent_depth\ncount scope-creating ancestors]
    L --> M[Apply brace / case /\naccess-specifier overrides]
    M --> N{depth == 0 but\n>= 4 leading spaces?}
    N -- Yes --> I
    N -- No --> O[Replace leading WS\nwith depth x TAB]
    O --> P[Write original file\nwith new indentation]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 177

Comment:
**Dead second clause in block-comment guard**

When `stripped.startswith('/*')`, `stripped.index('/*')` is always `0`, so `stripped.index('/*') + 2` is always `2`. A `*/` closing token can appear at index 2 at earliest (i.e. `/**/`), making `stripped.index('*/') < 2` always `False`. The entire second clause of the `or` is therefore unreachable and the condition collapses to just `'*/' not in stripped`. Consider simplifying:

```suggestion
            if '*/' not in stripped:
                in_block_comment = True
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 123-127

Comment:
**Excess blank lines between functions**

PEP 8 recommends two blank lines between top-level definitions. There are four blank lines here between `is_continuation_line` and `process_file`.

```suggestion

```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "style: Convert additional lines to tabs ..." | Re-trigger Greptile

continue

if stripped.startswith('/*'):
if '*/' not in stripped or stripped.index('*/') < stripped.index('/*') + 2:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Dead second clause in block-comment guard

When stripped.startswith('/*'), stripped.index('/*') is always 0, so stripped.index('/*') + 2 is always 2. A */ closing token can appear at index 2 at earliest (i.e. /**/), making stripped.index('*/') < 2 always False. The entire second clause of the or is therefore unreachable and the condition collapses to just '*/' not in stripped. Consider simplifying:

Suggested change
if '*/' not in stripped or stripped.index('*/') < stripped.index('/*') + 2:
if '*/' not in stripped:
in_block_comment = True
Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/cpp/convert_leading_spaces_to_tabs.py
Line: 177

Comment:
**Dead second clause in block-comment guard**

When `stripped.startswith('/*')`, `stripped.index('/*')` is always `0`, so `stripped.index('/*') + 2` is always `2`. A `*/` closing token can appear at index 2 at earliest (i.e. `/**/`), making `stripped.index('*/') < 2` always `False`. The entire second clause of the `or` is therefore unreachable and the condition collapses to just `'*/' not in stripped`. Consider simplifying:

```suggestion
            if '*/' not in stripped:
                in_block_comment = True
```

How can I resolve this? If you propose a fix, please make it concise.

@bobtista
Copy link
Copy Markdown
Author

bobtista commented Apr 9, 2026

Superseded by #2561-#2564 which include all phases (space-only, mixed whitespace, macro hints, and access specifiers).

@bobtista bobtista closed this Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant