Module: MilkTea::CBackend::Expressions

Included in:
MilkTea::CBackend
Defined in:
lib/milk_tea/core/c_backend/expressions.rb

Instance Method Summary collapse

Instance Method Details

#aggregate_field_type(type, field_name) ⇒ Object

Raises:



400
401
402
403
404
405
406
407
408
409
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 400

def aggregate_field_type(type, field_name)
  return proc_field_types(type).fetch(field_name) if type.is_a?(Types::Proc)
  if type.is_a?(Types::Nullable)
    return Types::Registry.primitive("bool") if field_name == "has_value"
    return type.base if field_name == "value"
  end
  return type.field(field_name) if type.respond_to?(:field)

  raise CBackendError.new("unsupported aggregate field lookup for #{type}", line: 0, column: 0, path: @path)
end

#binary_precedence(operator) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 150

def binary_precedence(operator)
  case operator
  when "or" then 1
  when "and" then 2
  when "|" then 3
  when "^" then 4
  when "&" then 5
  when "==", "!=" then 6
  when "<", "<=", ">", ">=" then 7
  when "<<", ">>" then 8
  when "+", "-" then 9
  when "*", "/", "%" then 10
  else
    raise CBackendError.new("unsupported binary operator #{operator}", line: 0, column: 0, path: @path)
  end
end

#discarded_expression(expression) ⇒ Object



323
324
325
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 323

def discarded_expression(expression)
  "(void)#{wrap_expression(expression)}"
end

#emit_address_of_operand(expression) ⇒ Object



327
328
329
330
331
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 327

def emit_address_of_operand(expression)
  return emit_expression(expression.operand) if expression.is_a?(IR::Unary) && expression.operator == "*"

  "&#{wrap_expression(expression)}"
end

#emit_aggregate_field_initializer(type, field) ⇒ Object



411
412
413
414
415
416
417
418
419
420
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 411

def emit_aggregate_field_initializer(type, field)
  field_type = aggregate_field_type(type, field.name)
  if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
    emit_nullable_some_initializer(field_type, field.value)
  elsif void_storage_field?(field_type)
    emit_void_field_initializer(field.value)
  else
    emit_initializer(field.value)
  end
end

#emit_aggregate_initializer(expression) ⇒ Object



222
223
224
225
226
227
228
229
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 222

def emit_aggregate_initializer(expression)
  return emit_zero_initializer(expression.type) if expression.fields.empty?

  fields = expression.fields.map do |field|
    ".#{sanitize_c_identifier(field.name)} = #{emit_aggregate_field_initializer(expression.type, field)}"
  end.join(", ")
  "{ #{fields} }"
end

#emit_aggregate_literal(expression) ⇒ Object



250
251
252
253
254
255
256
257
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 250

def emit_aggregate_literal(expression)
  return emit_zero_expression(expression.type) if expression.fields.empty?

  fields = expression.fields.map do |field|
    ".#{sanitize_c_identifier(field.name)} = #{emit_aggregate_field_initializer(expression.type, field)}"
  end.join(", ")
  "(#{c_type(expression.type)}){ #{fields} }"
end

#emit_array_call_statement(expression, out_argument, indent) ⇒ Object



284
285
286
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 284

def emit_array_call_statement(expression, out_argument, indent)
  "#{indent}#{emit_call_expression(expression, array_out_argument: out_argument)};"
end

#emit_array_compound_literal(expression) ⇒ Object



362
363
364
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 362

def emit_array_compound_literal(expression)
  "(#{c_declaration(expression.type, '')}) #{emit_array_initializer(expression)}"
end

#emit_array_copy_statement(destination, source, indent) ⇒ Object



288
289
290
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 288

def emit_array_copy_statement(destination, source, indent)
  "#{indent}memcpy(#{destination}, #{emit_expression(source)}, sizeof(#{destination}));"
end

#emit_array_initializer(expression) ⇒ Object



355
356
357
358
359
360
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 355

def emit_array_initializer(expression)
  return "{ 0 }" if expression.elements.empty?

  elements = expression.elements.map { |element| emit_initializer(element) }.join(", ")
  "{ #{elements} }"
