### 82.3 Extending pytranslate

Working of pytranslate:

- The entry point for pytranslate is the function `$pytranslate` defined in `share/pytranslate/pytranslate.lisp`.
- `$pytranslate` calls the function `maxima-to-ir` with the Maxima expression as an argument(henceforth referred as `expr`).
- `maxima-to-ir` determines if `expr` is atomic or non-atomic(lisp cons form). If atomic, `atom-to-ir` is called with `expr` which returns the IR for the atomic expression.
  To define/modify translation for atomic expressions, make changes to the definition of `atom-to-ir` in accordance with the IR.
- If `expr` is non-atomic, the function `cons-to-ir` is called with `expr` as an argument.
  - `cons-to-ir` looks for `(caar expr)` which specifies the type of `expr`, in hash-table *maxima-direct-ir-map* and if the type is found, then appends the retrieved IR with the result of lisp call `(mapcar #'maxima-to-ir (cdr expr))`, which applies maxima-to-ir function to all the elements present in the list. Effectively, recursively generate IR for all the elements present in `expr` and append them to the IR map for the type.
    Example:

        (%i9) show_form(a+b);
        ((MPLUS) $B $A)

        (%i10) pytranslate(a+b, t);
        (body (op + (element-array (symbol "v") (string "b")) \
        (element-array (symbol "v") (string "a"))))
        (%o10)
        (v["b"] + v["a"])

    Here, operator + with internal maxima representation, `(mplus)` is present in *maxima-direct-ir-map* and mapped to `(op +)` to which the result of generating IR for all other elements of the list (a b), i.e. `(ELEMENT-ARRAY (SYMBOL "v") (STRING "b")) (ELEMENT-ARRAY (SYMBOL "v") (STRING "a"))` is appended.

  - If `(caar expr)` is not found in *maxima-direct-ir-map*, then `cons-to-ir` looks for the type in *maxima-special-ir-map* which returns the function to handle the translation of the type of `expr`. `cons-to-ir` then calls the returned function with argument `expr` as an argument.
    Example:

        (%i11) show_form(g(x) := x^2);
        ((mdefine simp) (($g) $x) ((mexpt) $x 2))

        (%i12) pytranslate(g(x):=x^2, t);
        (body
         (body
          (func-def (symbol "g")
                    ((symbol "x") (op-no-bracket = (symbol "v") (symbol "v")))
                    (body-indented
                        (op-no-bracket = (symbol "v") (funcall (symbol "stack") \
                        (dictionary) (symbol "v")))
                        (obj-funcall (symbol "v") (symbol "ins") (dictionary \
                        ((string "x") (symbol "x"))))
                        (funcall (symbol "return")
                            (funcall (element-array (symbol "f") (string "pow"))
                                 (element-array (symbol "v") (string "x"))
                                          (num 2 0)))))
          (op-no-bracket = (element-array (symbol "f") (string "g")) \
          (symbol "g"))))
        (%o12)
        def g(x, v = v):
            v = Stack({}, v)
            v.ins({"x" : x})
            return(f["pow"](v["x"], 2))
        f["g"] = g

    Here, `mdefine`, which is the type of `expr` is present in *maxima-special-ir-map* which returns `func-def-to-ir` as handler function, which is then called with `expr` to generate the IR.
    To define/modify translation for a type, add an entry to *maxima-direct-ir-map* if only a part of the IR needs to be generated and the rest can be appended, otherwise, for complete handling of `expr`, add an entry to *maxima-special-ir-map* and define a function with the name defined in *maxima-special-ir-map* which returns the IR for the form. The function naming convention for ir generators is (type)-to-ir, where type is the `(caar expr)` for expression(`mdefine -> func-def-to-ir`). The function must return a valid IR for the specific type.

- After the generation of IR, the function `ir-to-python` is called with the generated `ir` as an argument, which performs the codegen in a recursive manner.
  - `ir-to-python` looks for lisp `(car ir)` in the hash-table *ir-python-direct-templates*, which maps IR type to function handlers and calls the function returned with `ir` as an argument.
- To extend the IR of pytranslate, define a function with the naming convention (type)-to-python and add the name to *ir-python-direct-templates*.