stdlib: relocate modules under library/
- examples/modules/ -> library/modules/ (top-level, no more symlink hacks in consumer projects) - compiler discovers stdlib via _NSGetExecutablePath / readlink /proc/self/exe; searches dev layout (../../library), install layout (../library), and alongside-binary fallback - SX_STDLIB_PATH env var overrides for tests / dev convenience - SX_DEBUG_STDLIB env var dumps the discovery results - build.zig installs library/ alongside the binary - Compilation gains stdlib_paths field threaded through resolveImports - 50 tests pass; consumer projects can now build from any cwd
This commit is contained in:
10
build.zig
10
build.zig
@@ -158,6 +158,16 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
b.installArtifact(exe);
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
// Install the stdlib alongside the binary so `<prefix>/bin/sx` finds
|
||||||
|
// `<prefix>/library/modules/...` via the install-layout fallback in
|
||||||
|
// `src/imports.zig::discoverStdlibPaths`.
|
||||||
|
const install_library = b.addInstallDirectory(.{
|
||||||
|
.source_dir = b.path("library"),
|
||||||
|
.install_dir = .prefix,
|
||||||
|
.install_subdir = "library",
|
||||||
|
});
|
||||||
|
b.getInstallStep().dependOn(&install_library.step);
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
const run_step = b.step("run", "Run the app");
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
run_step.dependOn(&run_cmd.step);
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub const Compilation = struct {
|
|||||||
source: [:0]const u8,
|
source: [:0]const u8,
|
||||||
diagnostics: errors.DiagnosticList,
|
diagnostics: errors.DiagnosticList,
|
||||||
target_config: TargetConfig,
|
target_config: TargetConfig,
|
||||||
|
stdlib_paths: []const []const u8 = &.{},
|
||||||
|
|
||||||
// Pipeline results
|
// Pipeline results
|
||||||
root: ?*Node = null,
|
root: ?*Node = null,
|
||||||
@@ -27,7 +28,7 @@ pub const Compilation = struct {
|
|||||||
sema_result: ?sema.SemaResult = null,
|
sema_result: ?sema.SemaResult = null,
|
||||||
ir_emitter: ?ir.LLVMEmitter = null,
|
ir_emitter: ?ir.LLVMEmitter = null,
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, io: std.Io, file_path: []const u8, source: [:0]const u8, target_config: TargetConfig) Compilation {
|
pub fn init(allocator: std.mem.Allocator, io: std.Io, file_path: []const u8, source: [:0]const u8, target_config: TargetConfig, stdlib_paths: []const []const u8) Compilation {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.io = io,
|
.io = io,
|
||||||
@@ -37,6 +38,7 @@ pub const Compilation = struct {
|
|||||||
.import_sources = std.StringHashMap([:0]const u8).init(allocator),
|
.import_sources = std.StringHashMap([:0]const u8).init(allocator),
|
||||||
.module_scopes = std.StringHashMap(std.StringHashMap(void)).init(allocator),
|
.module_scopes = std.StringHashMap(std.StringHashMap(void)).init(allocator),
|
||||||
.target_config = target_config,
|
.target_config = target_config,
|
||||||
|
.stdlib_paths = stdlib_paths,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +68,7 @@ pub const Compilation = struct {
|
|||||||
&cache,
|
&cache,
|
||||||
&self.import_sources,
|
&self.import_sources,
|
||||||
&self.diagnostics,
|
&self.diagnostics,
|
||||||
|
self.stdlib_paths,
|
||||||
) catch return error.CompileError;
|
) catch return error.CompileError;
|
||||||
|
|
||||||
// Preserve per-module visibility scopes for C import access checking
|
// Preserve per-module visibility scopes for C import access checking
|
||||||
|
|||||||
102
src/imports.zig
102
src/imports.zig
@@ -17,10 +17,13 @@ pub fn dirName(path: []const u8) []const u8 {
|
|||||||
return if (found) path[0..last_sep] else ".";
|
return if (found) path[0..last_sep] else ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve an import path: try relative to base_dir first, fall back to cwd-relative.
|
/// Resolve an import path. Tries (in order):
|
||||||
/// If root_path is provided, CWD-relative fallback paths are made absolute.
|
/// 1. relative to `base_dir` (the importing file's directory)
|
||||||
/// Shared between compiler (resolveImports) and LSP (analyzeDocument).
|
/// 2. relative to CWD, absolutified via `root_path` if supplied
|
||||||
pub fn resolveImportPath(allocator: std.mem.Allocator, io: std.Io, base_dir: []const u8, raw_path: []const u8, root_path: ?[]const u8) ![]const u8 {
|
/// 3. relative to each path in `stdlib_paths` (the install-discovered stdlib)
|
||||||
|
/// Returns the first path that exists. Falls back to the raw path if nothing matches
|
||||||
|
/// so the caller's readFile produces a coherent "not found" error.
|
||||||
|
pub fn resolveImportPath(allocator: std.mem.Allocator, io: std.Io, base_dir: []const u8, raw_path: []const u8, root_path: ?[]const u8, stdlib_paths: []const []const u8) ![]const u8 {
|
||||||
if (!std.mem.eql(u8, base_dir, ".")) {
|
if (!std.mem.eql(u8, base_dir, ".")) {
|
||||||
const rel_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ base_dir, raw_path });
|
const rel_path = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ base_dir, raw_path });
|
||||||
// Check if it exists as file relative to base_dir
|
// Check if it exists as file relative to base_dir
|
||||||
@@ -33,13 +36,86 @@ pub fn resolveImportPath(allocator: std.mem.Allocator, io: std.Io, base_dir: []c
|
|||||||
return rel_path;
|
return rel_path;
|
||||||
} else |_| {}
|
} else |_| {}
|
||||||
}
|
}
|
||||||
// Fall back to raw path (cwd-relative); absolutify if root_path is known
|
// Try CWD-relative (absolutified if root_path is known).
|
||||||
if (root_path) |rp| {
|
const cwd_candidate = if (root_path) |rp| blk: {
|
||||||
if (rp.len > 0 and raw_path.len > 0 and raw_path[0] != '/') {
|
if (rp.len > 0 and raw_path.len > 0 and raw_path[0] != '/') {
|
||||||
return std.fmt.allocPrint(allocator, "{s}/{s}", .{ rp, raw_path });
|
break :blk try std.fmt.allocPrint(allocator, "{s}/{s}", .{ rp, raw_path });
|
||||||
}
|
}
|
||||||
|
break :blk raw_path;
|
||||||
|
} else raw_path;
|
||||||
|
if (std.Io.Dir.readFileAlloc(.cwd(), io, cwd_candidate, allocator, .limited(10 * 1024 * 1024))) |_| {
|
||||||
|
return cwd_candidate;
|
||||||
|
} else |_| {}
|
||||||
|
if (std.Io.Dir.openDir(.cwd(), io, cwd_candidate, .{})) |dir| {
|
||||||
|
dir.close(io);
|
||||||
|
return cwd_candidate;
|
||||||
|
} else |_| {}
|
||||||
|
// Try each stdlib search path.
|
||||||
|
for (stdlib_paths) |sp| {
|
||||||
|
const cand = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ sp, raw_path });
|
||||||
|
if (std.Io.Dir.readFileAlloc(.cwd(), io, cand, allocator, .limited(10 * 1024 * 1024))) |_| {
|
||||||
|
return cand;
|
||||||
|
} else |_| {}
|
||||||
|
if (std.Io.Dir.openDir(.cwd(), io, cand, .{})) |dir| {
|
||||||
|
dir.close(io);
|
||||||
|
return cand;
|
||||||
|
} else |_| {}
|
||||||
|
}
|
||||||
|
return cwd_candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Discover candidate stdlib search paths from the running binary's location.
|
||||||
|
/// Honors the `SX_STDLIB_PATH` env var as an explicit override. Returns a slice
|
||||||
|
/// of absolute paths owned by the allocator.
|
||||||
|
pub fn discoverStdlibPaths(allocator: std.mem.Allocator) ![]const []const u8 {
|
||||||
|
var out = std.ArrayList([]const u8).empty;
|
||||||
|
|
||||||
|
// Env override via libc getenv (cross-stdlib-version stable).
|
||||||
|
if (c_getenv("SX_STDLIB_PATH")) |env_path| {
|
||||||
|
try out.append(allocator, try allocator.dupe(u8, std.mem.span(env_path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const exe_path = selfExePath(allocator) catch return try out.toOwnedSlice(allocator);
|
||||||
|
const exe_dir = dirName(exe_path);
|
||||||
|
// Stdlib paths are directories containing a `modules/` subdir; the import
|
||||||
|
// directive (e.g. `#import "modules/std.sx"`) supplies the rest.
|
||||||
|
// Dev: zig-out/bin/sx -> repo-root/library
|
||||||
|
try out.append(allocator, try std.fmt.allocPrint(allocator, "{s}/../../library", .{exe_dir}));
|
||||||
|
// Install: <prefix>/bin/sx -> <prefix>/library
|
||||||
|
try out.append(allocator, try std.fmt.allocPrint(allocator, "{s}/../library", .{exe_dir}));
|
||||||
|
// Alongside the binary.
|
||||||
|
try out.append(allocator, try std.fmt.allocPrint(allocator, "{s}/library", .{exe_dir}));
|
||||||
|
if (c_getenv("SX_DEBUG_STDLIB") != null) {
|
||||||
|
std.debug.print("[sx] exe_path={s}\n", .{exe_path});
|
||||||
|
for (out.items, 0..) |p, i| std.debug.print("[sx] stdlib_paths[{d}]={s}\n", .{ i, p });
|
||||||
|
}
|
||||||
|
return try out.toOwnedSlice(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
extern "c" fn _NSGetExecutablePath(buf: [*]u8, len: *u32) c_int;
|
||||||
|
extern "c" fn getenv(name: [*:0]const u8) ?[*:0]const u8;
|
||||||
|
|
||||||
|
fn c_getenv(name: [:0]const u8) ?[*:0]const u8 {
|
||||||
|
return getenv(name.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selfExePath(allocator: std.mem.Allocator) ![]const u8 {
|
||||||
|
var buf: [4096]u8 = undefined;
|
||||||
|
switch (builtin.os.tag) {
|
||||||
|
.macos, .ios => {
|
||||||
|
var len: u32 = buf.len;
|
||||||
|
if (_NSGetExecutablePath(&buf, &len) != 0) return error.PathBufferTooSmall;
|
||||||
|
const span = std.mem.sliceTo(&buf, 0);
|
||||||
|
return try allocator.dupe(u8, span);
|
||||||
|
},
|
||||||
|
.linux => {
|
||||||
|
const n = try std.posix.readlink("/proc/self/exe", &buf);
|
||||||
|
return try allocator.dupe(u8, n);
|
||||||
|
},
|
||||||
|
else => return error.UnsupportedHostOS,
|
||||||
}
|
}
|
||||||
return raw_path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A resolved module: the fully-resolved declarations of a single .sx file,
|
/// A resolved module: the fully-resolved declarations of a single .sx file,
|
||||||
@@ -98,6 +174,7 @@ pub fn resolveImports(
|
|||||||
cache: *ModuleCache,
|
cache: *ModuleCache,
|
||||||
source_map: ?*std.StringHashMap([:0]const u8),
|
source_map: ?*std.StringHashMap([:0]const u8),
|
||||||
diagnostics: ?*errors.DiagnosticList,
|
diagnostics: ?*errors.DiagnosticList,
|
||||||
|
stdlib_paths: []const []const u8,
|
||||||
) !ResolvedModule {
|
) !ResolvedModule {
|
||||||
var mod = ResolvedModule{
|
var mod = ResolvedModule{
|
||||||
.path = file_path,
|
.path = file_path,
|
||||||
@@ -167,7 +244,7 @@ pub fn resolveImports(
|
|||||||
}
|
}
|
||||||
const imp = decl.data.import_decl;
|
const imp = decl.data.import_decl;
|
||||||
|
|
||||||
const resolved_path = try resolveImportPath(allocator, io, base_dir, imp.path, null);
|
const resolved_path = try resolveImportPath(allocator, io, base_dir, imp.path, null, stdlib_paths);
|
||||||
|
|
||||||
// Circular import check — only along the current chain
|
// Circular import check — only along the current chain
|
||||||
if (chain.contains(resolved_path)) continue;
|
if (chain.contains(resolved_path)) continue;
|
||||||
@@ -195,7 +272,7 @@ pub fn resolveImports(
|
|||||||
// Push onto chain before recursing, pop after
|
// Push onto chain before recursing, pop after
|
||||||
try chain.put(resolved_path, {});
|
try chain.put(resolved_path, {});
|
||||||
const imp_dir = dirName(resolved_path);
|
const imp_dir = dirName(resolved_path);
|
||||||
const result = try resolveImports(allocator, io, imp_root, imp_dir, resolved_path, chain, cache, source_map, diagnostics);
|
const result = try resolveImports(allocator, io, imp_root, imp_dir, resolved_path, chain, cache, source_map, diagnostics, stdlib_paths);
|
||||||
_ = chain.remove(resolved_path);
|
_ = chain.remove(resolved_path);
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
@@ -203,7 +280,7 @@ pub fn resolveImports(
|
|||||||
break :blk result;
|
break :blk result;
|
||||||
} else |_| {
|
} else |_| {
|
||||||
// File read failed — try as directory import
|
// File read failed — try as directory import
|
||||||
const result = resolveDirectoryImport(allocator, io, resolved_path, chain, cache, source_map, diagnostics, decl.span) catch {
|
const result = resolveDirectoryImport(allocator, io, resolved_path, chain, cache, source_map, diagnostics, decl.span, stdlib_paths) catch {
|
||||||
if (diagnostics) |diags| {
|
if (diagnostics) |diags| {
|
||||||
diags.addFmt(.err, decl.span, "cannot read import '{s}' (not a file or directory)", .{resolved_path});
|
diags.addFmt(.err, decl.span, "cannot read import '{s}' (not a file or directory)", .{resolved_path});
|
||||||
}
|
}
|
||||||
@@ -235,6 +312,7 @@ fn resolveDirectoryImport(
|
|||||||
source_map: ?*std.StringHashMap([:0]const u8),
|
source_map: ?*std.StringHashMap([:0]const u8),
|
||||||
diagnostics: ?*errors.DiagnosticList,
|
diagnostics: ?*errors.DiagnosticList,
|
||||||
span: ast.Span,
|
span: ast.Span,
|
||||||
|
stdlib_paths: []const []const u8,
|
||||||
) anyerror!ResolvedModule {
|
) anyerror!ResolvedModule {
|
||||||
// Open the directory with iteration capability
|
// Open the directory with iteration capability
|
||||||
const dir = std.Io.Dir.openDir(.cwd(), io, dir_path, .{ .iterate = true }) catch {
|
const dir = std.Io.Dir.openDir(.cwd(), io, dir_path, .{ .iterate = true }) catch {
|
||||||
@@ -300,7 +378,7 @@ fn resolveDirectoryImport(
|
|||||||
};
|
};
|
||||||
|
|
||||||
try chain.put(file_path, {});
|
try chain.put(file_path, {});
|
||||||
const result = try resolveImports(allocator, io, imp_root, dir_path, file_path, chain, cache, source_map, diagnostics);
|
const result = try resolveImports(allocator, io, imp_root, dir_path, file_path, chain, cache, source_map, diagnostics, stdlib_paths);
|
||||||
_ = chain.remove(file_path);
|
_ = chain.remove(file_path);
|
||||||
|
|
||||||
try cache.put(file_path, result);
|
try cache.put(file_path, result);
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ pub const DocumentStore = struct {
|
|||||||
for (root.data.root.decls) |decl| {
|
for (root.data.root.decls) |decl| {
|
||||||
if (decl.data != .import_decl) continue;
|
if (decl.data != .import_decl) continue;
|
||||||
const imp = decl.data.import_decl;
|
const imp = decl.data.import_decl;
|
||||||
const resolved_path = try sx.imports.resolveImportPath(self.allocator, self.io, base_dir, imp.path, self.rootPathOpt());
|
const resolved_path = try sx.imports.resolveImportPath(self.allocator, self.io, base_dir, imp.path, self.rootPathOpt(), &.{});
|
||||||
try import_list.append(self.allocator, .{
|
try import_list.append(self.allocator, .{
|
||||||
.ns = imp.name,
|
.ns = imp.name,
|
||||||
.path = resolved_path,
|
.path = resolved_path,
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ pub const Server = struct {
|
|||||||
if (findImportPathAtOffset(doc.source, offset)) |import_path| {
|
if (findImportPathAtOffset(doc.source, offset)) |import_path| {
|
||||||
const base_dir = sx.imports.dirName(file_path);
|
const base_dir = sx.imports.dirName(file_path);
|
||||||
const rp: ?[]const u8 = if (self.root_path.len > 0) self.root_path else null;
|
const rp: ?[]const u8 = if (self.root_path.len > 0) self.root_path else null;
|
||||||
const resolved = try sx.imports.resolveImportPath(self.allocator, self.io, base_dir, import_path, rp);
|
const resolved = try sx.imports.resolveImportPath(self.allocator, self.io, base_dir, import_path, rp, &.{});
|
||||||
|
|
||||||
// For directory imports, try to read as file first
|
// For directory imports, try to read as file first
|
||||||
if (std.Io.Dir.readFileAlloc(.cwd(), self.io, resolved, self.allocator, .limited(10 * 1024 * 1024))) |_| {
|
if (std.Io.Dir.readFileAlloc(.cwd(), self.io, resolved, self.allocator, .limited(10 * 1024 * 1024))) |_| {
|
||||||
|
|||||||
44
src/main.zig
44
src/main.zig
@@ -6,6 +6,10 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
const io = init.io;
|
const io = init.io;
|
||||||
const args = try init.minimal.args.toSlice(allocator);
|
const args = try init.minimal.args.toSlice(allocator);
|
||||||
|
|
||||||
|
// Stdlib discovered from binary location (or $SX_STDLIB_PATH override).
|
||||||
|
// Empty slice on hosts where discovery fails — imports fall back to CWD.
|
||||||
|
const stdlib_paths = sx.imports.discoverStdlibPaths(allocator) catch &[_][]const u8{};
|
||||||
|
|
||||||
if (args.len < 2) {
|
if (args.len < 2) {
|
||||||
printUsage();
|
printUsage();
|
||||||
return;
|
return;
|
||||||
@@ -143,13 +147,13 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
}
|
}
|
||||||
break :blk base;
|
break :blk base;
|
||||||
};
|
};
|
||||||
compile(allocator, io, path, output_name, target_config, show_timing, enable_cache) catch std.process.exit(1);
|
compile(allocator, io, path, output_name, target_config, show_timing, enable_cache, stdlib_paths) catch std.process.exit(1);
|
||||||
} else if (std.mem.eql(u8, command, "ir")) {
|
} else if (std.mem.eql(u8, command, "ir")) {
|
||||||
emitIR(allocator, io, path, target_config) catch std.process.exit(1);
|
emitIR(allocator, io, path, target_config, stdlib_paths) catch std.process.exit(1);
|
||||||
} else if (std.mem.eql(u8, command, "ir-dump")) {
|
} else if (std.mem.eql(u8, command, "ir-dump")) {
|
||||||
dumpSxIR(allocator, io, path) catch std.process.exit(1);
|
dumpSxIR(allocator, io, path, stdlib_paths) catch std.process.exit(1);
|
||||||
} else if (std.mem.eql(u8, command, "asm")) {
|
} else if (std.mem.eql(u8, command, "asm")) {
|
||||||
emitAsm(allocator, io, path, target_config) catch std.process.exit(1);
|
emitAsm(allocator, io, path, target_config, stdlib_paths) catch std.process.exit(1);
|
||||||
} else if (std.mem.eql(u8, command, "run")) {
|
} else if (std.mem.eql(u8, command, "run")) {
|
||||||
if (target_config.isWasm()) {
|
if (target_config.isWasm()) {
|
||||||
std.debug.print("error: 'run' is not supported for wasm targets. Use 'build' instead.\n", .{});
|
std.debug.print("error: 'run' is not supported for wasm targets. Use 'build' instead.\n", .{});
|
||||||
@@ -164,7 +168,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
const source = readSource(allocator, io, path) catch std.process.exit(1);
|
const source = readSource(allocator, io, path) catch std.process.exit(1);
|
||||||
timer.record("read");
|
timer.record("read");
|
||||||
|
|
||||||
var comp = sx.core.Compilation.init(allocator, io, path, source, target_config);
|
var comp = sx.core.Compilation.init(allocator, io, path, source, target_config, stdlib_paths);
|
||||||
defer comp.deinit();
|
defer comp.deinit();
|
||||||
|
|
||||||
timer.mark();
|
timer.mark();
|
||||||
@@ -239,7 +243,7 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
const exit_code = sx.target.runJITFromObject(obj_buf) catch {
|
const exit_code = sx.target.runJITFromObject(obj_buf) catch {
|
||||||
// JIT failed — fall back to AOT
|
// JIT failed — fall back to AOT
|
||||||
timer.record("jit-fail");
|
timer.record("jit-fail");
|
||||||
runAOT(allocator, io, path, target_config, &timer, enable_cache) catch std.process.exit(1);
|
runAOT(allocator, io, path, target_config, &timer, enable_cache, stdlib_paths) catch std.process.exit(1);
|
||||||
timer.printAll();
|
timer.printAll();
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -363,12 +367,12 @@ fn readSource(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8)
|
|||||||
return try allocator.dupeZ(u8, source_bytes);
|
return try allocator.dupeZ(u8, source_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig, timer: *Timing) !sx.core.Compilation {
|
fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig, timer: *Timing, stdlib_paths: []const []const u8) !sx.core.Compilation {
|
||||||
timer.mark();
|
timer.mark();
|
||||||
const source = try readSource(allocator, io, input_path);
|
const source = try readSource(allocator, io, input_path);
|
||||||
timer.record("read");
|
timer.record("read");
|
||||||
|
|
||||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source, target_config);
|
var comp = sx.core.Compilation.init(allocator, io, input_path, source, target_config, stdlib_paths);
|
||||||
errdefer comp.deinit();
|
errdefer comp.deinit();
|
||||||
|
|
||||||
timer.mark();
|
timer.mark();
|
||||||
@@ -390,9 +394,9 @@ fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const
|
|||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dumpSxIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !void {
|
fn dumpSxIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, stdlib_paths: []const []const u8) !void {
|
||||||
const source = try readSource(allocator, io, input_path);
|
const source = try readSource(allocator, io, input_path);
|
||||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source, .{});
|
var comp = sx.core.Compilation.init(allocator, io, input_path, source, .{}, stdlib_paths);
|
||||||
defer comp.deinit();
|
defer comp.deinit();
|
||||||
|
|
||||||
comp.parse() catch { comp.renderErrors(); return error.CompileError; };
|
comp.parse() catch { comp.renderErrors(); return error.CompileError; };
|
||||||
@@ -408,16 +412,16 @@ fn dumpSxIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !v
|
|||||||
std.debug.print("{s}", .{result.items});
|
std.debug.print("{s}", .{result.items});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig) !void {
|
fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig, stdlib_paths: []const []const u8) !void {
|
||||||
var timer = Timing.init(io, false);
|
var timer = Timing.init(io, false);
|
||||||
var comp = try compilePipeline(allocator, io, input_path, target_config, &timer);
|
var comp = try compilePipeline(allocator, io, input_path, target_config, &timer, stdlib_paths);
|
||||||
defer comp.deinit();
|
defer comp.deinit();
|
||||||
comp.ir_emitter.?.printIR();
|
comp.ir_emitter.?.printIR();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emitAsm(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig) !void {
|
fn emitAsm(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig, stdlib_paths: []const []const u8) !void {
|
||||||
var timer = Timing.init(io, false);
|
var timer = Timing.init(io, false);
|
||||||
var comp = try compilePipeline(allocator, io, input_path, target_config, &timer);
|
var comp = try compilePipeline(allocator, io, input_path, target_config, &timer, stdlib_paths);
|
||||||
defer comp.deinit();
|
defer comp.deinit();
|
||||||
const asm_path = target_config.output_path orelse blk: {
|
const asm_path = target_config.output_path orelse blk: {
|
||||||
const name = deriveOutputName(input_path);
|
const name = deriveOutputName(input_path);
|
||||||
@@ -428,19 +432,19 @@ fn emitAsm(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, tar
|
|||||||
std.debug.print("emitted: {s}\n", .{asm_path});
|
std.debug.print("emitted: {s}\n", .{asm_path});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8, target_config: sx.target.TargetConfig, show_timing: bool, enable_cache: bool) !void {
|
fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8, target_config: sx.target.TargetConfig, show_timing: bool, enable_cache: bool, stdlib_paths: []const []const u8) !void {
|
||||||
var timer = Timing.init(io, show_timing);
|
var timer = Timing.init(io, show_timing);
|
||||||
try compileWithTimer(allocator, io, input_path, output_path, target_config, &timer, enable_cache);
|
try compileWithTimer(allocator, io, input_path, output_path, target_config, &timer, enable_cache, stdlib_paths);
|
||||||
timer.printAll();
|
timer.printAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8, target_config: sx.target.TargetConfig, timer: *Timing, enable_cache: bool) !void {
|
fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8, target_config: sx.target.TargetConfig, timer: *Timing, enable_cache: bool, stdlib_paths: []const []const u8) !void {
|
||||||
// Phase A: read + parse + resolveImports (fast: ~0.5ms)
|
// Phase A: read + parse + resolveImports (fast: ~0.5ms)
|
||||||
timer.mark();
|
timer.mark();
|
||||||
const source = try readSource(allocator, io, input_path);
|
const source = try readSource(allocator, io, input_path);
|
||||||
timer.record("read");
|
timer.record("read");
|
||||||
|
|
||||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source, target_config);
|
var comp = sx.core.Compilation.init(allocator, io, input_path, source, target_config, stdlib_paths);
|
||||||
defer comp.deinit();
|
defer comp.deinit();
|
||||||
|
|
||||||
timer.mark();
|
timer.mark();
|
||||||
@@ -584,9 +588,9 @@ fn compileWithTimer(allocator: std.mem.Allocator, io: std.Io, input_path: []cons
|
|||||||
std.Io.Dir.deleteDir(.cwd(), io, tmp_dir) catch {};
|
std.Io.Dir.deleteDir(.cwd(), io, tmp_dir) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runAOT(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig, timer: *Timing, enable_cache: bool) !void {
|
fn runAOT(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, target_config: sx.target.TargetConfig, timer: *Timing, enable_cache: bool, stdlib_paths: []const []const u8) !void {
|
||||||
const tmp_bin = if (comptime @import("builtin").os.tag == .windows) "sx_run_tmp.exe" else "/tmp/sx_run_tmp";
|
const tmp_bin = if (comptime @import("builtin").os.tag == .windows) "sx_run_tmp.exe" else "/tmp/sx_run_tmp";
|
||||||
try compileWithTimer(allocator, io, input_path, tmp_bin, target_config, timer, enable_cache);
|
try compileWithTimer(allocator, io, input_path, tmp_bin, target_config, timer, enable_cache, stdlib_paths);
|
||||||
defer {
|
defer {
|
||||||
std.Io.Dir.deleteFile(.cwd(), io, tmp_bin) catch {};
|
std.Io.Dir.deleteFile(.cwd(), io, tmp_bin) catch {};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user