mt-lang 0.3.14 → 0.3.16
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 +8 -8
- data/docs/language-design.md +4 -8
- data/docs/language-manual.md +17 -5
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/ast.rb +2 -2
- data/lib/milk_tea/core/control_flow/builder.rb +62 -2
- data/lib/milk_tea/core/lowering/async/analysis.rb +3 -9
- data/lib/milk_tea/core/lowering/async/lowering.rb +2 -10
- data/lib/milk_tea/core/lowering/async/normalization.rb +2 -7
- data/lib/milk_tea/core/lowering/block.rb +1 -5
- data/lib/milk_tea/core/lowering/proc.rb +1 -5
- data/lib/milk_tea/core/lowering/scans.rb +3 -1
- data/lib/milk_tea/core/lowering/utils.rb +1 -27
- data/lib/milk_tea/core/parser/statements.rb +18 -12
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +3 -11
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +2 -3
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +1 -1
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +1 -2
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +2 -4
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +2 -8
- data/lib/milk_tea/tooling/linter/imports_platform.rb +2 -4
- data/lib/milk_tea/tooling/linter/release_rules.rb +1 -6
- data/lib/milk_tea/tooling/linter/source_helpers.rb +0 -6
- data/lib/milk_tea/tooling/linter/visitors.rb +4 -8
- data/lib/milk_tea/tooling/sexpr_dumper.rb +2 -0
- data/std/asset_pack.mt +1 -1
- data/std/async/libuv_runtime.mt +6 -6
- data/std/async/mailbox.mt +4 -4
- data/std/cookie.mt +2 -2
- data/std/crypto.mt +1 -1
- data/std/curl/runtime.mt +10 -10
- data/std/fs.linux.mt +26 -26
- data/std/fs.windows.mt +22 -22
- data/std/goap.mt +2 -2
- data/std/http/server.mt +21 -21
- data/std/http.mt +14 -14
- data/std/jobs.mt +4 -4
- data/std/json.mt +5 -5
- data/std/log.mt +1 -1
- data/std/mem/tracking.mt +1 -1
- data/std/net/channel.mt +4 -4
- data/std/net/clock.mt +6 -6
- data/std/net/discovery.mt +7 -7
- data/std/net/lobby.mt +10 -10
- data/std/net/manager.mt +1 -1
- data/std/net/mux.mt +4 -4
- data/std/net/nat.mt +4 -4
- data/std/net/packet.mt +3 -3
- data/std/net/punch.mt +3 -3
- data/std/net/rpc.mt +3 -3
- data/std/net/session.mt +15 -15
- data/std/net/stun.mt +4 -4
- data/std/net/turn.mt +4 -4
- data/std/oauth2.mt +12 -12
- data/std/path.mt +8 -8
- data/std/process.mt +4 -4
- data/std/raylib/packed_assets.mt +5 -5
- data/std/serialize.mt +1 -1
- data/std/tar.mt +10 -10
- data/std/terminal.mt +18 -18
- data/std/tls.mt +8 -8
- data/std/uri.mt +1 -1
- data/std/utility.mt +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b5cd3c1ef5e380b8d0c5d4e20f829400d01c6fdfd3e495e8c98050f4af8b59ba
|
|
4
|
+
data.tar.gz: 0e083d1780c9d591b996604a8b489726fa0f0c6fb85b8dc03da87b681383d5ca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 44f866e7d6bf6fc4998e0a9054bf898b27ed47ef38149de1881baf1d810e845b94e3d1f3ff304486654ea339329d726a10d969bcff4021943cc98b03bfe3fe01
|
|
7
|
+
data.tar.gz: 0fa7237c14aa9e038b4d51ae08a5971430d0e47b97fb19caf619aeb80a5e562de99aae1cf342a11ffea41e3b2268a128454bbf022b3e9182ddd94ff2ff0aff45
|
data/README.md
CHANGED
|
@@ -477,7 +477,7 @@ Rules:
|
|
|
477
477
|
- Conditions must be `bool`.
|
|
478
478
|
- There is no truthy or falsy coercion from integers or pointers.
|
|
479
479
|
- `pass` is an explicit no-op statement for intentionally empty block bodies.
|
|
480
|
-
-
|
|
480
|
+
- Every block-taking statement accepts a `:`-newline-indented block, or a single statement on the same line after `:`. This applies to `if`/`else` (e.g. `if cond: stmt else: stmt`), `while`, `for`, `defer` (e.g. `defer: cleanup()`), and `unsafe`. `match` arms are the exception: their inline form is a single value expression.
|
|
481
481
|
|
|
482
482
|
`match` supports the following scrutinee types:
|
|
483
483
|
|
|
@@ -615,7 +615,7 @@ Rules:
|
|
|
615
615
|
|
|
616
616
|
`defer`:
|
|
617
617
|
|
|
618
|
-
- `defer expr`
|
|
618
|
+
- `defer: expr` — single-statement inline form
|
|
619
619
|
- `defer:` block form
|
|
620
620
|
- `return` is not allowed inside defer blocks.
|
|
621
621
|
|
data/docs/index.html
CHANGED
|
@@ -658,12 +658,12 @@ function main() -> int:
|
|
|
658
658
|
|
|
659
659
|
## Collections: Vec and Map (import std.hash for primitive keys)
|
|
660
660
|
var entities = vec.Vec[Entity].create()
|
|
661
|
-
defer entities.release()
|
|
661
|
+
defer: entities.release()
|
|
662
662
|
entities.push(Entity.create(1, EntityKind.player, "Hero"))
|
|
663
663
|
entities.push(Entity.create(2, EntityKind.enemy, "Goblin"))
|
|
664
664
|
|
|
665
665
|
var name_counts = map.Map[str, int].create()
|
|
666
|
-
defer name_counts.release()
|
|
666
|
+
defer: name_counts.release()
|
|
667
667
|
name_counts.set("player", 1)
|
|
668
668
|
name_counts.set("enemy", 5)
|
|
669
669
|
|
|
@@ -742,7 +742,7 @@ function main() -> int:
|
|
|
742
742
|
io.print_line(f"Position: #{position.x:.2}, #{position.y:.2}")
|
|
743
743
|
io.print_line(f"ID hex: #{player.entity.id:x}")
|
|
744
744
|
var msg = fmt.format(f"Score: #{score}")
|
|
745
|
-
defer msg.release()
|
|
745
|
+
defer: msg.release()
|
|
746
746
|
|
|
747
747
|
## Heredoc string
|
|
748
748
|
let help = <<-HELP
|
|
@@ -753,7 +753,7 @@ function main() -> int:
|
|
|
753
753
|
|
|
754
754
|
## Defer: cleanup at scope exit (lowers to C cleanup labels)
|
|
755
755
|
let data: own[int] = heap.must_alloc[int](1)
|
|
756
|
-
defer heap.release[int](data)
|
|
756
|
+
defer: heap.release[int](data)
|
|
757
757
|
|
|
758
758
|
## Proc / closure
|
|
759
759
|
let scale = make_scaler(2.5)
|
|
@@ -1598,11 +1598,11 @@ match record:
|
|
|
1598
1598
|
<button class="copy-btn" onclick="copyCode(this)">Copy</button>
|
|
1599
1599
|
<pre><code>function main() -> int:
|
|
1600
1600
|
rl.init_window(800, 600, "Game")
|
|
1601
|
-
defer rl.close_window()
|
|
1601
|
+
defer: rl.close_window()
|
|
1602
1602
|
|
|
1603
1603
|
while not rl.window_should_close():
|
|
1604
1604
|
rl.begin_drawing()
|
|
1605
|
-
defer rl.end_drawing()
|
|
1605
|
+
defer: rl.end_drawing()
|
|
1606
1606
|
render_frame()
|
|
1607
1607
|
|
|
1608
1608
|
return 0</code></pre>
|
|
@@ -2149,8 +2149,8 @@ function attach(window: ref[Window]) -> Result[void, EventError]:
|
|
|
2149
2149
|
let closed_sub = window.closed.subscribe(on_close)?
|
|
2150
2150
|
let resized_sub = window.resized.subscribe(on_resize)?
|
|
2151
2151
|
|
|
2152
|
-
defer window.closed.unsubscribe(closed_sub)
|
|
2153
|
-
defer window.resized.unsubscribe(resized_sub)
|
|
2152
|
+
defer: window.closed.unsubscribe(closed_sub)
|
|
2153
|
+
defer: window.resized.unsubscribe(resized_sub)
|
|
2154
2154
|
|
|
2155
2155
|
return Result[void, EventError].success()</code></pre>
|
|
2156
2156
|
</div>
|
data/docs/language-design.md
CHANGED
|
@@ -119,7 +119,7 @@ extending Player:
|
|
|
119
119
|
|
|
120
120
|
function main() -> int:
|
|
121
121
|
rl.init_window(screen_width, screen_height, "Milk Tea")
|
|
122
|
-
defer rl.close_window()
|
|
122
|
+
defer: rl.close_window()
|
|
123
123
|
|
|
124
124
|
var player = Player(
|
|
125
125
|
position = rl.Vector2(x = 400.0, y = 300.0),
|
|
@@ -132,7 +132,7 @@ function main() -> int:
|
|
|
132
132
|
player.update(dt)
|
|
133
133
|
|
|
134
134
|
rl.begin_drawing()
|
|
135
|
-
defer rl.end_drawing()
|
|
135
|
+
defer: rl.end_drawing()
|
|
136
136
|
|
|
137
137
|
rl.clear_background(rl.BLACK)
|
|
138
138
|
rl.draw_circle_v(player.position, player.radius, rl.GOLD)
|
|
@@ -423,16 +423,12 @@ Milk Tea should include a small number of control-flow features that materially
|
|
|
423
423
|
|
|
424
424
|
#### `defer`
|
|
425
425
|
|
|
426
|
-
`defer` registers cleanup code at scope exit and lowers to obvious cleanup labels in C.
|
|
426
|
+
`defer` registers cleanup code at scope exit and lowers to obvious cleanup labels in C. Both forms use the block-header `:`:
|
|
427
427
|
|
|
428
428
|
```mt
|
|
429
|
-
|
|
430
|
-
|
|
431
429
|
function load_texture(path: str) -> Result[Texture, LoadError]:
|
|
432
430
|
let texture = rl.load_texture(path)
|
|
433
|
-
|
|
434
|
-
if texture.id == 0:
|
|
435
|
-
return Result[Texture, LoadError].failure(error= LoadError.file_not_found)
|
|
431
|
+
defer: rl.unload_texture(texture)
|
|
436
432
|
|
|
437
433
|
return Result[Texture, LoadError].success(value= texture)
|
|
438
434
|
```
|
data/docs/language-manual.md
CHANGED
|
@@ -596,6 +596,8 @@ if x > 10: return "big" else if x > 5: return "med" else: return "small"
|
|
|
596
596
|
|
|
597
597
|
The inline form supports all statement kinds in the body (`return`, `let`, `var`, `defer`, assignment, expression statement, etc.). Blocks and inline form may be mixed: any branch may use either form independently.
|
|
598
598
|
|
|
599
|
+
Every block-taking statement follows the same rule: a `:` followed by a newline starts an indented block, while a `:` followed by anything else on the same line introduces exactly one inline statement. This applies uniformly to `if`/`else`, `while`, `for`, `defer`, and `unsafe` (§4.3, §4.4, §4.5). `match` arms are the exception: their inline form is a single value expression (§4.2).
|
|
600
|
+
|
|
599
601
|
### 4.2 Match
|
|
600
602
|
|
|
601
603
|
Scrutinee types supported:
|
|
@@ -717,6 +719,13 @@ Single-form `for` supports:
|
|
|
717
719
|
- `span[T]`
|
|
718
720
|
- custom structural iterables with a non-editable zero-argument `iter()` method
|
|
719
721
|
|
|
722
|
+
Every loop body accepts either a `:`-newline-indented block or a single statement on the same line as the header:
|
|
723
|
+
|
|
724
|
+
```mt
|
|
725
|
+
while ready: poll()
|
|
726
|
+
for value in values: accumulate(value)
|
|
727
|
+
```
|
|
728
|
+
|
|
720
729
|
Iterator protocol for custom structural iterables:
|
|
721
730
|
|
|
722
731
|
- the iterable value must expose `iter()` with no parameters
|
|
@@ -795,10 +804,10 @@ Rules:
|
|
|
795
804
|
|
|
796
805
|
### 4.4 Defer
|
|
797
806
|
|
|
798
|
-
|
|
807
|
+
Both forms use the block-header `:` introduced in §4:
|
|
799
808
|
|
|
800
809
|
```mt
|
|
801
|
-
defer cleanup()
|
|
810
|
+
defer: cleanup()
|
|
802
811
|
|
|
803
812
|
# or
|
|
804
813
|
|
|
@@ -807,7 +816,10 @@ defer:
|
|
|
807
816
|
release_b()
|
|
808
817
|
```
|
|
809
818
|
|
|
810
|
-
|
|
819
|
+
Rules:
|
|
820
|
+
|
|
821
|
+
- `defer` always requires `:`. A single statement may follow on the same line (`defer: release_a()`), or a `:`-newline-indented block may hold several statements.
|
|
822
|
+
- `return` is not allowed inside defer blocks.
|
|
811
823
|
|
|
812
824
|
### 4.5 Unsafe
|
|
813
825
|
|
|
@@ -1363,8 +1375,8 @@ function attach(window: ref[Window]) -> Result[void, EventError]:
|
|
|
1363
1375
|
let closed_sub = window.closed.subscribe(on_close)?
|
|
1364
1376
|
let resized_sub = window.resized.subscribe(on_resize)?
|
|
1365
1377
|
|
|
1366
|
-
defer window.closed.unsubscribe(closed_sub)
|
|
1367
|
-
defer window.resized.unsubscribe(resized_sub)
|
|
1378
|
+
defer: window.closed.unsubscribe(closed_sub)
|
|
1379
|
+
defer: window.resized.unsubscribe(resized_sub)
|
|
1368
1380
|
|
|
1369
1381
|
return Result[void, EventError].success()
|
|
1370
1382
|
```
|
data/lib/milk_tea/base.rb
CHANGED
data/lib/milk_tea/core/ast.rb
CHANGED
|
@@ -212,8 +212,8 @@ module MilkTea
|
|
|
212
212
|
ReturnStmt = Data.define(:value, :line, :column, :length) do
|
|
213
213
|
def initialize(value:, line: nil, column: nil, length: nil) = super
|
|
214
214
|
end
|
|
215
|
-
DeferStmt = Data.define(:
|
|
216
|
-
def initialize(
|
|
215
|
+
DeferStmt = Data.define(:body, :line, :column, :length) do
|
|
216
|
+
def initialize(body:, line: nil, column: nil, length: nil) = super
|
|
217
217
|
end
|
|
218
218
|
ErrorBlockStmt = Data.define(:body, :line, :column, :length, :message, :header_type, :header_expression, :header_bindings, :header_iterables) do
|
|
219
219
|
def initialize(body:, line: nil, column: nil, length: nil, message: nil, header_type: nil, header_expression: nil, header_bindings: nil, header_iterables: nil) = super
|
|
@@ -212,8 +212,8 @@ module MilkTea
|
|
|
212
212
|
when AST::UnsafeStmt
|
|
213
213
|
build_block(stmt.body, next_id, break_target:, continue_target:)
|
|
214
214
|
when AST::DeferStmt
|
|
215
|
-
body_entry =
|
|
216
|
-
expression_reads, expression_reads_info =
|
|
215
|
+
body_entry = build_block(stmt.body, next_id, break_target:, continue_target:)
|
|
216
|
+
expression_reads, expression_reads_info = statement_list_reads_with_sites(stmt.body)
|
|
217
217
|
defer_id = @graph.add_node(
|
|
218
218
|
kind: :defer,
|
|
219
219
|
statement: stmt,
|
|
@@ -315,6 +315,66 @@ module MilkTea
|
|
|
315
315
|
[reads, reads_info]
|
|
316
316
|
end
|
|
317
317
|
|
|
318
|
+
def statement_list_reads_with_sites(statements)
|
|
319
|
+
reads = Set.new
|
|
320
|
+
reads_info = []
|
|
321
|
+
statement_list_read_identifiers(statements, reads, reads_info)
|
|
322
|
+
[reads, reads_info]
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def statement_list_read_identifiers(statements, reads, reads_info)
|
|
326
|
+
Array(statements).each do |statement|
|
|
327
|
+
statement_read_identifiers(statement, reads, reads_info)
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def statement_read_identifiers(statement, reads, reads_info)
|
|
332
|
+
case statement
|
|
333
|
+
when AST::ExpressionStmt
|
|
334
|
+
read_identifiers(statement.expression, reads, reads_info)
|
|
335
|
+
when AST::DeferStmt
|
|
336
|
+
statement_list_read_identifiers(statement.body, reads, reads_info)
|
|
337
|
+
when AST::LocalDecl
|
|
338
|
+
read_identifiers(statement.value, reads, reads_info)
|
|
339
|
+
statement_list_read_identifiers(statement.else_body, reads, reads_info)
|
|
340
|
+
when AST::Assignment
|
|
341
|
+
read_identifiers(statement.target, reads, reads_info)
|
|
342
|
+
read_identifiers(statement.value, reads, reads_info)
|
|
343
|
+
when AST::ReturnStmt
|
|
344
|
+
read_identifiers(statement.value, reads, reads_info)
|
|
345
|
+
when AST::IfStmt
|
|
346
|
+
statement.branches.each do |branch|
|
|
347
|
+
read_identifiers(branch.condition, reads, reads_info)
|
|
348
|
+
statement_list_read_identifiers(branch.body, reads, reads_info)
|
|
349
|
+
end
|
|
350
|
+
statement_list_read_identifiers(statement.else_body, reads, reads_info)
|
|
351
|
+
when AST::WhileStmt
|
|
352
|
+
read_identifiers(statement.condition, reads, reads_info)
|
|
353
|
+
statement_list_read_identifiers(statement.body, reads, reads_info)
|
|
354
|
+
when AST::ForStmt
|
|
355
|
+
statement.iterables.each { |iterable| read_identifiers(iterable, reads, reads_info) }
|
|
356
|
+
statement_list_read_identifiers(statement.body, reads, reads_info)
|
|
357
|
+
when AST::UnsafeStmt
|
|
358
|
+
statement_list_read_identifiers(statement.body, reads, reads_info)
|
|
359
|
+
when AST::MatchStmt
|
|
360
|
+
read_identifiers(statement.expression, reads, reads_info)
|
|
361
|
+
statement.arms.each do |arm|
|
|
362
|
+
read_identifiers(arm.pattern, reads, reads_info)
|
|
363
|
+
statement_list_read_identifiers(arm.body, reads, reads_info)
|
|
364
|
+
end
|
|
365
|
+
when AST::StaticAssert
|
|
366
|
+
read_identifiers(statement.condition, reads, reads_info)
|
|
367
|
+
read_identifiers(statement.message, reads, reads_info)
|
|
368
|
+
when AST::WhenStmt
|
|
369
|
+
read_identifiers(statement.discriminant, reads, reads_info)
|
|
370
|
+
statement.branches.each do |branch|
|
|
371
|
+
read_identifiers(branch.pattern, reads, reads_info)
|
|
372
|
+
statement_list_read_identifiers(branch.body, reads, reads_info)
|
|
373
|
+
end
|
|
374
|
+
statement_list_read_identifiers(statement.else_body, reads, reads_info)
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
318
378
|
def read_identifiers(expression, names = Set.new, reads_info = [])
|
|
319
379
|
case expression
|
|
320
380
|
when nil
|
|
@@ -145,15 +145,9 @@ module MilkTea
|
|
|
145
145
|
when AST::UnsafeStmt
|
|
146
146
|
await_counter = analyze_async_statements!(statement.body, await_counter, env, param_fields, local_fields, await_fields)
|
|
147
147
|
when AST::DeferStmt
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
await_counter = analyze_async_statements!(statement.body, await_counter, cleanup_env, param_fields, local_fields, await_fields)
|
|
152
|
-
end
|
|
153
|
-
if statement.expression.is_a?(AST::AwaitExpr)
|
|
154
|
-
await_fields[statement.expression.object_id] = build_async_await_field_info(statement.expression, await_counter, env:, param_fields:, local_fields:)
|
|
155
|
-
await_counter += 1
|
|
156
|
-
end
|
|
148
|
+
cleanup_env = duplicate_env(env)
|
|
149
|
+
cleanup_env[:return_context] = cleanup_env[:return_context]&.merge(allow_return: false)
|
|
150
|
+
await_counter = analyze_async_statements!(statement.body, await_counter, cleanup_env, param_fields, local_fields, await_fields)
|
|
157
151
|
else
|
|
158
152
|
nil
|
|
159
153
|
end
|
|
@@ -194,7 +194,7 @@ module MilkTea
|
|
|
194
194
|
when AST::UnsafeStmt
|
|
195
195
|
statements_contain_await?(s.body, async_info)
|
|
196
196
|
when AST::DeferStmt
|
|
197
|
-
|
|
197
|
+
statements_contain_await?(s.body, async_info)
|
|
198
198
|
else
|
|
199
199
|
false
|
|
200
200
|
end
|
|
@@ -1237,15 +1237,7 @@ module MilkTea
|
|
|
1237
1237
|
end
|
|
1238
1238
|
|
|
1239
1239
|
def lower_async_defer_cleanup(statement, env:, async_info:)
|
|
1240
|
-
body
|
|
1241
|
-
statement.body
|
|
1242
|
-
elsif statement.expression
|
|
1243
|
-
[AST::ExpressionStmt.new(expression: statement.expression, line: statement.line)]
|
|
1244
|
-
else
|
|
1245
|
-
[]
|
|
1246
|
-
end
|
|
1247
|
-
|
|
1248
|
-
{ body:, env: snapshot_env(env) }
|
|
1240
|
+
{ body: statement.body, env: snapshot_env(env) }
|
|
1249
1241
|
end
|
|
1250
1242
|
|
|
1251
1243
|
def lower_async_cleanup_entries(local_defers, outer_defers, frame_expr:, raw_frame_expr:, async_info:)
|
|
@@ -154,13 +154,8 @@ module MilkTea
|
|
|
154
154
|
when AST::DeferStmt
|
|
155
155
|
cleanup_env = duplicate_env(env)
|
|
156
156
|
cleanup_env[:return_context] = cleanup_env[:return_context]&.merge(allow_return: false)
|
|
157
|
-
cleanup_body =
|
|
158
|
-
|
|
159
|
-
else
|
|
160
|
-
expression_setup, expression = normalize_async_expression(statement.expression, counter, env: cleanup_env)
|
|
161
|
-
expression_setup + [AST::ExpressionStmt.new(expression:, line: statement.line)]
|
|
162
|
-
end
|
|
163
|
-
[AST::DeferStmt.new(expression: nil, body: cleanup_body, line: statement.line, column: statement.column, length: statement.length)]
|
|
157
|
+
cleanup_body = normalize_async_statements(statement.body, counter, cleanup_env, return_type:)
|
|
158
|
+
[AST::DeferStmt.new(body: cleanup_body, line: statement.line, column: statement.column, length: statement.length)]
|
|
164
159
|
when AST::BreakStmt, AST::ContinueStmt, AST::StaticAssert, AST::PassStmt
|
|
165
160
|
[statement]
|
|
166
161
|
else
|
|
@@ -16,11 +16,7 @@ module MilkTea
|
|
|
16
16
|
statements.each do |statement|
|
|
17
17
|
case statement
|
|
18
18
|
when AST::DeferStmt
|
|
19
|
-
local_defers <<
|
|
20
|
-
lower_defer_cleanup_body(statement.body, env: local_env, return_type:)
|
|
21
|
-
else
|
|
22
|
-
lower_defer_cleanup_expression(statement.expression, env: local_env)
|
|
23
|
-
end
|
|
19
|
+
local_defers << lower_defer_cleanup_body(statement.body, env: local_env, return_type:)
|
|
24
20
|
when AST::UnsafeStmt
|
|
25
21
|
lower_block_unsafe_stmt(statement, lowered:, local_defers:, local_env:, active_defers:, return_type:, loop_flow:, allow_return:)
|
|
26
22
|
when AST::LocalDecl
|
|
@@ -180,11 +180,7 @@ module MilkTea
|
|
|
180
180
|
when AST::ReturnStmt
|
|
181
181
|
collect_proc_captures_from_expression(statement.value, env, local_scopes, captures) if statement.value
|
|
182
182
|
when AST::DeferStmt
|
|
183
|
-
|
|
184
|
-
collect_proc_captures_from_statements(statement.body, env, local_scopes + [{}], captures)
|
|
185
|
-
else
|
|
186
|
-
collect_proc_captures_from_expression(statement.expression, env, local_scopes, captures)
|
|
187
|
-
end
|
|
183
|
+
collect_proc_captures_from_statements(statement.body, env, local_scopes + [{}], captures)
|
|
188
184
|
when AST::ExpressionStmt
|
|
189
185
|
collect_proc_captures_from_expression(statement.expression, env, local_scopes, captures)
|
|
190
186
|
when AST::BreakStmt, AST::ContinueStmt, AST::PassStmt
|
|
@@ -144,8 +144,10 @@ module MilkTea
|
|
|
144
144
|
(expression && expression_uses_pattern?(expression, &predicate)) || block_uses_expression_pattern?(statement.body, &predicate)
|
|
145
145
|
when AST::ReturnStmt
|
|
146
146
|
statement.value && expression_uses_pattern?(statement.value, &predicate)
|
|
147
|
-
when AST::
|
|
147
|
+
when AST::ExpressionStmt
|
|
148
148
|
expression_uses_pattern?(statement.expression, &predicate)
|
|
149
|
+
when AST::DeferStmt
|
|
150
|
+
block_uses_expression_pattern?(statement.body, &predicate)
|
|
149
151
|
else
|
|
150
152
|
false
|
|
151
153
|
end
|
|
@@ -760,32 +760,6 @@ module MilkTea
|
|
|
760
760
|
end
|
|
761
761
|
end
|
|
762
762
|
|
|
763
|
-
def lower_defer_cleanup_expression(expression, env:)
|
|
764
|
-
prepared_setup, prepared_expression, prepared_cleanups = prepare_expression_with_cleanups(
|
|
765
|
-
expression,
|
|
766
|
-
env:,
|
|
767
|
-
expected_type: infer_expression_type(expression, env:),
|
|
768
|
-
allow_root_statement_foreign: true,
|
|
769
|
-
)
|
|
770
|
-
|
|
771
|
-
lowered = []
|
|
772
|
-
lowered.concat(prepared_setup)
|
|
773
|
-
if (foreign_call = foreign_call_info(prepared_expression, env))
|
|
774
|
-
setup, = lower_foreign_call_statement(
|
|
775
|
-
foreign_call,
|
|
776
|
-
env:,
|
|
777
|
-
expected_type: foreign_call[:binding].type.return_type,
|
|
778
|
-
statement_position: true,
|
|
779
|
-
discard_result: true,
|
|
780
|
-
)
|
|
781
|
-
lowered.concat(setup)
|
|
782
|
-
else
|
|
783
|
-
lowered << IR::ExpressionStmt.new(expression: lower_expression(prepared_expression, env:))
|
|
784
|
-
end
|
|
785
|
-
lowered.concat(prepared_cleanups.flat_map(&:itself))
|
|
786
|
-
lowered
|
|
787
|
-
end
|
|
788
|
-
|
|
789
763
|
def lower_defer_cleanup_body(statements, env:, return_type:)
|
|
790
764
|
lower_block(statements, env:, active_defers: [], return_type:, loop_flow: nil, allow_return: false)
|
|
791
765
|
end
|
|
@@ -1161,7 +1135,7 @@ module MilkTea
|
|
|
1161
1135
|
cached = cache[text]
|
|
1162
1136
|
return cached if cached
|
|
1163
1137
|
|
|
1164
|
-
identifier = text.gsub(/[^A-Za-z0-9_]+/, "_").gsub(/_+/, "_").sub(/_+$/, "").sub(/^_
|
|
1138
|
+
identifier = text.gsub(/[^A-Za-z0-9_]+/, "_").gsub(/_+/, "_").sub(/_+$/, "").sub(/^_+/, "")
|
|
1165
1139
|
cache[text] = identifier.empty? ? "value" : identifier
|
|
1166
1140
|
end
|
|
1167
1141
|
|
|
@@ -279,6 +279,18 @@ module MilkTea
|
|
|
279
279
|
check(:colon) && @current + 1 < @tokens.length && @tokens[@current + 1].type != :newline
|
|
280
280
|
end
|
|
281
281
|
|
|
282
|
+
def parse_inline_or_block_body(message)
|
|
283
|
+
if inline_block_body?
|
|
284
|
+
consume(:colon, "expected ':' #{message}")
|
|
285
|
+
@in_inline_block_body = true
|
|
286
|
+
result = [parse_statement]
|
|
287
|
+
@in_inline_block_body = false
|
|
288
|
+
result
|
|
289
|
+
else
|
|
290
|
+
parse_block
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
282
294
|
def parse_match_stmt
|
|
283
295
|
token = previous
|
|
284
296
|
line = token.line
|
|
@@ -456,7 +468,7 @@ module MilkTea
|
|
|
456
468
|
consume(:in, "expected 'in' in for loop")
|
|
457
469
|
iterables = [parse_expression]
|
|
458
470
|
iterables << parse_expression while match(:comma)
|
|
459
|
-
body =
|
|
471
|
+
body = parse_inline_or_block_body("after 'in' iterables")
|
|
460
472
|
AST::ForStmt.new(bindings:, iterables:, body:, line:, column: bindings.first.column)
|
|
461
473
|
rescue ParseError => e
|
|
462
474
|
raise unless @recovery_errors
|
|
@@ -530,7 +542,7 @@ module MilkTea
|
|
|
530
542
|
token = previous
|
|
531
543
|
line = token.line
|
|
532
544
|
condition = parse_expression
|
|
533
|
-
body =
|
|
545
|
+
body = parse_inline_or_block_body("after while condition")
|
|
534
546
|
AST::WhileStmt.new(condition:, body:, line:, column: token.column, length: token.lexeme.length)
|
|
535
547
|
rescue ParseError => e
|
|
536
548
|
raise unless @recovery_errors
|
|
@@ -580,14 +592,8 @@ module MilkTea
|
|
|
580
592
|
def parse_defer_stmt
|
|
581
593
|
token = previous
|
|
582
594
|
line = token.line
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
AST::DeferStmt.new(expression: nil, body:, line:, column: token.column, length: token.lexeme.length)
|
|
586
|
-
else
|
|
587
|
-
expression = parse_expression
|
|
588
|
-
consume_end_of_statement unless block_expression?(expression)
|
|
589
|
-
AST::DeferStmt.new(expression:, body: nil, line:, column: token.column, length: token.lexeme.length)
|
|
590
|
-
end
|
|
595
|
+
body = parse_inline_or_block_body("after defer")
|
|
596
|
+
AST::DeferStmt.new(body:, line:, column: token.column, length: token.lexeme.length)
|
|
591
597
|
end
|
|
592
598
|
|
|
593
599
|
def parse_when_decl
|
|
@@ -690,7 +696,7 @@ module MilkTea
|
|
|
690
696
|
consume(:in, "expected 'in' in for loop")
|
|
691
697
|
iterables = [parse_expression]
|
|
692
698
|
iterables << parse_expression while match(:comma)
|
|
693
|
-
body =
|
|
699
|
+
body = parse_inline_or_block_body("after 'in' iterables")
|
|
694
700
|
AST::ForStmt.new(bindings:, iterables:, body:, inline: true, line:, column: bindings.first.column)
|
|
695
701
|
rescue ParseError => e
|
|
696
702
|
raise unless @recovery_errors
|
|
@@ -705,7 +711,7 @@ module MilkTea
|
|
|
705
711
|
def parse_inline_while_stmt(inline_token)
|
|
706
712
|
line = inline_token.line
|
|
707
713
|
condition = parse_expression
|
|
708
|
-
body =
|
|
714
|
+
body = parse_inline_or_block_body("after inline while condition")
|
|
709
715
|
AST::WhileStmt.new(condition:, body:, inline: true, line:, column: inline_token.column, length: inline_token.lexeme.length)
|
|
710
716
|
rescue ParseError => e
|
|
711
717
|
raise unless @recovery_errors
|
|
@@ -521,13 +521,9 @@ module MilkTea
|
|
|
521
521
|
when AST::ReturnStmt
|
|
522
522
|
line(statement.value ? "return #{render_expression(statement.value)}" : "return")
|
|
523
523
|
when AST::DeferStmt
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
statement.body.each { |nested| emit_statement(nested) }
|
|
528
|
-
end
|
|
529
|
-
else
|
|
530
|
-
line("defer #{render_expression(statement.expression)}")
|
|
524
|
+
line("defer:")
|
|
525
|
+
with_indent do
|
|
526
|
+
statement.body.each { |nested| emit_statement(nested) }
|
|
531
527
|
end
|
|
532
528
|
when AST::ExpressionStmt
|
|
533
529
|
line(render_expression(statement.expression))
|
|
@@ -649,10 +645,6 @@ module MilkTea
|
|
|
649
645
|
"continue"
|
|
650
646
|
when AST::ReturnStmt
|
|
651
647
|
statement.value ? "return #{render_expression(statement.value)}" : "return"
|
|
652
|
-
when AST::DeferStmt
|
|
653
|
-
return nil if statement.body
|
|
654
|
-
|
|
655
|
-
"defer #{render_expression(statement.expression)}"
|
|
656
648
|
when AST::ExpressionStmt
|
|
657
649
|
render_expression(statement.expression)
|
|
658
650
|
else
|
|
@@ -180,8 +180,7 @@ module MilkTea
|
|
|
180
180
|
when AST::UnsafeStmt
|
|
181
181
|
statement.body.each { |s| validate_async_statement!(s) }
|
|
182
182
|
when AST::DeferStmt
|
|
183
|
-
|
|
184
|
-
statement.body&.each { |s| validate_async_statement!(s) }
|
|
183
|
+
statement.body.each { |s| validate_async_statement!(s) }
|
|
185
184
|
when AST::WhenStmt
|
|
186
185
|
statement.branches.each { |branch| branch.body.each { |s| validate_async_statement!(s) } }
|
|
187
186
|
statement.else_body&.each { |s| validate_async_statement!(s) }
|
|
@@ -230,7 +229,7 @@ module MilkTea
|
|
|
230
229
|
when AST::ReturnStmt
|
|
231
230
|
statement.value && expression_contains_await?(statement.value)
|
|
232
231
|
when AST::DeferStmt
|
|
233
|
-
|
|
232
|
+
statements_contain_await?(statement.body)
|
|
234
233
|
when AST::ExpressionStmt
|
|
235
234
|
expression_contains_await?(statement.expression)
|
|
236
235
|
else
|
|
@@ -209,7 +209,7 @@ module MilkTea
|
|
|
209
209
|
end
|
|
210
210
|
end
|
|
211
211
|
when AST::DeferStmt
|
|
212
|
-
lines.concat(statement_list_lines(statement.body))
|
|
212
|
+
lines.concat(statement_list_lines(statement.body))
|
|
213
213
|
when AST::Assignment
|
|
214
214
|
lines << expression_end_line(statement.value)
|
|
215
215
|
when AST::ReturnStmt
|
|
@@ -375,9 +375,8 @@ module MilkTea
|
|
|
375
375
|
body_names = names.dup
|
|
376
376
|
stmt.body&.each { |s| check_stmt_names(s, scopes, binding, body_names) }
|
|
377
377
|
when AST::DeferStmt
|
|
378
|
-
check_expr_names(stmt.expression, scopes, binding, names) if stmt.expression
|
|
379
378
|
body_names = names.dup
|
|
380
|
-
stmt.body
|
|
379
|
+
stmt.body.each { |s| check_stmt_names(s, scopes, binding, body_names) }
|
|
381
380
|
when AST::WhenStmt
|
|
382
381
|
check_expr_names(stmt.discriminant, scopes, binding, names)
|
|
383
382
|
stmt.branches.each do |b|
|
|
@@ -154,8 +154,7 @@ module MilkTea
|
|
|
154
154
|
statement.iterables.each { |iterable| preassign_local_binding_ids_in_expression(iterable) }
|
|
155
155
|
preassign_local_binding_ids_in_statements(statement.body || [])
|
|
156
156
|
when AST::DeferStmt
|
|
157
|
-
|
|
158
|
-
preassign_local_binding_ids_in_statements(statement.body || []) if statement.body
|
|
157
|
+
preassign_local_binding_ids_in_statements(statement.body)
|
|
159
158
|
when AST::ReturnStmt
|
|
160
159
|
preassign_local_binding_ids_in_expression(statement.value) if statement.value
|
|
161
160
|
when AST::StaticAssert
|
|
@@ -319,8 +318,7 @@ module MilkTea
|
|
|
319
318
|
end
|
|
320
319
|
walk_statements_for_precheck_resolution(statement.body || [], for_scopes, declaration_ids, identifier_ids)
|
|
321
320
|
when AST::DeferStmt
|
|
322
|
-
|
|
323
|
-
walk_statements_for_precheck_resolution(statement.body || [], block_scopes, declaration_ids, identifier_ids) if statement.body
|
|
321
|
+
walk_statements_for_precheck_resolution(statement.body, block_scopes, declaration_ids, identifier_ids)
|
|
324
322
|
when AST::ExpressionStmt
|
|
325
323
|
walk_expression_for_precheck_resolution(statement.expression, block_scopes, identifier_ids, declaration_ids)
|
|
326
324
|
when AST::ReturnStmt
|
|
@@ -193,14 +193,8 @@ module MilkTea
|
|
|
193
193
|
line: statement.line,
|
|
194
194
|
)
|
|
195
195
|
when AST::DeferStmt
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
check_block(statement.body, scopes:, return_type:, allow_return: false)
|
|
199
|
-
end
|
|
200
|
-
else
|
|
201
|
-
validate_consuming_foreign_expression!(statement.expression, scopes:, root_allowed: true)
|
|
202
|
-
validate_hoistable_foreign_expression!(statement.expression, scopes:, root_hoistable: false)
|
|
203
|
-
infer_expression(statement.expression, scopes:)
|
|
196
|
+
with_loop_barrier do
|
|
197
|
+
check_block(statement.body, scopes:, return_type:, allow_return: false)
|
|
204
198
|
end
|
|
205
199
|
when AST::ExpressionStmt
|
|
206
200
|
validate_consuming_foreign_expression!(statement.expression, scopes:, root_allowed: true)
|
|
@@ -484,8 +484,7 @@ module MilkTea
|
|
|
484
484
|
when AST::UnsafeStmt
|
|
485
485
|
stmt.body.each { |child| collect_indirect_import_uses_from_stmt(child, used, binding_resolution, import_module_names) }
|
|
486
486
|
when AST::DeferStmt
|
|
487
|
-
|
|
488
|
-
stmt.body&.each { |child| collect_indirect_import_uses_from_stmt(child, used, binding_resolution, import_module_names) }
|
|
487
|
+
stmt.body.each { |child| collect_indirect_import_uses_from_stmt(child, used, binding_resolution, import_module_names) }
|
|
489
488
|
when AST::ReturnStmt
|
|
490
489
|
collect_indirect_import_uses_from_expr(stmt.value, used, binding_resolution, import_module_names) if stmt.value
|
|
491
490
|
when AST::ExpressionStmt
|
|
@@ -766,8 +765,7 @@ module MilkTea
|
|
|
766
765
|
when AST::UnsafeStmt
|
|
767
766
|
stmt.body.each { |s| collect_names_from_statement(s, used) }
|
|
768
767
|
when AST::DeferStmt
|
|
769
|
-
|
|
770
|
-
stmt.body&.each { |s| collect_names_from_statement(s, used) }
|
|
768
|
+
stmt.body.each { |s| collect_names_from_statement(s, used) }
|
|
771
769
|
when AST::ReturnStmt
|
|
772
770
|
collect_names_from_expr(stmt.value, used) if stmt.value
|
|
773
771
|
when AST::ExpressionStmt
|