/** * Compile a string into a function or SimpleVariable. * * <p>Called by {@link #compileString(String)} when that has detected "${". * * <p>Calls {@link CompoundVariable#getNamedFunction(String)} if it detects: '(' - start of * parameter list '}' - end of function call * * @param reader points to input after the "${" * @return the function or variable object (or a String) */ Object makeFunction(StringReader reader) throws InvalidVariableException { char[] current = new char[1]; char previous = ' '; // TODO - why use space? StringBuilder buffer = new StringBuilder(); Object function; try { while (reader.read(current) == 1) { if (current[0] == '\\') { if (reader.read(current) == 0) { break; } previous = ' '; buffer.append(current[0]); continue; } else if (current[0] == '(' && previous != ' ') { String funcName = buffer.toString(); function = CompoundVariable.getNamedFunction(funcName); if (function instanceof Function) { ((Function) function).setParameters(parseParams(reader)); if (reader.read(current) == 0 || current[0] != '}') { reader.reset(); // set to start of string char[] cb = new char[100]; reader.read(cb); // return deliberately ignored throw new InvalidVariableException( "Expected } after " + funcName + " function call in " + new String(cb)); } if (function instanceof TestListener) { StandardJMeterEngine.register((TestListener) function); } return function; } else { // Function does not exist, so treat as per missing variable buffer.append(current[0]); } continue; } else if (current[0] == '}') { // variable, or function with no parameter list function = CompoundVariable.getNamedFunction(buffer.toString()); if (function instanceof Function) { // ensure that setParameters() is called. ((Function) function).setParameters(new LinkedList<CompoundVariable>()); } buffer.setLength(0); return function; } else { buffer.append(current[0]); previous = current[0]; } } } catch (IOException e) { log.error("Error parsing function: " + buffer.toString(), e); return null; } log.warn("Probably an invalid function string: " + buffer.toString()); return buffer.toString(); }
/** * Compile a String into a list of parameters, each made into a CompoundVariable. * * <p>Parses strings of the following form: * * <ul> * <li>text) * <li>text,text) * <li> * </ul> * * @param reader a StringReader pointing to the current input location, just after "(" * @return a list of CompoundVariable elements */ LinkedList<CompoundVariable> parseParams(StringReader reader) throws InvalidVariableException { LinkedList<CompoundVariable> result = new LinkedList<CompoundVariable>(); StringBuilder buffer = new StringBuilder(); char[] current = new char[1]; char previous = ' '; int functionRecursion = 0; int parenRecursion = 0; try { while (reader.read(current) == 1) { if (current[0] == '\\') { // Process escaped characters buffer.append(current[0]); // Store the \ if (reader.read(current) == 0) { break; // end of buffer } previous = ' '; buffer.append(current[0]); // store the following character continue; } else if (current[0] == ',' && functionRecursion == 0) { CompoundVariable param = new CompoundVariable(); param.setParameters(buffer.toString()); buffer.setLength(0); result.add(param); } else if (current[0] == ')' && functionRecursion == 0 && parenRecursion == 0) { // Detect functionName() so this does not generate empty string as the parameter if (buffer.length() == 0 && result.isEmpty()) { return result; } // Normal exit occurs here CompoundVariable param = new CompoundVariable(); param.setParameters(buffer.toString()); buffer.setLength(0); result.add(param); return result; } else if (current[0] == '{' && previous == '$') { buffer.append(current[0]); previous = current[0]; functionRecursion++; } else if (current[0] == '}' && functionRecursion > 0) { buffer.append(current[0]); previous = current[0]; functionRecursion--; } else if (current[0] == ')' && functionRecursion == 0 && parenRecursion > 0) { buffer.append(current[0]); previous = current[0]; parenRecursion--; } else if (current[0] == '(' && functionRecursion == 0) { buffer.append(current[0]); previous = current[0]; parenRecursion++; } else { buffer.append(current[0]); previous = current[0]; } } } catch (IOException e) { // Should not happen with StringReader log.error("Error parsing function: " + buffer.toString(), e); } // Dropped out, i.e. did not find closing ')' log.warn("Probably an invalid function string: " + buffer.toString()); CompoundVariable var = new CompoundVariable(); var.setParameters(buffer.toString()); result.add(var); return result; }