end

#emit_array_out_argument(destination) ⇒ Object



351
352
353
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 351

def emit_array_out_argument(destination)
  "&#{destination}"
end

#emit_array_return(expression, indent) ⇒ Object



292
293
294
295
296
297
298
299
300
301
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 292

def emit_array_return(expression, indent)
  if expression.is_a?(IR::Call) && array_type?(expression.type)
    return [emit_array_call_statement(expression, ARRAY_OUT_PARAM_NAME, indent), "#{indent}return;"]
  end

  [
    emit_array_copy_statement("*#{ARRAY_OUT_PARAM_NAME}", expression, indent),
    "#{indent}return;",
  ]
end

#emit_binary_expression(expression) ⇒ Object



113
114
115
116
117
118
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 113

def emit_binary_expression(expression)
  parent_precedence = binary_precedence(expression.operator)
  left = emit_binary_operand(expression.left, parent_precedence, side: :left)
  right = emit_binary_operand(expression.right, parent_precedence, side: :right)
  "#{left} #{c_operator(expression.operator)} #{right}"
end

#emit_binary_operand(expression, parent_precedence, side:) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 120

def emit_binary_operand(expression, parent_precedence, side:)
  text = emit_expression(expression)

  case expression
  when IR::Conditional
    "(#{text})"
  when IR::Binary
    child_precedence = binary_precedence(expression.operator)
    if child_precedence < parent_precedence || (side == :right && child_precedence == parent_precedence)
      "(#{text})"
    else
      text
    end
  else
    text
  end
end

#emit_call_callee(expression) ⇒ Object



342
343
344
345
346
347
348
349
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 342

def emit_call_callee(expression)
  case expression
  when IR::Name, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call
    emit_expression(expression)
  else
    wrap_expression(expression)
  end
end

#emit_call_expression(expression, array_out_argument: nil) ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 271

def emit_call_expression(expression, array_out_argument: nil)
  callee = expression.callee.is_a?(String) ? expression.callee : emit_call_callee(expression.callee)
  omit_receiver = omitted_method_receiver_call?(expression)
  arguments = []
  arguments << array_out_argument if array_out_argument
  arguments.concat(expression.arguments.drop(omit_receiver ? 1 : 0).map { |argument| emit_expression(argument) })
  call = "#{callee}(#{arguments.join(', ')})"
  return call unless omit_receiver && expression.arguments.any?
  return call if side_effect_free_expression?(expression.arguments.first)

  "(#{discarded_expression(expression.arguments.first)}, #{call})"
end

#emit_cast_operand(expression) ⇒ Object



333
334
335
336
337
338
339
340
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 333

def emit_cast_operand(expression)
  case expression
  when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::CheckedIndex, IR::CheckedSpanIndex, IR::NullableIndex, IR::NullableSpanIndex, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr, IR::AddressOf, IR::Cast, IR::Unary
    emit_expression(expression)
  else
    "(#{emit_expression(expression)})"
  end
end

#emit_conditional_condition(expression) ⇒ Object



145
146
147
148
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 145

def emit_conditional_condition(expression)
  text = emit_expression(expression)
  expression.is_a?(IR::Conditional) ? "(#{text})" : text
end

#emit_conditional_expression(expression) ⇒ Object



138
139
140
141
142
143
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 138

def emit_conditional_expression(expression)
  condition = emit_conditional_condition(expression.condition)
  then_expression = emit_expression(expression.then_expression)
  else_expression = emit_expression(expression.else_expression)
  "#{condition} ? #{then_expression} : #{else_expression}"
end

#emit_expression(expression) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 6

