Skip to content

Commit 3387692

Browse files
committed
feat: Add Python 3.10-3.14 syntax support
- Add Python 3.10 pattern matching (match/case statements) - Support literal, capture, wildcard, class, sequence, and mapping patterns - Support or patterns, as patterns, and guard conditions - Add Python 3.12 type parameter syntax (PEP 695) - Generic class and function type parameters: class Stack[T], def first[T]() - TypeVar, TypeVarTuple (*Ts), ParamSpec (**P) support - Type constraints: T: int, T: (int, str) - Type alias statement: type Vector = list[float] - Add Python 3.14 features - Template strings (t-strings): t"...", tr"..." - Bracketless except (PEP 758): except ValueError, TypeError: - Update PythonVersion enum with Python310, Python312, Python314 - Add comprehensive test suite for all new syntax features - All existing tests pass
1 parent 948159b commit 3387692

4 files changed

Lines changed: 683 additions & 4 deletions

File tree

chapi-ast-python/src/main/antlr/PythonLexer.g4

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ EXEC : 'exec';
7373
TRUE : 'True';
7474
FALSE : 'False';
7575

76+
// Python 3.10+ soft keywords (can also be used as identifiers)
77+
MATCH : 'match';
78+
CASE : 'case';
79+
80+
// Python 3.12+ soft keywords
81+
TYPE : 'type';
82+
7683
// Operators
7784

7885
DOT : '.';
@@ -118,7 +125,8 @@ RIGHT_SHIFT_ASSIGN : '>>=';
118125
POWER_ASSIGN : '**=';
119126
IDIV_ASSIGN : '//=';
120127

121-
STRING : ([uU] | [fF] [rR]? | [rR] [fF]?)? (SHORT_STRING | LONG_STRING)
128+
// String literals including Python 3.14 t-strings
129+
STRING : ([uU] | [fF] [rR]? | [rR] [fF]? | [tT] [rR]? | [rR] [tT])? (SHORT_STRING | LONG_STRING)
122130
| ([bB] [rR]? | [rR] [bB]) (SHORT_BYTES | LONG_BYTES)
123131
;
124132

chapi-ast-python/src/main/antlr/PythonParser.g4

Lines changed: 185 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ compound_stmt
6464
| TRY COLON suite (except_clause+ else_clause? finally_clause? | finally_clause) #try_stmt
6565
| ASYNC? WITH with_item (COMMA with_item)* COLON suite #with_stmt
6666
| decorator* (classdef | funcdef) #class_or_func_def_stmt
67+
| match_stmt #match_stmt_wrapper
6768
;
6869

6970
suite
@@ -87,23 +88,199 @@ finally_clause
8788
: FINALLY COLON suite
8889
;
8990

91+
// Python 3.10+ match statement (PEP 634)
92+
match_stmt
93+
: MATCH subject_expr COLON LINE_BREAK INDENT case_block+ DEDENT
94+
;
95+
96+
subject_expr
97+
: star_named_expression COMMA star_named_expressions?
98+
| named_expression
99+
;
100+
101+
star_named_expressions
102+
: (COMMA star_named_expression)+ COMMA?
103+
;
104+
105+
star_named_expression
106+
: STAR expr
107+
| named_expression
108+
;
109+
110+
named_expression
111+
: name ASSIGN test
112+
| test
113+
;
114+
115+
case_block
116+
: CASE pattern guard? COLON suite
117+
;
118+
119+
guard
120+
: IF test
121+
;
122+
123+
// Pattern matching patterns
124+
pattern
125+
: or_pattern
126+
| as_pattern
127+
;
128+
129+
as_pattern
130+
: or_pattern AS pattern_capture_target
131+
;
132+
133+
or_pattern
134+
: closed_pattern (OR_OP closed_pattern)*
135+
;
136+
137+
closed_pattern
138+
: literal_pattern
139+
| capture_pattern
140+
| wildcard_pattern
141+
| class_pattern
142+
| sequence_pattern
143+
| mapping_pattern
144+
| group_pattern
145+
;
146+
147+
literal_pattern
148+
: MINUS? number
149+
| STRING+
150+
| NONE
151+
| TRUE
152+
| FALSE
153+
;
154+
155+
capture_pattern
156+
: pattern_capture_target
157+
;
158+
159+
pattern_capture_target
160+
: name
161+
;
162+
163+
wildcard_pattern
164+
: NAME // Matches '_' specifically, handled semantically
165+
;
166+
167+
class_pattern
168+
: dotted_name OPEN_PAREN pattern_arguments? CLOSE_PAREN
169+
;
170+
171+
pattern_arguments
172+
: positional_patterns COMMA keyword_patterns COMMA?
173+
| positional_patterns COMMA?
174+
| keyword_patterns COMMA?
175+
;
176+
177+
positional_patterns
178+
: pattern (COMMA pattern)*
179+
;
180+
181+
keyword_patterns
182+
: keyword_pattern (COMMA keyword_pattern)*
183+
;
184+
185+
keyword_pattern
186+
: name ASSIGN pattern
187+
;
188+
189+
sequence_pattern
190+
: OPEN_BRACKET maybe_sequence_pattern? CLOSE_BRACKET
191+
| OPEN_PAREN open_sequence_pattern? CLOSE_PAREN
192+
;
193+
194+
open_sequence_pattern
195+
: maybe_star_pattern COMMA maybe_sequence_pattern?
196+
;
197+
198+
maybe_sequence_pattern
199+
: maybe_star_pattern (COMMA maybe_star_pattern)* COMMA?
200+
;
201+
202+
maybe_star_pattern
203+
: star_pattern
204+
| pattern
205+
;
206+
207+
star_pattern
208+
: STAR (pattern_capture_target | wildcard_pattern)
209+
;
210+
211+
mapping_pattern
212+
: OPEN_BRACE items_pattern? CLOSE_BRACE
213+
;
214+
215+
items_pattern
216+
: key_value_pattern (COMMA key_value_pattern)* COMMA?
217+
;
218+
219+
key_value_pattern
220+
: (literal_pattern | attr) COLON pattern
221+
| double_star_pattern
222+
;
223+
224+
double_star_pattern
225+
: POWER pattern_capture_target
226+
;
227+
228+
attr
229+
: dotted_name
230+
;
231+
232+
group_pattern
233+
: OPEN_PAREN pattern CLOSE_PAREN
234+
;
235+
90236
with_item
91237
// NB compile.c makes sure that the default except clause is last
92238
: test (AS expr)?
93239
;
94240

