diff options
Diffstat (limited to 'third_party/rust/glsl/src/transpiler')
-rw-r--r-- | third_party/rust/glsl/src/transpiler/glsl.rs | 1870 | ||||
-rw-r--r-- | third_party/rust/glsl/src/transpiler/mod.rs | 8 | ||||
-rw-r--r-- | third_party/rust/glsl/src/transpiler/spirv.rs | 95 |
3 files changed, 1973 insertions, 0 deletions
diff --git a/third_party/rust/glsl/src/transpiler/glsl.rs b/third_party/rust/glsl/src/transpiler/glsl.rs new file mode 100644 index 0000000000..da9395d333 --- /dev/null +++ b/third_party/rust/glsl/src/transpiler/glsl.rs @@ -0,0 +1,1870 @@ +//! A GLSL450/GLSL460 transpiler that takes a syntax tree and writes it as a plain raw GLSL +//! [`String`]. +//! +//! # Foreword +//! +//! This module exports several functions that just transform a part of a syntax tree into its raw +//! GLSL [`String`] representation. +//! +//! > Important note: this module – and actually, any [`transpiler`] module – is not responsible in +//! > optimizing the syntax tree nor semantically check its validity. This is done in other stages +//! > of the compilation process. +//! +//! In order to achieve that purpose, you could: +//! +//! - For each elements in the AST, return a [`String`] or [`Cow<str>`]. +//! - Insert the string representation via a formatter. +//! +//! The second solution is better because it lets the user handle the memory the way they want: +//! they might just use a dynamic buffer that implements [`Write`] or simply pass a `&mut` +//! [`String`]. It’s up to you. +//! +//! # How to use this module +//! +//! First, head over to the [`syntax`] module. That module defines the AST items defined by GLSL. This +//! very module provides you with functions like `show_*` taking the AST item and writing it to a +//! [`Write`] object. You’re likely to be interested in [`show_translation_unit`] to start with. +//! +//! [`Cow<str>`]: std::borrow::Cow +//! [`Write`]: std::fmt::Write +//! [`show_translation_unit`]: crate::transpiler::glsl::show_translation_unit +//! [`syntax`]: crate::syntax +//! [`transpiler`]: crate::transpiler + +use std::fmt::Write; + +use crate::syntax; + +// Precedence information for transpiling parentheses properly +trait HasPrecedence { + fn precedence(&self) -> u32; +} + +impl HasPrecedence for syntax::Expr { + fn precedence(&self) -> u32 { + match self { + // 0 isn't a valid precedence, but we use this to represent atomic expressions + Self::Variable(_) + | Self::IntConst(_) + | Self::UIntConst(_) + | Self::BoolConst(_) + | Self::FloatConst(_) + | Self::DoubleConst(_) => 0, + // Precedence operator expression is precedence of operator + Self::Unary(op, _) => op.precedence(), + Self::Binary(op, _, _) => op.precedence(), + Self::Ternary(_, _, _) => 15, + Self::Assignment(_, op, _) => op.precedence(), + Self::Bracket(_, _) + | Self::FunCall(_, _) + | Self::Dot(_, _) + | Self::PostInc(_) + | Self::PostDec(_) => 2, + Self::Comma(_, _) => 17, + } + } +} + +impl HasPrecedence for syntax::UnaryOp { + fn precedence(&self) -> u32 { + 3 + } +} + +impl HasPrecedence for syntax::BinaryOp { + fn precedence(&self) -> u32 { + match self { + Self::Mult | Self::Div | Self::Mod => 4, + Self::Add | Self::Sub => 5, + Self::LShift | Self::RShift => 6, + Self::LT | Self::GT | Self::LTE | Self::GTE => 7, + Self::Equal | Self::NonEqual => 8, + Self::BitAnd => 9, + Self::BitXor => 10, + Self::BitOr => 11, + Self::And => 12, + Self::Xor => 13, + Self::Or => 14, + } + } +} + +impl HasPrecedence for syntax::AssignmentOp { + fn precedence(&self) -> u32 { + 16 + } +} + +pub fn show_identifier<F>(f: &mut F, i: &syntax::Identifier) +where + F: Write, +{ + let _ = f.write_str(&i.0); +} + +pub fn show_type_name<F>(f: &mut F, t: &syntax::TypeName) +where + F: Write, +{ + let _ = f.write_str(&t.0); +} + +pub fn show_type_specifier_non_array<F>(f: &mut F, t: &syntax::TypeSpecifierNonArray) +where + F: Write, +{ + match *t { + syntax::TypeSpecifierNonArray::Void => { + let _ = f.write_str("void"); + } + syntax::TypeSpecifierNonArray::Bool => { + let _ = f.write_str("bool"); + } + syntax::TypeSpecifierNonArray::Int => { + let _ = f.write_str("int"); + } + syntax::TypeSpecifierNonArray::UInt => { + let _ = f.write_str("uint"); + } + syntax::TypeSpecifierNonArray::Float => { + let _ = f.write_str("float"); + } + syntax::TypeSpecifierNonArray::Double => { + let _ = f.write_str("double"); + } + syntax::TypeSpecifierNonArray::Vec2 => { + let _ = f.write_str("vec2"); + } + syntax::TypeSpecifierNonArray::Vec3 => { + let _ = f.write_str("vec3"); + } + syntax::TypeSpecifierNonArray::Vec4 => { + let _ = f.write_str("vec4"); + } + syntax::TypeSpecifierNonArray::DVec2 => { + let _ = f.write_str("dvec2"); + } + syntax::TypeSpecifierNonArray::DVec3 => { + let _ = f.write_str("dvec3"); + } + syntax::TypeSpecifierNonArray::DVec4 => { + let _ = f.write_str("dvec4"); + } + syntax::TypeSpecifierNonArray::BVec2 => { + let _ = f.write_str("bvec2"); + } + syntax::TypeSpecifierNonArray::BVec3 => { + let _ = f.write_str("bvec3"); + } + syntax::TypeSpecifierNonArray::BVec4 => { + let _ = f.write_str("bvec4"); + } + syntax::TypeSpecifierNonArray::IVec2 => { + let _ = f.write_str("ivec2"); + } + syntax::TypeSpecifierNonArray::IVec3 => { + let _ = f.write_str("ivec3"); + } + syntax::TypeSpecifierNonArray::IVec4 => { + let _ = f.write_str("ivec4"); + } + syntax::TypeSpecifierNonArray::UVec2 => { + let _ = f.write_str("uvec2"); + } + syntax::TypeSpecifierNonArray::UVec3 => { + let _ = f.write_str("uvec3"); + } + syntax::TypeSpecifierNonArray::UVec4 => { + let _ = f.write_str("uvec4"); + } + syntax::TypeSpecifierNonArray::Mat2 => { + let _ = f.write_str("mat2"); + } + syntax::TypeSpecifierNonArray::Mat3 => { + let _ = f.write_str("mat3"); + } + syntax::TypeSpecifierNonArray::Mat4 => { + let _ = f.write_str("mat4"); + } + syntax::TypeSpecifierNonArray::Mat23 => { + let _ = f.write_str("mat2x3"); + } + syntax::TypeSpecifierNonArray::Mat24 => { + let _ = f.write_str("mat2x4"); + } + syntax::TypeSpecifierNonArray::Mat32 => { + let _ = f.write_str("mat3x2"); + } + syntax::TypeSpecifierNonArray::Mat34 => { + let _ = f.write_str("mat3x4"); + } + syntax::TypeSpecifierNonArray::Mat42 => { + let _ = f.write_str("mat4x2"); + } + syntax::TypeSpecifierNonArray::Mat43 => { + let _ = f.write_str("mat4x3"); + } + syntax::TypeSpecifierNonArray::DMat2 => { + let _ = f.write_str("dmat2"); + } + syntax::TypeSpecifierNonArray::DMat3 => { + let _ = f.write_str("dmat3"); + } + syntax::TypeSpecifierNonArray::DMat4 => { + let _ = f.write_str("dmat4"); + } + syntax::TypeSpecifierNonArray::DMat23 => { + let _ = f.write_str("dmat2x3"); + } + syntax::TypeSpecifierNonArray::DMat24 => { + let _ = f.write_str("dmat2x4"); + } + syntax::TypeSpecifierNonArray::DMat32 => { + let _ = f.write_str("dmat3x2"); + } + syntax::TypeSpecifierNonArray::DMat34 => { + let _ = f.write_str("dmat3x4"); + } + syntax::TypeSpecifierNonArray::DMat42 => { + let _ = f.write_str("dmat4x2"); + } + syntax::TypeSpecifierNonArray::DMat43 => { + let _ = f.write_str("dmat4x3"); + } + syntax::TypeSpecifierNonArray::Sampler1D => { + let _ = f.write_str("sampler1D"); + } + syntax::TypeSpecifierNonArray::Image1D => { + let _ = f.write_str("image1D"); + } + syntax::TypeSpecifierNonArray::Sampler2D => { + let _ = f.write_str("sampler2D"); + } + syntax::TypeSpecifierNonArray::Image2D => { + let _ = f.write_str("image2D"); + } + syntax::TypeSpecifierNonArray::Sampler3D => { + let _ = f.write_str("sampler3D"); + } + syntax::TypeSpecifierNonArray::Image3D => { + let _ = f.write_str("image3D"); + } + syntax::TypeSpecifierNonArray::SamplerCube => { + let _ = f.write_str("samplerCube"); + } + syntax::TypeSpecifierNonArray::ImageCube => { + let _ = f.write_str("imageCube"); + } + syntax::TypeSpecifierNonArray::Sampler2DRect => { + let _ = f.write_str("sampler2DRect"); + } + syntax::TypeSpecifierNonArray::Image2DRect => { + let _ = f.write_str("image2DRect"); + } + syntax::TypeSpecifierNonArray::Sampler1DArray => { + let _ = f.write_str("sampler1DArray"); + } + syntax::TypeSpecifierNonArray::Image1DArray => { + let _ = f.write_str("image1DArray"); + } + syntax::TypeSpecifierNonArray::Sampler2DArray => { + let _ = f.write_str("sampler2DArray"); + } + syntax::TypeSpecifierNonArray::Image2DArray => { + let _ = f.write_str("image2DArray"); + } + syntax::TypeSpecifierNonArray::SamplerBuffer => { + let _ = f.write_str("samplerBuffer"); + } + syntax::TypeSpecifierNonArray::ImageBuffer => { + let _ = f.write_str("imageBuffer"); + } + syntax::TypeSpecifierNonArray::Sampler2DMS => { + let _ = f.write_str("sampler2DMS"); + } + syntax::TypeSpecifierNonArray::Image2DMS => { + let _ = f.write_str("image2DMS"); + } + syntax::TypeSpecifierNonArray::Sampler2DMSArray => { + let _ = f.write_str("sampler2DMSArray"); + } + syntax::TypeSpecifierNonArray::Image2DMSArray => { + let _ = f.write_str("image2DMSArray"); + } + syntax::TypeSpecifierNonArray::SamplerCubeArray => { + let _ = f.write_str("samplerCubeArray"); + } + syntax::TypeSpecifierNonArray::ImageCubeArray => { + let _ = f.write_str("imageCubeArray"); + } + syntax::TypeSpecifierNonArray::Sampler1DShadow => { + let _ = f.write_str("sampler1DShadow"); + } + syntax::TypeSpecifierNonArray::Sampler2DShadow => { + let _ = f.write_str("sampler2DShadow"); + } + syntax::TypeSpecifierNonArray::Sampler2DRectShadow => { + let _ = f.write_str("sampler2DRectShadow"); + } + syntax::TypeSpecifierNonArray::Sampler1DArrayShadow => { + let _ = f.write_str("sampler1DArrayShadow"); + } + syntax::TypeSpecifierNonArray::Sampler2DArrayShadow => { + let _ = f.write_str("sampler2DArrayShadow"); + } + syntax::TypeSpecifierNonArray::SamplerCubeShadow => { + let _ = f.write_str("samplerCubeShadow"); + } + syntax::TypeSpecifierNonArray::SamplerCubeArrayShadow => { + let _ = f.write_str("samplerCubeArrayShadow"); + } + syntax::TypeSpecifierNonArray::ISampler1D => { + let _ = f.write_str("isampler1D"); + } + syntax::TypeSpecifierNonArray::IImage1D => { + let _ = f.write_str("iimage1D"); + } + syntax::TypeSpecifierNonArray::ISampler2D => { + let _ = f.write_str("isampler2D"); + } + syntax::TypeSpecifierNonArray::IImage2D => { + let _ = f.write_str("iimage2D"); + } + syntax::TypeSpecifierNonArray::ISampler3D => { + let _ = f.write_str("isampler3D"); + } + syntax::TypeSpecifierNonArray::IImage3D => { + let _ = f.write_str("iimage3D"); + } + syntax::TypeSpecifierNonArray::ISamplerCube => { + let _ = f.write_str("isamplerCube"); + } + syntax::TypeSpecifierNonArray::IImageCube => { + let _ = f.write_str("iimageCube"); + } + syntax::TypeSpecifierNonArray::ISampler2DRect => { + let _ = f.write_str("isampler2DRect"); + } + syntax::TypeSpecifierNonArray::IImage2DRect => { + let _ = f.write_str("iimage2DRect"); + } + syntax::TypeSpecifierNonArray::ISampler1DArray => { + let _ = f.write_str("isampler1DArray"); + } + syntax::TypeSpecifierNonArray::IImage1DArray => { + let _ = f.write_str("iimage1DArray"); + } + syntax::TypeSpecifierNonArray::ISampler2DArray => { + let _ = f.write_str("isampler2DArray"); + } + syntax::TypeSpecifierNonArray::IImage2DArray => { + let _ = f.write_str("iimage2DArray"); + } + syntax::TypeSpecifierNonArray::ISamplerBuffer => { + let _ = f.write_str("isamplerBuffer"); + } + syntax::TypeSpecifierNonArray::IImageBuffer => { + let _ = f.write_str("iimageBuffer"); + } + syntax::TypeSpecifierNonArray::ISampler2DMS => { + let _ = f.write_str("isampler2MS"); + } + syntax::TypeSpecifierNonArray::IImage2DMS => { + let _ = f.write_str("iimage2DMS"); + } + syntax::TypeSpecifierNonArray::ISampler2DMSArray => { + let _ = f.write_str("isampler2DMSArray"); + } + syntax::TypeSpecifierNonArray::IImage2DMSArray => { + let _ = f.write_str("iimage2DMSArray"); + } + syntax::TypeSpecifierNonArray::ISamplerCubeArray => { + let _ = f.write_str("isamplerCubeArray"); + } + syntax::TypeSpecifierNonArray::IImageCubeArray => { + let _ = f.write_str("iimageCubeArray"); + } + syntax::TypeSpecifierNonArray::AtomicUInt => { + let _ = f.write_str("atomic_uint"); + } + syntax::TypeSpecifierNonArray::USampler1D => { + let _ = f.write_str("usampler1D"); + } + syntax::TypeSpecifierNonArray::UImage1D => { + let _ = f.write_str("uimage1D"); + } + syntax::TypeSpecifierNonArray::USampler2D => { + let _ = f.write_str("usampler2D"); + } + syntax::TypeSpecifierNonArray::UImage2D => { + let _ = f.write_str("uimage2D"); + } + syntax::TypeSpecifierNonArray::USampler3D => { + let _ = f.write_str("usampler3D"); + } + syntax::TypeSpecifierNonArray::UImage3D => { + let _ = f.write_str("uimage3D"); + } + syntax::TypeSpecifierNonArray::USamplerCube => { + let _ = f.write_str("usamplerCube"); + } + syntax::TypeSpecifierNonArray::UImageCube => { + let _ = f.write_str("uimageCube"); + } + syntax::TypeSpecifierNonArray::USampler2DRect => { + let _ = f.write_str("usampler2DRect"); + } + syntax::TypeSpecifierNonArray::UImage2DRect => { + let _ = f.write_str("uimage2DRect"); + } + syntax::TypeSpecifierNonArray::USampler1DArray => { + let _ = f.write_str("usampler1DArray"); + } + syntax::TypeSpecifierNonArray::UImage1DArray => { + let _ = f.write_str("uimage1DArray"); + } + syntax::TypeSpecifierNonArray::USampler2DArray => { + let _ = f.write_str("usampler2DArray"); + } + syntax::TypeSpecifierNonArray::UImage2DArray => { + let _ = f.write_str("uimage2DArray"); + } + syntax::TypeSpecifierNonArray::USamplerBuffer => { + let _ = f.write_str("usamplerBuffer"); + } + syntax::TypeSpecifierNonArray::UImageBuffer => { + let _ = f.write_str("uimageBuffer"); + } + syntax::TypeSpecifierNonArray::USampler2DMS => { + let _ = f.write_str("usampler2DMS"); + } + syntax::TypeSpecifierNonArray::UImage2DMS => { + let _ = f.write_str("uimage2DMS"); + } + syntax::TypeSpecifierNonArray::USampler2DMSArray => { + let _ = f.write_str("usamplerDMSArray"); + } + syntax::TypeSpecifierNonArray::UImage2DMSArray => { + let _ = f.write_str("uimage2DMSArray"); + } + syntax::TypeSpecifierNonArray::USamplerCubeArray => { + let _ = f.write_str("usamplerCubeArray"); + } + syntax::TypeSpecifierNonArray::UImageCubeArray => { + let _ = f.write_str("uimageCubeArray"); + } + syntax::TypeSpecifierNonArray::Struct(ref s) => show_struct_non_declaration(f, s), + syntax::TypeSpecifierNonArray::TypeName(ref tn) => show_type_name(f, tn), + } +} + +pub fn show_type_specifier<F>(f: &mut F, t: &syntax::TypeSpecifier) +where + F: Write, +{ + show_type_specifier_non_array(f, &t.ty); + + if let Some(ref arr_spec) = t.array_specifier { + show_array_spec(f, arr_spec); + } +} + +pub fn show_fully_specified_type<F>(f: &mut F, t: &syntax::FullySpecifiedType) +where + F: Write, +{ + if let Some(ref qual) = t.qualifier { + show_type_qualifier(f, &qual); + let _ = f.write_str(" "); + } + + show_type_specifier(f, &t.ty); +} + +pub fn show_struct_non_declaration<F>(f: &mut F, s: &syntax::StructSpecifier) +where + F: Write, +{ + let _ = f.write_str("struct "); + + if let Some(ref name) = s.name { + let _ = write!(f, "{} ", name); + } + + let _ = f.write_str("{\n"); + + for field in &s.fields.0 { + show_struct_field(f, field); + } + + let _ = f.write_str("}"); +} + +pub fn show_struct<F>(f: &mut F, s: &syntax::StructSpecifier) +where + F: Write, +{ + show_struct_non_declaration(f, s); + let _ = f.write_str(";\n"); +} + +pub fn show_struct_field<F>(f: &mut F, field: &syntax::StructFieldSpecifier) +where + F: Write, +{ + if let Some(ref qual) = field.qualifier { + show_type_qualifier(f, &qual); + let _ = f.write_str(" "); + } + + show_type_specifier(f, &field.ty); + let _ = f.write_str(" "); + + // there’s at least one identifier + let mut identifiers = field.identifiers.0.iter(); + let identifier = identifiers.next().unwrap(); + + show_arrayed_identifier(f, identifier); + + // write the rest of the identifiers + for identifier in identifiers { + let _ = f.write_str(", "); + show_arrayed_identifier(f, identifier); + } + + let _ = f.write_str(";\n"); +} + +pub fn show_array_spec<F>(f: &mut F, a: &syntax::ArraySpecifier) +where + F: Write, +{ + for dimension in &a.dimensions { + match *dimension { + syntax::ArraySpecifierDimension::Unsized => { + let _ = f.write_str("[]"); + } + syntax::ArraySpecifierDimension::ExplicitlySized(ref e) => { + let _ = f.write_str("["); + show_expr(f, &e); + let _ = f.write_str("]"); + } + } + } +} + +pub fn show_arrayed_identifier<F>(f: &mut F, a: &syntax::ArrayedIdentifier) +where + F: Write, +{ + let _ = write!(f, "{}", a.ident); + + if let Some(ref arr_spec) = a.array_spec { + show_array_spec(f, arr_spec); + } +} + +pub fn show_type_qualifier<F>(f: &mut F, q: &syntax::TypeQualifier) +where + F: Write, +{ + let mut qualifiers = q.qualifiers.0.iter(); + let first = qualifiers.next().unwrap(); + + show_type_qualifier_spec(f, first); + + for qual_spec in qualifiers { + let _ = f.write_str(" "); + show_type_qualifier_spec(f, qual_spec) + } +} + +pub fn show_type_qualifier_spec<F>(f: &mut F, q: &syntax::TypeQualifierSpec) +where + F: Write, +{ + match *q { + syntax::TypeQualifierSpec::Storage(ref s) => show_storage_qualifier(f, &s), + syntax::TypeQualifierSpec::Layout(ref l) => show_layout_qualifier(f, &l), + syntax::TypeQualifierSpec::Precision(ref p) => show_precision_qualifier(f, &p), + syntax::TypeQualifierSpec::Interpolation(ref i) => show_interpolation_qualifier(f, &i), + syntax::TypeQualifierSpec::Invariant => { + let _ = f.write_str("invariant"); + } + syntax::TypeQualifierSpec::Precise => { + let _ = f.write_str("precise"); + } + } +} + +pub fn show_storage_qualifier<F>(f: &mut F, q: &syntax::StorageQualifier) +where + F: Write, +{ + match *q { + syntax::StorageQualifier::Const => { + let _ = f.write_str("const"); + } + syntax::StorageQualifier::InOut => { + let _ = f.write_str("inout"); + } + syntax::StorageQualifier::In => { + let _ = f.write_str("in"); + } + syntax::StorageQualifier::Out => { + let _ = f.write_str("out"); + } + syntax::StorageQualifier::Centroid => { + let _ = f.write_str("centroid"); + } + syntax::StorageQualifier::Patch => { + let _ = f.write_str("patch"); + } + syntax::StorageQualifier::Sample => { + let _ = f.write_str("sample"); + } + syntax::StorageQualifier::Uniform => { + let _ = f.write_str("uniform"); + } + syntax::StorageQualifier::Attribute => { + let _ = f.write_str("attribute"); + } + syntax::StorageQualifier::Varying => { + let _ = f.write_str("varying"); + } + syntax::StorageQualifier::Buffer => { + let _ = f.write_str("buffer"); + } + syntax::StorageQualifier::Shared => { + let _ = f.write_str("shared"); + } + syntax::StorageQualifier::Coherent => { + let _ = f.write_str("coherent"); + } + syntax::StorageQualifier::Volatile => { + let _ = f.write_str("volatile"); + } + syntax::StorageQualifier::Restrict => { + let _ = f.write_str("restrict"); + } + syntax::StorageQualifier::ReadOnly => { + let _ = f.write_str("readonly"); + } + syntax::StorageQualifier::WriteOnly => { + let _ = f.write_str("writeonly"); + } + syntax::StorageQualifier::Subroutine(ref n) => show_subroutine(f, &n), + } +} + +pub fn show_subroutine<F>(f: &mut F, types: &Vec<syntax::TypeName>) +where + F: Write, +{ + let _ = f.write_str("subroutine"); + + if !types.is_empty() { + let _ = f.write_str("("); + + let mut types_iter = types.iter(); + let first = types_iter.next().unwrap(); + + show_type_name(f, first); + + for type_name in types_iter { + let _ = f.write_str(", "); + show_type_name(f, type_name); + } + + let _ = f.write_str(")"); + } +} + +pub fn show_layout_qualifier<F>(f: &mut F, l: &syntax::LayoutQualifier) +where + F: Write, +{ + let mut qualifiers = l.ids.0.iter(); + let first = qualifiers.next().unwrap(); + + let _ = f.write_str("layout ("); + show_layout_qualifier_spec(f, first); + + for qual_spec in qualifiers { + let _ = f.write_str(", "); + show_layout_qualifier_spec(f, qual_spec); + } + + let _ = f.write_str(")"); +} + +pub fn show_layout_qualifier_spec<F>(f: &mut F, l: &syntax::LayoutQualifierSpec) +where + F: Write, +{ + match *l { + syntax::LayoutQualifierSpec::Identifier(ref i, Some(ref e)) => { + let _ = write!(f, "{} = ", i); + show_expr(f, &e); + } + syntax::LayoutQualifierSpec::Identifier(ref i, None) => show_identifier(f, &i), + syntax::LayoutQualifierSpec::Shared => { + let _ = f.write_str("shared"); + } + } +} + +pub fn show_precision_qualifier<F>(f: &mut F, p: &syntax::PrecisionQualifier) +where + F: Write, +{ + match *p { + syntax::PrecisionQualifier::High => { + let _ = f.write_str("highp"); + } + syntax::PrecisionQualifier::Medium => { + let _ = f.write_str("mediump"); + } + syntax::PrecisionQualifier::Low => { + let _ = f.write_str("low"); + } + } +} + +pub fn show_interpolation_qualifier<F>(f: &mut F, i: &syntax::InterpolationQualifier) +where + F: Write, +{ + match *i { + syntax::InterpolationQualifier::Smooth => { + let _ = f.write_str("smooth"); + } + syntax::InterpolationQualifier::Flat => { + let _ = f.write_str("flat"); + } + syntax::InterpolationQualifier::NoPerspective => { + let _ = f.write_str("noperspective"); + } + } +} + +pub fn show_float<F>(f: &mut F, x: f32) +where + F: Write, +{ + if x.fract() == 0. { + let _ = write!(f, "{}.", x); + } else { + let _ = write!(f, "{}", x); + } +} + +pub fn show_double<F>(f: &mut F, x: f64) +where + F: Write, +{ + if x.fract() == 0. { + let _ = write!(f, "{}.lf", x); + } else { + let _ = write!(f, "{}lf", x); + } +} + +pub fn show_expr<F>(f: &mut F, expr: &syntax::Expr) +where + F: Write, +{ + match *expr { + syntax::Expr::Variable(ref i) => show_identifier(f, &i), + syntax::Expr::IntConst(ref x) => { + let _ = write!(f, "{}", x); + } + syntax::Expr::UIntConst(ref x) => { + let _ = write!(f, "{}u", x); + } + syntax::Expr::BoolConst(ref x) => { + let _ = write!(f, "{}", x); + } + syntax::Expr::FloatConst(ref x) => show_float(f, *x), + syntax::Expr::DoubleConst(ref x) => show_double(f, *x), + syntax::Expr::Unary(ref op, ref e) => { + // Note: all unary ops are right-to-left associative + show_unary_op(f, &op); + + if e.precedence() > op.precedence() { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } else if let syntax::Expr::Unary(eop, _) = &**e { + // Prevent double-unary plus/minus turning into inc/dec + if eop == op && (*eop == syntax::UnaryOp::Add || *eop == syntax::UnaryOp::Minus) { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } else { + show_expr(f, &e); + } + } else { + show_expr(f, &e); + } + } + syntax::Expr::Binary(ref op, ref l, ref r) => { + // Note: all binary ops are left-to-right associative (<= for left part) + + if l.precedence() <= op.precedence() { + show_expr(f, &l); + } else { + let _ = f.write_str("("); + show_expr(f, &l); + let _ = f.write_str(")"); + } + + show_binary_op(f, &op); + + if r.precedence() < op.precedence() { + show_expr(f, &r); + } else { + let _ = f.write_str("("); + show_expr(f, &r); + let _ = f.write_str(")"); + } + } + syntax::Expr::Ternary(ref c, ref s, ref e) => { + // Note: ternary is right-to-left associative (<= for right part) + + if c.precedence() < expr.precedence() { + show_expr(f, &c); + } else { + let _ = f.write_str("("); + show_expr(f, &c); + let _ = f.write_str(")"); + } + let _ = f.write_str(" ? "); + show_expr(f, &s); + let _ = f.write_str(" : "); + if e.precedence() <= expr.precedence() { + show_expr(f, &e); + } else { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } + } + syntax::Expr::Assignment(ref v, ref op, ref e) => { + // Note: all assignment ops are right-to-left associative + + if v.precedence() < op.precedence() { + show_expr(f, &v); + } else { + let _ = f.write_str("("); + show_expr(f, &v); + let _ = f.write_str(")"); + } + + let _ = f.write_str(" "); + show_assignment_op(f, &op); + let _ = f.write_str(" "); + + if e.precedence() <= op.precedence() { + show_expr(f, &e); + } else { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } + } + syntax::Expr::Bracket(ref e, ref a) => { + // Note: bracket is left-to-right associative + + if e.precedence() <= expr.precedence() { + show_expr(f, &e); + } else { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } + + show_array_spec(f, &a); + } + syntax::Expr::FunCall(ref fun, ref args) => { + show_function_identifier(f, &fun); + let _ = f.write_str("("); + + if !args.is_empty() { + let mut args_iter = args.iter(); + let first = args_iter.next().unwrap(); + show_expr(f, first); + + for e in args_iter { + let _ = f.write_str(", "); + show_expr(f, e); + } + } + + let _ = f.write_str(")"); + } + syntax::Expr::Dot(ref e, ref i) => { + // Note: dot is left-to-right associative + + if e.precedence() <= expr.precedence() { + show_expr(f, &e); + } else { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } + let _ = f.write_str("."); + show_identifier(f, &i); + } + syntax::Expr::PostInc(ref e) => { + // Note: post-increment is right-to-left associative + + if e.precedence() < expr.precedence() { + show_expr(f, &e); + } else { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } + + let _ = f.write_str("++"); + } + syntax::Expr::PostDec(ref e) => { + // Note: post-decrement is right-to-left associative + + if e.precedence() < expr.precedence() { + show_expr(f, &e); + } else { + let _ = f.write_str("("); + show_expr(f, &e); + let _ = f.write_str(")"); + } + + let _ = f.write_str("--"); + } + syntax::Expr::Comma(ref a, ref b) => { + // Note: comma is left-to-right associative + + if a.precedence() <= expr.precedence() { + show_expr(f, &a); + } else { + let _ = f.write_str("("); + show_expr(f, &a); + let _ = f.write_str(")"); + } + + let _ = f.write_str(", "); + + if b.precedence() < expr.precedence() { + show_expr(f, &b); + } else { + let _ = f.write_str("("); + show_expr(f, &b); + let _ = f.write_str(")"); + } + } + } +} + +pub fn show_path<F>(f: &mut F, path: &syntax::Path) +where + F: Write, +{ + match path { + syntax::Path::Absolute(s) => { + let _ = write!(f, "<{}>", s); + } + syntax::Path::Relative(s) => { + let _ = write!(f, "\"{}\"", s); + } + } +} + +pub fn show_unary_op<F>(f: &mut F, op: &syntax::UnaryOp) +where + F: Write, +{ + match *op { + syntax::UnaryOp::Inc => { + let _ = f.write_str("++"); + } + syntax::UnaryOp::Dec => { + let _ = f.write_str("--"); + } + syntax::UnaryOp::Add => { + let _ = f.write_str("+"); + } + syntax::UnaryOp::Minus => { + let _ = f.write_str("-"); + } + syntax::UnaryOp::Not => { + let _ = f.write_str("!"); + } + syntax::UnaryOp::Complement => { + let _ = f.write_str("~"); + } + } +} + +pub fn show_binary_op<F>(f: &mut F, op: &syntax::BinaryOp) +where + F: Write, +{ + match *op { + syntax::BinaryOp::Or => { + let _ = f.write_str("||"); + } + syntax::BinaryOp::Xor => { + let _ = f.write_str("^^"); + } + syntax::BinaryOp::And => { + let _ = f.write_str("&&"); + } + syntax::BinaryOp::BitOr => { + let _ = f.write_str("|"); + } + syntax::BinaryOp::BitXor => { + let _ = f.write_str("^"); + } + syntax::BinaryOp::BitAnd => { + let _ = f.write_str("&"); + } + syntax::BinaryOp::Equal => { + let _ = f.write_str("=="); + } + syntax::BinaryOp::NonEqual => { + let _ = f.write_str("!="); + } + syntax::BinaryOp::LT => { + let _ = f.write_str("<"); + } + syntax::BinaryOp::GT => { + let _ = f.write_str(">"); + } + syntax::BinaryOp::LTE => { + let _ = f.write_str("<="); + } + syntax::BinaryOp::GTE => { + let _ = f.write_str(">="); + } + syntax::BinaryOp::LShift => { + let _ = f.write_str("<<"); + } + syntax::BinaryOp::RShift => { + let _ = f.write_str(">>"); + } + syntax::BinaryOp::Add => { + let _ = f.write_str("+"); + } + syntax::BinaryOp::Sub => { + let _ = f.write_str("-"); + } + syntax::BinaryOp::Mult => { + let _ = f.write_str("*"); + } + syntax::BinaryOp::Div => { + let _ = f.write_str("/"); + } + syntax::BinaryOp::Mod => { + let _ = f.write_str("%"); + } + } +} + +pub fn show_assignment_op<F>(f: &mut F, op: &syntax::AssignmentOp) +where + F: Write, +{ + match *op { + syntax::AssignmentOp::Equal => { + let _ = f.write_str("="); + } + syntax::AssignmentOp::Mult => { + let _ = f.write_str("*="); + } + syntax::AssignmentOp::Div => { + let _ = f.write_str("/="); + } + syntax::AssignmentOp::Mod => { + let _ = f.write_str("%="); + } + syntax::AssignmentOp::Add => { + let _ = f.write_str("+="); + } + syntax::AssignmentOp::Sub => { + let _ = f.write_str("-="); + } + syntax::AssignmentOp::LShift => { + let _ = f.write_str("<<="); + } + syntax::AssignmentOp::RShift => { + let _ = f.write_str(">>="); + } + syntax::AssignmentOp::And => { + let _ = f.write_str("&="); + } + syntax::AssignmentOp::Xor => { + let _ = f.write_str("^="); + } + syntax::AssignmentOp::Or => { + let _ = f.write_str("|="); + } + } +} + +pub fn show_function_identifier<F>(f: &mut F, i: &syntax::FunIdentifier) +where + F: Write, +{ + match *i { + syntax::FunIdentifier::Identifier(ref n) => show_identifier(f, &n), + syntax::FunIdentifier::Expr(ref e) => show_expr(f, &*e), + } +} + +pub fn show_declaration<F>(f: &mut F, d: &syntax::Declaration) +where + F: Write, +{ + match *d { + syntax::Declaration::FunctionPrototype(ref proto) => { + show_function_prototype(f, &proto); + let _ = f.write_str(";\n"); + } + syntax::Declaration::InitDeclaratorList(ref list) => { + show_init_declarator_list(f, &list); + let _ = f.write_str(";\n"); + } + syntax::Declaration::Precision(ref qual, ref ty) => { + show_precision_qualifier(f, &qual); + show_type_specifier(f, &ty); + let _ = f.write_str(";\n"); + } + syntax::Declaration::Block(ref block) => { + show_block(f, &block); + let _ = f.write_str(";\n"); + } + syntax::Declaration::Global(ref qual, ref identifiers) => { + show_type_qualifier(f, &qual); + + if !identifiers.is_empty() { + let mut iter = identifiers.iter(); + let first = iter.next().unwrap(); + show_identifier(f, first); + + for identifier in iter { + let _ = write!(f, ", {}", identifier); + } + } + + let _ = f.write_str(";\n"); + } + } +} + +pub fn show_function_prototype<F>(f: &mut F, fp: &syntax::FunctionPrototype) +where + F: Write, +{ + show_fully_specified_type(f, &fp.ty); + let _ = f.write_str(" "); + show_identifier(f, &fp.name); + + let _ = f.write_str("("); + + if !fp.parameters.is_empty() { + let mut iter = fp.parameters.iter(); + let first = iter.next().unwrap(); + show_function_parameter_declaration(f, first); + + for param in iter { + let _ = f.write_str(", "); + show_function_parameter_declaration(f, param); + } + } + + let _ = f.write_str(")"); +} +pub fn show_function_parameter_declaration<F>(f: &mut F, p: &syntax::FunctionParameterDeclaration) +where + F: Write, +{ + match *p { + syntax::FunctionParameterDeclaration::Named(ref qual, ref fpd) => { + if let Some(ref q) = *qual { + show_type_qualifier(f, q); + let _ = f.write_str(" "); + } + + show_function_parameter_declarator(f, fpd); + } + syntax::FunctionParameterDeclaration::Unnamed(ref qual, ref ty) => { + if let Some(ref q) = *qual { + show_type_qualifier(f, q); + let _ = f.write_str(" "); + } + + show_type_specifier(f, ty); + } + } +} + +pub fn show_function_parameter_declarator<F>(f: &mut F, p: &syntax::FunctionParameterDeclarator) +where + F: Write, +{ + show_type_specifier(f, &p.ty); + let _ = f.write_str(" "); + show_arrayed_identifier(f, &p.ident); +} + +pub fn show_init_declarator_list<F>(f: &mut F, i: &syntax::InitDeclaratorList) +where + F: Write, +{ + show_single_declaration(f, &i.head); + + for decl in &i.tail { + let _ = f.write_str(", "); + show_single_declaration_no_type(f, decl); + } +} + +pub fn show_single_declaration<F>(f: &mut F, d: &syntax::SingleDeclaration) +where + F: Write, +{ + show_fully_specified_type(f, &d.ty); + + if let Some(ref name) = d.name { + let _ = f.write_str(" "); + show_identifier(f, name); + } + + if let Some(ref arr_spec) = d.array_specifier { + show_array_spec(f, arr_spec); + } + + if let Some(ref initializer) = d.initializer { + let _ = f.write_str(" = "); + show_initializer(f, initializer); + } +} + +pub fn show_single_declaration_no_type<F>(f: &mut F, d: &syntax::SingleDeclarationNoType) +where + F: Write, +{ + show_arrayed_identifier(f, &d.ident); + + if let Some(ref initializer) = d.initializer { + let _ = f.write_str(" = "); + show_initializer(f, initializer); + } +} + +pub fn show_initializer<F>(f: &mut F, i: &syntax::Initializer) +where + F: Write, +{ + match *i { + syntax::Initializer::Simple(ref e) => show_expr(f, e), + syntax::Initializer::List(ref list) => { + let mut iter = list.0.iter(); + let first = iter.next().unwrap(); + + let _ = f.write_str("{ "); + show_initializer(f, first); + + for ini in iter { + let _ = f.write_str(", "); + show_initializer(f, ini); + } + + let _ = f.write_str(" }"); + } + } +} + +pub fn show_block<F>(f: &mut F, b: &syntax::Block) +where + F: Write, +{ + show_type_qualifier(f, &b.qualifier); + let _ = f.write_str(" "); + show_identifier(f, &b.name); + let _ = f.write_str(" {"); + + for field in &b.fields { + show_struct_field(f, field); + let _ = f.write_str("\n"); + } + let _ = f.write_str("}"); + + if let Some(ref ident) = b.identifier { + show_arrayed_identifier(f, ident); + } +} + +pub fn show_function_definition<F>(f: &mut F, fd: &syntax::FunctionDefinition) +where + F: Write, +{ + show_function_prototype(f, &fd.prototype); + let _ = f.write_str(" "); + show_compound_statement(f, &fd.statement); +} + +pub fn show_compound_statement<F>(f: &mut F, cst: &syntax::CompoundStatement) +where + F: Write, +{ + let _ = f.write_str("{\n"); + + for st in &cst.statement_list { + show_statement(f, st); + } + + let _ = f.write_str("}\n"); +} + +pub fn show_statement<F>(f: &mut F, st: &syntax::Statement) +where + F: Write, +{ + match *st { + syntax::Statement::Compound(ref cst) => show_compound_statement(f, cst), + syntax::Statement::Simple(ref sst) => show_simple_statement(f, sst), + } +} + +pub fn show_simple_statement<F>(f: &mut F, sst: &syntax::SimpleStatement) +where + F: Write, +{ + match *sst { + syntax::SimpleStatement::Declaration(ref d) => show_declaration(f, d), + syntax::SimpleStatement::Expression(ref e) => show_expression_statement(f, e), + syntax::SimpleStatement::Selection(ref s) => show_selection_statement(f, s), + syntax::SimpleStatement::Switch(ref s) => show_switch_statement(f, s), + syntax::SimpleStatement::CaseLabel(ref cl) => show_case_label(f, cl), + syntax::SimpleStatement::Iteration(ref i) => show_iteration_statement(f, i), + syntax::SimpleStatement::Jump(ref j) => show_jump_statement(f, j), + } +} + +pub fn show_expression_statement<F>(f: &mut F, est: &syntax::ExprStatement) +where + F: Write, +{ + if let Some(ref e) = *est { + show_expr(f, e); + } + + let _ = f.write_str(";\n"); +} + +pub fn show_selection_statement<F>(f: &mut F, sst: &syntax::SelectionStatement) +where + F: Write, +{ + let _ = f.write_str("if ("); + show_expr(f, &sst.cond); + let _ = f.write_str(") {\n"); + show_selection_rest_statement(f, &sst.rest); +} + +pub fn show_selection_rest_statement<F>(f: &mut F, sst: &syntax::SelectionRestStatement) +where + F: Write, +{ + match *sst { + syntax::SelectionRestStatement::Statement(ref if_st) => { + show_statement(f, if_st); + let _ = f.write_str("}\n"); + } + syntax::SelectionRestStatement::Else(ref if_st, ref else_st) => { + show_statement(f, if_st); + let _ = f.write_str("} else "); + show_statement(f, else_st); + } + } +} + +pub fn show_switch_statement<F>(f: &mut F, sst: &syntax::SwitchStatement) +where + F: Write, +{ + let _ = f.write_str("switch ("); + show_expr(f, &sst.head); + let _ = f.write_str(") {\n"); + + for st in &sst.body { + show_statement(f, st); + } + + let _ = f.write_str("}\n"); +} + +pub fn show_case_label<F>(f: &mut F, cl: &syntax::CaseLabel) +where + F: Write, +{ + match *cl { + syntax::CaseLabel::Case(ref e) => { + let _ = f.write_str("case "); + show_expr(f, e); + let _ = f.write_str(":\n"); + } + syntax::CaseLabel::Def => { + let _ = f.write_str("default:\n"); + } + } +} + +pub fn show_iteration_statement<F>(f: &mut F, ist: &syntax::IterationStatement) +where + F: Write, +{ + match *ist { + syntax::IterationStatement::While(ref cond, ref body) => { + let _ = f.write_str("while ("); + show_condition(f, cond); + let _ = f.write_str(") "); + show_statement(f, body); + } + syntax::IterationStatement::DoWhile(ref body, ref cond) => { + let _ = f.write_str("do "); + show_statement(f, body); + let _ = f.write_str(" while ("); + show_expr(f, cond); + let _ = f.write_str(")\n"); + } + syntax::IterationStatement::For(ref init, ref rest, ref body) => { + let _ = f.write_str("for ("); + show_for_init_statement(f, init); + show_for_rest_statement(f, rest); + let _ = f.write_str(") "); + show_statement(f, body); + } + } +} + +pub fn show_condition<F>(f: &mut F, c: &syntax::Condition) +where + F: Write, +{ + match *c { + syntax::Condition::Expr(ref e) => show_expr(f, e), + syntax::Condition::Assignment(ref ty, ref name, ref initializer) => { + show_fully_specified_type(f, ty); + let _ = f.write_str(" "); + show_identifier(f, name); + let _ = f.write_str(" = "); + show_initializer(f, initializer); + } + } +} + +pub fn show_for_init_statement<F>(f: &mut F, i: &syntax::ForInitStatement) +where + F: Write, +{ + match *i { + syntax::ForInitStatement::Expression(ref expr) => { + if let Some(ref e) = *expr { + show_expr(f, e); + } + } + syntax::ForInitStatement::Declaration(ref d) => show_declaration(f, d), + } +} + +pub fn show_for_rest_statement<F>(f: &mut F, r: &syntax::ForRestStatement) +where + F: Write, +{ + if let Some(ref cond) = r.condition { + show_condition(f, cond); + } + + let _ = f.write_str("; "); + + if let Some(ref e) = r.post_expr { + show_expr(f, e); + } +} + +pub fn show_jump_statement<F>(f: &mut F, j: &syntax::JumpStatement) +where + F: Write, +{ + match *j { + syntax::JumpStatement::Continue => { + let _ = f.write_str("continue;\n"); + } + syntax::JumpStatement::Break => { + let _ = f.write_str("break;\n"); + } + syntax::JumpStatement::Discard => { + let _ = f.write_str("discard;\n"); + } + syntax::JumpStatement::Return(ref e) => { + let _ = f.write_str("return "); + if let Some(e) = e { + show_expr(f, e); + } + let _ = f.write_str(";\n"); + } + } +} + +pub fn show_preprocessor<F>(f: &mut F, pp: &syntax::Preprocessor) +where + F: Write, +{ + match *pp { + syntax::Preprocessor::Define(ref pd) => show_preprocessor_define(f, pd), + syntax::Preprocessor::Else => show_preprocessor_else(f), + syntax::Preprocessor::ElseIf(ref pei) => show_preprocessor_elseif(f, pei), + syntax::Preprocessor::EndIf => show_preprocessor_endif(f), + syntax::Preprocessor::Error(ref pe) => show_preprocessor_error(f, pe), + syntax::Preprocessor::If(ref pi) => show_preprocessor_if(f, pi), + syntax::Preprocessor::IfDef(ref pid) => show_preprocessor_ifdef(f, pid), + syntax::Preprocessor::IfNDef(ref pind) => show_preprocessor_ifndef(f, pind), + syntax::Preprocessor::Include(ref pi) => show_preprocessor_include(f, pi), + syntax::Preprocessor::Line(ref pl) => show_preprocessor_line(f, pl), + syntax::Preprocessor::Pragma(ref pp) => show_preprocessor_pragma(f, pp), + syntax::Preprocessor::Undef(ref pu) => show_preprocessor_undef(f, pu), + syntax::Preprocessor::Version(ref pv) => show_preprocessor_version(f, pv), + syntax::Preprocessor::Extension(ref pe) => show_preprocessor_extension(f, pe), + } +} + +pub fn show_preprocessor_define<F>(f: &mut F, pd: &syntax::PreprocessorDefine) +where + F: Write, +{ + match *pd { + syntax::PreprocessorDefine::ObjectLike { + ref ident, + ref value, + } => { + let _ = write!(f, "#define {} {}\n", ident, value); + } + + syntax::PreprocessorDefine::FunctionLike { + ref ident, + ref args, + ref value, + } => { + let _ = write!(f, "#define {}(", ident); + + if !args.is_empty() { + let _ = write!(f, "{}", &args[0]); + + for arg in &args[1..args.len()] { + let _ = write!(f, ", {}", arg); + } + } + + let _ = write!(f, ") {}\n", value); + } + } +} + +pub fn show_preprocessor_else<F>(f: &mut F) +where + F: Write, +{ + let _ = f.write_str("#else\n"); +} + +pub fn show_preprocessor_elseif<F>(f: &mut F, pei: &syntax::PreprocessorElseIf) +where + F: Write, +{ + let _ = write!(f, "#elseif {}\n", pei.condition); +} + +pub fn show_preprocessor_error<F>(f: &mut F, pe: &syntax::PreprocessorError) +where + F: Write, +{ + let _ = writeln!(f, "#error {}", pe.message); +} + +pub fn show_preprocessor_endif<F>(f: &mut F) +where + F: Write, +{ + let _ = f.write_str("#endif\n"); +} + +pub fn show_preprocessor_if<F>(f: &mut F, pi: &syntax::PreprocessorIf) +where + F: Write, +{ + let _ = write!(f, "#if {}\n", pi.condition); +} + +pub fn show_preprocessor_ifdef<F>(f: &mut F, pid: &syntax::PreprocessorIfDef) +where + F: Write, +{ + let _ = f.write_str("#ifdef "); + show_identifier(f, &pid.ident); + let _ = f.write_str("\n"); +} + +pub fn show_preprocessor_ifndef<F>(f: &mut F, pind: &syntax::PreprocessorIfNDef) +where + F: Write, +{ + let _ = f.write_str("#ifndef "); + show_identifier(f, &pind.ident); + let _ = f.write_str("\n"); +} + +pub fn show_preprocessor_include<F>(f: &mut F, pi: &syntax::PreprocessorInclude) +where + F: Write, +{ + let _ = f.write_str("#include "); + show_path(f, &pi.path); + let _ = f.write_str("\n"); +} + +pub fn show_preprocessor_line<F>(f: &mut F, pl: &syntax::PreprocessorLine) +where + F: Write, +{ + let _ = write!(f, "#line {}", pl.line); + if let Some(source_string_number) = pl.source_string_number { + let _ = write!(f, " {}", source_string_number); + } + let _ = f.write_str("\n"); +} + +pub fn show_preprocessor_pragma<F>(f: &mut F, pp: &syntax::PreprocessorPragma) +where + F: Write, +{ + let _ = writeln!(f, "#pragma {}", pp.command); +} + +pub fn show_preprocessor_undef<F>(f: &mut F, pud: &syntax::PreprocessorUndef) +where + F: Write, +{ + let _ = f.write_str("#undef "); + show_identifier(f, &pud.name); + let _ = f.write_str("\n"); +} + +pub fn show_preprocessor_version<F>(f: &mut F, pv: &syntax::PreprocessorVersion) +where + F: Write, +{ + let _ = write!(f, "#version {}", pv.version); + + if let Some(ref profile) = pv.profile { + match *profile { + syntax::PreprocessorVersionProfile::Core => { + let _ = f.write_str(" core"); + } + syntax::PreprocessorVersionProfile::Compatibility => { + let _ = f.write_str(" compatibility"); + } + syntax::PreprocessorVersionProfile::ES => { + let _ = f.write_str(" es"); + } + } + } + + let _ = f.write_str("\n"); +} + +pub fn show_preprocessor_extension<F>(f: &mut F, pe: &syntax::PreprocessorExtension) +where + F: Write, +{ + let _ = f.write_str("#extension "); + + match pe.name { + syntax::PreprocessorExtensionName::All => { + let _ = f.write_str("all"); + } + syntax::PreprocessorExtensionName::Specific(ref n) => { + let _ = f.write_str(n); + } + } + + if let Some(ref behavior) = pe.behavior { + match *behavior { + syntax::PreprocessorExtensionBehavior::Require => { + let _ = f.write_str(" : require"); + } + syntax::PreprocessorExtensionBehavior::Enable => { + let _ = f.write_str(" : enable"); + } + syntax::PreprocessorExtensionBehavior::Warn => { + let _ = f.write_str(" : warn"); + } + syntax::PreprocessorExtensionBehavior::Disable => { + let _ = f.write_str(" : disable"); + } + } + } + + let _ = f.write_str("\n"); +} + +pub fn show_external_declaration<F>(f: &mut F, ed: &syntax::ExternalDeclaration) +where + F: Write, +{ + match *ed { + syntax::ExternalDeclaration::Preprocessor(ref pp) => show_preprocessor(f, pp), + syntax::ExternalDeclaration::FunctionDefinition(ref fd) => show_function_definition(f, fd), + syntax::ExternalDeclaration::Declaration(ref d) => show_declaration(f, d), + } +} + +pub fn show_translation_unit<F>(f: &mut F, tu: &syntax::TranslationUnit) +where + F: Write, +{ + for ed in &(tu.0).0 { + show_external_declaration(f, ed); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::parsers::expr; + + fn to_string(e: &syntax::Expr) -> String { + let mut s = String::new(); + show_expr(&mut s, e); + s + } + + #[test] + fn unary_parentheses() { + assert_eq!(to_string(&expr("-a").unwrap().1), "-a"); + assert_eq!(to_string(&expr("-(a + b)").unwrap().1), "-(a+b)"); + assert_eq!(to_string(&expr("-a.x").unwrap().1), "-a.x"); + + assert_eq!(to_string(&expr("-(-a)").unwrap().1), "-(-a)"); + assert_eq!(to_string(&expr("+(+a)").unwrap().1), "+(+a)"); + assert_eq!(to_string(&expr("~~a").unwrap().1), "~~a"); + assert_eq!(to_string(&expr("--a").unwrap().1), "--a"); + assert_eq!(to_string(&expr("++a").unwrap().1), "++a"); + assert_eq!(to_string(&expr("+-a").unwrap().1), "+-a"); + } + + #[test] + fn binary_parentheses() { + assert_eq!(to_string(&expr("a + b").unwrap().1), "a+b"); + assert_eq!(to_string(&expr("a * b + c").unwrap().1), "a*b+c"); + assert_eq!(to_string(&expr("(a + b) * c").unwrap().1), "(a+b)*c"); + assert_eq!(to_string(&expr("a + (b * c)").unwrap().1), "a+b*c"); + assert_eq!(to_string(&expr("a * (b + c)").unwrap().1), "a*(b+c)"); + assert_eq!(to_string(&expr("(a * b) * c").unwrap().1), "a*b*c"); + assert_eq!(to_string(&expr("a * (b * c)").unwrap().1), "a*(b*c)"); + assert_eq!(to_string(&expr("a&&b&&c").unwrap().1), "a&&b&&c"); + assert_eq!( + to_string(&expr("n - p > 0. && u.y < n && u.y > p").unwrap().1), + "n-p>0.&&u.y<n&&u.y>p" + ); + } + + #[test] + fn ternary_parentheses() { + assert_eq!( + to_string(&expr("a ? b : c ? d : e").unwrap().1), + "a ? b : c ? d : e" + ); + assert_eq!( + to_string(&expr("(a ? b : c) ? d : e").unwrap().1), + "(a ? b : c) ? d : e" + ); + } + + #[test] + fn assignment_parentheses() { + assert_eq!(to_string(&expr("a = b = c").unwrap().1), "a = b = c"); + assert_eq!(to_string(&expr("(a = b) = c").unwrap().1), "(a = b) = c"); + } + + #[test] + fn dot_parentheses() { + assert_eq!(to_string(&expr("a.x").unwrap().1), "a.x"); + assert_eq!(to_string(&expr("(a + b).x").unwrap().1), "(a+b).x"); + } + + #[test] + fn test_parentheses() { + use crate::parsers::function_definition; + + const SRC: &'static str = r#"vec2 main() { +float n = 0.; +float p = 0.; +float u = vec2(0., 0.); +if (n-p>0.&&u.y<n&&u.y>p) { +} +return u; +} +"#; + + // Ideally we would use SRC as the expected, but there's a bug in block braces generation + const DST: &'static str = r#"vec2 main() { +float n = 0.; +float p = 0.; +float u = vec2(0., 0.); +if (n-p>0.&&u.y<n&&u.y>p) { +{ +} +} +return u; +} +"#; + + let mut s = String::new(); + show_function_definition(&mut s, &function_definition(SRC).unwrap().1); + + assert_eq!(s, DST); + } + + #[test] + fn roundtrip_glsl_complex_expr() { + let zero = syntax::Expr::DoubleConst(0.); + let ray = syntax::Expr::Variable("ray".into()); + let raydir = syntax::Expr::Dot(Box::new(ray), "dir".into()); + let vec4 = syntax::Expr::FunCall( + syntax::FunIdentifier::Identifier("vec4".into()), + vec![raydir, zero], + ); + let view = syntax::Expr::Variable("view".into()); + let iview = syntax::Expr::FunCall( + syntax::FunIdentifier::Identifier("inverse".into()), + vec![view], + ); + let mul = syntax::Expr::Binary(syntax::BinaryOp::Mult, Box::new(iview), Box::new(vec4)); + let xyz = syntax::Expr::Dot(Box::new(mul), "xyz".into()); + let input = syntax::Expr::FunCall( + syntax::FunIdentifier::Identifier("normalize".into()), + vec![xyz], + ); + + let mut output = String::new(); + show_expr(&mut output, &input); + let _ = output.write_str(";"); + + let back = expr(&output); + + assert_eq!(back, Ok((";", input)), "intermediate source '{}'", output); + } +} diff --git a/third_party/rust/glsl/src/transpiler/mod.rs b/third_party/rust/glsl/src/transpiler/mod.rs new file mode 100644 index 0000000000..cbb7d78190 --- /dev/null +++ b/third_party/rust/glsl/src/transpiler/mod.rs @@ -0,0 +1,8 @@ +//! GLSL transpilers – i.e. going from GLSL to anything else. +//! +//! There’s no public interface / trait to define what a transpiler is. It depends on the target +//! representation you aim. + +pub mod glsl; +#[cfg(feature = "spirv")] +pub mod spirv; diff --git a/third_party/rust/glsl/src/transpiler/spirv.rs b/third_party/rust/glsl/src/transpiler/spirv.rs new file mode 100644 index 0000000000..a75f3afab6 --- /dev/null +++ b/third_party/rust/glsl/src/transpiler/spirv.rs @@ -0,0 +1,95 @@ +//! SPIR-V transpiler. +//! +//! The current implementation uses the [shaderc](https://crates.io/crates/shaderc) crate to +//! transpile GLSL to SPIR-V. This is not ideal but will provide a default and starting +//! implementation. + +use shaderc; + +use crate::syntax; +use crate::transpiler::glsl as glsl_transpiler; + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum ShaderKind { + TessControl, + TessEvaluation, + Vertex, + Geometry, + Fragment, + Compute, +} + +impl From<ShaderKind> for shaderc::ShaderKind { + fn from(kind: ShaderKind) -> Self { + match kind { + ShaderKind::TessControl => shaderc::ShaderKind::TessControl, + ShaderKind::TessEvaluation => shaderc::ShaderKind::TessEvaluation, + ShaderKind::Vertex => shaderc::ShaderKind::Vertex, + ShaderKind::Geometry => shaderc::ShaderKind::Geometry, + ShaderKind::Fragment => shaderc::ShaderKind::Fragment, + ShaderKind::Compute => shaderc::ShaderKind::Compute, + } + } +} + +/// Transpile a GLSL AST into a SPIR-V internal buffer and write it to the given buffer. +/// +/// The current implementation is highly inefficient as it relies on internal allocations and +/// [shaderc](https://crates.io/crates/shaderc). +/// +/// If any error happens while transpiling, they’re returned as an opaque string. +pub fn transpile_translation_unit_to_binary<F>( + f: &mut F, + tu: &syntax::TranslationUnit, + kind: ShaderKind, +) -> Result<(), String> +where + F: std::io::Write, +{ + // write as GLSL in an intermediate buffer + let mut glsl_buffer = String::new(); + glsl_transpiler::show_translation_unit(&mut glsl_buffer, tu); + + // pass the GLSL-formatted string to shaderc + let mut compiler = shaderc::Compiler::new().unwrap(); + let options = shaderc::CompileOptions::new().unwrap(); + let kind = kind.into(); + let output = compiler + .compile_into_spirv(&glsl_buffer, kind, "glsl input", "main", Some(&options)) + .map_err(|e| format!("{}", e))?; + + let _ = f.write_all(output.as_binary_u8()); + + Ok(()) +} + +/// Transpile a GLSL AST into a SPIR-V internal buffer and write it to the given buffer. +/// +/// The current implementation is highly inefficient as it relies on internal allocations and +/// [shaderc](https://crates.io/crates/shaderc). +/// +/// If any error happens while transpiling, they’re returned as an opaque string. +pub fn transpile_translation_unit<F>( + f: &mut F, + tu: &syntax::TranslationUnit, + kind: ShaderKind, +) -> Result<(), String> +where + F: std::fmt::Write, +{ + // write as GLSL in an intermediate buffer + let mut glsl_buffer = String::new(); + glsl_transpiler::show_translation_unit(&mut glsl_buffer, tu); + + // pass the GLSL-formatted string to shaderc + let mut compiler = shaderc::Compiler::new().unwrap(); + let options = shaderc::CompileOptions::new().unwrap(); + let kind = kind.into(); + let output = compiler + .compile_into_spirv_assembly(&glsl_buffer, kind, "glsl input", "main", Some(&options)) + .map_err(|e| format!("{}", e))?; + + let _ = f.write_str(&output.as_text()); + + Ok(()) +} |