def emit_expression(expression)
  case expression
  when IR::Name
    expression.name
  when IR::Member
    operator = pointer_member_receiver?(expression.receiver) ? "->" : "."
    member = "#{wrap_member_receiver(expression.receiver)}#{operator}#{sanitize_c_identifier(expression.member)}"
    expression.type.is_a?(Types::Primitive) && expression.type.void? ? "((void)(#{member}))" : member
  when IR::Index
    "#{wrap_index_receiver(expression.receiver)}[#{emit_expression(expression.index)}]"
  when IR::CheckedIndex
    if (alias_name = checked_index_alias(expression))
      "(*#{alias_name})"
    else
      "(*#{checked_array_index_helper_name(expression.receiver_type)}(#{emit_address_of_operand(expression.receiver)}, #{emit_expression(expression.index)}))"
    end
  when IR::CheckedSpanIndex
    if (alias_name = checked_index_alias(expression))
      "(*#{alias_name})"
    else
      "(*#{checked_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)}))"
    end
  when IR::NullableIndex
    "#{nullable_array_index_helper_name(expression.receiver_type)}(#{emit_address_of_operand(expression.receiver)}, #{emit_expression(expression.index)})"
  when IR::NullableSpanIndex
    "#{nullable_span_index_helper_name(expression.receiver_type)}(#{emit_expression(expression.receiver)}, #{emit_expression(expression.index)})"
  when IR::Call
    if array_type?(expression.type)
      location = [@source_path, @current_line && "line #{@current_line}"].compact.join(" ")
      msg = "array-return call must be materialized before C emission"
      msg += " (#{location})" unless location.empty?
      raise CBackendError.new(msg, line: @current_line, path: @source_path)
    end

    emit_call_expression(expression)
  when IR::Unary
    if expression.operator == "not"
      "!#{wrap_expression(expression.operand)}"
    else
      "#{expression.operator}#{wrap_expression(expression.operand)}"
    end
  when IR::Binary
    return emit_str_equality_expression(expression) if str_equality_expression?(expression)
    return emit_variant_equality_expression(expression) if variant_equality_expression?(expression)
    return emit_nullable_null_comparison(expression) if nullable_null_comparison?(expression)

    emit_binary_expression(expression)
  when IR::Conditional
    emit_conditional_expression(expression)
  when IR::ReinterpretExpr
    if no_op_reinterpret?(expression.target_type, expression.source_type)
      emit_expression(expression.expression)
    else
      "#{reinterpret_helper_name(expression.target_type, expression.source_type)}(#{emit_expression(expression.expression)})"
    end
  when IR::SizeofExpr
    "sizeof(#{layout_type_expression(expression.target_type)})"
  when IR::AlignofExpr
    "_Alignof(#{layout_type_expression(expression.target_type)})"
  when IR::OffsetofExpr
    "offsetof(#{layout_type_expression(expression.target_type)}, #{sanitize_c_identifier(expression.field)})"
  when IR::IntegerLiteral
    expression.value.to_s
  when IR::FloatLiteral
    emit_float_literal(expression)
  when IR::StringLiteral
    expression.type.is_a?(Types::StringView) ? emit_str_literal(expression) : expression.value.inspect
  when IR::BooleanLiteral
    expression.value ? "true" : "false"
  when IR::NullLiteral
    nullable_value_type?(expression.type) ? emit_zero_expression(expression.type) : "NULL"
  when IR::ZeroInit
    emit_zero_expression(expression.type)
  when IR::AddressOf
    case expression.expression
    when IR::CheckedIndex
      alias_name = checked_index_alias(expression.expression)
      alias_name || "#{checked_array_index_helper_name(expression.expression.receiver_type)}(#{emit_address_of_operand(expression.expression.receiver)}, #{emit_expression(expression.expression.index)})"
    when IR::CheckedSpanIndex
      alias_name = checked_index_alias(expression.expression)
      alias_name || "#{checked_span_index_helper_name(expression.expression.receiver_type)}(#{emit_expression(expression.expression.receiver)}, #{emit_expression(expression.expression.index)})"
    else
      emit_address_of_operand(expression.expression)
    end
  when IR::Cast
    if no_op_cast?(expression)
      emit_expression(expression.expression)
    else
      "(#{c_type(expression.target_type)}) #{emit_cast_operand(expression.expression)}"
    end
  when IR::AggregateLiteral
    emit_aggregate_literal(expression)
  when IR::ArrayLiteral
    emit_array_compound_literal(expression)
  when IR::SimdLaneWith
    emit_simd_lane_with(expression)
  when IR::VariantLiteral
    emit_variant_literal(expression)
  else
    raise CBackendError.new("unsupported IR expression #{expression.class.name}", line: 0, column: 0, path: @path)
  end
