Skip to content

Commit 6fc6b14

Browse files
teoxoyjimblandy
authored andcommitted
handle var decl template list in the lowerer
1 parent 19311ba commit 6fc6b14

7 files changed

Lines changed: 206 additions & 40 deletions

File tree

naga/src/front/wgsl/error.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,9 @@ pub(crate) enum Error<'a> {
419419
UnderspecifiedCooperativeMatrix,
420420
InvalidCooperativeLoadType(Span),
421421
UnsupportedCooperativeScalar(Span),
422+
UnexpectedIdentForEnumerant(Span),
423+
UnexpectedExprForEnumerant(Span),
424+
UnusedArgsForTemplate(Vec<Span>),
422425
}
423426

424427
impl From<ConflictingDiagnosticRuleError> for Error<'_> {
@@ -1413,6 +1416,24 @@ impl<'a> Error<'a> {
14131416
labels: vec![(span, "type needs the scalar type specified".into())],
14141417
notes: vec![format!("must be F32")],
14151418
},
1419+
Error::UnexpectedIdentForEnumerant(ident_span) => ParseError {
1420+
message: format!(
1421+
"identifier `{}` resolves to a declaration",
1422+
&source[ident_span]
1423+
),
1424+
labels: vec![(ident_span, "needs to resolve to a predeclared enumerant".into())],
1425+
notes: vec![],
1426+
},
1427+
Error::UnexpectedExprForEnumerant(expr_span) => ParseError {
1428+
message: "unexpected expression".to_string(),
1429+
labels: vec![(expr_span, "needs to be an identifier resolving to a predeclared enumerant".into())],
1430+
notes: vec![],
1431+
},
1432+
Error::UnusedArgsForTemplate(ref expr_spans) => ParseError {
1433+
message: "unused expressions for template".to_string(),
1434+
labels: expr_spans.iter().cloned().map(|span| -> (_, _){ (span, "unused".into()) }).collect(),
1435+
notes: vec![],
1436+
},
14161437
}
14171438
}
14181439
}

naga/src/front/wgsl/lower/mod.rs

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ use alloc::{
77
};
88
use core::num::NonZeroU32;
99

10-
use crate::front::wgsl::error::{Error, ExpectedToken, InvalidAssignmentType};
1110
use crate::front::wgsl::index::Index;
1211
use crate::front::wgsl::parse::number::Number;
1312
use crate::front::wgsl::parse::{ast, conv};
1413
use crate::front::wgsl::Result;
14+
use crate::front::wgsl::{
15+
error::{Error, ExpectedToken, InvalidAssignmentType},
16+
parse::directive::enable_extension::EnableExtensions,
17+
};
1518
use crate::front::Typifier;
1619
use crate::{
1720
common::wgsl::{TryToWgsl, TypeContext},
@@ -1266,10 +1269,16 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
12661269
None
12671270
};
12681271

1272+
let space = Self::var_address_space(
1273+
&v.template_list,
1274+
&ctx.as_const(),
1275+
&tu.enable_extensions,
1276+
)?;
1277+
12691278
let handle = ctx.module.global_variables.append(
12701279
ir::GlobalVariable {
12711280
name: Some(v.name.name.to_string()),
1272-
space: v.space,
1281+
space,
12731282
binding,
12741283
ty,
12751284
init: initializer,
@@ -2576,6 +2585,66 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {
25762585
}
25772586
}
25782587

2588+
fn enumerant(
2589+
expr: Handle<ast::Expression<'source>>,
2590+
ctx: &ExpressionContext<'source, '_, '_>,
2591+
) -> Result<'source, (&'source str, Span)> {
2592+
let span = ctx.ast_expressions.get_span(expr);
2593+
let expr = &ctx.ast_expressions[expr];
2594+
2595+
match *expr {
2596+
ast::Expression::Ident(ast::IdentExpr::Local(_)) => {
2597+
Err(Box::new(Error::UnexpectedIdentForEnumerant(span)))
2598+
}
2599+
ast::Expression::Ident(ast::IdentExpr::Unresolved(name)) => {
2600+
if ctx.globals.get(name).is_some() {
2601+
Err(Box::new(Error::UnexpectedIdentForEnumerant(span)))
2602+
} else {
2603+
Ok((name, span))
2604+
}
2605+
}
2606+
_ => Err(Box::new(Error::UnexpectedExprForEnumerant(span))),
2607+
}
2608+
}
2609+
2610+
fn var_address_space(
2611+
template_list: &Option<Vec<Handle<ast::Expression<'source>>>>,
2612+
ctx: &ExpressionContext<'source, '_, '_>,
2613+
enable_extensions: &EnableExtensions,
2614+
) -> Result<'source, ir::AddressSpace> {
2615+
let mut address_space = ir::AddressSpace::Handle;
2616+
2617+
if let &Some(ref template_list) = template_list {
2618+
let mut template_list_args = template_list.iter();
2619+
let address_space_expr = template_list_args.next().unwrap();
2620+
2621+
let (enumerant, span) = Self::enumerant(*address_space_expr, ctx)?;
2622+
address_space = conv::map_address_space(enumerant, span, enable_extensions)?;
2623+
2624+
match address_space {
2625+
ir::AddressSpace::Storage { ref mut access } => {
2626+
if let Some(access_mode_expr) = template_list_args.next() {
2627+
let (enumerant, span) = Self::enumerant(*access_mode_expr, ctx)?;
2628+
let access_mode = conv::map_access_mode(enumerant, span)?;
2629+
*access = access_mode;
2630+
} else {
2631+
// defaulting to `read`
2632+
*access = ir::StorageAccess::LOAD
2633+
}
2634+
}
2635+
_ => {}
2636+
}
2637+
2638+
let unused_args: Vec<Span> = template_list_args
2639+
.map(|expr| ctx.ast_expressions.get_span(*expr))
2640+
.collect();
2641+
if !unused_args.is_empty() {
2642+
return Err(Box::new(Error::UnusedArgsForTemplate(unused_args)));
2643+
}
2644+
}
2645+
Ok(address_space)
2646+
}
2647+
25792648
fn binary(
25802649
&mut self,
25812650
op: ir::BinaryOperator,

naga/src/front/wgsl/parse/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ pub struct ResourceBinding<'a> {
167167
#[derive(Debug)]
168168
pub struct GlobalVariable<'a> {
169169
pub name: Ident<'a>,
170-
pub space: crate::AddressSpace,
170+
pub template_list: Option<Vec<Handle<Expression<'a>>>>,
171171
pub binding: Option<ResourceBinding<'a>>,
172172
pub ty: Option<Handle<Type<'a>>>,
173173
pub init: Option<Handle<Expression<'a>>>,

naga/src/front/wgsl/parse/conv.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ pub fn map_address_space<'a>(
3434
}
3535
}
3636

