glsl/lib.rs
1//! This crate is a GLSL450/GLSL460 compiler. It’s able to parse valid GLSL formatted source into
2//! an abstract syntax tree (AST). That AST can then be transformed into SPIR-V, your own format or
3//! even folded back to a raw GLSL [`String`] (think of a minifier, for instance).
4//!
5//! You’ll find several modules:
6//!
7//! - [`parser`], which exports the parsing interface. This is the place you will get most
8//! interesting types and traits, such as [`Parse`] and [`ParseError`].
9//! - [`syntax`], which exports the AST and language definitions. If you look into destructuring,
10//! transpiling or getting information on the GLSL code that got parsed, you will likely
11//! manipulate objects which types are defined in this module.
12//! - [`transpiler`], which provides you with GLSL transpilers. For instance, you will find _GLSL
13//! to GLSL_ transpiler, _GLSL to SPIR-V_ transpiler, etc.
14//! - [`visitor`](visitor), which gives you a way to visit AST nodes and mutate them, both with
15//! inner and outer mutation.
16//!
17//! Feel free to inspect those modules for further information.
18//!
19//! # GLSL parsing and transpiling
20//!
21//! Parsing is the most common operation you will do. It is not required per-se (you can still
22//! create your AST by hand or use [glsl-quasiquote] to create it at compile-time by using the GLSL
23//! syntax directly in Rust). However, in this section, we are going to see how we can parse from a
24//! string to several GLSL types.
25//!
26//! ## Parsing architecture
27//!
28//! Basically, the [`Parse`] trait gives you all you need to start parsing. This crate is designed
29//! around the concept of type-driven parsing: parsers are hidden and you just have to state what
30//! result type you expect.
31//!
32//! The most common type you want to parse to is [`TranslationUnit`], which represents a set of
33//! [`ExternalDeclaration`]s. An [`ExternalDeclaration`] is just a declaration at the top-most level
34//! of a shader. It can be a global, uniform declarations, vertex attributes, a function, a
35//! structure, etc. In that sense, a [`TranslationUnit`] is akin to a shader stage (vertex shader,
36//! fragment shader, etc.).
37//!
38//! You can parse any type that implements [`Parse`]. Parsers are mostly sensible to external
39//! blanks, which means that parsing an [`Expr`] starting with a blank will not work (this is not
40//! true for a [`TranslationUnit`] as it’s exceptionnally more permissive).
41//!
42//! ## Parsing an expression
43//!
44//! Let’s try to parse an expression.
45//!
46//! ```rust
47//! use glsl::parser::Parse as _;
48//! use glsl::syntax::Expr;
49//!
50//! let glsl = "(vec3(r, g, b) * cos(t * PI * .5)).xxz";
51//! let expr = Expr::parse(glsl);
52//! assert!(expr.is_ok());
53//! ```
54//!
55//! Here, `expr` is an AST which type is `Result<Expr, ParseError>` that represents the GLSL
56//! expression `(vec3(r, g, b) * cos(t * PI * .5)).xxz`, which is an outer (scalar) multiplication
57//! of an RGB color by a cosine of a time, the whole thing being
58//! [swizzled](https://en.wikipedia.org/wiki/Swizzling_(computer_graphics)) with XXZ. It is your
59//! responsibility to check if the parsing process has succeeded.
60//!
61//! In the previous example, the GLSL string is a constant and hardcoded. It could come from a file,
62//! network or built on the fly, but in the case of constant GLSL code, it would be preferable not
63//! to parse the string at runtime, right? Well, [glsl-quasiquote] is there exactly for that. You
64//! can ask **rustc** to parse that string and, if the parsing has succeeded, inject the AST
65//! directly into your code. No [`Result`], just the pure AST. Have a look at [glsl-quasiquote] for
66//! further details.
67//!
68//! ## Parsing a whole shader
69//!
70//! Vertex shaders, geometry shaders, fragment shaders and control and evaluation tessellation
71//! shaders can be parsed the same way by using one of the `TranslationUnit` or `ShaderStage` types.
72//!
73//! Here, a simple vertex shader being parsed.
74//!
75//! ```rust
76//! use glsl::parser::Parse as _;
77//! use glsl::syntax::ShaderStage;
78//!
79//! let glsl = "
80//! layout (location = 0) in vec3 pos;
81//! layout (location = 1) in vec4 col;
82//!
83//! out vec4 v_col;
84//!
85//! uniform mat4 projview;
86//!
87//! void main() {
88//! v_col = col; // pass color to the next stage
89//! gl_Position = projview * vec4(pos, 1.);
90//! }
91//! ";
92//! let stage = ShaderStage::parse(glsl);
93//! assert!(stage.is_ok());
94//! ```
95//!
96//! ## Visiting AST nodes
97//!
98//! The crate is also getting more and more combinators and functions to transform the AST or create
99//! nodes with regular Rust. The [`Visitor`] trait will be a great friend of yours when you will
100//! want to cope with deep mutation, filtering and validation. Have a look at the
101//! [`visitor`](visitor) module for a tutorial on how to use visitors.
102//!
103//! # About the GLSL versions…
104//!
105//! This crate can parse both GLSL450 and GLSL460 formatted input sources. At the language level,
106//! the difference between GLSL450 and GLSL460 is pretty much nothing, so both cases are covered.
107//!
108//! > If you’re wondering, the only difference between both versions is that in GLSL460, it’s
109//! > authorized to have semicolons (`;`) on empty lines at top-level in a shader.
110//!
111//! [glsl-quasiquote]: https://crates.io/crates/glsl-quasiquote
112//! [`Parse`]: crate::parser::Parse
113//! [`ParseError`]: crate::parser::ParseError
114//! [`ExternalDeclaration`]: crate::syntax::ExternalDeclaration
115//! [`TranslationUnit`]: crate::syntax::TranslationUnit
116//! [`Expr`]: crate::syntax::Expr
117//! [`Visitor`]: crate::visitor::Visitor
118
119#[cfg(test)]
120mod parse_tests;
121pub mod parser;
122mod parsers;
123pub mod syntax;
124pub mod transpiler;
125pub mod visitor;