From 0f803a2c7f732d7634ee9c8f38f27a653e8f8f1a Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Fri, 12 Dec 2025 16:26:58 -0300 Subject: [PATCH] docs: Add GOTO keyword documentation with migration guidance to ON patterns --- src/06-gbdialog/keyword-goto.md | 275 ++++++++++++++++++++++++++++++++ src/06-gbdialog/keywords.md | 1 + 2 files changed, 276 insertions(+) create mode 100644 src/06-gbdialog/keyword-goto.md diff --git a/src/06-gbdialog/keyword-goto.md b/src/06-gbdialog/keyword-goto.md new file mode 100644 index 00000000..b292086f --- /dev/null +++ b/src/06-gbdialog/keyword-goto.md @@ -0,0 +1,275 @@ +# GOTO Keyword + +> ⚠️ **WARNING: GOTO is supported but NOT RECOMMENDED** +> +> While GOTO works for backward compatibility, you should use **event-driven patterns with the ON keyword** instead. GOTO makes code harder to maintain and debug. + +## Syntax + +```basic +label: + ' statements +GOTO label + +IF condition THEN GOTO label +``` + +## Description + +`GOTO` transfers program execution to a labeled line. Labels are identifiers followed by a colon (`:`) at the start of a line. + +**This keyword exists for backward compatibility only.** Modern General Bots code should use: + +- `ON INSERT/UPDATE/DELETE OF` for event-driven programming +- `WHILE ... WEND` for loops +- `FOR EACH ... NEXT` for iteration +- `SUB` / `FUNCTION` for code organization + +--- + +## ❌ OLD WAY vs ✅ NEW WAY + +### Polling Loop (Don't Do This) + +```basic +' ❌ BAD: GOTO-based polling loop +mainLoop: + leads = FIND "leads", "processed = false" + FOR EACH lead IN leads + CALL processLead(lead) + NEXT lead + WAIT 5 +GOTO mainLoop +``` + +### Event-Driven (Do This Instead) + +```basic +' ✅ GOOD: Event-driven with ON keyword +ON INSERT OF "leads" + lead = GET LAST "leads" + + score = SCORE LEAD lead + + IF score.status = "hot" THEN + TALK TO "whatsapp:" + sales_phone, "🔥 Hot lead: " + lead.name + END IF +END ON +``` + +--- + +## Why ON is Better Than GOTO + +| Aspect | GOTO Loop | ON Event | +|--------|-----------|----------| +| **Efficiency** | Polls constantly, wastes CPU | Triggers only when data changes | +| **Code clarity** | Spaghetti code, hard to follow | Clear cause-and-effect | +| **Resource usage** | Always running | Idle until triggered | +| **Scalability** | Degrades with more data | Handles scale naturally | +| **Debugging** | Hard to trace execution | Clear event flow | +| **LLM integration** | Poor | Works well with TOOLs | + +--- + +## If You Must Use GOTO + +For legacy code migration or specific use cases, GOTO is supported: + +### Simple Loop + +```basic +counter: + TALK "Count: " + x + x = x + 1 + IF x < 5 THEN GOTO counter + TALK "Done!" +``` + +### Multiple Labels + +```basic +start: + TALK "Starting..." + GOTO process + +error: + TALK "An error occurred" + GOTO cleanup + +process: + result = DO_SOMETHING + IF result = "error" THEN GOTO error + TALK "Success!" + GOTO cleanup + +cleanup: + TALK "Cleaning up..." +``` + +### Conditional GOTO + +```basic +check: + IF temperature > 30 THEN GOTO too_hot + IF temperature < 10 THEN GOTO too_cold + TALK "Temperature is comfortable" + GOTO done + +too_hot: + TALK "Warning: Too hot!" + GPIO SET fan_pin, HIGH + GOTO done + +too_cold: + TALK "Warning: Too cold!" + GPIO SET heater_pin, HIGH + GOTO done + +done: + TALK "Check complete" +``` + +--- + +## How GOTO Works Internally + +GOTO is **not native to the Rhai engine**. General Bots transforms GOTO-based code into a state machine: + +```basic +' Your code: +loop: + x = x + 1 + IF x < 3 THEN GOTO loop + TALK "Done" +``` + +```basic +' Transformed internally to: +let __goto_label = "loop" +while __goto_label != "__exit" { + if __goto_label == "loop" { + x = x + 1 + if x < 3 { __goto_label = "loop"; continue; } + TALK "Done" + __goto_label = "__exit" + } +} +``` + +This transformation: +- Adds overhead compared to native loops +- Has a safety limit of 1,000,000 iterations to prevent infinite loops +- Emits warnings in the server logs recommending ON patterns + +--- + +## Limitations + +| Limitation | Description | +|------------|-------------| +| **No computed GOTO** | `GOTO variable` is not supported | +| **No GOSUB** | Use `SUB` / `CALL` instead | +| **No line numbers** | Only named labels are supported | +| **Performance** | Slower than native WHILE loops | +| **Iteration limit** | Maximum 1,000,000 iterations per GOTO loop | + +--- + +## Migration Guide + +### From GOTO Loop to WHILE + +```basic +' Before (GOTO): +start: + TALK "Hello" + x = x + 1 + IF x < 10 THEN GOTO start + +' After (WHILE): +WHILE x < 10 + TALK "Hello" + x = x + 1 +WEND +``` + +### From GOTO Loop to ON Event + +```basic +' Before (GOTO polling): +checkOrders: + orders = FIND "orders", "status = 'new'" + FOR EACH order IN orders + CALL processOrder(order) + NEXT order + WAIT 10 +GOTO checkOrders + +' After (ON event): +ON INSERT OF "orders" + order = GET LAST "orders" + IF order.status = "new" THEN + CALL processOrder(order) + END IF +END ON +``` + +### From GOTO Error Handling to ON ERROR + +```basic +' Before (GOTO): + result = RISKY_OPERATION + IF result = "error" THEN GOTO handleError + TALK "Success" + GOTO done +handleError: + TALK "Failed!" +done: + +' After (ON ERROR): +ON ERROR RESUME NEXT + result = RISKY_OPERATION + IF ERROR THEN + TALK "Failed!" + ELSE + TALK "Success" + END IF +ON ERROR GOTO 0 +``` + +--- + +## Best Practices + +1. **Don't use GOTO for new code** - Use WHILE, FOR EACH, ON, or SUB/FUNCTION +2. **Migrate existing GOTO code** - Refactor to event-driven patterns when possible +3. **If you must use GOTO** - Keep it simple, avoid deep nesting +4. **Add comments** - Explain why GOTO is necessary +5. **Set reasonable limits** - Don't rely on the 1M iteration safety limit + +--- + +## See Also + +- [ON Keyword](./keyword-on.md) - **Recommended**: Event-driven programming +- [WHILE ... WEND](./keyword-while.md) - Loop construct +- [FOR EACH ... NEXT](./keyword-for-each.md) - Iteration +- [SUB / FUNCTION](./keyword-sub.md) - Code organization +- [ON ERROR](./keyword-on-error.md) - Error handling + +--- + +## Summary + +| Use Case | Instead of GOTO, Use | +|----------|---------------------| +| Polling for changes | `ON INSERT/UPDATE/DELETE OF` | +| Repeating code | `WHILE ... WEND` | +| Iterating collections | `FOR EACH ... NEXT` | +| Reusable code blocks | `SUB` / `FUNCTION` + `CALL` | +| Error handling | `ON ERROR RESUME NEXT` | +| Conditional branching | `IF ... ELSEIF ... ELSE ... END IF` | +| Multiple conditions | `SWITCH ... CASE ... END SWITCH` | + +**The ON keyword is the future. GOTO is the past.** \ No newline at end of file diff --git a/src/06-gbdialog/keywords.md b/src/06-gbdialog/keywords.md index 480ba0f5..c4f75fda 100644 --- a/src/06-gbdialog/keywords.md +++ b/src/06-gbdialog/keywords.md @@ -84,6 +84,7 @@ See [Script Execution Flow](./script-execution-flow.md) for complete details. | `FORMAT` | Data | Format strings and dates | | `GENERATE PDF` | Files | Generate PDF from template | | `GET` | Variables | Get variable or API data | +| `GOTO` | Control | Jump to label (⚠️ use ON instead) | | `GET BOT MEMORY` | Memory | Retrieve bot-level persisted data | | `GET USER MEMORY` | Memory | Retrieve user-level persisted data (cross-bot) | | `GRAPHQL` | HTTP | Execute GraphQL query |