37+
pub fn map_access_mode(word: &str, span: Span) -> Result<'_, crate::StorageAccess> {
38+
match word {
39+
"read" => Ok(crate::StorageAccess::LOAD),
40+
"write" => Ok(crate::StorageAccess::STORE),
41+
"read_write" => Ok(crate::StorageAccess::LOAD | crate::StorageAccess::STORE),
42+
"atomic" => Ok(crate::StorageAccess::ATOMIC
43+
| crate::StorageAccess::LOAD
44+
| crate::StorageAccess::STORE),
45+
_ => Err(Box::new(Error::UnknownAccess(span))),
46+
}
47+
}
48+
3749
pub fn map_built_in(
3850
enable_extensions: &EnableExtensions,
3951
word: &str,

naga/src/front/wgsl/parse/lexer.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -607,29 +607,15 @@ impl<'a> Lexer<'a> {
607607
Ok((scalar, span))
608608
}
609609

610-
pub(in crate::front::wgsl) fn next_storage_access(
611-
&mut self,
612-
) -> Result<'a, crate::StorageAccess> {
613-
let (ident, span) = self.next_ident_with_span()?;
614-
match ident {
615-
"read" => Ok(crate::StorageAccess::LOAD),
616-
"write" => Ok(crate::StorageAccess::STORE),
617-
"read_write" => Ok(crate::StorageAccess::LOAD | crate::StorageAccess::STORE),
618-
"atomic" => Ok(crate::StorageAccess::ATOMIC
619-
| crate::StorageAccess::LOAD
620-
| crate::StorageAccess::STORE),
621-
_ => Err(Box::new(Error::UnknownAccess(span))),
622-
}
623-
}
624-
625610
pub(in crate::front::wgsl) fn next_format_generic(
626611
&mut self,
627612
) -> Result<'a, (crate::StorageFormat, crate::StorageAccess)> {
628613
self.expect(Token::TemplateArgsStart)?;
629614
let (ident, ident_span) = self.next_ident_with_span()?;
630615
let format = conv::map_storage_format(ident, ident_span)?;
631616
self.expect(Token::Separator(','))?;
632-
let access = self.next_storage_access()?;
617+
let (ident, ident_span) = self.next_ident_with_span()?;
618+
let access = conv::map_access_mode(ident, ident_span)?;
633619
self.expect(Token::TemplateArgsEnd)?;
634620
Ok((format, access))
635621
}

