Skip to content

Commit 7ddf868

Browse files
committed
[GR-18231] Add support for positional only parameters.
Initial commit of the positional parameters only feature. Also contains fix for: [GR-19934] SyntaxError duplicate arguments is not raised.
1 parent b6bbe48 commit 7ddf868

File tree

9 files changed

+656
-7
lines changed

9 files changed

+656
-7
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/parser/FuncDefTests.java

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public class FuncDefTests extends ParserTestBase {
5050
public void args01() throws Exception {
5151
checkScopeAndTree("def fn(a, b=0, *arg, k1, k2=0): return a + b + k1 + k2 + sum(arg)");
5252
}
53+
54+
@Test
55+
public void args02() throws Exception {
56+
checkSyntaxErrorMessage("def f(a, a): pass", "SyntaxError: duplicate argument 'a' in function definition");
57+
}
5358

5459
@Test
5560
public void functionDoc01() throws Exception {
@@ -227,6 +232,241 @@ public void recursion02() throws Exception {
227232
" recursionInner(0)");
228233
}
229234

235+
@Test
236+
public void positionalOnlyArg01() throws Exception {
237+
checkTreeResult("def name(p1, p2, /, p_or_kw, *, kw): pass");
238+
}
239+
240+
@Test
241+
public void positionalOnlyArg02() throws Exception {
242+
checkTreeResult("def name(p1, p2=None, /, p_or_kw=None, *, kw): pass");
243+
}
244+
245+
@Test
246+
public void positionalOnlyArg03() throws Exception {
247+
checkTreeResult("def name(p1, p2=None, /, *, kw): pass");
248+
}
249+
250+
@Test
251+
public void positionalOnlyArg04() throws Exception {
252+
checkTreeResult("def name(p1, p2=None, /): pass");
253+
}
254+
255+
@Test
256+
public void positionalOnlyArg05() throws Exception {
257+
checkTreeResult("def name(p1, p2, /, p_or_kw): pass");
258+
}
259+
260+
@Test
261+
public void positionalOnlyArg06() throws Exception {
262+
checkTreeResult("def name(p1, p2, /): pass");
263+
}
264+
265+
@Test
266+
public void positionalOnlyArg07() throws Exception {
267+
checkSyntaxErrorMessage("def name(p1, p2=None, /, p_or_kw, *, kw): pass", "SyntaxError: non-default argument follows default argument");
268+
}
269+
270+
@Test
271+
public void positionalOnlyArg08() throws Exception {
272+
checkSyntaxErrorMessage("def name(p1=None, p2, /, p_or_kw=None, *, kw): pass", "SyntaxError: non-default argument follows default argument");
273+
}
274+
275+
@Test
276+
public void positionalOnlyArg09() throws Exception {
277+
checkSyntaxErrorMessage("def name(p1=None, p2, /): pass", "SyntaxError: non-default argument follows default argument");
278+
}
279+
280+
@Test
281+
public void positionalOnlyArg10() throws Exception {
282+
checkSyntaxErrorMessage("def f(a, b = 5, /, c): pass", "SyntaxError: non-default argument follows default argument");
283+
}
284+
285+
@Test
286+
public void positionalOnlyArg11() throws Exception {
287+
checkSyntaxErrorMessage("def f(a = 5, b, /, c): pass", "SyntaxError: non-default argument follows default argument");
288+
}
289+
290+
@Test
291+
public void positionalOnlyArg12() throws Exception {
292+
checkSyntaxErrorMessage("def f(a = 5, b=1, /, c, *, d=2): pass", "SyntaxError: non-default argument follows default argument");
293+
}
294+
295+
@Test
296+
public void positionalOnlyArg13() throws Exception {
297+
checkSyntaxErrorMessage("def f(a = 5, b, /): pass", "SyntaxError: non-default argument follows default argument");
298+
}
299+
300+
@Test
301+
public void positionalOnlyArg14() throws Exception {
302+
checkSyntaxError("def f(*args, /): pass");
303+
}
304+
305+
@Test
306+
public void positionalOnlyArg15() throws Exception {
307+
checkSyntaxError("def f(*args, a, /): pass");
308+
}
309+
310+
@Test
311+
public void positionalOnlyArg16() throws Exception {
312+
checkSyntaxError("def f(**kwargs, /): pass");
313+
}
314+
315+
@Test
316+
public void positionalOnlyArg17() throws Exception {
317+
checkSyntaxError("def f(/, a = 1): pass");
318+
}
319+
320+
@Test
321+
public void positionalOnlyArg18() throws Exception {
322+
checkSyntaxError("def f(/, a): pass");
323+
}
324+
325+
@Test
326+
public void positionalOnlyArg19() throws Exception {
327+
checkSyntaxError("def f(/): pass");
328+
}
329+
330+
@Test
331+
public void positionalOnlyArg20() throws Exception {
332+
checkSyntaxError("def f(*, a, /): pass");
333+
}
334+
335+
@Test
336+
public void positionalOnlyArg21() throws Exception {
337+
checkSyntaxError("def f(*, /, a): pass");
338+
}
339+
340+
@Test
341+
public void positionalOnlyArg22() throws Exception {
342+
checkSyntaxErrorMessage("def f(a, /, a): pass", "SyntaxError: duplicate argument 'a' in function definition");
343+
}
344+
345+
@Test
346+
public void positionalOnlyArg23() throws Exception {
347+
checkSyntaxErrorMessage("def f(a, /, *, a): pass", "SyntaxError: duplicate argument 'a' in function definition");
348+
}
349+
350+
@Test
351+
public void positionalOnlyArg24() throws Exception {
352+
checkSyntaxError("def f(a, b/2, c): pass");
353+
}
354+
355+
@Test
356+
public void positionalOnlyArg25() throws Exception {
357+
checkSyntaxError("def f(a, /, c, /): pass");
358+
}
359+
360+
@Test
361+
public void positionalOnlyArg26() throws Exception {
362+
checkSyntaxError("def f(a, /, c, /, d): pass");
363+
}
364+
365+
@Test
366+
public void positionalOnlyArg27() throws Exception {
367+
checkSyntaxError("def f(a, /, c, /, d, *, e): pass");
368+
}
369+
370+
@Test
371+
public void positionalOnlyArg28() throws Exception {
372+
checkSyntaxError("def f(a, *, c, /, d, e): pass");
373+
}
374+
375+
@Test
376+
public void positionalOnlyArg29() throws Exception {
377+
checkSyntaxErrorMessage("async def f(a, b = 5, /, c): pass", "SyntaxError: non-default argument follows default argument");
378+
}
379+
380+
@Test
381+
public void positionalOnlyArg30() throws Exception {
382+
checkSyntaxErrorMessage("async def f(a = 5, b, /, c): pass", "SyntaxError: non-default argument follows default argument");
383+
}
384+
385+
@Test
386+
public void positionalOnlyArg31() throws Exception {
387+
checkSyntaxErrorMessage("async def f(a = 5, b=1, /, c, d=2): pass", "SyntaxError: non-default argument follows default argument");
388+
}
389+
390+
@Test
391+
public void positionalOnlyArg32() throws Exception {
392+
checkSyntaxErrorMessage("async def f(a = 5, b, /): pass", "SyntaxError: non-default argument follows default argument");
393+
}
394+
395+
@Test
396+
public void positionalOnlyArg33() throws Exception {
397+
checkSyntaxError("async def f(*args, /): pass");
398+
}
399+
400+
@Test
401+
public void positionalOnlyArg34() throws Exception {
402+
checkSyntaxError("async def f(*args, a, /): pass");
403+
}
404+
405+
@Test
406+
public void positionalOnlyArg35() throws Exception {
407+
checkSyntaxError("async def f(**kwargs, /): pass");
408+
}
409+
410+
@Test
411+
public void positionalOnlyArg36() throws Exception {
412+
checkSyntaxError("async def f(/, a = 1): pass");
413+
}
414+
415+
@Test
416+
public void positionalOnlyArg37() throws Exception {
417+
checkSyntaxError("async def f(/, a): pass");
418+
}
419+
420+
@Test
421+
public void positionalOnlyArg38() throws Exception {
422+
checkSyntaxError("async def f(/): pass");
423+
}
424+
425+
@Test
426+
public void positionalOnlyArg39() throws Exception {
427+
checkSyntaxError("async def f(*, a, /): pass");
428+
}
429+
430+
@Test
431+
public void positionalOnlyArg40() throws Exception {
432+
checkSyntaxError("async def f(*, /, a): pass");
433+
}
434+
435+
@Test
436+
public void positionalOnlyArg41() throws Exception {
437+
checkSyntaxErrorMessage("async def f(a, /, a): pass", "SyntaxError: duplicate argument 'a' in function definition");
438+
}
439+
440+
@Test
441+
public void positionalOnlyArg42() throws Exception {
442+
checkSyntaxErrorMessage("async def f(a, /, *, a): pass", "SyntaxError: duplicate argument 'a' in function definition");
443+
}
444+
445+
@Test
446+
public void positionalOnlyArg43() throws Exception {
447+
checkSyntaxError("async def f(a, b/2, c): pass");
448+
}
449+
450+
@Test
451+
public void positionalOnlyArg44() throws Exception {
452+
checkSyntaxError("async def f(a, /, c, /): pass");
453+
}
454+
455+
@Test
456+
public void positionalOnlyArg45() throws Exception {
457+
checkSyntaxError("async def f(a, /, c, /, d): pass");
458+
}
459+
460+
@Test
461+
public void positionalOnlyArg46() throws Exception {
462+
checkSyntaxError("async def f(a, /, c, /, d, *, e): pass");
463+
}
464+
465+
@Test
466+
public void positionalOnlyArg47() throws Exception {
467+
checkSyntaxError("async def f(a, *, c, /, d, e): pass");
468+
}
469+
230470
private void checkScopeAndTree() throws Exception {
231471
File testFile = getTestFileFromTestAndTestMethod();
232472
checkScopeFromFile(testFile, true);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
ModuleRootNode Name: <module 'positionalOnlyArg01'> SourceSection: [0,41]`def name(p1, p2, /, ...`
2+
Signature: varArgs=False, varKeywordArgs=False, noArguments=True, positionalOnly=True, requiresKeywordArgs=False
3+
FreeVars: None
4+
NeedsCellFrame: False
5+
FrameDescriptor: Empty
6+
Documentation: None
7+
InnerRootNode SourceSection: [0,41]`def name(p1, p2, /, ...`
8+
ExpressionWithSideEffect SourceSection: [0,41]`def name(p1, p2, /, ...`
9+
Expression:
10+
EmptyNode SourceSection: None
11+
SideEffect:
12+
WriteNameNodeGen SourceSection: [0,41]`def name(p1, p2, /, ...`
13+
Identifier: name
14+
FunctionDefinitionNode Name: name SourceSection: None
15+
Arguments: None
16+
KwArguments: None
17+
Documentation: StringLiteralNode: Empty
18+
FreeVarSlots: None
19+
ExecutionSlots:
20+
FreeVarsSlots: None
21+
CellVarsSlots: None
22+
FunctionRootNode SourceSection: [0,41]`def name(p1, p2, /, ...`
23+
Name: name
24+
Signature: varArgs=False, varKeywordArgs=False, noArguments=False, positionalOnly=False, requiresKeywordArgs=True
25+
Param Names: p1, p2, p_or_kw
26+
Keyword Names: kw
27+
CelVars: None
28+
FreeVars: None
29+
NeedsCellFrame: False
30+
FrameDescriptor: 6 slots [p1, p2, p_or_kw, *, kw, <return_val>]
31+
ExecutionSlots:
32+
FreeVarsSlots: None
33+
CellVarsSlots: None
34+
InnerRootNode SourceSection: [0,41]`def name(p1, p2, /, ...`
35+
ReturnTargetNode SourceSection: [0,41]`def name(p1, p2, /, ...`
36+
Body: BlockNode SourceSection: None
37+
BlockNode SourceSection: None
38+
WriteLocalVariableNodeGen SourceSection: None
39+
Identifier: p1
40+
WriteLocalFrameSlotNodeGen SourceSection: None
41+
Frame: [0,p1,Illegal]
42+
ArgumentExpressionNode SourceSection: None
43+
ReadIndexedArgumentNodeGen SourceSection: None
44+
Index: 0
45+
WriteLocalVariableNodeGen SourceSection: None
46+
Identifier: p2
47+
WriteLocalFrameSlotNodeGen SourceSection: None
48+
Frame: [1,p2,Illegal]
49+
ArgumentExpressionNode SourceSection: None
50+
ReadIndexedArgumentNodeGen SourceSection: None
51+
Index: 1
52+
WriteLocalVariableNodeGen SourceSection: None
53+
Identifier: p_or_kw
54+
WriteLocalFrameSlotNodeGen SourceSection: None
55+
Frame: [2,p_or_kw,Illegal]
56+
ArgumentExpressionNode SourceSection: None
57+
ReadIndexedArgumentNodeGen SourceSection: None
58+
Index: 2
59+
WriteLocalVariableNodeGen SourceSection: None
60+
Identifier: kw
61+
WriteLocalFrameSlotNodeGen SourceSection: None
62+
Frame: [4,kw,Illegal]
63+
ArgumentExpressionNode SourceSection: None
64+
ReadIndexedArgumentNodeGen SourceSection: None
65+
Index: 3
66+
ExpressionStatementNode SourceSection: [37,41]`pass`
67+
EmptyNode SourceSection: [37,41]`pass`
68+
Return Expresssion: ReadLocalVariableNode SourceSection: None
69+
Frame: [5,<return_val>,Illegal]
70+
ReadVariableFromFrameNodeGen SourceSection: None
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
ModuleRootNode Name: <module 'positionalOnlyArg02'> SourceSection: [0,51]`def name(p1, p2=None...`
2+
Signature: varArgs=False, varKeywordArgs=False, noArguments=True, positionalOnly=True, requiresKeywordArgs=False
3+
FreeVars: None
4+
NeedsCellFrame: False
5+
FrameDescriptor: Empty
6+
Documentation: None
7+
InnerRootNode SourceSection: [0,51]`def name(p1, p2=None...`
8+
ExpressionWithSideEffect SourceSection: [0,51]`def name(p1, p2=None...`
9+
Expression:
10+
EmptyNode SourceSection: None
11+
SideEffect:
12+
WriteNameNodeGen SourceSection: [0,51]`def name(p1, p2=None...`
13+
Identifier: name
14+
FunctionDefinitionNode Name: name SourceSection: None
15+
Arguments:
16+
ObjectLiteralNode SourceSection: [16,20]`None`
17+
ObjectLiteralNode SourceSection: [33,37]`None`
18+
KwArguments: None
19+
Documentation: StringLiteralNode: Empty
20+
FreeVarSlots: None
21+
ExecutionSlots:
22+
FreeVarsSlots: None
23+
CellVarsSlots: None
24+
FunctionRootNode SourceSection: [0,51]`def name(p1, p2=None...`
25+
Name: name
26+
Signature: varArgs=False, varKeywordArgs=False, noArguments=False, positionalOnly=False, requiresKeywordArgs=True
27+
Param Names: p1, p2, p_or_kw
28+
Keyword Names: kw
29+
CelVars: None
30+
FreeVars: None
31+
NeedsCellFrame: False
32+
FrameDescriptor: 6 slots [p1, p2, p_or_kw, *, kw, <return_val>]
33+
ExecutionSlots:
34+
FreeVarsSlots: None
35+
CellVarsSlots: None
36+
InnerRootNode SourceSection: [0,51]`def name(p1, p2=None...`
37+
ReturnTargetNode SourceSection: [0,51]`def name(p1, p2=None...`
38+
Body: BlockNode SourceSection: None
39+
BlockNode SourceSection: None
40+
WriteLocalVariableNodeGen SourceSection: None
41+
Identifier: p1
42+
WriteLocalFrameSlotNodeGen SourceSection: None
43+
Frame: [0,p1,Illegal]
44+
ArgumentExpressionNode SourceSection: None
45+
ReadIndexedArgumentNodeGen SourceSection: None
46+
Index: 0
47+
WriteLocalVariableNodeGen SourceSection: None
48+
Identifier: p2
49+
WriteLocalFrameSlotNodeGen SourceSection: None
50+
Frame: [1,p2,Illegal]
51+
ArgumentExpressionNode SourceSection: None
52+
ReadIndexedArgumentNodeGen SourceSection: None
53+
Index: 1
54+
WriteLocalVariableNodeGen SourceSection: None
55+
Identifier: p_or_kw
56+
WriteLocalFrameSlotNodeGen SourceSection: None
57+
Frame: [2,p_or_kw,Illegal]
58+
ArgumentExpressionNode SourceSection: None
59+
ReadIndexedArgumentNodeGen SourceSection: None
60+
Index: 2
61+
WriteLocalVariableNodeGen SourceSection: None
62+
Identifier: kw
63+
WriteLocalFrameSlotNodeGen SourceSection: None
64+
Frame: [4,kw,Illegal]
65+
ArgumentExpressionNode SourceSection: None
66+
ReadIndexedArgumentNodeGen SourceSection: None
67+
Index: 3
68+
ExpressionStatementNode SourceSection: [47,51]`pass`
69+
EmptyNode SourceSection: [47,51]`pass`
70+
Return Expresssion: ReadLocalVariableNode SourceSection: None
71+
Frame: [5,<return_val>,Illegal]
72+
ReadVariableFromFrameNodeGen SourceSection: None

0 commit comments

Comments
 (0)