glsl_lang/transpiler/
glsl.rs

1//! A GLSL450/GLSL460 transpiler that takes a syntax tree and writes it as a plain raw GLSL
2//! [`String`].
3//!
4//! # Foreword
5//!
6//! This module exports several functions that just transform a part of a syntax tree into its raw
7//! GLSL [`String`] representation.
8//!
9//! > Important note: this module – and actually, any [`transpiler`] module – is not responsible in
10//! > optimizing the syntax tree nor semantically check its validity. This is done in other stages
11//! > of the compilation process.
12//!
13//! In order to achieve that purpose, you could:
14//!
15//! - For each elements in the AST, return a [`String`] or [`Cow<str>`].
16//! - Insert the string representation via a formatter.
17//!
18//! The second solution is better because it lets the user handle the memory the way they want:
19//! they might just use a dynamic buffer that implements [`Write`] or simply pass a `&mut`
20//! [`String`]. It’s up to you.
21//!
22//! # How to use this module
23//!
24//! First, head over to the [`ast`] module. That module defines the AST items defined by GLSL. This
25//! very module provides you with functions like `show_*` taking the AST item and writing it to a
26//! [`Write`] object. You’re likely to be interested in [`show_translation_unit`] to start with.
27//!
28//! [`Cow<str>`]: std::borrow::Cow
29//! [`Write`]: std::fmt::Write
30//! [`show_translation_unit`]: crate::transpiler::glsl::show_translation_unit
31//! [`ast`]: crate::ast
32//! [`transpiler`]: crate::transpiler
33
34use std::fmt::Write;
35
36use once_cell::sync::Lazy;
37
38/// Indentation style of the output
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum IndentStyle {
41    /// No indentation is generated
42    None,
43    /// Items are indented with tabs. In case spaces are needed for alignment,
44    /// tabs are assumed to be `tab_size` characters wide.
45    Tabs {
46        /// Size of the tabs in characters
47        tab_size: u32,
48        /// Number of tab characters used per indent level
49        count: u32,
50    },
51    /// Items are indented with spaces.
52    Spaces {
53        /// Number of space characters used per indent level
54        count: u32,
55    },
56}
57
58impl IndentStyle {
59    /// Write the current indenting level and style to the output
60    pub fn write<F>(&self, f: &mut F, levels: u32) -> std::fmt::Result
61    where
62        F: Write + ?Sized,
63    {
64        match self {
65            Self::None => {}
66            Self::Tabs { count, .. } => {
67                for _ in 0..count * levels {
68                    f.write_char('\t')?;
69                }
70            }
71            Self::Spaces { count, .. } => {
72                for _ in 0..count * levels {
73                    f.write_char(' ')?;
74                }
75            }
76        }
77
78        Ok(())
79    }
80}
81
82impl Default for IndentStyle {
83    fn default() -> Self {
84        Self::Spaces { count: 4 }
85    }
86}
87
88/// Formatter whitespace
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum Whitespace {
91    /// No whitespace
92    None,
93    /// A space
94    Space,
95    /// A newline
96    Newline,
97}
98
99impl Whitespace {
100    /// Write this whitespace to the output
101    pub fn write<F>(&self, f: &mut F, state: &mut FormattingState) -> std::fmt::Result
102    where
103        F: Write + ?Sized,
104    {
105        match self {
106            Self::None => Ok(()),
107            Self::Space => f.write_char(' '),
108            Self::Newline => state.new_line(true),
109        }
110    }
111}
112
113/// Formatting settings for the GLSL transpiler
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct FormattingSettings {
116    /// Indentation style of the output
117    pub indent_style: IndentStyle,
118    /// Insert a space before block open braces
119    pub space_before_open_block: bool,
120    /// Insert newlines after block open braces
121    pub newline_after_open_block: bool,
122    /// Insert newlines before block close braces
123    pub newline_before_close_block: bool,
124    /// Insert newline after block close brace
125    pub newline_after_close_block: bool,
126    /// Insert newline after a compound statement collapsed to a simple statement
127    pub newline_after_collapsed_statement: bool,
128    /// Insert newline after a compound statement collapsed to a simple statement
129    pub newline_before_collapsed_statement: bool,
130    /// What to insert between fields of a struct
131    pub struct_field_separator: Whitespace,
132    /// What to insert after a struct declaration
133    pub struct_declaration_terminator: Whitespace,
134    /// What to insert after a declaration
135    pub declaration_terminator: Whitespace,
136    /// What to insert after the case label ending colon
137    pub case_label_terminator: Whitespace,
138    /// Insert spaces around binary ops
139    pub spaces_around_binary_ops: bool,
140    /// What to insert after a statement
141    pub statement_terminator: Whitespace,
142    /// What to insert after a function definition
143    pub function_definition_terminator: Whitespace,
144    /// Whether to collapse compound statements that contain a single statement
145    /// to a simple statement or not (i.e., remove braces)
146    pub collapse_single_item_compound_statements: bool,
147    /// Insert a space before the else keyword in an if statement
148    pub space_before_else: bool,
149    /// Insert a space after a list separator token (i.e., comma)
150    pub space_after_list_separator: bool,
151    /// Insert a space after a for statement separator token (i.e., semicolon)
152    pub space_after_for_statement_separator: bool,
153    /// Insert a space after the { and before the } delimiting a list of initializer
154    /// expressions
155    pub spaces_surrounding_initializer_list_expressions: bool,
156    /// Insert a space before the ( and after the ) that are part of a statement
157    pub spaces_surrounding_statement_parentheses: bool,
158}
159
160impl FormattingSettings {
161    /// Minifying (e.g, source code size reducing) formatting settings.
162    /// The generated code will be apt for machine consumption, but not for human comprehension
163    pub fn minifying() -> Self {
164        Self {
165            indent_style: IndentStyle::None,
166            space_before_open_block: false,
167            newline_after_open_block: false,
168            newline_before_close_block: false,
169            newline_after_close_block: false,
170            newline_after_collapsed_statement: false,
171            newline_before_collapsed_statement: false,
172            struct_field_separator: Whitespace::None,
173            struct_declaration_terminator: Whitespace::None,
174            declaration_terminator: Whitespace::None,
175            case_label_terminator: Whitespace::None,
176            spaces_around_binary_ops: false,
177            statement_terminator: Whitespace::None,
178            function_definition_terminator: Whitespace::None,
179            collapse_single_item_compound_statements: true,
180            space_before_else: false,
181            space_after_list_separator: false,
182            space_after_for_statement_separator: false,
183            spaces_surrounding_initializer_list_expressions: false,
184            spaces_surrounding_statement_parentheses: false,
185        }
186    }
187}
188
189impl Default for FormattingSettings {
190    fn default() -> Self {
191        Self {
192            indent_style: IndentStyle::default(),
193            space_before_open_block: true,
194            newline_after_open_block: true,
195            newline_before_close_block: true,
196            newline_after_close_block: true,
197            newline_after_collapsed_statement: true,
198            newline_before_collapsed_statement: true,
199            struct_field_separator: Whitespace::Newline,
200            struct_declaration_terminator: Whitespace::Newline,
201            declaration_terminator: Whitespace::Newline,
202            case_label_terminator: Whitespace::Newline,
203            spaces_around_binary_ops: true,
204            statement_terminator: Whitespace::Newline,
205            function_definition_terminator: Whitespace::Newline,
206            collapse_single_item_compound_statements: false,
207            space_before_else: true,
208            space_after_list_separator: true,
209            space_after_for_statement_separator: true,
210            spaces_surrounding_initializer_list_expressions: true,
211            spaces_surrounding_statement_parentheses: true,
212        }
213    }
214}
215
216/// Formatting state of the GLSL transpiler
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub struct FormattingState<'s> {
219    /// Formatting settings
220    pub settings: &'s FormattingSettings,
221    indentation_level: u32,
222    new_line_pending: bool,
223    in_function_definition_statement: bool,
224    last_flush_line_flushed_line: bool,
225    is_first_external_declaration: bool,
226}
227
228impl<'s> FormattingState<'s> {
229    fn write_indent<F>(&self, f: &mut F) -> std::fmt::Result
230    where
231        F: Write + ?Sized,
232    {
233        self.settings.indent_style.write(f, self.indentation_level)
234    }
235
236    fn write_line<F>(&mut self, f: &mut F) -> std::fmt::Result
237    where
238        F: Write + ?Sized,
239    {
240        f.write_char('\n')?;
241        self.write_indent(f)
242    }
243
244    /// Append a pending new line to the output
245    pub fn new_line(&mut self, required: bool) -> std::fmt::Result {
246        if required {
247            self.new_line_pending = true;
248        }
249
250        Ok(())
251    }
252
253    /// Consume the pending newlines
254    pub fn consume_newline(&mut self) {
255        self.new_line_pending = false;
256    }
257
258    /// Flush pending newlines to the output, if any
259    pub fn flush_line<F>(&mut self, f: &mut F) -> std::fmt::Result
260    where
261        F: Write + ?Sized,
262    {
263        if self.new_line_pending {
264            self.write_line(f)?;
265            self.new_line_pending = false;
266            self.last_flush_line_flushed_line = true;
267        } else {
268            self.last_flush_line_flushed_line = false;
269        }
270
271        Ok(())
272    }
273
274    /// Makes sure that the next text to be written to the output will be put
275    /// at an empty line, or at a line with only indentation characters.
276    /// Does nothing if the output is already at an empty line
277    pub fn move_to_empty_line<F>(&mut self, f: &mut F) -> std::fmt::Result
278    where
279        F: Write + ?Sized,
280    {
281        if !self.is_first_external_declaration && !self.last_flush_line_flushed_line {
282            self.new_line(true)?;
283            self.write_line(f)?;
284        }
285
286        Ok(())
287    }
288
289    /// Flush pending newlines as spaces to the output, if any
290    pub fn flush_space<F>(&mut self, f: &mut F) -> std::fmt::Result
291    where
292        F: Write + ?Sized,
293    {
294        if self.new_line_pending {
295            f.write_char(' ')?;
296            self.new_line_pending = false;
297        }
298
299        Ok(())
300    }
301
302    /// Enter a new compound statement block, and update the indentation level
303    pub fn enter_compound_statement_block<F>(&mut self, f: &mut F) -> std::fmt::Result
304    where
305        F: Write + ?Sized,
306    {
307        // Insert space if this is a top-level compound statement
308        if self.settings.space_before_open_block && self.in_function_definition_statement {
309            f.write_char(' ')?;
310        }
311
312        self.enter_block_inner(f)
313    }
314
315    /// Enters a new external declaration, flushing pending newlines
316    pub fn enter_external_declaration<F>(&mut self, f: &mut F) -> std::fmt::Result
317    where
318        F: Write + ?Sized,
319    {
320        self.flush_line(f)
321    }
322
323    /// Exits the current external declaration
324    pub fn exit_external_declaration(&mut self) {
325        self.is_first_external_declaration = false;
326    }
327
328    /// Enter a new block, and update the indentation level
329    pub fn enter_block<F>(&mut self, f: &mut F) -> std::fmt::Result
330    where
331        F: Write + ?Sized,
332    {
333        // Insert space
334        if self.settings.space_before_open_block {
335            f.write_char(' ')?;
336        }
337
338        self.enter_block_inner(f)
339    }
340
341    /// Common logic for entering a new block, and updating the indentation level
342    fn enter_block_inner<F>(&mut self, f: &mut F) -> std::fmt::Result
343    where
344        F: Write + ?Sized,
345    {
346        // Open block
347        f.write_char('{')?;
348
349        // Write line with new indentation level
350        self.indentation_level += 1;
351        self.new_line(self.settings.newline_after_open_block)?;
352
353        Ok(())
354    }
355
356    /// Exit the current block, and update the indentation level
357    pub fn exit_block<F>(&mut self, f: &mut F) -> std::fmt::Result
358    where
359        F: Write + ?Sized,
360    {
361        // Update indentation level
362        self.indentation_level -= 1;
363
364        // Next line
365        self.new_line(self.settings.newline_before_close_block)?;
366
367        // Flush lines
368        self.flush_line(f)?;
369
370        // Close block
371        f.write_char('}')?;
372
373        // Next line
374        self.new_line(self.settings.newline_after_close_block)?;
375
376        Ok(())
377    }
378
379    /// Enter a new function definition statement
380    pub fn enter_function_definition_statement(&mut self) {
381        self.in_function_definition_statement = true;
382    }
383
384    /// Consume the current function definition statement
385    pub fn consume_function_definition_statement(&mut self) {
386        self.in_function_definition_statement = false;
387    }
388
389    /// Enter a collapsed compound statement
390    pub fn enter_collapsed_compound_statement(&mut self) -> std::fmt::Result {
391        // Update indentation level
392        self.indentation_level += 1;
393
394        // Next line
395        if self.settings.newline_before_collapsed_statement {
396            self.new_line(self.settings.newline_before_collapsed_statement)?;
397        }
398
399        Ok(())
400    }
401
402    /// Exit the current collapsed compound statement
403    pub fn exit_collapsed_compound_statement(&mut self) -> std::fmt::Result {
404        // Update indentation level
405        self.indentation_level -= 1;
406
407        // Next line
408        if self.settings.newline_after_collapsed_statement {
409            self.new_line(self.settings.newline_after_collapsed_statement)?;
410        }
411
412        Ok(())
413    }
414
415    /// Enter a list initializer
416    pub fn enter_initializer_list<F>(&mut self, f: &mut F) -> std::fmt::Result
417    where
418        F: Write + ?Sized,
419    {
420        f.write_char('{')?;
421
422        if self
423            .settings
424            .spaces_surrounding_initializer_list_expressions
425        {
426            f.write_char(' ')?;
427        }
428
429        Ok(())
430    }
431
432    /// Exit the current list initializer
433    pub fn end_initializer_list<F>(&mut self, f: &mut F) -> std::fmt::Result
434    where
435        F: Write + ?Sized,
436    {
437        if self
438            .settings
439            .spaces_surrounding_initializer_list_expressions
440        {
441            f.write_char(' ')?;
442        }
443
444        f.write_char('}')
445    }
446
447    /// Enter a case label
448    pub fn enter_case_label<F>(&mut self, f: &mut F) -> std::fmt::Result
449    where
450        F: Write + ?Sized,
451    {
452        f.write_char(':')?;
453        self.settings.case_label_terminator.write(f, self)
454    }
455
456    /// Write a else keyword, part of an if statement
457    pub fn write_else<F>(&mut self, f: &mut F) -> std::fmt::Result
458    where
459        F: Write + ?Sized,
460    {
461        if self.settings.space_before_else {
462            f.write_char(' ')?;
463        }
464
465        f.write_str("else ")
466    }
467
468    /// Write a struct field separator
469    pub fn write_struct_field_separator<F>(&mut self, f: &mut F) -> std::fmt::Result
470    where
471        F: Write + ?Sized,
472    {
473        f.write_char(';')?;
474        self.settings.struct_field_separator.write(f, self)
475    }
476
477    /// Write a list separator
478    pub fn write_list_separator<F>(&mut self, f: &mut F) -> std::fmt::Result
479    where
480        F: Write + ?Sized,
481    {
482        f.write_char(',')?;
483        if self.settings.space_after_list_separator {
484            f.write_char(' ')?;
485        }
486
487        Ok(())
488    }
489
490    /// Write a for statement separator
491    pub fn write_for_statement_separator<F>(&mut self, f: &mut F) -> std::fmt::Result
492    where
493        F: Write + ?Sized,
494    {
495        f.write_char(';')?;
496        if self.settings.space_after_for_statement_separator {
497            f.write_char(' ')?;
498        }
499
500        Ok(())
501    }
502
503    /// Write a struct declaration terminator
504    pub fn write_struct_declaration_terminator<F>(&mut self, f: &mut F) -> std::fmt::Result
505    where
506        F: Write + ?Sized,
507    {
508        f.write_char(';')?;
509        self.settings.struct_declaration_terminator.write(f, self)
510    }
511
512    /// Write a declaration terminator
513    pub fn write_declaration_terminator<F>(&mut self, f: &mut F) -> std::fmt::Result
514    where
515        F: Write + ?Sized,
516    {
517        f.write_char(';')?;
518        self.settings.declaration_terminator.write(f, self)
519    }
520
521    /// Write a binary operator
522    pub fn write_binary_op<F>(&self, f: &mut F, op: &str) -> std::fmt::Result
523    where
524        F: Write + ?Sized,
525    {
526        if self.settings.spaces_around_binary_ops {
527            f.write_char(' ')?;
528        }
529
530        f.write_str(op)?;
531
532        if self.settings.spaces_around_binary_ops {
533            f.write_char(' ')?;
534        }
535
536        Ok(())
537    }
538
539    /// Write a statement terminator
540    pub fn write_statement_terminator<F>(&mut self, f: &mut F) -> std::fmt::Result
541    where
542        F: Write + ?Sized,
543    {
544        f.write_char(';')?;
545        self.settings.statement_terminator.write(f, self)
546    }
547
548    /// Write a function definition terminator
549    pub fn write_function_definition_terminator<F>(&mut self, f: &mut F) -> std::fmt::Result
550    where
551        F: Write + ?Sized,
552    {
553        self.settings.function_definition_terminator.write(f, self)
554    }
555
556    /// Write an opening parenthesis for a statement
557    pub fn write_statement_opening_parenthesis<F>(&mut self, f: &mut F) -> std::fmt::Result
558    where
559        F: Write + ?Sized,
560    {
561        if self.settings.spaces_surrounding_statement_parentheses {
562            f.write_char(' ')?;
563        }
564
565        f.write_char('(')
566    }
567
568    /// Write a closing parenthesis for a statement
569    pub fn write_statement_closing_parenthesis<F>(&mut self, f: &mut F) -> std::fmt::Result
570    where
571        F: Write + ?Sized,
572    {
573        f.write_char(')')?;
574
575        if self.settings.spaces_surrounding_statement_parentheses {
576            f.write_char(' ')?;
577        }
578
579        Ok(())
580    }
581}
582
583impl<'s> From<&'s FormattingSettings> for FormattingState<'s> {
584    fn from(settings: &'s FormattingSettings) -> Self {
585        Self {
586            settings,
587            indentation_level: 0,
588            new_line_pending: false,
589            in_function_definition_statement: false,
590            last_flush_line_flushed_line: false,
591            is_first_external_declaration: true,
592        }
593    }
594}
595
596static DEFAULT_SETTINGS: Lazy<FormattingSettings> = Lazy::new(FormattingSettings::default);
597
598impl Default for FormattingState<'static> {
599    fn default() -> Self {
600        Self {
601            settings: &DEFAULT_SETTINGS,
602            indentation_level: 0,
603            new_line_pending: false,
604            in_function_definition_statement: false,
605            last_flush_line_flushed_line: false,
606            is_first_external_declaration: true,
607        }
608    }
609}
610
611use crate::ast;
612
613/// Precedence information for transpiling parentheses properly
614trait HasPrecedence {
615    /// Return the precedence level of the expression
616    fn precedence(&self) -> u32;
617}
618
619impl HasPrecedence for ast::ExprData {
620    fn precedence(&self) -> u32 {
621        match self {
622            // 0 isn't a valid precedence, but we use this to represent atomic expressions
623            Self::Variable(_)
624            | Self::IntConst(_)
625            | Self::UIntConst(_)
626            | Self::BoolConst(_)
627            | Self::FloatConst(_)
628            | Self::DoubleConst(_) => 0,
629            // Precedence operator expression is precedence of operator
630            Self::Unary(op, _) => op.precedence(),
631            Self::Binary(op, _, _) => op.precedence(),
632            Self::Ternary(_, _, _) => 15,
633            Self::Assignment(_, op, _) => op.precedence(),
634            Self::Bracket(_, _)
635            | Self::FunCall(_, _)
636            | Self::Dot(_, _)
637            | Self::PostInc(_)
638            | Self::PostDec(_) => 2,
639            Self::Comma(_, _) => 17,
640        }
641    }
642}
643
644impl HasPrecedence for ast::UnaryOpData {
645    fn precedence(&self) -> u32 {
646        3
647    }
648}
649
650impl HasPrecedence for ast::BinaryOpData {
651    fn precedence(&self) -> u32 {
652        match self {
653            Self::Mult | Self::Div | Self::Mod => 4,
654            Self::Add | Self::Sub => 5,
655            Self::LShift | Self::RShift => 6,
656            Self::Lt | Self::Gt | Self::Lte | Self::Gte => 7,
657            Self::Equal | Self::NonEqual => 8,
658            Self::BitAnd => 9,
659            Self::BitXor => 10,
660            Self::BitOr => 11,
661            Self::And => 12,
662            Self::Xor => 13,
663            Self::Or => 14,
664        }
665    }
666}
667
668impl HasPrecedence for ast::AssignmentOp {
669    fn precedence(&self) -> u32 {
670        16
671    }
672}
673
674/// Transpile an identifier to GLSL
675pub fn show_identifier<F>(
676    f: &mut F,
677    i: &ast::Identifier,
678    _: &mut FormattingState<'_>,
679) -> std::fmt::Result
680where
681    F: Write + ?Sized,
682{
683    f.write_str(&i.0)
684}
685
686/// Transpile a type_name to GLSL
687pub fn show_type_name<F>(
688    f: &mut F,
689    t: &ast::TypeName,
690    _: &mut FormattingState<'_>,
691) -> std::fmt::Result
692where
693    F: Write + ?Sized,
694{
695    f.write_str(&t.0)
696}
697
698/// Transpile a type_specifier_non_array to GLSL
699pub fn show_type_specifier_non_array<F>(
700    f: &mut F,
701    t: &ast::TypeSpecifierNonArray,
702    state: &mut FormattingState<'_>,
703) -> std::fmt::Result
704where
705    F: Write + ?Sized,
706{
707    match **t {
708        ast::TypeSpecifierNonArrayData::Void => f.write_str("void"),
709        ast::TypeSpecifierNonArrayData::Bool => f.write_str("bool"),
710        ast::TypeSpecifierNonArrayData::Int => f.write_str("int"),
711        ast::TypeSpecifierNonArrayData::UInt => f.write_str("uint"),
712        ast::TypeSpecifierNonArrayData::Float => f.write_str("float"),
713        ast::TypeSpecifierNonArrayData::Double => f.write_str("double"),
714        ast::TypeSpecifierNonArrayData::Vec2 => f.write_str("vec2"),
715        ast::TypeSpecifierNonArrayData::Vec3 => f.write_str("vec3"),
716        ast::TypeSpecifierNonArrayData::Vec4 => f.write_str("vec4"),
717        ast::TypeSpecifierNonArrayData::DVec2 => f.write_str("dvec2"),
718        ast::TypeSpecifierNonArrayData::DVec3 => f.write_str("dvec3"),
719        ast::TypeSpecifierNonArrayData::DVec4 => f.write_str("dvec4"),
720        ast::TypeSpecifierNonArrayData::BVec2 => f.write_str("bvec2"),
721        ast::TypeSpecifierNonArrayData::BVec3 => f.write_str("bvec3"),
722        ast::TypeSpecifierNonArrayData::BVec4 => f.write_str("bvec4"),
723        ast::TypeSpecifierNonArrayData::IVec2 => f.write_str("ivec2"),
724        ast::TypeSpecifierNonArrayData::IVec3 => f.write_str("ivec3"),
725        ast::TypeSpecifierNonArrayData::IVec4 => f.write_str("ivec4"),
726        ast::TypeSpecifierNonArrayData::UVec2 => f.write_str("uvec2"),
727        ast::TypeSpecifierNonArrayData::UVec3 => f.write_str("uvec3"),
728        ast::TypeSpecifierNonArrayData::UVec4 => f.write_str("uvec4"),
729        ast::TypeSpecifierNonArrayData::Mat2 => f.write_str("mat2"),
730        ast::TypeSpecifierNonArrayData::Mat3 => f.write_str("mat3"),
731        ast::TypeSpecifierNonArrayData::Mat4 => f.write_str("mat4"),
732        ast::TypeSpecifierNonArrayData::Mat22 => f.write_str("mat2x2"),
733        ast::TypeSpecifierNonArrayData::Mat23 => f.write_str("mat2x3"),
734        ast::TypeSpecifierNonArrayData::Mat24 => f.write_str("mat2x4"),
735        ast::TypeSpecifierNonArrayData::Mat32 => f.write_str("mat3x2"),
736        ast::TypeSpecifierNonArrayData::Mat33 => f.write_str("mat3x3"),
737        ast::TypeSpecifierNonArrayData::Mat34 => f.write_str("mat3x4"),
738        ast::TypeSpecifierNonArrayData::Mat42 => f.write_str("mat4x2"),
739        ast::TypeSpecifierNonArrayData::Mat43 => f.write_str("mat4x3"),
740        ast::TypeSpecifierNonArrayData::Mat44 => f.write_str("mat4x4"),
741        ast::TypeSpecifierNonArrayData::DMat2 => f.write_str("dmat2"),
742        ast::TypeSpecifierNonArrayData::DMat3 => f.write_str("dmat3"),
743        ast::TypeSpecifierNonArrayData::DMat4 => f.write_str("dmat4"),
744        ast::TypeSpecifierNonArrayData::DMat22 => f.write_str("dmat2x2"),
745        ast::TypeSpecifierNonArrayData::DMat23 => f.write_str("dmat2x3"),
746        ast::TypeSpecifierNonArrayData::DMat24 => f.write_str("dmat2x4"),
747        ast::TypeSpecifierNonArrayData::DMat32 => f.write_str("dmat3x2"),
748        ast::TypeSpecifierNonArrayData::DMat33 => f.write_str("dmat3x3"),
749        ast::TypeSpecifierNonArrayData::DMat34 => f.write_str("dmat3x4"),
750        ast::TypeSpecifierNonArrayData::DMat42 => f.write_str("dmat4x2"),
751        ast::TypeSpecifierNonArrayData::DMat43 => f.write_str("dmat4x3"),
752        ast::TypeSpecifierNonArrayData::DMat44 => f.write_str("dmat4x4"),
753        ast::TypeSpecifierNonArrayData::Sampler1D => f.write_str("sampler1D"),
754        ast::TypeSpecifierNonArrayData::Image1D => f.write_str("image1D"),
755        ast::TypeSpecifierNonArrayData::Sampler2D => f.write_str("sampler2D"),
756        ast::TypeSpecifierNonArrayData::Image2D => f.write_str("image2D"),
757        ast::TypeSpecifierNonArrayData::Sampler3D => f.write_str("sampler3D"),
758        ast::TypeSpecifierNonArrayData::Image3D => f.write_str("image3D"),
759        ast::TypeSpecifierNonArrayData::SamplerCube => f.write_str("samplerCube"),
760        ast::TypeSpecifierNonArrayData::ImageCube => f.write_str("imageCube"),
761        ast::TypeSpecifierNonArrayData::Sampler2DRect => f.write_str("sampler2DRect"),
762        ast::TypeSpecifierNonArrayData::Image2DRect => f.write_str("image2DRect"),
763        ast::TypeSpecifierNonArrayData::Sampler1DArray => f.write_str("sampler1DArray"),
764        ast::TypeSpecifierNonArrayData::Image1DArray => f.write_str("image1DArray"),
765        ast::TypeSpecifierNonArrayData::Sampler2DArray => f.write_str("sampler2DArray"),
766        ast::TypeSpecifierNonArrayData::Image2DArray => f.write_str("image2DArray"),
767        ast::TypeSpecifierNonArrayData::SamplerBuffer => f.write_str("samplerBuffer"),
768        ast::TypeSpecifierNonArrayData::ImageBuffer => f.write_str("imageBuffer"),
769        ast::TypeSpecifierNonArrayData::Sampler2DMs => f.write_str("sampler2DMS"),
770        ast::TypeSpecifierNonArrayData::Image2DMs => f.write_str("image2DMS"),
771        ast::TypeSpecifierNonArrayData::Sampler2DMsArray => f.write_str("sampler2DMSArray"),
772        ast::TypeSpecifierNonArrayData::Image2DMsArray => f.write_str("image2DMSArray"),
773        ast::TypeSpecifierNonArrayData::SamplerCubeArray => f.write_str("samplerCubeArray"),
774        ast::TypeSpecifierNonArrayData::ImageCubeArray => f.write_str("imageCubeArray"),
775        ast::TypeSpecifierNonArrayData::Sampler1DShadow => f.write_str("sampler1DShadow"),
776        ast::TypeSpecifierNonArrayData::Sampler2DShadow => f.write_str("sampler2DShadow"),
777        ast::TypeSpecifierNonArrayData::Sampler2DRectShadow => f.write_str("sampler2DRectShadow"),
778        ast::TypeSpecifierNonArrayData::Sampler1DArrayShadow => f.write_str("sampler1DArrayShadow"),
779        ast::TypeSpecifierNonArrayData::Sampler2DArrayShadow => f.write_str("sampler2DArrayShadow"),
780        ast::TypeSpecifierNonArrayData::SamplerCubeShadow => f.write_str("samplerCubeShadow"),
781        ast::TypeSpecifierNonArrayData::SamplerCubeArrayShadow => {
782            f.write_str("samplerCubeArrayShadow")
783        }
784        ast::TypeSpecifierNonArrayData::ISampler1D => f.write_str("isampler1D"),
785        ast::TypeSpecifierNonArrayData::IImage1D => f.write_str("iimage1D"),
786        ast::TypeSpecifierNonArrayData::ISampler2D => f.write_str("isampler2D"),
787        ast::TypeSpecifierNonArrayData::IImage2D => f.write_str("iimage2D"),
788        ast::TypeSpecifierNonArrayData::ISampler3D => f.write_str("isampler3D"),
789        ast::TypeSpecifierNonArrayData::IImage3D => f.write_str("iimage3D"),
790        ast::TypeSpecifierNonArrayData::ISamplerCube => f.write_str("isamplerCube"),
791        ast::TypeSpecifierNonArrayData::IImageCube => f.write_str("iimageCube"),
792        ast::TypeSpecifierNonArrayData::ISampler2DRect => f.write_str("isampler2DRect"),
793        ast::TypeSpecifierNonArrayData::IImage2DRect => f.write_str("iimage2DRect"),
794        ast::TypeSpecifierNonArrayData::ISampler1DArray => f.write_str("isampler1DArray"),
795        ast::TypeSpecifierNonArrayData::IImage1DArray => f.write_str("iimage1DArray"),
796        ast::TypeSpecifierNonArrayData::ISampler2DArray => f.write_str("isampler2DArray"),
797        ast::TypeSpecifierNonArrayData::IImage2DArray => f.write_str("iimage2DArray"),
798        ast::TypeSpecifierNonArrayData::ISamplerBuffer => f.write_str("isamplerBuffer"),
799        ast::TypeSpecifierNonArrayData::IImageBuffer => f.write_str("iimageBuffer"),
800        ast::TypeSpecifierNonArrayData::ISampler2DMs => f.write_str("isampler2MS"),
801        ast::TypeSpecifierNonArrayData::IImage2DMs => f.write_str("iimage2DMS"),
802        ast::TypeSpecifierNonArrayData::ISampler2DMsArray => f.write_str("isampler2DMSArray"),
803        ast::TypeSpecifierNonArrayData::IImage2DMsArray => f.write_str("iimage2DMSArray"),
804        ast::TypeSpecifierNonArrayData::ISamplerCubeArray => f.write_str("isamplerCubeArray"),
805        ast::TypeSpecifierNonArrayData::IImageCubeArray => f.write_str("iimageCubeArray"),
806        ast::TypeSpecifierNonArrayData::AtomicUInt => f.write_str("atomic_uint"),
807        ast::TypeSpecifierNonArrayData::USampler1D => f.write_str("usampler1D"),
808        ast::TypeSpecifierNonArrayData::UImage1D => f.write_str("uimage1D"),
809        ast::TypeSpecifierNonArrayData::USampler2D => f.write_str("usampler2D"),
810        ast::TypeSpecifierNonArrayData::UImage2D => f.write_str("uimage2D"),
811        ast::TypeSpecifierNonArrayData::USampler3D => f.write_str("usampler3D"),
812        ast::TypeSpecifierNonArrayData::UImage3D => f.write_str("uimage3D"),
813        ast::TypeSpecifierNonArrayData::USamplerCube => f.write_str("usamplerCube"),
814        ast::TypeSpecifierNonArrayData::UImageCube => f.write_str("uimageCube"),
815        ast::TypeSpecifierNonArrayData::USampler2DRect => f.write_str("usampler2DRect"),
816        ast::TypeSpecifierNonArrayData::UImage2DRect => f.write_str("uimage2DRect"),
817        ast::TypeSpecifierNonArrayData::USampler1DArray => f.write_str("usampler1DArray"),
818        ast::TypeSpecifierNonArrayData::UImage1DArray => f.write_str("uimage1DArray"),
819        ast::TypeSpecifierNonArrayData::USampler2DArray => f.write_str("usampler2DArray"),
820        ast::TypeSpecifierNonArrayData::UImage2DArray => f.write_str("uimage2DArray"),
821        ast::TypeSpecifierNonArrayData::USamplerBuffer => f.write_str("usamplerBuffer"),
822        ast::TypeSpecifierNonArrayData::UImageBuffer => f.write_str("uimageBuffer"),
823        ast::TypeSpecifierNonArrayData::USampler2DMs => f.write_str("usampler2DMS"),
824        ast::TypeSpecifierNonArrayData::UImage2DMs => f.write_str("uimage2DMS"),
825        ast::TypeSpecifierNonArrayData::USampler2DMsArray => f.write_str("usamplerDMSArray"),
826        ast::TypeSpecifierNonArrayData::UImage2DMsArray => f.write_str("uimage2DMSArray"),
827        ast::TypeSpecifierNonArrayData::USamplerCubeArray => f.write_str("usamplerCubeArray"),
828        ast::TypeSpecifierNonArrayData::UImageCubeArray => f.write_str("uimageCubeArray"),
829        ast::TypeSpecifierNonArrayData::Texture1D => f.write_str("texture1D"),
830        ast::TypeSpecifierNonArrayData::Texture2D => f.write_str("texture2D"),
831        ast::TypeSpecifierNonArrayData::Texture3D => f.write_str("texture3D"),
832        ast::TypeSpecifierNonArrayData::TextureCube => f.write_str("textureCube"),
833        ast::TypeSpecifierNonArrayData::Texture2DRect => f.write_str("texture2DRect"),
834        ast::TypeSpecifierNonArrayData::Texture1DArray => f.write_str("texture1DArray"),
835        ast::TypeSpecifierNonArrayData::Texture2DArray => f.write_str("texture2DArray"),
836        ast::TypeSpecifierNonArrayData::TextureBuffer => f.write_str("textureBuffer"),
837        ast::TypeSpecifierNonArrayData::Texture2DMs => f.write_str("texture2DMS"),
838        ast::TypeSpecifierNonArrayData::Texture2DMsArray => f.write_str("texture2DMSArray"),
839        ast::TypeSpecifierNonArrayData::TextureCubeArray => f.write_str("textureCubeArray"),
840        ast::TypeSpecifierNonArrayData::ITexture1D => f.write_str("itexture1D"),
841        ast::TypeSpecifierNonArrayData::ITexture2D => f.write_str("itexture2D"),
842        ast::TypeSpecifierNonArrayData::ITexture3D => f.write_str("itexture3D"),
843        ast::TypeSpecifierNonArrayData::ITextureCube => f.write_str("itextureCube"),
844        ast::TypeSpecifierNonArrayData::ITexture2DRect => f.write_str("itexture2DRect"),
845        ast::TypeSpecifierNonArrayData::ITexture1DArray => f.write_str("itexture1DArray"),
846        ast::TypeSpecifierNonArrayData::ITexture2DArray => f.write_str("itexture2DArray"),
847        ast::TypeSpecifierNonArrayData::ITextureBuffer => f.write_str("itextureBuffer"),
848        ast::TypeSpecifierNonArrayData::ITexture2DMs => f.write_str("itexture2DMS"),
849        ast::TypeSpecifierNonArrayData::ITexture2DMsArray => f.write_str("itexture2DMSArray"),
850        ast::TypeSpecifierNonArrayData::ITextureCubeArray => f.write_str("itextureCubeArray"),
851        ast::TypeSpecifierNonArrayData::Sampler => f.write_str("sampler"),
852        ast::TypeSpecifierNonArrayData::SamplerShadow => f.write_str("samplerShadow"),
853        ast::TypeSpecifierNonArrayData::SubpassInput => f.write_str("subpassInput"),
854        ast::TypeSpecifierNonArrayData::ISubpassInput => f.write_str("isubpassInput"),
855        ast::TypeSpecifierNonArrayData::USubpassInput => f.write_str("usubpassInput"),
856        ast::TypeSpecifierNonArrayData::SubpassInputMs => f.write_str("subpassInputMS"),
857        ast::TypeSpecifierNonArrayData::ISubpassInputMs => f.write_str("isubpassInputMS"),
858        ast::TypeSpecifierNonArrayData::USubpassInputMs => f.write_str("usubpassInputMS"),
859        ast::TypeSpecifierNonArrayData::Struct(ref st) => show_struct_non_declaration(f, st, state),
860        ast::TypeSpecifierNonArrayData::TypeName(ref tn) => show_type_name(f, tn, state),
861    }
862}
863
864/// Transpile a type_specifier to GLSL
865pub fn show_type_specifier<F>(
866    f: &mut F,
867    t: &ast::TypeSpecifier,
868    state: &mut FormattingState<'_>,
869) -> std::fmt::Result
870where
871    F: Write + ?Sized,
872{
873    show_type_specifier_non_array(f, &t.ty, state)?;
874
875    if let Some(ref arr_spec) = t.array_specifier {
876        show_array_spec(f, arr_spec, state)?;
877    }
878
879    Ok(())
880}
881
882/// Transpile a fully_specified_type to GLSL
883pub fn show_fully_specified_type<F>(
884    f: &mut F,
885    t: &ast::FullySpecifiedType,
886    state: &mut FormattingState<'_>,
887) -> std::fmt::Result
888where
889    F: Write + ?Sized,
890{
891    if let Some(ref qual) = t.qualifier {
892        show_type_qualifier(f, qual, state)?;
893        f.write_char(' ')?;
894    }
895
896    show_type_specifier(f, &t.ty, state)
897}
898
899/// Transpile a struct_non_declaration to GLSL
900pub fn show_struct_non_declaration<F>(
901    f: &mut F,
902    st: &ast::StructSpecifier,
903    state: &mut FormattingState<'_>,
904) -> std::fmt::Result
905where
906    F: Write + ?Sized,
907{
908    f.write_str("struct ")?;
909
910    if let Some(ref name) = st.name {
911        write!(f, "{}", name)?;
912    }
913
914    state.enter_block(f)?;
915
916    for field in &st.fields {
917        state.flush_line(f)?;
918        show_struct_field(f, field, state)?;
919        state.write_struct_field_separator(f)?;
920    }
921
922    state.exit_block(f)?;
923
924    Ok(())
925}
926
927/// Transpile a struct to GLSL
928pub fn show_struct<F>(
929    f: &mut F,
930    st: &ast::StructSpecifier,
931    state: &mut FormattingState<'_>,
932) -> std::fmt::Result
933where
934    F: Write + ?Sized,
935{
936    show_struct_non_declaration(f, st, state)?;
937    state.write_struct_declaration_terminator(f)
938}
939
940/// Transpile a struct_field to GLSL
941pub fn show_struct_field<F>(
942    f: &mut F,
943    field: &ast::StructFieldSpecifier,
944    state: &mut FormattingState<'_>,
945) -> std::fmt::Result
946where
947    F: Write + ?Sized,
948{
949    if let Some(ref qual) = field.qualifier {
950        show_type_qualifier(f, qual, state)?;
951        f.write_char(' ')?;
952    }
953
954    show_type_specifier(f, &field.ty, state)?;
955    f.write_char(' ')?;
956
957    // there’s at least one identifier
958    let mut identifiers = field.identifiers.iter();
959    let identifier = identifiers.next().unwrap();
960
961    show_arrayed_identifier(f, identifier, state)?;
962
963    // write the rest of the identifiers
964    for identifier in identifiers {
965        state.write_list_separator(f)?;
966        show_arrayed_identifier(f, identifier, state)?;
967    }
968
969    Ok(())
970}
971
972/// Transpile an array_spec to GLSL
973pub fn show_array_spec<F>(
974    f: &mut F,
975    a: &ast::ArraySpecifier,
976    state: &mut FormattingState<'_>,
977) -> std::fmt::Result
978where
979    F: Write + ?Sized,
980{
981    for dimension in &a.dimensions {
982        match **dimension {
983            ast::ArraySpecifierDimensionData::Unsized => f.write_str("[]")?,
984            ast::ArraySpecifierDimensionData::ExplicitlySized(ref e) => {
985                f.write_char('[')?;
986                show_expr(f, e, state)?;
987                f.write_char(']')?
988            }
989        }
990    }
991
992    Ok(())
993}
994
995/// Transpile an arrayed_identifier to GLSL
996pub fn show_arrayed_identifier<F>(
997    f: &mut F,
998    a: &ast::ArrayedIdentifier,
999    state: &mut FormattingState<'_>,
1000) -> std::fmt::Result
1001where
1002    F: Write + ?Sized,
1003{
1004    write!(f, "{}", a.ident)?;
1005
1006    if let Some(ref arr_spec) = a.array_spec {
1007        show_array_spec(f, arr_spec, state)?;
1008    }
1009
1010    Ok(())
1011}
1012
1013/// Transpile a type_qualifier to GLSL
1014pub fn show_type_qualifier<F>(
1015    f: &mut F,
1016    q: &ast::TypeQualifier,
1017    state: &mut FormattingState<'_>,
1018) -> std::fmt::Result
1019where
1020    F: Write + ?Sized,
1021{
1022    let mut qualifiers = q.qualifiers.iter();
1023    let first = qualifiers.next().unwrap();
1024
1025    show_type_qualifier_spec(f, first, state)?;
1026
1027    for qual_spec in qualifiers {
1028        f.write_char(' ')?;
1029        show_type_qualifier_spec(f, qual_spec, state)?;
1030    }
1031
1032    Ok(())
1033}
1034
1035/// Transpile a type_qualifier_spec to GLSL
1036pub fn show_type_qualifier_spec<F>(
1037    f: &mut F,
1038    q: &ast::TypeQualifierSpec,
1039    state: &mut FormattingState<'_>,
1040) -> std::fmt::Result
1041where
1042    F: Write + ?Sized,
1043{
1044    match **q {
1045        ast::TypeQualifierSpecData::Storage(ref st) => show_storage_qualifier(f, st, state),
1046        ast::TypeQualifierSpecData::Layout(ref l) => show_layout_qualifier(f, l, state),
1047        ast::TypeQualifierSpecData::Precision(ref p) => show_precision_qualifier(f, p, state),
1048        ast::TypeQualifierSpecData::Interpolation(ref i) => {
1049            show_interpolation_qualifier(f, i, state)
1050        }
1051        ast::TypeQualifierSpecData::Invariant => f.write_str("invariant"),
1052        ast::TypeQualifierSpecData::Precise => f.write_str("precise"),
1053    }
1054}
1055
1056/// Transpile a storage_qualifier to GLSL
1057pub fn show_storage_qualifier<F>(
1058    f: &mut F,
1059    q: &ast::StorageQualifier,
1060    state: &mut FormattingState<'_>,
1061) -> std::fmt::Result
1062where
1063    F: Write + ?Sized,
1064{
1065    match **q {
1066        ast::StorageQualifierData::Const => f.write_str("const"),
1067        ast::StorageQualifierData::InOut => f.write_str("inout"),
1068        ast::StorageQualifierData::In => f.write_str("in"),
1069        ast::StorageQualifierData::Out => f.write_str("out"),
1070        ast::StorageQualifierData::Centroid => f.write_str("centroid"),
1071        ast::StorageQualifierData::Patch => f.write_str("patch"),
1072        ast::StorageQualifierData::Sample => f.write_str("sample"),
1073        ast::StorageQualifierData::Uniform => f.write_str("uniform"),
1074        ast::StorageQualifierData::Buffer => f.write_str("buffer"),
1075        ast::StorageQualifierData::Shared => f.write_str("shared"),
1076        ast::StorageQualifierData::Coherent => f.write_str("coherent"),
1077        ast::StorageQualifierData::Volatile => f.write_str("volatile"),
1078        ast::StorageQualifierData::Restrict => f.write_str("restrict"),
1079        ast::StorageQualifierData::ReadOnly => f.write_str("readonly"),
1080        ast::StorageQualifierData::WriteOnly => f.write_str("writeonly"),
1081        ast::StorageQualifierData::Attribute => f.write_str("attribute"),
1082        ast::StorageQualifierData::Varying => f.write_str("varying"),
1083        ast::StorageQualifierData::Subroutine(ref n) => show_subroutine(f, n, state),
1084    }
1085}
1086
1087/// Transpile a subroutine to GLSL
1088pub fn show_subroutine<F>(
1089    f: &mut F,
1090    types: &[ast::TypeSpecifier],
1091    state: &mut FormattingState<'_>,
1092) -> std::fmt::Result
1093where
1094    F: Write + ?Sized,
1095{
1096    f.write_str("subroutine")?;
1097
1098    if !types.is_empty() {
1099        f.write_char('(')?;
1100
1101        let mut types_iter = types.iter();
1102        let first = types_iter.next().unwrap();
1103
1104        show_type_specifier(f, first, state)?;
1105
1106        for type_name in types_iter {
1107            state.write_list_separator(f)?;
1108            show_type_specifier(f, type_name, state)?;
1109        }
1110
1111        f.write_char(')')?;
1112    }
1113
1114    Ok(())
1115}
1116
1117/// Transpile a layout_qualifier to GLSL
1118pub fn show_layout_qualifier<F>(
1119    f: &mut F,
1120    l: &ast::LayoutQualifier,
1121    state: &mut FormattingState<'_>,
1122) -> std::fmt::Result
1123where
1124    F: Write + ?Sized,
1125{
1126    let mut qualifiers = l.ids.iter();
1127    let first = qualifiers.next().unwrap();
1128
1129    f.write_str("layout(")?;
1130    show_layout_qualifier_spec(f, first, state)?;
1131
1132    for qual_spec in qualifiers {
1133        state.write_list_separator(f)?;
1134        show_layout_qualifier_spec(f, qual_spec, state)?;
1135    }
1136
1137    f.write_char(')')
1138}
1139
1140/// Transpile a layout_qualifier_spec to GLSL
1141pub fn show_layout_qualifier_spec<F>(
1142    f: &mut F,
1143    l: &ast::LayoutQualifierSpec,
1144    state: &mut FormattingState<'_>,
1145) -> std::fmt::Result
1146where
1147    F: Write + ?Sized,
1148{
1149    match **l {
1150        ast::LayoutQualifierSpecData::Identifier(ref i, Some(ref e)) => {
1151            write!(f, "{i}")?;
1152            state.write_binary_op(f, "=")?;
1153            show_expr(f, e, state)
1154        }
1155        ast::LayoutQualifierSpecData::Identifier(ref i, None) => show_identifier(f, i, state),
1156        ast::LayoutQualifierSpecData::Shared => f.write_str("shared"),
1157    }
1158}
1159
1160/// Transpile a precision_qualifier to GLSL
1161pub fn show_precision_qualifier<F>(
1162    f: &mut F,
1163    p: &ast::PrecisionQualifier,
1164    _: &mut FormattingState<'_>,
1165) -> std::fmt::Result
1166where
1167    F: Write + ?Sized,
1168{
1169    match **p {
1170        ast::PrecisionQualifierData::High => f.write_str("highp"),
1171        ast::PrecisionQualifierData::Medium => f.write_str("mediump"),
1172        ast::PrecisionQualifierData::Low => f.write_str("lowp"),
1173    }
1174}
1175
1176/// Transpile an interpolation_qualifier to GLSL
1177pub fn show_interpolation_qualifier<F>(
1178    f: &mut F,
1179    i: &ast::InterpolationQualifier,
1180    _: &mut FormattingState<'_>,
1181) -> std::fmt::Result
1182where
1183    F: Write + ?Sized,
1184{
1185    match **i {
1186        ast::InterpolationQualifierData::Smooth => f.write_str("smooth"),
1187        ast::InterpolationQualifierData::Flat => f.write_str("flat"),
1188        ast::InterpolationQualifierData::NoPerspective => f.write_str("noperspective"),
1189    }
1190}
1191
1192/// Transpile a float<F>(f: &mut F, x: f32, _: &mut FormattingState to GLSL
1193pub fn show_float<F>(f: &mut F, x: f32, _: &mut FormattingState<'_>) -> std::fmt::Result
1194where
1195    F: Write + ?Sized,
1196{
1197    if x.fract() == 0. {
1198        write!(f, "{}.", x)
1199    } else {
1200        write!(f, "{}", x)
1201    }
1202}
1203
1204/// Transpile a double<F>(f: &mut F, x: f64, _: &mut FormattingState to GLSL
1205pub fn show_double<F>(f: &mut F, x: f64, _: &mut FormattingState<'_>) -> std::fmt::Result
1206where
1207    F: Write + ?Sized,
1208{
1209    if x.fract() == 0. {
1210        write!(f, "{}.lf", x)
1211    } else {
1212        write!(f, "{}lf", x)
1213    }
1214}
1215
1216/// Transpile an expr to GLSL
1217pub fn show_expr<F>(
1218    f: &mut F,
1219    expr: &ast::Expr,
1220    state: &mut FormattingState<'_>,
1221) -> std::fmt::Result
1222where
1223    F: Write + ?Sized,
1224{
1225    match **expr {
1226        ast::ExprData::Variable(ref i) => show_identifier(f, i, state),
1227        ast::ExprData::IntConst(ref x) => write!(f, "{}", x),
1228        ast::ExprData::UIntConst(ref x) => write!(f, "{}u", x),
1229        ast::ExprData::BoolConst(ref x) => write!(f, "{}", x),
1230        ast::ExprData::FloatConst(ref x) => show_float(f, *x, state),
1231        ast::ExprData::DoubleConst(ref x) => show_double(f, *x, state),
1232        ast::ExprData::Unary(ref op, ref e) => {
1233            // Note: all unary ops are right-to-left associative
1234            show_unary_op(f, op, state)?;
1235
1236            if e.precedence() > op.precedence() {
1237                f.write_char('(')?;
1238                show_expr(f, e, state)?;
1239                f.write_char(')')
1240            } else if let ast::ExprData::Unary(eop, _) = &***e {
1241                // Prevent double-unary plus/minus turning into inc/dec
1242                if eop == op && (**eop == ast::UnaryOpData::Add || **eop == ast::UnaryOpData::Minus)
1243                {
1244                    f.write_char('(')?;
1245                    show_expr(f, e, state)?;
1246                    f.write_char(')')
1247                } else {
1248                    show_expr(f, e, state)
1249                }
1250            } else {
1251                show_expr(f, e, state)
1252            }
1253        }
1254        ast::ExprData::Binary(ref op, ref l, ref r) => {
1255            // Note: all binary ops are left-to-right associative (<= for left part)
1256
1257            if l.precedence() <= op.precedence() {
1258                show_expr(f, l, state)?;
1259            } else {
1260                f.write_char('(')?;
1261                show_expr(f, l, state)?;
1262                f.write_char(')')?;
1263            }
1264
1265            show_binary_op(f, op, state)?;
1266
1267            if r.precedence() < op.precedence() {
1268                show_expr(f, r, state)
1269            } else {
1270                f.write_char('(')?;
1271                show_expr(f, r, state)?;
1272                f.write_char(')')
1273            }
1274        }
1275        ast::ExprData::Ternary(ref c, ref st, ref e) => {
1276            // Note: ternary is right-to-left associative (<= for right part)
1277
1278            if c.precedence() < expr.precedence() {
1279                show_expr(f, c, state)?;
1280            } else {
1281                f.write_char('(')?;
1282                show_expr(f, c, state)?;
1283                f.write_char(')')?;
1284            }
1285            state.write_binary_op(f, "?")?;
1286            show_expr(f, st, state)?;
1287            state.write_binary_op(f, ":")?;
1288            if e.precedence() <= expr.precedence() {
1289                show_expr(f, e, state)
1290            } else {
1291                f.write_char('(')?;
1292                show_expr(f, e, state)?;
1293                f.write_char(')')
1294            }
1295        }
1296        ast::ExprData::Assignment(ref v, ref op, ref e) => {
1297            // Note: all assignment ops are right-to-left associative
1298
1299            if v.precedence() < op.precedence() {
1300                show_expr(f, v, state)?;
1301            } else {
1302                f.write_char('(')?;
1303                show_expr(f, v, state)?;
1304                f.write_char(')')?;
1305            }
1306
1307            show_assignment_op(f, op, state)?;
1308
1309            if e.precedence() <= op.precedence() {
1310                show_expr(f, e, state)
1311            } else {
1312                f.write_char('(')?;
1313                show_expr(f, e, state)?;
1314                f.write_char(')')
1315            }
1316        }
1317        ast::ExprData::Bracket(ref e, ref a) => {
1318            // Note: bracket is left-to-right associative
1319
1320            if e.precedence() <= expr.precedence() {
1321                show_expr(f, e, state)?;
1322            } else {
1323                f.write_char('(')?;
1324                show_expr(f, e, state)?;
1325                f.write_char(')')?;
1326            }
1327
1328            f.write_char('[')?;
1329            show_expr(f, a, state)?;
1330            f.write_char(']')
1331        }
1332        ast::ExprData::FunCall(ref fun, ref args) => {
1333            show_function_identifier(f, fun, state)?;
1334            f.write_char('(')?;
1335
1336            if !args.is_empty() {
1337                let mut args_iter = args.iter();
1338                let first = args_iter.next().unwrap();
1339                show_expr(f, first, state)?;
1340
1341                for e in args_iter {
1342                    state.write_list_separator(f)?;
1343                    show_expr(f, e, state)?;
1344                }
1345            }
1346
1347            f.write_char(')')
1348        }
1349        ast::ExprData::Dot(ref e, ref i) => {
1350            // Note: dot is left-to-right associative
1351
1352            if e.precedence() <= expr.precedence() {
1353                show_expr(f, e, state)?;
1354            } else {
1355                f.write_char('(')?;
1356                show_expr(f, e, state)?;
1357                f.write_char(')')?;
1358            }
1359            f.write_char('.')?;
1360            show_identifier(f, i, state)
1361        }
1362        ast::ExprData::PostInc(ref e) => {
1363            // Note: post-increment is right-to-left associative
1364
1365            if e.precedence() < expr.precedence() {
1366                show_expr(f, e, state)?;
1367            } else {
1368                f.write_char('(')?;
1369                show_expr(f, e, state)?;
1370                f.write_char(')')?;
1371            }
1372
1373            f.write_str("++")
1374        }
1375        ast::ExprData::PostDec(ref e) => {
1376            // Note: post-decrement is right-to-left associative
1377
1378            if e.precedence() < expr.precedence() {
1379                show_expr(f, e, state)?;
1380            } else {
1381                f.write_char('(')?;
1382                show_expr(f, e, state)?;
1383                f.write_char(')')?;
1384            }
1385
1386            f.write_str("--")
1387        }
1388        ast::ExprData::Comma(ref a, ref b) => {
1389            // Note: comma is left-to-right associative
1390
1391            if a.precedence() <= expr.precedence() {
1392                show_expr(f, a, state)?;
1393            } else {
1394                f.write_char('(')?;
1395                show_expr(f, a, state)?;
1396                f.write_char(')')?;
1397            }
1398
1399            state.write_list_separator(f)?;
1400
1401            if b.precedence() < expr.precedence() {
1402                show_expr(f, b, state)
1403            } else {
1404                f.write_char('(')?;
1405                show_expr(f, b, state)?;
1406                f.write_char(')')
1407            }
1408        }
1409    }
1410}
1411
1412/// Transpile a path<F>(f: &mut F, path: &ast::Path, _: &mut FormattingState to GLSL
1413pub fn show_path<F>(f: &mut F, path: &ast::Path, _: &mut FormattingState<'_>) -> std::fmt::Result
1414where
1415    F: Write + ?Sized,
1416{
1417    match **path {
1418        ast::PathData::Absolute(ref s) => write!(f, "<{}>", s),
1419        ast::PathData::Relative(ref s) => write!(f, "\"{}\"", s),
1420    }
1421}
1422
1423/// Transpile an unary_op to GLSL
1424pub fn show_unary_op<F>(
1425    f: &mut F,
1426    op: &ast::UnaryOp,
1427    _: &mut FormattingState<'_>,
1428) -> std::fmt::Result
1429where
1430    F: Write + ?Sized,
1431{
1432    match **op {
1433        ast::UnaryOpData::Inc => f.write_str("++"),
1434        ast::UnaryOpData::Dec => f.write_str("--"),
1435        ast::UnaryOpData::Add => f.write_str("+"),
1436        ast::UnaryOpData::Minus => f.write_str("-"),
1437        ast::UnaryOpData::Not => f.write_str("!"),
1438        ast::UnaryOpData::Complement => f.write_str("~"),
1439    }
1440}
1441
1442/// Transpile a binary_op to GLSL
1443pub fn show_binary_op<F>(
1444    f: &mut F,
1445    op: &ast::BinaryOp,
1446    state: &mut FormattingState<'_>,
1447) -> std::fmt::Result
1448where
1449    F: Write + ?Sized,
1450{
1451    match **op {
1452        ast::BinaryOpData::Or => state.write_binary_op(f, "||"),
1453        ast::BinaryOpData::Xor => state.write_binary_op(f, "^^"),
1454        ast::BinaryOpData::And => state.write_binary_op(f, "&&"),
1455        ast::BinaryOpData::BitOr => state.write_binary_op(f, "|"),
1456        ast::BinaryOpData::BitXor => state.write_binary_op(f, "^"),
1457        ast::BinaryOpData::BitAnd => state.write_binary_op(f, "&"),
1458        ast::BinaryOpData::Equal => state.write_binary_op(f, "=="),
1459        ast::BinaryOpData::NonEqual => state.write_binary_op(f, "!="),
1460        ast::BinaryOpData::Lt => state.write_binary_op(f, "<"),
1461        ast::BinaryOpData::Gt => state.write_binary_op(f, ">"),
1462        ast::BinaryOpData::Lte => state.write_binary_op(f, "<="),
1463        ast::BinaryOpData::Gte => state.write_binary_op(f, ">="),
1464        ast::BinaryOpData::LShift => state.write_binary_op(f, "<<"),
1465        ast::BinaryOpData::RShift => state.write_binary_op(f, ">>"),
1466        ast::BinaryOpData::Add => state.write_binary_op(f, "+"),
1467        ast::BinaryOpData::Sub => state.write_binary_op(f, "-"),
1468        ast::BinaryOpData::Mult => state.write_binary_op(f, "*"),
1469        ast::BinaryOpData::Div => state.write_binary_op(f, "/"),
1470        ast::BinaryOpData::Mod => state.write_binary_op(f, "%"),
1471    }
1472}
1473
1474/// Transpile an assignment_op to GLSL
1475pub fn show_assignment_op<F>(
1476    f: &mut F,
1477    op: &ast::AssignmentOp,
1478    state: &mut FormattingState<'_>,
1479) -> std::fmt::Result
1480where
1481    F: Write + ?Sized,
1482{
1483    match **op {
1484        ast::AssignmentOpData::Equal => state.write_binary_op(f, "="),
1485        ast::AssignmentOpData::Mult => state.write_binary_op(f, "*="),
1486        ast::AssignmentOpData::Div => state.write_binary_op(f, "/="),
1487        ast::AssignmentOpData::Mod => state.write_binary_op(f, "%="),
1488        ast::AssignmentOpData::Add => state.write_binary_op(f, "+="),
1489        ast::AssignmentOpData::Sub => state.write_binary_op(f, "-="),
1490        ast::AssignmentOpData::LShift => state.write_binary_op(f, "<<="),
1491        ast::AssignmentOpData::RShift => state.write_binary_op(f, ">>="),
1492        ast::AssignmentOpData::And => state.write_binary_op(f, "&="),
1493        ast::AssignmentOpData::Xor => state.write_binary_op(f, "^="),
1494        ast::AssignmentOpData::Or => state.write_binary_op(f, "|="),
1495    }
1496}
1497
1498/// Transpile a function_identifier to GLSL
1499pub fn show_function_identifier<F>(
1500    f: &mut F,
1501    i: &ast::FunIdentifier,
1502    state: &mut FormattingState<'_>,
1503) -> std::fmt::Result
1504where
1505    F: Write + ?Sized,
1506{
1507    match **i {
1508        ast::FunIdentifierData::TypeSpecifier(ref n) => show_type_specifier(f, n, state),
1509        ast::FunIdentifierData::Expr(ref e) => show_expr(f, e, state),
1510    }
1511}
1512
1513/// Transpile a declaration to GLSL
1514pub fn show_declaration<F>(
1515    f: &mut F,
1516    d: &ast::Declaration,
1517    state: &mut FormattingState<'_>,
1518) -> std::fmt::Result
1519where
1520    F: Write + ?Sized,
1521{
1522    match **d {
1523        ast::DeclarationData::FunctionPrototype(ref proto) => {
1524            show_function_prototype(f, proto, state)?;
1525        }
1526        ast::DeclarationData::InitDeclaratorList(ref list) => {
1527            show_init_declarator_list(f, list, state)?;
1528        }
1529        ast::DeclarationData::Precision(ref qual, ref ty) => {
1530            f.write_str("precision ")?;
1531            show_precision_qualifier(f, qual, state)?;
1532            f.write_str(" ")?;
1533            show_type_specifier(f, ty, state)?;
1534        }
1535        ast::DeclarationData::Block(ref block) => {
1536            show_block(f, block, state)?;
1537        }
1538        ast::DeclarationData::Invariant(ref ident) => {
1539            f.write_str("invariant")?;
1540            f.write_char(' ')?;
1541            show_identifier(f, ident, state)?;
1542        }
1543        ast::DeclarationData::TypeOnly(ref q) => {
1544            show_type_qualifier(f, q, state)?;
1545        }
1546    }
1547
1548    state.write_declaration_terminator(f)
1549}
1550
1551/// Transpile a function_prototype to GLSL
1552pub fn show_function_prototype<F>(
1553    f: &mut F,
1554    fp: &ast::FunctionPrototype,
1555    state: &mut FormattingState<'_>,
1556) -> std::fmt::Result
1557where
1558    F: Write + ?Sized,
1559{
1560    show_fully_specified_type(f, &fp.ty, state)?;
1561    f.write_char(' ')?;
1562    show_identifier(f, &fp.name, state)?;
1563
1564    f.write_char('(')?;
1565
1566    if !fp.parameters.is_empty() {
1567        let mut iter = fp.parameters.iter();
1568        let first = iter.next().unwrap();
1569        show_function_parameter_declaration(f, first, state)?;
1570
1571        for param in iter {
1572            state.write_list_separator(f)?;
1573            show_function_parameter_declaration(f, param, state)?;
1574        }
1575    }
1576
1577    f.write_char(')')
1578}
1579/// Transpile a function_parameter_declaration to GLSL
1580pub fn show_function_parameter_declaration<F>(
1581    f: &mut F,
1582    p: &ast::FunctionParameterDeclaration,
1583    state: &mut FormattingState<'_>,
1584) -> std::fmt::Result
1585where
1586    F: Write + ?Sized,
1587{
1588    match **p {
1589        ast::FunctionParameterDeclarationData::Named(ref qual, ref fpd) => {
1590            if let Some(ref q) = *qual {
1591                show_type_qualifier(f, q, state)?;
1592                f.write_char(' ')?;
1593            }
1594
1595            show_function_parameter_declarator(f, fpd, state)
1596        }
1597        ast::FunctionParameterDeclarationData::Unnamed(ref qual, ref ty) => {
1598            if let Some(ref q) = *qual {
1599                show_type_qualifier(f, q, state)?;
1600                f.write_char(' ')?;
1601            }
1602
1603            show_type_specifier(f, ty, state)
1604        }
1605    }
1606}
1607
1608/// Transpile a function_parameter_declarator to GLSL
1609pub fn show_function_parameter_declarator<F>(
1610    f: &mut F,
1611    p: &ast::FunctionParameterDeclarator,
1612    state: &mut FormattingState<'_>,
1613) -> std::fmt::Result
1614where
1615    F: Write + ?Sized,
1616{
1617    show_type_specifier(f, &p.ty, state)?;
1618    f.write_char(' ')?;
1619    show_arrayed_identifier(f, &p.ident, state)
1620}
1621
1622/// Transpile an init_declarator_list to GLSL
1623pub fn show_init_declarator_list<F>(
1624    f: &mut F,
1625    i: &ast::InitDeclaratorList,
1626    state: &mut FormattingState<'_>,
1627) -> std::fmt::Result
1628where
1629    F: Write + ?Sized,
1630{
1631    show_single_declaration(f, &i.head, state)?;
1632
1633    for decl in &i.tail {
1634        state.write_list_separator(f)?;
1635        show_single_declaration_no_type(f, decl, state)?;
1636    }
1637
1638    Ok(())
1639}
1640
1641/// Transpile a single_declaration to GLSL
1642pub fn show_single_declaration<F>(
1643    f: &mut F,
1644    d: &ast::SingleDeclaration,
1645    state: &mut FormattingState<'_>,
1646) -> std::fmt::Result
1647where
1648    F: Write + ?Sized,
1649{
1650    show_fully_specified_type(f, &d.ty, state)?;
1651
1652    if let Some(ref name) = d.name {
1653        f.write_char(' ')?;
1654        show_identifier(f, name, state)?;
1655    }
1656
1657    if let Some(ref arr_spec) = d.array_specifier {
1658        show_array_spec(f, arr_spec, state)?;
1659    }
1660
1661    if let Some(ref initializer) = d.initializer {
1662        state.write_binary_op(f, "=")?;
1663        show_initializer(f, initializer, state)?;
1664    }
1665
1666    Ok(())
1667}
1668
1669/// Transpile a single_declaration_no_type to GLSL
1670pub fn show_single_declaration_no_type<F>(
1671    f: &mut F,
1672    d: &ast::SingleDeclarationNoType,
1673    state: &mut FormattingState<'_>,
1674) -> std::fmt::Result
1675where
1676    F: Write + ?Sized,
1677{
1678    show_arrayed_identifier(f, &d.ident, state)?;
1679
1680    if let Some(ref initializer) = d.initializer {
1681        state.write_binary_op(f, "=")?;
1682        show_initializer(f, initializer, state)?;
1683    }
1684
1685    Ok(())
1686}
1687
1688/// Transpile an initializer to GLSL
1689pub fn show_initializer<F>(
1690    f: &mut F,
1691    i: &ast::Initializer,
1692    state: &mut FormattingState<'_>,
1693) -> std::fmt::Result
1694where
1695    F: Write + ?Sized,
1696{
1697    match **i {
1698        ast::InitializerData::Simple(ref e) => show_expr(f, e, state),
1699        ast::InitializerData::List(ref list) => {
1700            let mut iter = list.iter();
1701            let first = iter.next().unwrap();
1702
1703            state.enter_initializer_list(f)?;
1704
1705            show_initializer(f, first, state)?;
1706
1707            for ini in iter {
1708                state.write_list_separator(f)?;
1709                show_initializer(f, ini, state)?;
1710            }
1711
1712            state.end_initializer_list(f)
1713        }
1714    }
1715}
1716
1717/// Transpile a block<F>(f: &mut F, b: &ast::Block, state: &mut FormattingState to GLSL
1718pub fn show_block<F>(f: &mut F, b: &ast::Block, state: &mut FormattingState<'_>) -> std::fmt::Result
1719where
1720    F: Write + ?Sized,
1721{
1722    show_type_qualifier(f, &b.qualifier, state)?;
1723    f.write_char(' ')?;
1724    show_identifier(f, &b.name, state)?;
1725
1726    state.enter_block(f)?;
1727
1728    for field in &b.fields {
1729        state.flush_line(f)?;
1730        show_struct_field(f, field, state)?;
1731        state.write_struct_field_separator(f)?;
1732    }
1733
1734    state.exit_block(f)?;
1735
1736    if let Some(ref ident) = b.identifier {
1737        show_arrayed_identifier(f, ident, state)?;
1738    }
1739
1740    Ok(())
1741}
1742
1743/// Transpile a function_definition to GLSL
1744pub fn show_function_definition<F>(
1745    f: &mut F,
1746    fd: &ast::FunctionDefinition,
1747    state: &mut FormattingState<'_>,
1748) -> std::fmt::Result
1749where
1750    F: Write + ?Sized,
1751{
1752    show_function_prototype(f, &fd.prototype, state)?;
1753    state.enter_function_definition_statement();
1754    show_compound_statement(f, &fd.statement, state)?;
1755    state.flush_line(f)?;
1756    state.write_function_definition_terminator(f)
1757}
1758
1759/// Transpile a compound_statement to GLSL
1760pub fn show_compound_statement<F>(
1761    f: &mut F,
1762    cst: &ast::CompoundStatement,
1763    state: &mut FormattingState<'_>,
1764) -> std::fmt::Result
1765where
1766    F: Write + ?Sized,
1767{
1768    // Function definitions are the only symbols that require compound statements
1769    let collapse = !state.in_function_definition_statement
1770        && state.settings.collapse_single_item_compound_statements
1771        && cst.statement_list.len() == 1;
1772
1773    if collapse {
1774        state.enter_collapsed_compound_statement()?;
1775    } else {
1776        state.enter_compound_statement_block(f)?;
1777    }
1778
1779    // The next statements are no longer a symbol of the function prototype grammar rule
1780    state.consume_function_definition_statement();
1781
1782    for st in &cst.statement_list {
1783        show_statement(f, st, state)?;
1784    }
1785
1786    if collapse {
1787        state.exit_collapsed_compound_statement()?;
1788    } else {
1789        state.exit_block(f)?;
1790    }
1791
1792    Ok(())
1793}
1794
1795/// Transpile a statement to GLSL
1796pub fn show_statement<F>(
1797    f: &mut F,
1798    st: &ast::Statement,
1799    state: &mut FormattingState<'_>,
1800) -> std::fmt::Result
1801where
1802    F: Write + ?Sized,
1803{
1804    state.flush_line(f)?;
1805
1806    match **st {
1807        ast::StatementData::Declaration(ref d) => show_declaration(f, d, state),
1808        ast::StatementData::Expression(ref e) => show_expression_statement(f, e, state),
1809        ast::StatementData::Selection(ref st) => show_selection_statement(f, st, state),
1810        ast::StatementData::Switch(ref st) => show_switch_statement(f, st, state),
1811        ast::StatementData::CaseLabel(ref cl) => show_case_label(f, cl, state),
1812        ast::StatementData::Iteration(ref i) => show_iteration_statement(f, i, state),
1813        ast::StatementData::Jump(ref j) => show_jump_statement(f, j, state),
1814        ast::StatementData::Compound(ref c) => show_compound_statement(f, c, state),
1815    }
1816}
1817
1818/// Transpile an expression_statement to GLSL
1819pub fn show_expression_statement<F>(
1820    f: &mut F,
1821    est: &ast::ExprStatement,
1822    state: &mut FormattingState<'_>,
1823) -> std::fmt::Result
1824where
1825    F: Write + ?Sized,
1826{
1827    if let Some(ref e) = est.0 {
1828        show_expr(f, e, state)?;
1829    }
1830
1831    state.write_statement_terminator(f)
1832}
1833
1834/// Transpile a selection_statement to GLSL
1835pub fn show_selection_statement<F>(
1836    f: &mut F,
1837    sst: &ast::SelectionStatement,
1838    state: &mut FormattingState<'_>,
1839) -> std::fmt::Result
1840where
1841    F: Write + ?Sized,
1842{
1843    f.write_str("if")?;
1844    state.write_statement_opening_parenthesis(f)?;
1845    show_expr(f, &sst.cond, state)?;
1846    state.write_statement_closing_parenthesis(f)?;
1847    show_selection_rest_statement(f, &sst.rest, state)
1848}
1849
1850/// Transpile a selection_rest_statement to GLSL
1851pub fn show_selection_rest_statement<F>(
1852    f: &mut F,
1853    sst: &ast::SelectionRestStatement,
1854    state: &mut FormattingState<'_>,
1855) -> std::fmt::Result
1856where
1857    F: Write + ?Sized,
1858{
1859    match **sst {
1860        ast::SelectionRestStatementData::Statement(ref if_st) => show_statement(f, if_st, state),
1861        ast::SelectionRestStatementData::Else(ref if_st, ref else_st) => {
1862            show_statement(f, if_st, state)?;
1863            state.write_else(f)?;
1864            // TODO: This should be configurable instead of relying on show_statement's calling
1865            // flush_line
1866            state.consume_newline();
1867            show_statement(f, else_st, state)
1868        }
1869    }
1870}
1871
1872/// Transpile a switch_statement to GLSL
1873pub fn show_switch_statement<F>(
1874    f: &mut F,
1875    sst: &ast::SwitchStatement,
1876    state: &mut FormattingState<'_>,
1877) -> std::fmt::Result
1878where
1879    F: Write + ?Sized,
1880{
1881    f.write_str("switch")?;
1882    state.write_statement_opening_parenthesis(f)?;
1883    show_expr(f, &sst.head, state)?;
1884    // Do not call write_statement_closing_parenthesis to maybe save an unexpected
1885    // whitespace before the block
1886    f.write_char(')')?;
1887
1888    state.enter_block(f)?;
1889
1890    for st in &sst.body {
1891        show_statement(f, st, state)?;
1892    }
1893
1894    state.exit_block(f)
1895}
1896
1897/// Transpile a case_label to GLSL
1898pub fn show_case_label<F>(
1899    f: &mut F,
1900    cl: &ast::CaseLabel,
1901    state: &mut FormattingState<'_>,
1902) -> std::fmt::Result
1903where
1904    F: Write + ?Sized,
1905{
1906    match **cl {
1907        ast::CaseLabelData::Case(ref e) => {
1908            f.write_str("case ")?;
1909            show_expr(f, e, state)?;
1910            state.enter_case_label(f)
1911        }
1912        ast::CaseLabelData::Def => {
1913            f.write_str("default")?;
1914            state.enter_case_label(f)
1915        }
1916    }
1917}
1918
1919/// Transpile an iteration_statement to GLSL
1920pub fn show_iteration_statement<F>(
1921    f: &mut F,
1922    ist: &ast::IterationStatement,
1923    state: &mut FormattingState<'_>,
1924) -> std::fmt::Result
1925where
1926    F: Write + ?Sized,
1927{
1928    match **ist {
1929        ast::IterationStatementData::While(ref cond, ref body) => {
1930            f.write_str("while")?;
1931            state.write_statement_opening_parenthesis(f)?;
1932            show_condition(f, cond, state)?;
1933            state.write_statement_closing_parenthesis(f)?;
1934            show_statement(f, body, state)
1935        }
1936        ast::IterationStatementData::DoWhile(ref body, ref cond) => {
1937            f.write_str("do ")?;
1938            show_statement(f, body, state)?;
1939            f.write_str(" while")?;
1940            state.write_statement_opening_parenthesis(f)?;
1941            show_expr(f, cond, state)?;
1942            // Do not call write_statement_closing_parenthesis to maybe save an unexpected
1943            // whitespace before the terminator
1944            f.write_char(')')?;
1945            state.write_statement_terminator(f)
1946        }
1947        ast::IterationStatementData::For(ref init, ref rest, ref body) => {
1948            f.write_str("for")?;
1949            state.write_statement_opening_parenthesis(f)?;
1950            show_for_init_statement(f, init, state)?;
1951            state.flush_space(f)?;
1952            show_for_rest_statement(f, rest, state)?;
1953            state.write_statement_closing_parenthesis(f)?;
1954            show_statement(f, body, state)
1955        }
1956    }
1957}
1958
1959/// Transpile a condition to GLSL
1960pub fn show_condition<F>(
1961    f: &mut F,
1962    c: &ast::Condition,
1963    state: &mut FormattingState<'_>,
1964) -> std::fmt::Result
1965where
1966    F: Write + ?Sized,
1967{
1968    match **c {
1969        ast::ConditionData::Expr(ref e) => show_expr(f, e, state),
1970        ast::ConditionData::Assignment(ref ty, ref name, ref initializer) => {
1971            show_fully_specified_type(f, ty, state)?;
1972            f.write_char(' ')?;
1973            show_identifier(f, name, state)?;
1974            state.write_binary_op(f, "=")?;
1975            show_initializer(f, initializer, state)
1976        }
1977    }
1978}
1979
1980/// Transpile a for_init_statement to GLSL
1981pub fn show_for_init_statement<F>(
1982    f: &mut F,
1983    i: &ast::ForInitStatement,
1984    state: &mut FormattingState<'_>,
1985) -> std::fmt::Result
1986where
1987    F: Write + ?Sized,
1988{
1989    match **i {
1990        ast::ForInitStatementData::Expression(ref expr) => {
1991            if let Some(ref e) = *expr {
1992                show_expr(f, e, state)?;
1993            }
1994
1995            state.write_for_statement_separator(f)
1996        }
1997        ast::ForInitStatementData::Declaration(ref d) => show_declaration(f, d, state),
1998    }
1999}
2000
2001/// Transpile a for_rest_statement to GLSL
2002pub fn show_for_rest_statement<F>(
2003    f: &mut F,
2004    r: &ast::ForRestStatement,
2005    state: &mut FormattingState<'_>,
2006) -> std::fmt::Result
2007where
2008    F: Write + ?Sized,
2009{
2010    if let Some(ref cond) = r.condition {
2011        show_condition(f, cond, state)?;
2012    }
2013
2014    state.write_for_statement_separator(f)?;
2015
2016    if let Some(ref e) = r.post_expr {
2017        show_expr(f, e, state)?;
2018    }
2019
2020    Ok(())
2021}
2022
2023/// Transpile a jump_statement to GLSL
2024pub fn show_jump_statement<F>(
2025    f: &mut F,
2026    j: &ast::JumpStatement,
2027    state: &mut FormattingState<'_>,
2028) -> std::fmt::Result
2029where
2030    F: Write + ?Sized,
2031{
2032    match **j {
2033        ast::JumpStatementData::Continue => f.write_str("continue")?,
2034        ast::JumpStatementData::Break => f.write_str("break")?,
2035        ast::JumpStatementData::Discard => f.write_str("discard")?,
2036        ast::JumpStatementData::Return(ref e) => {
2037            f.write_str("return")?;
2038            if let Some(e) = e {
2039                f.write_char(' ')?;
2040                show_expr(f, e, state)?;
2041            }
2042        }
2043    }
2044
2045    state.write_statement_terminator(f)
2046}
2047
2048/// Transpile a preprocessor to GLSL
2049pub fn show_preprocessor<F>(
2050    f: &mut F,
2051    pp: &ast::Preprocessor,
2052    state: &mut FormattingState<'_>,
2053) -> std::fmt::Result
2054where
2055    F: Write + ?Sized,
2056{
2057    // As per spec, preprocessor directives must start on a line prefixed with
2058    // zero or more horizontal space characters
2059    state.move_to_empty_line(f)?;
2060
2061    match **pp {
2062        ast::PreprocessorData::Define(ref pd) => show_preprocessor_define(f, pd, state)?,
2063        ast::PreprocessorData::Else => show_preprocessor_else(f, state)?,
2064        ast::PreprocessorData::ElseIf(ref pei) => show_preprocessor_elseif(f, pei, state)?,
2065        ast::PreprocessorData::EndIf => show_preprocessor_endif(f, state)?,
2066        ast::PreprocessorData::Error(ref pe) => show_preprocessor_error(f, pe, state)?,
2067        ast::PreprocessorData::If(ref pi) => show_preprocessor_if(f, pi, state)?,
2068        ast::PreprocessorData::IfDef(ref pid) => show_preprocessor_ifdef(f, pid, state)?,
2069        ast::PreprocessorData::IfNDef(ref pind) => show_preprocessor_ifndef(f, pind, state)?,
2070        ast::PreprocessorData::Include(ref pi) => show_preprocessor_include(f, pi, state)?,
2071        ast::PreprocessorData::Line(ref pl) => show_preprocessor_line(f, pl, state)?,
2072        ast::PreprocessorData::Pragma(ref pp) => show_preprocessor_pragma(f, pp, state)?,
2073        ast::PreprocessorData::Undef(ref pu) => show_preprocessor_undef(f, pu, state)?,
2074        ast::PreprocessorData::Version(ref pv) => show_preprocessor_version(f, pv, state)?,
2075        ast::PreprocessorData::Extension(ref pe) => show_preprocessor_extension(f, pe, state)?,
2076    }
2077
2078    // As per spec, preprocessor directives are terminated by a new line
2079    state.new_line(true)
2080}
2081
2082/// Transpile a preprocessor_define to GLSL
2083pub fn show_preprocessor_define<F>(
2084    f: &mut F,
2085    pd: &ast::PreprocessorDefine,
2086    _: &mut FormattingState<'_>,
2087) -> std::fmt::Result
2088where
2089    F: Write + ?Sized,
2090{
2091    match **pd {
2092        ast::PreprocessorDefineData::ObjectLike {
2093            ref ident,
2094            ref value,
2095        } => write!(f, "#define {} {}", ident, value),
2096
2097        ast::PreprocessorDefineData::FunctionLike {
2098            ref ident,
2099            ref args,
2100            ref value,
2101        } => {
2102            write!(f, "#define {}(", ident)?;
2103
2104            if !args.is_empty() {
2105                write!(f, "{}", &args[0])?;
2106
2107                for arg in &args[1..args.len()] {
2108                    write!(f, ", {}", arg)?;
2109                }
2110            }
2111
2112            write!(f, ") {}", value)
2113        }
2114    }
2115}
2116
2117/// Transpile a preprocessor_else<F>(f: &mut F, _: &mut FormattingState to GLSL
2118pub fn show_preprocessor_else<F>(f: &mut F, _: &mut FormattingState<'_>) -> std::fmt::Result
2119where
2120    F: Write + ?Sized,
2121{
2122    f.write_str("#else")
2123}
2124
2125/// Transpile a preprocessor_elseif to GLSL
2126pub fn show_preprocessor_elseif<F>(
2127    f: &mut F,
2128    pei: &ast::PreprocessorElseIf,
2129    _: &mut FormattingState<'_>,
2130) -> std::fmt::Result
2131where
2132    F: Write + ?Sized,
2133{
2134    write!(f, "#elif {}", pei.condition)
2135}
2136
2137/// Transpile a preprocessor_error to GLSL
2138pub fn show_preprocessor_error<F>(
2139    f: &mut F,
2140    pe: &ast::PreprocessorError,
2141    _: &mut FormattingState<'_>,
2142) -> std::fmt::Result
2143where
2144    F: Write + ?Sized,
2145{
2146    write!(f, "#error {}", pe.message)
2147}
2148
2149/// Transpile a preprocessor_endif<F>(f: &mut F, _: &mut FormattingState to GLSL
2150pub fn show_preprocessor_endif<F>(f: &mut F, _: &mut FormattingState<'_>) -> std::fmt::Result
2151where
2152    F: Write + ?Sized,
2153{
2154    f.write_str("#endif")
2155}
2156
2157/// Transpile a preprocessor_if to GLSL
2158pub fn show_preprocessor_if<F>(
2159    f: &mut F,
2160    pi: &ast::PreprocessorIf,
2161    _: &mut FormattingState<'_>,
2162) -> std::fmt::Result
2163where
2164    F: Write + ?Sized,
2165{
2166    write!(f, "#if {}", pi.condition)
2167}
2168
2169/// Transpile a preprocessor_ifdef to GLSL
2170pub fn show_preprocessor_ifdef<F>(
2171    f: &mut F,
2172    pid: &ast::PreprocessorIfDef,
2173    state: &mut FormattingState<'_>,
2174) -> std::fmt::Result
2175where
2176    F: Write + ?Sized,
2177{
2178    f.write_str("#ifdef ")?;
2179    show_identifier(f, &pid.ident, state)
2180}
2181
2182/// Transpile a preprocessor_ifndef to GLSL
2183pub fn show_preprocessor_ifndef<F>(
2184    f: &mut F,
2185    pind: &ast::PreprocessorIfNDef,
2186    state: &mut FormattingState<'_>,
2187) -> std::fmt::Result
2188where
2189    F: Write + ?Sized,
2190{
2191    f.write_str("#ifndef ")?;
2192    show_identifier(f, &pind.ident, state)
2193}
2194
2195/// Transpile a preprocessor_include to GLSL
2196pub fn show_preprocessor_include<F>(
2197    f: &mut F,
2198    pi: &ast::PreprocessorInclude,
2199    state: &mut FormattingState<'_>,
2200) -> std::fmt::Result
2201where
2202    F: Write + ?Sized,
2203{
2204    f.write_str("#include ")?;
2205    show_path(f, &pi.path, state)
2206}
2207
2208/// Transpile a preprocessor_line to GLSL
2209pub fn show_preprocessor_line<F>(
2210    f: &mut F,
2211    pl: &ast::PreprocessorLine,
2212    _: &mut FormattingState<'_>,
2213) -> std::fmt::Result
2214where
2215    F: Write + ?Sized,
2216{
2217    write!(f, "#line {}", pl.line)?;
2218    if let Some(source_string_number) = pl.source_string_number {
2219        write!(f, " {}", source_string_number)?;
2220    }
2221    Ok(())
2222}
2223
2224/// Transpile a preprocessor_pragma to GLSL
2225pub fn show_preprocessor_pragma<F>(
2226    f: &mut F,
2227    pp: &ast::PreprocessorPragma,
2228    _: &mut FormattingState<'_>,
2229) -> std::fmt::Result
2230where
2231    F: Write + ?Sized,
2232{
2233    write!(f, "#pragma {}", pp.command)
2234}
2235
2236/// Transpile a preprocessor_undef to GLSL
2237pub fn show_preprocessor_undef<F>(
2238    f: &mut F,
2239    pud: &ast::PreprocessorUndef,
2240    state: &mut FormattingState<'_>,
2241) -> std::fmt::Result
2242where
2243    F: Write + ?Sized,
2244{
2245    f.write_str("#undef ")?;
2246    show_identifier(f, &pud.name, state)
2247}
2248
2249/// Transpile a preprocessor_version to GLSL
2250pub fn show_preprocessor_version<F>(
2251    f: &mut F,
2252    pv: &ast::PreprocessorVersion,
2253    _: &mut FormattingState<'_>,
2254) -> std::fmt::Result
2255where
2256    F: Write + ?Sized,
2257{
2258    write!(f, "#version {}", pv.version)?;
2259
2260    if let Some(ref profile) = pv.profile {
2261        match **profile {
2262            ast::PreprocessorVersionProfileData::Core => {
2263                f.write_str(" core")?;
2264            }
2265            ast::PreprocessorVersionProfileData::Compatibility => {
2266                f.write_str(" compatibility")?;
2267            }
2268            ast::PreprocessorVersionProfileData::Es => {
2269                f.write_str(" es")?;
2270            }
2271        }
2272    }
2273
2274    Ok(())
2275}
2276
2277/// Transpile a preprocessor_extension to GLSL
2278pub fn show_preprocessor_extension<F>(
2279    f: &mut F,
2280    pe: &ast::PreprocessorExtension,
2281    _: &mut FormattingState<'_>,
2282) -> std::fmt::Result
2283where
2284    F: Write + ?Sized,
2285{
2286    f.write_str("#extension ")?;
2287
2288    match *pe.name {
2289        ast::PreprocessorExtensionNameData::All => {
2290            f.write_str("all")?;
2291        }
2292        ast::PreprocessorExtensionNameData::Specific(ref n) => {
2293            f.write_str(n)?;
2294        }
2295    }
2296
2297    if let Some(ref behavior) = pe.behavior {
2298        match **behavior {
2299            ast::PreprocessorExtensionBehaviorData::Require => {
2300                f.write_str(" : require")?;
2301            }
2302            ast::PreprocessorExtensionBehaviorData::Enable => {
2303                f.write_str(" : enable")?;
2304            }
2305            ast::PreprocessorExtensionBehaviorData::Warn => {
2306                f.write_str(" : warn")?;
2307            }
2308            ast::PreprocessorExtensionBehaviorData::Disable => {
2309                f.write_str(" : disable")?;
2310            }
2311        }
2312    }
2313
2314    Ok(())
2315}
2316
2317/// Transpile an external_declaration to GLSL
2318pub fn show_external_declaration<F>(
2319    f: &mut F,
2320    ed: &ast::ExternalDeclaration,
2321    state: &mut FormattingState<'_>,
2322) -> std::fmt::Result
2323where
2324    F: Write + ?Sized,
2325{
2326    state.enter_external_declaration(f)?;
2327
2328    match **ed {
2329        ast::ExternalDeclarationData::Preprocessor(ref pp) => show_preprocessor(f, pp, state)?,
2330        ast::ExternalDeclarationData::FunctionDefinition(ref fd) => {
2331            show_function_definition(f, fd, state)?
2332        }
2333        ast::ExternalDeclarationData::Declaration(ref d) => show_declaration(f, d, state)?,
2334    }
2335
2336    state.exit_external_declaration();
2337
2338    Ok(())
2339}
2340
2341/// Transpile a translation_unit to GLSL
2342pub fn show_translation_unit<F>(
2343    f: &mut F,
2344    tu: &ast::TranslationUnit,
2345    mut state: FormattingState<'_>,
2346) -> std::fmt::Result
2347where
2348    F: Write + ?Sized,
2349{
2350    for ed in &tu.0 {
2351        show_external_declaration(f, ed, &mut state)?;
2352    }
2353
2354    Ok(())
2355}
2356
2357#[cfg(test)]
2358mod tests {
2359    use super::*;
2360    use crate::parse::{DefaultLexer, Parsable, ParseError};
2361    use expect_test::{expect, Expect};
2362    use glsl_lang_lexer::HasLexerError;
2363
2364    fn check_expr(src: &str, expected: Expect) {
2365        let expr = ast::Expr::parse(src).unwrap();
2366        let actual = to_string(&expr);
2367        expected.assert_eq(&actual);
2368    }
2369
2370    fn to_string(e: &ast::Expr) -> String {
2371        let mut state = String::new();
2372        show_expr(&mut state, e, &mut FormattingState::default()).unwrap();
2373        state
2374    }
2375
2376    #[cfg(not(feature = "lexer-full"))]
2377    fn parse_tu_with_preprocessor_directives(
2378        source: &str,
2379    ) -> Result<ast::TranslationUnit, ParseError<<DefaultLexer as HasLexerError>::Error>> {
2380        ast::TranslationUnit::parse(source)
2381    }
2382
2383    #[cfg(feature = "lexer-full")]
2384    fn parse_tu_with_preprocessor_directives(
2385        source: &str,
2386    ) -> Result<ast::TranslationUnit, ParseError<<DefaultLexer as HasLexerError>::Error>> {
2387        <ast::TranslationUnit as crate::parse::DefaultParse>::parse_with_options(
2388            source,
2389            &Default::default(),
2390        )
2391        .map(|(mut tu, _parse, iter)| {
2392            iter.into_directives().inject(&mut tu);
2393            tu
2394        })
2395    }
2396
2397    #[test]
2398    fn unary_parentheses() {
2399        check_expr("-a", expect![["-a"]]);
2400        check_expr("-(a + b)", expect![[r#"-(a + b)"#]]);
2401        check_expr("-a.x", expect![["-a.x"]]);
2402
2403        check_expr("-(-a)", expect![["-(-a)"]]);
2404        check_expr("+(+a)", expect![["+(+a)"]]);
2405        check_expr("~~a", expect![["~~a"]]);
2406        check_expr("--a", expect![["--a"]]);
2407        check_expr("++a", expect![["++a"]]);
2408        check_expr("+-a", expect![["+-a"]]);
2409    }
2410
2411    #[test]
2412    fn binary_parentheses() {
2413        check_expr("a + b", expect![[r#"a + b"#]]);
2414        check_expr("a * b + c", expect![[r#"a * b + c"#]]);
2415        check_expr("(a + b) * c", expect![[r#"(a + b) * c"#]]);
2416        check_expr("a + (b * c)", expect![[r#"a + b * c"#]]);
2417        check_expr("a * (b + c)", expect![[r#"a * (b + c)"#]]);
2418        check_expr("(a * b) * c", expect![[r#"a * b * c"#]]);
2419        check_expr("a * (b * c)", expect![[r#"a * (b * c)"#]]);
2420        check_expr("a&&b&&c", expect![[r#"a && b && c"#]]);
2421        check_expr(
2422            "n - p > 0. && u.y < n && u.y > p",
2423            expect![[r#"n - p > 0. && u.y < n && u.y > p"#]],
2424        );
2425    }
2426
2427    #[test]
2428    fn ternary_parentheses() {
2429        check_expr("a ? b : c ? d : e", expect![["a ? b : c ? d : e"]]);
2430        check_expr("(a ? b : c) ? d : e", expect![["(a ? b : c) ? d : e"]]);
2431    }
2432
2433    #[test]
2434    fn assignment_parentheses() {
2435        check_expr("a = b = c", expect![["a = b = c"]]);
2436        check_expr("(a = b) = c", expect![["(a = b) = c"]]);
2437    }
2438
2439    #[test]
2440    fn dot_parentheses() {
2441        check_expr("a.x", expect![["a.x"]]);
2442        check_expr("(a + b).x", expect![[r#"(a + b).x"#]]);
2443    }
2444
2445    #[test]
2446    fn array_indexes() {
2447        check_expr("arr[0][0]", expect![["arr[0][0]"]]);
2448    }
2449
2450    #[test]
2451    fn test_single_statement_function_is_not_collapsed() {
2452        const SRC: &str = r#"vec2 main() {
2453return vec2(0., 0.);
2454}
2455"#;
2456
2457        let mut s = String::new();
2458        show_function_definition(
2459            &mut s,
2460            &ast::FunctionDefinition::parse(SRC).unwrap(),
2461            &mut FormattingState::from(&FormattingSettings {
2462                collapse_single_item_compound_statements: true,
2463                ..Default::default()
2464            }),
2465        )
2466        .unwrap();
2467
2468        let expected = expect![[r#"
2469            vec2 main() {
2470                return vec2(0., 0.);
2471            }
2472        "#]];
2473
2474        expected.assert_eq(&s);
2475    }
2476
2477    #[test]
2478    fn test_minifying_statement_collapse() {
2479        const SRC: &str = r#"
2480            vec2 main() {
2481                if (110 == 110) {
2482                    return vec2(0., 0.);
2483                } else {
2484                    return vec2(1., 1.);
2485                }
2486            }
2487        "#;
2488
2489        let mut s = String::new();
2490        show_function_definition(
2491            &mut s,
2492            &ast::FunctionDefinition::parse(SRC).unwrap(),
2493            &mut FormattingState::from(&FormattingSettings {
2494                collapse_single_item_compound_statements: true,
2495                newline_after_collapsed_statement: false,
2496                newline_before_collapsed_statement: false,
2497                ..Default::default()
2498            }),
2499        )
2500        .unwrap();
2501
2502        let expected = expect![[r#"
2503            vec2 main() {
2504                if (110 == 110) return vec2(0., 0.); else return vec2(1., 1.);
2505            }
2506        "#]];
2507
2508        expected.assert_eq(&s);
2509    }
2510
2511    #[test]
2512    fn test_pretty_statement_collapse() {
2513        const SRC: &str = r#"
2514            vec2 main() {
2515                if (110 == 110) {
2516                    return vec2(0., 0.);
2517                } else {
2518                    return vec2(1., 1.);
2519                }
2520            }
2521        "#;
2522
2523        let mut s = String::new();
2524        show_function_definition(
2525            &mut s,
2526            &ast::FunctionDefinition::parse(SRC).unwrap(),
2527            &mut FormattingState::from(&FormattingSettings {
2528                collapse_single_item_compound_statements: true,
2529                statement_terminator: Whitespace::None,
2530                newline_after_collapsed_statement: true,
2531                newline_before_collapsed_statement: true,
2532                ..Default::default()
2533            }),
2534        )
2535        .unwrap();
2536
2537        let expected = expect![[r#"
2538            vec2 main() {
2539                if (110 == 110) 
2540                    return vec2(0., 0.); else 
2541                    return vec2(1., 1.);
2542            }
2543        "#]];
2544
2545        expected.assert_eq(&s);
2546    }
2547
2548    #[test]
2549    fn test_parentheses() {
2550        const SRC: &str = r#"
2551            vec2 main() {
2552                float n = 0.;
2553                float p = 0.;
2554                float u = vec2(0., 0.);
2555                if (n-p>0.&&u.y<n&&u.y>p) {}
2556                return u;
2557            }
2558        "#;
2559
2560        let mut s = String::new();
2561        show_function_definition(
2562            &mut s,
2563            &ast::FunctionDefinition::parse(SRC).unwrap(),
2564            &mut FormattingState::default(),
2565        )
2566        .unwrap();
2567
2568        let expected = expect![[r#"
2569            vec2 main() {
2570                float n = 0.;
2571                float p = 0.;
2572                float u = vec2(0., 0.);
2573                if (n - p > 0. && u.y < n && u.y > p) {
2574                }
2575                return u;
2576            }
2577        "#]];
2578
2579        expected.assert_eq(&s);
2580    }
2581
2582    #[test]
2583    fn roundtrip_glsl_complex_expr() {
2584        use lang_util::node::NodeContent;
2585
2586        let zero = ast::ExprData::DoubleConst(0.);
2587        let ray = ast::ExprData::Variable("ray".into_node());
2588        let raydir = ast::ExprData::Dot(Box::new(ray.into()), "dir".into_node());
2589        let vec4 = ast::ExprData::FunCall(
2590            ast::FunIdentifierData::TypeSpecifier(Box::new(
2591                ast::TypeSpecifierData::from(ast::TypeSpecifierNonArrayData::Vec4).into(),
2592            ))
2593            .into(),
2594            vec![raydir.into(), zero.into()],
2595        );
2596        let view = ast::ExprData::variable("view");
2597        let iview = ast::ExprData::FunCall(
2598            ast::FunIdentifierData::ident("inverse").into(),
2599            vec![view.into()],
2600        );
2601        let mul = ast::ExprData::Binary(
2602            ast::BinaryOpData::Mult.into(),
2603            Box::new(iview.into()),
2604            Box::new(vec4.into()),
2605        );
2606        let xyz = ast::ExprData::Dot(Box::new(mul.into()), "xyz".into_node());
2607        let input = ast::ExprData::FunCall(
2608            ast::FunIdentifierData::ident("normalize").into(),
2609            vec![xyz.into()],
2610        )
2611        .into();
2612
2613        let mut output = String::new();
2614        show_expr(&mut output, &input, &mut FormattingState::default()).unwrap();
2615
2616        let back = ast::Expr::parse(&output).unwrap();
2617        assert_eq!(back, input, "intermediate source '{}'", output);
2618    }
2619
2620    #[test]
2621    fn block_decl_formatting() {
2622        let src = r#"uniform Global { float param; float param2; };"#;
2623
2624        let mut s = String::new();
2625        show_external_declaration(
2626            &mut s,
2627            &ast::TranslationUnit::parse(src).unwrap().0[0],
2628            &mut FormattingState::default(),
2629        )
2630        .unwrap();
2631
2632        let expected = expect![[r#"
2633            uniform Global {
2634                float param;
2635                float param2;
2636            };"#]];
2637
2638        expected.assert_eq(&s);
2639    }
2640
2641    #[test]
2642    fn list_separator_formatting() {
2643        let src = r#"void main(vec2 x, vec3 y) {}"#;
2644
2645        let mut s = String::new();
2646        show_function_definition(
2647            &mut s,
2648            &ast::FunctionDefinition::parse(src).unwrap(),
2649            &mut FormattingState::from(&FormattingSettings {
2650                space_after_list_separator: false,
2651                ..Default::default()
2652            }),
2653        )
2654        .unwrap();
2655
2656        let expected = expect![[r#"
2657            void main(vec2 x,vec3 y) {
2658            }
2659        "#]];
2660
2661        expected.assert_eq(&s);
2662    }
2663
2664    #[test]
2665    fn preprocessor_directives_are_always_put_in_newlines() {
2666        let src = r#"
2667            #version 110
2668            vec3 u;
2669            vec3 v;
2670            #pragma "hi"
2671            vec3 w;
2672        "#;
2673
2674        let mut s = String::new();
2675        show_translation_unit(
2676            &mut s,
2677            &parse_tu_with_preprocessor_directives(src).unwrap(),
2678            FormattingState::from(&FormattingSettings {
2679                declaration_terminator: Whitespace::None,
2680                ..Default::default()
2681            }),
2682        )
2683        .unwrap();
2684
2685        let expected = expect![[r#"
2686            #version 110
2687            vec3 u;vec3 v;
2688            #pragma "hi"
2689            vec3 w;"#]];
2690
2691        expected.assert_eq(&s);
2692    }
2693
2694    static COMPLEX_GLSL_SOURCE: &str = r#"
2695        void main(smooth vec2[][] x, vec3 y) {
2696            if (var1)
2697                return a;
2698            else
2699                return b;
2700
2701            if (var2) {
2702                return --c;
2703            } else if (var3) {
2704                {
2705                    vec2 x;
2706                    vec2 y;
2707                }
2708
2709                return d++;
2710            } else {
2711                return q;
2712            }
2713
2714            const float e[3] = float[3](5.0, 7.2, 1.1);
2715            int f[2] = { 3, 4, };
2716
2717            switch (x) {
2718                case 0:
2719                    ++x;
2720                    break;
2721                case 1:
2722                    return;
2723                default:
2724                    discard;
2725            }
2726
2727            while (x) --x;
2728
2729            do {
2730                --y;
2731            } while (y);
2732
2733            for (x = 0; x < 5; ++x) {
2734                continue;
2735            }
2736        }
2737    "#;
2738
2739    #[test]
2740    fn complex_pretty_formatting() {
2741        let mut s = String::new();
2742        show_function_definition(
2743            &mut s,
2744            &ast::FunctionDefinition::parse(COMPLEX_GLSL_SOURCE).unwrap(),
2745            &mut FormattingState::from(&FormattingSettings::default()),
2746        )
2747        .unwrap();
2748
2749        let expected = expect![[r#"
2750            void main(smooth vec2[][] x, vec3 y) {
2751                if (var1) return a; else return b;
2752                if (var2) {
2753                    return --c;
2754                } else if (var3) {
2755                    {
2756                        vec2 x;
2757                        vec2 y;
2758                    }
2759                    return d++;
2760                } else {
2761                    return q;
2762                }
2763                const float e[3] = float[3](5., 7.2, 1.1);
2764                int f[2] = { 3, 4 };
2765                switch (x) {
2766                    case 0:
2767                    ++x;
2768                    break;
2769                    case 1:
2770                    return;
2771                    default:
2772                    discard;
2773                }
2774                while (x) --x;
2775                do {
2776                    --y;
2777                } while (y);
2778                for (x = 0; x < 5; ++x) {
2779                    continue;
2780                }
2781            }
2782        "#]];
2783
2784        expected.assert_eq(&s);
2785    }
2786
2787    #[test]
2788    fn preprocessor_directives_are_always_put_in_newlines_2() {
2789        let src = r#"
2790            vec3 u;
2791            #version 110
2792        "#;
2793
2794        let mut s = String::new();
2795        show_translation_unit(
2796            &mut s,
2797            &parse_tu_with_preprocessor_directives(src).unwrap(),
2798            FormattingState::from(&FormattingSettings {
2799                declaration_terminator: Whitespace::None,
2800                ..Default::default()
2801            }),
2802        )
2803        .unwrap();
2804
2805        let expected = expect![[r#"
2806            vec3 u;
2807            #version 110"#]];
2808
2809        expected.assert_eq(&s);
2810    }
2811
2812    #[test]
2813    fn complex_minifying_formatting() {
2814        let mut s = String::new();
2815        show_function_definition(
2816            &mut s,
2817            &ast::FunctionDefinition::parse(COMPLEX_GLSL_SOURCE).unwrap(),
2818            &mut FormattingState::from(&FormattingSettings::minifying()),
2819        )
2820        .unwrap();
2821
2822        let expected = expect!["void main(smooth vec2[][] x,vec3 y){if(var1)return a;else return b;if(var2)return --c;else if(var3){{vec2 x;vec2 y;}return d++;}else return q;const float e[3]=float[3](5.,7.2,1.1);int f[2]={3,4};switch(x){case 0:++x;break;case 1:return;default:discard;}while(x)--x;do --y; while(y);for(x=0;x<5;++x)continue;}"];
2823
2824        expected.assert_eq(&s);
2825    }
2826}