mirror of
https://github.com/ziglang/zig.git
synced 2025-12-29 17:43:17 +00:00
commit
302a69f127
@ -8,6 +8,7 @@ const log = std.log.scoped(.compilation);
|
||||
const Target = std.Target;
|
||||
|
||||
const Value = @import("value.zig").Value;
|
||||
const Type = @import("type.zig").Type;
|
||||
const target_util = @import("target.zig");
|
||||
const Package = @import("Package.zig");
|
||||
const link = @import("link.zig");
|
||||
@ -640,15 +641,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
|
||||
const root_scope = rs: {
|
||||
if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
|
||||
const struct_payload = try gpa.create(Type.Payload.EmptyStruct);
|
||||
const root_scope = try gpa.create(Module.Scope.File);
|
||||
struct_payload.* = .{ .scope = &root_scope.root_container };
|
||||
root_scope.* = .{
|
||||
.sub_file_path = root_pkg.root_src_path,
|
||||
// TODO this is duped so it can be freed in Container.deinit
|
||||
.sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
|
||||
.source = .{ .unloaded = {} },
|
||||
.contents = .{ .not_available = {} },
|
||||
.status = .never_loaded,
|
||||
.root_container = .{
|
||||
.file_scope = root_scope,
|
||||
.decls = .{},
|
||||
.ty = Type.initPayload(&struct_payload.base),
|
||||
},
|
||||
};
|
||||
break :rs &root_scope.base;
|
||||
@ -1025,6 +1030,17 @@ pub fn update(self: *Compilation) !void {
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO only analyze imports if they are still referenced
|
||||
for (module.import_table.items()) |entry| {
|
||||
entry.value.unload(module.gpa);
|
||||
module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
assert(self.totalErrorCount() != 0);
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -70,6 +70,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{},
|
||||
/// Error tags and their values, tag names are duped with mod.gpa.
|
||||
global_error_set: std.StringHashMapUnmanaged(u16) = .{},
|
||||
|
||||
/// Keys are fully qualified paths
|
||||
import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
|
||||
|
||||
/// Incrementing integer used to compare against the corresponding Decl
|
||||
/// field to determine whether a Decl's status applies to an ongoing update, or a
|
||||
/// previous analysis.
|
||||
@ -208,7 +211,7 @@ pub const Decl = struct {
|
||||
.container => {
|
||||
const container = @fieldParentPtr(Scope.Container, "base", self.scope);
|
||||
const tree = container.file_scope.contents.tree;
|
||||
// TODO Container should have it's own decls()
|
||||
// TODO Container should have its own decls()
|
||||
const decl_node = tree.root_node.decls()[self.src_index];
|
||||
return tree.token_locs[decl_node.firstToken()].start;
|
||||
},
|
||||
@ -532,12 +535,13 @@ pub const Scope = struct {
|
||||
|
||||
/// Direct children of the file.
|
||||
decls: std.AutoArrayHashMapUnmanaged(*Decl, void),
|
||||
|
||||
// TODO implement container types and put this in a status union
|
||||
// ty: Type
|
||||
ty: Type,
|
||||
|
||||
pub fn deinit(self: *Container, gpa: *Allocator) void {
|
||||
self.decls.deinit(gpa);
|
||||
// TODO either Container of File should have an arena for sub_file_path and ty
|
||||
gpa.destroy(self.ty.cast(Type.Payload.EmptyStruct).?);
|
||||
gpa.free(self.file_scope.sub_file_path);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
@ -854,6 +858,11 @@ pub fn deinit(self: *Module) void {
|
||||
gpa.free(entry.key);
|
||||
}
|
||||
self.global_error_set.deinit(gpa);
|
||||
|
||||
for (self.import_table.items()) |entry| {
|
||||
entry.value.base.destroy(gpa);
|
||||
}
|
||||
self.import_table.deinit(gpa);
|
||||
}
|
||||
|
||||
fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
|
||||
@ -2381,6 +2390,45 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst,
|
||||
return self.fail(scope, src, "TODO implement analysis of slice", .{});
|
||||
}
|
||||
|
||||
pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []const u8) !*Scope.File {
|
||||
// TODO if (package_table.get(target_string)) |pkg|
|
||||
if (self.import_table.get(target_string)) |some| {
|
||||
return some;
|
||||
}
|
||||
|
||||
// TODO check for imports outside of pkg path
|
||||
if (false) return error.ImportOutsidePkgPath;
|
||||
|
||||
// TODO Scope.Container arena for ty and sub_file_path
|
||||
const struct_payload = try self.gpa.create(Type.Payload.EmptyStruct);
|
||||
errdefer self.gpa.destroy(struct_payload);
|
||||
const file_scope = try self.gpa.create(Scope.File);
|
||||
errdefer self.gpa.destroy(file_scope);
|
||||
const file_path = try self.gpa.dupe(u8, target_string);
|
||||
errdefer self.gpa.free(file_path);
|
||||
|
||||
struct_payload.* = .{ .scope = &file_scope.root_container };
|
||||
file_scope.* = .{
|
||||
.sub_file_path = file_path,
|
||||
.source = .{ .unloaded = {} },
|
||||
.contents = .{ .not_available = {} },
|
||||
.status = .never_loaded,
|
||||
.root_container = .{
|
||||
.file_scope = file_scope,
|
||||
.decls = .{},
|
||||
.ty = Type.initPayload(&struct_payload.base),
|
||||
},
|
||||
};
|
||||
self.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
assert(self.comp.totalErrorCount() != 0);
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try self.import_table.put(self.gpa, file_scope.sub_file_path, file_scope);
|
||||
return file_scope;
|
||||
}
|
||||
|
||||
/// Asserts that lhs and rhs types are both numeric.
|
||||
pub fn cmpNumeric(
|
||||
self: *Module,
|
||||
|
||||
@ -1973,6 +1973,15 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
|
||||
}
|
||||
}
|
||||
|
||||
fn import(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
|
||||
try ensureBuiltinParamCount(mod, scope, call, 1);
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
const params = call.params();
|
||||
const target = try expr(mod, scope, .none, params[0]);
|
||||
return addZIRUnOp(mod, scope, src, .import, target);
|
||||
}
|
||||
|
||||
fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const builtin_name = tree.tokenSlice(call.builtin_token);
|
||||
@ -1995,6 +2004,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built
|
||||
} else if (mem.eql(u8, builtin_name, "@breakpoint")) {
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
return rlWrap(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint));
|
||||
} else if (mem.eql(u8, builtin_name, "@import")) {
|
||||
return rlWrap(mod, scope, rl, try import(mod, scope, call));
|
||||
} else {
|
||||
return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});
|
||||
}
|
||||
|
||||
@ -1454,6 +1454,11 @@ fn buildOutputType(
|
||||
cleanup_root_dir = dir;
|
||||
root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
|
||||
root_pkg_memory.root_src_path = try fs.path.relative(arena, p, src_path);
|
||||
} else if (fs.path.dirname(src_path)) |p| {
|
||||
const dir = try fs.cwd().openDir(p, .{});
|
||||
cleanup_root_dir = dir;
|
||||
root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
|
||||
root_pkg_memory.root_src_path = fs.path.basename(src_path);
|
||||
} else {
|
||||
root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() };
|
||||
root_pkg_memory.root_src_path = src_path;
|
||||
|
||||
15
src/test.zig
15
src/test.zig
@ -56,6 +56,12 @@ pub const TestContext = struct {
|
||||
},
|
||||
};
|
||||
|
||||
pub const File = struct {
|
||||
/// Contents of the importable file. Doesn't yet support incremental updates.
|
||||
src: [:0]const u8,
|
||||
path: []const u8,
|
||||
};
|
||||
|
||||
pub const TestType = enum {
|
||||
Zig,
|
||||
ZIR,
|
||||
@ -78,6 +84,8 @@ pub const TestContext = struct {
|
||||
extension: TestType,
|
||||
cbe: bool = false,
|
||||
|
||||
files: std.ArrayList(File),
|
||||
|
||||
/// Adds a subcase in which the module is updated with `src`, and the
|
||||
/// resulting ZIR is validated against `result`.
|
||||
pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
|
||||
@ -156,6 +164,7 @@ pub const TestContext = struct {
|
||||
.updates = std.ArrayList(Update).init(ctx.cases.allocator),
|
||||
.output_mode = .Exe,
|
||||
.extension = T,
|
||||
.files = std.ArrayList(File).init(ctx.cases.allocator),
|
||||
}) catch unreachable;
|
||||
return &ctx.cases.items[ctx.cases.items.len - 1];
|
||||
}
|
||||
@ -182,6 +191,7 @@ pub const TestContext = struct {
|
||||
.updates = std.ArrayList(Update).init(ctx.cases.allocator),
|
||||
.output_mode = .Obj,
|
||||
.extension = T,
|
||||
.files = std.ArrayList(File).init(ctx.cases.allocator),
|
||||
}) catch unreachable;
|
||||
return &ctx.cases.items[ctx.cases.items.len - 1];
|
||||
}
|
||||
@ -204,6 +214,7 @@ pub const TestContext = struct {
|
||||
.output_mode = .Obj,
|
||||
.extension = T,
|
||||
.cbe = true,
|
||||
.files = std.ArrayList(File).init(ctx.cases.allocator),
|
||||
}) catch unreachable;
|
||||
return &ctx.cases.items[ctx.cases.items.len - 1];
|
||||
}
|
||||
@ -505,6 +516,10 @@ pub const TestContext = struct {
|
||||
});
|
||||
defer comp.destroy();
|
||||
|
||||
for (case.files.items) |file| {
|
||||
try tmp.dir.writeFile(file.path, file.src);
|
||||
}
|
||||
|
||||
for (case.updates.items) |update, update_index| {
|
||||
var update_node = root_node.start("update", 3);
|
||||
update_node.activate();
|
||||
|
||||
112
src/type.zig
112
src/type.zig
@ -89,6 +89,8 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union, .error_union => return .ErrorUnion,
|
||||
|
||||
.anyframe_T, .@"anyframe" => return .AnyFrame,
|
||||
|
||||
.empty_struct => return .Struct,
|
||||
}
|
||||
}
|
||||
|
||||
@ -439,6 +441,7 @@ pub const Type = extern union {
|
||||
},
|
||||
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
|
||||
.error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle),
|
||||
.empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct),
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,6 +508,8 @@ pub const Type = extern union {
|
||||
.@"null" => return out_stream.writeAll("@Type(.Null)"),
|
||||
.@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
|
||||
|
||||
// TODO this should print the structs name
|
||||
.empty_struct => return out_stream.writeAll("struct {}"),
|
||||
.@"anyframe" => return out_stream.writeAll("anyframe"),
|
||||
.anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
|
||||
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
|
||||
@ -788,6 +793,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@ -910,6 +916,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.enum_literal,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -932,6 +939,7 @@ pub const Type = extern union {
|
||||
.@"undefined" => unreachable,
|
||||
.enum_literal => unreachable,
|
||||
.single_const_pointer_to_comptime_int => unreachable,
|
||||
.empty_struct => unreachable,
|
||||
|
||||
.u8,
|
||||
.i8,
|
||||
@ -1107,6 +1115,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1181,6 +1190,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.const_slice,
|
||||
@ -1252,6 +1262,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1332,6 +1343,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.pointer => {
|
||||
@ -1407,6 +1419,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.pointer => {
|
||||
@ -1524,6 +1537,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.elem_type,
|
||||
@ -1651,6 +1665,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.len,
|
||||
@ -1716,6 +1731,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1798,6 +1814,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.int_signed,
|
||||
@ -1872,6 +1889,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.int_unsigned,
|
||||
@ -1936,6 +1954,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
|
||||
.int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
|
||||
@ -2018,6 +2037,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
|
||||
.usize,
|
||||
@ -2129,6 +2149,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2206,6 +2227,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@ -2282,6 +2304,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@ -2358,6 +2381,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2431,6 +2455,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2504,6 +2529,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2577,6 +2603,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@ -2636,6 +2663,7 @@ pub const Type = extern union {
|
||||
.error_set_single,
|
||||
=> return null,
|
||||
|
||||
.empty_struct => return Value.initTag(.empty_struct_value),
|
||||
.void => return Value.initTag(.void_value),
|
||||
.noreturn => return Value.initTag(.unreachable_value),
|
||||
.@"null" => return Value.initTag(.null_value),
|
||||
@ -2743,6 +2771,7 @@ pub const Type = extern union {
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.empty_struct,
|
||||
=> return false,
|
||||
|
||||
.c_const_pointer,
|
||||
@ -2760,6 +2789,80 @@ pub const Type = extern union {
|
||||
(self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
|
||||
}
|
||||
|
||||
/// Asserts that the type is a container. (note: ErrorSet is not a container).
|
||||
pub fn getContainerScope(self: Type) *Module.Scope.Container {
|
||||
return switch (self.tag()) {
|
||||
.f16,
|
||||
.f32,
|
||||
.f64,
|
||||
.f128,
|
||||
.c_longdouble,
|
||||
.comptime_int,
|
||||
.comptime_float,
|
||||
.u8,
|
||||
.i8,
|
||||
.u16,
|
||||
.i16,
|
||||
.u32,
|
||||
.i32,
|
||||
.u64,
|
||||
.i64,
|
||||
.usize,
|
||||
.isize,
|
||||
.c_short,
|
||||
.c_ushort,
|
||||
.c_int,
|
||||
.c_uint,
|
||||
.c_long,
|
||||
.c_ulong,
|
||||
.c_longlong,
|
||||
.c_ulonglong,
|
||||
.bool,
|
||||
.type,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.function,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
.c_void,
|
||||
.void,
|
||||
.noreturn,
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.int_unsigned,
|
||||
.int_signed,
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.array_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.many_const_pointer,
|
||||
.many_mut_pointer,
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.c_const_pointer,
|
||||
.c_mut_pointer,
|
||||
.pointer,
|
||||
=> unreachable,
|
||||
|
||||
.empty_struct => self.cast(Type.Payload.EmptyStruct).?.scope,
|
||||
};
|
||||
}
|
||||
|
||||
/// This enum does not directly correspond to `std.builtin.TypeId` because
|
||||
/// it has extra enum tags in it, as a way of using less memory. For example,
|
||||
/// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
|
||||
@ -2835,6 +2938,7 @@ pub const Type = extern union {
|
||||
anyframe_T,
|
||||
error_set,
|
||||
error_set_single,
|
||||
empty_struct,
|
||||
|
||||
pub const last_no_payload_tag = Tag.const_slice_u8;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
@ -2942,6 +3046,14 @@ pub const Type = extern union {
|
||||
/// memory is owned by `Module`
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
/// Mostly used for namespace like structs with zero fields.
|
||||
/// Most commonly used for files.
|
||||
pub const EmptyStruct = struct {
|
||||
base: Payload = .{ .tag = .empty_struct },
|
||||
|
||||
scope: *Module.Scope.Container,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -68,6 +68,7 @@ pub const Value = extern union {
|
||||
one,
|
||||
void_value,
|
||||
unreachable_value,
|
||||
empty_struct_value,
|
||||
empty_array,
|
||||
null_value,
|
||||
bool_true,
|
||||
@ -182,6 +183,7 @@ pub const Value = extern union {
|
||||
.null_value,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.ty => {
|
||||
@ -312,6 +314,8 @@ pub const Value = extern union {
|
||||
.enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
|
||||
.anyframe_type => return out_stream.writeAll("anyframe"),
|
||||
|
||||
// TODO this should print `NAME{}`
|
||||
.empty_struct_value => return out_stream.writeAll("struct {}{}"),
|
||||
.null_value => return out_stream.writeAll("null"),
|
||||
.undef => return out_stream.writeAll("undefined"),
|
||||
.zero => return out_stream.writeAll("0"),
|
||||
@ -475,6 +479,7 @@ pub const Value = extern union {
|
||||
.float_128,
|
||||
.enum_literal,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -543,6 +548,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -626,6 +632,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -709,6 +716,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -820,6 +828,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -907,6 +916,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -1078,6 +1088,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -1152,6 +1163,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -1300,6 +1312,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.ref_val => self.cast(Payload.RefVal).?.val,
|
||||
@ -1383,6 +1396,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> unreachable,
|
||||
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
@ -1483,6 +1497,7 @@ pub const Value = extern union {
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
.empty_struct_value,
|
||||
=> false,
|
||||
|
||||
.undef => unreachable,
|
||||
|
||||
@ -161,6 +161,8 @@ pub const Inst = struct {
|
||||
@"fn",
|
||||
/// Returns a function type.
|
||||
fntype,
|
||||
/// @import(operand)
|
||||
import,
|
||||
/// Integer literal.
|
||||
int,
|
||||
/// Convert an integer value to another integer type, asserting that the destination type
|
||||
@ -315,6 +317,7 @@ pub const Inst = struct {
|
||||
.ensure_err_payload_void,
|
||||
.anyframe_type,
|
||||
.bitnot,
|
||||
.import,
|
||||
=> UnOp,
|
||||
|
||||
.add,
|
||||
@ -489,6 +492,7 @@ pub const Inst = struct {
|
||||
.error_set,
|
||||
.slice,
|
||||
.slice_start,
|
||||
.import,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
|
||||
@ -134,6 +134,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?),
|
||||
.slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
|
||||
.slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
|
||||
.import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1047,6 +1048,19 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
.val = Value.initPayload(&ref_payload.base),
|
||||
});
|
||||
},
|
||||
.Struct => {
|
||||
const container_scope = child_type.getContainerScope();
|
||||
if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
|
||||
// TODO if !decl.is_pub and inDifferentFiles() "{} is private"
|
||||
return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);
|
||||
}
|
||||
|
||||
if (&container_scope.file_scope.base == mod.root_scope) {
|
||||
return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{}'", .{field_name});
|
||||
} else {
|
||||
return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{}'", .{ child_type, field_name });
|
||||
}
|
||||
},
|
||||
else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),
|
||||
}
|
||||
},
|
||||
@ -1190,6 +1204,24 @@ fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn
|
||||
return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
|
||||
}
|
||||
|
||||
fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const operand = try resolveConstString(mod, scope, inst.positionals.operand);
|
||||
|
||||
const file_scope = mod.analyzeImport(scope, inst.base.src, operand) catch |err| switch (err) {
|
||||
// error.ImportOutsidePkgPath => {
|
||||
// return mod.fail(scope, inst.base.src, "import of file outside package path: '{}'", .{operand});
|
||||
// },
|
||||
error.FileNotFound => {
|
||||
return mod.fail(scope, inst.base.src, "unable to find '{}'", .{operand});
|
||||
},
|
||||
else => {
|
||||
// TODO user friendly error to string
|
||||
return mod.fail(scope, inst.base.src, "unable to open '{}': {}", .{ operand, @errorName(err) });
|
||||
},
|
||||
};
|
||||
return mod.constType(scope, inst.base.src, file_scope.root_container.ty);
|
||||
}
|
||||
|
||||
fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});
|
||||
}
|
||||
|
||||
@ -909,6 +909,44 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exe("basic import", linux_x64);
|
||||
case.addCompareOutput(
|
||||
\\export fn _start() noreturn {
|
||||
\\ @import("print.zig").print();
|
||||
\\ exit();
|
||||
\\}
|
||||
\\
|
||||
\\fn exit() noreturn {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (231),
|
||||
\\ [arg1] "{rdi}" (@as(usize, 0))
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ unreachable;
|
||||
\\}
|
||||
,
|
||||
"Hello, World!\n",
|
||||
);
|
||||
try case.files.append(.{
|
||||
.src =
|
||||
\\pub fn print() void {
|
||||
\\ asm volatile ("syscall"
|
||||
\\ :
|
||||
\\ : [number] "{rax}" (@as(usize, 1)),
|
||||
\\ [arg1] "{rdi}" (@as(usize, 1)),
|
||||
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
|
||||
\\ [arg3] "{rdx}" (@as(usize, 14))
|
||||
\\ : "rcx", "r11", "memory"
|
||||
\\ );
|
||||
\\ return;
|
||||
\\}
|
||||
,
|
||||
.path = "print.zig",
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exe("wasm function calls", wasi);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user