Slang 关键词与内置语法全解析:语法声明模型、核心模块词汇与保留前缀
【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang
本篇技术指南系统梳理 Slang 编译器中"关键词"的真实来源与注册机制:绝大多数看似关键词的标识符并非词法层保留字,而是绑定到解析回调的SyntaxDecl语法声明。读者读完将理解struct、func、if、__target_intrinsic等词汇分别由词法器、解析器语法表还是核心模块*.meta.slang提供,掌握新增或重命名一个关键词时需要修改的具体文件与注册入口,并能够区分编译器内部词汇(__前缀)与可被用户遮蔽的上下文关键字。
关键词从何而来:语法即声明的模型
理解 Slang 关键词体系的第一步,是接受一个非显然的事实:大多数"关键词"不是词法层的保留字。它们以TokenType::Identifier的形式到达解析器(完整 Token 分类见 tokens.md),只有在活动环境中存在某个SyntaxDecl把它们绑定到解析回调时,它们才成为"关键词"。因此,新增或重命名一个关键词,修改的是解析器的语法表或核心模块源码,而不是词法器。
关键词共有三个来源:
- 硬编码的语句关键词,位于 slang-parser.cpp。语句解析器通过
LookAheadToken("if")、LookAheadToken("for")等直接比对标识符,并分派到专用的解析函数。 - 解析器的
SyntaxParseInfo语法表,即 slang-parser.cpp 中的数组g_parseSyntaxEntries[](定义于 slang-parser.cpp)。getSyntaxParseInfos()将该数组以视图形式暴露(slang-parser.cpp),populateBaseLanguageModule()则把它注册进默认环境(slang-parser.cpp)。这是声明关键字、修饰符关键字和表达式关键字的来源。 - 核心模块
*.meta.slang声明。这些元模块(core.meta.slang、hlsl.meta.slang、glsl.meta.slang、diff.meta.slang)声明内置类型、函数与运算符,为默认环境贡献名字。它们在编译器启动时被处理,但属于"内置词汇"而非"关键词":只有SyntaxDecl绑定会驱动解析回调,而一个已知类型名只参与少数受限的类型消歧决策。
三条来源的注册路径由addBuiltinSyntaxImpl统一落地(slang-parser.cpp):它为每个词条创建一个SyntaxDecl,记录其syntaxClass与parseCallback,打上PublicModifier后加入当前作用域;addBuiltinSyntax与addSimpleModifierSyntax(后者固定使用parseSimpleSyntax回调)是其两个常用模板封装。
词法层识别的关键字
词法器不识别任何字母形式的关键字。在词法器/Token 目录中被显式拼写的唯一内容是标点与运算符——完整清单见 tokens.md 与 slang-token-defs.h。该头文件通过PUNCTUATION(...)宏声明了Semicolon(;)、Scope(::)、RightArrow(->)、DoubleRightArrow(=>)以及全部Op*运算符:
| TokenKind | 拼写 | TokenKind | 拼写 |
|---|---|---|---|
Semicolon | ; | OpAssign | = |
OpAdd | + | OpSub | - |
OpMul | * | OpDiv | / |
OpMod | % | OpNot | ! |
OpBitNot | ~ | OpLsh | << |
OpRsh | >> | OpEql | == |
OpNeq | != | OpGreater | > |
OpLess | < | OpGeq | >= |
OpLeq | <= | OpAnd | && |
OpOr | || | OpBitAnd | & |
OpBitOr | | | OpBitXor | ^ |
OpInc | ++ | OpDec | -- |
OpAddAssign | += | ...(赋值类复合运算符等,见头文件) |
运算符的完整词法表属于 grammar.md 的范畴,本文不重复列出。
解析器注册的语法关键字
Slang 关键词的主体由解析器而非词法器识别。语句关键字由语句解析器直接匹配;声明、修饰符与表达式关键字则注册在解析器的语法声明表(g_parseSyntaxEntries[])中,从而可以通过syntax/attribute_syntax声明被重定义或扩展。
这两种声明写作:
syntax <name> [: <SyntaxClass>] [= <existingKeyword>];attribute_syntax [<Name>(<param> : <Type>, ...)] : <SyntaxClass>;
两者都要命名一个 AST 节点类,由parseSyntaxDecl与parseAttributeSyntaxDecl通过ASTBuilder::findSyntaxClass解析,因此任何一种形式都无法引入编译器尚未声明的节点——扩展点是"已有节点的新拼写",而非"新节点"。这正是两种形式在实践中只出现在核心模块的原因;例如 core.meta.slang 中的syntax constexpr : ConstExprModifier;与attribute_syntax [ExperimentalModule] : ExperimentalModuleAttribute;即为代表。= <existingKeyword>别名形式会复制被命名关键词的解析回调和语法类,使新拼写成为即插即用的别名;在source_commit时刻,树中没有任何.slang源码使用该别名形式。
语句关键字
语句关键字由语句解析器通过直接比对标识符识别。以下行号均指 slang-parser.cpp 在source_commit时刻的版本:
| 关键字 | 解析位置 |
|---|---|
if | 第 6935 行(LookAheadToken("if")),位于Parser::ParseStatement(第 6928 行,其第二个参数是AllowCaseDefaultStatements标志,对应case行所述)。第二个前视在第 6937 行向前看两个 token 是否为let,从而把if let绑定形式路由到parseIfLetStatement(第 7308 行)而非parseIfStatement(第 7397 行);else在后者内部第 7406 行被消费 |
for | 第 6946 行(语句入口)。编译期形式从parseCompileTimeStmt(第 6914 行)进入,它先读取$,然后在第 6917 行检查for才调用parseCompileTimeForStmt(第 6868 行,当前仓库中实测位于第 6958 行)。其头不是普通的(init; cond; update)三元组,而是$for(i in Range(N)):parseCompileTimeForStmt读取循环变量,然后读取字面 tokenin与Range,再读取一个或两个范围表达式——Range(end)或Range(begin, end) |
while | 第 6948 行 |
do | 第 6950 行 |
break | 第 6952 行 |
continue | 第 6954 行 |
return | 第 6956 行 |
switch | 第 6965 行 |
__target_switch | 第 6967 行(parseTargetSwitchStmt);编译器内部 |
__stage_switch | 第 6969 行(parseStageSwitchStmt);编译器内部 |
__intrinsic_asm | 第 6971 行(parseIntrinsicAsmStmt);编译器内部 |
case | 第 6973 行(以及 switch 体内的第 6633、6663 行)。自allowCaseDefault参数加入后,语句解析器在任何位置都接受case再给出诊断:ParseCaseStmt总是构建节点,未传入AllowCaseDefaultStatements::Allow的调用方会报告CaseOutsideSwitch(E39999,第 6977 行) |
default | 第 6980 行(以及 switch 体内的第 6639、6663 行)。与case形态相同:无条件解析,除非调用方允许,否则在第 6985 行报告DefaultOutsideSwitch(E39999) |
__GPU_FOREACH | 第 6987 行(ParseGpuForeachStmt);编译器内部 |
discard | 第 6958 行 |
defer | 第 6993 行 |
throw | 第 7001 行 |
__requireCapability | 第 7005 行(Parser::ParseRequireCapabilityStatement,第 7626 行);编译器内部 |
catch | Parser::ParseDoCatchStatement(第 7506 行),由ParseDoStatement在第 7551 行进入。catch不与语句层的try配对 |
这些关键字不在语法声明表中,因为 Slang 将控制流视为封闭文法,用户代码无法重定义它们。注意try是表达式关键字(见下文"表达式关键字");语句层的异常处理器是do { ... } catch ( ... ) { ... },解析于 slang-parser.cpp 第 7482-7513 行。错误参数可选——裸catch捕获所有错误类型——并且ParseDoCatchStatement会在后面继续出现catch时循环,把每个CatchStmt作为下一个的tryBody,使catch子句链嵌套而非形成扁平列表。
每个编译器内部行解析固定形式,读者在核心模块源码中遇到它们时可以据此识别:
__stage_switch { case <stage>: ... default: ... }与__target_switch共享parseTargetSwitchStmtImpl;case后的标签是能力名,由findCapabilityName解析,无法识别时直接诊断而非当作标识符。__intrinsic_asm "<text>";,可选地在分号前跟一个逗号分隔的参数列表(如__intrinsic_asm "(gl_SubGroupID)";)。__GPU_FOREACH(<device>, <gridDims>, LAMBDA(uint3 <id>) { ... });——字面 tokenLAMBDA是文法的一部分,不是用户提供的名字。__requireCapability(<capability>, ...);,逗号分隔的能力名列表,每个同样由findCapabilityName解析。
声明关键字
声明关键字通过_makeParseDecl(...)(定义于 slang-parser.cpp 第 10696 行)注册进g_parseSyntaxEntries[](数组起点位于 slang-parser.cpp)。以双下划线(__)开头的标识符有意被命名空间化,作为编译器内部/非稳定词汇:
| 关键字 | 解析内容 |
|---|---|
typedef | C 风格类型别名(parseTypeDef) |
typealias | Slang 风格类型别名(parseTypeAliasDecl) |
associatedtype | 接口关联类型(parseAssocType,第 4307 行) |
__constraint | 接口级约束需求(parseInterfaceConstraintDecl,第 4349 行) |
__associatedfunc | 接口关联函数(parseAssocFunc) |
type_param | 模块级泛型类型参数(parseGlobalGenericTypeParamDecl) |
__generic | 泛型参数列表头(parseGenericDecl) |
__generic_value_param | 模块级泛型值参数(parseGlobalGenericValueParamDecl) |
extension,__extension | 类型扩展(parseExtensionDecl) |
__func_extension | 自定义导数的函数扩展简写(parseFuncExtensionDecl);实验特性(由-experimental-feature门控) |
interface | 接口(parseInterfaceDecl) |
__init | 构造函数(parseConstructorDecl) |
__subscript | 下标(parseSubscriptDecl) |
property | 属性(parsePropertyDecl) |
semantic | HLSL 风格语义声明(parseSemanticDecl) |
cbuffer | HLSL 常量缓冲声明(parseHLSLCBufferDecl) |
tbuffer | HLSL 纹理缓冲声明(parseHLSLTBufferDecl) |
syntax | 用户自定义语法(parseSyntaxDecl) |
attribute_syntax | 属性语法(parseAttributeSyntaxDecl) |
import,__import | 模块导入(parseImportDecl) |
__include | 包含指令(parseIncludeDecl) |
module | 模块声明(parseModuleDeclarationDecl) |
implementing | 模块实现声明(parseImplementingDecl) |
let | 不可变绑定(parseLetDecl) |
var | 可变绑定(parseVarDecl) |
func | 函数声明(parseFuncDecl) |
namespace | 命名空间块(parseNamespaceDecl) |
using | using 指令(parseUsingDecl) |
__ignored_block | 编译器内部忽略块 |
__transparent_block | 编译器内部透明块 |
__file_decl | 编译器内部按文件声明的分组 |
__require_capability | 能力需求(parseRequireCapabilityDecl) |
其中三行__形式值得单独展开,因为仅凭回调名无法推断其形态:
__constraint <type> == <type>;陈述类型相等需求,__constraint <type> : <type>;陈述子类型需求。两者都会成为所在接口的GenericTypeConstraintDecl成员,精化从基接口继承的This或关联类型——interface IDerived : IBase { __constraint DataType == This; }要求每个符合者对This.DataType == This成立。它只在接口体内有意义。__associatedfunc <function-type> <name>;——一个类型表达式后跟需求名。核心模块用它声明自动微分函数需求,例如 core.meta.slang 中的static __associatedfunc FwdDiffFuncType<FType> fwd_diff;。__func_extension接受一个高阶目标表达式、一个参数列表、可选throws子句、可选-> <result type>以及一个函数体。目标由语法声明查找而非硬编码的运算符列表解析,因此写作某个微分表达式关键字之一,如 hlsl.meta.slang 中的__func_extension<T : __BuiltinFloatingPointType, let N : int> fwd_diff(CoopVec<T, N>::__subscript::get)(DifferentialPair<CoopVec<T, N>> self, int index) -> DifferentialPair<T> { ... }。
struct、class和enum也是声明关键字,但不通过g_parseSyntaxEntries[]/_makeParseDecl注册。解析器改为在类型说明符解析器中直接做标识符前视分派(slang-parser.cpp 第 3425-3445 行),该路径由ParseDeclWithModifiers(slang-parser.cpp 第 5805 行)进入。专用解析例程(ParseStruct第 6376 行、ParseClass第 6447 行、parseEnumDecl第 6496 行)直接构造对应的 AST 节点。
在解析层面,class是class与struct中远为狭窄的一个。ParseClass只读取必需的名称、可选继承子句与函数体,再无其他。ParseStruct额外接受匿名形式(后面没有标识符时合成名字)、通过parseOptGenericDecl解析的泛型参数列表、无体的前向声明struct S;以及别名形式struct S = T;——因此泛型聚合类型必须写成struct,因为ParseClass没有任何路径消费泛型参数列表。除此之外解析器不区分二者:它构建ClassDecl而非StructDecl,把该选择的所有语义后果留给后续阶段(见 pipeline/03-semantic-check.md)。
同一个类型说明符解析器还通过直接标识符前视识别变长参数包类型形式expand与each(slang-parser.cpp 第 3446-3455 行),旁边是__first/__last/__trimFirst/__trimLast/__shapeConcat/__shapePermute/__shapeSwap/__shapeReduce/__packBranch形状工具(列于"表达式关键字"一节);这些同样不在g_parseSyntaxEntries[]中。紧接其后,同一链在第 3476 行接受functype,交给parseFuncTypeExpr(第 3261 行)解析函数类型;它也是按前视匹配而非注册为语法。拼写为functype(<parameter types>) -> <result type>——零个或多个逗号分隔的参数类型表达式、一个必需的->与一个结果类型。核心模块用它表示高阶参数,如 hlsl.meta.slang 中的This MapElement(functype(uint32_t, uint32_t, T) -> T mapOp);此类参数接受一个函数名作为实参。泛型参数列表接受同一关键字的functype F形式,以声明函数类型的泛型参数。
修饰符关键字
修饰符关键字通过_makeParseModifier注册于 slang-parser.cpp。部分为"简单"修饰符(单个关键字、单个 AST 节点类),部分带参数(如layout、__target_intrinsic)。
简单修饰符
| 关键字 | AST 节点 |
|---|---|
in | InModifier |
out | OutModifier |
inout | InOutModifier |
__ref | RefModifier |
__constref | BorrowModifier |
const | ConstModifier |
__builtin | BuiltinModifier |
highp,lowp,mediump | GLSLPrecisionModifier |
__global | ActualGlobalModifier |
inline | InlineModifier |
public,private,internal | PublicModifier,PrivateModifier,InternalModifier |
require | RequireModifier |
param | ParamModifier |
extern | ExternModifier |
dyn | DynModifier |
row_major,column_major | HLSLRowMajorLayoutModifier,HLSLColumnMajorLayoutModifier |
nointerpolation,noperspective,linear,sample,centroid,precise | 插值修饰符 |
groupshared | HLSLGroupSharedModifier |
static | HLSLStaticModifier |
uniform | HLSLUniformModifier |
export | HLSLExportModifier |
dynamic_uniform | DynamicUniformModifier |
override | OverrideModifier |
point,line,triangle,lineadj,triangleadj | 几何着色器输入修饰符 |
vertices,indices,primitives,payload | 网格着色器输出修饰符 |
__prefix,__postfix | 一元运算符位置修饰符 |
__exported | 再导出import修饰符 |
上表每一行都以_makeParseModifier(keyword, getSyntaxClass<...>())重载注册,其回调为parseSimpleSyntax:构造该类的实例且不读取任何后续 token。因此该关键字的全部解析期含义就是第二列中的节点,关于它所附着声明的一切在此处都不做检查。各节点类后续意味着什么,按节点类记录在 ast-reference/modifiers.md——读者应到该页(而非本页)查找row_major或nointerpolation这类修饰符的用户可观察效果。
回调解析的修饰符(部分带参数)
| 关键字 | 解析内容 |
|---|---|
shared | parseSharedModifier(在上下文上设置 HLSL groupshared / shared) |
volatile | parseVolatileModifier |
coherent | parseCoherentModifier |
restrict | parseRestrictModifier |
readonly | parseReadonlyModifier |
writeonly | parseWriteonlyModifier |
layout | parseLayoutModifier(GLSL 风格 layout 块) |
hitAttributeEXT | parseHitAttributeEXTModifier(光线追踪) |
__intrinsic_op | parseIntrinsicOpModifier |
__target_intrinsic | parseTargetIntrinsicModifier |
__specialized_for_target | parseSpecializedForTargetModifier |
__glsl_extension | parseGLSLExtensionModifier |
__glsl_version | parseGLSLVersionModifier |
__spirv_version | parseSPIRVVersionModifier |
__wgsl_extension | parseWGSLExtensionModifier |
__cuda_sm_version | parseCUDASMVersionModifier |
__builtin_type | parseBuiltinTypeModifier |
__builtin_requirement | parseBuiltinRequirementModifier |
__magic_type | parseMagicTypeModifier |
__magic_enum | parseMagicEnumModifier |
__intrinsic_type | parseIntrinsicTypeModifier |
__implicit_conversion | parseImplicitConversionModifier |
__attributeTarget | parseAttributeTargetModifier |
哪些形式真正带参数由回调决定,而非由表格标题决定。其中六个不读取任何 token:shared、volatile、coherent、restrict、readonly与writeonly均裸写,其回调存在是为了选择或复制节点而非解析操作数——shared在解析器的allowGLSLInput选项开启时构建HLSLGroupSharedModifier,否则构建HLSLEffectSharedModifier;volatile同时构建 HLSL 与 GLSL 节点,并从语言版本 2025 起将关键字诊断为弃用、2026 起移除。hitAttributeEXT同样不带参数。
layout接受一个圆括号括起的逗号分隔 GLSL 限定符列表,每项为裸名称或name = expr,如layout(local_size_x = 8, std430)。其余__前缀行接受圆括号参数列表:__glsl_extension(GL_KHR_shader_subgroup_basic)、__wgsl_extension(subgroups)、__specialized_for_target(glsl)、__attributeTarget(<SyntaxClass>)接受标识符;__glsl_version(430)、__builtin_type(<tag>)、__builtin_requirement(<kind>)接受整数;__spirv_version(1.3)、__cuda_sm_version(7.0)接受major.minor或带引号版本;__magic_type(<Name>[, <tag>])、__magic_enum接受带可选标签的名字;__intrinsic_type(<op>[, <operand>]...)接受 IR 操作码加可选整数操作数;__target_intrinsic(hlsl, "...")接受目标名加可选定义。其中四个仅在可选情况下接受圆括号,没有圆括号也各有含义:裸__intrinsic_op从函数名推导操作码,而非接受它否则可接受的整数或标识符;__target_intrinsic、__specialized_for_target与__implicit_conversion在无括号时回退到默认值。
表达式关键字
表达式关键字通过_makeParseExpr注册于 slang-parser.cpp:
| 关键字 | 解析内容 |
|---|---|
this | 自引用(parseThisExpr) |
true,false | 布尔字面量 |
nullptr | 空指针字面量 |
none | Optional的 none 字面量 |
try | 错误处理表达式(parseTryExpr) |
no_diff | 不可微包装(parseTreatAsDifferentiableExpr) |
__fwd_diff,fwd_diff | 前向模式微分(parseForwardDifferentiate) |
__bwd_diff,bwd_diff | 反向模式微分(parseBackwardDifferentiate) |
__apply | 反向高阶应用表达式(parseApplyForBwd);用于__func_extension内部,为自定义bwd_diff暴露 primal-with-context 伴生函数;实验特性 |
new | 堆式分配表达式;由parsePrefixExpr的AdvanceIf(parser, "new")分支特殊解析(slang-parser.cpp,parsePrefixExpr定义于第 9703 行;不经由_makeParseExpr) |
__return_val | 编译器内部返回值引用 |
__func_as_type | 函数即类型的反射 |
__dispatch_kernel | 内核分派原语 |
sizeof,alignof,countof | 大小 / 对齐 / 元素个数查询 |
__first,__last,__trimFirst,__trimLast,__shapeConcat,__shapePermute,__shapeSwap,__shapeReduce,__packBranch | 形状 / 打包工具表达式 |
__getAddress | 编译器内部取地址 |
__floatAsInt | 编译器内部位重解释 |
每一行的操作数形态由回调固定,且大多数(并非全部)行带圆括号:
try与no_diff后接一个叶子表达式,自身不带圆括号——try f(x)、no_diff f(x)。__return_val完全不带操作数;它是对待返回值的裸引用。fwd_diff/__fwd_diff、bwd_diff/__bwd_diff、__apply、__func_as_type、__getAddress、__floatAsInt与countof恰好接受一个圆括号操作数——fwd_diff(f)、countof(pack)。sizeof与alignof接受一个操作数加可选第二个数据布局操作数:sizeof(T)或sizeof(T, Std140DataLayout)。__first、__last、__trimFirst、__trimLast接受一个 pack 操作数;__shapePermute与__shapeReduce接受两个;__shapeConcat、__shapeSwap、__packBranch接受三个(__packBranch(<pack>, <empty type>, <non-empty type>))。__dispatch_kernel(<function>, <dispatch size>, <thread-group size>)接受三个。new是作用于后缀表达式的前缀运算符,写作new T(args)——先解析类型名及其实参列表,再折叠进NewExpr。
核心模块的语法声明
位于 source/slang 的四个*.meta.slang文件为默认环境贡献了额外名字。它们在"解析器语法表"的意义上不是关键字:解析器的语法查找只接受SyntaxDecl,因此这些名字是解析器在进行有限类型名消歧时查阅的内置词汇,而非解析关键字。处理要点:
- core.meta.slang 声明内置标量 / 向量 / 矩阵类型、
Optional与Tuple类型,以及核心内在函数。 - hlsl.meta.slang 叠加 HLSL 兼容名(
Texture2D、RWTexture2D、StructuredBuffer,mul、dot、length等内在函数,以及 wave 内在函数)。此处的两种"wave builtin"并不可互换。WaveGetWaveIndex()是普通的核心模块函数:它带有[require(cuda_glsl_hlsl_metal_spirv_wgsl, subgroup_workgroup_index)]与一个每目标一个分支的__target_switch函数体,其可用性在模块自身中即已声明。SV_WaveIndex与SV_GroupIndex则不是函数而是系统值语义,写在文件顶部附近的隐藏in全局变量__builtinWaveIndex与__builtinGroupIndex的:之后;模块未给它们附加任何能力需求,哪些目标接受它们由入口点可变参数合法化(pipeline/05-ir-passes.md)决定,而非在此处。因此WaveGetWaveIndex()才是可移植的拼写。 - 同一文件声明描述符堆词汇——
UntypedResourceHandle与UntypedSamplerHandle,连同__ResourceDescriptorHeapType/__SamplerDescriptorHeapType类型(其__subscript把索引变为句柄)——每个都由[require(glsl_hlsl_spirv_wgsl, descriptor_handle)]门控,使不支持的 target 在下标处即被诊断。这两个类型的用户级拼写是一对static const全局量ResourceDescriptorHeap与SamplerDescriptorHeap,因此表层形式是ResourceDescriptorHeap[i]。它产出的无类型句柄并不写下来:每个可堆强转的资源类型都声明一个接受句柄的__implicit_conversion构造函数,具体类型从赋值目标恢复,如RWStructuredBuffer<uint> buf = ResourceDescriptorHeap[0];。 - glsl.meta.slang 提供 GLSL 风格名字(
vec3、mat4、gl_Position等)。 - diff.meta.slang 贡献自动微分机制使用的微分对类型与辅助函数(见 pipeline/05-ir-passes.md)。
核心模块流水线的整体描述见 cross-cutting/core-module.md。
保留标识符前缀
按约定:
- 以
__开头的名字(如__intrinsic_op、__target_intrinsic、__init、__subscript、__import、__include、__constraint、__file_decl)表示用户代码不应依赖的编译器内部词汇。少数具有无下划线的解析器注册公开拼写(extension、import);__init、__subscript与__include在g_parseSyntaxEntries[]中没有无下划线拼写。 - 以
gl_开头的名字来自 GLSL 元模块,表示着色器阶段内建量。它们是普通全局声明——public out float4 gl_Position : SV_Position;——而非词汇类。 - 以
SV_开头的名字(HLSL 系统值语义)以语义字符串而非关键字形式出现;它们在语义检查期间被识别(pipeline/03-semantic-check.md)。
禁用 / 保留集合并非在词法上强制,而是由元模块编码的策略。两个前缀都是建议性的:背后没有任何诊断支撑,因此用户声明一个以此开头的名字就是普通声明。解析器仅在一处检查gl_前缀——名称以gl_开头的 GLSL 接口块被视为内建块的重声明,替换为EmptyDecl——并且从不检查SV_。解析器唯一的保留名检查是isReservedKeywordName(slang-parser.cpp),当声明符命名为struct、class、enum、typealias或typedef时发出警告(KeywordUsedAsName)——这五个拼写会开启一个类型说明符,因此与其中一个重名的名字无法在语句开头被引用。其注释陈述了其余词汇遵守的规则:几乎每个关键字都是上下文相关的,可被用户定义的名字遮蔽,包括func、let、var、interface、extension、import等声明关键字。
__前缀是真正承重的前缀,而且只对上述表格列出的确切拼写承重。只有__init、__subscript与__include的__前缀形式注册于g_parseSyntaxEntries[];裸init、subscript、include是普通标识符,可用作函数名并在语句开头调用。
【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考