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
@@ -413,7 +413,8 @@ module MilkTea
413
413
  read_identifiers(expression.expression, names, reads_info)
414
414
  expression.arms.each do |arm|
415
415
  read_identifiers(arm.pattern, names, reads_info)
416
- read_identifiers(arm.value, names, reads_info)
416
+ arm_value = arm.is_a?(AST::MatchExprArm) ? arm.value : arm.body
417
+ read_identifiers(arm_value, names, reads_info)
417
418
  end
418
419
  when AST::MatchStmt
419
420
  read_identifiers(expression.expression, names, reads_info)
@@ -45,6 +45,13 @@ module MilkTea
45
45
  "with" => :simd_lane_with,
46
46
  }.freeze
47
47
 
48
+ SPECIALIZED_RECEIVERS = {
49
+ "str_buffer" => { predicate: :str_buffer_type?, kinds: STR_BUFFER_METHOD_KINDS },
50
+ "event" => { predicate: :event_type?, kinds: EVENT_METHOD_KINDS },
51
+ "atomic" => { predicate: :atomic_type?, kinds: ATOMIC_METHOD_KINDS },
52
+ "simd" => { predicate: :simd_type?, kinds: SIMD_METHOD_KINDS },
53
+ }.freeze
54
+
48
55
  def type_ref_from_specialization(expression)
49
56
  case expression.callee
50
57
  when AST::Identifier
@@ -279,43 +279,17 @@ module MilkTea
279
279
  break
280
280
  end
281
281
 
282
- if char == "c" && heredoc_start?(line, index, cstring: true)
283
- return lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: true)
284
- end
285
-
286
- if char == "c" && line[index + 1] == "<" && line[index + 2] == "-" && identifier_start?(line[index + 3])
287
- error = LexError.new("expected '<<-' for heredoc string; did you mean 'c<<-#{identifier_start_token(line, index + 3)}'?", line: line_number, column: index + 1, path: @path)
288
- if @recovery_errors
289
- @recovery_errors << error
290
- else
291
- raise error
282
+ if (char == "c" || char == "f")
283
+ result = dispatch_cf_prefix(char, line, index, line_number, line_offset, lines:, line_index:)
284
+ if result
285
+ if result[0] == :return
286
+ return result[1]
287
+ else
288
+ index = result[1]
289
+ next
290
+ end
292
291
  end
293
292
  end
294
- if char == "c" && line[index + 1] == '"'
295
- result = lex_string(lines, line_index, line, index, line_number, line_offset:, cstring: true)
296
- return result.consumed_lines if result.consumed_lines > 1
297
-
298
- index = result.next_index
299
- next
300
- end
301
-
302
- if char == "f" && heredoc_start?(line, index, format: true)
303
- return lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: false, format: true)
304
- end
305
-
306
- if char == "f" && line[index + 1] == "<" && line[index + 2] == "-" && identifier_start?(line[index + 3])
307
- error = LexError.new("expected '<<-' for heredoc string; did you mean 'f<<-#{identifier_start_token(line, index + 3)}'?", line: line_number, column: index + 1, path: @path)
308
- if @recovery_errors
309
- @recovery_errors << error
310
- else
311
- raise error
312
- end
313
- end
314
-
315
- if char == "f" && line[index + 1] == '"'
316
- index = lex_format_string(line, index, line_number, line_offset:)
317
- next
318
- end
319
293
 
320
294
  if char == "<" && heredoc_start?(line, index)
321
295
  return lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: false)
@@ -391,6 +365,43 @@ module MilkTea
391
365
  end
392
366
  end
393
367
 
368
+ def dispatch_cf_prefix(char, line, index, line_number, line_offset, lines:, line_index:)
369
+ return nil unless char == "c" || char == "f"
370
+
371
+ is_c = char == "c"
372
+ is_f = char == "f"
373
+
374
+ if heredoc_start?(line, index, cstring: is_c, format: is_f)
375
+ n = lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: is_c, format: is_f)
376
+ return [:return, n]
377
+ end
378
+
379
+ if line[index + 1] == "<" && line[index + 2] == "-" && identifier_start?(line[index + 3])
380
+ error = LexError.new("expected '<<-' for heredoc string; did you mean '#{char}<<-#{identifier_start_token(line, index + 3)}'?", line: line_number, column: index + 1, path: @path)
381
+ if @recovery_errors
382
+ @recovery_errors << error
383
+ else
384
+ raise error
385
+ end
386
+ return nil
387
+ end
388
+
389
+ if line[index + 1] == '"'
390
+ if is_c
391
+ string_result = lex_string(lines, line_index, line, index, line_number, line_offset:, cstring: true)
392
+ if string_result.consumed_lines > 1
393
+ return [:return, string_result.consumed_lines]
394
+ end
395
+ return [:next, string_result.next_index]
396
+ end
397
+
398
+ new_index = lex_format_string(line, index, line_number, line_offset:)
399
+ return [:next, new_index]
400
+ end
401
+
402
+ nil
403
+ end
404
+
394
405
  def token(type, lexeme, literal, line, column, start_offset:, end_offset:)
395
406
  Token.new(
396
407
  type:,
@@ -1,5 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "expressions"
4
+ require_relative "loops"
5
+ require_relative "proc"
6
+ require_relative "resolve"
7
+ require_relative "utils"
8
+ require_relative "foreign_cstr"
9
+ require_relative "declarations"
10
+ require_relative "calls"
11
+
3
12
  module MilkTea
4
13
  module LowererBlock
5
14
  def lower_block(statements, env:, active_defers:, return_type:, loop_flow:, allow_return: true)
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "dyn"
4
+
3
5
  module MilkTea
4
6
  module LowererCalls
5
7
  def lower_call(expression, env:, type:)
@@ -78,7 +78,7 @@ module MilkTea
78
78
  end
79
79
  IR::AggregateLiteral.new(type:, fields:)
80
80
  else
81
- IR::IntegerLiteral.new(value: 0, type:)
81
+ raise LoweringError.new("unsupported const value type #{const_value.class}", line: 0, column: 0, path: @ctx.current_analysis_path)
82
82
  end
83
83
  end
84
84
 
@@ -1,14 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "resolve"
4
+ require_relative "utils"
5
+ require_relative "block"
6
+ require_relative "async/normalization"
7
+ require_relative "async/lowering"
8
+
3
9
  module MilkTea
4
10
  module LowererFunctions
5
11
  def lower_functions
6
12
  lowered = []
13
+ cursor = 0
14
+ declarations = @ctx.ast.declarations
7
15
 
8
- changed = true
9
- while changed
10
- changed = false
11
-
16
+ while cursor < declarations.length
12
17
  expanded_declarations.each do |decl|
13
18
  case decl
14
19
  when AST::FunctionDef
@@ -21,7 +26,6 @@ module MilkTea
21
26
 
22
27
  lowered << lower_function_decl(instance)
23
28
  @artifacts.lowered_function_linkage_names[linkage_name] = true
24
- changed = true
25
29
  end
26
30
  else
27
31
  linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name)
@@ -37,7 +41,6 @@ module MilkTea
37
41
  @artifacts.lowered_function_linkage_names[entrypoint.linkage_name] = true
38
42
  end
39
43
  end
40
- changed = true
41
44
  end
42
45
  when AST::ExtendingBlock
43
46
  receiver_type = resolve_extending_receiver_type(@ctx.analysis, decl.type_name)
@@ -56,7 +59,6 @@ module MilkTea
56
59
 
57
60
  lowered << lower_function_decl(instance, receiver_type:)
58
61
  @artifacts.lowered_function_linkage_names[linkage_name] = true
59
- changed = true
60
62
  end
61
63
  else
62
64
  linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name, receiver_type:)
@@ -64,11 +66,12 @@ module MilkTea
64
66
 
65
67
  lowered << lower_function_decl(binding, receiver_type:)
