| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- 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
|