NaomiatLibrary
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 5班進捗シート # day2(10/1) とりあえずインクリメントを先輩のを真似して実装してみることに https://qiita.com/DOSS_INCREMENT/items/8b050847145f635211e2 mainから辿っていく main->Py_BytesMain->pymain_main->Py_RunMain->pymain_run_python->pymain_run_file(main.c:309)-> main.c:373 PyRun_AnyFileExFlags(6)-> PyRun_SimpleFileExFlags(pythonrun.c:L341)-> pythonrun.c:398 PyRun_FileExFlags(fp, filename, Py_file_input, d, d,closeit,flags);(pythonrun.c:1038)-> pythonrun.c:1054 PyParser_ASTFromFileObject(fp, filename, NULL, start, NULL, NULL,flags, NULL, arena); おそらくこの中を見ればいいはず。というところまでわかった。 # day2.5 ## デバッグのメモ uftraceでどんな関数が呼び出されてるかみてみるといいかも http://namopa.hatenablog.com/entry/2017/12/13/174725 http://namopa.hatenablog.com/entry/2017/12/13/175106 uftraceがうまくいかなかったらlibitrace https://doss-gitlab.eidos.ic.i.u-tokyo.ac.jp/tau/libitrace ## その他参考にしたもの [python3.7でインクリメント](https://hackernoon.com/modifying-the-python-language-in-7-minutes-b94b0a99ce14) [これもcpythonの改造](https://yigarashi.hatenablog.com/entry/cpython) ドキュメントたち https://devguide.python.org/grammar/ https://pythonextensionpatterns.readthedocs.io/en/latest/refcount.html https://prog-lang-sys-ja-slack.github.io/wiki/ ↑こんなのに参加してみてもいいかもしれない ## インクリメントの実装(準備運動) branchを切るのを忘れずに. ## python.gram python.gramの文法が全くわからない… ``` Grammar/python.gram: The grammar, with actions that build AST nodes. After changing it, run make regen-pegen, to regenerate Parser/parser.c. (This runs Python’s parser generator, Tools/peg_generator). ``` って書いてあるのでとりあえず試してみたけど,make regen-pegenが通らない(future feature annotations is not definedが出る) ->python3.7でやる それでもsyntax error ->セイウチ演算子が使われているので3.8以上が必要.できた.ただしこれをやるとgnome-terminal(ubuntuの端末)が起動しなくなるのでやめましょう。… 多分pyenvでバージョン管理してやるとか色々できると思いますがわからなかったのでお願いします Grammer/python.gram :455(factorのところ) ``` | '++' a=factor {_Py_BinOp(a,Add,a,EXTRA)} ``` Grammer/Tokens:38(良さげなところに追加) ``` INCREMENT '++' ``` ```bash make regen-token make regen-pegen ``` たしかにparser.cとtoken.cとtoken.hが変更された。 これを`make`した結果はこれ ![](https://i.imgur.com/MXK7K1g.png) 二倍を返す特に役に立たない演算子ができた. ## インクリメントの実装 じゃあこれをインクリメントにしていく。 ``` | '++' a=factor { _Py_UnaryOp(UInc, a, EXTRA)} ``` にpython.gramを変更. お仲間のUAddとかがどこで定義されているか調べたい。とりあえず`make regen-pegen`あとに`make`してみる。 parser.cで`error:UInc undeclared`が出る。 Parser/Python.asdl ``` unaryop = Invert | Not | UAdd | USub | UInc ``` ``` make regen-ast ``` Include/Python-ast.hとPython/Python-ast.cが再生成される. この状態で`make`と`make install`できるが(install中にlibinstallがfailedするようになる、後述),pythonを実行すると`SystemError: unary op 5 not be possible`が出る。 UAddが他にどういうところで出てくるかを調べる.compileが怪しい? Python/compile.c ```c case UNARY_POSITIVE: case UNARY_NEGATIVE: case UNARY_NOT: case UNARY_INVERT: case UNARY_INCREMENT: ``` ```c case Usub: return UNARY_NEGATIVE; case UInc: return UNARY_INCREMENT; ``` makeすると`'UNARY_INCREMENT' undeclared`が出る。それはそう。 Incrude/opcode.h ``` #define UNARY_INCREMENT 166 ``` python3を実行すると`Python/compile.c:1157 compiler_addop: Assertion '!HAS_ARG(opcode)' failed`が出る。 原因を調べると,以下のようにすれば良さそうなことがわかる. Incrude/opcode.h ```c #define UNARY_INCREMENT 13 ``` もう一度python3を実行する. ``` XXX lineno: 1, opcode: 101 Traceback (most recent call last): File "<stdin>", line 1, in <module> SystemError: unknown opcode ``` (先輩のブログより抜粋)それにしたってopcode.hでオペコードを定義したのにunknownとはどういうことか」と思ってもう一度opcode.hを開いてみる。一行目に opcode.h ``` /* Auto-generated by Tools/scripts/generate_opcode_h.py */ ``` つまり自動生成されているので, code:python Lib/opcode.py ```python def_op('UNARY_INCREMENT', 13) ``` とした後. ``` regen-opcode regen-opcode-targets ``` する.(regen-allでも良い) あとはブログと同じになってきたのでブログを読んでコピペ Python/ceval.c ```c TARGET(UNARY_INCREMENT) { PyObject *right = TOP(); PyObject *inv, *sum; // note that -(~x) == x+1 for all x inv = PyNumber_Invert(right); //Py_DECREF(left); if (inv == NULL) goto error; sum = PyNumber_Negative(inv); Py_DECREF(inv); if (sum == NULL) goto error; SET_TOP(sum); DISPATCH(); } ``` あとはstoreを追加するだけ. 先輩がやっていた手法がよく理解できなかったのでとりあえずカスみたいな実装をしといた. STORE_NAMEを実行していることが`./bin/python3 -m dis <filename>`からわかるので、TARGET(STORE NAME)を真似 Python/ceval.c ``` case TARGET(UNARY_INCREMENT): { PyObject *right = TOP(); PyObject *inv,*sum; //-(~x)=x+1 inv=PyNumber_Invert(right); if (inv == NULL) goto error; sum = PyNumber_Negative(inv); Py_DECREF(inv); if (sum == NULL) goto error; //DISPATCH(); PyObject *names = f->f_code->co_names; PyObject *name = GETITEM(names, oparg); // PyObject *name = right; PyObject *v = sum; PyObject *ns = f->f_locals; int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); Py_DECREF(v); goto error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); Py_DECREF(v); if (err != 0) goto error; Py_DECREF(right); SET_TOP(sum); DISPATCH(); } ``` できた ![](https://i.imgur.com/edMhz5s.png) できた!!!!!なんとインクリメントの実装に(だいたい)成功しました。 が、なんか挙動が不自然。最後のところでtestは4,hogeは1にならなければいけません。たぶんceval.cのせい。めんどくさいので(day3まで)直しません。 よく使うこういうのは大丈夫そう ![](https://i.imgur.com/OIHS97E.png) ## チェックリストにあるのにやっていないこと [o]Python/ast.c will need changes to validate AST objects involved with the grammar change. ## 感想 練習としてやろうということでしたが,先輩たちのブログが有能すぎて重要なところはコピペでできてしまったのであまり練習になりませんでした感がある ## 詰まったこと python3.6.9だと__future__構文が使えなくてParserを作成するためのmakeに失敗した # day3 day2.5の確認 # day4 ## gitlab gitlabの設定を完了した ## やること決めた - 三項演算子をC言語風にする - - switchをつくる ## インクリメントでエラーが出ることを確認 ### setupterm python.gram, Python.asdlを書き換えた後make clean -> make regen-all -> make とすると途中で下のようなメッセージ。 ``` /home/denjo/doss/cpython/Modules/_cursesmodule.c: In function ‘_curses_setupterm_impl’: /home/denjo/doss/cpython/Modules/_cursesmodule.c:3362:35: error: implicit declaration of function ‘setupterm’; did you mean ‘set_term’? [-Werror=implicit-function-declaration] if (!initialised_setupterm && setupterm((char *)term, fd, &err) == ERR) { ^~~~~~~~~ set_term cc1: some warnings being treated as errors building '_curses_panel' extension ``` ### make installが止まる make installするとtestのあたりで以下のように止まってしまった。libinstall で失敗している。 ``` Compiling '/home/denjo/doss/cpython_install/lib/python3.10/test/test_winreg.py'... Exception in thread Thread-1: Traceback (most recent call last): File "/home/denjo/doss/cpython_install/lib/python3.10/threading.py", line 960, in _bootstrap_inner Compiling '/home/denjo/doss/cpython_install/lib/python3.10/test/test_winsound.py'... self.run() File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/process.py", line 320, in run self.terminate_broken(cause) File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/process.py", line 455, in terminate_broken work_item.future.set_exception(bpe) File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/_base.py", line 540, in set_exception raise InvalidStateError('{}: {!r}'.format(self._state, self)) concurrent.futures._base.InvalidStateError: CANCELLED: <Future at 0x7ff8e97f03c0 state=cancelled> Traceback (most recent call last): File "/home/denjo/doss/cpython_install/lib/python3.10/compileall.py", line 460, in <module> exit_status = int(not main()) File "/home/denjo/doss/cpython_install/lib/python3.10/compileall.py", line 437, in main Compiling '/home/denjo/doss/cpython_install/lib/python3.10/test/test_with.py'... if not compile_dir(dest, maxlevels, args.ddir, File "/home/denjo/doss/cpython_install/lib/python3.10/compileall.py", line 112, in compile_dir success = min(results, default=True) File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/process.py", line 559, in _chain_from_iterable_of_lists for element in iterable: File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/_base.py", line 600, in result_iterator yield fs.pop().result() File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/_base.py", line 440, in result Compiling '/home/denjo/doss/cpython_install/lib/python3.10/test/test_xdrlib.py'... return self.__get_result() File "/home/denjo/doss/cpython_install/lib/python3.10/concurrent/futures/_base.py", line 389, in __get_result raise self._exception concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending. Compiling '/home/denjo/doss/cpython_install/lib/python3.10/test/test_wsgiref.py'... KeyboardInterrupt Makefile:1451: recipe for target 'libinstall' failed make: [libinstall] 割り込み (無視されました) ``` UAddはあってUIncがないファイルを探したいので以下でにらめっこ。Python/ast_unparse.cが見つかる。どれが自動生成されるファイルなのかがはっきりしなくて苦労。 ``` ~/doss/cpython$ grep UAdd -r ./ ~/doss/cpython$ grep UInc -r ./ ``` Python/ast_unparse.c :179でUnaryOpのpriorityを定義しているので ``` case UInc: op = "++";pr = PR_FACTOR; break; ``` を追加したところ解決。(priorityが適切かは怪しい...) ### `hoge+ ++a`でhogeが++aになる 前述の通り。 ## `if ~ then ... else xxx` ブランチを切るのをわすれずに ``` git checkout master git checkout -b ternary ``` とりあえずインクリメントにはバグがたくさん存在するので、インクリメントを実装する前の段階から実装しています(私は) これでmake,make installすると止まらないでmake installが完了する 構文木がどうなるのか全然わからん とりあえず似ている構文について見てみる? `... if ~ else xxx`について見てみる ![](https://i.imgur.com/uXbDhB5.png) ↑ceval.cの中でどこを使ってるのかわかる 条件を先に評価して格納し、POP_JUMP_IF_FALSEをセットして、結果を読み出し、その結果でJUMP_FORWARDしてそう。 POP_JUMP_IF_FALSE のceval.c:3187が使われてそう POP_JUMP_IF_FALSEを何回か遡るとCALL_FUNCTIONが出てくる? よくわからないのでpython.gramを見てみる Grammer/python.gram ``` expressions[expr_ty]: | a=expression b=(',' c=expression { c })+ [','] { _Py_Tuple(CHECK(_PyPegen_seq_insert_in_front(p, a, b)), Load, EXTRA) } | a=expression ',' { _Py_Tuple(CHECK(_PyPegen_singleton_seq(p, a)), Load, EXTRA) } | expression expression[expr_ty] (memo): | a=disjunction 'if' b=disjunction 'else' c=expression { _Py_IfExp(b, a, c, EXTRA) } | disjunction | lambdef ``` あたりが三項演算子なので、 ``` | 'if' a=disjunction 'then' b=disjunction 'else' c=expression { _Py_IfExp(a, b, c, EXTRA) } ``` `make regen-pegen` ![](https://i.imgur.com/VXjZuZK.png) できちゃった.... ### 考えるべきこと disjunctionとexpressionsの使い分け ## switchを作る if else Grammer/python.gram(157) ``` if_stmt[stmt_ty]: | 'if' a=named_expression ':' b=block c=elif_stmt { _Py_If(a, b, CHECK((asdl_stmt_seq*)_PyPegen_singleton_seq(p, c)), EXTRA) } | 'if' a=named_expression ':' b=block c=[else_block] { _Py_If(a, b, c, EXTRA) } elif_stmt[stmt_ty]: | 'elif' a=named_expression ':' b=block c=elif_stmt { _Py_If(a, b, CHECK(_PyPegen_singleton_seq(p, c)), EXTRA) } | 'elif' a=named_expression ':' b=block c=[else_block] { _Py_If(a, b, c, EXTRA) } else_block[asdl_stmt_seq*]: 'else' ':' b=block { b } ``` for Grammer/python.gram(168) ``` for_stmt[stmt_ty]: | 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] { _Py_For(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA) } | ASYNC 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] { CHECK_VERSION(5, "Async for loops are", _Py_AsyncFor(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA)) } | invalid_for_target ``` が参考にできそう ``` switch_stmt[なにか] | 'switch' a=(変数) ':' b=(case文のブロック) {_Py_Switch(a,Extra)} case_block[なにか] | 'case' a=(定数) ':' b=block {_Py_Case(a,Extra)} ``` # day4.5 ### かんがえる 「なにか」はたぶんstmt_tyだけどstmt_tyってなんだ どうやってcase文がswich文の中で行われていることを知るんだろう _Py_Caseを錬成するにあたってそれをどこで定義すればいいか _PyPegen_singleton_seqはparser.cとpegen.cにあった(parser.cはpython.gramから自動生成されるので考えなくて良さそう) pegen.cを見てみると/* Creates a single-element asdl_seq* that contains a */とある。asdl_seqってなんだ… _Py_AsyncForはPython-ast.h(Parser/Python.asdlから自動生成される)とparser.cのなかにあった バイナリコード ![](https://i.imgur.com/h7DH8wh.png) caseもLOAD_NAME LOAD_CONST COMARE_OP POP_JUMP_IF_FALSEをつかえばよさそう ### やってみる ``` | &'while' while_stmt | &'switch' switch_stmt .......https://i.imgur.com/h7DH8wh.png else_block[asdl_stmt_seq*]: 'else' ':' b=block { b } switcha_stmt[stmt_ty]: | 'switcha' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,b,EXTRA)} case_block[stmt_ty]: | 'case' a=disjunction ':' b=block c=[case_block] {_Py_Case(a,b,c,EXTRA)} ``` caseのaはatomかも つぎはParser/Python.asdlに関数を追加する ``` | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment) | AsyncFor(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment) | While(expr test, stmt* body, stmt* orelse) | If(expr test, stmt* body, stmt* orelse) | With(withitem* items, stmt* body, string? type_comment) | AsyncWith(withitem* items, stmt* body, string? type_comment) ``` の下に、 ``` | Switch(stmt* body, stmt* cases) | Case(expr test, stmt* body,stmt* orelse) ``` make regen-all が通る。warningは以下。 ``` Parser/parser.c: In function 'switch_stmt_rule': Parser/parser.c:3898:33: warning: passing argument 1 of '_Py_Switch' from incompatible pointer type [-Wincompatible-pointer-types] _res = _Py_Switch ( a , EXTRA ); ^ In file included from Parser/pegen.h:7:0, from Parser/parser.c:2: ./Include/Python-ast.h:621:9: note: expected 'asdl_stmt_seq * {aka struct <anonymous> *}' but argument is of type 'expr_ty {aka struct _expr *}' stmt_ty _Py_Switch(asdl_stmt_seq * body, int lineno, int col_offset, int ``` これはたぶんSwitch(expr test)にすることで解決する ``` Python/compile.c: In function 'compiler_visit_stmt': Python/compile.c:3381:5: warning: enumeration value 'Switch_kind' not handled in switch [-Wswitch] switch (s->kind) { ^~~~~~ Python/compile.c:3381:5: warning: enumeration value 'Case_kind' not handled in switch [-Wswitch] Python/symtable.c: In function 'symtable_visit_stmt': Python/symtable.c:1178:5: warning: enumeration value 'Switch_kind' not handled in switch [-Wswitch] switch (s->kind) { ^~~~~~ Python/symtable.c:1178:5: warning: enumeration value 'Case_kind' not handled in switch [-Wswitch] ``` make make installするとエラーが出る ``` File "/tmp/tmpoyixj5ld/pip-20.1.1-py2.py3-none-any.whl/pip/_internal/vcs/bazaar.py", line 75 def switch(self, dest, url, rev_options): ^ SyntaxError: invalid syntax ``` switchをすべてswitchaにすると消えた(荒治療) これでsyntax errorにはならないようになった気がするけどなる。なんでだろう。 python3 -dでしらべたところ、NEWLINE関係で詰まってた。 python.gramを ``` switcha_stmt[stmt_ty]: | 'switcha' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,EXTRA)} case_block[stmt_ty]: | 'case' a=disjunction ':' b=block c=[case_block] {_Py_Case(a,b,c,EXTRA)} ``` に変更 これでsyntax errorは出なくなった。 ### 中身を作る 今は中身がないので ``` python3: Parser/pegen.c:1146: _PyPegen_run_parser: Assertion `PyAST_Validate(res)' failed. Aborted ``` が出る状態。これを中身を作って消していく。 たぶんcompile.cをいじればいいはず? compile.c ``` case Switcha_kind: return compiler_switch(c, s); case Case_kind: return compiler_case(c, s); ``` で、compiler_switch,compiler_caseをcompiler_ifを参考に変えていけば良さそう ``` static int compiler_switch(struct compiler *c, stmt_ty s) { return 1; } static int compiler_case() { return 1; } ``` ``` python3: Parser/pegen.c:1146: _PyPegen_run_parser: Assertion `PyAST_Validate(res)' failed. ``` が出る。 ast.c L539 ``` case Interactive_kind: res = validate_stmts(mod->v.Interactive.body); ``` でvalidate_stmtsが0になっていることが問題のようだ。 これをgdbで追うとvalidate_stmtのなかでSwitch_kindとCase_kindがないことが問題そうに見える。 validate_stme内にとりあえず以下のように追加しておく ``` case Switcha_kind: return 1; case Case_kind: return 1; ``` エラーが出なくなった。 ただしcaseはなにもしないまま。 ![](https://i.imgur.com/5gBe74C.png) ### compiler_xxってどんなふうにできてる? ``` static int compiler_if(struct compiler *c, stmt_ty s) { basicblock *end, *next; int constant; assert(s->kind == If_kind); end = compiler_new_block(c); if (end == NULL) return 0; constant = expr_constant(s->v.If.test); /* constant = 0: "if 0" * constant = 1: "if 1", "if 2", ... * constant = -1: rest */ if (constant == 0) { BEGIN_DO_NOT_EMIT_BYTECODE VISIT_SEQ(c, stmt, s->v.If.body); END_DO_NOT_EMIT_BYTECODE if (s->v.If.orelse) { VISIT_SEQ(c, stmt, s->v.If.orelse); } } else if (constant == 1) { VISIT_SEQ(c, stmt, s->v.If.body); if (s->v.If.orelse) { BEGIN_DO_NOT_EMIT_BYTECODE VISIT_SEQ(c, stmt, s->v.If.orelse); END_DO_NOT_EMIT_BYTECODE } } else { if (asdl_seq_LEN(s->v.If.orelse)) { next = compiler_new_block(c); if (next == NULL) return 0; } else { next = end; } if (!compiler_jump_if(c, s->v.If.test, next, 0)) { return 0; } VISIT_SEQ(c, stmt, s->v.If.body); if (asdl_seq_LEN(s->v.If.orelse)) { ADDOP_JUMP(c, JUMP_FORWARD, end); compiler_use_next_block(c, next); VISIT_SEQ(c, stmt, s->v.If.orelse); } } compiler_use_next_block(c, end); return 1; } ``` ふんふん `constant = (s->v.Switcha.test == s->v.Case.test):1?0;`的なことがしたいね… # day5 stmt_ty $\rightarrow$ 何かのルールを決めてる? Parser/parser.c(3540-)(自動生成) ``` static stmt_ty if_stmt_rule(Parser *p) { D(p->level++); if (p->error_indicator) { D(p->level--); return NULL; } stmt_ty _res = NULL; int _mark = p->mark; if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { p->error_indicator = 1; D(p->level--); return NULL; } ``` ~_kindはPython/compile.cのcompiler_visit_stmtとfind_annでついあしないとだめ? ### きょうのまとめ(押川) ガワだけ作ったけどこれあんまり意味がなかったかもしれない _PyPegen_xxxにしないといけないかもしれない (いとう) 条件分岐の構造的にtry文が参考になるかなとpython.gram, python.asdlあたりを読もうとするもよくわからず。エラーハンドラとかは関係ないので流して大枠を捉えられたら...😇 (押川) まずswitchが後続ブロックとしてなんらかのstmt*をうけとるためにはstmt_tyじゃなくてasdl_stmt_seq*じゃないといけないと思うんだけど、case文は機能的にどう頑張ってもstmt_ty(関数とか加えられる)になってしまう気がする # day5.5 とりあえず以下でがんばってみる python.asdl ``` | Switcha(expr test, stmt* cases) | Case(expr test, stmt* body,stmt* orelse) ``` python.gram ``` switcha_stmt[stmt_ty]: | 'switcha' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,b,EXTRA)} case_block[stmt_ty]: | 'case' a=atom ':' b=block c=[case_block] {_Py_Case(a,b,c,EXTRA)} ``` しばらく頑張ってみたが、 ``` python3: Python/compile.c:3628: compiler_nameop: Assertion `scope || PyUnicode_READ_CHAR(name, 0) == '_'' failed. ``` これがでる ``` /* XXX Leave assert here, but handle __doc__ and the like better */ assert(scope || PyUnicode_READ_CHAR(name, 0) == '_'); ``` ここらしい なんもわからん http://www.dzeta.jp/~junjis/code_reading/index.php?Python%2F%E3%83%90%E3%82%A4%E3%83%88%E3%82%B3%E3%83%BC%E3%83%89%E7%94%9F%E6%88%90%E3%82%92%E8%AA%AD%E3%82%80 https://pf-siedler.hatenablog.com/entry/2016/11/05/135007 https://pf-siedler.hatenablog.com/entry/2016/10/29/132210 なんもわからん ``` static int compiler_case(struct compiler *c, stmt_ty s, stmt_ty switch_s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL)return 0; assert(s->kind == Case_kind);; //constantは明らかに間違っているがあとでなおす int constant = (switch_s->v.Switcha.test == s->v.Case.test)?1:0; if(constant==0){//not match BEGIN_DO_NOT_EMIT_BYTECODE VISIT_SEQ(c, stmt, s->v.Case.body); END_DO_NOT_EMIT_BYTECODE }else{//match VISIT_SEQ(c, stmt, s->v.Case.body); } if(s->v.Case.orelse){ stmt_ty nexts=s->v.Case.orelse; compiler_use_next_block(c, next); SET_LOC(c,nexts); compiler_case(c,nexts,switch_s); } compiler_use_next_block(c, end); return 1; } static int compiler_switch(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL) { return 0; } assert(s->kind == Switcha_kind); stmt_ty switch_s=s; stmt_ty nexts=s->v.Switcha.cases; compiler_use_next_block(c, next); SET_LOC(c, nexts); compiler_case(c,nexts,switch_s); compiler_use_next_block(c, end); return 1; } ``` # day6 実現したいバイトコードはたぶんこう? これだとcaseのたびにswitchの右が評価されるので直感に反していそう ``` LOAD_NAME LOAD_CONST COMPARE_OP POP_JUMP_IF_FALSE (処理) LOAD_NAME LOAD_CONST COMPARE_OP POP_JUMP_IF_FALSE (処理) LOAD_NAME ... ``` え〜いとりあえずif文そのままにした(LOAD_NAMEが何回もできるようになる設計が思い浮かばないが) python.gram ``` switcha_stmt[stmt_ty]: | 'switcha' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,CHECK((asdl_stmt_seq*)_PyPegen_singleton_seq(p, b)),EXTRA)} case_block[stmt_ty]: | 'case' a=atom ':' b=block c=case_block {_Py_Case(a,b, CHECK(_PyPegen_singleton_seq(p, c)),EXTRA)} | 'case' a=atom ':' b=block c=[default_block] {_Py_Case(a,b,c,EXTRA)} default_block[asdl_stmt_seq*]: 'defaulta' ':' b=block {b} ``` compile.c ``` static int compiler_case(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL)return 0; assert(s->kind == Case_kind); int constant =1;// (switch_s->v.Switcha.test == s->v.Case.test)?1:0; if(constant==0){//not match BEGIN_DO_NOT_EMIT_BYTECODE VISIT_SEQ(c, stmt, s->v.Case.body); END_DO_NOT_EMIT_BYTECODE }else{//match VISIT_SEQ(c, stmt, s->v.Case.body); } if(s->v.Case.orelse){ compiler_use_next_block(c, next); VISIT_SEQ(c,stmt,s->v.Case.orelse); } compiler_use_next_block(c, end); return 1; } static int compiler_switch(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL) { return 0; } assert(s->kind == Switcha_kind); compiler_use_next_block(c, next); VISIT_SEQ(c,stmt,s->v.Switcha.cases); compiler_use_next_block(c, end); return 1; } ``` ![](https://i.imgur.com/Ibkd2HR.png) 条件調べるのむずかしそう…😨 VISITでtestを訪れることでLOAD_NAMEには成功するので、 ``` static int compiler_addcompare(struct compiler *c, cmpop_ty op) { int cmp; switch (op) { case Eq: cmp = Py_EQ; break; case NotEq: cmp = Py_NE; static int compiler_compare(struct compiler *c, expr_ty e) { Py_ssize_t i, n; if (!check_compare(c, e)) { return 0; } VISIT(c, expr, e->v.Compare.left); assert(asdl_seq_LEN(e->v.Compare.ops) > 0); n = asdl_seq_LEN(e->v.Compare.ops) - 1; if (n == 0) { VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, 0)); } ``` ココらへんを参考にCOMPAREをaddすればよさそう とりあえず、LOAD_CONSTをcaseの個数しなければならないところいがいについては実装できた ``` static int compiler_case(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL)return 0; assert(s->kind == Case_kind); VISIT(c,expr,s->v.Case.test); cmpop_ty op=Eq; ADDOP_COMPARE(c,op); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, next); int constant =1;// (switch_s->v.Switcha.test == s->v.Case.test)?1:0; if(constant==0){//not match BEGIN_DO_NOT_EMIT_BYTECODE VISIT_SEQ(c, stmt, s->v.Case.body); END_DO_NOT_EMIT_BYTECODE }else{//match VISIT_SEQ(c, stmt, s->v.Case.body); } compiler_use_next_block(c, next); if(s->v.Case.orelse){ VISIT_SEQ(c,stmt,s->v.Case.orelse); } compiler_use_next_block(c, end); return 1; } static int compiler_switch(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL) { return 0; } assert(s->kind == Switcha_kind); VISIT(c,expr,s->v.Switcha.test); VISIT(c,expr,s->v.Switcha.test); VISIT(c,expr,s->v.Switcha.test); compiler_use_next_block(c, next); VISIT_SEQ(c,stmt,s->v.Switcha.cases); compiler_use_next_block(c, end); return 1; } ``` ![](https://i.imgur.com/EmsLknS.png) 天才では?しかしこれではcaseの数が3以外のときにうまく行かないはずである。 あ、あと現時点ではdefaultが常に行われているようになっているので注意(あとで治す、まあbreakを勝手に行うようにしちゃえば問題なさそう) どうやってcaseの個数だけLOAD_NAMEを行えばいいのだろうか… DUP_TOPを使ったら出来た!! ![](https://i.imgur.com/4rGMYmX.png) というわけでswitchが実装できました。 変更点一覧(自動生成されているファイルも含む) https://doss-gitlab.eidos.ic.i.u-tokyo.ac.jp/pythonista/pythonista/-/commit/c4ef8a949897e3083e51dba25ee1f4512113ef54 compile.c ``` static int compiler_case(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL)return 0; assert(s->kind == Case_kind); ADDOP(c, DUP_TOP); VISIT(c,expr,s->v.Case.test); cmpop_ty op=Eq; ADDOP_COMPARE(c,op); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, next); VISIT_SEQ(c, stmt, s->v.Case.body); ADDOP_JUMP(c, JUMP_ABSOLUTE, end); compiler_use_next_block(c, next); if(s->v.Case.orelse){ VISIT_SEQ(c,stmt,s->v.Case.orelse); } compiler_use_next_block(c, end); return 1; } static int compiler_switch(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL) { return 0; } assert(s->kind == Switcha_kind); VISIT(c,expr,s->v.Switcha.test); compiler_use_next_block(c, next); VISIT_SEQ(c,stmt,s->v.Switcha.cases); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); return 1; } ``` バイナリコード ``` 1 0 LOAD_CONST 0 ('two') 2 STORE_NAME 0 (test) 2 4 LOAD_NAME 0 (test) 3 6 DUP_TOP 8 LOAD_CONST 1 ('one') 10 COMPARE_OP 2 (==) 12 POP_JUMP_IF_FALSE 24 4 14 LOAD_NAME 1 (print) 16 LOAD_CONST 1 ('one') 18 CALL_FUNCTION 1 20 POP_TOP 22 JUMP_ABSOLUTE 68 5 >> 24 DUP_TOP 26 LOAD_CONST 0 ('two') 28 COMPARE_OP 2 (==) 30 POP_JUMP_IF_FALSE 42 6 32 LOAD_NAME 1 (print) 34 LOAD_CONST 0 ('two') 36 CALL_FUNCTION 1 38 POP_TOP 40 JUMP_ABSOLUTE 68 7 >> 42 DUP_TOP 44 LOAD_CONST 2 ('zero') 46 COMPARE_OP 2 (==) 48 POP_JUMP_IF_FALSE 60 8 50 LOAD_NAME 1 (print) 52 LOAD_CONST 2 ('zero') 54 CALL_FUNCTION 1 56 POP_TOP 58 JUMP_ABSOLUTE 68 10 >> 60 LOAD_NAME 1 (print) 62 LOAD_CONST 3 ('default') 64 CALL_FUNCTION 1 66 POP_TOP >> 68 POP_TOP 70 LOAD_CONST 4 (None) 72 RETURN_VALUE ``` ## よくわからないこと symtable.cってなにしてるの?シンボルテーブルってものを作ってるらしい。それはなにをしている? # day7 ## 提出物メモ コード スライド レポート…ブログ形式 出来たことを書く ## やりたいことを決める https://bugs.python.org/ からやりたいことを見つける なかなかできそうなものがない… https://cpython-core-tutorial.readthedocs.io/en/latest/where_should_i_start.html によるとcpythonにコミットするのは難しいらしい PEPってやつもあるらしい https://www.python.org/dev/peps/ 結局簡単そうなものが見つからず、最初に出していた案から次にやることを見つけることになった。 # day7.5 インクリメントのバグを直しておきたい compile.cを ``` static int compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) { int op, scope; Py_ssize_t arg; enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype; PyObject *dict = c->u->u_names; PyObject *mangled; assert(!_PyUnicode_EqualToASCIIString(name, "None") && !_PyUnicode_EqualToASCIIString(name, "True") && !_PyUnicode_EqualToASCIIString(name, "False")); if (forbidden_name(c, name, ctx)) return 0; mangled = _Py_Mangle(c->u->u_private, name); if (!mangled) return 0; op = 0; optype = OP_NAME; scope = PyST_GetScope(c->u->u_ste, mangled); switch (scope) { case FREE: dict = c->u->u_freevars; optype = OP_DEREF; break; case CELL: dict = c->u->u_cellvars; optype = OP_DEREF; break; case LOCAL: if (c->u->u_ste->ste_type == FunctionBlock) optype = OP_FAST; break; case GLOBAL_IMPLICIT: if (c->u->u_ste->ste_type == FunctionBlock) optype = OP_GLOBAL; break; case GLOBAL_EXPLICIT: optype = OP_GLOBAL; break; default: /* scope can be 0 */ break; } /* XXX Leave assert here, but handle __doc__ and the like better */ assert(scope || PyUnicode_READ_CHAR(name, 0) == '_'); switch (optype) { case OP_DEREF: switch (ctx) { case Load: op = (c->u->u_ste->ste_type == ClassBlock) ? LOAD_CLASSDEREF : LOAD_DEREF; break; case Store: op = STORE_DEREF; break; case Del: op = DELETE_DEREF; break; } break; case OP_FAST: switch (ctx) { case Load: op = LOAD_FAST; break; case Store: op = STORE_FAST; break; case Del: op = DELETE_FAST; break; } ADDOP_N(c, op, mangled, varnames); return 1; case OP_GLOBAL: switch (ctx) { case Load: op = LOAD_GLOBAL; break; case Store: op = STORE_GLOBAL; break; case Del: op = DELETE_GLOBAL; break; } break; case OP_NAME: switch (ctx) { case Load: op = LOAD_NAME; break; case Store: op = STORE_NAME; break; case Del: op = DELETE_NAME; break; } break; } assert(op); arg = compiler_add_o(dict, mangled); Py_DECREF(mangled); if (arg < 0) return 0; return compiler_addop_i(c, op, arg); } ``` をもとにして直しておけばいいはず # day8 以下のように直したところ、インクリメントのバグがなおった。 ceval.c ``` case TARGET(UNARY_INCREMENT): { PyObject *right = TOP(); PyObject *inv,*sum; //-(~x)=x+1 inv=PyNumber_Invert(right); if (inv == NULL) goto error; sum = PyNumber_Negative(inv); Py_DECREF(inv); if (sum == NULL) goto error; //DISPATCH(); /* PyObject *names = f->f_code->co_names; PyObject *name = GETITEM(names, ++oparg); // PyObject *name = right; PyObject *v = sum; PyObject *ns = f->f_locals; int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); Py_DECREF(v); goto error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); Py_DECREF(v); if (err != 0) goto error; */ Py_DECREF(right); SET_TOP(sum); DISPATCH(); } ``` compile.c(unaryop_kindのところ) ``` compiler_visit_expr1(struct compiler *c, expr_ty e) { switch (e->kind) { case NamedExpr_kind: VISIT(c, expr, e->v.NamedExpr.value); ADDOP(c, DUP_TOP); VISIT(c, expr, e->v.NamedExpr.target); break; case BoolOp_kind: return compiler_boolop(c, e); case BinOp_kind: VISIT(c, expr, e->v.BinOp.left); VISIT(c, expr, e->v.BinOp.right); ADDOP(c, binop(e->v.BinOp.op)); break; case UnaryOp_kind: if(e->v.UnaryOp.op==UInc){ VISIT(c, expr, e->v.UnaryOp.operand); ADDOP(c, unaryop(e->v.UnaryOp.op)); ADDOP(c, DUP_TOP); assert( e->v.UnaryOp.operand->kind==Name_kind); compiler_nameop(c,e->v.UnaryOp.operand->v.Name.id,Store); /* identifier name=e->v.UnaryOp.operand->v.Name.id; PyObject *dict = c->u->u_names; int op=STORE_NAME; PyObject *mangled=_Py_Mangle(c->u->u_private, name); Py_ssize_t arg = compiler_add_o(dict, mangled); Py_DECREF(mangled); if (arg < 0) return 0; return compiler_addop_i(c, op, arg); */ }else{ VISIT(c, expr, e->v.UnaryOp.operand); ADDOP(c, unaryop(e->v.UnaryOp.op)); } break; case Lambda_kind: ``` 全変更点一覧 https://doss-gitlab.eidos.ic.i.u-tokyo.ac.jp/pythonista/pythonista/-/commit/06c5b41f45dea105e67a7c245777d29b11979b03 # day9 残り時間でできることがなさそうなのでスライドを作り始めた。 ## 全変更点まとめ デモンストレーションのために全変更をまとめたブランチを作らなきゃ ### if then else Grammer/python.gram L332 ``` #ifdef DOSS_IFTHENELSE | 'if' a=disjunction 'then' b=disjunction 'else' c=expression { _Py_IfExp(a, b, c, EXTRA) } #endif ``` make regen-pegen ### switch Grammer/python.gram L82 ``` #ifdef DOSS_SWITCH | &'switcha' switcha_stmt #endif ``` L168 ``` #ifdef DOSS_SWITCH switcha_stmt[stmt_ty]: | 'switcha' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,CHECK((asdl_stmt_seq*)_PyPegen_singleton_seq(p, b)),EXTRA)} case_block[stmt_ty]: | 'case' a=atom ':' b=block c=case_block {_Py_Case(a,b, CHECK(_PyPegen_singleton_seq(p, c)),EXTRA)} | 'case' a=atom ':' b=block c=[default_block] {_Py_Case(a,b,c,EXTRA)} default_block[asdl_stmt_seq*]: 'defaulta' ':' b=block {b} #endif ``` Parser/Python. L38 ``` --#ifdef DOSS_SWITCH | Switcha(expr test,stmt* cases) | Case(expr test, stmt* body,stmt* orelse) --#endif ``` Python/ast.c L404(要検証) ``` #ifdef DOSS_SWITCH case Switcha_kind: return 1; case Case_kind: return 1; #endif ``` Python/compile.c L2746 ``` #ifdef DOSS_SWITCH static int compiler_case(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL)return 0; assert(s->kind == Case_kind); ADDOP(c, DUP_TOP); VISIT(c,expr,s->v.Case.test); cmpop_ty op=Eq; ADDOP_COMPARE(c,op); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, next); VISIT_SEQ(c, stmt, s->v.Case.body); ADDOP_JUMP(c, JUMP_ABSOLUTE, end); compiler_use_next_block(c, next); if(s->v.Case.orelse){ VISIT_SEQ(c,stmt,s->v.Case.orelse); } compiler_use_next_block(c, end); return 1; } static int compiler_switch(struct compiler *c, stmt_ty s) { basicblock *end, *next; next = compiler_new_block(c); end = compiler_new_block(c); if (next == NULL || end == NULL) { return 0; } assert(s->kind == Switcha_kind); VISIT(c,expr,s->v.Switcha.test); compiler_use_next_block(c, next); VISIT_SEQ(c,stmt,s->v.Switcha.cases); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); return 1; } #endif ``` L3457 ``` #ifdef DOSS_SWITCH case Switcha_kind: return compiler_switch(c, s); case Case_kind: return compiler_case(c, s); #endif ``` Python/symtable.c L1294 ``` #ifdef DOSS_SWITCH case Switcha_kind: VISIT(st, expr, s->v.Switcha.test); VISIT_SEQ(st, stmt, s->v.Switcha.cases); break; case Case_kind: VISIT(st,expr,s->v.Case.test) VISIT_SEQ(st, stmt, s->v.Case.body); if (s->v.Case.orelse) VISIT_SEQ(st, stmt, s->v.Case.orelse); break; #endif ``` ### increment Grammer/python.gram L458 ``` #ifdef DOSS_INCREMENT | '++' a=NAME { _Py_UnaryOp(UInc, a, EXTRA)} #endif ``` Grammer/Tokens L56 ``` #ifdef DOSS_INCREMENT INCREMENT '++' #endif ``` make regen-token make regen-pegen Parser/Python.asdl L99 ``` --#ifdef DOSS_INCREMENT unaryop = Invert | Not | UAdd | USub | UInc --#endif ``` make regen-ast (Include/Python-ast.h, Python/Python-ast.c, Programs/#python.c#, Parser/token.c, Parser/parser.c, Lib/token.py, Include/token.h, Doc/library/token-list.incなどは自動生成される) Lib/opcode.py L68 ``` #ifdef DOSS_INCREMENT def_op('UNARY_INCREMENT', 13) #endif ``` regen-opcode regen-opcode-targets (Include/opcode.hは自動生成される) Python/compile.c L905 ``` #ifdef DOSS_INCREMENT case UNARY_INCREMENT: #endif ``` L3470 ``` #ifdef DOSS_INCREMENT case UInc: return UNARY_INCREMENT; #endif ``` L5014 ``` case UnaryOp_kind: #ifdef DOSS_INCREMENT if(e->v.UnaryOp.op==UInc){ VISIT(c, expr, e->v.UnaryOp.operand); ADDOP(c, unaryop(e->v.UnaryOp.op)); ADDOP(c, DUP_TOP); assert( e->v.UnaryOp.operand->kind==Name_kind); compiler_nameop(c,e->v.UnaryOp.operand->v.Name.id,Store); }else{ #endif VISIT(c, expr, e->v.UnaryOp.operand); ADDOP(c, unaryop(e->v.UnaryOp.op)); #ifdef DOSS_INCREMENT } #endif break; ``` Python/ceval.c L1619 ``` #ifdef DOSS_INCREMENT case TARGET(UNARY_INCREMENT): { PyObject *right = TOP(); PyObject *inv,*sum; //-(~x)=x+1 inv=PyNumber_Invert(right); if (inv == NULL) goto error; sum = PyNumber_Negative(inv); Py_DECREF(inv); if (sum == NULL) goto error; Py_DECREF(right); SET_TOP(sum); DISPATCH(); } #endif ``` Python/ast_unparse.c L179 ``` #ifdef DOSS_INCREMENT case UInc: op = "++";pr = PR_FACTOR; break; #endif ``` コンパイル CFLAGS="-O0 -pg -DDOSS_INCREMENT=1 -DDOSS_IFTHENELSE=1 -DDOSS_SWITCH=1" ./configure --with-openssl=/usr/local/openssl-1.1.0 --with-pydebug --prefix=/home/denjo/doss/cpython_install ## 時間が余ったらおまけ switchでisで比較できるようになるには 割とめんどくさい気がしてきた ``` LOAD_NAME PUSH(is,eq) DUP_TOP_TWO POP_TOP(is,eq) LOAD_CONST COMPARE_OP POP_JUMP_IF_FALSE (処理) JUMP_ABSOLUTE POP_TOP POP_TOP ``` すればよさそう。 ``` --#ifdef DOSS_SWITCH | Switcha(expr test,stmt* cases,int? compare_type) | Case(expr test, stmt* body,stmt* orelse) --#endif ``` ``` #ifdef DOSS_SWITCH switcha_stmt[stmt_ty]: | 'switcha' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,CHECK((asdl_stmt_seq*)_PyPegen_singleton_seq(p, b)),0,EXTRA)} switchb_stmt[stmt_ty]: | 'switchb' a=disjunction ':' NEWLINE INDENT b=case_block DEDENT {_Py_Switcha(a,CHECK((asdl_stmt_seq*)_PyPegen_singleton_seq(p, b)),1,EXTRA)} case_block[stmt_ty]: | 'case' a=atom ':' b=block c=case_block {_Py_Case(a,b, CHECK(_PyPegen_singleton_seq(p, c)),EXTRA)} | 'case' a=atom ':' b=block c=[default_block] {_Py_Case(a,b,c,EXTRA)} default_block[asdl_stmt_seq*]: 'defaulta' ':' b=block {b} #endif ``` バイトコード命令の一覧 https://docs.python.org/ja/3/library/dis.html …できた。 https://doss-gitlab.eidos.ic.i.u-tokyo.ac.jp/pythonista/pythonista/-/commit/5d97958d02eaa69ba71acbce5a5e95dbd6435d43

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully