Skip to content

Commit b8f2c2d

Browse files
committed
e
1 parent e7d7901 commit b8f2c2d

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed

source/Main.hx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,39 @@ class Main extends Sprite
285285
FlxG.signals.gameResized.add((w, h) -> resetSpriteCaches());
286286
FlxG.signals.focusGained.add(resetSpriteCaches);
287287

288+
289+
// Artificial loop using GoToTag as a label and GoTo as a goto
290+
var counter = 0;
291+
yutautil.CUMacroTools.GoToTag("loopStart");
292+
trace('goto test: $counter');
293+
counter++;
294+
if (counter >= 5) {
295+
yutautil.CUMacroTools.GoTo("loopEnd");
296+
} else {
297+
yutautil.CUMacroTools.GoTo("loopStart");
298+
}
299+
300+
yutautil.CUMacroTools.GoToTag("loopEnd");
301+
// This is just a test to see if the GoToTag and GoTo macros work correctly.
302+
303+
// Second test using 'using' import for string extension
304+
// (Assumes: import using yutautil.CUMacroTools;)
305+
var counter2 = 0;
306+
"loopStart2".GoToTag();
307+
trace('goto test 2: $counter2');
308+
counter2++;
309+
if (counter2 >= 5) {
310+
"loopEnd2".GoTo();
311+
} else {
312+
"loopStart2".GoTo();
313+
}
314+
"loopEnd2".GoToTag();
315+
// This is a test to see if the GoToTag and GoTo string extensions work correctly.
316+
317+
318+
// trace("E tag woooooorks!!!");
319+
320+
288321
#if android
289322
FlxG.android.preventDefaultKeys = [flixel.input.android.FlxAndroidKey.BACK];
290323
#end

source/import.hx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,5 @@ using StringTools;
9898
using yutautil.CollectionUtils;
9999
using yutautil.MetaData;
100100
using yutautil.PointerTools;
101+
using yutautil.CUMacroTools; // Careful. Using C++ Lables in Haxe may act strangely.
101102
#end

