Module: MilkTea::CBackend::Expressions
- Included in:
- MilkTea::CBackend
- Defined in:
- lib/milk_tea/core/c_backend/expressions.rb
Instance Method Summary collapse
- #aggregate_field_type(type, field_name) ⇒ Object
- #binary_precedence(operator) ⇒ Object
- #discarded_expression(expression) ⇒ Object
- #emit_address_of_operand(expression) ⇒ Object
- #emit_addressof_field_initializer(field_type, value) ⇒ Object
- #emit_aggregate_field_initializer(type, field) ⇒ Object
- #emit_aggregate_initializer(expression) ⇒ Object
- #emit_aggregate_literal(expression) ⇒ Object
- #emit_array_call_statement(expression, out_argument, indent) ⇒ Object
- #emit_array_compound_literal(expression) ⇒ Object
- #emit_array_copy_statement(destination, source, indent) ⇒ Object
- #emit_array_initializer(expression) ⇒ Object
- #emit_array_out_argument(destination) ⇒ Object
- #emit_array_return(expression, indent) ⇒ Object
- #emit_binary_expression(expression) ⇒ Object
- #emit_binary_operand(expression, parent_precedence, side:) ⇒ Object
- #emit_call_callee(expression) ⇒ Object
- #emit_call_expression(expression, array_out_argument: nil) ⇒ Object
- #emit_cast_operand(expression) ⇒ Object
- #emit_conditional_condition(expression) ⇒ Object
- #emit_conditional_expression(expression) ⇒ Object
- #emit_cyclic_array_initializer(field_type, value) ⇒ Object
- #emit_cyclic_struct_initializer(field_type, value) ⇒ Object
- #emit_expression(expression) ⇒ Object
- #emit_float_literal(expression) ⇒ Object
- #emit_initializer(expression) ⇒ Object
- #emit_nullable_null_comparison(expression) ⇒ Object
- #emit_nullable_some_initializer(nullable_type, value) ⇒ Object
- #emit_simd_lane_with(expression) ⇒ Object
- #emit_str_equality_expression(expression) ⇒ Object
- #emit_str_initializer(expression) ⇒ Object
- #emit_str_literal(expression) ⇒ Object
- #emit_variant_equality_expression(expression) ⇒ Object
- #emit_variant_field_initializer(type, arm_name, field) ⇒ Object
- #emit_variant_initializer(expression) ⇒ Object
- #emit_variant_literal(expression) ⇒ Object
- #emit_void_field_initializer(expression) ⇒ Object
- #emit_zero_expression(type) ⇒ Object
- #emit_zero_initializer(type) ⇒ Object
- #emitted_function_params(function) ⇒ Object
- #layout_type_expression(type) ⇒ Object
- #nullable_null_comparison?(expression) ⇒ Boolean
- #nullable_value_type?(type) ⇒ Boolean
- #omitted_method_receiver_call?(expression) ⇒ Boolean
- #omitted_method_receiver_function?(function) ⇒ Boolean
- #omitted_method_receiver_function_names ⇒ Object
- #str_equality_expression?(expression) ⇒ Boolean
- #variant_equality_expression?(expression) ⇒ Boolean
- #variant_equality_helper_name(type) ⇒ Object
- #void_storage_field?(type) ⇒ Boolean
- #wrap_expression(expression) ⇒ Object
Instance Method Details
#aggregate_field_type(type, field_name) ⇒ Object
399 400 401 402 403 404 405 406 407 408 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 399 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_addressof_field_initializer(field_type, value) ⇒ Object
444 445 446 447 448 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 444 def emit_addressof_field_initializer(field_type, value) c_type_name = named_type_c_name(field_type) inner = value.expression "((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))" end |
#emit_aggregate_field_initializer(type, field) ⇒ Object
410 411 412 413 414 415 416 417 418 419 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 410 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
361 362 363 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 361 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
354 355 356 357 358 359 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 354 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
350 351 352 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 350 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
341 342 343 344 345 346 347 348 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 341 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 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 333 def emit_cast_operand(expression) if expression.is_a?(IR::Binary) || expression.is_a?(IR::Conditional) "(#{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_cyclic_array_initializer(field_type, value) ⇒ Object
450 451 452 453 454 455 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 450 def emit_cyclic_array_initializer(field_type, value) elem_c_name = c_type(array_element_type(field_type)) elem_count = array_length(field_type) elements = value.is_a?(IR::ArrayLiteral) ? 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})))" end |
#emit_cyclic_struct_initializer(field_type, value) ⇒ Object
457 458 459 460 461 462 463 464 465 466 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 457 def emit_cyclic_struct_initializer(field_type, value) field_c_name = named_type_c_name(field_type) init = emit_initializer(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})))" 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
484 485 486 487 488 489 490 491 492 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 484 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
421 422 423 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 421 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
365 366 367 368 369 370 371 372 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 365 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
476 477 478 479 480 481 482 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 476 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
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 425 def emit_variant_field_initializer(type, arm_name, field) field_type = type.arm(arm_name).fetch(field.name) outer_c = named_type_c_name(type) 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) emit_addressof_field_initializer(field_type, field.value) elsif aggregate_field_creates_cycle?(field_type, outer_c) && array_type?(field_type) emit_cyclic_array_initializer(field_type, field.value) elsif aggregate_field_creates_cycle?(field_type, outer_c) && !field_type.is_a?(Types::GenericInstance) emit_cyclic_struct_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_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
468 469 470 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 468 def emit_void_field_initializer(expression) "(#{emit_expression(expression)}, 0)" end |
#emit_zero_expression(type) ⇒ Object
389 390 391 392 393 394 395 396 397 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 389 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
374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 374 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
503 504 505 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 503 def layout_type_expression(type) c_declaration(type, "") end |
#nullable_null_comparison?(expression) ⇒ 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
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
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
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_names ⇒ Object
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
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
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
472 473 474 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 472 def void_storage_field?(type) type.is_a?(Types::Primitive) && type.void? end |
#wrap_expression(expression) ⇒ Object
494 495 496 497 498 499 500 501 |
# File 'lib/milk_tea/core/c_backend/expressions.rb', line 494 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 |