22from abc import ABCMeta
33from typing import Iterator , Mapping , Optional , Pattern
44
5- _posix_variable = re .compile (
6- r"""
7- \$\{
8- (?P<name>[^\}:]*)
9- (?::-
10- (?P<default>[^\}]*)
11- )?
12- \}
13- """ ,
14- re .VERBOSE ,
15- ) # type: Pattern[str]
16-
175
186class Atom ():
197 __metaclass__ = ABCMeta
@@ -48,7 +36,7 @@ def resolve(self, env: Mapping[str, Optional[str]]) -> str:
4836
4937
5038class Variable (Atom ):
51- def __init__ (self , name : str , default : Optional [str ]) -> None :
39+ def __init__ (self , name : str , default : Optional [Iterator [ Atom ] ]) -> None :
5240 self .name = name
5341 self .default = default
5442
@@ -64,24 +52,52 @@ def __hash__(self) -> int:
6452 return hash ((self .__class__ , self .name , self .default ))
6553
6654 def resolve (self , env : Mapping [str , Optional [str ]]) -> str :
67- default = self .default if self .default is not None else ""
55+ # default = self.default if self.default is not None else ""
56+ default = "" .join (atom .resolve (env ) for atom in self .default ) if self .default is not None else ""
6857 result = env .get (self .name , default )
6958 return result if result is not None else ""
7059
7160
72- def parse_variables (value : str ) -> Iterator [Atom ]:
73- cursor = 0
61+ _variable_re = re .compile (
62+ r"""
63+ ^
64+ (?P<name>[^\}:]*?)
65+ (?::[-=]
66+ (?P<default>.*)
67+ )?
68+ $
69+ """ ,
70+ re .VERBOSE ,
71+ ) # type: Pattern[str]
72+
73+ ESC_CHAR = '\\ '
7474
75- for match in _posix_variable .finditer (value ):
76- (start , end ) = match .span ()
77- name = match .groupdict ()["name" ]
78- default = match .groupdict ()["default" ]
7975
80- if start > cursor :
81- yield Literal ( value = value [ cursor : start ])
76+ def parse_variables ( value : str ) -> Iterator [ Atom ] :
77+ cursor = 0
8278
83- yield Variable (name = name , default = default )
84- cursor = end
79+ starts = []
80+ esc = False
81+ for i in range (len (value )):
82+ if esc :
83+ esc = False
84+ elif ESC_CHAR == value [i ]:
85+ esc = True
86+ elif i < len (value ) - 1 and '$' == value [i ] and '{' == value [i + 1 ]:
87+ if len (starts ) == 0 and cursor < i :
88+ yield Literal (value = value [cursor :i ])
89+ starts .append (i + 2 )
90+ elif '}' == value [i ]:
91+ start = starts .pop ()
92+ end = i
93+ cursor = i + 1
94+ if len (starts ) == 0 :
95+ print (value [start :end ])
96+ for match in _variable_re .finditer (value [start :end ]):
97+ name = match .groupdict ()["name" ]
98+ default = match .groupdict ()["default" ]
99+ default = None if default is None else list (parse_variables (default ))
100+ yield Variable (name = name , default = default )
85101
86102 length = len (value )
87103 if cursor < length :
0 commit comments