source/yutautil/CUMacroTools.hx

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package yutautil;
2+
3+
import haxe.macro.Context;
4+
import haxe.macro.Expr;
5+
import haxe.macro.Type;
6+
7+
class CUMacroTools
8+
{
9+
// Static maps: "Class.method" -> array of tags/gotos
10+
static var tags:Map<String, Array<String>> = new Map();
11+
static var gotos:Map<String, Array<{tag:String, pos:Position}>> = new Map();
12+
13+
public static var validate:Bool = true; // Set manually to enable validation
14+
public static var debug:Bool = true; // Set manually to enable debug output
15+
16+
static var validationRegistered:Bool = false; // Ensure validation is only registered once
17+
static var needsValidation:Bool = false; // Set to true if GoTo is used
18+
19+
/**
20+
* WARNING: This macro uses untyped C++ goto, which may have unintended side-effects and is not portable.
21+
* Use with extreme caution!
22+
*/
23+
public static macro function GoTo(tag:String):Expr {
24+
// getMethodKey must be called inside the macro
25+
function getMethodKey():String {
26+
var curClass = Context.getLocalClass();
27+
var className = curClass != null ? curClass.get().name : "UnknownClass";
28+
var curMethod = Context.getLocalMethod();
29+
var methodName = curMethod != null ? curMethod : "UnknownMethod";
30+
return className + "." + methodName;
31+
}
32+
33+
var pos = Context.currentPos();
34+
var key = getMethodKey();
35+
var arr = gotos.get(key);
36+
if (arr == null) {
37+
arr = [];
38+
gotos.set(key, arr);
39+
}
40+
arr.push({tag: tag, pos: pos});
41+
42+
needsValidation = true;
43+
44+
// Register validation function only once if needed
45+
if (validate && !validationRegistered) {
46+
validationRegistered = true;
47+
Context.onAfterGenerate(function() {
48+
// Only run on C++ targets and if validation is needed
49+
if (!Context.defined("cpp") || !needsValidation) return;
50+
51+
var errors:Array<String> = [];
52+
for (key in gotos.keys()) {
53+
var gotosArr = gotos.get(key);
54+
var tagsArr = tags.get(key);
55+
for (goto in gotosArr) {
56+
if (tagsArr == null || tagsArr.indexOf(goto.tag) == -1) {
57+
var err = "Expected an existing goto tag in this method: '" + goto.tag + "' (" + key + ")";
58+
Context.error(err, goto.pos);
59+
errors.push(err);
60+
}
61+
}
62+
}
63+
64+
if (debug) {
65+
var info = "CUMacroTools Debug Info:\n";
66+
info += "Registered tags:\n";
67+
for (key in tags.keys()) {
68+
info += " " + key + ": " + tags.get(key) + "\n";
69+
}
70+
info += "Registered gotos:\n";
71+
for (key in gotos.keys()) {
72+
info += " " + key + ": ";
73+
var arr = gotos.get(key);
74+
info += [for (g in arr) g.tag].join(", ") + "\n";
75+
}
76+
if (errors.length > 0) {
77+
info += "Errors:\n" + errors.join("\n") + "\n";
78+
}
79+
Context.info(info, Context.currentPos());
80+
}
81+
});
82+
}
83+
84+
var code = 'goto ' + tag + ';';
85+
return macro untyped __cpp__($v{code});
86+
}
87+
88+
/**
89+
* WARNING: This macro emits a C++ label, which may have unintended side-effects and is not portable.
90+
* Use with extreme caution!
91+
*/
92+
public static macro function GoToTag(tag:String):Expr {
93+
// getMethodKey must be called inside the macro
94+
function getMethodKey():String {
95+
var curClass = Context.getLocalClass();
96+
var className = curClass != null ? curClass.get().name : "UnknownClass";
97+
var curMethod = Context.getLocalMethod();
98+
var methodName = curMethod != null ? curMethod : "UnknownMethod";
99+
return className + "." + methodName;
100+
}
101+
102+
var key = getMethodKey();
103+
var tagArr = tags.get(key);
104+
if (tagArr == null) {
105+
tagArr = [];
106+
tags.set(key, tagArr);
107+
}
108+
if (tagArr.indexOf(tag) == -1) tagArr.push(tag) else {
109+
Context.error("CUMacroTools.GoToTag: Tag '" + tag + "' already exists in method '" + key + "'." + "You cannot have the same tag twice.", Context.currentPos());
110+
}
111+
112+
Context.warning("CUMacroTools.GoToTag: Using C++ labels is not portable and may lead to unexpected behavior. Use with caution.", Context.currentPos());
113+
114+
// Check if this is C++.
115+
if (!Context.defined("cpp")) {
116+
Context.error("CUMacroTools.GoToTag can only be used in C++ targets.", Context.currentPos());
117+
}
118+
119+
var code = tag + ':';
120+
return macro untyped __cpp__($v{code});
121+
}
122+
123+
// The same functions above, but as C++ names.
124+
125+
public static macro function CGoTo(tag:String):Expr {
126+
return GoTo(tag);
127+
}
128+
129+
public static macro function CLabel(tag:String):Expr {
130+
return GoToTag(tag);
131+
}
132+
133+
134+

source/yutautil/CollectionUtils.hx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ typedef LuaScript = flixel.util.typeLimit.OneOfTwo<psychlua.FunkinLua, psychlua.
6161
// }
6262
// }
6363

64+
65+
6466
class KeyArray<K, V>
6567
{
6668
// An array with keys, similar to a dictionary, allowing for use of keys with arrayaccess.
@@ -1328,6 +1330,15 @@ class CollectionUtils
13281330
}
13291331
}
13301332

1333+
public static inline function catchWithVoid(tryFunc:Void->Void, catchFunc:Dynamic->Void):Void {
1334+
try {
1335+
tryFunc();
1336+
} catch (e:Dynamic) {
1337+
catchFunc(e);
1338+
}
1339+
}
1340+
1341+
13311342

13321343

13331344
public static inline function toArray<T>(input:Dynamic, ?type):Array<Any>

0 commit comments

Comments
 (0)