56个版本 (22个稳定版本)
7.0.0 | 2023年12月22日 |
---|---|
6.0.3 |
|
6.0.2 | 2023年3月23日 |
6.0.1 | 2021年7月11日 |
0.3.0 | 2017年7月31日 |
#58 在 解析器实现 中
每月4,763 次下载
用于 21 个crate(14个直接使用)
290KB
8K SLoC
这个crate是一个GLSL450/GLSL460编译器。它能将有效的GLSL格式源代码解析成抽象语法树(AST)。然后,该AST可以被转换成SPIR-V、自己的格式,甚至可以折叠回原始的GLSL String
(例如,一个压缩器)。
你可以找到几个模块
parser
,它导出了解析接口。这里是你可以获得大多数有趣类型和特质的所在地,例如Parse
和ParseError
。syntax
,它导出了AST和语言定义。如果你查看解构、转译或获取解析的GLSL代码的信息,你可能会操作在这个模块中定义类型的对象。transpiler
,它为你提供了GLSL转译器。例如,你可以找到 GLSL到GLSL 转译器,GLSL到SPIR-V 转译器等。visitor
,它为你提供了一种访问AST节点并修改它们的方式,包括内部和外部修改。
请随意检查这些模块以获取更多信息。
GLSL解析和转译
解析是你最常进行的操作。这不是必需的(你仍然可以手动创建AST或使用 glsl-quasiquote 在编译时通过在Rust中使用GLSL语法直接创建它)。然而,在本节中,我们将看到如何从字符串解析到几个GLSL类型。
解析架构
基本上,Parse
特质提供了您开始解析所需的一切。这个crate围绕类型驱动的解析概念进行设计:解析器是隐藏的,您只需声明您期望的结果类型。
您想要解析的最常见类型是TranslationUnit
,它代表一组ExternalDeclaration
。一个ExternalDeclaration
是着色器顶级层面的声明。它可以是一个全局、统一声明、顶点属性、函数、结构体等。从这个意义上讲,一个TranslationUnit
类似于着色器阶段(顶点着色器、片段着色器等)。
您可以解析实现Parse
的任何类型。解析器对外部空白敏感,这意味着以空白开始的Expr
解析将不会工作(这对TranslationUnit
来说不是真的,因为它非常宽容)。
解析一个表达式
让我们尝试解析一个表达式。
use glsl::parser::Parse as _;
use glsl::syntax::Expr;
let glsl = "(vec3(r, g, b) * cos(t * PI * .5)).xxz";
let expr = Expr::parse(glsl);
assert!(expr.is_ok());
在这里,expr
是一个AST,其类型为Result<Expr, ParseError>
,它表示GLSL表达式(vec3(r, g, b) * cos(t * PI * .5)).xxz
,这是RGB颜色与时间的余弦值的外部(标量)乘积,整个东西与XXZ进行了混洗。检查解析过程是否成功是您的责任。
在上一个例子中,GLSL字符串是一个常量,是硬编码的。它可以来自文件、网络或即时构建,但在常量GLSL代码的情况下,最好不在运行时解析字符串,对吗?嗯,glsl-quasiquote正是为此而存在的。您可以要求rustc解析该字符串,如果解析成功,则直接将AST注入到您的代码中。没有Result
,只有纯AST。有关详细信息,请参阅glsl-quasiquote。
解析整个着色器
顶点着色器、几何着色器、片段着色器以及控制和评估细分着色器可以通过使用TranslationUnit
或ShaderStage
类型以相同的方式进行解析。
在这里,一个简单的顶点着色器被解析。
use glsl::parser::Parse as _;
use glsl::syntax::ShaderStage;
let glsl = "
layout (location = 0) in vec3 pos;
layout (location = 1) in vec4 col;
out vec4 v_col;
uniform mat4 projview;
void main() {
v_col = col; // pass color to the next stage
gl_Position = projview * vec4(pos, 1.);
}
";
let stage = ShaderStage::parse(glsl);
assert!(stage.is_ok());
访问AST节点
这个crate也在不断增加组合子和函数来转换AST或使用常规Rust创建节点。当您想要处理深度变异、过滤和验证时,Visitor
trait将成为您的得力助手。请查看visitor
模块,了解如何使用访问者。
关于GLSL版本...
这个crate可以解析GLSL450和GLSL460格式的输入源。在语言层面上,GLSL450和GLSL460之间的差异几乎可以忽略不计,所以两种情况都得到了覆盖。
如果您想知道,两个版本之间的唯一区别是,在GLSL460中,在着色器顶层允许空行上有分号(
;
)。
依赖关系
~0.8–5MB
~112K SLoC