@@ -11,6 +11,7 @@ use crate::{
11
11
error:: { CodegenError , CodegenErrorType } ,
12
12
IndexMap ,
13
13
} ;
14
+ use bitflags:: bitflags;
14
15
use rustpython_ast as ast;
15
16
use rustpython_compiler_core:: Location ;
16
17
use std:: { borrow:: Cow , fmt} ;
@@ -94,38 +95,41 @@ pub enum SymbolScope {
94
95
Cell ,
95
96
}
96
97
98
+ bitflags ! {
99
+ pub struct SymbolFlags : u16 {
100
+ const REFERENCED = 0x001 ;
101
+ const ASSIGNED = 0x002 ;
102
+ const PARAMETER = 0x004 ;
103
+ const ANNOTATED = 0x008 ;
104
+ const IMPORTED = 0x010 ;
105
+ const NONLOCAL = 0x020 ;
106
+ // indicates if the symbol gets a value assigned by a named expression in a comprehension
107
+ // this is required to correct the scope in the analysis.
108
+ const ASSIGNED_IN_COMPREHENSION = 0x040 ;
109
+ // indicates that the symbol is used a bound iterator variable. We distinguish this case
110
+ // from normal assignment to detect unallowed re-assignment to iterator variables.
111
+ const ITER = 0x080 ;
112
+ /// indicates that the symbol is a free variable in a class method from the scope that the
113
+ /// class is defined in, e.g.:
114
+ /// ```python
115
+ /// def foo(x):
116
+ /// class A:
117
+ /// def method(self):
118
+ /// return x // is_free_class
119
+ /// ```
120
+ const FREE_CLASS = 0x100 ;
121
+ const BOUND = Self :: ASSIGNED . bits | Self :: PARAMETER . bits | Self :: IMPORTED . bits | Self :: ITER . bits;
122
+ }
123
+ }
124
+
97
125
/// A single symbol in a table. Has various properties such as the scope
98
126
/// of the symbol, and also the various uses of the symbol.
99
127
#[ derive( Debug , Clone ) ]
100
128
pub struct Symbol {
101
129
pub name : String ,
102
130
// pub table: SymbolTableRef,
103
131
pub scope : SymbolScope ,
104
- // TODO: Use bitflags replace
105
- pub is_referenced : bool ,
106
- pub is_assigned : bool ,
107
- pub is_parameter : bool ,
108
- pub is_annotated : bool ,
109
- pub is_imported : bool ,
110
- pub is_nonlocal : bool ,
111
-
112
- // indicates if the symbol gets a value assigned by a named expression in a comprehension
113
- // this is required to correct the scope in the analysis.
114
- pub is_assign_namedexpr_in_comprehension : bool ,
115
-
116
- // indicates that the symbol is used a bound iterator variable. We distinguish this case
117
- // from normal assignment to detect unallowed re-assignment to iterator variables.
118
- pub is_iter : bool ,
119
-
120
- /// indicates that the symbol is a free variable in a class method from the scope that the
121
- /// class is defined in, e.g.:
122
- /// ```python
123
- /// def foo(x):
124
- /// class A:
125
- /// def method(self):
126
- /// return x // is_free_class
127
- /// ```
128
- pub is_free_class : bool ,
132
+ pub flags : SymbolFlags ,
129
133
}
130
134
131
135
impl Symbol {
@@ -134,15 +138,7 @@ impl Symbol {
134
138
name : name. to_owned ( ) ,
135
139
// table,
136
140
scope : SymbolScope :: Unknown ,
137
- is_referenced : false ,
138
- is_assigned : false ,
139
- is_parameter : false ,
140
- is_annotated : false ,
141
- is_imported : false ,
142
- is_nonlocal : false ,
143
- is_assign_namedexpr_in_comprehension : false ,
144
- is_iter : false ,
145
- is_free_class : false ,
141
+ flags : SymbolFlags :: empty ( ) ,
146
142
}
147
143
}
148
144
@@ -158,7 +154,7 @@ impl Symbol {
158
154
}
159
155
160
156
pub fn is_bound ( & self ) -> bool {
161
- self . is_assigned || self . is_parameter || self . is_imported || self . is_iter
157
+ self . flags . intersects ( SymbolFlags :: BOUND )
162
158
}
163
159
}
164
160
@@ -300,7 +296,11 @@ impl SymbolTableAnalyzer {
300
296
st_typ : SymbolTableType ,
301
297
sub_tables : & mut [ SymbolTable ] ,
302
298
) -> SymbolTableResult {
303
- if symbol. is_assign_namedexpr_in_comprehension && st_typ == SymbolTableType :: Comprehension {
299
+ if symbol
300
+ . flags
301
+ . contains ( SymbolFlags :: ASSIGNED_IN_COMPREHENSION )
302
+ && st_typ == SymbolTableType :: Comprehension
303
+ {
304
304
// propagate symbol to next higher level that can hold it,
305
305
// i.e., function or module. Comprehension is skipped and
306
306
// Class is not allowed and detected as error.
@@ -388,10 +388,10 @@ impl SymbolTableAnalyzer {
388
388
for ( table, typ) in self . tables . iter_mut ( ) . rev ( ) . take ( decl_depth) {
389
389
if let SymbolTableType :: Class = typ {
390
390
if let Some ( free_class) = table. get_mut ( name) {
391
- free_class. is_free_class = true ;
391
+ free_class. flags . insert ( SymbolFlags :: FREE_CLASS )
392
392
} else {
393
393
let mut symbol = Symbol :: new ( name) ;
394
- symbol. is_free_class = true ;
394
+ symbol. flags . insert ( SymbolFlags :: FREE_CLASS ) ;
395
395
symbol. scope = SymbolScope :: Free ;
396
396
table. insert ( name. to_owned ( ) , symbol) ;
397
397
}
@@ -415,7 +415,7 @@ impl SymbolTableAnalyzer {
415
415
) -> Option < SymbolScope > {
416
416
sub_tables. iter ( ) . find_map ( |st| {
417
417
st. symbols . get ( name) . and_then ( |sym| {
418
- if sym. scope == SymbolScope :: Free || sym. is_free_class {
418
+ if sym. scope == SymbolScope :: Free || sym. flags . contains ( SymbolFlags :: FREE_CLASS ) {
419
419
if st_typ == SymbolTableType :: Class && name != "__class__" {
420
420
None
421
421
} else {
@@ -446,7 +446,7 @@ impl SymbolTableAnalyzer {
446
446
let table_type = last. 1 ;
447
447
448
448
// it is not allowed to use an iterator variable as assignee in a named expression
449
- if symbol. is_iter {
449
+ if symbol. flags . contains ( SymbolFlags :: ITER ) {
450
450
return Err ( SymbolTableError {
451
451
error : format ! (
452
452
"assignment expression cannot rebind comprehension iteration variable {}" ,
@@ -473,7 +473,7 @@ impl SymbolTableAnalyzer {
473
473
if let Some ( parent_symbol) = symbols. get_mut ( & symbol. name ) {
474
474
if let SymbolScope :: Unknown = parent_symbol. scope {
475
475
// this information is new, as the assignment is done in inner scope
476
- parent_symbol. is_assigned = true ;
476
+ parent_symbol. flags . insert ( SymbolFlags :: ASSIGNED ) ;
477
477
}
478
478
479
479
symbol. scope = if parent_symbol. is_global ( ) {
@@ -492,7 +492,7 @@ impl SymbolTableAnalyzer {
492
492
match symbols. get_mut ( & symbol. name ) {
493
493
Some ( parent_symbol) => {
494
494
// check if assignee is an iterator in top scope
495
- if parent_symbol. is_iter {
495
+ if parent_symbol. flags . contains ( SymbolFlags :: ITER ) {
496
496
return Err ( SymbolTableError {
497
497
error : format ! ( "assignment expression cannot rebind comprehension iteration variable {}" , symbol. name) ,
498
498
// TODO: accurate location info, somehow
@@ -501,7 +501,7 @@ impl SymbolTableAnalyzer {
501
501
}
502
502
503
503
// we synthesize the assignment to the symbol from inner scope
504
- parent_symbol. is_assigned = true ; // more checks are required
504
+ parent_symbol. flags . insert ( SymbolFlags :: ASSIGNED ) ; // more checks are required
505
505
}
506
506
None => {
507
507
// extend the scope of the inner symbol
@@ -1148,62 +1148,58 @@ impl SymbolTableBuilder {
1148
1148
1149
1149
// Some checks for the symbol that present on this scope level:
1150
1150
let symbol = if let Some ( symbol) = table. symbols . get_mut ( name. as_ref ( ) ) {
1151
+ let flags = & symbol. flags ;
1151
1152
// Role already set..
1152
1153
match role {
1153
- SymbolUsage :: Global => {
1154
- if !symbol. is_global ( ) {
1155
- if symbol. is_parameter {
1156
- return Err ( SymbolTableError {
1157
- error : format ! ( "name '{}' is parameter and global" , name) ,
1158
- location,
1159
- } ) ;
1160
- }
1161
- if symbol. is_referenced {
1162
- return Err ( SymbolTableError {
1163
- error : format ! (
1164
- "name '{}' is used prior to global declaration" ,
1165
- name
1166
- ) ,
1167
- location,
1168
- } ) ;
1169
- }
1170
- if symbol. is_annotated {
1171
- return Err ( SymbolTableError {
1172
- error : format ! ( "annotated name '{}' can't be global" , name) ,
1173
- location,
1174
- } ) ;
1175
- }
1176
- if symbol. is_assigned {
1177
- return Err ( SymbolTableError {
1178
- error : format ! (
1179
- "name '{}' is assigned to before global declaration" ,
1180
- name
1181
- ) ,
1182
- location,
1183
- } ) ;
1184
- }
1154
+ SymbolUsage :: Global if !symbol. is_global ( ) => {
1155
+ if flags. contains ( SymbolFlags :: PARAMETER ) {
1156
+ return Err ( SymbolTableError {
1157
+ error : format ! ( "name '{}' is parameter and global" , name) ,
1158
+ location,
1159
+ } ) ;
1160
+ }
1161
+ if flags. contains ( SymbolFlags :: REFERENCED ) {
1162
+ return Err ( SymbolTableError {
1163
+ error : format ! ( "name '{}' is used prior to global declaration" , name) ,
1164
+ location,
1165
+ } ) ;
1166
+ }
1167
+ if flags. contains ( SymbolFlags :: ANNOTATED ) {
1168
+ return Err ( SymbolTableError {
1169
+ error : format ! ( "annotated name '{}' can't be global" , name) ,
1170
+ location,
1171
+ } ) ;
1172
+ }
1173
+ if flags. contains ( SymbolFlags :: ASSIGNED ) {
1174
+ return Err ( SymbolTableError {
1175
+ error : format ! (
1176
+ "name '{}' is assigned to before global declaration" ,
1177
+ name
1178
+ ) ,
1179
+ location,
1180
+ } ) ;
1185
1181
}
1186
1182
}
1187
1183
SymbolUsage :: Nonlocal => {
1188
- if symbol . is_parameter {
1184
+ if flags . contains ( SymbolFlags :: PARAMETER ) {
1189
1185
return Err ( SymbolTableError {
1190
1186
error : format ! ( "name '{}' is parameter and nonlocal" , name) ,
1191
1187
location,
1192
1188
} ) ;
1193
1189
}
1194
- if symbol . is_referenced {
1190
+ if flags . contains ( SymbolFlags :: REFERENCED ) {
1195
1191
return Err ( SymbolTableError {
1196
1192
error : format ! ( "name '{}' is used prior to nonlocal declaration" , name) ,
1197
1193
location,
1198
1194
} ) ;
1199
1195
}
1200
- if symbol . is_annotated {
1196
+ if flags . contains ( SymbolFlags :: ANNOTATED ) {
1201
1197
return Err ( SymbolTableError {
1202
1198
error : format ! ( "annotated name '{}' can't be nonlocal" , name) ,
1203
1199
location,
1204
1200
} ) ;
1205
1201
}
1206
- if symbol . is_assigned {
1202
+ if flags . contains ( SymbolFlags :: ASSIGNED ) {
1207
1203
return Err ( SymbolTableError {
1208
1204
error : format ! (
1209
1205
"name '{}' is assigned to before nonlocal declaration" ,
@@ -1237,48 +1233,45 @@ impl SymbolTableBuilder {
1237
1233
table. symbols . entry ( name. into_owned ( ) ) . or_insert ( symbol)
1238
1234
} ;
1239
1235
1240
- // Set proper flags on symbol:
1236
+ // Set proper scope and flags on symbol:
1237
+ let flags = & mut symbol. flags ;
1241
1238
match role {
1242
1239
SymbolUsage :: Nonlocal => {
1243
1240
symbol. scope = SymbolScope :: Free ;
1244
- symbol . is_nonlocal = true ;
1241
+ flags . insert ( SymbolFlags :: NONLOCAL ) ;
1245
1242
}
1246
1243
SymbolUsage :: Imported => {
1247
- symbol. is_assigned = true ;
1248
- symbol. is_imported = true ;
1244
+ flags. insert ( SymbolFlags :: ASSIGNED | SymbolFlags :: IMPORTED ) ;
1249
1245
}
1250
1246
SymbolUsage :: Parameter => {
1251
- symbol . is_parameter = true ;
1247
+ flags . insert ( SymbolFlags :: PARAMETER ) ;
1252
1248
}
1253
1249
SymbolUsage :: AnnotationParameter => {
1254
- symbol. is_parameter = true ;
1255
- symbol. is_annotated = true ;
1250
+ flags. insert ( SymbolFlags :: PARAMETER | SymbolFlags :: ANNOTATED ) ;
1256
1251
}
1257
1252
SymbolUsage :: AnnotationAssigned => {
1258
- symbol. is_assigned = true ;
1259
- symbol. is_annotated = true ;
1253
+ flags. insert ( SymbolFlags :: ASSIGNED | SymbolFlags :: ANNOTATED ) ;
1260
1254
}
1261
1255
SymbolUsage :: Assigned => {
1262
- symbol . is_assigned = true ;
1256
+ flags . insert ( SymbolFlags :: ASSIGNED ) ;
1263
1257
}
1264
1258
SymbolUsage :: AssignedNamedExprInCompr => {
1265
- symbol. is_assigned = true ;
1266
- symbol. is_assign_namedexpr_in_comprehension = true ;
1259
+ flags. insert ( SymbolFlags :: ASSIGNED | SymbolFlags :: ASSIGNED_IN_COMPREHENSION ) ;
1267
1260
}
1268
1261
SymbolUsage :: Global => {
1269
1262
symbol. scope = SymbolScope :: GlobalExplicit ;
1270
1263
}
1271
1264
SymbolUsage :: Used => {
1272
- symbol . is_referenced = true ;
1265
+ flags . insert ( SymbolFlags :: REFERENCED ) ;
1273
1266
}
1274
1267
SymbolUsage :: Iter => {
1275
- symbol . is_iter = true ;
1268
+ flags . insert ( SymbolFlags :: ITER ) ;
1276
1269
}
1277
1270
}
1278
1271
1279
1272
// and even more checking
1280
1273
// it is not allowed to assign to iterator variables (by named expressions)
1281
- if symbol . is_iter && symbol . is_assigned
1274
+ if flags . contains ( SymbolFlags :: ITER | SymbolFlags :: ASSIGNED )
1282
1275
/*&& symbol.is_assign_namedexpr_in_comprehension*/
1283
1276
{
1284
1277
return Err ( SymbolTableError {
0 commit comments