|
|
@@ -0,0 +1,90 @@
|
|
|
+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
|