rhaiscript / rhai

Rhai - An embedded scripting language for Rust.
https://crates.io/crates/rhai
Apache License 2.0
3.73k stars 175 forks source link

Is it possible to use "goto" in rhai? #569

Closed youngzhaozju closed 2 years ago

youngzhaozju commented 2 years ago

Hey, I found the "goto" is a reserved keyword in rhai. https://rhai.rs/book/appendix/keywords.html?highlight=goto#reserved-keywords So, is it possible to utilize it? I cannot find any example to handle goto logic. Thank you! Regards, Yang

schungx commented 2 years ago

It is reserved but not used at the moment...

Any particular reason you need goto? Usually you can simulate it with exceptions.

youngzhaozju commented 2 years ago

It is reserved but not used at the moment...

Any particular reason you need goto? Usually you can simulate it with exceptions.

Thank you for your kind reply!

I plan to develop a flow-chart-based programming tool based on rhai. Here is an example of the flow chart, https://www.edrawsoft.com/lunch-sunday-flowchart-example.html

I want to generate rhai script code based on the flow chart, and then run the logic using rhai. If the "goto" is available in rhai, the logic "Enjoy your lunch" in the flow chart will be very easy. Without the goto, I cannot find anyother way to do so. Yes, it is possible to make "Enjoy your lunch" to be a function. But, for the purpose of universality, It is better to utilize "goto". For intance, "Enjoy your lunch" can connect to any other flow chart item, which will be very complex without the help of "goto".

Best regards, Yang

schungx commented 2 years ago

Well, you always have to be careful where you're jumping to via goto. For example, obviously you can jump back into a parent scope up the chain, but it would be difficult to jump into a separate inner scope without going through the chain of statements leading to that scope.

Now according to your lunch example, Enjoy your lunch needs to escape out of any scope it is in. That is the perfect case to throw a custom exception (which gets you out of any scope), or a simple return statement (which also gets you out of any functional scope).

Of course, to use return the statement must be inside a function; if you don't have a function, then you can use throw to throw a custom exception, that you can catch on the outside.

In fact, a goto that escapes a scope has the same implementation as catching an exception. A goto that jumps within the current scope is a jump statement, and a jump statement you can always simulate by wrapping the parent statements within a block scope and then jumping out of that. So, in other words, goto is nothing but exception + catching.

schungx commented 2 years ago

More illustration ,using your flow chart as an example.

I suppose you're compiling each decision block in the chart as an if statement, which turns the chart into a structured nested block of statements.

If Enjoy your lunch breaks out of the entire thing, then you can simply wrap the whole code inside a try block and then throw a custom exception, finally catch it.

If you want to link two blocks, say, from Anything you want to eat back to Find a restaurant, then you have created a loop, and it must be compiled into Rhai as a loop.

If you want to link two blocks that are in separate branches, say, from Order take out to Find a restaurant, then you're in trouble, because you are jumping from one inner scope to another inner scope without going through the parent.

Obviously, one solution is to compile the whole thing into a state machine, looping and switch-ing on the state. Then you can do anything you want with the graph.

youngzhaozju commented 2 years ago

More illustration ,using your flow chart as an example.

I suppose you're compiling each decision block in the chart as an if statement, which turns the chart into a structured nested block of statements.

If Enjoy your lunch breaks out of the entire thing, then you can simply wrap the whole code inside a try block and then throw a custom exception, finally catch it.

If you want to link two blocks, say, from Anything you want to eat back to Find a restaurant, then you have created a loop, and it must be compiled into Rhai as a loop.

If you want to link two blocks that are in separate branches, say, from Order take out to Find a restaurant, then you're in trouble, because you are jumping from one inner scope to another inner scope without going through the parent.

Obviously, one solution is to compile the whole thing into a state machine, looping and switch-ing on the state. Then you can do anything you want with the graph.

Hey schungx, Thanks so much for your kind reply! You inspired me a lot. I am trying to think about state machine and work flow engine instead of goto. Thank you again! Best regards, Yang

schungx commented 2 years ago

Thanks so much for your kind reply! You inspired me a lot. I am trying to think about state machine and work flow engine instead of goto. Thank you again!

A state machine is perfect for encoding a flow graph because that's what a state machine is defined as: a number of states (blocks) with transitions (arrows) based on decisions.

You don't really need Rhai to run your flow chart (unless of course you need scripting for individual blocks). You only need a simple states transition table and the machine should run itself. It is dead simple to compile.