Commit f6bc7498 authored by twanvl's avatar twanvl

Added count_chosen function;

Added I_DUP instruction
parent 7afe1ee1
...@@ -15,3 +15,6 @@ Is the given choice selected in the [[type:value#multiple_choice|multiple choice ...@@ -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", "blue") == false
> chosen(choice: "red", "red, blue") == true > chosen(choice: "red", "red, blue") == true
> chosen(choice: "blue", "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.
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?
...@@ -56,6 +56,7 @@ These functions are built into the program, other [[type:function]]s can be defi ...@@ -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:combined_editor]] Use one field to edit multiple others.
| [[fun:primary_choice]] Return the top level choice chosen from a choice field. | [[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: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: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: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. | [[fun:require_exclusive_choice]] Require that exactly one of the given choices is selected.
......
...@@ -10,18 +10,26 @@ If non of the choices is selected, selects the first one. ...@@ -10,18 +10,26 @@ If non of the choices is selected, selects the first one.
--Parameters-- --Parameters--
! Parameter Type Description ! Parameter Type Description
| @input@ [[type:string]] Multiple choice value to look update. | @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. | @choice1@ [[type:string]] Require multiple choices.
| @choice2@ [[type:string]] ''etc.'' | @choice2@ [[type:string]] ''etc.''
--Examples-- --Examples--
> require_choice(choice: "red", "red") == "red" > require_choice(choices: "red", "red") == "red"
> require_choice(choice: "red", "blue") == "blue, red" > require_choice(choices: "red", "blue") == "blue, red"
> require_choice(choice: "red", "red, blue") == "red, blue" > require_choice(choices: "red", "red, blue") == "red, blue"
> require_choice(choice1: "red", choice2: "green", "red, blue") == "red, blue" > require_choice(choices: "red,green", "red, blue") == "red, blue"
> require_choice(choice1: "red", choice2: "green", "red, green") == "red, blue" > require_choice(choices: "red,green", "red, green") == "red, blue"
> require_choice(choice1: "red", choice2: "green", "green, blue") == "green, blue" > require_choice(choices: "red,green", "green, blue") == "green, blue"
> require_choice(choice1: "red", choice2: "green", "black, blue") == "black, blue, red" > require_choice(choices: "red,green", "black, blue") == "black, blue, red"
--See also-- --See also--
| [[fun:exclusive_choice]] Require that ''at most one'' of the given choices is selected. | [[fun:exclusive_choice]] Require that ''at most one'' of the given choices is selected.
......
...@@ -3480,6 +3480,9 @@ ...@@ -3480,6 +3480,9 @@
<File <File
RelativePath="..\doc\function\copy_file.txt"> RelativePath="..\doc\function\copy_file.txt">
</File> </File>
<File
RelativePath="..\doc\function\count_chosen.txt">
</File>
<File <File
RelativePath="..\doc\function\crop.txt"> RelativePath="..\doc\function\crop.txt">
</File> </File>
......
...@@ -177,6 +177,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { ...@@ -177,6 +177,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
instrQuaternary(i.instr4, a, b, c, d); instrQuaternary(i.instr4, a, b, c, d);
break; break;
} }
// Duplicate stack
case I_DUP: {
stack.push_back(stack.at(stack.size() - i.data - 1));
break;
}
} }
} }
......
...@@ -325,6 +325,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) ...@@ -325,6 +325,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
a = dependency_dummy; a = dependency_dummy;
break; break;
} }
// Duplicate stack
case I_DUP: {
stack.push_back(stack.at(stack.size() - i.data - 1));
break;
}
} }
} }
......
...@@ -203,20 +203,24 @@ SCRIPT_FUNCTION(primary_choice) { ...@@ -203,20 +203,24 @@ SCRIPT_FUNCTION(primary_choice) {
// ----------------------------------------------------------------------------- : Multiple choice values // ----------------------------------------------------------------------------- : 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? /// Is the given choice active?
bool chosen(const String& choice, const String& input) { bool chosen(const String& choice, const String& input) {
for (size_t pos = 0 ; pos < input.size() ; ) { for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end+1 ) {
if (input.GetChar(pos) == _(' ')) {
++pos; // ingore whitespace
} else {
// does this choice match the one asked about? // does this choice match the one asked about?
size_t end = input.find_first_of(_(','), pos); if (end - start == choice.size() && is_substr(input, start, choice)) {
if (end == String::npos) end = input.size();
if (end - pos == choice.size() && is_substr(input, pos, choice)) {
return true; return true;
} }
pos = end + 1;
}
} }
return false; return false;
} }
...@@ -236,18 +240,13 @@ String filter_choices(const String& input, const vector<String>& choices, int mi ...@@ -236,18 +240,13 @@ String filter_choices(const String& input, const vector<String>& choices, int mi
if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure if (choices.empty()) return input; // do nothing, shouldn't happen, but better make sure
String ret; String ret;
int count = 0; int count = 0;
vector<bool> seen(choices.size()); // which choices have we seen? vector<bool> seen(choices.size()); // which choices have we seen in input?
for (size_t pos = 0 ; pos < input.size() ; ) { // walk over the input
if (input.GetChar(pos) == _(' ')) { for (size_t start = 0, end = 0 ; next_choice(start,end,input) ; start = end +1) {
++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 // is this choice in choices
bool in_choices = false; bool in_choices = false;
for (size_t i = 0 ; i < choices.size() ; ++i) { for (size_t i = 0 ; i < choices.size() ; ++i) {
if (!seen[i] && is_substr(input, pos, choices[i])) { if (!seen[i] && is_substr(input, start, choices[i])) {
seen[i] = true; ++count; seen[i] = true; ++count;
in_choices = true; in_choices = true;
break; break;
...@@ -256,9 +255,7 @@ String filter_choices(const String& input, const vector<String>& choices, int mi ...@@ -256,9 +255,7 @@ String filter_choices(const String& input, const vector<String>& choices, int mi
// is this choice unaffected? // is this choice unaffected?
if (!in_choices) { if (!in_choices) {
if (!ret.empty()) ret += _(", "); if (!ret.empty()) ret += _(", ");
ret += input.substr(pos, end - pos); ret += input.substr(start, end - start);
}
pos = end + 1;
} }
} }
// keep more choices // keep more choices
...@@ -301,12 +298,23 @@ String filter_choices(const String& input, const vector<String>& choices, int mi ...@@ -301,12 +298,23 @@ String filter_choices(const String& input, const vector<String>& choices, int mi
} }
// read 'choice#' arguments // read 'choice#' arguments
void read_choices_param(Context& ctx, vector<String>& choices) { void read_choices_param(Context& ctx, vector<String>& choices_out) {
for (int i = 0 ; ; ++i) { SCRIPT_OPTIONAL_PARAM_C(String,choices) {
String name = _("choice"); if (i > 0) name = name << i; for (size_t start = 0, end = 0 ; next_choice(start,end,choices) ; start = end + 1) {
SCRIPT_OPTIONAL_PARAM_N(String, name, choice) { choices_out.push_back(choices.substr(start,end-start));
choices.push_back(choice); }
} else if (i > 0) break; } 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) { ...@@ -345,6 +353,28 @@ SCRIPT_FUNCTION(remove_choice) {
SCRIPT_RETURN(filter_choices(input, choices, 0, 0, _(""))); 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 // ----------------------------------------------------------------------------- : Init
void init_script_editor_functions(Context& ctx) { void init_script_editor_functions(Context& ctx) {
...@@ -352,6 +382,7 @@ 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(_("combined editor"), script_combined_editor);
ctx.setVariable(_("primary choice"), script_primary_choice); ctx.setVariable(_("primary choice"), script_primary_choice);
ctx.setVariable(_("chosen"), script_chosen); ctx.setVariable(_("chosen"), script_chosen);
ctx.setVariable(_("count chosen"), script_count_chosen);
ctx.setVariable(_("require choice"), script_require_choice); ctx.setVariable(_("require choice"), script_require_choice);
ctx.setVariable(_("exclusive choice"), script_exclusive_choice); ctx.setVariable(_("exclusive choice"), script_exclusive_choice);
ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice); ctx.setVariable(_("require exclusive choice"), script_require_exclusive_choice);
......
...@@ -60,6 +60,7 @@ void init_script_variables() { ...@@ -60,6 +60,7 @@ void init_script_variables() {
Var(order); Var(order);
Var(filter); Var(filter);
Var(choice); Var(choice);
Var(choices);
Var(format); Var(format);
Var(tag); Var(tag);
Var(contents); Var(contents);
...@@ -199,13 +200,14 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { ...@@ -199,13 +200,14 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
case I_RGBA: ret += _("rgba"); break; case I_RGBA: ret += _("rgba"); break;
} }
break; break;
case I_DUP: ret += _("dup"); break;
} }
// arg // arg
switch (i.instr) { switch (i.instr) {
case I_PUSH_CONST: case I_MEMBER_C: // const case I_PUSH_CONST: case I_MEMBER_C: // const
ret += _("\t") + constants[i.data]->typeName(); ret += _("\t") + constants[i.data]->typeName();
break; 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); ret += String::Format(_("\t%d"), i.data);
break; break;
case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable 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) ...@@ -232,7 +234,7 @@ const Instruction* Script::backtraceSkip(const Instruction* instr, int to_skip)
// skip an instruction // skip an instruction
switch (instr->instr) { switch (instr->instr) {
case I_PUSH_CONST: case I_PUSH_CONST:
case I_GET_VAR: case I_GET_VAR: case I_DUP:
to_skip -= 1; break; // nett stack effect +1 to_skip -= 1; break; // nett stack effect +1
case I_BINARY: case I_BINARY:
to_skip += 1; break; // nett stack effect 1-2 == -1 to_skip += 1; break; // nett stack effect 1-2 == -1
......
No preview for this file type
...@@ -52,6 +52,7 @@ $built_in_functions = array( ...@@ -52,6 +52,7 @@ $built_in_functions = array(
'combined_editor' =>'', 'combined_editor' =>'',
'primary_choice' =>'', 'primary_choice' =>'',
'chosen' =>'', 'chosen' =>'',
'count_chosen' =>'',
'require_choice' =>'', 'require_choice' =>'',
'exclusive_choice' =>'', 'exclusive_choice' =>'',
'require_exclusive_choice'=>'', 'require_exclusive_choice'=>'',
......
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