Module: MilkTea::SexprDumper

Defined in:
lib/milk_tea/tooling/sexpr_dumper.rb

Constant Summary collapse

TYPES_SHORT_NAMES =

── Types serialisation ───────────────────────────────────────────

{
  "MilkTea::Types::Primitive"              => "Primitive",
  "MilkTea::Types::Null"                   => "Null",
  "MilkTea::Types::Nullable"               => "Nullable",
  "MilkTea::Types::GenericInstance"        => "Generic",
  "MilkTea::Types::Span"                   => "Span",
  "MilkTea::Types::Task"                   => "Task",
  "MilkTea::Types::Function"               => "Function",
  "MilkTea::Types::Proc"                   => "Proc",
  "MilkTea::Types::Tuple"                  => "Tuple",
  "MilkTea::Types::Vector"                 => "Vector",
  "MilkTea::Types::Matrix"                 => "Matrix",
  "MilkTea::Types::Quaternion"             => "Quaternion",
  "MilkTea::Types::SoA"                    => "SoA",
  "MilkTea::Types::Simd"                   => "Simd",
  "MilkTea::Types::Struct"                 => "Struct",
  "MilkTea::Types::StructInstance"         => "StructInstance",
  "MilkTea::Types::Union"                  => "Union",
  "MilkTea::Types::Variant"                => "Variant",
  "MilkTea::Types::VariantInstance"        => "VariantInstance",
  "MilkTea::Types::VariantArmPayload"      => "VariantArmPayload",
  "MilkTea::Types::Enum"                   => "Enum",
  "MilkTea::Types::Flags"                  => "Flags",
  "MilkTea::Types::Opaque"                 => "Opaque",
  "MilkTea::Types::StringView"             => "StringView",
  "MilkTea::Types::Dyn"                    => "Dyn",
  "MilkTea::Types::Parameter"              => "Parameter",
  "MilkTea::Types::LiteralTypeArg"         => "LiteralTypeArg",
  "MilkTea::Types::TypeVar"                => "TypeVar",
  "MilkTea::Types::LifetimeRef"            => "LifetimeRef",
  "MilkTea::Types::Event"                  => "Event",
  "MilkTea::Types::Subscription"           => "Subscription",
  "MilkTea::Types::Handle"                 => "Handle",
  "MilkTea::Types::TypeType"               => "TypeType",
  "MilkTea::Types::Error"                  => "Error",
  "MilkTea::Types::DynVtable"              => "DynVtable",
}.freeze
TYPES_CLASSES =
TYPES_SHORT_NAMES.keys.map do |name|
  name.split("::").reduce(Object) { |mod, part| mod.const_get(part) }
end.freeze

Class Method Summary collapse

Class Method Details

._emit_generic_type(type, buf) ⇒ Object



300
301
302
303
304
305
306
307
308
309
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 300

def _emit_generic_type(type, buf)
  type.instance_variables.sort.each do |ivar|
    next if skip_types_ivar?(ivar)
    name = ivar.to_s.sub(/\A@/, "")
    val = type.instance_variable_get(ivar)
    next if val.is_a?(Hash) || val.is_a?(Set) || val.is_a?(Proc)
    buf << " :" << name << " "
    emit_value(val, buf)
  end
end

.dump_ast(ast) ⇒ Object



13
14
15
16
17
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 13

def dump_ast(ast)
  buf = +""
  emit_value(ast, buf)
  buf
end

.dump_ir(program) ⇒ Object



7
8
9
10
11
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 7

def dump_ir(program)
  buf = +""
  emit_value(program, buf)
  buf
end

.dump_tokens(tokens) ⇒ Object



19
20
21
22
23
24
25
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 19

def dump_tokens(tokens)
  buf = +""
  buf << "("
  tokens.each_with_index { |t, i| buf << " " if i > 0; emit_token(t, buf) }
  buf << ")"
  buf
end

.emit_array(values, buf) ⇒ Object

── Array serialisation ───────────────────────────────────────────



63
64
65
66
67
68
69
70
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 63

def emit_array(values, buf)
  buf << "("
  values.each_with_index do |v, i|
    buf << " " if i > 0
    emit_value(v, buf)
  end
  buf << ")"
end

.emit_data(node, buf) ⇒ Object

── Data serialisation ────────────────────────────────────────────



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 48

def emit_data(node, buf)
  type_name = node.class.name.split("::").last(2).join("::")
  members = node.class.members
  buf << "(" << type_name
  members.each do |field|
    val = node.public_send(field)
    next if val.is_a?(Hash) || val.is_a?(Set)
    buf << " :" << field.to_s << " "
    emit_value(val, buf)
  end
  buf << ")"
end

.emit_string(value, buf) ⇒ Object

── atom helpers ──────────────────────────────────────────────────



320
321
322
323
324
325
326
327
328
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 320

def emit_string(value, buf)
  escaped = value.to_s
    .gsub("\\", "\\\\")
    .gsub('"', '\"')
    .gsub("\n", '\\n')
    .gsub("\t", '\\t')
    .gsub("\r", '\\r')
  buf << '"' << escaped << '"'
end

.emit_token(token, buf) ⇒ Object

── Token serialisation ───────────────────────────────────────────



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 74

def emit_token(token, buf)
  buf << "(token :type " << emit_token_type(token.type)
  buf << " :lexeme "
  emit_string(token.lexeme, buf)
  buf << " :literal "
  emit_value(token.literal, buf)
  buf << " :line " << token.line.to_s
  buf << " :column " << token.column.to_s
  buf << " :start_offset " << token.start_offset.to_s
  buf << " :end_offset " << token.end_offset.to_s
  buf << ")"
end

.emit_token_type(sym) ⇒ Object



87
88
89
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 87

