Skip to content
This repository was archived by the owner on Jul 27, 2023. It is now read-only.

Commit 704eb40

Browse files
authored
Add parsing of type alias statements i.e. the type keyword (RustPython#97)
Extends RustPython#95 Closes RustPython#82 Adds parsing of new `type` soft keyword for defining type aliases. Supports type alias statements as defined in PEP 695 e.g. ```python # A non-generic type alias type IntOrStr = int | str # A generic type alias type ListOrSet[T] = list[T] | set[T] # A type alias that includes a forward reference type AnimalOrVegetable = Animal | "Vegetable" # A generic self-referential type alias type RecursiveList[T] = T | list[RecursiveList[T]] ``` All type parameter kinds are supported as in RustPython#95. Builds on soft keyword abstractions introduced in RustPython/RustPython#4519
1 parent 6980037 commit 704eb40

9 files changed

+10920
-8447
lines changed

parser/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ fn gen_phf(out_dir: &Path) {
154154
.entry("raise", "Tok::Raise")
155155
.entry("return", "Tok::Return")
156156
.entry("try", "Tok::Try")
157+
.entry("type", "Tok::Type")
157158
.entry("while", "Tok::While")
158159
.entry("with", "Tok::With")
159160
.entry("yield", "Tok::Yield")

parser/src/parser.rs

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -894,11 +894,92 @@ except* OSError as e:
894894
assert!(parse(source, Mode::Interactive, "<embedded>").is_ok());
895895
}
896896

897+
#[test]
898+
#[cfg(feature = "all-nodes-with-ranges")]
899+
fn test_parse_type_declaration() {
900+
let source = r#"
901+
type X = int
902+
type X = int | str
903+
type X = int | "ForwardRefY"
904+
type X[T] = T | list[X[T]] # recursive
905+
type X[T] = int
906+
type X[T] = list[T] | set[T]
907+
type X[T, *Ts, **P] = (T, Ts, P)
908+
type X[T: int, *Ts, **P] = (T, Ts, P)
909+
type X[T: (int, str), *Ts, **P] = (T, Ts, P)
910+
911+
# soft keyword as alias name
912+
type type = int
913+
type match = int
914+
type case = int
915+
916+
# soft keyword as value
917+
type foo = type
918+
type foo = match
919+
type foo = case
920+
921+
# multine definitions
922+
type \
923+
X = int
924+
type X \
925+
= int
926+
type X = \
927+
int
928+
type X = (
929+
int
930+
)
931+
type \
932+
X[T] = T
933+
type X \
934+
[T] = T
935+
type X[T] \
936+
= T
937+
"#;
938+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
939+
}
940+
941+
#[test]
942+
#[cfg(feature = "all-nodes-with-ranges")]
943+
fn test_type_as_identifier() {
944+
let source = r#"\
945+
type *a + b, c # ((type * a) + b), c
946+
type *(a + b), c # (type * (a + b)), c
947+
type (*a + b, c) # type ((*(a + b)), c)
948+
type -a * b + c # (type - (a * b)) + c
949+
type -(a * b) + c # (type - (a * b)) + c
950+
type (-a) * b + c # (type (-(a * b))) + c
951+
type ().a # (type()).a
952+
type (()).a # (type(())).a
953+
type ((),).a # (type(())).a
954+
type [a].b # (type[a]).b
955+
type [a,].b # (type[(a,)]).b (not (type[a]).b)
956+
type [(a,)].b # (type[(a,)]).b
957+
type()[a:
958+
b] # (type())[a: b]
959+
if type := 1: pass
960+
type = lambda query: query == event
961+
print(type(12))
962+
type(type)
963+
a = (
964+
type in C
965+
)
966+
a = (
967+
type(b)
968+
)
969+
type (
970+
X = int
971+
)
972+
type = 1
973+
type = x = 1
974+
x = type = 1
975+
"#;
976+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
977+
}
978+
897979
#[test]
898980
#[cfg(feature = "all-nodes-with-ranges")]
899981
fn test_match_as_identifier() {
900-
let parse_ast = ast::Suite::parse(
901-
r#"
982+
let source = r#"\
902983
match *a + b, c # ((match * a) + b), c
903984
match *(a + b), c # (match * (a + b)), c
904985
match (*a + b, c) # match ((*(a + b)), c)
@@ -920,11 +1001,8 @@ match match:
9201001
pass
9211002
match = lambda query: query == event
9221003
print(match(12))
923-
"#,
924-
"<test>",
925-
)
926-
.unwrap();
927-
insta::assert_debug_snapshot!(parse_ast);
1004+
"#;
1005+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
9281006
}
9291007

9301008
#[test]

parser/src/python.lalrpop

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ SmallStatement: ast::Stmt = {
8686
GlobalStatement,
8787
NonlocalStatement,
8888
AssertStatement,
89+
TypeAliasStatement,
8990
};
9091

9192
PassStatement: ast::Stmt = {
@@ -978,6 +979,25 @@ FuncDef: ast::Stmt = {
978979
},
979980
};
980981

982+
TypeAliasName: ast::Expr = {
983+
<location:@L> <name:Identifier> <end_location:@R> => ast::Expr::Name(
984+
ast::ExprName { id: name, ctx: ast::ExprContext::Load, range: (location..end_location).into() },
985+
),
986+
}
987+
988+
TypeAliasStatement: ast::Stmt = {
989+
<location:@L> "type" <name:TypeAliasName> <type_params:TypeParamList?> "=" <value:Test<"all">> <end_location:@R> => {
990+
ast::Stmt::TypeAlias(
991+
ast::StmtTypeAlias {
992+
name: Box::new(name),
993+
value: Box::new(value),
994+
type_params: type_params.unwrap_or_default(),
995+
range: (location..end_location).into()
996+
},
997+
)
998+
},
999+
};
1000+
9811001
Parameters: ast::Arguments = {
9821002
<location:@L> "(" <a: (ParameterList<TypedParameter, StarTypedParameter, DoubleStarTypedParameter>)?> ")" <end_location:@R> =>? {
9831003
a.as_ref().map(validate_arguments).transpose()?;
@@ -1750,6 +1770,7 @@ extern {
17501770
"raise" => token::Tok::Raise,
17511771
"return" => token::Tok::Return,
17521772
"try" => token::Tok::Try,
1773+
"type" => token::Tok::Type,
17531774
"while" => token::Tok::While,
17541775
"match" => token::Tok::Match,
17551776
"case" => token::Tok::Case,

parser/src/python.rs

Lines changed: 8630 additions & 8289 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)