summaryrefslogtreecommitdiffstats
path: root/third_party/rust/glsl/src/parse_tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/glsl/src/parse_tests.rs')
-rw-r--r--third_party/rust/glsl/src/parse_tests.rs2847
1 files changed, 2847 insertions, 0 deletions
diff --git a/third_party/rust/glsl/src/parse_tests.rs b/third_party/rust/glsl/src/parse_tests.rs
new file mode 100644
index 0000000000..3a2c7a6880
--- /dev/null
+++ b/third_party/rust/glsl/src/parse_tests.rs
@@ -0,0 +1,2847 @@
+use crate::parsers::*;
+use crate::syntax;
+
+#[test]
+fn parse_uniline_comment() {
+ assert_eq!(comment("// lol"), Ok(("", " lol")));
+ assert_eq!(comment("// lol\nfoo"), Ok(("foo", " lol")));
+ assert_eq!(comment("// lol\\\nfoo"), Ok(("", " lol\\\nfoo")));
+ assert_eq!(
+ comment("// lol \\\n foo\n"),
+ Ok(("", " lol \\\n foo"))
+ );
+}
+
+#[test]
+fn parse_multiline_comment() {
+ assert_eq!(comment("/* lol\nfoo\n*/bar"), Ok(("bar", " lol\nfoo\n")));
+}
+
+#[test]
+fn parse_unsigned_suffix() {
+ assert_eq!(unsigned_suffix("u"), Ok(("", 'u')));
+ assert_eq!(unsigned_suffix("U"), Ok(("", 'U')));
+}
+
+#[test]
+fn parse_nonzero_digits() {
+ assert_eq!(nonzero_digits("3"), Ok(("", "3")));
+ assert_eq!(nonzero_digits("12345953"), Ok(("", "12345953")));
+}
+
+#[test]
+fn parse_decimal_lit() {
+ assert_eq!(decimal_lit("3"), Ok(("", Ok(3))));
+ assert_eq!(decimal_lit("3"), Ok(("", Ok(3))));
+ assert_eq!(decimal_lit("13"), Ok(("", Ok(13))));
+ assert_eq!(decimal_lit("42"), Ok(("", Ok(42))));
+ assert_eq!(decimal_lit("123456"), Ok(("", Ok(123456))));
+}
+
+#[test]
+fn parse_octal_lit() {
+ assert_eq!(octal_lit("0"), Ok(("", Ok(0o0))));
+ assert_eq!(octal_lit("03 "), Ok((" ", Ok(0o3))));
+ assert_eq!(octal_lit("012 "), Ok((" ", Ok(0o12))));
+ assert_eq!(octal_lit("07654321 "), Ok((" ", Ok(0o7654321))));
+}
+
+#[test]
+fn parse_hexadecimal_lit() {
+ assert_eq!(hexadecimal_lit("0x3 "), Ok((" ", Ok(0x3))));
+ assert_eq!(hexadecimal_lit("0x0123789"), Ok(("", Ok(0x0123789))));
+ assert_eq!(hexadecimal_lit("0xABCDEF"), Ok(("", Ok(0xabcdef))));
+ assert_eq!(hexadecimal_lit("0xabcdef"), Ok(("", Ok(0xabcdef))));
+}
+
+#[test]
+fn parse_integral_lit() {
+ assert_eq!(integral_lit("0"), Ok(("", 0)));
+ assert_eq!(integral_lit("3"), Ok(("", 3)));
+ assert_eq!(integral_lit("3 "), Ok((" ", 3)));
+ assert_eq!(integral_lit("03 "), Ok((" ", 3)));
+ assert_eq!(integral_lit("076556 "), Ok((" ", 0o76556)));
+ assert_eq!(integral_lit("012 "), Ok((" ", 0o12)));
+ assert_eq!(integral_lit("0x3 "), Ok((" ", 0x3)));
+ assert_eq!(integral_lit("0x9ABCDEF"), Ok(("", 0x9ABCDEF)));
+ assert_eq!(integral_lit("0x9ABCDEF"), Ok(("", 0x9ABCDEF)));
+ assert_eq!(integral_lit("0x9abcdef"), Ok(("", 0x9abcdef)));
+ assert_eq!(integral_lit("0x9abcdef"), Ok(("", 0x9abcdef)));
+ assert_eq!(integral_lit("0xffffffff"), Ok(("", 0xffffffffu32 as i32)));
+}
+
+#[test]
+fn parse_integral_neg_lit() {
+ assert_eq!(integral_lit("-3"), Ok(("", -3)));
+ assert_eq!(integral_lit("-3 "), Ok((" ", -3)));
+ assert_eq!(integral_lit("-03 "), Ok((" ", -3)));
+ assert_eq!(integral_lit("-076556 "), Ok((" ", -0o76556)));
+ assert_eq!(integral_lit("-012 "), Ok((" ", -0o12)));
+ assert_eq!(integral_lit("-0x3 "), Ok((" ", -0x3)));
+ assert_eq!(integral_lit("-0x9ABCDEF"), Ok(("", -0x9ABCDEF)));
+ assert_eq!(integral_lit("-0x9ABCDEF"), Ok(("", -0x9ABCDEF)));
+ assert_eq!(integral_lit("-0x9abcdef"), Ok(("", -0x9abcdef)));
+ assert_eq!(integral_lit("-0x9abcdef"), Ok(("", -0x9abcdef)));
+}
+
+#[test]
+fn parse_unsigned_lit() {
+ assert_eq!(unsigned_lit("0xffffffffU"), Ok(("", 0xffffffff as u32)));
+ assert_eq!(unsigned_lit("-1u"), Ok(("", 0xffffffff as u32)));
+ assert!(unsigned_lit("0xfffffffffU").is_err());
+}
+
+#[test]
+fn parse_float_lit() {
+ assert_eq!(float_lit("0.;"), Ok((";", 0.)));
+ assert_eq!(float_lit(".0;"), Ok((";", 0.)));
+ assert_eq!(float_lit(".035 "), Ok((" ", 0.035)));
+ assert_eq!(float_lit("0. "), Ok((" ", 0.)));
+ assert_eq!(float_lit("0.035 "), Ok((" ", 0.035)));
+ assert_eq!(float_lit(".035f"), Ok(("", 0.035)));
+ assert_eq!(float_lit("0.f"), Ok(("", 0.)));
+ assert_eq!(float_lit("314.f"), Ok(("", 314.)));
+ assert_eq!(float_lit("0.035f"), Ok(("", 0.035)));
+ assert_eq!(float_lit(".035F"), Ok(("", 0.035)));
+ assert_eq!(float_lit("0.F"), Ok(("", 0.)));
+ assert_eq!(float_lit("0.035F"), Ok(("", 0.035)));
+ assert_eq!(float_lit("1.03e+34 "), Ok((" ", 1.03e+34)));
+ assert_eq!(float_lit("1.03E+34 "), Ok((" ", 1.03E+34)));
+ assert_eq!(float_lit("1.03e-34 "), Ok((" ", 1.03e-34)));
+ assert_eq!(float_lit("1.03E-34 "), Ok((" ", 1.03E-34)));
+ assert_eq!(float_lit("1.03e+34f"), Ok(("", 1.03e+34)));
+ assert_eq!(float_lit("1.03E+34f"), Ok(("", 1.03E+34)));
+ assert_eq!(float_lit("1.03e-34f"), Ok(("", 1.03e-34)));
+ assert_eq!(float_lit("1.03E-34f"), Ok(("", 1.03E-34)));
+ assert_eq!(float_lit("1.03e+34F"), Ok(("", 1.03e+34)));
+ assert_eq!(float_lit("1.03E+34F"), Ok(("", 1.03E+34)));
+ assert_eq!(float_lit("1.03e-34F"), Ok(("", 1.03e-34)));
+ assert_eq!(float_lit("1.03E-34F"), Ok(("", 1.03E-34)));
+}
+
+#[test]
+fn parse_float_neg_lit() {
+ assert_eq!(float_lit("-.035 "), Ok((" ", -0.035)));
+ assert_eq!(float_lit("-0. "), Ok((" ", -0.)));
+ assert_eq!(float_lit("-0.035 "), Ok((" ", -0.035)));
+ assert_eq!(float_lit("-.035f"), Ok(("", -0.035)));
+ assert_eq!(float_lit("-0.f"), Ok(("", -0.)));
+ assert_eq!(float_lit("-0.035f"), Ok(("", -0.035)));
+ assert_eq!(float_lit("-.035F"), Ok(("", -0.035)));
+ assert_eq!(float_lit("-0.F"), Ok(("", -0.)));
+ assert_eq!(float_lit("-0.035F"), Ok(("", -0.035)));
+ assert_eq!(float_lit("-1.03e+34 "), Ok((" ", -1.03e+34)));
+ assert_eq!(float_lit("-1.03E+34 "), Ok((" ", -1.03E+34)));
+ assert_eq!(float_lit("-1.03e-34 "), Ok((" ", -1.03e-34)));
+ assert_eq!(float_lit("-1.03E-34 "), Ok((" ", -1.03E-34)));
+ assert_eq!(float_lit("-1.03e+34f"), Ok(("", -1.03e+34)));
+ assert_eq!(float_lit("-1.03E+34f"), Ok(("", -1.03E+34)));
+ assert_eq!(float_lit("-1.03e-34f"), Ok(("", -1.03e-34)));
+ assert_eq!(float_lit("-1.03E-34f"), Ok(("", -1.03E-34)));
+ assert_eq!(float_lit("-1.03e+34F"), Ok(("", -1.03e+34)));
+ assert_eq!(float_lit("-1.03E+34F"), Ok(("", -1.03E+34)));
+ assert_eq!(float_lit("-1.03e-34F"), Ok(("", -1.03e-34)));
+ assert_eq!(float_lit("-1.03E-34F"), Ok(("", -1.03E-34)));
+}
+
+#[test]
+fn parse_double_lit() {
+ assert_eq!(double_lit("0.;"), Ok((";", 0.)));
+ assert_eq!(double_lit(".0;"), Ok((";", 0.)));
+ assert_eq!(double_lit(".035 "), Ok((" ", 0.035)));
+ assert_eq!(double_lit("0. "), Ok((" ", 0.)));
+ assert_eq!(double_lit("0.035 "), Ok((" ", 0.035)));
+ assert_eq!(double_lit("0.lf"), Ok(("", 0.)));
+ assert_eq!(double_lit("0.035lf"), Ok(("", 0.035)));
+ assert_eq!(double_lit(".035lf"), Ok(("", 0.035)));
+ assert_eq!(double_lit(".035LF"), Ok(("", 0.035)));
+ assert_eq!(double_lit("0.LF"), Ok(("", 0.)));
+ assert_eq!(double_lit("0.035LF"), Ok(("", 0.035)));
+ assert_eq!(double_lit("1.03e+34lf"), Ok(("", 1.03e+34)));
+ assert_eq!(double_lit("1.03E+34lf"), Ok(("", 1.03E+34)));
+ assert_eq!(double_lit("1.03e-34lf"), Ok(("", 1.03e-34)));
+ assert_eq!(double_lit("1.03E-34lf"), Ok(("", 1.03E-34)));
+ assert_eq!(double_lit("1.03e+34LF"), Ok(("", 1.03e+34)));
+ assert_eq!(double_lit("1.03E+34LF"), Ok(("", 1.03E+34)));
+ assert_eq!(double_lit("1.03e-34LF"), Ok(("", 1.03e-34)));
+ assert_eq!(double_lit("1.03E-34LF"), Ok(("", 1.03E-34)));
+}
+
+#[test]
+fn parse_double_neg_lit() {
+ assert_eq!(double_lit("-0.;"), Ok((";", -0.)));
+ assert_eq!(double_lit("-.0;"), Ok((";", -0.)));
+ assert_eq!(double_lit("-.035 "), Ok((" ", -0.035)));
+ assert_eq!(double_lit("-0. "), Ok((" ", -0.)));
+ assert_eq!(double_lit("-0.035 "), Ok((" ", -0.035)));
+ assert_eq!(double_lit("-0.lf"), Ok(("", -0.)));
+ assert_eq!(double_lit("-0.035lf"), Ok(("", -0.035)));
+ assert_eq!(double_lit("-.035lf"), Ok(("", -0.035)));
+ assert_eq!(double_lit("-.035LF"), Ok(("", -0.035)));
+ assert_eq!(double_lit("-0.LF"), Ok(("", -0.)));
+ assert_eq!(double_lit("-0.035LF"), Ok(("", -0.035)));
+ assert_eq!(double_lit("-1.03e+34lf"), Ok(("", -1.03e+34)));
+ assert_eq!(double_lit("-1.03E+34lf"), Ok(("", -1.03E+34)));
+ assert_eq!(double_lit("-1.03e-34lf"), Ok(("", -1.03e-34)));
+ assert_eq!(double_lit("-1.03E-34lf"), Ok(("", -1.03E-34)));
+ assert_eq!(double_lit("-1.03e+34LF"), Ok(("", -1.03e+34)));
+ assert_eq!(double_lit("-1.03E+34LF"), Ok(("", -1.03E+34)));
+ assert_eq!(double_lit("-1.03e-34LF"), Ok(("", -1.03e-34)));
+ assert_eq!(double_lit("-1.03E-34LF"), Ok(("", -1.03E-34)));
+}
+
+#[test]
+fn parse_bool_lit() {
+ assert_eq!(bool_lit("false"), Ok(("", false)));
+ assert_eq!(bool_lit("true"), Ok(("", true)));
+}
+
+#[test]
+fn parse_identifier() {
+ assert_eq!(identifier("a"), Ok(("", "a".into())));
+ assert_eq!(identifier("ab_cd"), Ok(("", "ab_cd".into())));
+ assert_eq!(identifier("Ab_cd"), Ok(("", "Ab_cd".into())));
+ assert_eq!(identifier("Ab_c8d"), Ok(("", "Ab_c8d".into())));
+ assert_eq!(identifier("Ab_c8d9"), Ok(("", "Ab_c8d9".into())));
+}
+
+#[test]
+fn parse_unary_op_add() {
+ assert_eq!(unary_op("+ "), Ok((" ", syntax::UnaryOp::Add)));
+}
+
+#[test]
+fn parse_unary_op_minus() {
+ assert_eq!(unary_op("- "), Ok((" ", syntax::UnaryOp::Minus)));
+}
+
+#[test]
+fn parse_unary_op_not() {
+ assert_eq!(unary_op("!"), Ok(("", syntax::UnaryOp::Not)));
+}
+
+#[test]
+fn parse_unary_op_complement() {
+ assert_eq!(unary_op("~"), Ok(("", syntax::UnaryOp::Complement)));
+}
+
+#[test]
+fn parse_unary_op_inc() {
+ assert_eq!(unary_op("++"), Ok(("", syntax::UnaryOp::Inc)));
+}
+
+#[test]
+fn parse_unary_op_dec() {
+ assert_eq!(unary_op("--"), Ok(("", syntax::UnaryOp::Dec)));
+}
+
+#[test]
+fn parse_array_specifier_dimension_unsized() {
+ assert_eq!(
+ array_specifier_dimension("[]"),
+ Ok(("", syntax::ArraySpecifierDimension::Unsized))
+ );
+ assert_eq!(
+ array_specifier_dimension("[ ]"),
+ Ok(("", syntax::ArraySpecifierDimension::Unsized))
+ );
+ assert_eq!(
+ array_specifier_dimension("[\n]"),
+ Ok(("", syntax::ArraySpecifierDimension::Unsized))
+ );
+}
+
+#[test]
+fn parse_array_specifier_dimension_sized() {
+ let ix = syntax::Expr::IntConst(0);
+
+ assert_eq!(
+ array_specifier_dimension("[0]"),
+ Ok((
+ "",
+ syntax::ArraySpecifierDimension::ExplicitlySized(Box::new(ix.clone()))
+ ))
+ );
+ assert_eq!(
+ array_specifier_dimension("[\n0 \t]"),
+ Ok((
+ "",
+ syntax::ArraySpecifierDimension::ExplicitlySized(Box::new(ix))
+ ))
+ );
+}
+
+#[test]
+fn parse_array_specifier_unsized() {
+ assert_eq!(
+ array_specifier("[]"),
+ Ok((
+ "",
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::Unsized])
+ }
+ ))
+ )
+}
+
+#[test]
+fn parse_array_specifier_sized() {
+ let ix = syntax::Expr::IntConst(123);
+
+ assert_eq!(
+ array_specifier("[123]"),
+ Ok((
+ "",
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::ExplicitlySized(
+ Box::new(ix)
+ )])
+ }
+ ))
+ )
+}
+
+#[test]
+fn parse_array_specifier_sized_multiple() {
+ let a = syntax::Expr::IntConst(2);
+ let b = syntax::Expr::IntConst(100);
+ let d = syntax::Expr::IntConst(5);
+
+ assert_eq!(
+ array_specifier("[2][100][][5]"),
+ Ok((
+ "",
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![
+ syntax::ArraySpecifierDimension::ExplicitlySized(Box::new(a)),
+ syntax::ArraySpecifierDimension::ExplicitlySized(Box::new(b)),
+ syntax::ArraySpecifierDimension::Unsized,
+ syntax::ArraySpecifierDimension::ExplicitlySized(Box::new(d)),
+ ])
+ }
+ ))
+ )
+}
+
+#[test]
+fn parse_precise_qualifier() {
+ assert_eq!(precise_qualifier("precise "), Ok((" ", ())));
+}
+
+#[test]
+fn parse_invariant_qualifier() {
+ assert_eq!(invariant_qualifier("invariant "), Ok((" ", ())));
+}
+
+#[test]
+fn parse_interpolation_qualifier() {
+ assert_eq!(
+ interpolation_qualifier("smooth "),
+ Ok((" ", syntax::InterpolationQualifier::Smooth))
+ );
+ assert_eq!(
+ interpolation_qualifier("flat "),
+ Ok((" ", syntax::InterpolationQualifier::Flat))
+ );
+ assert_eq!(
+ interpolation_qualifier("noperspective "),
+ Ok((" ", syntax::InterpolationQualifier::NoPerspective))
+ );
+}
+
+#[test]
+fn parse_precision_qualifier() {
+ assert_eq!(
+ precision_qualifier("highp "),
+ Ok((" ", syntax::PrecisionQualifier::High))
+ );
+ assert_eq!(
+ precision_qualifier("mediump "),
+ Ok((" ", syntax::PrecisionQualifier::Medium))
+ );
+ assert_eq!(
+ precision_qualifier("lowp "),
+ Ok((" ", syntax::PrecisionQualifier::Low))
+ );
+}
+
+#[test]
+fn parse_storage_qualifier() {
+ assert_eq!(
+ storage_qualifier("const "),
+ Ok((" ", syntax::StorageQualifier::Const))
+ );
+ assert_eq!(
+ storage_qualifier("inout "),
+ Ok((" ", syntax::StorageQualifier::InOut))
+ );
+ assert_eq!(
+ storage_qualifier("in "),
+ Ok((" ", syntax::StorageQualifier::In))
+ );
+ assert_eq!(
+ storage_qualifier("out "),
+ Ok((" ", syntax::StorageQualifier::Out))
+ );
+ assert_eq!(
+ storage_qualifier("centroid "),
+ Ok((" ", syntax::StorageQualifier::Centroid))
+ );
+ assert_eq!(
+ storage_qualifier("patch "),
+ Ok((" ", syntax::StorageQualifier::Patch))
+ );
+ assert_eq!(
+ storage_qualifier("sample "),
+ Ok((" ", syntax::StorageQualifier::Sample))
+ );
+ assert_eq!(
+ storage_qualifier("uniform "),
+ Ok((" ", syntax::StorageQualifier::Uniform))
+ );
+ assert_eq!(
+ storage_qualifier("attribute "),
+ Ok((" ", syntax::StorageQualifier::Attribute))
+ );
+ assert_eq!(
+ storage_qualifier("varying "),
+ Ok((" ", syntax::StorageQualifier::Varying))
+ );
+ assert_eq!(
+ storage_qualifier("buffer "),
+ Ok((" ", syntax::StorageQualifier::Buffer))
+ );
+ assert_eq!(
+ storage_qualifier("shared "),
+ Ok((" ", syntax::StorageQualifier::Shared))
+ );
+ assert_eq!(
+ storage_qualifier("coherent "),
+ Ok((" ", syntax::StorageQualifier::Coherent))
+ );
+ assert_eq!(
+ storage_qualifier("volatile "),
+ Ok((" ", syntax::StorageQualifier::Volatile))
+ );
+ assert_eq!(
+ storage_qualifier("restrict "),
+ Ok((" ", syntax::StorageQualifier::Restrict))
+ );
+ assert_eq!(
+ storage_qualifier("readonly "),
+ Ok((" ", syntax::StorageQualifier::ReadOnly))
+ );
+ assert_eq!(
+ storage_qualifier("writeonly "),
+ Ok((" ", syntax::StorageQualifier::WriteOnly))
+ );
+ assert_eq!(
+ storage_qualifier("subroutine a"),
+ Ok((" a", syntax::StorageQualifier::Subroutine(vec![])))
+ );
+
+ let a = syntax::TypeName("vec3".to_owned());
+ let b = syntax::TypeName("float".to_owned());
+ let c = syntax::TypeName("dmat43".to_owned());
+ let types = vec![a, b, c];
+ assert_eq!(
+ storage_qualifier("subroutine ( vec3 , float \\\n, dmat43)"),
+ Ok(("", syntax::StorageQualifier::Subroutine(types)))
+ );
+}
+
+#[test]
+fn parse_layout_qualifier_std430() {
+ let expected = syntax::LayoutQualifier {
+ ids: syntax::NonEmpty(vec![syntax::LayoutQualifierSpec::Identifier(
+ "std430".into(),
+ None,
+ )]),
+ };
+
+ assert_eq!(
+ layout_qualifier("layout (std430)"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ layout_qualifier("layout (std430 )"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ layout_qualifier("layout \n\t ( std430 )"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(layout_qualifier("layout(std430)"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_layout_qualifier_shared() {
+ let expected = syntax::LayoutQualifier {
+ ids: syntax::NonEmpty(vec![syntax::LayoutQualifierSpec::Shared]),
+ };
+
+ assert_eq!(
+ layout_qualifier("layout (shared)"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ layout_qualifier("layout ( shared )"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(layout_qualifier("layout(shared)"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_layout_qualifier_list() {
+ let id_0 = syntax::LayoutQualifierSpec::Shared;
+ let id_1 = syntax::LayoutQualifierSpec::Identifier("std140".into(), None);
+ let id_2 = syntax::LayoutQualifierSpec::Identifier(
+ "max_vertices".into(),
+ Some(Box::new(syntax::Expr::IntConst(3))),
+ );
+ let expected = syntax::LayoutQualifier {
+ ids: syntax::NonEmpty(vec![id_0, id_1, id_2]),
+ };
+
+ assert_eq!(
+ layout_qualifier("layout (shared, std140, max_vertices = 3)"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ layout_qualifier("layout(shared,std140,max_vertices=3)"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ layout_qualifier("layout\n\n\t ( shared , std140, max_vertices= 3)"),
+ Ok(("", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_type_qualifier() {
+ let storage_qual = syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Const);
+ let id_0 = syntax::LayoutQualifierSpec::Shared;
+ let id_1 = syntax::LayoutQualifierSpec::Identifier("std140".into(), None);
+ let id_2 = syntax::LayoutQualifierSpec::Identifier(
+ "max_vertices".into(),
+ Some(Box::new(syntax::Expr::IntConst(3))),
+ );
+ let layout_qual = syntax::TypeQualifierSpec::Layout(syntax::LayoutQualifier {
+ ids: syntax::NonEmpty(vec![id_0, id_1, id_2]),
+ });
+ let expected = syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![storage_qual, layout_qual]),
+ };
+
+ assert_eq!(
+ type_qualifier("const layout (shared, std140, max_vertices = 3)"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ type_qualifier("const layout(shared,std140,max_vertices=3)"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_struct_field_specifier() {
+ let expected = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec4,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["foo".into()]),
+ };
+
+ assert_eq!(
+ struct_field_specifier("vec4 foo;"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ struct_field_specifier("vec4 foo ; "),
+ Ok((" ", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_struct_field_specifier_type_name() {
+ let expected = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::TypeName("S0238_3".into()),
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["x".into()]),
+ };
+
+ assert_eq!(
+ struct_field_specifier("S0238_3 x;"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ struct_field_specifier("S0238_3 x ;"),
+ Ok(("", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_struct_field_specifier_several() {
+ let expected = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec4,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["foo".into(), "bar".into(), "zoo".into()]),
+ };
+
+ assert_eq!(
+ struct_field_specifier("vec4 foo, bar, zoo;"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ struct_field_specifier("vec4 foo , bar , zoo ;"),
+ Ok(("", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_struct_specifier_one_field() {
+ let field = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec4,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["foo".into()]),
+ };
+ let expected = syntax::StructSpecifier {
+ name: Some("TestStruct".into()),
+ fields: syntax::NonEmpty(vec![field]),
+ };
+
+ assert_eq!(
+ struct_specifier("struct TestStruct { vec4 foo; }"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ struct_specifier("struct TestStruct \n \n\n {\n vec4 foo ;}"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_struct_specifier_multi_fields() {
+ let a = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec4,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["foo".into()]),
+ };
+ let b = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["bar".into()]),
+ };
+ let c = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::UInt,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["zoo".into()]),
+ };
+ let d = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::BVec3,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["foo_BAR_zoo3497_34".into()]),
+ };
+ let e = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::TypeName("S0238_3".into()),
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["x".into()]),
+ };
+ let expected = syntax::StructSpecifier {
+ name: Some("_TestStruct_934i".into()),
+ fields: syntax::NonEmpty(vec![a, b, c, d, e]),
+ };
+
+ assert_eq!(
+ struct_specifier(
+ "struct _TestStruct_934i { vec4 foo; float bar; uint zoo; bvec3 foo_BAR_zoo3497_34; S0238_3 x; }"
+ ),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ struct_specifier(
+ "struct _TestStruct_934i{vec4 foo;float bar;uint zoo;bvec3 foo_BAR_zoo3497_34;S0238_3 x;}"
+ ),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(struct_specifier("struct _TestStruct_934i\n { vec4\nfoo ; \n\t float\n\t\t bar ; \nuint zoo; \n bvec3 foo_BAR_zoo3497_34\n\n\t\n\t\n ; S0238_3 x;}"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_type_specifier_non_array() {
+ assert_eq!(
+ type_specifier_non_array("bool"),
+ Ok(("", syntax::TypeSpecifierNonArray::Bool))
+ );
+ assert_eq!(
+ type_specifier_non_array("int"),
+ Ok(("", syntax::TypeSpecifierNonArray::Int))
+ );
+ assert_eq!(
+ type_specifier_non_array("uint"),
+ Ok(("", syntax::TypeSpecifierNonArray::UInt))
+ );
+ assert_eq!(
+ type_specifier_non_array("float"),
+ Ok(("", syntax::TypeSpecifierNonArray::Float))
+ );
+ assert_eq!(
+ type_specifier_non_array("double"),
+ Ok(("", syntax::TypeSpecifierNonArray::Double))
+ );
+ assert_eq!(
+ type_specifier_non_array("vec2"),
+ Ok(("", syntax::TypeSpecifierNonArray::Vec2))
+ );
+ assert_eq!(
+ type_specifier_non_array("vec3"),
+ Ok(("", syntax::TypeSpecifierNonArray::Vec3))
+ );
+ assert_eq!(
+ type_specifier_non_array("vec4"),
+ Ok(("", syntax::TypeSpecifierNonArray::Vec4))
+ );
+ assert_eq!(
+ type_specifier_non_array("dvec2"),
+ Ok(("", syntax::TypeSpecifierNonArray::DVec2))
+ );
+ assert_eq!(
+ type_specifier_non_array("dvec3"),
+ Ok(("", syntax::TypeSpecifierNonArray::DVec3))
+ );
+ assert_eq!(
+ type_specifier_non_array("dvec4"),
+ Ok(("", syntax::TypeSpecifierNonArray::DVec4))
+ );
+ assert_eq!(
+ type_specifier_non_array("bvec2"),
+ Ok(("", syntax::TypeSpecifierNonArray::BVec2))
+ );
+ assert_eq!(
+ type_specifier_non_array("bvec3"),
+ Ok(("", syntax::TypeSpecifierNonArray::BVec3))
+ );
+ assert_eq!(
+ type_specifier_non_array("bvec4"),
+ Ok(("", syntax::TypeSpecifierNonArray::BVec4))
+ );
+ assert_eq!(
+ type_specifier_non_array("ivec2"),
+ Ok(("", syntax::TypeSpecifierNonArray::IVec2))
+ );
+ assert_eq!(
+ type_specifier_non_array("ivec3"),
+ Ok(("", syntax::TypeSpecifierNonArray::IVec3))
+ );
+ assert_eq!(
+ type_specifier_non_array("ivec4"),
+ Ok(("", syntax::TypeSpecifierNonArray::IVec4))
+ );
+ assert_eq!(
+ type_specifier_non_array("uvec2"),
+ Ok(("", syntax::TypeSpecifierNonArray::UVec2))
+ );
+ assert_eq!(
+ type_specifier_non_array("uvec3"),
+ Ok(("", syntax::TypeSpecifierNonArray::UVec3))
+ );
+ assert_eq!(
+ type_specifier_non_array("uvec4"),
+ Ok(("", syntax::TypeSpecifierNonArray::UVec4))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat2"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat2))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat3"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat3))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat4"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat4))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat2x2"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat2))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat2x3"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat23))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat2x4"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat24))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat3x2"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat32))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat3x3"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat3))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat3x4"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat34))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat4x2"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat42))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat4x3"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat43))
+ );
+ assert_eq!(
+ type_specifier_non_array("mat4x4"),
+ Ok(("", syntax::TypeSpecifierNonArray::Mat4))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat2"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat2))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat3"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat3))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat4"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat4))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat2x2"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat2))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat2x3"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat23))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat2x4"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat24))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat3x2"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat32))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat3x3"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat3))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat3x4"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat34))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat4x2"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat42))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat4x3"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat43))
+ );
+ assert_eq!(
+ type_specifier_non_array("dmat4x4"),
+ Ok(("", syntax::TypeSpecifierNonArray::DMat4))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler1D"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler1D))
+ );
+ assert_eq!(
+ type_specifier_non_array("image1D"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image1D))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2D"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2D))
+ );
+ assert_eq!(
+ type_specifier_non_array("image2D"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image2D))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler3D"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler3D))
+ );
+ assert_eq!(
+ type_specifier_non_array("image3D"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image3D))
+ );
+ assert_eq!(
+ type_specifier_non_array("samplerCube"),
+ Ok(("", syntax::TypeSpecifierNonArray::SamplerCube))
+ );
+ assert_eq!(
+ type_specifier_non_array("imageCube"),
+ Ok(("", syntax::TypeSpecifierNonArray::ImageCube))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DRect"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DRect))
+ );
+ assert_eq!(
+ type_specifier_non_array("image2DRect"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image2DRect))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler1DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler1DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("image1DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image1DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("image2DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image2DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("samplerBuffer"),
+ Ok(("", syntax::TypeSpecifierNonArray::SamplerBuffer))
+ );
+ assert_eq!(
+ type_specifier_non_array("imageBuffer"),
+ Ok(("", syntax::TypeSpecifierNonArray::ImageBuffer))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DMS"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DMS))
+ );
+ assert_eq!(
+ type_specifier_non_array("image2DMS"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image2DMS))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DMSArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DMSArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("image2DMSArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::Image2DMSArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("samplerCubeArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::SamplerCubeArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("imageCubeArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::ImageCubeArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler1DShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler1DShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DRectShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DRectShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler1DArrayShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler1DArrayShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("sampler2DArrayShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::Sampler2DArrayShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("samplerCubeShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::SamplerCubeShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("samplerCubeArrayShadow"),
+ Ok(("", syntax::TypeSpecifierNonArray::SamplerCubeArrayShadow))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler1D"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler1D))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage1D"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage1D))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler2D"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler2D))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage2D"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage2D))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler3D"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler3D))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage3D"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage3D))
+ );
+ assert_eq!(
+ type_specifier_non_array("isamplerCube"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISamplerCube))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimageCube"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImageCube))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler2DRect"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler2DRect))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage2DRect"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage2DRect))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler1DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler1DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage1DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage1DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler2DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler2DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage2DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage2DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("isamplerBuffer"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISamplerBuffer))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimageBuffer"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImageBuffer))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler2DMS"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler2DMS))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage2DMS"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage2DMS))
+ );
+ assert_eq!(
+ type_specifier_non_array("isampler2DMSArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISampler2DMSArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimage2DMSArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImage2DMSArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("isamplerCubeArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::ISamplerCubeArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("iimageCubeArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::IImageCubeArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("atomic_uint"),
+ Ok(("", syntax::TypeSpecifierNonArray::AtomicUInt))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler1D"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler1D))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage1D"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage1D))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler2D"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler2D))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage2D"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage2D))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler3D"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler3D))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage3D"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage3D))
+ );
+ assert_eq!(
+ type_specifier_non_array("usamplerCube"),
+ Ok(("", syntax::TypeSpecifierNonArray::USamplerCube))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimageCube"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImageCube))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler2DRect"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler2DRect))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage2DRect"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage2DRect))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler1DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler1DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage1DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage1DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler2DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler2DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage2DArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage2DArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("usamplerBuffer"),
+ Ok(("", syntax::TypeSpecifierNonArray::USamplerBuffer))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimageBuffer"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImageBuffer))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler2DMS"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler2DMS))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage2DMS"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage2DMS))
+ );
+ assert_eq!(
+ type_specifier_non_array("usampler2DMSArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::USampler2DMSArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimage2DMSArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImage2DMSArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("usamplerCubeArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::USamplerCubeArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("uimageCubeArray"),
+ Ok(("", syntax::TypeSpecifierNonArray::UImageCubeArray))
+ );
+ assert_eq!(
+ type_specifier_non_array("ReturnType"),
+ Ok((
+ "",
+ syntax::TypeSpecifierNonArray::TypeName(syntax::TypeName::new("ReturnType").unwrap())
+ ))
+ );
+}
+
+#[test]
+fn parse_type_specifier() {
+ assert_eq!(
+ type_specifier("uint;"),
+ Ok((
+ ";",
+ syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::UInt,
+ array_specifier: None
+ }
+ ))
+ );
+ assert_eq!(
+ type_specifier("iimage2DMSArray[35];"),
+ Ok((
+ ";",
+ syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::IImage2DMSArray,
+ array_specifier: Some(syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::ExplicitlySized(
+ Box::new(syntax::Expr::IntConst(35))
+ )])
+ })
+ }
+ ))
+ );
+}
+
+#[test]
+fn parse_fully_specified_type() {
+ let ty = syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::IImage2DMSArray,
+ array_specifier: None,
+ };
+ let expected = syntax::FullySpecifiedType {
+ qualifier: None,
+ ty,
+ };
+
+ assert_eq!(
+ fully_specified_type("iimage2DMSArray;"),
+ Ok((";", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_fully_specified_type_with_qualifier() {
+ let qual_spec = syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Subroutine(vec![
+ "vec2".into(),
+ "S032_29k".into(),
+ ]));
+ let qual = syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![qual_spec]),
+ };
+ let ty = syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::IImage2DMSArray,
+ array_specifier: None,
+ };
+ let expected = syntax::FullySpecifiedType {
+ qualifier: Some(qual),
+ ty,
+ };
+
+ assert_eq!(
+ fully_specified_type("subroutine (vec2, S032_29k) iimage2DMSArray;"),
+ Ok((";", expected.clone()))
+ );
+ assert_eq!(
+ fully_specified_type("subroutine ( vec2\t\n \t , \n S032_29k )\n iimage2DMSArray ;"),
+ Ok((" ;", expected.clone()))
+ );
+ assert_eq!(
+ fully_specified_type("subroutine(vec2,S032_29k)iimage2DMSArray;"),
+ Ok((";", expected))
+ );
+}
+
+#[test]
+fn parse_primary_expr_intconst() {
+ assert_eq!(primary_expr("0 "), Ok((" ", syntax::Expr::IntConst(0))));
+ assert_eq!(primary_expr("1 "), Ok((" ", syntax::Expr::IntConst(1))));
+}
+
+#[test]
+fn parse_primary_expr_uintconst() {
+ assert_eq!(primary_expr("0u "), Ok((" ", syntax::Expr::UIntConst(0))));
+ assert_eq!(primary_expr("1u "), Ok((" ", syntax::Expr::UIntConst(1))));
+}
+
+#[test]
+fn parse_primary_expr_floatconst() {
+ assert_eq!(
+ primary_expr("0.f "),
+ Ok((" ", syntax::Expr::FloatConst(0.)))
+ );
+ assert_eq!(
+ primary_expr("1.f "),
+ Ok((" ", syntax::Expr::FloatConst(1.)))
+ );
+ assert_eq!(
+ primary_expr("0.F "),
+ Ok((" ", syntax::Expr::FloatConst(0.)))
+ );
+ assert_eq!(
+ primary_expr("1.F "),
+ Ok((" ", syntax::Expr::FloatConst(1.)))
+ );
+}
+
+#[test]
+fn parse_primary_expr_doubleconst() {
+ assert_eq!(primary_expr("0. "), Ok((" ", syntax::Expr::FloatConst(0.))));
+ assert_eq!(primary_expr("1. "), Ok((" ", syntax::Expr::FloatConst(1.))));
+ assert_eq!(
+ primary_expr("0.lf "),
+ Ok((" ", syntax::Expr::DoubleConst(0.)))
+ );
+ assert_eq!(
+ primary_expr("1.lf "),
+ Ok((" ", syntax::Expr::DoubleConst(1.)))
+ );
+ assert_eq!(
+ primary_expr("0.LF "),
+ Ok((" ", syntax::Expr::DoubleConst(0.)))
+ );
+ assert_eq!(
+ primary_expr("1.LF "),
+ Ok((" ", syntax::Expr::DoubleConst(1.)))
+ );
+}
+
+#[test]
+fn parse_primary_expr_boolconst() {
+ assert_eq!(
+ primary_expr("false"),
+ Ok(("", syntax::Expr::BoolConst(false.to_owned())))
+ );
+ assert_eq!(
+ primary_expr("true"),
+ Ok(("", syntax::Expr::BoolConst(true.to_owned())))
+ );
+}
+
+#[test]
+fn parse_primary_expr_parens() {
+ assert_eq!(primary_expr("(0)"), Ok(("", syntax::Expr::IntConst(0))));
+ assert_eq!(primary_expr("( 0 )"), Ok(("", syntax::Expr::IntConst(0))));
+ assert_eq!(
+ primary_expr("( .0 )"),
+ Ok(("", syntax::Expr::FloatConst(0.)))
+ );
+ assert_eq!(
+ primary_expr("( (.0) )"),
+ Ok(("", syntax::Expr::FloatConst(0.)))
+ );
+ assert_eq!(
+ primary_expr("(true) "),
+ Ok((" ", syntax::Expr::BoolConst(true)))
+ );
+}
+
+#[test]
+fn parse_postfix_function_call_no_args() {
+ let fun = syntax::FunIdentifier::Identifier("vec3".into());
+ let args = Vec::new();
+ let expected = syntax::Expr::FunCall(fun, args);
+
+ assert_eq!(postfix_expr("vec3();"), Ok((";", expected.clone())));
+ assert_eq!(postfix_expr("vec3 ( ) ;"), Ok((" ;", expected.clone())));
+ assert_eq!(postfix_expr("vec3 (\nvoid\n) ;"), Ok((" ;", expected)));
+}
+
+#[test]
+fn parse_postfix_function_call_one_arg() {
+ let fun = syntax::FunIdentifier::Identifier("foo".into());
+ let args = vec![syntax::Expr::IntConst(0)];
+ let expected = syntax::Expr::FunCall(fun, args);
+
+ assert_eq!(postfix_expr("foo(0);"), Ok((";", expected.clone())));
+ assert_eq!(postfix_expr("foo ( 0 ) ;"), Ok((" ;", expected.clone())));
+ assert_eq!(postfix_expr("foo (\n0\t\n) ;"), Ok((" ;", expected)));
+}
+
+#[test]
+fn parse_postfix_function_call_multi_arg() {
+ let fun = syntax::FunIdentifier::Identifier("foo".into());
+ let args = vec![
+ syntax::Expr::IntConst(0),
+ syntax::Expr::BoolConst(false),
+ syntax::Expr::Variable("bar".into()),
+ ];
+ let expected = syntax::Expr::FunCall(fun, args);
+
+ assert_eq!(
+ postfix_expr("foo(0, false, bar);"),
+ Ok((";", expected.clone()))
+ );
+ assert_eq!(
+ postfix_expr("foo ( 0\t, false ,\t\tbar) ;"),
+ Ok((" ;", expected))
+ );
+}
+
+#[test]
+fn parse_postfix_expr_bracket() {
+ let id = syntax::Expr::Variable("foo".into());
+ let array_spec = syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::ExplicitlySized(
+ Box::new(syntax::Expr::IntConst(7354)),
+ )]),
+ };
+ let expected = syntax::Expr::Bracket(Box::new(id), array_spec);
+
+ assert_eq!(postfix_expr("foo[7354];"), Ok((";", expected.clone())));
+ assert_eq!(postfix_expr("foo[\n 7354 ] ;"), Ok((";", expected)));
+}
+
+#[test]
+fn parse_postfix_expr_dot() {
+ let foo = Box::new(syntax::Expr::Variable("foo".into()));
+ let expected = syntax::Expr::Dot(foo, "bar".into());
+
+ assert_eq!(postfix_expr("foo.bar;"), Ok((";", expected.clone())));
+ assert_eq!(postfix_expr("(foo).bar;"), Ok((";", expected)));
+}
+
+#[test]
+fn parse_postfix_expr_dot_several() {
+ let foo = Box::new(syntax::Expr::Variable("foo".into()));
+ let expected = syntax::Expr::Dot(Box::new(syntax::Expr::Dot(foo, "bar".into())), "zoo".into());
+
+ assert_eq!(postfix_expr("foo.bar.zoo;"), Ok((";", expected.clone())));
+ assert_eq!(postfix_expr("(foo).bar.zoo;"), Ok((";", expected.clone())));
+ assert_eq!(postfix_expr("(foo.bar).zoo;"), Ok((";", expected)));
+}
+
+#[test]
+fn parse_postfix_postinc() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::PostInc(Box::new(foo));
+
+ assert_eq!(postfix_expr("foo++;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_postfix_postdec() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::PostDec(Box::new(foo));
+
+ assert_eq!(postfix_expr("foo--;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_unary_add() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::Unary(syntax::UnaryOp::Add, Box::new(foo));
+
+ assert_eq!(unary_expr("+foo;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_unary_minus() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::Unary(syntax::UnaryOp::Minus, Box::new(foo));
+
+ assert_eq!(unary_expr("-foo;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_unary_not() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::Unary(syntax::UnaryOp::Not, Box::new(foo));
+
+ assert_eq!(unary_expr("!foo;"), Ok((";", expected)));
+}
+
+#[test]
+fn parse_unary_complement() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::Unary(syntax::UnaryOp::Complement, Box::new(foo));
+
+ assert_eq!(unary_expr("~foo;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_unary_inc() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::Unary(syntax::UnaryOp::Inc, Box::new(foo));
+
+ assert_eq!(unary_expr("++foo;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_unary_dec() {
+ let foo = syntax::Expr::Variable("foo".into());
+ let expected = syntax::Expr::Unary(syntax::UnaryOp::Dec, Box::new(foo));
+
+ assert_eq!(unary_expr("--foo;"), Ok((";", expected.clone())));
+}
+
+#[test]
+fn parse_expr_float() {
+ assert_eq!(expr("314.;"), Ok((";", syntax::Expr::FloatConst(314.))));
+ assert_eq!(expr("314.f;"), Ok((";", syntax::Expr::FloatConst(314.))));
+ assert_eq!(expr("314.LF;"), Ok((";", syntax::Expr::DoubleConst(314.))));
+}
+
+#[test]
+fn parse_expr_add_2() {
+ let one = Box::new(syntax::Expr::IntConst(1));
+ let expected = syntax::Expr::Binary(syntax::BinaryOp::Add, one.clone(), one);
+
+ assert_eq!(expr("1 + 1;"), Ok((";", expected.clone())));
+ assert_eq!(expr("1+1;"), Ok((";", expected.clone())));
+ assert_eq!(expr("(1 + 1);"), Ok((";", expected)));
+}
+
+#[test]
+fn parse_expr_add_3() {
+ let one = Box::new(syntax::Expr::UIntConst(1));
+ let two = Box::new(syntax::Expr::UIntConst(2));
+ let three = Box::new(syntax::Expr::UIntConst(3));
+ let expected = syntax::Expr::Binary(
+ syntax::BinaryOp::Add,
+ Box::new(syntax::Expr::Binary(syntax::BinaryOp::Add, one, two)),
+ three,
+ );
+
+ assert_eq!(expr("1u + 2u + 3u"), Ok(("", expected.clone())));
+ assert_eq!(expr("1u + 2u + 3u "), Ok((" ", expected.clone())));
+ assert_eq!(expr("1u+2u+3u"), Ok(("", expected.clone())));
+ assert_eq!(expr("((1u + 2u) + 3u)"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_expr_add_mult_3() {
+ let one = Box::new(syntax::Expr::UIntConst(1));
+ let two = Box::new(syntax::Expr::UIntConst(2));
+ let three = Box::new(syntax::Expr::UIntConst(3));
+ let expected = syntax::Expr::Binary(
+ syntax::BinaryOp::Add,
+ Box::new(syntax::Expr::Binary(syntax::BinaryOp::Mult, one, two)),
+ three,
+ );
+
+ assert_eq!(expr("1u * 2u + 3u ;"), Ok((" ;", expected.clone())));
+ assert_eq!(expr("1u*2u+3u;"), Ok((";", expected.clone())));
+ assert_eq!(expr("(1u * 2u) + 3u;"), Ok((";", expected)));
+}
+
+#[test]
+fn parse_expr_add_sub_mult_div() {
+ let one = Box::new(syntax::Expr::IntConst(1));
+ let two = Box::new(syntax::Expr::IntConst(2));
+ let three = Box::new(syntax::Expr::IntConst(3));
+ let four = Box::new(syntax::Expr::IntConst(4));
+ let five = Box::new(syntax::Expr::IntConst(5));
+ let six = Box::new(syntax::Expr::IntConst(6));
+ let expected = syntax::Expr::Binary(
+ syntax::BinaryOp::Add,
+ Box::new(syntax::Expr::Binary(
+ syntax::BinaryOp::Mult,
+ one,
+ Box::new(syntax::Expr::Binary(syntax::BinaryOp::Add, two, three)),
+ )),
+ Box::new(syntax::Expr::Binary(
+ syntax::BinaryOp::Div,
+ four,
+ Box::new(syntax::Expr::Binary(syntax::BinaryOp::Add, five, six)),
+ )),
+ );
+
+ assert_eq!(
+ expr("1 * (2 + 3) + 4 / (5 + 6);"),
+ Ok((";", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_complex_expr() {
+ let input = "normalize((inverse(view) * vec4(ray.dir, 0.)).xyz);";
+ let zero = syntax::Expr::FloatConst(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 normalize = syntax::Expr::FunCall(
+ syntax::FunIdentifier::Identifier("normalize".into()),
+ vec![xyz],
+ );
+ let expected = normalize;
+
+ assert_eq!(expr(&input[..]), Ok((";", expected)));
+}
+
+#[test]
+fn parse_function_identifier_typename() {
+ let expected = syntax::FunIdentifier::Identifier("foo".into());
+ assert_eq!(function_identifier("foo("), Ok(("(", expected.clone())));
+ assert_eq!(function_identifier("foo\n\t("), Ok(("(", expected.clone())));
+ assert_eq!(function_identifier("foo\n ("), Ok(("(", expected)));
+}
+
+#[test]
+fn parse_function_identifier_cast() {
+ let expected = syntax::FunIdentifier::Identifier("vec3".into());
+ assert_eq!(function_identifier("vec3("), Ok(("(", expected.clone())));
+ assert_eq!(function_identifier("vec3 ("), Ok(("(", expected.clone())));
+ assert_eq!(function_identifier("vec3\t\n\n \t ("), Ok(("(", expected)));
+}
+
+#[test]
+fn parse_function_identifier_cast_array_unsized() {
+ let expected = syntax::FunIdentifier::Expr(Box::new(syntax::Expr::Bracket(
+ Box::new(syntax::Expr::Variable("vec3".into())),
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::Unsized]),
+ },
+ )));
+
+ assert_eq!(function_identifier("vec3[]("), Ok(("(", expected.clone())));
+ assert_eq!(function_identifier("vec3 [\t\n]("), Ok(("(", expected)));
+}
+
+#[test]
+fn parse_function_identifier_cast_array_sized() {
+ let expected = syntax::FunIdentifier::Expr(Box::new(syntax::Expr::Bracket(
+ Box::new(syntax::Expr::Variable("vec3".into())),
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::ExplicitlySized(
+ Box::new(syntax::Expr::IntConst(12)),
+ )]),
+ },
+ )));
+
+ assert_eq!(
+ function_identifier("vec3[12]("),
+ Ok(("(", expected.clone()))
+ );
+ assert_eq!(function_identifier("vec3 [\t 12\n]("), Ok(("(", expected)));
+}
+
+#[test]
+fn parse_void() {
+ assert_eq!(void("void "), Ok((" ", ())));
+}
+
+#[test]
+fn parse_assignment_op_equal() {
+ assert_eq!(assignment_op("= "), Ok((" ", syntax::AssignmentOp::Equal)));
+}
+
+#[test]
+fn parse_assignment_op_mult() {
+ assert_eq!(assignment_op("*= "), Ok((" ", syntax::AssignmentOp::Mult)));
+}
+
+#[test]
+fn parse_assignment_op_div() {
+ assert_eq!(assignment_op("/= "), Ok((" ", syntax::AssignmentOp::Div)));
+}
+
+#[test]
+fn parse_assignment_op_mod() {
+ assert_eq!(assignment_op("%= "), Ok((" ", syntax::AssignmentOp::Mod)));
+}
+
+#[test]
+fn parse_assignment_op_add() {
+ assert_eq!(assignment_op("+= "), Ok((" ", syntax::AssignmentOp::Add)));
+}
+
+#[test]
+fn parse_assignment_op_sub() {
+ assert_eq!(assignment_op("-= "), Ok((" ", syntax::AssignmentOp::Sub)));
+}
+
+#[test]
+fn parse_assignment_op_lshift() {
+ assert_eq!(
+ assignment_op("<<= "),
+ Ok((" ", syntax::AssignmentOp::LShift))
+ );
+}
+
+#[test]
+fn parse_assignment_op_rshift() {
+ assert_eq!(
+ assignment_op(">>= "),
+ Ok((" ", syntax::AssignmentOp::RShift))
+ );
+}
+
+#[test]
+fn parse_assignment_op_and() {
+ assert_eq!(assignment_op("&= "), Ok((" ", syntax::AssignmentOp::And)));
+}
+
+#[test]
+fn parse_assignment_op_xor() {
+ assert_eq!(assignment_op("^= "), Ok((" ", syntax::AssignmentOp::Xor)));
+}
+
+#[test]
+fn parse_assignment_op_or() {
+ assert_eq!(assignment_op("|= "), Ok((" ", syntax::AssignmentOp::Or)));
+}
+
+#[test]
+fn parse_expr_statement() {
+ let expected = Some(syntax::Expr::Assignment(
+ Box::new(syntax::Expr::Variable("foo".into())),
+ syntax::AssignmentOp::Equal,
+ Box::new(syntax::Expr::FloatConst(314.)),
+ ));
+
+ assert_eq!(expr_statement("foo = 314.f;"), Ok(("", expected.clone())));
+ assert_eq!(expr_statement("foo=314.f;"), Ok(("", expected.clone())));
+ assert_eq!(expr_statement("foo\n\t= \n314.f;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_declaration_function_prototype() {
+ let rt = syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec3,
+ array_specifier: None,
+ },
+ };
+ let arg0_ty = syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec2,
+ array_specifier: None,
+ };
+ let arg0 = syntax::FunctionParameterDeclaration::Unnamed(None, arg0_ty);
+ let qual_spec = syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Out);
+ let qual = syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![qual_spec]),
+ };
+ let arg1 = syntax::FunctionParameterDeclaration::Named(
+ Some(qual),
+ syntax::FunctionParameterDeclarator {
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ },
+ ident: "the_arg".into(),
+ },
+ );
+ let fp = syntax::FunctionPrototype {
+ ty: rt,
+ name: "foo".into(),
+ parameters: vec![arg0, arg1],
+ };
+ let expected = syntax::Declaration::FunctionPrototype(fp);
+
+ assert_eq!(
+ declaration("vec3 foo(vec2, out float the_arg);"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ declaration("vec3 \nfoo ( vec2\n, out float \n\tthe_arg )\n;"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ declaration("vec3 foo(vec2,out float the_arg);"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_declaration_init_declarator_list_single() {
+ let ty = syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Int,
+ array_specifier: None,
+ },
+ };
+ let sd = syntax::SingleDeclaration {
+ ty,
+ name: Some("foo".into()),
+ array_specifier: None,
+ initializer: Some(syntax::Initializer::Simple(Box::new(
+ syntax::Expr::IntConst(34),
+ ))),
+ };
+ let idl = syntax::InitDeclaratorList {
+ head: sd,
+ tail: Vec::new(),
+ };
+ let expected = syntax::Declaration::InitDeclaratorList(idl);
+
+ assert_eq!(declaration("int foo = 34;"), Ok(("", expected.clone())));
+ assert_eq!(declaration("int foo=34;"), Ok(("", expected.clone())));
+ assert_eq!(declaration("int \t \nfoo =\t34 ;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_declaration_init_declarator_list_complex() {
+ let ty = syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Int,
+ array_specifier: None,
+ },
+ };
+ let sd = syntax::SingleDeclaration {
+ ty,
+ name: Some("foo".into()),
+ array_specifier: None,
+ initializer: Some(syntax::Initializer::Simple(Box::new(
+ syntax::Expr::IntConst(34),
+ ))),
+ };
+ let sdnt = syntax::SingleDeclarationNoType {
+ ident: "bar".into(),
+ initializer: Some(syntax::Initializer::Simple(Box::new(
+ syntax::Expr::IntConst(12),
+ ))),
+ };
+ let expected = syntax::Declaration::InitDeclaratorList(syntax::InitDeclaratorList {
+ head: sd,
+ tail: vec![sdnt],
+ });
+
+ assert_eq!(
+ declaration("int foo = 34, bar = 12;"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ declaration("int foo=34,bar=12;"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ declaration("int \t \nfoo =\t34 \n,\tbar= 12\n ;"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_declaration_precision_low() {
+ let qual = syntax::PrecisionQualifier::Low;
+ let ty = syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ };
+ let expected = syntax::Declaration::Precision(qual, ty);
+
+ assert_eq!(declaration("precision lowp float;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_declaration_precision_medium() {
+ let qual = syntax::PrecisionQualifier::Medium;
+ let ty = syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ };
+ let expected = syntax::Declaration::Precision(qual, ty);
+
+ assert_eq!(declaration("precision mediump float;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_declaration_precision_high() {
+ let qual = syntax::PrecisionQualifier::High;
+ let ty = syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ };
+ let expected = syntax::Declaration::Precision(qual, ty);
+
+ assert_eq!(declaration("precision highp float;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_declaration_uniform_block() {
+ let qual_spec = syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Uniform);
+ let qual = syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![qual_spec]),
+ };
+ let f0 = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["a".into()]),
+ };
+ let f1 = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec3,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["b".into()]),
+ };
+ let f2 = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::TypeName("foo".into()),
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["c".into(), "d".into()]),
+ };
+ let expected = syntax::Declaration::Block(syntax::Block {
+ qualifier: qual,
+ name: "UniformBlockTest".into(),
+ fields: vec![f0, f1, f2],
+ identifier: None,
+ });
+
+ assert_eq!(
+ declaration("uniform UniformBlockTest { float a; vec3 b; foo c, d; };"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(declaration("uniform \nUniformBlockTest\n {\n \t float a \n; \nvec3 b\n; foo \nc\n, \nd\n;\n }\n\t\n\t\t \t;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_declaration_buffer_block() {
+ let qual_spec = syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Buffer);
+ let qual = syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![qual_spec]),
+ };
+ let f0 = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["a".into()]),
+ };
+ let f1 = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec3,
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec![syntax::ArrayedIdentifier::new(
+ "b",
+ Some(syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::Unsized]),
+ }),
+ )]),
+ };
+ let f2 = syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::TypeName("foo".into()),
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["c".into(), "d".into()]),
+ };
+ let expected = syntax::Declaration::Block(syntax::Block {
+ qualifier: qual,
+ name: "UniformBlockTest".into(),
+ fields: vec![f0, f1, f2],
+ identifier: None,
+ });
+
+ assert_eq!(
+ declaration("buffer UniformBlockTest { float a; vec3 b[]; foo c, d; };"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(declaration("buffer \nUniformBlockTest\n {\n \t float a \n; \nvec3 b [ ]\n; foo \nc\n, \nd\n;\n }\n\t\n\t\t \t;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_selection_statement_if() {
+ let cond = syntax::Expr::Binary(
+ syntax::BinaryOp::LT,
+ Box::new(syntax::Expr::Variable("foo".into())),
+ Box::new(syntax::Expr::IntConst(10)),
+ );
+ let ret = Box::new(syntax::Expr::BoolConst(false));
+ let st = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Jump(
+ syntax::JumpStatement::Return(Some(ret)),
+ )));
+ let body = syntax::Statement::Compound(Box::new(syntax::CompoundStatement {
+ statement_list: vec![st],
+ }));
+ let rest = syntax::SelectionRestStatement::Statement(Box::new(body));
+ let expected = syntax::SelectionStatement {
+ cond: Box::new(cond),
+ rest,
+ };
+
+ assert_eq!(
+ selection_statement("if (foo < 10) { return false; }K"),
+ Ok(("K", expected.clone()))
+ );
+ assert_eq!(
+ selection_statement("if \n(foo<10\n) \t{return false;}K"),
+ Ok(("K", expected))
+ );
+}
+
+#[test]
+fn parse_selection_statement_if_else() {
+ let cond = syntax::Expr::Binary(
+ syntax::BinaryOp::LT,
+ Box::new(syntax::Expr::Variable("foo".into())),
+ Box::new(syntax::Expr::IntConst(10)),
+ );
+ let if_ret = Box::new(syntax::Expr::FloatConst(0.));
+ let if_st = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Jump(
+ syntax::JumpStatement::Return(Some(if_ret)),
+ )));
+ let if_body = syntax::Statement::Compound(Box::new(syntax::CompoundStatement {
+ statement_list: vec![if_st],
+ }));
+ let else_ret = Box::new(syntax::Expr::Variable("foo".into()));
+ let else_st = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Jump(
+ syntax::JumpStatement::Return(Some(else_ret)),
+ )));
+ let else_body = syntax::Statement::Compound(Box::new(syntax::CompoundStatement {
+ statement_list: vec![else_st],
+ }));
+ let rest = syntax::SelectionRestStatement::Else(Box::new(if_body), Box::new(else_body));
+ let expected = syntax::SelectionStatement {
+ cond: Box::new(cond),
+ rest,
+ };
+
+ assert_eq!(
+ selection_statement("if (foo < 10) { return 0.f; } else { return foo; }"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ selection_statement("if \n(foo<10\n) \t{return 0.f\t;\n\n}\n else{\n\t return foo ;}"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_switch_statement_empty() {
+ let head = Box::new(syntax::Expr::Variable("foo".into()));
+ let expected = syntax::SwitchStatement {
+ head,
+ body: Vec::new(),
+ };
+
+ assert_eq!(
+ switch_statement("switch (foo) {}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ switch_statement("switch(foo){}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ switch_statement("switch\n\n ( foo \t \n) { \n\n }"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_switch_statement_cases() {
+ let head = Box::new(syntax::Expr::Variable("foo".into()));
+ let case0 = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::CaseLabel(
+ syntax::CaseLabel::Case(Box::new(syntax::Expr::IntConst(0))),
+ )));
+ let case1 = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::CaseLabel(
+ syntax::CaseLabel::Case(Box::new(syntax::Expr::IntConst(1))),
+ )));
+ let ret = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Jump(
+ syntax::JumpStatement::Return(Some(Box::new(syntax::Expr::UIntConst(12)))),
+ )));
+ let expected = syntax::SwitchStatement {
+ head,
+ body: vec![case0, case1, ret],
+ };
+
+ assert_eq!(
+ switch_statement("switch (foo) { case 0: case 1: return 12u; }"),
+ Ok(("", expected.clone()))
+ );
+}
+
+#[test]
+fn parse_case_label_def() {
+ assert_eq!(case_label("default:"), Ok(("", syntax::CaseLabel::Def)));
+ assert_eq!(case_label("default :"), Ok(("", syntax::CaseLabel::Def)));
+}
+
+#[test]
+fn parse_case_label() {
+ let expected = syntax::CaseLabel::Case(Box::new(syntax::Expr::IntConst(3)));
+
+ assert_eq!(case_label("case 3:"), Ok(("", expected.clone())));
+ assert_eq!(case_label("case\n\t 3 :"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_iteration_statement_while_empty() {
+ let cond = syntax::Condition::Expr(Box::new(syntax::Expr::Binary(
+ syntax::BinaryOp::GTE,
+ Box::new(syntax::Expr::Variable("a".into())),
+ Box::new(syntax::Expr::Variable("b".into())),
+ )));
+ let st = syntax::Statement::Compound(Box::new(syntax::CompoundStatement {
+ statement_list: Vec::new(),
+ }));
+ let expected = syntax::IterationStatement::While(cond, Box::new(st));
+
+ assert_eq!(
+ iteration_statement("while (a >= b) {}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ iteration_statement("while(a>=b){}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ iteration_statement("while ( a >=\n\tb )\t { \n}"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_iteration_statement_do_while_empty() {
+ let st = syntax::Statement::Compound(Box::new(syntax::CompoundStatement {
+ statement_list: Vec::new(),
+ }));
+ let cond = Box::new(syntax::Expr::Binary(
+ syntax::BinaryOp::GTE,
+ Box::new(syntax::Expr::Variable("a".into())),
+ Box::new(syntax::Expr::Variable("b".into())),
+ ));
+ let expected = syntax::IterationStatement::DoWhile(Box::new(st), cond);
+
+ assert_eq!(
+ iteration_statement("do {} while (a >= b);"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ iteration_statement("do{}while(a>=b);"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ iteration_statement("do \n {\n} while ( a >=\n\tb )\t \n;"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_iteration_statement_for_empty() {
+ let init = syntax::ForInitStatement::Declaration(Box::new(
+ syntax::Declaration::InitDeclaratorList(syntax::InitDeclaratorList {
+ head: syntax::SingleDeclaration {
+ ty: syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Float,
+ array_specifier: None,
+ },
+ },
+ name: Some("i".into()),
+ array_specifier: None,
+ initializer: Some(syntax::Initializer::Simple(Box::new(
+ syntax::Expr::FloatConst(0.),
+ ))),
+ },
+ tail: Vec::new(),
+ }),
+ ));
+ let rest = syntax::ForRestStatement {
+ condition: Some(syntax::Condition::Expr(Box::new(syntax::Expr::Binary(
+ syntax::BinaryOp::LTE,
+ Box::new(syntax::Expr::Variable("i".into())),
+ Box::new(syntax::Expr::FloatConst(10.)),
+ )))),
+ post_expr: Some(Box::new(syntax::Expr::Unary(
+ syntax::UnaryOp::Inc,
+ Box::new(syntax::Expr::Variable("i".into())),
+ ))),
+ };
+ let st = syntax::Statement::Compound(Box::new(syntax::CompoundStatement {
+ statement_list: Vec::new(),
+ }));
+ let expected = syntax::IterationStatement::For(init, rest, Box::new(st));
+
+ assert_eq!(
+ iteration_statement("for (float i = 0.f; i <= 10.f; ++i) {}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ iteration_statement("for(float i=0.f;i<=10.f;++i){}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ iteration_statement("for\n\t ( \t\n\nfloat \ni \t=\n0.f\n;\ni\t<= 10.f; \n++i\n)\n{\n}"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_jump_continue() {
+ assert_eq!(
+ jump_statement("continue;"),
+ Ok(("", syntax::JumpStatement::Continue))
+ );
+}
+
+#[test]
+fn parse_jump_break() {
+ assert_eq!(
+ jump_statement("break;"),
+ Ok(("", syntax::JumpStatement::Break))
+ );
+}
+
+#[test]
+fn parse_jump_return() {
+ let expected = syntax::JumpStatement::Return(Some(Box::new(syntax::Expr::IntConst(3))));
+ assert_eq!(jump_statement("return 3;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_jump_empty_return() {
+ let expected = syntax::SimpleStatement::Jump(syntax::JumpStatement::Return(None));
+ assert_eq!(simple_statement("return;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_jump_discard() {
+ assert_eq!(
+ jump_statement("discard;"),
+ Ok(("", syntax::JumpStatement::Discard))
+ );
+}
+
+#[test]
+fn parse_simple_statement_return() {
+ let e = syntax::Expr::BoolConst(false);
+ let expected = syntax::SimpleStatement::Jump(syntax::JumpStatement::Return(Some(Box::new(e))));
+
+ assert_eq!(simple_statement("return false;"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_compound_statement_empty() {
+ let expected = syntax::CompoundStatement {
+ statement_list: Vec::new(),
+ };
+
+ assert_eq!(compound_statement("{}"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_compound_statement() {
+ let st0 = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Selection(
+ syntax::SelectionStatement {
+ cond: Box::new(syntax::Expr::BoolConst(true)),
+ rest: syntax::SelectionRestStatement::Statement(Box::new(syntax::Statement::Compound(
+ Box::new(syntax::CompoundStatement {
+ statement_list: Vec::new(),
+ }),
+ ))),
+ },
+ )));
+ let st1 = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Declaration(
+ syntax::Declaration::InitDeclaratorList(syntax::InitDeclaratorList {
+ head: syntax::SingleDeclaration {
+ ty: syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::ISampler3D,
+ array_specifier: None,
+ },
+ },
+ name: Some("x".into()),
+ array_specifier: None,
+ initializer: None,
+ },
+ tail: Vec::new(),
+ }),
+ )));
+ let st2 = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Jump(
+ syntax::JumpStatement::Return(Some(Box::new(syntax::Expr::IntConst(42)))),
+ )));
+ let expected = syntax::CompoundStatement {
+ statement_list: vec![st0, st1, st2],
+ };
+
+ assert_eq!(
+ compound_statement("{ if (true) {} isampler3D x; return 42 ; }"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ compound_statement("{if(true){}isampler3D x;return 42;}"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_function_definition() {
+ let rt = syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::IImage2DArray,
+ array_specifier: None,
+ },
+ };
+ let fp = syntax::FunctionPrototype {
+ ty: rt,
+ name: "foo".into(),
+ parameters: Vec::new(),
+ };
+ let st0 = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Jump(
+ syntax::JumpStatement::Return(Some(Box::new(syntax::Expr::Variable("bar".into())))),
+ )));
+ let expected = syntax::FunctionDefinition {
+ prototype: fp,
+ statement: syntax::CompoundStatement {
+ statement_list: vec![st0],
+ },
+ };
+
+ assert_eq!(
+ function_definition("iimage2DArray foo() { return bar; }"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ function_definition("iimage2DArray \tfoo\n()\n \n{\n return \nbar\n;}"),
+ Ok(("", expected.clone()))
+ );
+ assert_eq!(
+ function_definition("iimage2DArray foo(){return bar;}"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_buffer_block_0() {
+ let src = include_str!("../data/tests/buffer_block_0.glsl");
+ let main_fn = syntax::ExternalDeclaration::FunctionDefinition(syntax::FunctionDefinition {
+ prototype: syntax::FunctionPrototype {
+ ty: syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Void,
+ array_specifier: None,
+ },
+ },
+ name: "main".into(),
+ parameters: Vec::new(),
+ },
+ statement: syntax::CompoundStatement {
+ statement_list: Vec::new(),
+ },
+ });
+ let buffer_block =
+ syntax::ExternalDeclaration::Declaration(syntax::Declaration::Block(syntax::Block {
+ qualifier: syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![syntax::TypeQualifierSpec::Storage(
+ syntax::StorageQualifier::Buffer,
+ )]),
+ },
+ name: "Foo".into(),
+ fields: vec![syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::TypeName("char".into()),
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec![syntax::ArrayedIdentifier::new(
+ "tiles",
+ Some(syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::Unsized]),
+ }),
+ )]),
+ }],
+ identifier: Some("main_tiles".into()),
+ }));
+ let expected = syntax::TranslationUnit(syntax::NonEmpty(vec![buffer_block, main_fn]));
+
+ assert_eq!(translation_unit(src), Ok(("", expected)));
+}
+
+#[test]
+fn parse_layout_buffer_block_0() {
+ let src = include_str!("../data/tests/layout_buffer_block_0.glsl");
+ let layout = syntax::LayoutQualifier {
+ ids: syntax::NonEmpty(vec![
+ syntax::LayoutQualifierSpec::Identifier(
+ "set".into(),
+ Some(Box::new(syntax::Expr::IntConst(0))),
+ ),
+ syntax::LayoutQualifierSpec::Identifier(
+ "binding".into(),
+ Some(Box::new(syntax::Expr::IntConst(0))),
+ ),
+ ]),
+ };
+ let type_qual = syntax::TypeQualifier {
+ qualifiers: syntax::NonEmpty(vec![
+ syntax::TypeQualifierSpec::Layout(layout),
+ syntax::TypeQualifierSpec::Storage(syntax::StorageQualifier::Buffer),
+ ]),
+ };
+ let block = syntax::ExternalDeclaration::Declaration(syntax::Declaration::Block(syntax::Block {
+ qualifier: type_qual,
+ name: "Foo".into(),
+ fields: vec![syntax::StructFieldSpecifier {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::TypeName("char".into()),
+ array_specifier: None,
+ },
+ identifiers: syntax::NonEmpty(vec!["a".into()]),
+ }],
+ identifier: Some("foo".into()),
+ }));
+
+ let expected = syntax::TranslationUnit(syntax::NonEmpty(vec![block]));
+
+ assert_eq!(translation_unit(src), Ok(("", expected)));
+}
+
+#[test]
+fn parse_pp_space0() {
+ assert_eq!(pp_space0(" \\\n "), Ok(("", " \\\n ")));
+ assert_eq!(pp_space0(""), Ok(("", "")));
+}
+
+#[test]
+fn parse_pp_version_number() {
+ assert_eq!(pp_version_number("450"), Ok(("", 450)));
+}
+
+#[test]
+fn parse_pp_version_profile() {
+ assert_eq!(
+ pp_version_profile("core"),
+ Ok(("", syntax::PreprocessorVersionProfile::Core))
+ );
+ assert_eq!(
+ pp_version_profile("compatibility"),
+ Ok(("", syntax::PreprocessorVersionProfile::Compatibility))
+ );
+ assert_eq!(
+ pp_version_profile("es"),
+ Ok(("", syntax::PreprocessorVersionProfile::ES))
+ );
+}
+
+#[test]
+fn parse_pp_version() {
+ assert_eq!(
+ preprocessor("#version 450\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Version(syntax::PreprocessorVersion {
+ version: 450,
+ profile: None,
+ })
+ ))
+ );
+
+ assert_eq!(
+ preprocessor("#version 450 core\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Version(syntax::PreprocessorVersion {
+ version: 450,
+ profile: Some(syntax::PreprocessorVersionProfile::Core)
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_version_newline() {
+ assert_eq!(
+ preprocessor("#version 450\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Version(syntax::PreprocessorVersion {
+ version: 450,
+ profile: None,
+ })
+ ))
+ );
+
+ assert_eq!(
+ preprocessor("#version 450 core\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Version(syntax::PreprocessorVersion {
+ version: 450,
+ profile: Some(syntax::PreprocessorVersionProfile::Core)
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_define() {
+ let expect = |v: &str| {
+ Ok((
+ "",
+ syntax::Preprocessor::Define(syntax::PreprocessorDefine::ObjectLike {
+ ident: "test".into(),
+ value: v.to_owned(),
+ }),
+ ))
+ };
+
+ assert_eq!(preprocessor("#define test 1.0"), expect("1.0"));
+ assert_eq!(preprocessor("#define test \\\n 1.0"), expect("1.0"));
+ assert_eq!(preprocessor("#define test 1.0\n"), expect("1.0"));
+
+ assert_eq!(
+ preprocessor("#define test123 .0f\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Define(syntax::PreprocessorDefine::ObjectLike {
+ ident: "test123".into(),
+ value: ".0f".to_owned()
+ })
+ ))
+ );
+
+ assert_eq!(
+ preprocessor("#define test 1\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Define(syntax::PreprocessorDefine::ObjectLike {
+ ident: "test".into(),
+ value: "1".to_owned()
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_define_with_args() {
+ let expected = syntax::Preprocessor::Define(syntax::PreprocessorDefine::FunctionLike {
+ ident: "add".into(),
+ args: vec![
+ syntax::Identifier::new("x").unwrap(),
+ syntax::Identifier::new("y").unwrap(),
+ ],
+ value: "(x + y)".to_owned(),
+ });
+
+ assert_eq!(
+ preprocessor("#define \\\n add(x, y) \\\n (x + y)"),
+ Ok(("", expected.clone()))
+ );
+
+ assert_eq!(
+ preprocessor("#define \\\n add( x, y ) \\\n (x + y)"),
+ Ok(("", expected))
+ );
+}
+
+#[test]
+fn parse_pp_define_multiline() {
+ assert_eq!(
+ preprocessor(
+ r#"#define foo \
+ 32"#
+ ),
+ Ok((
+ "",
+ syntax::Preprocessor::Define(syntax::PreprocessorDefine::ObjectLike {
+ ident: "foo".into(),
+ value: "32".to_owned(),
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_else() {
+ assert_eq!(
+ preprocessor("# else\n"),
+ Ok(("", syntax::Preprocessor::Else))
+ );
+}
+
+#[test]
+fn parse_pp_elseif() {
+ assert_eq!(
+ preprocessor("# elseif \\\n42\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::ElseIf(syntax::PreprocessorElseIf {
+ condition: "42".to_owned()
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_endif() {
+ assert_eq!(
+ preprocessor("#\\\nendif"),
+ Ok(("", syntax::Preprocessor::EndIf))
+ );
+}
+
+#[test]
+fn parse_pp_error() {
+ assert_eq!(
+ preprocessor("#error \\\n some message"),
+ Ok((
+ "",
+ syntax::Preprocessor::Error(syntax::PreprocessorError {
+ message: "some message".to_owned()
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_if() {
+ assert_eq!(
+ preprocessor("# \\\nif 42"),
+ Ok((
+ "",
+ syntax::Preprocessor::If(syntax::PreprocessorIf {
+ condition: "42".to_owned()
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_ifdef() {
+ assert_eq!(
+ preprocessor("#ifdef FOO\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::IfDef(syntax::PreprocessorIfDef {
+ ident: syntax::Identifier("FOO".to_owned())
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_ifndef() {
+ assert_eq!(
+ preprocessor("#\\\nifndef \\\n FOO\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::IfNDef(syntax::PreprocessorIfNDef {
+ ident: syntax::Identifier("FOO".to_owned())
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_include() {
+ assert_eq!(
+ preprocessor("#include <filename>\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Include(syntax::PreprocessorInclude {
+ path: syntax::Path::Absolute("filename".to_owned())
+ })
+ ))
+ );
+
+ assert_eq!(
+ preprocessor("#include \\\n\"filename\"\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Include(syntax::PreprocessorInclude {
+ path: syntax::Path::Relative("filename".to_owned())
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_line() {
+ assert_eq!(
+ preprocessor("# line \\\n2\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Line(syntax::PreprocessorLine {
+ line: 2,
+ source_string_number: None,
+ })
+ ))
+ );
+
+ assert_eq!(
+ preprocessor("#line 2 \\\n 4\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Line(syntax::PreprocessorLine {
+ line: 2,
+ source_string_number: Some(4),
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_pragma() {
+ assert_eq!(
+ preprocessor("#\\\npragma some flag"),
+ Ok((
+ "",
+ syntax::Preprocessor::Pragma(syntax::PreprocessorPragma {
+ command: "some flag".to_owned()
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_undef() {
+ assert_eq!(
+ preprocessor("# undef \\\n FOO"),
+ Ok((
+ "",
+ syntax::Preprocessor::Undef(syntax::PreprocessorUndef {
+ name: syntax::Identifier("FOO".to_owned())
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_extension_name() {
+ assert_eq!(
+ pp_extension_name("all"),
+ Ok(("", syntax::PreprocessorExtensionName::All))
+ );
+ assert_eq!(
+ pp_extension_name("GL_foobar_extension "),
+ Ok((
+ " ",
+ syntax::PreprocessorExtensionName::Specific("GL_foobar_extension".to_owned())
+ ))
+ );
+}
+
+#[test]
+fn parse_pp_extension_behavior() {
+ assert_eq!(
+ pp_extension_behavior("require"),
+ Ok(("", syntax::PreprocessorExtensionBehavior::Require))
+ );
+ assert_eq!(
+ pp_extension_behavior("enable"),
+ Ok(("", syntax::PreprocessorExtensionBehavior::Enable))
+ );
+ assert_eq!(
+ pp_extension_behavior("warn"),
+ Ok(("", syntax::PreprocessorExtensionBehavior::Warn))
+ );
+ assert_eq!(
+ pp_extension_behavior("disable"),
+ Ok(("", syntax::PreprocessorExtensionBehavior::Disable))
+ );
+}
+
+#[test]
+fn parse_pp_extension() {
+ assert_eq!(
+ preprocessor("#extension all: require\n"),
+ Ok((
+ "",
+ syntax::Preprocessor::Extension(syntax::PreprocessorExtension {
+ name: syntax::PreprocessorExtensionName::All,
+ behavior: Some(syntax::PreprocessorExtensionBehavior::Require)
+ })
+ ))
+ );
+}
+
+#[test]
+fn parse_dot_field_expr_array() {
+ let src = "a[0].xyz;";
+ let expected = syntax::Expr::Dot(
+ Box::new(syntax::Expr::Bracket(
+ Box::new(syntax::Expr::Variable("a".into())),
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::ExplicitlySized(
+ Box::new(syntax::Expr::IntConst(0)),
+ )]),
+ },
+ )),
+ "xyz".into(),
+ );
+
+ assert_eq!(expr(src), Ok((";", expected)));
+}
+
+#[test]
+fn parse_dot_field_expr_statement() {
+ let src = "vec3 v = smoothstep(vec3(border_width), vec3(0.0), v_barycenter).zyx;";
+ let fun = syntax::FunIdentifier::Identifier("smoothstep".into());
+ let args = vec![
+ syntax::Expr::FunCall(
+ syntax::FunIdentifier::Identifier("vec3".into()),
+ vec![syntax::Expr::Variable("border_width".into())],
+ ),
+ syntax::Expr::FunCall(
+ syntax::FunIdentifier::Identifier("vec3".into()),
+ vec![syntax::Expr::FloatConst(0.)],
+ ),
+ syntax::Expr::Variable("v_barycenter".into()),
+ ];
+ let ini = syntax::Initializer::Simple(Box::new(syntax::Expr::Dot(
+ Box::new(syntax::Expr::FunCall(fun, args)),
+ "zyx".into(),
+ )));
+ let sd = syntax::SingleDeclaration {
+ ty: syntax::FullySpecifiedType {
+ qualifier: None,
+ ty: syntax::TypeSpecifier {
+ ty: syntax::TypeSpecifierNonArray::Vec3,
+ array_specifier: None,
+ },
+ },
+ name: Some("v".into()),
+ array_specifier: None,
+ initializer: Some(ini),
+ };
+ let expected = syntax::Statement::Simple(Box::new(syntax::SimpleStatement::Declaration(
+ syntax::Declaration::InitDeclaratorList(syntax::InitDeclaratorList {
+ head: sd,
+ tail: Vec::new(),
+ }),
+ )));
+
+ assert_eq!(statement(src), Ok(("", expected)));
+}
+
+#[test]
+fn parse_arrayed_identifier() {
+ let expected = syntax::ArrayedIdentifier::new(
+ "foo",
+ syntax::ArraySpecifier {
+ dimensions: syntax::NonEmpty(vec![syntax::ArraySpecifierDimension::Unsized]),
+ },
+ );
+
+ assert_eq!(arrayed_identifier("foo[]"), Ok(("", expected.clone())));
+ assert_eq!(arrayed_identifier("foo \t\n [\n\t ]"), Ok(("", expected)));
+}
+
+#[test]
+fn parse_nested_parens() {
+ let start = std::time::Instant::now();
+ parens_expr("((((((((1.0f))))))))").unwrap();
+ let elapsed = start.elapsed();
+ assert!(elapsed.as_millis() < 100, "{} ms", elapsed.as_millis());
+}