mt-lang 0.3.10 → 0.3.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0eb8fe30acd589069404d9a88cba70713a36937acf80299123b7a9b5a909b5da
4
- data.tar.gz: 3f7a0240fcfc10f0617e94fdb6d28abe40c1ffbc6bfaa12e87235f4440ffaef6
3
+ metadata.gz: efa0075ce73ffd0c92161f778399c599c6443e4375194a8bfeda883b3c29ea09
4
+ data.tar.gz: 978ab66cd06f4261edb72629f528c020890250ed7b57bbd75bee8cbe01e7e6a1
5
5
  SHA512:
6
- metadata.gz: f9623980449010f1a2895f715153948845edb191cb0164b9e48b615527d6d2aa0809abae016c07fa85197628e2baf190ca08adc2c14b31934b22465b9ca01f45
7
- data.tar.gz: 543375cd1021947da13d214f8aacf379d565a6e840564dc9e9233bd7673200d967318c1ef7ca209000182c78fa98c141c2ceddcd9ca1c91d5b221d0caac9d03b
6
+ metadata.gz: b0516d11fd07ed4c2db9bfaa4d59735821cfc3245aca280118f87593e7fa1fb2fec3be0c8208efc87b91c4cd79215e3a593602b43e1d9811572fcdcced93c280
7
+ data.tar.gz: 1a27eb0e66b9b15330ae28273b59ddfa430a6e7439811c2ca196b685cb6e8379b56016bb3a6eed60b347582fd013d8ba29f0c7024fbec0c13b67592aff3e0eba
data/README.md CHANGED
@@ -30,6 +30,7 @@ Package manifests, build workflow, and run workflow are documented separately in
30
30
  - External files are the dedicated raw ABI surface, usually for generated or low-level `std.c.*` bindings.
31
31
  - Module lookup resolves `a.b.c` to `a/b/c.mt`.
32
32
  - Inside a package, the file path relative to `package.source_root` defines the module name; platform-specific files such as `name.linux.mt` still map to module `name`.
33
+ - Circular module imports are supported via forward-declaration bindings and two-pass checking. Cycle members see each other's type declarations in the first pass and full type information in the second pass.
33
34
  - In ordinary files, `import` statements appear only at the top.
34
35
  - In external files, leading `import` statements are allowed after `external`.
35
36
  - Only external files accept `include`, `link`, and `compiler_flag` directives.
@@ -314,6 +315,7 @@ Rules:
314
315
  - Compile-time reflection over validated attributes uses `has_attribute`, `attribute_of`, `attribute_arg[T]`, `field_of`, and `callable_of`.
315
316
  - `field_of(...)`, `callable_of(...)`, and `attribute_of(...)` produce compile-time handle values with source-visible handle types `field_handle`, `callable_handle`, and `attribute_handle`.
316
317
  - The current C backend lowers `packed` / `align(...)` attributes with GNU-style `__attribute__((...))`, so these layout controls currently require a Clang/GCC-family compiler. On Windows that means Clang or GCC-family toolchains such as MinGW; `cl.exe` is not a supported backend for these attributes today. On wasm/browser targets the same feature works through Emscripten `emcc`, which is Clang-based.
318
+ - Keywords and reserved words are accepted as variant arm names, struct/union field names, enum/flags member names, lifetime parameters (`@return`), type parameters (`Box[return]`), and named constructor arguments (`Meta(return = 1)`). Primitive type names (`int`, `str`, `ref`, etc.) remain reserved and cannot be used in these positions.
317
319
 
