A lexer class for the Slang shading language that extends an HLSL lexer. It swaps in Slang-specific language definition and classifies identifiers with extra rules for module introducers (module, import, implementing, __include, __import) and interface-like names starting with 'I' followed by an uppercase letter and then a lowercase letter.
using Editor.Prism.Text.LanguageDb;
namespace Editor.Prism.Text.Lexer;
/// <summary>
/// The Slang lexer. Slang is a superset of HLSL, so the whole scanner is inherited from
/// <see cref="HlslLexer"/>; this class swaps in the Slang word tables and adds the deltas that need
/// context the tables cannot express — module names after <c>module</c>, <c>import</c>,
/// <c>implementing</c> and <c>__include</c>, and the fact that s&box's <c>system.fxc</c> symbols
/// and its <c>< … ></c> annotation grammar are not part of the language.
/// </summary>
public sealed class SlangLexer : HlslLexer
{
/// <inheritdoc/>
public override string Language => "slang";
/// <inheritdoc/>
protected override LanguageDefinition Definition => SlangLanguage.Definition;
/// <inheritdoc/>
protected override TokenKind ClassifyIdentifier( string word, IdentifierContext ctx )
{
// `module scene;`, `import mathlib;`, `implementing scene;`, `__include helpers;`
if ( !ctx.AfterDot && !ctx.AfterScope && IsModuleIntroducer( ctx.PreviousWord ) )
return TokenKind.IncludePath;
// An interface name in a generic constraint reads far better as a type.
if ( !ctx.AfterDot && !ctx.AfterScope && !ctx.BeforeParen && LooksLikeInterface( word ) )
return TokenKind.UserType;
return base.ClassifyIdentifier( word, ctx );
}
private static bool IsModuleIntroducer( string word ) =>
word is "module" or "import" or "implementing" or "__include" or "__import";
private static bool LooksLikeInterface( string word )
{
// The Slang core module and every convention in the wild name interfaces `IFoo`.
if ( word.Length < 3 || word[0] != 'I' )
return false;
if ( !char.IsUpper( word[1] ) )
return false;
for ( var i = 2; i < word.Length; i++ )
{
if ( char.IsLower( word[i] ) )
return true;
}
return false;
}
}