66
68
  @artifacts.lowered_function_linkage_names[linkage_name] = true
67
- changed = true
68
69
  end
69
70
  end
70
71
  end
71
72
  end
73
+
74
+ cursor = declarations.length
72
75
  end
73
76
 
74
77
  lowered
@@ -1506,7 +1506,7 @@ module MilkTea
1506
1506
  case argument
1507
1507
  when AST::TypeRef
1508
1508
  resolve_type_argument_ref(argument, type_params:)
1509
- when AST::FunctionType, AST::ProcType
1509
+ when AST::FunctionType, AST::ProcType, AST::TupleType
1510
1510
  resolve_type_ref(argument, type_params:)
1511
1511
  when AST::IntegerLiteral, AST::FloatLiteral
1512
1512
  Types::LiteralTypeArg.new(argument.value)
@@ -1518,12 +1518,19 @@ module MilkTea
1518
1518
  def resolve_type_argument_ref(type_ref, type_params:)
1519
1519
  return resolve_type_ref(type_ref, type_params:) unless literal_type_argument_name_candidate?(type_ref)
1520
1520
 
1521
- resolve_type_ref(type_ref, type_params:)
1522
- rescue LoweringError => error
1521
+ result = try_resolve_type_ref(type_ref, type_params:)
1522
+ return result if result
1523
+
1523
1524
  literal_type_argument = resolve_named_literal_type_argument(type_ref)
1524
1525
  return literal_type_argument if literal_type_argument
1525
1526
 
1526
- raise error
1527
+ resolve_type_ref(type_ref, type_params:)
1528
+ end
1529
+
1530
+ def try_resolve_type_ref(type_ref, type_params:)
1531
+ resolve_type_ref(type_ref, type_params:)
1532
+ rescue LoweringError
1533
+ nil
1527
1534
  end
1528
1535
 
1529
1536
  def literal_type_argument_name_candidate?(type_ref)
@@ -1,26 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "functions"
4
+ require_relative "resolve"
5
+ require_relative "utils"
6
+
3
7
  module MilkTea
4
8
  module LowererScans
5
9
  def collect_structs
6
- @ctx.ast.declarations.each do |decl|
7
- case decl
8
- when AST::WhenStmt
9
- body = lower_when_chosen_body(decl)
10
- body&.each { |nested| collect_struct_from_decl(nested) }
11
- when AST::OpaqueDecl
12
- @ctx.opaque_types[decl.name] = @ctx.types.fetch(decl.name)
13
- when AST::StructDecl
14
- @ctx.struct_types[decl.name] = @ctx.types.fetch(decl.name)
15
- collect_nested_structs(decl)
16
- when AST::UnionDecl
17
- @ctx.union_types[decl.name] = @ctx.types.fetch(decl.name)
18
- end
19
- end
10
+ @ctx.ast.declarations.each { |decl| collect_one_struct_decl(decl) }
20
11
  end
21
12
 
22
- def collect_struct_from_decl(decl)
13
+ def collect_one_struct_decl(decl)
23
14
  case decl
15
+ when AST::WhenStmt
16
+ body = lower_when_chosen_body(decl)
17
+ body&.each { |nested| collect_one_struct_decl(nested) }
24
18
  when AST::OpaqueDecl
25
19
  @ctx.opaque_types[decl.name] = @ctx.types.fetch(decl.name)
26
20
  when AST::StructDecl
@@ -28,12 +22,13 @@ module MilkTea
28
22
  collect_nested_structs(decl)
29
23
  when AST::UnionDecl
30
24
  @ctx.union_types[decl.name] = @ctx.types.fetch(decl.name)
31
- when AST::WhenStmt
32
- body = lower_when_chosen_body(decl)
33
- body&.each { |nested| collect_struct_from_decl(nested) }
34
25
  end
35
26
  end
36
27
 
28
+ def collect_struct_from_decl(decl)
29
+ collect_one_struct_decl(decl)
30
+ end
31
+
37
32
  def lower_when_chosen_body(decl)
