├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── Cargo.toml ├── README.md ├── glsl-quasiquote ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── lib.rs │ ├── quoted.rs │ └── tokenize.rs └── tests │ └── lib.rs ├── glsl-tree ├── CHANGELOG.md ├── Cargo.toml ├── README.md └── src │ └── main.rs ├── glsl ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── data │ └── tests │ │ ├── buffer_block_0.glsl │ │ └── layout_buffer_block_0.glsl ├── fuzz │ ├── .gitignore │ ├── Cargo.toml │ └── fuzz_targets │ │ ├── parse_expr.rs │ │ ├── parse_integral_lit.rs │ │ ├── parse_translation_unit.rs │ │ └── transpile_expr.rs ├── src │ ├── lib.rs │ ├── parse_tests.rs │ ├── parser.rs │ ├── parsers.rs │ ├── parsers │ │ └── nom_helpers.rs │ ├── syntax.rs │ ├── transpiler │ │ ├── glsl.rs │ │ ├── mod.rs │ │ └── spirv.rs │ └── visitor.rs └── tests │ ├── incorrect_statement.rs │ ├── left_associativity.rs │ └── missing_zero_float.rs └── rustfmt.toml /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [pull_request] 3 | 4 | jobs: 5 | glsl-linux: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Cargo update 10 | run: cargo update 11 | - name: Build glsl 12 | run: | 13 | cd $GITHUB_WORKSPACE/glsl 14 | cargo build --verbose 15 | - name: Test glsl 16 | run: | 17 | cd $GITHUB_WORKSPACE/glsl 18 | cargo test --verbose 19 | 20 | glsl-tree-linux: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Cargo update 25 | run: cargo update 26 | - name: Build glsl-tree 27 | run: | 28 | cd $GITHUB_WORKSPACE/glsl-tree 29 | cargo build --verbose 30 | 31 | glsl-quasiquote-linux: 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v4 35 | - name: Switch to nightly Rust 36 | run: rustup default nightly 37 | - name: Build glsl-quasiquote 38 | run: | 39 | cd $GITHUB_WORKSPACE/glsl-quasiquote 40 | cargo build --verbose 41 | - name: Test glsl-quasiquote 42 | run: | 43 | cd $GITHUB_WORKSPACE/glsl-quasiquote 44 | cargo test --verbose 45 | 46 | glsl-macos: 47 | runs-on: macOS-latest 48 | steps: 49 | - uses: actions/checkout@v4 50 | - name: Cargo update 51 | run: cargo update 52 | - name: Build glsl 53 | run: | 54 | cd $GITHUB_WORKSPACE/glsl 55 | cargo build --verbose 56 | - name: Test glsl 57 | run: | 58 | cd $GITHUB_WORKSPACE/glsl 59 | cargo test --verbose 60 | 61 | glsl-tree-macos: 62 | runs-on: macOS-latest 63 | steps: 64 | - uses: actions/checkout@v4 65 | - name: Cargo update 66 | run: cargo update 67 | - name: Build glsl-tree 68 | run: | 69 | cd $GITHUB_WORKSPACE/glsl-tree 70 | cargo build --verbose 71 | 72 | glsl-quasiquote-macos: 73 | runs-on: macOS-latest 74 | steps: 75 | - uses: actions/checkout@v4 76 | - name: Switch to nightly Rust 77 | run: rustup default nightly 78 | - name: Build glsl-quasiquote 79 | run: | 80 | cd $GITHUB_WORKSPACE/glsl-quasiquote 81 | cargo build --verbose 82 | - name: Test glsl-quasiquote 83 | run: | 84 | cd $GITHUB_WORKSPACE/glsl-quasiquote 85 | cargo test --verbose 86 | 87 | glsl-windows: 88 | runs-on: windows-latest 89 | steps: 90 | - uses: actions/checkout@v4 91 | - name: Cargo update 92 | run: cargo update 93 | - name: Build glsl 94 | run: | 95 | cd $env:GITHUB_WORKSPACE\glsl 96 | cargo build --verbose 97 | - name: Test glsl 98 | run: | 99 | cd $env:GITHUB_WORKSPACE\glsl 100 | cargo test --verbose 101 | 102 | glsl-tree-windows: 103 | runs-on: windows-latest 104 | steps: 105 | - uses: actions/checkout@v4 106 | - name: Cargo update 107 | run: cargo update 108 | - name: Build glsl-tree 109 | run: | 110 | cd $env:GITHUB_WORKSPACE\glsl-tree 111 | cargo build --verbose 112 | 113 | glsl-quasiquote-windows: 114 | runs-on: windows-latest 115 | steps: 116 | - uses: actions/checkout@v4 117 | - name: Switch to nightly Rust 118 | run: rustup default nightly 119 | - name: Build glsl-quasiquote 120 | run: | 121 | cd $env:GITHUB_WORKSPACE\glsl-quasiquote 122 | cargo build --verbose 123 | - name: Test glsl-quasiquote 124 | run: | 125 | cd $env:GITHUB_WORKSPACE\glsl-quasiquote 126 | cargo test --verbose 127 | 128 | check-fmt: 129 | runs-on: ubuntu-latest 130 | steps: 131 | - uses: actions/checkout@v4 132 | - name: Ensure code is correctly formatted 133 | run: cargo fmt -- --check 134 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "glsl", 5 | "glsl-tree", 6 | "glsl-quasiquote" 7 | ] 8 | 9 | [patch.crates-io] 10 | glsl = { path = "./glsl" } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenGL Shading Language parser and AST manipulation crates 2 | 3 | The project has moved to [sourcehut](https://sr.ht/~hadronized/glsl). 4 | -------------------------------------------------------------------------------- /glsl-quasiquote/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 7.0 2 | 3 | > Dec 23, 2023 4 | 5 | - Bump to replace the yanked `glsl-6.0.3` version. 6 | 7 | # 6.0.1 8 | 9 | > Dec 19th, 2023 10 | 11 | - Support `proc-macro-faithful-display-0.2`. 12 | 13 | # 6.0 14 | 15 | > Dec 7th, 2020 16 | 17 | - Support for `glsl-6.0`. 18 | 19 | # 5.0 20 | 21 | > Jul 27th, 2020 22 | 23 | - Support for `glsl-5.0`. 24 | 25 | # 4.0 26 | 27 | > Mon 6th Jan 2020 28 | 29 | ## Major changes 30 | 31 | - Support for `glsl-4.0`. 32 | 33 | # 3.0 34 | 35 | > Wed 14th Nov 2019 36 | 37 | ## Major changes 38 | 39 | - Adapt internals to support `glsl-3.0` version. 40 | 41 | # 2.0 42 | 43 | > Thu 24th Oct 2019 44 | 45 | ## Major changes 46 | 47 | - Bump `glsl-2.0` version. 48 | 49 | # 1.0 50 | 51 | > Thu 18th of July 2019 52 | 53 | - Adapt to the new `&str` parsing (especially because of the `Parse` trait). 54 | 55 | ## 0.3.1 56 | 57 | > Sun 9th of December 2018 58 | 59 | - Fix [a nasty bug](https://github.com/phaazon/glsl/issues/60) that was causing valid code to 60 | break. 61 | 62 | # 0.3 63 | 64 | > Wed 21th of November 2018 65 | 66 | - Add support for #define. 67 | 68 | ## 0.2.2 69 | 70 | > Sun 11th of November 2018 71 | 72 | - Fix internal code for tokenizers. 73 | 74 | ## 0.2.1 75 | 76 | > Mon 5th of November 2018 77 | 78 | - Add the `Tokenize` trait and move tokenizers in their own modules. 79 | 80 | # 0.2 81 | 82 | > Sun 21st of October 2018 83 | 84 | - Support GLSL pragmas. 85 | - Make the now redundant `glsl_str!` macro deprecated. 86 | 87 | ## 0.1.1 88 | 89 | > Wed 10th of October 2018 90 | 91 | - Fix some internal representation of produral Rust tokens. 92 | 93 | # 0.1 94 | 95 | > Fri 5th of October 2018 96 | 97 | - Initial revision. 98 | -------------------------------------------------------------------------------- /glsl-quasiquote/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | > **If you have a doubt on how you should contribute, feel free to open an issue and ask! There’s no 4 | > question that shouldn’t be answered.** 5 | 6 | ## Project workflow 7 | 8 | - Fork the project to your GitHub workspace. 9 | - Create a new branch with a name that reflects your work. This project adopts a somewhat similar 10 | branch naming as *gitflow*: 11 | - If you’re working on a *feature*, prefix the branch name by `feature/`. 12 | - If you’re working on a *bug fix*, prefix the branch name by `fix/`. 13 | - If you’re adding documentation, enhancing code readability, refactoring and making the place 14 | a better code base to work with, prefix the branch name by `enhancement/`. 15 | - Add some commits to your branch. Keep in mind that your commits should be atomic enough so that 16 | the commit message doesn’t get to complicated. For instance, it’s highly discouraged to create 17 | commits that touch to a lot of files with several algorithms, concepts and ideas altered at the 18 | same time. Feel free to use `git commit -p`, `git add` and even `git reset` to edit your commits 19 | hygiene. 20 | - Once you’re done and your branch pushed, open a pull request on the project page. 21 | 22 | ## Code conventions 23 | 24 | - No `rustfmt` (so far) because of how specific formatting can become. 25 | - Put `{` on the same line as the item, not after. Example: 26 | ```rust 27 | struct Foo { // good 28 | // … 29 | } 30 | 31 | struct Foo // not good 32 | { 33 | // … 34 | } 35 | ``` 36 | - Type ascriptions must be done on the same line, without aligning and with no space between the 37 | value and the `:` and a single space between the `:` and the type. However, please try to avoid 38 | them as much as the rustc type inference engine can deduce it for us. Example: 39 | ```rust 40 | let x: u32 = 0; // good 41 | let y: &'static str = "hello"; // not good, the type inference can deduce 42 | let a : Foo = Foo::new(); // not good: extra space between a and : 43 | ``` 44 | - Short function signatures have the `where` clause – if any – on the same line. Example: 45 | ```rust 46 | fn short_fn(t: T) where T: Clone + Display { 47 | // … 48 | } 49 | ``` 50 | - However, long function signatures, long `trait`s and `impl`s have the the `where` clause on the 51 | line below the list of trait bounds, with each trait bound on its specific line, finishing with 52 | the last bound with the opening bracket `{`. Also, the arguments are laid out on several lines. 53 | Example: 54 | ```rust 55 | fn very_long_function_name_with_lot_of_trait_bounds( 56 | t: T, 57 | foo: &Foo, 58 | name: &str 59 | ) -> impl MyTrait 60 | where T: Clone + Display, 61 | Q: From { 62 | // … 63 | } 64 | ``` 65 | - All public symbols (functions, types, traits, trait implementations, macros, etc.) must be 66 | documented. This is not mandatory for contributions but really highly appreciated. 67 | - Please comment the internals of your code and don’t obfuscate. However, good onelines are still 68 | good oneliners. ;) 69 | - Test are more than welcomed. 70 | -------------------------------------------------------------------------------- /glsl-quasiquote/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glsl-quasiquote" 3 | version = "7.0.0" 4 | license = "BSD-3-Clause" 5 | authors = ["Dimitri Sabadie "] 6 | description = "The glsl! procedural macro, providing quasiquoting of the glsl crate." 7 | keywords = ["GLSL", "OpenGL", "SPIR-V", "parser", "proc-macro"] 8 | categories = ["parsing", "rendering"] 9 | homepage = "https://github.com/phaazon/glsl" 10 | repository = "https://github.com/phaazon/glsl" 11 | documentation = "https://docs.rs/glsl-quasiquote" 12 | readme = "README.md" 13 | 14 | edition = "2018" 15 | 16 | [badges] 17 | travis-ci = { repository = "phaazon/glsl", branch = "master" } 18 | 19 | [lib] 20 | proc-macro = true 21 | 22 | [dependencies] 23 | glsl = "7" 24 | proc-macro2 = "1" 25 | proc-macro-faithful-display = "0.2" 26 | quote = "1" 27 | -------------------------------------------------------------------------------- /glsl-quasiquote/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Dimitri Sabadie 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Dimitri Sabadie nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /glsl-quasiquote/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/phaazon/glsl-quasiquote.svg?branch=master)](https://travis-ci.org/phaazon/glsl-quasiquote) 2 | [![crates.io](https://img.shields.io/crates/v/glsl-quasiquote.svg)](https://crates.io/crates/glsl-quasiquote) 3 | [![docs.rs](https://docs.rs/glsl-quasiquote/badge.svg)](https://docs.rs/glsl-quasiquote) 4 | ![License](https://img.shields.io/badge/license-BSD3-blue.svg?style=flat) 5 | 6 | 7 | 8 | # GLSL quasiquoting. 9 | 10 | This crate exports a procedural macro: `glsl!`. It enables quasiquoting by allowing you to 11 | embed GLSL source code directly into rust via the syntax: 12 | 13 | ```rust 14 | #![feature(proc_macro_hygiene)] 15 | 16 | use glsl::syntax::TranslationUnit; 17 | use glsl_quasiquote::glsl; 18 | 19 | let tu: TranslationUnit = glsl!{ 20 | // your GLSL code here 21 | void main() { 22 | } 23 | }; 24 | ``` 25 | 26 | The `glsl!` macro accepts the GLSL code directly. You can then write plain GLSL. Especially, 27 | since version **0.2**, the macro accepts plain GLSL pragmas (both `#version` and `#extension`). 28 | 29 | The `glsl!` procedural macro resolves at compile-time to [`TranslationUnit`], 30 | allowing you to manipulate the GLSL AST directly. Feel free to have a look at the 31 | [`glsl`](https://crates.io/crates/glsl) crate for further information. 32 | 33 | # Getting started 34 | 35 | Add the following to your dependencies in your `Cargo.toml`: 36 | 37 | ```toml 38 | glsl = "1" 39 | glsl-quasiquote = "1" 40 | ``` 41 | 42 | Then, you currently need to have a nightly compiler and the following feature enabled: 43 | 44 | ```rust 45 | #![feature(proc_macro_hygiene)] 46 | ``` 47 | 48 | Then, depending on which you’re using the 2018 edition or not: 49 | 50 | > *Non-2018 edition* 51 | 52 | ```rust 53 | extern crate glsl; 54 | #[macro_use] extern crate glsl_quasiquote; 55 | ``` 56 | 57 | > *2018 edition* 58 | 59 | ```rust 60 | use glsl_quasiquote::glsl; 61 | ``` 62 | 63 | # Special warnings and considerations 64 | 65 | Because of the nature of the Rust tokenizer, dots (`.`) at the beginning of a token is not part 66 | of the token. For instance, `.3` is reinterpreted as `.` and `3` (two tokens). This will lead 67 | to incorrect parsing if you try to represent the number `0.3` with `.3`. While accepted by 68 | [glsl](https://crates.io/crates/glsl), this is not accepted by this crate. This limitation is 69 | due to how Rust tokenizes input in procedural macro and is very unlikely to change. 70 | 71 | [`TranslationUnit`]: https://docs.rs/glsl/1.0.0/glsl/syntax/struct.TranslationUnit.html 72 | 73 | 74 | -------------------------------------------------------------------------------- /glsl-quasiquote/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_span)] 2 | 3 | //! # GLSL quasiquoting. 4 | //! 5 | //! This crate exports a procedural macro: `glsl!`. It enables quasiquoting by allowing you to 6 | //! embed GLSL source code directly into rust via the syntax: 7 | //! 8 | //! ``` 9 | //! #![feature(proc_macro_hygiene)] 10 | //! 11 | //! use glsl::syntax::TranslationUnit; 12 | //! use glsl_quasiquote::glsl; 13 | //! 14 | //! let tu: TranslationUnit = glsl!{ 15 | //! // your GLSL code here 16 | //! void main() { 17 | //! } 18 | //! }; 19 | //! ``` 20 | //! 21 | //! The `glsl!` macro accepts the GLSL code directly. You can then write plain GLSL. Especially, 22 | //! since version **0.2**, the macro accepts plain GLSL pragmas (both `#version` and `#extension`). 23 | //! 24 | //! The `glsl!` procedural macro resolves at compile-time to [`TranslationUnit`], 25 | //! allowing you to manipulate the GLSL AST directly. Feel free to have a look at the 26 | //! [`glsl`](https://crates.io/crates/glsl) crate for further information. 27 | //! 28 | //! # Getting started 29 | //! 30 | //! Add the following to your dependencies in your `Cargo.toml`: 31 | //! 32 | //! ```toml 33 | //! glsl = "1" 34 | //! glsl-quasiquote = "1" 35 | //! ``` 36 | //! 37 | //! Then, you currently need to have a nightly compiler and the following feature enabled: 38 | //! 39 | //! ``` 40 | //! #![feature(proc_macro_hygiene)] 41 | //! ``` 42 | //! 43 | //! Then, depending on which you’re using the 2018 edition or not: 44 | //! 45 | //! > *Non-2018 edition* 46 | //! 47 | //! ``` 48 | //! extern crate glsl; 49 | //! #[macro_use] extern crate glsl_quasiquote; 50 | //! ``` 51 | //! 52 | //! > *2018 edition* 53 | //! 54 | //! ``` 55 | //! use glsl_quasiquote::glsl; 56 | //! ``` 57 | //! 58 | //! # Special warnings and considerations 59 | //! 60 | //! Because of the nature of the Rust tokenizer, dots (`.`) at the beginning of a token is not part 61 | //! of the token. For instance, `.3` is reinterpreted as `.` and `3` (two tokens). This will lead 62 | //! to incorrect parsing if you try to represent the number `0.3` with `.3`. While accepted by 63 | //! [glsl](https://crates.io/crates/glsl), this is not accepted by this crate. This limitation is 64 | //! due to how Rust tokenizes input in procedural macro and is very unlikely to change. 65 | //! 66 | //! [`TranslationUnit`]: https://docs.rs/glsl/1.0.0/glsl/syntax/struct.TranslationUnit.html 67 | 68 | extern crate proc_macro; 69 | 70 | use glsl::parser::Parse; 71 | use glsl::syntax; 72 | use proc_macro2::TokenStream; 73 | use proc_macro_faithful_display::faithful_display; 74 | 75 | use crate::tokenize::Tokenize; 76 | 77 | mod quoted; 78 | mod tokenize; 79 | 80 | /// Create a [`TranslationUnit`]. 81 | /// 82 | /// [`TranslationUnit`]: https://docs.rs/glsl/1.0.0/glsl/syntax/struct.TranslationUnit.html 83 | #[proc_macro] 84 | pub fn glsl(input: proc_macro::TokenStream) -> proc_macro::TokenStream { 85 | let s = format!("{}", faithful_display(&input)); 86 | let parsed: Result = Parse::parse(&s); 87 | 88 | if let Ok(tu) = parsed { 89 | // create the stream and return it 90 | let mut stream = TokenStream::new(); 91 | tu.tokenize(&mut stream); 92 | 93 | stream.into() 94 | } else { 95 | panic!("GLSL error: {:?}", parsed); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /glsl-quasiquote/src/quoted.rs: -------------------------------------------------------------------------------- 1 | //! A set of small traits that enable tokenizing some common types that get tokenizing erased 2 | //! normally, such as `Option` as `Some(_)` or `None`, `Box` as `Box::new(_)`, etc. 3 | 4 | use proc_macro2::TokenStream; 5 | use quote::{quote, ToTokens}; 6 | 7 | use glsl::syntax::{Identifier, TypeName}; 8 | 9 | // Quoted type. 10 | pub trait Quoted { 11 | fn quote(&self) -> TokenStream; 12 | } 13 | 14 | impl Quoted for String { 15 | fn quote(&self) -> TokenStream { 16 | quote! { #self.to_owned() } 17 | } 18 | } 19 | 20 | impl Quoted for Option 21 | where 22 | T: ToTokens, 23 | { 24 | fn quote(&self) -> TokenStream { 25 | if let Some(ref x) = *self { 26 | quote! { Some(#x) } 27 | } else { 28 | quote! { None } 29 | } 30 | } 31 | } 32 | 33 | impl Quoted for Box 34 | where 35 | T: ToTokens, 36 | { 37 | fn quote(&self) -> TokenStream { 38 | quote! { Box::new(#self) } 39 | } 40 | } 41 | 42 | impl Quoted for Identifier { 43 | fn quote(&self) -> TokenStream { 44 | let s = &self.0; 45 | quote! { glsl::syntax::Identifier(#s.to_owned()) } 46 | } 47 | } 48 | 49 | impl Quoted for TypeName { 50 | fn quote(&self) -> TokenStream { 51 | let s = &self.0; 52 | quote! { glsl::syntax::TypeName(#s.to_owned()) } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /glsl-quasiquote/src/tokenize.rs: -------------------------------------------------------------------------------- 1 | //! The [`Tokenize`] trait, turning [glsl](https://crates.io/crates/glsl) into [`TokenStream`]s. 2 | 3 | use glsl::syntax; 4 | use proc_macro2::TokenStream; 5 | use quote::{quote, ToTokens}; 6 | use std::iter::once; 7 | 8 | use crate::quoted::Quoted; 9 | 10 | /// Tokenize a value into a stream of tokens. 11 | pub trait Tokenize { 12 | /// Inject self into a [`TokenStream`]. 13 | fn tokenize(&self, stream: &mut TokenStream); 14 | } 15 | 16 | impl Tokenize for bool { 17 | fn tokenize(&self, stream: &mut TokenStream) { 18 | self.to_tokens(stream) 19 | } 20 | } 21 | 22 | impl Tokenize for i32 { 23 | fn tokenize(&self, stream: &mut TokenStream) { 24 | self.to_tokens(stream) 25 | } 26 | } 27 | 28 | impl Tokenize for u32 { 29 | fn tokenize(&self, stream: &mut TokenStream) { 30 | self.to_tokens(stream) 31 | } 32 | } 33 | 34 | impl Tokenize for f32 { 35 | fn tokenize(&self, stream: &mut TokenStream) { 36 | self.to_tokens(stream) 37 | } 38 | } 39 | 40 | impl Tokenize for f64 { 41 | fn tokenize(&self, stream: &mut TokenStream) { 42 | self.to_tokens(stream) 43 | } 44 | } 45 | 46 | macro_rules! impl_tokenize { 47 | ($type_name:ty, $tokenizer:ident) => { 48 | impl Tokenize for $type_name { 49 | fn tokenize(&self, stream: &mut TokenStream) { 50 | stream.extend(once($tokenizer(self))) 51 | } 52 | } 53 | }; 54 | } 55 | 56 | impl_tokenize!(syntax::Identifier, tokenize_identifier); 57 | impl_tokenize!(syntax::TypeName, tokenize_type_name); 58 | impl_tokenize!( 59 | syntax::TypeSpecifierNonArray, 60 | tokenize_type_specifier_non_array 61 | ); 62 | impl_tokenize!(syntax::TypeSpecifier, tokenize_type_specifier); 63 | impl_tokenize!(syntax::UnaryOp, tokenize_unary_op); 64 | impl_tokenize!(syntax::StructFieldSpecifier, tokenize_struct_field); 65 | impl_tokenize!(syntax::StructSpecifier, tokenize_struct_non_declaration); 66 | impl_tokenize!(syntax::StorageQualifier, tokenize_storage_qualifier); 67 | impl_tokenize!(syntax::LayoutQualifier, tokenize_layout_qualifier); 68 | impl_tokenize!(syntax::PrecisionQualifier, tokenize_precision_qualifier); 69 | impl_tokenize!( 70 | syntax::InterpolationQualifier, 71 | tokenize_interpolation_qualifier 72 | ); 73 | impl_tokenize!(syntax::TypeQualifier, tokenize_type_qualifier); 74 | impl_tokenize!(syntax::TypeQualifierSpec, tokenize_type_qualifier_spec); 75 | impl_tokenize!(syntax::FullySpecifiedType, tokenize_fully_specified_type); 76 | impl_tokenize!(syntax::ArraySpecifier, tokenize_array_spec); 77 | impl_tokenize!(syntax::Expr, tokenize_expr); 78 | impl_tokenize!(syntax::Declaration, tokenize_declaration); 79 | impl_tokenize!(syntax::FunctionPrototype, tokenize_function_prototype); 80 | impl_tokenize!(syntax::InitDeclaratorList, tokenize_init_declarator_list); 81 | impl_tokenize!(syntax::SingleDeclaration, tokenize_single_declaration); 82 | impl_tokenize!(syntax::Initializer, tokenize_initializer); 83 | impl_tokenize!(syntax::FunIdentifier, tokenize_function_identifier); 84 | impl_tokenize!(syntax::AssignmentOp, tokenize_assignment_op); 85 | impl_tokenize!(syntax::SimpleStatement, tokenize_simple_statement); 86 | impl_tokenize!(syntax::ExprStatement, tokenize_expr_statement); 87 | impl_tokenize!(syntax::SelectionStatement, tokenize_selection_statement); 88 | impl_tokenize!(syntax::SwitchStatement, tokenize_switch_statement); 89 | impl_tokenize!(syntax::CaseLabel, tokenize_case_label); 90 | impl_tokenize!(syntax::IterationStatement, tokenize_iteration_statement); 91 | impl_tokenize!(syntax::JumpStatement, tokenize_jump_statement); 92 | impl_tokenize!(syntax::Condition, tokenize_condition); 93 | impl_tokenize!(syntax::Statement, tokenize_statement); 94 | impl_tokenize!(syntax::CompoundStatement, tokenize_compound_statement); 95 | impl_tokenize!(syntax::FunctionDefinition, tokenize_function_definition); 96 | impl_tokenize!(syntax::ExternalDeclaration, tokenize_external_declaration); 97 | impl_tokenize!(syntax::TranslationUnit, tokenize_translation_unit); 98 | impl_tokenize!(syntax::Preprocessor, tokenize_preprocessor); 99 | impl_tokenize!(syntax::PreprocessorDefine, tokenize_preprocessor_define); 100 | impl_tokenize!(syntax::PreprocessorElIf, tokenize_preprocessor_elif); 101 | impl_tokenize!(syntax::PreprocessorError, tokenize_preprocessor_error); 102 | impl_tokenize!(syntax::PreprocessorIf, tokenize_preprocessor_if); 103 | impl_tokenize!(syntax::PreprocessorIfDef, tokenize_preprocessor_ifdef); 104 | impl_tokenize!(syntax::PreprocessorIfNDef, tokenize_preprocessor_ifndef); 105 | impl_tokenize!(syntax::PreprocessorInclude, tokenize_preprocessor_include); 106 | impl_tokenize!(syntax::PreprocessorLine, tokenize_preprocessor_line); 107 | impl_tokenize!(syntax::PreprocessorPragma, tokenize_preprocessor_pragma); 108 | impl_tokenize!(syntax::PreprocessorUndef, tokenize_preprocessor_undef); 109 | impl_tokenize!(syntax::PreprocessorVersion, tokenize_preprocessor_version); 110 | impl_tokenize!( 111 | syntax::PreprocessorVersionProfile, 112 | tokenize_preprocessor_version_profile 113 | ); 114 | impl_tokenize!( 115 | syntax::PreprocessorExtensionName, 116 | tokenize_preprocessor_extension_name 117 | ); 118 | impl_tokenize!( 119 | syntax::PreprocessorExtensionBehavior, 120 | tokenize_preprocessor_extension_behavior 121 | ); 122 | impl_tokenize!( 123 | syntax::PreprocessorExtension, 124 | tokenize_preprocessor_extension 125 | ); 126 | 127 | fn tokenize_identifier(i: &syntax::Identifier) -> TokenStream { 128 | let i = i.quote(); 129 | quote! { #i } 130 | } 131 | 132 | fn tokenize_path(p: &syntax::Path) -> TokenStream { 133 | match p { 134 | syntax::Path::Absolute(s) => quote! { glsl::syntax::Path::Absolute(#s.to_owned()) }, 135 | syntax::Path::Relative(s) => quote! { glsl::syntax::Path::Relative(#s.to_owned()) }, 136 | } 137 | } 138 | 139 | fn tokenize_type_name(tn: &syntax::TypeName) -> TokenStream { 140 | let tn = tn.quote(); 141 | quote! { #tn } 142 | } 143 | 144 | fn tokenize_type_specifier_non_array(t: &syntax::TypeSpecifierNonArray) -> TokenStream { 145 | match *t { 146 | syntax::TypeSpecifierNonArray::Void => quote! { glsl::syntax::TypeSpecifierNonArray::Void }, 147 | syntax::TypeSpecifierNonArray::Bool => quote! { glsl::syntax::TypeSpecifierNonArray::Bool }, 148 | syntax::TypeSpecifierNonArray::Int => quote! { glsl::syntax::TypeSpecifierNonArray::Int }, 149 | syntax::TypeSpecifierNonArray::UInt => quote! { glsl::syntax::TypeSpecifierNonArray::UInt }, 150 | syntax::TypeSpecifierNonArray::Float => quote! { glsl::syntax::TypeSpecifierNonArray::Float }, 151 | syntax::TypeSpecifierNonArray::Double => quote! { glsl::syntax::TypeSpecifierNonArray::Double }, 152 | syntax::TypeSpecifierNonArray::Vec2 => quote! { glsl::syntax::TypeSpecifierNonArray::Vec2 }, 153 | syntax::TypeSpecifierNonArray::Vec3 => quote! { glsl::syntax::TypeSpecifierNonArray::Vec3 }, 154 | syntax::TypeSpecifierNonArray::Vec4 => quote! { glsl::syntax::TypeSpecifierNonArray::Vec4 }, 155 | syntax::TypeSpecifierNonArray::DVec2 => quote! { glsl::syntax::TypeSpecifierNonArray::DVec2 }, 156 | syntax::TypeSpecifierNonArray::DVec3 => quote! { glsl::syntax::TypeSpecifierNonArray::DVec3 }, 157 | syntax::TypeSpecifierNonArray::DVec4 => quote! { glsl::syntax::TypeSpecifierNonArray::DVec4 }, 158 | syntax::TypeSpecifierNonArray::BVec2 => quote! { glsl::syntax::TypeSpecifierNonArray::BVec2 }, 159 | syntax::TypeSpecifierNonArray::BVec3 => quote! { glsl::syntax::TypeSpecifierNonArray::BVec3 }, 160 | syntax::TypeSpecifierNonArray::BVec4 => quote! { glsl::syntax::TypeSpecifierNonArray::BVec4 }, 161 | syntax::TypeSpecifierNonArray::IVec2 => quote! { glsl::syntax::TypeSpecifierNonArray::IVec2 }, 162 | syntax::TypeSpecifierNonArray::IVec3 => quote! { glsl::syntax::TypeSpecifierNonArray::IVec3 }, 163 | syntax::TypeSpecifierNonArray::IVec4 => quote! { glsl::syntax::TypeSpecifierNonArray::IVec4 }, 164 | syntax::TypeSpecifierNonArray::UVec2 => quote! { glsl::syntax::TypeSpecifierNonArray::UVec2 }, 165 | syntax::TypeSpecifierNonArray::UVec3 => quote! { glsl::syntax::TypeSpecifierNonArray::UVec3 }, 166 | syntax::TypeSpecifierNonArray::UVec4 => quote! { glsl::syntax::TypeSpecifierNonArray::UVec4 }, 167 | syntax::TypeSpecifierNonArray::Mat2 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat2 }, 168 | syntax::TypeSpecifierNonArray::Mat3 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat3 }, 169 | syntax::TypeSpecifierNonArray::Mat4 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat4 }, 170 | syntax::TypeSpecifierNonArray::Mat23 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat23 }, 171 | syntax::TypeSpecifierNonArray::Mat24 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat24 }, 172 | syntax::TypeSpecifierNonArray::Mat32 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat32 }, 173 | syntax::TypeSpecifierNonArray::Mat34 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat34 }, 174 | syntax::TypeSpecifierNonArray::Mat42 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat42 }, 175 | syntax::TypeSpecifierNonArray::Mat43 => quote! { glsl::syntax::TypeSpecifierNonArray::Mat43 }, 176 | syntax::TypeSpecifierNonArray::DMat2 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat2 }, 177 | syntax::TypeSpecifierNonArray::DMat3 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat3 }, 178 | syntax::TypeSpecifierNonArray::DMat4 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat4 }, 179 | syntax::TypeSpecifierNonArray::DMat23 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat23 }, 180 | syntax::TypeSpecifierNonArray::DMat24 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat24 }, 181 | syntax::TypeSpecifierNonArray::DMat32 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat32 }, 182 | syntax::TypeSpecifierNonArray::DMat34 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat34 }, 183 | syntax::TypeSpecifierNonArray::DMat42 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat42 }, 184 | syntax::TypeSpecifierNonArray::DMat43 => quote! { glsl::syntax::TypeSpecifierNonArray::DMat43 }, 185 | syntax::TypeSpecifierNonArray::Sampler1D => { 186 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler1D } 187 | } 188 | syntax::TypeSpecifierNonArray::Image1D => { 189 | quote! { glsl::syntax::TypeSpecifierNonArray::Image1D } 190 | } 191 | syntax::TypeSpecifierNonArray::Sampler2D => { 192 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2D } 193 | } 194 | syntax::TypeSpecifierNonArray::Image2D => { 195 | quote! { glsl::syntax::TypeSpecifierNonArray::Image2D } 196 | } 197 | syntax::TypeSpecifierNonArray::Sampler3D => { 198 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler3D } 199 | } 200 | syntax::TypeSpecifierNonArray::Image3D => { 201 | quote! { glsl::syntax::TypeSpecifierNonArray::Image3D } 202 | } 203 | syntax::TypeSpecifierNonArray::SamplerCube => { 204 | quote! { glsl::syntax::TypeSpecifierNonArray::SamplerCube } 205 | } 206 | syntax::TypeSpecifierNonArray::ImageCube => { 207 | quote! { glsl::syntax::TypeSpecifierNonArray::ImageCube } 208 | } 209 | syntax::TypeSpecifierNonArray::Sampler2DRect => { 210 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DRect } 211 | } 212 | syntax::TypeSpecifierNonArray::Image2DRect => { 213 | quote! { glsl::syntax::TypeSpecifierNonArray::Image2DRect } 214 | } 215 | syntax::TypeSpecifierNonArray::Sampler1DArray => { 216 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler1DArray } 217 | } 218 | syntax::TypeSpecifierNonArray::Image1DArray => { 219 | quote! { glsl::syntax::TypeSpecifierNonArray::Image1DArray } 220 | } 221 | syntax::TypeSpecifierNonArray::Sampler2DArray => { 222 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DArray } 223 | } 224 | syntax::TypeSpecifierNonArray::Image2DArray => { 225 | quote! { glsl::syntax::TypeSpecifierNonArray::Image2DArray } 226 | } 227 | syntax::TypeSpecifierNonArray::SamplerBuffer => { 228 | quote! { glsl::syntax::TypeSpecifierNonArray::SamplerBuffer } 229 | } 230 | syntax::TypeSpecifierNonArray::ImageBuffer => { 231 | quote! { glsl::syntax::TypeSpecifierNonArray::ImageBuffer } 232 | } 233 | syntax::TypeSpecifierNonArray::Sampler2DMS => { 234 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DMS } 235 | } 236 | syntax::TypeSpecifierNonArray::Image2DMS => { 237 | quote! { glsl::syntax::TypeSpecifierNonArray::Image2DMS } 238 | } 239 | syntax::TypeSpecifierNonArray::Sampler2DMSArray => { 240 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DMSArray } 241 | } 242 | syntax::TypeSpecifierNonArray::Image2DMSArray => { 243 | quote! { glsl::syntax::TypeSpecifierNonArray::Image2DMSArray } 244 | } 245 | syntax::TypeSpecifierNonArray::SamplerCubeArray => { 246 | quote! { glsl::syntax::TypeSpecifierNonArray::SamplerCubeArray } 247 | } 248 | syntax::TypeSpecifierNonArray::ImageCubeArray => { 249 | quote! { glsl::syntax::TypeSpecifierNonArray::ImageCubeArray } 250 | } 251 | syntax::TypeSpecifierNonArray::Sampler1DShadow => { 252 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler1DShadow } 253 | } 254 | syntax::TypeSpecifierNonArray::Sampler2DShadow => { 255 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DShadow } 256 | } 257 | syntax::TypeSpecifierNonArray::Sampler2DRectShadow => { 258 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DRectShadow } 259 | } 260 | syntax::TypeSpecifierNonArray::Sampler1DArrayShadow => { 261 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler1DArrayShadow } 262 | } 263 | syntax::TypeSpecifierNonArray::Sampler2DArrayShadow => { 264 | quote! { glsl::syntax::TypeSpecifierNonArray::Sampler2DArrayShadow } 265 | } 266 | syntax::TypeSpecifierNonArray::SamplerCubeShadow => { 267 | quote! { glsl::syntax::TypeSpecifierNonArray::SamplerCubeShadow } 268 | } 269 | syntax::TypeSpecifierNonArray::SamplerCubeArrayShadow => { 270 | quote! { glsl::syntax::TypeSpecifierNonArray::SamplerCubeArrayShadow } 271 | } 272 | syntax::TypeSpecifierNonArray::ISampler1D => { 273 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler1D } 274 | } 275 | syntax::TypeSpecifierNonArray::IImage1D => { 276 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage1D } 277 | } 278 | syntax::TypeSpecifierNonArray::ISampler2D => { 279 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler2D } 280 | } 281 | syntax::TypeSpecifierNonArray::IImage2D => { 282 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage2D } 283 | } 284 | syntax::TypeSpecifierNonArray::ISampler3D => { 285 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler3D } 286 | } 287 | syntax::TypeSpecifierNonArray::IImage3D => { 288 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage3D } 289 | } 290 | syntax::TypeSpecifierNonArray::ISamplerCube => { 291 | quote! { glsl::syntax::TypeSpecifierNonArray::ISamplerCube } 292 | } 293 | syntax::TypeSpecifierNonArray::IImageCube => { 294 | quote! { glsl::syntax::TypeSpecifierNonArray::IImageCube } 295 | } 296 | syntax::TypeSpecifierNonArray::ISampler2DRect => { 297 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler2DRect } 298 | } 299 | syntax::TypeSpecifierNonArray::IImage2DRect => { 300 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage2DRect } 301 | } 302 | syntax::TypeSpecifierNonArray::ISampler1DArray => { 303 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler1DArray } 304 | } 305 | syntax::TypeSpecifierNonArray::IImage1DArray => { 306 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage1DArray } 307 | } 308 | syntax::TypeSpecifierNonArray::ISampler2DArray => { 309 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler2DArray } 310 | } 311 | syntax::TypeSpecifierNonArray::IImage2DArray => { 312 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage2DArray } 313 | } 314 | syntax::TypeSpecifierNonArray::ISamplerBuffer => { 315 | quote! { glsl::syntax::TypeSpecifierNonArray::ISamplerBuffer } 316 | } 317 | syntax::TypeSpecifierNonArray::IImageBuffer => { 318 | quote! { glsl::syntax::TypeSpecifierNonArray::IImageBuffer } 319 | } 320 | syntax::TypeSpecifierNonArray::ISampler2DMS => { 321 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler2DMS } 322 | } 323 | syntax::TypeSpecifierNonArray::IImage2DMS => { 324 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage2DMS } 325 | } 326 | syntax::TypeSpecifierNonArray::ISampler2DMSArray => { 327 | quote! { glsl::syntax::TypeSpecifierNonArray::ISampler2DMSArray } 328 | } 329 | syntax::TypeSpecifierNonArray::IImage2DMSArray => { 330 | quote! { glsl::syntax::TypeSpecifierNonArray::IImage2DMSArray } 331 | } 332 | syntax::TypeSpecifierNonArray::ISamplerCubeArray => { 333 | quote! { glsl::syntax::TypeSpecifierNonArray::ISamplerCubeArray } 334 | } 335 | syntax::TypeSpecifierNonArray::IImageCubeArray => { 336 | quote! { glsl::syntax::TypeSpecifierNonArray::IImageCubeArray } 337 | } 338 | syntax::TypeSpecifierNonArray::AtomicUInt => { 339 | quote! { glsl::syntax::TypeSpecifierNonArray::AtomicUInt } 340 | } 341 | syntax::TypeSpecifierNonArray::USampler1D => { 342 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler1D } 343 | } 344 | syntax::TypeSpecifierNonArray::UImage1D => { 345 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage1D } 346 | } 347 | syntax::TypeSpecifierNonArray::USampler2D => { 348 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler2D } 349 | } 350 | syntax::TypeSpecifierNonArray::UImage2D => { 351 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage2D } 352 | } 353 | syntax::TypeSpecifierNonArray::USampler3D => { 354 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler3D } 355 | } 356 | syntax::TypeSpecifierNonArray::UImage3D => { 357 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage3D } 358 | } 359 | syntax::TypeSpecifierNonArray::USamplerCube => { 360 | quote! { glsl::syntax::TypeSpecifierNonArray::USamplerCube } 361 | } 362 | syntax::TypeSpecifierNonArray::UImageCube => { 363 | quote! { glsl::syntax::TypeSpecifierNonArray::UImageCube } 364 | } 365 | syntax::TypeSpecifierNonArray::USampler2DRect => { 366 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler2DRect } 367 | } 368 | syntax::TypeSpecifierNonArray::UImage2DRect => { 369 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage2DRect } 370 | } 371 | syntax::TypeSpecifierNonArray::USampler1DArray => { 372 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler1DArray } 373 | } 374 | syntax::TypeSpecifierNonArray::UImage1DArray => { 375 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage1DArray } 376 | } 377 | syntax::TypeSpecifierNonArray::USampler2DArray => { 378 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler2DArray } 379 | } 380 | syntax::TypeSpecifierNonArray::UImage2DArray => { 381 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage2DArray } 382 | } 383 | syntax::TypeSpecifierNonArray::USamplerBuffer => { 384 | quote! { glsl::syntax::TypeSpecifierNonArray::USamplerBuffer } 385 | } 386 | syntax::TypeSpecifierNonArray::UImageBuffer => { 387 | quote! { glsl::syntax::TypeSpecifierNonArray::UImageBuffer } 388 | } 389 | syntax::TypeSpecifierNonArray::USampler2DMS => { 390 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler2DMS } 391 | } 392 | syntax::TypeSpecifierNonArray::UImage2DMS => { 393 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage2DMS } 394 | } 395 | syntax::TypeSpecifierNonArray::USampler2DMSArray => { 396 | quote! { glsl::syntax::TypeSpecifierNonArray::USampler2DMSArray } 397 | } 398 | syntax::TypeSpecifierNonArray::UImage2DMSArray => { 399 | quote! { glsl::syntax::TypeSpecifierNonArray::UImage2DMSArray } 400 | } 401 | syntax::TypeSpecifierNonArray::USamplerCubeArray => { 402 | quote! { glsl::syntax::TypeSpecifierNonArray::USamplerCubeArray } 403 | } 404 | syntax::TypeSpecifierNonArray::UImageCubeArray => { 405 | quote! { glsl::syntax::TypeSpecifierNonArray::UImageCubeArray } 406 | } 407 | 408 | syntax::TypeSpecifierNonArray::Struct(ref s) => { 409 | let s = tokenize_struct_non_declaration(s); 410 | quote! { glsl::syntax::TypeSpecifierNonArray::Struct(#s) } 411 | } 412 | 413 | syntax::TypeSpecifierNonArray::TypeName(ref tn) => { 414 | let tn = tn.quote(); 415 | 416 | quote! { glsl::syntax::TypeSpecifierNonArray::TypeName(#tn) } 417 | } 418 | } 419 | } 420 | 421 | fn tokenize_type_specifier(t: &syntax::TypeSpecifier) -> TokenStream { 422 | let ty = tokenize_type_specifier_non_array(&t.ty); 423 | let array_specifier = t.array_specifier.as_ref().map(tokenize_array_spec).quote(); 424 | 425 | quote! { 426 | glsl::syntax::TypeSpecifier { 427 | ty: #ty, 428 | array_specifier: #array_specifier 429 | } 430 | } 431 | } 432 | 433 | fn tokenize_fully_specified_type(t: &syntax::FullySpecifiedType) -> TokenStream { 434 | let qual = t.qualifier.as_ref().map(tokenize_type_qualifier).quote(); 435 | let ty = tokenize_type_specifier(&t.ty); 436 | 437 | quote! { 438 | glsl::syntax::FullySpecifiedType { 439 | qualifier: #qual, 440 | ty: #ty 441 | } 442 | } 443 | } 444 | 445 | fn tokenize_struct_non_declaration(s: &syntax::StructSpecifier) -> TokenStream { 446 | let name = s.name.as_ref().map(|n| n.quote()); 447 | let fields = s.fields.0.iter().map(tokenize_struct_field); 448 | 449 | quote! { 450 | glsl::syntax::StructSpecifier { 451 | name: Some(#name), 452 | fields: glsl::syntax::NonEmpty(vec![#(#fields),*]) 453 | } 454 | } 455 | } 456 | 457 | fn tokenize_struct_field(field: &syntax::StructFieldSpecifier) -> TokenStream { 458 | let qual = field 459 | .qualifier 460 | .as_ref() 461 | .map(tokenize_type_qualifier) 462 | .quote(); 463 | let ty = tokenize_type_specifier(&field.ty); 464 | let identifiers = field.identifiers.0.iter().map(tokenize_arrayed_identifier); 465 | 466 | quote! { 467 | glsl::syntax::StructFieldSpecifier { 468 | qualifier: #qual, 469 | ty: #ty, 470 | identifiers: glsl::syntax::NonEmpty(vec![#(#identifiers),*]) 471 | } 472 | } 473 | } 474 | 475 | fn tokenize_array_spec(a: &syntax::ArraySpecifier) -> TokenStream { 476 | let dimensions = a.dimensions.0.iter().map(tokenize_array_spec_dim); 477 | 478 | quote! { 479 | glsl::syntax::ArraySpecifier { dimensions: glsl::syntax::NonEmpty(vec![#(#dimensions),*]) } 480 | } 481 | } 482 | 483 | fn tokenize_array_spec_dim(a: &syntax::ArraySpecifierDimension) -> TokenStream { 484 | match *a { 485 | syntax::ArraySpecifierDimension::Unsized => { 486 | quote! { glsl::syntax::ArraySpecifierDimension::Unsized } 487 | } 488 | syntax::ArraySpecifierDimension::ExplicitlySized(ref e) => { 489 | let expr = Box::new(tokenize_expr(&e)).quote(); 490 | quote! { glsl::syntax::ArraySpecifierDimension::ExplicitlySized(#expr) } 491 | } 492 | } 493 | } 494 | 495 | fn tokenize_arrayed_identifier(identifier: &syntax::ArrayedIdentifier) -> TokenStream { 496 | let ident = identifier.ident.quote(); 497 | let array_spec = identifier 498 | .array_spec 499 | .as_ref() 500 | .map(tokenize_array_spec) 501 | .quote(); 502 | 503 | quote! { 504 | glsl::syntax::ArrayedIdentifier::new(#ident, #array_spec) 505 | } 506 | } 507 | 508 | fn tokenize_type_qualifier(q: &syntax::TypeQualifier) -> TokenStream { 509 | let quals = q.qualifiers.0.iter().map(tokenize_type_qualifier_spec); 510 | 511 | quote! { 512 | glsl::syntax::TypeQualifier { 513 | qualifiers: glsl::syntax::NonEmpty(vec![#(#quals),*]) 514 | } 515 | } 516 | } 517 | 518 | fn tokenize_type_qualifier_spec(q: &syntax::TypeQualifierSpec) -> TokenStream { 519 | match *q { 520 | syntax::TypeQualifierSpec::Storage(ref s) => { 521 | let s = tokenize_storage_qualifier(s); 522 | quote! { glsl::syntax::TypeQualifierSpec::Storage(#s) } 523 | } 524 | 525 | syntax::TypeQualifierSpec::Layout(ref l) => { 526 | let l = tokenize_layout_qualifier(l); 527 | quote! { glsl::syntax::TypeQualifierSpec::Layout(#l) } 528 | } 529 | 530 | syntax::TypeQualifierSpec::Precision(ref p) => { 531 | let p = tokenize_precision_qualifier(p); 532 | quote! { glsl::syntax::TypeQualifierSpec::Precision(#p) } 533 | } 534 | 535 | syntax::TypeQualifierSpec::Interpolation(ref i) => { 536 | let i = tokenize_interpolation_qualifier(i); 537 | quote! { glsl::syntax::TypeQualifierSpec::Interpolation(#i) } 538 | } 539 | 540 | syntax::TypeQualifierSpec::Invariant => quote! { glsl::syntax::TypeQualifierSpec::Invariant }, 541 | 542 | syntax::TypeQualifierSpec::Precise => quote! { glsl::syntax::TypeQualifierSpec::Precise }, 543 | } 544 | } 545 | 546 | fn tokenize_storage_qualifier(q: &syntax::StorageQualifier) -> TokenStream { 547 | match *q { 548 | syntax::StorageQualifier::Const => quote! { glsl::syntax::StorageQualifier::Const }, 549 | syntax::StorageQualifier::InOut => quote! { glsl::syntax::StorageQualifier::InOut }, 550 | syntax::StorageQualifier::In => quote! { glsl::syntax::StorageQualifier::In }, 551 | syntax::StorageQualifier::Out => quote! { glsl::syntax::StorageQualifier::Out }, 552 | syntax::StorageQualifier::Centroid => quote! { glsl::syntax::StorageQualifier::Centroid }, 553 | syntax::StorageQualifier::Patch => quote! { glsl::syntax::StorageQualifier::Patch }, 554 | syntax::StorageQualifier::Sample => quote! { glsl::syntax::StorageQualifier::Sample }, 555 | syntax::StorageQualifier::Uniform => quote! { glsl::syntax::StorageQualifier::Uniform }, 556 | syntax::StorageQualifier::Attribute => quote! { glsl::syntax::StorageQualifier::Attribute }, 557 | syntax::StorageQualifier::Varying => quote! { glsl::syntax::StorageQualifier::Varying }, 558 | syntax::StorageQualifier::Buffer => quote! { glsl::syntax::StorageQualifier::Buffer }, 559 | syntax::StorageQualifier::Shared => quote! { glsl::syntax::StorageQualifier::Shared }, 560 | syntax::StorageQualifier::Coherent => quote! { glsl::syntax::StorageQualifier::Coherent }, 561 | syntax::StorageQualifier::Volatile => quote! { glsl::syntax::StorageQualifier::Volatile }, 562 | syntax::StorageQualifier::Restrict => quote! { glsl::syntax::StorageQualifier::Restrict }, 563 | syntax::StorageQualifier::ReadOnly => quote! { glsl::syntax::StorageQualifier::ReadOnly }, 564 | syntax::StorageQualifier::WriteOnly => quote! { glsl::syntax::StorageQualifier::WriteOnly }, 565 | 566 | syntax::StorageQualifier::Subroutine(ref n) => { 567 | let n = n.iter().map(|t| t.quote()); 568 | 569 | quote! { 570 | StorageQualifier::Subroutine(vec![#(#n),*]) 571 | } 572 | } 573 | } 574 | } 575 | 576 | fn tokenize_layout_qualifier(l: &syntax::LayoutQualifier) -> TokenStream { 577 | let ids = l.ids.0.iter().map(tokenize_layout_qualifier_spec); 578 | 579 | quote! { 580 | glsl::syntax::LayoutQualifier { 581 | ids: glsl::syntax::NonEmpty(vec![#(#ids),*]) 582 | } 583 | } 584 | } 585 | 586 | fn tokenize_layout_qualifier_spec(l: &syntax::LayoutQualifierSpec) -> TokenStream { 587 | match *l { 588 | syntax::LayoutQualifierSpec::Identifier(ref i, ref e) => { 589 | let i = i.quote(); 590 | let expr = e 591 | .as_ref() 592 | .map(|e| Box::new(tokenize_expr(&e)).quote()) 593 | .quote(); 594 | quote! { glsl::syntax::LayoutQualifierSpec::Identifier(#i, #expr) } 595 | } 596 | 597 | syntax::LayoutQualifierSpec::Shared => quote! { glsl::syntax::LayoutQualifierSpec::Shared }, 598 | } 599 | } 600 | 601 | fn tokenize_precision_qualifier(p: &syntax::PrecisionQualifier) -> TokenStream { 602 | match *p { 603 | syntax::PrecisionQualifier::High => quote! { glsl::syntax::PrecisionQualifier::High }, 604 | syntax::PrecisionQualifier::Medium => quote! { glsl::syntax::PrecisionQualifier::Medium }, 605 | syntax::PrecisionQualifier::Low => quote! { glsl::syntax::PrecisionQualifier::Low }, 606 | } 607 | } 608 | 609 | fn tokenize_interpolation_qualifier(i: &syntax::InterpolationQualifier) -> TokenStream { 610 | match *i { 611 | syntax::InterpolationQualifier::Smooth => { 612 | quote! { glsl::syntax::InterpolationQualifier::Smooth } 613 | } 614 | syntax::InterpolationQualifier::Flat => quote! { glsl::syntax::InterpolationQualifier::Flat }, 615 | syntax::InterpolationQualifier::NoPerspective => { 616 | quote! { glsl::syntax::InterpolationQualifier::NoPerspective } 617 | } 618 | } 619 | } 620 | 621 | fn tokenize_expr(expr: &syntax::Expr) -> TokenStream { 622 | match *expr { 623 | syntax::Expr::Variable(ref i) => { 624 | let i = i.quote(); 625 | quote! { glsl::syntax::Expr::Variable(#i) } 626 | } 627 | 628 | syntax::Expr::IntConst(ref x) => quote! { glsl::syntax::Expr::IntConst(#x) }, 629 | 630 | syntax::Expr::UIntConst(ref x) => quote! { glsl::syntax::Expr::UIntConst(#x) }, 631 | 632 | syntax::Expr::BoolConst(ref x) => quote! { glsl::syntax::Expr::BoolConst(#x) }, 633 | 634 | syntax::Expr::FloatConst(ref x) => quote! { glsl::syntax::Expr::FloatConst(#x) }, 635 | 636 | syntax::Expr::DoubleConst(ref x) => quote! { glsl::syntax::Expr::DoubleConst(#x) }, 637 | 638 | syntax::Expr::Unary(ref op, ref e) => { 639 | let op = tokenize_unary_op(op); 640 | let e = Box::new(tokenize_expr(e)).quote(); 641 | quote! { glsl::syntax::Expr::Unary(#op, #e) } 642 | } 643 | 644 | syntax::Expr::Binary(ref op, ref l, ref r) => { 645 | let op = tokenize_binary_op(op); 646 | let l = Box::new(tokenize_expr(l)).quote(); 647 | let r = Box::new(tokenize_expr(r)).quote(); 648 | quote! { glsl::syntax::Expr::Binary(#op, #l, #r) } 649 | } 650 | 651 | syntax::Expr::Ternary(ref c, ref s, ref e) => { 652 | let c = Box::new(tokenize_expr(c)).quote(); 653 | let s = Box::new(tokenize_expr(s)).quote(); 654 | let e = Box::new(tokenize_expr(e)).quote(); 655 | quote! { glsl::syntax::Expr::Ternary(#c, #s, #e) } 656 | } 657 | 658 | syntax::Expr::Assignment(ref v, ref op, ref e) => { 659 | let v = Box::new(tokenize_expr(v)).quote(); 660 | let op = tokenize_assignment_op(op); 661 | let e = Box::new(tokenize_expr(e)).quote(); 662 | quote! { glsl::syntax::Expr::Assignment(#v, #op, #e) } 663 | } 664 | 665 | syntax::Expr::Bracket(ref e, ref a) => { 666 | let e = Box::new(tokenize_expr(e)).quote(); 667 | let a = tokenize_array_spec(a); 668 | quote! { glsl::syntax::Expr::Bracket(#e, #a) } 669 | } 670 | 671 | syntax::Expr::FunCall(ref fun, ref args) => { 672 | let fun = tokenize_function_identifier(fun); 673 | let args = args.iter().map(tokenize_expr); 674 | quote! { glsl::syntax::Expr::FunCall(#fun, vec![#(#args),*]) } 675 | } 676 | 677 | syntax::Expr::Dot(ref e, ref i) => { 678 | let e = Box::new(tokenize_expr(e)).quote(); 679 | let i = i.quote(); 680 | 681 | quote! { glsl::syntax::Expr::Dot(#e, #i) } 682 | } 683 | 684 | syntax::Expr::PostInc(ref e) => { 685 | let e = Box::new(tokenize_expr(e)).quote(); 686 | quote! { glsl::syntax::Expr::PostInc(#e) } 687 | } 688 | 689 | syntax::Expr::PostDec(ref e) => { 690 | let e = Box::new(tokenize_expr(e)).quote(); 691 | quote! { glsl::syntax::Expr::PostDec(#e) } 692 | } 693 | 694 | syntax::Expr::Comma(ref a, ref b) => { 695 | let a = Box::new(tokenize_expr(a)).quote(); 696 | let b = Box::new(tokenize_expr(b)).quote(); 697 | quote! { glsl::syntax::Expr::Comma(#a, #b) } 698 | } 699 | } 700 | } 701 | 702 | fn tokenize_unary_op(op: &syntax::UnaryOp) -> TokenStream { 703 | match *op { 704 | syntax::UnaryOp::Inc => quote! { glsl::syntax::UnaryOp::Inc }, 705 | syntax::UnaryOp::Dec => quote! { glsl::syntax::UnaryOp::Dec }, 706 | syntax::UnaryOp::Add => quote! { glsl::syntax::UnaryOp::Add }, 707 | syntax::UnaryOp::Minus => quote! { glsl::syntax::UnaryOp::Minus }, 708 | syntax::UnaryOp::Not => quote! { glsl::syntax::UnaryOp::Not }, 709 | syntax::UnaryOp::Complement => quote! { glsl::syntax::UnaryOp::Complement }, 710 | } 711 | } 712 | 713 | fn tokenize_binary_op(op: &syntax::BinaryOp) -> TokenStream { 714 | match *op { 715 | syntax::BinaryOp::Or => quote! { glsl::syntax::BinaryOp::Or }, 716 | syntax::BinaryOp::Xor => quote! { glsl::syntax::BinaryOp::Xor }, 717 | syntax::BinaryOp::And => quote! { glsl::syntax::BinaryOp::And }, 718 | syntax::BinaryOp::BitOr => quote! { glsl::syntax::BinaryOp::BitOr }, 719 | syntax::BinaryOp::BitXor => quote! { glsl::syntax::BinaryOp::BitXor }, 720 | syntax::BinaryOp::BitAnd => quote! { glsl::syntax::BinaryOp::BitAnd }, 721 | syntax::BinaryOp::Equal => quote! { glsl::syntax::BinaryOp::Equal }, 722 | syntax::BinaryOp::NonEqual => quote! { glsl::syntax::BinaryOp::NonEqual }, 723 | syntax::BinaryOp::LT => quote! { glsl::syntax::BinaryOp::LT }, 724 | syntax::BinaryOp::GT => quote! { glsl::syntax::BinaryOp::GT }, 725 | syntax::BinaryOp::LTE => quote! { glsl::syntax::BinaryOp::LTE }, 726 | syntax::BinaryOp::GTE => quote! { glsl::syntax::BinaryOp::GTE }, 727 | syntax::BinaryOp::LShift => quote! { glsl::syntax::BinaryOp::LShift }, 728 | syntax::BinaryOp::RShift => quote! { glsl::syntax::BinaryOp::RShift }, 729 | syntax::BinaryOp::Add => quote! { glsl::syntax::BinaryOp::Add }, 730 | syntax::BinaryOp::Sub => quote! { glsl::syntax::BinaryOp::Sub }, 731 | syntax::BinaryOp::Mult => quote! { glsl::syntax::BinaryOp::Mult }, 732 | syntax::BinaryOp::Div => quote! { glsl::syntax::BinaryOp::Div }, 733 | syntax::BinaryOp::Mod => quote! { glsl::syntax::BinaryOp::Mod }, 734 | } 735 | } 736 | 737 | fn tokenize_assignment_op(op: &syntax::AssignmentOp) -> TokenStream { 738 | match *op { 739 | syntax::AssignmentOp::Equal => quote! { glsl::syntax::AssignmentOp::Equal }, 740 | syntax::AssignmentOp::Mult => quote! { glsl::syntax::AssignmentOp::Mult }, 741 | syntax::AssignmentOp::Div => quote! { glsl::syntax::AssignmentOp::Div }, 742 | syntax::AssignmentOp::Mod => quote! { glsl::syntax::AssignmentOp::Mod }, 743 | syntax::AssignmentOp::Add => quote! { glsl::syntax::AssignmentOp::Add }, 744 | syntax::AssignmentOp::Sub => quote! { glsl::syntax::AssignmentOp::Sub }, 745 | syntax::AssignmentOp::LShift => quote! { glsl::syntax::AssignmentOp::LShift }, 746 | syntax::AssignmentOp::RShift => quote! { glsl::syntax::AssignmentOp::RShift }, 747 | syntax::AssignmentOp::And => quote! { glsl::syntax::AssignmentOp::And }, 748 | syntax::AssignmentOp::Xor => quote! { glsl::syntax::AssignmentOp::Xor }, 749 | syntax::AssignmentOp::Or => quote! { AssignmentOp::Or }, 750 | } 751 | } 752 | 753 | fn tokenize_function_identifier(i: &syntax::FunIdentifier) -> TokenStream { 754 | match *i { 755 | syntax::FunIdentifier::Identifier(ref n) => { 756 | let n = n.quote(); 757 | quote! { glsl::syntax::FunIdentifier::Identifier(#n) } 758 | } 759 | 760 | syntax::FunIdentifier::Expr(ref e) => { 761 | let e = Box::new(tokenize_expr(e)).quote(); 762 | quote! { glsl::syntax::FunIdentifier::Expr(#e) } 763 | } 764 | } 765 | } 766 | 767 | fn tokenize_declaration(d: &syntax::Declaration) -> TokenStream { 768 | match *d { 769 | syntax::Declaration::FunctionPrototype(ref proto) => { 770 | let p = tokenize_function_prototype(proto); 771 | quote! { glsl::syntax::Declaration::FunctionPrototype(#p) } 772 | } 773 | 774 | syntax::Declaration::InitDeclaratorList(ref list) => { 775 | let l = tokenize_init_declarator_list(list); 776 | quote! { glsl::syntax::Declaration::InitDeclaratorList(#l) } 777 | } 778 | 779 | syntax::Declaration::Precision(ref qual, ref ty) => { 780 | let qual = tokenize_precision_qualifier(qual); 781 | let ty = tokenize_type_specifier(ty); 782 | quote! { glsl::syntax::Declaration::Precision(#qual, #ty) } 783 | } 784 | 785 | syntax::Declaration::Block(ref block) => { 786 | let block = tokenize_block(block); 787 | quote! { glsl::syntax::Declaration::Block(#block) } 788 | } 789 | 790 | syntax::Declaration::Global(ref qual, ref identifiers) => { 791 | let qual = tokenize_type_qualifier(qual); 792 | let identifiers = identifiers.iter().map(|i| i.quote()); 793 | 794 | quote! { glsl::syntax::Declaration::Global(#qual, vec![#(#identifiers),*]) } 795 | } 796 | } 797 | } 798 | 799 | fn tokenize_function_prototype(fp: &syntax::FunctionPrototype) -> TokenStream { 800 | let ty = tokenize_fully_specified_type(&fp.ty); 801 | let name = fp.name.quote(); 802 | let params = fp 803 | .parameters 804 | .iter() 805 | .map(tokenize_function_parameter_declaration); 806 | 807 | quote! { 808 | glsl::syntax::FunctionPrototype { 809 | ty: #ty, 810 | name: #name, 811 | parameters: vec![#(#params),*] 812 | } 813 | } 814 | } 815 | 816 | fn tokenize_function_parameter_declaration( 817 | p: &syntax::FunctionParameterDeclaration, 818 | ) -> TokenStream { 819 | match *p { 820 | syntax::FunctionParameterDeclaration::Named(ref qual, ref fpd) => { 821 | let qual = qual.as_ref().map(tokenize_type_qualifier).quote(); 822 | let fpd = tokenize_function_parameter_declarator(fpd); 823 | quote! { glsl::syntax::FunctionParameterDeclaration::Named(#qual, #fpd) } 824 | } 825 | 826 | syntax::FunctionParameterDeclaration::Unnamed(ref qual, ref ty) => { 827 | let qual = qual.as_ref().map(tokenize_type_qualifier).quote(); 828 | let ty = tokenize_type_specifier(ty); 829 | quote! { glsl::syntax::FunctionParameterDeclaration::Unnamed(#qual, #ty) } 830 | } 831 | } 832 | } 833 | 834 | fn tokenize_function_parameter_declarator(p: &syntax::FunctionParameterDeclarator) -> TokenStream { 835 | let ty = tokenize_type_specifier(&p.ty); 836 | let ident = tokenize_arrayed_identifier(&p.ident); 837 | 838 | quote! { 839 | glsl::syntax::FunctionParameterDeclarator { 840 | ty: #ty, 841 | ident: #ident 842 | } 843 | } 844 | } 845 | 846 | fn tokenize_init_declarator_list(i: &syntax::InitDeclaratorList) -> TokenStream { 847 | let head = tokenize_single_declaration(&i.head); 848 | let tail = i.tail.iter().map(tokenize_single_declaration_no_type); 849 | 850 | quote! { 851 | glsl::syntax::InitDeclaratorList { 852 | head: #head, 853 | tail: vec![#(#tail),*] 854 | } 855 | } 856 | } 857 | 858 | fn tokenize_single_declaration(d: &syntax::SingleDeclaration) -> TokenStream { 859 | let ty = tokenize_fully_specified_type(&d.ty); 860 | let name = d.name.as_ref().map(|i| i.quote()).quote(); 861 | let array_specifier = d.array_specifier.as_ref().map(tokenize_array_spec).quote(); 862 | let initializer = d.initializer.as_ref().map(tokenize_initializer).quote(); 863 | 864 | quote! { 865 | glsl::syntax::SingleDeclaration { 866 | ty: #ty, 867 | name: #name, 868 | array_specifier: #array_specifier, 869 | initializer: #initializer 870 | } 871 | } 872 | } 873 | 874 | fn tokenize_single_declaration_no_type(d: &syntax::SingleDeclarationNoType) -> TokenStream { 875 | let ident = tokenize_arrayed_identifier(&d.ident); 876 | let initializer = d.initializer.as_ref().map(tokenize_initializer).quote(); 877 | 878 | quote! { 879 | glsl::syntax::SingleDeclarationNoType { 880 | ident: #ident, 881 | initializer: #initializer 882 | } 883 | } 884 | } 885 | 886 | fn tokenize_initializer(i: &syntax::Initializer) -> TokenStream { 887 | match *i { 888 | syntax::Initializer::Simple(ref e) => { 889 | let e = Box::new(tokenize_expr(e)).quote(); 890 | quote! { glsl::syntax::Initializer::Simple(#e) } 891 | } 892 | 893 | syntax::Initializer::List(ref list) => { 894 | let l = list.0.iter().map(tokenize_initializer); 895 | quote! { glsl::syntax::Initializer::List(glsl::syntax::NonEmpty(vec![#(#l),*])) } 896 | } 897 | } 898 | } 899 | 900 | fn tokenize_block(b: &syntax::Block) -> TokenStream { 901 | let qual = tokenize_type_qualifier(&b.qualifier); 902 | let name = b.name.quote(); 903 | let fields = b.fields.iter().map(tokenize_struct_field); 904 | let identifier = b 905 | .identifier 906 | .as_ref() 907 | .map(tokenize_arrayed_identifier) 908 | .quote(); 909 | 910 | quote! { 911 | glsl::syntax::Block { 912 | qualifier: #qual, 913 | name: #name, 914 | fields: vec![#(#fields),*], 915 | identifier: #identifier 916 | } 917 | } 918 | } 919 | 920 | fn tokenize_function_definition(fd: &syntax::FunctionDefinition) -> TokenStream { 921 | let p = tokenize_function_prototype(&fd.prototype); 922 | let s = tokenize_compound_statement(&fd.statement); 923 | 924 | quote! { 925 | glsl::syntax::FunctionDefinition { 926 | prototype: #p, 927 | statement: #s 928 | } 929 | } 930 | } 931 | 932 | fn tokenize_compound_statement(cst: &syntax::CompoundStatement) -> TokenStream { 933 | let s = cst.statement_list.iter().map(tokenize_statement); 934 | 935 | quote! { 936 | glsl::syntax::CompoundStatement { 937 | statement_list: vec![#(#s),*] 938 | } 939 | } 940 | } 941 | 942 | fn tokenize_statement(st: &syntax::Statement) -> TokenStream { 943 | match *st { 944 | syntax::Statement::Compound(ref cst) => { 945 | let s = Box::new(tokenize_compound_statement(cst)).quote(); 946 | quote! { glsl::syntax::Statement::Compound(#s) } 947 | } 948 | 949 | syntax::Statement::Simple(ref sst) => { 950 | let s = Box::new(tokenize_simple_statement(sst)).quote(); 951 | quote! { glsl::syntax::Statement::Simple(#s) } 952 | } 953 | } 954 | } 955 | 956 | fn tokenize_simple_statement(sst: &syntax::SimpleStatement) -> TokenStream { 957 | match *sst { 958 | syntax::SimpleStatement::Declaration(ref d) => { 959 | let d = tokenize_declaration(d); 960 | quote! { glsl::syntax::SimpleStatement::Declaration(#d) } 961 | } 962 | 963 | syntax::SimpleStatement::Expression(ref e) => { 964 | let e = tokenize_expr_statement(e); 965 | quote! { glsl::syntax::SimpleStatement::Expression(#e) } 966 | } 967 | 968 | syntax::SimpleStatement::Selection(ref s) => { 969 | let s = tokenize_selection_statement(s); 970 | quote! { glsl::syntax::SimpleStatement::Selection(#s) } 971 | } 972 | 973 | syntax::SimpleStatement::Switch(ref s) => { 974 | let s = tokenize_switch_statement(s); 975 | quote! { glsl::syntax::SimpleStatement::Switch(#s) } 976 | } 977 | 978 | syntax::SimpleStatement::CaseLabel(ref cl) => { 979 | let cl = tokenize_case_label(cl); 980 | quote! { glsl::syntax::SimpleStatement::CaseLabel(#cl) } 981 | } 982 | 983 | syntax::SimpleStatement::Iteration(ref i) => { 984 | let i = tokenize_iteration_statement(i); 985 | quote! { glsl::syntax::SimpleStatement::Iteration(#i) } 986 | } 987 | 988 | syntax::SimpleStatement::Jump(ref j) => { 989 | let j = tokenize_jump_statement(j); 990 | quote! { glsl::syntax::SimpleStatement::Jump(#j) } 991 | } 992 | } 993 | } 994 | 995 | fn tokenize_expr_statement(est: &syntax::ExprStatement) -> TokenStream { 996 | let e = est.as_ref().map(|e| tokenize_expr(&e)).quote(); 997 | quote! {#e} 998 | } 999 | 1000 | fn tokenize_selection_statement(sst: &syntax::SelectionStatement) -> TokenStream { 1001 | let cond = Box::new(tokenize_expr(&sst.cond)).quote(); 1002 | let rest = tokenize_selection_rest_statement(&sst.rest); 1003 | 1004 | quote! { 1005 | glsl::syntax::SelectionStatement { 1006 | cond: #cond, 1007 | rest: #rest 1008 | } 1009 | } 1010 | } 1011 | 1012 | fn tokenize_selection_rest_statement(sst: &syntax::SelectionRestStatement) -> TokenStream { 1013 | match *sst { 1014 | syntax::SelectionRestStatement::Statement(ref if_st) => { 1015 | let e = Box::new(tokenize_statement(if_st)).quote(); 1016 | quote! { glsl::syntax::SelectionRestStatement::Statement(#e) } 1017 | } 1018 | 1019 | syntax::SelectionRestStatement::Else(ref if_st, ref else_st) => { 1020 | let if_st = Box::new(tokenize_statement(if_st)).quote(); 1021 | let else_st = Box::new(tokenize_statement(else_st)).quote(); 1022 | quote! { glsl::syntax::SelectionRestStatement::Else(#if_st, #else_st) } 1023 | } 1024 | } 1025 | } 1026 | 1027 | fn tokenize_switch_statement(sst: &syntax::SwitchStatement) -> TokenStream { 1028 | let head = Box::new(tokenize_expr(&sst.head)).quote(); 1029 | let body = sst.body.iter().map(tokenize_statement); 1030 | 1031 | quote! { 1032 | glsl::syntax::SwitchStatement { 1033 | head: #head, 1034 | body: vec![#(#body),*] 1035 | } 1036 | } 1037 | } 1038 | 1039 | fn tokenize_case_label(cl: &syntax::CaseLabel) -> TokenStream { 1040 | match *cl { 1041 | syntax::CaseLabel::Case(ref e) => { 1042 | let e = Box::new(tokenize_expr(e)).quote(); 1043 | quote! { glsl::syntax::CaseLabel::Case(#e) } 1044 | } 1045 | 1046 | syntax::CaseLabel::Def => quote! { glsl::syntax::CaseLabel::Def }, 1047 | } 1048 | } 1049 | 1050 | fn tokenize_iteration_statement(ist: &syntax::IterationStatement) -> TokenStream { 1051 | match *ist { 1052 | syntax::IterationStatement::While(ref cond, ref body) => { 1053 | let cond = tokenize_condition(cond); 1054 | let body = Box::new(tokenize_statement(body)).quote(); 1055 | quote! { glsl::syntax::IterationStatement::While(#cond, #body) } 1056 | } 1057 | 1058 | syntax::IterationStatement::DoWhile(ref body, ref cond) => { 1059 | let body = Box::new(tokenize_statement(body)).quote(); 1060 | let cond = Box::new(tokenize_expr(cond)).quote(); 1061 | quote! { glsl::syntax::IterationStatement::DoWhile(#body, #cond) } 1062 | } 1063 | 1064 | syntax::IterationStatement::For(ref init, ref rest, ref body) => { 1065 | let init = tokenize_for_init_statement(init); 1066 | let rest = tokenize_for_rest_statement(rest); 1067 | let body = Box::new(tokenize_statement(body)).quote(); 1068 | quote! { glsl::syntax::IterationStatement::For(#init, #rest, #body) } 1069 | } 1070 | } 1071 | } 1072 | 1073 | fn tokenize_condition(c: &syntax::Condition) -> TokenStream { 1074 | match *c { 1075 | syntax::Condition::Expr(ref e) => { 1076 | let e = Box::new(tokenize_expr(e)).quote(); 1077 | quote! { glsl::syntax::Condition::Expr(#e) } 1078 | } 1079 | 1080 | syntax::Condition::Assignment(ref ty, ref name, ref initializer) => { 1081 | let ty = tokenize_fully_specified_type(ty); 1082 | let name = name.quote(); 1083 | let initializer = tokenize_initializer(initializer); 1084 | 1085 | quote! { glsl::syntax::Condition::Assignment(#ty, #name, #initializer) } 1086 | } 1087 | } 1088 | } 1089 | 1090 | fn tokenize_for_init_statement(i: &syntax::ForInitStatement) -> TokenStream { 1091 | match *i { 1092 | syntax::ForInitStatement::Expression(ref expr) => { 1093 | let e = expr.as_ref().map(|e| tokenize_expr(&e)).quote(); 1094 | quote! { glsl::syntax::ForInitStatement::Expression(#e) } 1095 | } 1096 | 1097 | syntax::ForInitStatement::Declaration(ref d) => { 1098 | let d = Box::new(tokenize_declaration(d)).quote(); 1099 | quote! { glsl::syntax::ForInitStatement::Declaration(#d) } 1100 | } 1101 | } 1102 | } 1103 | 1104 | fn tokenize_for_rest_statement(r: &syntax::ForRestStatement) -> TokenStream { 1105 | let cond = r.condition.as_ref().map(tokenize_condition).quote(); 1106 | let post = r 1107 | .post_expr 1108 | .as_ref() 1109 | .map(|e| Box::new(tokenize_expr(&e)).quote()) 1110 | .quote(); 1111 | 1112 | quote! { 1113 | glsl::syntax::ForRestStatement { 1114 | condition: #cond, 1115 | post: #post 1116 | } 1117 | } 1118 | } 1119 | 1120 | fn tokenize_jump_statement(j: &syntax::JumpStatement) -> TokenStream { 1121 | match *j { 1122 | syntax::JumpStatement::Continue => quote! { glsl::syntax::JumpStatement::Continue }, 1123 | syntax::JumpStatement::Break => quote! { glsl::syntax::JumpStatement::Break }, 1124 | syntax::JumpStatement::Discard => quote! { glsl::syntax::JumpStatement::Discard }, 1125 | syntax::JumpStatement::Return(ref e) => { 1126 | let e = e 1127 | .as_ref() 1128 | .map(|e| Box::new(tokenize_expr(e)).quote()) 1129 | .quote(); 1130 | quote! { glsl::syntax::JumpStatement::Return(#e) } 1131 | } 1132 | } 1133 | } 1134 | 1135 | fn tokenize_preprocessor(pp: &syntax::Preprocessor) -> TokenStream { 1136 | match *pp { 1137 | syntax::Preprocessor::Define(ref pd) => { 1138 | let pd = tokenize_preprocessor_define(pd); 1139 | quote! { glsl::syntax::Preprocessor::Define(#pd) } 1140 | } 1141 | 1142 | syntax::Preprocessor::Else => { 1143 | quote! { glsl::syntax::Preprocessor::Else } 1144 | } 1145 | 1146 | syntax::Preprocessor::ElIf(ref pei) => { 1147 | let pei = tokenize_preprocessor_elif(pei); 1148 | quote! { glsl::syntax::Preprocessor::ElIf(#pei) } 1149 | } 1150 | 1151 | syntax::Preprocessor::EndIf => { 1152 | quote! { glsl::syntax::Preprocessor::EndIf } 1153 | } 1154 | 1155 | syntax::Preprocessor::Error(ref pe) => { 1156 | let pe = tokenize_preprocessor_error(pe); 1157 | quote! { glsl::syntax::Preprocessor::Error(#pe) } 1158 | } 1159 | 1160 | syntax::Preprocessor::If(ref pi) => { 1161 | let pi = tokenize_preprocessor_if(pi); 1162 | quote! { glsl::syntax::Preprocessor::If(#pi) } 1163 | } 1164 | 1165 | syntax::Preprocessor::IfDef(ref pid) => { 1166 | let pid = tokenize_preprocessor_ifdef(pid); 1167 | quote! { glsl::syntax::Preprocessor::IfDef(#pid) } 1168 | } 1169 | 1170 | syntax::Preprocessor::IfNDef(ref pind) => { 1171 | let pind = tokenize_preprocessor_ifndef(pind); 1172 | quote! { glsl::syntax::Preprocessor::IfNDef(#pind) } 1173 | } 1174 | 1175 | syntax::Preprocessor::Include(ref pi) => { 1176 | let pi = tokenize_preprocessor_include(pi); 1177 | quote! { glsl::syntax::Preprocessor::Include(#pi) } 1178 | } 1179 | 1180 | syntax::Preprocessor::Line(ref pl) => { 1181 | let pl = tokenize_preprocessor_line(pl); 1182 | quote! { glsl::syntax::Preprocessor::Line(#pl) } 1183 | } 1184 | 1185 | syntax::Preprocessor::Pragma(ref pp) => { 1186 | let pp = tokenize_preprocessor_pragma(pp); 1187 | quote! { glsl::syntax::Preprocessor::Pragma(#pp) } 1188 | } 1189 | 1190 | syntax::Preprocessor::Undef(ref pu) => { 1191 | let pu = tokenize_preprocessor_undef(pu); 1192 | quote! { glsl::syntax::Preprocessor::Undef(#pu) } 1193 | } 1194 | 1195 | syntax::Preprocessor::Version(ref pv) => { 1196 | let pv = tokenize_preprocessor_version(pv); 1197 | quote! { glsl::syntax::Preprocessor::Version(#pv) } 1198 | } 1199 | 1200 | syntax::Preprocessor::Extension(ref pe) => { 1201 | let pe = tokenize_preprocessor_extension(pe); 1202 | quote! { glsl::syntax::Preprocessor::Extension(#pe) } 1203 | } 1204 | } 1205 | } 1206 | 1207 | fn tokenize_preprocessor_define(pd: &syntax::PreprocessorDefine) -> TokenStream { 1208 | match *pd { 1209 | syntax::PreprocessorDefine::ObjectLike { 1210 | ref ident, 1211 | ref value, 1212 | } => { 1213 | let ident = tokenize_identifier(ident); 1214 | let value = value.quote(); 1215 | 1216 | quote! { 1217 | glsl::syntax::PreprocessorDefine::ObjectLike { 1218 | ident: #ident, 1219 | value: #value 1220 | } 1221 | } 1222 | } 1223 | 1224 | syntax::PreprocessorDefine::FunctionLike { 1225 | ref ident, 1226 | ref args, 1227 | ref value, 1228 | } => { 1229 | let ident = tokenize_identifier(ident); 1230 | let args = args.iter().map(|a| a.quote()); 1231 | let value = value.quote(); 1232 | 1233 | quote! { 1234 | glsl::syntax::PreprocessorDefine::FunctionLike { 1235 | ident: #ident, 1236 | args: vec![#(#args),*], 1237 | value: #value 1238 | } 1239 | } 1240 | } 1241 | } 1242 | } 1243 | 1244 | fn tokenize_preprocessor_elif(pei: &syntax::PreprocessorElIf) -> TokenStream { 1245 | let condition = pei.condition.quote(); 1246 | 1247 | quote! { 1248 | glsl::syntax::PreprocessorElIf { 1249 | condition: #condition 1250 | } 1251 | } 1252 | } 1253 | 1254 | fn tokenize_preprocessor_error(pe: &syntax::PreprocessorError) -> TokenStream { 1255 | let message = &pe.message; 1256 | 1257 | quote! { 1258 | glsl::syntax::PreprocessorError { 1259 | message: #message.to_owned() 1260 | } 1261 | } 1262 | } 1263 | 1264 | fn tokenize_preprocessor_if(pi: &syntax::PreprocessorIf) -> TokenStream { 1265 | let condition = pi.condition.quote(); 1266 | 1267 | quote! { 1268 | glsl::syntax::PreprocessorIf { 1269 | condition: #condition 1270 | } 1271 | } 1272 | } 1273 | 1274 | fn tokenize_preprocessor_ifdef(pid: &syntax::PreprocessorIfDef) -> TokenStream { 1275 | let ident = tokenize_identifier(&pid.ident); 1276 | 1277 | quote! { 1278 | glsl::syntax::PreprocessorIfDef { 1279 | ident: #ident 1280 | } 1281 | } 1282 | } 1283 | 1284 | fn tokenize_preprocessor_ifndef(pind: &syntax::PreprocessorIfNDef) -> TokenStream { 1285 | let ident = tokenize_identifier(&pind.ident); 1286 | 1287 | quote! { 1288 | glsl::syntax::PreprocessorIfNDef { 1289 | ident: #ident 1290 | } 1291 | } 1292 | } 1293 | 1294 | fn tokenize_preprocessor_include(pi: &syntax::PreprocessorInclude) -> TokenStream { 1295 | let path = tokenize_path(&pi.path); 1296 | 1297 | quote! { 1298 | glsl::syntax::PreprocessorInclude { 1299 | path: #path 1300 | } 1301 | } 1302 | } 1303 | 1304 | fn tokenize_preprocessor_line(pl: &syntax::PreprocessorLine) -> TokenStream { 1305 | let line = pl.line; 1306 | let source_string_number = pl.source_string_number.quote(); 1307 | 1308 | quote! { 1309 | glsl::syntax::PreprocessorLine { 1310 | line: #line, 1311 | source_string_number: #source_string_number 1312 | } 1313 | } 1314 | } 1315 | 1316 | fn tokenize_preprocessor_pragma(pp: &syntax::PreprocessorPragma) -> TokenStream { 1317 | let command = &pp.command; 1318 | 1319 | quote! { 1320 | glsl::syntax::PreprocessorPragma { 1321 | command: #command.to_owned() 1322 | } 1323 | } 1324 | } 1325 | 1326 | fn tokenize_preprocessor_undef(pu: &syntax::PreprocessorUndef) -> TokenStream { 1327 | let name = tokenize_identifier(&pu.name); 1328 | 1329 | quote! { 1330 | glsl::syntax::PreprocessorUndef { 1331 | name: #name 1332 | } 1333 | } 1334 | } 1335 | 1336 | fn tokenize_preprocessor_version(pv: &syntax::PreprocessorVersion) -> TokenStream { 1337 | let version = pv.version; 1338 | let profile = pv 1339 | .profile 1340 | .as_ref() 1341 | .map(tokenize_preprocessor_version_profile) 1342 | .quote(); 1343 | 1344 | quote! { 1345 | glsl::syntax::PreprocessorVersion { 1346 | version: #version, 1347 | profile: #profile 1348 | } 1349 | } 1350 | } 1351 | 1352 | fn tokenize_preprocessor_version_profile( 1353 | profile: &syntax::PreprocessorVersionProfile, 1354 | ) -> TokenStream { 1355 | match *profile { 1356 | syntax::PreprocessorVersionProfile::Core => { 1357 | quote! { glsl::syntax::PreprocessorVersionProfile::Core } 1358 | } 1359 | syntax::PreprocessorVersionProfile::Compatibility => { 1360 | quote! { glsl::syntax::PreprocessorVersionProfile::Compatibility } 1361 | } 1362 | syntax::PreprocessorVersionProfile::ES => { 1363 | quote! { glsl::syntax::PreprocessorVersionProfile::ES } 1364 | } 1365 | } 1366 | } 1367 | 1368 | fn tokenize_preprocessor_extension(pe: &syntax::PreprocessorExtension) -> TokenStream { 1369 | let name = tokenize_preprocessor_extension_name(&pe.name); 1370 | let behavior = pe 1371 | .behavior 1372 | .as_ref() 1373 | .map(tokenize_preprocessor_extension_behavior) 1374 | .quote(); 1375 | 1376 | quote! { 1377 | glsl::syntax::PreprocessorExtension { 1378 | name: #name, 1379 | behavior: #behavior 1380 | } 1381 | } 1382 | } 1383 | 1384 | fn tokenize_preprocessor_extension_name(name: &syntax::PreprocessorExtensionName) -> TokenStream { 1385 | match *name { 1386 | syntax::PreprocessorExtensionName::All => { 1387 | quote! { glsl::syntax::PreprocessorExtensionName::All } 1388 | } 1389 | syntax::PreprocessorExtensionName::Specific(ref n) => { 1390 | quote! { glsl::syntax::PreprocessorExtensionName::Specific(#n.to_owned()) } 1391 | } 1392 | } 1393 | } 1394 | 1395 | fn tokenize_preprocessor_extension_behavior( 1396 | behavior: &syntax::PreprocessorExtensionBehavior, 1397 | ) -> TokenStream { 1398 | match *behavior { 1399 | syntax::PreprocessorExtensionBehavior::Require => { 1400 | quote! { glsl::syntax::PreprocessorExtensionBehavior::Require } 1401 | } 1402 | syntax::PreprocessorExtensionBehavior::Enable => { 1403 | quote! { glsl::syntax::PreprocessorExtensionBehavior::Enable } 1404 | } 1405 | syntax::PreprocessorExtensionBehavior::Warn => { 1406 | quote! { glsl::syntax::PreprocessorExtensionBehavior::Warn } 1407 | } 1408 | syntax::PreprocessorExtensionBehavior::Disable => { 1409 | quote! { glsl::syntax::PreprocessorExtensionBehavior::Disable } 1410 | } 1411 | } 1412 | } 1413 | 1414 | fn tokenize_external_declaration(ed: &syntax::ExternalDeclaration) -> TokenStream { 1415 | match *ed { 1416 | syntax::ExternalDeclaration::Preprocessor(ref pp) => { 1417 | let pp = tokenize_preprocessor(pp); 1418 | quote! { glsl::syntax::ExternalDeclaration::Preprocessor(#pp) } 1419 | } 1420 | 1421 | syntax::ExternalDeclaration::FunctionDefinition(ref fd) => { 1422 | let fd = tokenize_function_definition(fd); 1423 | quote! { glsl::syntax::ExternalDeclaration::FunctionDefinition(#fd) } 1424 | } 1425 | 1426 | syntax::ExternalDeclaration::Declaration(ref d) => { 1427 | let d = tokenize_declaration(d); 1428 | quote! { glsl::syntax::ExternalDeclaration::Declaration(#d) } 1429 | } 1430 | } 1431 | } 1432 | 1433 | fn tokenize_translation_unit(tu: &syntax::TranslationUnit) -> TokenStream { 1434 | let tu = (tu.0).0.iter().map(tokenize_external_declaration); 1435 | quote! { glsl::syntax::TranslationUnit(glsl::syntax::NonEmpty(vec![#(#tu),*])) } 1436 | } 1437 | -------------------------------------------------------------------------------- /glsl-quasiquote/tests/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(proc_macro_hygiene)] 2 | 3 | extern crate glsl; 4 | #[macro_use] 5 | extern crate glsl_quasiquote; 6 | 7 | #[test] 8 | fn void_main_empty() { 9 | let _ = glsl! {void main() {}}; 10 | } 11 | 12 | #[test] 13 | fn understands_version_and_extension() { 14 | let _ = glsl! { 15 | #version 330 core 16 | #extension GL_foo_bar : require 17 | void main() { 18 | } 19 | }; 20 | } 21 | 22 | #[test] 23 | fn understands_pp_define_undef() { 24 | let _ = glsl! { 25 | #define foo 32 26 | #undef foo 27 | void main() { 28 | } 29 | }; 30 | } 31 | 32 | #[test] 33 | fn understands_pp_tests() { 34 | let _ = glsl! { 35 | #else 36 | #elif 0 37 | #endif 38 | #if 0 39 | #ifdef foo 40 | #ifndef foo 41 | void main() { 42 | } 43 | }; 44 | } 45 | 46 | #[test] 47 | fn understands_pp_files() { 48 | let _ = glsl! { 49 | #include 50 | #include "filename" 51 | #line 2 52 | #line 2 4 53 | void main() { 54 | } 55 | }; 56 | } 57 | 58 | #[test] 59 | fn understands_pp_error() { 60 | let _ = glsl! { 61 | #error some command 62 | void main() { 63 | } 64 | }; 65 | } 66 | 67 | #[test] 68 | fn understands_pp_pragma() { 69 | let _ = glsl! { 70 | #pragma some flag 71 | void main() { 72 | } 73 | }; 74 | } 75 | 76 | #[test] 77 | fn fn_returns_int() { 78 | let _ = glsl! { 79 | int test() { 80 | return 3.; 81 | } 82 | }; 83 | } 84 | 85 | #[test] 86 | fn simple_struct() { 87 | let _ = glsl! { 88 | struct V { 89 | vec4 p; 90 | vec2 uv; 91 | }; 92 | 93 | struct F { 94 | vec4 color; 95 | }; 96 | }; 97 | } 98 | 99 | #[test] 100 | fn struct_several_ident_per_field() { 101 | let _ = glsl! { 102 | struct S { 103 | float a, b, c; 104 | }; 105 | }; 106 | } 107 | 108 | #[test] 109 | fn struct_with_identifiers() { 110 | let _ = glsl! { 111 | struct S { 112 | float a, b, c; 113 | } foo, bar, zoo; 114 | }; 115 | } 116 | 117 | #[test] 118 | fn struct_with_arrayed_identifiers() { 119 | let _ = glsl! { 120 | struct S { 121 | float a, b, c; 122 | } foo[3], bar[12], zoo[]; 123 | }; 124 | } 125 | 126 | #[test] 127 | fn typed_return() { 128 | let _ = glsl! { 129 | ReturnType foo() { 130 | } 131 | }; 132 | } 133 | 134 | #[test] 135 | fn dot_expr() { 136 | let _ = glsl! { 137 | void main() { 138 | let x = foo.xyz; 139 | let y = 1.; 140 | let z = .3; 141 | } 142 | }; 143 | } 144 | -------------------------------------------------------------------------------- /glsl-tree/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.3 4 | 5 | > Dec 23, 2023 6 | 7 | - Bump to replace the yanked `glsl-6.0.3` version. 8 | 9 | ## 0.2.1 10 | 11 | > Mar 23rd, 2023 12 | 13 | - [glsl-6.0](https://crates.io/crates/glsl/6.0.0) support. 14 | 15 | ## 0.2 16 | 17 | > Aug 12th, 2020 18 | 19 | - [glsl-5.0](https://crates.io/crates/glsl/5.0.0) support. 20 | 21 | ## 0.1 22 | 23 | > Jul 27th, 2020 24 | 25 | - Initial revision. 26 | -------------------------------------------------------------------------------- /glsl-tree/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glsl-tree" 3 | version = "0.3.0" 4 | license = "BSD-3-Clause" 5 | authors = ["Dimitri Sabadie "] 6 | description = "Print a GLSL AST to stdout" 7 | keywords = ["GLSL", "OpenGL", "SPIR-V", "parser"] 8 | categories = ["parsing", "rendering"] 9 | homepage = "https://github.com/phaazon/glsl" 10 | repository = "https://github.com/phaazon/glsl" 11 | readme = "README.md" 12 | edition = "2018" 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | 16 | [dependencies] 17 | glsl = "7" 18 | -------------------------------------------------------------------------------- /glsl-tree/README.md: -------------------------------------------------------------------------------- 1 | # A debug / GLSL tree (AST) viewer 2 | 3 | This small program is an AST viewer that aims to help people debug what is going on while parsing 4 | an input GLSL string. 5 | 6 | The binary reads the GLSL input on _stdin_ and outputs the parsed tree on _stdout_ if succeeded, or 7 | prints errors on _stderr_. 8 | -------------------------------------------------------------------------------- /glsl-tree/src/main.rs: -------------------------------------------------------------------------------- 1 | use glsl::parser::Parse as _; 2 | use glsl::syntax::ShaderStage; 3 | use std::io; 4 | use std::process::exit; 5 | 6 | fn main() { 7 | let mut content = String::new(); 8 | 9 | match io::stdin().read_line(&mut content) { 10 | Ok(_) => match ShaderStage::parse(content) { 11 | Ok(ast) => println!("{:#?}", ast), 12 | 13 | Err(err) => { 14 | eprintln!("cannot parse GLSL:\n{}", err); 15 | exit(1); 16 | } 17 | }, 18 | 19 | Err(err) => { 20 | eprintln!("cannot read from stdin: {}", err); 21 | exit(2); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /glsl/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 7.0 2 | 3 | > Dec 23, 2023 4 | 5 | - Bump to replace the yanked `glsl-6.0.3` version. 6 | 7 | # 6.0.3 8 | 9 | > Dec 19, 2023 10 | 11 | - **Yanked, as this actually contains a breaking change**. 12 | - Fix missing `do-while` and `for` init expressions semicolons (7abee68). 13 | - Replace now-standard `#elseif` preprocessor directivy by `#elif` (2791414). 14 | - Some fixes for the GLSL transpiler: 15 | - `low -> lowp` 16 | - A missing whitespace between precision qualifiers and the type of the variable. 17 | 18 | # 6.0.2 19 | 20 | > Mar 23, 2023 21 | 22 | - Switch to `nom-7`. 23 | 24 | # 6.0.1 25 | 26 | > Jul 11, 2021 27 | 28 | - Better scheme for parenthesis generation in the GLSL transpiler. 29 | - Fix matrices types in the GLSL transpiler. 30 | - Fix end-of-line parser, which now accepts CR LF too. 31 | 32 | # 6.0 33 | 34 | > Dec 7th, 2020 35 | 36 | - Change the meaning of `Visitor` and `Host`. They now take the AST nodes by simple references (`&`) and not via 37 | mutable references (`&mut`) anymore. This will allow people to use visitors in much more contexts. 38 | - Add `VisitorMut` and `HostMut` to visit AST nodes mutably. These correspond to the previous (version `<6.0`) `Visitor` 39 | and `Host` traits. If you were using them and require mutability, feel free to simply switch to `VisitorMut` and 40 | `HostMut`. 41 | 42 | # 5.0.2 43 | 44 | > Nov 1st, 2020 45 | 46 | - Bump `nom-6.0`. 47 | 48 | # 5.0.1 49 | 50 | > Aug 12th, 2020 51 | 52 | - Fix float / double literal parsing priority. Floats are parsed first now in case of a polymorphic 53 | constant. 54 | 55 | # 5.0.0 56 | 57 | > Jul 27th, 2020 58 | 59 | - Fix array specifiers by splitting the `ArraySpecifier` type into two types: 60 | - `ArraySpecifier`, which holds a non-empty list of `ArraySpecifierDimension`. 61 | - `ArraySpecifierDimension`, which is the “old” `ArraySpecifier`. 62 | This change allows for multidimensional array specifiers. 63 | 64 | ## Migration guide 65 | 66 | - If you were using array specifiers, you need to wrap them inside an `ArraySpecifierDimension` 67 | and wrap it in a `ArraySpecifier { dimensions: NonEmpty(vec![here]) }` expression, where `here` 68 | is your specifier. 69 | 70 | # 4.1.1 71 | 72 | > Wed Jul 1st 2020 73 | 74 | - Fix the _identifier_ parser, that previously failed to parse identifiers starting with an 75 | underscore (`_`) while it is permitted (chapter 3.7 of the GLSLang spec). 76 | - Fix associativity for logical binary operators (`||`, `&&`). 77 | 78 | # 4.1 79 | 80 | > Fri Jun 19th 2020 81 | 82 | - Implement `std::error::Error` for error types. 83 | 84 | # 4.0.3 85 | 86 | > Fri Mar 6th 2020 87 | 88 | - Move all the unit tests code into their ow module to prevent rustc from parsing them if we 89 | don’t build with tests. 90 | 91 | # 4.0.2 92 | 93 | > Mon 10th Feb 2020 94 | 95 | - Remove the `lexical` feature from `nom`. It’s useful only when using functions such as the 96 | `float` combinator, which we don’t use. 97 | 98 | # 4.0.1 99 | 100 | > Tue 21st Jan 2020 101 | 102 | - Fix a bug occurring in the function-like `#define` parser (i.e. `#define foo(x) (y)`) that 103 | would prevent the use of whitespaces in the argument list. 104 | 105 | # 4.0 106 | 107 | > Mon 6th Jan 2020 108 | 109 | ## Major changes 110 | 111 | - Add support for `attribute` and `varying` keyword as a backward-compatible parser. 112 | - Fix binary operator associativity. They were (_erroneously_) right-associative. They’re now 113 | parsed as left-associative. 114 | 115 | # 3.0 116 | 117 | > Wed 14th Nov 2019 118 | 119 | ## Major changes 120 | 121 | - `JumpStatement::Return` now takes an optional `Expr` instead of an `Expr` directly. That allows 122 | for parsing statements such as `return;`, which should have 123 | been supported from the beginning. 124 | - Support for missing preprocessor directives: 125 | - `#if`. 126 | - `#ifdef`. 127 | - `#ifndef`. 128 | - `#elseif`. 129 | - `#else`. 130 | - `#endif`. 131 | - `#error`. 132 | - `#include`. 133 | - `#line`. 134 | - `#pragma`. 135 | - `#undef`. 136 | 137 | ## Patch changes 138 | 139 | - Add a `rustfmt.toml` to reformat everything and stay consistent. If you want contribute, ensure 140 | you are correctly using `rustfmt` (either by running `cargo fmt` before submitting a PR or by 141 | configuring your editor to format the code for you). This is important, as not respecting the 142 | formatting would make your contribution impossible to merge due to a CI check. 143 | - Support for _multiline_ annotations (`\`). Multiline annotations are currently supported as 144 | part of _spaces_ — i.e. you cannot use them to break an identifier on two lines for instance. 145 | This choice makes it faster to parse without too much compromises (after all, `\` is mostly used 146 | in CPP directives in GLSL). 147 | - Fix a bug with _recoverable parsers_ that would produce parent parsers to ignore GLSL grammar 148 | errors. That fix also implies a boost in performance due to short-circuiting optimizations. 149 | 150 | # 2.0.1 151 | 152 | > Fri 8th Nov 2019 153 | 154 | - Improve performance of expression parsers. 155 | 156 | # 2.0 157 | 158 | > Thu 24th Oct 2019 159 | 160 | ## Major changes 161 | 162 | - Add `ShaderKind::Compute`. 163 | - Remove `NonEmpty::from_iter` and `TranslationUnit::from_iter` as they were deprecated. Use 164 | `*::from_non_empty_iter` instead. 165 | 166 | ## Patch changes 167 | 168 | - Fix tokenizer of `Block`. 169 | - Fix a bug while parsing floating-point numbers. 170 | - Reformat with `rustfmt`. 171 | 172 | # 1.2 173 | 174 | > Wed 18th Sep 2019 175 | 176 | ## Deprecations 177 | 178 | - `NonEmpty::from_iter` and `TranslationUnit::from_iter` are deprecated in favor of 179 | `*::from_non_empty_iter`. 180 | 181 | ## Minor changes 182 | 183 | - Add binary SPIR-V transpilation. That enables to transpile GLSL directly into a SPIR-V buffer. 184 | - Add `NonEmpty::from_non_empty_iter` and `TranslationUnit::from_non_empty_iter`. 185 | 186 | # 1.1.1 187 | 188 | > Tue 17th Sep 2019 189 | 190 | - Update internal code for Rust edition 2018. 191 | 192 | # 1.1 193 | 194 | > Tue 30th of July 2019 195 | 196 | - Add the `ShaderStage` type alias to `TranslationUnit`. 197 | - Enhance the front documentation to showcase how to use how to use the crate. 198 | 199 | # 1.0.2 200 | 201 | > Tue 23rd of July 2019 202 | 203 | - Change the description of the project and update documentation. 204 | 205 | # 1.0.1 206 | 207 | > Tue 23rd of July 2019 208 | 209 | - Change the `external_declaration` parser so that it can also accept _GLSL460_. That should be a 210 | breaking change because now, _GLSL450_ formatted input accepts feature from _GLSL460_, which 211 | shouldn’t be allowed. Nevertheless, the added feature (being able to use semicolons (`;`) on 212 | empty lines at top-level) is not really an interesting property and no breakage should happen. 213 | 214 | # 1.0 215 | 216 | > Thu 18th of July 2019 217 | 218 | - Migrate all parsers to [nom-5](https://crates.io/crates/nom/5.0.0). 219 | - Improve and add unit and integration tests. 220 | - Improve overall documentation. 221 | - Enhance some allocation scheme (removed them by using more adapted parsers). 222 | - Completely remove the byte (`&[u8]`) parsing. That was a bad idea, for both its impractical 223 | aspect and error removing. Parsing is done on string slices now (`&str`). 224 | 225 | # 0.13.5 226 | 227 | > Sun 9th of December 2018 228 | 229 | - Add the SPIR-V transpiler. Currently, it’s feature-gated and *very* experimental. Feel free to 230 | try and provide feedback about it. 231 | - Add simple accessors for `ParseResult`. 232 | - Fix a typo in the documentation of syntax. 233 | - Add some unit and integration tests. 234 | - Add `Identifier::as_str` and `TypeName::as_str` 235 | 236 | # 0.13.4 237 | 238 | > Wed 25nd of November 2018 239 | 240 | - Add `NonEmpty::push` and `NonEmpty::pop`. 241 | - Implement `Deref` and `DerefMut` for `TranslationUnit`. 242 | 243 | # 0.13.3 244 | 245 | > Wed 24nd of November 2018 246 | 247 | - Add `NonEmpty::from_iter` and `TranslationUnit::from_iter`. 248 | - Implement `IntoIterator` for `NonEmpty` and `TranslationUnit`. 249 | 250 | # 0.13.2 251 | 252 | > Wed 22nd of November 2018 253 | 254 | - Fix a typo in documentation. 255 | 256 | # 0.13.1 257 | 258 | > Wed 22nd of November 2018 259 | 260 | - Fix a link in documentation. 261 | 262 | # 0.13 263 | 264 | > Wed 21st of November 2018 265 | 266 | - Update/reset hyperlinks in all the documentation for types, traits, methods, etc. 267 | - General enhancement of the documentation. 268 | - `ExternalDeclaration::new_struct` can now fail. Check the doc for further details. 269 | - `NonEmpty`, `Identifier` and `TypeName` and `TranslationUnit` are now plain types and not 270 | aliases anymore. 271 | - Add AST visitors. Visitors allow for traversing through an AST and on-the-fly mutation, 272 | filtering, etc. 273 | - The `#define` preprocessor pragma is now supported in a limited form (it can only be used in 274 | the global scope). 275 | 276 | # 0.12 277 | 278 | > Sun 11th of November 2018 279 | 280 | - Fix the type of identifier stored in `Block`: it now uses the new encoding for arrayed 281 | identifiers. 282 | - `Block` parsers update for the arrayd identifier change. 283 | 284 | # 0.11 285 | 286 | > Sat 10th of November 2018 287 | 288 | - Add helper functions to build objects form the `syntax` module. Those are intended to be a 289 | simple way to build ASTs out of Rust code instead of parsing. 290 | - Enhance the documentation of the `Preprocessor` type. 291 | 292 | # 0.10.1 293 | 294 | > Fri 2nd of November 2018 295 | 296 | - Add some missing implementors of `Parse` for types from `glsl::syntax`. 297 | 298 | # 0.10 299 | 300 | > Fri 2nd of November 2018 301 | 302 | - Hide the `parsers` module. It’s not exposed anymore as it was mostly 303 | [nom](https://crates.io/crates/nom) parsers and we don’t like leaking internals. 304 | - Introduce the `Parser` trait, acting as an abstraction over the internal parsers. Implementors 305 | provide a type-driven parsing experience that is very similar to the one as 306 | [FromStr](https://doc.rust-lang.org/std/str/trait.FromStr.html). This change is actually 307 | mandatory for the [glsl-quasiquote](https://crates.io/crates/glsl-quasiquote) crate’s `glsl!` 308 | proc-macro to allow people use it for any GLSL item (and not only `TranslationUnit`). 309 | - Enhance the overall documentation. 310 | 311 | # 0.9.2 312 | 313 | > Wed 3rd of October 2018 314 | 315 | - Fix GLSL transpiled representation of `IVec*`. It was plain wrong. 316 | 317 | # 0.9.1 318 | 319 | > Sat 7th of July 2018 320 | 321 | - Fix unit testing in transpilers. 322 | 323 | # 0.9 324 | 325 | > Sat 7th of July 2018 326 | 327 | - Big cleanup of the module hierarchy. 328 | - Enhanced the documentation. 329 | 330 | # 0.8.1 331 | 332 | > Sun, 17th of June 2018 333 | 334 | - Add the `README.md` path to the `Cargo.toml` manifest. 335 | 336 | # 0.8 337 | 338 | > Sun 17th of June 2018 339 | 340 | This version introduces breaking changes because public types used in return positions have changed. 341 | These concern only intermediate `nom` functions, so if you do not make a fancy use of this crate, 342 | you souldn’t have to worry too much when migrating. 343 | 344 | - Fix the roundtrip issue with the GLSL writer (precedence wasn’t correctly respected). 345 | - Simplify internal code. 346 | - Error instead of panicking when parsing overflowing integer literals. 347 | - Fix panic trying to parse literals starting with whitespace. 348 | - Add fuzzing to find out panics. 349 | 350 | # 0.7.2 351 | 352 | > Wed 13th of December 2017 353 | 354 | - Fix the `show_expr` when the `Expr` is a `Expr::UIntConst`. 355 | 356 | # 0.7.1 357 | 358 | > Mon 20th of November 2017 359 | 360 | - `std::error::Error` is now implemented for `ParseError`. 361 | 362 | # 0.7 363 | 364 | > Wed 27th of September 2017 365 | 366 | - Add support for postfix expressions as function identifiers. 367 | 368 | # 0.6.5 369 | 370 | > Mon 4th of September 2017 371 | 372 | - Fix the formatting of floating values when the fractional part is `0`. 373 | 374 | # 0.6.4 375 | 376 | > Mon 4th of September 2017 377 | 378 | - Fix the output for `show_struct_specifier`. 379 | 380 | # 0.6.3 381 | 382 | > Mon 4th of September 2017 383 | 384 | - Fix the output for `show_struct_specifier`. 385 | 386 | # 0.6.2 387 | 388 | > Mon 4th of September 2017 389 | 390 | - Remove a warning. 391 | 392 | # 0.6.1 393 | 394 | > Mon 4th of September 2017 395 | 396 | - Fix `show_struct_specifier`. 397 | 398 | # 0.6 399 | 400 | > Fri 1st of September 2017 401 | 402 | - The `TypeSpecifier` type was wrong as it didn’t carry any `ArraySpecifier` information while the 403 | GLSL specification’s grammar about type specifiers states they should. Fixed. 404 | 405 | # 0.5 406 | 407 | > Mon 7th of August 2017 408 | 409 | - The `parse` and `parse_str` functions now take as second argument the parser to run. This enables 410 | using those functions and all the neat logic the wrap in dependent projects. 411 | 412 | # 0.4.2 413 | 414 | > Fri 4th of August 2017 415 | 416 | - A GLSL writer is now available. 417 | - Some parsers yield non-empty list of syntax trees. Those had the incorrect `Vec` type. They were 418 | replaced by `NonEmpty`, which is an alias to `Vec`, but carry the semantic that it has at least 419 | one element in it. 420 | 421 | # 0.4.1 422 | 423 | > Thu 3rd of August 2017 424 | 425 | - Uni/multi-line comments are now supported. 426 | 427 | # 0.4 428 | 429 | > Wed 2nd of August 2017 430 | 431 | - The `Declaration::Block` variant was refactored for a better usage. 432 | - Dot field selections and, in a mory general way, postfix expressions completely fixed. The 433 | `syntax` module was altered to make it easier to work with dot field selection. Also related, 434 | the function identifier syntax is now isomorphic to an identifier. 435 | 436 | # 0.3.1 437 | 438 | > Tue 1st of August 2017 439 | 440 | - Fix the `preprocessor` parser so that it eats surrounding blanks. 441 | 442 | # 0.3 443 | 444 | > Mon 31st of July 2017 445 | 446 | - Add a very minimalistic yet working preprocessor. It parses `#version` and `#extension` 447 | commands. Those have to be declared at the top of your file, even though this implementation 448 | accepts them at any place an external declaration could be defined. Feel free to submit a PR 449 | if you want to change that behavior, I don’t really mind. 450 | - Enhance the runtime error reporting. It’s not perfect, but it’s way better than before! 451 | - `void` is now recognized as `TypeSpecifier::Void` instead of the erroneous 452 | `TypeSpecifier::TypeName("void")`. 453 | 454 | # 0.2.2 455 | 456 | > Mon 31st of July 2017 457 | 458 | - The `layout` parser had a nasty bug that would treat a list of key-value pairs as an expression 459 | assignment. This was fixed and it now treats it as a list of pairs of identifier associated with a 460 | possible constant expression. 461 | - The `StructFieldSpecifier` type and its associated parser were wrong. Was missing: 462 | + the type qualifier 463 | + for each identifier defined in the field specifier, its optional array specifier, as in 464 | `float foo[3];` or `vec3 bar[];` for unsized ones. 465 | 466 | # 0.2.1 467 | 468 | > Sun 30th of July 2017 469 | 470 | - More documentation to help people to get their feet wet. 471 | 472 | # 0.2 473 | 474 | > Sat 29th of July 2017 475 | 476 | - The whole parsing API is public. 477 | 478 | # 0.1 479 | 480 | - Initial revision. 481 | -------------------------------------------------------------------------------- /glsl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "glsl" 3 | version = "7.0.0" 4 | license = "BSD-3-Clause" 5 | authors = ["Dimitri Sabadie "] 6 | description = "A GLSL450/GLSL460 parser." 7 | keywords = ["GLSL", "OpenGL", "SPIR-V", "parser"] 8 | categories = ["parsing", "rendering"] 9 | homepage = "https://github.com/phaazon/glsl" 10 | repository = "https://github.com/phaazon/glsl" 11 | documentation = "https://docs.rs/glsl" 12 | readme = "README.md" 13 | 14 | edition = "2018" 15 | 16 | [features] 17 | spirv = ["shaderc"] 18 | 19 | [dependencies] 20 | nom = { version = "7", default-features = false, features = ["std"] } 21 | shaderc = { version = "0.6", optional = true } 22 | -------------------------------------------------------------------------------- /glsl/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Dimitri Sabadie 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Dimitri Sabadie nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /glsl/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/phaazon/glsl.svg?branch=master)](https://travis-ci.org/phaazon/glsl) 2 | [![crates.io](https://img.shields.io/crates/v/glsl.svg)](https://crates.io/crates/glsl) 3 | [![docs.rs](https://docs.rs/glsl/badge.svg)](https://docs.rs/glsl) 4 | ![License](https://img.shields.io/badge/license-BSD3-blue.svg?style=flat) 5 | 6 | 7 | 8 | This crate is a GLSL450/GLSL460 compiler. It’s able to parse valid GLSL formatted source into 9 | an abstract syntax tree (AST). That AST can then be transformed into SPIR-V, your own format or 10 | even folded back to a raw GLSL [`String`] (think of a minifier, for instance). 11 | 12 | You’ll find several modules: 13 | 14 | - [`parser`], which exports the parsing interface. This is the place you will get most 15 | interesting types and traits, such as [`Parse`] and [`ParseError`]. 16 | - [`syntax`], which exports the AST and language definitions. If you look into destructuring, 17 | transpiling or getting information on the GLSL code that got parsed, you will likely 18 | manipulate objects which types are defined in this module. 19 | - [`transpiler`], which provides you with GLSL transpilers. For instance, you will find _GLSL 20 | to GLSL_ transpiler, _GLSL to SPIR-V_ transpiler, etc. 21 | - [`visitor`](visitor), which gives you a way to visit AST nodes and mutate them, both with 22 | inner and outer mutation. 23 | 24 | Feel free to inspect those modules for further information. 25 | 26 | # GLSL parsing and transpiling 27 | 28 | Parsing is the most common operation you will do. It is not required per-se (you can still 29 | create your AST by hand or use [glsl-quasiquote] to create it at compile-time by using the GLSL 30 | syntax directly in Rust). However, in this section, we are going to see how we can parse from a 31 | string to several GLSL types. 32 | 33 | ## Parsing architecture 34 | 35 | Basically, the [`Parse`] trait gives you all you need to start parsing. This crate is designed 36 | around the concept of type-driven parsing: parsers are hidden and you just have to state what 37 | result type you expect. 38 | 39 | The most common type you want to parse to is [`TranslationUnit`], which represents a set of 40 | [`ExternalDeclaration`]s. An [`ExternalDeclaration`] is just a declaration at the top-most level 41 | of a shader. It can be a global, uniform declarations, vertex attributes, a function, a 42 | structure, etc. In that sense, a [`TranslationUnit`] is akin to a shader stage (vertex shader, 43 | fragment shader, etc.). 44 | 45 | You can parse any type that implements [`Parse`]. Parsers are mostly sensible to external 46 | blanks, which means that parsing an [`Expr`] starting with a blank will not work (this is not 47 | true for a [`TranslationUnit`] as it’s exceptionnally more permissive). 48 | 49 | ## Parsing an expression 50 | 51 | Let’s try to parse an expression. 52 | 53 | ```rust 54 | use glsl::parser::Parse as _; 55 | use glsl::syntax::Expr; 56 | 57 | let glsl = "(vec3(r, g, b) * cos(t * PI * .5)).xxz"; 58 | let expr = Expr::parse(glsl); 59 | assert!(expr.is_ok()); 60 | ``` 61 | 62 | Here, `expr` is an AST which type is `Result` that represents the GLSL 63 | expression `(vec3(r, g, b) * cos(t * PI * .5)).xxz`, which is an outer (scalar) multiplication 64 | of an RGB color by a cosine of a time, the whole thing being 65 | [swizzled](https://en.wikipedia.org/wiki/Swizzling_\(computer_graphics\)) with XXZ. It is your 66 | responsibility to check if the parsing process has succeeded. 67 | 68 | In the previous example, the GLSL string is a constant and hardcoded. It could come from a file, 69 | network or built on the fly, but in the case of constant GLSL code, it would be preferable not 70 | to parse the string at runtime, right? Well, [glsl-quasiquote] is there exactly for that. You 71 | can ask **rustc** to parse that string and, if the parsing has succeeded, inject the AST 72 | directly into your code. No [`Result`], just the pure AST. Have a look at [glsl-quasiquote] for 73 | further details. 74 | 75 | ## Parsing a whole shader 76 | 77 | Vertex shaders, geometry shaders, fragment shaders and control and evaluation tessellation 78 | shaders can be parsed the same way by using one of the `TranslationUnit` or `ShaderStage` types. 79 | 80 | Here, a simple vertex shader being parsed. 81 | 82 | ```rust 83 | use glsl::parser::Parse as _; 84 | use glsl::syntax::ShaderStage; 85 | 86 | let glsl = " 87 | layout (location = 0) in vec3 pos; 88 | layout (location = 1) in vec4 col; 89 | 90 | out vec4 v_col; 91 | 92 | uniform mat4 projview; 93 | 94 | void main() { 95 | v_col = col; // pass color to the next stage 96 | gl_Position = projview * vec4(pos, 1.); 97 | } 98 | "; 99 | let stage = ShaderStage::parse(glsl); 100 | assert!(stage.is_ok()); 101 | ``` 102 | 103 | ## Visiting AST nodes 104 | 105 | The crate is also getting more and more combinators and functions to transform the AST or create 106 | nodes with regular Rust. The [`Visitor`] trait will be a great friend of yours when you will 107 | want to cope with deep mutation, filtering and validation. Have a look at the 108 | [`visitor`](visitor) module for a tutorial on how to use visitors. 109 | 110 | # About the GLSL versions… 111 | 112 | This crate can parse both GLSL450 and GLSL460 formatted input sources. At the language level, 113 | the difference between GLSL450 and GLSL460 is pretty much nothing, so both cases are covered. 114 | 115 | > If you’re wondering, the only difference between both versions is that in GLSL460, it’s 116 | > authorized to have semicolons (`;`) on empty lines at top-level in a shader. 117 | 118 | [glsl-quasiquote]: https://crates.io/crates/glsl-quasiquote 119 | [`Parse`]: crate::parser::Parse 120 | [`ParseError`]: crate::parser::ParseError 121 | [`ExternalDeclaration`]: crate::syntax::ExternalDeclaration 122 | [`TranslationUnit`]: crate::syntax::TranslationUnit 123 | [`Expr`]: crate::syntax::Expr 124 | [`Visitor`]: crate::visitor::Visitor 125 | 126 | 127 | -------------------------------------------------------------------------------- /glsl/data/tests/buffer_block_0.glsl: -------------------------------------------------------------------------------- 1 | buffer Foo { 2 | char tiles[]; 3 | } main_tiles; 4 | 5 | void main() { 6 | } 7 | -------------------------------------------------------------------------------- /glsl/data/tests/layout_buffer_block_0.glsl: -------------------------------------------------------------------------------- 1 | layout(set = 0, binding = 0) buffer Foo { 2 | char a; 3 | } foo; 4 | -------------------------------------------------------------------------------- /glsl/fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | -------------------------------------------------------------------------------- /glsl/fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "glsl-fuzz" 4 | version = "0.0.1" 5 | authors = ["Automatically generated"] 6 | publish = false 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies.glsl] 12 | path = ".." 13 | [dependencies.libfuzzer-sys] 14 | git = "https://github.com/rust-fuzz/libfuzzer-sys.git" 15 | 16 | [dependencies.nom] 17 | version = "3.2" 18 | default-features = true 19 | features = ["verbose-errors"] 20 | 21 | # Prevent this from interfering with workspaces 22 | [workspace] 23 | members = ["."] 24 | 25 | [[bin]] 26 | name = "parse_expr" 27 | path = "fuzz_targets/parse_expr.rs" 28 | 29 | [[bin]] 30 | name = "parse_integral_lit" 31 | path = "fuzz_targets/parse_integral_lit.rs" 32 | 33 | [[bin]] 34 | name = "transpile_expr" 35 | path = "fuzz_targets/transpile_expr.rs" 36 | 37 | [[bin]] 38 | name = "parse_translation_unit" 39 | path = "fuzz_targets/parse_translation_unit.rs" 40 | -------------------------------------------------------------------------------- /glsl/fuzz/fuzz_targets/parse_expr.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate glsl; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | glsl::parsers::expr(data); 8 | }); 9 | -------------------------------------------------------------------------------- /glsl/fuzz/fuzz_targets/parse_integral_lit.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate glsl; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | glsl::parsers::integral_lit(data); 8 | }); 9 | -------------------------------------------------------------------------------- /glsl/fuzz/fuzz_targets/parse_translation_unit.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate glsl; 5 | 6 | fuzz_target!(|data: &[u8]| { 7 | glsl::parsers::translation_unit(data); 8 | }); 9 | -------------------------------------------------------------------------------- /glsl/fuzz/fuzz_targets/transpile_expr.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #[macro_use] 3 | extern crate libfuzzer_sys; 4 | extern crate glsl; 5 | extern crate nom; 6 | use nom::IResult; 7 | use std::str::from_utf8; 8 | 9 | fuzz_target!(|data: &[u8]| { 10 | if from_utf8(data).is_ok() { 11 | let expr = glsl::parsers::expr(data); 12 | match expr { 13 | IResult::Done(_, expr) => { 14 | let mut output = String::new(); 15 | glsl::transpiler::glsl::show_expr(&mut output, &expr); 16 | output.push(';'); 17 | let readback_expr = glsl::parsers::expr(output.as_bytes()); 18 | match readback_expr { 19 | IResult::Done(_, readback_expr) => assert_eq!(expr, readback_expr), 20 | _ => panic!("Failed to re-parse '{}'", output), 21 | } 22 | } 23 | _ => {} 24 | } 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /glsl/src/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` 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)] 120 | mod parse_tests; 121 | pub mod parser; 122 | mod parsers; 123 | pub mod syntax; 124 | pub mod transpiler; 125 | pub mod visitor; 126 | -------------------------------------------------------------------------------- /glsl/src/parser.rs: -------------------------------------------------------------------------------- 1 | //! GLSL parsing. 2 | //! 3 | //! This module gives you several functions and types to deal with GLSL parsing, transforming an 4 | //! input source into an AST. The AST is defined in the [`syntax`] module. 5 | //! 6 | //! You want to use the [`Parse`]’s methods to get starting with parsing and pattern match on 7 | //! the resulting [`Result`]. In case of an error, you can inspect the content of the [`ParseError`] 8 | //! object in the `Err` variant. 9 | //! 10 | //! [`Parse`]: crate::parser::Parse 11 | //! [`ParseError`]: crate::parser::ParseError 12 | 13 | use nom::error::convert_error; 14 | use nom::Err as NomErr; 15 | use std::fmt; 16 | 17 | use crate::parsers::ParserResult; 18 | use crate::syntax; 19 | 20 | /// A parse error. It contains a [`String`] giving information on the reason why the parser failed. 21 | #[derive(Clone, Debug, Eq, PartialEq)] 22 | pub struct ParseError { 23 | pub info: String, 24 | } 25 | 26 | impl std::error::Error for ParseError {} 27 | 28 | impl fmt::Display for ParseError { 29 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 30 | write!(f, "error: {}", self.info) 31 | } 32 | } 33 | 34 | /// Run a parser `P` on a given `[&str`] input. 35 | pub(crate) fn run_parser(source: &str, parser: P) -> Result 36 | where 37 | P: FnOnce(&str) -> ParserResult, 38 | { 39 | match parser(source) { 40 | Ok((_, x)) => Ok(x), 41 | 42 | Err(e) => match e { 43 | NomErr::Incomplete(_) => Err(ParseError { 44 | info: "incomplete parser".to_owned(), 45 | }), 46 | 47 | NomErr::Error(err) | NomErr::Failure(err) => { 48 | let info = convert_error(source, err); 49 | Err(ParseError { info }) 50 | } 51 | }, 52 | } 53 | } 54 | 55 | /// Class of types that can be parsed. 56 | /// 57 | /// This trait exposes the [`Parse::parse`] function that can be used to parse GLSL types. 58 | /// 59 | /// The methods from this trait are the standard way to parse data into GLSL ASTs. 60 | pub trait Parse: Sized { 61 | /// Parse from a string slice. 62 | fn parse(source: B) -> Result 63 | where 64 | B: AsRef; 65 | } 66 | 67 | /// Macro to implement Parse for a given type. 68 | macro_rules! impl_parse { 69 | ($type_name:ty, $parser_name:ident) => { 70 | impl Parse for $type_name { 71 | fn parse(source: B) -> Result 72 | where 73 | B: AsRef, 74 | { 75 | run_parser(source.as_ref(), $crate::parsers::$parser_name) 76 | } 77 | } 78 | }; 79 | } 80 | 81 | impl_parse!(syntax::Identifier, identifier); 82 | impl_parse!(syntax::TypeSpecifierNonArray, type_specifier_non_array); 83 | impl_parse!(syntax::TypeSpecifier, type_specifier); 84 | impl_parse!(syntax::UnaryOp, unary_op); 85 | impl_parse!(syntax::StructFieldSpecifier, struct_field_specifier); 86 | impl_parse!(syntax::StructSpecifier, struct_specifier); 87 | impl_parse!(syntax::StorageQualifier, storage_qualifier); 88 | impl_parse!(syntax::LayoutQualifier, layout_qualifier); 89 | impl_parse!(syntax::PrecisionQualifier, precision_qualifier); 90 | impl_parse!(syntax::InterpolationQualifier, interpolation_qualifier); 91 | impl_parse!(syntax::TypeQualifier, type_qualifier); 92 | impl_parse!(syntax::TypeQualifierSpec, type_qualifier_spec); 93 | impl_parse!(syntax::FullySpecifiedType, fully_specified_type); 94 | impl_parse!(syntax::ArraySpecifier, array_specifier); 95 | impl_parse!(syntax::Expr, expr); 96 | impl_parse!(syntax::Declaration, declaration); 97 | impl_parse!(syntax::FunctionPrototype, function_prototype); 98 | impl_parse!(syntax::InitDeclaratorList, init_declarator_list); 99 | impl_parse!(syntax::SingleDeclaration, single_declaration); 100 | impl_parse!(syntax::Initializer, initializer); 101 | impl_parse!(syntax::FunIdentifier, function_identifier); 102 | impl_parse!(syntax::AssignmentOp, assignment_op); 103 | impl_parse!(syntax::SimpleStatement, simple_statement); 104 | impl_parse!(syntax::ExprStatement, expr_statement); 105 | impl_parse!(syntax::SelectionStatement, selection_statement); 106 | impl_parse!(syntax::SwitchStatement, switch_statement); 107 | impl_parse!(syntax::CaseLabel, case_label); 108 | impl_parse!(syntax::IterationStatement, iteration_statement); 109 | impl_parse!(syntax::JumpStatement, jump_statement); 110 | impl_parse!(syntax::Condition, condition); 111 | impl_parse!(syntax::Statement, statement); 112 | impl_parse!(syntax::CompoundStatement, compound_statement); 113 | impl_parse!(syntax::FunctionDefinition, function_definition); 114 | impl_parse!(syntax::ExternalDeclaration, external_declaration); 115 | impl_parse!(syntax::TranslationUnit, translation_unit); 116 | impl_parse!(syntax::Preprocessor, preprocessor); 117 | impl_parse!(syntax::PreprocessorVersion, pp_version); 118 | impl_parse!(syntax::PreprocessorVersionProfile, pp_version_profile); 119 | impl_parse!(syntax::PreprocessorExtensionName, pp_extension_name); 120 | impl_parse!(syntax::PreprocessorExtensionBehavior, pp_extension_behavior); 121 | impl_parse!(syntax::PreprocessorExtension, pp_extension); 122 | -------------------------------------------------------------------------------- /glsl/src/parsers/nom_helpers.rs: -------------------------------------------------------------------------------- 1 | //! Various nom parser helpers. 2 | 3 | use nom::branch::alt; 4 | use nom::bytes::complete::tag; 5 | use nom::character::complete::{anychar, line_ending, multispace1}; 6 | use nom::combinator::{map, recognize, value}; 7 | use nom::error::{ErrorKind, VerboseError, VerboseErrorKind}; 8 | use nom::multi::fold_many0; 9 | use nom::{Err as NomErr, IResult}; 10 | 11 | pub type ParserResult<'a, O> = IResult<&'a str, O, VerboseError<&'a str>>; 12 | 13 | // A constant parser that just forwards the value it’s parametered with without reading anything 14 | // from the input. Especially useful as “fallback” in an alternative parser. 15 | pub fn cnst<'a, T, E>(t: T) -> impl FnMut(&'a str) -> Result<(&'a str, T), E> 16 | where 17 | T: 'a + Clone, 18 | { 19 | move |i| Ok((i, t.clone())) 20 | } 21 | 22 | // End-of-input parser. 23 | // 24 | // Yields `()` if the parser is at the end of the input; an error otherwise. 25 | pub fn eoi(i: &str) -> ParserResult<()> { 26 | if i.is_empty() { 27 | Ok((i, ())) 28 | } else { 29 | Err(NomErr::Error(VerboseError { 30 | errors: vec![(i, VerboseErrorKind::Nom(ErrorKind::Eof))], 31 | })) 32 | } 33 | } 34 | 35 | // A newline parser that accepts: 36 | // 37 | // - A newline. 38 | // - The end of input. 39 | pub fn eol(i: &str) -> ParserResult<()> { 40 | alt(( 41 | eoi, // this one goes first because it’s very cheap 42 | value((), line_ending), 43 | ))(i) 44 | } 45 | 46 | // Apply the `f` parser until `g` succeeds. Both parsers consume the input. 47 | pub fn till<'a, A, B, F, G>(mut f: F, mut g: G) -> impl FnMut(&'a str) -> ParserResult<'a, ()> 48 | where 49 | F: FnMut(&'a str) -> ParserResult<'a, A>, 50 | G: FnMut(&'a str) -> ParserResult<'a, B>, 51 | { 52 | move |mut i| loop { 53 | if let Ok((i2, _)) = g(i) { 54 | break Ok((i2, ())); 55 | } 56 | 57 | let (i2, _) = f(i)?; 58 | i = i2; 59 | } 60 | } 61 | 62 | // A version of many0 that discards the result of the parser, preventing allocating. 63 | pub fn many0_<'a, A, F>(mut f: F) -> impl FnMut(&'a str) -> ParserResult<'a, ()> 64 | where 65 | F: FnMut(&'a str) -> ParserResult<'a, A>, 66 | { 67 | move |i| fold_many0(&mut f, || (), |_, _| ())(i) 68 | } 69 | 70 | /// Parse a string until the end of line. 71 | /// 72 | /// This parser accepts the multiline annotation (\) to break the string on several lines. 73 | /// 74 | /// Discard any leading newline. 75 | pub fn str_till_eol(i: &str) -> ParserResult<&str> { 76 | map( 77 | recognize(till(alt((value((), tag("\\\n")), value((), anychar))), eol)), 78 | |i| { 79 | if i.as_bytes().last() == Some(&b'\n') { 80 | &i[0..i.len() - 1] 81 | } else { 82 | i 83 | } 84 | }, 85 | )(i) 86 | } 87 | 88 | // Blank base parser. 89 | // 90 | // This parser succeeds with multispaces and multiline annotation. 91 | // 92 | // Taylor Swift loves it. 93 | pub fn blank_space(i: &str) -> ParserResult<&str> { 94 | recognize(many0_(alt((multispace1, tag("\\\n")))))(i) 95 | } 96 | -------------------------------------------------------------------------------- /glsl/src/syntax.rs: -------------------------------------------------------------------------------- 1 | //! GLSL abstract syntax tree and grammar. 2 | //! 3 | //! This module exports all the grammar syntax that defines GLSL. You’ll be handling ASTs 4 | //! representing your GLSL source. 5 | //! 6 | //! The most external form of a GLSL parsed AST is [`TranslationUnit`] (a shader). Some parts of the 7 | //! tree are *boxed*. This is due to two facts: 8 | //! 9 | //! - Recursion is used, hence we need a way to give our types a static size. 10 | //! - Because of some very deep variants, runtime size would explode if no indirection weren’t 11 | //! in place. 12 | //! 13 | //! The types are commented so feel free to inspect each of theme. As a starter, you should read 14 | //! the documentation of [`Expr`], [`FunctionDefinition`], [`Statement`] and [`TranslationUnit`]. 15 | //! 16 | //! [`Statement`]: crate::syntax::Statement 17 | //! [`TranslationUnit`]: crate::syntax::TranslationUnit 18 | //! [`Expr`]: crate::syntax::Expr 19 | //! [`FunctionDefinition`]: crate::syntax::FunctionDefinition 20 | 21 | use std::fmt; 22 | use std::iter::{once, FromIterator}; 23 | use std::ops::{Deref, DerefMut}; 24 | 25 | /// A non-empty [`Vec`]. It has at least one element. 26 | #[derive(Clone, Debug, PartialEq)] 27 | pub struct NonEmpty(pub Vec); 28 | 29 | impl NonEmpty { 30 | /// Construct a non-empty from an iterator. 31 | /// 32 | /// # Errors 33 | /// 34 | /// `None` if the iterator yields no value. 35 | pub fn from_non_empty_iter(iter: I) -> Option 36 | where 37 | I: IntoIterator, 38 | { 39 | let vec: Vec<_> = iter.into_iter().collect(); 40 | 41 | if vec.is_empty() { 42 | None 43 | } else { 44 | Some(NonEmpty(vec)) 45 | } 46 | } 47 | 48 | /// Move a new item at the end of the non-empty. 49 | pub fn push(&mut self, item: T) { 50 | self.0.push(item); 51 | } 52 | 53 | /// Move out the last element of the non-empty. 54 | /// 55 | /// # Errors 56 | /// 57 | /// This function returns `None` if called on a non-empty that contains a single element. 58 | pub fn pop(&mut self) -> Option { 59 | if self.0.len() == 1 { 60 | None 61 | } else { 62 | self.0.pop() 63 | } 64 | } 65 | } 66 | 67 | impl IntoIterator for NonEmpty { 68 | type IntoIter = as IntoIterator>::IntoIter; 69 | type Item = T; 70 | 71 | fn into_iter(self) -> Self::IntoIter { 72 | self.0.into_iter() 73 | } 74 | } 75 | 76 | impl<'a, T> IntoIterator for &'a NonEmpty { 77 | type IntoIter = <&'a Vec as IntoIterator>::IntoIter; 78 | type Item = &'a T; 79 | 80 | fn into_iter(self) -> Self::IntoIter { 81 | self.0.iter() 82 | } 83 | } 84 | 85 | impl<'a, T> IntoIterator for &'a mut NonEmpty { 86 | type IntoIter = <&'a mut Vec as IntoIterator>::IntoIter; 87 | type Item = &'a mut T; 88 | 89 | fn into_iter(self) -> Self::IntoIter { 90 | self.0.iter_mut() 91 | } 92 | } 93 | 94 | impl Extend for NonEmpty { 95 | fn extend(&mut self, iter: I) 96 | where 97 | I: IntoIterator, 98 | { 99 | self.0.extend(iter); 100 | } 101 | } 102 | 103 | /// A path literal. 104 | #[derive(Clone, Debug, PartialEq)] 105 | pub enum Path { 106 | /// Specified with angle brackets. 107 | Absolute(String), 108 | /// Specified with double quotes. 109 | Relative(String), 110 | } 111 | 112 | /// Error that might occur when creating a new [`Identifier`]. 113 | #[derive(Debug)] 114 | pub enum IdentifierError { 115 | StartsWithDigit, 116 | ContainsNonASCIIAlphaNum, 117 | } 118 | 119 | impl std::error::Error for IdentifierError {} 120 | 121 | impl fmt::Display for IdentifierError { 122 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 123 | match *self { 124 | IdentifierError::StartsWithDigit => f.write_str("starts starts with a digit"), 125 | 126 | IdentifierError::ContainsNonASCIIAlphaNum => { 127 | f.write_str("contains at least one non-alphanumeric ASCII character") 128 | } 129 | } 130 | } 131 | } 132 | 133 | /// A generic identifier. 134 | #[derive(Clone, Debug, PartialEq)] 135 | pub struct Identifier(pub String); 136 | 137 | impl Identifier { 138 | /// Create a new [`Identifier`]. 139 | /// 140 | /// # Errors 141 | /// 142 | /// This function will fail if the identifier starts with a digit or contains non-alphanumeric 143 | /// ASCII characters. 144 | pub fn new(name: N) -> Result 145 | where 146 | N: Into, 147 | { 148 | let name = name.into(); 149 | 150 | if name 151 | .chars() 152 | .next() 153 | .map(|c| c.is_ascii_alphabetic() || c == '_') 154 | == Some(false) 155 | { 156 | // check the first letter is not a digit 157 | Err(IdentifierError::StartsWithDigit) 158 | } else if name.contains(|c: char| !(c.is_ascii_alphanumeric() || c == '_')) { 159 | // check we only have ASCII alphanumeric characters 160 | Err(IdentifierError::ContainsNonASCIIAlphaNum) 161 | } else { 162 | Ok(Identifier(name)) 163 | } 164 | } 165 | 166 | /// Get the string representation of the identifier. 167 | pub fn as_str(&self) -> &str { 168 | &self.0 169 | } 170 | } 171 | 172 | impl<'a> From<&'a str> for Identifier { 173 | fn from(s: &str) -> Self { 174 | Identifier(s.to_owned()) 175 | } 176 | } 177 | 178 | impl From for Identifier { 179 | fn from(s: String) -> Self { 180 | Identifier(s) 181 | } 182 | } 183 | 184 | impl fmt::Display for Identifier { 185 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 186 | self.0.fmt(f) 187 | } 188 | } 189 | 190 | /// Any type name. 191 | #[derive(Clone, Debug, PartialEq)] 192 | pub struct TypeName(pub String); 193 | 194 | impl TypeName { 195 | /// Create a new [`TypeName`]. 196 | /// 197 | /// # Errors 198 | /// 199 | /// This function will fail if the type name starts with a digit or contains non-alphanumeric 200 | /// ASCII characters. 201 | pub fn new(name: N) -> Result 202 | where 203 | N: Into, 204 | { 205 | // build as identifier and unwrap into type name 206 | let Identifier(tn) = Identifier::new(name)?; 207 | Ok(TypeName(tn)) 208 | } 209 | 210 | /// Get the string representation of the type name. 211 | pub fn as_str(&self) -> &str { 212 | &self.0 213 | } 214 | } 215 | 216 | impl<'a> From<&'a str> for TypeName { 217 | fn from(s: &str) -> Self { 218 | TypeName(s.to_owned()) 219 | } 220 | } 221 | 222 | impl From for TypeName { 223 | fn from(s: String) -> Self { 224 | TypeName(s) 225 | } 226 | } 227 | 228 | impl fmt::Display for TypeName { 229 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { 230 | self.0.fmt(f) 231 | } 232 | } 233 | 234 | /// Type specifier (non-array). 235 | #[derive(Clone, Debug, PartialEq)] 236 | pub enum TypeSpecifierNonArray { 237 | // transparent types 238 | Void, 239 | Bool, 240 | Int, 241 | UInt, 242 | Float, 243 | Double, 244 | Vec2, 245 | Vec3, 246 | Vec4, 247 | DVec2, 248 | DVec3, 249 | DVec4, 250 | BVec2, 251 | BVec3, 252 | BVec4, 253 | IVec2, 254 | IVec3, 255 | IVec4, 256 | UVec2, 257 | UVec3, 258 | UVec4, 259 | Mat2, 260 | Mat3, 261 | Mat4, 262 | Mat23, 263 | Mat24, 264 | Mat32, 265 | Mat34, 266 | Mat42, 267 | Mat43, 268 | DMat2, 269 | DMat3, 270 | DMat4, 271 | DMat23, 272 | DMat24, 273 | DMat32, 274 | DMat34, 275 | DMat42, 276 | DMat43, 277 | // floating point opaque types 278 | Sampler1D, 279 | Image1D, 280 | Sampler2D, 281 | Image2D, 282 | Sampler3D, 283 | Image3D, 284 | SamplerCube, 285 | ImageCube, 286 | Sampler2DRect, 287 | Image2DRect, 288 | Sampler1DArray, 289 | Image1DArray, 290 | Sampler2DArray, 291 | Image2DArray, 292 | SamplerBuffer, 293 | ImageBuffer, 294 | Sampler2DMS, 295 | Image2DMS, 296 | Sampler2DMSArray, 297 | Image2DMSArray, 298 | SamplerCubeArray, 299 | ImageCubeArray, 300 | Sampler1DShadow, 301 | Sampler2DShadow, 302 | Sampler2DRectShadow, 303 | Sampler1DArrayShadow, 304 | Sampler2DArrayShadow, 305 | SamplerCubeShadow, 306 | SamplerCubeArrayShadow, 307 | // signed integer opaque types 308 | ISampler1D, 309 | IImage1D, 310 | ISampler2D, 311 | IImage2D, 312 | ISampler3D, 313 | IImage3D, 314 | ISamplerCube, 315 | IImageCube, 316 | ISampler2DRect, 317 | IImage2DRect, 318 | ISampler1DArray, 319 | IImage1DArray, 320 | ISampler2DArray, 321 | IImage2DArray, 322 | ISamplerBuffer, 323 | IImageBuffer, 324 | ISampler2DMS, 325 | IImage2DMS, 326 | ISampler2DMSArray, 327 | IImage2DMSArray, 328 | ISamplerCubeArray, 329 | IImageCubeArray, 330 | // unsigned integer opaque types 331 | AtomicUInt, 332 | USampler1D, 333 | UImage1D, 334 | USampler2D, 335 | UImage2D, 336 | USampler3D, 337 | UImage3D, 338 | USamplerCube, 339 | UImageCube, 340 | USampler2DRect, 341 | UImage2DRect, 342 | USampler1DArray, 343 | UImage1DArray, 344 | USampler2DArray, 345 | UImage2DArray, 346 | USamplerBuffer, 347 | UImageBuffer, 348 | USampler2DMS, 349 | UImage2DMS, 350 | USampler2DMSArray, 351 | UImage2DMSArray, 352 | USamplerCubeArray, 353 | UImageCubeArray, 354 | Struct(StructSpecifier), 355 | TypeName(TypeName), 356 | } 357 | 358 | /// Type specifier. 359 | #[derive(Clone, Debug, PartialEq)] 360 | pub struct TypeSpecifier { 361 | pub ty: TypeSpecifierNonArray, 362 | pub array_specifier: Option, 363 | } 364 | 365 | impl TypeSpecifier { 366 | pub fn new(ty: TypeSpecifierNonArray) -> Self { 367 | TypeSpecifier { 368 | ty, 369 | array_specifier: None, 370 | } 371 | } 372 | } 373 | 374 | impl From for TypeSpecifier { 375 | fn from(ty: TypeSpecifierNonArray) -> Self { 376 | TypeSpecifier::new(ty) 377 | } 378 | } 379 | 380 | /// Struct specifier. Used to create new, user-defined types. 381 | #[derive(Clone, Debug, PartialEq)] 382 | pub struct StructSpecifier { 383 | pub name: Option, 384 | pub fields: NonEmpty, 385 | } 386 | 387 | /// Struct field specifier. Used to add fields to struct specifiers. 388 | #[derive(Clone, Debug, PartialEq)] 389 | pub struct StructFieldSpecifier { 390 | pub qualifier: Option, 391 | pub ty: TypeSpecifier, 392 | pub identifiers: NonEmpty, // several identifiers of the same type 393 | } 394 | 395 | impl StructFieldSpecifier { 396 | /// Create a struct field. 397 | pub fn new(identifier: A, ty: T) -> Self 398 | where 399 | A: Into, 400 | T: Into, 401 | { 402 | StructFieldSpecifier { 403 | qualifier: None, 404 | ty: ty.into(), 405 | identifiers: NonEmpty(vec![identifier.into()]), 406 | } 407 | } 408 | 409 | /// Create a list of struct fields that all have the same type. 410 | pub fn new_many(identifiers: I, ty: TypeSpecifier) -> Self 411 | where 412 | I: IntoIterator, 413 | { 414 | StructFieldSpecifier { 415 | qualifier: None, 416 | ty, 417 | identifiers: NonEmpty(identifiers.into_iter().collect()), 418 | } 419 | } 420 | } 421 | 422 | /// An identifier with an optional array specifier. 423 | #[derive(Clone, Debug, PartialEq)] 424 | pub struct ArrayedIdentifier { 425 | pub ident: Identifier, 426 | pub array_spec: Option, 427 | } 428 | 429 | impl ArrayedIdentifier { 430 | pub fn new(ident: I, array_spec: AS) -> Self 431 | where 432 | I: Into, 433 | AS: Into>, 434 | { 435 | ArrayedIdentifier { 436 | ident: ident.into(), 437 | array_spec: array_spec.into(), 438 | } 439 | } 440 | } 441 | 442 | impl<'a> From<&'a str> for ArrayedIdentifier { 443 | fn from(ident: &str) -> Self { 444 | ArrayedIdentifier { 445 | ident: Identifier(ident.to_owned()), 446 | array_spec: None, 447 | } 448 | } 449 | } 450 | 451 | impl From for ArrayedIdentifier { 452 | fn from(ident: Identifier) -> Self { 453 | ArrayedIdentifier { 454 | ident, 455 | array_spec: None, 456 | } 457 | } 458 | } 459 | 460 | /// Type qualifier. 461 | #[derive(Clone, Debug, PartialEq)] 462 | pub struct TypeQualifier { 463 | pub qualifiers: NonEmpty, 464 | } 465 | 466 | /// Type qualifier spec. 467 | #[derive(Clone, Debug, PartialEq)] 468 | pub enum TypeQualifierSpec { 469 | Storage(StorageQualifier), 470 | Layout(LayoutQualifier), 471 | Precision(PrecisionQualifier), 472 | Interpolation(InterpolationQualifier), 473 | Invariant, 474 | Precise, 475 | } 476 | 477 | /// Storage qualifier. 478 | #[derive(Clone, Debug, PartialEq)] 479 | pub enum StorageQualifier { 480 | Const, 481 | InOut, 482 | In, 483 | Out, 484 | Centroid, 485 | Patch, 486 | Sample, 487 | Uniform, 488 | Attribute, 489 | Varying, 490 | Buffer, 491 | Shared, 492 | Coherent, 493 | Volatile, 494 | Restrict, 495 | ReadOnly, 496 | WriteOnly, 497 | Subroutine(Vec), 498 | } 499 | 500 | /// Layout qualifier. 501 | #[derive(Clone, Debug, PartialEq)] 502 | pub struct LayoutQualifier { 503 | pub ids: NonEmpty, 504 | } 505 | 506 | /// Layout qualifier spec. 507 | #[derive(Clone, Debug, PartialEq)] 508 | pub enum LayoutQualifierSpec { 509 | Identifier(Identifier, Option>), 510 | Shared, 511 | } 512 | 513 | /// Precision qualifier. 514 | #[derive(Clone, Debug, PartialEq)] 515 | pub enum PrecisionQualifier { 516 | High, 517 | Medium, 518 | Low, 519 | } 520 | 521 | /// Interpolation qualifier. 522 | #[derive(Clone, Debug, PartialEq)] 523 | pub enum InterpolationQualifier { 524 | Smooth, 525 | Flat, 526 | NoPerspective, 527 | } 528 | 529 | /// Fully specified type. 530 | #[derive(Clone, Debug, PartialEq)] 531 | pub struct FullySpecifiedType { 532 | pub qualifier: Option, 533 | pub ty: TypeSpecifier, 534 | } 535 | 536 | impl FullySpecifiedType { 537 | pub fn new(ty: TypeSpecifierNonArray) -> Self { 538 | FullySpecifiedType { 539 | qualifier: None, 540 | ty: TypeSpecifier { 541 | ty, 542 | array_specifier: None, 543 | }, 544 | } 545 | } 546 | } 547 | 548 | impl From for FullySpecifiedType { 549 | fn from(ty: TypeSpecifierNonArray) -> Self { 550 | FullySpecifiedType::new(ty) 551 | } 552 | } 553 | 554 | /// Dimensionality of an array. 555 | #[derive(Clone, Debug, PartialEq)] 556 | pub struct ArraySpecifier { 557 | /// List of all the dimensions – possibly unsized or explicitly-sized. 558 | pub dimensions: NonEmpty, 559 | } 560 | 561 | /// One array specifier dimension. 562 | #[derive(Clone, Debug, PartialEq)] 563 | pub enum ArraySpecifierDimension { 564 | Unsized, 565 | ExplicitlySized(Box), 566 | } 567 | 568 | /// A declaration. 569 | #[derive(Clone, Debug, PartialEq)] 570 | pub enum Declaration { 571 | FunctionPrototype(FunctionPrototype), 572 | InitDeclaratorList(InitDeclaratorList), 573 | Precision(PrecisionQualifier, TypeSpecifier), 574 | Block(Block), 575 | Global(TypeQualifier, Vec), 576 | } 577 | 578 | /// A general purpose block, containing fields and possibly a list of declared identifiers. Semantic 579 | /// is given with the storage qualifier. 580 | #[derive(Clone, Debug, PartialEq)] 581 | pub struct Block { 582 | pub qualifier: TypeQualifier, 583 | pub name: Identifier, 584 | pub fields: Vec, 585 | pub identifier: Option, 586 | } 587 | 588 | /// Function identifier. 589 | #[derive(Clone, Debug, PartialEq)] 590 | pub enum FunIdentifier { 591 | Identifier(Identifier), 592 | Expr(Box), 593 | } 594 | 595 | impl FunIdentifier { 596 | pub(crate) fn into_expr(self) -> Option { 597 | match self { 598 | FunIdentifier::Identifier(..) => None, 599 | FunIdentifier::Expr(expr) => Some(*expr), 600 | } 601 | } 602 | } 603 | 604 | /// Function prototype. 605 | #[derive(Clone, Debug, PartialEq)] 606 | pub struct FunctionPrototype { 607 | pub ty: FullySpecifiedType, 608 | pub name: Identifier, 609 | pub parameters: Vec, 610 | } 611 | 612 | /// Function parameter declaration. 613 | #[derive(Clone, Debug, PartialEq)] 614 | pub enum FunctionParameterDeclaration { 615 | Named(Option, FunctionParameterDeclarator), 616 | Unnamed(Option, TypeSpecifier), 617 | } 618 | 619 | impl FunctionParameterDeclaration { 620 | /// Create a named function argument. 621 | pub fn new_named(ident: I, ty: T) -> Self 622 | where 623 | I: Into, 624 | T: Into, 625 | { 626 | let declator = FunctionParameterDeclarator { 627 | ty: ty.into(), 628 | ident: ident.into(), 629 | }; 630 | 631 | FunctionParameterDeclaration::Named(None, declator) 632 | } 633 | 634 | /// Create an unnamed function argument (mostly useful for interfaces / function prototypes). 635 | pub fn new_unnamed(ty: T) -> Self 636 | where 637 | T: Into, 638 | { 639 | FunctionParameterDeclaration::Unnamed(None, ty.into()) 640 | } 641 | } 642 | 643 | /// Function parameter declarator. 644 | #[derive(Clone, Debug, PartialEq)] 645 | pub struct FunctionParameterDeclarator { 646 | pub ty: TypeSpecifier, 647 | pub ident: ArrayedIdentifier, 648 | } 649 | 650 | /// Init declarator list. 651 | #[derive(Clone, Debug, PartialEq)] 652 | pub struct InitDeclaratorList { 653 | pub head: SingleDeclaration, 654 | pub tail: Vec, 655 | } 656 | 657 | /// Single declaration. 658 | #[derive(Clone, Debug, PartialEq)] 659 | pub struct SingleDeclaration { 660 | pub ty: FullySpecifiedType, 661 | pub name: Option, 662 | pub array_specifier: Option, 663 | pub initializer: Option, 664 | } 665 | 666 | /// A single declaration with implicit, already-defined type. 667 | #[derive(Clone, Debug, PartialEq)] 668 | pub struct SingleDeclarationNoType { 669 | pub ident: ArrayedIdentifier, 670 | pub initializer: Option, 671 | } 672 | 673 | /// Initializer. 674 | #[derive(Clone, Debug, PartialEq)] 675 | pub enum Initializer { 676 | Simple(Box), 677 | List(NonEmpty), 678 | } 679 | 680 | impl From for Initializer { 681 | fn from(e: Expr) -> Self { 682 | Initializer::Simple(Box::new(e)) 683 | } 684 | } 685 | 686 | /// The most general form of an expression. As you can see if you read the variant list, in GLSL, an 687 | /// assignment is an expression. This is a bit silly but think of an assignment as a statement first 688 | /// then an expression which evaluates to what the statement “returns”. 689 | /// 690 | /// An expression is either an assignment or a list (comma) of assignments. 691 | #[derive(Clone, Debug, PartialEq)] 692 | pub enum Expr { 693 | /// A variable expression, using an identifier. 694 | Variable(Identifier), 695 | /// Integral constant expression. 696 | IntConst(i32), 697 | /// Unsigned integral constant expression. 698 | UIntConst(u32), 699 | /// Boolean constant expression. 700 | BoolConst(bool), 701 | /// Single precision floating expression. 702 | FloatConst(f32), 703 | /// Double precision floating expression. 704 | DoubleConst(f64), 705 | /// A unary expression, gathering a single expression and a unary operator. 706 | Unary(UnaryOp, Box), 707 | /// A binary expression, gathering two expressions and a binary operator. 708 | Binary(BinaryOp, Box, Box), 709 | /// A ternary conditional expression, gathering three expressions. 710 | Ternary(Box, Box, Box), 711 | /// An assignment is also an expression. Gathers an expression that defines what to assign to, an 712 | /// assignment operator and the value to associate with. 713 | Assignment(Box, AssignmentOp, Box), 714 | /// Add an array specifier to an expression. 715 | Bracket(Box, ArraySpecifier), 716 | /// A functional call. It has a function identifier and a list of expressions (arguments). 717 | FunCall(FunIdentifier, Vec), 718 | /// An expression associated with a field selection (struct). 719 | Dot(Box, Identifier), 720 | /// Post-incrementation of an expression. 721 | PostInc(Box), 722 | /// Post-decrementation of an expression. 723 | PostDec(Box), 724 | /// An expression that contains several, separated with comma. 725 | Comma(Box, Box), 726 | } 727 | 728 | impl From for Expr { 729 | fn from(x: i32) -> Expr { 730 | Expr::IntConst(x) 731 | } 732 | } 733 | 734 | impl From for Expr { 735 | fn from(x: u32) -> Expr { 736 | Expr::UIntConst(x) 737 | } 738 | } 739 | 740 | impl From for Expr { 741 | fn from(x: bool) -> Expr { 742 | Expr::BoolConst(x) 743 | } 744 | } 745 | 746 | impl From for Expr { 747 | fn from(x: f32) -> Expr { 748 | Expr::FloatConst(x) 749 | } 750 | } 751 | 752 | impl From for Expr { 753 | fn from(x: f64) -> Expr { 754 | Expr::DoubleConst(x) 755 | } 756 | } 757 | 758 | /// All unary operators that exist in GLSL. 759 | #[derive(Clone, Debug, PartialEq)] 760 | pub enum UnaryOp { 761 | Inc, 762 | Dec, 763 | Add, 764 | Minus, 765 | Not, 766 | Complement, 767 | } 768 | 769 | /// All binary operators that exist in GLSL. 770 | #[derive(Clone, Debug, PartialEq)] 771 | pub enum BinaryOp { 772 | Or, 773 | Xor, 774 | And, 775 | BitOr, 776 | BitXor, 777 | BitAnd, 778 | Equal, 779 | NonEqual, 780 | LT, 781 | GT, 782 | LTE, 783 | GTE, 784 | LShift, 785 | RShift, 786 | Add, 787 | Sub, 788 | Mult, 789 | Div, 790 | Mod, 791 | } 792 | 793 | /// All possible operators for assigning expressions. 794 | #[derive(Clone, Debug, PartialEq)] 795 | pub enum AssignmentOp { 796 | Equal, 797 | Mult, 798 | Div, 799 | Mod, 800 | Add, 801 | Sub, 802 | LShift, 803 | RShift, 804 | And, 805 | Xor, 806 | Or, 807 | } 808 | 809 | /// Starting rule. 810 | #[derive(Clone, Debug, PartialEq)] 811 | pub struct TranslationUnit(pub NonEmpty); 812 | 813 | /// A shader stage. 814 | pub type ShaderStage = TranslationUnit; 815 | 816 | impl TranslationUnit { 817 | /// Construct a translation unit from an iterator representing a _non-empty_ sequence of 818 | /// [`ExternalDeclaration`]. 819 | /// 820 | /// # Errors 821 | /// 822 | /// `None` if the iterator yields no value. 823 | pub fn from_non_empty_iter(iter: I) -> Option 824 | where 825 | I: IntoIterator, 826 | { 827 | NonEmpty::from_non_empty_iter(iter).map(TranslationUnit) 828 | } 829 | } 830 | 831 | impl Deref for TranslationUnit { 832 | type Target = NonEmpty; 833 | 834 | fn deref(&self) -> &Self::Target { 835 | &self.0 836 | } 837 | } 838 | 839 | impl DerefMut for TranslationUnit { 840 | fn deref_mut(&mut self) -> &mut Self::Target { 841 | &mut self.0 842 | } 843 | } 844 | 845 | impl IntoIterator for TranslationUnit { 846 | type IntoIter = as IntoIterator>::IntoIter; 847 | type Item = ExternalDeclaration; 848 | 849 | fn into_iter(self) -> Self::IntoIter { 850 | self.0.into_iter() 851 | } 852 | } 853 | 854 | impl<'a> IntoIterator for &'a TranslationUnit { 855 | type IntoIter = <&'a NonEmpty as IntoIterator>::IntoIter; 856 | type Item = &'a ExternalDeclaration; 857 | 858 | fn into_iter(self) -> Self::IntoIter { 859 | (&self.0).into_iter() 860 | } 861 | } 862 | 863 | impl<'a> IntoIterator for &'a mut TranslationUnit { 864 | type IntoIter = <&'a mut NonEmpty as IntoIterator>::IntoIter; 865 | type Item = &'a mut ExternalDeclaration; 866 | 867 | fn into_iter(self) -> Self::IntoIter { 868 | (&mut self.0).into_iter() 869 | } 870 | } 871 | 872 | /// External declaration. 873 | #[derive(Clone, Debug, PartialEq)] 874 | pub enum ExternalDeclaration { 875 | Preprocessor(Preprocessor), 876 | FunctionDefinition(FunctionDefinition), 877 | Declaration(Declaration), 878 | } 879 | 880 | impl ExternalDeclaration { 881 | /// Create a new function. 882 | pub fn new_fn(ret_ty: T, name: N, args: A, body: S) -> Self 883 | where 884 | T: Into, 885 | N: Into, 886 | A: IntoIterator, 887 | S: IntoIterator, 888 | { 889 | ExternalDeclaration::FunctionDefinition(FunctionDefinition { 890 | prototype: FunctionPrototype { 891 | ty: ret_ty.into(), 892 | name: name.into(), 893 | parameters: args.into_iter().collect(), 894 | }, 895 | statement: CompoundStatement { 896 | statement_list: body.into_iter().collect(), 897 | }, 898 | }) 899 | } 900 | 901 | /// Create a new structure. 902 | /// 903 | /// # Errors 904 | /// 905 | /// - [`None`] if no fields are provided. GLSL forbids having empty structs. 906 | pub fn new_struct(name: N, fields: F) -> Option 907 | where 908 | N: Into, 909 | F: IntoIterator, 910 | { 911 | let fields: Vec<_> = fields.into_iter().collect(); 912 | 913 | if fields.is_empty() { 914 | None 915 | } else { 916 | Some(ExternalDeclaration::Declaration( 917 | Declaration::InitDeclaratorList(InitDeclaratorList { 918 | head: SingleDeclaration { 919 | ty: FullySpecifiedType { 920 | qualifier: None, 921 | ty: TypeSpecifier { 922 | ty: TypeSpecifierNonArray::Struct(StructSpecifier { 923 | name: Some(name.into()), 924 | fields: NonEmpty(fields.into_iter().collect()), 925 | }), 926 | array_specifier: None, 927 | }, 928 | }, 929 | name: None, 930 | array_specifier: None, 931 | initializer: None, 932 | }, 933 | tail: vec![], 934 | }), 935 | )) 936 | } 937 | } 938 | } 939 | 940 | /// Function definition. 941 | #[derive(Clone, Debug, PartialEq)] 942 | pub struct FunctionDefinition { 943 | pub prototype: FunctionPrototype, 944 | pub statement: CompoundStatement, 945 | } 946 | 947 | /// Compound statement (with no new scope). 948 | #[derive(Clone, Debug, PartialEq)] 949 | pub struct CompoundStatement { 950 | pub statement_list: Vec, 951 | } 952 | 953 | impl FromIterator for CompoundStatement { 954 | fn from_iter(iter: T) -> Self 955 | where 956 | T: IntoIterator, 957 | { 958 | CompoundStatement { 959 | statement_list: iter.into_iter().collect(), 960 | } 961 | } 962 | } 963 | 964 | /// Statement. 965 | #[derive(Clone, Debug, PartialEq)] 966 | pub enum Statement { 967 | Compound(Box), 968 | Simple(Box), 969 | } 970 | 971 | impl Statement { 972 | /// Create a case-label sequence of nested statements. 973 | pub fn new_case(case: C, statements: S) -> Self 974 | where 975 | C: Into, 976 | S: IntoIterator, 977 | { 978 | let case_stmt = Statement::Simple(Box::new(SimpleStatement::CaseLabel(case.into()))); 979 | 980 | Statement::Compound(Box::new(CompoundStatement { 981 | statement_list: once(case_stmt).chain(statements.into_iter()).collect(), 982 | })) 983 | } 984 | 985 | /// Declare a new variable. 986 | /// 987 | /// `ty` is the type of the variable, `name` the name of the binding to create, 988 | /// `array_specifier` an optional argument to make your binding an array and 989 | /// `initializer` 990 | pub fn declare_var(ty: T, name: N, array_specifier: A, initializer: I) -> Self 991 | where 992 | T: Into, 993 | N: Into, 994 | A: Into>, 995 | I: Into>, 996 | { 997 | Statement::Simple(Box::new(SimpleStatement::Declaration( 998 | Declaration::InitDeclaratorList(InitDeclaratorList { 999 | head: SingleDeclaration { 1000 | ty: ty.into(), 1001 | name: Some(name.into()), 1002 | array_specifier: array_specifier.into(), 1003 | initializer: initializer.into(), 1004 | }, 1005 | tail: Vec::new(), 1006 | }), 1007 | ))) 1008 | } 1009 | } 1010 | 1011 | /// Simple statement. 1012 | #[derive(Clone, Debug, PartialEq)] 1013 | pub enum SimpleStatement { 1014 | Declaration(Declaration), 1015 | Expression(ExprStatement), 1016 | Selection(SelectionStatement), 1017 | Switch(SwitchStatement), 1018 | CaseLabel(CaseLabel), 1019 | Iteration(IterationStatement), 1020 | Jump(JumpStatement), 1021 | } 1022 | 1023 | impl SimpleStatement { 1024 | /// Create a new expression statement. 1025 | pub fn new_expr(expr: E) -> Self 1026 | where 1027 | E: Into, 1028 | { 1029 | SimpleStatement::Expression(Some(expr.into())) 1030 | } 1031 | 1032 | /// Create a new selection statement (if / else). 1033 | pub fn new_if_else(ife: If, truee: True, falsee: False) -> Self 1034 | where 1035 | If: Into, 1036 | True: Into, 1037 | False: Into, 1038 | { 1039 | SimpleStatement::Selection(SelectionStatement { 1040 | cond: Box::new(ife.into()), 1041 | rest: SelectionRestStatement::Else(Box::new(truee.into()), Box::new(falsee.into())), 1042 | }) 1043 | } 1044 | 1045 | /// Create a new switch statement. 1046 | /// 1047 | /// A switch statement is always composed of a [`SimpleStatement::Switch`] block, that contains it 1048 | /// all, and has as body a compound list of case statements. 1049 | pub fn new_switch(head: H, body: B) -> Self 1050 | where 1051 | H: Into, 1052 | B: IntoIterator, 1053 | { 1054 | SimpleStatement::Switch(SwitchStatement { 1055 | head: Box::new(head.into()), 1056 | body: body.into_iter().collect(), 1057 | }) 1058 | } 1059 | 1060 | /// Create a new while statement. 1061 | pub fn new_while(cond: C, body: S) -> Self 1062 | where 1063 | C: Into, 1064 | S: Into, 1065 | { 1066 | SimpleStatement::Iteration(IterationStatement::While( 1067 | cond.into(), 1068 | Box::new(body.into()), 1069 | )) 1070 | } 1071 | 1072 | /// Create a new do-while statement. 1073 | pub fn new_do_while(body: S, cond: C) -> Self 1074 | where 1075 | S: Into, 1076 | C: Into, 1077 | { 1078 | SimpleStatement::Iteration(IterationStatement::DoWhile( 1079 | Box::new(body.into()), 1080 | Box::new(cond.into()), 1081 | )) 1082 | } 1083 | } 1084 | 1085 | /// Expression statement. 1086 | pub type ExprStatement = Option; 1087 | 1088 | /// Selection statement. 1089 | #[derive(Clone, Debug, PartialEq)] 1090 | pub struct SelectionStatement { 1091 | pub cond: Box, 1092 | pub rest: SelectionRestStatement, 1093 | } 1094 | 1095 | /// Condition. 1096 | #[derive(Clone, Debug, PartialEq)] 1097 | pub enum Condition { 1098 | Expr(Box), 1099 | Assignment(FullySpecifiedType, Identifier, Initializer), 1100 | } 1101 | 1102 | impl From for Condition { 1103 | fn from(expr: Expr) -> Self { 1104 | Condition::Expr(Box::new(expr)) 1105 | } 1106 | } 1107 | 1108 | /// Selection rest statement. 1109 | #[derive(Clone, Debug, PartialEq)] 1110 | pub enum SelectionRestStatement { 1111 | /// Body of the if. 1112 | Statement(Box), 1113 | /// The first argument is the body of the if, the rest is the next statement. 1114 | Else(Box, Box), 1115 | } 1116 | 1117 | /// Switch statement. 1118 | #[derive(Clone, Debug, PartialEq)] 1119 | pub struct SwitchStatement { 1120 | pub head: Box, 1121 | pub body: Vec, 1122 | } 1123 | 1124 | /// Case label statement. 1125 | #[derive(Clone, Debug, PartialEq)] 1126 | pub enum CaseLabel { 1127 | Case(Box), 1128 | Def, 1129 | } 1130 | 1131 | /// Iteration statement. 1132 | #[derive(Clone, Debug, PartialEq)] 1133 | pub enum IterationStatement { 1134 | While(Condition, Box), 1135 | DoWhile(Box, Box), 1136 | For(ForInitStatement, ForRestStatement, Box), 1137 | } 1138 | 1139 | /// For init statement. 1140 | #[derive(Clone, Debug, PartialEq)] 1141 | pub enum ForInitStatement { 1142 | Expression(Option), 1143 | Declaration(Box), 1144 | } 1145 | 1146 | /// For init statement. 1147 | #[derive(Clone, Debug, PartialEq)] 1148 | pub struct ForRestStatement { 1149 | pub condition: Option, 1150 | pub post_expr: Option>, 1151 | } 1152 | 1153 | /// Jump statement. 1154 | #[derive(Clone, Debug, PartialEq)] 1155 | pub enum JumpStatement { 1156 | Continue, 1157 | Break, 1158 | Return(Option>), 1159 | Discard, 1160 | } 1161 | 1162 | /// Some basic preprocessor directives. 1163 | /// 1164 | /// As it’s important to carry them around the AST because they cannot be substituted in a normal 1165 | /// preprocessor (they’re used by GPU’s compilers), those preprocessor directives are available for 1166 | /// inspection. 1167 | #[derive(Clone, Debug, PartialEq)] 1168 | pub enum Preprocessor { 1169 | Define(PreprocessorDefine), 1170 | Else, 1171 | ElIf(PreprocessorElIf), 1172 | EndIf, 1173 | Error(PreprocessorError), 1174 | If(PreprocessorIf), 1175 | IfDef(PreprocessorIfDef), 1176 | IfNDef(PreprocessorIfNDef), 1177 | Include(PreprocessorInclude), 1178 | Line(PreprocessorLine), 1179 | Pragma(PreprocessorPragma), 1180 | Undef(PreprocessorUndef), 1181 | Version(PreprocessorVersion), 1182 | Extension(PreprocessorExtension), 1183 | } 1184 | 1185 | /// A #define preprocessor directive. 1186 | /// 1187 | /// Allows any expression but only Integer and Float literals make sense 1188 | #[derive(Clone, Debug, PartialEq)] 1189 | pub enum PreprocessorDefine { 1190 | ObjectLike { 1191 | ident: Identifier, 1192 | value: String, 1193 | }, 1194 | 1195 | FunctionLike { 1196 | ident: Identifier, 1197 | args: Vec, 1198 | value: String, 1199 | }, 1200 | } 1201 | 1202 | /// An #elif preprocessor directive. 1203 | #[derive(Clone, Debug, PartialEq)] 1204 | pub struct PreprocessorElIf { 1205 | pub condition: String, 1206 | } 1207 | 1208 | /// An #error preprocessor directive. 1209 | #[derive(Clone, Debug, PartialEq)] 1210 | pub struct PreprocessorError { 1211 | pub message: String, 1212 | } 1213 | 1214 | /// An #if preprocessor directive. 1215 | #[derive(Clone, Debug, PartialEq)] 1216 | pub struct PreprocessorIf { 1217 | pub condition: String, 1218 | } 1219 | 1220 | /// An #ifdef preprocessor directive. 1221 | #[derive(Clone, Debug, PartialEq)] 1222 | pub struct PreprocessorIfDef { 1223 | pub ident: Identifier, 1224 | } 1225 | 1226 | /// A #ifndef preprocessor directive. 1227 | #[derive(Clone, Debug, PartialEq)] 1228 | pub struct PreprocessorIfNDef { 1229 | pub ident: Identifier, 1230 | } 1231 | 1232 | /// An #include name annotation. 1233 | #[derive(Clone, Debug, PartialEq)] 1234 | pub struct PreprocessorInclude { 1235 | pub path: Path, 1236 | } 1237 | 1238 | /// A #line preprocessor directive. 1239 | #[derive(Clone, Debug, PartialEq)] 1240 | pub struct PreprocessorLine { 1241 | pub line: u32, 1242 | pub source_string_number: Option, 1243 | } 1244 | 1245 | /// A #pragma preprocessor directive. 1246 | /// Holds compiler-specific command. 1247 | #[derive(Clone, Debug, PartialEq)] 1248 | pub struct PreprocessorPragma { 1249 | pub command: String, 1250 | } 1251 | 1252 | /// A #undef preprocessor directive. 1253 | #[derive(Clone, Debug, PartialEq)] 1254 | pub struct PreprocessorUndef { 1255 | pub name: Identifier, 1256 | } 1257 | 1258 | /// A #version preprocessor directive. 1259 | #[derive(Clone, Debug, PartialEq)] 1260 | pub struct PreprocessorVersion { 1261 | pub version: u16, 1262 | pub profile: Option, 1263 | } 1264 | 1265 | /// A #version profile annotation. 1266 | #[derive(Clone, Debug, PartialEq)] 1267 | pub enum PreprocessorVersionProfile { 1268 | Core, 1269 | Compatibility, 1270 | ES, 1271 | } 1272 | 1273 | /// An #extension preprocessor directive. 1274 | #[derive(Clone, Debug, PartialEq)] 1275 | pub struct PreprocessorExtension { 1276 | pub name: PreprocessorExtensionName, 1277 | pub behavior: Option, 1278 | } 1279 | 1280 | /// An #extension name annotation. 1281 | #[derive(Clone, Debug, PartialEq)] 1282 | pub enum PreprocessorExtensionName { 1283 | /// All extensions you could ever imagine in your whole lifetime (how crazy is that!). 1284 | All, 1285 | /// A specific extension. 1286 | Specific(String), 1287 | } 1288 | 1289 | /// An #extension behavior annotation. 1290 | #[derive(Clone, Debug, PartialEq)] 1291 | pub enum PreprocessorExtensionBehavior { 1292 | Require, 1293 | Enable, 1294 | Warn, 1295 | Disable, 1296 | } 1297 | 1298 | #[cfg(test)] 1299 | mod tests { 1300 | use super::*; 1301 | 1302 | #[test] 1303 | fn create_new_identifier() { 1304 | assert!(Identifier::new("foo_bar").is_ok()); 1305 | assert!(Identifier::new("3foo_bar").is_err()); 1306 | assert!(Identifier::new("FooBar").is_ok()); 1307 | assert!(Identifier::new("_FooBar").is_ok()); 1308 | assert!(Identifier::new("foo3").is_ok()); 1309 | assert!(Identifier::new("foo3_").is_ok()); 1310 | assert!(Identifier::new("fδo3_").is_err()); 1311 | } 1312 | 1313 | #[test] 1314 | fn create_new_type_name() { 1315 | assert!(TypeName::new("foo_bar").is_ok()); 1316 | assert!(TypeName::new("FooBar").is_ok()); 1317 | assert!(TypeName::new("foo3").is_ok()); 1318 | assert!(TypeName::new("foo3_").is_ok()); 1319 | 1320 | assert!(TypeName::new("_FooBar").is_ok()); 1321 | assert!(TypeName::new("3foo_bar").is_err()); 1322 | assert!(TypeName::new("fδo3_").is_err()); 1323 | } 1324 | 1325 | // bool predicate(float x) { 1326 | // } 1327 | #[test] 1328 | fn declare_new_fn() { 1329 | let _ = ExternalDeclaration::new_fn( 1330 | TypeSpecifierNonArray::Bool, 1331 | "predicate", 1332 | vec![FunctionParameterDeclaration::new_named( 1333 | "x", 1334 | TypeSpecifierNonArray::Float, 1335 | )], 1336 | vec![], 1337 | ); 1338 | } 1339 | 1340 | // struct Point2D { 1341 | // float x; 1342 | // float y; 1343 | // }; 1344 | #[test] 1345 | fn declare_struct() { 1346 | let point = ExternalDeclaration::new_struct( 1347 | "Point2D", 1348 | vec![ 1349 | StructFieldSpecifier::new("x", TypeSpecifierNonArray::Double), 1350 | StructFieldSpecifier::new("y", TypeSpecifierNonArray::Double), 1351 | ], 1352 | ); 1353 | 1354 | assert!(point.is_some()); 1355 | } 1356 | 1357 | // struct Point2D {}; 1358 | #[test] 1359 | fn declare_bad_struct() { 1360 | let point = ExternalDeclaration::new_struct("Point2D", vec![]); 1361 | assert!(point.is_none()); 1362 | } 1363 | 1364 | #[test] 1365 | fn initializer_from_expr() { 1366 | let _: Initializer = Expr::from(false).into(); 1367 | } 1368 | } 1369 | -------------------------------------------------------------------------------- /glsl/src/transpiler/mod.rs: -------------------------------------------------------------------------------- 1 | //! GLSL transpilers – i.e. going from GLSL to anything else. 2 | //! 3 | //! There’s no public interface / trait to define what a transpiler is. It depends on the target 4 | //! representation you aim. 5 | 6 | pub mod glsl; 7 | #[cfg(feature = "spirv")] 8 | pub mod spirv; 9 | -------------------------------------------------------------------------------- /glsl/src/transpiler/spirv.rs: -------------------------------------------------------------------------------- 1 | //! SPIR-V transpiler. 2 | //! 3 | //! The current implementation uses the [shaderc](https://crates.io/crates/shaderc) crate to 4 | //! transpile GLSL to SPIR-V. This is not ideal but will provide a default and starting 5 | //! implementation. 6 | 7 | use shaderc; 8 | 9 | use crate::syntax; 10 | use crate::transpiler::glsl as glsl_transpiler; 11 | 12 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 13 | pub enum ShaderKind { 14 | TessControl, 15 | TessEvaluation, 16 | Vertex, 17 | Geometry, 18 | Fragment, 19 | Compute, 20 | } 21 | 22 | impl From for shaderc::ShaderKind { 23 | fn from(kind: ShaderKind) -> Self { 24 | match kind { 25 | ShaderKind::TessControl => shaderc::ShaderKind::TessControl, 26 | ShaderKind::TessEvaluation => shaderc::ShaderKind::TessEvaluation, 27 | ShaderKind::Vertex => shaderc::ShaderKind::Vertex, 28 | ShaderKind::Geometry => shaderc::ShaderKind::Geometry, 29 | ShaderKind::Fragment => shaderc::ShaderKind::Fragment, 30 | ShaderKind::Compute => shaderc::ShaderKind::Compute, 31 | } 32 | } 33 | } 34 | 35 | /// Transpile a GLSL AST into a SPIR-V internal buffer and write it to the given buffer. 36 | /// 37 | /// The current implementation is highly inefficient as it relies on internal allocations and 38 | /// [shaderc](https://crates.io/crates/shaderc). 39 | /// 40 | /// If any error happens while transpiling, they’re returned as an opaque string. 41 | pub fn transpile_translation_unit_to_binary( 42 | f: &mut F, 43 | tu: &syntax::TranslationUnit, 44 | kind: ShaderKind, 45 | ) -> Result<(), String> 46 | where 47 | F: std::io::Write, 48 | { 49 | // write as GLSL in an intermediate buffer 50 | let mut glsl_buffer = String::new(); 51 | glsl_transpiler::show_translation_unit(&mut glsl_buffer, tu); 52 | 53 | // pass the GLSL-formatted string to shaderc 54 | let mut compiler = shaderc::Compiler::new().unwrap(); 55 | let options = shaderc::CompileOptions::new().unwrap(); 56 | let kind = kind.into(); 57 | let output = compiler 58 | .compile_into_spirv(&glsl_buffer, kind, "glsl input", "main", Some(&options)) 59 | .map_err(|e| format!("{}", e))?; 60 | 61 | let _ = f.write_all(output.as_binary_u8()); 62 | 63 | Ok(()) 64 | } 65 | 66 | /// Transpile a GLSL AST into a SPIR-V internal buffer and write it to the given buffer. 67 | /// 68 | /// The current implementation is highly inefficient as it relies on internal allocations and 69 | /// [shaderc](https://crates.io/crates/shaderc). 70 | /// 71 | /// If any error happens while transpiling, they’re returned as an opaque string. 72 | pub fn transpile_translation_unit( 73 | f: &mut F, 74 | tu: &syntax::TranslationUnit, 75 | kind: ShaderKind, 76 | ) -> Result<(), String> 77 | where 78 | F: std::fmt::Write, 79 | { 80 | // write as GLSL in an intermediate buffer 81 | let mut glsl_buffer = String::new(); 82 | glsl_transpiler::show_translation_unit(&mut glsl_buffer, tu); 83 | 84 | // pass the GLSL-formatted string to shaderc 85 | let mut compiler = shaderc::Compiler::new().unwrap(); 86 | let options = shaderc::CompileOptions::new().unwrap(); 87 | let kind = kind.into(); 88 | let output = compiler 89 | .compile_into_spirv_assembly(&glsl_buffer, kind, "glsl input", "main", Some(&options)) 90 | .map_err(|e| format!("{}", e))?; 91 | 92 | let _ = f.write_str(&output.as_text()); 93 | 94 | Ok(()) 95 | } 96 | -------------------------------------------------------------------------------- /glsl/src/visitor.rs: -------------------------------------------------------------------------------- 1 | //! AST visitors (i.e. on-the-fly mutation at different places in the AST). 2 | //! 3 | //! Visitors are mutable objects that can mutate parts of an AST while traversing it. You can see 4 | //! them as flexible mutations taking place on *patterns* representing your AST – they get called 5 | //! everytime an interesting node gets visited. Because of their mutable nature, you can accumulate 6 | //! a state as you traverse the AST and implement exotic filtering. 7 | //! 8 | //! Visitors must implement the [`Visitor`] trait in order to be usable. 9 | //! 10 | //! In order to visit any part of an AST (from its very top root or from any part of it), you must 11 | //! use the [`Host`] interface, that provides the [`Host::visit`] function. 12 | //! 13 | //! For instance, we can imagine visiting an AST to count how many variables are declared: 14 | //! 15 | //! ``` 16 | //! use glsl::syntax::{CompoundStatement, Expr, SingleDeclaration, Statement, TypeSpecifierNonArray}; 17 | //! use glsl::visitor::{Host, Visit, Visitor}; 18 | //! use std::iter::FromIterator; 19 | //! 20 | //! let decl0 = Statement::declare_var( 21 | //! TypeSpecifierNonArray::Float, 22 | //! "x", 23 | //! None, 24 | //! Some(Expr::from(3.14).into()) 25 | //! ); 26 | //! 27 | //! let decl1 = Statement::declare_var( 28 | //! TypeSpecifierNonArray::Int, 29 | //! "y", 30 | //! None, 31 | //! None 32 | //! ); 33 | //! 34 | //! let decl2 = Statement::declare_var( 35 | //! TypeSpecifierNonArray::Vec4, 36 | //! "z", 37 | //! None, 38 | //! None 39 | //! ); 40 | //! 41 | //! let compound = CompoundStatement::from_iter(vec![decl0, decl1, decl2]); 42 | //! 43 | //! // our visitor that will count the number of variables it saw 44 | //! struct Counter { 45 | //! var_nb: usize 46 | //! } 47 | //! 48 | //! impl Visitor for Counter { 49 | //! // we are only interested in single declaration with a name 50 | //! fn visit_single_declaration(&mut self, declaration: &SingleDeclaration) -> Visit { 51 | //! if declaration.name.is_some() { 52 | //! self.var_nb += 1; 53 | //! } 54 | //! 55 | //! // do not go deeper 56 | //! Visit::Parent 57 | //! } 58 | //! } 59 | //! 60 | //! let mut counter = Counter { var_nb: 0 }; 61 | //! compound.visit(&mut counter); 62 | //! assert_eq!(counter.var_nb, 3); 63 | //! ``` 64 | //! 65 | //! [`Host`]: crate::visitor::Host 66 | //! [`Host::visit`]: crate::visitor::Host::visit 67 | //! [`Visitor`]: crate::visitor::Visitor 68 | 69 | use crate::syntax; 70 | 71 | /// Visit strategy after having visited an AST node. 72 | /// 73 | /// Some AST nodes have *children* – in enum’s variants, in some fields as nested in [`Vec`], etc. 74 | /// Those nodes can be visited depending on the strategy you chose. 75 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 76 | pub enum Visit { 77 | /// The visitor will go deeper in the AST by visiting all the children, if any. If no children are 78 | /// present or if having children doesn’t make sense for a specific part of the AST, this 79 | /// strategy will be ignored. 80 | Children, 81 | /// The visitor won’t visit children nor siblings and will go up. 82 | Parent, 83 | } 84 | 85 | macro_rules! make_visitor_trait { 86 | ($t:ident, $($ref:tt)*) => { 87 | /// Visitor object, visiting AST nodes. 88 | /// 89 | /// This trait exists in two flavors, depending on whether you want to mutate the AST or not: [`Visitor`] doesn’t 90 | /// allow for mutation while [`VisitorMut`] does. 91 | pub trait $t { 92 | fn visit_translation_unit(&mut self, _: $($ref)* syntax::TranslationUnit) -> Visit { 93 | Visit::Children 94 | } 95 | 96 | fn visit_external_declaration(&mut self, _: $($ref)* syntax::ExternalDeclaration) -> Visit { 97 | Visit::Children 98 | } 99 | 100 | fn visit_identifier(&mut self, _: $($ref)* syntax::Identifier) -> Visit { 101 | Visit::Children 102 | } 103 | 104 | fn visit_arrayed_identifier(&mut self, _: $($ref)* syntax::ArrayedIdentifier) -> Visit { 105 | Visit::Children 106 | } 107 | 108 | fn visit_type_name(&mut self, _: $($ref)* syntax::TypeName) -> Visit { 109 | Visit::Children 110 | } 111 | 112 | fn visit_block(&mut self, _: $($ref)* syntax::Block) -> Visit { 113 | Visit::Children 114 | } 115 | 116 | fn visit_for_init_statement(&mut self, _: $($ref)* syntax::ForInitStatement) -> Visit { 117 | Visit::Children 118 | } 119 | 120 | fn visit_for_rest_statement(&mut self, _: $($ref)* syntax::ForRestStatement) -> Visit { 121 | Visit::Children 122 | } 123 | 124 | fn visit_function_definition(&mut self, _: $($ref)* syntax::FunctionDefinition) -> Visit { 125 | Visit::Children 126 | } 127 | 128 | fn visit_function_parameter_declarator( 129 | &mut self, 130 | _: $($ref)* syntax::FunctionParameterDeclarator, 131 | ) -> Visit { 132 | Visit::Children 133 | } 134 | 135 | fn visit_function_prototype(&mut self, _: $($ref)* syntax::FunctionPrototype) -> Visit { 136 | Visit::Children 137 | } 138 | 139 | fn visit_init_declarator_list(&mut self, _: $($ref)* syntax::InitDeclaratorList) -> Visit { 140 | Visit::Children 141 | } 142 | 143 | fn visit_layout_qualifier(&mut self, _: $($ref)* syntax::LayoutQualifier) -> Visit { 144 | Visit::Children 145 | } 146 | 147 | fn visit_preprocessor(&mut self, _: $($ref)* syntax::Preprocessor) -> Visit { 148 | Visit::Children 149 | } 150 | 151 | fn visit_preprocessor_define(&mut self, _: $($ref)* syntax::PreprocessorDefine) -> Visit { 152 | Visit::Children 153 | } 154 | 155 | fn visit_preprocessor_elif(&mut self, _: $($ref)* syntax::PreprocessorElIf) -> Visit { 156 | Visit::Children 157 | } 158 | 159 | fn visit_preprocessor_error(&mut self, _: $($ref)* syntax::PreprocessorError) -> Visit { 160 | Visit::Children 161 | } 162 | 163 | fn visit_preprocessor_extension(&mut self, _: $($ref)* syntax::PreprocessorExtension) -> Visit { 164 | Visit::Children 165 | } 166 | 167 | fn visit_preprocessor_extension_behavior( 168 | &mut self, 169 | _: $($ref)* syntax::PreprocessorExtensionBehavior, 170 | ) -> Visit { 171 | Visit::Children 172 | } 173 | 174 | fn visit_preprocessor_extension_name( 175 | &mut self, 176 | _: $($ref)* syntax::PreprocessorExtensionName, 177 | ) -> Visit { 178 | Visit::Children 179 | } 180 | 181 | fn visit_preprocessor_if(&mut self, _: $($ref)* syntax::PreprocessorIf) -> Visit { 182 | Visit::Children 183 | } 184 | 185 | fn visit_preprocessor_ifdef(&mut self, _: $($ref)* syntax::PreprocessorIfDef) -> Visit { 186 | Visit::Children 187 | } 188 | 189 | fn visit_preprocessor_ifndef(&mut self, _: $($ref)* syntax::PreprocessorIfNDef) -> Visit { 190 | Visit::Children 191 | } 192 | 193 | fn visit_preprocessor_include(&mut self, _: $($ref)* syntax::PreprocessorInclude) -> Visit { 194 | Visit::Children 195 | } 196 | 197 | fn visit_preprocessor_line(&mut self, _: $($ref)* syntax::PreprocessorLine) -> Visit { 198 | Visit::Children 199 | } 200 | 201 | fn visit_preprocessor_pragma(&mut self, _: $($ref)* syntax::PreprocessorPragma) -> Visit { 202 | Visit::Children 203 | } 204 | 205 | fn visit_preprocessor_undef(&mut self, _: $($ref)* syntax::PreprocessorUndef) -> Visit { 206 | Visit::Children 207 | } 208 | 209 | fn visit_preprocessor_version(&mut self, _: $($ref)* syntax::PreprocessorVersion) -> Visit { 210 | Visit::Children 211 | } 212 | 213 | fn visit_preprocessor_version_profile( 214 | &mut self, 215 | _: $($ref)* syntax::PreprocessorVersionProfile, 216 | ) -> Visit { 217 | Visit::Children 218 | } 219 | 220 | fn visit_selection_statement(&mut self, _: $($ref)* syntax::SelectionStatement) -> Visit { 221 | Visit::Children 222 | } 223 | 224 | fn visit_selection_rest_statement(&mut self, _: $($ref)* syntax::SelectionRestStatement) -> Visit { 225 | Visit::Children 226 | } 227 | 228 | fn visit_single_declaration(&mut self, _: $($ref)* syntax::SingleDeclaration) -> Visit { 229 | Visit::Children 230 | } 231 | 232 | fn visit_single_declaration_no_type(&mut self, _: $($ref)* syntax::SingleDeclarationNoType) -> Visit { 233 | Visit::Children 234 | } 235 | 236 | fn visit_struct_field_specifier(&mut self, _: $($ref)* syntax::StructFieldSpecifier) -> Visit { 237 | Visit::Children 238 | } 239 | 240 | fn visit_struct_specifier(&mut self, _: $($ref)* syntax::StructSpecifier) -> Visit { 241 | Visit::Children 242 | } 243 | 244 | fn visit_switch_statement(&mut self, _: $($ref)* syntax::SwitchStatement) -> Visit { 245 | Visit::Children 246 | } 247 | 248 | fn visit_type_qualifier(&mut self, _: $($ref)* syntax::TypeQualifier) -> Visit { 249 | Visit::Children 250 | } 251 | 252 | fn visit_type_specifier(&mut self, _: $($ref)* syntax::TypeSpecifier) -> Visit { 253 | Visit::Children 254 | } 255 | 256 | fn visit_full_specified_type(&mut self, _: $($ref)* syntax::FullySpecifiedType) -> Visit { 257 | Visit::Children 258 | } 259 | 260 | fn visit_array_specifier(&mut self, _: $($ref)* syntax::ArraySpecifier) -> Visit { 261 | Visit::Children 262 | } 263 | 264 | fn visit_array_specifier_dimension(&mut self, _: $($ref)* syntax::ArraySpecifierDimension) -> Visit { 265 | Visit::Children 266 | } 267 | 268 | fn visit_assignment_op(&mut self, _: $($ref)* syntax::AssignmentOp) -> Visit { 269 | Visit::Children 270 | } 271 | 272 | fn visit_binary_op(&mut self, _: $($ref)* syntax::BinaryOp) -> Visit { 273 | Visit::Children 274 | } 275 | 276 | fn visit_case_label(&mut self, _: $($ref)* syntax::CaseLabel) -> Visit { 277 | Visit::Children 278 | } 279 | 280 | fn visit_condition(&mut self, _: $($ref)* syntax::Condition) -> Visit { 281 | Visit::Children 282 | } 283 | 284 | fn visit_declaration(&mut self, _: $($ref)* syntax::Declaration) -> Visit { 285 | Visit::Children 286 | } 287 | 288 | fn visit_expr(&mut self, _: $($ref)* syntax::Expr) -> Visit { 289 | Visit::Children 290 | } 291 | 292 | fn visit_fun_identifier(&mut self, _: $($ref)* syntax::FunIdentifier) -> Visit { 293 | Visit::Children 294 | } 295 | 296 | fn visit_function_parameter_declaration( 297 | &mut self, 298 | _: $($ref)* syntax::FunctionParameterDeclaration, 299 | ) -> Visit { 300 | Visit::Children 301 | } 302 | 303 | fn visit_initializer(&mut self, _: $($ref)* syntax::Initializer) -> Visit { 304 | Visit::Children 305 | } 306 | 307 | fn visit_interpolation_qualifier(&mut self, _: $($ref)* syntax::InterpolationQualifier) -> Visit { 308 | Visit::Children 309 | } 310 | 311 | fn visit_iteration_statement(&mut self, _: $($ref)* syntax::IterationStatement) -> Visit { 312 | Visit::Children 313 | } 314 | 315 | fn visit_jump_statement(&mut self, _: $($ref)* syntax::JumpStatement) -> Visit { 316 | Visit::Children 317 | } 318 | 319 | fn visit_layout_qualifier_spec(&mut self, _: $($ref)* syntax::LayoutQualifierSpec) -> Visit { 320 | Visit::Children 321 | } 322 | 323 | fn visit_precision_qualifier(&mut self, _: $($ref)* syntax::PrecisionQualifier) -> Visit { 324 | Visit::Children 325 | } 326 | 327 | fn visit_statement(&mut self, _: $($ref)* syntax::Statement) -> Visit { 328 | Visit::Children 329 | } 330 | 331 | fn visit_compound_statement(&mut self, _: $($ref)* syntax::CompoundStatement) -> Visit { 332 | Visit::Children 333 | } 334 | 335 | fn visit_simple_statement(&mut self, _: $($ref)* syntax::SimpleStatement) -> Visit { 336 | Visit::Children 337 | } 338 | 339 | fn visit_storage_qualifier(&mut self, _: $($ref)* syntax::StorageQualifier) -> Visit { 340 | Visit::Children 341 | } 342 | 343 | fn visit_type_qualifier_spec(&mut self, _: $($ref)* syntax::TypeQualifierSpec) -> Visit { 344 | Visit::Children 345 | } 346 | 347 | fn visit_type_specifier_non_array(&mut self, _: $($ref)* syntax::TypeSpecifierNonArray) -> Visit { 348 | Visit::Children 349 | } 350 | 351 | fn visit_unary_op(&mut self, _: $($ref)* syntax::UnaryOp) -> Visit { 352 | Visit::Children 353 | } 354 | 355 | fn visit_expr_statement(&mut self, _: $($ref)* syntax::ExprStatement) -> Visit { 356 | Visit::Children 357 | } 358 | } 359 | } 360 | } 361 | 362 | macro_rules! make_host_trait { 363 | ($host_ty:ident, $visitor_ty:ident, $mthd_name:ident, $($ref:tt)*) => { 364 | /// Part of the AST that can be visited. 365 | /// 366 | /// You shouldn’t have to worry about this type nor how to implement it – it’s completely 367 | /// implemented for you. However, it works in a pretty simple way: any implementor of the host trait can 368 | /// be used with a visitor. 369 | /// 370 | /// The idea is that visiting an AST node is a two-step process: 371 | /// 372 | /// - First, you *can* get your visitor called once as soon as an interesting node gets visited. 373 | /// For instance, if your visitor has an implementation for visiting expressions, everytime an 374 | /// expression gets visited, your visitor will run. 375 | /// - If your implementation of visiting an AST node returns [`Visit::Children`] and if the given 376 | /// node has children, the visitor will go deeper, invoking other calls if you have defined any. 377 | /// A typical pattern you might want to do is to implement your visitor to gets run on all 378 | /// typenames. Since expressions contains variables, you will get your visitor called once again 379 | /// there. 380 | /// - Notice that since visitors are mutable, you can accumulate a state as you go deeper in the 381 | /// AST to implement various checks and validations. 382 | /// 383 | /// Note that this trait exists in two versions: an immutable one, [`Host`], which doesn’t allow you to mutate the 384 | /// AST (but takes a `&`), and a mutable one, [`HostMut`], which allows for AST mutation. 385 | pub trait $host_ty { 386 | /// Visit an AST node. 387 | fn $mthd_name($($ref)* self, visitor: &mut V) 388 | where 389 | V: $visitor_ty; 390 | } 391 | 392 | impl $host_ty for Option 393 | where 394 | T: $host_ty, 395 | { 396 | fn $mthd_name($($ref)* self, visitor: &mut V) 397 | where 398 | V: $visitor_ty, 399 | { 400 | if let Some(x) = self { 401 | x.$mthd_name(visitor); 402 | } 403 | } 404 | } 405 | 406 | impl $host_ty for Box 407 | where 408 | T: $host_ty, 409 | { 410 | fn $mthd_name($($ref)* self, visitor: &mut V) 411 | where 412 | V: $visitor_ty, 413 | { 414 | (**self).$mthd_name(visitor); 415 | } 416 | } 417 | 418 | impl $host_ty for syntax::TranslationUnit { 419 | fn $mthd_name($($ref)* self, visitor: &mut V) 420 | where 421 | V: $visitor_ty, 422 | { 423 | let visit = visitor.visit_translation_unit(self); 424 | 425 | if visit == Visit::Children { 426 | for ed in $($ref)* (self.0).0 { 427 | ed.$mthd_name(visitor); 428 | } 429 | } 430 | } 431 | } 432 | 433 | impl $host_ty for syntax::ExternalDeclaration { 434 | fn $mthd_name($($ref)* self, visitor: &mut V) 435 | where 436 | V: $visitor_ty, 437 | { 438 | let visit = visitor.visit_external_declaration(self); 439 | 440 | if visit == Visit::Children { 441 | match self { 442 | syntax::ExternalDeclaration::Preprocessor(p) => p.$mthd_name(visitor), 443 | syntax::ExternalDeclaration::FunctionDefinition(fd) => fd.$mthd_name(visitor), 444 | syntax::ExternalDeclaration::Declaration(d) => d.$mthd_name(visitor), 445 | } 446 | } 447 | } 448 | } 449 | 450 | impl $host_ty for syntax::Preprocessor { 451 | fn $mthd_name($($ref)* self, visitor: &mut V) 452 | where 453 | V: $visitor_ty, 454 | { 455 | let visit = visitor.visit_preprocessor(self); 456 | 457 | if visit == Visit::Children { 458 | match self { 459 | syntax::Preprocessor::Define(pd) => pd.$mthd_name(visitor), 460 | syntax::Preprocessor::Else => (), 461 | syntax::Preprocessor::ElIf(pei) => pei.$mthd_name(visitor), 462 | syntax::Preprocessor::EndIf => (), 463 | syntax::Preprocessor::Error(pe) => pe.$mthd_name(visitor), 464 | syntax::Preprocessor::If(pi) => pi.$mthd_name(visitor), 465 | syntax::Preprocessor::IfDef(pid) => pid.$mthd_name(visitor), 466 | syntax::Preprocessor::IfNDef(pind) => pind.$mthd_name(visitor), 467 | syntax::Preprocessor::Include(pi) => pi.$mthd_name(visitor), 468 | syntax::Preprocessor::Line(pl) => pl.$mthd_name(visitor), 469 | syntax::Preprocessor::Pragma(pp) => pp.$mthd_name(visitor), 470 | syntax::Preprocessor::Undef(pu) => pu.$mthd_name(visitor), 471 | syntax::Preprocessor::Version(pv) => pv.$mthd_name(visitor), 472 | syntax::Preprocessor::Extension(ext) => ext.$mthd_name(visitor), 473 | } 474 | } 475 | } 476 | } 477 | 478 | impl $host_ty for syntax::PreprocessorDefine { 479 | fn $mthd_name($($ref)* self, visitor: &mut V) 480 | where 481 | V: $visitor_ty, 482 | { 483 | let visit = visitor.visit_preprocessor_define(self); 484 | 485 | if visit == Visit::Children { 486 | match self { 487 | syntax::PreprocessorDefine::ObjectLike { ident, .. } => { 488 | ident.$mthd_name(visitor); 489 | } 490 | 491 | syntax::PreprocessorDefine::FunctionLike { 492 | ident, 493 | args, 494 | .. 495 | } => { 496 | ident.$mthd_name(visitor); 497 | 498 | for arg in args { 499 | arg.$mthd_name(visitor); 500 | } 501 | } 502 | } 503 | } 504 | } 505 | } 506 | 507 | impl $host_ty for syntax::PreprocessorElIf { 508 | fn $mthd_name($($ref)* self, visitor: &mut V) 509 | where 510 | V: $visitor_ty, 511 | { 512 | let _ = visitor.visit_preprocessor_elif(self); 513 | } 514 | } 515 | 516 | impl $host_ty for syntax::PreprocessorError { 517 | fn $mthd_name($($ref)* self, visitor: &mut V) 518 | where 519 | V: $visitor_ty, 520 | { 521 | let _ = visitor.visit_preprocessor_error(self); 522 | } 523 | } 524 | 525 | impl $host_ty for syntax::PreprocessorIf { 526 | fn $mthd_name($($ref)* self, visitor: &mut V) 527 | where 528 | V: $visitor_ty, 529 | { 530 | let _ = visitor.visit_preprocessor_if(self); 531 | } 532 | } 533 | 534 | impl $host_ty for syntax::PreprocessorIfDef { 535 | fn $mthd_name($($ref)* self, visitor: &mut V) 536 | where 537 | V: $visitor_ty, 538 | { 539 | let visit = visitor.visit_preprocessor_ifdef(self); 540 | 541 | if visit == Visit::Children { 542 | self.ident.$mthd_name(visitor); 543 | } 544 | } 545 | } 546 | 547 | impl $host_ty for syntax::PreprocessorIfNDef { 548 | fn $mthd_name($($ref)* self, visitor: &mut V) 549 | where 550 | V: $visitor_ty, 551 | { 552 | let visit = visitor.visit_preprocessor_ifndef(self); 553 | 554 | if visit == Visit::Children { 555 | self.ident.$mthd_name(visitor); 556 | } 557 | } 558 | } 559 | 560 | impl $host_ty for syntax::PreprocessorInclude { 561 | fn $mthd_name($($ref)* self, visitor: &mut V) 562 | where 563 | V: $visitor_ty, 564 | { 565 | let _ = visitor.visit_preprocessor_include(self); 566 | } 567 | } 568 | 569 | impl $host_ty for syntax::PreprocessorLine { 570 | fn $mthd_name($($ref)* self, visitor: &mut V) 571 | where 572 | V: $visitor_ty, 573 | { 574 | let _ = visitor.visit_preprocessor_line(self); 575 | } 576 | } 577 | 578 | impl $host_ty for syntax::PreprocessorPragma { 579 | fn $mthd_name($($ref)* self, visitor: &mut V) 580 | where 581 | V: $visitor_ty, 582 | { 583 | let _ = visitor.visit_preprocessor_pragma(self); 584 | } 585 | } 586 | 587 | impl $host_ty for syntax::PreprocessorUndef { 588 | fn $mthd_name($($ref)* self, visitor: &mut V) 589 | where 590 | V: $visitor_ty, 591 | { 592 | let visit = visitor.visit_preprocessor_undef(self); 593 | 594 | if visit == Visit::Children { 595 | self.name.$mthd_name(visitor); 596 | } 597 | } 598 | } 599 | 600 | impl $host_ty for syntax::PreprocessorVersion { 601 | fn $mthd_name($($ref)* self, visitor: &mut V) 602 | where 603 | V: $visitor_ty, 604 | { 605 | let visit = visitor.visit_preprocessor_version(self); 606 | 607 | if visit == Visit::Children { 608 | self.profile.$mthd_name(visitor); 609 | } 610 | } 611 | } 612 | 613 | impl $host_ty for syntax::PreprocessorVersionProfile { 614 | fn $mthd_name($($ref)* self, visitor: &mut V) 615 | where 616 | V: $visitor_ty, 617 | { 618 | let _ = visitor.visit_preprocessor_version_profile(self); 619 | } 620 | } 621 | 622 | impl $host_ty for syntax::PreprocessorExtension { 623 | fn $mthd_name($($ref)* self, visitor: &mut V) 624 | where 625 | V: $visitor_ty, 626 | { 627 | let visit = visitor.visit_preprocessor_extension(self); 628 | 629 | if visit == Visit::Children { 630 | self.name.$mthd_name(visitor); 631 | self.behavior.$mthd_name(visitor); 632 | } 633 | } 634 | } 635 | 636 | impl $host_ty for syntax::PreprocessorExtensionBehavior { 637 | fn $mthd_name($($ref)* self, visitor: &mut V) 638 | where 639 | V: $visitor_ty, 640 | { 641 | let _ = visitor.visit_preprocessor_extension_behavior(self); 642 | } 643 | } 644 | 645 | impl $host_ty for syntax::PreprocessorExtensionName { 646 | fn $mthd_name($($ref)* self, visitor: &mut V) 647 | where 648 | V: $visitor_ty, 649 | { 650 | let _ = visitor.visit_preprocessor_extension_name(self); 651 | } 652 | } 653 | 654 | impl $host_ty for syntax::FunctionPrototype { 655 | fn $mthd_name($($ref)* self, visitor: &mut V) 656 | where 657 | V: $visitor_ty, 658 | { 659 | let visit = visitor.visit_function_prototype(self); 660 | 661 | if visit == Visit::Children { 662 | self.ty.$mthd_name(visitor); 663 | self.name.$mthd_name(visitor); 664 | 665 | for param in $($ref)* self.parameters { 666 | param.$mthd_name(visitor); 667 | } 668 | } 669 | } 670 | } 671 | 672 | impl $host_ty for syntax::FunctionParameterDeclaration { 673 | fn $mthd_name($($ref)* self, visitor: &mut V) 674 | where 675 | V: $visitor_ty, 676 | { 677 | let visit = visitor.visit_function_parameter_declaration(self); 678 | 679 | if visit == Visit::Children { 680 | match self { 681 | syntax::FunctionParameterDeclaration::Named(tq, fpd) => { 682 | tq.$mthd_name(visitor); 683 | fpd.$mthd_name(visitor); 684 | } 685 | 686 | syntax::FunctionParameterDeclaration::Unnamed(tq, ty) => { 687 | tq.$mthd_name(visitor); 688 | ty.$mthd_name(visitor); 689 | } 690 | } 691 | } 692 | } 693 | } 694 | 695 | impl $host_ty for syntax::FunctionParameterDeclarator { 696 | fn $mthd_name($($ref)* self, visitor: &mut V) 697 | where 698 | V: $visitor_ty, 699 | { 700 | let visit = visitor.visit_function_parameter_declarator(self); 701 | 702 | if visit == Visit::Children { 703 | self.ty.$mthd_name(visitor); 704 | self.ident.$mthd_name(visitor); 705 | } 706 | } 707 | } 708 | 709 | impl $host_ty for syntax::FunctionDefinition { 710 | fn $mthd_name($($ref)* self, visitor: &mut V) 711 | where 712 | V: $visitor_ty, 713 | { 714 | let visit = visitor.visit_function_definition(self); 715 | 716 | if visit == Visit::Children { 717 | self.prototype.$mthd_name(visitor); 718 | self.statement.$mthd_name(visitor); 719 | } 720 | } 721 | } 722 | 723 | impl $host_ty for syntax::Declaration { 724 | fn $mthd_name($($ref)* self, visitor: &mut V) 725 | where 726 | V: $visitor_ty, 727 | { 728 | let visit = visitor.visit_declaration(self); 729 | 730 | if visit == Visit::Children { 731 | match self { 732 | syntax::Declaration::FunctionPrototype(fp) => fp.$mthd_name(visitor), 733 | 734 | syntax::Declaration::InitDeclaratorList(idl) => idl.$mthd_name(visitor), 735 | 736 | syntax::Declaration::Precision(pq, ty) => { 737 | pq.$mthd_name(visitor); 738 | ty.$mthd_name(visitor); 739 | } 740 | 741 | syntax::Declaration::Block(block) => block.$mthd_name(visitor), 742 | 743 | syntax::Declaration::Global(tq, idents) => { 744 | tq.$mthd_name(visitor); 745 | 746 | for ident in idents { 747 | ident.$mthd_name(visitor); 748 | } 749 | } 750 | } 751 | } 752 | } 753 | } 754 | 755 | impl $host_ty for syntax::Block { 756 | fn $mthd_name($($ref)* self, visitor: &mut V) 757 | where 758 | V: $visitor_ty, 759 | { 760 | let visit = visitor.visit_block(self); 761 | 762 | if visit == Visit::Children { 763 | self.qualifier.$mthd_name(visitor); 764 | self.name.$mthd_name(visitor); 765 | 766 | for field in $($ref)* self.fields { 767 | field.$mthd_name(visitor); 768 | } 769 | 770 | self.identifier.$mthd_name(visitor); 771 | } 772 | } 773 | } 774 | 775 | impl $host_ty for syntax::InitDeclaratorList { 776 | fn $mthd_name($($ref)* self, visitor: &mut V) 777 | where 778 | V: $visitor_ty, 779 | { 780 | let visit = visitor.visit_init_declarator_list(self); 781 | 782 | if visit == Visit::Children { 783 | self.head.$mthd_name(visitor); 784 | 785 | for d in $($ref)* self.tail { 786 | d.$mthd_name(visitor); 787 | } 788 | } 789 | } 790 | } 791 | 792 | impl $host_ty for syntax::SingleDeclaration { 793 | fn $mthd_name($($ref)* self, visitor: &mut V) 794 | where 795 | V: $visitor_ty, 796 | { 797 | let visit = visitor.visit_single_declaration(self); 798 | 799 | if visit == Visit::Children { 800 | self.ty.$mthd_name(visitor); 801 | self.name.$mthd_name(visitor); 802 | self.array_specifier.$mthd_name(visitor); 803 | self.initializer.$mthd_name(visitor); 804 | } 805 | } 806 | } 807 | 808 | impl $host_ty for syntax::SingleDeclarationNoType { 809 | fn $mthd_name($($ref)* self, visitor: &mut V) 810 | where 811 | V: $visitor_ty, 812 | { 813 | let visit = visitor.visit_single_declaration_no_type(self); 814 | 815 | if visit == Visit::Children { 816 | self.ident.$mthd_name(visitor); 817 | self.initializer.$mthd_name(visitor); 818 | } 819 | } 820 | } 821 | 822 | impl $host_ty for syntax::FullySpecifiedType { 823 | fn $mthd_name($($ref)* self, visitor: &mut V) 824 | where 825 | V: $visitor_ty, 826 | { 827 | let visit = visitor.visit_full_specified_type(self); 828 | 829 | if visit == Visit::Children { 830 | self.qualifier.$mthd_name(visitor); 831 | self.ty.$mthd_name(visitor); 832 | } 833 | } 834 | } 835 | 836 | impl $host_ty for syntax::TypeSpecifier { 837 | fn $mthd_name($($ref)* self, visitor: &mut V) 838 | where 839 | V: $visitor_ty, 840 | { 841 | let visit = visitor.visit_type_specifier(self); 842 | 843 | if visit == Visit::Children { 844 | self.ty.$mthd_name(visitor); 845 | self.array_specifier.$mthd_name(visitor); 846 | } 847 | } 848 | } 849 | 850 | impl $host_ty for syntax::TypeSpecifierNonArray { 851 | fn $mthd_name($($ref)* self, visitor: &mut V) 852 | where 853 | V: $visitor_ty, 854 | { 855 | let visit = visitor.visit_type_specifier_non_array(self); 856 | 857 | if visit == Visit::Children { 858 | match self { 859 | syntax::TypeSpecifierNonArray::Struct(ss) => ss.$mthd_name(visitor), 860 | syntax::TypeSpecifierNonArray::TypeName(tn) => tn.$mthd_name(visitor), 861 | _ => (), 862 | } 863 | } 864 | } 865 | } 866 | 867 | impl $host_ty for syntax::TypeQualifier { 868 | fn $mthd_name($($ref)* self, visitor: &mut V) 869 | where 870 | V: $visitor_ty, 871 | { 872 | let visit = visitor.visit_type_qualifier(self); 873 | 874 | if visit == Visit::Children { 875 | for tqs in $($ref)* self.qualifiers.0 { 876 | tqs.$mthd_name(visitor); 877 | } 878 | } 879 | } 880 | } 881 | 882 | impl $host_ty for syntax::TypeQualifierSpec { 883 | fn $mthd_name($($ref)* self, visitor: &mut V) 884 | where 885 | V: $visitor_ty, 886 | { 887 | let visit = visitor.visit_type_qualifier_spec(self); 888 | 889 | if visit == Visit::Children { 890 | match self { 891 | syntax::TypeQualifierSpec::Storage(sq) => sq.$mthd_name(visitor), 892 | syntax::TypeQualifierSpec::Layout(lq) => lq.$mthd_name(visitor), 893 | syntax::TypeQualifierSpec::Precision(pq) => pq.$mthd_name(visitor), 894 | syntax::TypeQualifierSpec::Interpolation(iq) => iq.$mthd_name(visitor), 895 | _ => (), 896 | } 897 | } 898 | } 899 | } 900 | 901 | impl $host_ty for syntax::StorageQualifier { 902 | fn $mthd_name($($ref)* self, visitor: &mut V) 903 | where 904 | V: $visitor_ty, 905 | { 906 | let visit = visitor.visit_storage_qualifier(self); 907 | 908 | if visit == Visit::Children { 909 | if let syntax::StorageQualifier::Subroutine(names) = self { 910 | for name in names { 911 | name.$mthd_name(visitor); 912 | } 913 | } 914 | } 915 | } 916 | } 917 | 918 | impl $host_ty for syntax::LayoutQualifier { 919 | fn $mthd_name($($ref)* self, visitor: &mut V) 920 | where 921 | V: $visitor_ty, 922 | { 923 | let visit = visitor.visit_layout_qualifier(self); 924 | 925 | if visit == Visit::Children { 926 | for lqs in $($ref)* self.ids.0 { 927 | lqs.$mthd_name(visitor); 928 | } 929 | } 930 | } 931 | } 932 | 933 | impl $host_ty for syntax::LayoutQualifierSpec { 934 | fn $mthd_name($($ref)* self, visitor: &mut V) 935 | where 936 | V: $visitor_ty, 937 | { 938 | let visit = visitor.visit_layout_qualifier_spec(self); 939 | 940 | if visit == Visit::Children { 941 | if let syntax::LayoutQualifierSpec::Identifier(ident, expr) = self { 942 | ident.$mthd_name(visitor); 943 | 944 | if let Some(e) = expr { 945 | e.$mthd_name(visitor); 946 | } 947 | } 948 | } 949 | } 950 | } 951 | 952 | impl $host_ty for syntax::PrecisionQualifier { 953 | fn $mthd_name($($ref)* self, visitor: &mut V) 954 | where 955 | V: $visitor_ty, 956 | { 957 | let _ = visitor.visit_precision_qualifier(self); 958 | } 959 | } 960 | 961 | impl $host_ty for syntax::InterpolationQualifier { 962 | fn $mthd_name($($ref)* self, visitor: &mut V) 963 | where 964 | V: $visitor_ty, 965 | { 966 | let _ = visitor.visit_interpolation_qualifier(self); 967 | } 968 | } 969 | 970 | impl $host_ty for syntax::TypeName { 971 | fn $mthd_name($($ref)* self, visitor: &mut V) 972 | where 973 | V: $visitor_ty, 974 | { 975 | let _ = visitor.visit_type_name(self); 976 | } 977 | } 978 | 979 | impl $host_ty for syntax::Identifier { 980 | fn $mthd_name($($ref)* self, visitor: &mut V) 981 | where 982 | V: $visitor_ty, 983 | { 984 | let _ = visitor.visit_identifier(self); 985 | } 986 | } 987 | 988 | impl $host_ty for syntax::ArrayedIdentifier { 989 | fn $mthd_name($($ref)* self, visitor: &mut V) 990 | where 991 | V: $visitor_ty, 992 | { 993 | let visit = visitor.visit_arrayed_identifier(self); 994 | 995 | if visit == Visit::Children { 996 | self.ident.$mthd_name(visitor); 997 | self.array_spec.$mthd_name(visitor); 998 | } 999 | } 1000 | } 1001 | 1002 | impl $host_ty for syntax::Expr { 1003 | fn $mthd_name($($ref)* self, visitor: &mut V) 1004 | where 1005 | V: $visitor_ty, 1006 | { 1007 | let visit = visitor.visit_expr(self); 1008 | 1009 | if visit == Visit::Children { 1010 | match self { 1011 | syntax::Expr::Variable(ident) => ident.$mthd_name(visitor), 1012 | 1013 | syntax::Expr::Unary(op, e) => { 1014 | op.$mthd_name(visitor); 1015 | e.$mthd_name(visitor); 1016 | } 1017 | 1018 | syntax::Expr::Binary(op, a, b) => { 1019 | op.$mthd_name(visitor); 1020 | a.$mthd_name(visitor); 1021 | b.$mthd_name(visitor); 1022 | } 1023 | 1024 | syntax::Expr::Ternary(a, b, c) => { 1025 | a.$mthd_name(visitor); 1026 | b.$mthd_name(visitor); 1027 | c.$mthd_name(visitor); 1028 | } 1029 | 1030 | syntax::Expr::Assignment(lhs, op, rhs) => { 1031 | lhs.$mthd_name(visitor); 1032 | op.$mthd_name(visitor); 1033 | rhs.$mthd_name(visitor); 1034 | } 1035 | 1036 | syntax::Expr::Bracket(e, arr_spec) => { 1037 | e.$mthd_name(visitor); 1038 | arr_spec.$mthd_name(visitor); 1039 | } 1040 | 1041 | syntax::Expr::FunCall(fi, params) => { 1042 | fi.$mthd_name(visitor); 1043 | 1044 | for param in params { 1045 | param.$mthd_name(visitor); 1046 | } 1047 | } 1048 | 1049 | syntax::Expr::Dot(e, i) => { 1050 | e.$mthd_name(visitor); 1051 | i.$mthd_name(visitor); 1052 | } 1053 | 1054 | syntax::Expr::PostInc(e) => e.$mthd_name(visitor), 1055 | 1056 | syntax::Expr::PostDec(e) => e.$mthd_name(visitor), 1057 | 1058 | syntax::Expr::Comma(a, b) => { 1059 | a.$mthd_name(visitor); 1060 | b.$mthd_name(visitor); 1061 | } 1062 | 1063 | _ => (), 1064 | } 1065 | } 1066 | } 1067 | } 1068 | 1069 | impl $host_ty for syntax::UnaryOp { 1070 | fn $mthd_name($($ref)* self, visitor: &mut V) 1071 | where 1072 | V: $visitor_ty, 1073 | { 1074 | let _ = visitor.visit_unary_op(self); 1075 | } 1076 | } 1077 | 1078 | impl $host_ty for syntax::BinaryOp { 1079 | fn $mthd_name($($ref)* self, visitor: &mut V) 1080 | where 1081 | V: $visitor_ty, 1082 | { 1083 | let _ = visitor.visit_binary_op(self); 1084 | } 1085 | } 1086 | 1087 | impl $host_ty for syntax::AssignmentOp { 1088 | fn $mthd_name($($ref)* self, visitor: &mut V) 1089 | where 1090 | V: $visitor_ty, 1091 | { 1092 | let _ = visitor.visit_assignment_op(self); 1093 | } 1094 | } 1095 | 1096 | impl $host_ty for syntax::ArraySpecifier { 1097 | fn $mthd_name($($ref)* self, visitor: &mut V) 1098 | where 1099 | V: $visitor_ty, 1100 | { 1101 | let visit = visitor.visit_array_specifier(self); 1102 | 1103 | if visit == Visit::Children { 1104 | for dimension in $($ref)* self.dimensions { 1105 | dimension.$mthd_name(visitor); 1106 | } 1107 | } 1108 | } 1109 | } 1110 | 1111 | impl $host_ty for syntax::ArraySpecifierDimension { 1112 | fn $mthd_name($($ref)* self, visitor: &mut V) 1113 | where 1114 | V: $visitor_ty, 1115 | { 1116 | let visit = visitor.visit_array_specifier_dimension(self); 1117 | 1118 | if visit == Visit::Children { 1119 | if let syntax::ArraySpecifierDimension::ExplicitlySized(e) = self { 1120 | e.$mthd_name(visitor); 1121 | } 1122 | } 1123 | } 1124 | } 1125 | 1126 | impl $host_ty for syntax::FunIdentifier { 1127 | fn $mthd_name($($ref)* self, visitor: &mut V) 1128 | where 1129 | V: $visitor_ty, 1130 | { 1131 | let visit = visitor.visit_fun_identifier(self); 1132 | 1133 | if visit == Visit::Children { 1134 | match self { 1135 | syntax::FunIdentifier::Identifier(i) => i.$mthd_name(visitor), 1136 | syntax::FunIdentifier::Expr(e) => e.$mthd_name(visitor), 1137 | } 1138 | } 1139 | } 1140 | } 1141 | 1142 | impl $host_ty for syntax::StructSpecifier { 1143 | fn $mthd_name($($ref)* self, visitor: &mut V) 1144 | where 1145 | V: $visitor_ty, 1146 | { 1147 | let visit = visitor.visit_struct_specifier(self); 1148 | 1149 | if visit == Visit::Children { 1150 | self.name.$mthd_name(visitor); 1151 | 1152 | for field in $($ref)* self.fields.0 { 1153 | field.$mthd_name(visitor); 1154 | } 1155 | } 1156 | } 1157 | } 1158 | 1159 | impl $host_ty for syntax::StructFieldSpecifier { 1160 | fn $mthd_name($($ref)* self, visitor: &mut V) 1161 | where 1162 | V: $visitor_ty, 1163 | { 1164 | let visit = visitor.visit_struct_field_specifier(self); 1165 | 1166 | if visit == Visit::Children { 1167 | self.qualifier.$mthd_name(visitor); 1168 | self.ty.$mthd_name(visitor); 1169 | 1170 | for identifier in $($ref)* self.identifiers.0 { 1171 | identifier.$mthd_name(visitor); 1172 | } 1173 | } 1174 | } 1175 | } 1176 | 1177 | impl $host_ty for syntax::Statement { 1178 | fn $mthd_name($($ref)* self, visitor: &mut V) 1179 | where 1180 | V: $visitor_ty, 1181 | { 1182 | let visit = visitor.visit_statement(self); 1183 | 1184 | if visit == Visit::Children { 1185 | match self { 1186 | syntax::Statement::Compound(cs) => cs.$mthd_name(visitor), 1187 | syntax::Statement::Simple(ss) => ss.$mthd_name(visitor), 1188 | } 1189 | } 1190 | } 1191 | } 1192 | 1193 | impl $host_ty for syntax::SimpleStatement { 1194 | fn $mthd_name($($ref)* self, visitor: &mut V) 1195 | where 1196 | V: $visitor_ty, 1197 | { 1198 | let visit = visitor.visit_simple_statement(self); 1199 | 1200 | if visit == Visit::Children { 1201 | match self { 1202 | syntax::SimpleStatement::Declaration(d) => d.$mthd_name(visitor), 1203 | syntax::SimpleStatement::Expression(e) => e.$mthd_name(visitor), 1204 | syntax::SimpleStatement::Selection(s) => s.$mthd_name(visitor), 1205 | syntax::SimpleStatement::Switch(s) => s.$mthd_name(visitor), 1206 | syntax::SimpleStatement::CaseLabel(cl) => cl.$mthd_name(visitor), 1207 | syntax::SimpleStatement::Iteration(i) => i.$mthd_name(visitor), 1208 | syntax::SimpleStatement::Jump(j) => j.$mthd_name(visitor), 1209 | } 1210 | } 1211 | } 1212 | } 1213 | 1214 | impl $host_ty for syntax::CompoundStatement { 1215 | fn $mthd_name($($ref)* self, visitor: &mut V) 1216 | where 1217 | V: $visitor_ty, 1218 | { 1219 | let visit = visitor.visit_compound_statement(self); 1220 | 1221 | if visit == Visit::Children { 1222 | for stmt in $($ref)* self.statement_list { 1223 | stmt.$mthd_name(visitor); 1224 | } 1225 | } 1226 | } 1227 | } 1228 | 1229 | impl $host_ty for syntax::SelectionStatement { 1230 | fn $mthd_name($($ref)* self, visitor: &mut V) 1231 | where 1232 | V: $visitor_ty, 1233 | { 1234 | let visit = visitor.visit_selection_statement(self); 1235 | 1236 | if visit == Visit::Children { 1237 | self.cond.$mthd_name(visitor); 1238 | self.rest.$mthd_name(visitor); 1239 | } 1240 | } 1241 | } 1242 | 1243 | impl $host_ty for syntax::SelectionRestStatement { 1244 | fn $mthd_name($($ref)* self, visitor: &mut V) 1245 | where 1246 | V: $visitor_ty, 1247 | { 1248 | let visit = visitor.visit_selection_rest_statement(self); 1249 | 1250 | if visit == Visit::Children { 1251 | match self { 1252 | syntax::SelectionRestStatement::Statement(s) => s.$mthd_name(visitor), 1253 | 1254 | syntax::SelectionRestStatement::Else(a, b) => { 1255 | a.$mthd_name(visitor); 1256 | b.$mthd_name(visitor); 1257 | } 1258 | } 1259 | } 1260 | } 1261 | } 1262 | 1263 | impl $host_ty for syntax::SwitchStatement { 1264 | fn $mthd_name($($ref)* self, visitor: &mut V) 1265 | where 1266 | V: $visitor_ty, 1267 | { 1268 | let visit = visitor.visit_switch_statement(self); 1269 | 1270 | if visit == Visit::Children { 1271 | self.head.$mthd_name(visitor); 1272 | 1273 | for s in $($ref)* self.body { 1274 | s.$mthd_name(visitor); 1275 | } 1276 | } 1277 | } 1278 | } 1279 | 1280 | impl $host_ty for syntax::CaseLabel { 1281 | fn $mthd_name($($ref)* self, visitor: &mut V) 1282 | where 1283 | V: $visitor_ty, 1284 | { 1285 | let visit = visitor.visit_case_label(self); 1286 | 1287 | if visit == Visit::Children { 1288 | if let syntax::CaseLabel::Case(e) = self { 1289 | e.$mthd_name(visitor); 1290 | } 1291 | } 1292 | } 1293 | } 1294 | 1295 | impl $host_ty for syntax::IterationStatement { 1296 | fn $mthd_name($($ref)* self, visitor: &mut V) 1297 | where 1298 | V: $visitor_ty, 1299 | { 1300 | let visit = visitor.visit_iteration_statement(self); 1301 | 1302 | if visit == Visit::Children { 1303 | match self { 1304 | syntax::IterationStatement::While(c, s) => { 1305 | c.$mthd_name(visitor); 1306 | s.$mthd_name(visitor); 1307 | } 1308 | 1309 | syntax::IterationStatement::DoWhile(s, e) => { 1310 | s.$mthd_name(visitor); 1311 | e.$mthd_name(visitor); 1312 | } 1313 | 1314 | syntax::IterationStatement::For(fis, frs, s) => { 1315 | fis.$mthd_name(visitor); 1316 | frs.$mthd_name(visitor); 1317 | s.$mthd_name(visitor); 1318 | } 1319 | } 1320 | } 1321 | } 1322 | } 1323 | 1324 | impl $host_ty for syntax::ForInitStatement { 1325 | fn $mthd_name($($ref)* self, visitor: &mut V) 1326 | where 1327 | V: $visitor_ty, 1328 | { 1329 | let visit = visitor.visit_for_init_statement(self); 1330 | 1331 | if visit == Visit::Children { 1332 | match self { 1333 | syntax::ForInitStatement::Expression(e) => e.$mthd_name(visitor), 1334 | syntax::ForInitStatement::Declaration(d) => d.$mthd_name(visitor), 1335 | } 1336 | } 1337 | } 1338 | } 1339 | 1340 | impl $host_ty for syntax::ForRestStatement { 1341 | fn $mthd_name($($ref)* self, visitor: &mut V) 1342 | where 1343 | V: $visitor_ty, 1344 | { 1345 | let visit = visitor.visit_for_rest_statement(self); 1346 | 1347 | if visit == Visit::Children { 1348 | self.condition.$mthd_name(visitor); 1349 | self.post_expr.$mthd_name(visitor); 1350 | } 1351 | } 1352 | } 1353 | 1354 | impl $host_ty for syntax::JumpStatement { 1355 | fn $mthd_name($($ref)* self, visitor: &mut V) 1356 | where 1357 | V: $visitor_ty, 1358 | { 1359 | let visit = visitor.visit_jump_statement(self); 1360 | 1361 | if visit == Visit::Children { 1362 | if let syntax::JumpStatement::Return(r) = self { 1363 | r.$mthd_name(visitor); 1364 | } 1365 | } 1366 | } 1367 | } 1368 | 1369 | impl $host_ty for syntax::Condition { 1370 | fn $mthd_name($($ref)* self, visitor: &mut V) 1371 | where 1372 | V: $visitor_ty, 1373 | { 1374 | let visit = visitor.visit_condition(self); 1375 | 1376 | if visit == Visit::Children { 1377 | match self { 1378 | syntax::Condition::Expr(e) => e.$mthd_name(visitor), 1379 | 1380 | syntax::Condition::Assignment(fst, ident, init) => { 1381 | fst.$mthd_name(visitor); 1382 | ident.$mthd_name(visitor); 1383 | init.$mthd_name(visitor); 1384 | } 1385 | } 1386 | } 1387 | } 1388 | } 1389 | 1390 | impl $host_ty for syntax::Initializer { 1391 | fn $mthd_name($($ref)* self, visitor: &mut V) 1392 | where 1393 | V: $visitor_ty, 1394 | { 1395 | let visit = visitor.visit_initializer(self); 1396 | 1397 | if visit == Visit::Children { 1398 | match self { 1399 | syntax::Initializer::Simple(e) => e.$mthd_name(visitor), 1400 | 1401 | syntax::Initializer::List(i) => { 1402 | for i in $($ref)* i.0 { 1403 | i.$mthd_name(visitor); 1404 | } 1405 | } 1406 | } 1407 | } 1408 | } 1409 | } 1410 | } 1411 | } 1412 | 1413 | // immutable 1414 | make_visitor_trait!(Visitor, &); 1415 | make_host_trait!(Host, Visitor, visit, &); 1416 | 1417 | // mutable 1418 | make_visitor_trait!(VisitorMut, &mut); 1419 | make_host_trait!(HostMut, VisitorMut, visit_mut, &mut); 1420 | 1421 | #[cfg(test)] 1422 | mod tests { 1423 | use std::iter::FromIterator; 1424 | 1425 | use super::*; 1426 | use syntax; 1427 | 1428 | #[test] 1429 | fn count_variables() { 1430 | let decl0 = syntax::Statement::declare_var( 1431 | syntax::TypeSpecifierNonArray::Float, 1432 | "x", 1433 | None, 1434 | Some(syntax::Expr::from(3.14).into()), 1435 | ); 1436 | 1437 | let decl1 = syntax::Statement::declare_var(syntax::TypeSpecifierNonArray::Int, "y", None, None); 1438 | 1439 | let decl2 = 1440 | syntax::Statement::declare_var(syntax::TypeSpecifierNonArray::Vec4, "z", None, None); 1441 | 1442 | let compound = syntax::CompoundStatement::from_iter(vec![decl0, decl1, decl2]); 1443 | 1444 | // our visitor that will count the number of variables it saw 1445 | struct Counter { 1446 | var_nb: usize, 1447 | } 1448 | 1449 | impl Visitor for Counter { 1450 | // we are only interested in single declaration with a name 1451 | fn visit_single_declaration(&mut self, declaration: &syntax::SingleDeclaration) -> Visit { 1452 | if declaration.name.is_some() { 1453 | self.var_nb += 1; 1454 | } 1455 | 1456 | // do not go deeper 1457 | Visit::Parent 1458 | } 1459 | } 1460 | 1461 | let mut counter = Counter { var_nb: 0 }; 1462 | compound.visit(&mut counter); 1463 | assert_eq!(counter.var_nb, 3); 1464 | } 1465 | } 1466 | -------------------------------------------------------------------------------- /glsl/tests/incorrect_statement.rs: -------------------------------------------------------------------------------- 1 | use glsl::parser::Parse; 2 | use glsl::syntax; 3 | 4 | #[test] 5 | fn incorrect_statement() { 6 | let r = syntax::TranslationUnit::parse( 7 | " 8 | int fetch_transform(int id) { 9 | return id; 10 | } 11 | 12 | bool ray_plane() { 13 | if 1 { 14 | } 15 | ", 16 | ); 17 | 18 | assert!(r.is_err()); 19 | } 20 | -------------------------------------------------------------------------------- /glsl/tests/left_associativity.rs: -------------------------------------------------------------------------------- 1 | use glsl::parser::Parse; 2 | use glsl::syntax; 3 | 4 | #[test] 5 | fn left_associativity() { 6 | for (opstr, opname) in [ 7 | ("+", syntax::BinaryOp::Add), 8 | ("&&", syntax::BinaryOp::And), 9 | ("||", syntax::BinaryOp::Or), 10 | ] 11 | .iter() 12 | { 13 | let r = syntax::TranslationUnit::parse(format!( 14 | " 15 | void main() {{ 16 | x = a {op} b {op} c; 17 | }} 18 | ", 19 | op = opstr 20 | )); 21 | 22 | let expected = syntax::TranslationUnit::from_non_empty_iter(vec![ 23 | syntax::ExternalDeclaration::FunctionDefinition(syntax::FunctionDefinition { 24 | prototype: syntax::FunctionPrototype { 25 | ty: syntax::FullySpecifiedType { 26 | qualifier: None, 27 | ty: syntax::TypeSpecifier { 28 | ty: syntax::TypeSpecifierNonArray::Void, 29 | array_specifier: None, 30 | }, 31 | }, 32 | name: "main".into(), 33 | parameters: Vec::new(), 34 | }, 35 | statement: syntax::CompoundStatement { 36 | statement_list: vec![syntax::Statement::Simple(Box::new( 37 | syntax::SimpleStatement::Expression(Some(syntax::Expr::Assignment( 38 | Box::new(syntax::Expr::Variable("x".into())), 39 | syntax::AssignmentOp::Equal, 40 | Box::new(syntax::Expr::Binary( 41 | opname.clone(), 42 | Box::new(syntax::Expr::Binary( 43 | opname.clone(), 44 | Box::new(syntax::Expr::Variable("a".into())), 45 | Box::new(syntax::Expr::Variable("b".into())), 46 | )), 47 | Box::new(syntax::Expr::Variable("c".into())), 48 | )), 49 | ))), 50 | ))], 51 | }, 52 | }), 53 | ]) 54 | .unwrap(); 55 | 56 | assert_eq!(r, Ok(expected)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /glsl/tests/missing_zero_float.rs: -------------------------------------------------------------------------------- 1 | extern crate glsl; 2 | 3 | use glsl::parser::Parse; 4 | use glsl::syntax::TranslationUnit; 5 | 6 | #[test] 7 | fn missing_zero_float_is_valid() { 8 | let r = TranslationUnit::parse( 9 | " 10 | void main() { 11 | float x = 1. * .5; 12 | }", 13 | ); 14 | 15 | assert!(r.is_ok()); 16 | } 17 | 18 | #[test] 19 | fn float_exp_is_valid() { 20 | let r = TranslationUnit::parse( 21 | " 22 | void main() { 23 | float x = 1e-5; 24 | }", 25 | ); 26 | 27 | assert!(r.is_ok()); 28 | } 29 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2018" 2 | 3 | fn_args_layout = "Tall" 4 | force_explicit_abi = true 5 | hard_tabs = false 6 | max_width = 100 7 | merge_derives = true 8 | newline_style = "Unix" 9 | remove_nested_parens = true 10 | reorder_imports = true 11 | reorder_modules = true 12 | tab_spaces = 2 13 | use_field_init_shorthand = true 14 | use_small_heuristics = "Default" 15 | use_try_shorthand = true 16 | --------------------------------------------------------------------------------