mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
Allow unsigned integers in switch
This commit is contained in:
committed by
Dzmitry Malyshau
parent
6a57559070
commit
d5fc05e8a4
@@ -1427,11 +1427,18 @@ impl<'a, W: Write> Writer<'a, W> {
|
||||
write!(self.out, "switch(")?;
|
||||
self.write_expr(selector, ctx)?;
|
||||
writeln!(self.out, ") {{")?;
|
||||
let type_postfix = match *ctx.info[selector].ty.inner_with(&self.module.types) {
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
..
|
||||
} => "u",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
// Write all cases
|
||||
let l2 = level.next();
|
||||
for case in cases {
|
||||
writeln!(self.out, "{}case {}:", l2, case.value)?;
|
||||
writeln!(self.out, "{}case {}{}:", l2, case.value, type_postfix)?;
|
||||
|
||||
for sta in case.body.iter() {
|
||||
self.write_stmt(sta, ctx, l2.next())?;
|
||||
|
||||
@@ -1370,13 +1370,24 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
|
||||
write!(self.out, "switch(")?;
|
||||
self.write_expr(module, selector, func_ctx)?;
|
||||
writeln!(self.out, ") {{")?;
|
||||
let type_postfix = match *func_ctx.info[selector].ty.inner_with(&module.types) {
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
..
|
||||
} => "u",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
// Write all cases
|
||||
let indent_level_1 = level.next();
|
||||
let indent_level_2 = indent_level_1.next();
|
||||
|
||||
for case in cases {
|
||||
writeln!(self.out, "{}case {}: {{", indent_level_1, case.value)?;
|
||||
writeln!(
|
||||
self.out,
|
||||
"{}case {}{}: {{",
|
||||
indent_level_1, case.value, type_postfix
|
||||
)?;
|
||||
|
||||
if case.fall_through {
|
||||
// Generate each fallthrough case statement in a new block. This is done to
|
||||
|
||||
@@ -1439,10 +1439,17 @@ impl<W: Write> Writer<W> {
|
||||
} => {
|
||||
write!(self.out, "{}switch(", level)?;
|
||||
self.put_expression(selector, &context.expression, true)?;
|
||||
let type_postfix = match *context.expression.resolve_type(selector) {
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
..
|
||||
} => "u",
|
||||
_ => "",
|
||||
};
|
||||
writeln!(self.out, ") {{")?;
|
||||
let lcase = level.next();
|
||||
for case in cases.iter() {
|
||||
writeln!(self.out, "{}case {}: {{", lcase, case.value)?;
|
||||
writeln!(self.out, "{}case {}{}: {{", lcase, case.value, type_postfix)?;
|
||||
self.put_block(lcase.next(), &case.body, context)?;
|
||||
if !case.fall_through {
|
||||
writeln!(self.out, "{}break;", lcase.next())?;
|
||||
|
||||
@@ -887,6 +887,13 @@ impl<W: Write> Writer<W> {
|
||||
let all_fall_through = cases
|
||||
.iter()
|
||||
.all(|case| case.fall_through && case.body.is_empty());
|
||||
let type_postfix = match *func_ctx.info[selector].ty.inner_with(&module.types) {
|
||||
crate::TypeInner::Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
..
|
||||
} => "u",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
let l2 = level.next();
|
||||
if !cases.is_empty() {
|
||||
@@ -896,11 +903,11 @@ impl<W: Write> Writer<W> {
|
||||
}
|
||||
if !all_fall_through && case.fall_through && case.body.is_empty() {
|
||||
write_case = false;
|
||||
write!(self.out, "{}, ", case.value)?;
|
||||
write!(self.out, "{}{}, ", case.value, type_postfix)?;
|
||||
continue;
|
||||
} else {
|
||||
write_case = true;
|
||||
writeln!(self.out, "{}: {{", case.value)?;
|
||||
writeln!(self.out, "{}{}: {{", case.value, type_postfix)?;
|
||||
}
|
||||
|
||||
for sta in case.body.iter() {
|
||||
|
||||
@@ -157,19 +157,12 @@ impl<'source> ParsingContext<'source> {
|
||||
|
||||
self.expect(parser, TokenValue::LeftParen)?;
|
||||
|
||||
let (mut selector, selector_meta) = {
|
||||
let selector = {
|
||||
let mut stmt = ctx.stmt_ctx();
|
||||
let expr = self.parse_expression(parser, ctx, &mut stmt, body)?;
|
||||
ctx.lower_expect(stmt, parser, expr, ExprPos::Rhs, body)?
|
||||
ctx.lower_expect(stmt, parser, expr, ExprPos::Rhs, body)?.0
|
||||
};
|
||||
|
||||
if let Some(crate::ScalarKind::Uint) = parser
|
||||
.resolve_type(ctx, selector, selector_meta)?
|
||||
.scalar_kind()
|
||||
{
|
||||
ctx.conversion(&mut selector, selector_meta, crate::ScalarKind::Sint, 4)?
|
||||
}
|
||||
|
||||
self.expect(parser, TokenValue::RightParen)?;
|
||||
|
||||
ctx.emit_flush(body);
|
||||
|
||||
@@ -21,7 +21,7 @@ use self::{
|
||||
lexer::Lexer,
|
||||
number_literals::{
|
||||
get_f32_literal, get_i32_literal, get_u32_literal, parse_generic_non_negative_int_literal,
|
||||
parse_non_negative_sint_literal, parse_sint_literal,
|
||||
parse_non_negative_sint_literal,
|
||||
},
|
||||
};
|
||||
use codespan_reporting::{
|
||||
@@ -83,6 +83,7 @@ pub enum ExpectedToken<'a> {
|
||||
ty: Option<NumberType>,
|
||||
width: Option<Bytes>,
|
||||
},
|
||||
Integer,
|
||||
Constant,
|
||||
/// Expected: constant, parenthesized expression, identifier
|
||||
PrimaryExpression,
|
||||
@@ -218,6 +219,7 @@ impl<'a> Error<'a> {
|
||||
)
|
||||
}
|
||||
},
|
||||
ExpectedToken::Integer => "unsigned/signed integer literal".to_string(),
|
||||
ExpectedToken::Constant => "constant".to_string(),
|
||||
ExpectedToken::PrimaryExpression => "expression".to_string(),
|
||||
ExpectedToken::AttributeSeparator => "attribute separator (',') or an end of the attribute list (']]')".to_string(),
|
||||
@@ -1242,6 +1244,28 @@ impl Parser {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_switch_value<'a>(lexer: &mut Lexer<'a>, uint: bool) -> Result<i32, Error<'a>> {
|
||||
let token_span = lexer.next();
|
||||
let word = match token_span.0 {
|
||||
Token::Number { value, width, .. } => {
|
||||
if let Some(width) = width {
|
||||
if width != 4 {
|
||||
// Only 32-bit literals supported by the spec and naga for now!
|
||||
return Err(Error::BadScalarWidth(token_span.1, width));
|
||||
}
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
_ => return Err(Error::Unexpected(token_span, ExpectedToken::Integer)),
|
||||
};
|
||||
|
||||
match uint {
|
||||
true => get_u32_literal(word, token_span.1).map(|v| v as i32),
|
||||
false => get_i32_literal(word, token_span.1),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_atomic_pointer<'a>(
|
||||
&mut self,
|
||||
lexer: &mut Lexer<'a>,
|
||||
@@ -3425,6 +3449,11 @@ impl Parser {
|
||||
lexer,
|
||||
context.as_expression(block, &mut emitter),
|
||||
)?;
|
||||
let uint = Some(crate::ScalarKind::Uint)
|
||||
== context
|
||||
.as_expression(block, &mut emitter)
|
||||
.resolve_type(selector)?
|
||||
.scalar_kind();
|
||||
lexer.expect(Token::Paren(')'))?;
|
||||
block.extend(emitter.finish(context.expressions));
|
||||
lexer.expect(Token::Paren('{'))?;
|
||||
@@ -3438,7 +3467,7 @@ impl Parser {
|
||||
// parse a list of values
|
||||
let value = loop {
|
||||
// TODO: Switch statements also allow for floats, bools and unsigned integers. See https://www.w3.org/TR/WGSL/#switch-statement
|
||||
let value = parse_sint_literal(lexer, 4)?;
|
||||
let value = Self::parse_switch_value(lexer, uint)?;
|
||||
if lexer.skip(Token::Separator(',')) {
|
||||
if lexer.skip(Token::Separator(':')) {
|
||||
break value;
|
||||
|
||||
@@ -69,36 +69,6 @@ pub fn get_f32_literal(word: &str, span: Span) -> Result<f32, Error<'_>> {
|
||||
parsed_val.map_err(|e| Error::BadFloat(span, e))
|
||||
}
|
||||
|
||||
pub(super) fn parse_sint_literal<'a>(
|
||||
lexer: &mut Lexer<'a>,
|
||||
width: Bytes,
|
||||
) -> Result<i32, Error<'a>> {
|
||||
let token_span = lexer.next();
|
||||
|
||||
if width != 4 {
|
||||
// Only 32-bit literals supported by the spec and naga for now!
|
||||
return Err(Error::BadScalarWidth(token_span.1, width));
|
||||
}
|
||||
|
||||
match token_span {
|
||||
(
|
||||
Token::Number {
|
||||
value,
|
||||
ty: NumberType::Sint,
|
||||
width: token_width,
|
||||
},
|
||||
span,
|
||||
) if token_width.unwrap_or(4) == width => get_i32_literal(value, span),
|
||||
other => Err(Error::Unexpected(
|
||||
other,
|
||||
ExpectedToken::Number {
|
||||
ty: Some(NumberType::Sint),
|
||||
width: Some(width),
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn _parse_uint_literal<'a>(
|
||||
lexer: &mut Lexer<'a>,
|
||||
width: Bytes,
|
||||
|
||||
@@ -1260,7 +1260,7 @@ pub use block::Block;
|
||||
pub struct SwitchCase {
|
||||
/// Value, upon which the case is considered true.
|
||||
pub value: i32,
|
||||
/// Body of the cae.
|
||||
/// Body of the case.
|
||||
pub body: Block,
|
||||
/// If true, the control flow continues to the next case in the list,
|
||||
/// or default.
|
||||
|
||||
@@ -90,7 +90,7 @@ pub enum FunctionError {
|
||||
InvalidIfType(Handle<crate::Expression>),
|
||||
#[error("The `switch` value {0:?} is not an integer scalar")]
|
||||
InvalidSwitchType(Handle<crate::Expression>),
|
||||
#[error("Multiple `switch` cases for {0} are present")]
|
||||
#[error("Multiple `switch` cases for {0:?} are present")]
|
||||
ConflictingSwitchCase(i32),
|
||||
#[error("The pointer {0:?} doesn't relate to a valid destination for a store")]
|
||||
InvalidStorePointer(Handle<crate::Expression>),
|
||||
@@ -375,6 +375,10 @@ impl super::Validator {
|
||||
ref default,
|
||||
} => {
|
||||
match *context.resolve_type(selector, &self.valid_expression_set)? {
|
||||
Ti::Scalar {
|
||||
kind: crate::ScalarKind::Uint,
|
||||
width: _,
|
||||
} => {}
|
||||
Ti::Scalar {
|
||||
kind: crate::ScalarKind::Sint,
|
||||
width: _,
|
||||
|
||||
Reference in New Issue
Block a user