318
320
  Enum and flags values support the full set of comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`) against values of the same enum type and against their backing integer type. Comparisons use the underlying integer backing values. Flags also support bitwise operators (`|`, `&`, `^`, `~`).
319
321
 
@@ -490,7 +490,7 @@ Milk Tea has first-class compiler support for multithreading. The threading mode
490
490
  parallel for i in 0..entity_count:
491
491
  positions[i] += velocities[i] * dt
492
492
 
493
- # Structured fork-join: each do block runs on a separate thread
493
+ # Structured fork-join: each statement runs on a separate thread
494
494
  parallel:
495
495
  textures = load_textures(path)
496
496
  sounds = load_sounds(path)
@@ -501,7 +501,6 @@ Design choices:
501
501
  - **Structured, not fire-and-forget.** All `parallel for` and `parallel:` blocks are synchronous barriers — the calling thread blocks until all work completes. This guarantees that captured local variables remain alive for the duration and eliminates lifetime concerns without ownership annotations.
502
502
  - **Compile-time safety.** `ref[T]` captures are rejected because mutable aliases across thread boundaries create data races. The `parallel:` block enforces single-writer-or-multiple-readers: if one statement writes a variable, no other block may read or write it.
503
503
  - **Value capture, pointer-based arrays.** Scalars and spans are captured by value (the span's data pointer still references the original storage). Arrays are captured as pointers to their first element, so writes in the worker affect the original array.
504
- - **`do` is a keyword.** It is recognized inside `parallel:` blocks to introduce each concurrent unit of work.
505
504
  - **Real OS threads via libuv.** Thread dispatch uses `uv_thread_create` / `uv_thread_join`, consistent with `std.thread` and `std.sync`. CPU count is detected at runtime via `uv_cpu_info`. The first chunk runs on the calling thread to avoid unnecessary dispatch when the workload is small.
506
505
  - **No forced dependency.** The build system automatically detects `parallel for` and `parallel:` usage via a sema-level flag and links libuv only when needed.
507
506
 
@@ -51,6 +51,7 @@ Rules:
51
51
  - Valid platform filename suffixes are `linux`, `windows`, and `wasm`.
52
52
  - The platform suffix is not part of the module name. `import a.b.c` stays the same on every target.
53
53
  - Milk Tea does not have a source-level conditional compilation syntax such as `#if`, `#ifdef`, or per-declaration platform attributes.
54
+ - Circular module imports are supported. When two modules import each other, the compiler uses forward-declaration bindings for the first pass and full type-checked bindings for the second pass, enabling cross-module type references and constructors in cycle groups.
54
55
 
55
56
  ## 2. Lexical Rules
56
57
 
@@ -360,6 +361,17 @@ Compile-time reflection over validated attributes uses `has_attribute`, `attribu
360
361
 
361
362
  The current C backend lowers `packed` / `align(...)` attributes with GNU-style `__attribute__((...))`, so these layout controls currently require a Clang/GCC-family compiler. On Windows that means Clang or GCC-family toolchains such as MinGW; `cl.exe` is not a supported backend for these attributes today. On wasm/browser targets the same feature works through Emscripten `emcc`, which is Clang-based.
362
363
 
364
+ Language-level keywords and reserved words are accepted as:
365
+ - variant arm names (`return(val: int)`, `if(arg: bool)`)
366
+ - struct and union field names (`return: int`, `let: str`)
367
+ - enum and flags member names (`return = 1`, `if = 6`)
368
+ - variant arm payload field names (`execute(return: int)`)
369
+ - lifetime parameter names (`struct Buf[@return]`)
370
+ - type parameter names (`struct Box[return]`, `identity[type]`)
371
+ - named arguments in struct/variant literals (`Meta(return = 1)`)
372
+
373
+ Primitive type names (`int`, `str`, `bool`, `ref`, `ptr`, `span`, `type`, etc.) remain reserved and cannot be used as names.
374
+
363
375
  ### 3.4a Enum and flags operators
364
376
 
365
377
  Enum and flags values support the full set of comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`) against values of the same enum type and against their backing integer type. Comparisons use the underlying integer backing values.
@@ -746,7 +758,6 @@ parallel:
746
758
  Rules:
747
759
 
748
760
  - A `parallel:` block must contain at least two statements.
