Skip to content

Commit

Permalink
[wgsl-in] Fail on repeated attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
fornwall committed Aug 10, 2023
1 parent 061d499 commit 1d0583d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/front/wgsl/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ pub enum InvalidAssignmentType {
}

#[derive(Clone, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub enum Error<'a> {
Unexpected(Span, ExpectedToken<'a>),
UnexpectedComponents(Span),
Expand Down Expand Up @@ -168,6 +169,7 @@ pub enum Error<'a> {
InvalidIdentifierUnderscore(Span),
ReservedIdentifierPrefix(Span),
UnknownAddressSpace(Span),
RepeatedAttribute(Span),
UnknownAttribute(Span),
UnknownBuiltin(Span),
UnknownAccess(Span),
Expand Down Expand Up @@ -430,6 +432,11 @@ impl<'a> Error<'a> {
labels: vec![(bad_span, "unknown address space".into())],
notes: vec![],
},
Error::RepeatedAttribute(bad_span) => ParseError {
message: format!("repeated attribute: '{}'", &source[bad_span]),
labels: vec![(bad_span, "repated attribute".into())],
notes: vec![],
},
Error::UnknownAttribute(bad_span) => ParseError {
message: format!("unknown attribute: '{}'", &source[bad_span]),
labels: vec![(bad_span, "unknown attribute".into())],
Expand Down
15 changes: 14 additions & 1 deletion src/front/wgsl/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,29 +136,42 @@ impl BindingParser {
name: &'a str,
name_span: Span,
) -> Result<(), Error<'a>> {
let fail_if_repeated = |repeated| {
if repeated {
return Err(Error::RepeatedAttribute(name_span));
}
Ok(())
};

match name {
"location" => {
lexer.expect(Token::Paren('('))?;
fail_if_repeated(self.location.is_some())?;
self.location = Some(Parser::non_negative_i32_literal(lexer)?);
lexer.expect(Token::Paren(')'))?;
}
"builtin" => {
lexer.expect(Token::Paren('('))?;
let (raw, span) = lexer.next_ident_with_span()?;
fail_if_repeated(self.built_in.is_some())?;
self.built_in = Some(conv::map_built_in(raw, span)?);
lexer.expect(Token::Paren(')'))?;
}
"interpolate" => {
lexer.expect(Token::Paren('('))?;
let (raw, span) = lexer.next_ident_with_span()?;
fail_if_repeated(self.interpolation.is_some())?;
self.interpolation = Some(conv::map_interpolation(raw, span)?);
if lexer.skip(Token::Separator(',')) {
let (raw, span) = lexer.next_ident_with_span()?;
self.sampling = Some(conv::map_sampling(raw, span)?);
}
lexer.expect(Token::Paren(')'))?;
}
"invariant" => self.invariant = true,
"invariant" => {
fail_if_repeated(self.invariant)?;
self.invariant = true;
}
_ => return Err(Error::UnknownAttribute(name_span)),
}
Ok(())
Expand Down
27 changes: 27 additions & 0 deletions src/front/wgsl/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,3 +481,30 @@ fn parse_alias() {
)
.unwrap();
}

#[test]
fn parse_repeated_attributes() {
use crate::{
front::wgsl::{error::Error, Frontend},
Span,
};

let template = "@vertex fn vs() -> __REPLACE__ vec4<f32> { return vec4<f32>(0.0); }";
for attribute in [
"location(0)",
"builtin(position)",
"interpolate(flat)",
"invariant",
] {
let shader = template.replace("__REPLACE__", &format!("@{attribute} @{attribute}"));
let name_length = attribute.rfind('(').unwrap_or(attribute.len()) as u32;
let span_start = shader.rfind(attribute).unwrap() as u32;
let span_end = span_start + name_length;

let result = Frontend::new().inner(&shader);
assert_eq!(
result.unwrap_err(),
Error::RepeatedAttribute(Span::new(span_start, span_end))
);
}
}

0 comments on commit 1d0583d

Please sign in to comment.