end

#emit_float_literal(expression) ⇒ Object



473
474
475
476
477
478
479
480
481
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 473

def emit_float_literal(expression)
  value = expression.value
  literal = if value.finite? && value == value.to_i
    format("%.1f", value)
  else
    value.to_s
  end
  expression.type.name == "float" ? "#{literal}f" : literal
end

#emit_initializer(expression) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 205

def emit_initializer(expression)
  case expression
  when IR::ArrayLiteral
    emit_array_initializer(expression)
  when IR::AggregateLiteral
    emit_aggregate_initializer(expression)
  when IR::VariantLiteral
    emit_variant_initializer(expression)
  when IR::StringLiteral
    expression.type.is_a?(Types::StringView) ? emit_str_initializer(expression) : emit_expression(expression)
  when IR::ZeroInit
    emit_zero_initializer(expression.type)
  else
    emit_expression(expression)
  end
end

#emit_nullable_null_comparison(expression) ⇒ Object



199
200
201
202
203
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 199

def emit_nullable_null_comparison(expression)
  operand = expression.left.is_a?(IR::NullLiteral) ? expression.right : expression.left
  access = "#{wrap_member_receiver(operand)}.has_value"
  expression.operator == "==" ? "!#{access}" : access
end

#emit_nullable_some_initializer(nullable_type, value) ⇒ Object



422
423
424
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 422

def emit_nullable_some_initializer(nullable_type, value)
  "(#{c_type(nullable_type)}){ .has_value = true, .value = #{emit_initializer(value)} }"
end

#emit_simd_lane_with(expression) ⇒ Object



366
367
368
369
370
371
372
373
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 366

def emit_simd_lane_with(expression)
  simd_type = expression.type
  elem_c = primitive_c_type(simd_type.element_type.name)
  src = wrap_expression(expression.src)
  idx = emit_expression(expression.index)
  val = wrap_expression(expression.value)
  "({ #{c_type(simd_type)} _mt_with = #{src}; ((#{elem_c}*)&_mt_with)[#{idx}] = #{val}; _mt_with; })"
end

#emit_str_equality_expression(expression) ⇒ Object



167
168
169
170
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 167

def emit_str_equality_expression(expression)
  call = "mt_str_equal(#{emit_expression(expression.left)}, #{emit_expression(expression.right)})"
  expression.operator == "!=" ? "!#{call}" : call
end

#emit_str_initializer(expression) ⇒ Object



242
243
244
245
246
247
248
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 242

def emit_str_initializer(expression)
  if @str_literal_map && @str_literal_map[expression.value]
    @str_literal_map[expression.value]
  else
    "{ .data = #{expression.value.inspect}, .len = #{expression.value.bytesize} }"
  end
end

#emit_str_literal(expression) ⇒ Object



465
466
467
468
469
470
471
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 465

def emit_str_literal(expression)
  if @str_literal_map && @str_literal_map[expression.value]
    @str_literal_map[expression.value]
  else
    "(mt_str){ .data = #{expression.value.inspect}, .len = #{expression.value.bytesize} }"
  end
end

#emit_variant_equality_expression(expression) ⇒ Object



177
178
179
180
181
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 177

def emit_variant_equality_expression(expression)
  helper_name = variant_equality_helper_name(expression.left.type)
  call = "#{helper_name}(#{emit_expression(expression.left)}, #{emit_expression(expression.right)})"
  expression.operator == "!=" ? "!#{call}" : call
end

#emit_variant_field_initializer(type, arm_name, field) ⇒ Object



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 426

