diff --git a/src/astgen.zig b/src/astgen.zig index 38464245214f696d4612a50adbc91a21258ba982..54e149942fc175a4ba510339ab4fe020ec5d46e0 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -35,7 +35,7 @@ pub const Replacement = struct { pub const Block = struct { name: Type, func: ?string, - args: []const []const string, + args: []const Arg, body: Body, bttm: Body, @@ -53,7 +53,12 @@ pub const Body = []const Value; pub const Fn = struct { name: string, raw: bool, - args: []const []const string, + args: []const Arg, +}; + +pub const Arg = union(enum) { + lookup: []const string, + plain: string, }; // @@ -93,6 +98,7 @@ const Parser = struct { } fn tryEatSymbol(comptime self: *Parser, comptime needle: string) bool { + if (self.index >= self.tokens.len) return false; switch (self.tokens[self.index].data) { .symbol => |sym| { if (std.mem.eql(u8, sym, needle)) { @@ -194,23 +200,25 @@ const Parser = struct { return Value{ .element = self.doElement() }; } - pub fn doArgs(comptime self: *Parser) []const []const string { - var ret: []const []const string = &.{}; - var temp: []const string = &.{self.eat(.word)}; + pub fn doArgs(comptime self: *Parser) []const Arg { + var ret: []const Arg = &.{}; + var temp: []const string = &.{}; while (!self.tryEatSymbol("}")) { + if (self.nextIs(.string)) { + ret = ret ++ &[_]Arg{.{ .plain = self.eat(.string) }}; + continue; + } + if (temp.len == 0 and self.nextIs(.word)) { + temp = temp ++ &[_]string{self.eat(.word)}; + } if (self.tryEatSymbol(".")) { temp = temp ++ &[_]string{self.eat(.word)}; } else { - ret = ret ++ &[_][]const string{temp}; + ret = ret ++ &[_]Arg{.{ .lookup = temp }}; temp = &.{}; - if (comptime self.nextIs(.string)) { - ret = ret ++ &[_][]const string{&.{self.eat(.string)}}; - } else { - temp = &.{self.eat(.word)}; - } } } - if (temp.len > 0) ret = ret ++ &[_][]const string{temp}; + if (temp.len > 0) ret = ret ++ &[_]Arg{.{ .lookup = temp }}; return ret; } diff --git a/src/lib.zig b/src/lib.zig index e5048a0e8ccbba8055fbe85e815d685f38d5c437..d2b15668f4da312ff5b835eed4bbc321c61513b7 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -127,7 +127,7 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V .block => |v| { const body = astgen.Value{ .body = v.body }; const bottom = astgen.Value{ .body = v.bttm }; - const x = if (comptime std.mem.eql(u8, v.args[0][0], "this")) search(v.args[0][1..], data) else search(v.args[0], ctx); + const x = resolveArg(v.args[0], data, ctx); const T = @TypeOf(x); const TI = @typeInfo(T); switch (v.name) { @@ -167,7 +167,7 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V }, .ifequal => { comptime assertEqual(v.args.len, 2); - const y = if (comptime std.mem.eql(u8, v.args[1][0], "this")) search(v.args[1][1..], data) else search(v.args[1], ctx); + const y = resolveArg(v.args[1], data, ctx); if (@typeInfo(@TypeOf(x)) == .Enum and comptime std.meta.trait.isZigString(@TypeOf(y))) { return try doif(alloc, writer, body, bottom, data, ctx, opts, std.mem.eql(u8, @tagName(x), y)); } @@ -175,7 +175,7 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V }, .ifnotequal => { comptime assertEqual(v.args.len, 2); - const y = if (comptime std.mem.eql(u8, v.args[1][0], "this")) search(v.args[1][1..], data) else search(v.args[1], ctx); + const y = resolveArg(v.args[1], data, ctx); if (@typeInfo(@TypeOf(x)) == .Enum and comptime std.meta.trait.isZigString(@TypeOf(y))) { return try doif(alloc, writer, body, bottom, data, ctx, opts, std.mem.eql(u8, @tagName(x), y)); } @@ -201,7 +201,7 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V args.@"1" = list.writer(); inline for (v.args, 0..) |arg, i| { const field_name = comptime std.fmt.comptimePrint("{d}", .{i + 2}); - @field(args, field_name) = if (comptime std.mem.eql(u8, arg[0], "this")) search(arg[1..], data) else search(arg, ctx); + @field(args, field_name) = resolveArg(arg, data, ctx); } const repvalue = astgen.Value{ .replacement = .{ .arms = &.{"this"}, .raw = v.raw } }; try @call(.auto, func, args); @@ -223,7 +223,7 @@ inline fn do(alloc: std.mem.Allocator, writer: anytype, comptime value: astgen.V }; inline for (v.args, 0..) |arg, i| { const field_name = comptime std.fmt.comptimePrint("{d}", .{i}); - @field(args[3], field_name) = if (comptime std.mem.eql(u8, arg[0], "this")) search(arg[1..], data) else search(arg, ctx); + @field(args[3], field_name) = resolveArg(arg, data, ctx); } const repvalue = astgen.Value{ .replacement = .{ .arms = &.{"this"}, .raw = v.raw } }; try @call(.auto, func, args); @@ -248,6 +248,20 @@ pub const DoOptions = struct { flag1: bool, }; +fn resolveArg(comptime arg: astgen.Arg, data: anytype, ctx: anytype) ResolveArg(arg, @TypeOf(data), @TypeOf(ctx)) { + return switch (arg) { + .plain => |av| av[1 .. av.len - 1], + .lookup => |av| if (comptime std.mem.eql(u8, av[0], "this")) search(av[1..], data) else search(av, ctx), + }; +} + +fn ResolveArg(comptime arg: astgen.Arg, comptime This: type, comptime Ctx: type) type { + return switch (arg) { + .plain => string, + .lookup => |av| if (comptime std.mem.eql(u8, av[0], "this")) FieldSearch(This, av[1..]) else FieldSearch(Ctx, av), + }; +} + fn search(comptime args: []const string, ctx: anytype) FieldSearch(@TypeOf(ctx), args) { if (args.len == 0) return ctx; if (args[0][0] == '"') return std.mem.trim(u8, args[0], "\"");