diff --git a/src/astgen.zig b/src/astgen.zig index 1ed732f1734cf48e2c22e261c506b8e3e07e4c18..08166d23fbf9a17bfa23cea35cb2769c6bc2ee17 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -31,6 +31,7 @@ pub const Block = struct { name: Type, args: []const []const string, body: []const Value, + bttm: []const Value, pub const Type = enum { each, @@ -134,8 +135,19 @@ const Parser = struct { if (std.meta.stringToEnum(Block.Type, w)) |name| { const args = self.doArgs(); var children: []const Value = &.{}; + var bottom: []const Value = &.{}; + var top = true; while (!self.tryEatSymbol("/")) { - children = children ++ &[_]Value{self.doValue()}; + if (self.tryEatSymbol("<")) { + std.debug.assert(std.mem.eql(u8, "else", self.eat(.word))); + self.eatSymbol(">"); + top = false; + } + if (top) { + children = children ++ &[_]Value{self.doValue()}; + } else { + bottom = bottom ++ &[_]Value{self.doValue()}; + } } std.debug.assert(std.mem.eql(u8, @tagName(name), self.eat(.word))); self.eatSymbol("/"); @@ -143,6 +155,7 @@ const Parser = struct { .name = name, .args = args, .body = children, + .bttm = bottom, } }; } return Value{ .function = .{ diff --git a/src/lib.zig b/src/lib.zig index d9040b1bad030183105b2c9b70585c2bd5010ebd..63947c8f3d92df14bc239de8d6ee0d5c967ad319 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -14,7 +14,7 @@ const tokenize = @import("./tokenize.zig"); const astgen = @import("./astgen.zig"); pub fn parse(comptime input: []const u8) astgen.Value { - return astgen.Value{ .element = astgen.do(tokenize.do(input, &.{ '[', '=', ']', '(', ')', '{', '}', '#', '/', '.' })) }; + return astgen.Value{ .element = astgen.do(tokenize.do(input, &.{ '[', '=', ']', '(', ')', '{', '}', '#', '/', '.', '<', '>' })) }; } pub fn compile(writer: anytype, comptime value: astgen.Value, data: anytype) !void { @@ -83,20 +83,22 @@ fn do(writer: anytype, comptime value: astgen.Value, data: anytype, ctx: anytype .@"if" => { comptime assertEqual(v.args.len, 1); const x = search(v.args[0], data); - switch (@typeInfo(@TypeOf(x))) { - .Bool => if (x) try do(writer, body, data, ctx, indent, flag1), - .Optional => if (x) |_| try do(writer, body, data, ctx, indent, flag1), + const content = switch (@typeInfo(@TypeOf(x))) { + .Bool => if (x) v.body else v.bttm, + .Optional => if (x) |_| v.body else v.bttm, else => unreachable, - } + }; + try do(writer, body, content, ctx, indent, flag1); }, .ifnot => { comptime assertEqual(v.args.len, 1); const x = search(v.args[0], data); - switch (@typeInfo(@TypeOf(x))) { - .Bool => if (x) {} else try do(writer, body, data, ctx, indent, flag1), - .Optional => if (x) |_| {} else try do(writer, body, data, ctx, indent, flag1), + const content = switch (@typeInfo(@TypeOf(x))) { + .Bool => if (x) v.bttm else v.body, + .Optional => if (x) |_| v.bttm else v.body, else => unreachable, - } + }; + try do(writer, body, content, ctx, indent, flag1); }, .ifequal => { comptime assertEqual(v.args.len, 2);