95241
// Python 2 : EXCEPT test COMMA name
96242
// Python 3 : EXCEPT test AS name
243+
// Python 3.14+ (PEP 758): EXCEPT test, test, test without parentheses (only WITHOUT AS clause)
97244
except_clause
98245
: EXCEPT (test ({CheckVersion(2)}? COMMA name {SetVersion(2);} | {CheckVersion(3)}? AS name {SetVersion(3);})?)? COLON suite
246+
| EXCEPT except_types COLON suite // Python 3.14+ without parentheses (no AS clause allowed)
247+
;
248+
249+
// Python 3.14+ allows multiple exception types without parentheses
250+
except_types
251+
: test (COMMA test)+
99252
;
100253

101254
classdef
102-
: CLASS name (OPEN_PAREN arglist? CLOSE_PAREN)? COLON suite
255+
: CLASS name type_params? (OPEN_PAREN arglist? CLOSE_PAREN)? COLON suite
103256
;
104257

105258
funcdef
106-
: ASYNC? DEF name OPEN_PAREN typedargslist? CLOSE_PAREN (ARROW test)? COLON suite
259+
: ASYNC? DEF name type_params? OPEN_PAREN typedargslist? CLOSE_PAREN (ARROW test)? COLON suite
260+
;
261+
262+
// Python 3.12+ type parameter syntax (PEP 695)
263+
type_params
264+
: OPEN_BRACKET type_param_list CLOSE_BRACKET
265+
;
266+
267+
type_param_list
268+
: type_param (COMMA type_param)* COMMA?
269+
;
270+
271+
type_param
272+
: name type_param_bound? // TypeVar: T, T: int
273+
| STAR name // TypeVarTuple: *Ts
274+
| POWER name // ParamSpec: **P
275+
;
276+
277+
type_param_bound
278+
: COLON test // T: SomeType or T: (Type1, Type2)
279+
;
280+
281+
// Python 3.12+ type alias statement (PEP 695)
282+
type_alias_stmt
283+
: TYPE name type_params? ASSIGN test
107284
;
108285

109286
// python 3 paramters
@@ -159,6 +336,7 @@ small_stmt
159336
| {CheckVersion(2)}? EXEC expr (IN test (COMMA test)?)? {SetVersion(2);} #exec_stmt // Python 2
160337
| ASSERT test (COMMA test)? #assert_stmt
161338
| {CheckVersion(3)}? NONLOCAL name (COMMA name)* {SetVersion(3);} #nonlocal_stmt // Python 3
339+
| type_alias_stmt #type_stmt // Python 3.12+
162340
;
163341

164342
import_dot_ellipsis : (DOT | ELLIPSIS) ;
@@ -313,6 +491,11 @@ name
313491
: NAME
314492
| TRUE
315493
| FALSE
494+
// Python 3.10+ soft keywords (can be used as identifiers)
495+
| MATCH
496+
| CASE
497+
// Python 3.12+ soft keywords
498+
| TYPE
316499
;
317500

318501
number

chapi-ast-python/src/main/java/chapi/ast/antlr/PythonVersion.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
package chapi.ast.antlr;
22

3+
/**
4+
* Python version enumeration for syntax compatibility.
5+
*
6+
* Version history:
7+
* - Python 3.10: Pattern matching (match/case)
8+
* - Python 3.12: Type parameter syntax (PEP 695), type statement
9+
* - Python 3.14: Template strings (t-strings), bracketless except (PEP 758)
10+
*/
311
public enum PythonVersion {
412
Autodetect(0),
513
Python2(2),
6-
Python3(3);
14+
Python3(3),
15+
Python310(310), // Pattern matching
16+
Python312(312), // Type parameter syntax
17+
Python314(314); // Template strings, bracketless except
718

819
private final int value;
920

@@ -14,4 +25,25 @@ public enum PythonVersion {
1425
public int getValue() {
1526
return value;
1627
}
28+
29+
/**
30+
* Check if this version supports Python 3.10+ features (pattern matching)
31+
*/
32+
public boolean supportsPatternMatching() {
33+
return this == Autodetect || value >= 310 || this == Python3;
34+
}
35+
36+
/**
37+
* Check if this version supports Python 3.12+ features (type parameters)
38+
*/
39+
public boolean supportsTypeParameters() {
40+
return this == Autodetect || value >= 312;
41+
}
42+
43+
/**
44+
* Check if this version supports Python 3.14+ features (t-strings, bracketless except)
45+
*/
46+
public boolean supportsPython314Features() {
47+
return this == Autodetect || value >= 314;
48+
}
1749
}

0 commit comments

Comments
 (0)