mt-lang 0.2.17 → 0.2.18
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 +4 -4
- data/README.md +2 -2
- data/docs/index.html +5 -0
- data/docs/language-manual.md +8 -0
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +6 -5
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +137 -2
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +13 -1
- data/lib/milk_tea/lsp/server/hover.rb +6 -1
- data/lib/milk_tea/lsp/server/rename.rb +3 -1
- data/std/lru_cache.mt +75 -0
- data/std/ring_buffer.mt +131 -0
- data/std/sparse_set.mt +170 -0
- data/std/spatial.mt +46 -47
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 35157666294e3aadb1c8106b1ccbacdf0d548f06a009b99c2a7799e76436e320
|
|
4
|
+
data.tar.gz: acc6091f6f22e2bbe340ebba54f49dc0b195849294f6086959027751a6cbfee1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 831ed7f14aaef5be511434b7697f0f0d23896d78fd2cfd5ef6037fee9c9909dbce3cc6c51bd6d9b1c95dae2dbeb7990b1cece93f455990f3f7c4e911dc64e24a
|
|
7
|
+
data.tar.gz: 6621e043744173fe77a457a3823a6b38032b4f12a71f96f707539154578bf9b7c95d8e688d36ba7d44404148ed4f85a47b55a3a00d81fb13e466fa86e9bc1be7
|
data/README.md
CHANGED
|
@@ -855,7 +855,7 @@ Core modules in `std/`:
|
|
|
855
855
|
- `std.option.Option[T]` — optional value with `is_some`, `is_none`, `unwrap`, `expect`, `unwrap_or`, `unwrap_or_else` (auto-imported via prelude)
|
|
856
856
|
- `std.result.Result[T, E]` — fallible computation with `is_success`, `is_failure`, `unwrap`, `unwrap_error`, `unwrap_or`, `unwrap_or_else`, `ok`, `error`, `map_error` (auto-imported via prelude)
|
|
857
857
|
|
|
858
|
-
**Collections**: `std.vec.Vec[T]`, `std.deque.Deque[T]`, `std.map.Map[K,V]`, `std.set.Set[T]`, `std.ordered_map.OrderedMap[K,V]`, `std.ordered_set.OrderedSet[T]`, `std.binary_heap.BinaryHeap[T]`, `std.priority_queue.PriorityQueue[T]`, `std.linked_map.LinkedMap[K,V]`, `std.linked_set.LinkedSet[T]`, `std.counter.Counter[T]`, `std.multiset.MultiSet[T]`, `std.queue.Queue[T]`, `std.stack.Stack[T]`
|
|
858
|
+
**Collections**: `std.vec.Vec[T]`, `std.deque.Deque[T]`, `std.map.Map[K,V]`, `std.set.Set[T]`, `std.ordered_map.OrderedMap[K,V]`, `std.ordered_set.OrderedSet[T]`, `std.binary_heap.BinaryHeap[T]`, `std.priority_queue.PriorityQueue[T]`, `std.linked_map.LinkedMap[K,V]`, `std.linked_set.LinkedSet[T]`, `std.counter.Counter[T]`, `std.multiset.MultiSet[T]`, `std.queue.Queue[T]`, `std.stack.Stack[T]`, `std.bitset.Bitset`, `std.spatial.SpatialGrid[T]`, `std.ring_buffer.RingBuffer[T]`, `std.sparse_set.SparseSet[T]`, `std.lru_cache.LruCache[K,V]`
|
|
859
859
|
|
|
860
860
|
**Serialization**: `std.json`, `std.toml`, `std.uri`, `std.serialize`
|
|
861
861
|
|
|
@@ -872,7 +872,7 @@ Core modules in `std/`:
|
|
|
872
872
|
**Other**: `std.bytes`, `std.ctype`, `std.asset_pack`, `std.cell`
|
|
873
873
|
|
|
874
874
|
See module source for full method surface. Iterator forms:
|
|
875
|
-
- Pointer-returning (`next() -> nullable ptr[T]`): `Vec`, `Deque`, `BinaryHeap`/`PriorityQueue`/`OrderedSet` (read-only), `OrderedMap.keys`/`Map.keys`/`Set`/`LinkedMap.keys`/`LinkedSet`/`Counter.keys`/`MultiSet.values`, `Queue`/`Stack` (mutable)
|
|
875
|
+
- Pointer-returning (`next() -> nullable ptr[T]`): `Vec`, `Deque`, `BinaryHeap`/`PriorityQueue`/`OrderedSet` (read-only), `OrderedMap.keys`/`Map.keys`/`Set`/`LinkedMap.keys`/`LinkedSet`/`Counter.keys`/`MultiSet.values`, `Queue`/`Stack` (mutable), `RingBuffer`, `SparseSet`
|
|
876
876
|
- `next() -> bool` + `current()`: `OrderedMap.entries`/`iter`, `Map.entries`/`iter`, `LinkedMap.entries`/`iter`, `Counter.counts`/`entries`/`iter`, `MultiSet.entries`/`iter`, `SnapshotValues`/`SnapshotEntries`
|
|
877
877
|
|
|
878
878
|
## 12. Strings, Text, And Builders
|
data/docs/index.html
CHANGED
|
@@ -2164,6 +2164,11 @@ function attach(window: ref[Window]) -> Result[void, EventError]:
|
|
|
2164
2164
|
<tr><td><code>std.multiset</code></td><td><code>MultiSet[T]</code></td><td>Values read-only; entries <code>current()</code></td><td>Bag with per-element counts</td></tr>
|
|
2165
2165
|
<tr><td><code>std.queue</code></td><td><code>Queue[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>FIFO facade over Deque</td></tr>
|
|
2166
2166
|
<tr><td><code>std.stack</code></td><td><code>Stack[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>LIFO facade over Deque</td></tr>
|
|
2167
|
+
<tr><td><code>std.bitset</code></td><td><code>Bitset</code></td><td>—</td><td>Bit-level set with popcount</td></tr>
|
|
2168
|
+
<tr><td><code>std.spatial</code></td><td><code>SpatialGrid[T]</code></td><td>—</td><td>Uniform spatial hash grid (returns Vec)</td></tr>
|
|
2169
|
+
<tr><td><code>std.ring_buffer</code></td><td><code>RingBuffer[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>Fixed-capacity circular buffer</td></tr>
|
|
2170
|
+
<tr><td><code>std.sparse_set</code></td><td><code>SparseSet[T]</code></td><td>Mutable <code>ptr[T]?</code></td><td>O(1) insert/remove; dense iteration</td></tr>
|
|
2171
|
+
<tr><td><code>std.lru_cache</code></td><td><code>LruCache[K,V]</code></td><td><code>entries()</code></td><td>Capacity-bounded LRU eviction map</td></tr>
|
|
2167
2172
|
</table>
|
|
2168
2173
|
</div>
|
|
2169
2174
|
|
data/docs/language-manual.md
CHANGED
|
@@ -1129,6 +1129,11 @@ The current shipped collection modules in `std` are:
|
|
|
1129
1129
|
- `std.multiset.MultiSet[T]`: insertion-ordered bag built on `Counter[T]`, with `create`, `with_capacity`, `len`, `total_count`, `distinct_len`, `capacity`, `is_empty`, `count`, `contains`, `values`, `entries`, `iter`, `is_subset`, `union_with`, `intersection`, `difference`, `symmetric_difference`, `clear`, `release`, `reserve`, `insert`, `add`, `remove_one`, and `remove_all`.
|
|
1130
1130
|
- `std.queue.Queue[T]`: FIFO facade over `Deque[T]`, with `create`, `with_capacity`, `len`, `capacity`, `is_empty`, `iter`, `peek`, `clear`, `release`, `reserve`, `enqueue`, and `dequeue`.
|
|
1131
1131
|
- `std.stack.Stack[T]`: LIFO facade over `Deque[T]`, with `create`, `with_capacity`, `len`, `capacity`, `is_empty`, `iter`, `peek`, `clear`, `release`, `reserve`, `push`, and `pop`.
|
|
1132
|
+
- `std.bitset.Bitset`: bit-level set backed by a heap-allocated word array, with `create`, `with_capacity`, `len`, `is_empty`, `set`, `clear`, `test`, `toggle`, `count`, `any`, `all`, `none`, `find_first_set`, `find_first_clear`, `clear_all`, `reserve`, and `release`.
|
|
1133
|
+
- `std.spatial.SpatialGrid[T]`: uniform spatial hash grid with `create`, `with_origin`, `insert`, `insert_many`, `query_radius`, `clear`, `release`, `cell_count`, `occupied_cells`, and `entity_count`.
|
|
1134
|
+
- `std.ring_buffer.RingBuffer[T]`: fixed-capacity circular buffer that overwrites oldest entries when full, with `with_capacity`, `len`, `capacity`, `is_empty`, `is_full`, `iter`, `get`, `at`, `peek`, `push`, `pop`, `clear`, and `release`.
|
|
1135
|
+
- `std.sparse_set.SparseSet[T]`: O(1) insert/remove/contains with cache-friendly dense iteration, keyed by `ptr_uint` handle, with `create`, `with_capacity`, `len`, `is_empty`, `iter`, `get`, `at`, `contains`, `key_at`, `insert`, `remove`, `clear`, `reserve`, and `release`.
|
|
1136
|
+
- `std.lru_cache.LruCache[K, V]`: capacity-bounded linked hash map with LRU eviction, keyed by the canonical `hash[K](...)` and `equal[K](...)` hooks, with `with_capacity`, `len`, `capacity`, `is_empty`, `iter`, `get`, `at`, `contains`, `set`, `remove`, `clear`, and `release`.
|
|
1132
1137
|
- `std.linked_map_view.SnapshotValues[K, V]`: read-only snapshot view over `LinkedMap` values in insertion order, with `create(values: linked_map.Entries[K, V])` and `iter`.
|
|
1133
1138
|
- `std.linked_map_view.SnapshotEntries[K, V]`: read-only snapshot view over `LinkedMap` entries in insertion order, with `create(values: linked_map.Entries[K, V])` and `iter`.
|
|
1134
1139
|
|
|
@@ -1151,7 +1156,10 @@ Iterator notes for those collection modules:
|
|
|
1151
1156
|
- `MultiSet.values()` uses the pointer-returning iterator form with read-only value pointers in first-seen order.
|
|
1152
1157
|
- `MultiSet.entries()` and `MultiSet.iter()` use the `next() -> bool` plus `current()` iterator form and yield immutable `{ value, count }` snapshots.
|
|
1153
1158
|
- `Queue.iter()` and `Stack.iter()` use the same mutable pointer-returning iterator form as `Deque.iter()`, and `peek()` returns a mutable element pointer because changing an element value does not violate FIFO/LIFO ordering invariants.
|
|
1159
|
+
- `RingBuffer.iter()` uses the pointer-returning iterator form with mutable element pointers.
|
|
1160
|
+
- `SparseSet.iter()` uses the pointer-returning iterator form with mutable element pointers in dense order.
|
|
1154
1161
|
- `SnapshotValues.iter()` and `SnapshotEntries.iter()` use the `next() -> bool` plus `current()` iterator form in insertion order.
|
|
1162
|
+
- `SpatialGrid` does not expose a direct iterator; query results are returned as a `Vec[T]`.
|
|
1155
1163
|
|
|
1156
1164
|
## 8. Strings, C Strings, And Format Strings
|
|
1157
1165
|
|
data/lib/milk_tea/base.rb
CHANGED
|
@@ -122,11 +122,12 @@ module MilkTea
|
|
|
122
122
|
start_line = [binding.ast.respond_to?(:line) ? binding.ast.line : nil, snapshots.first.line].compact.min
|
|
123
123
|
end_line = snapshots.last.line
|
|
124
124
|
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
|
|
125
|
+
# Extend end_line to cover the actual function body so that completion
|
|
126
|
+
# and hover lookups resolve correctly even when snapshots don't reach
|
|
127
|
+
# the final body line (common for generic functions whose bodies are
|
|
128
|
+
# only partially analysed, and functions whose last statement does not
|
|
129
|
+
# record a snapshot).
|
|
130
|
+
if binding.ast.respond_to?(:body) && binding.ast.body
|
|
130
131
|
body_end = last_ast_line(binding.ast.body)
|
|
131
132
|
end_line = body_end if body_end && body_end > end_line
|
|
132
133
|
end
|
|
@@ -334,6 +334,7 @@ module MilkTea
|
|
|
334
334
|
when AST::LocalDecl
|
|
335
335
|
check_expr_names(stmt.value, scopes, binding, names) if stmt.value
|
|
336
336
|
names.add(stmt.name) if stmt.name
|
|
337
|
+
try_record_generic_local_snapshot(stmt, scopes, binding) if stmt.name && stmt.value
|
|
337
338
|
when AST::Assignment
|
|
338
339
|
check_expr_names(stmt.target, scopes, binding, names)
|
|
339
340
|
check_expr_names(stmt.value, scopes, binding, names)
|
|
@@ -457,6 +458,138 @@ module MilkTea
|
|
|
457
458
|
raise_sema_error("unknown name #{name}", node)
|
|
458
459
|
end
|
|
459
460
|
|
|
461
|
+
# When a generic method body contains a let/var declaration, always record a
|
|
462
|
+
# completion snapshot so hover and completion can discover the local, even
|
|
463
|
+
# when full type inference is impossible. The inferred type is used when
|
|
464
|
+
# available; otherwise the explicit type annotation on the declaration is
|
|
465
|
+
# consulted. As a last resort a fallback primitive type is used so the
|
|
466
|
+
# binding is never silently dropped.
|
|
467
|
+
def try_record_generic_local_snapshot(stmt, scopes, binding)
|
|
468
|
+
type = infer_local_initializer_type(stmt, scopes) ||
|
|
469
|
+
explicit_declaration_type_for(stmt) ||
|
|
470
|
+
fallback_completion_type
|
|
471
|
+
|
|
472
|
+
decl_kind = stmt.kind == :var ? :var : :let
|
|
473
|
+
vb = value_binding(name: stmt.name, type: type, mutable: stmt.kind == :var, kind: decl_kind)
|
|
474
|
+
new_scopes = scopes.dup.unshift({ stmt.name => vb })
|
|
475
|
+
record_local_completion_snapshot(stmt.line, stmt.column, new_scopes)
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def infer_local_initializer_type(stmt, scopes)
|
|
479
|
+
return nil unless stmt.value
|
|
480
|
+
|
|
481
|
+
infer_simple_local_type(stmt.value, scopes)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def explicit_declaration_type_for(stmt)
|
|
485
|
+
annotation = stmt.respond_to?(:type) ? stmt.type : nil
|
|
486
|
+
return nil unless annotation
|
|
487
|
+
|
|
488
|
+
name = annotation.respond_to?(:name) ? annotation.name : annotation.to_s
|
|
489
|
+
@ctx.types[name]
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def fallback_completion_type
|
|
493
|
+
@ctx.types["int"] || @ctx.types.values.first
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def infer_simple_local_type(value, scopes)
|
|
497
|
+
case value
|
|
498
|
+
when AST::Call
|
|
499
|
+
infer_call_return_type(value, scopes)
|
|
500
|
+
when AST::MemberAccess
|
|
501
|
+
infer_member_access_field_type(value, scopes)
|
|
502
|
+
when AST::Identifier
|
|
503
|
+
(binding = lookup_value(value.name, scopes)) ? binding.type : nil
|
|
504
|
+
when AST::IntegerLiteral
|
|
505
|
+
@ctx.types["int"]
|
|
506
|
+
when AST::FloatLiteral
|
|
507
|
+
@ctx.types["float"] || @ctx.types["double"]
|
|
508
|
+
when AST::CharLiteral
|
|
509
|
+
@ctx.types["ubyte"]
|
|
510
|
+
when AST::BooleanLiteral
|
|
511
|
+
@ctx.types["bool"]
|
|
512
|
+
when AST::StringLiteral
|
|
513
|
+
@ctx.types["str"]
|
|
514
|
+
when AST::PrefixCast
|
|
515
|
+
if value.target_type.respond_to?(:name)
|
|
516
|
+
@ctx.types[value.target_type.name] || @ctx.types["int"]
|
|
517
|
+
else
|
|
518
|
+
@ctx.types["int"]
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def infer_member_access_field_type(value, scopes)
|
|
524
|
+
receiver_type = case value.receiver
|
|
525
|
+
when AST::Identifier
|
|
526
|
+
if value.receiver.name == "this"
|
|
527
|
+
(binding = lookup_value("this", scopes)) ? binding.type : nil
|
|
528
|
+
else
|
|
529
|
+
(binding = lookup_value(value.receiver.name, scopes)) ? binding.type : nil
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
return nil unless receiver_type
|
|
533
|
+
|
|
534
|
+
field_receiver = receiver_type_for_fields(receiver_type)
|
|
535
|
+
field_receiver&.respond_to?(:fields) ? field_receiver.fields[value.member] : nil
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
def infer_call_return_type(call, scopes)
|
|
539
|
+
callee = call.callee
|
|
540
|
+
callee = callee.callee while callee.is_a?(AST::Specialization)
|
|
541
|
+
|
|
542
|
+
case callee
|
|
543
|
+
when AST::Identifier
|
|
544
|
+
func = @ctx.top_level_functions[callee.name]
|
|
545
|
+
return func.type.return_type if func
|
|
546
|
+
|
|
547
|
+
member = callee.name
|
|
548
|
+
this_binding = lookup_value("this", scopes)
|
|
549
|
+
if this_binding && (rt = receiver_type_for_fields(this_binding.type))
|
|
550
|
+
method = @ctx.methods.dig(rt, member)
|
|
551
|
+
return method.type.return_type if method
|
|
552
|
+
end
|
|
553
|
+
when AST::MemberAccess
|
|
554
|
+
name = resolve_receiver_name_for_call_inference(callee, scopes)
|
|
555
|
+
member = callee.member
|
|
556
|
+
return nil unless name
|
|
557
|
+
|
|
558
|
+
if (import = @ctx.imports[name])
|
|
559
|
+
func = import.functions[member]
|
|
560
|
+
return func.type.return_type if func
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
receiver_type = @ctx.types[name]
|
|
564
|
+
if receiver_type && @ctx.methods.key?(receiver_type)
|
|
565
|
+
method = @ctx.methods[receiver_type]["static:#{member}"] || @ctx.methods[receiver_type][member]
|
|
566
|
+
return method.type.return_type if method
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
nil
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
def resolve_receiver_name_for_call_inference(callee, scopes)
|
|
573
|
+
case callee.receiver
|
|
574
|
+
when AST::Identifier
|
|
575
|
+
if callee.receiver.name == "this"
|
|
576
|
+
binding = lookup_value("this", scopes)
|
|
577
|
+
return nil unless binding
|
|
578
|
+
this_type = receiver_type_for_fields(binding.type)
|
|
579
|
+
this_type&.name
|
|
580
|
+
else
|
|
581
|
+
callee.receiver.name
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
def receiver_type_for_fields(type)
|
|
587
|
+
type = type.base while type.is_a?(Types::Nullable)
|
|
588
|
+
type = type.arguments.first if type.respond_to?(:name) && type.name == 'ref' && type.respond_to?(:arguments) && type.arguments&.length == 1
|
|
589
|
+
type = type.definition if type.respond_to?(:definition)
|
|
590
|
+
type
|
|
591
|
+
end
|
|
592
|
+
|
|
460
593
|
# Scans generic method bodies for assignments to this through a
|
|
461
594
|
# non-editable receiver. Full body checking is deferred to call-site
|
|
462
595
|
# specialization, but immutable-this violations are type-independent.
|
|
@@ -491,8 +624,10 @@ module MilkTea
|
|
|
491
624
|
with_scope(binding.body_params) do |scopes|
|
|
492
625
|
start_local_completion_frame(binding, scopes)
|
|
493
626
|
if binding.type_params.any?
|
|
494
|
-
|
|
495
|
-
|
|
627
|
+
if binding.ast.respond_to?(:body)
|
|
628
|
+
check_generic_method_immutable_this(binding, scopes)
|
|
629
|
+
check_generic_method_names(binding, scopes)
|
|
630
|
+
end
|
|
496
631
|
return
|
|
497
632
|
end
|
|
498
633
|
|
|
@@ -22,7 +22,19 @@ module MilkTea
|
|
|
22
22
|
if @nullability_flow_result && idx + 1 < statements.length
|
|
23
23
|
apply_nullability_continuation_refinements!(nested_scopes, statements[idx + 1])
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
end_line = statement_end_line(statement)
|
|
26
|
+
# When the statement spans multiple lines (e.g. let … else:),
|
|
27
|
+
# record an extra snapshot at the declaration line so that
|
|
28
|
+
# hover and completion lookups on the declaration line itself
|
|
29
|
+
# can still find the new binding.
|
|
30
|
+
if end_line && statement.respond_to?(:line) && statement.line && end_line > statement.line
|
|
31
|
+
record_local_completion_snapshot(
|
|
32
|
+
statement.line,
|
|
33
|
+
statement.respond_to?(:column) ? statement.column : 0,
|
|
34
|
+
nested_scopes,
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
record_local_completion_snapshot(end_line, 1_000_000, nested_scopes)
|
|
26
38
|
rescue SemanticError => e
|
|
27
39
|
if @collecting_errors
|
|
28
40
|
@structural_errors << e
|
|
@@ -1264,9 +1264,14 @@ module MilkTea
|
|
|
1264
1264
|
|
|
1265
1265
|
header_line_tokens = non_trivia_tokens_on_line(tokens, current.line)
|
|
1266
1266
|
header = header_line_tokens.first
|
|
1267
|
+
type_index = 1
|
|
1268
|
+
if header&.type == :public
|
|
1269
|
+
header = header_line_tokens[1]
|
|
1270
|
+
type_index = 2
|
|
1271
|
+
end
|
|
1267
1272
|
return nil unless [:struct, :union].include?(header&.type)
|
|
1268
1273
|
|
|
1269
|
-
type_token = header_line_tokens[
|
|
1274
|
+
type_token = header_line_tokens[type_index]
|
|
1270
1275
|
return nil unless type_token&.type == :identifier
|
|
1271
1276
|
|
|
1272
1277
|
return resolve_type_receiver_info(facts, type_token.lexeme, type_token.lexeme)
|
|
@@ -462,7 +462,9 @@ module MilkTea
|
|
|
462
462
|
struct_type = find_struct_containing_field(facts, field_name)
|
|
463
463
|
return nil unless struct_type
|
|
464
464
|
|
|
465
|
-
changes =
|
|
465
|
+
changes = {}
|
|
466
|
+
edits = collect_struct_field_changes(uri, field_name, new_name)
|
|
467
|
+
changes[uri] = edits if edits
|
|
466
468
|
related_uris = @workspace.related_open_document_uris(uri)
|
|
467
469
|
related_uris.each do |related_uri|
|
|
468
470
|
next if related_uri == uri
|
data/std/lru_cache.mt
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import std.linked_map as linked_map
|
|
2
|
+
|
|
3
|
+
public struct LruCache[K, V]:
|
|
4
|
+
values: linked_map.LinkedMap[K, V]
|
|
5
|
+
max_capacity: ptr_uint
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
extending LruCache[K, V]:
|
|
9
|
+
public static function with_capacity(capacity: ptr_uint) -> LruCache[K, V]:
|
|
10
|
+
return LruCache[K, V](values = linked_map.LinkedMap[K, V].with_capacity(capacity), max_capacity = capacity)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
public function len() -> ptr_uint:
|
|
14
|
+
return this.values.len()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public function capacity() -> ptr_uint:
|
|
18
|
+
return this.max_capacity
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
public function is_empty() -> bool:
|
|
22
|
+
return this.values.is_empty()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
public function iter() -> linked_map.Entries[K, V]:
|
|
26
|
+
return this.values.entries()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
public editable function get(key: K) -> ptr[V]?:
|
|
30
|
+
let removed = this.values.remove_entry(key)
|
|
31
|
+
match removed:
|
|
32
|
+
Option.some as entry:
|
|
33
|
+
this.values.set(key, entry.value.value)
|
|
34
|
+
return this.values.get(key)
|
|
35
|
+
Option.none:
|
|
36
|
+
return null
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
public editable function at(key: K) -> Option[V]:
|
|
40
|
+
let p = this.get(key) else:
|
|
41
|
+
return Option[V].none
|
|
42
|
+
|
|
43
|
+
unsafe:
|
|
44
|
+
return Option[V].some(value = read(p))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
public function contains(key: K) -> bool:
|
|
48
|
+
return this.values.contains(key)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
public editable function clear() -> void:
|
|
52
|
+
this.values.clear()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
public editable function release() -> void:
|
|
56
|
+
this.values.release()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
public editable function set(key: K, value: V) -> void:
|
|
60
|
+
this.values.remove(key)
|
|
61
|
+
|
|
62
|
+
if this.values.len() == this.max_capacity:
|
|
63
|
+
var key_iter = this.values.keys()
|
|
64
|
+
let first_key_ptr = key_iter.next() else:
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
unsafe:
|
|
68
|
+
let first_key = read(ptr[K]<-first_key_ptr)
|
|
69
|
+
this.values.remove(first_key)
|
|
70
|
+
|
|
71
|
+
this.values.set(key, value)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
public editable function remove(key: K) -> bool:
|
|
75
|
+
return this.values.remove(key).is_some()
|
data/std/ring_buffer.mt
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import std.mem.heap as heap
|
|
2
|
+
|
|
3
|
+
public struct RingBuffer[T]:
|
|
4
|
+
data: own[T]?
|
|
5
|
+
head: ptr_uint
|
|
6
|
+
len: ptr_uint
|
|
7
|
+
capacity: ptr_uint
|
|
8
|
+
|
|
9
|
+
public struct Iter[T]:
|
|
10
|
+
data: ptr[T]?
|
|
11
|
+
head: ptr_uint
|
|
12
|
+
len: ptr_uint
|
|
13
|
+
capacity: ptr_uint
|
|
14
|
+
index: ptr_uint
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
extending RingBuffer[T]:
|
|
18
|
+
public static function with_capacity(capacity: ptr_uint) -> RingBuffer[T]:
|
|
19
|
+
let data = heap.must_alloc[T](capacity)
|
|
20
|
+
return RingBuffer[T](data = data, head = 0, len = 0, capacity = capacity)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
static function physical_index(head: ptr_uint, capacity: ptr_uint, index: ptr_uint) -> ptr_uint:
|
|
24
|
+
let raw = head + index
|
|
25
|
+
if raw >= capacity:
|
|
26
|
+
return raw - capacity
|
|
27
|
+
|
|
28
|
+
return raw
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
public function len() -> ptr_uint:
|
|
32
|
+
return this.len
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
public function capacity() -> ptr_uint:
|
|
36
|
+
return this.capacity
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
public function is_empty() -> bool:
|
|
40
|
+
return this.len == 0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
public function is_full() -> bool:
|
|
44
|
+
return this.len == this.capacity
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
public function iter() -> Iter[T]:
|
|
48
|
+
return Iter[T](data = this.data, head = this.head, len = this.len, capacity = this.capacity, index = 0)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
public function get(index: ptr_uint) -> ptr[T]?:
|
|
52
|
+
if index >= this.len:
|
|
53
|
+
return null
|
|
54
|
+
|
|
55
|
+
let data = this.data else:
|
|
56
|
+
fatal(c"ring_buffer.RingBuffer.get missing storage")
|
|
57
|
+
|
|
58
|
+
return unsafe: ptr[T]<-data + RingBuffer[T].physical_index(this.head, this.capacity, index)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
public function at(index: ptr_uint) -> Option[T]:
|
|
62
|
+
let p = this.get(index) else:
|
|
63
|
+
return Option[T].none
|
|
64
|
+
|
|
65
|
+
unsafe:
|
|
66
|
+
return Option[T].some(value = read(p))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
public function peek() -> ptr[T]?:
|
|
70
|
+
return this.get(0)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
public editable function push(value: T) -> void:
|
|
74
|
+
let data = this.data else:
|
|
75
|
+
fatal(c"ring_buffer.RingBuffer.push missing storage")
|
|
76
|
+
|
|
77
|
+
let tail = RingBuffer[T].physical_index(this.head, this.capacity, this.len)
|
|
78
|
+
|
|
79
|
+
unsafe:
|
|
80
|
+
let data_ptr = ptr[T]<-data
|
|
81
|
+
read(data_ptr + tail) = value
|
|
82
|
+
|
|
83
|
+
if this.len == this.capacity:
|
|
84
|
+
this.head = RingBuffer[T].physical_index(this.head, this.capacity, 1)
|
|
85
|
+
else:
|
|
86
|
+
this.len += 1
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
public editable function pop() -> Option[T]:
|
|
90
|
+
if this.len == 0:
|
|
91
|
+
return Option[T].none
|
|
92
|
+
|
|
93
|
+
let data = this.data else:
|
|
94
|
+
fatal(c"ring_buffer.RingBuffer.pop missing storage")
|
|
95
|
+
|
|
96
|
+
unsafe:
|
|
97
|
+
let data_ptr = ptr[T]<-data
|
|
98
|
+
let value = read(data_ptr + this.head)
|
|
99
|
+
this.head = RingBuffer[T].physical_index(this.head, this.capacity, 1)
|
|
100
|
+
this.len -= 1
|
|
101
|
+
return Option[T].some(value = value)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
public editable function clear() -> void:
|
|
105
|
+
this.head = 0
|
|
106
|
+
this.len = 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
public editable function release() -> void:
|
|
110
|
+
heap.release(this.data)
|
|
111
|
+
this.data = null
|
|
112
|
+
this.head = 0
|
|
113
|
+
this.len = 0
|
|
114
|
+
this.capacity = 0
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
extending Iter[T]:
|
|
118
|
+
public function iter() -> Iter[T]:
|
|
119
|
+
return this
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
public editable function next() -> ptr[T]?:
|
|
123
|
+
if this.index >= this.len:
|
|
124
|
+
return null
|
|
125
|
+
|
|
126
|
+
let data = this.data else:
|
|
127
|
+
fatal(c"ring_buffer.Iter.next missing storage")
|
|
128
|
+
|
|
129
|
+
let current_index = this.index
|
|
130
|
+
this.index += 1
|
|
131
|
+
return unsafe: ptr[T]<-data + RingBuffer[T].physical_index(this.head, this.capacity, current_index)
|
data/std/sparse_set.mt
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import std.vec as vec
|
|
2
|
+
|
|
3
|
+
const SPARSE_EMPTY: ptr_uint = ~ptr_uint<-0
|
|
4
|
+
|
|
5
|
+
public struct SparseSet[T]:
|
|
6
|
+
sparse: vec.Vec[ptr_uint]
|
|
7
|
+
dense: vec.Vec[T]
|
|
8
|
+
keys: vec.Vec[ptr_uint]
|
|
9
|
+
|
|
10
|
+
public struct Iter[T]:
|
|
11
|
+
data: ptr[T]?
|
|
12
|
+
index: ptr_uint
|
|
13
|
+
len: ptr_uint
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
extending SparseSet[T]:
|
|
17
|
+
public static function create() -> SparseSet[T]:
|
|
18
|
+
return SparseSet[T](
|
|
19
|
+
sparse = vec.Vec[ptr_uint].create(),
|
|
20
|
+
dense = vec.Vec[T].create(),
|
|
21
|
+
keys = vec.Vec[ptr_uint].create(),
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
public static function with_capacity(capacity: ptr_uint) -> SparseSet[T]:
|
|
26
|
+
var result = SparseSet[T].create()
|
|
27
|
+
result.reserve(capacity)
|
|
28
|
+
return result
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
public function len() -> ptr_uint:
|
|
32
|
+
return this.dense.len()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
public function is_empty() -> bool:
|
|
36
|
+
return this.dense.is_empty()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
public function iter() -> Iter[T]:
|
|
40
|
+
let view = this.dense.as_span()
|
|
41
|
+
return Iter[T](data = view.data, index = 0, len = view.len)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
public function get(key: ptr_uint) -> ptr[T]?:
|
|
45
|
+
if key >= this.sparse.len():
|
|
46
|
+
return null
|
|
47
|
+
|
|
48
|
+
let position = this.sparse.get(key) else:
|
|
49
|
+
fatal(c"sparse_set.SparseSet.get missing sparse storage")
|
|
50
|
+
|
|
51
|
+
unsafe:
|
|
52
|
+
let index = read(ptr[ptr_uint]<-position)
|
|
53
|
+
if index == SPARSE_EMPTY:
|
|
54
|
+
return null
|
|
55
|
+
|
|
56
|
+
return this.dense.get(index)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
public function at(key: ptr_uint) -> Option[T]:
|
|
60
|
+
let p = this.get(key) else:
|
|
61
|
+
return Option[T].none
|
|
62
|
+
|
|
63
|
+
unsafe:
|
|
64
|
+
return Option[T].some(value = read(p))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
public function contains(key: ptr_uint) -> bool:
|
|
68
|
+
return this.get(key) != null
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
public function key_at(dense_index: ptr_uint) -> ptr_uint:
|
|
72
|
+
let key_ptr = this.keys.get(dense_index) else:
|
|
73
|
+
fatal(c"sparse_set.SparseSet.key_at missing keys storage")
|
|
74
|
+
|
|
75
|
+
unsafe:
|
|
76
|
+
return read(ptr[ptr_uint]<-key_ptr)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
public editable function clear() -> void:
|
|
80
|
+
this.sparse.clear()
|
|
81
|
+
this.dense.clear()
|
|
82
|
+
this.keys.clear()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
public editable function release() -> void:
|
|
86
|
+
this.sparse.release()
|
|
87
|
+
this.dense.release()
|
|
88
|
+
this.keys.release()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
public editable function reserve(min_capacity: ptr_uint) -> void:
|
|
92
|
+
this.dense.reserve(min_capacity)
|
|
93
|
+
this.keys.reserve(min_capacity)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
public editable function insert(key: ptr_uint, value: T) -> bool:
|
|
97
|
+
while key >= this.sparse.len():
|
|
98
|
+
this.sparse.push(SPARSE_EMPTY)
|
|
99
|
+
|
|
100
|
+
let position = this.sparse.get(key) else:
|
|
101
|
+
fatal(c"sparse_set.SparseSet.insert missing sparse storage")
|
|
102
|
+
|
|
103
|
+
unsafe:
|
|
104
|
+
if read(ptr[ptr_uint]<-position) != SPARSE_EMPTY:
|
|
105
|
+
return false
|
|
106
|
+
|
|
107
|
+
let dense_index = this.dense.len()
|
|
108
|
+
this.dense.push(value)
|
|
109
|
+
this.keys.push(key)
|
|
110
|
+
|
|
111
|
+
unsafe:
|
|
112
|
+
read(ptr[ptr_uint]<-position) = dense_index
|
|
113
|
+
|
|
114
|
+
return true
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
public editable function remove(key: ptr_uint) -> bool:
|
|
118
|
+
if key >= this.sparse.len():
|
|
119
|
+
return false
|
|
120
|
+
|
|
121
|
+
let dense_index_ptr = this.sparse.get(key) else:
|
|
122
|
+
fatal(c"sparse_set.SparseSet.remove missing sparse storage")
|
|
123
|
+
|
|
124
|
+
unsafe:
|
|
125
|
+
let dense_index = read(ptr[ptr_uint]<-dense_index_ptr)
|
|
126
|
+
if dense_index == SPARSE_EMPTY:
|
|
127
|
+
return false
|
|
128
|
+
|
|
129
|
+
let last_index = this.dense.len() - 1
|
|
130
|
+
if dense_index != last_index:
|
|
131
|
+
let last_value = this.dense.get(last_index) else:
|
|
132
|
+
fatal(c"sparse_set.SparseSet.remove missing last dense value")
|
|
133
|
+
let dense_slot = this.dense.get(dense_index) else:
|
|
134
|
+
fatal(c"sparse_set.SparseSet.remove missing dense slot")
|
|
135
|
+
read(dense_slot) = read(last_value)
|
|
136
|
+
|
|
137
|
+
let last_key = this.keys.get(last_index) else:
|
|
138
|
+
fatal(c"sparse_set.SparseSet.remove missing last key")
|
|
139
|
+
let moved_key = read(ptr[ptr_uint]<-last_key)
|
|
140
|
+
|
|
141
|
+
let key_slot = this.keys.get(dense_index) else:
|
|
142
|
+
fatal(c"sparse_set.SparseSet.remove missing key slot")
|
|
143
|
+
read(ptr[ptr_uint]<-key_slot) = moved_key
|
|
144
|
+
|
|
145
|
+
let moved_sparse_ptr = this.sparse.get(moved_key) else:
|
|
146
|
+
fatal(c"sparse_set.SparseSet.remove missing sparse entry for moved key")
|
|
147
|
+
read(ptr[ptr_uint]<-moved_sparse_ptr) = dense_index
|
|
148
|
+
|
|
149
|
+
this.dense.pop()
|
|
150
|
+
this.keys.pop()
|
|
151
|
+
read(ptr[ptr_uint]<-dense_index_ptr) = SPARSE_EMPTY
|
|
152
|
+
|
|
153
|
+
return true
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
extending Iter[T]:
|
|
157
|
+
public function iter() -> Iter[T]:
|
|
158
|
+
return this
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
public editable function next() -> ptr[T]?:
|
|
162
|
+
if this.index >= this.len:
|
|
163
|
+
return null
|
|
164
|
+
|
|
165
|
+
let data = this.data else:
|
|
166
|
+
fatal(c"sparse_set.Iter.next missing storage")
|
|
167
|
+
|
|
168
|
+
let current_index = this.index
|
|
169
|
+
this.index += 1
|
|
170
|
+
return unsafe: ptr[T]<-data + current_index
|
data/std/spatial.mt
CHANGED
|
@@ -9,7 +9,53 @@ public struct SpatialGrid[T]:
|
|
|
9
9
|
origin_y: float
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
function cell_index[T](grid: ref[SpatialGrid[T]], x: float, y: float) -> Option[ptr_uint]:
|
|
13
|
+
let cx = int<-(float<-((x - grid.origin_x) / grid.cell_size))
|
|
14
|
+
let cy = int<-(float<-((y - grid.origin_y) / grid.cell_size))
|
|
15
|
+
if cx < 0 or cy < 0 or uint<-cx >= grid.cols or uint<-cy >= grid.rows:
|
|
16
|
+
return Option[ptr_uint].none()
|
|
17
|
+
return Option[ptr_uint].some(value = ptr_uint<-cx + ptr_uint<-cy * ptr_uint<-grid.cols)
|
|
18
|
+
|
|
19
|
+
|
|
12
20
|
extending SpatialGrid[T]:
|
|
21
|
+
public static function create(cell_size: float, width: float, height: float) -> SpatialGrid[T]:
|
|
22
|
+
var cols: uint = uint<-(float<-width / cell_size)
|
|
23
|
+
var rows: uint = uint<-(float<-height / cell_size)
|
|
24
|
+
if cols == 0:
|
|
25
|
+
cols = 1
|
|
26
|
+
if rows == 0:
|
|
27
|
+
rows = 1
|
|
28
|
+
|
|
29
|
+
var cells = vec.Vec[vec.Vec[T]].create()
|
|
30
|
+
var total: ptr_uint = ptr_uint<-cols * ptr_uint<-rows
|
|
31
|
+
var i: ptr_uint = 0
|
|
32
|
+
while i < total:
|
|
33
|
+
cells.push(vec.Vec[T].create())
|
|
34
|
+
i += 1
|
|
35
|
+
|
|
36
|
+
return SpatialGrid[T](
|
|
37
|
+
cells = cells,
|
|
38
|
+
cell_size = cell_size,
|
|
39
|
+
cols = cols,
|
|
40
|
+
rows = rows,
|
|
41
|
+
origin_x = 0.0,
|
|
42
|
+
origin_y = 0.0
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
public static function with_origin(
|
|
47
|
+
cell_size: float,
|
|
48
|
+
width: float,
|
|
49
|
+
height: float,
|
|
50
|
+
origin_x: float,
|
|
51
|
+
origin_y: float
|
|
52
|
+
) -> SpatialGrid[T]:
|
|
53
|
+
var grid = SpatialGrid[T].create(cell_size, width, height)
|
|
54
|
+
grid.origin_x = origin_x
|
|
55
|
+
grid.origin_y = origin_y
|
|
56
|
+
return grid
|
|
57
|
+
|
|
58
|
+
|
|
13
59
|
public editable function release() -> void:
|
|
14
60
|
var i: ptr_uint = 0
|
|
15
61
|
while i < this.cells.len():
|
|
@@ -20,53 +66,6 @@ extending SpatialGrid[T]:
|
|
|
20
66
|
this.cells.release()
|
|
21
67
|
|
|
22
68
|
|
|
23
|
-
function cell_index[T](grid: ref[SpatialGrid[T]], x: float, y: float) -> Option[ptr_uint]:
|
|
24
|
-
let cx = int<-(float<-((x - grid.origin_x) / grid.cell_size))
|
|
25
|
-
let cy = int<-(float<-((y - grid.origin_y) / grid.cell_size))
|
|
26
|
-
if cx < 0 or cy < 0 or uint<-cx >= grid.cols or uint<-cy >= grid.rows:
|
|
27
|
-
return Option[ptr_uint].none()
|
|
28
|
-
return Option[ptr_uint].some(value = ptr_uint<-cx + ptr_uint<-cy * ptr_uint<-grid.cols)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
public function new[T](cell_size: float, width: float, height: float) -> SpatialGrid[T]:
|
|
32
|
-
var cols: uint = uint<-(float<-width / cell_size)
|
|
33
|
-
var rows: uint = uint<-(float<-height / cell_size)
|
|
34
|
-
if cols == 0:
|
|
35
|
-
cols = 1
|
|
36
|
-
if rows == 0:
|
|
37
|
-
rows = 1
|
|
38
|
-
|
|
39
|
-
var cells = vec.Vec[vec.Vec[T]].create()
|
|
40
|
-
var total: ptr_uint = ptr_uint<-cols * ptr_uint<-rows
|
|
41
|
-
var i: ptr_uint = 0
|
|
42
|
-
while i < total:
|
|
43
|
-
cells.push(vec.Vec[T].create())
|
|
44
|
-
i += 1
|
|
45
|
-
|
|
46
|
-
return SpatialGrid[T](
|
|
47
|
-
cells = cells,
|
|
48
|
-
cell_size = cell_size,
|
|
49
|
-
cols = cols,
|
|
50
|
-
rows = rows,
|
|
51
|
-
origin_x = 0.0,
|
|
52
|
-
origin_y = 0.0
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
public function new_with_origin[T](
|
|
57
|
-
cell_size: float,
|
|
58
|
-
width: float,
|
|
59
|
-
height: float,
|
|
60
|
-
origin_x: float,
|
|
61
|
-
origin_y: float
|
|
62
|
-
) -> SpatialGrid[T]:
|
|
63
|
-
var grid = new[T](cell_size, width, height)
|
|
64
|
-
grid.origin_x = origin_x
|
|
65
|
-
grid.origin_y = origin_y
|
|
66
|
-
return grid
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
extending SpatialGrid[T]:
|
|
70
69
|
public editable function insert(entity: T, x: float, y: float) -> void:
|
|
71
70
|
let idx_opt = cell_index(ref_of(this), x, y)
|
|
72
71
|
match idx_opt:
|
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.2.
|
|
4
|
+
version: 0.2.18
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -498,6 +498,7 @@ files:
|
|
|
498
498
|
- std/linked_map_view.mt
|
|
499
499
|
- std/linked_set.mt
|
|
500
500
|
- std/log.mt
|
|
501
|
+
- std/lru_cache.mt
|
|
501
502
|
- std/map.mt
|
|
502
503
|
- std/math.mt
|
|
503
504
|
- std/mem/arena.mt
|
|
@@ -543,6 +544,7 @@ files:
|
|
|
543
544
|
- std/raylib/tracy_gpu.mt
|
|
544
545
|
- std/raymath.mt
|
|
545
546
|
- std/result.mt
|
|
547
|
+
- std/ring_buffer.mt
|
|
546
548
|
- std/rlgl.mt
|
|
547
549
|
- std/rpng.mt
|
|
548
550
|
- std/rres.mt
|
|
@@ -550,6 +552,7 @@ files:
|
|
|
550
552
|
- std/sdl3/runtime.mt
|
|
551
553
|
- std/serialize.mt
|
|
552
554
|
- std/set.mt
|
|
555
|
+
- std/sparse_set.mt
|
|
553
556
|
- std/spatial.mt
|
|
554
557
|
- std/sqlite3.mt
|
|
555
558
|
- std/stack.mt
|
|
@@ -583,7 +586,7 @@ metadata:
|
|
|
583
586
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
584
587
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
585
588
|
post_install_message: |
|
|
586
|
-
Milk Tea 0.2.
|
|
589
|
+
Milk Tea 0.2.18 installed!
|
|
587
590
|
|
|
588
591
|
System requirements:
|
|
589
592
|
- A C compiler (gcc or clang) must be available on PATH
|