stride3d/stride · warning · LexerException

{msg}

Error message

{msg}

What it means

JoinReader.warning reports lexer warnings (e.g. trigraph conversion/ignoring) by forwarding them to the current LexerSource; if no source is attached (source == null), it throws LexerException with the warning text instead. In other words, a merely warning-grade condition becomes a fatal error when the reader has no source to report through.

Solutions

  1. Call init(preprocessor, lexerSource) on the JoinReader before reading so warnings route to the source's warning handler.
  2. Remove or escape the trigraph sequence (e.g. '??(' -> '( ') from the input text.
  3. Disable trigraph warnings via the preprocessor feature/warning flags (Feature.TRIGRAPHS / Warning.TRIGRAPHS) if trigraphs are intentional.
  4. Install a PreprocessorListener so LexerSource.warning logs instead of propagating.

Example fix

// before: reader created without a source; a trigraph warning throws
var reader = new JoinReader(stream);
// after: attach source so warnings are reported, not thrown
var reader = new JoinReader(stream);
reader.init(preprocessor, new LexerSource(reader, "shader.sdsl"));
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure the reader is wired to a source before reading
if (!readerIsInitialized)
    throw new InvalidOperationException("JoinReader must be init(pp, source)-ed before read()");

Try / catch

try
{
    int c = reader.read();
}
catch (LexerException ex)
{
    logger.Warn($"Trigraph/diagnostic while lexing: {ex.Message}");
}

Prevention

When it happens

Trigger: Reading input through a JoinReader that was never init()-ed with a Preprocessor/LexerSource (or whose source was detached) while a trigraph sequence '??x' is encountered and trigraph warnings are enabled (Warning.TRIGRAPHS).

Common situations: Constructing a JoinReader manually without calling init(pp, source); preprocessing shader code containing legacy '??(' style trigraph sequences on a reader without a source; ported C preprocessor code paths where the source is set later than first read.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/3155dd6767060cb3. Report an issue: GitHub.

Appendix: source

Thrown at sources/shaders/Stride.Shaders.Parsers/CppNet/JoinReader.cs:88

            if(uptr > 0)
                return unget[--uptr];
            return _in.Read();
        }

        private void _unread(int c)
        {
            if(c != -1)
                unget[uptr++] = c;
            System.Diagnostics.Debug.Assert(uptr <= unget.Length,
                    "JoinReader ungets too many characters");
        }

        protected void warning(String msg)
        {
            if(source != null)
                source.warning(msg);
            else
                throw new LexerException(msg);
        }

        private char trigraph(char raw, char repl)
        {
            if(trigraphs) {
                if(warnings)
                    warning("trigraph ??" + raw + " converted to " + repl);
                return repl;
            } else {
                if(warnings)
                    warning("trigraph ??" + raw + " ignored");
                _unread(raw);
                _unread('?');
                return '?';
            }
        }

        private int _read()

View on GitHub (pinned to 96fad776d2)