allow nested parameter substitutions
diff --git a/reclass/utils/refvalue.py b/reclass/utils/refvalue.py
index b8e730b..e02f195 100644
--- a/reclass/utils/refvalue.py
+++ b/reclass/utils/refvalue.py
@@ -7,6 +7,9 @@
 # Released under the terms of the Artistic Licence 2.0
 #
 
+import pyparsing as pp
+from lxml import etree
+
 import re
 
 from reclass.utils.dictpath import DictPath
@@ -16,7 +19,10 @@
         UndefinedVariableError
 
 _SENTINELS = [re.escape(s) for s in PARAMETER_INTERPOLATION_SENTINELS]
-_RE = '{0}\s*(.+?)\s*{1}'.format(*_SENTINELS)
+_RE = '(.+?)(?={0}|$)'.format(_SENTINELS[0])
+
+_STR = 'STR'
+_REF = 'REF'
 
 class RefValue(object):
     '''
@@ -54,26 +60,57 @@
     the default delimiter.
     '''
 
-    INTERPOLATION_RE = re.compile(_RE)
-
     def __init__(self, string, delim=PARAMETER_INTERPOLATION_DELIMITER):
-        self._strings = []
-        self._refs = []
         self._delim = delim
+        self._tokens = []
+        self._refs = []
         self._parse(string)
 
     def _parse(self, string):
-        parts = RefValue.INTERPOLATION_RE.split(string)
-        self._refs = parts[1:][::2]
-        self._strings = parts[0:][::2]
-        self._check_strings(string)
+        # order of checking is important here, the nested ${} check then the regex
+        scanner = pp.ZeroOrMore(pp.MatchFirst([
+                                pp.nestedExpr(opener=PARAMETER_INTERPOLATION_SENTINELS[0], closer=PARAMETER_INTERPOLATION_SENTINELS[1]).setResultsName(_REF),
+                                pp.Regex(_RE).setResultsName(_STR, listAllMatches=True)
+                  ]))
+        result = scanner.leaveWhitespace().parseString(string)
+        xml = etree.fromstring(result.asXML())
+        self._parseXML(xml)
+        self._assembleRefs(self._tokens)
 
-    def _check_strings(self, orig):
-        for s in self._strings:
-            pos = s.find(PARAMETER_INTERPOLATION_SENTINELS[0])
-            if pos >= 0:
-                raise IncompleteInterpolationError(orig,
-                                                   PARAMETER_INTERPOLATION_SENTINELS[1])
+    def _parseXML(self, elements):
+        self._tokens = []
+        for el in elements:
+            if (el.tag == _STR):
+                self._tokens.append((_STR, el.text))
+            elif (el.tag == _REF):
+                self._tokens.append((_REF, self._parseRefXML(el)))
+            else:
+                self._tokens.append(('???', '???'))
+
+    def _parseRefXML(self, elements):
+        result = []
+        for el in elements:
+            if (len(el) == 0):
+                result.append((_STR, el.text))
+            else:
+                result.append((_REF, self._parseRefXML(el)))
+        return result
+
+    def _assembleRefs(self, tokens, first=True):
+        string = ''
+        retNone = False
+        for token in tokens:
+            if token[0] == _STR:
+                string += token[1]
+            elif token[0] == _REF:
+                s = self._assembleRefs(token[1], first=False)
+                if s != None:
+                    self._refs.append(s)
+                if not first:
+                   retNone = True
+        if retNone:
+            string = None
+        return string
 
     def _resolve(self, ref, context):
         path = DictPath(self._delim, ref)
@@ -88,28 +125,27 @@
     def get_references(self):
         return self._refs
 
-    def _assemble(self, resolver):
-        if not self.has_references():
-            return self._strings[0]
-
-        if self._strings == ['', '']:
-            # preserve the type of the referenced variable
-            return resolver(self._refs[0])
-
-        # reassemble the string by taking a string and str(ref) pairwise
-        ret = ''
-        for i in range(0, len(self._refs)):
-            ret += self._strings[i] + str(resolver(self._refs[i]))
-        if len(self._strings) > len(self._refs):
-            # and finally append a trailing string, if any
-            ret += self._strings[-1]
-        return ret
+    def _assemble(self, tokens, resolver):
+        # Preserve type if only one token
+        if len(tokens) == 1:
+            if tokens[0][0] == _STR:
+                return tokens[0][1]
+            elif tokens[0][0] == _REF:
+                return resolver(self._assemble(tokens[0][1], resolver))
+        # Multiple tokens
+        string = ''
+        for token in tokens:
+            if token[0] == _STR:
+                string += token[1]
+            elif token[0] == _REF:
+                string += str(resolver(self._assemble(token[1], resolver)))
+        return string
 
     def render(self, context):
         resolver = lambda s: self._resolve(s, context)
-        return self._assemble(resolver)
+        return self._assemble(self._tokens, resolver)
 
     def __repr__(self):
         do_not_resolve = lambda s: s.join(PARAMETER_INTERPOLATION_SENTINELS)
-        return 'RefValue(%r, %r)' % (self._assemble(do_not_resolve),
+        return 'RefValue(%r, %r)' % (self._assemble(self._tokens, do_not_resolve),
                                      self._delim)