749
- - `do` is a contextual keyword — only recognized inside `parallel:` blocks, not reserved globally.
750
761
  - Each statement must not contain `break`, `continue`, `return`, or `defer`.
751
762
  - The compiler enforces single-writer-or-multiple-readers: if a variable is written in one statement, no other block may access it.
752
763
  - Captured `ref[T]` values are rejected at compile time.
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.10"
6
+ VERSION = "0.3.11"
7
7
 
8
8
  def self.root
9
9
  @root ||= Pathname.new(File.expand_path("../..", __dir__))
@@ -153,17 +153,17 @@ module MilkTea
153
153
  VariantArm = Data.define(:name, :fields, :line, :column) do
154
154
  def initialize(name:, fields:, line: nil, column: nil) = super
155
155
  end
156
- MatchArm = Data.define(:pattern, :binding_name, :binding_line, :binding_column, :body) do
157
- def initialize(pattern:, binding_name:, body:, binding_line: nil, binding_column: nil) = super
156
+ MatchArm = Data.define(:pattern, :binding_name, :binding_line, :binding_column, :body, :line, :column) do
157
+ def initialize(pattern:, binding_name:, body:, binding_line: nil, binding_column: nil, line: nil, column: nil) = super
158
158
  end
159
159
  MatchStmt = Data.define(:expression, :arms, :inline, :line, :column, :length) do
160
160
  def initialize(expression:, arms:, inline: false, line: nil, column: nil, length: nil) = super
161
161
  end
162
- MatchExprArm = Data.define(:pattern, :binding_name, :binding_line, :binding_column, :value) do
163
- def initialize(pattern:, binding_name:, value:, binding_line: nil, binding_column: nil) = super
162
+ MatchExprArm = Data.define(:pattern, :binding_name, :binding_line, :binding_column, :value, :line, :column) do
163
+ def initialize(pattern:, binding_name:, value:, binding_line: nil, binding_column: nil, line: nil, column: nil) = super
164
164
  end
165
- WhenBranch = Data.define(:pattern, :binding_name, :binding_line, :binding_column, :body) do
166
- def initialize(pattern:, binding_name:, body:, binding_line: nil, binding_column: nil) = super
165
+ WhenBranch = Data.define(:pattern, :binding_name, :binding_line, :binding_column, :body, :line, :column) do
166
+ def initialize(pattern:, binding_name:, body:, binding_line: nil, binding_column: nil, line: nil, column: nil) = super
167
167
  end
168
168
  WhenStmt = Data.define(:discriminant, :branches, :else_body, :line, :column, :length) do
169
169
  def initialize(discriminant:, branches:, else_body:, line: nil, column: nil, length: nil) = super
@@ -93,7 +93,7 @@ module MilkTea
93
93
  arms = statement.arms.map do |arm|
94
94
  arm_env = duplicate_env(env)
95
95
  bind_async_variant_match_arm_env!(arm_env, scrutinee_type, arm)
96
- AST::MatchArm.new(pattern: arm.pattern, binding_name: arm.binding_name, body: normalize_async_statements(arm.body, counter, arm_env, return_type:))
96
+ AST::MatchArm.new(pattern: arm.pattern, binding_name: arm.binding_name, body: normalize_async_statements(arm.body, counter, arm_env, return_type:), line: arm.line, column: arm.column)
97
97
  end
98
98
  expr_setup + [AST::MatchStmt.new(expression:, arms:)]
99
99
  when AST::WhileStmt
@@ -307,6 +307,8 @@ module MilkTea
307
307
  binding_line: arm.binding_line,
308
308
  binding_column: arm.binding_column,
309
309
  value: normalized_value,
310
+ line: arm.line,
311
+ column: arm.column,
310
312
  )]
311
313
  end
312
314
 
@@ -326,6 +328,8 @@ module MilkTea
326
328
  binding_line: arm.binding_line,
327
329
  binding_column: arm.binding_column,
