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 }