3
3
import copy
4
4
import os
5
5
import re
6
- from dataclasses import replace
6
+ from dataclasses import dataclass , replace
7
7
from typing import Pattern
8
8
9
9
from fortls .constants import (
@@ -291,6 +291,13 @@ def __init__(
291
291
}
292
292
293
293
294
+ @dataclass
295
+ class AssociateMap :
296
+ var : fortran_var
297
+ bind_name : str
298
+ link_name : str
299
+
300
+
294
301
class fortran_diagnostic :
295
302
def __init__ (
296
303
self , sline : int , message : str , severity : int = 1 , find_word : str = None
@@ -1365,33 +1372,65 @@ def get_desc(self):
1365
1372
class fortran_associate (fortran_block ):
1366
1373
def __init__ (self , file_ast : fortran_ast , line_number : int , name : str ):
1367
1374
super ().__init__ (file_ast , line_number , name )
1368
- self .assoc_links = []
1375
+ self .links : list [ AssociateMap ] = [] # holds the info to associate variables
1369
1376
1370
1377
def get_type (self , no_link = False ):
1371
1378
return ASSOC_TYPE_ID
1372
1379
1373
1380
def get_desc (self ):
1374
1381
return "ASSOCIATE"
1375
1382
1376
- def create_binding_variable (self , file_ast , line_number , bound_name , link_var ):
1377
- new_var = fortran_var (file_ast , line_number , bound_name , "UNKNOWN" , [])
1378
- self .assoc_links .append ([new_var , bound_name , link_var ])
1383
+ def create_binding_variable (
1384
+ self , file_ast : fortran_ast , line_number : int , bind_name : str , link_name : str
1385
+ ) -> fortran_var :
1386
+ """Create a new variable to be linked upon resolution to the real variable
1387
+ that contains the information of the mapping from the parent scope to the
1388
+ ASSOCIATE block scope.
1389
+
1390
+ Parameters
1391
+ ----------
1392
+ file_ast : fortran_ast
1393
+ AST file
1394
+ line_number : int
1395
+ Line number
1396
+ bind_name : str
1397
+ Name of the ASSOCIATE block variable
1398
+ link_name : str
1399
+ Name of the parent scope variable
1400
+
1401
+ Returns
1402
+ -------
1403
+ fortran_var
1404
+ Variable object holding the ASSOCIATE block variable, pending resolution
1405
+ """
1406
+ new_var = fortran_var (file_ast , line_number , bind_name , "UNKNOWN" , [])
1407
+ self .links .append (AssociateMap (new_var , bind_name , link_name ))
1379
1408
return new_var
1380
1409
1381
1410
def resolve_link (self , obj_tree ):
1382
- for assoc_link in self .assoc_links :
1383
- var_stack = get_var_stack (assoc_link [2 ])
1384
- if len (var_stack ) > 1 :
1411
+ # Loop through the list of the associated variables map and resolve the links
1412
+ # find the AST node that that corresponds to the variable with link_name
1413
+ for assoc in self .links :
1414
+ # TODO: extract the dimensions component from the link_name
1415
+ # re.sub(r'\(.*\)', '', link_name) removes the dimensions component
1416
+ # keywords = re.match(r'(.*)\((.*)\)', link_name).groups()
1417
+ # now pass the keywords through the dimension_parser and set the keywords
1418
+ # in the associate object. Hover should now pick the local keywords
1419
+ # over the linked_object keywords
1420
+ assoc .link_name = re .sub (r"\(.*\)" , "" , assoc .link_name )
1421
+ var_stack = get_var_stack (assoc .link_name )
1422
+ is_member = len (var_stack ) > 1
1423
+ if is_member :
1385
1424
type_scope = climb_type_tree (var_stack , self , obj_tree )
1386
1425
if type_scope is None :
1387
1426
continue
1388
1427
var_obj = find_in_scope (type_scope , var_stack [- 1 ], obj_tree )
1389
1428
if var_obj is not None :
1390
- assoc_link [ 0 ] .link_obj = var_obj
1429
+ assoc . var .link_obj = var_obj
1391
1430
else :
1392
- var_obj = find_in_scope (self , assoc_link [ 2 ] , obj_tree )
1431
+ var_obj = find_in_scope (self , assoc . link_name , obj_tree )
1393
1432
if var_obj is not None :
1394
- assoc_link [ 0 ] .link_obj = var_obj
1433
+ assoc . var .link_obj = var_obj
1395
1434
1396
1435
def require_link (self ):
1397
1436
return True
@@ -1601,6 +1640,7 @@ def get_type_obj(self, obj_tree):
1601
1640
self .type_obj = type_obj
1602
1641
return self .type_obj
1603
1642
1643
+ # XXX: unused delete or use for associate blocks
1604
1644
def set_dim (self , dim_str ):
1605
1645
if KEYWORD_ID_DICT ["dimension" ] not in self .keywords :
1606
1646
self .keywords .append (KEYWORD_ID_DICT ["dimension" ])
@@ -1618,9 +1658,9 @@ def get_snippet(self, name_replace=None, drop_arg=-1):
1618
1658
1619
1659
def get_hover (self , long = False , include_doc = True , drop_arg = - 1 ):
1620
1660
doc_str = self .get_documentation ()
1621
- hover_str = ", " . join (
1622
- [ self . desc ] + get_keywords ( self . keywords , self . keyword_info )
1623
- )
1661
+ # In associated blocks we need to fetch the desc and keywords of the
1662
+ # linked object
1663
+ hover_str = ", " . join ([ self . get_desc ()] + self . get_keywords () )
1624
1664
# TODO: at this stage we can mae this lowercase
1625
1665
# Add parameter value in the output
1626
1666
if self .is_parameter () and self .param_val :
@@ -1629,6 +1669,14 @@ def get_hover(self, long=False, include_doc=True, drop_arg=-1):
1629
1669
hover_str += "\n {0}" .format ("\n " .join (doc_str .splitlines ()))
1630
1670
return hover_str , True
1631
1671
1672
+ def get_keywords (self ):
1673
+ # TODO: if local keywords are set they should take precedence over link_obj
1674
+ # Alternatively, I could do a dictionary merge with local variables
1675
+ # having precedence by default and use a flag to override?
1676
+ if self .link_obj is not None :
1677
+ return get_keywords (self .link_obj .keywords , self .link_obj .keyword_info )
1678
+ return get_keywords (self .keywords , self .keyword_info )
1679
+
1632
1680
def is_optional (self ):
1633
1681
if self .keywords .count (KEYWORD_ID_DICT ["optional" ]) > 0 :
1634
1682
return True
0 commit comments