[naga wgsl-in] Parse LHS expressions as such, not as generic expressions

Fixes #4383
This commit is contained in:
Andy Leiserson
2025-03-03 17:42:04 -08:00
committed by Jim Blandy
parent 7319512778
commit 4e14f2032e
3 changed files with 91 additions and 7 deletions

View File

@@ -151,6 +151,7 @@ enum Rule {
Directive,
GenericExpr,
EnclosedExpr,
LhsExpr,
}
struct ParsedAttribute<T> {
@@ -937,6 +938,53 @@ impl Parser {
})
}
/// Parse a `lhs_expression`.
///
/// LHS expressions only support the `&` and `*` operators and
/// the `[]` and `.` postfix selectors.
fn lhs_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
self.track_recursion(|this| {
this.push_rule_span(Rule::LhsExpr, lexer);
let start = lexer.start_byte_offset();
let expr = match lexer.peek() {
(Token::Operation('*'), _) => {
let _ = lexer.next();
let expr = this.lhs_expression(lexer, ctx)?;
let expr = ast::Expression::Deref(expr);
let span = this.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
(Token::Operation('&'), _) => {
let _ = lexer.next();
let expr = this.lhs_expression(lexer, ctx)?;
let expr = ast::Expression::AddrOf(expr);
let span = this.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
(Token::Operation('('), _) => {
let _ = lexer.next();
let primary_expr = this.lhs_expression(lexer, ctx)?;
lexer.expect(Token::Paren(')'))?;
this.postfix(start, lexer, ctx, primary_expr)?
}
(Token::Word(word), span) => {
let _ = lexer.next();
let ident = this.ident_expr(word, span, ctx);
let primary_expr = ctx.expressions.append(ast::Expression::Ident(ident), span);
this.postfix(start, lexer, ctx, primary_expr)?
}
_ => this.singular_expression(lexer, ctx)?,
};
this.pop_rule_span(lexer);
Ok(expr)
})
}
/// Parse a `singular_expression`.
fn singular_expression<'a>(
&mut self,
@@ -1781,7 +1829,7 @@ impl Parser {
block: &mut ast::Block<'a>,
) -> Result<(), Error<'a>> {
let span_start = lexer.start_byte_offset();
let target = self.general_expression(lexer, ctx)?;
let target = self.lhs_expression(lexer, ctx)?;
self.assignment_op_and_rhs(lexer, ctx, block, target, span_start)
}

View File

@@ -420,6 +420,42 @@ fn parse_expressions() {
}").unwrap();
}
#[test]
fn parse_assignment_statements() {
parse_str(
"
struct Foo { x: i32 };
fn foo() {
var x: u32 = 0u;
x++;
x--;
x = 1u;
x += 1u;
var v: vec2<f32> = vec2<f32>(1.0, 1.0);
v[0] += 1.0;
(v)[0] += 1.0;
var s: Foo = Foo(0);
s.x -= 1;
(s.x) -= 1;
(s).x -= 1;
_ = 5u;
}",
)
.unwrap();
let error = parse_str(
"fn foo() {
x|x++;
}",
)
.unwrap_err();
assert_eq!(
error.message(),
"expected assignment or increment/decrement, found \"|\"",
);
}
#[test]
fn binary_expression_mixed_scalar_and_vector_operands() {
for (operand, expect_splat) in [

View File

@@ -1759,11 +1759,11 @@ fn binary_statement() {
3 + 5;
}
",
r###"error: expected assignment or increment/decrement, found ";"
┌─ wgsl:3:18
r###"error: expected assignment or increment/decrement, found "+"
┌─ wgsl:3:15
3 │ 3 + 5;
^ expected assignment or increment/decrement
│ ^ expected assignment or increment/decrement
"###,
);
@@ -1777,11 +1777,11 @@ fn assign_to_expr() {
3 + 5 = 10;
}
",
r###"error: invalid left-hand side of assignment
┌─ wgsl:3:13
r###"error: expected assignment or increment/decrement, found "+"
┌─ wgsl:3:15
3 │ 3 + 5 = 10;
^^^^^ cannot assign to this expression
^ expected assignment or increment/decrement
"###,
);