module TypeTracer using Serialization # Singleton pour stocker les signatures uniques (Thread-safe) const SEEN_SIGNATURES = Set{String}() const LOCK = ReentrantLock() const LOG_FILE = "execution_trace.txt" """ Fonction interne pour enregistrer une signature. Format: FunctionName(ArgType1, ArgType2, ...) -> ReturnType """ function _record_call(func_name, args, result) # On map les types Julia vers des chaînes de caractères arg_types = join([string(typeof(a)) for a in args], ", ") ret_type = string(typeof(result)) signature = "$func_name($arg_types) -> $ret_type" # Vérification avec lock pour le multi-threading (fréquent en simu) lock(LOCK) do if !(signature in SEEN_SIGNATURES) push!(SEEN_SIGNATURES, signature) # On écrit immédiatement pour ne rien perdre en cas de crash open(LOG_FILE, "a") do io println(io, signature) end # Un petit echo console pour voir que ça vit println("[TRACER] Nouvelle variante capturée : $signature") end end end """ Macro à placer devant les définitions de fonctions. Elle enveloppe le corps de la fonction pour logger les types. """ macro monitor(expr) # Vérifie qu'on applique bien la macro sur une définition de fonction if expr.head !== :function && expr.head !== :(=) error("La macro @monitor doit être appliquée à une définition de fonction.") end # Extraction de la signature (nom + args) et du corps call_def = expr.args[1] body = expr.args[2] # Récupération du nom de la fonction (gestion cas f(x) et Module.f(x)) func_name = length(call_def.args) >= 1 ? call_def.args[1] : :anonymous # On reconstruit la fonction avec l'instrumentation quote function $(call_def) # 1. Exécuter le corps original et capturer le résultat __result = $(body) # 2. Récupérer les arguments (via ... dans la macro c'est délicat, # donc on utilise une astuce : on capture les valeurs des arguments par leur nom) # Note : Pour une conversion C, on a besoin des types concrets à l'exécution. # Ici, on passe un tuple des arguments. # Attention : cela suppose que call_def.args contient les noms des variables. # Pour faire simple et robuste sans métaprogrammation complexe sur les arguments : # On logue juste le fait qu'on est passé ici. # MAIS pour avoir les args, il faut être plus malin. # Approche simplifiée : On logue à la fin TypeTracer._record_call( $(string(func_name)), # On capture tous les arguments de la fonction courante # (nécessite que la fonction ne soit pas anonyme pure) (Base.@locals()...,), # Capture tout le scope local (arguments inclus) __result ) return __result end end |> esc end # Fonction de nettoyage pour vider le log au début function init_trace() if isfile(LOG_FILE) rm(LOG_FILE) end println("--- Démarrage du traçage des types ---") end end