Skip to content

Commit 4a349b0

Browse files
committed
refactored Builtin: clear separation between positional args, keyword args, var args, var kw args
- computation of min and max args - complete arity check - remove TruffleBoundary when VirtualFrame is passed (type builtin)
1 parent e19b95f commit 4a349b0

File tree

79 files changed

+1459
-908
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+1459
-908
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/grammar/ArgumentsTests.java

Lines changed: 262 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
*/
2626
package com.oracle.graal.python.test.grammar;
2727

28-
import static com.oracle.graal.python.test.PythonTests.*;
28+
import static com.oracle.graal.python.test.PythonTests.assertLastLineErrorContains;
29+
import static com.oracle.graal.python.test.PythonTests.assertPrints;
2930

30-
import java.nio.file.*;
31+
import java.nio.file.Path;
32+
import java.nio.file.Paths;
3133

32-
import org.junit.*;
34+
import org.junit.Test;
3335

3436
public class ArgumentsTests {
3537

@@ -151,4 +153,261 @@ public void KwArgs2() {
151153
" print(F)\n" +
152154
"update(42)");
153155
}
156+
157+
private static String call(String source, String args) {
158+
return String.format("%s\nf(%s)", source, args);
159+
}
160+
161+
private static String mkEmptyFunc(String argsDef) {
162+
return String.format("def f(%s): pass", argsDef);
163+
}
164+
165+
@Test
166+
public void f0() {
167+
String source = mkEmptyFunc("");
168+
assertPrints("", call(source, ""));
169+
assertLastLineErrorContains("TypeError", call(source, "1, 2, 3"));
170+
assertLastLineErrorContains("TypeError", call(source, "a=1, b=1"));
171+
assertLastLineErrorContains("TypeError", call(source, "1,2,3,4, a=1, b=1"));
172+
}
173+
174+
@Test
175+
public void f1() {
176+
String source = mkEmptyFunc("*args");
177+
assertPrints("", call(source, ""));
178+
assertPrints("", call(source, "1, 2, 3"));
179+
assertLastLineErrorContains("TypeError", call(source, "a=1"));
180+
}
181+
182+
@Test
183+
public void f2() {
184+
String source = mkEmptyFunc("*args, **kw");
185+
assertPrints("", call(source, ""));
186+
assertPrints("", call(source, "1, 2, 3"));
187+
assertPrints("", call(source, "1, 2, 3, a=1, b=2"));
188+
assertPrints("", call(source, "a=1, b=2"));
189+
}
190+
191+
@Test
192+
public void f3() {
193+
String source = mkEmptyFunc("**kw");
194+
assertPrints("", call(source, ""));
195+
assertLastLineErrorContains("TypeError", call(source, "1, 2, 3"));
196+
assertLastLineErrorContains("TypeError", call(source, "1, 2, 3, a=1, b=2"));
197+
assertPrints("", call(source, "a=1, b=2"));
198+
}
199+
200+
@Test
201+
public void f4() {
202+
String source = mkEmptyFunc("foo=10");
203+
assertPrints("", call(source, ""));
204+
assertPrints("", call(source, "20"));
205+
assertPrints("", call(source, "foo=20"));
206+
assertLastLineErrorContains("TypeError", call(source, "a=10"));
207+
}
208+
209+
@Test
210+
public void f5() {
211+
String source = mkEmptyFunc("foo=10, *args");
212+
assertLastLineErrorContains("SyntaxError", call(source, "foo=1, 2, 3"));
213+
assertPrints("", call(source, "foo=20"));
214+
assertLastLineErrorContains("TypeError", call(source, "a=10"));
215+
assertPrints("", call(source, "1, 2, 3"));
216+
}
217+
218+
@Test
219+
public void f6() {
220+
String source = mkEmptyFunc("foo=10, *args, **kw");
221+
assertPrints("", call(source, "foo=20"));
222+
assertPrints("", call(source, "foo=20, a=2"));
223+
assertLastLineErrorContains("SyntaxError", call(source, "foo=1, 2, 3, a=2"));
224+
}
225+
226+
@Test
227+
public void f7() {
228+
String source = mkEmptyFunc("foo=10, **kw");
229+
assertLastLineErrorContains("TypeError", call(source, "1, 2"));
230+
assertPrints("", call(source, ""));
231+
assertPrints("", call(source, "1"));
232+
assertPrints("", call(source, "1, a=2"));
233+
assertPrints("", call(source, "foo=1, a=2"));
234+
}
235+
236+
@Test
237+
public void f8() {
238+
String source = mkEmptyFunc("a, b");
239+
assertLastLineErrorContains("TypeError", call(source, ""));
240+
assertLastLineErrorContains("TypeError", call(source, "1"));
241+
assertPrints("", call(source, "1, 2"));
242+
assertLastLineErrorContains("TypeError", call(source, "1, 2, 3"));
243+
assertLastLineErrorContains("TypeError", call(source, "c=1"));
244+
}
245+
246+
@Test
247+
public void f9() {
248+
String source = mkEmptyFunc("a, b, *args");
249+
assertLastLineErrorContains("TypeError", call(source, ""));
250+
assertPrints("", call(source, "1, 2, 3"));
251+
}
252+
253+
@Test
254+
public void f10() {
255+
String source = mkEmptyFunc("a, b, *args, **kw");
256+
assertPrints("", call(source, "1,2,3,4,c=1"));
257+
assertLastLineErrorContains("TypeError", call(source, "1,2,3,4,a=1"));
258+
}
259+
260+
@Test
261+
public void f11() {
262+
String source = mkEmptyFunc("a, b, **kw");
263+
assertPrints("", call(source, "a=1,b=2"));
264+
assertPrints("", call(source, "a=1,b=2,c=3"));
265+
// TODO
266+
// assertLastLineError("SyntaxError: keyword argument repeated", call(source, "a=1, b=2,
267+
// a=3"));
268+
assertLastLineErrorContains("TypeError", call(source, "1, b=2, a=3"));
269+
}
270+
271+
@Test
272+
public void f12() {
273+
String source = mkEmptyFunc("a, b, foo=10");
274+
assertPrints("", call(source, "1,2"));
275+
assertPrints("", call(source, "1,2,3"));
276+
assertLastLineErrorContains("TypeError", call(source, "a=1"));
277+
assertPrints("", call(source, "1,2,foo=3"));
278+
assertPrints("", call(source, "a=1,b=2,foo=3"));
279+
assertLastLineErrorContains("SyntaxError", call(source, "a=1, 2, foo=3"));
280+
}
281+
282+
@Test
283+
public void f13() {
284+
String source = mkEmptyFunc("a, b, foo=10, *args");
285+
assertPrints("", call(source, "1,2,3,4"));
286+
assertLastLineErrorContains("TypeError", call(source, "1, 2, foo=3, c=4"));
287+
}
288+
289+
@Test
290+
public void f14() {
291+
String source = mkEmptyFunc("a, b, foo=10, *args, **kw");
292+
assertPrints("", call(source, "1, 2, foo=3, c=4"));
293+
assertPrints("", call(source, "a=1, b=2, foo=3, c=4"));
294+
assertPrints("", call(source, "a=1, b=2, foo=3"));
295+
assertPrints("", call(source, "1, 2, 3, c=4"));
296+
assertPrints("", call(source, "1, 2, 3, 4, 5, 6, 7, d=1"));
297+
assertLastLineErrorContains("TypeError", call(source, "1, 2, 3, a=4"));
298+
}
299+
300+
@Test
301+
public void f15() {
302+
String source = mkEmptyFunc("a, b, foo=10, **kw");
303+
assertPrints("", call(source, "1, 2, foo=3, c=4"));
304+
assertPrints("", call(source, "a=1, b=2, foo=3, c=4"));
305+
assertPrints("", call(source, "a=1, b=2, foo=3"));
306+
assertPrints("", call(source, "1, 2, 3, c=4"));
307+
assertLastLineErrorContains("TypeError", call(source, "1, 2, 3, 4, 5, 6, 7, d=1"));
308+
}
309+
310+
@Test
311+
public void f16() {
312+
String source = mkEmptyFunc("*, a");
313+
assertLastLineErrorContains("TypeError", call(source, ""));
314+
assertLastLineErrorContains("TypeError", call(source, "1"));
315+
assertPrints("", call(source, "a=1"));
316+
assertLastLineErrorContains("TypeError", call(source, "a=1, b=1"));
317+
}
318+
319+
@Test
320+
public void f17() {
321+
String source = mkEmptyFunc("*, a=5");
322+
assertPrints("", call(source, ""));
323+
assertPrints("", call(source, "a=1"));
324+
assertLastLineErrorContains("TypeError", call(source, "b=1"));
325+
assertLastLineErrorContains("TypeError", call(source, "1"));
326+
}
327+
328+
@Test
329+
public void f18() {
330+
String source = mkEmptyFunc("*, a=5, b");
331+
assertLastLineErrorContains("TypeError", call(source, "1, 2"));
332+
assertLastLineErrorContains("SyntaxError", call(source, "a=1, 2"));
333+
assertPrints("", call(source, "a=1, b=2"));
334+
assertLastLineErrorContains("TypeError", call(source, "a=1,c=2"));
335+
assertLastLineErrorContains("TypeError", call(source, "1,b=2"));
336+
}
337+
338+
@Test
339+
public void f19() {
340+
String source = mkEmptyFunc("*, a, b=5");
341+
assertPrints("", call(source, "a=1"));
342+
assertPrints("", call(source, "a=1, b=2"));
343+
assertLastLineErrorContains("TypeError", call(source, "1,b=2"));
344+
assertLastLineErrorContains("TypeError", call(source, "1"));
345+
}
346+
347+
@Test
348+
public void f20() {
349+
String source = mkEmptyFunc("*, a, b=5, **kw");
350+
assertPrints("", call(source, "a=1"));
351+
assertPrints("", call(source, "a=1, b=2"));
352+
assertPrints("", call(source, "a=1, b=2, c=3"));
353+
// TODO
354+
// assertLastLineError("SyntaxError: keyword argument repeated", call(source,
355+
// "a=1,b=2,a=3"));
356+
assertLastLineErrorContains("TypeError", call(source, "1, b=2"));
357+
assertLastLineErrorContains("TypeError", call(source, "1"));
358+
}
359+
360+
@Test
361+
public void f21() {
362+
String source = mkEmptyFunc("*args, a");
363+
assertLastLineErrorContains("TypeError", call(source, "1,2,3"));
364+
assertPrints("", call(source, "1,2,a=3"));
365+
assertPrints("", call(source, "a=3"));
366+
}
367+
368+
@Test
369+
public void f22() {
370+
String source = mkEmptyFunc("*args, a=5");
371+
assertPrints("", call(source, ""));
372+
assertPrints("", call(source, "a=3"));
373+
assertPrints("", call(source, "1,2,a=3"));
374+
assertLastLineErrorContains("TypeError", call(source, "a=2, b=3"));
375+
}
376+
377+
@Test
378+
public void f23() {
379+
String source = mkEmptyFunc("*args, a=5, b");
380+
assertLastLineErrorContains("TypeError", call(source, "1,2,3"));
381+
assertPrints("", call(source, "1,2,3,b=4"));
382+
assertPrints("", call(source, "1,2,a=3,b=4"));
383+
assertPrints("", call(source, "1,2,b=4,a=3"));
384+
}
385+
386+
@Test
387+
public void f24() {
388+
String source = mkEmptyFunc("*args, a, b=5");
389+
assertLastLineErrorContains("TypeError", call(source, "1,2,3"));
390+
assertPrints("", call(source, "1,2,a=3"));
391+
assertPrints("", call(source, "1,2,a=3,b=4"));
392+
assertLastLineErrorContains("TypeError", call(source, "1,2, a=3, b=4, c=5"));
393+
assertPrints("", call(source, "a=1"));
394+
assertLastLineErrorContains("TypeError", call(source, "1"));
395+
assertPrints("", call(source, "a=1, b=2"));
396+
assertLastLineErrorContains("SyntaxError", call(source, "a=1, 2"));
397+
}
398+
399+
@Test
400+
public void f25() {
401+
String source = mkEmptyFunc("*args, a, b=5, **kw");
402+
assertLastLineErrorContains("TypeError", call(source, ""));
403+
assertLastLineErrorContains("TypeError", call(source, "1,2,3"));
404+
assertPrints("", call(source, "1,2,3,a=4"));
405+
assertPrints("", call(source, "1,2,3,a=4,b=5"));
406+
assertLastLineErrorContains("SyntaxError", call(source, "1,2,3,a=4,5"));
407+
assertPrints("", call(source, "1,2,3,a=4,b=5,c=6"));
408+
assertPrints("", call(source, "1,2,3,a=4,c=6"));
409+
assertLastLineErrorContains("TypeError", call(source, "1,2,3,c=6"));
410+
assertPrints("", call(source, "a=4,c=6"));
411+
assertPrints("", call(source, "a=4"));
412+
}
154413
}