def emit_variant_field_initializer(type, arm_name, field)
  field_type = type.arm(arm_name).fetch(field.name)
  if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
    emit_nullable_some_initializer(field_type, field.value)
  elsif field.value.is_a?(IR::AddressOf) && !field_type.is_a?(Types::Nullable)
    c_type_name = named_type_c_name(field_type)
    inner = field.value.expression
    "((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))"
  elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
        array_type?(field_type)
    elem_c_name = c_type(array_element_type(field_type))
    elem_count = array_length(field_type)
    elements = field.value.is_a?(IR::ArrayLiteral) ? field.value.elements.map { |e| emit_initializer(e) }.join(", ") : ""
    "((#{elem_c_name}*)memcpy(malloc(#{elem_count} * sizeof(#{elem_c_name})), &(#{elem_c_name}[#{elem_count}]){ #{elements} }, #{elem_count} * sizeof(#{elem_c_name})))"
  elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
        !field_type.is_a?(Types::GenericInstance)
    field_c_name = named_type_c_name(field_type)
    init = emit_initializer(field.value)
    source_expr = if init.start_with?("{")
      "&(#{c_type(field_type)})#{init}"
    else
      "&(#{init})"
    end
    "((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
  elsif void_storage_field?(field_type)
    emit_void_field_initializer(field.value)
  else
    emit_initializer(field.value)
  end
end

#emit_variant_initializer(expression) ⇒ Object



231
232
233
234
235
236
237
238
239
240
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 231

def emit_variant_initializer(expression)
  outer_c = named_type_c_name(expression.type)
  kind_constant = "#{outer_c}_kind_#{expression.arm_name}"
  if expression.fields.empty?
    "{ .kind = #{kind_constant} }"
  else
    payload_fields = expression.fields.map { |field| ".#{sanitize_c_identifier(field.name)} = #{emit_variant_field_initializer(expression.type, expression.arm_name, field)}" }.join(", ")
    "{ .kind = #{kind_constant}, .data.#{sanitize_c_identifier(expression.arm_name)} = { #{payload_fields} } }"
  end
end

#emit_variant_literal(expression) ⇒ Object



259
260
261
262
263
264
265
266
267
268
269
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 259

def emit_variant_literal(expression)
  outer_c = named_type_c_name(expression.type)
  kind_constant = "#{outer_c}_kind_#{expression.arm_name}"
  if expression.fields.empty?
    "(#{outer_c}){ .kind = #{kind_constant} }"
  else
    arm_c = "#{outer_c}_#{expression.arm_name}"
    payload_fields = expression.fields.map { |field| ".#{sanitize_c_identifier(field.name)} = #{emit_variant_field_initializer(expression.type, expression.arm_name, field)}" }.join(", ")
    "(#{outer_c}){ .kind = #{kind_constant}, .data.#{sanitize_c_identifier(expression.arm_name)} = (struct #{arm_c}){ #{payload_fields} } }"
  end
end

#emit_void_field_initializer(expression) ⇒ Object



457
458
459
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 457

def emit_void_field_initializer(expression)
  "(#{emit_expression(expression)}, 0)"
end

#emit_zero_expression(type) ⇒ Object



390
391
392
393
394
395
396
397
398
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 390

def emit_zero_expression(type)
  return "(#{c_type(type)}) #{emit_zero_initializer(type)}" if type.is_a?(Types::StringView)
  return "NULL" if type.is_a?(Types::Nullable) && c_backend_pointer_like_type?(type.base)
  return "(#{c_type(type)}){ 0 }" if type.is_a?(Types::Nullable)
  return emit_zero_initializer(type) if type.is_a?(Types::Primitive)
  return emit_zero_initializer(type) if type.is_a?(Types::EnumBase)

  "(#{c_declaration(type, '')}) #{emit_zero_initializer(type)}"
end

#emit_zero_initializer(type) ⇒ Object



375
376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 375

