CPython - インクリメントの追加 全変更点まとめ

# 変更手順まとめ
本記事は[Pythonに前置・後置インクリメントを追加してみた](https://qiita.com/r1c0chet/items/94c6acdd02ec066dbd18)の参考ページです。

基本的に以下の順番で変更しました。
Parser/tokenizer.c, Python/ast.cなど、公式サイトでは変更が必要とされていたものでも変更していないものもあります。

## Grammar/Tokens
`++`というものが存在することを明記
```
INCREMENT               '++'
```
`$ make regen-token`を実行する必要がある

## Grammar/python.gram
実際に`++`というトークンはどのような使用法（文法）で用いられるのか，そしてどのような解釈をするのか
つまり`a = primary`（変数，配列，構造体）に対して`++a`, `a++`という文法を許容・追加し，それぞれ前置・後置インクリメントとして解釈すると記述した
```
factor[expr_ty] (memo):
    | '+' a=factor { _PyAST_UnaryOp(UAdd, a, EXTRA) }
    | '-' a=factor { _PyAST_UnaryOp(USub, a, EXTRA) }
    | '~' a=factor { _PyAST_UnaryOp(Invert, a, EXTRA) }
    | '++' a=primary { _PyAST_UnaryOp(PreIncr, a, EXTRA) }
    | a=primary '++' { _PyAST_UnaryOp(PostIncr, a, EXTRA) }
    | power
```
`$ make regen-pegen`を実行する必要がある

## Parser/Python.asdl
`unary_op`に`Pre/PostIncr`を追加
```
unaryop = Invert | Not | UAdd | USub | PreIncr | PostIncr
```
`$ make regen-ast`を実行する必要がある

## Python/ast_unparse.c
```
static int
append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, int level)
{
    const char *op;
    int pr;

    switch (e->v.UnaryOp.op) {
    case Invert: op = "~"; pr = PR_FACTOR; break;
    case Not: op = "not "; pr = PR_NOT; break;
    case UAdd: op = "+"; pr = PR_FACTOR; break;
    case USub: op = "-"; pr = PR_FACTOR; break;
    case PreIncr: op = "++"; pr = PR_FACTOR; break;
    case PostIncr: op = "++"; pr = PR_FACTOR; break;
    default:
        PyErr_SetString(PyExc_SystemError,
                        "unknown unary operator");
        return -1;
    }

    APPEND_STR_IF(level > pr, "(");
    APPEND_STR(op);
    APPEND_EXPR(e->v.UnaryOp.operand, pr);
    APPEND_STR_IF(level > pr, ")");
    return 0;
}
```

## Lib/opcode.py
オペコードの定義
```
def_op('UNARY_PREINCREMENT', 13)
def_op('UNARY_POSTINCREMENT', 14)
```

## Doc/Library/dis.rst
```
**Unary operations**
.. opcode:: UNARY_PREINCREMENT

   Implements ``TOS = TOS + 1``.

.. opcode:: UNARY_POSTINCREMENT

   Implements ``TOS = TOS + 1``.
```
`$make regen-opcode regen-opcode-targets`を実行する必要がある

## Python/ceval.c
オペコードにしたがって実行されるTARGETを記述
ここでは`+1`をしていて，`STORE`，`RETURN_VALUE`のためにスタックをセットしている．
```
TARGET(UNARY_PREINCREMENT) {
    PyObject *value = TOP();
    PyObject *res = PyNumber_Add(value, _PyLong_GetOne());
    Py_DECREF(value);
    SET_TOP(res);
    PUSH(res);
    if (res == NULL)
        goto error;
    DISPATCH();
}

TARGET(UNARY_POSTINCREMENT) {
    PyObject *value = TOP();
    PyObject *res = PyNumber_Add(value, _PyLong_GetOne());
    PUSH(res);
    if (res == NULL)
        goto error;
    DISPATCH();
}

```
`$ make regen-importlib`を実行する必要がある

## Python/compile.c
コンパイラの動作の記述
`Pre/PostIncr`を受け取ると，`UNARY_PRE/POSTINCREMENT`と型にあった適切な`STORE`を実行する
```
static int
compiler_visit_expr1(struct compiler *c, expr_ty e)
{
    switch (e->kind) {
    // 省略
    case UnaryOp_kind:
        VISIT(c, expr, e->v.UnaryOp.operand);
        ADDOP(c, unaryop(e->v.UnaryOp.op));
        if (e->v.UnaryOp.op == PreIncr || e->v.UnaryOp.op == PostIncr) {
            // increment op
            expr_ty operand = e->v.UnaryOp.operand;
            if (e->v.UnaryOp.operand->kind == Name_kind) {
                // store name
                compiler_nameop(c, operand->v.Name.id, Store);
            }
            else if (e->v.UnaryOp.operand->kind == Subscript_kind) {
                // store subscript
                operand->v.Attribute.ctx = Store;
                VISIT(c, expr, operand);
            }
            else if (e->v.UnaryOp.operand->kind == Attribute_kind) {
                // store attribute
                operand->v.Attribute.ctx = Store;
                VISIT(c, expr, operand);
            }
            else {
                // type error
                PyErr_Format(PyExc_SystemError,
                "invalid node type (%d) for increment",
                e->kind);
                return 0;
            }
        }
        break;
    // 省略
    return 1;
}
```

## Lib/ast.py
unop, unop_precedenceに`++`を追加
```
unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-", "PreIncr": "++", "PostIncr": "++"}
unop_precedence = {
    "not": _Precedence.NOT,
    "~": _Precedence.FACTOR,
    "+": _Precedence.FACTOR,
    "-": _Precedence.FACTOR,
    "++": _Precedence.FACTOR,
}
```

## Doc/Library/ast.rst
```
.. class:: UAdd
           USub
           Not
           Invert
           PreIncr
           PostIncr
```