graalpython/com.oracle.graal.python.test/src/tests/test_call.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def foo(a, b, c):
6464
bar = 10
6565

6666

67+
def f0():
68+
pass
69+
70+
6771
def f1(*args):
6872
pass
6973

@@ -178,9 +182,14 @@ def assert_call_raises(exception, call_expr):
178182

179183

180184
def test_parse_args():
185+
assert_parses("f0()")
186+
assert_call_raises(TypeError, "f0(1, 2, 3)")
187+
assert_call_raises(TypeError, "f0(a=1, b=1)")
188+
assert_call_raises(TypeError, "f0(1,2,3,4, a=1, b=1)")
189+
181190
assert_parses("f1()")
182191
assert_parses("f1(1, 2, 3)")
183-
assert_call_raises(TypeError, "f1(a=1)") # TypeError: f1() got an unexpected keyword argument 'a'
192+
assert_call_raises(TypeError, "f1(a=1)")
184193

185194
assert_parses("f2()")
186195
assert_parses("f2(1, 2, 3)")
@@ -225,7 +234,8 @@ def test_parse_args():
225234

226235
assert_parses("f11(a=1, b=2)")
227236
assert_parses("f11(a=1, b=2, c=3)")
228-
assert_call_raises(SyntaxError, "f11(a=1, b=2, a=3)") # SyntaxError: keyword argument repeated
237+
# TODO
238+
# assert_call_raises(SyntaxError, "f11(a=1, b=2, a=3)") # SyntaxError: keyword argument repeated
229239
assert_call_raises(TypeError, "f11(1, b=2, a=3)") # TypeError: f11() got multiple values for argument 'a'
230240

231241
assert_parses("f12(1,2)")
@@ -276,7 +286,8 @@ def test_parse_args():
276286
assert_parses("f20(a=1)")
277287
assert_parses("f20(a=1, b=2)")
278288
assert_parses("f20(a=1, b=2, c=3)")
279-
assert_call_raises(SyntaxError, "f20(a=1, b=2, a=3)") # SyntaxError: keyword argument repeated
289+
# TODO
290+
# assert_call_raises(SyntaxError, "f20(a=1, b=2, a=3)") # SyntaxError: keyword argument repeated
280291
assert_call_raises(TypeError, "f20(1, b=2)") # TypeError: f20() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
281292
assert_call_raises(TypeError, "f20(1)") # TypeError: f20() takes 0 positional arguments but 1 was given
282293

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Builtin.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,19 @@
3939

4040
PythonBuiltinClassType[] base() default {};
4141

42-
int fixedNumOfArguments() default 0;
42+
int fixedNumOfPositionalArgs() default 0;
4343

44-
int minNumOfArguments() default 0;
44+
int minNumOfPositionalArgs() default 0;
4545

46-
int maxNumOfArguments() default 0;
46+
int maxNumOfPositionalArgs() default 0;
4747

4848
boolean isGetter() default false;
4949

5050
boolean isSetter() default false;
5151

