diff options
Diffstat (limited to 'third_party/rust/naga/src/front/glsl/parser_tests.rs')
-rw-r--r-- | third_party/rust/naga/src/front/glsl/parser_tests.rs | 858 |
1 files changed, 858 insertions, 0 deletions
diff --git a/third_party/rust/naga/src/front/glsl/parser_tests.rs b/third_party/rust/naga/src/front/glsl/parser_tests.rs new file mode 100644 index 0000000000..259052cd27 --- /dev/null +++ b/third_party/rust/naga/src/front/glsl/parser_tests.rs @@ -0,0 +1,858 @@ +use super::{ + ast::Profile, + error::ExpectedToken, + error::{Error, ErrorKind, ParseError}, + token::TokenValue, + Frontend, Options, Span, +}; +use crate::ShaderStage; +use pp_rs::token::PreprocessorError; + +#[test] +fn version() { + let mut frontend = Frontend::default(); + + // invalid versions + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + "#version 99000\n void main(){}", + ) + .err() + .unwrap(), + ParseError { + errors: vec![Error { + kind: ErrorKind::InvalidVersion(99000), + meta: Span::new(9, 14) + }], + }, + ); + + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + "#version 449\n void main(){}", + ) + .err() + .unwrap(), + ParseError { + errors: vec![Error { + kind: ErrorKind::InvalidVersion(449), + meta: Span::new(9, 12) + }] + }, + ); + + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + "#version 450 smart\n void main(){}", + ) + .err() + .unwrap(), + ParseError { + errors: vec![Error { + kind: ErrorKind::InvalidProfile("smart".into()), + meta: Span::new(13, 18), + }] + }, + ); + + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + "#version 450\nvoid main(){} #version 450", + ) + .err() + .unwrap(), + ParseError { + errors: vec![ + Error { + kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,), + meta: Span::new(27, 28), + }, + Error { + kind: ErrorKind::InvalidToken( + TokenValue::Identifier("version".into()), + vec![ExpectedToken::Eof] + ), + meta: Span::new(28, 35) + } + ] + }, + ); + + // valid versions + frontend + .parse( + &Options::from(ShaderStage::Vertex), + " # version 450\nvoid main() {}", + ) + .unwrap(); + assert_eq!( + (frontend.metadata().version, frontend.metadata().profile), + (450, Profile::Core) + ); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + "#version 450\nvoid main() {}", + ) + .unwrap(); + assert_eq!( + (frontend.metadata().version, frontend.metadata().profile), + (450, Profile::Core) + ); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + "#version 450 core\nvoid main(void) {}", + ) + .unwrap(); + assert_eq!( + (frontend.metadata().version, frontend.metadata().profile), + (450, Profile::Core) + ); +} + +#[test] +fn control_flow() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + if (true) { + return 1; + } else { + return 2; + } + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + if (true) { + return 1; + } + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + int x; + int y = 3; + switch (5) { + case 2: + x = 2; + case 5: + x = 5; + y = 2; + break; + default: + x = 0; + } + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + int x = 0; + while(x < 5) { + x = x + 1; + } + do { + x = x - 1; + } while(x >= 4) + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + int x = 0; + for(int i = 0; i < 10;) { + x = x + 2; + } + for(;;); + return x; + } + "#, + ) + .unwrap(); +} + +#[test] +fn declarations() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + layout(location = 0) in vec2 v_uv; + layout(location = 0) out vec4 o_color; + layout(set = 1, binding = 1) uniform texture2D tex; + layout(set = 1, binding = 2) uniform sampler tex_sampler; + + layout(early_fragment_tests) in; + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + layout(std140, set = 2, binding = 0) + uniform u_locals { + vec3 model_offs; + float load_time; + ivec4 atlas_offs; + }; + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + layout(push_constant) + uniform u_locals { + vec3 model_offs; + float load_time; + ivec4 atlas_offs; + }; + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + layout(std430, set = 2, binding = 0) + uniform u_locals { + vec3 model_offs; + float load_time; + ivec4 atlas_offs; + }; + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + layout(std140, set = 2, binding = 0) + uniform u_locals { + vec3 model_offs; + float load_time; + } block_var; + + void main() { + load_time * model_offs; + block_var.load_time * block_var.model_offs; + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + float vector = vec4(1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0); + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + precision highp float; + + void main() {} + "#, + ) + .unwrap(); +} + +#[test] +fn textures() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + #version 450 + layout(location = 0) in vec2 v_uv; + layout(location = 0) out vec4 o_color; + layout(set = 1, binding = 1) uniform texture2D tex; + layout(set = 1, binding = 2) uniform sampler tex_sampler; + void main() { + o_color = texture(sampler2D(tex, tex_sampler), v_uv); + o_color.a = texture(sampler2D(tex, tex_sampler), v_uv, 2.0).a; + } + "#, + ) + .unwrap(); +} + +#[test] +fn functions() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void test1(float); + void test1(float) {} + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void test2(float a) {} + void test3(float a, float b) {} + void test4(float, float) {} + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + float test(float a) { return a; } + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + float test(vec4 p) { + return p.x; + } + + void main() {} + "#, + ) + .unwrap(); + + // Function overloading + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + float test(vec2 p); + float test(vec3 p); + float test(vec4 p); + + float test(vec2 p) { + return p.x; + } + + float test(vec3 p) { + return p.x; + } + + float test(vec4 p) { + return p.x; + } + + void main() {} + "#, + ) + .unwrap(); + + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + int test(vec4 p) { + return p.x; + } + + float test(vec4 p) { + return p.x; + } + + void main() {} + "#, + ) + .err() + .unwrap(), + ParseError { + errors: vec![Error { + kind: ErrorKind::SemanticError("Function already defined".into()), + meta: Span::new(134, 152), + }] + }, + ); + + println!(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + float callee(uint q) { + return float(q); + } + + float caller() { + callee(1u); + } + + void main() {} + "#, + ) + .unwrap(); + + // Nested function call + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + layout(set = 0, binding = 1) uniform texture2D t_noise; + layout(set = 0, binding = 2) uniform sampler s_noise; + + void main() { + textureLod(sampler2D(t_noise, s_noise), vec2(1.0), 0); + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void fun(vec2 in_parameter, out float out_parameter) { + ivec2 _ = ivec2(in_parameter); + } + + void main() { + float a; + fun(vec2(1.0), a); + } + "#, + ) + .unwrap(); +} + +#[test] +fn constants() { + use crate::{Constant, Expression, Type, TypeInner}; + + let mut frontend = Frontend::default(); + + let module = frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + const float a = 1.0; + float global = a; + const float b = a; + + void main() {} + "#, + ) + .unwrap(); + + let mut types = module.types.iter(); + let mut constants = module.constants.iter(); + let mut const_expressions = module.const_expressions.iter(); + + let (ty_handle, ty) = types.next().unwrap(); + assert_eq!( + ty, + &Type { + name: None, + inner: TypeInner::Scalar(crate::Scalar::F32) + } + ); + + let (init_handle, init) = const_expressions.next().unwrap(); + assert_eq!(init, &Expression::Literal(crate::Literal::F32(1.0))); + + assert_eq!( + constants.next().unwrap().1, + &Constant { + name: Some("a".to_owned()), + r#override: crate::Override::None, + ty: ty_handle, + init: init_handle + } + ); + + assert_eq!( + constants.next().unwrap().1, + &Constant { + name: Some("b".to_owned()), + r#override: crate::Override::None, + ty: ty_handle, + init: init_handle + } + ); + + assert!(constants.next().is_none()); +} + +#[test] +fn function_overloading() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + + float saturate(float v) { return clamp(v, 0.0, 1.0); } + vec2 saturate(vec2 v) { return clamp(v, vec2(0.0), vec2(1.0)); } + vec3 saturate(vec3 v) { return clamp(v, vec3(0.0), vec3(1.0)); } + vec4 saturate(vec4 v) { return clamp(v, vec4(0.0), vec4(1.0)); } + + void main() { + float v1 = saturate(1.5); + vec2 v2 = saturate(vec2(0.5, 1.5)); + vec3 v3 = saturate(vec3(0.5, 1.5, 2.5)); + vec3 v4 = saturate(vec4(0.5, 1.5, 2.5, 3.5)); + } + "#, + ) + .unwrap(); +} + +#[test] +fn implicit_conversions() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + mat4 a = mat4(1); + float b = 1u; + float c = 1 + 2.0; + } + "#, + ) + .unwrap(); + + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void test(int a) {} + void test(uint a) {} + + void main() { + test(1.0); + } + "#, + ) + .err() + .unwrap(), + ParseError { + errors: vec![Error { + kind: ErrorKind::SemanticError("Unknown function \'test\'".into()), + meta: Span::new(156, 165), + }] + }, + ); + + assert_eq!( + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void test(float a) {} + void test(uint a) {} + + void main() { + test(1); + } + "#, + ) + .err() + .unwrap(), + ParseError { + errors: vec![Error { + kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()), + meta: Span::new(158, 165), + }] + } + ); +} + +#[test] +fn structs() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + Test { + vec4 pos; + } xx; + + void main() {} + "#, + ) + .unwrap_err(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + struct Test { + vec4 pos; + }; + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + const int NUM_VECS = 42; + struct Test { + vec4 vecs[NUM_VECS]; + }; + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + struct Hello { + vec4 test; + } test() { + return Hello( vec4(1.0) ); + } + + void main() {} + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + struct Test {}; + + void main() {} + "#, + ) + .unwrap_err(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + inout struct Test { + vec4 x; + }; + + void main() {} + "#, + ) + .unwrap_err(); +} + +#[test] +fn swizzles() { + let mut frontend = Frontend::default(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + vec4 v = vec4(1); + v.xyz = vec3(2); + v.x = 5.0; + v.xyz.zxy.yx.xy = vec2(5.0, 1.0); + } + "#, + ) + .unwrap(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + vec4 v = vec4(1); + v.xx = vec2(5.0); + } + "#, + ) + .unwrap_err(); + + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + vec3 v = vec3(1); + v.w = 2.0; + } + "#, + ) + .unwrap_err(); +} + +#[test] +fn expressions() { + let mut frontend = Frontend::default(); + + // Vector indexing + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + float test(int index) { + vec4 v = vec4(1.0, 2.0, 3.0, 4.0); + return v[index] + 1.0; + } + + void main() {} + "#, + ) + .unwrap(); + + // Prefix increment/decrement + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + uint index = 0; + + --index; + ++index; + } + "#, + ) + .unwrap(); + + // Dynamic indexing of array + frontend + .parse( + &Options::from(ShaderStage::Vertex), + r#" + # version 450 + void main() { + const vec4 positions[1] = { vec4(0) }; + + gl_Position = positions[gl_VertexIndex]; + } + "#, + ) + .unwrap(); +} |