328
330
  body: pattern_setup + value_setup + [AST::Assignment.new(target: AST::Identifier.new(name: temp_name), operator: "=", value: arm.value)],
331
+ line: arm.line,
332
+ column: arm.column,
329
333
  )
330
334
  end,
331
335
  line: expression.line,
@@ -372,10 +372,10 @@ module MilkTea
372
372
  break if check(:rbracket)
373
373
 
374
374
  if match(:at)
375
- name_token = consume_name("expected lifetime name after @")
375
+ name_token = consume_name_allowing_keywords("expected lifetime name after @")
376
376
  lifetime_params << "@#{name_token.lexeme}"
377
377
  else
378
- name_token = consume_name("expected type parameter name")
378
+ name_token = consume_name_allowing_keywords("expected type parameter name")
379
379
  if match(:colon)
380
380
  value_type = parse_type_ref
381
381
  type_params << AST::ValueTypeParam.new(
@@ -419,7 +419,7 @@ module MilkTea
419
419
 
420
420
  raise error(visibility_token, "public is only allowed on struct events") if visibility == :public
421
421
 
422
- field_token = consume_name("expected field name")
422
+ field_token = consume_name_allowing_keywords("expected field name")
423
423
  field_name = field_token.lexeme
424
424
  consume(:colon, "expected ':' after field name")
425
425
  field_type = parse_type_ref
@@ -440,7 +440,7 @@ module MilkTea
440
440
  name = name_token.lexeme
441
441
  c_name = parse_optional_explicit_c_name
442
442
  fields = parse_named_block do
443
- field_name = consume_name("expected field name").lexeme
443
+ field_name = consume_name_allowing_keywords("expected field name").lexeme
444
444
  consume(:colon, "expected ':' after field name")
445
445
  field_type = parse_type_ref
446
446
  consume_end_of_statement
@@ -471,7 +471,7 @@ module MilkTea
471
471
  members = []
472
472
  skip_newlines
473
473
  until check(:dedent) || eof?
474
- member_token = consume_name("expected member name")
474
+ member_token = consume_name_allowing_keywords("expected member name")
475
475
  member_name = member_token.lexeme
476
476
  if match(:equal)
477
477
  value = parse_expression
@@ -493,10 +493,10 @@ module MilkTea
493
493
  name = name_token.lexeme
494
494
  type_params = parse_declaration_type_params
495
495
  arms = parse_named_block do
496
- arm_name = consume_name("expected variant arm name").lexeme
496
+ arm_name = consume_name_allowing_keywords("expected variant arm name").lexeme
497
497
  fields = if match(:lparen)
498
498
  parsed = parse_comma_separated_until(:rparen) do
499
- field_name = consume_name("expected field name").lexeme
499
+ field_name = consume_name_allowing_keywords("expected field name").lexeme
500
500
  consume(:colon, "expected ':' after field name")
501
501
  field_type = parse_type_ref
502
502
  AST::Field.new(name: field_name, type: field_type)
@@ -105,6 +105,8 @@ module MilkTea
105
105
  binding_line: binding_token&.line,
106
106
  binding_column: binding_token&.column,
107
107
  value:,
108
+ line: pattern.line,
109
+ column: pattern.column,
108
110
  )
109
111
  end
110
112
  end
@@ -153,6 +155,8 @@ module MilkTea
153
155
  binding_line: nil,
154
156
  binding_column: nil,
155
157
  value: AST::BooleanLiteral.new(value: true),
158
+ line: arm_pattern.line,
159
+ column: arm_pattern.column,
156
160
  ),
157
161
  AST::MatchExprArm.new(
158
162
  pattern: AST::Identifier.new(name: "_", line:, column:),
@@ -160,6 +164,8 @@ module MilkTea
160
164
  binding_line: nil,
161
165
  binding_column: nil,
162
166
  value: AST::BooleanLiteral.new(value: false),
167
+ line:,
168
+ column:,
163
169
  ),
164
170
  ],
165
171
  line:,
