cleaning up

This commit is contained in:
Andreas Schaafsma 2025-03-11 19:02:15 +01:00
parent ac5787e2fb
commit 9720731afb
2 changed files with 242 additions and 111 deletions

View File

@ -1,136 +1,266 @@
package engine.macros; package engine.macros;
#if macro
import haxe.macro.Expr; import haxe.macro.Expr;
import haxe.macro.Context; import haxe.macro.Context;
import haxe.macro.Type;
import haxe.macro.Expr.Field; import haxe.macro.Expr.Field;
import haxe.macro.Expr.Function;
import haxe.macro.Expr.Access;
private typedef CVarMetadata = { private typedef CVarMetadata = {
name: Expr, name:Expr,
type: String, type:String,
value: Expr, value:Expr,
flags: Expr, flags:Expr,
help: Expr, help:Expr,
?callback: Expr ?callback:Expr
} }
class ConVarDecorators { class ConVarDecorators {
static function extractCVarMetadata(params:Array<Expr>):CVarMetadata { static function extractCVarMetadata(params:Array<Expr>):CVarMetadata {
var metadata:CVarMetadata = null; if (params == null || params.length == 0) return null;
var metadata:CVarMetadata = {
name: macro "",
type: "CString",
value: macro 0,
flags: macro "FCVAR_NONE",
help: macro "",
callback: macro null
};
switch (params[0].expr) { switch (params[0].expr) {
case EObjectDecl(fields): case EObjectDecl(fields):
metadata = { var fieldMap = [
name: macro "", "name" => function(expr) metadata.name = expr,
type: "CString", "type" => function(expr) metadata.type = switch (expr.expr) {
value: macro 0, case EConst(CString(s)): s;
flags: macro "FCVAR_NONE", case _: "CString";
help: macro "", },
callback: macro null "value" => function(expr) metadata.value = expr,
}; "flags" => function(expr) metadata.flags = expr,
"help" => function(expr) metadata.help = expr,
"callback" => function(expr) metadata.callback = expr
];
for (field in fields) { for (field in fields) {
switch (field.field) { if (fieldMap.exists(field.field)) {
case "name": metadata.name = field.expr; fieldMap[field.field](field.expr);
case "type": metadata.type = switch(field.expr.expr) { } else {
case EConst(CString(s)): s; Context.error("Unexpected field: " + field.field, field.expr.pos);
case _: "CString";
}
case "value": metadata.value = field.expr;
case "flags": metadata.flags = field.expr;
case "help": metadata.help = field.expr;
case "callback": metadata.callback = field.expr;
case _:
} }
} }
case _: case _:
} }
return metadata; return metadata;
} }
// Process command fields
private static function processCommandField(field:Field, cmdMeta:MetadataEntry, extraFields:Array<Field>):Void {
if (!isFieldKind(field, "FFun")) {
Context.error("The @:concmd metadata can only be applied to functions", field.pos);
return;
}
var pos = Context.currentPos();
var functionReference = getFunctionFromField(field);
if (functionReference == null) return;
var name = cmdMeta.params.length > 0 ? getStringFromExpr(cmdMeta.params[0]) ?? field.name : field.name;
var functionExpression = macro function(args:Array<String>) ${functionReference.expr};
var initExpr = macro {
var cmd = engine.ConVar.registerCCmd($v{name}, $functionExpression);
cmd;
};
var initName = "__init__cmd_" + name;
extraFields.push(createStaticInitField(initName, initExpr, pos));
}
// Process convar fields
private static function processConVarField(field:Field, cvarMeta:MetadataEntry, extraFields:Array<Field>):Void {
if (!isFieldKind(field, "FVar")) {
Context.error("The @:convar metadata can only be applied to variables", field.pos);
return;
}
var pos = Context.currentPos();
var meta = extractCVarMetadata(cvarMeta.params);
if (meta == null) {
Context.error("Metadata extraction failed for field: " + field.name, field.pos);
return;
}
var cvarName = getStringFromMetaExpr(meta.name) ?? field.name;
var fieldName = field.name;
var isStatic = hasAccess(field, AStatic);
var varType = getVarType(field);
if (isStatic) {
// Handle static fields
var staticInitExpr = macro {
var cvar = $i{fieldName} = engine.ConVar.registerCVar(
${meta.name},
${Context.parse('engine.enums.console.CVarType.' + meta.type, pos)},
${meta.value},
${Context.parse('engine.enums.console.CVarFlag.' + switch (meta.flags.expr) {
case EConst(CString(s)): s;
case _: "FCVAR_NONE";
}, pos)},
${meta.help},
${meta.callback ?? macro null}
);
trace($v{"Registered CVar: "} + $e{meta.name});
cvar;
};
extraFields.push(createStaticInitField("__init__" + cvarName, staticInitExpr, pos));
} else {
// Handle instance fields
updateFieldInitialValue(field, macro null);
var instanceInitExpr = macro {
if (Reflect.field(this, $v{fieldName}) == null) {
Reflect.setField(this, $v{fieldName}, engine.ConVar.registerCVar(
${meta.name},
${Context.parse('engine.enums.console.CVarType.' + meta.type, pos)},
${meta.value},
${Context.parse('engine.enums.console.CVarFlag.' + switch (meta.flags.expr) {
case EConst(CString(s)): s;
case _: "FCVAR_NONE";
}, pos)},
${meta.help},
${meta.callback ?? macro null}
));
trace($v{"Registered CVar: "} + $e{meta.name});
}
};
ensureConstructorWithInit(extraFields, instanceInitExpr, pos);
}
}
// Utility functions
private static function isFieldKind(field:Field, kind:String):Bool {
return switch (field.kind) {
case FFun(_) if (kind == "FFun"): true;
case FVar(_, _) if (kind == "FVar"): true;
case FProp(_, _, _, _) if (kind == "FProp"): true;
case _: false;
}
}
private static function getFunctionFromField(field:Field):Function {
return switch (field.kind) {
case FFun(f): f;
case _: null;
}
}
private static function getVarType(field:Field):ComplexType {
return switch (field.kind) {
case FVar(t, _): t;
case _: null;
}
}
private static function updateFieldInitialValue(field:Field, expr:Expr):Void {
switch (field.kind) {
case FVar(t, _): field.kind = FVar(t, expr);
case _:
}
}
private static function getStringFromExpr(expr:Expr):String {
return switch (expr.expr) {
case EConst(CString(s)): s;
case _: null;
}
}
private static function getStringFromMetaExpr(expr:Expr):String {
return switch (expr.expr) {
case EConst(CString(s)): s;
case _: null;
}
}
private static function hasAccess(field:Field, access:Access):Bool {
return field.access != null && field.access.indexOf(access) >= 0;
}
private static function createStaticInitField(name:String, initExpr:Expr, pos:Position):Field {
return {
name: name,
access: [AStatic],
kind: FVar(null, initExpr),
pos: pos,
doc: null,
meta: [{ name: ":keep", params: [], pos: pos }]
};
}
private static function ensureConstructorWithInit(fields:Array<Field>, initExpr:Expr, pos:Position):Void {
var cls = Context.getLocalClass().get();
var hasSuperClass = cls.superClass != null;
var constructor = Lambda.find(fields, function(f) return f.name == "new");
if (constructor == null) {
constructor = {
name: "new",
access: [APublic],
kind: FFun({
args: [],
expr: if (hasSuperClass) macro {
super();
$initExpr;
} else macro {
$initExpr;
},
ret: null
}),
pos: pos,
meta: []
};
fields.push(constructor);
} else {
switch (constructor.kind) {
case FFun(f):
switch(f.expr.expr) {
case EBlock(exprs):
exprs.push(initExpr);
case _:
f.expr = macro {
${f.expr};
$initExpr;
}
}
case _:
}
}
}
public static macro function build():Array<Field> { public static macro function build():Array<Field> {
var fields = Context.getBuildFields(); var fields = Context.getBuildFields();
var pos = Context.currentPos(); var extraFields:Array<Field> = [];
for (field in fields) { for (field in fields) {
var cmdMeta = field.meta != null ? Lambda.find(field.meta, function(m) return m.name == ":concmd") : null; if (field.meta == null) continue;
var cvarMeta = field.meta != null ? Lambda.find(field.meta, function(m) return m.name == ":convar") : null;
var cmdMeta = Lambda.find(field.meta, function(m) return m.name == ":concmd");
var cvarMeta = Lambda.find(field.meta, function(m) return m.name == ":convar");
if (cmdMeta != null) { if (cmdMeta != null) {
switch field.kind { processCommandField(field, cmdMeta, extraFields);
case FFun(f):
var name = cmdMeta.params.length > 0 ? switch (cmdMeta.params[0].expr) {
case EConst(CString(s)): s;
case _: field.name;
} : field.name;
var fnExpr = macro function(args:Array<String>) ${f.expr};
var initExpr = macro {
var cmd = engine.ConVar.registerCCmd($v{name}, $fnExpr);
cmd; // Return the command reference
};
// Generate a safe initialization field name
var initName = "__init__" + name;
fields.push({
name: initName,
access: [AStatic],
kind: FVar(null, initExpr),
pos: pos,
doc: null,
meta: [{
name: ":keep",
params: [],
pos: pos
}]
});
case _:
}
} else if (cvarMeta != null && cvarMeta.params.length > 0) { } else if (cvarMeta != null && cvarMeta.params.length > 0) {
switch (field.kind) { processConVarField(field, cvarMeta, extraFields);
case FVar(t, e):
var meta = extractCVarMetadata(cvarMeta.params);
if (meta == null) continue;
// Extract name from metadata expression
var cvarName = switch(meta.name.expr) {
case EConst(CString(s)): s;
case _: field.name;
};
var initExpr = macro {
var cvar = $i{field.name} = engine.ConVar.registerCVar(
${meta.name},
${Context.parse('engine.enums.console.CVarType.' + meta.type, pos)},
${meta.value},
${Context.parse('engine.enums.console.CVarFlag.' + switch(meta.flags.expr) {
case EConst(CString(s)): s;
case _: "FCVAR_NONE";
}, pos)},
${meta.help},
${meta.callback ?? macro null}
);
trace($v{"Registered CVar: "} + $e{meta.name});
cvar; // Return the CVar reference
};
fields.push({
name: "__init__" + cvarName,
access: [AStatic],
kind: FVar(null, initExpr),
pos: pos,
doc: null,
meta: [{
name: ":keep",
params: [],
pos: pos
}]
});
case _:
}
} }
} }
return fields;
return fields.concat(extraFields);
} }
} }
#end

View File

@ -26,12 +26,13 @@ class Console extends Sprite {
public var cAutoComp:TextField; public var cAutoComp:TextField;
public static var consoleInstance:Console; public static var consoleInstance:Console;
@:convar({
name: "mat_consolebg", @:convar({
type: "CString", name: "mat_consolebg",
value: "0x222222", type: "CString",
help: "console background color", value: "0x222222",
callback: () -> { help: "console background color",
callback: () -> {
if (Console.consoleInstance != null){ if (Console.consoleInstance != null){
Console.consoleInstance.cOut.backgroundColor = Std.parseInt(Console.consoleInstance.cvar_mat_consolebg.value); Console.consoleInstance.cOut.backgroundColor = Std.parseInt(Console.consoleInstance.cvar_mat_consolebg.value);
Console.consoleInstance.cIn.backgroundColor = Std.parseInt(Console.consoleInstance.cvar_mat_consolebg.value); Console.consoleInstance.cIn.backgroundColor = Std.parseInt(Console.consoleInstance.cvar_mat_consolebg.value);