Commit 0c3250cf authored by twanvl's avatar twanvl

Now all regex functions use ScriptRule.

The *_rule functions can now be considered deprecated
Documented this by removing mentions of the rule functions, except for a mention of backwards compatibility.
parent 7346a364
......@@ -2,20 +2,21 @@ Function: break_text
--Usage--
> break_text(some_string, match: regular expression, in_context: regular expression)
> break_rule(match: ..., in_context: ...)(some_string)
Break text by only keeping the parts of the input that match the regular expression.
The function returns a [[type:list]] of parts.
If @in_context@ is given, the context must also match the string where the match is represented as <tt>&lt;match></tt>.
This function is available in [[script:rule form]].
When the @break_text@ is used many times the rule form is more efficient, because the regular expression is only compiled once.
When the @break_text@ is used many times with the same @match@ or @in_context@ values it is more efficient to declare these as default arguments:
> my_break := break_text@(match: "something")
> my_break("input") # called many times
This way the regular expression is only compiled once.
--Filter vs. break--
The function @filter_text@ is very similar to @break_text@, instead of returning a list it concatenates the items.
So for example where @break_text@ would return @["a","b","c"]@, @filter_text@ would return @"abc"@.
So for example where @break_text@ returns @["a","b","c"]@, @filter_text@ would return @"abc"@.
In fact, @filter_text@ could be implemented as
> filter_text := { for part in break_text() do part }
......@@ -32,10 +33,9 @@ In fact, @filter_text@ could be implemented as
> break_text(match: "/", "a/b/c") == ["/","/"]
> break_text(match: "[^/]+", "a/b/c") == ["a","b","c"]
>
> f := break_rule(match: "xx+")
> f := break_text@(match: "xx+")
> f("xyzxxxxyyzz") == ["xxxx"]
--See also--
| [[fun:filter_text|filter_text / filter_rule]]
Keep only the text matching a regular expression.
| [[fun:filter_text]] Keep only the text matching a regular expression.
......@@ -15,5 +15,5 @@ Does one string contain another at any position?
> contains("abcdefg", match:"abd") == false
--See also--
| [[fun:match|match / match_rule]] Does a string match a regular expression?
| [[fun:match]] Does a string match a regular expression?
| [[fun:chosen]] Is the given choice selected in a multiple choice value?
......@@ -2,7 +2,6 @@ Function: expand_keywords
--Usage--
> expand_keywords(some_tagged_string, default_expand: {...}, combine: {...})
> expand_keywords_rule(default_expand: {...}, combine: {...})(some_tagged_string)
Find [[type:keyword]]s and generate their reminder text.
......@@ -28,8 +27,6 @@ For example, in the case of magic:
> )
is used. This shows reminder text by default based on a [[type:set]] option, and it combined the keyword as @"keyword (reminder)"@.
This function is available in [[script:rule form]].
--Parameters--
! Parameter Type Description
| @input@ [[type:tagged string]] String to expand keywords in.
......@@ -41,5 +38,5 @@ Assuming a keyword @"mse"@ exists with reminder text @"Magic Set Editor"@ exists
> expand_keywords(default_expand: {true}, combine: { keyword + " = " + reminder }, "mse is cool")
> == "<kw-A>mse = Magic Set Editor is cool</kw-A>"
>
> f := expand_keywords_rule(default_expand: {true}, combine: { keyword+"="+reminder })
> f := expand_keywords@(default_expand: {true}, combine: { keyword+"="+reminder })
> f("mse is cool") == "<kw-A>mse = Magic Set Editor is cool</kw-A>"
......@@ -2,14 +2,15 @@ Function: filter_text
--Usage--
> filter_text(some_string, match: regular expression, in_context: regular expression)
> filter_rule(match: ..., in_context: ...)(some_string)
Filter text by only keeping the parts of the input that match the regular expression.
If @in_context@ is given, the context must also match the string where the match is represented as <tt>&lt;match></tt>.
This function is available in [[script:rule form]].
When the @filter_text@ is used many times the rule form is more efficient, because the regular expression is only compiled once.
When the @filter_text@ is used many times with the same @match@ or @in_context@ values it is more efficient to declare these as default arguments:
> my_filter := filter_text@(match: "something")
> my_filter("input") # called many times
This way the regular expression is only compiled once.
--Parameters--
! Parameter Type Description
......@@ -22,11 +23,9 @@ When the @filter_text@ is used many times the rule form is more efficient, becau
> filter_text(match: ".", in_context:"a<match>", "banana") == "nn"
> filter_text(match: "[xy]", "xyz") == "xy"
>
> f := filter_rule(match: "xx+")
> f := filter_text@(match: "xx+")
> f("xyzxxyyzz") == "xx"
--See also--
| [[fun:break_text|break_text / break_rule]]
Break text into parts each matching a regular expression.
| [[fun:replace|replace / replace_rule]]
Replace text matching a regular expression.
| [[fun:break_text]] Break text into parts each matching a regular expression.
| [[fun:replace]] Replace text matching a regular expression.
......@@ -2,12 +2,9 @@ Function: format
--Usage--
> format(some_number, format: format_specification)
> format_rule(format: format_specification)(some_number)
Format a number or other string as a string, [[http://www.cplusplus.com/reference/clibrary/cstdio/printf.html|printf]] style.
This function is available in [[script:rule form]].
--Parameters--
! Parameter Type Description
| @input@ [[type:int]] or [[type:double]] or [[type:string]]
......@@ -19,5 +16,5 @@ This function is available in [[script:rule form]].
> format(format: "%03d", 13) == "013"
> format(format: "%3s", "xy") == " xy"
>
> f := format_rule(format: "%03d")
> f := format@(format: "%03d")
> f(1) == "001"
......@@ -9,27 +9,19 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:reverse]] Reverse a string, @"aBc" -> "cBa"@.
| [[fun:trim]] Remove leading and trailing whitespace from a string, @" abc " -> "abc"@.
| [[fun:substring]] Extract a part of a string.
| [[fun:format|format / format_rule]]
Format a number as a string (printf).
| [[fun:format]] Format a number as a string (printf).
| [[fun:curly_quotes]] Make quotes curly.
| [[fun:replace|replace / replace_rule]]
Replace text matching a regular expression.
| [[fun:filter_text|filter_text / filter_rule]]
Keep only the text matching a regular expression.
| [[fun:break_text|break_text / break_rule]]
Break text into parts each matching a regular expression.
| [[fun:sort_text|sort_text / sort_rule]]
Sort the letters in a string using a custom order.
| [[fun:replace]] Replace text matching a regular expression.
| [[fun:filter_text]] Keep only the text matching a regular expression.
| [[fun:break_text]] Break text into parts each matching a regular expression.
| [[fun:sort_text]] Sort the letters in a string using a custom order.
| [[fun:contains]] Does a string contain another one?
| [[fun:match|match / match_rule]]
Does a string match a regular expression?
| [[fun:match]] Does a string match a regular expression?
| [[fun:regex_escape]] Escape a string for use in a regular expression.
! [[type:tagged_string|Tags]] <<<
| [[fun:tag_contents|tag_contents / tag_contents_rule]]
Change the contents of a specific tag.
| [[fun:remove_tag|remove_tag / tag_remove_rule]]
Remove a tag, keep the contents.
| [[fun:tag_contents]] Change the contents of a specific tag.
| [[fun:remove_tag]] Remove a tag, keep the contents.
| [[fun:remove_tags]] Remove all tags from tagged text.
! [[type:list|Lists]] <<<
......@@ -40,8 +32,7 @@ These functions are built into the program, other [[type:function]]s can be defi
| [[fun:filter_list]] Filter a list, keeping only elements that match a predicate.
! Keywords <<<
| [[fun:expand_keywords|expand_keywords / expand_keywords_rule]]
Expand the keywords in a piece of text.
| [[fun:expand_keywords]] Expand the keywords in a piece of text.
| [[fun:keyword_usage]] What keywords are used on a card, and how often are they used?
! English language <<<
......
......@@ -2,12 +2,13 @@ Function: match
--Usage--
> match(some_string, match: regular expression)
> match_rule(match:regular expression)(some_string)
Does a string match the given [[type:regex|regular expression]]?
This function is available in [[script:rule form]].
When the match is performed many times the rule form is more efficient, because the regular expression is only compiled once.
When the match is performed many times with the same regular expression it is more efficient to declare that as a default argument:
> my_match := match@(match: "something")
> my_match("input") # called many times
This way the regular expression is only compiled once.
--Parameters--
! Parameter Type Description
......@@ -20,7 +21,7 @@ When the match is performed many times the rule form is more efficient, because
> match("abc", match:"b+") == true
> match("abc", match:"$b+^") == false
>
> f := match_rule(match: "a+|b+")
> f := match@(match: "a+|b+")
> f("xyz") == false
> f("aabb") == true
......
......@@ -2,14 +2,11 @@ Function: remove_tag
--Usage--
> remove_tag(tag: some_tag, some_string)
> tag_remove_rule(tag: some_tag)(some_string)
Remove a tag and its matching close tag from a [[type:tagged string]], but keep the contents.
The tag can be a whole tag, @"<tag>"@, or a prefix @"<i"@. In the latter case all tags starting with @"<i"@ are removed.
This function is available in [[script:rule form]].
--Parameters--
! Parameter Type Description
| @tag@ [[type:string]] Tag to remove
......@@ -19,10 +16,10 @@ This function is available in [[script:rule form]].
> remove_tag(tag: "<b>", "<b>bold <i>text</i></b>") == "bold <i>text</i>"
> remove_tag(tag: "<b", "<b-auto>bold</b-auto> text") == "bold text"
>
> f := tag_remove_rule(tag: "<i-auto>")
> f := remove_tag@(tag: "<i-auto>")
> f("text, <i-auto>reminder</i-auto> <i>italic</i>") == "text, reminder <i>italic</i>"
--See also--
| [[fun:tag_contents|tag_contents / tag_contents_rule]]
Change the contents of a specific tag.
| [[fun:to_text]] Remove all tags from tagged text.
| [[fun:tag_contents]] Change the contents of a specific tag.
| [[fun:remove_tags]] Remove all tags from tagged text.
| [[fun:to_text]] Remove all tags from tagged text, and convert it to a [[type:string]].
......@@ -17,5 +17,4 @@ This function differs from [[fun:to_text]], that function also un-escapes &lt; c
--See also--
| [[fun:to_text]] Remove all tags from tagged text, and convert it to a [[type:string]].
| [[fun:remove_tag|remove_tag / tag_remove_rule]]
Remove a single tag type.
| [[fun:remove_tag]] Remove a single tag type.
......@@ -2,7 +2,6 @@ Function: replace
--Usage--
> replace(some_string, match: regular expression, replace: replacement, in_context: regular expression)
> replace_rule(match: ..., replace: ..., in_context: ...)(some_string)
Replace all matches of a regular expression with a replacement value.
The replacement can either be a string or a function.
......@@ -11,8 +10,10 @@ The replacement can either be a string or a function.
Optionally a context can be given. The replacement is only performed if the string where the match is represented as <tt>&lt;match></tt> also matches the context.
This function is available in [[script:rule form]].
When the replacement is performed many times the rule form is more efficient, because the regular expression is only compiled once.
When the @replace@ is used many times with the same @match@ or @in_context@ values it is more efficient to declare these as default arguments:
> my_replace := replace@(match: "something", replace: "something else")
> my_replace("input") # called many times
This way the regular expression is compiled only once.
--Parameters--
! Parameter Type Description
......@@ -26,11 +27,11 @@ When the replacement is performed many times the rule form is more efficient, be
> replace(match: "a", replace: "e", "banana") == "benene"
> replace(match: "a", replace: "e", in_context: "<match>n", "banana") == "benena"
> replace(match: "(a|b)x", replace: "[\\0,\\1]", "axabxc") == "[ax,a]a[bx,b]c"
> replace(match: "[ab]", replace: { to_upper(input) }, "banana") == "BAnAnA"
> replace(match: "[ab]", replace: to_upper, "banana") == "BAnAnA"
> replace(match: "([0-9])[*]([0-9])", replace: { _1 * _2 }, "2*2+3*3") == "4+9"
>
> f := replace_rule(match: "xx+", replace: "A")
> f := replace@(match: "xx+", replace: "A")
> f("xyzxxyyzz") == "xyzAAyyzz"
--See also--
| [[fun:filter_text|filter_text / filter_rule]]
Keep only the text matching a regular expression.
| [[fun:filter_text]] Keep only the text matching a regular expression.
......@@ -2,7 +2,6 @@ Function: sort_text
--Usage--
> sort_text(order: order specification, some_text)
> sort_rule(order: order specification)(some_text)
Sort a string or filter it by keeping specific characters.
......@@ -45,8 +44,6 @@ behaves the same as
> sort_text(order: "x")
because the first @"x"@ already selects all xs from the input.
This function is available in [[script:rule form]].
--Parameters--
! Parameter Type Description
| @input@ [[type:string]] Text to sort
......@@ -67,5 +64,5 @@ This function is available in [[script:rule form]].
> sort_text(order: "pattern(./. cycle(wubrg))", "wgw/g") == "g/w"
> sort_text(order: "[1234567890]cycle(wubrg)", "21wg") == "21gw"
>
> f := sort_rule(order: "[1234567890]cycle(wubrg)")
> f := sort_text@(order: "[1234567890]cycle(wubrg)")
> f("21wg") == "21gw"
......@@ -2,15 +2,12 @@ Function: tag_contents
--Usage--
> tag_contents(tag: some_tag, contents: some_function, some_string)
> tag_contents_rule(tag: some_tag, contents: some_function)(some_string)
Apply a function to the contents of a particular tag.
The function is called with @input@ set to the old value inside the tag.
The tag can be a whole tag, @"<tag>"@, or a prefix @"<i"@. In the latter case all tags starting with @"<i"@ are removed.
This function is available in [[script:rule form]].
--Parameters--
! Parameter Type Description
| @tag@ [[type:string]] Tag to match
......@@ -23,9 +20,8 @@ This function is available in [[script:rule form]].
> tag_contents(tag: "<atom-name", contents: { card.name }, "<atom-name-auto></atom-name-auto> loses 1 life")
> == "<atom-name-auto>Pink Elephant</atom-name-auto> loses 1 life"
>
> f := tag_contents_rule(tag: "<i>", contents: {""})
> f := tag_contents@(tag: "<i>", contents: {""})
> f("text, <i-auto>reminder</i-auto> <i>italic</i>") == "text, <i-auto>reminder</i-auto> <i></i>"
--See also--
| [[fun:remove_tag|remove_tag / tag_remove_rule]]
Remove a tag, keep the contents.
| [[fun:remove_tag]] Remove a tag, keep the contents.
......@@ -23,12 +23,15 @@ Instead define a function in the init script.
>field:
> script: flubble_script()
--Use rule form--
If a function is available in [[script:rule form]] use it where possible.
--Use default arguments--
Many rules can be chained together using the @+@ operator.
Many functions can be chained together using the @+@ operator.
For these functions [[script:default arguments]] can be given.
Have a look at @text_filter@ in the magic game file for an example.
Using default arguments is especially important for functions that work on [[type:regex|regular expressions]],
since it allows MSE to compile the regular expressions just once instead of for every call.
--Don't be afraid to nest--
Don't be afraid to nest complex things like @if@ expressions inside other expressions.
For example the blend scripts for magic use:
......
......@@ -11,21 +11,24 @@ For determining whether the argument is set only explicit arguments count, not e
> arg := "something else"
> function() == "argument was: default"
//Defaults are evaluated at the time the @@@@ operator is evaluated, so they can be used to simulate static scoping.
Defaults are evaluated at the time the @@@@ operator is evaluated, they will not be overriden later
> default := "old default"
> function := { "argument was: " + arg }@(arg: default)
> default := "new default"
> function() == "argument was: old default"
--Rule functions--
Some functions are available in ''rule form''.
These rule form functions are functions that create a new [[type:function]] with some defaults filled in.
That new function, the rule, applies some transformation to the input and returns the result.
In earlier versions of MSE some functions were available in a special ''rule form''.
A call to for example @replace_rule(match:"abc",replace:"xyz")@ is equivalent to @replace@@(match:"abc",replace:"xyz")@ .
For backwards compatability these functions are still available, but they should not be used for new templates.
Programming in a ''rule style'' is still very useful.
A rule is like a normal function with all parameters given, except for the @input@.
Rules are often combined using the + operator, for example:
These rules can then be combined using the @+@ operator, for example:
> # First all "a"s are replaced, then all "b"s.
> remove_as_and_bs := replace_rule(match: "a", replace: "") +
> replace_rule(match: "b", replace: "")
> remove_as_and_bs := replace@(match: "a", replace: "") +
> replace@(match: "b", replace: "")
>
> text_with_as_and_bs := "bla bla bla"
> text_without_as_and_bs := remove_as_and_bs(text_with_as_and_bs)
......
......@@ -5,9 +5,9 @@ MSE uses a custom scripting language to add complicated behaviour to [[type:fiel
--Topics--
* [[script:introduction|Introduction to scripting]]
* [[script:Operators]]
* [[script:variables|Variables]]
* [[script:functions|Functions]]
* [[script:default_arguments|Default arguments]]
* [[script:Variables]]
* [[script:Functions]]
* [[script:Default arguments]]
* [[script:Control structures]]
* [[script:Predefined variables]]
* [[script:Best practices]]
......
Rule form
Some functions are available in ''rule form''.
These rule form functions are functions that create a new [[type:function]].
That new function, the rule, applies some transformation to the input and returns the result.
A rule is like a normal function with all parameters given, except for the @input@.
Rules are often combined using the + operator, for example:
> # First all "a"s are replaced, then all "b"s.
> remove_as_and_bs := replace_rule(match: "a", replace: "") +
> replace_rule(match: "b", replace: "")
>
> text_with_as_and_bs := "bla bla bla"
> text_without_as_and_bs := remove_as_and_bs(text_with_as_and_bs)
......@@ -13,7 +13,7 @@ Functions can be composed using the @+@ operator, evaluating @a + b@ first evalu
> example := to_upper + { "result == {input}" }
> example("xyz") == "result == XYZ"
Multiple functions can be changed together like this, especially using [[script:rule form]].
Multiple functions can be changed together like this, this is especially convenient in combination with [[script:default arguments]].
--Example--
> example := { a + b }
......
......@@ -48,7 +48,7 @@ This is written as the character with code 1 in files.
--Related functions--
The following script functions deal with tags:
| [[fun:tag_contents|tag_contents / tag_contents_rule]]
Change the contents of a specific tag.
| [[fun:remove_tag|remove_tag / tag_remove_rule]]
Remove a tag, keep the contents.
| [[fun:tag_contents]] Change the contents of a specific tag.
| [[fun:remove_tag]] Remove a tag, keep the contents.
| [[fun:remove_tags]] Remove all tags from tagged text.
| [[fun:to_text]] Remove all tags from tagged text, and convert it to a [[type:string]].
......@@ -30,6 +30,7 @@ ScriptRegexP regex_from_script(const ScriptValueP& value) {
// is it a regex already?
ScriptRegexP regex = dynamic_pointer_cast<ScriptRegex>(value);
if (!regex) {
// TODO: introduce some kind of caching?
// compile string
regex = new_intrusive<ScriptRegex>();
if (!regex->regex.Compile(*value, wxRE_ADVANCED)) {
......@@ -225,6 +226,7 @@ SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(replace) {
// ----------------------------------------------------------------------------- : Rules : regex filter
/*
class ScriptFilterRule : public ScriptValue {
public:
virtual ScriptType type() const { return SCRIPT_FUNCTION; }
......@@ -259,7 +261,7 @@ ScriptValueP filter_rule(Context& ctx) {
SCRIPT_PARAM_DEFAULT_C(String, in_context, String());
// cache
//*
// *
const int CACHE_SIZE = 6;
struct CacheItem{
String match, in_context;
......@@ -279,9 +281,9 @@ ScriptValueP filter_rule(Context& ctx) {
cache[cache_pos].rule = intrusive_ptr<ScriptFilterRule>(new ScriptFilterRule);
intrusive_ptr<ScriptFilterRule>& ret = cache[cache_pos].rule;
cache_pos = (cache_pos+1) % CACHE_SIZE;
/*/
/ * /
intrusive_ptr<ScriptFilterRule> ret(new ScriptFilterRule);
//*/
//* /
// match
if (!ret->regex.Compile(match, wxRE_ADVANCED)) {
......@@ -301,6 +303,36 @@ SCRIPT_FUNCTION(filter_rule) {
}
SCRIPT_FUNCTION(filter_text) {
return filter_rule(ctx)->eval(ctx);
}*/
SCRIPT_FUNCTION_WITH_SIMPLIFY(filter_text) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_C(ScriptRegexP, match);
SCRIPT_OPTIONAL_PARAM_C_(ScriptRegexP, in_context);
String ret;
// find all matches
while (match->regex.Matches(input)) {
// match, append to result
size_t start, len;
bool ok = match->regex.GetMatch(&start, &len, 0);
assert(ok);
String inside = input.substr(start, len); // the match
String next_input = input.substr(start + len); // everything after the match
if (!in_context || in_context->regex.Matches(input.substr(0,start) + _("<match>") + next_input)) {
// no context or context match
ret += inside;
}
input = next_input;
}
SCRIPT_RETURN(ret);
}
SCRIPT_FUNCTION_SIMPLIFY_CLOSURE(filter_text) {
FOR_EACH(b, closure.bindings) {
if (b.first == SCRIPT_VAR_match || b.first == SCRIPT_VAR_in_context) {
b.second = regex_from_script(b.second); // pre-compile
}
}
return ScriptValueP();
}
// ----------------------------------------------------------------------------- : Rules : regex break
......@@ -452,7 +484,7 @@ void init_script_regex_functions(Context& ctx) {
ctx.setVariable(_("break text"), script_break_text);
ctx.setVariable(_("match"), script_match);
ctx.setVariable(_("replace rule"), new_intrusive1<ScriptRule>(script_replace));
ctx.setVariable(_("filter rule"), script_filter_rule);
ctx.setVariable(_("filter rule"), new_intrusive1<ScriptRule>(script_filter_text));
ctx.setVariable(_("break rule"), new_intrusive1<ScriptRule>(script_break_text));
ctx.setVariable(_("match rule"), new_intrusive1<ScriptRule>(script_match));
}
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