@@ -338,7 +344,7 @@ module MilkTea
338
344
  end
339
345
 
340
346
  def parse_call_argument
341
- if check_name && check_next(:equal)
347
+ if (check_name || keyword_token?(peek)) && check_next(:equal)
342
348
  name = advance.lexeme
343
349
  consume(:equal, "expected '=' after named argument name")
344
350
  AST::Argument.new(name:, value: parse_expression)
@@ -351,6 +351,8 @@ module MilkTea
351
351
  binding_line: binding_token&.line,
352
352
  binding_column: binding_token&.column,
353
353
  value:,
354
+ line: pattern.line,
355
+ column: pattern.column,
354
356
  )
355
357
  end
356
358
  else
@@ -362,6 +364,8 @@ module MilkTea
362
364
  binding_line: binding_token&.line,
363
365
  binding_column: binding_token&.column,
364
366
  body:,
367
+ line: pattern.line,
368
+ column: pattern.column,
365
369
  )
366
370
  end
367
371
  end
@@ -376,6 +380,8 @@ module MilkTea
376
380
  binding_line: binding_token&.line,
377
381
  binding_column: binding_token&.column,
378
382
  body: recovered_body,
383
+ line: patterns.first&.line,
384
+ column: patterns.first&.column,
379
385
  )] if recovered_body
380
386
 
381
387
  raise
@@ -615,6 +621,8 @@ module MilkTea
615
621
  binding_line: binding_token.line,
616
622
  binding_column: binding_token.column,
617
623
  body:,
624
+ line: pattern.line,
625
+ column: pattern.column,
618
626
  )
619
627
  skip_newlines
620
628
  end
@@ -92,7 +92,7 @@ module MilkTea
92
92
 
93
93
  first_token = peek
94
94
  if match(:at)
95
- lt_token = consume_name("expected lifetime name after @")
95
+ lt_token = consume_name_allowing_keywords("expected lifetime name after @")
96
96
  return AST::TypeRef.new(name: AST::QualifiedName.new(parts: ["@#{lt_token.lexeme}"]), arguments: [], nullable: false, lifetime: nil, line: first_token.line, column: first_token.column, length: lt_token.lexeme.length + 1)
97
97
  end
98
98
  name = parse_qualified_name
@@ -101,7 +101,7 @@ module MilkTea
101
101
  if match(:lbracket)
102
102
  if check(:at) && name.to_s == "ref"
103
103
  match(:at)
104
- lt_token = consume_name("expected lifetime name after @")
104
+ lt_token = consume_name_allowing_keywords("expected lifetime name after @")
105
105
  lifetime = "@#{lt_token.lexeme}"
106
106
  consume(:comma, "expected ',' after lifetime in type arguments")
107
107
  end
@@ -167,7 +167,7 @@ module MilkTea
167
167
  end
168
168
 
169
169
  def parse_function_type_param
170
- name_token = consume_name("expected function type parameter name")
170
+ name_token = consume_name_allowing_keywords("expected function type parameter name")
171
171
  name = name_token.lexeme
172
172
  consume(:colon, "expected ':' after function type parameter name")
173
173
  type = parse_type_ref
@@ -190,7 +190,7 @@ module MilkTea
190
190
  return [] unless match(:lbracket)
191
191
 
192
192
  params = parse_comma_separated_until(:rbracket) do
193
- name_token = consume_name("expected type parameter name")
193
+ name_token = consume_name_allowing_keywords("expected type parameter name")
194
194
  name = name_token.lexeme
195
195
  if match(:colon)
196
196
  value_type = parse_type_ref
@@ -208,7 +208,7 @@ module MilkTea
208
208
  def resolve_type_param_constraints(type_params)
209
209
  type_params.each_with_object({}) do |type_param, constraints|
210
210
  if type_param.is_a?(AST::ValueTypeParam)
