Commit 7afe1ee1 authored by twanvl's avatar twanvl

Be more strict about type conversion:

  * numbers are no longer auto converted to booleans, use to_boolean or != 0
  * booleans are no longer auto converted to numbers, use to_int
  * strings will soon no longer be auto converted to numbers, use to_int

Added version information ("since 0.3.7") to documentation
parent 18bbf484
...@@ -157,7 +157,7 @@ init script: ...@@ -157,7 +157,7 @@ init script:
# Number of colors in a card_color # Number of colors in a card_color
card_color_color_count := { card_color_color_count := {
chosen(choice:"white") + chosen(choice:"blue") + chosen(choice:"black") + chosen(choice:"red") + chosen(choice:"green") + chosen(choice:"artifact") for each choice in ["white","blue","black","red","green","artifact"] do to_int(chosen())
} }
# Clean up color field # Clean up color field
card_color_filter := { card_color_filter := {
...@@ -1883,7 +1883,18 @@ pack type: ...@@ -1883,7 +1883,18 @@ pack type:
name: Common name: Common
amount: 11 amount: 11
filter: card.rarity == "common" filter: card.rarity == "common"
pack type:
name: Additional rare
card type:
name: Rare
amount: 1
filter: card.rarity == "rare"
pack type:
name: Additional common
card type:
name: Rare
amount: 1
filter: card.rarity == "rare"
......
Function: assert Function: assert
DOC_MSE_VERSION: since 0.3.7
--Usage-- --Usage--
> assert(condition) > assert(condition)
...@@ -12,5 +14,5 @@ Note: @assert@ is a special built-in keyword, so that the error message can incl ...@@ -12,5 +14,5 @@ Note: @assert@ is a special built-in keyword, so that the error message can incl
| @input@ [[type:boolean]] Condition to check. | @input@ [[type:boolean]] Condition to check.
--Examples-- --Examples--
> assert(1 + 1 == 2) == nil # nothing happens > assert(1 + 1 == 2) # nothing happens
> assert(1 * 1 == 2) == nil # An error message is shown > assert(1 * 1 == 2) # An error message is shown
...@@ -2,6 +2,13 @@ Script functions by category ...@@ -2,6 +2,13 @@ Script functions by category
These functions are built into the program, other [[type:function]]s can be defined using the scripting language. These functions are built into the program, other [[type:function]]s can be defined using the scripting language.
! Type conversion <<<
| [[fun:to_string]] Convert any value to a [[type:string]]
| [[fun:to_int]] Convert any value to a [[type:int]]
| [[fun:to_real]] Convert any value to a [[type:double]]
| [[fun:to_boolean]] Convert any value to a [[type:boolean]]
| [[fun:to_color]] Convert any value to a [[type:color]]
! Text manipulation <<< ! Text manipulation <<<
| [[fun:to_upper]] Convert a string to upper case, @"aBc" -> "ABC"@. | [[fun:to_upper]] Convert a string to upper case, @"aBc" -> "ABC"@.
| [[fun:to_lower]] Convert a string to lower case, @"aBc" -> "abc"@. | [[fun:to_lower]] Convert a string to lower case, @"aBc" -> "abc"@.
......
Function: to_boolean
DOC_MSE_VERSION: since 0.3.7
--Usage--
> to_boolean(any value)
Convert any value to a [[type:boolean]] representation.
Normally numbers are not converted to booleans automatically, with the to_boolean function @0@ is converted to @false@ while any other number is converted to @true@.
--Parameters--
! Parameter Type Description
| @input@ ''any type'' Value to convert to a boolean.
--Examples--
> to_boolean(true) == true
> to_boolean("true") == true
> to_boolean(1) == true
> to_boolean(0) == false
Function: to_color
DOC_MSE_VERSION: since 0.3.7
--Usage--
> to_color(any value)
Convert any value to a [[type:color]].
--Parameters--
! Parameter Type Description
| @input@ ''any type'' Value to convert to a color
--Examples--
> to_color("red") == rgb(255,0,0)
Function: to_int
DOC_MSE_VERSION: since 0.3.7
--Usage--
> to_int(any value)
Convert any value to a [[type:int]].
* Real numbers are rounded towards zero when converted to integer numbers.
* The boolean value @true@ becomes @1@, while @false@ is converted to @0@.
* For colors the grayscale value between @0@ and @255@ is returned.
--Parameters--
! Parameter Type Description
| @input@ ''any type'' Value to convert to an integer number
--Examples--
> to_int(1.5) == "1"
> to_int("15") == "15"
> to_int(true) == 1
--See also--
| [[fun:to_real]] Convert any value to a [[type:double]]
Function: to_real
DOC_MSE_VERSION: since 0.3.7
--Usage--
> to_real(any value)
Convert any value to a [[type:double]].
--Parameters--
! Parameter Type Description
| @input@ ''any type'' Value to convert to a real number
--Examples--
> to_real(1) == 1.0
> to_real("1.5") == "1.5"
--See also--
| [[fun:to_int]] Convert any value to a [[type:int]]
Function: to_string
DOC_MSE_VERSION: since 0.3.7
--Usage--
> to_string(any value)
Convert any value to a [[type:string]] representation.
The @to_string@ function should not be confused with @to_text@,
the former converts things like number to string, while the latter removes tags from a [[type:tagged string]].
--Parameters--
! Parameter Type Description
| @input@ ''any type'' Value to convert to a string
| @format@ ''optional'' Formating to apply.
--Examples--
> to_string(to_color("blue")) == "rgb(0,0,255)"
> to_string(10 + 20) == "30"
> to_string(10 + 20, format: ".3f") == "30.000"
> to_string(10 + 20, format: "x") == "1e" # hexadecimal notation
Default arguments Default arguments
DOC_MSE_VERSION: since 0.3.7
It is possible to declare default arguments for functions using the @@@@ operator. It is possible to declare default arguments for functions using the @@@@ operator.
> function := { "argument was: " + arg }@(arg:"default") > function := { "argument was: " + arg }@(arg:"default")
If this function is called without the @arg@ argument, then the default value @"default"@ is used instead. If this function is called without the @arg@ argument, then the default value @"default"@ is used instead.
...@@ -19,6 +21,8 @@ Defaults are evaluated at the time the @@@@ operator is evaluated, they will not ...@@ -19,6 +21,8 @@ Defaults are evaluated at the time the @@@@ operator is evaluated, they will not
--Rule functions-- --Rule functions--
DOC_MSE_VERSION: until 0.3.6
In earlier versions of MSE some functions were available in a special ''rule form''. 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")@ . 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. For backwards compatability these functions are still available, but they should not be used for new templates.
......
...@@ -16,6 +16,7 @@ See also: ...@@ -16,6 +16,7 @@ See also:
* [[fun:index|Built in functions]] * [[fun:index|Built in functions]]
--Syntax index-- --Syntax index--
| @#comment@ Comments ignored by the parser
| @123@ [[type:int|A literal number]] | @123@ [[type:int|A literal number]]
| @"stuff"@ [[type:string|A literal string]] | @"stuff"@ [[type:string|A literal string]]
| @[a,b,c]@ [[type:list|A literal list]] | @[a,b,c]@ [[type:list|A literal list]]
......
...@@ -22,3 +22,5 @@ The operators @or@, @and@ and @xor@ combine two booleans: ...@@ -22,3 +22,5 @@ The operators @or@, @and@ and @xor@ combine two booleans:
| @true@ @false@ @true@ @false@ @true@ | @true@ @false@ @true@ @false@ @true@
| @true@ @true@ @true@ @true@ @false@ | @true@ @true@ @true@ @true@ @false@
--See also--
| [[fun:to_boolean]] Convert a value to a boolean
...@@ -27,3 +27,6 @@ For example: ...@@ -27,3 +27,6 @@ For example:
| @rgba(0,0,0,0)@ transparent <div style="border:1px solid black; width:30px;height:15px;text-align:center;">over</div> | @rgba(0,0,0,0)@ transparent <div style="border:1px solid black; width:30px;height:15px;text-align:center;">over</div>
| @rgba(255,0,0,128)@ transparent red <div style="border:1px solid black; background:rgb(255,128,128);color:rgb(128,0,0);width:30px;height:15px;text-align:center;">over</div> | @rgba(255,0,0,128)@ transparent red <div style="border:1px solid black; background:rgb(255,128,128);color:rgb(128,0,0);width:30px;height:15px;text-align:center;">over</div>
| @rgba(0,0,255,192)@ transparent blue <div style="border:1px solid black; background:rgb(64,64,255);color:rgb(0,0,192);width:30px;height:15px;text-align:center;">over</div> | @rgba(0,0,255,192)@ transparent blue <div style="border:1px solid black; background:rgb(64,64,255);color:rgb(0,0,192);width:30px;height:15px;text-align:center;">over</div>
--See also--
| [[fun:to_color]] Convert any value to a color
...@@ -12,4 +12,5 @@ Conversion from integer to real numbers happens automatically in scripting. ...@@ -12,4 +12,5 @@ Conversion from integer to real numbers happens automatically in scripting.
> 123.1 + 456 * -1 > 123.1 + 456 * -1
--See also-- --See also--
* [[type:int]] | [[type:int]] Integer numbers
| [[fun:to_real]] Convert a value to a real number
...@@ -10,4 +10,5 @@ In many cases negative numbers don't make sense, but the program never complains ...@@ -10,4 +10,5 @@ In many cases negative numbers don't make sense, but the program never complains
> 123 + 456 * -1 > 123 + 456 * -1
--See also-- --See also--
* [[type:double]] | [[type:double]] Number type that can contain fractional values.
| [[fun:to_int]] Convert a value to an integer number
...@@ -25,10 +25,17 @@ Sections between curly braces are interpreted as script code, that is concatenta ...@@ -25,10 +25,17 @@ Sections between curly braces are interpreted as script code, that is concatenta
> "ab{1 + 1}c" == "ab2c" > "ab{1 + 1}c" == "ab2c"
This can be nested arbitrarily. This can be nested arbitrarily.
The @+@ operator concatenates strings. Numbers and most other values are automatically converted to strings when needed. The @+@ operator concatenates strings. Numbers and most other values are automatically converted to strings when needed. This conversion can be forced with the [[fun:to_string]] function.
Using the @[]@ or @.@ operator characters in a string can be selected. 0 is the first character: Using the @[]@ or @.@ operator characters in a string can be selected. 0 is the first character:
> "xyz"[0] == "x" > "xyz"[0] == "x"
> "xyz".0 == "x" # same thing > "xyz".0 == "x" # same thing
> "xyz".1 == "y"
> "xyz".2 == "z"
It is an error to select characters outside the string It is an error to select characters outside the string
> "xyz".10 # error > "xyz".10 # error
\ No newline at end of file
--See also--
| [[type:tagged string]] A string containg tags.
| [[fun:to_string]] Convert any value to a [[type:string]]
...@@ -649,6 +649,7 @@ KeywordParamValue::operator String() const { ...@@ -649,6 +649,7 @@ KeywordParamValue::operator String() const {
KeywordParamValue::operator int() const { return *to_script(value); } // a bit of a hack KeywordParamValue::operator int() const { return *to_script(value); } // a bit of a hack
KeywordParamValue::operator double() const { return *to_script(value); } KeywordParamValue::operator double() const { return *to_script(value); }
KeywordParamValue::operator bool() const { return *to_script(value); }
KeywordParamValue::operator AColor() const { return *to_script(value); } KeywordParamValue::operator AColor() const { return *to_script(value); }
int KeywordParamValue::itemCount() const { return to_script(value)->itemCount(); } int KeywordParamValue::itemCount() const { return to_script(value)->itemCount(); }
......
...@@ -176,6 +176,7 @@ class KeywordParamValue : public ScriptValue { ...@@ -176,6 +176,7 @@ class KeywordParamValue : public ScriptValue {
virtual String typeName() const; virtual String typeName() const;
virtual operator String() const; virtual operator String() const;
virtual operator int() const; virtual operator int() const;
virtual operator bool() const;
virtual operator double() const; virtual operator double() const;
virtual operator AColor() const; virtual operator AColor() const;
virtual int itemCount() const; virtual int itemCount() const;
......
...@@ -3399,6 +3399,420 @@ ...@@ -3399,6 +3399,420 @@
</File> </File>
</Filter> </Filter>
</Filter> </Filter>
<Filter
Name="doc"
Filter="">
<Filter
Name="about"
Filter="">
</Filter>
<Filter
Name="file"
Filter="">
<File
RelativePath="..\doc\file\format.txt">
</File>
<File
RelativePath="..\doc\file\index.txt">
</File>
<File
RelativePath="..\doc\file\package.txt">
</File>
<File
RelativePath="..\doc\file\style_triangle.txt">
</File>
</Filter>
<Filter
Name="script"
Filter="">
<File
RelativePath="..\doc\script\best_practices.txt">
</File>
<File
RelativePath="..\doc\script\control_structures.txt">
</File>
<File
RelativePath="..\doc\script\default_arguments.txt">
</File>
<File
RelativePath="..\doc\script\functions.txt">
</File>
<File
RelativePath="..\doc\script\index.txt">
</File>
<File
RelativePath="..\doc\script\introduction.txt">
</File>
<File
RelativePath="..\doc\script\operators.txt">
</File>
<File
RelativePath="..\doc\script\predefined_variables.txt">
</File>
<File
RelativePath="..\doc\script\variables.txt">
</File>
</Filter>
<Filter
Name="function"
Filter="">
<File
RelativePath="..\doc\function\assert.txt">
</File>
<File
RelativePath="..\doc\function\break_text.txt">
</File>
<File
RelativePath="..\doc\function\built_in_image.txt">
</File>
<File
RelativePath="..\doc\function\chosen.txt">
</File>
<File
RelativePath="..\doc\function\combine_blend.txt">
</File>
<File
RelativePath="..\doc\function\combined_editor.txt">
</File>
<File
RelativePath="..\doc\function\contains.txt">
</File>
<File
RelativePath="..\doc\function\copy_file.txt">
</File>
<File
RelativePath="..\doc\function\crop.txt">
</File>
<File
RelativePath="..\doc\function\curly_quotes.txt">
</File>
<File
RelativePath="..\doc\function\drop_shadow.txt">
</File>
<File
RelativePath="..\doc\function\english_number.txt">
</File>
<File
RelativePath="..\doc\function\english_plural.txt">
</File>
<File
RelativePath="..\doc\function\enlarge.txt">
</File>
<File
RelativePath="..\doc\function\exclusive_choice.txt">
</File>
<File
RelativePath="..\doc\function\expand_keywords.txt">
</File>
<File
RelativePath="..\doc\function\filter_list.txt">
</File>
<File
RelativePath="..\doc\function\filter_text.txt">
</File>
<File
RelativePath="..\doc\function\format.txt">
</File>
<File
RelativePath="..\doc\function\index.txt">
</File>
<File
RelativePath="..\doc\function\keyword_usage.txt">
</File>
<File
RelativePath="..\doc\function\length.txt">
</File>
<File
RelativePath="..\doc\function\linear_blend.txt">
</File>
<File
RelativePath="..\doc\function\masked_blend.txt">
</File>
<File
RelativePath="..\doc\function\match.txt">
</File>
<File
RelativePath="..\doc\function\number_of_items.txt">
</File>
<File
RelativePath="..\doc\function\position.txt">
</File>
<File
RelativePath="..\doc\function\primary_choice.txt">
</File>
<File
RelativePath="..\doc\function\process_english_hints.txt">
</File>
<File
RelativePath="..\doc\function\regex_escape.txt">
</File>
<File
RelativePath="..\doc\function\remove_choice.txt">
</File>
<File
RelativePath="..\doc\function\remove_tag.txt">
</File>
<File
RelativePath="..\doc\function\remove_tags.txt">
</File>
<File
RelativePath="..\doc\function\replace.txt">
</File>
<File
RelativePath="..\doc\function\require_choice.txt">
</File>
<File
RelativePath="..\doc\function\require_exclusive_choice.txt">
</File>
<File
RelativePath="..\doc\function\reverse.txt">
</File>
<File
RelativePath="..\doc\function\saturate.txt">
</File>
<File
RelativePath="..\doc\function\set_alpha.txt">
</File>
<File
RelativePath="..\doc\function\set_combine.txt">
</File>
<File
RelativePath="..\doc\function\set_mask.txt">
</File>
<File
RelativePath="..\doc\function\sort_list.txt">
</File>
<File
RelativePath="..\doc\function\sort_text.txt">
</File>
<File
RelativePath="..\doc\function\substring.txt">
</File>
<File
RelativePath="..\doc\function\symbol_variation.txt">
</File>
<File
RelativePath="..\doc\function\symbols_to_html.txt">
</File>
<File
RelativePath="..\doc\function\tag_contents.txt">
</File>
<File
RelativePath="..\doc\function\to_boolean.txt">
</File>
<File
RelativePath="..\doc\function\to_color.txt">
</File>
<File
RelativePath="..\doc\function\to_html.txt">
</File>
<File
RelativePath="..\doc\function\to_int.txt">
</File>
<File
RelativePath="..\doc\function\to_lower.txt">
</File>
<File
RelativePath="..\doc\function\to_real.txt">
</File>
<File
RelativePath="..\doc\function\to_string.txt">
</File>
<File
RelativePath="..\doc\function\to_text.txt">
</File>
<File
RelativePath="..\doc\function\to_title.txt">
</File>
<File
RelativePath="..\doc\function\to_upper.txt">
</File>
<File
RelativePath="..\doc\function\trace.txt">
</File>
<File
RelativePath="..\doc\function\trim.txt">
</File>
<File
RelativePath="..\doc\function\write_image_file.txt">
</File>
<File
RelativePath="..\doc\function\write_text_file.txt">
</File>
</Filter>
<Filter
Name="type"
Filter="">
<File
RelativePath="..\doc\type\alignment.txt">
</File>
<File
RelativePath="..\doc\type\boolean.txt">
</File>
<File
RelativePath="..\doc\type\card.txt">
</File>
<File
RelativePath="..\doc\type\choice.txt">
</File>
<File
RelativePath="..\doc\type\choice_render_style.txt">
</File>
<File
RelativePath="..\doc\type\color.txt">
</File>
<File
RelativePath="..\doc\type\color_choice.txt">
</File>
<File
RelativePath="..\doc\type\combine.txt">
</File>
<File
RelativePath="..\doc\type\control_point.txt">
</File>
<File
RelativePath="..\doc\type\dependency.txt">
</File>
<File
RelativePath="..\doc\type\direction.txt">
</File>
<File
RelativePath="..\doc\type\double.txt">
</File>
<File
RelativePath="..\doc\type\export_template.txt">
</File>
<File
RelativePath="..\doc\type\field.txt">
</File>
<File
RelativePath="..\doc\type\filename.txt">
</File>
<File
RelativePath="..\doc\type\font.txt">
</File>
<File
RelativePath="..\doc\type\function.txt">
</File>
<File
RelativePath="..\doc\type\game.txt">
</File>
<File
RelativePath="..\doc\type\graph_type.txt">
</File>
<File
RelativePath="..\doc\type\image.txt">
</File>
<File
RelativePath="..\doc\type\include.txt">
</File>
<File
RelativePath="..\doc\type\index.txt">
</File>
<File
RelativePath="..\doc\type\indexmap.txt">
</File>
<File
RelativePath="..\doc\type\insert_symbol_menu.txt">
</File>
<File
RelativePath="..\doc\type\installer.txt">
</File>
<File
RelativePath="..\doc\type\int.txt">
</File>
<File
RelativePath="..\doc\type\keyword.txt">
</File>
<File
RelativePath="..\doc\type\keyword_mode.txt">
</File>
<File
RelativePath="..\doc\type\keyword_param_reference_script.txt">
</File>
<File
RelativePath="..\doc\type\keyword_param_type.txt">
</File>
<File
RelativePath="..\doc\type\list.txt">
</File>
<File
RelativePath="..\doc\type\locale.txt">
</File>
<File
RelativePath="..\doc\type\map.txt">
</File>
<File
RelativePath="..\doc\type\regex.txt">
</File>
<File
RelativePath="..\doc\type\script.txt">
</File>
<File
RelativePath="..\doc\type\scriptable.txt">
</File>
<File
RelativePath="..\doc\type\set.txt">
</File>
<File
RelativePath="..\doc\type\settings.txt">
</File>
<File
RelativePath="..\doc\type\statistics_category.txt">
</File>
<File
RelativePath="..\doc\type\statistics_dimension.txt">
</File>
<File
RelativePath="..\doc\type\string.txt">
</File>
<File
RelativePath="..\doc\type\style.txt">
</File>
<File
RelativePath="..\doc\type\stylesheet.txt">
</File>
<File
RelativePath="..\doc\type\symbol.txt">
</File>
<File
RelativePath="..\doc\type\symbol_combine.txt">
</File>
<File
RelativePath="..\doc\type\symbol_font.txt">
</File>
<File
RelativePath="..\doc\type\symbol_font_reference.txt">
</File>
<File
RelativePath="..\doc\type\symbol_font_symbol.txt">
</File>
<File
RelativePath="..\doc\type\symbol_part.txt">
</File>
<File
RelativePath="..\doc\type\symbol_variation.txt">
</File>
<File
RelativePath="..\doc\type\tagged_string.txt">
</File>
<File
RelativePath="..\doc\type\value.txt">
</File>
<File
RelativePath="..\doc\type\vector2d.txt">
</File>
<File
RelativePath="..\doc\type\version.txt">
</File>
<File
RelativePath="..\doc\type\word_list.txt">
</File>
<File
RelativePath="..\doc\type\word_list_word.txt">
</File>
</Filter>
</Filter>
<File <File
RelativePath=".\code_template.cpp"> RelativePath=".\code_template.cpp">
<FileConfiguration <FileConfiguration
......
...@@ -63,7 +63,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { ...@@ -63,7 +63,7 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
} }
// Conditional jump // Conditional jump
case I_JUMP_IF_NOT: { case I_JUMP_IF_NOT: {
int condition = *stack.back(); bool condition = *stack.back();
stack.pop_back(); stack.pop_back();
if (!condition) { if (!condition) {
instr = &script.instructions[i.data]; instr = &script.instructions[i.data];
...@@ -322,6 +322,11 @@ class ScriptCompose : public ScriptValue { ...@@ -322,6 +322,11 @@ class ScriptCompose : public ScriptValue {
a = to_script((int)*a OP (int)*b); \ a = to_script((int)*a OP (int)*b); \
break break
// operator on bools
#define OPERATOR_B(OP) \
a = to_script((bool)*a OP (bool)*b); \
break
// operator on doubles or ints // operator on doubles or ints
#define OPERATOR_DI(OP) \ #define OPERATOR_DI(OP) \
if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) { \ if (at == SCRIPT_DOUBLE || bt == SCRIPT_DOUBLE) { \
...@@ -392,9 +397,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& ...@@ -392,9 +397,9 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
a = to_script((int)*a % (int)*b); a = to_script((int)*a % (int)*b);
} }
break; break;
case I_AND: OPERATOR_I(&&); case I_AND: OPERATOR_B(&&);
case I_OR: OPERATOR_I(||); case I_OR: OPERATOR_B(||);
case I_XOR: a = to_script((bool)*a != (bool)*b); break; case I_XOR: OPERATOR_B(!=);
case I_EQ: a = to_script( equal(a,b)); break; case I_EQ: a = to_script( equal(a,b)); break;
case I_NEQ: a = to_script(!equal(a,b)); break; case I_NEQ: a = to_script(!equal(a,b)); break;
case I_LT: OPERATOR_DI(<); case I_LT: OPERATOR_DI(<);
......
...@@ -78,6 +78,7 @@ class ScriptMissingVariable : public ScriptValue { ...@@ -78,6 +78,7 @@ class ScriptMissingVariable : public ScriptValue {
virtual operator String() const { return wxEmptyString; } virtual operator String() const { return wxEmptyString; }
virtual operator double() const { return 0.0; } virtual operator double() const { return 0.0; }
virtual operator int() const { return 0; } virtual operator int() const { return 0; }
virtual operator bool() const { return false; }
virtual ScriptValueP eval(Context&) const { return script_nil; } // nil() == nil virtual ScriptValueP eval(Context&) const { return script_nil; } // nil() == nil
private: private:
String name; ///< Name of the variable String name; ///< Name of the variable
......
...@@ -37,6 +37,75 @@ SCRIPT_FUNCTION(warning) { ...@@ -37,6 +37,75 @@ SCRIPT_FUNCTION(warning) {
return script_nil; return script_nil;
} }
// ----------------------------------------------------------------------------- : Conversion
/// Format the input variable based on a printf like style specification
String format_input(const String& format, Context& ctx) {
String fmt = _("%") + replace_all(format, _("%"), _(""));
// determine type expected by format string
if (format.find_first_of(_("DdIiOoXx")) != String::npos) {
SCRIPT_PARAM_C(int, input);
return String::Format(fmt, input);
} else if (format.find_first_of(_("EeFfGg")) != String::npos) {
SCRIPT_PARAM_C(double, input);
return String::Format(fmt, input);
} else if (format.find_first_of(_("Ss")) != String::npos) {
SCRIPT_PARAM_C(String, input);
return format_string(fmt, input);
} else {
throw ScriptError(_ERROR_1_("unsupported format", format));
}
}
SCRIPT_FUNCTION(to_string) {
ScriptValueP format = ctx.getVariable(SCRIPT_VAR_format);
if (format && format->type() == SCRIPT_STRING) {
// format specifier. Be careful, the built in function 'format' has the same name
SCRIPT_RETURN(format_input(*format, ctx));
} else {
// simple conversion
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(input);
}
}
SCRIPT_FUNCTION(to_int) {
ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input);
ScriptType t = input->type();
int result;
if (t == SCRIPT_BOOL) {
result = (bool)*input ? 1 : 0;
} else if (t == SCRIPT_COLOR) {
AColor c = (AColor)*input;
result = (c.Red() + c.Blue() + c.Green()) / 3;
} else {
result = (int)*input;
}
SCRIPT_RETURN(result);
}
SCRIPT_FUNCTION(to_real) {
SCRIPT_PARAM_C(double, input);
SCRIPT_RETURN(input);
}
SCRIPT_FUNCTION(to_boolean) {
ScriptValueP input = ctx.getVariable(SCRIPT_VAR_input);
ScriptType t = input->type();
bool result;
if (t == SCRIPT_INT) {
result = (int)*input != 0;
} else {
result = (bool)*input;
}
SCRIPT_RETURN(result);
}
SCRIPT_FUNCTION(to_color) {
SCRIPT_PARAM_C(AColor, input);
SCRIPT_RETURN(input);
}
// ----------------------------------------------------------------------------- : String stuff // ----------------------------------------------------------------------------- : String stuff
// convert a string to upper case // convert a string to upper case
...@@ -95,20 +164,7 @@ SCRIPT_FUNCTION(contains) { ...@@ -95,20 +164,7 @@ SCRIPT_FUNCTION(contains) {
SCRIPT_FUNCTION(format) { SCRIPT_FUNCTION(format) {
SCRIPT_PARAM_C(String, format); SCRIPT_PARAM_C(String, format);
String fmt = _("%") + replace_all(format, _("%"), _("")); SCRIPT_RETURN(format_input(format,ctx));
// determine type expected by format string
if (format.find_first_of(_("DdIiOoXx")) != String::npos) {
SCRIPT_PARAM_C(int, input);
SCRIPT_RETURN(String::Format(fmt, input));
} else if (format.find_first_of(_("EeFfGg")) != String::npos) {
SCRIPT_PARAM_C(double, input);
SCRIPT_RETURN(String::Format(fmt, input));
} else if (format.find_first_of(_("Ss")) != String::npos) {
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(format_string(fmt, input));
} else {
throw ScriptError(_ERROR_1_("unsupported format", format));
}
} }
SCRIPT_FUNCTION(curly_quotes) { SCRIPT_FUNCTION(curly_quotes) {
...@@ -394,6 +450,12 @@ SCRIPT_FUNCTION(rule) { ...@@ -394,6 +450,12 @@ SCRIPT_FUNCTION(rule) {
void init_script_basic_functions(Context& ctx) { void init_script_basic_functions(Context& ctx) {
// debugging // debugging
ctx.setVariable(_("trace"), script_trace); ctx.setVariable(_("trace"), script_trace);
// conversion
ctx.setVariable(_("to string"), script_to_string);
ctx.setVariable(_("to int"), script_to_int);
ctx.setVariable(_("to real"), script_to_real);
ctx.setVariable(_("to boolean"), script_to_boolean);
ctx.setVariable(_("to color"), script_to_color);
// string // string
ctx.setVariable(_("to upper"), script_to_upper); ctx.setVariable(_("to upper"), script_to_upper);
ctx.setVariable(_("to lower"), script_to_lower); ctx.setVariable(_("to lower"), script_to_lower);
......
...@@ -419,4 +419,5 @@ void init_script_export_functions(Context& ctx) { ...@@ -419,4 +419,5 @@ void init_script_export_functions(Context& ctx) {
ctx.setVariable(_("copy file"), script_copy_file); ctx.setVariable(_("copy file"), script_copy_file);
ctx.setVariable(_("write text file"), script_write_text_file); ctx.setVariable(_("write text file"), script_write_text_file);
ctx.setVariable(_("write image file"), script_write_image_file); ctx.setVariable(_("write image file"), script_write_image_file);
//ctx.setVariable(_("write set file"), script_write_set_file);//TODO
} }
...@@ -29,6 +29,11 @@ template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValu ...@@ -29,6 +29,11 @@ template <> inline GeneratedImageP from_script<GeneratedImageP>(const ScriptValu
return image_from_script(value); return image_from_script(value);
} }
SCRIPT_FUNCTION(to_image) {
SCRIPT_PARAM_C(GeneratedImageP, input);
return input;
}
// ----------------------------------------------------------------------------- : Image functions // ----------------------------------------------------------------------------- : Image functions
SCRIPT_FUNCTION(linear_blend) { SCRIPT_FUNCTION(linear_blend) {
...@@ -181,6 +186,7 @@ SCRIPT_FUNCTION(built_in_image) { ...@@ -181,6 +186,7 @@ SCRIPT_FUNCTION(built_in_image) {
// ----------------------------------------------------------------------------- : Init // ----------------------------------------------------------------------------- : Init
void init_script_image_functions(Context& ctx) { void init_script_image_functions(Context& ctx) {
ctx.setVariable(_("to image"), script_to_image);
ctx.setVariable(_("linear blend"), script_linear_blend); ctx.setVariable(_("linear blend"), script_linear_blend);
ctx.setVariable(_("masked blend"), script_masked_blend); ctx.setVariable(_("masked blend"), script_masked_blend);
ctx.setVariable(_("combine blend"), script_combine_blend); ctx.setVariable(_("combine blend"), script_combine_blend);
......
...@@ -23,7 +23,7 @@ DECLARE_TYPEOF_COLLECTION(ScriptParseError); ...@@ -23,7 +23,7 @@ DECLARE_TYPEOF_COLLECTION(ScriptParseError);
void store(const ScriptValueP& val, String& var) { var = val->toString(); } void store(const ScriptValueP& val, String& var) { var = val->toString(); }
void store(const ScriptValueP& val, int& var) { var = *val; } void store(const ScriptValueP& val, int& var) { var = *val; }
void store(const ScriptValueP& val, double& var) { var = *val; } void store(const ScriptValueP& val, double& var) { var = *val; }
void store(const ScriptValueP& val, bool& var) { var = static_cast<int>(*val); } void store(const ScriptValueP& val, bool& var) { var = *val; }
void store(const ScriptValueP& val, Color& var) { var = (AColor)*val; } void store(const ScriptValueP& val, Color& var) { var = (AColor)*val; }
void store(const ScriptValueP& val, AColor& var) { var = *val; } void store(const ScriptValueP& val, AColor& var) { var = *val; }
void store(const ScriptValueP& val, Defaultable<String>& var) { var.assign(*val); } void store(const ScriptValueP& val, Defaultable<String>& var) { var.assign(*val); }
......
...@@ -60,6 +60,7 @@ class ScriptDelayedError : public ScriptValue { ...@@ -60,6 +60,7 @@ class ScriptDelayedError : public ScriptValue {
virtual operator String() const; virtual operator String() const;
virtual operator double() const; virtual operator double() const;
virtual operator int() const; virtual operator int() const;
virtual operator bool() const;
virtual operator AColor() const; virtual operator AColor() const;
virtual int itemCount() const; virtual int itemCount() const;
virtual CompareWhat compareAs(String&, void const*&) const; virtual CompareWhat compareAs(String&, void const*&) const;
...@@ -243,6 +244,7 @@ class ScriptObject : public ScriptValue { ...@@ -243,6 +244,7 @@ class ScriptObject : public ScriptValue {
virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); } virtual operator String() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator String(); }
virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); } virtual operator double() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator double(); }
virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); } virtual operator int() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator int(); }
virtual operator bool() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator bool(); }
virtual operator AColor() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator AColor(); } virtual operator AColor() const { ScriptValueP d = getDefault(); return d ? *d : ScriptValue::operator AColor(); }
virtual ScriptValueP getMember(const String& name) const { virtual ScriptValueP getMember(const String& name) const {
GetMember gm(name); GetMember gm(name);
......
...@@ -20,6 +20,7 @@ DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>); ...@@ -20,6 +20,7 @@ DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>);
ScriptValue::operator String() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("string" ))); } ScriptValue::operator String() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("string" ))); }
ScriptValue::operator int() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("integer" ))); } ScriptValue::operator int() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("integer" ))); }
ScriptValue::operator bool() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("boolean" ))); }
ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("double" ))); } ScriptValue::operator double() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("double" ))); }
ScriptValue::operator AColor() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); } ScriptValue::operator AColor() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("color" ))); }
ScriptValueP ScriptValue::eval(Context&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); } ScriptValueP ScriptValue::eval(Context&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("function"))); }
...@@ -43,6 +44,8 @@ bool equal(const ScriptValueP& a, const ScriptValueP& b) { ...@@ -43,6 +44,8 @@ bool equal(const ScriptValueP& a, const ScriptValueP& b) {
ScriptType at = a->type(), bt = b->type(); ScriptType at = a->type(), bt = b->type();
if (at == bt && at == SCRIPT_INT) { if (at == bt && at == SCRIPT_INT) {
return (int)*a == (int)*b; return (int)*a == (int)*b;
} else if (at == bt && at == SCRIPT_BOOL) {
return (bool)*a == (bool)*b;
} else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) && } else if ((at == SCRIPT_INT || at == SCRIPT_DOUBLE) &&
(bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) { (bt == SCRIPT_INT || bt == SCRIPT_DOUBLE)) {
return (double)*a == (double)*b; return (double)*a == (double)*b;
...@@ -81,6 +84,7 @@ String ScriptDelayedError::typeName() const { throw error; } ...@@ -81,6 +84,7 @@ String ScriptDelayedError::typeName() const { throw error; }
ScriptDelayedError::operator String() const { throw error; } ScriptDelayedError::operator String() const { throw error; }
ScriptDelayedError::operator double() const { throw error; } ScriptDelayedError::operator double() const { throw error; }
ScriptDelayedError::operator int() const { throw error; } ScriptDelayedError::operator int() const { throw error; }
ScriptDelayedError::operator bool() const { throw error; }
ScriptDelayedError::operator AColor() const { throw error; } ScriptDelayedError::operator AColor() const { throw error; }
int ScriptDelayedError::itemCount() const { throw error; } int ScriptDelayedError::itemCount() const { throw error; }
CompareWhat ScriptDelayedError::compareAs(String&, void const*&) const { throw error; } CompareWhat ScriptDelayedError::compareAs(String&, void const*&) const { throw error; }
...@@ -171,10 +175,11 @@ ScriptValueP to_script(int v) { ...@@ -171,10 +175,11 @@ ScriptValueP to_script(int v) {
class ScriptBool : public ScriptValue { class ScriptBool : public ScriptValue {
public: public:
ScriptBool(bool v) : value(v) {} ScriptBool(bool v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_INT; } virtual ScriptType type() const { return SCRIPT_BOOL; }
virtual String typeName() const { return _TYPE_("boolean"); } virtual String typeName() const { return _TYPE_("boolean"); }
virtual operator String() const { return value ? _("true") : _("false"); } virtual operator String() const { return value ? _("true") : _("false"); }
virtual operator int() const { return value; } // bools don't autoconvert to int
virtual operator bool() const { return value; }
private: private:
bool value; bool value;
}; };
...@@ -227,12 +232,17 @@ class ScriptString : public ScriptValue { ...@@ -227,12 +232,17 @@ class ScriptString : public ScriptValue {
long l; long l;
if (value.ToLong(&l)) { if (value.ToLong(&l)) {
return l; return l;
} else if (value == _("yes") || value == _("true")) { } else {
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("integer")));
}
}
virtual operator bool() const {
if (value == _("yes") || value == _("true")) {
return true; return true;
} else if (value == _("no") || value == _("false") || value.empty()) { } else if (value == _("no") || value == _("false") || value.empty()) {
return false; return false;
} else { } else {
throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("integer"))); throw ScriptError(_ERROR_3_("can't convert value", value, typeName(), _TYPE_("boolean")));
} }
} }
virtual operator AColor() const { virtual operator AColor() const {
...@@ -270,7 +280,7 @@ class ScriptAColor : public ScriptValue { ...@@ -270,7 +280,7 @@ class ScriptAColor : public ScriptValue {
virtual ScriptType type() const { return SCRIPT_COLOR; } virtual ScriptType type() const { return SCRIPT_COLOR; }
virtual String typeName() const { return _TYPE_("color"); } virtual String typeName() const { return _TYPE_("color"); }
virtual operator AColor() const { return value; } virtual operator AColor() const { return value; }
virtual operator int() const { return (value.Red() + value.Blue() + value.Green()) / 3; } // colors don't auto convert to int, use to_int to force
virtual operator String() const { virtual operator String() const {
return format_acolor(value); return format_acolor(value);
} }
...@@ -296,6 +306,7 @@ class ScriptNil : public ScriptValue { ...@@ -296,6 +306,7 @@ class ScriptNil : public ScriptValue {
virtual operator String() const { return wxEmptyString; } virtual operator String() const { return wxEmptyString; }
virtual operator double() const { return 0.0; } virtual operator double() const { return 0.0; }
virtual operator int() const { return 0; } virtual operator int() const { return 0; }
virtual operator bool() const { return false; }
virtual ScriptValueP eval(Context&) const { return script_nil; } // nil() == nil virtual ScriptValueP eval(Context&) const { return script_nil; } // nil() == nil
}; };
......
...@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(ScriptValue); ...@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(ScriptValue);
enum ScriptType enum ScriptType
{ SCRIPT_NIL { SCRIPT_NIL
, SCRIPT_INT , SCRIPT_INT
, SCRIPT_BOOL
, SCRIPT_DOUBLE , SCRIPT_DOUBLE
, SCRIPT_STRING , SCRIPT_STRING
, SCRIPT_COLOR , SCRIPT_COLOR
...@@ -62,7 +63,7 @@ class ScriptValue : public IntrusivePtrBaseWithDelete { ...@@ -62,7 +63,7 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
/// Convert this value to an integer /// Convert this value to an integer
virtual operator int() const; virtual operator int() const;
/// Convert this value to a boolean /// Convert this value to a boolean
inline operator bool() const { return (int)*this; } virtual operator bool() const;
/// Convert this value to a color /// Convert this value to a color
virtual operator AColor() const; virtual operator AColor() const;
......
...@@ -161,6 +161,12 @@ function autoformat__handle(&$i, $prefix, $first, $fail_same = false) { ...@@ -161,6 +161,12 @@ function autoformat__handle(&$i, $prefix, $first, $fail_same = false) {
} elseif (preg_match("@^//@", $line)) { } elseif (preg_match("@^//@", $line)) {
// ignore // ignore
// version information block
} elseif (preg_match("@^DOC_MSE_VERSION:@", $line)) {
$line = preg_replace("@^[A-Z_]+:\s*@",'',$line);
$text .= "<div class=\"version-note\">" . $line . "</div>\n";
$state = '';
// Just text // Just text
} else if ($fail_same && $autoformat__lines[$i-1]{$len-1} != ' ' && $text != '') { } else if ($fail_same && $autoformat__lines[$i-1]{$len-1} != ' ' && $text != '') {
// consecutive * and # lines are different items // consecutive * and # lines are different items
......
...@@ -4,6 +4,12 @@ ...@@ -4,6 +4,12 @@
global $built_in_functions; global $built_in_functions;
$built_in_functions = array( $built_in_functions = array(
// conversion
'to_string' =>'',
'to_int' =>'',
'to_real' =>'',
'to_boolean' =>'',
'to_color' =>'',
// text // text
'to_upper' =>'', 'to_upper' =>'',
'to_lower' =>'', 'to_lower' =>'',
......
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