mt-lang 0.3.11 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,342 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MilkTea
4
+ module SexprDumper
5
+ module_function
6
+
7
+ def dump_ir(program)
8
+ buf = +""
9
+ emit_value(program, buf)
10
+ buf
11
+ end
12
+
13
+ def dump_ast(ast)
14
+ buf = +""
15
+ emit_value(ast, buf)
16
+ buf
17
+ end
18
+
19
+ def dump_tokens(tokens)
20
+ buf = +""
21
+ buf << "("
22
+ tokens.each_with_index { |t, i| buf << " " if i > 0; emit_token(t, buf) }
23
+ buf << ")"
24
+ buf
25
+ end
26
+
27
+ # ── value dispatcher ──────────────────────────────────────────────
28
+
29
+ def emit_value(value, buf)
30
+ case value
31
+ when ::Data then emit_data(value, buf)
32
+ when Array then emit_array(value, buf)
33
+ when *TYPES_CLASSES then emit_types_object(value, buf)
34
+ when nil then buf << "nil"
35
+ when true then buf << "true"
36
+ when false then buf << "false"
37
+ when Integer then buf << value.to_s
38
+ when Float then buf << format_float(value)
39
+ when String then emit_string(value, buf)
40
+ when Symbol then buf << ":" << value.to_s.tr("_", "-")
41
+ else buf << escape_string(value.to_s)
42
+ end
43
+ end
44
+
45
+ # ── Data serialisation ────────────────────────────────────────────
46
+
47
+ def emit_data(node, buf)
48
+ type_name = node.class.name.split("::").last(2).join("::")
49
+ members = node.class.members
50
+ buf << "(" << type_name
51
+ members.each do |field|
52
+ val = node.public_send(field)
53
+ buf << " :" << field.to_s << " "
54
+ emit_value(val, buf)
55
+ end
56
+ buf << ")"
57
+ end
58
+
59
+ # ── Array serialisation ───────────────────────────────────────────
60
+
61
+ def emit_array(values, buf)
62
+ buf << "("
63
+ values.each_with_index do |v, i|
64
+ buf << " " if i > 0
65
+ emit_value(v, buf)
66
+ end
67
+ buf << ")"
68
+ end
69
+
70
+ # ── Token serialisation ───────────────────────────────────────────
71
+
72
+ def emit_token(token, buf)
73
+ buf << "(token :type " << emit_token_type(token.type)
74
+ buf << " :lexeme "
75
+ emit_string(token.lexeme, buf)
76
+ buf << " :literal "
77
+ emit_value(token.literal, buf)
78
+ buf << " :line " << token.line.to_s
79
+ buf << " :column " << token.column.to_s
80
+ buf << " :start_offset " << token.start_offset.to_s
81
+ buf << " :end_offset " << token.end_offset.to_s
82
+ buf << ")"
83
+ end
84
+
85
+ def emit_token_type(sym)
86
+ ":" + sym.to_s.tr("_", "-")
87
+ end
88
+
89
+ # ── Types serialisation ───────────────────────────────────────────
90
+
91
+ TYPES_SHORT_NAMES = {
92
+ "MilkTea::Types::Primitive" => "Primitive",
93
+ "MilkTea::Types::Null" => "Null",
94
+ "MilkTea::Types::Nullable" => "Nullable",
95
+ "MilkTea::Types::GenericInstance" => "Generic",
96
+ "MilkTea::Types::Span" => "Span",
97
+ "MilkTea::Types::Task" => "Task",
98
+ "MilkTea::Types::Function" => "Function",
99
+ "MilkTea::Types::Proc" => "Proc",
100
+ "MilkTea::Types::Tuple" => "Tuple",
101
+ "MilkTea::Types::Vector" => "Vector",
102
+ "MilkTea::Types::Matrix" => "Matrix",
103
+ "MilkTea::Types::Quaternion" => "Quaternion",
104
+ "MilkTea::Types::SoA" => "SoA",
105
+ "MilkTea::Types::Simd" => "Simd",
106
+ "MilkTea::Types::Struct" => "Struct",
107
+ "MilkTea::Types::StructInstance" => "StructInstance",
108
+ "MilkTea::Types::Union" => "Union",
109
+ "MilkTea::Types::Variant" => "Variant",
110
+ "MilkTea::Types::VariantInstance" => "VariantInstance",
111
+ "MilkTea::Types::VariantArmPayload" => "VariantArmPayload",
112
+ "MilkTea::Types::Enum" => "Enum",
113
+ "MilkTea::Types::Flags" => "Flags",
114
+ "MilkTea::Types::Opaque" => "Opaque",
115
+ "MilkTea::Types::StringView" => "StringView",
116
+ "MilkTea::Types::Dyn" => "Dyn",
117
+ "MilkTea::Types::Parameter" => "Parameter",
118
+ "MilkTea::Types::LiteralTypeArg" => "LiteralTypeArg",
119
+ "MilkTea::Types::TypeVar" => "TypeVar",
120
+ "MilkTea::Types::LifetimeRef" => "LifetimeRef",
121
+ "MilkTea::Types::Event" => "Event",
122
+ "MilkTea::Types::Subscription" => "Subscription",
123
+ "MilkTea::Types::Handle" => "Handle",
124
+ "MilkTea::Types::TypeType" => "TypeType",
125
+ "MilkTea::Types::Error" => "Error",
126
+ "MilkTea::Types::DynVtable" => "DynVtable",
127
+ }.freeze
128
+
129
+ TYPES_CLASSES = TYPES_SHORT_NAMES.keys.map do |name|
130
+ name.split("::").reduce(Object) { |mod, part| mod.const_get(part) }
131
+ end.freeze
132
+
133
+ def emit_types_object(type, buf)
134
+ short = TYPES_SHORT_NAMES[type.class.name] || type.class.name.split("::").last
135
+ buf << "(Types::" << short
136
+ emit_types_fields(type, buf)
137
+ buf << ")"
138
+ end
139
+
140
+ def emit_types_fields(type, buf)
141
+ case type
142
+ when Types::Primitive
143
+ buf << " :name "
144
+ emit_string(type.name, buf)
145
+ when Types::Null
146
+ buf << " :target_type "
147
+ emit_value(type.target_type, buf)
148
+ when Types::Nullable
149
+ buf << " :base "
150
+ emit_value(type.base, buf)
151
+ when Types::GenericInstance
152
+ buf << " :name "
153
+ emit_string(type.name, buf)
154
+ buf << " :arguments "
155
+ emit_array(type.arguments, buf)
156
+ when Types::Span
157
+ buf << " :element_type "
158
+ emit_value(type.element_type, buf)
159
+ when Types::Task
160
+ buf << " :result_type "
161
+ emit_value(type.result_type, buf)
162
+ when Types::Function
163
+ buf << " :name "
164
+ emit_string(type.name, buf)
165
+ buf << " :params "
166
+ emit_array(type.params, buf)
167
+ buf << " :return_type "
168
+ emit_value(type.return_type, buf)
169
+ buf << " :receiver_type "
170
+ emit_value(type.receiver_type, buf)
171
+ buf << " :receiver_editable "
172
+ emit_value(type.receiver_editable, buf)
173
+ buf << " :variadic "
174
+ emit_value(type.variadic, buf)
175
+ buf << " :external "
176
+ emit_value(type.external, buf)
177
+ when Types::Proc
178
+ buf << " :params "
179
+ emit_array(type.params, buf)
180
+ buf << " :return_type "
181
+ emit_value(type.return_type, buf)
182
+ when Types::Tuple
183
+ buf << " :element_types "
184
+ emit_array(type.element_types, buf)
185
+ buf << " :field_names "
186
+ emit_value(type.field_names, buf)
187
+ when Types::Vector
188
+ buf << " :name "
189
+ emit_string(type.name, buf)
190
+ when Types::Matrix
191
+ buf << " :name "
192
+ emit_string(type.name, buf)
193
+ when Types::Quaternion
194
+ buf << " :name "
195
+ emit_string(type.name, buf)
196
+ when Types::SoA
197
+ buf << " :element_type "
198
+ emit_value(type.element_type, buf)
199
+ buf << " :count "
200
+ emit_value(type.count, buf)
201
+ when Types::Simd
202
+ buf << " :element_type "
203
+ emit_value(type.element_type, buf)
204
+ buf << " :lane_count "
205
+ emit_value(type.lane_count, buf)
206
+ when Types::Struct
207
+ buf << " :name "
208
+ emit_string(type.name, buf)
209
+ buf << " :module_name "
210
+ emit_value(type.module_name, buf)
211
+ when Types::StructInstance
212
+ buf << " :name "
213
+ emit_string(type.name, buf)
214
+ buf << " :module_name "
215
+ emit_value(type.module_name, buf)
216
+ buf << " :arguments "
217
+ emit_array(type.arguments, buf)
218
+ when Types::Union
219
+ buf << " :name "
220
+ emit_string(type.name, buf)
221
+ buf << " :module_name "
222
+ emit_value(type.module_name, buf)
223
+ when Types::Variant
224
+ buf << " :name "
225
+ emit_string(type.name, buf)
226
+ buf << " :module_name "
227
+ emit_value(type.module_name, buf)
228
+ when Types::VariantInstance
229
+ buf << " :name "
230
+ emit_string(type.name, buf)
231
+ buf << " :module_name "
232
+ emit_value(type.module_name, buf)
233
+ buf << " :arguments "
234
+ emit_array(type.arguments, buf)
235
+ when Types::VariantArmPayload
236
+ buf << " :variant_name "
237
+ emit_string(type.variant_type.name, buf)
238
+ buf << " :arm_name "
239
+ emit_string(type.arm_name, buf)
240
+ when Types::Enum
241
+ buf << " :name "
242
+ emit_string(type.name, buf)
243
+ buf << " :module_name "
244
+ emit_value(type.module_name, buf)
245
+ when Types::Flags
246
+ buf << " :name "
247
+ emit_string(type.name, buf)
248
+ buf << " :module_name "
249
+ emit_value(type.module_name, buf)
250
+ when Types::Opaque
251
+ buf << " :name "
252
+ emit_string(type.name, buf)
253
+ buf << " :module_name "
254
+ emit_value(type.module_name, buf)
255
+ when Types::StringView
256
+ # no fields
257
+ when Types::Dyn
258
+ buf << " :interface_name "
259
+ emit_string(type.interface_binding.name, buf)
260
+ buf << " :type_arguments "
261
+ emit_array(type.type_arguments, buf)
262
+ when Types::Parameter
263
+ buf << " :name "
264
+ emit_string(type.name, buf)
265
+ buf << " :type "
266
+ emit_value(type.type, buf)
267
+ buf << " :mutable "
268
+ emit_value(type.mutable, buf)
269
+ buf << " :passing_mode "
270
+ emit_value(type.passing_mode, buf)
271
+ buf << " :boundary_type "
272
+ emit_value(type.boundary_type, buf)
273
+ when Types::LiteralTypeArg
274
+ buf << " :value "
275
+ emit_value(type.value, buf)
276
+ when Types::TypeVar
277
+ buf << " :name "
278
+ emit_string(type.name, buf)
279
+ when Types::LifetimeRef
280
+ buf << " :name "
281
+ emit_string(type.name, buf)
282
+ when Types::Event
283
+ buf << " :name "
284
+ emit_string(type.name, buf)
285
+ buf << " :capacity "
286
+ emit_value(type.capacity, buf)
287
+ buf << " :payload_type "
288
+ emit_value(type.payload_type, buf)
289
+ when Types::Subscription
290
+ # no fields (singleton)
291
+ when Types::Handle
292
+ # no fields (singleton)
293
+ else
294
+ _emit_generic_type(type, buf)
295
+ end
296
+ end
297
+
298
+ def _emit_generic_type(type, buf)
299
+ type.instance_variables.sort.each do |ivar|
300
+ next if skip_types_ivar?(ivar)
301
+ name = ivar.to_s.sub(/\A@/, "")
302
+ val = type.instance_variable_get(ivar)
303
+ next if val.is_a?(Hash) || val.is_a?(Set) || val.is_a?(Proc)
304
+ buf << " :" << name << " "
305
+ emit_value(val, buf)
306
+ end
307
+ end
308
+
309
+ def skip_types_ivar?(ivar)
310
+ %i[@hash @integer @float @numeric @pointer_sized_integer
311
+ @signed_integer @unsigned_integer @fixed_width_integer
312
+ @boolean @void @integer_width @float_width @backing_type
313
+ @arms @arm_names @arm_field_hashes @instances].include?(ivar)
314
+ end
315
+
316
+ # ── atom helpers ──────────────────────────────────────────────────
317
+
318
+ def emit_string(value, buf)
319
+ escaped = value.to_s
320
+ .gsub("\\", "\\\\")
321
+ .gsub('"', '\"')
322
+ .gsub("\n", '\\n')
323
+ .gsub("\t", '\\t')
324
+ .gsub("\r", '\\r')
325
+ buf << '"' << escaped << '"'
326
+ end
327
+
328
+ def escape_string(value)
329
+ value.to_s
330
+ .gsub("\\", "\\\\")
331
+ .gsub('"', '\"')
332
+ .gsub("\n", '\\n')
333
+ .gsub("\t", '\\t')
334
+ .gsub("\r", '\\r')
335
+ end
336
+
337
+ def format_float(value)
338
+ s = sprintf("%.17g", value)
339
+ s.include?(".") || s.include?("e") ? s : s + ".0"
340
+ end
341
+ end
342
+ end