def emit_zero_initializer(type)
  return "{ 0 }" if type.is_a?(Types::StringView)
  return "{ 0 }" if array_type?(type)
  return "NULL" if type.is_a?(Types::Nullable) && c_backend_pointer_like_type?(type.base)
  return "{ 0 }" if type.is_a?(Types::Nullable)
  return "NULL" if raw_pointer_type?(type) || ref_type?(type)
  return "NULL" if type.is_a?(Types::Opaque) && !type.external
  return "false" if type.is_a?(Types::Primitive) && type.boolean?
  return "0.0" if type.is_a?(Types::Primitive) && type.float?
  return "0" if type.is_a?(Types::Primitive) && !type.void?
  return "(#{c_type(type)}) 0" if type.is_a?(Types::EnumBase)

  "{ 0 }"
end

#emitted_function_params(function) ⇒ Object



303
304
305
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 303

def emitted_function_params(function)
  omitted_method_receiver_function?(function) ? function.params.drop(1) : function.params
end

#layout_type_expression(type) ⇒ Object



492
493
494
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 492

def layout_type_expression(type)
  c_declaration(type, "")
end

#nullable_null_comparison?(expression) ⇒ Boolean

Returns:

  • (Boolean)


192
193
194
195
196
197
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 192

def nullable_null_comparison?(expression)
  return false unless EQUALITY_OPERATORS.include?(expression.operator)

  (nullable_value_type?(expression.left.type) && expression.right.is_a?(IR::NullLiteral)) ||
    (nullable_value_type?(expression.right.type) && expression.left.is_a?(IR::NullLiteral))
end

#nullable_value_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


188
189
190
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 188

def nullable_value_type?(type)
  type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(type.base)
end

#omitted_method_receiver_call?(expression) ⇒ Boolean

Returns:

  • (Boolean)


307
308
309
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 307

def omitted_method_receiver_call?(expression)
  expression.callee.is_a?(String) && omitted_method_receiver_function_names.key?(expression.callee)
end

#omitted_method_receiver_function?(function) ⇒ Boolean

Returns:

  • (Boolean)


317
318
319
320
321
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 317

def omitted_method_receiver_function?(function)
  function.method_receiver_param &&
    function.params.first &&
    name_reference_count_in_statements(function.body, function.params.first.linkage_name).zero?
end

#omitted_method_receiver_function_namesObject



311
312
313
314
315
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 311

def omitted_method_receiver_function_names
  @omitted_method_receiver_function_names ||= emitted_functions.each_with_object({}) do |function, omitted|
    omitted[function.linkage_name] = true if omitted_method_receiver_function?(function)
  end
end

#str_equality_expression?(expression) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 109

def str_equality_expression?(expression)
  EQUALITY_OPERATORS.include?(expression.operator) && expression.left.type.is_a?(Types::StringView) && expression.right.type.is_a?(Types::StringView)
end

#variant_equality_expression?(expression) ⇒ Boolean

Returns:

  • (Boolean)


172
173
174
175
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 172

def variant_equality_expression?(expression)
  EQUALITY_OPERATORS.include?(expression.operator) &&
    (expression.left.type.is_a?(Types::Variant) || expression.left.type.is_a?(Types::VariantArmPayload))
end

#variant_equality_helper_name(type) ⇒ Object



183
184
185
186
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 183

def variant_equality_helper_name(type)
  variant = type.is_a?(Types::VariantArmPayload) ? type.variant_type : type
  "mt_variant_eq_#{named_type_c_name(variant)}"
end

#void_storage_field?(type) ⇒ Boolean

Returns:

  • (Boolean)


461
462
463
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 461

def void_storage_field?(type)
  type.is_a?(Types::Primitive) && type.void?
end

#wrap_expression(expression) ⇒ Object



483
484
485
486
487
488
489
490
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 483

def wrap_expression(expression)
  case expression
  when IR::Name, IR::IntegerLiteral, IR::FloatLiteral, IR::StringLiteral, IR::BooleanLiteral, IR::NullLiteral, IR::ZeroInit, IR::Member, IR::Index, IR::Call, IR::AggregateLiteral, IR::ArrayLiteral, IR::ReinterpretExpr, IR::SizeofExpr, IR::AlignofExpr, IR::OffsetofExpr
    emit_expression(expression)
  else
    "(#{emit_expression(expression)})"
  end
end