Embedded programming language for Zig
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Begin work on the runtime

Added:
- External library loading
- WIP runtime library

IamPyu 08261695 0e75298c

+194 -38
+40 -18
build.zig
··· 4 4 const target = b.standardTargetOptions(.{}); 5 5 const optimize = b.standardOptimizeOption(.{}); 6 6 7 + const test_step = b.step("test", "Run tests"); 8 + 7 9 const mitochondria_dep = b.dependency("mitochondria", .{ 8 10 .target = target, 9 11 .optimize = optimize, 10 12 }); 11 13 const mitochondria_mod = mitochondria_dep.module("mitochondria"); 12 14 13 - const mod = b.addModule("zexa", .{ 15 + const zexa_mod = b.addModule("zexa", .{ 14 16 .root_source_file = b.path("src/root.zig"), 15 17 .target = target, 16 18 .optimize = optimize, 17 19 }); 18 - mod.addImport("mitochondria", mitochondria_mod); 20 + zexa_mod.addImport("mitochondria", mitochondria_mod); 19 21 20 - const lib = b.addLibrary(.{ 22 + // { 23 + const zexa_lib = b.addLibrary(.{ 21 24 .name = "zexa", 22 - .root_module = mod, 25 + .root_module = zexa_mod, 23 26 }); 24 - b.installArtifact(lib); 27 + b.installArtifact(zexa_lib); 25 28 26 - const mod_tests = b.addTest(.{ 27 - .root_module = mod, 29 + const zexa_tests = b.addTest(.{ 30 + .root_module = zexa_mod, 28 31 }); 29 - const run_mod_tests = b.addRunArtifact(mod_tests); 30 - const test_step = b.step("test", "Run tests"); 31 - test_step.dependOn(&run_mod_tests.step); 32 + const run_zexa_tests = b.addRunArtifact(zexa_tests); 33 + test_step.dependOn(&run_zexa_tests.step); 34 + // } 35 + 36 + const zexa_runtime_mod = b.addModule("zexa-runtime", .{ 37 + .root_source_file = b.path("runtime/root.zig"), 38 + // .target = b.resolveTargetQuery(.{ 39 + // .os_tag = .wasi, 40 + // .cpu_arch = .wasm32, 41 + // }), 42 + .target = target, 43 + .optimize = optimize, 44 + }); 45 + zexa_runtime_mod.addImport("zexa", zexa_mod); 46 + 47 + const zexa_runtime_lib = b.addLibrary(.{ 48 + .name = "zexaruntime", 49 + .root_module = zexa_runtime_mod, 50 + .linkage = .dynamic, 51 + }); 52 + b.installArtifact(zexa_runtime_lib); 53 + // { 54 + const zexa_runtime_tests = b.addTest(.{ 55 + .root_module = zexa_runtime_mod, 56 + }); 57 + 58 + const run_zexa_runtime_tests = b.addRunArtifact(zexa_runtime_tests); 59 + test_step.dependOn(&run_zexa_runtime_tests.step); 60 + // } 32 61 33 62 const add_exe = b.option(bool, "exe", "Whether to build the Zexa interpreter") orelse true; 34 63 ··· 38 67 .target = target, 39 68 .optimize = optimize, 40 69 }); 41 - exe_mod.addImport("zexa", mod); 70 + exe_mod.addImport("zexa", zexa_mod); 42 71 43 72 const exe = b.addExecutable(.{ 44 73 .name = "zexa", 45 74 .root_module = exe_mod, 46 75 }); 47 76 b.installArtifact(exe); 48 - const run_zexa = b.addRunArtifact(exe); 49 - if (b.args) |a| { 50 - run_zexa.addArgs(a); 51 - } 52 - 53 - const run_step = b.step("run", "Run zexa interpreter"); 54 - run_step.dependOn(&run_zexa.step); 55 77 } 56 78 }
+2
runtime/TODO.txt
··· 1 + - runtime library providing access to system apis (filesystem, i/o, networking, process) 2 + - self-contained applicaton archives (like java .jar)
+44
runtime/lib/os.zig
··· 1 + const std = @import("std"); 2 + 3 + const z = @import("../z.zig"); 4 + 5 + pub fn abort(scope: *z.Scope, args: []const *z.Value) z.RuntimeError!*z.Value { 6 + _ = scope; 7 + _ = args; 8 + std.process.abort(); 9 + } 10 + 11 + pub fn exit(scope: *z.Scope, args: []const *z.Value) z.RuntimeError!*z.Value { 12 + var sb = try scope.stringBuilder(); 13 + defer sb.deinit(); 14 + 15 + if (args.len != 1) { 16 + try z.util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); 17 + try scope.setException(sb.written()); 18 + return z.RuntimeError.InvalidArguments; 19 + } 20 + 21 + const num: u8 = switch (args[0].expr) { 22 + .num => |n| @intFromFloat(n), 23 + .nil => 0, 24 + else => { 25 + try z.util.invalidType(&sb, .num, args[0].getType()); 26 + try scope.setException(sb.written()); 27 + return z.RuntimeError.InvalidArguments; 28 + }, 29 + }; 30 + 31 + std.process.exit(num); 32 + } 33 + 34 + // pub fn system(scope: *z.Scope, args: []const *z.Value) z.RuntimeError!*z.Value { 35 + // var sb = try scope.stringBuilder(); 36 + // defer sb.deinit(); 37 + 38 + // if (args.len != 1) { 39 + // try z.util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); 40 + // try scope.setException(sb.written()); 41 + // return z.RuntimeError.InvalidArguments; 42 + // } 43 + 44 + // }
+12
runtime/root.zig
··· 1 + const std = @import("std"); 2 + const z = @import("./z.zig"); 3 + 4 + const os = @import("./lib/os.zig"); 5 + 6 + pub export fn load(scope: *z.Scope) void { 7 + scope.insertRegistry(&.{ 8 + // -- OS -- 9 + .{ "abort", z.Value.initNativeFunc(scope, os.abort) catch return }, 10 + .{ "exit", z.Value.initNativeFunc(scope, os.exit) catch return }, 11 + }) catch return; 12 + }
+2
runtime/test.zexa
··· 1 + (loadlib "zig-out/lib/libzexaruntime.so") 2 + (exit 2)
+8
runtime/z.zig
··· 1 + const zexa = @import("zexa"); 2 + 3 + pub const Scope = zexa.lang.Scope; 4 + pub const Value = zexa.lang.Value; 5 + pub const AST = zexa.lang.AST; 6 + pub const RuntimeError = zexa.lang.RuntimeError; 7 + 8 + pub const util = zexa.util;
+69 -17
src/corelib.zig
··· 10 10 11 11 const util = @import("./util.zig"); 12 12 const SliceIterator = util.SliceIterator; 13 - const StringBuilder = util.StringBuilder; 13 + // const StringBuilder = util.StringBuilder; 14 14 15 15 const EXCEPTION_SIZE = 30; 16 16 ··· 37 37 .{ "list", try Value.initNativeFunc(scope, list) }, 38 38 .{ "append", try Value.initNativeFunc(scope, append) }, 39 39 .{ "map", try Value.initNativeFunc(scope, map) }, 40 + .{ "loadlib", try Value.initNativeFunc(scope, loadlib) }, 40 41 41 42 .{ "add", try Value.initNativeFunc(scope, add) }, 42 43 .{ "sub", try Value.initNativeFunc(scope, sub) }, ··· 56 57 } 57 58 58 59 pub fn @"if"(scope: *Scope, args: []const *Value) RuntimeError!AST { 59 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 60 + var sb = try scope.stringBuilder(); 60 61 defer sb.deinit(); 61 62 if (args.len != 3) { 62 63 try util.unexpectedArguments(&sb, .{ .expected = 3, .got = args.len }); ··· 75 76 } 76 77 77 78 pub fn @"while"(scope: *Scope, args: []const *Value) RuntimeError!AST { 78 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 79 + var sb = try scope.stringBuilder(); 79 80 defer sb.deinit(); 80 81 if (args.len == 0) { 81 82 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = 0, .mode = .at_least }); ··· 96 97 } 97 98 98 99 pub fn let(scope: *Scope, args: []const *Value) RuntimeError!AST { 99 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 100 + var sb = try scope.stringBuilder(); 100 101 defer sb.deinit(); 101 102 if (args.len == 0) { 102 103 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = 0, .mode = .at_least }); ··· 137 138 } 138 139 139 140 pub fn lambda(scope: *Scope, args: []const *Value) RuntimeError!AST { 140 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 141 + var sb = try scope.stringBuilder(); 141 142 defer sb.deinit(); 142 143 if (args.len == 0) { 143 144 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = 0, .mode = .at_least }); ··· 174 175 } 175 176 176 177 pub fn dolist(scope: *Scope, args: []const *Value) RuntimeError!AST { 177 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 178 + var sb = try scope.stringBuilder(); 178 179 defer sb.deinit(); 179 180 if (args.len < 2) { 180 181 try util.unexpectedArguments(&sb, .{ .expected = 2, .got = args.len, .mode = .at_least }); ··· 206 207 // -- FUNCTIONS -- 207 208 208 209 pub fn eval(scope: *Scope, args: []const *Value) RuntimeError!*Value { 209 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 210 + var sb = try scope.stringBuilder(); 210 211 defer sb.deinit(); 211 212 if (args.len != 1) { 212 213 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); ··· 218 219 } 219 220 220 221 pub fn define(scope: *Scope, args: []const *Value) RuntimeError!*Value { 221 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 222 + var sb = try scope.stringBuilder(); 222 223 defer sb.deinit(); 223 224 if (args.len != 2) { 224 225 try util.unexpectedArguments(&sb, .{ .expected = 2, .got = args.len }); ··· 237 238 238 239 pub fn set(scope: *Scope, args: []const *Value) RuntimeError!*Value { 239 240 var iter = SliceIterator(*Value).init(args); 240 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 241 + var sb = try scope.stringBuilder(); 241 242 defer sb.deinit(); 242 243 243 244 while (iter.next()) |sym| { ··· 278 279 } 279 280 280 281 pub fn format(scope: *Scope, args: []const *Value) RuntimeError!*Value { 281 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 282 + var sb = try scope.stringBuilder(); 282 283 defer sb.deinit(); 283 284 284 285 if (args.len == 0) { ··· 340 341 } 341 342 342 343 pub fn clone(scope: *Scope, args: []const *Value) RuntimeError!*Value { 343 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 344 + var sb = try scope.stringBuilder(); 344 345 defer sb.deinit(); 345 346 if (args.len != 1) { 346 347 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); ··· 373 374 } 374 375 375 376 pub fn append(scope: *Scope, args: []const *Value) RuntimeError!*Value { 376 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 377 + var sb = try scope.stringBuilder(); 377 378 defer sb.deinit(); 378 379 if (args.len == 0) { 379 380 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len, .mode = .at_least }); ··· 392 393 } 393 394 394 395 pub fn map(scope: *Scope, args: []const *Value) RuntimeError!*Value { 395 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 396 + var sb = try scope.stringBuilder(); 396 397 defer sb.deinit(); 397 398 if (args.len != 2) { 398 399 try util.unexpectedArguments(&sb, .{ .expected = 2, .got = args.len }); ··· 414 415 return iterable; 415 416 } 416 417 418 + pub fn loadlib(scope: *Scope, args: []const *Value) RuntimeError!*Value { 419 + var sb = try scope.stringBuilder(); 420 + defer sb.deinit(); 421 + 422 + if (args.len != 1) { 423 + sb.clear(); 424 + try util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); 425 + try scope.setException(sb.written()); 426 + return RuntimeError.InvalidArguments; 427 + } 428 + 429 + const path = switch (args[0].expr) { 430 + .str => |s| s, 431 + else => { 432 + sb.clear(); 433 + try util.invalidType(&sb, .str, args[0].getType()); 434 + try scope.setException(sb.written()); 435 + return RuntimeError.InvalidArguments; 436 + }, 437 + }; 438 + 439 + const realpath = std.fs.cwd().realpathAlloc(scope.allocator, path) catch { 440 + try scope.setException("couldn't get realpath for library"); 441 + return RuntimeError.External; 442 + }; 443 + defer scope.allocator.free(realpath); 444 + 445 + const exists = if (std.fs.accessAbsolute(realpath, .{})) |_| true else |_| false; 446 + if (!exists) { 447 + std.debug.print("fuck you\n", .{}); 448 + return RuntimeError.Exception; 449 + } 450 + 451 + const sym: [:0]const u8 = "load"; 452 + 453 + var dynlib = std.DynLib.open(realpath) catch |e| { 454 + try scope.setException(@errorName(e)); 455 + return RuntimeError.External; 456 + }; 457 + const lib = dynlib.lookup(zexa.lang.Library, sym) orelse { 458 + sb.clear(); 459 + try sb.appendFormat("symbol not found: {s}", .{sym}); 460 + try scope.setException(sb.written()); 461 + return RuntimeError.Exception; 462 + }; 463 + 464 + try scope.getRoot().loadLibrary(lib); 465 + 466 + return try Value.initNil(scope); 467 + } 468 + 417 469 // -- OPERATORS -- 418 470 419 471 pub fn add(scope: *Scope, args: []const *Value) RuntimeError!*Value { ··· 473 525 } 474 526 475 527 pub fn eql(scope: *Scope, args: []const *Value) RuntimeError!*Value { 476 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 528 + var sb = try scope.stringBuilder(); 477 529 defer sb.deinit(); 478 530 if (args.len != 2) { 479 531 try util.unexpectedArguments(&sb, .{ .expected = 2, .got = args.len }); ··· 486 538 } 487 539 488 540 pub fn not(scope: *Scope, args: []const *Value) RuntimeError!*Value { 489 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 541 + var sb = try scope.stringBuilder(); 490 542 defer sb.deinit(); 491 543 if (args.len != 1) { 492 544 try util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); ··· 498 550 } 499 551 500 552 pub fn @"and"(scope: *Scope, args: []const *Value) RuntimeError!*Value { 501 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 553 + var sb = try scope.stringBuilder(); 502 554 defer sb.deinit(); 503 555 if (args.len != 2) { 504 556 try util.unexpectedArguments(&sb, .{ .expected = 2, .got = args.len }); ··· 511 563 } 512 564 513 565 pub fn @"or"(scope: *Scope, args: []const *Value) RuntimeError!*Value { 514 - var sb = try StringBuilder.init(scope.allocator, EXCEPTION_SIZE); 566 + var sb = try scope.stringBuilder(); 515 567 defer sb.deinit(); 516 568 if (args.len != 2) { 517 569 try util.unexpectedArguments(&sb, .{ .expected = 2, .got = args.len });
+17 -3
src/lang.zig
··· 25 25 pub const NativeMacro = *const fn (scope: *Scope, args: []const *Value) RuntimeError!AST; 26 26 27 27 /// A function that runs on a scope to define new values 28 - pub const Library = *const fn (scope: *Scope) RuntimeError!void; 28 + pub const Library = *const fn (scope: *Scope) void; 29 29 30 30 /// Abstract syntax tree of a program 31 31 pub const AST = []const *Value; ··· 511 511 } 512 512 }, 513 513 .native_macro => {}, 514 - else => return RuntimeError.InvalidFunction, 514 + else => { 515 + var sb = try scope.stringBuilder(); 516 + defer sb.deinit(); 517 + try sb.appendFormat("invalid function type: {any}", .{self.getType()}); 518 + try scope.setException(sb.written()); 519 + 520 + return RuntimeError.InvalidFunction; 521 + }, 515 522 } 516 523 517 524 const value = blk: { ··· 791 798 792 799 /// Load a library into the scope 793 800 pub fn loadLibrary(self: *Self, lib: Library) RuntimeError!void { 794 - try lib(self); 801 + lib(self); 802 + } 803 + 804 + const SB = @import("./util.zig").StringBuilder; 805 + 806 + /// Create a StringBuilder 807 + pub fn stringBuilder(self: *Self) RuntimeError!SB { 808 + return try SB.init(self.allocator, 30); 795 809 } 796 810 };