From a0a034ae792989910e93480dde9804950fdd3da7 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Thu, 29 Oct 2026 20:54:06 +0800 Subject: [PATCH 1/2] fix(compiler): preserve trailing comparisons under aggressive size optimization Restrict the tail Skip If rewrite to negated conditions so comparison conditions retain the pinned OverPy canonical control-flow structure. Replace text-based expectations with an oracle-backed differential fixture covering default directives, aggressive alone, combined directives, and preserved negation lowering. Fixes #671 --- crates/opy-rs/src/compiler/lowering/rules.rs | 43 ++++++------------- .../opy-rs/src/compiler/tests/control_flow.rs | 29 +------------ .../fixture.json | 25 +++++++++++ .../oracle.json | 34 +++++++++++++++ .../source.opy | 25 +++++++++++ 5 files changed, 99 insertions(+), 57 deletions(-) create mode 100644 crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/fixture.json create mode 100644 crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json create mode 100644 crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy diff --git a/crates/opy-rs/src/compiler/lowering/rules.rs b/crates/opy-rs/src/compiler/lowering/rules.rs index 2a8b4248..6911166b 100644 --- a/crates/opy-rs/src/compiler/lowering/rules.rs +++ b/crates/opy-rs/src/compiler/lowering/rules.rs @@ -456,37 +456,20 @@ impl<'a> Lowering<'a> { .. } = statement && branches.len() == 1 + && let Expr::Unary { op, operand, .. } = &*branches[0].condition + && op == "not" + && !branches[0].body.is_empty() { - let branch = &branches[0]; - let is_not_condition = matches!( - &*branch.condition, - Expr::Unary { op, .. } if op == "not" - ); - let is_comparison = matches!( - &*branch.condition, - Expr::Binary { op, .. } - if matches!(op.as_str(), "==" | "!=" | "<" | "<=" | ">" | ">=") - ); - if (is_not_condition || is_comparison) && !branch.body.is_empty() { - let body = self.lower_actions(&branch.body, break_target)?; - if !body.is_empty() && (is_not_condition || branch.body.len() == 1) { - let condition = if is_not_condition { - let Expr::Unary { operand, .. } = &*branch.condition else { - unreachable!() - }; - self.lower_value(operand)? - } else { - let condition = self.lower_value(&branch.condition)?; - self.push_call("not", vec![condition]) - }; - let distance = self.canonical_action_width(&body, *span)?; - let distance = self.push_number(distance as f64); - let skip = self.push_call_action("skipIf", &[condition, distance]); - self.mark_action_origins(std::slice::from_ref(&skip), *span); - actions.push(skip); - actions.extend(body); - continue; - } + let body = self.lower_actions(&branches[0].body, break_target)?; + if !body.is_empty() { + let condition = self.lower_value(operand)?; + let distance = self.canonical_action_width(&body, *span)?; + let distance = self.push_number(distance as f64); + let skip = self.push_call_action("skipIf", &[condition, distance]); + self.mark_action_origins(std::slice::from_ref(&skip), *span); + actions.push(skip); + actions.extend(body); + continue; } } if self.lower_conditional_label_jump(statement, &mut actions)? { diff --git a/crates/opy-rs/src/compiler/tests/control_flow.rs b/crates/opy-rs/src/compiler/tests/control_flow.rs index 7fcb87cb..9b1e1ed4 100644 --- a/crates/opy-rs/src/compiler/tests/control_flow.rs +++ b/crates/opy-rs/src/compiler/tests/control_flow.rs @@ -119,33 +119,8 @@ fn control_flow_debug_lowers_to_a_native_hud_action() { } #[test] -fn aggressive_size_optimization_lowers_a_tail_comparison_to_skip_if() { - let source = "#!optimizeForSize\n#!optimizeForSizeAggressive\nglobalvar g\nrule \"r\":\n @Event global\n if g == 1:\n g = 2\n"; - let hir = crate::compile(source, "source.opy", Path::new(".")).unwrap(); - let artifact = Compiler::new().unwrap().compile_hir(&hir).unwrap(); - - assert!( - artifact - .emitted - .contains("Skip If(Not(Compare(Global.g, ==, 1)), True);") - ); - assert!(!artifact.emitted.contains("If(Compare(Global.g, ==, 1));")); -} - -#[test] -fn aggressive_size_optimization_respects_directive_boundaries() { - let source = "globalvar g\nrule \"before\":\n @Event global\n if g == 1:\n g = 2\n#!optimizeForSize\n#!optimizeForSizeAggressive\nrule \"after\":\n @Event global\n if g == 1:\n g = 2\n#!disableOptimizations\nrule \"disabled\":\n @Event global\n if g == 1:\n g = 2\n"; - let hir = crate::compile(source, "source.opy", Path::new(".")).unwrap(); - let artifact = Compiler::new().unwrap().compile_hir(&hir).unwrap(); - - assert_eq!(artifact.emitted.matches("Skip If(").count(), 1); - assert_eq!( - artifact - .emitted - .matches("If(Compare(Global.g, ==, 1));") - .count(), - 2 - ); +fn aggressive_size_control_flow_matches_the_pinned_oracle() { + assert_native_wir_equivalent("structural-size-aggressive-control-flow"); } #[test] diff --git a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/fixture.json b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/fixture.json new file mode 100644 index 00000000..9cda6458 --- /dev/null +++ b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/fixture.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "id": "synthetic/structural-size-aggressive-control-flow", + "category": "compilation", + "features": [ + "structural convergence", + "control flow", + "optimizeForSize", + "optimizeForSizeAggressive" + ], + "source": "source.opy", + "tests": { + "source": { + "nativeStatus": "success", + "relationship": "match", + "ruleNames": true + }, + "compiler": { + "nativeStatus": "success", + "relationship": "match", + "comparison": "semantic-wir", + "semanticEquivalent": true + } + } +} diff --git a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json new file mode 100644 index 00000000..a224ee78 --- /dev/null +++ b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json @@ -0,0 +1,34 @@ +{ + "compile": { + "diagnostics": [], + "exitCode": 0, + "status": "success", + "stdout": "", + "workshop": "variables {\n global:\n 0: g\n}\n\nrule (\"default comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"aggressive alone comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\n//Optimize for size enabled\nrule (\"tail comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negation\") {\n event {\n Ongoing - Global;\n }\n actions {\n Skip If(Global.g, True);\n Set Global Variable(g, 2);\n //__label_if_2__:\n }\n}\n", + "workshopExact": "variables {\n global:\n 0: g\n}\n\nrule (\"default comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"aggressive alone comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\n//Optimize for size enabled\nrule (\"tail comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negation\") {\n event {\n Ongoing - Global;\n }\n actions {\n Skip If(Global.g, True);\n Set Global Variable(g, 2);\n //__label_if_2__:\n }\n}\n\n", + "workshopSha256": "64f20f75c61267f73da65b180c8bafed761e015f3eb60a1ff9f3164526b1f736" + }, + "fixture": "synthetic/structural-size-aggressive-control-flow", + "input": { + "files": [ + { + "path": "source.opy", + "sha256": "067d3ff4b9f13149551b07a309061d2ad5c6ade9662ee98cb3b93924012a4b87" + } + ], + "sha256": "a899f77bfc8812c0f598ac4153db42fa23443e1af4bc02ef0e8f0bb79b5949a9", + "source": "source.opy" + }, + "oracle": { + "contentCommit": "5a7d0e294b8cad73b9701987bb584d0551d7fa4d", + "gitHead": "ec763c1d245aa5485ef61af5b2bda4975bce4877", + "integrity": "sha512-C5F6btT5yn19BvHuE0bjMuSd/2esebBabmpL4SYLQFuJ4IdouVOKEoMLLuJFAyNc0Phwrolblj5GDkDGYR0ofg==", + "language": "en-US", + "license": "GPL-3.0-only", + "name": "overpy", + "registryTarball": "https://registry.npmjs.org/overpy/-/overpy-9.7.17.tgz", + "repository": "https://github.com/Zezombye/overpy", + "version": "9.7.17" + }, + "schemaVersion": 1 +} diff --git a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy new file mode 100644 index 00000000..116ba01b --- /dev/null +++ b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy @@ -0,0 +1,25 @@ +globalvar g + +rule "default comparison": + @Event global + if g == 1: + g = 2 + +#!optimizeForSizeAggressive + +rule "aggressive alone comparison": + @Event global + if g == 1: + g = 2 + +#!optimizeForSize + +rule "tail comparison": + @Event global + if g == 1: + g = 2 + +rule "tail negation": + @Event global + if not g: + g = 2 From d750d71c7ebb15875dbf801cc22a05e22d0802f1 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Thu, 29 Oct 2026 21:45:23 +0800 Subject: [PATCH 2/2] fix: preserve normalized tail comparisons under aggressive size optimization (#671) --- crates/opy-rs/src/compiler/lowering/rules.rs | 6 +- .../compiler/lowering/rules/tail_negation.rs | 19 ++++++ .../oracle.json | 10 ++-- .../source.opy | 60 +++++++++++++++++++ 4 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 crates/opy-rs/src/compiler/lowering/rules/tail_negation.rs diff --git a/crates/opy-rs/src/compiler/lowering/rules.rs b/crates/opy-rs/src/compiler/lowering/rules.rs index 6911166b..1c0b7fa8 100644 --- a/crates/opy-rs/src/compiler/lowering/rules.rs +++ b/crates/opy-rs/src/compiler/lowering/rules.rs @@ -1,6 +1,8 @@ use super::*; use crate::enums; +mod tail_negation; + impl<'a> Lowering<'a> { pub(in crate::compiler) fn lower_rules(&mut self) -> Result<(), IntegrationError> { for entry in &self.hir.rules { @@ -456,9 +458,7 @@ impl<'a> Lowering<'a> { .. } = statement && branches.len() == 1 - && let Expr::Unary { op, operand, .. } = &*branches[0].condition - && op == "not" - && !branches[0].body.is_empty() + && let Some(operand) = tail_negation::operand(self, &branches[0].condition)? { let body = self.lower_actions(&branches[0].body, break_target)?; if !body.is_empty() { diff --git a/crates/opy-rs/src/compiler/lowering/rules/tail_negation.rs b/crates/opy-rs/src/compiler/lowering/rules/tail_negation.rs new file mode 100644 index 00000000..b62bff48 --- /dev/null +++ b/crates/opy-rs/src/compiler/lowering/rules/tail_negation.rs @@ -0,0 +1,19 @@ +use super::*; + +pub(super) fn operand<'expr>( + lowering: &mut Lowering<'_>, + condition: &'expr Expr, +) -> Result, IntegrationError> { + let Expr::Unary { op, operand, .. } = condition else { + return Ok(None); + }; + if op != "not" { + return Ok(None); + } + let condition = lowering.lower_value(condition)?; + Ok(matches!( + lowering.materialize_value(condition), + workshop_rs::Value::Call { name, .. } if name == "not" + ) + .then_some(operand.as_ref())) +} diff --git a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json index a224ee78..dff271b5 100644 --- a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json +++ b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/oracle.json @@ -4,19 +4,19 @@ "exitCode": 0, "status": "success", "stdout": "", - "workshop": "variables {\n global:\n 0: g\n}\n\nrule (\"default comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"aggressive alone comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\n//Optimize for size enabled\nrule (\"tail comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negation\") {\n event {\n Ongoing - Global;\n }\n actions {\n Skip If(Global.g, True);\n Set Global Variable(g, 2);\n //__label_if_2__:\n }\n}\n", - "workshopExact": "variables {\n global:\n 0: g\n}\n\nrule (\"default comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"aggressive alone comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\n//Optimize for size enabled\nrule (\"tail comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negation\") {\n event {\n Ongoing - Global;\n }\n actions {\n Skip If(Global.g, True);\n Set Global Variable(g, 2);\n //__label_if_2__:\n }\n}\n\n", - "workshopSha256": "64f20f75c61267f73da65b180c8bafed761e015f3eb60a1ff9f3164526b1f736" + "workshop": "variables {\n global:\n 0: g\n}\n\nrule (\"default comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"aggressive alone comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\n//Optimize for size enabled\nrule (\"tail comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negation\") {\n event {\n Ongoing - Global;\n }\n actions {\n Skip If(Global.g, True);\n Set Global Variable(g, 2);\n //__label_if_2__:\n }\n}\n\nrule (\"tail negated equality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, !=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated inequality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated less than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated less than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated greater than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated greater than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated equality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated inequality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, !=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated less than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated less than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated greater than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated greater than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >=, 1));\n Set Global Variable(g, 2);\n }\n}\n", + "workshopExact": "variables {\n global:\n 0: g\n}\n\nrule (\"default comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"aggressive alone comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\n//Optimize for size enabled\nrule (\"tail comparison\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negation\") {\n event {\n Ongoing - Global;\n }\n actions {\n Skip If(Global.g, True);\n Set Global Variable(g, 2);\n //__label_if_2__:\n }\n}\n\nrule (\"tail negated equality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, !=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated inequality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated less than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated less than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated greater than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail negated greater than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated equality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, ==, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated inequality\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, !=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated less than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated less than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, <=, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated greater than\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >, 1));\n Set Global Variable(g, 2);\n }\n}\n\nrule (\"tail double negated greater than or equal\") {\n event {\n Ongoing - Global;\n }\n actions {\n If(Compare(Global.g, >=, 1));\n Set Global Variable(g, 2);\n }\n}\n\n", + "workshopSha256": "31be06ac043a30f8ac3b00ac5df598ca7477c89ff06453d880727d2dec45bc56" }, "fixture": "synthetic/structural-size-aggressive-control-flow", "input": { "files": [ { "path": "source.opy", - "sha256": "067d3ff4b9f13149551b07a309061d2ad5c6ade9662ee98cb3b93924012a4b87" + "sha256": "df747c12bdc3e40e4536ada503116ee01db93126c374fb4a13f522e70ac4a638" } ], - "sha256": "a899f77bfc8812c0f598ac4153db42fa23443e1af4bc02ef0e8f0bb79b5949a9", + "sha256": "bdac5cd906b8da4a24f36ec794f7bdd0dd279a4a967fc410a806185b3c18efd6", "source": "source.opy" }, "oracle": { diff --git a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy index 116ba01b..e44f4b52 100644 --- a/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy +++ b/crates/opy-rs/tests/fixtures/corpus/synthetic/structural-size-aggressive-control-flow/source.opy @@ -23,3 +23,63 @@ rule "tail negation": @Event global if not g: g = 2 + +rule "tail negated equality": + @Event global + if not (g == 1): + g = 2 + +rule "tail negated inequality": + @Event global + if not (g != 1): + g = 2 + +rule "tail negated less than": + @Event global + if not (g < 1): + g = 2 + +rule "tail negated less than or equal": + @Event global + if not (g <= 1): + g = 2 + +rule "tail negated greater than": + @Event global + if not (g > 1): + g = 2 + +rule "tail negated greater than or equal": + @Event global + if not (g >= 1): + g = 2 + +rule "tail double negated equality": + @Event global + if not not (g == 1): + g = 2 + +rule "tail double negated inequality": + @Event global + if not not (g != 1): + g = 2 + +rule "tail double negated less than": + @Event global + if not not (g < 1): + g = 2 + +rule "tail double negated less than or equal": + @Event global + if not not (g <= 1): + g = 2 + +rule "tail double negated greater than": + @Event global + if not not (g > 1): + g = 2 + +rule "tail double negated greater than or equal": + @Event global + if not not (g >= 1): + g = 2