Files
MagicSetEditor2/src/data/keyword.hpp
T
GenevensiS 436c437189 add compiler directives
add compiler directives
2025-12-30 01:18:04 +01:00

214 lines
9.3 KiB
C++

//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#pragma once
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <script/scriptable.hpp>
#include <util/dynamic_arg.hpp>
#include <util/regex.hpp>
#include <data/filter.hpp>
DECLARE_POINTER_TYPE(KeywordParam);
DECLARE_POINTER_TYPE(KeywordMode);
DECLARE_POINTER_TYPE(Keyword);
DECLARE_POINTER_TYPE(ParamReferenceType);
class KeywordTrie;
class Value;
// ----------------------------------------------------------------------------- : Keyword parameters
class ParamReferenceType : public IntrusivePtrBase<ParamReferenceType> {
public:
String name; ///< Name of the parameter reference type
String description; ///< Description (for status bar)
StringScript script; ///< Code to insert into the reminder text script, input is the actual parameter name
DECLARE_REFLECTION();
};
/// Parameter type of keywords
class KeywordParam : public IntrusivePtrBase<KeywordParam> {
public:
KeywordParam();
String name; ///< Name of the parameter type
String description; ///< Description of the parameter type
String placeholder; ///< Placholder for <atom-kwpph>, name is used if this is empty
bool optional; ///< Can this parameter be left out (a placeholder is then used)
String match; ///< Regular expression to match (including separators)
String separator_before_is; ///< Regular expression of separator before the param
Regex separator_before_re; ///< Regular expression of separator before the param, compiled
Regex separator_before_eat;///< Regular expression of separator before the param, if eat_separator
String separator_after_is; ///< Regular expression of separator after the param
Regex separator_after_re; ///< Regular expression of separator after the param, compiled
Regex separator_after_eat; ///< Regular expression of separator after the param, if eat_separator
bool eat_separator; ///< Remove the separator from the match string if it also appears there (prevent duplicates)
OptionalScript script; ///< Transformation of the value for showing as the parameter
OptionalScript reminder_script; ///< Transformation of the value for showing in the reminder text
OptionalScript separator_script; ///< Transformation of the separator
String example; ///< Example for the keyword editor
vector<ParamReferenceTypeP> refer_scripts;///< Way to refer to a parameter from the reminder text script
//% /// Make a string that can function as a separator before the parameter
//% /** This tries to decode the separator_before_is regex */
//% String make_separator_before() const;
/// Compile regexes for separators
void compile();
/// Remove separator_before from the end of the text
void eat_separator_before(String& text);
/// Advance i past separator_before if it is at position i in the text
void eat_separator_after(const String& text, size_t& i);
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : Keyword mode
/// Information on when and how to use a keyword
class KeywordMode : public IntrusivePtrBase<KeywordMode> {
public:
KeywordMode() : is_default(false) {}
String name; ///< Name of the mode
String description; ///< Description of the type
bool is_default; ///< This is the default mode for new keywords
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : Keyword expansion
/// A keyword for a set or a game
class Keyword : public IntrusivePtrVirtualBase {
public:
Keyword() : fixed(false), valid(false) {}
String keyword; ///< The keyword, only for human use
String rules; ///< Rules/explanation
String match; ///< String to match, <atom-param> tags are used for parameters
vector<KeywordParamP> parameters; ///< The types of parameters
StringScript reminder; ///< Reminder text of the keyword
String mode; ///< Mode of use, can be used by scripts (only gives the name)
/// Regular expression to match and split parameters, automatically generated.
/** The regex has exactly 2 * parameters.size() + 1 captures (excluding the entire match, caputure 0),
* captures 1,3,... capture the plain text of the match string
* captures 2,4,... capture the separators and parameters
*/
Regex match_re;
bool fixed; ///< Is this keyword uneditable? (true for game keywods, false for set keywords)
bool valid; ///< Is this keyword okay (reminder text compiles & runs; match does not match "")
/// Find the index of the mode in a list of possibilities.
/** Returns the default if not found and 0 if there is no default */
size_t findMode(const vector<KeywordModeP>& modes) const;
/// Prepare the expansion: (re)generate matchRe and the list of parameters.
/** Throws when there is an error in the input
* @param param_types A list of all parameter types.
* @param force Re-prepare even if the regex&parameters are okay
*/
void prepare(const vector<KeywordParamP>& param_types, bool force = false);
/// Does the keyword contain the given query word?
bool contains(QuickFilterPart const& query) const;
DECLARE_REFLECTION();
};
inline String type_name(const Keyword&) {
return _TYPE_("keyword");
}
inline String type_name(const vector<KeywordP>&) {
return _TYPE_("keywords"); // not actually used, only for locale.pl script
}
// ----------------------------------------------------------------------------- : Using keywords
/// Store keyword usage statistics here, using value_being_updated as the key
typedef vector<pair<const Value*, const Keyword*>> KeywordUsageStatistics;
struct KeywordExpandOptions {
ScriptValueP match_condition;
ScriptValueP expand_default;
ScriptValueP combine_script;
Context& ctx;
KeywordUsageStatistics* stat;
const Value* stat_key;
};
/// A database of keywords to allow for fast matching
/** NOTE: keywords may not be altered after they are added to the database,
* The database should be rebuild.
*/
class KeywordDatabase {
public:
KeywordDatabase();
~KeywordDatabase();
/// Add a list of keywords to be matched
void add(const vector<KeywordP>&);
/// Add a keyword to be matched
void add(const Keyword&);
/// Prepare the parameters and match regex for a list of keywords
static void prepare_parameters(const vector<KeywordParamP>&, const vector<KeywordP>&);
/// Clear the database
void clear();
/// Is the database empty?
inline bool empty() const { return !root; }
/// Expand/update all keywords in the given string.
/** @param options.expand_default script function indicating whether reminder text should be shown by default
* @param options.combine_script script function to combine keyword and reminder text in some way
* @param options.case_sensitive case sensitive matching of keywords?
* @param options.ctx context for evaluation of scripts
* @param options.stats where to put keyword statistics
*/
String expand(const String& text, const KeywordExpandOptions&) const;
private:
unique_ptr<KeywordTrie> root; ///< Data structure for finding keywords
/// (try to) expand a single keyword
/** If the keyword matches:
* - add the result to out
* - advance the tagged and untagged string by dropping a part from the front
* - return true
*/
bool tryExpand(const Keyword& kw, size_t pos, String& tagged, String& untagged, String& out, char expand_type,
const ScriptValueP& match_condition, const ScriptValueP& expand_default, const ScriptValueP& combine_script, Context& ctx,
KeywordUsageStatistics* stat, Value* stat_key) const;
};
// ----------------------------------------------------------------------------- : Processing parameters
/// A script value containing the value of a keyword parameter
class KeywordParamValue : public ScriptValue {
public:
KeywordParamValue(const String& type, const String& separator_before, const String& separator_after, const String& value)
: type_name(type), separator_before(separator_before), separator_after(separator_after), value(value)
{}
String type_name;
String separator_before, separator_after;
String value;
ScriptType type() const override;
String typeName() const override;
String toString() const override;
int toInt() const override;
bool toBool() const override;
double toDouble() const override;
Color toColor() const override;
int itemCount() const override;
ScriptValueP getMember(const String& name) const override;
};