Parser Combinator
Parser
// fichier INI
[section]
data=12
data2=chat
[section2]
toto=1
{
"section": {
"data": 12,
"data2": "chat"
},
"section2": {
"toto": 1
}
}
Fichier INI en JSON
Anatomie d'un parser
Currying
Il s'agit d'une fonction retournant une fonction
Permet de retarder l'appel de la fonction
Permet aussi de spécialiser un comportement
Sans currying
const func1 => console.log("func1");
func1() // affiche "func1" dans la console
Avec currying
const buildFunc1 = function() {
return function() {
console.log("func1")
}
};
buildFunc1(); // n'affiche rien dans la console
const buildFunc1 = function() {
return function() {
console.log("func1")
}
};
buildFunc1()(); // affiche "func1" dans la console
const buildFunc1 = () => () => console.log("func1")
buildFunc1()(); // affiche "func1" dans la console
Currying avec contexte
const buildFunc2 = contexte => () => console.log("func2 "+contexte)
buildFunc2("toto")(); // affiche "func2 toto" dans la console
Le contexte est injecté dans la fonction renvoyé
Function First class citizen
const buildFunc2 = contexte => () => console.log("func2 "+contexte)
const func2WithToto = buildFunc2("toto");
const func2WithTata = buildFunc2("tata");
func2WithToto(); // affiche "func2 toto" dans la console
func2WithTata(); // affiche "func2 tata" dans la console
Une fonction est une variable comme une autre
La fonction peut aussi avoir des paramètres
const buildFunc3 = contexte => prefix => console.log( prefix + " func3 "+ contexte)
const func2WithToto = buildFunc3("toto");
const func2WithTata = buildFunc3("tata");
func2WithToto("prefix1"); // affiche "prefix1 func2 toto" dans la console
func2WithTata("prefix2"); // affiche "prefix2 func2 tata" dans la console
Et être utilisé en conjonction du contexte injecté
Tag parser
Renvoie un parser capable de matcher le token
text = "AAB"
parser = tag "A"
resultat = parser text // succès
text = "BAB"
parser = tag "A"
resultat = parser text // échec
Parser un seul caractère
text = "chateau"
parser = tag "chat"
resultat = parser text // succès
text = "chapeau"
parser = tag "chat"
resultat = parser text // échec
Parser un ensemble de token
Le ET logique
text = "ABB"
parserA = tag "A"
parserB = tag "B"
parser = parserA AND parserB
resultat = parser text // succès
text = "AAB"
parserA = tag "A"
parserB = tag "B"
parser = parserA AND parserB
resultat = parser text // échec
Lier deux parsers tag
text = "ABC"
parserA = tag "A"
parserB = tag "B"
parserC = tag "C"
parserAandB = parserA AND parserB
parser = parserAandB AND parserC
resultat = parser text // succès
Lier 2 parsers tout court
On généralise !
text = "ABC"
parserA = tag "A"
parserB = tag "B"
parserC = tag "C"
parser = ALL [ parserA, parserB, parserC ]
resultat = parser text // succès
Sous forme de code
Le OU logique
parserA = tag "A"
parserB = tag "B"
parser = parserA OR parserB
resultat = parser "AZ" // succès
resultat = parser "BZ" // succès
resultat = parser "ZZ" // échec
Lier deux parsers tag
On généralise !
parserA = tag "A"
parserB = tag "B"
parserC = tag "C"
parser = ANY [ parserA, parserB, parserC ]
resultat = parser "AZZ" // succès
resultat = parser "BZZ" // succès
resultat = parser "CZZ" // succès
resultat = parser "ZZZ" // échec
Sous forme de code
Répétition
parser = REPEAT ( tag "A", {3} )
resultat = parser "AAAA" // succès
resultat = parser "AAAB" // succès
resultat = parser "ABAA" // échec
resultat = parser "AABA" // échec
Appliquer une répétition à un parser
Exactement n fois
Le parser doit matcher exactement n fois
Au moins n fois
Fail si le parser n'a pas matché au moins n fois
Au plus n fois
Matchera entre 0 et n fois
0 fois ou plus
Ne fail jamais
1 fois ou plus
Fail si le parser répété ne match pas au moins une fois
Délimiter un bloc
parserOpen = tag "("
parserClose = tag ")"
parser = DELIMITER parserOpen parserClose
resultat = parser "( toto )" // succès le group est " toto "
resultat = parser " toto )" // échec le texte ne commence pas par le délimiter de début
resultat = parser "( toto " // échec le groupe ne se ferme jamais
Le cas "simple"
parserOpen = tag "("
parserClose = tag ")"
parser = DELIMITER parserOpen parserClose
resultat = parser "( ( 2 + 3 ) * 5 )" // succès renvoie un résultat
//composite contenant le groupe imbriqué " 2 + 3 " suivi du reste " * 5 "
Le cas imbriqué
Consommer et modifier le résultat d'un parser
Applique une fonction sur un parser et en renvoie un nouveau modifié
parser1 = tag "1"
// fn est une fonction qui en cas de succès réalise un parseInt de la chaine de caractère
parser = fn parser1
resultat = parser1 "1" // retourne "1" en chaine de caractères
resultat = parser "1" // retourne 1 sous la forme d'un nombre exploitable
Un texte qui devient un nombre
Détecter la représentation RVB textuelle d'une couleur hexadécimale
2 formats:
- #fff
- #ffffff
Mais insensible à la casse
- #FFf
- #ffFFff
On s'occupe de la partie 6 digits
Et de la partie 3 digits
On combine tout
parserColorHexa "fff" // échec, ne commence pas par "#"
parserColorHexa "#ff" // échec, ne possède ni 3 ni 6 digit après le "#"
parserColorHexa "#fff" // succès
parserColorHexa "#fFf" // succès
parserColorHexa "#ffffff" // succès
parserColorHexa "#fFFfff" // succès
Résultat de notre parser
Parser Combinator
By akanoa
Parser Combinator
- 114