docs: public Appender parse( String pattern ) throws IllegalArgumentException
  	{
  		List<Appender> appenders = new ArrayList<Appender>();
  		int prev = 0;
  		int pos = 0;
  		while ((pos = pattern.indexOf(VAR_START, pos)) >= 0)
  		{
  			// Add text between beginning/end of last variable
  			if ( pos > prev )
  			{
  				appenders.add(new TextAppender(pattern.substring(prev, pos)));
  			}
  
  			// Move to real variable name beginning
  			pos += VAR_START_LEN;
  
  			// Next close bracket (not necessarily the variable end bracket if
  			// there is a default value with nested variables
  			int endVariable = pattern.indexOf(VAR_CLOSE, pos);
  			if ( endVariable < 0 )
  			{
  				throw new IllegalArgumentException(format(
  						"Syntax error in property value ''{0}'', missing close bracket ''{1}'' for variable beginning at col {2}: ''{3}''", pattern,
  						VAR_CLOSE, pos - VAR_START_LEN, pattern.substring(pos - VAR_START_LEN)));
  			}
  
  			// Try to skip eventual internal variable here
  			int nextVariable = pattern.indexOf(VAR_START, pos);
  			// Just used to throw exception with more accurate message
  			int lastEndVariable = endVariable;
  			boolean hasNested = false;
  			while (nextVariable >= 0 && nextVariable < endVariable)
  			{
  				hasNested = true;
  				endVariable = pattern.indexOf(VAR_CLOSE, endVariable + VAR_CLOSE_LEN);
  				// Something is badly closed
  				if ( endVariable < 0 )
  				{
  					throw new IllegalArgumentException(format(
  							"Syntax error in property value ''{0}'', missing close bracket ''{1}'' for variable beginning at col {2}: ''{3}''",
  							pattern, VAR_CLOSE, nextVariable, pattern.substring(nextVariable, lastEndVariable)));
  				}
  				nextVariable = pattern.indexOf(VAR_START, nextVariable + VAR_START_LEN);
  				lastEndVariable = endVariable;
  			}
  			// The chunk to process
  			final String rawKey = pattern.substring(pos - VAR_START_LEN, endVariable + VAR_CLOSE_LEN);
  			// Key without variable start and end symbols
  			final String key = pattern.substring(pos, endVariable);
  
  			int pipeIndex = key.indexOf(PIPE_SEPARATOR);
  
  			boolean hasKeyVariables = false;
  			boolean hasDefault = false;
  			boolean hasDefaultVariables = false;
  
  			// There is a pipe
  			if ( pipeIndex >= 0 )
  			{
  				// No nested property detected, simple default part
  				if ( !hasNested )
  				{
  					hasDefault = true;
  					hasDefaultVariables = false;
  				}
  				// There is a pipe and nested variable,
  				// determine if pipe is for the current variable or a nested key
  				// variable
  				else
  				{
  					int nextStartKeyVariable = key.indexOf(VAR_START);
  					hasKeyVariables = pipeIndex > nextStartKeyVariable;
  					if ( hasKeyVariables )
  					{
  						// ff${fdf}|${f}
  						int nextEndKeyVariable = key.indexOf(VAR_CLOSE, nextStartKeyVariable + VAR_START_LEN);
  						pipeIndex = key.indexOf(PIPE_SEPARATOR, nextEndKeyVariable + VAR_CLOSE_LEN);
  						while (pipeIndex >= 0 && pipeIndex > nextStartKeyVariable)
  						{
  							pipeIndex = key.indexOf(PIPE_SEPARATOR, nextEndKeyVariable + VAR_CLOSE_LEN);
  							nextStartKeyVariable = key.indexOf(VAR_START, nextStartKeyVariable + VAR_START_LEN);
  							// No more nested variable
  							if ( nextStartKeyVariable < 0 )
  							{
  								break;
  							}
  							nextEndKeyVariable = key.indexOf(VAR_CLOSE, nextEndKeyVariable + VAR_CLOSE_LEN);
  							if ( nextEndKeyVariable < 0 )
  							{
  								throw new IllegalArgumentException(
  										format("Syntax error in property value ''{0}'', missing close bracket ''{1}'' for variable beginning at col {2}: ''{3}''",
  												pattern, VAR_CLOSE, nextStartKeyVariable, key.substring(nextStartKeyVariable)));
  							}
  						}
  					}
  
  					// nested variables are only for key, current variable does
  					// not have a default value
  					if ( pipeIndex >= 0 )
  					{
  						hasDefault = true;
  						hasDefaultVariables = key.indexOf(VAR_START, pipeIndex) >= 0;
  					}
  
  				}
  			}
  			// No pipe, there is key variables if nested elements have been
  			// detected
  			else
  			{
  				hasKeyVariables = hasNested;
  			}
  
  			// Construct variable appenders
  			String keyPart = null;
  			String defaultPart = null;
  			if ( hasDefault )
  			{
  				keyPart = key.substring(0, pipeIndex).trim();
  				defaultPart = key.substring(pipeIndex + PIPE_SEPARATOR_LEN).trim();
  			} else
  			{
  				keyPart = key.trim();
  			}
  			// Choose TextAppender when relevant to avoid unecessary parsing when it's clearly not needed
  			appenders.add(new KeyAppender(this, rawKey, hasKeyVariables ? parse(keyPart) : new TextAppender(keyPart), !hasDefault ? null
  					: (hasDefaultVariables ? parse(defaultPart) : new TextAppender(defaultPart))));
  
  			prev = endVariable + VAR_CLOSE_LEN;
  			pos = prev;
  		}
  
  		if ( prev < pattern.length() )
  		{
  			appenders.add(new TextAppender(pattern.substring(prev)));
  		}
  
  		return appenders.size() == 1 ? appenders.get(0) : new MixinAppender(pattern, appenders);
  	}