lib/termtex/src/ast.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 pub const Expr = union(enum) {
  4     row: []const *Expr,
  5     text: []const u8,
  6     operator: Operator,
  7     space: Space,
  8     fraction: Fraction,
  9     sqrt: Radical,
 10     scripts: Scripts,
 11     accent: Accent,
 12     grid: Grid,
 13     annotation: Annotation,
 14     delimited: Delimited,
 15 };
 16 
 17 pub const Space = struct {
 18     numerator: i32,
 19     denominator: u32,
 20 };
 21 
 22 pub const LimitPolicy = enum {
 23     auto,
 24     limits,
 25     nolimits,
 26 };
 27 
 28 pub const Operator = struct {
 29     body: *Expr,
 30     limit_policy: LimitPolicy = .auto,
 31 };
 32 
 33 pub const FractionStyle = enum {
 34     text,
 35     display,
 36 };
 37 
 38 pub const Fraction = struct {
 39     numerator: *Expr,
 40     denominator: *Expr,
 41     style: FractionStyle = .text,
 42 };
 43 
 44 pub const Radical = struct {
 45     index: ?*Expr = null,
 46     body: *Expr,
 47 };
 48 
 49 pub const Scripts = struct {
 50     base: *Expr,
 51     sub: ?*Expr = null,
 52     sup: ?*Expr = null,
 53 };
 54 
 55 pub const AccentMark = enum {
 56     bar,
 57     hat,
 58     vec,
 59     dot,
 60     underline,
 61     tilde,
 62     check,
 63     breve,
 64     ddot,
 65     acute,
 66     grave,
 67     ring,
 68     overleft,
 69     overleftright,
 70 };
 71 
 72 pub const Accent = struct {
 73     mark: AccentMark,
 74     body: *Expr,
 75 };
 76 
 77 pub const AnnotationKind = enum {
 78     plain,
 79     overbrace,
 80     underbrace,
 81     boxed,
 82 };
 83 
 84 pub const Annotation = struct {
 85     base: *Expr,
 86     over: ?*Expr = null,
 87     under: ?*Expr = null,
 88     kind: AnnotationKind = .plain,
 89 };
 90 
 91 pub const Delimited = struct {
 92     left: Delimiter,
 93     body: *Expr,
 94     right: Delimiter,
 95 };
 96 
 97 pub const Delimiter = union(enum) {
 98     none,
 99     shape: DelimiterShape,
100     text: []const u8,
101 };
102 
103 pub const DelimiterShape = enum {
104     left_paren,
105     right_paren,
106     left_bracket,
107     right_bracket,
108     left_brace,
109     right_brace,
110     bar,
111     double_bar,
112     left_angle,
113     right_angle,
114     left_double_angle,
115     right_double_angle,
116     left_double_bracket,
117     right_double_bracket,
118     left_floor,
119     right_floor,
120     left_ceil,
121     right_ceil,
122 };
123 
124 pub const GridFence = enum {
125     none,
126     paren,
127     bracket,
128     brace,
129     bar,
130     double_bar,
131     left_brace,
132 };
133 
134 pub const GridAlignment = enum {
135     center,
136     left,
137 };
138 
139 pub const Grid = struct {
140     rows: []const GridRow,
141     fence: GridFence = .none,
142     alignment: GridAlignment = .center,
143 };
144 
145 pub const GridRow = struct {
146     cells: []const *Expr,
147 };
148 
149 pub fn empty(arena: std.mem.Allocator) std.mem.Allocator.Error!*Expr {
150     return text(arena, "");
151 }
152 
153 pub fn text(arena: std.mem.Allocator, value: []const u8) std.mem.Allocator.Error!*Expr {
154     const owned = try arena.dupe(u8, value);
155     return node(arena, .{ .text = owned });
156 }
157 
158 pub fn operator(arena: std.mem.Allocator, body: *Expr, limit_policy: LimitPolicy) std.mem.Allocator.Error!*Expr {
159     return node(arena, .{ .operator = .{
160         .body = body,
161         .limit_policy = limit_policy,
162     } });
163 }
164 
165 pub fn space(arena: std.mem.Allocator, value: Space) std.mem.Allocator.Error!*Expr {
166     return node(arena, .{ .space = value });
167 }
168 
169 pub fn row(arena: std.mem.Allocator, items: []const *Expr) std.mem.Allocator.Error!*Expr {
170     if (items.len == 0) return empty(arena);
171     if (items.len == 1) return items[0];
172     const owned = try arena.dupe(*Expr, items);
173     return node(arena, .{ .row = owned });
174 }
175 
176 pub fn node(arena: std.mem.Allocator, expr: Expr) std.mem.Allocator.Error!*Expr {
177     const out = try arena.create(Expr);
178     out.* = expr;
179     return out;
180 }
181 
182 pub fn textValue(expr: *const Expr) ?[]const u8 {
183     return switch (expr.*) {
184         .text => |value| value,
185         .operator => |value| textValue(value.body),
186         else => null,
187     };
188 }