From dfae1b2729584163c2308a727d4cb2ece4aa5c1e Mon Sep 17 00:00:00 2001 From: twanvl Date: Sat, 28 Jun 2008 14:41:38 +0000 Subject: [PATCH] Added count_chosen function; Added I_DUP instruction git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1007 0fc631ac-6414-0410-93d0-97cfa31319b6 --- doc/function/chosen.txt | 3 + doc/function/count_chosen.txt | 24 ++++ doc/function/index.txt | 1 + doc/function/require_choice.txt | 24 ++-- src/mse.vcproj | 3 + src/script/context.cpp | 5 + src/script/dependency.cpp | 5 + src/script/functions/editor.cpp | 109 +++++++++++------- src/script/script.cpp | 6 +- src/script/script.hpp | 3 + .../drupal/mse-drupal-modules/highlight.inc | 1 + 11 files changed, 135 insertions(+), 49 deletions(-) create mode 100644 doc/function/count_chosen.txt diff --git a/doc/function/chosen.txt b/doc/function/chosen.txt index 5adb5de2..6e499620 100644 --- a/doc/function/chosen.txt +++ b/doc/function/chosen.txt @@ -15,3 +15,6 @@ Is the given choice selected in the [[type:value#multiple_choice|multiple choice > chosen(choice: "red", "blue") == false > chosen(choice: "red", "red, blue") == true > chosen(choice: "blue", "red, blue") == true + +--See also-- +| [[fun:count_chosen]] Count then number of choices selected in a multiple choice value. diff --git a/doc/function/count_chosen.txt b/doc/function/count_chosen.txt new file mode 100644 index 00000000..cb9bf91c --- /dev/null +++ b/doc/function/count_chosen.txt @@ -0,0 +1,24 @@ +Function: count_chosen + +DOC_MSE_VERSION: since 0.3.7 + +--Usage-- +> count_chosen(choices: some_string, some_multiple_choice_value) + +Coint the number of choices that are selected in a [[type:value#multiple_choice|multiple choice value]]. + +If the @choices@ parameter is given then only choices from that list are counted. + +--Parameters-- +! Parameter Type Description +| @input@ [[type:string]] Multiple choice value to look in. +| @choices@ optional [[type:string]] A comma separated list of choices to look for. + +--Examples-- +> count_chosen("") == 0 +> count_chosen("red") == 1 +> count_chosen("red, green") == 2 +> count_chosen("red, green", choices: "red,blue") == 1 + +--See also-- +| [[fun:chosen]] Is a given choice selected in a multiple choice value? diff --git a/doc/function/index.txt b/doc/function/index.txt index dfd51a30..887619a3 100644 --- a/doc/function/index.txt +++ b/doc/function/index.txt @@ -56,6 +56,7 @@ These functions are built into the program, other [[type:function]]s can be defi | [[fun:combined_editor]] Use one field to edit multiple others. | [[fun:primary_choice]] Return the top level choice chosen from a choice field. | [[fun:chosen]] Is the given choice selected in a multiple choice value? +| [[fun:count_chosen]] Count then number of choices selected in a multiple choice value. | [[fun:require_choice]] Require that at least one of the given choices is selected. | [[fun:exclusive_choice]] Require that at most one of the given choices is selected. | [[fun:require_exclusive_choice]] Require that exactly one of the given choices is selected. diff --git a/doc/function/require_choice.txt b/doc/function/require_choice.txt index 563c3a8c..0c816982 100644 --- a/doc/function/require_choice.txt +++ b/doc/function/require_choice.txt @@ -10,18 +10,26 @@ If non of the choices is selected, selects the first one. --Parameters-- ! Parameter Type Description | @input@ [[type:string]] Multiple choice value to look update. -| @choice@ [[type:string]] Choice to require. +| @choices@ [[type:string]] Comma separated list of choices of which one is required. + +For backwards compatability the following form is also supported: + +DOC_MSE_VERSION: until 0.3.6 + +! Parameter Type Description +| @input@ [[type:string]] Multiple choice value to look update. +| @choice@ [[type:string]] Single choice to require. | @choice1@ [[type:string]] Require multiple choices. | @choice2@ [[type:string]] ''etc.'' --Examples-- -> require_choice(choice: "red", "red") == "red" -> require_choice(choice: "red", "blue") == "blue, red" -> require_choice(choice: "red", "red, blue") == "red, blue" -> require_choice(choice1: "red", choice2: "green", "red, blue") == "red, blue" -> require_choice(choice1: "red", choice2: "green", "red, green") == "red, blue" -> require_choice(choice1: "red", choice2: "green", "green, blue") == "green, blue" -> require_choice(choice1: "red", choice2: "green", "black, blue") == "black, blue, red" +> require_choice(choices: "red", "red") == "red" +> require_choice(choices: "red", "blue") == "blue, red" +> require_choice(choices: "red", "red, blue") == "red, blue" +> require_choice(choices: "red,green", "red, blue") == "red, blue" +> require_choice(choices: "red,green", "red, green") == "red, blue" +> require_choice(choices: "red,green", "green, blue") == "green, blue" +> require_choice(choices: "red,green", "black, blue") == "black, blue, red" --See also-- | [[fun:exclusive_choice]] Require that ''at most one'' of the given choices is selected. diff --git a/src/mse.vcproj b/src/mse.vcproj index 6c4289c9..f9de2549 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -3480,6 +3480,9 @@ + + diff --git a/src/script/context.cpp b/src/script/context.cpp index e1f790c1..e0cc116e 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -177,6 +177,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { instrQuaternary(i.instr4, a, b, c, d); break; } + // Duplicate stack + case I_DUP: { + stack.push_back(stack.at(stack.size() - i.data - 1)); + break; + } } } diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 2196311b..8900202c 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -325,6 +325,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) a = dependency_dummy; break; } + // Duplicate stack + case I_DUP: { + stack.push_back(stack.at(stack.size() - i.data - 1)); + break; + } } } diff --git a/src/script/functions/editor.cpp b/src/script/functions/editor.cpp index fbe05cc5..882c5e91 100644 --- a/src/script/functions/editor.cpp +++ b/src/script/functions/editor.cpp @@ -203,19 +203,23 @@ SCRIPT_FUNCTION(primary_choice) { // ----------------------------------------------------------------------------- : Multiple choice values +/// Iterate over a comma separated list +bool next_choice(size_t& start, size_t& end, const String& input) { + if (start >= input.size()) return false; + // ingore whitespace + while (start < input.size() && input.GetChar(start) == _(' ')) ++start; + // find end + end = input.find_first_of(_(','), start); + if (end == String::npos) end = input.size(); + return true; +} + /// Is the given choice active? bool chosen(const String& choice, const String& input) { - for (size_t pos = 0 ; pos < input.size() ; ) { - if (input.GetChar(pos) == _(' ')) { - ++pos; // ingore whitespace - } else { - // does this choice match the one asked about? - size_t end = input.find_first_of(_(','), pos); - if (end == String::npos) end = input.size(); - if (end - pos == choice.size() && is_substr(input, pos, choice)) { - return true; - } - pos = end + 1; + for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) { + // does this choice match the one asked about? + if (end - start == choice.size() && is_substr(input, start, choice)) { + return true; } } return false; @@ -236,29 +240,22 @@ String filter_choices(const String& input, const vector& choices, int mi if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure String ret; int count = 0; - vector seen(choices.size()); // which choices have we seen? - for (size_t pos = 0 ; pos < input.size() ; ) { - if (input.GetChar(pos) == _(' ')) { - ++pos; // ingore whitespace - } else { - // does this choice match the one asked about? - size_t end = input.find_first_of(_(','), pos); - if (end == String::npos) end = input.size(); - // is this choice in choices - bool in_choices = false; - for (size_t i = 0 ; i < choices.size() ; ++i) { - if (!seen[i] && is_substr(input, pos, choices[i])) { - seen[i] = true; ++count; - in_choices = true; - break; - } + vector seen(choices.size()); // which choices have we seen in input? + // walk over the input + for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) { + // is this choice in choices + bool in_choices = false; + for (size_t i = 0 ; i < choices.size() ; ++i) { + if (!seen[i] && is_substr(input, start, choices[i])) { + seen[i] = true; ++count; + in_choices = true; + break; } - // is this choice unaffected? - if (!in_choices) { - if (!ret.empty()) ret += _(", "); - ret += input.substr(pos, end - pos); - } - pos = end + 1; + } + // is this choice unaffected? + if (!in_choices) { + if (!ret.empty()) ret += _(", "); + ret += input.substr(start, end - start); } } // keep more choices @@ -301,12 +298,23 @@ String filter_choices(const String& input, const vector& choices, int mi } // read 'choice#' arguments -void read_choices_param(Context& ctx, vector& choices) { - for (int i = 0 ; ; ++i) { - String name = _("choice"); if (i > 0) name = name << i; - SCRIPT_OPTIONAL_PARAM_N(String, name, choice) { - choices.push_back(choice); - } else if (i > 0) break; +void read_choices_param(Context& ctx, vector& choices_out) { + SCRIPT_OPTIONAL_PARAM_C(String,choices) { + for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) { + choices_out.push_back(choices.substr(start,end-start)); + } + } else { + // old style: separate arguments + SCRIPT_OPTIONAL_PARAM_C(String,choice) { + choices_out.push_back(choice); + } else { + for (int i = 1 ; ; ++i) { + String name = _("choice"); + SCRIPT_OPTIONAL_PARAM_N(String, name << i, choice) { + choices_out.push_back(choice); + } else break; + } + } } } @@ -345,6 +353,28 @@ SCRIPT_FUNCTION(remove_choice) { SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _(""))); } +// count how many choices are active +SCRIPT_FUNCTION(count_chosen) { + SCRIPT_PARAM_C(String,input); + SCRIPT_OPTIONAL_PARAM_C(String,choices) { + // only count specific choices + int count = 0; + for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) { + if (chosen(choices.substr(start,end-start),input)) ++count; + } + SCRIPT_RETURN(count); + } else { + // count all choices => count comma's + 1 + if (input.empty()) { + SCRIPT_RETURN(0); + } else { + int count = 1; + FOR_EACH(c, input) if (c == _(',')) ++count; + SCRIPT_RETURN(count); + } + } +} + // ----------------------------------------------------------------------------- : Init void init_script_editor_functions(Context& ctx) { @@ -352,6 +382,7 @@ void init_script_editor_functions(Context& ctx) { ctx.setVariable(_("combined editor"), script_combined_editor); ctx.setVariable(_("primary choice"), script_primary_choice); ctx.setVariable(_("chosen"), script_chosen); + ctx.setVariable(_("count chosen"), script_count_chosen); ctx.setVariable(_("require choice"), script_require_choice); ctx.setVariable(_("exclusive choice"), script_exclusive_choice); ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice); diff --git a/src/script/script.cpp b/src/script/script.cpp index 2becb44f..b44ca848 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -60,6 +60,7 @@ void init_script_variables() { Var(order); Var(filter); Var(choice); + Var(choices); Var(format); Var(tag); Var(contents); @@ -199,13 +200,14 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { case I_RGBA: ret += _("rgba"); break; } break; + case I_DUP: ret += _("dup"); break; } // arg switch (i.instr) { case I_PUSH_CONST: case I_MEMBER_C: // const ret += _("\t") + constants[i.data]->typeName(); break; - case I_JUMP: case I_JUMP_IF_NOT: case I_LOOP: case I_MAKE_OBJECT: case I_CALL: case I_CLOSURE: // int + case I_JUMP: case I_JUMP_IF_NOT: case I_LOOP: case I_MAKE_OBJECT: case I_CALL: case I_CLOSURE: case I_DUP: // int ret += String::Format(_("\t%d"), i.data); break; case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable @@ -232,7 +234,7 @@ const Instruction* Script::backtraceSkip(const Instruction* instr, int to_skip) // skip an instruction switch (instr->instr) { case I_PUSH_CONST: - case I_GET_VAR: + case I_GET_VAR: case I_DUP: to_skip -= 1; break; // nett stack effect +1 case I_BINARY: to_skip += 1; break; // nett stack effect 1-2 == -1 diff --git a/src/script/script.hpp b/src/script/script.hpp index d9068ae8..293eb7f4 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -41,6 +41,7 @@ enum InstructionType , I_BINARY = 12 ///< arg = 2ary instr : pop 2 values, apply a function, push the result , I_TERNARY = 13 ///< arg = 3ary instr : pop 3 values, apply a function, push the result , I_QUATERNARY = 14 ///< arg = 4ary instr : pop 4 values, apply a function, push the result +, I_DUP = 15 ///< arg = int : duplicate the k-from-top element of the stack }; /// Types of unary instructions (taking one argument from the stack) @@ -117,6 +118,7 @@ enum Variable , SCRIPT_VAR_order , SCRIPT_VAR_filter , SCRIPT_VAR_choice +, SCRIPT_VAR_choices , SCRIPT_VAR_format , SCRIPT_VAR_tag , SCRIPT_VAR_contents @@ -204,3 +206,4 @@ class Script : public ScriptValue { // ----------------------------------------------------------------------------- : EOF #endif + \ No newline at end of file diff --git a/tools/website/drupal/mse-drupal-modules/highlight.inc b/tools/website/drupal/mse-drupal-modules/highlight.inc index 2725b414..d8ea4ef3 100644 --- a/tools/website/drupal/mse-drupal-modules/highlight.inc +++ b/tools/website/drupal/mse-drupal-modules/highlight.inc @@ -52,6 +52,7 @@ $built_in_functions = array( 'combined_editor' =>'', 'primary_choice' =>'', 'chosen' =>'', + 'count_chosen' =>'', 'require_choice' =>'', 'exclusive_choice' =>'', 'require_exclusive_choice'=>'',