2
2
from abc import ABCMeta
3
3
from typing import Iterator , Mapping , Optional , Pattern
4
4
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
-
17
5
18
6
class Atom ():
19
7
__metaclass__ = ABCMeta
@@ -48,7 +36,7 @@ def resolve(self, env: Mapping[str, Optional[str]]) -> str:
48
36
49
37
50
38
class Variable (Atom ):
51
- def __init__ (self , name : str , default : Optional [str ]) -> None :
39
+ def __init__ (self , name : str , default : Optional [Iterator [ Atom ] ]) -> None :
52
40
self .name = name
53
41
self .default = default
54
42
@@ -64,24 +52,52 @@ def __hash__(self) -> int:
64
52
return hash ((self .__class__ , self .name , self .default ))
65
53
66
54
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 ""
68
57
result = env .get (self .name , default )
69
58
return result if result is not None else ""
70
59
71
60
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 = '\\ '
74
74
75
- for match in _posix_variable .finditer (value ):
76
- (start , end ) = match .span ()
77
- name = match .groupdict ()["name" ]
78
- default = match .groupdict ()["default" ]
79
75
80
- if start > cursor :
81
- yield Literal ( value = value [ cursor : start ])
76
+ def parse_variables ( value : str ) -> Iterator [ Atom ] :
77
+ cursor = 0
82
78
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 )
85
101
86
102
length = len (value )
87
103
if cursor < length :
0 commit comments