def emit_token_type(sym)
  ":" + sym.to_s.tr("_", "-")
end

.emit_types_fields(type, buf) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 142

def emit_types_fields(type, buf)
  case type
  when Types::Primitive
    buf << " :name "
    emit_string(type.name, buf)
  when Types::Null
    buf << " :target_type "
    emit_value(type.target_type, buf)
  when Types::Nullable
    buf << " :base "
    emit_value(type.base, buf)
  when Types::GenericInstance
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :arguments "
    emit_array(type.arguments, buf)
  when Types::Span
    buf << " :element_type "
    emit_value(type.element_type, buf)
  when Types::Task
    buf << " :result_type "
    emit_value(type.result_type, buf)
  when Types::Function
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :params "
    emit_array(type.params, buf)
    buf << " :return_type "
    emit_value(type.return_type, buf)
    buf << " :receiver_type "
    emit_value(type.receiver_type, buf)
    buf << " :receiver_editable "
    emit_value(type.receiver_editable, buf)
    buf << " :variadic "
    emit_value(type.variadic, buf)
    buf << " :external "
    emit_value(type.external, buf)
  when Types::Proc
    buf << " :params "
    emit_array(type.params, buf)
    buf << " :return_type "
    emit_value(type.return_type, buf)
  when Types::Tuple
    buf << " :element_types "
    emit_array(type.element_types, buf)
    buf << " :field_names "
    emit_value(type.field_names, buf)
  when Types::Vector
    buf << " :name "
    emit_string(type.name, buf)
  when Types::Matrix
    buf << " :name "
    emit_string(type.name, buf)
  when Types::Quaternion
    buf << " :name "
    emit_string(type.name, buf)
  when Types::SoA
    buf << " :element_type "
    emit_value(type.element_type, buf)
    buf << " :count "
    emit_value(type.count, buf)
  when Types::Simd
    buf << " :element_type "
    emit_value(type.element_type, buf)
    buf << " :lane_count "
    emit_value(type.lane_count, buf)
  when Types::Struct
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
  when Types::StructInstance
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
    buf << " :arguments "
    emit_array(type.arguments, buf)
  when Types::Union
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
  when Types::Variant
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
  when Types::VariantInstance
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
    buf << " :arguments "
    emit_array(type.arguments, buf)
  when Types::VariantArmPayload
    buf << " :variant_name "
    emit_string(type.variant_type.name, buf)
    buf << " :arm_name "
    emit_string(type.arm_name, buf)
  when Types::Enum
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
  when Types::Flags
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
  when Types::Opaque
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :module_name "
    emit_value(type.module_name, buf)
  when Types::StringView
    # no fields
  when Types::Dyn
    buf << " :interface_name "
    emit_string(type.interface_binding.name, buf)
    buf << " :type_arguments "
    emit_array(type.type_arguments, buf)
  when Types::Parameter
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :type "
    emit_value(type.type, buf)
    buf << " :mutable "
    emit_value(type.mutable, buf)
    buf << " :passing_mode "
    emit_value(type.passing_mode, buf)
    buf << " :boundary_type "
    emit_value(type.boundary_type, buf)
  when Types::LiteralTypeArg
    buf << " :value "
    emit_value(type.value, buf)
  when Types::TypeVar
    buf << " :name "
    emit_string(type.name, buf)
  when Types::LifetimeRef
    buf << " :name "
    emit_string(type.name, buf)
  when Types::Event
    buf << " :name "
    emit_string(type.name, buf)
    buf << " :capacity "
    emit_value(type.capacity, buf)
    buf << " :payload_type "
    emit_value(type.payload_type, buf)
  when Types::Subscription
    # no fields (singleton)
  when Types::Handle
    # no fields (singleton)
  else
    _emit_generic_type(type, buf)
  end
end

.emit_types_object(type, buf) ⇒ Object



135
136
137
138
139
140
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 135

def emit_types_object(type, buf)
  short = TYPES_SHORT_NAMES[type.class.name] || type.class.name.split("::").last
  buf << "(Types::" << short
  emit_types_fields(type, buf)
  buf << ")"
end

.emit_value(value, buf) ⇒ Object

── value dispatcher ──────────────────────────────────────────────



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 29

def emit_value(value, buf)
  case value
  when ::Data then emit_data(value, buf)
  when Array  then emit_array(value, buf)
  when *TYPES_CLASSES then emit_types_object(value, buf)
  when nil    then buf << "nil"
  when true   then buf << "true"
  when false  then buf << "false"
  when Integer then buf << value.to_s
  when Float   then buf << format_float(value)
  when String  then emit_string(value, buf)
  when Symbol  then buf << ":" << value.to_s.tr("_", "-")
  when Hash, Set then nil
  else buf << escape_string(value.to_s)
  end
end

.escape_string(value) ⇒ Object



330
331
332
333
334
335
336
337
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 330

def escape_string(value)
  value.to_s
    .gsub("\\", "\\\\")
    .gsub('"', '\"')
    .gsub("\n", '\\n')
    .gsub("\t", '\\t')
    .gsub("\r", '\\r')
end

.format_float(value) ⇒ Object



339
340
341
342
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 339

def format_float(value)
  s = sprintf("%.17g", value)
  s.include?(".") || s.include?("e") ? s : s + ".0"
end

.skip_types_ivar?(ivar) ⇒ Boolean

Returns:

  • (Boolean)


311
312
313
314
315
316
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 311

def skip_types_ivar?(ivar)
  %i[@hash @integer @float @numeric @pointer_sized_integer
     @signed_integer @unsigned_integer @fixed_width_integer
     @boolean @void @integer_width @float_width @backing_type
     @arms @arm_names @arm_field_hashes @instances].include?(ivar)
end