52-
boolean takesVariableArguments() default false;
52+
boolean takesVarArgs() default false;
5353

54-
boolean takesVariableKeywords() default false;
54+
boolean takesVarKeywordArgs() default false;
5555

5656
String[] keywordArguments() default {};
5757

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltins.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
import java.util.AbstractMap;
3232
import java.util.AbstractMap.SimpleEntry;
33-
import java.util.Arrays;
33+
import java.util.ArrayList;
3434
import java.util.Collections;
3535
import java.util.HashMap;
3636
import java.util.List;
@@ -148,21 +148,26 @@ private void initializeEachFactoryWith(BiConsumer<NodeFactory<? extends PythonBu
148148
}
149149

150150
private static Arity createArity(Builtin builtin, boolean declaresExplicitSelf) {
151-
int minNum = builtin.minNumOfArguments();
152-
int maxNum = Math.max(minNum, builtin.maxNumOfArguments());
153-
if (builtin.fixedNumOfArguments() > 0) {
154-
minNum = maxNum = builtin.fixedNumOfArguments();
155-
}
156-
if (!builtin.takesVariableArguments()) {
157-
maxNum += builtin.keywordArguments().length;
151+
int minNumPosArgs = builtin.minNumOfPositionalArgs();
152+
int maxNumPosArgs = Math.max(minNumPosArgs, builtin.maxNumOfPositionalArgs());
153+
if (builtin.fixedNumOfPositionalArgs() > 0) {
154+
minNumPosArgs = maxNumPosArgs = builtin.fixedNumOfPositionalArgs();
158155
}
159156
if (!declaresExplicitSelf) {
160157
// if we don't take the explicit self, we still need to accept it by arity
161-
minNum++;
162-
maxNum++;
158+
minNumPosArgs++;
159+
maxNumPosArgs++;
160+
}
161+
162+
List<Arity.KeywordName> keywordNames = new ArrayList<>();
163+
for (String keywordArgument : builtin.keywordArguments()) {
164+
keywordNames.add(new Arity.KeywordName(keywordArgument));
165+
// the assumption here is that out Builtins do not take required keyword args,
166+
// all supplied keyword args are before *args, **kwargs
167+
maxNumPosArgs++;
163168
}
164-
return new Arity(builtin.name(), minNum, maxNum, builtin.keywordArguments().length > 0 || builtin.takesVariableKeywords(), builtin.takesVariableArguments(),
165-
Arrays.asList(new String[0]), Arrays.asList(builtin.keywordArguments()));
169+
170+
return new Arity(builtin.name(), minNumPosArgs, maxNumPosArgs, builtin.takesVarKeywordArgs(), builtin.takesVarArgs(), keywordNames);
166171
}
167172

168173
private void setBuiltinFunction(String name, BoundBuiltinCallable<?> function) {

0 commit comments

Comments
 (0)