Como compilar um decorador - C ++, Python e sua própria implementação. Parte 2

Decoradores são um dos recursos mais incomuns do Python. Essa é uma ferramenta que só pode existir completamente em uma linguagem interpretada e de tipo dinâmico. Na primeira parte do artigo, meu amigoWitcher136 mostrou como em C ++ implementar a versão mais próxima da referência (Python) dos decoradores.



Vou contar como decidi tentar implementar decoradores em uma linguagem de programação compilada , para a qual acabei escrevendo meu próprio compilador Haskell pequeno baseado no LLVM .





Índice



  1. Como os decoradores funcionam em Python
  2. Haskell e LLVM - compilador nativo
  3. Então, como você compila um decorador?




Como os decoradores funcionam em Python



Antes de mergulhar no algoritmo de compilação do decorador, vamos falar sobre a implementação de decoradores em python e por que ele não pode ser reproduzido da mesma forma em uma linguagem compilada. Percebo imediatamente que, neste artigo, python é entendido como CPython. Todas as partes do compartimento do motor se referem apenas a ele.



, , , , — , .



Python, - , :



decorator, func, old. newold


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 flattenflatten @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". DecoratorTargetincr.



, — . , , , "" — , .



, :



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 Foi uma experiência muito interessante e incomum para mim - espero que você também tenha aprendido algo útil com essa história. Se você precisar de um artigo separado sobre como escrever um compilador Haskell baseado em LLVM - escreva nos comentários.

Vou tentar responder a quaisquer perguntas nos comentários ou em um telegrama - @ nu11_pointer_exception




All Articles