38
33
  val = compile_time_const_value(decl.discriminant)
39
34
  return nil if val.nil?
@@ -20,19 +20,24 @@ module MilkTea
20
20
  when AST::StructDecl, AST::UnionDecl, AST::VariantDecl, AST::EnumDecl, AST::FlagsDecl, AST::OpaqueDecl, AST::TypeAliasDecl
21
21
  type_declarations[declaration.name] = declaration
22
22
  target = exported_declaration?(analysis, declaration) ? types : private_types
23
- target[declaration.name] = analysis.types.fetch(declaration.name)
23
+ resolved_type = analysis.types[declaration.name]
24
+ target[declaration.name] = resolved_type if resolved_type
24
25
  when AST::InterfaceDecl
25
26
  target = exported_declaration?(analysis, declaration) ? interfaces : private_interfaces
26
- target[declaration.name] = analysis.interfaces.fetch(declaration.name)
27
+ resolved_iface = analysis.interfaces[declaration.name]
28
+ target[declaration.name] = resolved_iface if resolved_iface
27
29
  when AST::AttributeDecl
28
30
  target = exported_declaration?(analysis, declaration) ? attributes : private_attributes
29
- target[declaration.name] = analysis.attributes.fetch(declaration.name)
31
+ resolved_attr = analysis.attributes[declaration.name]
32
+ target[declaration.name] = resolved_attr if resolved_attr
30
33
  when AST::ConstDecl, AST::VarDecl, AST::EventDecl
31
34
  target = exported_declaration?(analysis, declaration) ? values : private_values
32
- target[declaration.name] = analysis.values.fetch(declaration.name)
35
+ resolved_val = analysis.values[declaration.name]
36
+ target[declaration.name] = resolved_val if resolved_val
33
37
  when AST::FunctionDef, AST::ExternFunctionDecl, AST::ForeignFunctionDecl
34
38
  target = exported_declaration?(analysis, declaration) ? functions : private_functions
35
- target[declaration.name] = analysis.functions.fetch(declaration.name)
39
+ resolved_func = analysis.functions[declaration.name]
40
+ target[declaration.name] = resolved_func if resolved_func
36
41
  end
37
42
  end
38
43
 
@@ -136,17 +141,16 @@ module MilkTea
136
141
  imported_interface_binding?(interface, analysis.imports)
137
142
  end
138
143
 
144
+ BUILTIN_EXPORTABLE_RECEIVER_TYPES = %w[
145
+ StringView Primitive Vector Matrix Quaternion SoA Simd Span Task Dyn
146
+ ].map { |n| "Types::#{n}" }.freeze
147
+
148
+ def builtin_exportable_receiver?(receiver_type)
149
+ BUILTIN_EXPORTABLE_RECEIVER_TYPES.any? { |name| receiver_type.class.to_s.end_with?(name.split("::").last) }
150
+ end
151
+
139
152
  def exported_method_receiver?(receiver_type, analysis, exported_types)
140
- return true if receiver_type.is_a?(Types::StringView)
141
- return true if receiver_type.is_a?(Types::Primitive)
142
- return true if receiver_type.is_a?(Types::Vector)
143
- return true if receiver_type.is_a?(Types::Matrix)
144
- return true if receiver_type.is_a?(Types::Quaternion)
145
- return true if receiver_type.is_a?(Types::SoA)
146
- return true if receiver_type.is_a?(Types::Simd)
147
- return true if receiver_type.is_a?(Types::Span)
148
- return true if receiver_type.is_a?(Types::Task)
149
- return true if receiver_type.is_a?(Types::Dyn)
153
+ return true if builtin_exportable_receiver?(receiver_type)
150
154
  return true if exported_types.value?(receiver_type)
151
155
  return true if imported_receiver_type?(receiver_type, analysis.imports)
152
156
  return exported_method_receiver?(receiver_type.base, analysis, exported_types) if receiver_type.is_a?(Types::Nullable)