Skip to content

Commit

Permalink
new ops to execute script lines and execute scripts as functions (mon…
Browse files Browse the repository at this point in the history
…ome#313)

* execute script line and functions

* better naming for ops

* fix bug with es_pop

* help and docs
  • Loading branch information
scanner-darkly authored May 1, 2023
1 parent 69fa05e commit 4473f1d
Show file tree
Hide file tree
Showing 21 changed files with 483 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- **FIX**: improve `TR.P` accuracy
- **FIX**: fix `KILL` not stopping TR pulses in progress
- **NEW**: new op: `SCALE0` / `SCL0`
- **NEW**: new ops: `$F`, `$F1`, `$F2`, `$L`, `$L1`, `$L2`, `$S`, `$S1`, `$S2`, `I1`, `I2`, `FR`

## v4.0.0

Expand Down
150 changes: 150 additions & 0 deletions docs/ops/controlflow.toml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,156 @@ Get or set the trigger polarity of script `x`, determining which trigger edges t
3: either edge
"""

[$F]
prototype = "$F script"
short = "execute script as a function"
description = """
This op will execute a script similarly to `SCRIPT` op but it will also return a value,
which means you can define a script that calculates something and then use it in an expression.
To set the return value, either place an expression at the end of the script without
assigning it to anything or assign it to the special function return variable `FR`. If you do
both, `FR` will be used, and if you don't do either, zero will be returned.
Let's say you update script 1 to return the square of `X`: `* X X` (which you could also
write as `FR * X X`). Then you can use it in an expression like this: `A + A $F 1`.
This op can save space if you have a calculation that is used in multiple places.
Other than returning a value, a function script isn't different from a regular script
and can perform other actions in addition to calculating something, including calling
other scripts. The same limit of 8 maximum nested calls applies here to prevent infinite loops.
If you need to be able to pass parameters into your function, use `$F1` or `$F2` ops.
"""

[$F1]
prototype = "$F1 script param"
short = "execute script as a function with 1 parameter"
description = """
Same as `$F` but you can also pass a single parameter into the function. Inside the function
script you can get the parameter using `I1` op.
Let's say you create a script that returns the square of the passed parameter: `FR * I1 I1`.
You can then calculate the square of a number by executing `$F1 value`.
See the description of `$F` op for more details on executing scripts as functions.
"""

[$F2]
prototype = "$F2 script param1 param2"
short = "execute script as a function with 2 parameters"
description = """
Same as `$F` but you can also pass two parameters into a function. Inside the function script
you can get them using `I1` and `I2` ops.
Let's say you create a script that returns a randomly selected value out of the two
provided values: `FR ? TOSS I1 I2`. You can then save space by using `$F2 1 X Y` instead of
`? TOSS X Y`. More importantly, you could use it in multiple places, and if you later
want to change the calculation to something else, you just need to update the function script.
See the description of `$F` op for more details on executing scripts as functions.
"""

[$L]
prototype = "$L script line"
short = "execute script line"
description = """
This op executes the specified script line. This allows you to use a script as a library of sorts,
where each line does something different, so you can use the same script for multiple purposes.
It also allows you to use free lines in a script to extend another script.
This op behaves similarly to `$F` op in that it can be used as a function in an expression
by setting the return value with `FR`. Let's say the first line in script 1 is this: `FR * X X`.
You can then get the square of `X` by executing `$L 1 1`.
If you want to use it as a function and you need to pass some parameters into it, use
`$L1` / `$L2` ops.
This op is also useful if you have a loop that doesn't fit on one line - define the line
later in the script and then reference it in the loop:
```
#1
L 1 6: A + A $L 1 3
BREAK
SCALE X Y C D I
```
Don't forget to add `BREAK` before the line so that it's not executed when the whole script
is executed. If you use this technique, you can also save space by using `$S` op which executes
a line within the same script.
"""

[$L1]
prototype = "$L1 script line param"
short = "execute script line as a function with 1 parameter"
description = """
Execute the specified script line as a function that takes 1 parameter. See the description of
`$L` and `$F1` ops for more details.
"""

[$L2]
prototype = "$L2 script line param1 param2"
short = "execute script line as a function with 2 parameters"
description = """
Execute the specified script line as a function that takes 2 parameters. See the description of
`$L` and `$F2` ops for more details.
"""

[$S]
prototype = "$S line"
short = "execute script line within the same script as a function"
description = """
This is exactly the same as `$L $ line` but saves you space on not having to specify the script
number if the line you want to execute is within the same script.
See the description of `$L` for more details.
"""

[$S1]
prototype = "$S1 line param"
short = "execute script line within the same script as a function with 1 parameter"
description = """
This is exactly the same as `$L1 $ line param` but saves you space on not having to specify
the script number if the line you want to execute is within the same script.
See the description of `$L1` for more details.
"""

[$S2]
prototype = "$S2 line param1 param2"
short = "execute script line within the same script as a function with 2 parameters"
description = """
This is exactly the same as `$L2 $ line param1 param2` but saves you space on not having
to specify the script number if the line you want to execute is within the same script.
See the description of `$L2` for more details.
"""

[I1]
prototype = "I1"
short = "get the first parameter when executing a script as a function"
description = """
This op returns the first parameter when a script is called as a function using
`$F1` / `$F2` / `$L1` / `$L2` / `$S1` / `$S2` ops. If the script is called
using other ops, this op will return zero.
"""

[I2]
prototype = "I2"
short = "get the second parameter when executing a script as a function"
description = """
This op returns the second parameter when a script is called as a function using
`$F2` / `$L2` / `$S2` ops. If the script is called using other ops, this op will return zero.
"""

[FR]
prototype = "FR"
prototype_set = "FR x"
short = "get/set the return value when a script is called as a function"
description = """
Use this op to get or set the return value in a script that is called as a function.
"""

[SCENE]
prototype = "SCENE"
prototype_set = "SCENE x"
Expand Down
1 change: 1 addition & 0 deletions docs/whats_new.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- **FIX**: improve `TR.P` accuracy
- **FIX**: fix `KILL` not stopping TR pulses in progress
- **NEW**: new op: `SCALE0` / `SCL0`
- **NEW**: new ops: `$F`, `$F1`, `$F2`, `$L`, `$L1`, `$L2`, `$S`, `$S1`, `$S2`, `I1`, `I2`, `FR`

## v4.0.0

Expand Down
4 changes: 2 additions & 2 deletions module/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void flash_prepare() {
int confirm = 1;
uint32_t counter = 0;
int toggle = 0;
#define TIMEOUT 50000
#define TIMEOUT 100000
while (confirm == 1 && (++counter < TIMEOUT)) {
confirm = gpio_get_pin_value(NMI);
if ((counter % 1000) == 0) {
Expand Down Expand Up @@ -126,7 +126,7 @@ void flash_read(uint8_t preset_no, scene_state_t *scene,
SCENE_TEXT_LINES * SCENE_TEXT_CHARS);
// need to reset timestamps
uint32_t ticks = get_ticks();
for (size_t i = 0; i < TEMP_SCRIPT; i++)
for (size_t i = 0; i < TOTAL_SCRIPT_COUNT; i++)
scene->scripts[i].last_time = ticks;
scene->variables.time = 0;

Expand Down
14 changes: 13 additions & 1 deletion module/help_mode.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const char* help2[HELP2_LENGTH] = { "2/17 VARIABLES",
"PRINT X",
" GET/PRINT VALUE" };

#define HELP3_LENGTH 61
#define HELP3_LENGTH 73
const char* help3[HELP3_LENGTH] = { "3/17 PARAMETERS",
" ",
"TR A-D|SET TR VALUE (0,1)",
Expand Down Expand Up @@ -161,6 +161,18 @@ const char* help3[HELP3_LENGTH] = { "3/17 PARAMETERS",
"SCRIPT.POL",
" GET/SET ACTIVE SCRIPT EDGES",
" 1 RISING, 2 FALLING, 3 BOTH",
"$F RUN SCRIPT AS FUNCTION",
"$F1 -\"- WITH 1 PARAM",
"$F2 -\" WITH 2 PARAMS",
"$L RUN SCRIPT LINE",
"$L1 -\"- WITH 1 PARAM",
"$L2 -\"- WITH 2 PARAMS",
"$S RUN SELF'S LINE",
"$S1 -\"- WITH 1 PARAM",
"$S2 -\"- WITH 2 PARAMS",
"I1 GET 1ST PARAM",
"I2 GET 2ND PARAM",
"FR SET FUNCTION RETURN",
"SCENE|GET/SET SCENE #",
"SCENE.G|SET SCENE, EXCL GRID",
"SCENE.P|SET SCENE, EXCL PATTERN",
Expand Down
8 changes: 4 additions & 4 deletions module/live_mode.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,14 +354,14 @@ void execute_line() {
}
memcpy(&history[0], &command, sizeof(command));

ss_clear_script(&scene_state, TEMP_SCRIPT);
ss_overwrite_script_command(&scene_state, TEMP_SCRIPT, 0, &command);
ss_clear_script(&scene_state, LIVE_SCRIPT);
ss_overwrite_script_command(&scene_state, LIVE_SCRIPT, 0, &command);
exec_state_t es;
es_init(&es);
es_push(&es);
es_variables(&es)->script_number = TEMP_SCRIPT;
es_variables(&es)->script_number = LIVE_SCRIPT;

output = run_script_with_exec_state(&scene_state, &es, TEMP_SCRIPT);
output = run_script_with_exec_state(&scene_state, &es, LIVE_SCRIPT);
}

history_line = -1;
Expand Down
7 changes: 6 additions & 1 deletion module/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1204,11 +1204,16 @@ int main(void) {
if (is_flash_fresh()) {
char s[36];
strcpy(s, "SCENES WILL BE OVERWRITTEN!");
region_fill(&line[4], 0);
font_string_region_clip(&line[4], s, 0, 0, 0x4, 0);
region_draw(&line[4]);

strcpy(s, "PRESS ONLY IF YOU ARE");
region_fill(&line[5], 0);
font_string_region_clip(&line[5], s, 0, 0, 0x4, 0);
region_draw(&line[5]);

strcpy(s, "PRESS TO CONFIRM");
strcpy(s, "UPDATING FIRMWARE");
region_fill(&line[6], 0);
font_string_region_clip(&line[6], s, 0, 0, 0x4, 0);
region_draw(&line[6]);
Expand Down
14 changes: 13 additions & 1 deletion src/match_token.rl
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@
"<>" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_RIGHT_ANGLED); };
">=<" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED_EQUAL_LEFT_ANGLED); };
"<=>" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_EQUAL_RIGHT_ANGLED); };
"!" => { MATCH_OP(E_OP_SYM_EXCLAMATION); };
"!" => { MATCH_OP(E_OP_SYM_EXCLAMATION); };
"<<" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_x2); };
">>" => { MATCH_OP(E_OP_SYM_RIGHT_ANGLED_x2); };
"<<<" => { MATCH_OP(E_OP_SYM_LEFT_ANGLED_x3); };
Expand Down Expand Up @@ -320,6 +320,18 @@
"BREAK" => { MATCH_OP(E_OP_BREAK); };
"BRK" => { MATCH_OP(E_OP_BRK); };
"SYNC" => { MATCH_OP(E_OP_SYNC); };
"$F" => { MATCH_OP(E_OP_SYM_DOLLAR_F); };
"$F1" => { MATCH_OP(E_OP_SYM_DOLLAR_F1); };
"$F2" => { MATCH_OP(E_OP_SYM_DOLLAR_F2); };
"$L" => { MATCH_OP(E_OP_SYM_DOLLAR_L); };
"$L1" => { MATCH_OP(E_OP_SYM_DOLLAR_L1); };
"$L2" => { MATCH_OP(E_OP_SYM_DOLLAR_L2); };
"$S" => { MATCH_OP(E_OP_SYM_DOLLAR_S); };
"$S1" => { MATCH_OP(E_OP_SYM_DOLLAR_S1); };
"$S2" => { MATCH_OP(E_OP_SYM_DOLLAR_S2); };
"I1" => { MATCH_OP(E_OP_I1); };
"I2" => { MATCH_OP(E_OP_I2); };
"FR" => { MATCH_OP(E_OP_FR); };

# delay
"DEL.CLR" => { MATCH_OP(E_OP_DEL_CLR); };
Expand Down
Loading

0 comments on commit 4473f1d

Please sign in to comment.