---
# System prepended metadata

title: Rpython

---

#  Rpython

RPythonは、Python言語の制限付きサブセットです。PyPyツールチェーンで動的言語インタプリタを実装するために使用されます。
<!--この制限により、RPythonのプログラムの型推論（ひいては他の言語への翻訳）が可能になります。-->


## 1. HELLO WORD 
これは、RPythonで書かれた普通のHello Worldプログラムのソースコードです。
```python=
def entry_point(argv):     #entry_pointは関数の名前です
    print "Hello, World!"
    return 0

# ターゲット関数は、RPythonプログラムのメイン関数です。
# コマンドライン引数を入力として受け取り、エントリポイント関数を返します。
def target(*args):
    return entry_point
```
コンパイラによって "hello-c "という名前の実行形式が生成される。実行ファイルを起動すると、"Hello, World!" が出ます。

```python=
vietanh@KU-info2019-031:~/Rpython$ ./hello-c
Hello, World!
```
----
RPythonの構文はPythonの制限付きバージョンなので、どんなPythonインタプリタでも以前のようにhello worldのサンプルを実行することができます。

```python=
def entry_point(argv):
    print "Hello, World!"
    return 0

def target(*args):
    return entry_point

# Pythonでスクリプトを解釈するためのエントリーポイントです。
if __name__ == "__main__":
    import sys  #sysはPythonのインタプリタや実行環境に関する情報を扱うためのライブラリです。
    entry_point(sys.argv)　　#sys.argvはコマンドライン引数を扱います。コマンドライン引数とは名前の通り、コマンドラインで指定した引数のことです＃

    
#main() は関数を呼び出しています。
if __name__ == '__main__': # __name__ は Python で使用できる隠し変数の 1 つで、モジュール名を表す文字列が入っています.
   #構文は自分がインポートされてないときだけ main() を呼び出すという意味になります。 __name__ の値を見ることで 1 つのファイルで実行スクリプトとモジュールの両方を実装することができるようになります。 
```   
-----
## ２．組み込み型 
### 2.1 真偽判定テスト
Python と同じです。
以下の値はfalseとする：

- None : 変数に None というキーワードを代入すると、その変数はどの型にも属さない変数になります。
- False
- 任意の数値型のゼロ、例えば、0, 0L, 0.0。

- 空のシーケンス、例えば、''、()、[]。 空のタプルを作りたいときは () を使います

- 空のマッピング、例えば{}。 要素が空の辞書を作る場合は x = {} とします。


それ以外の値はすべて真(True)とみなされます.
ブール値の結果を持つ演算は、常に 偽(false) の場合は 0 または False を、真(true) の場合は 1 または True を返します。
<!-- 偽:    真:   -->
----
### 2.2 ブール演算
and、or、not 使えます。


### 2.3  比較
<, <=, >, >=, ==, !=, is, is not :使えます。
isとis notはオブジェクトの同一性を比較する操作である。

### 2.4 数値型 (Numeric Types)

#### 2.4.1 組み込みの数値型(Built-in numeric types)
 数値の種類には、整数（int）、長整数(long)、浮動小数点数(float　フロート)の3種類があります。
