KeywordCallState determineInitialKeywordCallState(KeywordCallState initialKeywordCallState) { /* * in this particular case, we need to do lookahead to see if we have zero or more direct variable references, * followed by a variable reference suffixed with an equal sign. If this is the case, those variables will be * considered as lvalues and the following argument as a keyword. */ KeywordCallState keywordCallState = scanLine(initialKeywordCallState, line, argOff); if (!keywordCallState.isUndetermined()) { return keywordCallState; } outer: for (int lineIdx = lineIterator.nextIndex(); lineIdx < lines.size(); ++lineIdx) { RobotLine nextLine = lines.get(lineIdx); LineType type = nextLine.type; switch (type) { case COMMENT_LINE: continue; case CONTINUATION_LINE: { int nextLineArgOff = determineContinuationLineArgOff(nextLine); keywordCallState = scanLine(keywordCallState, nextLine, nextLineArgOff); if (!keywordCallState.isUndetermined()) { return keywordCallState; } break; } default: break outer; } } // no equal sign found so.. return initialKeywordCallState == KeywordCallState.UNDETERMINED_NOT_FOR_NOINDENT ? KeywordCallState.KEYWORD_NOT_FOR_NOINDENT : KeywordCallState.KEYWORD; }
private KeywordCallState scanLine( KeywordCallState initialKeywordCallState, RobotLine scanLine, int scanOff) { assert initialKeywordCallState.isUndetermined(); for (; scanOff < scanLine.arguments.size(); ++scanOff) { ParsedString parsedString = scanLine.arguments.get(scanOff); if (parsedString.isEmpty()) { if (initialKeywordCallState == KeywordCallState.UNDETERMINED) { // no variables yet continue; } else { // no equal sign found before first non-variable parameter return initialKeywordCallState == KeywordCallState.UNDETERMINED_NOT_FOR_NOINDENT ? KeywordCallState.KEYWORD_NOT_FOR_NOINDENT : KeywordCallState.KEYWORD; } } String arg = parsedString.getValue(); switch (arg.charAt(0)) { case '$': case '@': // TODO ensure it's a proper lvalue initialKeywordCallState = KeywordCallState.UNDETERMINED_GOTVARIABLE; break; default: // non-variable and no prior lvalue indication, so.. return initialKeywordCallState == KeywordCallState.UNDETERMINED_NOT_FOR_NOINDENT ? KeywordCallState.KEYWORD_NOT_FOR_NOINDENT : KeywordCallState.KEYWORD; } if (arg.endsWith("=")) { return initialKeywordCallState == KeywordCallState.UNDETERMINED_NOT_FOR_NOINDENT ? KeywordCallState.LVALUE_NOINDENT : KeywordCallState.LVALUE; } } return initialKeywordCallState; }
/** * Before this is called the first time, keywordSequence_keywordCallState must be initialized to * either UNDETERMINED, UNDETERMINED_NOINDENT, KEYWORD_NOINDENT, KEYWORD_NOT_FOR_NOINDENT * * @param templatesEnabled whether the template flags {@link #globalTemplateAtLine} and {@link * #localTemplateAtLine} affect keyword calls during this invocation */ private void parseKeywordCall(boolean templatesEnabled) { if (keywordSequence_keywordCallState.isUndetermined()) { keywordSequence_keywordCallState = determineInitialKeywordCallState(keywordSequence_keywordCallState); } switch (keywordSequence_keywordCallState) { case LVALUE_NOINDENT: case LVALUE: { ParsedString variable = line.arguments.get(argOff); if (!variable.isEmpty() || keywordSequence_keywordCallState == KeywordCallState.LVALUE_NOINDENT) { variable.setType(ArgumentType.KEYWORD_LVALUE); if (variable.getValue().endsWith("=")) { keywordSequence_keywordCallState = KeywordCallState.KEYWORD_NOT_FOR_NOINDENT; } } prepareNextToken(); return; } case KEYWORD_NOT_FOR_NOINDENT: case KEYWORD: { ParsedString keyword = line.arguments.get(argOff); if (!keyword.isEmpty() || keywordSequence_keywordCallState == KeywordCallState.KEYWORD_NOT_FOR_NOINDENT) { if (keyword.getValue().equals(":FOR") && keywordSequence_keywordCallState != KeywordCallState.KEYWORD_NOT_FOR_NOINDENT) { keyword.setType(ArgumentType.FOR_PART); keywordSequence_keywordCallState = KeywordCallState.FOR_VARS; } else { if (templatesEnabled && isTemplateActive()) { keyword.setType(ArgumentType.KEYWORD_ARG); // TODO support "Run Keyword If" etc as template keyword keywordSequence_keywordArgPos = KEYWORD_ARG_POS_NONE; } else if (NONE_STR.equals(keyword.getValue())) { // TODO verify what is this branch about keyword.setType(ArgumentType.SETTING_VAL); keywordSequence_keywordArgPos = KEYWORD_ARG_POS_NONE; } else { keyword.setType(ArgumentType.KEYWORD_CALL); setUpKeywordArgPos(keyword); } keywordSequence_keywordCallState = KeywordCallState.KEYWORD_ARGS; } } prepareNextToken(); return; } case FOR_VARS: { ParsedString arg = line.arguments.get(argOff); String argVal = arg.getValue(); if (argVal.equals("IN") || argVal.equals("IN RANGE")) { arg.setType(ArgumentType.FOR_PART); keywordSequence_keywordCallState = KeywordCallState.FOR_ARGS; prepareNextToken(); return; } arg.setType(ArgumentType.KEYWORD_LVALUE); prepareNextToken(); return; } case FOR_ARGS: { setArgTypesToEol(ArgumentType.KEYWORD_ARG); prepareNextLine(); return; } case KEYWORD_ARGS: { ParsedString arg = line.arguments.get(argOff); boolean isKeyword; switch (keywordSequence_keywordArgPos) { case KEYWORD_ARG_POS_NONE: isKeyword = false; break; case KEYWORD_ARG_POS_ALL: isKeyword = true; break; default: isKeyword = keywordSequence_currentArgPos++ == keywordSequence_keywordArgPos; if (isKeyword) { setUpKeywordArgPos(arg); } break; } if (isKeyword) { arg.setType(ArgumentType.KEYWORD_CALL_DYNAMIC); } else { arg.setType(ArgumentType.KEYWORD_ARG); } prepareNextToken(); return; } default: throw new RuntimeException(); } }