211
- ensure_non_reserved_type_binding_name!(
211
+ ensure_non_reserved_value_type_name!(
212
212
  type_param.name,
213
213
  kind_label: "type parameter",
214
214
  line: type_param.line,
@@ -218,7 +218,7 @@ module MilkTea
218
218
  next
219
219
  end
220
220
 
221
- ensure_non_reserved_type_binding_name!(
221
+ ensure_non_reserved_value_type_name!(
222
222
  type_param.name,
223
223
  kind_label: "type parameter",
224
224
  line: type_param.line,
@@ -482,7 +482,7 @@ module MilkTea
482
482
  raise_sema_error("duplicate field #{decl.name}.#{field.name}") if fields.key?(field.name)
483
483
  raise_sema_error("duplicate member #{decl.name}.#{field.name}") if events.key?(field.name)
484
484
  unless raw_module?
485
- ensure_non_reserved_type_binding_name!(
485
+ ensure_non_reserved_value_type_name!(
486
486
  field.name,
487
487
  kind_label: "field #{decl.name}",
488
488
  line: field.line || decl.line,
@@ -576,7 +576,7 @@ module MilkTea
576
576
  decl.members.each do |member|
577
577
  raise_sema_error("duplicate member #{decl.name}.#{member.name}") if member_names.include?(member.name)
578
578
  unless raw_module?
579
- ensure_non_reserved_type_binding_name!(
579
+ ensure_non_reserved_value_type_name!(
580
580
  member.name,
581
581
  kind_label: "member #{decl.name}",
582
582
  line: member.line || decl.line,
@@ -645,7 +645,7 @@ module MilkTea
645
645
  begin
646
646
  raise_sema_error("duplicate arm #{decl.name}.#{arm.name}") if seen_arms.include?(arm.name)
647
647
  unless raw_module?
648
- ensure_non_reserved_type_binding_name!(
648
+ ensure_non_reserved_value_type_name!(
649
649
  arm.name,
650
650
  kind_label: "arm #{decl.name}",
651
651
  line: arm.line || decl.line,
@@ -661,7 +661,7 @@ module MilkTea
661
661
  begin
662
662
  raise_sema_error("duplicate field #{arm.name}.#{field.name}") if seen_fields.include?(field.name)
663
663
  unless raw_module?
664
- ensure_non_reserved_type_binding_name!(
664
+ ensure_non_reserved_value_type_name!(
665
665
  field.name,
666
666
  kind_label: "field #{decl.name}.#{arm.name}",
667
667
  line: field.line || decl.line,
@@ -275,6 +275,12 @@ module MilkTea
275
275
  end
276
276
 
277
277
  if KEYWORD_TOKEN_TYPES.include?(tok.type)
278
+ return [:typeParameter, []] if keyword_lifetime_or_type_param?(tokens, index)
279
+ return [:type, []] if keyword_type_annotation?(tokens, index)
280
+ return [:enumMember, [:declaration]] if variant_enum_member_declaration?(tokens, index)
281
+ return [:property, [:declaration]] if keyword_field_declaration_token?(tokens, index)
282
+ return [:property, []] if keyword_member_access?(tokens, index)
283
+ return [:parameter, []] if keyword_named_argument_token?(tokens, index)
278
284
  return [:keyword, []]
279
285
  end
280
286
 
@@ -550,6 +556,64 @@ module MilkTea
550
556
  next_tok&.type == :colon
551
557
  end
552
558
 
559
+ def keyword_field_declaration_token?(tokens, index)
560
+ return false if match_arm_binding_token?(tokens, index)
561
+ return false if destructure_let_binding?(tokens, index)
562
+
563
+ next_tok = next_non_trivia_token(tokens, index + 1)
564
+ next_tok&.type == :colon
565
+ end
566
+
567
+ def keyword_member_access?(tokens, index)
568
+ prev_index = previous_non_trivia_token_index(tokens, index)
569
+ return false unless prev_index
570
+
571
+ tokens[prev_index].type == :dot
572
+ end
573
+
574
+ def keyword_lifetime_or_type_param?(tokens, index)
575
+ prev_index = previous_non_trivia_token_index(tokens, index)
576
+ return false unless prev_index
577
+
578
+ prev_type = tokens[prev_index].type
579
+ return true if prev_type == :at
580
+ return true if prev_type == :lbracket
581
+ return true if prev_type == :comma && inside_type_params?(tokens, prev_index)
582
+ false
583
+ end
584
+
585
+ def inside_type_params?(tokens, comma_index)
586
+ i = comma_index - 1
587
+ while i >= 0
588
+ t = tokens[i]
589
+ break if t.type == :lbracket
590
+ return false if t.type == :newline || t.type == :rbracket || t.type == :lparen
591
+ i -= 1
592
+ end
593
+ return false if i < 0
594
+
595
+ prev = previous_non_trivia_token_index(tokens, i)
596
+ return true if prev && %i[struct variant enum flags function fn proc].include?(tokens[prev].type)
597
+ return true if prev && tokens[prev].type == :rbracket
598
+ return true if prev && tokens[prev].type == :identifier
599
+
600
+ false
601
+ end
602
+
603
+ def keyword_named_argument_token?(tokens, index)
604
+ next_tok = next_non_trivia_token(tokens, index + 1)
605
+ next_tok&.type == :equal
606
+ end
607
+
608
+ def keyword_type_annotation?(tokens, index)
609
+ tok = tokens[index]
610
+ prev_index = previous_non_trivia_token_index(tokens, index)
611
+ return false unless prev_index
612
+ return false unless %i[colon arrow].include?(tokens[prev_index].type)
613
+
614
+ tokens[prev_index].line == tok.line
615
+ end
616
+
553
617
  def destructure_let_binding?(tokens, index)
554
618
  tok = tokens[index]
555
619
  return false unless tok&.type == :identifier
@@ -1611,6 +1611,7 @@ module MilkTea
1611
1611
  input_path = nil
1612
1612
  theme_path = nil
1613
1613
  output_path = nil
1614
+ textmate_only = false
1614
1615
 
1615
1616
  until @argv.empty?
1616
1617
  arg = @argv.first
@@ -1629,6 +1630,9 @@ module MilkTea
1629
1630
  @err.puts("snapshot: missing value for --output")
1630
1631
  return 1
1631
1632
  end
1633
+ when "--textmate-only"
1634
+ @argv.shift
1635
+ textmate_only = true
1632
1636
  else
1633
1637
  if arg.start_with?("-")
1634
1638
  @err.puts("snapshot: unknown option #{arg}")
@@ -1674,10 +1678,12 @@ module MilkTea
1674
1678
  args.push("-o", output_path) if output_path
1675
1679
 
1676
1680
  semantic_result = nil
1677
- begin
1678
- semantic_result = MilkTea::LSP::Server.semantic_tokens_for_path(input_path)
1679
- rescue => e
1680
- @err.puts("snapshot: semantic analysis skipped: #{e.message}")
1681
+ unless textmate_only
1682
+ begin
1683
+ semantic_result = MilkTea::LSP::Server.semantic_tokens_for_path(input_path)
1684
+ rescue => e
1685
+ @err.puts("snapshot: semantic analysis skipped: #{e.message}")
1686
+ end
1681
1687
  end
1682
1688
 
1683
1689
  if semantic_result && semantic_result[:entries] && !semantic_result[:entries].empty?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mt-lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.3.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Long (Teefan) Tran
@@ -603,7 +603,7 @@ metadata:
603
603
  homepage_uri: https://teefan.github.io/mt-lang/
604
604
  source_code_uri: https://github.com/teefan/mt-lang
605
605
  post_install_message: |
606
- Milk Tea 0.3.10 installed!
606
+ Milk Tea 0.3.11 installed!
607
607
 
608
608
  System requirements:
609
609
  - A C compiler (gcc or clang) must be available on PATH