にほんごのれんしゅう

日本語として伝えるための訓練を兼ねたテクログ

shedskin

shedskinとは

 PythonのコードをC++に変換するもの.
 もう,C++で書くのがめんどくさくなったら,これで出力したコードをコピペしてC++の開発を行えばよろしい.
Wikipediaによれば下記のように認識しているようである.

Shed Skin は、暗黙的に静的に型付けされたPythonプログラムを最適化されたC++プログラムに変換する実験的なコンパイラである。型についての制約条件を満たすため、プログラムは多くの場合変更する必要があるが、変更した後でも、Python プログラムとしての正しさは保つことができる。Shed Skin は現在のところ Python の標準ライブラリをそれほど使用していない小さなプログラムに限定されている。現在までに変換できた最大のプログラムは 1,600 行である。

補足

暗黙的に静的に型付けとは?
以下に,暗黙的に静的に型付けしたものと違うものを示す
正例

some = ""
some = "hello, world"

負例

some = 10
some = "hello, world" #int型からstr型への変換はC++的には無理

使用できる標準ライブラリは?
- re
- math
- os
- sys

使用できない標準ライブラリは?
- liburl
- pickle
- ほかたくさん

なぜ,1600行程度が解釈限界なのか
C++に変換されたコードを確認すると定数やループ処理に特別な変数を使っているようである.この変数に使用回数に限度がある.
これは,ScalaがJavaVirutalMachineの中間言語を吐き出すときに,Scalaコンパイラが暗黙的にいろんな変数を作ることと,チューリング完全にするために再帰的な処理を途中で打ち切ってある程度余裕をもたして22変数までしか作らないこととと類似している.

コンパイラの解釈レベルをあげればいいのか? 解釈レベルを1depthあげるだけで,コンパイル時間が爆発したり,いろいろなことを犠牲にしなくてはならないという反作用を持っているので,ライブラリに手を入れられないニュービーであると自覚するものには拡張不能である.
型論,圏論の専門家が制限をいつか取り払ってくれることを期待しよう.

Noneは使えるか

string型のときのみ,なぜかNoneがサポートされていた.
None型をIntに変換しようしとしたら型情報不一致でgccコンパイルできなかった.
None型はstring型に変換可能.
これは設計者がcharのデフォルトはNULL or nullptrであるからという認識に基づいているものである.
Noneが全部に使えないのは痛いなぁ,,,*

classは作れるのか

作れる.
しかし,かなり独特なクラス設計になうので,覚悟されたほうがよい

class Moge:
   def __init__(self):
     self.some    = None
     self.someNum = None #数字を意図して初期化しようとしてはNG
   def echo(self):
     print self.some
     return self.some

上記のようなクラスをpythonで作成するとする.
変換されたC++のコードのプロトタイプ宣言は以下のものである.

using namespace __shedskin__; //namespace名はこれで決定らしい
namespace __test01__ { //test01はファイル名であった.ファイル名がnamespaceになるのだろう
extern str *const_0, *const_1; //外部に公開することがあるということだろう.soモジュールを作ることにも使えそうである.
class Moge; //唐突なプロトタイプ宣言

extern str *__name__; 
extern Moge *moge; //当然のごとく外部でこのインスタンスが使われることを想定している
extern class_ *cl_Moge;//isintanceofで型を調べるときに文字情報を引き出す変数である
class Moge : public pyobj {
public://基本的にpublic
     str *some; //なぜかstr型が特定されている.やはりNoneはstring型に許された特権のようだ
     void *someNum; //同じNoneなのにvoid
     Moge() {}//__init__のコンストラクタは無視
     Moge(int __ss_init) {//shedskinが管理する数値,人間には意味がない
         this->__class__ = cl_Moge;//isintanceofを使用時に名前解決できるようにしている
         __init__();//ここでinitを呼ぶ.Pythonのコンストラクタに相当
      }
      str *echo(); //ほとんどのstrクラスがstd::stringを再発名したメモリの自動解放機能を備えている
      void *__init__(); 
 };
 } // module namespace

さて,プロトタイプ宣言はここまで.
実装を見ていくことにしよう.

#include "math.hpp" 
#include "os/__init__.hpp" 
#include "os/path.hpp"
#include "test01.hpp"

namespace __test01__ {
str *const_0, *const_1; //externする意味があんまりないんじゃない
str *__name__;
Moge *moge;
/**
class Moge
*/
class_ *cl_Moge;
str *Moge::echo() {
    print2(NULL,0,1, this->some);//独自プリント関数, shared objectにして外部参照したらsegmentation faultした.NULL,0,1に意味がありそうである
    return this->some;
}
void *Moge::__init__() {
    this->some = NULL;
    this->someNum = NULL;
    return NULL; //時代はまだnullptrを認めていない
}
void __init() {
    const_0 = new str("__main__"); //文字リテラルはすべて strインスタンス化する
    const_1 = new str("hello, world");
    __name__ = new str("__main__");
    cl_Moge = new class_("Moge"); //isintanceof用
    if (__eq(__name__, const_0)) {
        moge = (new Moge(1)); //1という,マジックナンバーがわからない
        moge->some = const_1;
        moge->echo();
    }
}

} // module namespace

int main(int __ss_argc, char **__ss_argv) {
    __shedskin__::__init(); //この辺は全部関数名変えて利用するのがいいよね
    __re__::__init();
    __sys__::__init(__ss_argc, __ss_argv);
    __stat__::__init();
    __os__::__path__::__init();
    __os__::__init();
}