You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1281 lines
42 KiB
1281 lines
42 KiB
4 years ago
|
/**
|
||
|
* API that provides functions for working with text data, including
|
||
|
* standard `string` and Acedia's `Text` and raw string format
|
||
|
* `array<Text.Character>`.
|
||
|
* Copyright 2020 Anton Tarasenko
|
||
|
*------------------------------------------------------------------------------
|
||
|
* This file is part of Acedia.
|
||
|
*
|
||
|
* Acedia is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Acedia is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Acedia. If not, see <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
class TextAPI extends Singleton
|
||
|
dependson(Text);
|
||
|
|
||
|
// Escape code point is used to change output's color and is used in
|
||
|
// Unreal Engine's `string`s.
|
||
|
var private const int CODEPOINT_ESCAPE;
|
||
|
// Opening and closing symbols for colored blocks in formatted strings.
|
||
|
var private const int CODEPOINT_OPEN_FORMAT;
|
||
|
var private const int CODEPOINT_CLOSE_FORMAT;
|
||
|
// Symbol to escape any character in formatted strings,
|
||
|
// including above mentioned opening and closing symbols.
|
||
|
var private const int CODEPOINT_FORMAT_ESCAPE;
|
||
|
|
||
|
// Every formatted string essentially consists of multiple differently
|
||
|
// formatted (colored) parts. Such strings will be more convenient for us to
|
||
|
// work with if we separate them from each other.
|
||
|
// This structure represents one such block: maximum uninterrupted
|
||
|
// substring, every character of which has identical formatting.
|
||
|
// Do note that a single block does not define text formatting, -
|
||
|
// it is defined by the whole sequence of blocks before it
|
||
|
// (if `isOpening == false` you only know that you should change previous
|
||
|
// formatting, but you do not know to what).
|
||
|
struct FormattedBlock
|
||
|
{
|
||
|
// Did this block start by opening or closing formatted part?
|
||
|
// Ignored for the very first block without any formatting.
|
||
|
var bool isOpening;
|
||
|
// Full text inside the block, without any formatting
|
||
|
var array<Text.Character> contents;
|
||
|
// Formatting tag for this block
|
||
|
// (ignored for `isOpening == false`)
|
||
|
var string tag;
|
||
|
// Whitespace symbol that separates tag from the `contents`;
|
||
|
// For the purposes of reassembling a `string` broken into blocks.
|
||
|
var Text.Character delimiter;
|
||
|
};
|
||
|
|
||
|
private final function FormattedBlock CreateFormattedBlock(bool isOpening)
|
||
|
{
|
||
|
local FormattedBlock newBlock;
|
||
|
newBlock.isOpening = isOpening;
|
||
|
return newBlock;
|
||
|
}
|
||
|
|
||
|
// Function that breaks formatted string into array of `FormattedBlock`s.
|
||
|
// Returned array is guaranteed to always have at least one block.
|
||
|
// First block in array always corresponds to part of the input string
|
||
|
// (`source`) without any formatting defined, even if it's empty.
|
||
|
// This is to avoid `FormattedBlock` having a third option besides two defined
|
||
|
// by `isOpening` variable.
|
||
|
private final function array<FormattedBlock> DecomposeFormattedString(
|
||
|
string source)
|
||
|
{
|
||
|
local Parser parser;
|
||
|
local Text.Character nextCharacter;
|
||
|
local FormattedBlock nextBlock;
|
||
|
local array<FormattedBlock> result;
|
||
|
parser = ParseString(source, STRING_Plain);
|
||
|
while (!parser.HasFinished()) {
|
||
|
parser.MCharacter(nextCharacter);
|
||
|
// New formatted block by "{<color>"
|
||
|
if (IsCodePoint(nextCharacter, CODEPOINT_OPEN_FORMAT))
|
||
|
{
|
||
|
result[result.length] = nextBlock;
|
||
|
nextBlock = CreateFormattedBlock(true);
|
||
|
parser.MUntil(nextBlock.tag,, true).MCharacter(nextBlock.delimiter);
|
||
|
if (!parser.Ok()) {
|
||
|
break;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
// New formatted block by "}"
|
||
|
if (IsCodePoint(nextCharacter, CODEPOINT_CLOSE_FORMAT))
|
||
|
{
|
||
|
result[result.length] = nextBlock;
|
||
|
nextBlock = CreateFormattedBlock(false);
|
||
|
continue;
|
||
|
}
|
||
|
// Escaped sequence
|
||
|
if (IsCodePoint(nextCharacter, CODEPOINT_FORMAT_ESCAPE)) {
|
||
|
parser.MCharacter(nextCharacter);
|
||
|
}
|
||
|
if (!parser.Ok()) {
|
||
|
break;
|
||
|
}
|
||
|
nextBlock.contents[nextBlock.contents.length] = nextCharacter;
|
||
|
}
|
||
|
// Only put in empty block if there is nothing else.
|
||
|
if (nextBlock.contents.length > 0 || result.length == 0) {
|
||
|
result[result.length] = nextBlock;
|
||
|
}
|
||
|
_.memory.Free(parser);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts given `string` (`source`) of specified type `sourceType`
|
||
|
* into the "raw data", a sequence of individually colored symbols.
|
||
|
*
|
||
|
* @param source `string` that we want to break into a raw data.
|
||
|
* @param sourceType Type of the `string`, plain by default.
|
||
|
* @return Raw data, corresponding to the given `string` if it's
|
||
|
* treated according to `sourceType`.
|
||
|
*/
|
||
|
public final function array<Text.Character> StringToRaw(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
if (sourceType == STRING_Plain) return StoR_Plain(source);
|
||
|
if (sourceType == STRING_Formatted) return StoR_Formatted(source);
|
||
|
return StoR_Colored(source);
|
||
|
}
|
||
|
|
||
|
// Subroutine for converting plain string into raw data
|
||
|
private final function array<Text.Character> StoR_Plain(string source)
|
||
|
{
|
||
|
local int i;
|
||
|
local int sourceLength;
|
||
|
local Text.Character nextCharacter;
|
||
|
local array<Text.Character> result;
|
||
|
|
||
|
// Decompose `source` into integer codes
|
||
|
sourceLength = Len(source);
|
||
|
for (i = 0; i < sourceLength; i += 1)
|
||
|
{
|
||
|
nextCharacter.codePoint = Asc(Mid(source, i, 1));
|
||
|
result[result.length] = nextCharacter;
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Subroutine for converting colored string into raw data
|
||
|
private final function array<Text.Character> StoR_Colored(string source)
|
||
|
{
|
||
|
local int i;
|
||
|
local int sourceLength;
|
||
|
local array<int> sourceAsIntegers;
|
||
|
local Text.Character nextCharacter;
|
||
|
local array<Text.Character> result;
|
||
|
|
||
|
// Decompose `source` into integer codes
|
||
|
sourceLength = Len(source);
|
||
|
for (i = 0; i < sourceLength; i += 1)
|
||
|
{
|
||
|
sourceAsIntegers[sourceAsIntegers.length] = Asc(Mid(source, i, 1));
|
||
|
}
|
||
|
// Record string as array of `Character`s, parsing color tags
|
||
|
i = 0;
|
||
|
while (i < sourceLength)
|
||
|
{
|
||
|
if (sourceAsIntegers[i] == CODEPOINT_ESCAPE)
|
||
|
{
|
||
|
if (i + 3 >= sourceLength) break;
|
||
|
nextCharacter.colorType = STRCOLOR_Struct;
|
||
|
nextCharacter.color = _.color.RGB( sourceAsIntegers[i + 1],
|
||
|
sourceAsIntegers[i + 2],
|
||
|
sourceAsIntegers[i + 3]);
|
||
|
i += 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nextCharacter.codePoint = sourceAsIntegers[i];
|
||
|
result[result.length] = nextCharacter;
|
||
|
i += 1;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Subroutine for converting formatted string into raw data
|
||
|
private final function array<Text.Character> StoR_Formatted(string source)
|
||
|
{
|
||
|
local int i, j;
|
||
|
local Parser parser;
|
||
|
local Text.Character nextCharacter;
|
||
|
local array<FormattedBlock> decomposedSource;
|
||
|
local array<Text.Character> blockContentsCopy;
|
||
|
local array<Text.Character> colorStack;
|
||
|
local array<Text.Character> result;
|
||
|
parser = Parser(_.memory.Borrow(class'Parser'));
|
||
|
nextCharacter.colorType = STRCOLOR_Default;
|
||
|
decomposedSource = DecomposeFormattedString(source);
|
||
|
// First element of `decomposedSource` is special and has
|
||
|
// no color information, see `DecomposeFormattedString()` for details.
|
||
|
result = decomposedSource[0].contents;
|
||
|
for (i = 1; i < decomposedSource.length; i += 1)
|
||
|
{
|
||
|
if (decomposedSource[i].isOpening)
|
||
|
{
|
||
|
parser.Initialize(decomposedSource[i].tag);
|
||
|
nextCharacter = PushIntoColorStack(colorStack, parser);
|
||
|
}
|
||
|
else if (colorStack.length > 0) {
|
||
|
nextCharacter = PopColorStack(colorStack);
|
||
|
}
|
||
|
// This whole method is mostly to decide which formatting each symbol
|
||
|
// should have, so we only copy code points from block's `contents`.
|
||
|
blockContentsCopy = decomposedSource[i].contents;
|
||
|
for (j = 0; j < blockContentsCopy.length; j += 1)
|
||
|
{
|
||
|
nextCharacter.codePoint = blockContentsCopy[j].codePoint;
|
||
|
result[result.length] = nextCharacter;
|
||
|
}
|
||
|
}
|
||
|
_.memory.Free(parser);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Following two functions are to maintain a "color stack" that will
|
||
|
// remember unclosed colors (new colors are obtained from a parser) defined in
|
||
|
// formatted string, on order.
|
||
|
// It is necessary to deal with possible folded formatting definitions in
|
||
|
// formatted strings.
|
||
|
// For storing the color information we simply use `Text.Character`,
|
||
|
// ignoring all information that is not related to colors.
|
||
|
private final function Text.Character PushIntoColorStack(
|
||
|
out array<Text.Character> stack,
|
||
|
Parser colorDefinitionParser)
|
||
|
{
|
||
|
local Text.Character coloredCharacter;
|
||
|
if (colorDefinitionParser.Match("$").Ok()) {
|
||
|
coloredCharacter.colorType = STRCOLOR_Alias;
|
||
|
colorDefinitionParser.MUntil(coloredCharacter.colorAlias,, true);
|
||
|
}
|
||
|
else {
|
||
|
coloredCharacter.colorType = STRCOLOR_Struct;
|
||
|
}
|
||
|
colorDefinitionParser.R();
|
||
|
if (!_.color.ParseWith(colorDefinitionParser, coloredCharacter.color)) {
|
||
|
coloredCharacter.colorType = STRCOLOR_Default;
|
||
|
}
|
||
|
stack[stack.length] = coloredCharacter;
|
||
|
return coloredCharacter;
|
||
|
}
|
||
|
|
||
|
private final function Text.Character PopColorStack(
|
||
|
out array<Text.Character> stack)
|
||
|
{
|
||
|
local Text.Character coloredCharacter;
|
||
|
stack.length = Max(0, stack.length - 1);
|
||
|
if (stack.length > 0) {
|
||
|
coloredCharacter = stack[stack.length - 1];
|
||
|
}
|
||
|
else {
|
||
|
coloredCharacter.colorType = STRCOLOR_Default;
|
||
|
}
|
||
|
return coloredCharacter;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts given "raw data" (`source`) into a `string` of a specified type
|
||
|
* `sourceType`.
|
||
|
*
|
||
|
* @param source Raw data that we want to assemble into a `string`.
|
||
|
* @param sourceType Type of the `string` we want to assemble,
|
||
|
* plain by default.
|
||
|
* @return `string`, assembled from given "raw data" in `sourceType` format.
|
||
|
*/
|
||
|
public final function string RawToString(
|
||
|
array<Text.Character> source,
|
||
|
optional Text.StringType sourceType,
|
||
|
optional Color defaultColor
|
||
|
)
|
||
|
{
|
||
|
if (sourceType == STRING_Plain) return RtoS_Plain(source);
|
||
|
if (sourceType == STRING_Formatted) return RtoS_Formatted(source);
|
||
|
return RtoS_Colored(source, defaultColor);
|
||
|
}
|
||
|
|
||
|
// Subroutine for converting raw data into plain `string`
|
||
|
private final function string RtoS_Plain(array<Text.Character> rawData)
|
||
|
{
|
||
|
local int i;
|
||
|
local string result;
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
result $= Chr(rawData[i].codePoint);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Subroutine for converting raw data into colored `string`
|
||
|
private final function string RtoS_Colored
|
||
|
(
|
||
|
array<Text.Character> rawData,
|
||
|
Color defaultColor
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local Color currentColor;
|
||
|
local Color nextColor;
|
||
|
local string result;
|
||
|
defaultColor = _.color.FixColor(defaultColor);
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
// Skip any escape codepoints to avoid unnecessary colorization
|
||
|
if (IsCodePoint(rawData[i], CODEPOINT_ESCAPE)) continue;
|
||
|
// Find `nextColor` that `rawData[i]` is supposed to have
|
||
|
if (rawData[i].colorType != STRCOLOR_Default)
|
||
|
{
|
||
|
nextColor = _.color.FixColor(rawData[i].color);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nextColor = defaultColor;
|
||
|
}
|
||
|
// Add color tag (either initially or when color changes)
|
||
|
if (i == 0 || !_.color.AreEqual(nextColor, currentColor))
|
||
|
{
|
||
|
currentColor = nextColor;
|
||
|
result $= Chr(CODEPOINT_ESCAPE);
|
||
|
result $= Chr(currentColor.r);
|
||
|
result $= Chr(currentColor.g);
|
||
|
result $= Chr(currentColor.b);
|
||
|
}
|
||
|
result $= Chr(rawData[i].codePoint);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// Subroutine for converting raw data into formatted `string`
|
||
|
private final function string RtoS_Formatted(array<Text.Character> rawData)
|
||
|
{
|
||
|
local int i;
|
||
|
local bool isColorChange;
|
||
|
local Text.Character previousCharacter;
|
||
|
local string result;
|
||
|
previousCharacter.colorType = STRCOLOR_Default;
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
isColorChange = rawData[i].colorType != previousCharacter.colorType;
|
||
|
if (!isColorChange && rawData[i].colorType != STRCOLOR_Default)
|
||
|
{
|
||
|
isColorChange = !_.color.AreEqual( rawData[i].color,
|
||
|
previousCharacter.color);
|
||
|
}
|
||
|
if (isColorChange)
|
||
|
{
|
||
|
if (previousCharacter.colorType != STRCOLOR_Default) {
|
||
|
result $= "}";
|
||
|
}
|
||
|
if (rawData[i].colorType == STRCOLOR_Struct) {
|
||
|
result $= "{" $ _.color.ToString(rawData[i].color) $ " ";
|
||
|
}
|
||
|
if (rawData[i].colorType == STRCOLOR_Alias) {
|
||
|
result $= "{" $ "$" $ rawData[i].colorAlias $ " ";
|
||
|
}
|
||
|
}
|
||
|
if ( IsCodePoint(rawData[i], CODEPOINT_OPEN_FORMAT)
|
||
|
|| IsCodePoint(rawData[i], CODEPOINT_CLOSE_FORMAT)) {
|
||
|
result $= "&";
|
||
|
}
|
||
|
result $= Chr(rawData[i].codePoint);
|
||
|
previousCharacter = rawData[i];
|
||
|
}
|
||
|
if (previousCharacter.colorType != STRCOLOR_Default) {
|
||
|
result $= "}";
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts between three different types of `string`.
|
||
|
*
|
||
|
* @param input `string` to convers
|
||
|
* @param currentType Current type of the given `string`.
|
||
|
* @param newType Type to which given `string` must be converted to.
|
||
|
* @param defaultColor In case `input` is being converted into a
|
||
|
* `STRING_Colored` type, this color will be used for characters
|
||
|
* without one. Otherwise unused.
|
||
|
*/
|
||
|
public final function string ConvertString(
|
||
|
string input,
|
||
|
Text.StringType currentType,
|
||
|
Text.StringType newType,
|
||
|
optional Color defaultColor)
|
||
|
{
|
||
|
local array<Text.Character> rawData;
|
||
|
if (currentType == newType) return input;
|
||
|
rawData = StringToRaw(input, currentType);
|
||
|
return RawToString(rawData, newType, defaultColor);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given character is lower case.
|
||
|
*
|
||
|
* Result of this method describes whether character is
|
||
|
* precisely "lower case", instead of just "not being upper of title case".
|
||
|
* That is, this method will return `true` for characters that aren't
|
||
|
* considered either lowercase or uppercase (like "#", "@" or "&").
|
||
|
*
|
||
|
* @param character Character to test for lower case.
|
||
|
* @return `true` if given character is lower case.
|
||
|
*/
|
||
|
public final function bool IsLower(Text.Character character)
|
||
|
{
|
||
|
// Small Latin letters
|
||
|
if (character.codePoint >= 97 && character.codePoint <= 122) {
|
||
|
return true;
|
||
|
}
|
||
|
// Small Cyrillic (Russian) letters
|
||
|
if (character.codePoint >= 1072 && character.codePoint <= 1103) {
|
||
|
return true;
|
||
|
}
|
||
|
// `ё`
|
||
|
if (character.codePoint == 1105) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given `string` is in lower case.
|
||
|
*
|
||
|
* This function returns `true` as long as it's equal to it's own
|
||
|
* `ToLowerString()` folding.
|
||
|
* This means that it can contain symbols that neither lower or upper case, or
|
||
|
* upper case symbols that don't have a lower case folding.
|
||
|
*
|
||
|
* To check whether a symbol is lower cased, use a combination of
|
||
|
* `GetCharacter()` and `IsLower()`.
|
||
|
*
|
||
|
* @param source `string` to check for being in lower case.
|
||
|
* @param sourceType Type of the `string` to check; default is plain string.
|
||
|
* @return `true` if `string` is equal to it's own lower folding,
|
||
|
* (per character given by `ToLower()` method).
|
||
|
*/
|
||
|
public final function bool IsLowerString
|
||
|
(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local array<Text.Character> rawData;
|
||
|
rawData = StringToRaw(source, sourceType);
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
if (rawData[i] != ToLower(rawData[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given character is upper case.
|
||
|
*
|
||
|
* Result of this method describes whether character is
|
||
|
* precisely "upper case", instead of just "not being upper of title case".
|
||
|
* That is, this method will return `true` for characters that aren't
|
||
|
* considered either uppercase or uppercase (like "#", "@" or "&").
|
||
|
*
|
||
|
* @param character Character to test for upper case.
|
||
|
* @return `true` if given character is upper case.
|
||
|
*/
|
||
|
public final function bool IsUpper(Text.Character character)
|
||
|
{
|
||
|
// Capital Latin letters
|
||
|
if (character.codePoint >= 65 && character.codePoint <= 90) {
|
||
|
return true;
|
||
|
}
|
||
|
// Capital Cyrillic (Russian) letters
|
||
|
if (character.codePoint >= 1040 && character.codePoint <= 1071) {
|
||
|
return true;
|
||
|
}
|
||
|
// `Ё`
|
||
|
if (character.codePoint == 1025) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given `string` is in upper case.
|
||
|
*
|
||
|
* This function returns `true` as long as it's equal to it's own
|
||
|
* `ToUpperString()` folding.
|
||
|
* This means that it can contain symbols that neither lower or upper case, or
|
||
|
* lower case symbols that don't have an upper case folding.
|
||
|
*
|
||
|
* To check whether a symbol is upper cased, use a combination of
|
||
|
* `GetCharacter()` and `IsUpper()`.
|
||
|
*
|
||
|
* @param source `string` to check for being in upper case.
|
||
|
* @param sourceType Type of the `string` to check; default is plain string.
|
||
|
* @return `true` if `string` is equal to it's own upper folding,
|
||
|
* (per character given by `ToUpper()` method).
|
||
|
*/
|
||
|
public final function bool IsUpperString
|
||
|
(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local array<Text.Character> rawData;
|
||
|
rawData = StringToRaw(source, sourceType);
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
if (rawData[i] != ToUpper(rawData[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given character corresponds to a digit.
|
||
|
*
|
||
|
* @param codePoint Unicode code point to check for being a digit.
|
||
|
* @return `true` if given Unicode code point is a digit, `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsDigit(Text.Character character)
|
||
|
{
|
||
|
if (character.codePoint >= 48 && character.codePoint <= 57) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given character is an ASCII character.
|
||
|
*
|
||
|
* @param character Character to check for being a digit.
|
||
|
* @return `true` if given character is a digit, `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsASCII(Text.Character character)
|
||
|
{
|
||
|
if (character.codePoint >= 0 && character.codePoint <= 127) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given `string` consists only from ASCII characters
|
||
|
* (ignoring characters in 4-byte color change sequences in colored strings).
|
||
|
*
|
||
|
* @param source `string` to test for being ASCII-only.
|
||
|
* @param sourceType Type of the passed `string`.
|
||
|
* @return `true` if passed `string` contains only ASCII characters.
|
||
|
*/
|
||
|
public final function bool IsASCIIString
|
||
|
(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local array<Text.Character> rawData;
|
||
|
rawData = StringToRaw(source, sourceType);
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
if (!IsASCII(rawData[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given character represents some kind of white space
|
||
|
* symbol (like space ~ 0x0020, tab ~ 0x0009, etc.),
|
||
|
* according to either Unicode or a more classic space symbol definition,
|
||
|
* that includes:
|
||
|
* whitespace, tab, line feed, line tabulation, form feed, carriage return.
|
||
|
*
|
||
|
* @param character Character to check for being a whitespace.
|
||
|
* @return `true` if given character is a whitespace, `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsWhitespace(Text.Character character)
|
||
|
{
|
||
|
switch (character.codePoint)
|
||
|
{
|
||
|
// Classic whitespaces
|
||
|
case 0x0020: // Whitespace
|
||
|
case 0x0009: // Tab
|
||
|
case 0x000A: // Line feed
|
||
|
case 0x000B: // Line tabulation
|
||
|
case 0x000C: // Form feed
|
||
|
case 0x000D: // Carriage return
|
||
|
// Unicode Characters in the 'Separator, Space' Category
|
||
|
case 0x00A0: // No-break space
|
||
|
case 0x1680: // Ogham space mark
|
||
|
case 0x2000: // En quad
|
||
|
case 0x2001: // Em quad
|
||
|
case 0x2002: // En space
|
||
|
case 0x2003: // Em space
|
||
|
case 0x2004: // Three-per-em space
|
||
|
case 0x2005: // Four-per-em space
|
||
|
case 0x2006: // Six-per-em space
|
||
|
case 0x2007: // Figure space
|
||
|
case 0x2008: // Punctuation space
|
||
|
case 0x2009: // Thin space
|
||
|
case 0x200A: // Hair space
|
||
|
case 0x202F: // Narrow no-break space
|
||
|
case 0x205F: // Medium mathematical space
|
||
|
case 0x3000: // Ideographic space
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if passed character is one of the following quotation mark symbols:
|
||
|
* `"`, `'`, `\``.
|
||
|
*
|
||
|
* @param character Character to check for being a quotation mark.
|
||
|
* @return `true` if given Unicode code point denotes one of the recognized
|
||
|
* quote symbols, `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsQuotationMark(Text.Character character)
|
||
|
{
|
||
|
if (character.codePoint == 0x0022) return true;
|
||
|
if (character.codePoint == 0x0027) return true;
|
||
|
if (character.codePoint == 0x0060) return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts given character into a number it represents in some base
|
||
|
* (from 2 to 36), i.e.:
|
||
|
* 1 -> 1
|
||
|
* 7 -> 7
|
||
|
* a -> 10
|
||
|
* e -> 14
|
||
|
* z -> 35
|
||
|
*
|
||
|
* @param character Character to convert into integer.
|
||
|
* Case does not matter, i.e. "a" and "A" will be treated the same.
|
||
|
* @param base Base to use for conversion.
|
||
|
* Valid values are from `2` to `36` (inclusive);
|
||
|
* If invalid value was specified (such as default `0`),
|
||
|
* the base of `36` is assumed, since that would allow for all possible
|
||
|
* characters to be converted.
|
||
|
* @return Positive integer value that is denoted by
|
||
|
* given character in given base;
|
||
|
* `-1` if given character does not represent anything in the given base.
|
||
|
*/
|
||
|
public final function int CharacterToInt
|
||
|
(
|
||
|
Text.Character character,
|
||
|
optional int base
|
||
|
)
|
||
|
{
|
||
|
local int number;
|
||
|
if (base < 2 || base > 36) {
|
||
|
base = 36;
|
||
|
}
|
||
|
character = ToLower(character);
|
||
|
// digits
|
||
|
if (character.codePoint >= 0x0030 && character.codePoint <= 0x0039) {
|
||
|
number = character.codePoint - 0x0030;
|
||
|
}
|
||
|
// a-z
|
||
|
else if (character.codePoint >= 0x0061 && character.codePoint <= 0x007a) {
|
||
|
number = character.codePoint - 0x0061 + 10;
|
||
|
}
|
||
|
else {
|
||
|
return -1;
|
||
|
}
|
||
|
if (number >= base) {
|
||
|
return -1;
|
||
|
}
|
||
|
return number;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given `character` can be represented by a given `codePoint` in
|
||
|
* Unicode standard.
|
||
|
*
|
||
|
* @param character Character to check.
|
||
|
* @param codePoint Code point to check.
|
||
|
* @return `true` if given character can be represented by a given code point
|
||
|
* and `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsCodePoint(Text.Character character, int codePoint)
|
||
|
{
|
||
|
return (character.codePoint == codePoint);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a particular character from a given `string`, of a given type,
|
||
|
* with preserved color information.
|
||
|
*
|
||
|
* @param source String, from which to fetch the character.
|
||
|
* @param position Which, in order, character to fetch
|
||
|
* (starting counting from '0').
|
||
|
* By default returns first (`0`th) character.
|
||
|
* @param sourceType Type of the given `source` `string`.
|
||
|
* @return Character from a `source` at a given position `position`.
|
||
|
* If given position is out-of-bounds for a given `string`
|
||
|
* (it is either negative or at least the same as a total character count),
|
||
|
* - returns invalid character.
|
||
|
*/
|
||
|
public final function Text.Character GetCharacter
|
||
|
(
|
||
|
string source,
|
||
|
optional int position,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
local Text.Character resultCharacter;
|
||
|
local array<Text.Character> rawData;
|
||
|
if (position < 0) return GetInvalidCharacter();
|
||
|
|
||
|
// `STRING_Plain` is the only type where we do not need to do any parsing
|
||
|
// and get just fetch a character, so handle it separately.
|
||
|
if (sourceType == STRING_Plain)
|
||
|
{
|
||
|
if (position >= Len(source)) {
|
||
|
return GetInvalidCharacter();
|
||
|
}
|
||
|
resultCharacter.codePoint = Asc(Mid(source, position, 1));
|
||
|
return resultCharacter;
|
||
|
}
|
||
|
rawData = StringToRaw(source, sourceType);
|
||
|
if (position >= rawData.length) {
|
||
|
return GetInvalidCharacter();
|
||
|
}
|
||
|
return rawData[position];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns color of a given `Character` with set default color.
|
||
|
*
|
||
|
* `Character`s can have their color set to "default", meaning they would use
|
||
|
* whatever considered default color in the context.
|
||
|
*
|
||
|
* @param character `Character`, which color to return.
|
||
|
* @param defaultColor Color, considered default.
|
||
|
* @return Supposed color of a given `Character`, assuming default color is
|
||
|
* `defaultColor`.
|
||
|
*/
|
||
|
public final function Color GetCharacterColor(
|
||
|
Text.Character character,
|
||
|
Color defaultColor)
|
||
|
{
|
||
|
if (character.colorType == STRCOLOR_Default) {
|
||
|
return defaultColor;
|
||
|
}
|
||
|
return character.color;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns character that is considered invalid.
|
||
|
*
|
||
|
* It is not unique, there can be different invalid characters.
|
||
|
*
|
||
|
* @return Invalid character instance.
|
||
|
*/
|
||
|
public final function Text.Character GetInvalidCharacter()
|
||
|
{
|
||
|
local Text.Character result;
|
||
|
result.codePoint = -1;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given character is invalid.
|
||
|
*
|
||
|
* @param character Character to check.
|
||
|
* @return `true` if passed character is valid and `false` otherwise.
|
||
|
*/
|
||
|
public final function bool IsValidCharacter(Text.Character character)
|
||
|
{
|
||
|
return (character.codePoint >= 0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given characters are equal, with or without accounting
|
||
|
* for their case.
|
||
|
*
|
||
|
* @param codePoint1 Character to compare.
|
||
|
* @param codePoint2 Character to compare.
|
||
|
* @param caseInsensitive Optional parameter,
|
||
|
* if `false` we will require characters to be exactly the same,
|
||
|
* if `true` we will also consider characters equal if they
|
||
|
* only differ by case.
|
||
|
* @return `true` if given characters are considered equal,
|
||
|
* `false` otherwise.
|
||
|
*/
|
||
|
public final function bool AreEqual(
|
||
|
Text.Character character1,
|
||
|
Text.Character character2,
|
||
|
optional bool caseInsensitive
|
||
|
)
|
||
|
{
|
||
|
if (character1.codePoint == character2.codePoint) return true;
|
||
|
if (character1.codePoint < 0 && character2.codePoint < 0) return true;
|
||
|
|
||
|
if (caseInsensitive)
|
||
|
{
|
||
|
character1 = ToLower(character1);
|
||
|
character2 = ToLower(character2);
|
||
|
}
|
||
|
return (character1.codePoint == character2.codePoint);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if given `string`s are equal to each other, with or without
|
||
|
* accounting for their case.
|
||
|
*
|
||
|
* @param string1 `string` to compare.
|
||
|
* @param string2 `string` to compare.
|
||
|
* @param caseInsensitive Optional parameter,
|
||
|
* if `false` we will require `string`s to be exactly the same,
|
||
|
* if `true` we will also consider `string`s equal if their corresponding
|
||
|
* characters only differ by case.
|
||
|
* @return `true` if given `string`s are considered equal, `false` otherwise.
|
||
|
*/
|
||
|
public final function bool AreEqualStrings(
|
||
|
string string1,
|
||
|
string string2,
|
||
|
optional bool caseInsensitive
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local array<Text.Character> rawData1, rawData2;
|
||
|
rawData1 = StringToRaw(string1);
|
||
|
rawData2 = StringToRaw(string2);
|
||
|
if (rawData1.length != rawData2.length) return false;
|
||
|
|
||
|
for (i = 0; i < rawData1.length; i += 1)
|
||
|
{
|
||
|
if (!AreEqual(rawData1[i], rawData2[i], caseInsensitive)) return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts Unicode code point into it's lower case folding,
|
||
|
* as defined by Unicode standard.
|
||
|
*
|
||
|
* @param codePoint Code point to convert into lower case.
|
||
|
* @return Lower case folding of the given code point. If Unicode standard does
|
||
|
* not define any lower case folding (like "&" or "!") for given code point, -
|
||
|
* function returns given code point unchanged.
|
||
|
*/
|
||
|
public final function Text.Character ToLower(Text.Character character)
|
||
|
{
|
||
|
local int newCodePoint;
|
||
|
newCodePoint =
|
||
|
class'UnicodeData'.static.ToLowerCodePoint(character.codePoint);
|
||
|
if (newCodePoint >= 0) {
|
||
|
character.codePoint = newCodePoint;
|
||
|
}
|
||
|
return character;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts Unicode code point into it's upper case version,
|
||
|
* as defined by Unicode standard.
|
||
|
*
|
||
|
* @param codePoint Code point to convert into upper case.
|
||
|
* @return Upper case version of the given code point. If Unicode standard does
|
||
|
* not define any upper case version (like "&" or "!") for given code point, -
|
||
|
* function returns given code point unchanged.
|
||
|
*/
|
||
|
public final function Text.Character ToUpper(Text.Character character)
|
||
|
{
|
||
|
local int newCodePoint;
|
||
|
newCodePoint =
|
||
|
class'UnicodeData'.static.ToUpperCodePoint(character.codePoint);
|
||
|
if (newCodePoint >= 0) {
|
||
|
character.codePoint = newCodePoint;
|
||
|
}
|
||
|
return character;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts `string` to lower case.
|
||
|
*
|
||
|
* Changes every symbol in the `string` to their lower case folding.
|
||
|
* Characters without lower case folding (like "&" or "!") are left unchanged.
|
||
|
*
|
||
|
* @param source `string` that will be converted into a lower case.
|
||
|
* @return Lower case folding of a given `string`.
|
||
|
*/
|
||
|
public final function string ToLowerString(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
if (sourceType == STRING_Plain) {
|
||
|
return ConvertCaseForString_Plain(source, LCASE_Lower);
|
||
|
}
|
||
|
if (sourceType == STRING_Formatted) {
|
||
|
return ConvertCaseForString_Formatted(source, LCASE_Lower);
|
||
|
}
|
||
|
return ConvertCaseForString_Colored(source, LCASE_Lower);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Converts `string` to upper case.
|
||
|
*
|
||
|
* Changes every symbol in the `string` to their upper case folding.
|
||
|
* Characters without upper case folding (like "&" or "!") are left unchanged.
|
||
|
*
|
||
|
* @param source `string` that will be converted into an upper case.
|
||
|
* @return Upper case folding of a given `string`.
|
||
|
*/
|
||
|
public final function string ToUpperString(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType
|
||
|
)
|
||
|
{
|
||
|
if (sourceType == STRING_Plain) {
|
||
|
return ConvertCaseForString_Plain(source, LCASE_Upper);
|
||
|
}
|
||
|
if (sourceType == STRING_Formatted) {
|
||
|
return ConvertCaseForString_Formatted(source, LCASE_Upper);
|
||
|
}
|
||
|
return ConvertCaseForString_Colored(source, LCASE_Upper);
|
||
|
}
|
||
|
|
||
|
private final function string ConvertCaseForString_Plain
|
||
|
(
|
||
|
string source,
|
||
|
Text.LetterCase targetCase
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local array<Text.Character> rawData;
|
||
|
rawData = StringToRaw(source, STRING_Plain);
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
if (targetCase == LCASE_Lower) {
|
||
|
rawData[i] = ToLower(rawData[i]);
|
||
|
}
|
||
|
else {
|
||
|
rawData[i] = ToUpper(rawData[i]);
|
||
|
}
|
||
|
}
|
||
|
return RawToString(rawData, STRING_Plain);
|
||
|
}
|
||
|
|
||
|
private final function string ConvertCaseForString_Colored
|
||
|
(
|
||
|
string source,
|
||
|
Text.LetterCase targetCase
|
||
|
)
|
||
|
{
|
||
|
local int i;
|
||
|
local string result;
|
||
|
local array<Text.Character> rawData;
|
||
|
rawData = StringToRaw(source, STRING_Colored);
|
||
|
for (i = 0; i < rawData.length; i += 1)
|
||
|
{
|
||
|
if (targetCase == LCASE_Lower) {
|
||
|
rawData[i] = ToLower(rawData[i]);
|
||
|
}
|
||
|
else {
|
||
|
rawData[i] = ToUpper(rawData[i]);
|
||
|
}
|
||
|
}
|
||
|
result = RawToString(rawData, STRING_Colored);
|
||
|
if (rawData.length > 0 && rawData[0].colorType == STRCOLOR_Default) {
|
||
|
result = Mid(result, 4);
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private final function string ConvertCaseForString_Formatted
|
||
|
(
|
||
|
string source,
|
||
|
Text.LetterCase targetCase
|
||
|
)
|
||
|
{
|
||
|
// TODO: finish it later, no one needs it right now,
|
||
|
// no idea wtf I even bothered with these functions
|
||
|
return source;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns hash for a raw `string` data.
|
||
|
*
|
||
|
* Uses djb2 algorithm, somewhat adapted to make use of formatting
|
||
|
* (color) information. Hopefully it did not broke horribly.
|
||
|
*
|
||
|
* @param rawData Data to calculate hash of.
|
||
|
* @return Hash of the given data.
|
||
|
*/
|
||
|
public final function int GetHashRaw(array<Text.Character> rawData) {
|
||
|
local int i;
|
||
|
local int colorInt;
|
||
|
local int hash;
|
||
|
hash = 5381;
|
||
|
for (i = 0; i < rawData.length; i += 1) {
|
||
|
// hash * 33 + rawData[i].codePoint
|
||
|
hash = ((hash << 5) + hash) + rawData[i].codePoint;
|
||
|
if (rawData[i].colorType != STRCOLOR_Default) {
|
||
|
colorInt = rawData[i].color.r
|
||
|
+ rawData[i].color.g * 0x00ff
|
||
|
+ rawData[i].color.b * 0xffff;
|
||
|
hash = ((hash << 5) + hash) + colorInt;
|
||
|
}
|
||
|
}
|
||
|
return hash;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns hash for a `string` data.
|
||
|
*
|
||
|
* Uses djb2 algorithm, somewhat adapted to make use of formatting
|
||
|
* (color) information. Hopefully it did not broke horribly.
|
||
|
*
|
||
|
* @param rawData `string` to calculate hash of.
|
||
|
* @param sourceType Type of the `string`, in case you want has to be more
|
||
|
* formatting-independent. Leaving default value (`STRING_Plain`) should be
|
||
|
* fine for almost any use case.
|
||
|
* @return Hash of the given data.
|
||
|
*/
|
||
|
public final function int GetHash(
|
||
|
string source,
|
||
|
optional Text.StringType sourceType) {
|
||
|
return GetHashRaw(StringToRaw(source, sourceType));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a new, empty `Text`.
|
||
|
*
|
||
|
* This is a shortcut, same result cam be achieved by `new class'Text'`.
|
||
|
*
|
||
|
* @return Brand new, empty instance of `Text`.
|
||
|
*/
|
||
|
public final function Text Empty()
|
||
|
{
|
||
|
local Text newText;
|
||
|
newText = new class'Text';
|
||
|
return newText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a `Text` that will contain a given `string`. Parameter made optional
|
||
|
* to enable easier way of creating empty `Text`.
|
||
|
*
|
||
|
* @param source `string` that will be copied into returned `Text`.
|
||
|
* @return New instance (not taken from the object pool) of `Text` that
|
||
|
* will contain passed `string`.
|
||
|
*/
|
||
|
public final function Text FromString(optional string source)
|
||
|
{
|
||
|
local Text newText;
|
||
|
newText = new class'Text';
|
||
|
newText.CopyString(source);
|
||
|
return newText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a `Text` that will contain `string` with characters recorded in the
|
||
|
* given array. Parameter made optional to enable easier way of
|
||
|
* creating empty `Text`.
|
||
|
*
|
||
|
* @param rawData Sequence of characters that will be copied into
|
||
|
* returned `Text`.
|
||
|
* @return New instance (not taken from the object pool) of `Text` that
|
||
|
* will contain passed sequence of Unicode code points.
|
||
|
*/
|
||
|
public final function Text FromRaw(array<Text.Character> rawData)
|
||
|
{
|
||
|
local Text newText;
|
||
|
newText = new class'Text';
|
||
|
newText.CopyRaw(rawData);
|
||
|
return newText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method for creating a new, uninitialized parser object.
|
||
|
*
|
||
|
* Always creates a new parser. This method should be used when you plan to
|
||
|
* store created `Parser` and reuse later.
|
||
|
* To parse something once it's advised to use
|
||
|
* `Parse()`, `ParseString()` or `ParseRaw()` instead.
|
||
|
*
|
||
|
* It is a good practice to free created `Parser` once you don't need it.
|
||
|
*
|
||
|
* @see `Parser`
|
||
|
* @return Guaranteed to be new, uninitialized `Parser`.
|
||
|
*/
|
||
|
public final function Parser NewParser()
|
||
|
{
|
||
|
return (new class'Parser');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method for creating a new parser, initialized with contents of given `Text`.
|
||
|
*
|
||
|
* Always creates a new parser. This method should be used when you plan to
|
||
|
* store created `Parser` and reuse later.
|
||
|
* To parse something once it's advised to use `Parse()` instead.
|
||
|
*
|
||
|
* It is a good practice to free created `Parser` once you don't need it.
|
||
|
*
|
||
|
* @see `Parser`
|
||
|
* @param source Returned `Parser` will be setup to parse the contents of
|
||
|
* the passed `Text`.
|
||
|
* If `none` value is passed, - parser won't be initialized.
|
||
|
* @return Guaranteed to be new `Parser`,
|
||
|
* initialized with contents of `source`.
|
||
|
*/
|
||
|
public final function Parser NewParserFromText(Text source)
|
||
|
{
|
||
|
local Parser parser;
|
||
|
parser = new class'Parser';
|
||
|
parser.InitializeT(source);
|
||
|
return parser;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method for creating a new parser, initialized with a given `string`.
|
||
|
*
|
||
|
* Always creates a new parser. This method should be used when you plan to
|
||
|
* store created `Parser` and reuse later.
|
||
|
* To parse something once it's advised to use `ParseString()` instead.
|
||
|
*
|
||
|
* It is a good practice to free created `Parser` once you don't need it.
|
||
|
*
|
||
|
* @see `Parser`
|
||
|
* @param source Returned `Parser` will be setup to parse the `source`.
|
||
|
* @return Guaranteed to be new `Parser`, initialized with given `string`.
|
||
|
*/
|
||
|
public final function Parser NewParserFromString(string source)
|
||
|
{
|
||
|
local Parser parser;
|
||
|
parser = new class'Parser';
|
||
|
parser.Initialize(source);
|
||
|
return parser;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Method for creating a new parser, initialized with a given sequence of
|
||
|
* characters.
|
||
|
*
|
||
|
* Always creates a new parser. This method should be used when you plan to
|
||
|
* store created `Parser` and reuse later.
|
||
|
* To parse something once it's advised to use `ParseRaw()` instead.
|
||
|
*
|
||
|
* It is a good practice to free created `Parser` once you don't need it.
|
||
|
*
|
||
|
* @see `Parser`
|
||
|
* @param source Returned `Parser` will be setup to parse passed
|
||
|
* characters sequence.
|
||
|
* @return Guaranteed to be new `Parser`, initialized with given
|
||
|
* characters sequence.
|
||
|
*/
|
||
|
public final function Parser NewParserFromRaw(array<Text.Character> source)
|
||
|
{
|
||
|
local Parser parser;
|
||
|
parser = new class'Parser';
|
||
|
parser.InitializeRaw(source);
|
||
|
return parser;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns "temporary" `Parser` that can be used for one-time parsing,
|
||
|
* initialized with a given sequence of characters.
|
||
|
* It will be automatically freed to be reused again after
|
||
|
* current tick ends.
|
||
|
*
|
||
|
* Returned `Parser` does not have to be a new object and
|
||
|
* it is possible that it is still referenced by some buggy or malicious code.
|
||
|
* To ensure that no problem arises:
|
||
|
* 1. Re-initialize returned `Parser` after executing any piece of
|
||
|
* code that you do not trust to misuse `Parser`s;
|
||
|
* 2. Do not use obtained reference after current tick ends or
|
||
|
* calling `FreeParser()` on it.
|
||
|
* For more details @see `Parser`.
|
||
|
*
|
||
|
* @param source Returned `Parser` will be setup to parse passed
|
||
|
* characters sequence.
|
||
|
* @return Temporary `Parser`, initialized with given
|
||
|
* characters sequence.
|
||
|
*/
|
||
|
public final function Parser ParseRaw(array<Text.Character> source)
|
||
|
{
|
||
|
local Parser parser;
|
||
|
parser = Parser(_.memory.Borrow(class'Parser'));
|
||
|
if (parser != none)
|
||
|
{
|
||
|
parser.InitializeRaw(source);
|
||
|
return parser;
|
||
|
}
|
||
|
return none;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns "temporary" `Parser` that can be used for one-time parsing,
|
||
|
* initialized with contents of given `Text`.
|
||
|
* It will be automatically freed to be reused again after
|
||
|
* current tick ends.
|
||
|
*
|
||
|
* Returned `Parser` does not have to be a new object and
|
||
|
* it is possible that it is still referenced by some buggy or malicious code.
|
||
|
* To ensure that no problem arises:
|
||
|
* 1. Re-initialize returned `Parser` after executing any piece of
|
||
|
* code that you do not trust to misuse `Parser`s;
|
||
|
* 2. Do not use obtained reference after current tick ends or
|
||
|
* calling `FreeParser()` on it.
|
||
|
* For more details @see `Parser`.
|
||
|
*
|
||
|
* @param source Returned `Parser` will be setup to parse the contents of
|
||
|
* the passed `Text`.
|
||
|
* @return Temporary `Parser`, initialized with contents of the given `Text`.
|
||
|
*/
|
||
|
public final function Parser Parse(Text source)
|
||
|
{
|
||
|
local Parser parser;
|
||
|
if (source == none) return NewParser();
|
||
|
|
||
|
parser = Parser(_.memory.Borrow(class'Parser'));
|
||
|
if (parser != none)
|
||
|
{
|
||
|
parser.InitializeT(source);
|
||
|
return parser;
|
||
|
}
|
||
|
return none;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns "temporary" `Parser` that can be used for one-time parsing,
|
||
|
* initialized `string`.
|
||
|
* It will be automatically freed to be reused again after
|
||
|
* current tick ends.
|
||
|
*
|
||
|
* Returned `Parser` does not have to be a new object and
|
||
|
* it is possible that it is still referenced by some buggy or malicious code.
|
||
|
* To ensure that no problem arises:
|
||
|
* 1. Re-initialize returned `Parser` after executing any piece of
|
||
|
* code that you do not trust to misuse `Parser`s;
|
||
|
* 2. Do not use obtained reference after current tick ends or
|
||
|
* calling `FreeParser()` on it.
|
||
|
* For more details @see `Parser`.
|
||
|
*
|
||
|
* @param source Returned `Parser` will be setup to parse `source`.
|
||
|
* @return Temporary `Parser`, initialized with the given `string`.
|
||
|
*/
|
||
|
public final function Parser ParseString (
|
||
|
string source,
|
||
|
optional Text.StringType sourceType) {
|
||
|
local Parser parser;
|
||
|
parser = Parser(_.memory.Borrow(class'Parser'));
|
||
|
if (parser != none) {
|
||
|
parser.Initialize(source, sourceType);
|
||
|
return parser;
|
||
|
}
|
||
|
return none;
|
||
|
}
|
||
|
|
||
|
defaultproperties
|
||
|
{
|
||
|
CODEPOINT_ESCAPE = 27 // ANSI escape code
|
||
|
CODEPOINT_OPEN_FORMAT = 123 // '{'
|
||
|
CODEPOINT_CLOSE_FORMAT = 125 // '}'
|
||
|
CODEPOINT_FORMAT_ESCAPE = 38 // '&'
|
||
|
}
|