Embedded programming language for Zig
1
fork

Configure Feed

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

New features and changes:

- Add mkdir function in new fs module in the runtime
- Strings are now allocated in top-most scope to prevent string decay
- Add `setexcept` function to corelib
- As a compromise use `die` function when libraries fail to load

IamPyu ca81baa5 e83a8100

+69 -10
+26
runtime/lib/fs.zig
··· 1 + const std = @import("std"); 2 + const z = @import("../z.zig"); 3 + 4 + pub fn mkdir(scope: *z.Scope, args: []const *z.Value) z.RuntimeError!*z.Value { 5 + var sb = try scope.stringBuilder(); 6 + defer sb.deinit(); 7 + 8 + if (args.len != 1) { 9 + try z.util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); 10 + try scope.setException(sb.written()); 11 + return z.RuntimeError.InvalidArguments; 12 + } else if (args[0].getType() != .str) { 13 + try z.util.invalidType(&sb, .str, args[0].getType()); 14 + try scope.setException(sb.written()); 15 + return z.RuntimeError.InvalidType; 16 + } 17 + 18 + const path = args[0].expr.str; 19 + 20 + const real = std.fs.cwd().realpathAlloc(scope.allocator, path) catch return z.RuntimeError.Exception; 21 + defer scope.allocator.free(real); 22 + 23 + std.fs.makeDirAbsolute(real) catch return z.RuntimeError.Exception; 24 + 25 + return z.Value.initNil(scope); 26 + }
-1
runtime/lib/os.zig
··· 1 1 const std = @import("std"); 2 - 3 2 const z = @import("../z.zig"); 4 3 5 4 pub fn abort(scope: *z.Scope, args: []const *z.Value) z.RuntimeError!*z.Value {
+8 -4
runtime/root.zig
··· 2 2 const z = @import("./z.zig"); 3 3 4 4 pub const os = @import("./lib/os.zig"); 5 + pub const fs = @import("./lib/fs.zig"); 5 6 6 7 pub export fn load(scope: *z.Scope) void { 7 8 scope.insertRegistry(&.{ 8 9 // -- OS -- 9 - .{ "abort", z.Value.initNativeFunc(scope, os.abort) catch return }, 10 - .{ "exit", z.Value.initNativeFunc(scope, os.exit) catch return }, 11 - .{ "getcwd", z.Value.initNativeFunc(scope, os.getcwd) catch return }, 12 - }) catch return; 10 + .{ "abort", z.Value.initNativeFunc(scope, os.abort) catch z.util.die("abort") }, 11 + .{ "exit", z.Value.initNativeFunc(scope, os.exit) catch z.util.die("exit") }, 12 + .{ "getcwd", z.Value.initNativeFunc(scope, os.getcwd) catch z.util.die("getcwd") }, 13 + 14 + // -- FS -- 15 + .{ "mkdir", z.Value.initNativeFunc(scope, fs.mkdir) catch z.util.die("mkdir") }, 16 + }) catch z.util.die("insertRegistry"); 13 17 }
+24 -1
src/corelib.zig
··· 35 35 .{ "append", try Value.initNativeFunc(scope, append) }, 36 36 .{ "map", try Value.initNativeFunc(scope, map) }, 37 37 .{ "loadlib", try Value.initNativeFunc(scope, loadlib) }, 38 + .{ "setexcept", try Value.initNativeFunc(scope, setexcept) }, 38 39 39 40 .{ "add", try Value.initNativeFunc(scope, add) }, 40 41 .{ "sub", try Value.initNativeFunc(scope, sub) }, ··· 212 213 return RuntimeError.InvalidArguments; 213 214 } 214 215 215 - return scope.evalExpr(args[0]); 216 + return scope.parent.?.evalExpr(args[0]); 216 217 } 217 218 218 219 pub fn define(scope: *Scope, args: []const *Value) RuntimeError!*Value { ··· 451 452 try scope.setException(@errorName(e)); 452 453 return RuntimeError.External; 453 454 }; 455 + defer dynlib.close(); 454 456 const lib = dynlib.lookup(zexa.lang.Library, sym) orelse { 455 457 sb.clear(); 456 458 try sb.appendFormat("symbol not found: {s}", .{sym}); ··· 461 463 try scope.getRoot().loadLibrary(lib); 462 464 463 465 return try Value.initNil(scope); 466 + } 467 + 468 + pub fn setexcept(scope: *Scope, args: []const *Value) RuntimeError!*Value { 469 + var sb = try scope.stringBuilder(); 470 + 471 + if (args.len != 1) { 472 + try util.unexpectedArguments(&sb, .{ .expected = 1, .got = args.len }); 473 + try scope.setException(sb.written()); 474 + return RuntimeError.InvalidArguments; 475 + } 476 + 477 + const msg = switch (args[0].expr) { 478 + .str => |s| s, 479 + else => { 480 + try util.invalidType(&sb, .str, args[0].getType()); 481 + return RuntimeError.InvalidType; 482 + }, 483 + }; 484 + 485 + try scope.setException(msg); 486 + return Value.initNil(scope); 464 487 } 465 488 466 489 // -- OPERATORS --
+4 -2
src/lang.zig
··· 639 639 640 640 /// Allocate a string bounded to the scope 641 641 pub fn createString(self: *Self, str: []const u8) ![]const u8 { 642 - const out = try self.allocator.alloc(u8, str.len); 642 + const scope = self.getRoot(); 643 + const out = try scope.allocator.alloc(u8, str.len); 643 644 @memcpy(out, str); 644 - try self.tracked_strings.append(self.allocator, out); 645 + try scope.tracked_strings.append(self.allocator, out); 645 646 return out; 646 647 } 647 648 ··· 769 770 770 771 /// Load a library into the scope 771 772 pub fn loadLibrary(self: *Self, lib: Library) RuntimeError!void { 773 + // TODO: suddenly started segfaulting, fix later 772 774 lib(self); 773 775 } 774 776
+7
src/util.zig
··· 1 + const std = @import("std"); 1 2 const zexa = @import("./root.zig"); 2 3 const Value = zexa.lang.Value; 3 4 const ValueType = zexa.lang.ValueType; ··· 6 7 7 8 pub const SliceIterator = mitochondria.SliceIterator; 8 9 pub const StringBuilder = mitochondria.StringBuilder; 10 + 11 + /// unrecoverable error or you just dont want to handle errors you fucking idiot 12 + pub fn die(message: []const u8) noreturn { 13 + std.debug.print("{s}\n", .{message}); 14 + std.process.abort(); 15 + } 9 16 10 17 pub fn undefinedVariable(sb: *StringBuilder, name: []const u8) !void { 11 18 try sb.appendFormat("undefined variable: {s}", .{name});
-2
test/argument-grow.zexa
··· 10 10 (set 'accum (add accum 1)) 11 11 (eval call) 12 12 (append call (format "Argument %{}" accum))) 13 - 14 - ;; TODO: I've also discovered that strings are completely broken on Debug / ReleaseSafe builds.