@@ -1302,9 +1302,44 @@ def find_tag_and_check(
1302
1302
return tag
1303
1303
1304
1304
1305
+ def get_lookup_reference_name (expr : BaseElement ) -> str :
1306
+ """
1307
+ Find the lookup name of the reference expression associated to
1308
+ `expr`, or None if there is no such a reference.
1309
+
1310
+ In general, the lookup reference name coincides with the lookup_name
1311
+ of the expression. However, there are some exceptions:
1312
+
1313
+ * Expressions with heads `HoldPattern`, Condition`, or `PatternTest`
1314
+ are not considered *reference* expressions. The reference expression
1315
+ is the reference expression of its first element.
1316
+ * (named) `Pattern` expressions takes its lookup_reference_name from the
1317
+ pattern their hold.
1318
+ * `Verbatim` expressions pick the lookup_reference_name from
1319
+ the lookup_name of the expression they hold.
1320
+ * Blanks pick the lookup_reference_name from the pattern head
1321
+ (its unique element if they has one). If the Blank expression does not
1322
+ have elements (generic blank) then there is no lookup_reference_name,
1323
+ and returns an empty string.
1324
+ """
1325
+ expr = get_reference_expression (expr )
1326
+ if expr .has_form ("System`Pattern" , 2 ):
1327
+ return get_lookup_reference_name (expr .elements [1 ])
1328
+ if expr .has_form ("System`Verbatim" , 1 ):
1329
+ # For Verbatim pick the lookup name directly from the expression.
1330
+ return expr .elements [0 ].get_lookup_name ()
1331
+ if expr .has_form (
1332
+ ("System`Blank" , "System`BlankSequence" , "System`BlankNullSequence" ), None
1333
+ ):
1334
+ if len (expr .elements ) == 1 :
1335
+ return get_lookup_reference_name (expr .elements [0 ])
1336
+ return ""
1337
+ return expr .get_lookup_name ()
1338
+
1339
+
1305
1340
def get_reference_expression (lhs : BaseElement ) -> BaseElement :
1306
1341
"""
1307
- Strip `Condition`, `PatternTest` and `HoldPattern` from an expression
1342
+ Strip `Condition`, `PatternTest` and `HoldPattern` from an expression.
1308
1343
"""
1309
1344
strip_headers = (
1310
1345
SymbolHoldPattern ,
@@ -1379,18 +1414,8 @@ def process_tags_and_upset_allow_custom(
1379
1414
name = lhs .get_head_name ()
1380
1415
lhs_reference_expr = get_reference_expression (lhs )
1381
1416
1382
- def get_lookup_name (expr ):
1383
- expr = get_reference_expression (expr )
1384
- if expr .has_form ("System`Pattern" , 2 ):
1385
- return expr .elements [1 ].get_lookup_name ()
1386
- if expr .has_form (
1387
- ("System`Blank" , "System`BlankSequence" , "System`BlankNullSequence" ), 1
1388
- ):
1389
- return expr .elements [0 ].get_lookup_name ()
1390
- return expr .get_lookup_name ()
1391
-
1392
1417
if upset :
1393
- tags = []
1418
+ tags_set = set ()
1394
1419
if isinstance (lhs_reference_expr , Atom ):
1395
1420
symbol_name = self .get_name ()
1396
1421
evaluation .message (
@@ -1401,20 +1426,33 @@ def get_lookup_name(expr):
1401
1426
)
1402
1427
raise AssignmentException (lhs , None )
1403
1428
for element in lhs_reference_expr .get_elements ():
1404
- name = get_lookup_name (element )
1405
- tags .append (name )
1406
- return tags , lhs_reference_expr
1429
+ # elements of the expression can also be wrapped in `HoldPattern`
1430
+ # or `Condition`. Tag candidates are obtained by stripping out
1431
+ # these wrappers.
1432
+ # Still, if the element is a `Blank*`, the reference is
1433
+ # set to its argument. If it does not have arguments (or have many)
1434
+ # skip it.
1435
+ name = get_lookup_reference_name (element )
1436
+ if name is not None :
1437
+ tags_set .add (name )
1438
+ return list (tags_set ), lhs_reference_expr
1407
1439
1408
1440
if tags is None :
1409
- name = get_lookup_name (lhs_reference_expr )
1441
+ name = get_lookup_reference_name (lhs_reference_expr )
1410
1442
if not name :
1411
1443
evaluation .message (self .get_name (), "setraw" , lhs_reference_expr )
1412
1444
raise AssignmentException (lhs , None )
1413
1445
tags = [name ]
1414
1446
else :
1415
- allowed_names = [get_lookup_name (lhs_reference_expr )]
1447
+ allowed_names = set ()
1448
+ name = get_lookup_reference_name (lhs_reference_expr )
1449
+ if name :
1450
+ allowed_names .add (name )
1451
+
1416
1452
for element in lhs_reference_expr .get_elements ():
1417
- allowed_names .append (get_lookup_name (element ))
1453
+ name = get_lookup_reference_name (element )
1454
+ if name :
1455
+ allowed_names .add (name )
1418
1456
for name in tags :
1419
1457
if name not in allowed_names :
1420
1458
evaluation .message (self .get_name (), "tagnfd" , Symbol (name ))
@@ -1463,19 +1501,34 @@ def process_tags_and_upset_dont_allow_custom(
1463
1501
the list of allowed tags.
1464
1502
1465
1503
"""
1504
+
1505
+ def get_lookup_name (expr ):
1506
+ expr = get_reference_expression (expr )
1507
+ if expr .has_form ("System`Pattern" , 2 ):
1508
+ return get_lookup_name (expr .elements [1 ])
1509
+ if expr .has_form (
1510
+ ("System`Blank" , "System`BlankSequence" , "System`BlankNullSequence" ), None
1511
+ ):
1512
+ if len (expr .elements ) == 1 :
1513
+ return get_lookup_name (expr .elements [0 ])
1514
+ return None
1515
+ return expr .get_lookup_name ()
1516
+
1466
1517
if isinstance (lhs_reference , Expression ):
1467
1518
lhs_reference = lhs_reference .evaluate_elements (evaluation )
1468
1519
name = lhs .get_head_name ()
1469
1520
if upset :
1470
- tags = [lhs_reference .get_lookup_name ()]
1521
+ name = get_lookup_name (lhs_reference )
1522
+ tags = [name ] if name is not None else None
1471
1523
elif tags is None :
1472
- name = lhs_reference . get_lookup_name ()
1524
+ name = get_lookup_name (lhs_reference )
1473
1525
if not name :
1474
1526
evaluation .message (self .get_name (), "setraw" , lhs_reference )
1475
1527
raise AssignmentException (lhs , None )
1476
1528
tags = [name ]
1477
1529
else :
1478
- allowed_names = [lhs_reference .get_lookup_name ()]
1530
+ name = get_lookup_name (lhs_reference )
1531
+ allowed_names = [name ] if name else []
1479
1532
for name in tags :
1480
1533
if name not in allowed_names :
1481
1534
evaluation .message (self .get_name (), "tagnfd" , Symbol (name ))
0 commit comments