native class StringTokens (str, separator, discardSeparators, groupSeparators, limit) satisfies {String+} { String str; Boolean separator(Character ch); Boolean discardSeparators; Boolean groupSeparators; Integer? limit; shared actual native Iterator<String> iterator(); shared actual native Boolean empty; } native("js") class StringTokens (str, separator, discardSeparators, groupSeparators, limit) satisfies {String+} { String str; Boolean separator(Character ch); Boolean discardSeparators; Boolean groupSeparators; Integer? limit; shared actual native("js") Boolean empty => false; shared actual native("js") Iterator<String> iterator() { dynamic str = this.str; return object satisfies Iterator<String> { variable value first = true; variable value lastTokenWasSeparator = false; variable value count = 0; variable value index = 0; Integer currentCodePoint { dynamic { return str.codePointAt(index); } } Integer currentCharCode { dynamic { return str.codePointAt(index); } } void advanceToEnd() { dynamic { index = str.length; } } void advance() { index += #d800 <= currentCharCode <= #dbff then 2 else 1; } value eof { dynamic { return index >= str.length; } } value separator => !eof && outer.separator(currentCodePoint.character); value regular => !eof && !outer.separator(currentCodePoint.character); String token(Integer start, Boolean separator) { if (!separator) { count ++; } first = false; lastTokenWasSeparator = separator; dynamic { return str.substring(start, index); } } function emptyToken() { count ++; first = false; lastTokenWasSeparator = false; return ""; } shared actual String|Finished next() { if (!eof) { if (first || lastTokenWasSeparator, separator) { return emptyToken(); } if (separator) { value start = index; advance(); if (groupSeparators) { while (separator) { advance(); } } if (!discardSeparators) { return token(start, true); } } value start = index; if (exists limit, count>=limit) { advanceToEnd(); } else { while (regular) { advance(); } } return token(start, true); } else if (lastTokenWasSeparator) { return emptyToken(); } else { return finished; } } }; } } native("jvm") class StringTokens (str, separator, discardSeparators, groupSeparators, limit) satisfies {String+} { import java.lang { JString=String, JCharacter=Character } String str; Boolean separator(Character ch); Boolean discardSeparators; Boolean groupSeparators; Integer? limit; shared actual native("jvm") Boolean empty => false; shared actual native("jvm") Iterator<String> iterator() => object satisfies Iterator<String> { value string = JString(str); variable value first = true; variable value lastTokenWasSeparator = false; variable value count = 0; variable value index = 0; void advanceToEnd() { index = string.length(); } void advance() { index += JCharacter.charCount(string.codePointAt(index)); } value eof => index >= string.length(); value separator => !eof && outer.separator(string.codePointAt(index).character); value regular => !eof && !outer.separator(string.codePointAt(index).character); String token(Integer start, Boolean separator) { if (!separator) { count ++; } first = false; lastTokenWasSeparator = separator; return string.substring(start, index); } String emptyToken() { count ++; first = false; lastTokenWasSeparator = false; return ""; } shared actual String|Finished next() { if (!eof) { if (first || lastTokenWasSeparator, separator) { return emptyToken(); } if (separator) { value start = index; advance(); if (groupSeparators) { while (separator) { advance(); } } if (!discardSeparators) { return token(start, true); } } value start = index; if (exists limit, count>=limit) { advanceToEnd(); } else { while (regular) { advance(); } } return token(start, true); } else if (lastTokenWasSeparator) { return emptyToken(); } else { return finished; } } }; }