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



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

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 ───────────────────────────────────────────



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

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 ────────────────────────────────────────────



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

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)
    buf << " :" << field.to_s << " "
    emit_value(val, buf)
  end
  buf << ")"
end

.emit_string(value, buf) ⇒ Object

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



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

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 ───────────────────────────────────────────



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

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



85
86
87
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 85

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

.emit_types_fields(type, buf) ⇒ Object



140
141
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
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 140

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



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

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
# 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("_", "-")
  else buf << escape_string(value.to_s)
  end
end

.escape_string(value) ⇒ Object



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

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

.format_float(value) ⇒ Object



337
338
339
340
# File 'lib/milk_tea/tooling/sexpr_dumper.rb', line 337

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

.skip_types_ivar?(ivar) ⇒ Boolean

Returns:

  • (Boolean)


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

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