code: private void parse() {
  		if (this.expression.charAt(0) == '!') {
  			this.not = true;
  			this.expression = this.expression.substring(1);
  		}
  
  		StringBuilder sb = new StringBuilder();
  		State state = State.PROPERTY_PATH;
  
  		for (int i = 0; i < this.expression.length(); ++i) {
  			char c = this.expression.charAt(i);
  
  			switch (state) {
  			case PROPERTY_PATH:
  				if (isPropertyPathChar(c)) {
  					sb.append(c);
  					break;
  				}
  				this.propertyPath = sb.toString();
  				sb.setLength(0);
  				this.opcode = Opcode.forChar(c);
  				state = State.OPERAND;
  				break;
  
  			case OPERAND:
  				sb.append(c);
  				break;
  
  			default:
  				throw new IllegalStateException();
  			}
  		}
  
  		if (state == State.PROPERTY_PATH) {
  			assert this.opcode == Opcode.NONE;
  			this.propertyPath = sb.toString();
  			this.opcode = Opcode.NOT_EMPTY;
  		} else {
  			if (sb.length() > 0) {
  				// operand string builder may be empty if operand is missing, e.g. 'value='
  				this.operand = sb.toString();
  			}
  		}
  	}
docs: Parse conditional expression string and return the property path. This method is in fact a morphological parser, i.e. a
  lexer. It just identifies expression components and initialize internal state. Does not check validity; all
  <em>insanity</em> tests are performed by {@link #evaluate(Object)} counterpart. Returns <em>property path</em> expression
  component, which is in fact the only mandatory part.