diff --git a/src/front/glsl/ast.rs b/src/front/glsl/ast.rs index 148049a688..cbb21f6de9 100644 --- a/src/front/glsl/ast.rs +++ b/src/front/glsl/ast.rs @@ -159,6 +159,15 @@ pub enum HirExprKind { /// The target expression expr: Handle, }, + /// A method call like `what.something(a, b, c)` + Method { + /// expression the method call applies to (`what` in the example) + expr: Handle, + /// the method name (`something` in the example) + name: String, + /// the arguments to the method (`a`, `b`, and `c` in the example) + args: Vec>, + }, } #[derive(Debug, Hash, PartialEq, Eq)] diff --git a/src/front/glsl/context.rs b/src/front/glsl/context.rs index 13eb5d180a..c269e5fd18 100644 --- a/src/front/glsl/context.rs +++ b/src/front/glsl/context.rs @@ -1366,6 +1366,67 @@ impl Context { value } } + HirExprKind::Method { + expr: object, + ref name, + ref args, + } if ExprPos::Lhs != pos => { + let args = args + .iter() + .map(|e| self.lower_expect_inner(stmt, parser, *e, ExprPos::Rhs, body)) + .collect::>>()?; + match name.as_ref() { + "length" => { + if !args.is_empty() { + parser.errors.push(Error { + kind: ErrorKind::SemanticError( + ".length() doesn't take any arguments".into(), + ), + meta, + }); + } + let lowered_array = + self.lower_expect_inner(stmt, parser, object, pos, body)?.0; + let array_type = parser.resolve_type(self, lowered_array, meta)?; + + match *array_type { + TypeInner::Array { + size: crate::ArraySize::Constant(size), + .. + } => { + let mut array_length = + self.add_expression(Expression::Constant(size), meta, body); + self.forced_conversion( + parser, + &mut array_length, + meta, + ScalarKind::Sint, + 4, + )?; + array_length + } + // let the error be handled in type checking if it's not a dynamic array + _ => { + let mut array_length = self.add_expression( + Expression::ArrayLength(lowered_array), + meta, + body, + ); + self.conversion(&mut array_length, meta, ScalarKind::Sint, 4)?; + array_length + } + } + } + _ => { + return Err(Error { + kind: ErrorKind::SemanticError( + format!("unknown method '{}'", name).into(), + ), + meta, + }); + } + } + } _ => { return Err(Error { kind: ErrorKind::SemanticError( diff --git a/src/front/glsl/parser/expressions.rs b/src/front/glsl/parser/expressions.rs index 44f9ea9d0d..ad9cf80a0f 100644 --- a/src/front/glsl/parser/expressions.rs +++ b/src/front/glsl/parser/expressions.rs @@ -231,6 +231,24 @@ impl<'source> ParsingContext<'source> { TokenValue::Dot => { let (field, end_meta) = self.expect_ident(parser)?; + if self.bump_if(parser, TokenValue::LeftParen).is_some() { + let args = + self.parse_function_call_args(parser, ctx, stmt, body, &mut meta)?; + + base = stmt.hir_exprs.append( + HirExpr { + kind: HirExprKind::Method { + expr: base, + name: field, + args, + }, + meta, + }, + Default::default(), + ); + continue; + } + meta.subsume(end_meta); base = stmt.hir_exprs.append( HirExpr { diff --git a/tests/in/glsl/expressions.frag b/tests/in/glsl/expressions.frag index acf0ea9213..2e386057b5 100644 --- a/tests/in/glsl/expressions.frag +++ b/tests/in/glsl/expressions.frag @@ -132,6 +132,18 @@ void testMatrixMultiplication(mat4x3 a, mat4x4 b) { mat4x3 c = a * b; } +layout(std430, binding = 0) buffer a_buf { + float a[]; +}; + +void testLength() { + int len = a.length(); +} + +void testConstantLength(float a[4u]) { + int len = a.length(); +} + out vec4 o_color; void main() { privatePointer(global); diff --git a/tests/out/wgsl/expressions-frag.wgsl b/tests/out/wgsl/expressions-frag.wgsl index 7cf1eace0e..5c8a3de5fd 100644 --- a/tests/out/wgsl/expressions-frag.wgsl +++ b/tests/out/wgsl/expressions-frag.wgsl @@ -2,11 +2,17 @@ struct BST { data: i32, } +struct a_buf { + a: array, +} + struct FragmentOutput { @location(0) o_color: vec4, } var global: f32; +@group(0) @binding(0) +var global_1: a_buf; var o_color: vec4; fn testBinOpVecFloat(a: vec4, b: f32) { @@ -369,28 +375,47 @@ fn testMatrixMultiplication(a_22: mat4x3, b_18: mat4x4) { return; } +fn testLength() { + var len: i32; + + len = i32(arrayLength((&global_1.a))); + return; +} + +fn testConstantLength(a_24: array) { + var a_25: array; + var len_1: i32 = 4; + + _ = (&global_1.a); + a_25 = a_24; + _ = a_25; + _ = i32(4u); +} + fn main_1() { var local_5: f32; + _ = (&global_1.a); _ = global; - let _e3 = global; - local_5 = _e3; + let _e5 = global; + local_5 = _e5; privatePointer((&local_5)); - let _e5 = local_5; - global = _e5; - let _e6 = o_color; - _ = _e6.xyzw; - let _e9 = vec4(1.0); - o_color.x = _e9.x; - o_color.y = _e9.y; - o_color.z = _e9.z; - o_color.w = _e9.w; + let _e7 = local_5; + global = _e7; + let _e8 = o_color; + _ = _e8.xyzw; + let _e11 = vec4(1.0); + o_color.x = _e11.x; + o_color.y = _e11.y; + o_color.z = _e11.z; + o_color.w = _e11.w; return; } @fragment fn main() -> FragmentOutput { + _ = (&global_1.a); main_1(); - let _e5 = o_color; - return FragmentOutput(_e5); + let _e7 = o_color; + return FragmentOutput(_e7); }