/* ============================================================================== FrameSequenceParser.cpp Created: 11 Dec 2019 8:49:02am Author: 除村 武志 ============================================================================== */ #include "FrameSequenceParser.h" std::vector FrameSequenceParser::parseSlope (const String& input, int minValue, int maxValue, ParseError* error) { std::vector retval; // find index of "to" int toIndex = input.indexOf ("to"); if (toIndex < 0) { // Normally this is impossible because it's checking existance of "to" to check if it's a slope *error = kParseErrorMissingSlopeValueDelimiter; return retval; } if (toIndex < 1) { *error = kParseErrorMissingSlopeInitialValue; return retval; } // find index of "in" int inIndex = input.indexOf ("in"); if (inIndex < 0) { *error = kParseErrorMissingSlopeLengthDelimiter; return retval; } if (inIndex > input.length() - 3) { *error = kParseErrorMissingSlopeFrameCount; return retval; } if (inIndex - toIndex < 3) { *error = kParseErrorMissingSlopeFinalValue; return retval; } // get 3 substrings separated by "to" and "in" and put them into `from`, `to`, `cntStr` String fromStr = input.substring (0, toIndex); String toStr = input.substring (toIndex + 2, inIndex); String cntStr = input.substring (inIndex + 2, input.length()); // remove "f" from `cntStr` if exists String cntStr_t = cntStr.replace ("f", ""); if (!fromStr.containsOnly ("-0123456789")) { *error = kParseErrorNotANumber; return retval; } if (!toStr.containsOnly ("-0123456789")) { *error = kParseErrorNotANumber; return retval; } if (!cntStr_t.containsOnly ("-0123456789")) { *error = kParseErrorNotANumber; return retval; } // convert each strings to int double fromValue = fromStr.getDoubleValue(); double toValue = toStr.getDoubleValue(); double cntValue = cntStr_t.getDoubleValue(); if (fromValue > (double)maxValue || toValue > (double)maxValue ) { *error = kParseErrorValueOutOfRange; return retval; } if (fromValue < (double)minValue || toValue < (double)minValue ) { *error = kParseErrorValueOutOfRange; return retval; } if (cntValue < 2.0) { *error = kParseErrorFrameLengthTooShort; return retval; } // calculate slope as double double slope = (toValue - fromValue) / (cntValue - 1.0); for (double i = 0; i < cntValue; i += 1.0) { double value = fromValue + slope * i; int rounded = round (value); retval.push_back (rounded); } return retval; } std::vector FrameSequenceParser::parseHold (const String& input, int minValue, int maxValue, ParseError* error) { std::vector retval; // find index of "x" int xIndex = input.indexOf ("x"); if (xIndex < 1) { *error = kParseErrorMissingHoldValue; return retval; } if (xIndex >= input.length() - 1) { *error = kParseErrorMissingHoldFrameCount; return retval; } // separate into value, count String valueStr = input.substring (0, xIndex); String cntStr = input.substring (xIndex + 1, input.length()); // remove "f" from `cntStr` if exists String cntStr_t = cntStr.replace ("f", ""); if (!valueStr.containsOnly ("-0123456789")) { *error = kParseErrorNotANumber; return retval; } if (!cntStr_t.containsOnly ("-0123456789")) { *error = kParseErrorNotANumber; return retval; } int value = valueStr.getIntValue(); if (value < minValue || value > maxValue) { *error = kParseErrorValueOutOfRange; return retval; } int count = cntStr_t.getIntValue(); for (int i = 0; i < count; i++) { retval.push_back (value); } return retval; } std::vector FrameSequenceParser::parseSegment (const String& input, int minValue, int maxValue, ParseError* error) { std::vector retval; StringArray temp; temp.addTokens (input, ",", ""); for (String aToken : temp) { std::vector parsed; if (aToken.contains ("to")) { // parse as slope parsed = parseSlope (aToken, minValue, maxValue, error); } else if (aToken.contains ("x")) { // parse as repeat-fixed-value parsed = parseHold (aToken, minValue, maxValue, error); } else { // parse as single value if (aToken.length() < 1) { *error = kParseErrorNotANumber; return retval; } if (!aToken.containsOnly ("-0123456789")) { *error = kParseErrorNotANumber; return retval; } int value = aToken.getIntValue(); if (value < minValue || value > maxValue) { *error = kParseErrorValueOutOfRange; return retval; } parsed.push_back (value); } retval.insert (retval.end(), parsed.begin(), parsed.end()); } return retval; } SegmentIndexes FrameSequenceParser::findSegment(const String& input) { int releaseBlockIndex = -1; int repeatStartIndex = -1; int repeatEndIndex = -1; int openBracketCount = 0; int closeBracketCount = 0; SegmentIndexes retval = SegmentIndexes(); // loop by character for (int i = 0; i < input.length(); i++) { if (input[i] == '|') // found "|": { if (releaseBlockIndex >= 0) { // if releaseBlockIndex is already determined: Duplication Error retval.error = kParseErrorDuplicatedReleaseDelimiter; return retval; } // if(repeatStartIndex >= 0) { // // if appeard before "[" or "]": Repetition After Release Error // throw new FrameSequenceParseException(TRANS("You cannot repeat in release phase"), true); // } // set releaseBlockIndex releaseBlockIndex = i + 1; if (repeatEndIndex < 0) { // if "]" is omitted: Also set repeatEndIndex repeatEndIndex = i; } } if (input[i] == '[') /// found "[": { openBracketCount++; if (openBracketCount > 1) { // Duplication Error retval.error = kParseErrorDuplicatedOpenBracket; return retval; } if (releaseBlockIndex >= 0) { // if repeat end is already defined: Repetition After Release Error retval.error = kParseErrorRepeatingInReleaseBlock; return retval; } if (repeatEndIndex >= 0) { // if repeat end is already defined: Repetition After Release Error retval.error = kParseErrorDuplicatedOpenBracket; return retval; } // set repeatStartIndex repeatStartIndex = i + 1; } if (input[i] == ']') // found "]": { closeBracketCount++; if (closeBracketCount > 1) { // Duplication Error retval.error = kParseErrorDuplicatedCloseBracket; return retval; } if (repeatStartIndex < 0) { // if repeatStartIndex hasn't set: Syntax Error retval.error = kParseErrorUnmatchingCloseBracket; return retval; } if (releaseBlockIndex >= 0) { // if repeat end is already defined: Repetition After Release Error retval.error = kParseErrorRepeatingInReleaseBlock; return retval; } repeatEndIndex = i; } } // if (releaseBlockIndex < 0) { // "|" didn't explicitly specified // releaseBlockIndex = trimmed.length(); // } if (openBracketCount != closeBracketCount) { retval.error = kParseErrorUnmatchingBracketNumber; return retval; } if (releaseBlockIndex - repeatEndIndex > 1) { // throw new FrameSequenceParseException(TRANS("Elements between repeat block and release block will be ignored"), false); // FiXME: non-fatal exceptionをどう扱うか } retval.releaseBlockIndex = releaseBlockIndex; retval.repeatStartIndex = repeatStartIndex; retval.repeatEndIndex = repeatEndIndex; return retval; } void FrameSequenceParser::splitSegment (const String& input, SegmentIndexes indexes, String& beforeRepeat, String& insideRepeat, String& afterRelease) { int releaseBlockIndex = indexes.releaseBlockIndex; int repeatStartIndex = indexes.repeatStartIndex; int repeatEndIndex = indexes.repeatEndIndex; // Just for convenience bool hasRelease = (releaseBlockIndex >= 0); bool shouldRepeat = (repeatStartIndex >= 0); if (shouldRepeat) { if (hasRelease) { beforeRepeat = input.substring(0, repeatStartIndex - 1); insideRepeat = input.substring (repeatStartIndex, repeatEndIndex); afterRelease = input.substring(releaseBlockIndex, input.length()); } else { beforeRepeat = input.substring(0, repeatStartIndex - 1); insideRepeat = input.substring (repeatStartIndex, repeatEndIndex); } } else { if (hasRelease) { beforeRepeat = input.substring (0, releaseBlockIndex - 1); afterRelease = input.substring (releaseBlockIndex, input.length()); } else { beforeRepeat = input.substring (0, input.length()); } } } FrameSequence FrameSequenceParser::parse (const String& input, int minValue, int maxValue, ParseError* error) { FrameSequence fs; //----------------------------------- // // Preprocessing // //----------------------------------- // Remove white spaces String trimmed = input.replace (" ", ""); // // Overall structure // SegmentIndexes si = findSegment(trimmed); // Just for convenience bool hasRelease = (si.releaseBlockIndex >= 0); bool shouldRepeat = (si.repeatStartIndex >= 0); //----------------------------------- // // Split segments // //----------------------------------- String str_beforeRepeat; String str_insideRepeat; String str_release; splitSegment(trimmed, si, str_beforeRepeat, str_insideRepeat, str_release); //----------------------------------- // // Parse segments // //----------------------------------- // Parse main segment to get frameSequence // And set frameSequence value to working variable // FrameSequence *fs = std::make_unique(); std::vector sequence = parseSegment (str_beforeRepeat, minValue, maxValue, error); if (*error > kParseErrorLevelFatal) { return fs; } fs.sequence = sequence; fs.sequence.reserve (1000); fs.releaseSequenceStartIndex = (int)fs.sequence.size(); if (shouldRepeat) // If repeat segment exists: { // Set repeatStartIndex according to current working frameSequence length fs.isLooped = true; fs.loopStartIndex = (int)fs.sequence.size(); // Parse repeat segment and to get frameSequence std::vector repeatSeq = parseSegment (str_insideRepeat, minValue, maxValue, error); if (*error > kParseErrorLevelFatal) { return fs; } if (repeatSeq.size() == 0) { // Repeat section is defined but content is empty *error = kParseWarningRepeatSegmentEmpty; } // Add the result to working frameSequence fs.sequence.insert (fs.sequence.end(), repeatSeq.begin(), repeatSeq.end()); // Set repeatEndIndex according to current working frameSequence length fs.releaseSequenceStartIndex = (int)fs.sequence.size(); } if (fs.sequence.size() == 0) { *error = kParseErrorPreReleaseSegmentEmpty; } if (hasRelease) // If release exists: { // Set releaseStartIndex according to current working frameSequence length fs.releaseSequenceStartIndex = (int)fs.sequence.size(); fs.hasRelease = true; // Parse release segment to get frameSequence std::vector releaseSeq = parseSegment (str_release, minValue, maxValue, error); if (*error > kParseErrorLevelFatal) { return fs; } if (releaseSeq.size() == 0) { // Release section is defined but content is empty *error = kParseWarningRepeatSegmentEmpty; } // Add the result to working frameSequence fs.sequence.insert (fs.sequence.end(), releaseSeq.begin(), releaseSeq.end()); printf ("success"); } // return the frameSequence return fs; }