naga/src/front/wgsl/parse/mod.rs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,24 +1330,7 @@ impl Parser {
13301330
ctx: &mut ExpressionContext<'a, '_, '_>,
13311331
) -> Result<'a, ast::GlobalVariable<'a>> {
13321332
self.push_rule_span(Rule::VariableDecl, lexer);
1333-
let mut space = crate::AddressSpace::Handle;
1334-
1335-
if lexer.next_if(Token::TemplateArgsStart) {
1336-
let (class_str, span) = lexer.next_ident_with_span()?;
1337-
space = match class_str {
1338-
"storage" => {
1339-
let access = if lexer.next_if(Token::Separator(',')) {
1340-
lexer.next_storage_access()?
1341-
} else {
1342-
// defaulting to `read`
1343-
crate::StorageAccess::LOAD
1344-
};
1345-
crate::AddressSpace::Storage { access }
1346-
}
1347-
_ => conv::map_address_space(class_str, span, &lexer.enable_extensions)?,
1348-
};
1349-
lexer.expect(Token::TemplateArgsEnd)?;
1350-
}
1333+
let template_list = self.maybe_template_list(lexer, ctx)?;
13511334
let (name, ty) = self.optionally_typed_ident(lexer, ctx)?;
13521335

13531336
let init = if lexer.next_if(Token::Operation('=')) {
@@ -1361,7 +1344,7 @@ impl Parser {
13611344

13621345
Ok(ast::GlobalVariable {
13631346
name,
1364-
space,
1347+
template_list,
13651348
binding: None,
13661349
ty,
13671350
init,
@@ -1442,6 +1425,24 @@ impl Parser {
14421425
Ok(members)
14431426
}
14441427

1428+
fn maybe_template_list<'a>(
1429+
&mut self,
1430+
lexer: &mut Lexer<'a>,
1431+
ctx: &mut ExpressionContext<'a, '_, '_>,
1432+
) -> Result<'a, Option<Vec<Handle<ast::Expression<'a>>>>> {
1433+
if lexer.next_if(Token::TemplateArgsStart) {
1434+
let mut args = Vec::new();
1435+
args.push(self.expression(lexer, ctx)?);
1436+
while lexer.next_if(Token::Separator(',')) && lexer.peek().0 != Token::TemplateArgsEnd {
1437+
args.push(self.expression(lexer, ctx)?);
1438+
}
1439+
lexer.expect(Token::TemplateArgsEnd)?;
1440+
Ok(Some(args))
1441+
} else {
1442+
Ok(None)
1443+
}
1444+
}
1445+
14451446
/// Parses `<T>`, returning T and span of T
14461447
fn singular_generic<'a>(
14471448
&mut self,
@@ -1773,9 +1774,10 @@ impl Parser {
17731774
let base = self.type_specifier(lexer, ctx)?;
17741775
if let crate::AddressSpace::Storage { ref mut access } = space {
17751776
*access = if lexer.end_of_generic_arguments() {
1776-
let result = lexer.next_storage_access()?;
1777+
let (ident, span) = lexer.next_ident_with_span()?;
1778+
let access = conv::map_access_mode(ident, span)?;
17771779
lexer.next_if(Token::Separator(','));
1778-
result
1780+
access
17791781
} else {
17801782
crate::StorageAccess::LOAD
17811783
};

naga/src/front/wgsl/tests.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,3 +900,79 @@ error: found conflicting `diagnostic(…)` rule(s)
900900
}
901901
}
902902
}
903+
904+
mod template {
905+
use crate::front::wgsl::assert_parse_err;
906+
907+
#[test]
908+
fn missing_template_end() {
909+
assert_parse_err(
910+
"
911+
fn storage() {}
912+
var<storage
913+
",
914+
"\
915+
error: expected identifier, found \"<\"
916+
┌─ wgsl:3:4
917+
918+
3 │ var<storage
919+
│ ^ expected identifier
920+
921+
",
922+
);
923+
}
924+
925+
#[test]
926+
fn enumerant_shadowing() {
927+
assert_parse_err(
928+
"
929+
fn storage() {}
930+
var<storage> s: u32;
931+
",
932+
"\
933+
error: identifier `storage` resolves to a declaration
934+
┌─ wgsl:3:5
935+
936+
3 │ var<storage> s: u32;
937+
│ ^^^^^^^ needs to resolve to a predeclared enumerant
938+
939+
",
940+
);
941+
}
942+
943+
#[test]
944+
fn unexpected_expr_as_enumerant() {
945+
assert_parse_err(
946+
"
947+
var<1 + 1> s: u32;
948+
",
949+
"\
950+
error: unexpected expression
951+
┌─ wgsl:2:5
952+
953+
2 │ var<1 + 1> s: u32;
954+
│ ^^^^^ needs to be an identifier resolving to a predeclared enumerant
955+
956+
",
957+
);
958+
}
959+
960+
#[test]
961+
fn unused_exprs_for_template() {
962+
assert_parse_err(
963+
"
964+
var<storage, read_write, extra0, extra1> s: u32;
965+
",
966+
"\
967+
error: unused expressions for template
968+
┌─ wgsl:2:26
969+
970+
2 │ var<storage, read_write, extra0, extra1> s: u32;
971+
│ ^^^^^^ ^^^^^^ unused
972+
│ │\x20\x20\x20\x20\x20\x20\x20\x20
973+
│ unused
974+
975+
",
976+
);
977+
}
978+
}

0 commit comments

Comments
 (0)