# Tests todo:
# - inout with varyings, attributes, uniforms (and arrays of 'em)
# - inout with arrays, array elements
# - inout with array elements
# - inout by-value semantics (arrays & elements & structs)

# Done:
# - control flow: return, return in loop, etc.

group datatypes "Function Parameter Data Types"

	case float_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				return -a;
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_vec2
		version 300 es
		values
		{
			input vec2 in0		= [ vec2(0.0, 1.0) | vec2(2.0, 2.5) ];
			output float out0	= [ -1.0 | -4.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (vec2 a)
			{
				return -(a.x + a.y);
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_vec3
		version 300 es
		values
		{
			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
			output float out0	= [ 1.0 | -0.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (vec3 a)
			{
				return -(a.x + a.y + a.z);
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_vec4
		version 300 es
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, -2.0, 0.5) | vec4(2.0, 2.5, 4.0, -7.0) ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (vec4 a)
			{
				return -(a.x + a.y + a.z + a.w);
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_mat2
		version 300 es
		values
		{
			input mat2 in0		= [ mat2(0.0, 1.0, -2.0, 0.5) | mat2(2.0, 2.5, 4.0, -7.0) ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (mat2 a)
			{
				return -(a[0][0] + a[0][1] + a[1][0] + a[1][1]);
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_mat3
		version 300 es
		values
		{
			input mat3 in0		= [ mat3(0.0, 1.0, -2.0, 0.5, 1.0, -1.0, 2.0, 4.0, -1.0) | mat3(2.0, 2.5, 4.0, -7.0, 2.5, 3.0, 0.5, -3.5, 1.0) ];
			output float out0	= [ -4.5 | -5.0 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (mat3 a)
			{
				return -(a[0][0] + a[0][1] + a[0][2] + a[1][0] + a[1][1] + a[1][2] + a[2][0] + a[2][1] + a[2][2]);
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_mat4
		version 300 es
		values
		{
			input mat4 in0		= [ mat4(0.0, 1.0, -2.0, 0.5, 1.0, -1.0, 2.0, 4.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -2.0, -2.0) | mat4(2.0, 2.5, 4.0, -7.0, 2.5, 3.0, 0.5, -3.5, 1.0, 0.0, 2.0, -1.0, 1.0, 0.0, -1.0, 3.0) ];
			output float out0	= [ -5.5 | -9.0 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (mat4 a)
			{
				return -(a[0][0] + a[0][1] + a[0][2] + a[0][3] + a[1][0] + a[1][1] + a[1][2] + a[1][3] + a[2][0] + a[2][1] + a[2][2] + a[2][3] + a[3][0] + a[3][1] + a[3][2] + a[3][3]);
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case int_int
		version 300 es
		values
		{
			input int in0		= [ -1 | 0 | 1 | 4 ];
			output int out0		= [ 1 | 0 | -1 | -4 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (int a)
			{
				return -a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case int_ivec2
		version 300 es
		values
		{
			input ivec2 in0		= [ ivec2(-1, 0) | ivec2(1, 4) ];
			output int out0		= [ 1 | -5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (ivec2 a)
			{
				return -(a.x + a.y);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case int_ivec3
		version 300 es
		values
		{
			input ivec3 in0		= [ ivec3(-1, 0, 2) | ivec3(1, 4, -8) ];
			output int out0		= [ -1 | 3 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (ivec3 a)
			{
				return -(a.x + a.y + a.z);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case int_ivec4
		version 300 es
		values
		{
			input ivec4 in0		= [ ivec4(-1, 0, 2, 2) | ivec4(1, 4, -8, 2) ];
			output int out0		= [ -3 | 1 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (ivec4 a)
			{
				return -(a.x + a.y + a.z + a.w);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case uint_uint
		version 300 es
		values
		{
			input uint in0		= [ 1 | 0 | 2 | 4 ];
			output uint out0	= [ 1 | 0 | 4 | 16 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			uint func (uint a)
			{
				return a*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case uint_uvec2
		version 300 es
		values
		{
			input uvec2 in0		= [ uvec2(1, 0) | uvec2(2, 4) ];
			output uint out0	= [ 1 | 6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			uint func (uvec2 a)
			{
				return (a.x + a.y);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case uint_uvec3
		version 300 es
		values
		{
			input uvec3 in0		= [ uvec3(1, 0, 2) | uvec3(1, 4, 8) ];
			output uint out0		= [ 3 | 13 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			uint func (uvec3 a)
			{
				return (a.x + a.y + a.z);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case uint_uvec4
		version 300 es
		values
		{
			input uvec4 in0		= [ uvec4(1, 0, 2, 2) | uvec4(1, 4, 8, 2) ];
			output uint out0	= [ 5 | 15 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			uint func (uvec4 a)
			{
				return (a.x + a.y + a.z + a.w);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case bool_bool
		version 300 es
		values
		{
			input bool in0		= [ true | false ];
			output bool out0	= [ false | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (bool a)
			{
				return !a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case bool_bvec2
		version 300 es
		values
		{
			input bvec2 in0		= [ bvec2(true, true) | bvec2(false, true) ];
			output bool out0	= [ false | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (bvec2 a)
			{
				return !(a.x == a.y);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case bool_bvec3
		version 300 es
		values
		{
			input bvec3 in0		= [ bvec3(true, true, false) | bvec3(true, false, false) ];
			output bool out0	= [ false | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (bvec3 a)
			{
				return (a.x == a.y) == a.z;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case bool_bvec4
		version 300 es
		values
		{
			input bvec4 in0		= [ bvec4(true, true, true, false) | bvec4(false, false, true, true) | bvec4(true, false, false, true) ];
			output bool out0	= [ false | true | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (bvec4 a)
			{
				return ((a.x == a.y) == (a.z == a.w));
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case mat2
		version 300 es
		values
		{
			input mat2 in0	= [ mat2(-2.0, 0.5, -1.0, 1.0) | mat2(1.0, -3.5, -3.5, 2.5) | mat2(-2.0, -2.0, 3.5, 0.0) ];
			output mat2 out0	= [ mat2(4.0, -1.0, 2.0, -2.0) | mat2(-2.0, 7.0, 7.0, -5.0) | mat2(4.0, 4.0, -7.0, -0.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat2 func (mat2 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat2x3
		version 300 es
		values
		{
			input mat2x3 in0	= [ mat2x3(2.5, 0.0, 1.0, -2.5, 1.0, 3.0) | mat2x3(0.0, 2.0, 1.5, -3.5, 2.0, 0.5) | mat2x3(-1.5, -3.5, 2.5, 0.0, 1.5, 3.0) ];
			output mat2x3 out0	= [ mat2x3(-5.0, -0.0, -2.0, 5.0, -2.0, -6.0) | mat2x3(-0.0, -4.0, -3.0, 7.0, -4.0, -1.0) | mat2x3(3.0, 7.0, -5.0, -0.0, -3.0, -6.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat2x3 func (mat2x3 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat2x4
		version 300 es
		values
		{
			input mat2x4 in0	= [ mat2x4(1.5, 3.0, -1.0, 2.5, -0.5, 3.5, 3.0, -3.0) | mat2x4(-2.5, -2.0, 3.5, -0.5, 1.0, -1.5, 0.0, -1.0) | mat2x4(-1.0, 0.5, 0.5, 3.0, 1.5, 3.0, 2.5, 3.5) ];
			output mat2x4 out0	= [ mat2x4(-3.0, -6.0, 2.0, -5.0, 1.0, -7.0, -6.0, 6.0) | mat2x4(5.0, 4.0, -7.0, 1.0, -2.0, 3.0, -0.0, 2.0) | mat2x4(2.0, -1.0, -1.0, -6.0, -3.0, -6.0, -5.0, -7.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat2x4 func (mat2x4 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat3x2
		version 300 es
		values
		{
			input mat3x2 in0	= [ mat3x2(1.5, -2.5, 2.5, 3.5, 3.0, 0.5) | mat3x2(1.5, -2.0, 2.5, 0.5, -1.5, -3.5) | mat3x2(2.5, 3.5, -3.0, 2.5, -0.5, -2.5) ];
			output mat3x2 out0	= [ mat3x2(-3.0, 5.0, -5.0, -7.0, -6.0, -1.0) | mat3x2(-3.0, 4.0, -5.0, -1.0, 3.0, 7.0) | mat3x2(-5.0, -7.0, 6.0, -5.0, 1.0, 5.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat3x2 func (mat3x2 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat3
		version 300 es
		values
		{
			input mat3 in0	= [ mat3(-1.5, 2.0, 3.0, -3.5, 1.0, -3.5, 1.5, -1.5, 3.0) | mat3(3.5, 0.0, 3.5, -1.5, -3.0, 0.5, -3.5, -2.5, -0.5) | mat3(1.0, -2.5, -3.5, 3.0, -1.5, 3.5, 3.0, -1.0, -0.5) ];
			output mat3 out0	= [ mat3(3.0, -4.0, -6.0, 7.0, -2.0, 7.0, -3.0, 3.0, -6.0) | mat3(-7.0, -0.0, -7.0, 3.0, 6.0, -1.0, 7.0, 5.0, 1.0) | mat3(-2.0, 5.0, 7.0, -6.0, 3.0, -7.0, -6.0, 2.0, 1.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat3 func (mat3 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat3x4
		version 300 es
		values
		{
			input mat3x4 in0	= [ mat3x4(0.0, 1.0, 0.5, 0.5, 1.0, 3.5, 0.0, -0.5, 1.5, -2.0, -1.5, 3.5) | mat3x4(0.0, 0.5, -3.5, -0.5, 0.5, -3.5, 1.0, 1.0, -3.5, 1.0, -0.5, 1.5) | mat3x4(-1.0, 1.5, 2.0, -3.5, -3.5, 1.5, 3.5, -2.0, -0.5, 0.5, -1.5, -1.0) ];
			output mat3x4 out0	= [ mat3x4(-0.0, -2.0, -1.0, -1.0, -2.0, -7.0, -0.0, 1.0, -3.0, 4.0, 3.0, -7.0) | mat3x4(-0.0, -1.0, 7.0, 1.0, -1.0, 7.0, -2.0, -2.0, 7.0, -2.0, 1.0, -3.0) | mat3x4(2.0, -3.0, -4.0, 7.0, 7.0, -3.0, -7.0, 4.0, 1.0, -1.0, 3.0, 2.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat3x4 func (mat3x4 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat4x2
		version 300 es
		values
		{
			input mat4x2 in0	= [ mat4x2(-1.5, -1.0, 0.5, -1.5, -1.0, 2.0, -3.5, 0.5) | mat4x2(2.0, -1.5, -2.0, 2.5, -2.0, -2.5, -0.5, 1.5) | mat4x2(-3.0, -1.5, -1.0, 2.5, -0.5, 2.5, -2.5, -1.0) ];
			output mat4x2 out0	= [ mat4x2(3.0, 2.0, -1.0, 3.0, 2.0, -4.0, 7.0, -1.0) | mat4x2(-4.0, 3.0, 4.0, -5.0, 4.0, 5.0, 1.0, -3.0) | mat4x2(6.0, 3.0, 2.0, -5.0, 1.0, -5.0, 5.0, 2.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat4x2 func (mat4x2 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat4x3
		version 300 es
		values
		{
			input mat4x3 in0	= [ mat4x3(1.0, 3.0, -0.5, -2.0, -3.0, 0.0, -2.5, 2.5, 2.5, -2.5, -1.5, 2.5) | mat4x3(1.0, 2.5, -1.0, -3.0, -1.5, 2.0, -1.5, -1.0, -0.5, -0.5, -0.5, 3.0) | mat4x3(-2.5, -3.5, 3.5, 3.0, 3.5, -0.5, 3.5, 3.0, -2.0, 2.0, 2.5, 1.0) ];
			output mat4x3 out0	= [ mat4x3(-2.0, -6.0, 1.0, 4.0, 6.0, -0.0, 5.0, -5.0, -5.0, 5.0, 3.0, -5.0) | mat4x3(-2.0, -5.0, 2.0, 6.0, 3.0, -4.0, 3.0, 2.0, 1.0, 1.0, 1.0, -6.0) | mat4x3(5.0, 7.0, -7.0, -6.0, -7.0, 1.0, -7.0, -6.0, 4.0, -4.0, -5.0, -2.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat4x3 func (mat4x3 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end


	case mat4
		version 300 es
		values
		{
			input mat4 in0	= [ mat4(0.0, -1.5, -1.0, -2.0, -3.0, 0.5, -1.5, 2.5, -3.5, 3.0, 1.5, 3.0, 3.0, 3.0, 0.5, -3.5) | mat4(2.0, -2.5, -1.5, 1.0, 0.0, -0.5, 3.5, 1.0, -1.0, -2.0, 2.5, 0.0, 2.0, -1.0, -2.5, 0.5) | mat4(2.5, -2.5, 2.0, 3.0, 2.5, 2.5, -3.5, 1.0, 2.5, -3.5, -1.5, -1.5, 0.0, -0.5, 0.0, 2.0) ];
			output mat4 out0	= [ mat4(-0.0, 3.0, 2.0, 4.0, 6.0, -1.0, 3.0, -5.0, 7.0, -6.0, -3.0, -6.0, -6.0, -6.0, -1.0, 7.0) | mat4(-4.0, 5.0, 3.0, -2.0, -0.0, 1.0, -7.0, -2.0, 2.0, 4.0, -5.0, -0.0, -4.0, 2.0, 5.0, -1.0) | mat4(-5.0, 5.0, -4.0, -6.0, -5.0, -5.0, 7.0, -2.0, -5.0, 7.0, 3.0, 3.0, -0.0, 1.0, -0.0, -4.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			mat4 func (mat4 a)
			{
				return -2.0*a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case float_struct
		version 300 es
		values
		{
			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
			output float out0	= [ 1.0 | -0.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			struct Pos { float a, b, c; };

			float func (Pos p)
			{
				return -(p.a + p.b + p.c);
			}

			void main()
			{
				Pos p = Pos(in0.x, in0.y, in0.z);
				out0 = func(p);
				${OUTPUT}
			}
		""
	end

	case struct_struct
		version 300 es
		values
		{
			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
			output float out0	= [ 1.0 | -0.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			struct Pos { float a, b, c; };

			Pos func (Pos p)
			{
				return Pos(-p.a, -p.b, -p.c);
			}

			void main()
			{
				Pos p = Pos(in0.x, in0.y, in0.z);
				p = func(p);
				out0 = p.a + p.b + p.c;
				${OUTPUT}
			}
		""
	end

	case struct_nested_struct
		version 300 es
		values
		{
			input vec3 in0		= [ vec3(0.0, 1.0, -2.0) | vec3(2.0, 2.5, -4.0) ];
			output float out0	= [ 1.0 | -0.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			struct Pos { float a, b, c; };
			struct Line { Pos start, end; };

			Line func (Pos p)
			{
				return Line(p, Pos(-p.a, -p.b, -p.c));
			}

			float sum (Pos p)
			{
				return (p.a + p.b + p.c);
			}

			void main()
			{
				Pos p = Pos(in0.x, in0.y, in0.z);
				Line line = func(p);
				out0 = sum(line.start) + (2.0 * sum(line.end));
				${OUTPUT}
			}
		""
	end

	case struct_constructor_highp_in_fragment
		version 300 es
		desc "passing highp vector to struct constructor in fragment shader yields all zeros"
		vertex ""
			#version 300 es
			${VERTEX_DECLARATIONS}
			void main()
			{
				${VERTEX_OUTPUT}
			}
		""
		fragment ""
			#version 300 es
			${FRAGMENT_DECLARATIONS}
			#ifdef GL_FRAGMENT_PRECISION_HIGH
			#define PRECISION highp
			#else
			#define PRECISION mediump
			#endif
			struct Test {
				PRECISION vec3 color;
			} ;
			void main() {
				PRECISION vec3 color = vec3(0.2, 2.0, 0.1);
				Test test = Test(color);
				// Bias the color so all components are guaranteed > 1.0.
				${FRAG_COLOR} = vec4(vec3(0.25, 0.55, 0.65) + vec3(4.0, 0.25, 4.0) * test.color, 1.0);
			}
		""
	end


end # datatypes

group qualifiers "Function Parameter Qualifiers"

	case in_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (in float a)
			{
				a = -a;
				return 2.0 * a;
			}

			void main()
			{
				${SETUP}
				float f = in0;
				float g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case out_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (out float a)
			{
				a = -1.0;
			}

			void main()
			{
				${SETUP}
				float f = 1.0;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case inout_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (inout float a)
			{
				a = -a;
			}

			void main()
			{
				${SETUP}
				float f = 1.0;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case in_lowp_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (in lowp float a)
			{
				a = -a;
				return 2.0 * a;
			}

			void main()
			{
				${SETUP}
				float f = in0;
				float g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case out_lowp_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (out lowp float a)
			{
				a = -1.0;
			}

			void main()
			{
				${SETUP}
				float f = 1.0;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case inout_lowp_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (inout lowp float a)
			{
				a = -a;
			}

			void main()
			{
				${SETUP}
				float f = 1.0;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case in_highp_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (in highp float a)
			{
				a = -a;
				return 2.0 * a;
			}

			void main()
			{
				${SETUP}
				float f = in0;
				float g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case out_highp_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (out highp float a)
			{
				a = -1.0;
			}

			void main()
			{
				${SETUP}
				float f = 1.0;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case inout_highp_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (inout highp float a)
			{
				a = -a;
			}

			void main()
			{
				${SETUP}
				float f = 1.0;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case const_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (const float a)
			{
				float b = -a;
				return 2.0 * b;
			}

			void main()
			{
				${SETUP}
				float f = in0;
				float g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case const_in_float
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (const in float a)
			{
				float b = -a;
				return 2.0 * b;
			}

			void main()
			{
				${SETUP}
				float f = in0;
				float g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case in_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 4 ];
			output int out0		= [ 0 | -1 | 2 | -4 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (in int a)
			{
				a = -a;
				return 2 * a;
			}

			void main()
			{
				${SETUP}
				int f = in0;
				int g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case out_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (out int a)
			{
				a = -1;
			}

			void main()
			{
				${SETUP}
				int f = 1;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case inout_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (inout int a)
			{
				a = -a;
			}

			void main()
			{
				${SETUP}
				int f = 1;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case in_lowp_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 4 ];
			output int out0		= [ 0 | -1 | 2 | -4 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (in lowp int a)
			{
				a = -a;
				return 2 * a;
			}

			void main()
			{
				${SETUP}
				int f = in0;
				int g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case out_lowp_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (out lowp int a)
			{
				a = -1;
			}

			void main()
			{
				${SETUP}
				int f = 1;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case inout_lowp_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (inout lowp int a)
			{
				a = -a;
			}

			void main()
			{
				${SETUP}
				int f = 1;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case in_highp_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 4 ];
			output int out0		= [ 0 | -1 | 2 | -4 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (in highp int a)
			{
				a = -a;
				return 2 * a;
			}

			void main()
			{
				${SETUP}
				int f = in0;
				int g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case out_highp_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (out highp int a)
			{
				a = -1;
			}

			void main()
			{
				${SETUP}
				int f = 1;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case inout_highp_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (inout highp int a)
			{
				a = -a;
			}

			void main()
			{
				${SETUP}
				int f = 1;
				func(f);
				out0 = f * in0;
				${OUTPUT}
			}
		""
	end

	case const_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 4 ];
			output int out0		= [ 0 | -1 | 2 | -4 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (const int a)
			{
				int b = -a;
				return 2 * b;
			}

			void main()
			{
				${SETUP}
				int f = in0;
				int g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case const_in_int
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 4 ];
			output int out0		= [ 0 | -1 | 2 | -4 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (const in int a)
			{
				int b = -a;
				return 2 * b;
			}

			void main()
			{
				${SETUP}
				int f = in0;
				int g = func(f);
				out0 = f + g;
				${OUTPUT}
			}
		""
	end

	case in_bool
		version 300 es
		values
		{
			input bool in0		= [ true | false ];
			output bool out0	= [ true | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (in bool a)
			{
				a = !a;
				return a;
			}

			void main()
			{
				${SETUP}
				bool f = in0;
				bool g = func(f);
				out0 = (f != g);
				${OUTPUT}
			}
		""
	end

	case out_bool
		version 300 es
		values
		{
			input bool in0		= [ true | false ];
			output bool out0	= [ false | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (out bool a)
			{
				a = false;
			}

			void main()
			{
				${SETUP}
				bool f = true;
				func(f);
				out0 = (in0 == f);
				${OUTPUT}
			}
		""
	end

	case inout_bool
		version 300 es
		values
		{
			input bool in0		= [ true | false ];
			output bool out0	= [ false | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (inout bool a)
			{
				a = !a;
			}

			void main()
			{
				${SETUP}
				bool f = true;
				func(f);
				out0 = (in0 == f);
				${OUTPUT}
			}
		""
	end

	case const_bool
		version 300 es
		values
		{
			input bool in0		= [ true | false ];
			output bool out0	= [ true | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (const bool a)
			{
				bool b = !a;
				return b;
			}

			void main()
			{
				${SETUP}
				bool f = in0;
				bool g = func(f);
				out0 = (f != g);
				${OUTPUT}
			}
		""
	end

end # qualifiers

group declarations "Function Declarations"

	case basic
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (void);

			float func (void)
			{
				return -1.0;
			}

			void main()
			{
				out0 = func() * in0;
				${OUTPUT}
			}
		""
	end

	case basic_arg
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f);

			float func (float f)
			{
				return -f;
			}

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case define_after_use
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (void);

			void main()
			{
				out0 = func() * in0;
				${OUTPUT}
			}

			float func (void)
			{
				return -1.0;
			}
		""
	end

	case double_declare
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (void);

			float func (void);

			float func (void)
			{
				return -1.0;
			}

			void main()
			{
				out0 = func() * in0;
				${OUTPUT}
			}
		""
	end

	case declare_after_define
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (void)
			{
				return -1.0;
			}

			float func (void);

			void main()
			{
				out0 = func() * in0;
				${OUTPUT}
			}
		""
	end

	case void_vs_no_void
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func ();

			void main()
			{
				out0 = func() * in0;
				${OUTPUT}
			}

			float func (void)
			{
				return -1.0;
			}
		""
	end

	case in_vs_no_in
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f);

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}

			float func (in float f)
			{
				return -f;
			}
		""
	end

	case default_vs_explicit_precision
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f);

			void main()
			{
				out0 = func(in0);
				${OUTPUT}
			}

			float func (mediump float f)
			{
				return -f;
			}
		""
	end


end # declarations

group overloading "Function Overloading"

	case user_func_arg_type_simple
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (float a)
			{
				return -a;
			}

			int func (int a)
			{
				return -a;
			}

			void main()
			{
				out0 = func(in0) * float(func(-1));
				${OUTPUT}
			}
		""
	end

	case user_func_arg_float_types
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (float a) { return -a; }
			vec2 func (vec2 a) { return a.yx; }
			vec3 func (vec3 a) { return a.xxx; }
			vec4 func (vec4 a) { return a.wwww; }

			void main()
			{
				out0 = func(func(func(func(vec4(in0)).xyz).xy).x);
				${OUTPUT}
			}
		""
	end

	case user_func_arg_int_types
		version 300 es
		values
		{
			input int in0		= [ 0 | 1 | -2 | 6 ];
			output int out0		= [ 0 | -1 | 2 | -6 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (int a) { return -a; }
			ivec2 func (ivec2 a) { return a.yx; }
			ivec3 func (ivec3 a) { return a.xxx; }
			ivec4 func (ivec4 a) { return a.wwww; }

			void main()
			{
				${SETUP}
				out0 = func(func(func(func(ivec4(in0)).xyz).xy).x);
				${OUTPUT}
			}
		""
	end

	case user_func_arg_bool_types
		version 300 es
		values
		{
			input bool in0		= [ true | false ];
			output bool out0	= [ false | true ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (bool a) { return !a; }
			bvec2 func (bvec2 a) { return a.yx; }
			bvec3 func (bvec3 a) { return a.xxx; }
			bvec4 func (bvec4 a) { return a.wwww; }

			void main()
			{
				${SETUP}
				out0 = func(func(func(func(bvec4(in0)).xyz).xy).x);
				${OUTPUT}
			}
		""
	end

	case user_func_arg_basic_types
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			float func (float a) { return -a; }
			vec2 func (vec2 a) { return a.yx; }
			vec3 func (vec3 a) { return a.xxx; }
			vec4 func (vec4 a) { return a.wwww; }
			int func (int a) { return -a; }
			ivec2 func (ivec2 a) { return a.yx; }
			ivec3 func (ivec3 a) { return a.xxx; }
			ivec4 func (ivec4 a) { return a.wwww; }
			bool func (bool a) { return !a; }
			bvec2 func (bvec2 a) { return a.yx; }
			bvec3 func (bvec3 a) { return a.xxx; }
			bvec4 func (bvec4 a) { return a.wwww; }

			void main()
			{
				${SETUP}
				if (func(func(bvec4(false)).x))
					out0 = func(in0) * float(func(-1));
				else
					out0 = float(func(func(ivec4(func(func(func(vec4(0.5)).xyz).xy).xxxx)).xy).x);
				${OUTPUT}
			}
		""
	end

	case user_func_arg_complex_types
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			struct Pos { float a, b, c; };
			struct Line { Pos start, end; };

			float func (float a) { return -a; }
			float func (float a[4]) { return a[0] + a[3]; }
			vec2 func (vec2 a) { return a.yx; }
			vec3 func (vec3 a) { return a.xxx; }
			vec4 func (vec4 a) { return a.wwww; }
			vec4 func (vec4 a[4]) { return a[1] + a[2]; }
			int func (int a) { return -a; }
			ivec2 func (ivec2 a) { return a.yx; }
			ivec3 func (ivec3 a) { return a.xxx; }
			ivec4 func (ivec4 a) { return a.wwww; }
			bool func (bool a) { return !a; }
			bvec2 func (bvec2 a) { return a.yx; }
			bvec3 func (bvec3 a) { return a.xxx; }
			bvec4 func (bvec4 a) { return a.wwww; }
			Pos func (Pos a) { return a; }
			Line func (Line a) { return Line(a.end, a.start); }

			void main()
			{
				${SETUP}
				float arr[4];
				vec4 arr2[4];
				out0 = func(arr) + func(arr2).x;
				if (func(func(bvec4(false)).x))
					out0 = func(in0) * float(func(-1));
				else
					out0 = float(func(func(ivec4(func(func(func(vec4(0.5)).xyz).xy).xxxx)).xy).x);
				${OUTPUT}
			}
		""
	end

	case user_func_arguments
		version 300 es
		values
		{
			input float in0		= [ 0.0 | 1.0 | -2.0 | 2.5 ];
			output float out0	= [ 0.0 | -1.0 | 2.0 | -2.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				return -a;
			}

			float func (float a, float b)
			{
				return a * b;
			}

			void main()
			{
				out0 = func(in0) * func(-0.5, -2.0);
				${OUTPUT}
			}
		""
	end

	case array_size
		version 300 es
		values
		{
			output float out0	= [ 1.0 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f[3])
			{
				return f[0];
			}

			float func (float f[4])
			{
				return f[1];
			}

			void main ()
			{
				${SETUP}
				float[4] x = float[4] (-1.0, 1.0, 0.0, 0.0);
				out0 = func(x);
				${OUTPUT}
			}
		""
	end

end # overloading

group array_arguments "Arrays as Arguments"

	case local_in_float
		version 300 es
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (in float a[4])
			{
				a[0] = -1.0;
				a[2] = -4.0;
				a[3] = -3.0 * a[1];
				return a[0];
			}

			void main()
			{
				float arr[4];
				arr[0] = in0.x;
				arr[1] = in0.y;
				arr[2] = in0.z;
				arr[3] = in0.w;
				float f = func(arr);
				out0 = f * vec4(arr[0], arr[1], arr[2], arr[3]);
				${OUTPUT}
			}
		""
	end

	case global_in_float
		version 300 es
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (in float a[4])
			{
				a[0] = -1.0;
				a[2] = -4.0;
				a[3] = -3.0 * a[1];
				return a[0];
			}

			float arr[4];

			void main()
			{
				arr[0] = in0.x;
				arr[1] = in0.y;
				arr[2] = in0.z;
				arr[3] = in0.w;
				float f = func(arr);
				out0 = f * vec4(arr[0], arr[1], arr[2], arr[3]);
				${OUTPUT}
			}
		""
	end

	case local_in_int
		version 300 es
		values
		{
			input ivec4 in0		= [ ivec4(0, 1, 2, -4) | ivec4(-7, -11, 13, 19) ];
			output ivec4 out0	= [ ivec4(0, -1, -2, 4) | ivec4(7, 11, -13, -19) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (in int a[4])
			{
				a[0] = -1;
				a[2] = -4;
				a[3] = -3 * a[1];
				return a[0];
			}

			void main()
			{
				${SETUP}
				int arr[4];
				arr[0] = in0.x;
				arr[1] = in0.y;
				arr[2] = in0.z;
				arr[3] = in0.w;
				int f = func(arr);
				out0 = f * ivec4(arr[0], arr[1], arr[2], arr[3]);
				${OUTPUT}
			}
		""
	end

	case global_in_int
		version 300 es
		values
		{
			input ivec4 in0		= [ ivec4(0, 1, 2, 4) | ivec4(-7, -11, 13, 19) ];
			output ivec4 out0	= [ ivec4(0, -1, -2, -4) | ivec4(7, 11, -13, -19) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (in int a[4])
			{
				a[0] = -1;
				a[2] = -4;
				a[3] = -3 * a[1];
				return a[0];
			}

			int arr[4];

			void main()
			{
				${SETUP}
				arr[0] = in0.x;
				arr[1] = in0.y;
				arr[2] = in0.z;
				arr[3] = in0.w;
				int f = func(arr);
				out0 = f * ivec4(arr[0], arr[1], arr[2], arr[3]);
				${OUTPUT}
			}

		""
	end

	case local_in_bool
		version 300 es
		values
		{
			input bvec4 in0		= [ bvec4(true, true, false, true) | bvec4(false, false, false, false) ];
			output bvec4 out0	= [ bvec4(false, false, true, false) | bvec4(true, true, true, true) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (in bool a[4])
			{
				a[0] = false;
				a[2] = true;
				a[3] = !a[1];
				return a[0];
			}

			void main()
			{
				${SETUP}
				bool arr[4];
				arr[0] = !in0.x;
				arr[1] = !in0.y;
				arr[2] = !in0.z;
				arr[3] = !in0.w;
				func(arr);
				out0 = bvec4(arr[0], arr[1], arr[2], arr[3]);
				${OUTPUT}
			}
		""
	end

	case global_in_bool
		version 300 es
		values
		{
			input bvec4 in0		= [ bvec4(true, true, false, true) | bvec4(false, false, false, false) ];
			output bvec4 out0	= [ bvec4(false, false, true, false) | bvec4(true, true, true, true) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			bool func (in bool a[4])
			{
				a[0] = false;
				a[2] = true;
				a[3] = !a[1];
				return a[0];
			}

			bool arr[4];

			void main()
			{
				${SETUP}
				arr[0] = !in0.x;
				arr[1] = !in0.y;
				arr[2] = !in0.z;
				arr[3] = !in0.w;
				func(arr);
				out0 = bvec4(arr[0], arr[1], arr[2], arr[3]);
				${OUTPUT}
			}
		""
	end

	case test_helpers
		version 300 es
		desc "Check that helper functions are supported properly."
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output float out0	= [ 1.0 | 1.0 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			vec4 get (in float arr[4]);
			void set (out float arr[4], vec4 val);
			void negate (inout float arr[4]);
			bool test (in float arr[4], vec4 ref);
			bool isEqual (in float a[4], in float b[4]);

			void main()
			{
				float arr[4];
				set(arr, in0);
				negate(arr);
				out0 = float(test(arr, -in0));
				${OUTPUT}
			}

			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
			void negate (inout float arr[4]) { set(arr, -get(arr)); }
			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
		""
	end

	case copy_local_in_on_call
		version 300 es
		desc "Check that local 'in' arguments are copied on call and don't alias."
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			vec4 get (in float arr[4]);
			void set (out float arr[4], vec4 val);
			void negate (inout float arr[4]);
			bool test (in float arr[4], vec4 ref);
			bool isEqual (in float a[4], in float b[4]);

			float func (in float a[4], in float b[4])
			{
				a[0] = 2.123;
				a[2] = -4.123;
				return isEqual(a, b) ? 1.0 : -1.0;
			}

			void main()
			{
				float arr[4];
				set(arr, in0);
				out0 = in0 * func(arr, arr);
				${OUTPUT}
			}

			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
			void negate (inout float arr[4]) { set(arr, -get(arr)); }
			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
		""
	end

	case copy_global_in_on_call
		version 300 es
		desc "Check that global 'in' arguments are copied on call and don't alias."
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			vec4 get (in float arr[4]);
			void set (out float arr[4], vec4 val);
			void negate (inout float arr[4]);
			bool test (in float arr[4], vec4 ref);
			bool isEqual (in float a[4], in float b[4]);

			float func (in float a[4], in float b[4])
			{
				a[0] = 2.123;
				a[2] = -4.123;
				return isEqual(a, b) ? 1.0 : -1.0;
			}

			float arr[4];

			void main()
			{
				set(arr, in0);
				out0 = in0 * func(arr, arr);
				${OUTPUT}
			}

			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
			void negate (inout float arr[4]) { set(arr, -get(arr)); }
			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
		""
	end

	case copy_local_inout_on_call
		version 300 es
		desc "Check that local 'in' arguments are copied on call and don't alias."
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			vec4 get (in float arr[4]);
			void set (out float arr[4], vec4 val);
			void negate (inout float arr[4]);
			bool test (in float arr[4], vec4 ref);
			bool isEqual (in float a[4], in float b[4]);

			float func (inout float a[4], inout float b[4])
			{
				negate(a);
				return isEqual(a, b) ? 1.0 : -1.0;
			}

			void main()
			{
				float arr[4];
				set(arr, in0);
				float m = func(arr, arr); // returns -1.0
				float n = float(test(arr, in0) || test(arr, -in0));
				out0 = in0 * m * n;
				${OUTPUT}
			}

			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
			void negate (inout float arr[4]) { set(arr, -get(arr)); }
			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
		""
	end

	case copy_global_inout_on_call
		version 300 es
		desc "Check that global 'in' arguments are copied on call and don't alias."
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, 2.0, -4.0) | vec4(-7.5, 12.125, -0.25, 16.0) ];
			output vec4 out0	= [ vec4(0.0, -1.0, -2.0, 4.0) | vec4(7.5, -12.125, 0.25, -16.0) ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			vec4 get (in float arr[4]);
			void set (out float arr[4], vec4 val);
			void negate (inout float arr[4]);
			bool test (in float arr[4], vec4 ref);
			bool isEqual (in float a[4], in float b[4]);

			float func (in float a[4], in float b[4])
			{
				negate(a);
				return isEqual(a, b) ? 1.0 : -1.0;
			}

			float arr[4];

			void main()
			{
				set(arr, in0);
				float m = func(arr, arr); // returns -1.0
				float n = float(test(arr, in0) || test(arr, -in0));
				out0 = in0 * m * n;
				${OUTPUT}
			}

			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
			void negate (inout float arr[4]) { set(arr, -get(arr)); }
			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }
		""
	end

#			vec4 get (in float arr[4]);
#			void set (out float arr[4], vec4 val);
#			void negate (inout float arr[4]);
#			bool test (in float arr[4], vec4 ref);
#			bool isEqual (in float a[4], in float b[4]);

#			float absDiff (vec4 a, vec4 b) { vec4 d = abs(a - b); return max(max(d.x, d.y), max(d.z, d.w)); }
#			vec4 get (in float arr[4]) { return vec4(arr[0], arr[1], arr[2], arr[3]); }
#			void set (out float arr[4], vec4 val) { arr[0] = val.x; arr[1] = val.y; arr[2] = val.z; arr[3] = val.w; }
#			void negate (inout float arr[4]) { set(arr, -get(arr)); }
#			bool test (in float arr[4], vec4 ref) { return (absDiff(get(arr), ref) < 0.1); }
#			bool isEqual (in float a[4], in float b[4]) { return (absDiff(get(a), get(b)) < 0.1); }

end # array_arguments

#group qualifiers "Function Parameter Qualifiers"
#
#end # qualifiers

group control_flow "Control Flow In Functions"

	case simple_return
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				return -a;
				a = a * -1.0;
				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_in_if
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				if (a != 0.0)
					return -a;
				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_in_else
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				if (a == 0.0)
					return 1.0;
				else
					return -a;
				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_in_loop
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				while (a < 100.0)
					return -a;
				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_in_loop_if
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				while (a < 100.0)
				{
					a = -a;
					if (a != 0.0)
						return a;
					else
						return -1.0;
				}
				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_after_loop
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				for (int i = 0; i < 5; i++)
					a = -a;
				return a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_after_break
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				for (int i = 0; i < 6; i++)
				{
					a = -a;
					if (i == 4)
						break;
				}
				return a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_after_continue
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				for (int i = 0; i < 6; i++)
				{
					if (i == 4)
						continue;
					a = -a;
				}
				return a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_in_nested_loop
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				for (int i = 0; i < 6; i++)
				{
					a = -a;
					for (int j = 0; j < 4; j++)
					{
						a = -a;
						if (i == 1)
							return a;
					}
					if (i == 4)
						return 1.0;
				}
				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case return_after_loop_sequence
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				int i;
				for (i = 0; i < 6; i++) // negate a
				{
					a = -a;
					if (i == 4)
						a = -a;
				}

				for (; i < 10; i++) // keep a
				{
					if (i == 8)
						continue;
					else if (i == 9)
						break;
					a = -a;
				}

				return a;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

	case mixed_return_break_continue
		version 300 es
		values
		{
			input float in0		= [ -0.5 | 1.5 ];
			output float out0	= [ 0.5 | -1.5 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float a)
			{
				int i;
				for (i = 0; i < 6; i++)
				{
					if (i == 0)
						continue;
					else if (i == 1)
					{
					}
					else if (i == 3)
						break;
					else
						return a;
					a = -a;
				}

				return 1.0;
			}

			void main()
			{
				${SETUP}
				out0 = func(in0);
				${OUTPUT}
			}
		""
	end

end # control_flow

group misc "Miscellaneous"

	case multi_arg_float
		version 300 es
		values
		{
			input vec4 in0		= [ vec4(0.0, 1.0, -2.0, 0.5) | vec4(2.0, 2.5, 4.0, -7.0) ];
			output float out0	= [ 0.5 | -1.5 ]; # -sum(in0)
		}

		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float sum(vec4 v) { return (v.x + v.y + v.z + v.w); }

			float func (float a, vec3 b, vec2 c, vec2 d, vec4 e)
			{
				return -sum(vec4(a, b) + vec4(c, d)) + sum(e);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0.y, in0.xzw, in0.wz, in0.yx, in0);
				${OUTPUT}
			}
		""
	end

	case multi_arg_int
		version 300 es
		values
		{
			input ivec4 in0		= [ ivec4(-1, 0, 2, 2) | ivec4(1, 4, -8, 2) ];
			output int out0		= [ -3 | 1 ];
		}

		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int sum(ivec4 v) { return (v.x + v.y + v.z + v.w); }

			int func (int a, ivec3 b, ivec2 c, ivec2 d, ivec4 e)
			{
				return -sum(ivec4(a, b) + ivec4(c, d)) + sum(e);
			}

			void main()
			{
				${SETUP}
				out0 = func(in0.y, in0.xzw, in0.wz, in0.yx, in0);
				${OUTPUT}
			}
		""
	end

	case argument_eval_order_1
		version 300 es
		values
		{
			input int in0	= [  0 | 1 | 3 | 5 ];
			output int out0	= [ -1 | 5 | 11 | 17 ];
		}

		both ""
			#version 300 es
			precision highp float;
			${DECLARATIONS}

			int func (float a, int b, bool c, int d)
			{
				if (c)
					return b + int(a) + d;
				else
					return -1;
			}

			void main ()
			{
				${SETUP}
				float v0 = float(in0);
				int v1 = in0;
				out0 = func((v0 += 1.0), v1++, (v0 > 1.5), v1);
				${OUTPUT}
			}
		""
	end

	case argument_eval_order_2
		version 300 es
		values
		{
			input int in0	= [ 0 | -1 | 3 | 5 ];
			output int out0	= [ 3 | -1 | 9 | 13 ];
		}

		both ""
			#version 300 es
			precision highp float;
			${DECLARATIONS}

			int g;

			int modG (int v)
			{
				g += v;
				return v;
			}

			int func (float a, int b, bool c, int d)
			{
				if (c)
					return b + int(a) + d;
				else
					return -1;
			}

			void main ()
			{
				${SETUP}
				out0 = func(float(g = in0), modG(2), --g > 0, g);
				${OUTPUT}
			}
		""
	end

end # misc

group invalid "Invalid Functions"
	case break_in_body
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func ()
			{
				break;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case continue_in_body
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func ()
			{
				continue;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case return_value_from_void_function
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func ()
			{
				return 1.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case extra_arguments
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (float f)
			{
			}

			void main ()
			{
				func(1.0, 2.0);
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case missing_arguments
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (float f)
			{
			}

			void main ()
			{
				func();
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case missing_argument_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (in f)
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case argument_basetype_mismatch
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			void func (float f)
			{
			}

			void main ()
			{
				func(2);
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case argument_scalar_vector_mismatch
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec2 f)
			{
			}

			void main ()
			{
				func(2.0);
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case argument_vector_size_mismatch
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f)
			{
			}

			void main ()
			{
				func(vec2(2.0));
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case duplicate_function
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f);

			void func (vec3 f)
			{
			}

			void func (vec3 f)
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case prototype_mismatch_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f);

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}

			float func (vec3 f)
			{
				return f.x;
			}
		""
	end

	case prototype_unspecified_array_size
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f[]);

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case call_mismatch_argument_array_size
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f[3]);
			void func (vec3 f[3])
			{
			}

			void main ()
			{
				vec3 array[4];
				func(array);
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case prototype_mismatch_argument_const
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f);
			void func (const vec3 f)
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case prototype_mismatch_argument_array_const
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f[3]);
			void func (const vec3 f[3])
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case prototype_mismatch_array_inout
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (out vec3 f);
			void func (inout vec3 f)
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case missing_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			func (float f);
			func (inout vec3 f[3])
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case call_before_definition
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void main ()
			{
				func(1.0);
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}

			void func (float f)
			{
			}

		""
	end

	case argument_precision_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (lowp float f)
			{
				return f;
			}

			float func (mediump float f)
			{
				return f;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case argument_in_out_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (in float f)
			{
			}

			void func (out float f)
			{
				f = 1.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case argument_in_inout_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (in float f)
			{
			}

			void func (inout float f)
			{
				f = -f;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case argument_out_inout_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (out float f)
			{
				f = -1.0;
			}

			void func (inout float f)
			{
				f = -f;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case return_type_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f)
			{
				return f;
			}

			int func (float f)
			{
				return int(f);
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case return_type_precision_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			lowp float func (float f)
			{
				return f;
			}

			mediump float func (float f)
			{
				return f;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case return_type_const_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f)
			{
				return f;
			}

			const float func (float f)
			{
				return f;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case return_without_value
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (float f)
			{
				return;
				return 1.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case local_function_prototype
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void main ()
			{
				float func (float f);

				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case local_function_definition
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void main ()
			{
				float func (float f)
				{
					return 1.0;
				}

				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case name_type_conflict
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			struct foo { float a; }

			float foo (float f)
			{
				return 1.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case const_overload
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f)
			{
			}

			void func (const vec3 f)
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case uniform_local
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f)
			{
				uniform float u;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case in_local
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f)
			{
				in float v;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case out_local
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f)
			{
				in float a;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case inout_local
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (vec3 f)
			{
				inout float a;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case uniform_argument
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void func (uniform vec3 f)
			{
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case uniform_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			uniform float func (vec3 f)
			{
				return f.x;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case in_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			in float func (vec3 f)
			{
				return f.x;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(func(vec3(1.0)));
			}
		""
	end

	case out_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			out float func (vec3 f)
			{
				return f.x;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(func(vec3(1.0)));
			}
		""
	end

	case inout_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			inout float func (vec3 f)
			{
				return f.x;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(func(vec3(1.0)));
			}
		""
	end

	case main_invalid_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case main_has_arguments
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			void main (float f)
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case main_missing_return_type
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case write_const_arg
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (const float f)
			{
				f = 1.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case write_const_array_arg
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (const float f[3])
			{
				f[0] = 1.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(1.0);
			}
		""
	end

	case use_const_arg_in_const_expr
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (const int i)
			{
				const int z = i+1;
				return float(z);
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(func(1));
			}
		""
	end

	case use_const_arg_as_array_size
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float func (const int i)
			{
				float f[i];
				f[0] = 1.0;
				return f[0];
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(func(1));
			}
		""
	end

	case overload_builtin_function
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			int sin (int x)
			{
				return int(sin(float(x)));
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(sin(1));
			}
		""
	end

	case redefine_builtin_function
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float sin (float x)
			{
				return 0.0;
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(sin(1.0));
			}
		""
	end

	case basic_recursion
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float fib (float x)
			{
				if (x <= 1.0)
					return x;
				else
					return fib(x-2.0) + fib(x-1.0);
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(fib(5.0));
			}
		""
	end

	case simple_tail_recursion
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}

			float rec (float x)
			{
				if (x <= 0.0)
					return 0.0;
				else
					return rec(x-1.0);
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(rec(5.0));
			}
		""
	end

	case dynamic_conditional_recursion
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}
			uniform float ua;
			uniform float ub;

			float funcA (float x);
			float funcB (float x);

			float funcA (float x)
			{
				if (ub+x > 0.0)
					funcB(x*2.0);
				else
					return ub;
			}

			float funcB (float x)
			{
				return sqrt(funcA(x));
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(funcB(ua));
			}
		""
	end

	case dynamic_loop_recursion
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}
			uniform float ua;
			uniform float ub;

			float funcA (float x);
			float funcB (float x);

			float funcA (float x)
			{
				for (float z = 0.0; z < ub+x; z++)
				{
					if (z > 2.0)
						funcB(z*2.0);
					else
						return z;
				}
			}

			float funcB (float x)
			{
				return sqrt(funcA(x));
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(funcB(ua));
			}
		""
	end

	case dynamic_switch_recursion
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			${DECLARATIONS}
			uniform float ua;
			uniform mediump int ub;

			float funcA (float x);
			float funcB (float x);

			float funcA (float x)
			{
				switch (ub + int(x))
				{
					case 0: return ua-1.0;
					case 1: return ua;
					case 2: return funcB(x*2.0);
					default: return 0.0;
				}
			}

			float funcB (float x)
			{
				return sqrt(funcA(x));
			}

			void main ()
			{
				${POSITION_FRAG_COLOR} = vec4(funcB(ua));
			}
		""
	end

	case modify_const_arg
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (const int a)
			{
				a = -a;
				return 2 * a;
			}

			void main()
			{
				${POSITION_FRAG_COLOR} = vec4(func(3));
			}
		""
	end

	case init_const_local_from_const_arg
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (const int a)
			{
				const int b = -a;
				return 2 * b;
			}

			void main()
			{
				${POSITION_FRAG_COLOR} = vec4(func(3));
			}
		""
	end

	case array_size_from_const_arg
		version 300 es
		expect compile_fail
		both ""
			#version 300 es
			precision mediump float;
			precision mediump int;
			${DECLARATIONS}

			int func (const int a)
			{
				int arr[a];
				arr[1] = 3;
				return arr[1];
			}

			void main()
			{
				${POSITION_FRAG_COLOR} = vec4(func(3));
			}
		""
	end

end # invalid