glast/
lib.rs

1//! *glast* is a crate for parsing and manipulating **gl**sl **a**bstract **s**yntax **t**rees, and a lot more.
2//!
3//! ⚠ This crate is still heavily **work-in-progress**. The main functionality & API of the lexer and parser are
4//! roughly finalized, but small changes and tweaks are still to be expected, and other features are not
5//! implemented yet.
6//!
7//! This crate is part of a larger effort to provide a high-quality LSP implementation for GLSL. Hence, this crate
8//! exposes more than just the basic lexing and parsing functionality found in other crates or libraries for other
9//! languages:
10//! - The lexer changes the grammar depending on an encountered version directive, in line with the specification.
11//! - Lexing and parsing functions produce useful metadata about their inputs.
12//! - The parser produces not only an AST, but also syntax and (some) semantic diagnostics, as well as syntax
13//!   highlighting information.
14//! - The parser correctly expands arbitrarily-complex macros anywhere that it should, in line with the
15//!   specification.
16//! - The parser correctly handles all conditional compilation, no matter how convoluted. Full control over which
17//!   conditional branches to include/exclude is provided, include the ability to evaluate conditional directives
18//!   on-the-fly.
19//! - Both the lexer and parser are aiming to be 100% specification compliant.
20//!
21//! The currently supported GLSL versions are:
22//!
23//! |GLSL version|OpenGL version|
24//! |-|-|
25//! |460|4.6|
26//! |450|4.5|
27//!
28//! There are plans to support many more versions, not limited to but including 110 (default), 130, 330, 400, 410,
29//! and 100 (es), 300 es & 320 es
30//!
31//! # The parsing pipeline
32//! This crate is split into modules representing the different stages of parsing/manipulation:
33//! - [`lexer`] - Lexer and the token stream.
34//! - [`parser`] - Parser and the abstract syntax tree.
35//! - `analyzer` - High intermediate representation and analysis, such as name resolution.
36//!
37//! This crate operates only on [`str`] inputs because the GLSL specification states that GLSL source strings must
38//! use the UTF-8 encoding. That means that if the source can be parsed into a valid Rust [`str`] then it must be
39//! valid, so no support for `[u8]` inputs is provided.
40//!
41//! ## Source String
42//! We start with a string of characters that makes up the glsl source file. We will use the following example to
43//! illustrate the pipeline:
44//! ```c
45//! // Comment
46//! int i = 5.0+1;
47//! ```
48//!
49//! ## Lexer
50//! This is the first transformation in the parsing pipeline, and it converts a string of characters into a stream
51//! of tokens. The source string would become (in pseudocode):
52//! ```text
53//! (comment " Comment") (ident "int") (ident "i") (op "=") (float "5.0") (op "+") (int "1") (punct ";")
54//! ```
55//!
56//! ## Parser
57//! This is the next transformation in the parsing pipeline, and it converts the token stream into a tree that only
58//! contains semantic information, loosing things like irrelevant punctuation symbols or comments.
59//!
60//! Firstly, conditional compilation is applied to the token stream. Then, the resulting token stream is parsed,
61//! expanding any macros in the process.
62//!
63//! The token stream would become (in pseudocode):
64//! ```text
65//! VariableDeclaration {
66//!     type: Primitive.Int,
67//!     ident: Identifier("i"),
68//!     value: BinaryExpression {
69//!         left: Float(5.0),
70//!         op: Addition,
71//!         right: Int(1),
72//!     }
73//! }
74//! ```
75//!
76//! ## Analyzer
77//! This is the final stage of the parsing pipeline, and includes actions such as name resolution and
78//! type-checking.
79//!
80//! ⚠ This module is **not implemented yet**.
81//!
82//! # Diagnostics
83//! The parser produces syntax errors when it encounters invalid syntax. It also produces semantic diagnostics in
84//! relation to macros. All other semantic diagnostics are currently waiting on the `analyzer` module to be
85//! implemented.
86//!
87//! For more details, see the [`diag`] module.
88//!
89//! # Syntax Highlighting
90//! The parser produces syntax highlighting tokens as part of the parsing process. These tokens correctly highlight
91//! all text that has been parsed, but they are not fully semantically-aware; this is because the parser only
92//! creates an abstract syntax tree, it does not perform name-resolution. This means that currently most
93//! identifiers are of the `UncheckedIdent` variant. Once the `analyzer` module has been implemented to include
94//! name-resolution functionality, these syntax tokens can be converted into more specific variable/type/function
95//! identifiers, which would result in fully semantically-aware highlighting information.
96//!
97//! For more details, see the [`syntax`] module.
98//!
99//! # Security
100//! This crate has zero uses of `unsafe`.
101//!
102//! This crate does not execute arbitrary source code; any evaluations (such as evaluating `#if` expressions) are
103//! free of any side-effects. This crate takes in string slices, performs analysis operations, and returns data
104//! structures; it does not perform any I/O or networking calls.
105//!
106//! # Performance & Testing
107//! Currently, this crate has not been particularly optimized for performance; there is a lot of `clone()`-ing. The
108//! general internal structure is well suited for optimization, but the work has not yet been done because the
109//! internals have undergone numerous large-scale refactors and re-writes whilst the functionality and public api
110//! have matured. Unless any massive oversights have occurred, the current structure is the one that will go
111//! forward, and once this crate has been given a bit of use to iron out any remaining minor bugs, it will be
112//! optimized to minimize data cloning and memory allocations.
113//!
114//! Currently, this crate does not have extensive testing. Some parts of the crate have good unit test coverage,
115//! but other parts lack any tests completely and there are no integration tests yet. This is an important goal
116//! that is being progressively worked towards.
117
118pub mod diag;
119pub mod lexer;
120pub mod parser;
121mod span;
122pub mod syntax;
123
124pub use span::*;
125
126/// Describes a GLSL version.
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
128pub enum GlslVersion {
129	/// OpenGL 4.5
130	_450,
131	/// OpenGL 4.6
132	_460,
133	/// A GLSL version unsupported by the crate.
134	#[default]
135	// TODO: The default GLSL version in reality is 110, but we currently don't support that.
136	Unsupported,
137}
138
139impl GlslVersion {
140	/// Parses a number into a GLSL version.
141	fn parse(num: usize) -> Option<Self> {
142		match num {
143			450 => Some(Self::_450),
144			460 => Some(Self::_460),
145			_ => None,
146		}
147	}
148}
149
150/// Holds either one or the other value.
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub enum Either<L, R> {
153	Left(L),
154	Right(R),
155}
156
157/// Holds one of 3 possible values.
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159enum Either3<A, B, C> {
160	A(A),
161	B(B),
162	C(C),
163}