dusk: rewrite AstGen.zig and IR.zig
This commit is contained in:
parent
46c5ca1dd0
commit
624ab118db
5 changed files with 1043 additions and 479 deletions
|
|
@ -171,7 +171,7 @@ pub const Node = struct {
|
||||||
/// RHS : block
|
/// RHS : block
|
||||||
fn_decl,
|
fn_decl,
|
||||||
/// TOK : ident
|
/// TOK : ident
|
||||||
/// LHS : ? Attributes
|
/// LHS : ?span(Attribute)
|
||||||
/// RHS : type
|
/// RHS : type
|
||||||
fn_param,
|
fn_param,
|
||||||
|
|
||||||
|
|
@ -367,7 +367,7 @@ pub const Node = struct {
|
||||||
/// RHS : --
|
/// RHS : --
|
||||||
user_type,
|
user_type,
|
||||||
|
|
||||||
// ####### Attr #######
|
// ####### Attribute #######
|
||||||
|
|
||||||
// TOK : attr
|
// TOK : attr
|
||||||
attr,
|
attr,
|
||||||
|
|
@ -650,6 +650,7 @@ pub const InterpolationSample = enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const AddressSpace = enum {
|
pub const AddressSpace = enum {
|
||||||
|
none, // TODO
|
||||||
function,
|
function,
|
||||||
private,
|
private,
|
||||||
workgroup,
|
workgroup,
|
||||||
|
|
@ -658,6 +659,7 @@ pub const AddressSpace = enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const AccessMode = enum {
|
pub const AccessMode = enum {
|
||||||
|
none, // TODO
|
||||||
read,
|
read,
|
||||||
write,
|
write,
|
||||||
read_write,
|
read_write,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -4,11 +4,15 @@ const Ast = @import("Ast.zig");
|
||||||
const ErrorMsg = @import("main.zig").ErrorMsg;
|
const ErrorMsg = @import("main.zig").ErrorMsg;
|
||||||
const IR = @This();
|
const IR = @This();
|
||||||
|
|
||||||
arena: std.heap.ArenaAllocator,
|
allocator: std.mem.Allocator,
|
||||||
root: TranslationUnit,
|
instructions: []const Inst,
|
||||||
|
refs: []const Ref,
|
||||||
|
strings: []const u8,
|
||||||
|
|
||||||
pub fn deinit(self: IR) void {
|
pub fn deinit(self: IR) void {
|
||||||
self.arena.deinit();
|
self.allocator.free(self.instructions);
|
||||||
|
self.allocator.free(self.refs);
|
||||||
|
self.allocator.free(self.strings);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const AstGenResult = union(enum) {
|
pub const AstGenResult = union(enum) {
|
||||||
|
|
@ -17,193 +21,276 @@ pub const AstGenResult = union(enum) {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn generate(allocator: std.mem.Allocator, tree: *const Ast) !AstGenResult {
|
pub fn generate(allocator: std.mem.Allocator, tree: *const Ast) !AstGenResult {
|
||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
|
||||||
errdefer arena.deinit();
|
|
||||||
|
|
||||||
var astgen = AstGen{
|
var astgen = AstGen{
|
||||||
.arena = arena.allocator(),
|
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.tree = tree,
|
.tree = tree,
|
||||||
.errors = .{},
|
.scope_pool = std.heap.MemoryPool(AstGen.Scope).init(allocator),
|
||||||
};
|
};
|
||||||
defer astgen.deinit();
|
defer astgen.deinit();
|
||||||
|
|
||||||
const root = try astgen.translationUnit() orelse {
|
if (!try astgen.translationUnit()) {
|
||||||
arena.deinit();
|
return .{ .errors = try astgen.errors.toOwnedSlice(allocator) };
|
||||||
return .{
|
}
|
||||||
.errors = try astgen.errors.toOwnedSlice(allocator),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return .{ .ir = .{ .arena = arena, .root = root } };
|
return .{ .ir = .{
|
||||||
|
.allocator = allocator,
|
||||||
|
.instructions = try astgen.instructions.toOwnedSlice(allocator),
|
||||||
|
.refs = try astgen.refs.toOwnedSlice(allocator),
|
||||||
|
.strings = try astgen.strings.toOwnedSlice(allocator),
|
||||||
|
} };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TranslationUnit = []const GlobalDecl;
|
pub const Ref = u32;
|
||||||
|
pub const null_ref: Ref = std.math.maxInt(Ref);
|
||||||
|
|
||||||
pub const GlobalDecl = union(enum) {
|
pub const Inst = packed struct {
|
||||||
variable: GlobalVariable,
|
tag: Tag,
|
||||||
@"struct": StructDecl,
|
data: Data,
|
||||||
};
|
|
||||||
|
|
||||||
pub const GlobalVariable = struct {
|
pub const Tag = enum(u6) {
|
||||||
name: []const u8,
|
/// data is global_variable
|
||||||
type: union(enum) {},
|
global_variable,
|
||||||
expr: Expression,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const StructDecl = struct {
|
/// data is struct_decl
|
||||||
name: []const u8,
|
struct_decl,
|
||||||
members: []const StructMember,
|
/// data is struct_member
|
||||||
};
|
struct_member,
|
||||||
|
|
||||||
pub const StructMember = struct {
|
/// data is attr_simple
|
||||||
name: []const u8,
|
attr_simple,
|
||||||
type: Type,
|
/// data is attr_expr
|
||||||
|
attr_expr,
|
||||||
|
/// data is attr_builtin
|
||||||
|
attr_builtin,
|
||||||
|
/// data is attr_workgroup
|
||||||
|
attr_workgroup,
|
||||||
|
/// data is attr_interpolate
|
||||||
|
attr_interpolate,
|
||||||
|
|
||||||
pub const Type = union(enum) {
|
/// data is none
|
||||||
bool,
|
bool_type,
|
||||||
@"struct": []const u8,
|
/// data is none
|
||||||
number: NumberType,
|
i32_type,
|
||||||
vector: VectorType,
|
/// data is none
|
||||||
matrix: MatrixType,
|
u32_type,
|
||||||
atomic: AtomicType,
|
/// data is none
|
||||||
array: ArrayType,
|
f32_type,
|
||||||
|
/// data is none
|
||||||
|
f16_type,
|
||||||
|
/// data is vector_type
|
||||||
|
vector_type,
|
||||||
|
/// data is matrix_type
|
||||||
|
matrix_type,
|
||||||
|
/// data is atomic_type
|
||||||
|
atomic_type,
|
||||||
|
/// data is array_type
|
||||||
|
array_type,
|
||||||
|
/// data is ptr_type
|
||||||
|
ptr_type,
|
||||||
|
/// data is none
|
||||||
|
sampler_type,
|
||||||
|
/// data is none
|
||||||
|
comparison_sampler_type,
|
||||||
|
/// data is sampled_texture_type
|
||||||
|
sampled_texture_type,
|
||||||
|
/// data is multisampled_texture_type
|
||||||
|
multisampled_texture_type,
|
||||||
|
/// data is storage_texture_type
|
||||||
|
storage_texture_type,
|
||||||
|
/// data is depth_texture_type
|
||||||
|
depth_texture_type,
|
||||||
|
/// data is none
|
||||||
|
external_sampled_texture_type,
|
||||||
|
|
||||||
|
/// data is integer_literal
|
||||||
|
integer_literal,
|
||||||
|
/// data is float_literal
|
||||||
|
float_literal,
|
||||||
|
/// data is none
|
||||||
|
true_literal,
|
||||||
|
/// data is none
|
||||||
|
false_literal,
|
||||||
|
|
||||||
|
/// data is ref
|
||||||
|
not,
|
||||||
|
/// data is ref
|
||||||
|
negate,
|
||||||
|
/// data is ref
|
||||||
|
deref,
|
||||||
|
/// data is ref
|
||||||
|
addr_of,
|
||||||
|
|
||||||
|
/// data is binary
|
||||||
|
mul,
|
||||||
|
/// data is binary
|
||||||
|
div,
|
||||||
|
/// data is binary
|
||||||
|
mod,
|
||||||
|
/// data is binary
|
||||||
|
add,
|
||||||
|
/// data is binary
|
||||||
|
sub,
|
||||||
|
/// data is binary
|
||||||
|
shift_left,
|
||||||
|
/// data is binary
|
||||||
|
shift_right,
|
||||||
|
/// data is binary
|
||||||
|
binary_and,
|
||||||
|
/// data is binary
|
||||||
|
binary_or,
|
||||||
|
/// data is binary
|
||||||
|
binary_xor,
|
||||||
|
/// data is binary
|
||||||
|
circuit_and,
|
||||||
|
/// data is binary
|
||||||
|
circuit_or,
|
||||||
|
/// data is binary
|
||||||
|
equal,
|
||||||
|
/// data is binary
|
||||||
|
not_equal,
|
||||||
|
/// data is binary
|
||||||
|
less,
|
||||||
|
/// data is binary
|
||||||
|
less_equal,
|
||||||
|
/// data is binary
|
||||||
|
greater,
|
||||||
|
/// data is binary
|
||||||
|
greater_equal,
|
||||||
|
|
||||||
|
/// data is binary
|
||||||
|
index,
|
||||||
|
/// data is member_access
|
||||||
|
member_access,
|
||||||
|
/// data is binary (lhs is expr, rhs is type)
|
||||||
|
bitcast,
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
pub const Expression = union(enum) {
|
pub const Data = packed union {
|
||||||
literal: Literal,
|
/// TODO: https://github.com/ziglang/zig/issues/14980
|
||||||
ident: []const u8,
|
none: u1,
|
||||||
unary: struct {
|
ref: Ref,
|
||||||
op: UnaryOperator,
|
global_variable: packed struct {
|
||||||
expr: *const Expression,
|
/// index to null-terminated string in `strings`
|
||||||
},
|
name: u32,
|
||||||
binary: struct {
|
type: Ref,
|
||||||
op: BinaryOperator,
|
addr_space: Ast.AddressSpace = .none,
|
||||||
lhs: *const Expression,
|
access_mode: Ast.AccessMode = .none,
|
||||||
rhs: *const Expression,
|
/// length of attributes
|
||||||
},
|
attrs: u4 = 0,
|
||||||
index: struct {
|
},
|
||||||
base: *const Expression,
|
struct_decl: packed struct {
|
||||||
index: *const Expression,
|
/// index to null-terminated string in `strings`
|
||||||
},
|
name: u32,
|
||||||
member: struct {
|
/// length of the member Ref's which comes after this
|
||||||
base: *const Expression,
|
members: u32,
|
||||||
field: []const u8,
|
},
|
||||||
},
|
struct_member: packed struct {
|
||||||
bitcast: struct {
|
/// index to null-terminated string in `strings`
|
||||||
expr: *const Expression,
|
name: u32,
|
||||||
to: union(enum) {
|
type: Ref,
|
||||||
number: NumberType,
|
@"align": u29, // 0 means null
|
||||||
vector: VectorType,
|
},
|
||||||
|
/// attributes with no argument.
|
||||||
|
attr_simple: enum {
|
||||||
|
invariant,
|
||||||
|
@"const",
|
||||||
|
vertex,
|
||||||
|
fragment,
|
||||||
|
compute,
|
||||||
|
},
|
||||||
|
/// attributes with an expression argument.
|
||||||
|
attr_expr: packed struct {
|
||||||
|
kind: enum {
|
||||||
|
@"align",
|
||||||
|
binding,
|
||||||
|
group,
|
||||||
|
id,
|
||||||
|
location,
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
expr: Ref,
|
||||||
|
},
|
||||||
|
/// @builtin attribute which accepts a BuiltinValue argument.
|
||||||
|
attr_builtin: Ast.BuiltinValue,
|
||||||
|
/// @workgroup attribute. accepts at laest 1 argument.
|
||||||
|
attr_workgroup: packed struct {
|
||||||
|
expr0: Ref,
|
||||||
|
expr1: Ref = null_ref,
|
||||||
|
expr2: Ref = null_ref,
|
||||||
|
},
|
||||||
|
/// @interpolate attribute. accepts 2 arguments.
|
||||||
|
attr_interpolate: packed struct {
|
||||||
|
type: Ast.InterpolationType,
|
||||||
|
sample: Ast.InterpolationSample,
|
||||||
|
},
|
||||||
|
vector_type: packed struct {
|
||||||
|
component_type: Ref,
|
||||||
|
size: enum { two, three, four },
|
||||||
|
},
|
||||||
|
matrix_type: packed struct {
|
||||||
|
component_type: Ref,
|
||||||
|
cols: enum { two, three, four },
|
||||||
|
rows: enum { two, three, four },
|
||||||
|
},
|
||||||
|
atomic_type: packed struct { component_type: Ref },
|
||||||
|
array_type: packed struct {
|
||||||
|
component_type: Ref,
|
||||||
|
size: Ref = null_ref,
|
||||||
|
},
|
||||||
|
ptr_type: packed struct {
|
||||||
|
component_type: Ref,
|
||||||
|
addr_space: Ast.AddressSpace,
|
||||||
|
access_mode: Ast.AccessMode,
|
||||||
|
},
|
||||||
|
sampled_texture_type: packed struct {
|
||||||
|
kind: enum {
|
||||||
|
@"1d",
|
||||||
|
@"2d",
|
||||||
|
@"2d_array",
|
||||||
|
@"3d",
|
||||||
|
cube,
|
||||||
|
cube_array,
|
||||||
|
},
|
||||||
|
component_type: Ref,
|
||||||
|
},
|
||||||
|
multisampled_texture_type: packed struct {
|
||||||
|
kind: enum { @"2d" },
|
||||||
|
component_type: Ref,
|
||||||
|
},
|
||||||
|
storage_texture_type: packed struct {
|
||||||
|
kind: enum {
|
||||||
|
@"1d",
|
||||||
|
@"2d",
|
||||||
|
@"2d_array",
|
||||||
|
@"3d",
|
||||||
|
},
|
||||||
|
texel_format: Ast.TexelFormat,
|
||||||
|
access_mode: MultisampledTextureTypeKind,
|
||||||
|
},
|
||||||
|
depth_texture_type: enum {
|
||||||
|
@"2d",
|
||||||
|
@"2d_array",
|
||||||
|
cube,
|
||||||
|
cube_array,
|
||||||
|
multisampled_2d,
|
||||||
|
},
|
||||||
|
integer_literal: i64,
|
||||||
|
float_literal: f64,
|
||||||
|
/// meaning of LHS and RHS depends on the corresponding Tag.
|
||||||
|
binary: packed struct {
|
||||||
|
lhs: Ref,
|
||||||
|
rhs: Ref,
|
||||||
|
},
|
||||||
|
member_access: packed struct {
|
||||||
|
base: Ref,
|
||||||
|
/// index to null-terminated string in `strings`
|
||||||
|
name: u32,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Literal = union(enum) {
|
pub const MultisampledTextureTypeKind = enum { write };
|
||||||
number: NumberLiteral,
|
|
||||||
bool: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const NumberLiteral = union(enum) {
|
|
||||||
int: i64,
|
|
||||||
float: f64,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const UnaryOperator = enum {
|
|
||||||
not,
|
|
||||||
negate,
|
|
||||||
addr_of,
|
|
||||||
deref,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const BinaryOperator = enum {
|
|
||||||
mul,
|
|
||||||
div,
|
|
||||||
mod,
|
|
||||||
add,
|
|
||||||
sub,
|
|
||||||
shift_left,
|
|
||||||
shift_right,
|
|
||||||
binary_and,
|
|
||||||
binary_or,
|
|
||||||
binary_xor,
|
|
||||||
circuit_and,
|
|
||||||
circuit_or,
|
|
||||||
equal,
|
|
||||||
not_equal,
|
|
||||||
less,
|
|
||||||
less_equal,
|
|
||||||
greater,
|
|
||||||
greater_equal,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const NumberType = enum {
|
|
||||||
i32,
|
|
||||||
u32,
|
|
||||||
f32,
|
|
||||||
f16,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const VectorType = struct {
|
|
||||||
size: Size,
|
|
||||||
component_type: Type,
|
|
||||||
|
|
||||||
pub const Type = union(enum) {
|
|
||||||
bool,
|
|
||||||
number: NumberType,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Size = enum {
|
comptime {
|
||||||
vec2,
|
std.debug.assert(@bitSizeOf(Inst) <= 104); // 13B
|
||||||
vec3,
|
}
|
||||||
vec4,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const MatrixType = struct {
|
|
||||||
size: Size,
|
|
||||||
component_type: Type,
|
|
||||||
|
|
||||||
pub const Type = enum {
|
|
||||||
f32,
|
|
||||||
f16,
|
|
||||||
abstract_float,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Size = enum {
|
|
||||||
mat2x2,
|
|
||||||
mat2x3,
|
|
||||||
mat2x4,
|
|
||||||
mat3x2,
|
|
||||||
mat3x3,
|
|
||||||
mat3x4,
|
|
||||||
mat4x2,
|
|
||||||
mat4x3,
|
|
||||||
mat4x4,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const AtomicType = struct {
|
|
||||||
component_type: Type,
|
|
||||||
|
|
||||||
pub const Type = enum {
|
|
||||||
u32,
|
|
||||||
i32,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const ArrayType = struct {
|
|
||||||
component_type: Type,
|
|
||||||
size: ?NumberLiteral = null,
|
|
||||||
|
|
||||||
pub const Type = union(enum) {
|
|
||||||
bool,
|
|
||||||
number: NumberType,
|
|
||||||
@"struct": []const u8,
|
|
||||||
vector: VectorType,
|
|
||||||
matrix: MatrixType,
|
|
||||||
atomic: AtomicType,
|
|
||||||
array: *Type,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,8 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Ast = @import("Ast.zig");
|
const Ast = @import("Ast.zig");
|
||||||
const Token = @import("Token.zig");
|
const Token = @import("Token.zig");
|
||||||
const Tokenizer = @import("Tokenizer.zig");
|
|
||||||
const Extension = @import("main.zig").Extension;
|
const Extension = @import("main.zig").Extension;
|
||||||
const ErrorMsg = @import("main.zig").ErrorMsg;
|
const ErrorMsg = @import("main.zig").ErrorMsg;
|
||||||
const comptimePrint = std.fmt.comptimePrint;
|
|
||||||
const fieldNames = std.meta.fieldNames;
|
const fieldNames = std.meta.fieldNames;
|
||||||
const Parser = @This();
|
const Parser = @This();
|
||||||
|
|
||||||
|
|
@ -1877,7 +1875,7 @@ fn addExtra(p: *Parser, extra: anytype) error{OutOfMemory}!Ast.Index {
|
||||||
try p.extra.ensureUnusedCapacity(p.allocator, fields.len);
|
try p.extra.ensureUnusedCapacity(p.allocator, fields.len);
|
||||||
const result = @intCast(Ast.Index, p.extra.items.len);
|
const result = @intCast(Ast.Index, p.extra.items.len);
|
||||||
inline for (fields) |field| {
|
inline for (fields) |field| {
|
||||||
comptime std.debug.assert(field.type == Ast.Index or field.type == Ast.Index);
|
comptime std.debug.assert(field.type == Ast.Index);
|
||||||
p.extra.appendAssumeCapacity(@field(extra, field.name));
|
p.extra.appendAssumeCapacity(@field(extra, field.name));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,10 @@ fn expectError(source: [:0]const u8, err: dusk.ErrorMsg) !void {
|
||||||
.{ err.note.?.msg, err_list[0].note.?.msg },
|
.{ err.note.?.msg, err_list[0].note.?.msg },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (err.note == null) {
|
||||||
|
std.debug.print("\x1b[31mnote missed: {s}\x1b[0m\n", .{err_list[0].note.?.msg});
|
||||||
|
return error.NoteMissed;
|
||||||
|
}
|
||||||
try expect(std.mem.eql(u8, err.note.?.msg, err_list[0].note.?.msg));
|
try expect(std.mem.eql(u8, err.note.?.msg, err_list[0].note.?.msg));
|
||||||
if (err_list[0].note.?.loc) |_| {
|
if (err_list[0].note.?.loc) |_| {
|
||||||
errdefer {
|
errdefer {
|
||||||
|
|
@ -232,7 +236,22 @@ test "variable & expressions" {
|
||||||
// try expect(ir.nodeTag(@"7") == .number_literal);
|
// try expect(ir.nodeTag(@"7") == .number_literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "analyser errors" {
|
test "simple analyse's result" {
|
||||||
|
// {
|
||||||
|
// const source =
|
||||||
|
// \\type T0 = f32;
|
||||||
|
// \\type T1 = T0;
|
||||||
|
// \\type T2 = T1;
|
||||||
|
// \\type T3 = T2;
|
||||||
|
// \\struct S0 { m0: T3 }
|
||||||
|
// ;
|
||||||
|
// var ir = try expectIR(source);
|
||||||
|
// // try std.testing.expect(ir.root[0].@"struct".members[0].type.number == .f32);
|
||||||
|
// ir.deinit();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
test "must error" {
|
||||||
{
|
{
|
||||||
const source = "^";
|
const source = "^";
|
||||||
try expectError(source, .{
|
try expectError(source, .{
|
||||||
|
|
@ -260,18 +279,17 @@ test "analyser errors" {
|
||||||
\\struct S0 { m: S1 }
|
\\struct S0 { m: S1 }
|
||||||
;
|
;
|
||||||
try expectError(source, .{
|
try expectError(source, .{
|
||||||
.msg = "'S1' is neither an struct or type alias",
|
.msg = "'S1' is not a type",
|
||||||
.loc = .{ .start = 27, .end = 29 },
|
.loc = .{ .start = 27, .end = 29 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const source =
|
const source =
|
||||||
\\type T = sampler;
|
\\struct S0 { m: sampler }
|
||||||
\\struct S0 { m: T }
|
|
||||||
;
|
;
|
||||||
try expectError(source, .{
|
try expectError(source, .{
|
||||||
.msg = "invalid struct member type 'T'",
|
.msg = "invalid struct member type 'sampler'",
|
||||||
.loc = .{ .start = 30, .end = 31 },
|
.loc = .{ .start = 12, .end = 13 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -285,4 +303,23 @@ test "analyser errors" {
|
||||||
.note = .{ .msg = "other declaration here", .loc = .{ .start = 4, .end = 6 } },
|
.note = .{ .msg = "other declaration here", .loc = .{ .start = 4, .end = 6 } },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const source = "struct S { m0: vec2<sampler> }";
|
||||||
|
try expectError(source, .{
|
||||||
|
.msg = "invalid vector component type",
|
||||||
|
.loc = .{ .start = 20, .end = 27 },
|
||||||
|
.note = .{ .msg = "must be 'i32', 'u32', 'f32', 'f16' or 'bool'" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const source =
|
||||||
|
\\type T0 = sampler;
|
||||||
|
\\type T1 = texture_1d<T0>;
|
||||||
|
;
|
||||||
|
try expectError(source, .{
|
||||||
|
.msg = "invalid sampled texture component type",
|
||||||
|
.loc = .{ .start = 40, .end = 42 },
|
||||||
|
.note = .{ .msg = "must be 'i32', 'u32' or 'f32'" },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue