mt-lang 0.3.17 → 0.3.22

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -1
  3. data/lib/milk_tea/core/c_backend/expressions.rb +34 -23
  4. data/lib/milk_tea/core/c_backend/feature_detection.rb +25 -45
  5. data/lib/milk_tea/core/c_backend/type_collectors.rb +18 -30
  6. data/lib/milk_tea/core/c_backend/type_declaration.rb +0 -6
  7. data/lib/milk_tea/core/c_backend.rb +49 -39
  8. data/lib/milk_tea/core/compile_time.rb +98 -72
  9. data/lib/milk_tea/core/control_flow/builder.rb +2 -1
  10. data/lib/milk_tea/core/intrinsics.rb +7 -0
  11. data/lib/milk_tea/core/lexer.rb +46 -35
  12. data/lib/milk_tea/core/lowering/block.rb +9 -0
  13. data/lib/milk_tea/core/lowering/calls.rb +2 -0
  14. data/lib/milk_tea/core/lowering/declarations.rb +1 -1
  15. data/lib/milk_tea/core/lowering/functions.rb +11 -8
  16. data/lib/milk_tea/core/lowering/resolve.rb +11 -4
  17. data/lib/milk_tea/core/lowering/scans.rb +13 -18
  18. data/lib/milk_tea/core/module_binder.rb +19 -15
  19. data/lib/milk_tea/core/module_loader.rb +212 -59
  20. data/lib/milk_tea/core/module_path_resolver.rb +8 -7
  21. data/lib/milk_tea/core/parser/declarations.rb +43 -19
  22. data/lib/milk_tea/core/parser/expressions.rb +5 -8
  23. data/lib/milk_tea/core/parser/statements.rb +5 -5
  24. data/lib/milk_tea/core/parser.rb +26 -0
  25. data/lib/milk_tea/core/semantic_analyzer/calls.rb +24 -31
  26. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +20 -23
  27. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +146 -92
  28. data/lib/milk_tea/core/semantic_analyzer/statements.rb +19 -41
  29. data/lib/milk_tea/core/semantic_analyzer.rb +56 -37
  30. data/lib/milk_tea/core/types.rb +12 -17
  31. data/lib/milk_tea/lsp/diagnostics.rb +13 -0
  32. data/lib/milk_tea/lsp/server/semantic_tokens.rb +6 -0
  33. data/lib/milk_tea/tooling/cli/commands/bindgen.rb +11 -0
  34. data/lib/milk_tea/tooling/cli/commands/build.rb +37 -0
  35. data/lib/milk_tea/tooling/cli/commands/cache.rb +46 -0
  36. data/lib/milk_tea/tooling/cli/commands/check.rb +106 -0
  37. data/lib/milk_tea/tooling/cli/commands/command_base.rb +8 -0
  38. data/lib/milk_tea/tooling/cli/commands/completions.rb +48 -0
  39. data/lib/milk_tea/tooling/cli/commands/dap.rb +58 -0
  40. data/lib/milk_tea/tooling/cli/commands/debug.rb +77 -0
  41. data/lib/milk_tea/tooling/cli/commands/deps.rb +17 -0
  42. data/lib/milk_tea/tooling/cli/commands/docs.rb +58 -0
  43. data/lib/milk_tea/tooling/cli/commands/emit_c.rb +64 -0
  44. data/lib/milk_tea/tooling/cli/commands/format.rb +199 -0
  45. data/lib/milk_tea/tooling/cli/commands/lex.rb +46 -0
  46. data/lib/milk_tea/tooling/cli/commands/lint.rb +248 -0
  47. data/lib/milk_tea/tooling/cli/commands/lower.rb +50 -0
  48. data/lib/milk_tea/tooling/cli/commands/lsp.rb +43 -0
  49. data/lib/milk_tea/tooling/cli/commands/new.rb +26 -0
  50. data/lib/milk_tea/tooling/cli/commands/parse.rb +51 -0
  51. data/lib/milk_tea/tooling/cli/commands/run.rb +99 -0
  52. data/lib/milk_tea/tooling/cli/commands/snapshot.rb +117 -0
  53. data/lib/milk_tea/tooling/cli/commands/test.rb +557 -0
  54. data/lib/milk_tea/tooling/cli/commands/toolchain.rb +16 -0
  55. data/lib/milk_tea/tooling/cli.rb +101 -1893
  56. data/lib/milk_tea/tooling/sexpr_dumper.rb +7 -7
  57. metadata +24 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2f84289b1bcb599ca81cbada0b1e1a925d9962ffe186471b84026f372fb358b
4
- data.tar.gz: 566b98b015518f583e31fa2f0a75753c3b0abfd5a4047210945b3209c3caf1f3
3
+ metadata.gz: 6dc76fcf0acde63fa4060157d6c6864dedcc32b0f5c2cd60422e9948d9861dab
4
+ data.tar.gz: 0b1bf5aee4d6be4d0f1968a7dacaf35e37557336a5911834a17324d23bd60ba3
5
5
  SHA512:
6
- metadata.gz: ee114072cb26ed2527e0b3703cb7f8a913e37234e6937b3a307ce72363e8a6e10a34e0a149d508a8c02e64c1a0a0f5e9b1ae482b76f068bfb6bf0b8784f34a44
7
- data.tar.gz: 9b29c88530cf6110381123ef8135434caa47aa85abf955a8bd9f25d93fa1b8059691d52804c17e4080a2a3d0ad916aa689470ec8d7719a7186fa62eddb026525
6
+ metadata.gz: 1b34537660a1c2424b3f829ff6ef18d35de4366fe76d0a0938216261b1f9c7c56d8fce2c8a0ac1162f17ddc8c1a2c565f9e08f2f5f0056624f4959d35833cabf
7
+ data.tar.gz: 9b6b00b5b761ab3128c617acb8398c64b829df1e2d6984661bc6e8bfb2081b9fa408fd5e8774e1b540884a59caef4eef146c3a05f0d176cb62019471b4e28b88
data/lib/milk_tea/base.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  require "pathname"
4
4
 
5
5
  module MilkTea
6
- VERSION = "0.3.17"
6
+ VERSION = "0.3.22"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -331,11 +331,10 @@ module MilkTea
331
331
  end
332
332
 
333
333
  def emit_cast_operand(expression)
334
- case expression
335
- 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
336
- emit_expression(expression)
337
- else
334
+ if expression.is_a?(IR::Binary) || expression.is_a?(IR::Conditional)
338
335
  "(#{emit_expression(expression)})"
336
+ else
337
+ emit_expression(expression)
339
338
  end
340
339
  end
341
340
 
@@ -425,28 +424,16 @@ module MilkTea
425
424
 
426
425
  def emit_variant_field_initializer(type, arm_name, field)
427
426
  field_type = type.arm(arm_name).fetch(field.name)
427
+ outer_c = named_type_c_name(type)
428
+
428
429
  if field_type.is_a?(Types::Nullable) && !field.value.type.is_a?(Types::Nullable) && !c_backend_pointer_like_type?(field_type.base)
429
430
  emit_nullable_some_initializer(field_type, field.value)
430
431
  elsif field.value.is_a?(IR::AddressOf) && !field_type.is_a?(Types::Nullable)
431
- c_type_name = named_type_c_name(field_type)
432
- inner = field.value.expression
433
- "((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))"
434
- elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
435
- array_type?(field_type)
436
- elem_c_name = c_type(array_element_type(field_type))
437
- elem_count = array_length(field_type)
438
- elements = field.value.is_a?(IR::ArrayLiteral) ? field.value.elements.map { |e| emit_initializer(e) }.join(", ") : ""
439
- "((#{elem_c_name}*)memcpy(malloc(#{elem_count} * sizeof(#{elem_c_name})), &(#{elem_c_name}[#{elem_count}]){ #{elements} }, #{elem_count} * sizeof(#{elem_c_name})))"
440
- elsif aggregate_field_creates_cycle?(field_type, named_type_c_name(type)) &&
441
- !field_type.is_a?(Types::GenericInstance)
442
- field_c_name = named_type_c_name(field_type)
443
- init = emit_initializer(field.value)
444
- source_expr = if init.start_with?("{")
445
- "&(#{c_type(field_type)})#{init}"
446
- else
447
- "&(#{init})"
448
- end
449
- "((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
432
+ emit_addressof_field_initializer(field_type, field.value)
433
+ elsif aggregate_field_creates_cycle?(field_type, outer_c) && array_type?(field_type)
434
+ emit_cyclic_array_initializer(field_type, field.value)
435
+ elsif aggregate_field_creates_cycle?(field_type, outer_c) && !field_type.is_a?(Types::GenericInstance)
436
+ emit_cyclic_struct_initializer(field_type, field.value)
450
437
  elsif void_storage_field?(field_type)
451
438
  emit_void_field_initializer(field.value)
452
439
  else
@@ -454,6 +441,30 @@ module MilkTea
454
441
  end
455
442
  end
456
443
 
444
+ def emit_addressof_field_initializer(field_type, value)
445
+ c_type_name = named_type_c_name(field_type)
446
+ inner = value.expression
447
+ "((#{c_type_name}*)memcpy(malloc(sizeof(#{c_type_name})), &(#{emit_expression(inner)}), sizeof(#{c_type_name})))"
448
+ end
449
+
450
+ def emit_cyclic_array_initializer(field_type, value)
451
+ elem_c_name = c_type(array_element_type(field_type))
452
+ elem_count = array_length(field_type)
453
+ elements = value.is_a?(IR::ArrayLiteral) ? value.elements.map { |e| emit_initializer(e) }.join(", ") : ""
454
+ "((#{elem_c_name}*)memcpy(malloc(#{elem_count} * sizeof(#{elem_c_name})), &(#{elem_c_name}[#{elem_count}]){ #{elements} }, #{elem_count} * sizeof(#{elem_c_name})))"
455
+ end
456
+
457
+ def emit_cyclic_struct_initializer(field_type, value)
458
+ field_c_name = named_type_c_name(field_type)
459
+ init = emit_initializer(value)
460
+ source_expr = if init.start_with?("{")
461
+ "&(#{c_type(field_type)})#{init}"
462
+ else
463
+ "&(#{init})"
464
+ end
465
+ "((#{field_c_name}*)memcpy(malloc(sizeof(#{field_c_name})), #{source_expr}, sizeof(#{field_c_name})))"
466
+ end
467
+
457
468
  def emit_void_field_initializer(expression)
458
469
  "(#{emit_expression(expression)}, 0)"
459
470
  end
@@ -342,66 +342,46 @@ module MilkTea
342
342
  function.body.any? { |statement| statement_uses_str_equality?(statement) }
343
343
  end
344
344
 
345
- def statement_uses_named_call?(statement, callees)
345
+ def any_ir_statement?(statement, expression_pred:, **kwargs)
346
346
  case statement
347
347
  when IR::LocalDecl
348
- expression_uses_named_call?(statement.value, callees)
348
+ statement.value && expression_pred.call(statement.value, **kwargs)
349
349
  when IR::Assignment
350
- expression_uses_named_call?(statement.target, callees) || expression_uses_named_call?(statement.value, callees)
350
+ expression_pred.call(statement.target, **kwargs) || expression_pred.call(statement.value, **kwargs)
351
351
  when IR::BlockStmt
352
- statement.body.any? { |inner| statement_uses_named_call?(inner, callees) }
352
+ statement.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) }
353
353
  when IR::WhileStmt
354
- expression_uses_named_call?(statement.condition, callees) || statement.body.any? { |inner| statement_uses_named_call?(inner, callees) }
354
+ expression_pred.call(statement.condition, **kwargs) ||
355
+ statement.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) }
355
356
  when IR::ForStmt
356
- statement_uses_named_call?(statement.init, callees) ||
357
- expression_uses_named_call?(statement.condition, callees) ||
358
- statement.body.any? { |inner| statement_uses_named_call?(inner, callees) } ||
359
- statement_uses_named_call?(statement.post, callees)
357
+ any_ir_statement?(statement.init, expression_pred:, **kwargs) ||
358
+ expression_pred.call(statement.condition, **kwargs) ||
359
+ statement.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) } ||
360
+ any_ir_statement?(statement.post, expression_pred:, **kwargs)
360
361
  when IR::IfStmt
361
- expression_uses_named_call?(statement.condition, callees) ||
362
- statement.then_body.any? { |inner| statement_uses_named_call?(inner, callees) } ||
363
- (statement.else_body && statement.else_body.any? { |inner| statement_uses_named_call?(inner, callees) })
362
+ expression_pred.call(statement.condition, **kwargs) ||
363
+ statement.then_body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) } ||
364
+ (statement.else_body && statement.else_body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) })
364
365
  when IR::SwitchStmt
365
- expression_uses_named_call?(statement.expression, callees) || statement.cases.any? { |switch_case| switch_case.body.any? { |inner| statement_uses_named_call?(inner, callees) } }
366
+ expression_pred.call(statement.expression, **kwargs) ||
367
+ statement.cases.any? { |switch_case| switch_case.body.any? { |inner| any_ir_statement?(inner, expression_pred:, **kwargs) } }
366
368
  when IR::StaticAssert
367
- expression_uses_named_call?(statement.condition, callees) || expression_uses_named_call?(statement.message, callees)
369
+ expression_pred.call(statement.condition, **kwargs) || expression_pred.call(statement.message, **kwargs)
368
370
  when IR::ReturnStmt
369
- statement.value && expression_uses_named_call?(statement.value, callees)
371
+ statement.value && expression_pred.call(statement.value, **kwargs)
370
372
  when IR::ExpressionStmt
371
- expression_uses_named_call?(statement.expression, callees)
373
+ expression_pred.call(statement.expression, **kwargs)
374
+ else
375
+ false
372
376
  end
373
377
  end
374
378
 
379
+ def statement_uses_named_call?(statement, callees)
380
+ any_ir_statement?(statement, expression_pred: ->(e) { expression_uses_named_call?(e, callees) })
381
+ end
382
+
375
383
  def statement_uses_str_equality?(statement)
376
- case statement
377
- when IR::LocalDecl
378
- expression_uses_str_equality?(statement.value)
379
- when IR::Assignment
380
- expression_uses_str_equality?(statement.target) || expression_uses_str_equality?(statement.value)
381
- when IR::BlockStmt
382
- statement.body.any? { |inner| statement_uses_str_equality?(inner) }
383
- when IR::WhileStmt
384
- expression_uses_str_equality?(statement.condition) || statement.body.any? { |inner| statement_uses_str_equality?(inner) }
385
- when IR::ForStmt
386
- statement_uses_str_equality?(statement.init) ||
387
- expression_uses_str_equality?(statement.condition) ||
388
- statement.body.any? { |inner| statement_uses_str_equality?(inner) } ||
389
- statement_uses_str_equality?(statement.post)
390
- when IR::IfStmt
391
- expression_uses_str_equality?(statement.condition) ||
392
- statement.then_body.any? { |inner| statement_uses_str_equality?(inner) } ||
393
- (statement.else_body && statement.else_body.any? { |inner| statement_uses_str_equality?(inner) })
394
- when IR::SwitchStmt
395
- expression_uses_str_equality?(statement.expression) || statement.cases.any? { |switch_case| switch_case.body.any? { |inner| statement_uses_str_equality?(inner) } }
396
- when IR::StaticAssert
397
- expression_uses_str_equality?(statement.condition) || expression_uses_str_equality?(statement.message)
398
- when IR::ReturnStmt
399
- statement.value && expression_uses_str_equality?(statement.value)
400
- when IR::ExpressionStmt
401
- expression_uses_str_equality?(statement.expression)
402
- else
403
- false
404
- end
384
+ any_ir_statement?(statement, expression_pred: ->(e) { expression_uses_str_equality?(e) })
405
385
  end
406
386
 
407
387
  def expression_uses_named_call?(expression, callees)
@@ -241,21 +241,15 @@ module MilkTea
241
241
  end
242
242
 
243
243
  def collect_soa_from_statements(statements, soa_types, visited)
244
- statements.each do |stmt|
245
- case stmt
246
- when IR::LocalDecl
247
- collect_soa_type(stmt.type, soa_types, visited)
248
- when IR::BlockStmt
249
- collect_soa_from_statements(stmt.body, soa_types, visited)
250
- when IR::IfStmt
251
- collect_soa_from_statements(stmt.then_body || [], soa_types, visited)
252
- collect_soa_from_statements(stmt.else_body || [], soa_types, visited)
253
- when IR::WhileStmt
254
- collect_soa_from_statements(stmt.body || [], soa_types, visited)
255
- when IR::ForStmt
256
- collect_soa_from_statements(stmt.body || [], soa_types, visited)
257
- end
258
- end
244
+ each_ir_statement_for_type_collection(statements,
245
+ type_collector_method: :collect_soa_type,
246
+ expression_walker_method: :collect_soa_type_in_expression,
247
+ accumulator: soa_types, visited:)
248
+ end
249
+
250
+ def collect_soa_type_in_expression(expression, soa_types, visited)
251
+ return unless expression.respond_to?(:type)
252
+ collect_soa_type(expression.type, soa_types, visited)
259
253
  end
260
254
 
261
255
  def collect_soa_type(type, soa_types, visited)
@@ -290,21 +284,15 @@ module MilkTea
290
284
  end
291
285
 
292
286
  def collect_simd_from_statements(statements, simd_types, visited)
293
- statements.each do |stmt|
294
- case stmt
295
- when IR::LocalDecl
296
- collect_simd_type(stmt.type, simd_types, visited)
297
- when IR::BlockStmt
298
- collect_simd_from_statements(stmt.body, simd_types, visited)
299
- when IR::IfStmt
300
- collect_simd_from_statements(stmt.then_body || [], simd_types, visited)
301
- collect_simd_from_statements(stmt.else_body || [], simd_types, visited)
302
- when IR::WhileStmt
303
- collect_simd_from_statements(stmt.body || [], simd_types, visited)
304
- when IR::ForStmt
305
- collect_simd_from_statements(stmt.body || [], simd_types, visited)
306
- end
307
- end
287
+ each_ir_statement_for_type_collection(statements,
288
+ type_collector_method: :collect_simd_type,
289
+ expression_walker_method: :collect_simd_type_in_expression,
290
+ accumulator: simd_types, visited:)
291
+ end
292
+
293
+ def collect_simd_type_in_expression(expression, simd_types, visited)
294
+ return unless expression.respond_to?(:type)
295
+ collect_simd_type(expression.type, simd_types, visited)
308
296
  end
309
297
 
310
298
  def collect_simd_type(type, simd_types, visited)
@@ -61,12 +61,6 @@ module MilkTea
61
61
  lines
62
62
  end
63
63
 
64
- def variant_self_reference?(type, outer_c)
65
- return false unless type.is_a?(Types::Variant) || type.is_a?(Types::VariantInstance)
66
-
67
- named_type_c_name(type) == outer_c
68
- end
69
-
70
64
  def emit_variant(variant_decl)
71
65
  lines = []
72
66
  outer_c = variant_decl.linkage_name
@@ -75,11 +75,27 @@ module MilkTea
75
75
 
76
76
  def emit
77
77
  lines = []
78
+ @cyclic_aggregate_pairs = build_cyclic_aggregate_pairs(
79
+ emitted_aggregate_structs + collect_generic_struct_decls + collect_task_decls + collect_proc_decls + collect_dyn_decls + collect_str_buffer_decls + collect_nullable_opt_decls +
80
+ emitted_aggregate_unions +
81
+ emitted_aggregate_variants + collect_generic_variant_decls
82
+ )
83
+
78
84
  constants = emitted_constants
79
- all_struct_decls = emitted_aggregate_structs + collect_generic_struct_decls + collect_task_decls + collect_proc_decls + collect_dyn_decls + collect_str_buffer_decls + collect_nullable_opt_decls
80
- all_variant_decls = emitted_aggregate_variants + collect_generic_variant_decls
81
- all_decls_for_cycle = all_struct_decls + emitted_aggregate_unions + all_variant_decls
82
- @cyclic_aggregate_pairs = build_cyclic_aggregate_pairs(all_decls_for_cycle)
85
+
86
+ emit_preamble(lines)
87
+ emit_conditional_helpers(lines)
88
+ emit_type_declarations(lines)
89
+ emit_function_forward_declarations(lines)
90
+ emit_globals_and_constants(lines, constants)
91
+ emit_per_type_helpers(lines)
92
+ emit_string_literal_constants_section(lines)
93
+ emit_function_definitions(lines)
94
+
95
+ lines.join("\n").rstrip + "\n"
96
+ end
97
+
98
+ def emit_preamble(lines)
83
99
  headers = @program.includes.map(&:header)
84
100
  if headers.include?("\"fs_support.h\"") || headers.include?("\"tls_support.h\"") || uses_parallel_for_helper? || uses_spawn_all_helper? || uses_detach_helper?
85
101
  lines << "#ifndef _GNU_SOURCE"
@@ -103,70 +119,61 @@ module MilkTea
103
119
  lines << "#include #{header}"
104
120
  end
105
121
  lines << ""
122
+ end
106
123
 
124
+ def emit_conditional_helpers(lines)
107
125
  if uses_string_view?
108
126
  lines.concat(emit_string_type)
109
127
  lines << ""
110
128
  end
111
-
112
129
  if uses_vector_math_types?
113
130
  lines.concat(emit_vector_math_types)
114
131
  lines << ""
115
132
  end
116
-
117
133
  if uses_fatal_helper?
118
134
  lines.concat(emit_fatal_helper)
119
135
  lines << ""
120
136
  end
121
-
122
137
  if uses_format_helpers?
123
138
  lines.concat(emit_format_helpers)
124
139
  lines << ""
125
140
  end
126
-
127
141
  if uses_fmt_builder?
128
142
  lines.concat(emit_fmt_builder_helpers)
129
143
  lines << ""
130
144
  end
131
-
132
145
  if uses_str_equality_helper?
133
146
  lines.concat(emit_str_equality_helper)
134
147
  lines << ""
135
148
  end
136
-
137
149
  if uses_text_buffer_helpers?
138
150
  lines.concat(emit_text_buffer_helpers)
139
151
  lines << ""
140
152
  end
141
-
142
153
  if uses_async_memory_helpers?
143
154
  lines.concat(emit_async_memory_helpers)
144
155
  lines << ""
145
156
  end
146
-
147
157
  if uses_parallel_for_helper?
148
158
  lines.concat(emit_parallel_for_helper)
149
159
  lines << ""
150
160
  end
151
-
152
161
  if uses_spawn_all_helper?
153
162
  lines.concat(emit_spawn_all_helper)
154
163
  lines << ""
155
164
  end
156
-
157
165
  if uses_detach_helper?
158
166
  lines.concat(emit_detach_helpers)
159
167
  lines << ""
160
168
  end
169
+ end
161
170
 
162
- opaque_decls = @program.opaques
163
- aggregate_decls = sort_aggregate_decls(
164
- all_struct_decls,
165
- emitted_aggregate_unions,
166
- all_variant_decls,
167
- )
171
+ def emit_type_declarations(lines)
172
+ all_struct_decls = emitted_aggregate_structs + collect_generic_struct_decls + collect_task_decls + collect_proc_decls + collect_dyn_decls + collect_str_buffer_decls + collect_nullable_opt_decls
173
+ all_variant_decls = emitted_aggregate_variants + collect_generic_variant_decls
174
+ aggregate_decls = sort_aggregate_decls(all_struct_decls, emitted_aggregate_unions, all_variant_decls)
168
175
 
169
- forward_declarations = emit_forward_declarations(opaque_decls, aggregate_decls)
176
+ forward_declarations = emit_forward_declarations(@program.opaques, aggregate_decls)
170
177
  unless forward_declarations.empty?
171
178
  lines.concat(forward_declarations)
172
179
  lines << ""
@@ -236,13 +243,17 @@ module MilkTea
236
243
  lines.concat(emit_variant_equality_helpers)
237
244
  lines << ""
238
245
  end
246
+ end
239
247
 
248
+ def emit_function_forward_declarations(lines)
240
249
  function_declarations = emit_function_declarations(emitted_functions)
241
250
  unless function_declarations.empty?
242
251
  lines.concat(function_declarations)
243
252
  lines << ""
244
253
  end
254
+ end
245
255
 
256
+ def emit_globals_and_constants(lines, constants)
246
257
  constants.each do |constant|
247
258
  @current_line = constant.line if constant.line
248
259
  @source_path ||= constant.path if constant.path
@@ -262,51 +273,50 @@ module MilkTea
262
273
  lines << emit_static_assert(statement)
263
274
  end
264
275
  lines << "" unless @program.static_asserts.empty?
276
+ end
265
277
 
266
- reinterpret_helpers = collect_reinterpret_helpers
267
- reinterpret_helpers.each do |helper|
278
+ def emit_per_type_helpers(lines)
279
+ collect_reinterpret_helpers.each do |helper|
268
280
  lines.concat(emit_reinterpret_helper(helper))
269
281
  lines << ""
270
282
  end
271
283
 
272
- checked_array_index_types = collect_checked_array_index_types
273
- checked_array_index_types.each do |type|
284
+ collect_checked_array_index_types.each do |type|
274
285
  lines.concat(emit_checked_array_index_helper(type))
275
286
  lines << ""
276
287
  end
277
288
 
278
- checked_span_index_types = collect_checked_span_index_types
279
- checked_span_index_types.each do |type|
289
+ collect_checked_span_index_types.each do |type|
280
290
  lines.concat(emit_checked_span_index_helper(type))
281
291
  lines << ""
282
292
  end
283
293
 
284
- nullable_array_index_types = collect_checked_array_index_types(nullable_only: true)
285
- nullable_array_index_types.each do |type|
294
+ collect_checked_array_index_types(nullable_only: true).each do |type|
286
295
  lines.concat(emit_nullable_array_index_helper(type))
287
296
  lines << ""
288
297
  end
289
298
 
290
- nullable_span_index_types = collect_checked_span_index_types(nullable_only: true)
291
- nullable_span_index_types.each do |type|
299
+ collect_checked_span_index_types(nullable_only: true).each do |type|
292
300
  lines.concat(emit_nullable_span_index_helper(type))
293
301
  lines << ""
294
302
  end
303
+ end
295
304
 
305
+ def emit_string_literal_constants_section(lines)
296
306
  str_literals = collect_str_literals
297
- unless str_literals.empty?
298
- @str_literal_map = {}
299
- str_literals.each_with_index { |value, i| @str_literal_map[value] = str_literal_name(i) }
300
- lines.concat(emit_str_literal_constants(str_literals))
301
- lines << ""
302
- end
307
+ return if str_literals.empty?
308
+
309
+ @str_literal_map = {}
310
+ str_literals.each_with_index { |value, i| @str_literal_map[value] = str_literal_name(i) }
311
+ lines.concat(emit_str_literal_constants(str_literals))
312
+ lines << ""
313
+ end
303
314
 
315
+ def emit_function_definitions(lines)
304
316
  emitted_functions.each do |function|
305
317
  lines.concat(emit_function(function))
306
318
  lines << ""
307
319
  end
308
-
309
- lines.join("\n").rstrip + "\n"
310
320
  end
311
321
  end
312
322
  end
@@ -252,75 +252,7 @@ module MilkTea
252
252
  resolve_member_access: ->(ma_expr) {
253
253
  @checker.evaluate_compile_time_const_value(ma_expr, scopes:)
254
254
  },
255
- resolve_call: ->(call_expr) {
256
- if call_expr.callee.is_a?(AST::Identifier)
257
- func = @checker.top_level_function(call_expr.callee.name)
258
- if func&.ast&.respond_to?(:const) && func.ast.const
259
- begin
260
- initial_vars = {}
261
- func.ast.params.each_with_index do |param, idx|
262
- return nil if idx >= call_expr.arguments.length
263
-
264
- arg_expr = call_expr.arguments[idx].value
265
- arg_value = case arg_expr
266
- when AST::Identifier
267
- @variables[arg_expr.name] || @checker.evaluate_compile_time_const_value(arg_expr, scopes:)
268
- else
269
- CompileTime.evaluate(
270
- arg_expr,
271
- resolve_identifier: ->(id) { @variables[id.name] || @checker.evaluate_compile_time_const_value(id, scopes:) },
272
- resolve_member_access: ->(ma) { @checker.evaluate_compile_time_const_value(ma, scopes:) },
273
- resolve_type_ref: nil,
274
- resolve_call: nil,
275
- )
276
- end
277
- return nil unless arg_value
278
-
279
- initial_vars[param.name] = arg_value
280
- end
281
- ctx = CompileTime::BlockContext.new(@checker, initial_variables: initial_vars)
282
- next ctx.evaluate_block(func.ast.body, scopes:)
283
- rescue CompileTime::ReturnValue => e
284
- next e.value
285
- end
286
- end
287
- end
288
-
289
- types = if @checker.respond_to?(:types)
290
- @checker.types
291
- else
292
- @checker.instance_variable_get(:@ctx).types
293
- end
294
- callee_name = if call_expr.callee.is_a?(AST::Specialization) && call_expr.callee.callee.respond_to?(:name)
295
- call_expr.callee.callee.name
296
- elsif call_expr.callee.respond_to?(:name)
297
- call_expr.callee.name
298
- end
299
- if callee_name && (type = types[callee_name]) && type.is_a?(Types::Struct)
300
- fields = {}
301
- call_expr.arguments.each do |argument|
302
- val = evaluate_expression(argument.value, scopes:)
303
- return nil unless val
304
- fields[argument.name] = val
305
- end
306
- next fields
307
- end
308
-
309
- if call_expr.callee.is_a?(AST::Specialization) && @checker.respond_to?(:resolve_type_expression)
310
- resolved = @checker.resolve_type_expression(call_expr.callee)
311
- if resolved && @checker.respond_to?(:array_type?) && @checker.array_type?(resolved)
312
- values = []
313
- call_expr.arguments.each do |argument|
314
- val = evaluate_expression(argument.value, scopes:)
315
- return nil unless val
316
- values << val
317
- end
318
- next values
319
- end
320
- end
321
-
322
- @checker.evaluate_compile_time_const_value(call_expr, scopes:)
323
- },
255
+ resolve_call: ->(call_expr) { resolve_compile_time_call(call_expr, scopes:) },
324
256
  )
325
257
  end
326
258
  end
