mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-21 15:57:42 +00:00
286 lines
7.8 KiB
C++
286 lines
7.8 KiB
C++
/*
|
|
Copyright: © SIL International.
|
|
Description: Internal functions for LDML transforms
|
|
Create Date: 6 Oct 2022
|
|
Authors: Steven R. Loomis
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "kmx/kmx_plus.h"
|
|
#include "kmx/kmx_xstring.h"
|
|
#include <deque>
|
|
#include <map>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
#include "debuglog.h"
|
|
|
|
#include "util_regex.hpp"
|
|
|
|
namespace km {
|
|
namespace core {
|
|
namespace ldml {
|
|
|
|
|
|
using km::core::kmx::SimpleUSet;
|
|
|
|
/** a reorder weight, such as primary, secondary, etc. */
|
|
typedef signed char reorder_weight;
|
|
|
|
|
|
|
|
/**
|
|
* Type of a group
|
|
*/
|
|
enum any_group_type {
|
|
transform = LDML_TRAN_GROUP_TYPE_TRANSFORM,
|
|
reorder = LDML_TRAN_GROUP_TYPE_REORDER,
|
|
};
|
|
|
|
/**
|
|
* Corresponds to an 'elem' entry
|
|
*/
|
|
class element {
|
|
public:
|
|
/** construct from a SimpleUSet */
|
|
element(const SimpleUSet &u, KMX_DWORD flags);
|
|
/** construct from a single char */
|
|
element(km_core_usv ch, KMX_DWORD flags);
|
|
/** @returns true if a SimpleUSet type */
|
|
bool is_uset() const;
|
|
/** @returns true if prebase bit set*/
|
|
bool is_prebase() const;
|
|
/** @returns true if tertiary base bit set */
|
|
bool is_tertiary_base() const;
|
|
/** @returns the primary order */
|
|
reorder_weight get_order() const;
|
|
/** @returns the tertiary order */
|
|
reorder_weight get_tertiary() const;
|
|
/** @returns raw elem flags */
|
|
KMX_DWORD get_flags() const;
|
|
/** @returns true if matches this character*/
|
|
bool matches(km_core_usv ch) const;
|
|
/** debugging: dump this element via DebugLog() */
|
|
void dump() const;
|
|
|
|
private:
|
|
// TODO-LDML: support multi-char strings? (Not needed currently)
|
|
const km_core_usv chr;
|
|
const SimpleUSet uset;
|
|
const KMX_DWORD flags;
|
|
};
|
|
|
|
/**
|
|
* An ordered list of strings.
|
|
*/
|
|
typedef std::deque<std::u32string> string_list;
|
|
|
|
/**
|
|
* Inner element, representing <transform>
|
|
*/
|
|
class transform_entry {
|
|
public:
|
|
transform_entry(const transform_entry &other);
|
|
/** simpler constructor for tests */
|
|
transform_entry(
|
|
const std::u32string &from,
|
|
const std::u32string &to
|
|
);
|
|
transform_entry(
|
|
const std::u32string &from,
|
|
const std::u32string &to,
|
|
KMX_DWORD mapFrom,
|
|
KMX_DWORD mapTo,
|
|
const kmx::kmx_plus &kplus,
|
|
bool &valid,
|
|
bool normalization_disabled);
|
|
|
|
/**
|
|
* If matching, apply the match to the output string
|
|
* @param input input string to match
|
|
* @param output output string
|
|
* @returns length of 'input' which was matched
|
|
*/
|
|
size_t apply(const std::u32string &input, std::u32string &output) const;
|
|
|
|
private:
|
|
const std::u32string fFrom;
|
|
const std::u32string fTo;
|
|
km::core::util::km_regex fFromPattern;
|
|
|
|
const KMX_DWORD fMapFromStrId;
|
|
const KMX_DWORD fMapToStrId;
|
|
std::deque<std::u32string> fMapFromList;
|
|
std::deque<std::u32string> fMapToList;
|
|
bool normalization_disabled;
|
|
/** @returns the index of the item in the fMapFromList list, or -1 */
|
|
int32_t findIndexFrom(const std::u32string &match) const;
|
|
public:
|
|
/** @returns the index of the item in the list, or -1 */
|
|
static int32_t findIndex(const std::u32string &match, const std::deque<std::u32string> list);
|
|
};
|
|
|
|
/**
|
|
* a group of <transform> entries - a <transformGroup>
|
|
*/
|
|
class transform_group : public std::deque<transform_entry> {
|
|
public:
|
|
transform_group();
|
|
|
|
/**
|
|
* Find the first match in the group and apply it.
|
|
* @param input input string to match
|
|
* @param output output string
|
|
* @returns length of 'input' which was matched
|
|
*/
|
|
size_t apply(const std::u32string &input, std::u32string &output) const;
|
|
};
|
|
|
|
/** a single char, categorized according to reorder rules*/
|
|
struct reorder_sort_key {
|
|
km_core_usv ch; // the single char value
|
|
reorder_weight primary; // primary order value
|
|
reorder_weight secondary; // index position
|
|
reorder_weight tertiary; // tertiary value, defaults to 0
|
|
reorder_weight quaternary; // index again
|
|
bool is_tertiary_base; // remember that this key was a tertiary base
|
|
|
|
/** @returns -1, 0, 1 depending on ordering */
|
|
int compare(const reorder_sort_key &other) const;
|
|
bool operator<(const reorder_sort_key &other) const;
|
|
bool operator>(const reorder_sort_key &other) const;
|
|
|
|
/** create a 'baseline' sort key, with each character having primary weight 0 */
|
|
static std::deque<reorder_sort_key> from(const std::u32string &str);
|
|
|
|
/** TODO-LDML: for debugging. */
|
|
void dump() const;
|
|
};
|
|
|
|
/**
|
|
* List of elements.
|
|
*/
|
|
class element_list : public std::deque<element> {
|
|
public:
|
|
/** @returns 0 if no match, or number of chars at end matched */
|
|
size_t match_end(const std::u32string &str) const;
|
|
|
|
/**
|
|
* Update the deque (see reorder_sort_key::from()) with the weights from this element list
|
|
* starting at the beginning of this element list
|
|
* @param offset start at this offset in the deque. Still starts at the first element
|
|
* @param key key deque to update
|
|
* @returns the key parameter
|
|
*/
|
|
std::deque<reorder_sort_key> &update_sort_key(size_t offset, std::deque<reorder_sort_key> &key) const;
|
|
|
|
/** construct from KMX+ elem id*/
|
|
bool
|
|
load(const kmx::kmx_plus& kplus, kmx::KMXPLUS_ELEM id);
|
|
|
|
/** TODO-LDML: for debugging */
|
|
void dump() const;
|
|
};
|
|
|
|
class reorder_entry {
|
|
public:
|
|
/** construct an entry from elements */
|
|
reorder_entry(const element_list &elements);
|
|
/** construct an element from elements and before */
|
|
reorder_entry(const element_list &elements, const element_list &before);
|
|
/**
|
|
* Does it match?
|
|
* @param str string to match
|
|
* @param offset start matching at this offset
|
|
* @return 0 if no match otherwise length matched
|
|
*/
|
|
size_t match_end(std::u32string &str, size_t offset, size_t len) const;
|
|
|
|
/** @returns -1, 0, 1 depending on ordering */
|
|
int compare(const reorder_entry &other) const;
|
|
bool operator<(const reorder_entry &other) const;
|
|
bool operator>(const reorder_entry &other) const;
|
|
|
|
public:
|
|
element_list elements;
|
|
element_list before;
|
|
};
|
|
|
|
/** a list of entries, such as in a group */
|
|
typedef std::deque<reorder_entry> reorder_list;
|
|
|
|
/** subtype that's a list of reorders */
|
|
struct reorder_group {
|
|
public:
|
|
reorder_list list;
|
|
/** apply this reordering. Return true if changed. */
|
|
bool apply(std::u32string &str) const;
|
|
};
|
|
|
|
/** container for either a transform or a reorder group */
|
|
class any_group {
|
|
public:
|
|
any_group(const transform_group &g);
|
|
any_group(const reorder_group &g);
|
|
any_group_type type; // transform or reorder
|
|
transform_group transform;
|
|
reorder_group reorder;
|
|
size_t apply(std::u32string &input, std::u32string &output, size_t matched) const;
|
|
|
|
private:
|
|
size_t apply_transform(std::u32string &input, std::u32string &output, size_t matched) const;
|
|
size_t apply_reorder(std::u32string &input, std::u32string &output, size_t matched) const;
|
|
};
|
|
|
|
/**
|
|
* A list of any_groups
|
|
*/
|
|
typedef std::deque<any_group> group_list;
|
|
|
|
/**
|
|
* This represents an entire <transforms> element
|
|
*/
|
|
class transforms {
|
|
private:
|
|
group_list transform_groups;
|
|
bool normalization_disabled;
|
|
public:
|
|
transforms(bool normalization_disabled);
|
|
|
|
/**
|
|
* Add a transform group
|
|
*/
|
|
void addGroup(const transform_group &s);
|
|
/**
|
|
* Add a reorder group
|
|
*/
|
|
void addGroup(const reorder_group &s);
|
|
|
|
/**
|
|
* Attempt to match and apply a pattern change.
|
|
*
|
|
* @param input original input text. Will not be altered.
|
|
* @param output if matched, contains the replacement output text
|
|
* @return length in chars of the input (counting from the end) which matched context
|
|
*/
|
|
size_t apply(const std::u32string &input, std::u32string &output);
|
|
|
|
/**
|
|
* For tests
|
|
* @return true if str was altered
|
|
*/
|
|
bool apply(std::u32string &str);
|
|
|
|
public:
|
|
/** load from a kmx_plus data section, either tran or bksp */
|
|
static transforms *
|
|
load(const kmx::kmx_plus &kplus,
|
|
const core::kmx::COMP_KMXPLUS_TRAN *tran,
|
|
const core::kmx::COMP_KMXPLUS_TRAN_Helper &tranHelper);
|
|
};
|
|
|
|
|
|
} // namespace ldml
|
|
} // namespace core
|
|
} // namespace km
|