dusk: basic binary expression errors
This commit is contained in:
parent
a14cb00ddd
commit
e620d8f759
5 changed files with 336 additions and 148 deletions
|
|
@ -362,11 +362,6 @@ pub const Node = struct {
|
||||||
/// RHS : --
|
/// RHS : --
|
||||||
depth_texture_type,
|
depth_texture_type,
|
||||||
|
|
||||||
/// TOK : ident
|
|
||||||
/// LHS : --
|
|
||||||
/// RHS : --
|
|
||||||
user_type,
|
|
||||||
|
|
||||||
// ####### Attribute #######
|
// ####### Attribute #######
|
||||||
|
|
||||||
// TOK : attr
|
// TOK : attr
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ const AstGen = @This();
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
tree: *const Ast,
|
tree: *const Ast,
|
||||||
instructions: std.ArrayListUnmanaged(IR.Inst) = .{},
|
instructions: IR.Inst.List = .{},
|
||||||
refs: std.ArrayListUnmanaged(IR.Inst.Ref) = .{},
|
refs: std.ArrayListUnmanaged(IR.Inst.Ref) = .{},
|
||||||
strings: std.ArrayListUnmanaged(u8) = .{},
|
strings: std.ArrayListUnmanaged(u8) = .{},
|
||||||
scratch: std.ArrayListUnmanaged(IR.Inst.Ref) = .{},
|
scratch: std.ArrayListUnmanaged(IR.Inst.Ref) = .{},
|
||||||
|
|
@ -52,6 +52,21 @@ pub fn genTranslationUnit(self: *AstGen) !u32 {
|
||||||
return try self.addRefList(self.scratch.items[scratch_top..]);
|
return try self.addRefList(self.scratch.items[scratch_top..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn genDecl(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
||||||
|
const ref = scope.decls.get(node).?;
|
||||||
|
if (ref != .none) return ref;
|
||||||
|
|
||||||
|
const decl = switch (self.tree.nodeTag(node)) {
|
||||||
|
.global_variable => try self.genGlobalVariable(scope, node),
|
||||||
|
.type_alias => try self.genTypeAlias(scope, node),
|
||||||
|
.struct_decl => try self.genStruct(scope, node),
|
||||||
|
else => return error.AnalysisFail, // TODO: make this unreachable
|
||||||
|
};
|
||||||
|
scope.decls.putAssumeCapacity(node, decl);
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// adds `decls` to scope and checks for re-declarations
|
||||||
pub fn scanDecls(self: *AstGen, scope: *Scope, decls: []const Ast.Index) !void {
|
pub fn scanDecls(self: *AstGen, scope: *Scope, decls: []const Ast.Index) !void {
|
||||||
std.debug.assert(scope.decls.count() == 0);
|
std.debug.assert(scope.decls.count() == 0);
|
||||||
|
|
||||||
|
|
@ -69,15 +84,15 @@ pub fn scanDecls(self: *AstGen, scope: *Scope, decls: []const Ast.Index) !void {
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
var name_iter = scope.decls.keyIterator();
|
var iter = scope.decls.keyIterator();
|
||||||
while (name_iter.next()) |node| {
|
while (iter.next()) |node| {
|
||||||
if (std.mem.eql(u8, self.declNameLoc(node.*).?.slice(self.tree.source), name)) {
|
if (std.mem.eql(u8, name, self.declNameLoc(node.*).?.slice(self.tree.source))) {
|
||||||
try self.errors.add(
|
try self.errors.add(
|
||||||
loc,
|
loc,
|
||||||
"redeclaration of '{s}'",
|
"redeclaration of '{s}'",
|
||||||
.{name},
|
.{name},
|
||||||
try self.errors.createNote(
|
try self.errors.createNote(
|
||||||
self.declNameLoc(node.*).?,
|
self.declNameLoc(node.*),
|
||||||
"other declaration here",
|
"other declaration here",
|
||||||
.{},
|
.{},
|
||||||
),
|
),
|
||||||
|
|
@ -90,41 +105,42 @@ pub fn scanDecls(self: *AstGen, scope: *Scope, decls: []const Ast.Index) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn genDecl(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
/// takes token location and returns the first declaration
|
||||||
const ref = scope.decls.get(node).?;
|
/// in current and parent scopes
|
||||||
if (ref != .none) return ref;
|
pub fn declRef(self: *AstGen, scope: *Scope, loc: Token.Loc) error{ OutOfMemory, AnalysisFail }!IR.Inst.Ref {
|
||||||
|
|
||||||
const decl = switch (self.tree.nodeTag(node)) {
|
|
||||||
.global_variable => try self.genGlobalVariable(scope, node),
|
|
||||||
.type_alias => try self.genTypeAlias(scope, node),
|
|
||||||
.struct_decl => try self.genStruct(scope, node),
|
|
||||||
else => return error.AnalysisFail, // TODO: else prong should not ever be trigerred
|
|
||||||
};
|
|
||||||
scope.decls.putAssumeCapacity(node, decl);
|
|
||||||
return decl;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn declRef(self: *AstGen, scope: *Scope, loc: Token.Loc) !IR.Inst.Ref {
|
|
||||||
const name = loc.slice(self.tree.source);
|
const name = loc.slice(self.tree.source);
|
||||||
|
|
||||||
var s = scope;
|
var s = scope;
|
||||||
while (true) {
|
while (true) {
|
||||||
var name_iter = s.decls.keyIterator();
|
var node_iter = s.decls.keyIterator();
|
||||||
while (name_iter.next()) |node| {
|
while (node_iter.next()) |node| {
|
||||||
if (std.mem.eql(u8, self.declNameLoc(node.*).?.slice(self.tree.source), name)) {
|
if (std.mem.eql(u8, name, self.declNameLoc(node.*).?.slice(self.tree.source))) {
|
||||||
return self.genDecl(scope, node.*);
|
return self.genDecl(scope, node.*);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = scope.parent orelse break;
|
s = scope.parent orelse {
|
||||||
|
try self.errors.add(
|
||||||
|
loc,
|
||||||
|
"use of undeclared identifier '{s}'",
|
||||||
|
.{name},
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
return error.AnalysisFail;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try self.errors.add(
|
/// returns declaration type or if type is unkown, returns value
|
||||||
loc,
|
pub fn valueOrType(inst: IR.Inst) IR.Inst.Ref {
|
||||||
"use of undeclared identifier '{s}'",
|
switch (inst.tag) {
|
||||||
.{name},
|
.global_variable_decl => {
|
||||||
null,
|
const decl_type = inst.data.global_variable_decl.type;
|
||||||
);
|
if (decl_type == .none) {
|
||||||
return error.AnalysisFail;
|
return inst.data.global_variable_decl.expr;
|
||||||
|
}
|
||||||
|
return decl_type;
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn genTypeAlias(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
pub fn genTypeAlias(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
||||||
|
|
@ -286,47 +302,103 @@ pub fn genStruct(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn genExpr(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
pub fn genExpr(self: *AstGen, scope: *Scope, node: Ast.Index) !IR.Inst.Ref {
|
||||||
const tag = self.tree.nodeTag(node);
|
const node_loc = self.tree.tokenLoc(self.tree.nodeToken(node));
|
||||||
const lhs = self.tree.nodeLHS(node);
|
const node_tag = self.tree.nodeTag(node);
|
||||||
const rhs = self.tree.nodeRHS(node);
|
const node_lhs = self.tree.nodeLHS(node);
|
||||||
|
const node_rhs = self.tree.nodeRHS(node);
|
||||||
|
const node_lhs_loc = self.tree.tokenLoc(self.tree.nodeToken(node_lhs));
|
||||||
|
const node_rhs_loc = self.tree.tokenLoc(self.tree.nodeToken(node_rhs));
|
||||||
|
|
||||||
switch (tag) {
|
switch (node_tag) {
|
||||||
.bool_true => return .true_literal,
|
.bool_true => return .true_literal,
|
||||||
.bool_false => return .true_literal,
|
.bool_false => return .false_literal,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
const inst_index = try self.reserveInst();
|
const inst_index = try self.reserveInst();
|
||||||
const inst: IR.Inst = switch (tag) {
|
const inst: IR.Inst = switch (node_tag) {
|
||||||
.number_literal => .{ .tag = .integer_literal, .data = .{ .integer_literal = 1 } },
|
.number_literal => .{ .tag = .integer_literal, .data = .{ .integer_literal = 1 } },
|
||||||
.not => .{ .tag = .not, .data = .{ .ref = try self.genExpr(scope, lhs) } },
|
.not => .{ .tag = .not, .data = .{ .ref = try self.genExpr(scope, node_lhs) } },
|
||||||
.negate => .{ .tag = .negate, .data = .{ .ref = try self.genExpr(scope, lhs) } },
|
.negate => .{ .tag = .negate, .data = .{ .ref = try self.genExpr(scope, node_lhs) } },
|
||||||
.deref => .{ .tag = .deref, .data = .{ .ref = try self.genExpr(scope, lhs) } },
|
.deref => .{ .tag = .deref, .data = .{ .ref = try self.genExpr(scope, node_lhs) } },
|
||||||
.addr_of => .{ .tag = .addr_of, .data = .{ .ref = try self.genExpr(scope, lhs) } },
|
.addr_of => .{ .tag = .addr_of, .data = .{ .ref = try self.genExpr(scope, node_lhs) } },
|
||||||
.mul => .{ .tag = .mul, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
|
||||||
.div => .{ .tag = .div, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.mul,
|
||||||
.mod => .{ .tag = .mod, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.div,
|
||||||
.add => .{ .tag = .add, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.mod,
|
||||||
.sub => .{ .tag = .sub, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.add,
|
||||||
.shift_left => .{ .tag = .shift_left, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.sub,
|
||||||
.shift_right => .{ .tag = .shift_right, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.shift_left,
|
||||||
.binary_and => .{ .tag = .binary_and, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.shift_right,
|
||||||
.binary_or => .{ .tag = .binary_or, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.binary_and,
|
||||||
.binary_xor => .{ .tag = .binary_xor, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.binary_or,
|
||||||
.circuit_and => .{ .tag = .circuit_and, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.binary_xor,
|
||||||
.circuit_or => .{ .tag = .circuit_or, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.circuit_and,
|
||||||
.equal => .{ .tag = .equal, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.circuit_or,
|
||||||
.not_equal => .{ .tag = .not_equal, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.equal,
|
||||||
.less => .{ .tag = .less, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.not_equal,
|
||||||
.less_equal => .{ .tag = .less_equal, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.less,
|
||||||
.greater => .{ .tag = .greater, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.less_equal,
|
||||||
.greater_equal => .{ .tag = .greater_equal, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.greater,
|
||||||
.index_access => .{ .tag = .index, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
.greater_equal,
|
||||||
.component_access => .{ .tag = .member_access, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genExpr(scope, rhs) } } },
|
=> blk: {
|
||||||
.bitcast => .{ .tag = .bitcast, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, lhs), .rhs = try self.genType(scope, rhs) } } },
|
const lhs = try self.genExpr(scope, node_lhs);
|
||||||
|
const rhs = try self.genExpr(scope, node_rhs);
|
||||||
|
const inst_tag: IR.Inst.Tag = switch (node_tag) {
|
||||||
|
.mul => .mul,
|
||||||
|
.div => .div,
|
||||||
|
.mod => .mod,
|
||||||
|
.add => .add,
|
||||||
|
.sub => .sub,
|
||||||
|
.shift_left => .shift_left,
|
||||||
|
.shift_right => .shift_right,
|
||||||
|
.binary_and => .binary_and,
|
||||||
|
.binary_or => .binary_or,
|
||||||
|
.binary_xor => .binary_xor,
|
||||||
|
.circuit_and => .circuit_and,
|
||||||
|
.circuit_or => .circuit_or,
|
||||||
|
.equal => .equal,
|
||||||
|
.not_equal => .not_equal,
|
||||||
|
.less => .less,
|
||||||
|
.less_equal => .less_equal,
|
||||||
|
.greater => .greater,
|
||||||
|
.greater_equal => .greater_equal,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (try self.isIntegerResulting(lhs, false)) {
|
||||||
|
if (try self.isIntegerResulting(rhs, false)) {
|
||||||
|
break :blk .{
|
||||||
|
.tag = inst_tag,
|
||||||
|
.data = .{ .binary = .{ .lhs = lhs, .rhs = rhs } },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.errors.add(
|
||||||
|
node_loc,
|
||||||
|
"incompatible types: '{s}' and '{s}'",
|
||||||
|
.{ node_lhs_loc.slice(self.tree.source), node_rhs_loc.slice(self.tree.source) },
|
||||||
|
try self.errors.createNote(
|
||||||
|
null,
|
||||||
|
"{} and {}",
|
||||||
|
.{ self.instructions.items[lhs.toIndex().?].tag, self.instructions.items[rhs.toIndex().?].tag },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return error.AnalysisFail;
|
||||||
|
},
|
||||||
|
|
||||||
|
.index_access => .{ .tag = .index, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, node_lhs), .rhs = try self.genExpr(scope, node_rhs) } } },
|
||||||
|
.component_access => .{ .tag = .member_access, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, node_lhs), .rhs = try self.genExpr(scope, node_rhs) } } },
|
||||||
|
.bitcast => .{ .tag = .bitcast, .data = .{ .binary = .{ .lhs = try self.genExpr(scope, node_lhs), .rhs = try self.genType(scope, node_rhs) } } },
|
||||||
.ident_expr => .{
|
.ident_expr => .{
|
||||||
.tag = .ident,
|
.tag = .var_ref,
|
||||||
.data = .{ .name = try self.addString(self.tree.tokenLoc(self.tree.nodeToken(node)).slice(self.tree.source)) },
|
.data = .{
|
||||||
|
.var_ref = .{
|
||||||
|
.name = try self.addString(self.tree.tokenLoc(self.tree.nodeToken(node)).slice(self.tree.source)),
|
||||||
|
.variable = try self.declRef(scope, node_loc),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
std.debug.print("WTF REALLY\n", .{});
|
std.debug.print("WTF REALLY\n", .{});
|
||||||
|
|
@ -364,76 +436,6 @@ pub fn addInst(self: *AstGen, inst: IR.Inst) error{OutOfMemory}!IR.Inst.Index {
|
||||||
return @intCast(IR.Inst.Index, self.instructions.items.len - 1);
|
return @intCast(IR.Inst.Index, self.instructions.items.len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // pub fn expression(self: *AstGen, node: Ast.Index) !?IR.Expression {
|
|
||||||
// // const lhs = self.tree.nodeLHS(node);
|
|
||||||
// // const rhs = self.tree.nodeRHS(node);
|
|
||||||
// // const loc = self.tree.tokenLoc(self.tree.nodeToken(node));
|
|
||||||
// // return switch (self.tree.nodeTag(node)) {
|
|
||||||
// // .mul => {
|
|
||||||
// // const lir = try self.expression(lhs) orelse return null;
|
|
||||||
// // const rir = try self.expression(rhs) orelse return null;
|
|
||||||
|
|
||||||
// // const is_valid_op =
|
|
||||||
// // (lir == .number and rir == .number) or
|
|
||||||
// // ((lir == .construct and lir.construct == .vector) and rir == .number) or
|
|
||||||
// // (lir == .number and (rir == .construct and rir.construct == .vector)) or
|
|
||||||
// // ((lir == .construct and lir.construct == .vector) and (rir == .construct and rir.construct == .vector)) or
|
|
||||||
// // ((lir == .construct and lir.construct == .matrix) and (rir == .construct and rir.construct == .matrix));
|
|
||||||
// // if (!is_valid_op) {
|
|
||||||
// // try self.errors.add(
|
|
||||||
// // loc,
|
|
||||||
// // "invalid operation with '{s}' and '{s}'",
|
|
||||||
// // .{ @tagName(std.meta.activeTag(lir)), @tagName(std.meta.activeTag(rir)) },
|
|
||||||
// // null,
|
|
||||||
// // );
|
|
||||||
// // return null;
|
|
||||||
// // }
|
|
||||||
// // },
|
|
||||||
// // // .div,
|
|
||||||
// // // .mod,
|
|
||||||
// // // .add,
|
|
||||||
// // // .sub,
|
|
||||||
// // // .shift_left,
|
|
||||||
// // // .shift_right,
|
|
||||||
// // // .binary_and,
|
|
||||||
// // // .binary_or,
|
|
||||||
// // // .binary_xor,
|
|
||||||
// // // .circuit_and,
|
|
||||||
// // // .circuit_or,
|
|
||||||
// // .number_literal => .{ .literal = try self.create(.{ .number = try self.create(try self.numberLiteral(node) orelse return null) }) },
|
|
||||||
// // .bool_literal => .{ .literal = try self.create(.{ .bool = self.boolLiteral(node) }) },
|
|
||||||
// // else => return null, // TODO
|
|
||||||
// // };
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // pub fn numberLiteral(self: *AstGen, node: Ast.Index) !?IR.NumberLiteral {
|
|
||||||
// // const loc = self.tree.tokenLoc(self.tree.nodeToken(node));
|
|
||||||
// // const str = loc.slice(self.tree.source);
|
|
||||||
|
|
||||||
// // if (std.mem.startsWith(u8, str, "0") and
|
|
||||||
// // !std.mem.endsWith(u8, str, "i") and
|
|
||||||
// // !std.mem.endsWith(u8, str, "u") and
|
|
||||||
// // !std.mem.endsWith(u8, str, "f") and
|
|
||||||
// // !std.mem.endsWith(u8, str, "h"))
|
|
||||||
// // {
|
|
||||||
// // try self.errors.add(
|
|
||||||
// // loc,
|
|
||||||
// // "number literal cannot have leading 0",
|
|
||||||
// // .{str},
|
|
||||||
// // null,
|
|
||||||
// // );
|
|
||||||
// // return null;
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // return null;
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// // pub fn boolLiteral(self: *AstGen, node: Ast.Index) bool {
|
|
||||||
// // const loc = self.tree.tokenLoc(self.tree.nodeToken(node));
|
|
||||||
// // const str = loc.slice(self.tree.source);
|
|
||||||
// // return str[0] == 't';
|
|
||||||
// // }
|
|
||||||
|
|
||||||
pub fn genType(self: *AstGen, scope: *Scope, node: Ast.Index) error{ AnalysisFail, OutOfMemory }!IR.Inst.Ref {
|
pub fn genType(self: *AstGen, scope: *Scope, node: Ast.Index) error{ AnalysisFail, OutOfMemory }!IR.Inst.Ref {
|
||||||
return switch (self.tree.nodeTag(node)) {
|
return switch (self.tree.nodeTag(node)) {
|
||||||
.bool_type => try self.genBoolType(node),
|
.bool_type => try self.genBoolType(node),
|
||||||
|
|
@ -442,7 +444,7 @@ pub fn genType(self: *AstGen, scope: *Scope, node: Ast.Index) error{ AnalysisFai
|
||||||
.matrix_type => try self.genMatrixType(scope, node),
|
.matrix_type => try self.genMatrixType(scope, node),
|
||||||
.atomic_type => try self.genAtomicType(scope, node),
|
.atomic_type => try self.genAtomicType(scope, node),
|
||||||
.array_type => try self.genArrayType(scope, node),
|
.array_type => try self.genArrayType(scope, node),
|
||||||
.user_type => {
|
.ident_expr => {
|
||||||
const node_loc = self.tree.tokenLoc(self.tree.nodeToken(node));
|
const node_loc = self.tree.tokenLoc(self.tree.nodeToken(node));
|
||||||
const decl_ref = try self.declRef(scope, node_loc);
|
const decl_ref = try self.declRef(scope, node_loc);
|
||||||
switch (decl_ref) {
|
switch (decl_ref) {
|
||||||
|
|
@ -1084,3 +1086,34 @@ pub fn declNameLoc(self: *AstGen, node: Ast.Index) ?Token.Loc {
|
||||||
};
|
};
|
||||||
return self.tree.tokenLoc(token);
|
return self.tree.tokenLoc(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isIntegerResulting(self: *AstGen, ref: IR.Inst.Ref, is_decl: bool) !bool {
|
||||||
|
if (is_decl and ref.isNumberType()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ref.isNumberLiteral(self.instructions) or
|
||||||
|
ref.is(self.instructions, &.{
|
||||||
|
.mul,
|
||||||
|
.div,
|
||||||
|
.mod,
|
||||||
|
.add,
|
||||||
|
.sub,
|
||||||
|
.shift_left,
|
||||||
|
.shift_right,
|
||||||
|
.binary_and,
|
||||||
|
.binary_or,
|
||||||
|
.binary_xor,
|
||||||
|
})) {
|
||||||
|
return true;
|
||||||
|
} else if (ref.is(self.instructions, &.{.var_ref})) {
|
||||||
|
const inst = self.instructions.items[ref.toIndex().?];
|
||||||
|
const var_inst = self.instructions.items[inst.data.var_ref.variable.toIndex().?];
|
||||||
|
return self.isIntegerResulting(valueOrType(var_inst), true);
|
||||||
|
} else if (ref.is(self.instructions, &.{.deref})) {
|
||||||
|
const inst = self.instructions.items[ref.toIndex().?];
|
||||||
|
return self.isIntegerResulting(inst.data.ref, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ pub const Inst = struct {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
data: Data,
|
data: Data,
|
||||||
|
|
||||||
|
pub const List = std.ArrayListUnmanaged(Inst);
|
||||||
pub const Index = u32;
|
pub const Index = u32;
|
||||||
|
|
||||||
const ref_start_index = @typeInfo(Ref).Enum.fields.len;
|
const ref_start_index = @typeInfo(Ref).Enum.fields.len;
|
||||||
|
|
@ -88,6 +89,149 @@ pub const Inst = struct {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is(self: Ref, list: List, comptime expected: []const Inst.Tag) bool {
|
||||||
|
inline for (expected) |e| {
|
||||||
|
if (list.items[self.toIndex().?].tag == e) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isType(self: Ref, list: List) bool {
|
||||||
|
return switch (self) {
|
||||||
|
.none,
|
||||||
|
.true_literal,
|
||||||
|
.false_literal,
|
||||||
|
=> false,
|
||||||
|
.bool_type,
|
||||||
|
.i32_type,
|
||||||
|
.u32_type,
|
||||||
|
.f32_type,
|
||||||
|
.f16_type,
|
||||||
|
.sampler_type,
|
||||||
|
.comparison_sampler_type,
|
||||||
|
.external_sampled_texture_type,
|
||||||
|
=> true,
|
||||||
|
_ => switch (list.items[self.toIndex().?].tag) {
|
||||||
|
.struct_decl,
|
||||||
|
.vector_type,
|
||||||
|
.matrix_type,
|
||||||
|
.atomic_type,
|
||||||
|
.array_type,
|
||||||
|
.ptr_type,
|
||||||
|
.sampled_texture_type,
|
||||||
|
.multisampled_texture_type,
|
||||||
|
.storage_texture_type,
|
||||||
|
.depth_texture_type,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isNumberType(self: Ref) bool {
|
||||||
|
return switch (self) {
|
||||||
|
.i32_type,
|
||||||
|
.u32_type,
|
||||||
|
.f32_type,
|
||||||
|
.f16_type,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isLiteral(self: Ref, list: List) bool {
|
||||||
|
return switch (self) {
|
||||||
|
.true_literal,
|
||||||
|
.false_literal,
|
||||||
|
=> true,
|
||||||
|
.none,
|
||||||
|
.bool_type,
|
||||||
|
.i32_type,
|
||||||
|
.u32_type,
|
||||||
|
.f32_type,
|
||||||
|
.f16_type,
|
||||||
|
.sampler_type,
|
||||||
|
.comparison_sampler_type,
|
||||||
|
.external_sampled_texture_type,
|
||||||
|
=> false,
|
||||||
|
_ => switch (list.items[self.toIndex().?].tag) {
|
||||||
|
.integer_literal,
|
||||||
|
.float_literal,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBoolLiteral(self: Ref) bool {
|
||||||
|
return switch (self) {
|
||||||
|
.true_literal,
|
||||||
|
.false_literal,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isNumberLiteral(self: Ref, list: List) bool {
|
||||||
|
const i = self.toIndex() orelse return false;
|
||||||
|
return switch (list.items[i].tag) {
|
||||||
|
.integer_literal,
|
||||||
|
.float_literal,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isExpr(self: Ref, list: List) bool {
|
||||||
|
const i = self.toIndex() orelse return false;
|
||||||
|
return switch (list.items[i].tag) {
|
||||||
|
.index,
|
||||||
|
.member_access,
|
||||||
|
.bitcast,
|
||||||
|
.ident,
|
||||||
|
=> true,
|
||||||
|
else => self.isBinaryExpr() or self.isUnaryExpr(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isBinaryExpr(self: Ref, list: List) bool {
|
||||||
|
const i = self.toIndex() orelse return false;
|
||||||
|
return switch (list.items[i].tag) {
|
||||||
|
.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,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isUnaryExpr(self: Ref, list: List) bool {
|
||||||
|
const i = self.toIndex() orelse return false;
|
||||||
|
return switch (list.items[i].tag) {
|
||||||
|
.not,
|
||||||
|
.negate,
|
||||||
|
.deref,
|
||||||
|
.addr_of,
|
||||||
|
=> true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Tag = enum(u6) {
|
pub const Tag = enum(u6) {
|
||||||
|
|
@ -187,8 +331,8 @@ pub const Inst = struct {
|
||||||
/// data is binary (lhs is expr, rhs is type)
|
/// data is binary (lhs is expr, rhs is type)
|
||||||
bitcast,
|
bitcast,
|
||||||
|
|
||||||
/// data is name
|
/// data is var_ref
|
||||||
ident,
|
var_ref,
|
||||||
|
|
||||||
pub fn isDecl(self: Tag) bool {
|
pub fn isDecl(self: Tag) bool {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
|
|
@ -200,8 +344,7 @@ pub const Inst = struct {
|
||||||
|
|
||||||
pub const Data = union {
|
pub const Data = union {
|
||||||
ref: Ref,
|
ref: Ref,
|
||||||
/// index to null-terminated string in `strings`
|
var_ref: VarRef,
|
||||||
name: u32,
|
|
||||||
global_variable_decl: GlobalVariableDecl,
|
global_variable_decl: GlobalVariableDecl,
|
||||||
struct_decl: StructDecl,
|
struct_decl: StructDecl,
|
||||||
struct_member: StructMember,
|
struct_member: StructMember,
|
||||||
|
|
@ -231,10 +374,16 @@ pub const Inst = struct {
|
||||||
member_access: MemberAccess,
|
member_access: MemberAccess,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const VarRef = struct {
|
||||||
|
/// index to null-terminated string in `strings`
|
||||||
|
name: u32,
|
||||||
|
variable: Ref,
|
||||||
|
};
|
||||||
|
|
||||||
pub const GlobalVariableDecl = struct {
|
pub const GlobalVariableDecl = struct {
|
||||||
/// index to null-terminated string in `strings`
|
/// index to null-terminated string in `strings`
|
||||||
name: u32,
|
name: u32,
|
||||||
type: Ref,
|
type: Ref = .none,
|
||||||
addr_space: AddressSpace,
|
addr_space: AddressSpace,
|
||||||
access_mode: AccessMode,
|
access_mode: AccessMode,
|
||||||
/// length of attributes
|
/// length of attributes
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,16 @@ pub fn globalVarDecl(p: *Parser, attrs: ?Ast.Index) !?Ast.Index {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initializer == Ast.null_index and var_type == Ast.null_index) {
|
||||||
|
try p.errors.add(
|
||||||
|
p.getToken(.loc, var_token),
|
||||||
|
"initializer expression is required while type is unknown",
|
||||||
|
.{},
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
return error.Parsing;
|
||||||
|
}
|
||||||
|
|
||||||
const extra = try p.addExtra(Ast.Node.GlobalVarDecl{
|
const extra = try p.addExtra(Ast.Node.GlobalVarDecl{
|
||||||
.attrs = attrs orelse Ast.null_index,
|
.attrs = attrs orelse Ast.null_index,
|
||||||
.name = name_token,
|
.name = name_token,
|
||||||
|
|
@ -1042,7 +1052,7 @@ pub fn expectTypeSpecifier(p: *Parser) error{ OutOfMemory, Parsing }!Ast.Index {
|
||||||
pub fn typeSpecifier(p: *Parser) !?Ast.Index {
|
pub fn typeSpecifier(p: *Parser) !?Ast.Index {
|
||||||
if (p.peekToken(.tag, 0) == .ident) {
|
if (p.peekToken(.tag, 0) == .ident) {
|
||||||
const main_token = p.advanceToken();
|
const main_token = p.advanceToken();
|
||||||
return try p.addNode(.{ .tag = .user_type, .main_token = main_token });
|
return try p.addNode(.{ .tag = .ident_expr, .main_token = main_token });
|
||||||
}
|
}
|
||||||
return p.typeSpecifierWithoutIdent();
|
return p.typeSpecifierWithoutIdent();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ struct SimParams {
|
||||||
rule3Scale : f32,
|
rule3Scale : f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@group(0) @binding(0) var<uniform> params : SimParams;
|
var v0 = 5;
|
||||||
|
@group(0) @binding(0) var<uniform> params : SimParams = *v0 * 1 + 2;
|
||||||
@group(0) @binding(1) var<storage> particlesSrc : Particles;
|
@group(0) @binding(1) var<storage> particlesSrc : Particles;
|
||||||
@group(0) @binding(2) var<storage,read_write> particlesDst : Particles;
|
@group(0) @binding(2) var<storage,read_write> particlesDst : Particles;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue