Skip to content

Commit 706a330

Browse files
authored
Implement function captures. (#749)
1 parent 82e9273 commit 706a330

File tree

7 files changed

+115
-14
lines changed

7 files changed

+115
-14
lines changed

spec/compilers/call_captured

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
component Main {
2+
fun test (argument1 : String, argument2: Number) : Html {
3+
<div/>
4+
}
5+
6+
fun render : Html {
7+
test(_, _)("A", 0)
8+
}
9+
}
10+
--------------------------------------------------------------------------------
11+
import { createElement as A } from "./runtime.js";
12+
13+
export const B = () => {
14+
const a = (b, c) => {
15+
return A(`div`, {})
16+
};
17+
return ((d, e) => {
18+
a(d, e)
19+
})(`A`, 0)
20+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
component Main {
2+
fun test (argument1 : String, argument2: Number) : String {
3+
""
4+
}
5+
6+
fun render : String {
7+
test(argument2: 0, argument1: _)("")
8+
}
9+
}
10+
--------------------------------------------------------------------------------
11+
export const A = () => {
12+
const a = (b, c) => {
13+
return ``
14+
};
15+
return ((d) => {
16+
a(d, 0)
17+
})(``)
18+
};

spec/examples/call

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,36 @@ component Main {
161161
}
162162
}
163163
-------------------------------------------------------------------------------
164+
component Main {
165+
fun test (argument1 : String, argument2: Number) : Html {
166+
<div/>
167+
}
168+
169+
fun render : Html {
170+
test(_, _)("A", 0)
171+
}
172+
}
173+
-------------------------------------------------------------------------------
174+
component Main {
175+
fun test (argument1 : String, argument2: Number) : Html {
176+
<div/>
177+
}
178+
179+
fun render : Html {
180+
test("A", _)(0)
181+
}
182+
}
183+
-------------------------------------------------------------------------------
184+
component Main {
185+
fun test (argument1 : String, argument2: Number) : Html {
186+
<div/>
187+
}
188+
189+
fun render : Html {
190+
test(_, 0)("A")
191+
}
192+
}
193+
-------------------------------------------------------------------------------
164194
module Test {
165195
fun a (x : Bool, value : String) : String {
166196
value

src/compilers/call.cr

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,21 @@ module Mint
55
expression =
66
compile node.expression
77

8+
captures =
9+
[] of Compiled
10+
811
arguments =
912
node
1013
.arguments
1114
.sort_by { |item| resolve_order.index(item) || -1 }
12-
.map { |item| compile item }
15+
.map do |item|
16+
case item.value
17+
when Ast::Discard
18+
[Variable.new.as(Item)].tap { |var| captures << var }
19+
else
20+
compile item
21+
end
22+
end
1323

1424
receiver =
1525
case
@@ -19,7 +29,14 @@ module Mint
1929
expression
2030
end
2131

22-
js.call(receiver, arguments)
32+
call =
33+
js.call(receiver, arguments)
34+
35+
if captures.size > 0
36+
["("] + js.arrow_function(captures) { call } + [")"]
37+
else
38+
call
39+
end
2340
end
2441
end
2542
end

src/parsers/call.cr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Mint
88
arguments = list(
99
terminator: ')',
1010
separator: ','
11-
) { field(key_required: false) }
11+
) { field(key_required: false, discard: true) }
1212

1313
whitespace
1414
next error :call_expected_closing_parenthesis do

src/parsers/field.cr

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Mint
22
class Parser
3-
def field(*, key_required : Bool = true) : Ast::Field?
3+
def field(*, key_required : Bool = true, discard : Bool = false) : Ast::Field?
44
parse do |start_position|
55
comment = self.comment
66
whitespace
@@ -17,7 +17,13 @@ module Mint
1717
end
1818

1919
next if key_required && !key
20-
next unless value = expression
20+
21+
next unless value =
22+
if discard
23+
self.discard || expression
24+
else
25+
expression
26+
end
2127

2228
Ast::Field.new(
2329
from: start_position,

src/type_checkers/call.cr

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ module Mint
2424
argument_size
2525
end
2626

27-
parameters =
28-
[] of Checkable
29-
3027
error! :call_argument_size_mismatch do
3128
block do
3229
text "The function you called takes"
@@ -71,13 +68,22 @@ module Mint
7168
end
7269
end
7370

74-
args.each_with_index do |argument, index|
75-
argument_type =
76-
resolve argument
71+
parameters = [] of Checkable
72+
captures = [] of Checkable
7773

74+
args.each_with_index do |argument, index|
7875
function_argument_type =
7976
function_type.parameters[index]
8077

78+
argument_type =
79+
case argument.value
80+
when Ast::Discard
81+
captures << function_argument_type
82+
function_argument_type
83+
else
84+
resolve argument
85+
end
86+
8187
error! :call_argument_type_mismatch do
8288
ordinal =
8389
ordinal(index + 1)
@@ -116,10 +122,14 @@ module Mint
116122

117123
final = resolve_type(result.parameters.last)
118124

119-
if node.await && final.name == "Promise"
120-
final.parameters.first
125+
if captures.empty?
126+
if node.await && final.name == "Promise"
127+
final.parameters.first
128+
else
129+
final
130+
end
121131
else
122-
final
132+
Type.new("Function", captures + [final])
123133
end
124134
end
125135
end

0 commit comments

Comments
 (0)