Quelle mod.rs
Sprache: unbekannt
|
|
rahmenlose Ansicht.rs DruckansichtUnknown {[0] [0] [0]}Entwicklung
use crate::diagnostic_filter::{
self, DiagnosticFilter, DiagnosticFilterMap, DiagnosticFilterNode, FilterableTrigger ingRule,
ShouldConflictOnFullDuplicate, StandardFilterableTriggeringRule,
};
use crate::front::wgsl::error::{DiagnosticAttributeNotSupportedPosition, Error, ExpectedToken};
use crate::front::wgsl::parse::directive::enable_extension::{
EnableExtension, EnableExtensions, UnimplementedEnableExtension,
};
use crate::front::wgsl::parse::directive::language_extension::LanguageExtension;
use crate::front::wgsl::parse::directive::DirectiveKind;
use crate::front::wgsl::parse::lexer::{Lexer, Token};
use crate::front::wgsl::parse::number::Number;
use crate::front::wgsl::Scalar;
use crate::front::SymbolTable;
use crate::{Arena, FastIndexSet, Handle, ShaderStage, Span};
pub mod ast;
pub mod conv;
pub mod directive;
pub mod lexer;
pub mod number;
/// State for constructing an AST expression.
///
/// Not to be confused with [`lower::ExpressionContext`], which is for producing
/// Naga IR from the AST we produce here.
///
/// [`lower::ExpressionContext`]: super::lower::ExpressionContext
struct ExpressionContext<'input, 'temp, 'out> {
/// The [`TranslationUnit::expressions`] arena to which we should contribute
/// expressions.
///
/// [`TranslationUnit::expressions`]: ast::TranslationUnit::expressions
expressions: &'out mut Arena<ast::Expression<'input>>,
/// The [`TranslationUnit::types`] arena to which we should contribute new
/// types.
///
/// [`TranslationUnit::types`]: ast::TranslationUnit::types
types: &'out mut Arena<ast::Type<'input>>,
/// A map from identifiers in scope to the locals/arguments they represent.
///
/// The handles refer to the [`locals`] arena; see that field's
/// documentation for details.
///
/// [`locals`]: ExpressionContext::locals
local_table: &'temp mut SymbolTable<&'input str, Handle<ast::Local>>,
/// Local variable and function argument arena for the function we're building.
///
/// Note that the [`ast::Local`] here is actually a zero-sized type. This
/// `Arena`'s only role is to assign a unique `Handle` to each local
/// identifier, and track its definition's span for use in diagnostics. All
/// the detailed information about locals - names, types, etc. - is kept in
/// the [`LocalDecl`] statements we parsed from their declarations. For
/// arguments, that information is kept in [`arguments`].
///
/// In the AST, when an [`Ident`] expression refers to a local variable or
/// argument, its [`IdentExpr`] holds the referent's `Handle<Local>` in this
/// arena.
///
/// During lowering, [`LocalDecl`] statements add entries to a per-function
/// table that maps `Handle<Local>` values to their Naga representations,
/// accessed via [`StatementContext::local_table`] and
/// [`LocalExpressionContext::local_table`]. This table is then consulted when
/// lowering subsequent [`Ident`] expressions.
///
/// [`LocalDecl`]: ast::StatementKind::LocalDecl
/// [`arguments`]: ast::Function::arguments
/// [`Ident`]: ast::Expression::Ident
/// [`IdentExpr`]: ast::IdentExpr
/// [`StatementContext::local_table`]: super::lower::StatementContext::local_table
/// [`LocalExpressionContext::local_table`]: super::lower::LocalExpressionContext::local_table
locals: &'out mut Arena<ast::Local>,
/// Identifiers used by the current global declaration that have no local definition.
///
/// This becomes the [`GlobalDecl`]'s [`dependencies`] set.
///
/// Note that we don't know at parse time what kind of [`GlobalDecl`] the
/// name refers to. We can't look up names until we've seen the entire
/// translation unit.
///
/// [`GlobalDecl`]: ast::GlobalDecl
/// [`dependencies`]: ast::GlobalDecl::dependencies
unresolved: &'out mut FastIndexSet<ast::Dependency<'input>>,
}
impl<'a> ExpressionContext<'a, '_, '_> {
fn parse_binary_op(
&mut self,
lexer: &mut Lexer<'a>,
classifier: impl Fn(Token<'a>) -> Option<crate::BinaryOperator>,
mut parser: impl FnMut(
&mut Lexer<'a>,
&mut Self,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
let start = lexer.start_byte_offset();
let mut accumulator = parser(lexer, self)?;
while let Some(op) = classifier(lexer.peek().0) {
let _ = lexer.next();
let left = accumulator;
let right = parser(lexer, self)?;
accumulator = self.expressions.append(
ast::Expression::Binary { op, left, right },
lexer.span_from(start),
);
}
Ok(accumulator)
}
fn declare_local(&mut self, name: ast::Ident<'a>) -> Result<Handle<ast::Local>, Error<'a>> {
let handle = self.locals.append(ast::Local, name.span);
if let Some(old) = self.local_table.add(name.name, handle) {
Err(Error::Redefinition {
previous: self.locals.get_span(old),
current: name.span,
})
} else {
Ok(handle)
}
}
fn new_scalar(&mut self, scalar: Scalar) -> Handle<ast::Type<'a>> {
self.types
.append(ast::Type::Scalar(scalar), Span::UNDEFINED)
}
}
/// Which grammar rule we are in the midst of parsing.
///
/// This is used for error checking. `Parser` maintains a stack of
/// these and (occasionally) checks that it is being pushed and popped
/// as expected.
#[derive(Copy, Clone, Debug, PartialEq)]
enum Rule {
Attribute,
VariableDecl,
TypeDecl,
FunctionDecl,
Block,
Statement,
PrimaryExpr,
SingularExpr,
UnaryExpr,
GeneralExpr,
Directive,
GenericExpr,
EnclosedExpr,
}
struct ParsedAttribute<T> {
value: Option<T>,
}
impl<T> Default for ParsedAttribute<T> {
fn default() -> Self {
Self { value: None }
}
}
impl<T> ParsedAttribute<T> {
fn set(&mut self, value: T, name_span: Span) -> Result<(), Error<'static>> {
if self.value.is_some() {
return Err(Error::RepeatedAttribute(name_span));
}
self.value = Some(value);
Ok(())
}
}
#[derive(Default)]
struct BindingParser<'a> {
location: ParsedAttribute<Handle<ast::Expression<'a>>>,
second_blend_source: ParsedAttribute<bool>,
built_in: ParsedAttribute<crate::BuiltIn>,
interpolation: ParsedAttribute<crate::Interpolation>,
sampling: ParsedAttribute<crate::Sampling>,
invariant: ParsedAttribute<bool>,
}
impl<'a> BindingParser<'a> {
fn parse(
&mut self,
parser: &mut Parser,
lexer: &mut Lexer<'a>,
name: &'a str,
name_span: Span,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<(), Error<'a>> {
match name {
"location" => {
lexer.expect(Token::Paren('('))?;
self.location
.set(parser.general_expression(lexer, ctx)?, name_span)?;
lexer.expect(Token::Paren(')'))?;
}
"builtin" => {
lexer.expect(Token::Paren('('))?;
let (raw, span) = lexer.next_ident_with_span()?;
self.built_in
.set(conv::map_built_in(raw, span)?, name_span)?;
lexer.expect(Token::Paren(')'))?;
}
"interpolate" => {
lexer.expect(Token::Paren('('))?;
let (raw, span) = lexer.next_ident_with_span()?;
self.interpolation
.set(conv::map_interpolation(raw, span)?, name_span)?;
if lexer.skip(Token::Separator(',')) {
let (raw, span) = lexer.next_ident_with_span()?;
self.sampling
.set(conv::map_sampling(raw, span)?, name_span)?;
}
lexer.expect(Token::Paren(')'))?;
}
"second_blend_source" => {
self.second_blend_source.set(true, name_span)?;
}
"invariant" => {
self.invariant.set(true, name_span)?;
}
_ => return Err(Error::UnknownAttribute(name_span)),
}
Ok(())
}
fn finish(self, span: Span) -> Result<Option<ast::Binding<'a>>, Error<'a>> {
match (
self.location.value,
self.built_in.value,
self.interpolation.value,
self.sampling.value,
self.invariant.value.unwrap_or_default(),
) {
(None, None, None, None, false) => Ok(None),
(Some(location), None, interpolation, sampling, false) => {
// Before handing over the completed `Module`, we call
// `apply_default_interpolation` to ensure that the interpolation and
// sampling have been explicitly specified on all vertex shader output and fragment
// shader input user bindings, so leaving them potentially `None` here is fine.
Ok(Some(ast::Binding::Location {
location,
interpolation,
sampling,
second_blend_source: self.second_blend_source.value.unwrap_or(false),
}))
}
(None, Some(crate::BuiltIn::Position { .. }), None, None, invariant) => {
Ok(Some(ast::Binding::BuiltIn(crate::BuiltIn::Position {
invariant,
})))
}
(None, Some(built_in), None, None, false) => Ok(Some(ast::Binding::BuiltIn(built_in))),
(_, _, _, _, _) => Err(Error::InconsistentBinding(span)),
}
}
}
pub struct Parser {
rules: Vec<(Rule, usize)>,
}
impl Parser {
pub const fn new() -> Self {
Parser { rules: Vec::new() }
}
fn reset(&mut self) {
self.rules.clear();
}
fn push_rule_span(&mut self, rule: Rule, lexer: &mut Lexer<'_>) {
self.rules.push((rule, lexer.start_byte_offset()));
}
fn pop_rule_span(&mut self, lexer: &Lexer<'_>) -> Span {
let (_, initial) = self.rules.pop().unwrap();
lexer.span_from(initial)
}
fn peek_rule_span(&mut self, lexer: &Lexer<'_>) -> Span {
let &(_, initial) = self.rules.last().unwrap();
lexer.span_from(initial)
}
fn race_rules(&self, rule0: Rule, rule1: Rule) -> Option<Rule> {
Some(
self.rules
.iter()
.rev()
.find(|&x| x.0 == rule0 || x.0 == rule1)?
.0,
)
}
fn switch_value<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<ast::SwitchValue<'a>, Error<'a>> {
if let Token::Word("default") = lexer.peek().0 {
let _ = lexer.next();
return Ok(ast::SwitchValue::Default);
}
let expr = self.general_expression(lexer, ctx)?;
Ok(ast::SwitchValue::Expr(expr))
}
/// Decide if we're looking at a construction expression, and return its
/// type if so.
///
/// If the identifier `word` is a [type-defining keyword], then return a
/// [`ConstructorType`] value describing the type to build. Return an error
/// if the type is not constructible (like `sampler`).
///
/// If `word` isn't a type name, then return `None`.
///
/// [type-defining keyword]: https://gpuweb.github.io/gpuweb/wgsl/#type-defining-keywords
/// [`ConstructorType`]: ast::ConstructorType
fn constructor_type<'a>(
&mut self,
lexer: &mut Lexer<'a>,
word: &'a str,
span: Span,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Option<ast::ConstructorType<'a>>, Error<'a>> {
if let Some(scalar) = conv::get_scalar_type(word) {
return Ok(Some(ast::ConstructorType::Scalar(scalar)));
}
let partial = match word {
"vec2" => ast::ConstructorType::PartialVector {
size: crate::VectorSize::Bi,
},
"vec2i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::I32),
ty_span: Span::UNDEFINED,
}))
}
"vec2u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::U32),
ty_span: Span::UNDEFINED,
}))
}
"vec2f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"vec3" => ast::ConstructorType::PartialVector {
size: crate::VectorSize::Tri,
},
"vec3i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::I32),
ty_span: Span::UNDEFINED,
}))
}
"vec3u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::U32),
ty_span: Span::UNDEFINED,
}))
}
"vec3f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"vec4" => ast::ConstructorType::PartialVector {
size: crate::VectorSize::Quad,
},
"vec4i" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::I32),
ty_span: Span::UNDEFINED,
}))
}
"vec4u" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::U32),
ty_span: Span::UNDEFINED,
}))
}
"vec4f" => {
return Ok(Some(ast::ConstructorType::Vector {
size: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat2x2" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Bi,
},
"mat2x2f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat2x3" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Tri,
},
"mat2x3f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat2x4" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Quad,
},
"mat2x4f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat3x2" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Bi,
},
"mat3x2f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat3x3" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Tri,
},
"mat3x3f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat3x4" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Quad,
},
"mat3x4f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat4x2" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Bi,
},
"mat4x2f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat4x3" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Tri,
},
"mat4x3f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"mat4x4" => ast::ConstructorType::PartialMatrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Quad,
},
"mat4x4f" => {
return Ok(Some(ast::ConstructorType::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
}))
}
"array" => ast::ConstructorType::PartialArray,
"atomic"
| "binding_array"
| "sampler"
| "sampler_comparison"
| "texture_1d"
| "texture_1d_array"
| "texture_2d"
| "texture_2d_array"
| "texture_3d"
| "texture_cube"
| "texture_cube_array"
| "texture_multisampled_2d"
| "texture_multisampled_2d_array"
| "texture_depth_2d"
| "texture_depth_2d_array"
| "texture_depth_cube"
| "texture_depth_cube_array"
| "texture_depth_multisampled_2d"
| "texture_storage_1d"
| "texture_storage_1d_array"
| "texture_storage_2d"
| "texture_storage_2d_array"
| "texture_storage_3d" => return Err(Error::TypeNotConstructible(span)),
_ => return Ok(None),
};
// parse component type if present
match (lexer.peek().0, partial) {
(Token::Paren('<'), ast::ConstructorType::PartialVector { size }) => {
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
Ok(Some(ast::ConstructorType::Vector { size, ty, ty_span }))
}
(Token::Paren('<'), ast::ConstructorType::PartialMatrix { columns, rows }) => {
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
Ok(Some(ast::ConstructorType::Matrix {
columns,
rows,
ty,
ty_span,
}))
}
(Token::Paren('<'), ast::ConstructorType::PartialArray) => {
lexer.expect_generic_paren('<')?;
let base = self.type_decl(lexer, ctx)?;
let size = if lexer.skip(Token::Separator(',')) {
let expr = self.const_generic_expression(lexer, ctx)?;
ast::ArraySize::Constant(expr)
} else {
ast::ArraySize::Dynamic
};
lexer.expect_generic_paren('>')?;
Ok(Some(ast::ConstructorType::Array { base, size }))
}
(_, partial) => Ok(Some(partial)),
}
}
/// Expects `name` to be consumed (not in lexer).
fn arguments<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Vec<Handle<ast::Expression<'a>>>, Error<'a>> {
self.push_rule_span(Rule::EnclosedExpr, lexer);
lexer.open_arguments()?;
let mut arguments = Vec::new();
loop {
if !arguments.is_empty() {
if !lexer.next_argument()? {
break;
}
} else if lexer.skip(Token::Paren(')')) {
break;
}
let arg = self.general_expression(lexer, ctx)?;
arguments.push(arg);
}
self.pop_rule_span(lexer);
Ok(arguments)
}
fn enclosed_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
self.push_rule_span(Rule::EnclosedExpr, lexer);
let expr = self.general_expression(lexer, ctx)?;
self.pop_rule_span(lexer);
Ok(expr)
}
/// Expects [`Rule::PrimaryExpr`] or [`Rule::SingularExpr`] on top; does not pop it.
/// Expects `name` to be consumed (not in lexer).
fn function_call<'a>(
&mut self,
lexer: &mut Lexer<'a>,
name: &'a str,
name_span: Span,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
assert!(self.rules.last().is_some());
let expr = match name {
// bitcast looks like a function call, but it's an operator and must be handled differently.
"bitcast" => {
let (to, span) = self.singular_generic(lexer, ctx)?;
lexer.open_arguments()?;
let expr = self.general_expression(lexer, ctx)?;
lexer.close_arguments()?;
ast::Expression::Bitcast {
expr,
to,
ty_span: span,
}
}
// everything else must be handled later, since they can be hidden by user-defined functions.
_ => {
let arguments = self.arguments(lexer, ctx)?;
ctx.unresolved.insert(ast::Dependency {
ident: name,
usage: name_span,
});
ast::Expression::Call {
function: ast::Ident {
name,
span: name_span,
},
arguments,
}
}
};
let span = self.peek_rule_span(lexer);
let expr = ctx.expressions.append(expr, span);
Ok(expr)
}
fn ident_expr<'a>(
&mut self,
name: &'a str,
name_span: Span,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> ast::IdentExpr<'a> {
match ctx.local_table.lookup(name) {
Some(&local) => ast::IdentExpr::Local(local),
None => {
ctx.unresolved.insert(ast::Dependency {
ident: name,
usage: name_span,
});
ast::IdentExpr::Unresolved(name)
}
}
}
fn primary_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
self.push_rule_span(Rule::PrimaryExpr, lexer);
const fn literal_ray_flag<'b>(flag: crate::RayFlag) -> ast::Expression<'b> {
ast::Expression::Literal(ast::Literal::Number(Number::U32(flag.bits())))
}
const fn literal_ray_intersection<'b>(
intersection: crate::RayQueryIntersection,
) -> ast::Expression<'b> {
ast::Expression::Literal(ast::Literal::Number(Number::U32(intersection as u32)))
}
let expr = match lexer.peek() {
(Token::Paren('('), _) => {
let _ = lexer.next();
let expr = self.enclosed_expression(lexer, ctx)?;
lexer.expect(Token::Paren(')'))?;
self.pop_rule_span(lexer);
return Ok(expr);
}
(Token::Word("true"), _) => {
let _ = lexer.next();
ast::Expression::Literal(ast::Literal::Bool(true))
}
(Token::Word("false"), _) => {
let _ = lexer.next();
ast::Expression::Literal(ast::Literal::Bool(false))
}
(Token::Number(res), span) => {
let _ = lexer.next();
let num = res.map_err(|err| match err {
super::error::NumberError::UnimplementedF16 => {
Error::EnableExtensionNotEnabled {
kind: EnableExtension::Unimplemented(UnimplementedEnableExtension::F16),
span,
}
}
err => Error::BadNumber(span, err),
})?;
ast::Expression::Literal(ast::Literal::Number(num))
}
(Token::Word("RAY_FLAG_NONE"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::empty())
}
(Token::Word("RAY_FLAG_FORCE_OPAQUE"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::FORCE_OPAQUE)
}
(Token::Word("RAY_FLAG_FORCE_NO_OPAQUE"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::FORCE_NO_OPAQUE)
}
(Token::Word("RAY_FLAG_TERMINATE_ON_FIRST_HIT"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::TERMINATE_ON_FIRST_HIT)
}
(Token::Word("RAY_FLAG_SKIP_CLOSEST_HIT_SHADER"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::SKIP_CLOSEST_HIT_SHADER)
}
(Token::Word("RAY_FLAG_CULL_BACK_FACING"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::CULL_BACK_FACING)
}
(Token::Word("RAY_FLAG_CULL_FRONT_FACING"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::CULL_FRONT_FACING)
}
(Token::Word("RAY_FLAG_CULL_OPAQUE"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::CULL_OPAQUE)
}
(Token::Word("RAY_FLAG_CULL_NO_OPAQUE"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::CULL_NO_OPAQUE)
}
(Token::Word("RAY_FLAG_SKIP_TRIANGLES"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::SKIP_TRIANGLES)
}
(Token::Word("RAY_FLAG_SKIP_AABBS"), _) => {
let _ = lexer.next();
literal_ray_flag(crate::RayFlag::SKIP_AABBS)
}
(Token::Word("RAY_QUERY_INTERSECTION_NONE"), _) => {
let _ = lexer.next();
literal_ray_intersection(crate::RayQueryIntersection::None)
}
(Token::Word("RAY_QUERY_INTERSECTION_TRIANGLE"), _) => {
let _ = lexer.next();
literal_ray_intersection(crate::RayQueryIntersection::Triangle)
}
(Token::Word("RAY_QUERY_INTERSECTION_GENERATED"), _) => {
let _ = lexer.next();
literal_ray_intersection(crate::RayQueryIntersection::Generated)
}
(Token::Word("RAY_QUERY_INTERSECTION_AABB"), _) => {
let _ = lexer.next();
literal_ray_intersection(crate::RayQueryIntersection::Aabb)
}
(Token::Word(word), span) => {
let start = lexer.start_byte_offset();
let _ = lexer.next();
if let Some(ty) = self.constructor_type(lexer, word, span, ctx)? {
let ty_span = lexer.span_from(start);
let components = self.arguments(lexer, ctx)?;
ast::Expression::Construct {
ty,
ty_span,
components,
}
} else if let Token::Paren('(') = lexer.peek().0 {
self.pop_rule_span(lexer);
return self.function_call(lexer, word, span, ctx);
} else if word == "bitcast" {
self.pop_rule_span(lexer);
return self.function_call(lexer, word, span, ctx);
} else {
let ident = self.ident_expr(word, span, ctx);
ast::Expression::Ident(ident)
}
}
other => return Err(Error::Unexpected(other.1, ExpectedToken::PrimaryExpression)),
};
let span = self.pop_rule_span(lexer);
let expr = ctx.expressions.append(expr, span);
Ok(expr)
}
fn postfix<'a>(
&mut self,
span_start: usize,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
expr: Handle<ast::Expression<'a>>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
let mut expr = expr;
loop {
let expression = match lexer.peek().0 {
Token::Separator('.') => {
let _ = lexer.next();
let field = lexer.next_ident()?;
ast::Expression::Member { base: expr, field }
}
Token::Paren('[') => {
let _ = lexer.next();
let index = self.enclosed_expression(lexer, ctx)?;
lexer.expect(Token::Paren(']'))?;
ast::Expression::Index { base: expr, index }
}
_ => break,
};
let span = lexer.span_from(span_start);
expr = ctx.expressions.append(expression, span);
}
Ok(expr)
}
fn const_generic_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
self.push_rule_span(Rule::GenericExpr, lexer);
let expr = self.general_expression(lexer, ctx)?;
self.pop_rule_span(lexer);
Ok(expr)
}
/// Parse a `unary_expression`.
fn unary_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
self.push_rule_span(Rule::UnaryExpr, lexer);
//TODO: refactor this to avoid backing up
let expr = match lexer.peek().0 {
Token::Operation('-') => {
let _ = lexer.next();
let expr = self.unary_expression(lexer, ctx)?;
let expr = ast::Expression::Unary {
op: crate::UnaryOperator::Negate,
expr,
};
let span = self.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
Token::Operation('!') => {
let _ = lexer.next();
let expr = self.unary_expression(lexer, ctx)?;
let expr = ast::Expression::Unary {
op: crate::UnaryOperator::LogicalNot,
expr,
};
let span = self.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
Token::Operation('~') => {
let _ = lexer.next();
let expr = self.unary_expression(lexer, ctx)?;
let expr = ast::Expression::Unary {
op: crate::UnaryOperator::BitwiseNot,
expr,
};
let span = self.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
Token::Operation('*') => {
let _ = lexer.next();
let expr = self.unary_expression(lexer, ctx)?;
let expr = ast::Expression::Deref(expr);
let span = self.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
Token::Operation('&') => {
let _ = lexer.next();
let expr = self.unary_expression(lexer, ctx)?;
let expr = ast::Expression::AddrOf(expr);
let span = self.peek_rule_span(lexer);
ctx.expressions.append(expr, span)
}
_ => self.singular_expression(lexer, ctx)?,
};
self.pop_rule_span(lexer);
Ok(expr)
}
/// Parse a `singular_expression`.
fn singular_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
let start = lexer.start_byte_offset();
self.push_rule_span(Rule::SingularExpr, lexer);
let primary_expr = self.primary_expression(lexer, ctx)?;
let singular_expr = self.postfix(start, lexer, ctx, primary_expr)?;
self.pop_rule_span(lexer);
Ok(singular_expr)
}
fn equality_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
context: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
// equality_expression
context.parse_binary_op(
lexer,
|token| match token {
Token::LogicalOperation('=') => Some(crate::BinaryOperator::Equal),
Token::LogicalOperation('!') => Some(crate::BinaryOperator::NotEqual),
_ => None,
},
// relational_expression
|lexer, context| {
let enclosing = self.race_rules(Rule::GenericExpr, Rule::EnclosedExpr);
context.parse_binary_op(
lexer,
match enclosing {
Some(Rule::GenericExpr) => |token| match token {
Token::LogicalOperation('<') => Some(crate::BinaryOperator::LessEqual),
Token::LogicalOperation('>') => {
Some(crate::BinaryOperator::GreaterEqual)
}
_ => None,
},
_ => |token| match token {
Token::Paren('<') => Some(crate::BinaryOperator::Less),
Token::Paren('>') => Some(crate::BinaryOperator::Greater),
Token::LogicalOperation('<') => Some(crate::BinaryOperator::LessEqual),
Token::LogicalOperation('>') => {
Some(crate::BinaryOperator::GreaterEqual)
}
_ => None,
},
},
// shift_expression
|lexer, context| {
context.parse_binary_op(
lexer,
match enclosing {
Some(Rule::GenericExpr) => |token| match token {
Token::ShiftOperation('<') => {
Some(crate::BinaryOperator::ShiftLeft)
}
_ => None,
},
_ => |token| match token {
Token::ShiftOperation('<') => {
Some(crate::BinaryOperator::ShiftLeft)
}
Token::ShiftOperation('>') => {
Some(crate::BinaryOperator::ShiftRight)
}
_ => None,
},
},
// additive_expression
|lexer, context| {
context.parse_binary_op(
lexer,
|token| match token {
Token::Operation('+') => Some(crate::BinaryOperator::Add),
Token::Operation('-') => {
Some(crate::BinaryOperator::Subtract)
}
_ => None,
},
// multiplicative_expression
|lexer, context| {
context.parse_binary_op(
lexer,
|token| match token {
Token::Operation('*') => {
Some(crate::BinaryOperator::Multiply)
}
Token::Operation('/') => {
Some(crate::BinaryOperator::Divide)
}
Token::Operation('%') => {
Some(crate::BinaryOperator::Modulo)
}
_ => None,
},
|lexer, context| self.unary_expression(lexer, context),
)
},
)
},
)
},
)
},
)
}
fn general_expression<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Expression<'a>>, Error<'a>> {
self.general_expression_with_span(lexer, ctx)
.map(|(expr, _)| expr)
}
fn general_expression_with_span<'a>(
&mut self,
lexer: &mut Lexer<'a>,
context: &mut ExpressionContext<'a, '_, '_>,
) -> Result<(Handle<ast::Expression<'a>>, Span), Error<'a>> {
self.push_rule_span(Rule::GeneralExpr, lexer);
// logical_or_expression
let handle = context.parse_binary_op(
lexer,
|token| match token {
Token::LogicalOperation('|') => Some(crate::BinaryOperator::LogicalOr),
_ => None,
},
// logical_and_expression
|lexer, context| {
context.parse_binary_op(
lexer,
|token| match token {
Token::LogicalOperation('&') => Some(crate::BinaryOperator::LogicalAnd),
_ => None,
},
// inclusive_or_expression
|lexer, context| {
context.parse_binary_op(
lexer,
|token| match token {
Token::Operation('|') => Some(crate::BinaryOperator::InclusiveOr),
_ => None,
},
// exclusive_or_expression
|lexer, context| {
context.parse_binary_op(
lexer,
|token| match token {
Token::Operation('^') => {
Some(crate::BinaryOperator::ExclusiveOr)
}
_ => None,
},
// and_expression
|lexer, context| {
context.parse_binary_op(
lexer,
|token| match token {
Token::Operation('&') => {
Some(crate::BinaryOperator::And)
}
_ => None,
},
|lexer, context| {
self.equality_expression(lexer, context)
},
)
},
)
},
)
},
)
},
)?;
Ok((handle, self.pop_rule_span(lexer)))
}
fn variable_decl<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<ast::GlobalVariable<'a>, Error<'a>> {
self.push_rule_span(Rule::VariableDecl, lexer);
let mut space = crate::AddressSpace::Handle;
if lexer.skip(Token::Paren('<')) {
let (class_str, span) = lexer.next_ident_with_span()?;
space = match class_str {
"storage" => {
let access = if lexer.skip(Token::Separator(',')) {
lexer.next_storage_access()?
} else {
// defaulting to `read`
crate::StorageAccess::LOAD
};
crate::AddressSpace::Storage { access }
}
_ => conv::map_address_space(class_str, span)?,
};
lexer.expect(Token::Paren('>'))?;
}
let name = lexer.next_ident()?;
let ty = if lexer.skip(Token::Separator(':')) {
Some(self.type_decl(lexer, ctx)?)
} else {
None
};
let init = if lexer.skip(Token::Operation('=')) {
let handle = self.general_expression(lexer, ctx)?;
Some(handle)
} else {
None
};
lexer.expect(Token::Separator(';'))?;
self.pop_rule_span(lexer);
Ok(ast::GlobalVariable {
name,
space,
binding: None,
ty,
init,
})
}
fn struct_body<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Vec<ast::StructMember<'a>>, Error<'a>> {
let mut members = Vec::new();
lexer.expect(Token::Paren('{'))?;
let mut ready = true;
while !lexer.skip(Token::Paren('}')) {
if !ready {
return Err(Error::Unexpected(
lexer.next().1,
ExpectedToken::Token(Token::Separator(',')),
));
}
let (mut size, mut align) = (ParsedAttribute::default(), ParsedAttribute::default());
self.push_rule_span(Rule::Attribute, lexer);
let mut bind_parser = BindingParser::default();
while lexer.skip(Token::Attribute) {
match lexer.next_ident_with_span()? {
("size", name_span) => {
lexer.expect(Token::Paren('('))?;
let expr = self.general_expression(lexer, ctx)?;
lexer.expect(Token::Paren(')'))?;
size.set(expr, name_span)?;
}
("align", name_span) => {
lexer.expect(Token::Paren('('))?;
let expr = self.general_expression(lexer, ctx)?;
lexer.expect(Token::Paren(')'))?;
align.set(expr, name_span)?;
}
(word, word_span) => bind_parser.parse(self, lexer, word, word_span, ctx)?,
}
}
let bind_span = self.pop_rule_span(lexer);
let binding = bind_parser.finish(bind_span)?;
let name = lexer.next_ident()?;
lexer.expect(Token::Separator(':'))?;
let ty = self.type_decl(lexer, ctx)?;
ready = lexer.skip(Token::Separator(','));
members.push(ast::StructMember {
name,
ty,
binding,
size: size.value,
align: align.value,
});
}
Ok(members)
}
/// Parses `<T>`, returning T and span of T
fn singular_generic<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<(Handle<ast::Type<'a>>, Span), Error<'a>> {
lexer.expect_generic_paren('<')?;
let start = lexer.start_byte_offset();
let ty = self.type_decl(lexer, ctx)?;
let span = lexer.span_from(start);
lexer.expect_generic_paren('>')?;
Ok((ty, span))
}
fn matrix_with_type<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
columns: crate::VectorSize,
rows: crate::VectorSize,
) -> Result<ast::Type<'a>, Error<'a>> {
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
Ok(ast::Type::Matrix {
columns,
rows,
ty,
ty_span,
})
}
fn type_decl_impl<'a>(
&mut self,
lexer: &mut Lexer<'a>,
word: &'a str,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Option<ast::Type<'a>>, Error<'a>> {
if let Some(scalar) = conv::get_scalar_type(word) {
return Ok(Some(ast::Type::Scalar(scalar)));
}
Ok(Some(match word {
"vec2" => {
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
ast::Type::Vector {
size: crate::VectorSize::Bi,
ty,
ty_span,
}
}
"vec2i" => ast::Type::Vector {
size: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::I32),
ty_span: Span::UNDEFINED,
},
"vec2u" => ast::Type::Vector {
size: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::U32),
ty_span: Span::UNDEFINED,
},
"vec2f" => ast::Type::Vector {
size: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"vec3" => {
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
ast::Type::Vector {
size: crate::VectorSize::Tri,
ty,
ty_span,
}
}
"vec3i" => ast::Type::Vector {
size: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::I32),
ty_span: Span::UNDEFINED,
},
"vec3u" => ast::Type::Vector {
size: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::U32),
ty_span: Span::UNDEFINED,
},
"vec3f" => ast::Type::Vector {
size: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"vec4" => {
let (ty, ty_span) = self.singular_generic(lexer, ctx)?;
ast::Type::Vector {
size: crate::VectorSize::Quad,
ty,
ty_span,
}
}
"vec4i" => ast::Type::Vector {
size: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::I32),
ty_span: Span::UNDEFINED,
},
"vec4u" => ast::Type::Vector {
size: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::U32),
ty_span: Span::UNDEFINED,
},
"vec4f" => ast::Type::Vector {
size: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat2x2" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Bi)?
}
"mat2x2f" => ast::Type::Matrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat2x3" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Tri)?
}
"mat2x3f" => ast::Type::Matrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat2x4" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Bi, crate::VectorSize::Quad)?
}
"mat2x4f" => ast::Type::Matrix {
columns: crate::VectorSize::Bi,
rows: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat3x2" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Bi)?
}
"mat3x2f" => ast::Type::Matrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat3x3" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Tri)?
}
"mat3x3f" => ast::Type::Matrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat3x4" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Tri, crate::VectorSize::Quad)?
}
"mat3x4f" => ast::Type::Matrix {
columns: crate::VectorSize::Tri,
rows: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat4x2" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Bi)?
}
"mat4x2f" => ast::Type::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Bi,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat4x3" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Tri)?
}
"mat4x3f" => ast::Type::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Tri,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"mat4x4" => {
self.matrix_with_type(lexer, ctx, crate::VectorSize::Quad, crate::VectorSize::Quad)?
}
"mat4x4f" => ast::Type::Matrix {
columns: crate::VectorSize::Quad,
rows: crate::VectorSize::Quad,
ty: ctx.new_scalar(Scalar::F32),
ty_span: Span::UNDEFINED,
},
"atomic" => {
let scalar = lexer.next_scalar_generic()?;
ast::Type::Atomic(scalar)
}
"ptr" => {
lexer.expect_generic_paren('<')?;
let (ident, span) = lexer.next_ident_with_span()?;
let mut space = conv::map_address_space(ident, span)?;
lexer.expect(Token::Separator(','))?;
let base = self.type_decl(lexer, ctx)?;
if let crate::AddressSpace::Storage { ref mut access } = space {
*access = if lexer.skip(Token::Separator(',')) {
lexer.next_storage_access()?
} else {
crate::StorageAccess::LOAD
};
}
lexer.expect_generic_paren('>')?;
ast::Type::Pointer { base, space }
}
"array" => {
lexer.expect_generic_paren('<')?;
let base = self.type_decl(lexer, ctx)?;
let size = if lexer.skip(Token::Separator(',')) {
let size = self.const_generic_expression(lexer, ctx)?;
ast::ArraySize::Constant(size)
} else {
ast::ArraySize::Dynamic
};
lexer.expect_generic_paren('>')?;
ast::Type::Array { base, size }
}
"binding_array" => {
lexer.expect_generic_paren('<')?;
let base = self.type_decl(lexer, ctx)?;
let size = if lexer.skip(Token::Separator(',')) {
let size = self.unary_expression(lexer, ctx)?;
ast::ArraySize::Constant(size)
} else {
ast::ArraySize::Dynamic
};
lexer.expect_generic_paren('>')?;
ast::Type::BindingArray { base, size }
}
"sampler" => ast::Type::Sampler { comparison: false },
"sampler_comparison" => ast::Type::Sampler { comparison: true },
"texture_1d" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D1,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_1d_array" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D1,
arrayed: true,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_2d" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_2d_array" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: true,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_3d" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D3,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_cube" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::Cube,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_cube_array" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::Cube,
arrayed: true,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: false,
},
}
}
"texture_multisampled_2d" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: true,
},
}
}
"texture_multisampled_2d_array" => {
let (scalar, span) = lexer.next_scalar_generic_with_span()?;
Self::check_texture_sample_type(scalar, span)?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: true,
class: crate::ImageClass::Sampled {
kind: scalar.kind,
multi: true,
},
}
}
"texture_depth_2d" => ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Depth { multi: false },
},
"texture_depth_2d_array" => ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: true,
class: crate::ImageClass::Depth { multi: false },
},
"texture_depth_cube" => ast::Type::Image {
dim: crate::ImageDimension::Cube,
arrayed: false,
class: crate::ImageClass::Depth { multi: false },
},
"texture_depth_cube_array" => ast::Type::Image {
dim: crate::ImageDimension::Cube,
arrayed: true,
class: crate::ImageClass::Depth { multi: false },
},
"texture_depth_multisampled_2d" => ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Depth { multi: true },
},
"texture_storage_1d" => {
let (format, access) = lexer.next_format_generic()?;
ast::Type::Image {
dim: crate::ImageDimension::D1,
arrayed: false,
class: crate::ImageClass::Storage { format, access },
}
}
"texture_storage_1d_array" => {
let (format, access) = lexer.next_format_generic()?;
ast::Type::Image {
dim: crate::ImageDimension::D1,
arrayed: true,
class: crate::ImageClass::Storage { format, access },
}
}
"texture_storage_2d" => {
let (format, access) = lexer.next_format_generic()?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: false,
class: crate::ImageClass::Storage { format, access },
}
}
"texture_storage_2d_array" => {
let (format, access) = lexer.next_format_generic()?;
ast::Type::Image {
dim: crate::ImageDimension::D2,
arrayed: true,
class: crate::ImageClass::Storage { format, access },
}
}
"texture_storage_3d" => {
let (format, access) = lexer.next_format_generic()?;
ast::Type::Image {
dim: crate::ImageDimension::D3,
arrayed: false,
class: crate::ImageClass::Storage { format, access },
}
}
"acceleration_structure" => ast::Type::AccelerationStructure,
"ray_query" => ast::Type::RayQuery,
"RayDesc" => ast::Type::RayDesc,
"RayIntersection" => ast::Type::RayIntersection,
_ => return Ok(None),
}))
}
const fn check_texture_sample_type(scalar: Scalar, span: Span) -> Result<(), Error<'static>> {
use crate::ScalarKind::*;
// Validate according to https://gpuweb.github.io/gpuweb/wgsl/#sampled-texture-type
match scalar {
Scalar {
kind: Float | Sint | Uint,
width: 4,
} => Ok(()),
_ => Err(Error::BadTextureSampleType { span, scalar }),
}
}
/// Parse type declaration of a given name.
fn type_decl<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
) -> Result<Handle<ast::Type<'a>>, Error<'a>> {
self.push_rule_span(Rule::TypeDecl, lexer);
let (name, span) = lexer.next_ident_with_span()?;
let ty = match self.type_decl_impl(lexer, name, ctx)? {
Some(ty) => ty,
None => {
ctx.unresolved.insert(ast::Dependency {
ident: name,
usage: span,
});
ast::Type::User(ast::Ident { name, span })
}
};
self.pop_rule_span(lexer);
let handle = ctx.types.append(ty, Span::UNDEFINED);
Ok(handle)
}
fn assignment_op_and_rhs<'a>(
&mut self,
lexer: &mut Lexer<'a>,
ctx: &mut ExpressionContext<'a, '_, '_>,
block: &mut ast::Block<'a>,
target: Handle<ast::Expression<'a>>,
span_start: usize,
) -> Result<(), Error<'a>> {
--> --------------------
--> maximum size reached
--> --------------------
[ 0.66Quellennavigators
]
|
2026-04-04
|