@@ -435,13 +367,108 @@ module MilkTea
435
367
 
436
368
  nil
437
369
  end
370
+
371
+ def resolve_compile_time_call(call_expr, scopes:)
372
+ result = try_const_function_call(call_expr, scopes:)
373
+ return result if result
374
+
375
+ result = try_struct_constructor_call(call_expr, scopes:)
376
+ return result if result
377
+
378
+ result = try_array_constructor_call(call_expr, scopes:)
379
+ return result if result
380
+
381
+ @checker.evaluate_compile_time_const_value(call_expr, scopes:)
382
+ end
383
+
384
+ def try_const_function_call(call_expr, scopes:)
385
+ return unless call_expr.callee.is_a?(AST::Identifier)
386
+
387
+ func = @checker.top_level_function(call_expr.callee.name)
388
+ return unless func&.ast&.respond_to?(:const) && func.ast.const
389
+
390
+ begin
391
+ initial_vars = {}
392
+ func.ast.params.each_with_index do |param, idx|
393
+ return nil if idx >= call_expr.arguments.length
394
+
395
+ arg_expr = call_expr.arguments[idx].value
396
+ arg_value = case arg_expr
397
+ when AST::Identifier
398
+ @variables[arg_expr.name] || @checker.evaluate_compile_time_const_value(arg_expr, scopes:)
399
+ else
400
+ CompileTime.evaluate(
401
+ arg_expr,
402
+ resolve_identifier: ->(id) { @variables[id.name] || @checker.evaluate_compile_time_const_value(id, scopes:) },
403
+ resolve_member_access: ->(ma) { @checker.evaluate_compile_time_const_value(ma, scopes:) },
404
+ resolve_type_ref: nil,
405
+ resolve_call: nil,
406
+ )
407
+ end
408
+ return nil unless arg_value
409
+
410
+ initial_vars[param.name] = arg_value
411
+ end
412
+ ctx = BlockContext.new(@checker, initial_variables: initial_vars)
413
+ ctx.evaluate_block(func.ast.body, scopes:)
414
+ rescue ReturnValue => e
415
+ e.value
416
+ end
417
+ end
418
+
419
+ def try_struct_constructor_call(call_expr, scopes:)
420
+ types = if @checker.respond_to?(:types)
421
+ @checker.types
422
+ else
423
+ @checker.instance_variable_get(:@ctx).types
424
+ end
425
+ callee_name = if call_expr.callee.is_a?(AST::Specialization) && call_expr.callee.callee.respond_to?(:name)
426
+ call_expr.callee.callee.name
427
+ elsif call_expr.callee.respond_to?(:name)
428
+ call_expr.callee.name
429
+ end
430
+ return unless callee_name
431
+
432
+ type = types[callee_name]
433
+ return unless type.is_a?(Types::Struct)
434
+
435
+ fields = {}
436
+ call_expr.arguments.each do |argument|
437
+ val = evaluate_expression(argument.value, scopes:)
438
+ return nil unless val
439
+ fields[argument.name] = val
440
+ end
441
+ fields
442
+ end
443
+
444
+ def try_array_constructor_call(call_expr, scopes:)
445
+ return unless call_expr.callee.is_a?(AST::Specialization)
446
+ return unless @checker.respond_to?(:resolve_type_expression)
447
+
448
+ resolved = @checker.resolve_type_expression(call_expr.callee)
449
+ return unless resolved && @checker.respond_to?(:array_type?) && @checker.array_type?(resolved)
450
+
451
+ values = []
452
+ call_expr.arguments.each do |argument|
453
+ val = evaluate_expression(argument.value, scopes:)
454
+ return nil unless val
455
+ values << val
456
+ end
457
+ values
458
+ end
438
459
  end
439
460
 
440
461
  class Evaluator < ConstEval::Evaluator
441
462
 
442
463
  def resolve_layout_type(type_ref)
443
- super
444
- rescue SemanticError
464
+ result = begin
465
+ super
466
+ rescue SemanticError
467
+ nil
468
+ end
469
+ return result if result
470
+ return result if result
471
+
445
472
  return unless type_ref.respond_to?(:name) && type_ref.name.parts.length >= 1
446
473
 
447
474
  expression = ::MilkTea::AST.build_chain_from_parts(type_ref.name.parts)
@@ -455,7 +482,6 @@ module MilkTea
455
482
  nil
456
483
  end
457
484
 
458
-
459
485
  end
460
486
 
461
487
  def self.evaluate(expression, resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)