Intégration de l'interpréteur Yaegi pour l'exécution dynamique de code Go

Architecture et Cas d'Usage

Yaegi se distingue comme un interpréteur Go natif, permettant l'évaluation de code source à l'exécution. Il offre une alternative robuste pour le chargement de plugins, l'extension d'applications et le prototypage rapide, le tout sans dépendances externes autres que la bibliothèque standard.

Caractéristiques Techniques

  • Conformité stricte avec les spécifications du langage Go.
  • Architecture 100% Go, facilitant le cross-compilation et l'intégration.
  • Sandboxing natif : isolation des appels système et du paquet unsafe par défaut.
  • API d'évaluation minimaliste et performante.
  • Compatibilité avec les versions récentes de l'écosystème Go.

Domaines d'Application

  • Moteurs de règles métier dynamiques.
  • Systèmes de plugins rechargables à chaud.
  • Environnements REPL pour le débogage et l'expérimentation algorithmique.
  • Automatisation de tâches système via des scripts natifs.

Mise en place de l'environnement

L'acquistiion de l'outil en ligne de commande s'effectue via le gestionnaire de modules Go :

go install github.com/traefik/yaegi/cmd/yaegi@latest

Pour une intégration en tant que bibliothèque au sein de votre propre projet :

import "github.com/traefik/yaegi/interp"

Évaluation de Code et Intégration

Exécution via le REPL

L'interpréteur interactif permet de tester des instructions et d'explorer la bibliothèque standard à la volée :

$ yaegi
> import "math"
> math.Sqrt(144)
12
> import "strings"
> strings.ToUpper("yaegi")
"YAEGI"

Scripts Auto-exécutables

Il est possible de créer des scripts Go directement exécutables depuis le système d'exploitation en utilisant le shebang approprié :

#!/usr/bin/env yaegi
package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now().Format("15:04:05")
    fmt.Printf("Execution started at %s\n", now)
}

Rendez le fichier exécutable et lancez-le :

chmod +x timer.go
./timer.go

Intégration Programmatique (Embarqué)

L'API d'interprétation permet d'injecter un moteur d'exécution dans une application hôte. Voici une approche modifiée pour illustrer l'évaluation de structures de données et de boucles :

package main

import (
    "fmt"
    "log"

    "github.com/traefik/yaegi/interp"
    "github.com/traefik/yaegi/stdlib"
)

func main() {
    // Initialisation du contexte d'interprétation
    evaluateur := interp.New(interp.Options{})
    evaluateur.Use(stdlib.Symbols)

    // Importation des dépendances nécessaires
    if _, err := evaluateur.Eval(`import "fmt"`); err != nil {
        log.Fatalf("Erreur d'import: %v", err)
    }

    // Exécution d'une logique dynamique
    script := `
        data := []int{10, 20, 30, 40}
        somme := 0
        for _, val := range data {
            somme += val
        }
        fmt.Printf("Le total est : %d\n", somme)
    `
    
    if _, err := evaluateur.Eval(script); err != nil {
        log.Fatalf("Erreur d'exécution: %v", err)
    }
}

Fonctionnalités Avancées et Limites

Injection de Logique Dynamique

Yaegi excelle dans l'extraction de symboles Go compilés vers des contextes interprétés. Exemple de manipulation de fonctions mathématiques à la volée :

const codeDynamique = `package calculateur
func AppliquerRemise(prix float64, taux float64) float64 {
    return prix * (1 - taux/100)
}`

ctx := interp.New(interp.Options{})
ctx.Eval(codeDynamique)

// Récupération et typage de la fonction
symbole, _ := ctx.Eval("calculateur.AppliquerRemise")
fonctionRemise := symbole.Interface().(func(float64, float64) float64)

prixFinal := fonctionRemise(150.0, 20.0) // Résultat attendu : 120.0
fmt.Printf("Prix après remise : %.2f\n", prixFinal)

Options de la CLI

Pour des besoins spécifiques nécessitant un accès bas niveau, des drapeaux peuvent être activés pour lever les restrictions de sécurité :

# Activation des appels système et du paquet unsafe
yaegi -syscall -unsafe -unrestricted mon_script.go

Contraintes Techniques Actuelles

L'architecture par interprétation AST implique certaines limites inhérentes :

  • Incompatibilité avec les fichiers d'assemblage (.s).
  • Absence de support pour l'interfaçage direct avec C (cgo).
  • Surcoût de performance par rapport au code natif compilé.
  • Gestion spécifique des modules Go nécessitant des wrappers explicites pour les bibliothèques tierces non standard.

Étiquettes: yaegi go-interpreter dynamic-scripting go-plugins ast-evaluation

Publié le 24 juin à 22h56