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

Commit 1cb6925

Browse files
committed
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 type IntOrStr = int | str type ListOrSet[T] = list[T] | set[T] type AnimalOrVegetable = Animal | "Vegetable" 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 dba9ff1 commit 1cb6925

9 files changed

+10620
-8360
lines changed

Diff for: parser/build.rs

+1
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")

Diff for: parser/src/parser.rs

+83-7
Original file line numberDiff line numberDiff line change
@@ -882,10 +882,89 @@ except* OSError as e:
882882
assert!(parse(source, Mode::Interactive, "<embedded>").is_ok());
883883
}
884884

885+
#[test]
886+
fn test_parse_type_declaration() {
887+
let source = r#"
888+
type X = int
889+
type X = int | str
890+
type X = int | "ForwardRefY"
891+
type X[T] = T | list[X[T]] # recursive
892+
type X[T] = int
893+
type X[T] = list[T] | set[T]
894+
type X[T, *Ts, **P] = (T, Ts, P)
895+
type X[T: int, *Ts, **P] = (T, Ts, P)
896+
type X[T: (int, str), *Ts, **P] = (T, Ts, P)
897+
898+
# soft keyword as alias name
899+
type type = int
900+
type match = int
901+
type case = int
902+
903+
# soft keyword as value
904+
type foo = type
905+
type foo = match
906+
type foo = case
907+
908+
# multine definitions
909+
type \
910+
X = int
911+
type X \
912+
= int
913+
type X = \
914+
int
915+
type X = (
916+
int
917+
)
918+
type \
919+
X[T] = T
920+
type X \
921+
[T] = T
922+
type X[T] \
923+
= T
924+
"#;
925+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
926+
}
927+
928+
#[test]
929+
fn test_type_as_identifier() {
930+
let source = r#"\
931+
type *a + b, c # ((type * a) + b), c
932+
type *(a + b), c # (type * (a + b)), c
933+
type (*a + b, c) # type ((*(a + b)), c)
934+
type -a * b + c # (type - (a * b)) + c
935+
type -(a * b) + c # (type - (a * b)) + c
936+
type (-a) * b + c # (type (-(a * b))) + c
937+
type ().a # (type()).a
938+
type (()).a # (type(())).a
939+
type ((),).a # (type(())).a
940+
type [a].b # (type[a]).b
941+
type [a,].b # (type[(a,)]).b (not (type[a]).b)
942+
type [(a,)].b # (type[(a,)]).b
943+
type()[a:
944+
b] # (type())[a: b]
945+
if type := 1: pass
946+
type = lambda query: query == event
947+
print(type(12))
948+
type(type)
949+
a = (
950+
type in C
951+
)
952+
a = (
953+
type(b)
954+
)
955+
type (
956+
X = int
957+
)
958+
type = 1
959+
type = x = 1
960+
x = type = 1
961+
"#;
962+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
963+
}
964+
885965
#[test]
886966
fn test_match_as_identifier() {
887-
let parse_ast = ast::Suite::parse(
888-
r#"
967+
let source = r#"\
889968
match *a + b, c # ((match * a) + b), c
890969
match *(a + b), c # (match * (a + b)), c
891970
match (*a + b, c) # match ((*(a + b)), c)
@@ -907,11 +986,8 @@ match match:
907986
pass
908987
match = lambda query: query == event
909988
print(match(12))
910-
"#,
911-
"<test>",
912-
)
913-
.unwrap();
914-
insta::assert_debug_snapshot!(parse_ast);
989+
"#;
990+
insta::assert_debug_snapshot!(ast::Suite::parse(source, "<test>").unwrap());
915991
}
916992

917993
#[test]

Diff for: parser/src/python.lalrpop

+21
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.into(), 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()?;
@@ -1757,6 +1777,7 @@ extern {
17571777
"raise" => token::Tok::Raise,
17581778
"return" => token::Tok::Return,
17591779
"try" => token::Tok::Try,
1780+
"type" => token::Tok::Type,
17601781
"while" => token::Tok::While,
17611782
"match" => token::Tok::Match,
17621783
"case" => token::Tok::Case,

Diff for: parser/src/python.rs

+8,536-8,195
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)