なお、RPythonではint型とlong型は同じ型である。
- 数値に対しては四則演算ができます:
-- 加算：　x+y
-- 減算：x-y
-- 乗算: x*y
-- 除算: x/y    11/4=2.75
-- 商: x//y    11//4=2
-- 剰余: x%y   11%4=3
:::info
long(), complex(), conjugate(), x ** y, divmode(x, y), pow(x, y), float(nan) などは Python で使用できる演算や組み込み関数ですが、RPython では現在サポートされていません。しかし、RPythonのmathライブラリはいくつかの数学関数を提供しています。
:::
#### 2.4.2 ビット演算
RPythonの整数型に対するビット演算は、Pythonと同じです。
<!--
x =  2 , y =  4
x | y = 6  (or)　　　論理和
x ^ y = 6  (XOR)　　　排他的論理和：^演算：
x & y = 0  (AND) 　論理積
x << n = 32  (Bitwise left shift)　　　ビットシフト: <<演算子、
x >> n = 1  (Bitwise right shift)　　　ビットシフト:　>>演算子
~x = -3   (Bitwise NOT)　　　ビット反転
-->
2進数で表した整数型intの値の各ビットに対して、それぞれ論理積、論理和、排他的論理和、ビット反転、左ビットシフト、右ビットシフトを行う。
```python=
def numeric_bitwise():
    x = 2
    y = 4
    n = 1
    print "x = ", x, ", y = ", y
    print "x | y =", x | y      #論理和
    print "x ^ y =", x ^ y      #(XOR)排他的論理和：^演算
    print "x & y =", x & y      #(AND) 　論理積
    print "x << n =", x << n    # (Bitwise left shift) ビットシフト: <<演算子、
    print "x >> n =", x >> n    #(Bitwise right shift)　　　ビットシフト:　>>演算子
    print "~x =", ~x            # ビット反転

def entry_point(argv):
    numeric_bitwise()
    return 0

def target(*args): 　　#*args:複数の引数をタプルとして受け取る
    return entry_point
# vietanh@KU-info2019-031:~/Rpython$ ./test-c
# x =  2 , y =  4
# x | y = 6
# x ^ y = 6
# x & y = 0
# x << n = 4
# x >> n = 1
# ~x = -3
```
<!--
*argsのように*をつけた引数を定義すると、任意の数の引数を指定できる
```python=
def my_sum(*args):
    return sum(args)

print(my_sum(1, 2, 3, 4))
# 10
```
-->


- x&y: 論理積は、2つの数値の同じ位置にあるビットを互いに比較します。掛け算します。*
例えば、　2＆4＝？？？
まず、2つの数値10と12を2進数として表します:
            2=0010
            4=0100


| 2 | 4 | 2&4 |
| -- | ---| ------|
|  0  | 0 | 0     |
|   0 |  1|   0
|   1| 0 | 0
|   0 | 0 |0
  
その結果、2進数の0000が得られます。==>10進数では0という

- x|y 論理和は2つの数値の同じ位置にあるビットを比較し、足し算します。計算結果の1以上はすべて1として扱います（2→1）。 

| 2 | 4 | 2 / 4 |
| -- | ---| ------|
|  o  |0  | 0     |
|   0 |  1|   1   |
|    1| 0 | 1     |
|   0 | 0 |0      |

その結果、2進数の0110が得られる。10進数の6である。
- ~x: (NOT)ビット反転は 各ビットの逆の値を返します.ビットの符号も変更する。
<!--RPythonでは上の桁が無限に0で埋められていると見なして、反転も上の桁が無限に1で埋められているという想定でマイナスを返します:-->
==ヒント：　~x→ -(x+1) という式==
例えば：
 2=0100 (=0100 正の数なので、０前に付けます。) 
~2=1011（1011になる。 1は負の整数、011は10進数で3という数.
＝＝＞　10進数では-3という

- x ^ y:排他的論理和 (XOR)： 2つの数値の同じ位置にあるビットを互いに比較します。足し算して、計算結果の1以上はすべて０として扱います（1+1=2=0b10 → 0）


| 2 | 4 | 2^4 |
| -- | ---| ------|
|  0 |0   | 0     |
|  0 |  1 |   1   |
|    1| 0 | 1     |
|   0 | 0 |0      |

＝＝＞　10進数では 6という

- x << n: Bitwise left shift : 指定した桁だけ左にずらして、空いたビットには0が入ります。

