Ajout de filter.py, qui contient un parseur de filtres.
This commit is contained in:
parent
12b8166e82
commit
a629e4c82f
1 changed files with 244 additions and 0 deletions
244
filter.py
Normal file
244
filter.py
Normal file
|
@ -0,0 +1,244 @@
|
|||
#/usr/bin/env python
|
||||
# -*- coding: utf8 -*-
|
||||
|
||||
def human_to_ldap(filtre):
|
||||
"""
|
||||
Transforme les filtres "human readables" en
|
||||
filtres respectant la syntaxe LDAP.
|
||||
"""
|
||||
# Piles, quand on croise une parenthèse ouvrante
|
||||
# on change de pile
|
||||
stacks = {0:''}
|
||||
|
||||
# Position dans la pile
|
||||
pos = 0
|
||||
|
||||
# operateur \in {&, |, &|, }
|
||||
operateur = ""
|
||||
|
||||
# La pile externe, qu'on merge à la pile en cours quand c'est utile.
|
||||
ext_stack = ""
|
||||
|
||||
# Élement de la forme paiement=2012 ou retour de la pile
|
||||
# supérieure (quand on croise une parenthèse fermante, la
|
||||
# pile est dumpée dans argument)
|
||||
# Est systématiquement dumpé dans ext_stack quand on croise
|
||||
# un opérateur.
|
||||
argument = ""
|
||||
|
||||
# Y a-t-il un ! dans la salle ?
|
||||
neg = False
|
||||
|
||||
# Quand on quitte une pile parenthésée, on veut savoir quel était
|
||||
# l'opérateur actif avant, pour que le comportement de la fonction
|
||||
# soit défini.
|
||||
anciens_operateurs = []
|
||||
|
||||
for char in filtre:
|
||||
if char == "(":
|
||||
|
||||
# Une nouvelle stack ne démarre que si le dernier argument a été dumpé
|
||||
# dans l'ext stack (si ce n'est pas le cas quand on respecte la syntaxe
|
||||
# des filtres, la fonction est mal codée, donc on plante).
|
||||
if argument != "":
|
||||
raise ValueError('Argument entammé non terminé !')
|
||||
|
||||
# Un dumpe ext_stack dans la stack en cours.
|
||||
stacks[pos] += "%s" % (ext_stack)
|
||||
|
||||
# On augmente le conteur de la stack
|
||||
pos = pos + 1
|
||||
|
||||
# On (ré)?initialise la stack
|
||||
stacks[pos] = ''
|
||||
|
||||
# On stocke l'opérateur en cours dans la stack inférieure dans
|
||||
# une liste.
|
||||
anciens_operateurs.append(operateur)
|
||||
|
||||
# On flush operateur
|
||||
operateur = ""
|
||||
|
||||
# On flush ext_stack, l'environnement est enfin propre pour
|
||||
# bosser dans la nouvelle pile.
|
||||
ext_stack = ""
|
||||
|
||||
elif char == ")":
|
||||
# Cas classique
|
||||
if operateur == "|":
|
||||
ext_stack += "(%s)" % argument
|
||||
|
||||
# Moins classique, &| est un opérateur servant à dire qu'on
|
||||
# a déjà croisé un | dans la stack en cours, le cas échéant,
|
||||
# celui-ci doit être pris en compte, pour respecter la
|
||||
# priorité du &. Dans ce cas seulement, une parenthèse
|
||||
# est ouverte et non fermée (cf elif char == '&' cas
|
||||
# operateur == "|"), on la ferme ici.
|
||||
elif operateur == "&|":
|
||||
argument += ")"
|
||||
ext_stack += "(%s)" % argument
|
||||
|
||||
# Classique
|
||||
elif operateur == "&":
|
||||
ext_stack += "(%s)" % argument
|
||||
|
||||
# Pas d'opérateur, pas de parenthèse superflue.
|
||||
else:
|
||||
ext_stack += "%s" % argument
|
||||
|
||||
# On passe la stack en argument, les parenthèses
|
||||
# l'encadrant seront placées d'un qu'un opérateur
|
||||
# sera croisé.
|
||||
argument = "%s%s" % (stacks[pos], ext_stack)
|
||||
|
||||
# Ménage
|
||||
stacks[pos] = ""
|
||||
ext_stack = ""
|
||||
pos = pos - 1
|
||||
|
||||
# Retour à l'opérateur de la stack précédente.
|
||||
operateur = anciens_operateurs.pop()
|
||||
|
||||
elif char == "|":
|
||||
if not argument:
|
||||
raise ValueError('Aucun argument')
|
||||
|
||||
# Ce cas permet d'éviter une répétition de la forme :
|
||||
# (|(a)(|(b)(c))), quand on est déjà dans un ou, on
|
||||
# rajoute juste l'argument suivant sans remettre de
|
||||
# symbole.
|
||||
if operateur == "|":
|
||||
# neg est True si on a croisé un ! dans la chaîne.
|
||||
# À améliorer pour qu'il ne marche que pour !=
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
# Ajout à la stack externe de l'argument
|
||||
ext_stack += "(%s)" % argument
|
||||
argument = ""
|
||||
|
||||
elif operateur == "&":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "(%s)" % argument
|
||||
|
||||
# | prend le relais sur &, on dumpe ext_stack et on commence une nouvelle
|
||||
# chaîne qui sera ajoutée à droite. Le ou va tout à gauche de la stack
|
||||
# en cours, pour s'appliquer sur tout son contenu.
|
||||
stacks[pos] = "%s(%s%s)" % (char, stacks[pos], ext_stack)
|
||||
ext_stack = ""
|
||||
argument = ""
|
||||
operateur = "|"
|
||||
|
||||
# C'est un & dans un |, donc on ferme juste la chaîne
|
||||
# des &, d'où la parenthèse fermante en trop.
|
||||
elif operateur == "&|":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "(%s)" % argument
|
||||
argument = ""
|
||||
stacks[pos] = "%s%s)" % (stacks[pos], ext_stack)
|
||||
ext_stack = ""
|
||||
operateur = "|"
|
||||
|
||||
# Pas encore d'opérateur annoncé
|
||||
elif operateur == "":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "%s" % argument
|
||||
argument = ""
|
||||
|
||||
# ouverture
|
||||
stacks[pos] = "%s(%s%s)" % (char, stacks[pos], ext_stack)
|
||||
ext_stack = ""
|
||||
operateur = "|"
|
||||
|
||||
else:
|
||||
raise TypeError('Erreur d\'opérateur.')
|
||||
|
||||
elif char == "&":
|
||||
if not argument:
|
||||
raise ValueError('Aucun argument')
|
||||
|
||||
if operateur == "&":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "(%s)" % argument
|
||||
argument = ""
|
||||
|
||||
# Le cas spécial, on ouvre un & après un |, donc pour respecter
|
||||
# la priorité de &, on démarre une nouvelle chaîne, mais dans
|
||||
# l'ext_stack (contrairement à char == '|', operateur == "&")
|
||||
elif operateur == "|":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "(%s(%s)" % (char, argument)
|
||||
argument = ""
|
||||
operateur = "&|"
|
||||
|
||||
# On était déjà dans un &|...
|
||||
elif operateur == "&|":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "(%s)" % argument
|
||||
argument = ""
|
||||
|
||||
# Comme ci-dessus
|
||||
elif operateur == "":
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
neg = False
|
||||
|
||||
ext_stack += "%s" % argument
|
||||
argument = ""
|
||||
|
||||
stacks[pos] = "%s(%s%s)" % (char, stacks[pos], ext_stack)
|
||||
ext_stack = ""
|
||||
operateur = "&"
|
||||
|
||||
else:
|
||||
raise TypeError('Erreur d\'opérateur.')
|
||||
|
||||
elif char == "!":
|
||||
neg = True
|
||||
|
||||
# Remplissage d'argument
|
||||
else:
|
||||
argument += char
|
||||
|
||||
# Décommenter pour débug.
|
||||
# En modifiant un peu, encore plus utile pour savoir ce qu'il
|
||||
# fait à chaque étape !
|
||||
#print stacks
|
||||
#print pos, argument, ext_stack, operateur
|
||||
|
||||
if pos > 0:
|
||||
raise Exception("Tu ne sais pas parenthéser, crétin.")
|
||||
|
||||
else:
|
||||
# Comme parenthèse fermante.
|
||||
if neg:
|
||||
argument = "!(%s)" % argument
|
||||
if operateur == "&|":
|
||||
argument += ')'
|
||||
ext_stack += "(%s)" % argument
|
||||
|
||||
argument = ""
|
||||
stacks[pos] = "(%s%s)" % (stacks[pos], ext_stack)
|
||||
ext_stack = ""
|
||||
|
||||
# On retourne la pile de plus haut niveau
|
||||
return stacks[0]
|
Loading…
Add table
Add a link
Reference in a new issue