Comment compiler un décorateur - C ++, Python et implémentation personnalisée. Partie 2

Les décorateurs sont l'une des fonctionnalités les plus inhabituelles de Python. Il s'agit d'un outil qui ne peut exister pleinement que dans une langue interprétée et typée dynamiquement. Dans la premiÚre partie de l'article, mon amiSorceleur136 a montré comment implémenter en C ++ la version la plus proche de la version de référence (Python) des décorateurs.



Je vais vous expliquer comment j'ai décidé d'essayer d'implémenter des décorateurs dans un langage de programmation compilé , pour lequel j'ai fini par écrire mon propre petit compilateur Haskell basé sur LLVM .





Table des matiĂšres



  1. Comment les décorateurs fonctionnent en Python
  2. Haskell et LLVM - compilateur natif
  3. Alors, comment compilez-vous un décorateur?




Comment les décorateurs fonctionnent en Python



Avant de plonger dans l'algorithme de compilation des dĂ©corateurs, parlons de l'implĂ©mentation des dĂ©corateurs en python, et pourquoi il ne peut pas ĂȘtre reproduit sous la mĂȘme forme dans le langage compilĂ©. Je note tout de suite que dans cet article, python est compris comme CPython. Toutes les piĂšces du compartiment moteur s'y rĂ©fĂšrent uniquement.



, , , , — , .



Python, - , :



decorator, func, old. new — old


def decorator(func):
    def new(*args, **kwargs):
        print('Hey!')
        return func(*args, **kwargs)
    return new

@decorator
def old():
    pass

# old()  "Hey!" -   old    new


— , -, — , .



CPython

Python-. , - — , , , . , , , — - "" .



, , , — - "" . : BINARY_SUBSTRACT () TypeError, 1 'a'. , STORE_FAST ( ), , , TypeError, .. STORE_FAST — .



, new — . -, , , decorator old.



1. —



. decorator , :



name = input('  ')

def first(func):
    ...  #  

def second (func):
    ...  #  

if name == 'first':
    decorator = first
elif name == 'second':
    decorator = second
else:
    decorator = lambda f: f   #    

@decorator 
def old():
    pass


, old . (, C++) , (- ), . Python — , , , " ", .



, , old void-, , — , , , .



, Python, : .



2. Python



def decorator(func):
    def two_args(x, y):
        ...
    return two_args

@decorator
def one_arg(x):
    ...


, . one_arg , ( ) — , , , (, "" ). , ? " " . , , decorator -, .



, , , — . , .



— — func? , , — , . func A, A. void* func, , .



— func , — Witcher136 . , (. C++ ).






. :



  • — ?
  • — ?
  • , , ( )


, Python — . , — Python — .

— " ", , , . , .



.





Haskell LLVM —



Haskell, , LLVM . Haskell llvm-hs, LLVM. Parsec, , - ( , , Parsec — parser combinators).



, Grit, ( , , ) — . .



Grit — expression-oriented ()



Grit, , if-else, , — , .



int main() = {
    int i = 0;
    i = i + if(someFunction() > 0) {
        1;
    }
    else {
        0;
    };
};


, i 1, someFunction , , 0 .



return



, ( ) .



, — , Grit, — , . returns, — , ; .



, , "" — "", — , .



int simple(int x) = {
    /* 
          
        x   y
    */
    int y = someOtherFunction();
    x + y;
};

/*
   ,    ,    .
      ,   
*/
int incr(int x) = x + 1;

int main() returns statusCode {
    /*
             returns
         ,  
           .
         "" 
         ,     
    */
    int statusCode = 0;
    int result = someFunction();
    if (someFunction < 0) {
        statusCode = 1;
    };
};


Auto — Grit



Grit auto, , ( ) .



— , . — — , — ..

, , returns.



auto half (int x) = x / 2;   //   incr    float





(expression-oriented), return ( — ) — Grit. , .

, , .



— ?





?



, , — runtime compile-time, .



, , , — , .



-, Grit — , ( AST, abstract syntax tree), . -, , .



, :



@auto flatten = {
    auto result = @target;
    if (result < 0) {
        0;
    }
    else {
         result;
    };
};


, , 0, 0, .



@auto flatten — flatten @auto — , (@ — , , ).



. , — , , , .



— @target. , . ( ), , , , ( ).

, AST @target, . , , — . , .



, Grit, — , Python.



, :



@auto lockFunction = {
    mutex.lock();
    @target
};


, - :



@auto optional = if (checkCondition()) {
    @target;
}
else {
    someDefaultValue;
};




Grit :



@auto flatten = {
    auto result = @target;
    if (result < 0) {
        0;
    }
    else {
         result;
    };
};

@flatten
int incr(int x) = x+1;


flatten , .



"" , - :



Decorator "flatten" auto {
  BinaryOp = (Def auto "result") (DecoratorTarget)
  If (BinaryOp < (Var "result") (Int 0)) {
    Int 0
  }
  else {
    Var "result"
  }
}
Function "incr" int ; args [Def int "x"] ; modifiers [Decorator "flatten"] ; returns Nothing {
  BinaryOp + (Var "x") (Int 1)
}


, — Decorator, incr , Decorator "flatten". DecoratorTarget — incr.



, — . , , , "" — , .



, :



Function (int -> int) incr ["x"] {
  BinaryOp i= (Def int "result") (
    Block int {
      BinaryOp i+ (Var int "x") (int 1)
    }
  )
  If int (BinaryOp b< (Var int "result") (int 0)) {
    int 0
  }
  else {
    Var int "result"
  }
}


:



  • — AST, .
  • incr — , flatten, DecoratorTarget Block {...} — " ", . , , — int "result". BinaryOp i= int-, result auto — , , .


, , , . Python, , , Grit.



, — , , :



@auto lockF(mutex M) {
    M.lock();
    @target;
};

@lockF()
int someFunction(...)


— mutex M, "", (, , Python — ).



, @args, , " " . , @args.length — , @args.1 — . - , - — .



, Haskell , , , , . , ( , ), - .



, stack



PS Ce fut une expérience trÚs intéressante et inhabituelle pour moi - j'espÚre que vous aussi vous pourrez tirer quelque chose d'utile de cette histoire. Si vous avez besoin d'un article séparé sur l'écriture d'un compilateur Haskell basé sur LLVM, écrivez dans les commentaires.

Je vais essayer de répondre à toutes les questions dans les commentaires, ou dans un télégramme - @ nu11_pointer_exception




All Articles