![](https://i.imgur.com/kbXrLM4.png)
2<<1:
>0010 =2
  0100 =4
- x >> n: Bitwise right shift 指定した桁だけ右にずらして、最下位より先に押し出されたビットは消えます。0は正の数を示します, 数字の1は負の数字を表します

![](https://i.imgur.com/WbeRJpi.png)


2 >> 1

>0011  = 2
 001  = 1


#### 2.4.3 Additional methods(他のメソッド)
Pythonでは，整数型と浮動小数点型に対していくつかのメソッドが追加されています．しかし、これらのメソッドはすべてRPythonではサポートされていません。
例えば：float.is_integer()；int.bit_length()；long.bit_length()；・・・サポートされてない。

#### 2.4.4 Math functions(数学関数)
RpythonではPythonと同じ数学関数を使用できます.
数学関数には、fabs, log, log10, log1p, copysign, atan2, frexp, modf, ldexp, pow, fmod, hypot, floor, sqrt, sin, cos, acos, asin, atan, ceil, cosh, exp, fabs, sinh, tan, tanh, acosh, asinh, atanh, expm1, が含まれています。
```python=
import math

def numeric_math():
    print math.pi
    print math.log(10)
    print math.sqrt(2)   #へいほうこん

def entry_point(argv):
    numeric_math()
    return 0

def target(*args): 
    return entry_point

# vietanh@KU-info2019-031:~/Rpython$ ./test-c
# 3.14159265359
# 2.302585
# 1.414214
```
### 2.5 Iterator Types(イテレータ型)
RPython のイテレータ型は Python と似ていて、コンテナ上のイテレータに役立ちます。イテレータオブジェクトは __ iter__() と next() メソッドをサポートする必要があります。
:::info 
RPythonでは、__iter__()メソッドでリストのイテレータオブジェクトを取得することはできません。
my_list = [4, 7, 0, 3]
my_iter = my_list.__iter__()   #rython で使えない。
:::
<!-- イテレータオブジェクト（list、tuple、set など）は内部にイテレータを持ち、for 文で要素を反復的に処理する際に自動的に使われる。要は、コンテナに入っている要素一つ一つアクセスして返している。    -->
![](https://i.imgur.com/XKUsC5I.png)
- イテレータとは、list, tuple, set などの集合を表現するオブジェクトを  iter 関数  を使って  コピー  したようなものです。
- イテレータからは   next 関数  を使って、 １つずつ要素を  取り出す  ことができます。


```python=
#PYTHON
my_list = [4, 7, 0, 3]
 
# iter（）関数を使用してイテレーターを作成します
my_iter = iter(my_list)
#my_iter = my_list.__iter__()  pythonで使える。
 
#next()関数
#prints 4
print(next(my_iter))
 
#prints 7
print(next(my_iter))

#prints 0
print(my_iter.__next__())

#prints 3
print(my_iter.__next__())
  
```


<!--while True:
    try:
        i = next(my_iter)
    except StopIteration:
        break
    print(i)  
-->

<!-- Class とは：
　Pythonは、オブジェクト指向プログラミング言語の1つです。オブジェクト指向とは、値やそれを扱うためのソースコードをまとめて「オブジェクト（物）」として扱う考え方です。

　オブジェクトを表現するために重要な機能が、「クラス」です。クラスは、オブジェクトを生成するときのひな型のようなものです。
-->

<!--
オブジェクト指向におけるクラスとは、オブジェクトを生成するうえで使われる型のようなものです
-->


```python=
#RPYTHON
#オブジェクト指向におけるクラスとは、オブジェクトを生成するうえで使われる型のようなものです
#selfは、インスタンス自身を示すものです。
class Counter():　
    c = 100

    def __iter__(self):　#selfは「オブジェクト(インスタンス)自身」を意味するものです。
        return self

    def next(self):
        t = self.c
        self.c += 1
        return t

def iterator():
    l = [1, 2, 3, 4, 5]

    it = iter(l)    # return an iterator object on the list l
    print(it.next()) # リストの最初の要素をプリントする  1

    d = Counter()     #dにはクラスCounterのプロパティもあります

    it = d.__iter__()    #class Counter()　の中に 　”def __iter__(self)”　関数:　呼び出し ==> itはイテレータになります
    print(it.next())         #イテレータからはnext関数を使って、 要素を 取り出すこと  　＝100；self.c=101　になります。
    
    print(next(it))          #"def next(self)" 関数を使って　101を返します。

def entry_point(argv):
    iterator()
    return 0

def target(*args): return entry_point
```

def iterator_unsupported():
    l = [1, 2, 3, 4, 5]

    # __iter__() method for list is not supported in RPython
    it = l.__iter__()
    print(it.next())


<!--
イテレータを理解して、自分で定義できるようになると、次のようなことができるようになります:
- for 文の in で使えるようになったり
- 集合を引数に取る関数で使えるようになったりします
-->
コンテナオブジェクトの __ iter__() メソッドがジェネレータとして実装されている場合、 __ iter__() と next() メソッドを持つイテレータオブジェクトが自動的に返されます。
<!-- 
return文でそのまま値を返す関数を作ったとします。一度に大きなリストが返ってくるような関数だと、たくさんのメモリを一度に消費してしまうことになります。

そのようなときは、yieldを使う事でその莫大な量の戻り値を小分けにして返すことが出来ます。
-->
- ジェネレータは、イテレータの一種になります。要素を取り出すごとに処理を実行して、要素を生成することが出来ます。
- 繰り返し処理はyield（イールド）を使うとメモリの消費が少ない
- ジェネレータのnext関数を使う
 
```python=
class Box():
    content = []

    def add(self, cat):      #空のlist に要素を追加します
        self.content.append(cat)

    def __iter__(self):
        for i in self.content:   #リスト内の要素を繰り返します
            yield i       #要素が返す

def iterator_generator():
    b = Box()
    b.add("Tiger")
    b.add("Kitty")

    it = b.__iter__()　　　#itはイテレータになります
    print it.next()      

    for i in b:
        print i

def entry_point(argv):
    iterator_generator()
    return 0

def target(*args): 
    return entry_point

```




### 2.6 Sequence Types (シーケンス型)
文字列、Unicode文字列、リスト、タプル、バイト配列、バッファ、xrangeオブジェクトの7種類の配列があります。
```python=
def sequence():
    s = "this is a string"        #文字列
    u = u"this is a unicode string"           #Unicode文字列
    l = ["this", "is", "a", "list", "of", "strings"]      #リスト
    t = ("first", "second")      #タプル
    ba = bytearray(b"\x44\x45\x41\x44\x42\x45\x45\x46")   #バイト配列
    buf = buffer(s, 10, 6)   #バッファ
    r = xrange(0, 5, 2)   #xrangeオブジェクト

    print s; print u; print l; print t; print ba; print buf
    # this is a string
    # this is a unicode string
    # ['this', 'is', 'a', 'list', 'of', 'strings']
    # ('first', 'second')
    # DEADBEEF
    # string
    
    for i in r: print i    #0,2,4

    # x in s: True if an item of s is equal to x, else False
    if 't' in s:
        print "t is in string", s      #t is in string this is a string

    # x not in s:  False if an item of s is equal to x, else True
    if 'b' not in u:
        print "b is not in unicode string", u       #b is not in unicode string this is a unicode string

    # s + t: sとtの連結
    print l + [":)"]    #['this', 'is', 'a', 'list', 'of', 'strings', ':)']

    # s * n, n * s: にn回足すのと同じ
    print t * 2      #('first', 'second', 'first', 'second')

    # s[i]: s の第 1 項、原点 0
    print "3rd item of l is:", l[2]       #3rd item of l is: a

    # s[i:j]: からsの切れ端は、iからjまで
    print "slice of s:", s[2:-1]     #slice of s: is is a strin

    # len(s): length of s
    print "length of ba is", len(ba)   #length of ba is 8

    # s.index(x): sにおけるxの最初の出現位置のインデックス
    print l.index("of")   #4

    # s.count(x):  s におけるxの総発生数
    print s.count("is")     #2

def entry_point(argv):
    sequence()
    return 0

def target(*args): return entry_point
```

#### 2.6.1 STRING
RPythonでは、いくつかの文字列メソッドのみがサポートされています。
以下の例は、RPythonでサポートされているメソッドとその使用方法を示しています:
```python=
# -*- coding: utf-8 -*-
def strings():
    s = "this is a string"

    print s.count("this", 0, len(s))    #1

    if s.endswith("ing"): print "s ends with string"   #文字列の終わり: s ends with string

    if s.find("is"): print "found is in s"   #s文字列に"is"がある場合...

    s2 = "thisisastring2"  
    if s2.isalnum(): print "s2 is alnum"   #isalnum()メソッド は、英文字と数字以外が含まれていれば「Flase」を返すことができます。

    s3 = "thisisastringthree"
    if s3.isalpha(): print "s3 is alpha"　　#isalpha() メソッドは有効な文字列の場合、True を返します。数字や特殊文字などの他の文字が見つかった場合は、False を返します.

    s4 = "12345"
    if s4.isdigit(): print "s4 is digit"   #isdigit() メソッドは文字列中のすべての文字が数字で使われる文字列の場合にTRUEを返します

    l = ["this", "is", "a", "string"]
    print " ".join(l)      #リストの要素(str)を連結・結合する際はjoinを使います。 ==> this is a string

    print "THI IS A STRING".lower()  #小文字 : thi is a string
    print '   spacious   '.lstrip()  #引数として渡された文字をStringの左から削除します  : spacious 
    print s.rfind("is")  #rfind（）は、文字列strが見つかった最後のインデックスを返します。見つからなかった場合は-1を返します :  5
    print s.rsplit(" ")  #rsplitは右側から文字列を指定回数分割する : ['this', 'is', 'a', 'string']
    print s.split(" ") #文字列を分割する  ['this', 'is', 'a', 'string']

    s_lines = "This is a string.\nAnd another string."
    print s_lines.splitlines()

    if s.startswith("this"): print "s starts with this"

    print '   spacious   '.strip()
    print s.upper()

    print "%s, %d, %x, %o, %f" % ("string", 1, 16, 9, 3.14)

def entry_point(argv):
    strings()
    return 0

def target(*args): return entry_point
```
----
## 3.組込み関数(built-in Functions)
Python インタープリタには多くの組み込み関数がありますが、RPython でサポートされているのはそのうちのわずかなものです。
:::info
RPythonでは組み込みの関数は非常に限られています。例えば、sum()はRPythonではサポートされていません。さらに、min()のようなサポートされている関数は、Pythonでは同じ機能を提供しません。RPythonのmin()関数は2つの値しか比較できませんが、Pythonではリスト中の最小値を見つけるのに使うことができます。
:::

```python=
def builtin_functions():
    print bool(1)     # return a boolean value  =True
    print int(1.0)    # return an integer value =1
    print float(1)    # return a float value =1.0
    print chr(65)     # return a string of one character whose ASCII code is the input = A
    print str(53)     # return a string containing a nicely printable representation of an object 
    print unichr(97)  # return the Unicode string of one character whose Unicode code is the integer input

    print bytearray('abc')  # return a new array of bytes
    print list('abc')       # return a list whose items are the same and in the same order as iterable’s items
    for i in range(3):      # create a list containing arithmetic progressions
        print i
    for i in xrange(3):
        print i
    seasons = ['Spring', 'Summer', 'Fall', 'Winter']
    for i in enumerate(seasons):    # return an enumerate object
        print i
    print min(1, 2)    # return the smallest of two arguments
    print max(1, 2)    # return the largest of two arguments
    for i in reversed([1, 2, 3]):    # return a reverse iterator
        print i

def entry_point(argv):
    builtin_functions()
    return 0

def target(*args): return entry_point

```
```python=
vietanh@KU-info2019-031:~/Rpython$ ./built-in-c
True
1
1.0
A
53
a
abc
abc
0
1
2
0
1
2
(0, 'Spring')
(1, 'Summer')
(2, 'Fall')
(3, 'Winter')
1
2
3
2
1
```

## 4。 Class
RPythonのクラスはPythonと非常によく似ています。クラスを継承し、メソッドをオーバーライドすることができます。
:::info
RPythonにはいくつかの制約があります: 単一継承しかサポートされない。 単一継承サポートしない。多重継承サポートしません。
:::
クラスとは新しい型を定義するための仕組みです。クラスを使うことで複数の変数と関数を集約した変数を作ることができるようになります。
<!--
__ init__() はいわゆるコンストラクタです。コンストラクタには 2 つの役割があります:
- インスタンス化をするときに最初に呼び出される
- クラスのメンバ変数を定義し、それを初期化する

self というのはクラスインスタンスを表す変数です。
- インスタンス変数として参照する
- クラス変数として参照する
- クラス継承の際も使える

-->
```python=
class Animal(object):　#親クラス  (メソッドがある)
    def __init__(self, name):　＃クラスのメンバ変数を定義＃
        self.name = name

    def greet(self):    #メソッドとして greet() という関数をそれぞれのクラスで定義しておきます。
        self.say("I'm " + self.name + ".")

    def say(self, msg): pass

class Cat(Animal):  #子クラス　　（親クラスのメソッドを実行可能）
    def say(self, msg):
        print "Meow, " + msg

class Dog(Animal):
    def say(self, msg):
        print "Wuff, " + msg

def classes():
    c = Cat("Kitty")   #子クラスをインスタンス化
    c.greet()           # Meow, I'm Kitty.

    d = Dog("Buddy")
    d.greet()           # Wuff, I'm Buddy.

def entry_point(argv):
    classes()
    return 0

def target(*args): return entry_point
```
```python=
vietanh@KU-info2019-031:~/Rpython$ ./class-c
Meow, I'm Kitty.
Wuff, I'm Buddy.
```

<!--
多重継承継承の例：Rpython サポートしない
```python=
class Calculation1:
    def Summation(self, a, b):
        return a + b;
 
class Calculation2:
    def Multiplication(self, a, b):
        return a * b;
 
class Derived(Calculation1, Calculation2):
    def Divide(self, a, b):
        return a / b;
 
d = Derived()
print(d.Summation(10, 20))
print(d.Multiplication(10, 20))
print(d.Divide(10, 20))

C:\Users\r201902979ij\Downloads\４年生\test>python class.py
30
200
0.5
```
-->

Pythonでは複数のクラスを継承することができ、これを多重継承と呼びます。多重継承をする場合は、親クラスをカンマ区切りで指定します。
:::info
多重継承は mixin のみで対応。
クラス本体で rpython.rlib.objectmodel.import_from_mixin(M) を使って、クラス(M)の内容を丸ごとコピーします。
:::
```python=
from rpython.rlib.objectmodel import import_from_mixin

class ActivityMixin(object):  
    def eat(self, food):
        print "Eating " + food

class Animal(object):
    import_from_mixin(ActivityMixin)    # import ActivityMixin  (ActivityMixinのメソッドを作ることができます)

    def __init__(self, name):
        self.name = name

    def greet(self):
        self.say("I'm " + self.name + ".")

    def say(self, msg): pass

class Cat(Animal):　#子クラス
    def say(self, msg):
        print "Meow, " + msg


def classes():
    c = Cat("Kitty")
    c.greet()           # Meow, I'm Kitty.
    c.eat("cat food")　　　#Eating cat food

def entry_point(argv):
    classes()
    return 0

def target(*args): return entry_point
```
---
## 5.  Flow Control　（フローコントロール）
### 5.1 Variables
変数は、各制御フローポイントで最大1種類の値を含む必要があります。

```python=
def compiler_error(arg):  #argument:関数に渡される引数
    v = 0              # v is an integer
    if arg:
        v = 1          # vに整数1を代入する
    else:
        v = ""         # 文字列 "" をvに代入する
    return v

def entry_point(argv): compiler_error(argv[1]); return 0
def target(*args): return entry_point
```
compiler_error関数の制御フローグラフを下図に示す:
![](https://i.imgur.com/L2Ib3he.png)

見ての通り、マージポイント（緑でハイライト）では、v2は整数1か空文字列""のどちらかになります。これはRPythonの制限に違反しています。

### 5.2 例外事項
Pythonの例外処理を完全にサポート

## 6.Modules (rlib)
RPythonの標準ライブラリ(rlibとも呼ばれる)には、一般的に便利なモジュールがたくさんあります。
### 6.1 listsort
RPython でリストをソートするには、Timsort ソートアルゴリズムを提供する rpython.rlib.listsort モジュールを使用することができます。
```python=
from rpython.rlib.listsort import TimSort

def listsort():
    lst = [10, 1, 9, 2, 8, 3, 7, 4, 5, 6]
    TimSort(lst).sort()
    print lst

def entry_point(argv):
    listsort()
    return 0

def target(*args): return entry_point
```
```python=
vietanh@KU-info2019-031:~/Rpython$ ./list-sort-c
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```
### 6.2 rarithmetic
rarithmetic は，整数演算を表現するためのクラスと演算を提供します．

### 6.3 rbigint
rbigint は，数学関数，型変換，比較など，大きな整数を扱う関数を含んでいます．

----
## 7.　JIT
Simple Example:
The following example is a interpreter of brainfuck language with JIT. There is a detailed tutorial (part1, part2) on how to write a simple interpreter with RPython. Here, we briefly introduce some JIT-related data structures, functions, and decorators.

----
## 8. Foreign Function Interface (rffi) 外部関数インターフェース

RPythonの外部関数インターフェースはrffiと呼ばれています。rffiを使うと、低レベルの外部C関数の宣言、関数の外部登録、Cの型定義などができます。

----
### 8.1 Call Functions in libc (libc の関数の呼び出し)
次の例は、rffiを使ってlibcのmath関数を呼び出す方法です。

```python=
from rpython.rtyper.lltypesystem import rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rlib.rarithmetic import r_int32, r_int64, r_longlong

eci = ExternalCompilationInfo(
    includes=['stdlib.h'],
)

# int abs(int j);
c_abs = rffi.llexternal('abs',                     # function name
                        [rffi.INT],                # 引数型
                        rffi.INT,                  # return type リターンタイプ
                        compilation_info=eci)
def rffi_example():
    int_number = r_int32(-10)
    print c_abs(int_number)

def entry_point(argv): rffi_example(); return 0
def target(*args): return entry_point
```
```python=
vietanh@KU-info2019-031:~/Rpython$ ./rffi-c
10
```
----
### 8.2 Separate Module Source(セパレートモジュールソース)
また、C関数を直接書くこともできます。RPython translatorのCビルドツールが自動的にC関数をコンパイルしてリンクしてくれます。
```python=
from rpython.rtyper.lltypesystem import rffi
from rpython.rtyper.lltypesystem.lltype import Signed
from rpython.translator.tool.cbuild import ExternalCompilationInfo

c_source = """
int someexternalfunction(int x)
{
    return (x + 3);
}
"""

eci = ExternalCompilationInfo(separate_module_sources=[c_source])
c_someexternalfunction = rffi.llexternal('someexternalfunction',
                                         [Signed],
                                         Signed,
                                         compilation_info=eci)

def rffi_example():
    print c_someexternalfunction(1)

def entry_point(argv): rffi_example(); return 0
def target(*args): return entry_point
```
```python=
vietanh@KU-info2019-031:~/Rpython$ ./rffi-2-c
4
```
----
### 8.3 String Operations (文字列操作)
ASCIIやunicodeエンコーディングなど、文字列変換を行うための関数がいくつか用意されています。

----
### 8.4 List Conversion(リスト変換)
文字列のリストはよく使われるので、"liststr2charpp"と"charpp2liststr"という2つの関数のペアが用意されています。"free_charpp" を使ってリストを解放します。
ここでは、文字列のリストの合計の長さを計算する例を示します。
```python=
* liststr2charpp: list[str] -> char**, NULL terminated
* free_charpp: frees list of char**, NULL terminated
* charpp2liststr: char** NULL terminated -> list[str].  No freeing is done.
```
```python=
from rpython.rtyper.lltypesystem import rffi
from rpython.translator.tool.cbuild import ExternalCompilationInfo

# Calculate the total length of strings in the list
c_source = """
#include <string.h>

int strlen_list(char *args[]) {
    char **p = args;         // CHARPP in RPython
    int l = 0;
    while (*p) {
        l += strlen(*p);
        p++;
    }
    return l;
}
"""
eci = ExternalCompilationInfo(separate_module_sources=[c_source])
c_strlen_list = rffi.llexternal('strlen_list',           # function name
                                [rffi.CCHARPP],          # parameters
                                rffi.SIGNED,             # return value
                                compilation_info=eci)

def rffi_list_example():
    l = ["Hello", ",", "World", "!"]
    l_charpp = rffi.liststr2charpp(l)  #char 型返し
    r = c_strlen_list(l_charpp)
    rffi.free_charpp(l_charpp)　　    #リストを解放する
    print r

def entry_point(argv): rffi_list_example(); return 0
def target(*args): return entry_point
```
----
## 9. Compilation Errors  コンパイルエラー

### 9.1 コンパイルエラー
このエラーメッセージは、異なるタイプのものが混在しているために起こる非常に一般的なエラーメッセージです。
5章にあります・
```python=
def compiler_error(arg):
    v = 0              # v is an integer
    if arg:
        v = 1          # assign integer 1 to v
    else:
        v = ""         # assign string "" to v
    return v

def entry_point(argv): compiler_error(argv[1]); return 0
def target(*args): return entry_point
```
----

### 9.2 AnnotatorError 
"AnnotatorError" は、RPythonのプログラムにアノテーションを付ける際に発生するコンパイラエラーのクラスです。このクラスには、いくつかの具体的なエラーがあります。

- UnionError (annotator/module.py): アノテーターが型の競合で文句を言う。

- TooLateForChange (annotator/listdef.py): ドキュメント化されていません。

- ListChangeUnallowed (annotator/listdef.py): ドキュメントはありません。

- NoSuchAttrError (annotator/classdesc.py): クラスに属性が存在しない。

- SignatureError (annotator/signature.py): 関数宣言のシグネチャが異なる。
----
例えば、これはよくあるアノテーションのミスです:
```python=
def func(): return 0
def compiler_error(arg):
    func(1)

def entry_point(argv): compiler_error(argv[1]); return 0
def target(*args): return entry_point
```
```python=
[translation:ERROR] AnnotatorError:

signature mismatch: func() takes no arguments (1 given)


Occurred processing the following simple_call:
  function func <test.py, line 1> returning

    v0 = simple_call((function func), (1))

In <FunctionGraph of (test:2)compiler_error at 0x7f1b16d3db90>:
Happened at file test.py line 3

==>     func(1)

Known variable annotations:

Processing block:
 block@6[arg_0] is a <class 'rpython.flowspace.flowcontext.SpamBlock'>
 in (test:2)compiler_error
 containing the following operations:
       v0 = simple_call((function func), (1))
 --end--
```
3行目で、 署名の不一致があります。具体的には、この関数は引数を取らず、3行目で与えられた1つの引数を取ります。

----
### 9.3 FlowingError
FlowingErrorは、RPythonコンパイラがコントロールフロー・グラフを構築する際のエラーに関するものです。以下はFlowingErrorが発生する一般的な原因です。
- unsupported operations

- invalid exception class

- cannot import modules

- local variable referenced before assignment

- global name is not defined

----
例：
```python=
def compiler_error(arg):
    return v

def entry_point(argv): compiler_error(argv[1]); return 0
def target(*args): return entry_point
```
```python=
[translation:ERROR] FlowingError:

global name 'v' is not defined

In <FunctionGraph of (test:1)compiler_error at 0x7f322cd80b90>:
Happened at file test.py line 2

        return v

Processing block:
 block@9[argv_0] is a <class 'rpython.flowspace.flowcontext.SpamBlock'>
 in (test:4)entry_point
 containing the following operations:
       v0 = getitem(argv_0, (1))
       v1 = simple_call((function compiler_error), v0)
 --end--
```
 'v' が定義されていない.
 
 ----
 
 ## 10 Rewriting Python Benchmarks (Pythonベンチマークの書き換え)
 いくつかの例（フィボナッチ数）を使って、RPythonでPythonコードを書き換えるためのヒントを説明します。
 次のコードは、フィボナッチ数を再帰的に計算するものである。
```python=
def fib(n):
    if n == 0 or n == 1:
        return 1
    return fib(n - 1) + fib(n - 2)

def main():
    fib(40)

if __name__ == '__main__':
    main()
```
このベンチマークを実行するには、RPythonにエントリポイントを伝えるためのターゲット関数を追加する必要があります。
```python=
def fib(n):
    if n == 0 or n == 1:
        return 1
    return fib(n - 1) + fib(n - 2)

# nは定数であってはならない
def main(n):
    ret = fib(n)
    # output the result, otherwise RPython will optimize out the above call
    # (the `transform_dead_op_vars` pass)
    print ret

def target(*args):              # we need a target function
    return entry_point, None

def entry_point(argv):
    main(int(argv[1]))          # get n from the arguments
    return 0
```
ここでは、GNU timeコマンドを用いて、プロセスのライフタイム中の実行時間と最大レジデントセットサイズを計測するだけである。
```python=
import time
start_time = time.time()
def fib(n):
    if n == 0 or n == 1:
        return 1
    return fib(n - 1) + fib(n - 2)

def main():
    fib(40)

if __name__ == '__main__':
    main()
print("--- %s seconds ---" % (time.time() - start_time))

C:\Users\r201902979ij\Downloads\４年生\test>python fib.py
--- 62.72197651863098 seconds ---

```
