Commit 986a6a2c authored by twanvl's avatar twanvl

Added support for separators that are part of a parameter;

Keywords match whole words only;
Added english_singular/plural functions;
Fixed possible infinite loop in reader
parent ca2737ca
This diff is collapsed.
This diff is collapsed.
......@@ -34,15 +34,28 @@ class ParamReferenceType : public IntrusivePtrBase<ParamReferenceType> {
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
OptionalScript script; ///< Transformation of the value for showing in the reminder text
String example; ///< Example for the keyword editor
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
wxRegEx separator_before_re; ///< Regular expression of separator before the param, compiled
wxRegEx separator_before_eat;///< Regular expression of separator before 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
void compile();
DECLARE_REFLECTION();
};
......@@ -76,9 +89,9 @@ class Keyword : public IntrusivePtrVirtualBase {
/// 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 parameters
* captures 2,4,... capture the separators and parameters
*/
wxRegEx matchRe;
wxRegEx 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 "")
......@@ -132,5 +145,23 @@ class KeywordDatabase {
KeywordTrie* root; ///< Data structure for finding keywords
};
// ----------------------------------------------------------------------------- : Processing parameters
/// A script value containing the value of a keyword parameter
class KeywordParamValue : public ScriptValue {
public:
KeywordParamValue(const String& type, const String& separator, const String& value)
: type_name(type), separator(separator), value(value)
{}
String type_name;
String separator;
String value;
virtual ScriptType type() const;
virtual String typeName() const;
virtual operator String() const;
virtual ScriptValueP getMember(const String& name) const;
};
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -70,7 +70,7 @@ String do_english_num(String input, String(*fun)(int)) {
// a keyword parameter, of the form "<param->123</param->"
size_t start = skip_tag(input, 0);
if (start != String::npos) {
size_t end = input.find_first_of(_('<'), start);
size_t end = input.find_first_of(_('<'), start);
if (end != String::npos) {
String is = input.substr(start, end - start);
long i = 0;
......@@ -105,6 +105,54 @@ SCRIPT_FUNCTION(english_number_multiple) {
SCRIPT_RETURN(do_english_num(input, english_number_multiple));
}
// ----------------------------------------------------------------------------- : Singular/plural
String english_singular(const String& str) {
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
return str.substr(0, str.size() - 3) + _("y");
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
return str.substr(0, str.size() - 1);
} else {
return str;
}
}
String english_plural(const String& str) {
if (str.size() > 1 && str.GetChar(str.size() - 1) == _('y')) {
return str.substr(0, str.size() - 1) + _("ies");
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
return str + _("es");
} else {
return str + _("s");
}
}
// script_english_singular/plural/singplur
String do_english(String input, String(*fun)(const String&)) {
if (is_substr(input, 0, _("<param-"))) {
// a keyword parameter, of the form "<param->123</param->"
size_t start = skip_tag(input, 0);
if (start != String::npos) {
size_t end = input.find_first_of(_('<'), start);
if (end != String::npos) {
String is = input.substr(start, end - start);
return substr_replace(input, start, end, fun(is));
}
}
return input; // failed
} else {
return fun(input);
}
}
SCRIPT_FUNCTION(english_singular) {
SCRIPT_PARAM(String, input);
SCRIPT_RETURN(do_english(input, english_singular));
}
SCRIPT_FUNCTION(english_plural) {
SCRIPT_PARAM(String, input);
SCRIPT_RETURN(do_english(input, english_plural));
}
// ----------------------------------------------------------------------------- : Hints
bool is_vowel(Char c) {
......@@ -160,6 +208,24 @@ String process_english_hints(const String& str) {
}
ret += c;
++i;
} else if (is_substr(str, i, _("<singular>"))) {
// singular -> keep, plural -> drop
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, start);
if (singplur == 1 && end != String::npos) {
ret += str.substr(start, end - start);
}
singplur = 0;
i = skip_tag(str, end);
} else if (is_substr(str, i, _("<plural>"))) {
// singular -> drop, plural -> keep
size_t start = skip_tag(str, i);
size_t end = match_close_tag(str, start);
if (singplur == 2 && end != String::npos) {
ret += str.substr(start, end - start);
}
singplur = 0;
i = skip_tag(str, end);
} else if (c == _('(') && singplur) {
// singular -> drop (...), plural -> keep it
size_t end = str.find_first_of(_(')'), i);
......@@ -192,5 +258,7 @@ void init_script_english_functions(Context& ctx) {
ctx.setVariable(_("english number"), script_english_number);
ctx.setVariable(_("english number a"), script_english_number_a);
ctx.setVariable(_("english number multiple"), script_english_number_multiple);
ctx.setVariable(_("english singular"), script_english_singular);
ctx.setVariable(_("english plural"), script_english_plural);
ctx.setVariable(_("process english hints"), script_process_english_hints);
}
......@@ -132,6 +132,7 @@ void Reader::readLine(bool in_string) {
}
key = cannocial_name_form(trim(key));
value = pos == String::npos ? _("") : trim_left(line.substr(pos+1));
if (key.empty() && pos!=String::npos) key = _(" "); // we don't want an empty key if there was a colon
}
void Reader::unknownKey() {
......@@ -162,7 +163,7 @@ void Reader::unknownKey() {
return;
}
}
if (indent == expected_indent) {
if (indent >= expected_indent) {
warning(_("Unexpected key: '") + key + _("'"));
do {
moveNext();
......
......@@ -386,11 +386,6 @@ String remove_tag_contents(const String& str, const String& tag) {
// ----------------------------------------------------------------------------- : Updates
/// Return all open or close tags in the given range from a string
/** for example:
* if close_tags == false, "text<tag>text</tag>text" --> "<tag>"
* if close_tags == true, "text<tag>text</tag>text" --> "</tag>"
*/
String get_tags(const String& str, size_t start, size_t end, bool open_tags, bool close_tags) {
String ret;
bool intag = false;
......
......@@ -143,6 +143,13 @@ String remove_tag_contents(const String& str, const String& tag);
// ----------------------------------------------------------------------------- : Updates
/// Return all open or close tags in the given range from a string
/** for example:
* if close_tags == false, "text<tag>text</tag>text" --> "<tag>"
* if close_tags == true, "text<tag>text</tag>text" --> "</tag>"
*/
String get_tags(const String& str, size_t start, size_t end, bool open_tags, bool close_tags);
/// Replace a subsection of 'input' with 'replacement'.
/** The section to replace is indicated by [start...end).
* This function makes sure tags still match. It also attempts to cancel out tags.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment