Back to flin
flin

La référence complète des opcodes FLIN

La référence complète des opcodes FLIN : arithmétique, flux de contrôle, entités, vues et instructions de fermetures.

Juste A. Gnimavo (Thales) & Claude | March 26, 2026 9 min flin
EN/ FR/ ES
flinopcodesbytecodereferenceinstruction-setvm

Chaque langage de programmation, en son coeur, est un jeu d'instructions. La syntaxe et la sémantique avec lesquelles les développeurs interagissent sont une façade sur un ensemble fini d'opérations que la machine exécute réellement. Cet article documente chaque opcode du bytecode de FLIN -- le jeu d'instructions complet qui alimente la machine virtuelle.

Le jeu d'instructions de FLIN couvre 16 catégories et plus de 100 opcodes, allant de la manipulation de pile de base aux requêtes sémantiques alimentées par l'IA. Chaque opcode est un seul octet, suivi de zéro ou plusieurs octets d'opérandes. Cet encodage compact garde les fichiers de bytecode petits et la distribution d'instructions rapide.

Comprendre le jeu d'opcodes est essentiel pour quiconque veut savoir ce que FLIN fait réellement quand vous écrivez count++ ou save user ou {for todo in todos}. C'est le langage sous le langage.


Encodage des instructions

Avant de lister les opcodes, il est utile de comprendre comment ils sont encodés dans le flux de bytecode. FLIN utilise des instructions de longueur variable avec cinq formats :

Format 0 -- Pas d'opérande (1 octet) :
  [opcode]
  Exemples : Add, Sub, Mul, Pop, Dup, Return, Halt

Format 1 -- Un opérande u8 (2 octets) :
  [opcode] [u8]
  Exemples : LoadLocal, StoreLocal (emplacements 0-255)

Format 2 -- Un opérande u16 (3 octets) :
  [opcode] [u16 little-endian]
  Exemples : LoadConst, LoadGlobal, Jump

Format 3 -- Un opérande u32 (5 octets) :
  [opcode] [u32 little-endian]
  Exemples : JumpFar, CallNative

Format 4 -- Deux opérandes u8 (3 octets) :
  [opcode] [u8] [u8]
  Exemples : Call (arité, const_idx)

Toutes les valeurs multi-octets sont en little-endian. Les instructions les plus courantes (arithmétique, opérations de pile) sont de Format 0 -- un seul octet sans opérandes. Cela signifie que le bytecode FLIN typique fait en moyenne environ 1,5 octet par instruction, ce qui est remarquablement compact.


Catégorie 1 : flux de contrôle (0x00-0x0F)

Les instructions de flux de contrôle gèrent le chemin d'exécution -- arrêt, saut, appel et retour.

OctetMnémoniqueOpérandesEffet de pileDescription
0x00Halt----Arrêter l'exécution, retourner le sommet de pile
0x01Nop----Pas d'opération (utilisé pour le remplissage)
0x02Jumpu16 addr--Saut inconditionnel à l'adresse
0x03JumpIfTrueu16 addrcond ->Dépiler et sauter si vrai
0x04JumpIfFalseu16 addrcond ->Dépiler et sauter si faux
0x05JumpIfNoneu16 addrval ->Dépiler et sauter si None
0x06Callu8 aritéfn, args... -> resultAppeler une fonction avec N args
0x07CallNativeu16 idxargs... -> resultAppeler une fonction intégrée
0x08Return--result ->Retourner d'une fonction
0x09JumpFaru32 addr--Saut avec adresse 32 bits

Halt est toujours la dernière instruction d'un programme. Sans elle, la VM dépasserait la fin du tableau de bytecode. Le compilateur s'assure que chaque chemin de code se termine par Halt ou Return.

JumpIfNone existe spécifiquement pour la gestion des valeurs optionnelles. Dans FLIN, de nombreuses opérations peuvent retourner None (une recherche en base de données qui ne trouve rien, un accès à une liste hors limites), et vérifier None est assez courant pour mériter sa propre instruction plutôt qu'une séquence de deux instructions IsNone + JumpIfTrue.


Catégorie 2 : opérations de pile (0x10-0x1F)

Les instructions de pile manipulent directement la pile d'opérandes.

OctetMnémoniqueOpérandesEffet de pileDescription
0x10LoadConstu16 idx-> valuePousser une constante du pool
0x11Pop--value ->Jeter le sommet de pile
0x12Dup--v -> v, vDupliquer le sommet
0x13Dup2--a, b -> a, b, a, bDupliquer les deux du sommet
0x14Swap--a, b -> b, aÉchanger les deux du sommet
0x15Over--a, b -> a, b, aCopier le deuxième au sommet
0x16LoadNone---> nonePousser None
0x17LoadTrue---> truePousser true
0x18LoadFalse---> falsePousser false
0x19LoadInt0---> 0Pousser l'entier 0
0x1ALoadInt1---> 1Pousser l'entier 1
0x1BLoadIntN1---> -1Pousser l'entier -1
0x1CLoadSmallInti8 val-> valPousser un petit entier (-128..127)

Les instructions de constantes spécialisées (LoadNone, LoadTrue, LoadFalse, LoadInt0, LoadInt1, LoadIntN1, LoadSmallInt) sont des optimisations. Au lieu du LoadConst de trois octets suivi d'une recherche dans le pool de constantes, ces instructions d'un ou deux octets poussent directement les valeurs couramment utilisées. Le compilateur les émet automatiquement quand il détecte une constante qui correspond.


Catégories 3-14 : variables, arithmétique, entités, vues et plus

Les catégories restantes suivent le même pattern systématique :

  • Catégorie 3 (0x20-0x2F) : Variables locales -- LoadLocal, StoreLocal, IncrLocal, DecrLocal
  • Catégorie 4 (0x30-0x3F) : Variables globales -- LoadGlobal, StoreGlobal, LoadGlobalDirect, StoreGlobalDirect
  • Catégorie 5 (0x40-0x4F) : Arithmétique -- Add, Sub, Mul, Div, Mod, Neg, Incr, Decr, Pow, IntDiv
  • Catégories 6-7 (0x50-0x6F) : Comparaison et logique -- Eq, NotEq, Lt, Gt, IsNone, And, Or, Not, opérations bit à bit
  • Catégorie 8 (0x70-0x7F) : Objets et champs -- CreateObject, GetField, SetField, HasField, CreateEntity
  • Catégorie 9 (0x80-0x8F) : Listes et maps -- CreateList, GetIndex, SetIndex, ListPush, CreateMap, MapGet, MapSet
  • Catégorie 10 (0x90-0x9F) : Opérations d'entités -- Save, Delete, QueryAll, QueryFind, QueryWhere, QueryFirst, QueryCount
  • Catégorie 11 (0xA0-0xAF) : Opérations de vues -- couvertes en détail dans l'article précédent
  • Catégories 12-13 (0xB0-0xCF) : Opérations d'intent et temporelles -- Ask, Search, Embed, AtVersion, AtTime, History, LoadNow
  • Catégorie 14 (0xD0-0xEF) : Fonctions intégrées -- Print, ToString, Len, Replace, Abs, Floor, Ceil, Round, Sqrt, ListMap, ListFilter, ListReduce

Un détail critique concernant Eq : il effectue une comparaison profonde pour les objets. Deux chaînes avec le même contenu mais des valeurs ObjectId différentes sont égales. Cela a nécessité un helper values_equal() dédié dans la VM qui déréférence les objets et compare leurs contenus, plutôt que de comparer leurs adresses sur le tas. Se tromper là-dessus était un bogue que nous avons attrapé dans la Session 026 -- "hello" == "hello" retournait false parce qu'il comparait les valeurs ObjectId.

Add fait double emploi : pour les nombres, il effectue l'addition. Pour les chaînes, il effectue la concaténation. La VM vérifie les types des deux opérandes à l'exécution et distribue en conséquence.

IncrLocal et DecrLocal sont des instructions fusionnées. La façon naïve d'incrémenter une variable locale est LoadLocal 0; LoadInt1; Add; StoreLocal 0 -- quatre instructions, quatre cycles de distribution. IncrLocal 0 fait la même chose en une instruction, deux octets. Dans une boucle serrée, cela économise 75 % de la surcharge par itération.


L'espace d'opcodes

L'espace d'opcodes de FLIN est un seul octet (0x00-0xFF), divisé en 16 plages de 16 opcodes chacune. Actuellement, environ 110 des 256 opcodes possibles sont assignés. Cela laisse de la place pour environ 146 instructions futures sans casser l'encodage sur un seul octet.

La plage 0xF0-0xFF est réservée pour les instructions de débogage et spéciales :

OctetMnémoniqueDescription
0xF0BreakpointPoint d'arrêt du débogueur
0xF1SourceLocMarqueur d'emplacement source (pour les traces de pile)
0xFEExtendedPréfixe d'opcode étendu (pour les futurs opcodes à 2 octets)
0xFFInvalidInstruction invalide (déclenche toujours une erreur)

Le préfixe Extended (0xFE) est une conception tournée vers l'avenir. Si FLIN épuise un jour l'espace d'opcodes sur un seul octet, Extended suivi d'un deuxième octet donne accès à 256 opcodes supplémentaires sans changer l'encodage des instructions existantes.


Philosophie de conception

Trois principes ont guidé la conception des opcodes :

Orthogonalité. Chaque opcode fait une chose. Add additionne. LoadLocal charge une locale. CreateElement crée un élément. Il n'y a pas d'instructions qui combinent des opérations non liées (avec l'exception délibérée des instructions fusionnées comme IncrLocal, qui combinent un chargement, une addition et un stockage pour la performance).

Discipline de pile. Chaque opcode documente son effet de pile : combien de valeurs il consomme et combien il produit. Le compilateur utilise ces effets de pile pour vérifier que le bytecode généré est équilibré -- chaque chemin de code laisse la pile à la même hauteur. Un bogue dans le compilateur qui produit du bytecode déséquilibré serait attrapé par cette vérification.

Extension sans rupture. Les plages d'opcodes sont regroupées par catégorie, avec des espaces laissés pour les ajouts futurs. Les opérations d'entités ont de la place pour plus de types de requêtes. Les opérations de vues ont de la place pour plus d'instructions de manipulation DOM. Les plages réservées assurent que le format de bytecode de FLIN peut évoluer sans invalider les fichiers compilés existants.


Ceci est la partie 25 de la série « Comment nous avons construit FLIN », documentant comment un CEO à Abidjan et un CTO IA ont construit un langage de programmation à partir de zéro.

Prochain : [26] Rechargement à chaud de modules en 42 ms -- comment les changements de fichiers vont du disque au navigateur en moins de 50 millisecondes.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude thales

Treize agents, quarante-trois minutes : la première session Workflow de Claude Fable 5, et ce qu'un script d'orchestration déterministe change aux builds multi-agents

Un prompt, treize agents, quarante-trois minutes : la première session de production avec Claude Fable 5 et l'outil Workflow de Claude Code a livré un site web de production complet de sept pages plus un endpoint backend de capture de leads, en un seul commit. Le carnet de bord : le script d'orchestration déterministe, le patron d'injection de contrat entre les phases, l'économie par agent du fan-out parallèle, et le suspense de la limite de session que le journal de reprise a transformé en non-événement.

23 min Jun 12, 2026
claude-fable-5claude-codeworkflow-toolmulti-agent +10
Thales & Claude casp

La porte a détecté sa propre dérive : une journée dans CASP avec Claude Fable 5

Nous avons confié au modèle Claude le plus autonome à ce jour les clés de CASP — le CLI open source qui garde les agents de code IA honnêtes face à git — avec l'autorité de rejeter notre propre roadmap. Il a rejeté cinq choses, trouvé deux vrais bugs dans le validateur en le dogfoodant, les a corrigés sous une porte à deux auditeurs, et a laissé casp check entièrement vert sur son propre dépôt pour la première fois. CASP 0.3.0 en est le résultat.

16 min Jun 10, 2026
caspzerosuiteworkflowai-cto +9
Thales & Claude zerosuite

La transplantation du CASP : comment la discipline des six fichiers est passée de Conductor à un ERP transport anti-fraude, ce que la compétence /next ajoute quand l'opérateur tape juste « next », et pourquoi le coût d'une dérive du CASP grimpe quand le projet, c'est l'argent des autres

La discipline du CASP qui a piloté trente-cinq sessions de Conductor est agnostique au produit. Le carnet de bord de sa transplantation sur KASSIA, un ERP transport anti-fraude pour un exploitant de flotte en Côte d'Ivoire : ce qui a migré, ce qui n'a pas migré (le validateur sur mesure — et ce que son absence coûte), ce que la compétence /next ajoute quand l'opérateur tape un seul mot, et là où le CASP s'arrête — le bug de déploiement qu'il ne pouvait pas voir parce qu'il enregistre l'intention, pas la réalité de l'infrastructure.

23 min Jun 8, 2026
kassiaerp-kassia-transport-logistiquezerosuiteCASP +15