├── .gitignore
├── LICENSE
├── README.md
├── dub.json
├── sample.d
├── samples
├── base64.ore
├── base64_sample.ore
├── befunge.ore
├── ffi
│ ├── ptr
│ │ ├── build.sh
│ │ ├── libptr_test.ore
│ │ └── ptr.c
│ ├── sq
│ │ ├── build.sh
│ │ ├── libsq_test.ore
│ │ └── sq.c
│ └── str
│ │ ├── build.sh
│ │ ├── libstr_test.ore
│ │ └── str.c
├── fizzbuzz.ore
├── nqueen.ore
├── nqueen.scm
├── tak.ore
├── twitter.ore
└── twitter_sample.ore
└── source
├── app.d
└── orelang
├── Closure.d
├── Engine.d
├── Interpreter.d
├── Parser.d
├── Transpiler.d
├── Util.d
├── Value.d
├── expression
├── CallOperator.d
├── ClassType.d
├── IExpression.d
├── ImmediateValue.d
├── Macro.d
└── SymbolValue.d
└── operator
├── AddOperator.d
├── AliasOperator.d
├── ArrayOperators.d
├── AsIVOperator.d
├── AssertOperator.d
├── CarOperator.d
├── CdrOperator.d
├── ClassOperators.d
├── CondOperator.d
├── ConsOperator.d
├── ConvOperators.d
├── CurlOperators.d
├── DatetimeOperators.d
├── DebugOperators.d
├── DeffunOperator.d
├── DefineOperator.d
├── DefmacroOperator.d
├── DefvarOperator.d
├── DigestOperators.d
├── DivOperator.d
├── DllOperator.d
├── DynamicOperator.d
├── EqualOperator.d
├── EvalOperator.d
├── FileClass.d
├── FileOperators.d
├── FilterOperator.d
├── FoldOperator.d
├── ForeachOperator.d
├── GetOperator.d
├── GetfunOperator.d
├── HashMapOperators.d
├── IOperator.d
├── IfOperator.d
├── IsHashMapOperator.d
├── IsListOperator.d
├── IsNullOperator.d
├── LambdaOperator.d
├── LengthOperator.d
├── LetOperator.d
├── LoadOperator.d
├── LogicOperator.d
├── MapOperator.d
├── ModOperator.d
├── MulOperator.d
├── NopOperator.d
├── PathOperators.d
├── PrintOperator.d
├── RandomOperators.d
├── RegexClass.d
├── RemoveOperator.d
├── SeqOperator.d
├── SetIdxOperator.d
├── SetOperator.d
├── SortOperator.d
├── StdioOperators.d
├── StepOperator.d
├── StringOperators.d
├── SubOperator.d
├── SystemOperator.d
├── TimesOperator.d
├── TranspileOperator.d
├── TypeOperator.d
├── UUIDOperators.d
├── UntilOperator.d
├── UriOperators.d
├── WhenOperator.d
└── WhileOperator.d
/.gitignore:
--------------------------------------------------------------------------------
1 | .dub
2 | docs.json
3 | __dummy.html
4 | *.o
5 | *.obj
6 | .*.sw*
7 | .*.*.sw*
8 | ChickenClisp
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ChickenClisp - An implementation of Orelang in D
2 | Copyright (C) 2016 Akihiro Shoji
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the "Software"),
6 | to deal in the Software without restriction, including without limitation
7 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 | and/or sell copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included
12 | in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
20 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ChickenClisp
2 | Scheme風の文法を持つLisp言語(インタプリタ)
3 | ChickenClispには複数の処理系を自分で実装したが([TypeScriptによるもの](https://github.com/alphaKAI/ChickenClisp_ts), [Pythonによるもの](https://github.com/alphaKAI/ChickenClisp_py))これはD言語で実装したものである.
4 | GithubにてMITライセンスのもとでオープンソースで公開している: [ChickenClisp](https://github.com/alphaKAI/ChickenClisp)
5 |
6 |
7 | ## ChickenClispの文法
8 | ChickenClispのプログラムは[S式](https://ja.wikipedia.org/wiki/S式)で記述する.
9 |
10 | ```scheme
11 | (関数名 引数1 引数2)
12 | ```
13 |
14 | というように書く.
15 | 複数行の式を1つの式としたい場合は次のように書く(1番最後の式がその式の値になる)
16 |
17 | ```scheme
18 | (begin
19 | (式1)
20 | (式2)
21 | (式3 ←この式の値がbeginから始まるブロックの値となる))
22 | ```
23 |
24 | (beginの代わりにstepを用いてもいい)
25 |
26 | ## ChickenClispの機能
27 |
28 | ChickenClispでは関数は第1級オブジェクトである.
29 | また,提供するリテラルとして,10進整数(64bit符号付き整数型),倍精度浮動小数点数,string型,クロージャ型,マクロ,クラスがある.
30 |
31 | ChickenClispは以下の機能を提供する
32 |
33 | * 関数型プログラミングやオブジェクト指向プログラミングなどマルチパラダイムサポート
34 | * ifやcondによる条件分岐
35 | * whileやloop関数によるループ
36 | * 関数定義
37 | * 無名関数(ラムダ式)
38 | * クロージャ
39 | * マクロ(構文木を操作可能)
40 | * クラス定義可能なclass構文
41 | * File操作やネットワークプログラミング,正規表現を行うための標準ライブラリ
42 | * リスト操作のための豊富な標準関数
43 |
44 |
45 | 以下には標準ライブラリとして実装した関数について説明する.
46 |
47 | ### 算術演算子
48 |
49 | |関数名|説明|使用例|
50 | |:-----|:---|:-----|
51 | |+|和(2項演算子)|(+ 1 2)|
52 | |-|差(2項演算子)|(- 1 2)|
53 | |\*|積(2項演算子)|(\* 1 2)|
54 | |/|商(2項演算子)|(/ 1 2)|
55 | |%|剰余(2項演算子)|(% 3 2)|
56 |
57 | ### 比較演算子
58 |
59 | |関数名|説明|使用例|
60 | |:-----|:---|:-----|
61 | |=|a = bとしたとき,aとbが等しいかを比較する(2項演算子)|(= 1 1)|
62 | |<|a < bとしたとき,a < b となるか比較する(2項演算子)|(< 1 2)|
63 | |>|a > bとしたとき,a > b となるか比較する(2項演算子)|(> 1 2)|
64 | |<=|a <= bとしたとき,a <= b となるか比較する(2項演算子)|(<= 1 2)|
65 | |>=|a >= bとしたとき,a >= b となるか比較する(2項演算子)|(>= 1 2)|
66 |
67 |
68 | ### 変数/関数定義のための関数
69 |
70 | |関数名|説明|使用例|
71 | |:-----|:---|:-----|
72 | |def|関数を定義する|(def square (x) (\* x x))|
73 | |set|変数に値を設定する|(set x 0)|
74 | |set-p|大域スコープの変数に値をセットする|(set-p x 0)|
75 | |set-c|インスタンス変数に値をセットする|(set-c x 0)|
76 | |get|変数の値を取得する|(get x)|
77 | |let|ブロック変数を定義する|(let ((x 1) (y 2)) (+ x y))|
78 | |as-iv|リテラルを即値型(ImmediateValue型)に変換する|(as-iv 1)|
79 | |def-var|変数を定義する|(def-var x 0)|
80 | |def-macro|マクロを定義する|(def-macro calc (op a b) (op a b))とした後に(calc + 1 3)や(calc * 1 3)|
81 |
82 |
83 | ### ループのための関数
84 |
85 | |関数名|説明|使用例|
86 | |:-----|:---|:-----|
87 | |step|複数行の式を1つの式にする関数(複文のための関数)|(step
(expr1)
(expr2)
(expr3))|
88 | |times|第1引数に指定した回数,第2引数に渡した式を評価する|(times 4 (println "foo"))|
89 | |until|第1引数に指定した条件式が真になるまで,第2引数に渡した式を評価する|(def-var x 0)
(until (> x 5)
(step
(println x)
(set x (+ x 1))))|
90 | |until|第1引数に指定した条件式が真であるあいだ,2引数に渡した式を評価する|(def-var x 0)
(while (< x 5)
(step
(println x)
(set x (+ x 1))))|
91 |
92 |
93 | ### 論理演算子
94 |
95 | |関数名|説明|使用例|
96 | |:-----|:---|:-----|
97 | |!|論理否定をする|(! true)|
98 | |&&|論理積|a && b|
99 | ||||論理和|a || b|
100 |
101 |
102 | ### 標準出力関数
103 | |関数名|説明|使用例|
104 | |:-----|:---|:-----|
105 | |print|与えられた複数個の式を標準出力に出力する|(print 1 2 3)|
106 | |println|与えられた複数個の式を標準出力に出力し,末尾で改行を行う|(println 1 2 3)|
107 |
108 |
109 | ### 条件分岐のための関数
110 | |関数名|説明|使用例|
111 | |:-----|:---|:-----|
112 | |if|第1引数に与えられた式を評価し,真なら第2引数に与えられた式を,
偽なら第3引数に与えられた式を評価する
(第3引数は省略可能で,その場合は偽の場合は何も行われない)| (if (= 1 1) "true" "false")|
113 | |cond|複数の式をとり,その式は
((条件式) (条件式式が真の場合に評価される式))という形となって,
上から順に評価していき,条件式が真になった場合に対応する式を評価する.
1つもマッチしなかった場合かつelseがある場合はelseが評価される|(def-var x 2)
(cond ((= x 0) (println "x is 0"))
((= x 1) (println "x is 1"))
(else (println "x is not 0 or 1)))|
114 | |when|第1引数に与えられた式を評価し,真なら第2引数以降に与えられた式を評価する|(def-var x true)
(when x
(print "x is ")
(println x))|
115 |
116 |
117 | ### リスト操作のための関数
118 | |関数名|説明|使用例|
119 | |:-----|:---|:-----|
120 | |car|リストの第1要素を取り出す|(car '(1 2 3))|
121 | |cdr|リストの第2要素以降を取り出す|(cdr '(1 2 3))|
122 | |seq|与えられた個数の整数からなるリストを生成する|(seq 5) ←これは'(0 1 2 3 4)と等しい|
123 | |cons|与えられた引数からリストを生成する|(cons 1 2)|
124 | |sort|与えられたリストをソートする|(sort '(3 2 1))|
125 | |list?|与えられたリテラルがリストであるかを判定する|(list? x)|
126 | |remove|filterと似ているが,マッチした要素を消す|(remove (lambda (x) (= x 1)) '(1 2 3))|
127 | |length|リストの長さを得る|(length '(1 2 3))|
128 |
129 |
130 | ### 関数型プログラミング言語由来の関数
131 | |関数名|説明|使用例|
132 | |:-----|:---|:-----|
133 | |lambda|無名関数(ラムダ式)を定義する|(lambda (x) (+ x x))|
134 | |map|リストに対し関数を射影する|(map (lambda (x) (\* x x)) '(1 2 3))|
135 | |for-each|リストに対し関数を適応する|(for-each (lambda (x) (\* x x)) '(1 2 3))|
136 | |fold|リストに対し関数を適用し畳み込む|(def max (x y) (if (> x y) x y))
(print (fold max 0 '(5 3 4 2 1)))|
137 | |filter|第1引数に与えられた関数に,第2引数に与えられたリストから値をそれぞれ適用し,関数が真になる値だけを集める|(filter (lambda (x) (= 0 (% x 2))) '(1 2 3 4 5 6))|
138 |
139 |
140 | ### ハッシュマップに関する関数
141 | |関数名|説明|使用例|
142 | |:-----|:---|:-----|
143 | |new-hash|hashを生成する|(new-hash)|
144 | |make-hash|hashを生成する|(make-hash a) ←aという変数名のhashmapを生成する|
145 | |hash-set-value|hashに値を設定する|(hash-set-value a "apple" "red")|
146 | |hash-get-value|hashの値を取得する|(hash-get-value a "apple")|
147 | |hash-get-keys|hashのkeyを全てリストとして取得する|(hash-set-keys a)|
148 | |hash-get-values|hashのvalueを全てリストとして取得する|(hash-set-values a)|
149 |
150 |
151 | ### 文字列操作の関数
152 | |関数名|説明|使用例|
153 | |:-----|:---|:-----|
154 | |string-concat|文字列を連結する|(string-concat "Apple is " "red")|
155 | |string-join|リストをjoinする|(string-join '("a" "b" "c") ",")|
156 | |string-split|区切り文字で文字列を分割する|(string-split "a,b,c" ",")|
157 | |string-length|文字列の長さを取得する|(string-length "abc")|
158 | |string-slice|文字列のスライスを取得する|(string-slice "abcd" 1 3)|
159 | |as-string|リテラルを文字列に変換する|(as-string 5)|
160 | |string-repeat|与えられた文字列を指定回繰り返す|(string-repeat "abc" 5)|
161 | |string-chomp|与えられた文字列の末尾の改行を除く|(string-chomp "abc\n")|
162 |
163 |
164 | ### 型変換関数
165 | |関数名|説明|使用例|
166 | |:-----|:---|:-----|
167 | |number-to-string|数値を文字列に変換する|(number-to-string 1)|
168 | |string-to-number|文字列を数値に変換する|(string-to-number "1")|
169 | |number-to-char|数値をASCII charに変換する|(number-to-char 97)|
170 | |char-to-number|ASCII charを数値に変換する|(char-to-number "a")|
171 | |float-to-integer|浮動小数点数を整数に変換する|(float-to-integer 1.0)|
172 | |ubytes-to-string|バイト列を文字列に変換する|省略|
173 | |ubytes-to-integers|バイト列を整数列に変換する|省略|
174 |
175 |
176 | ### 配列操作系の関数
177 | |関数名|説明|使用例|
178 | |:-----|:---|:-----|
179 | |array-new|配列を生成する|(array-new)|
180 | |array-get-n|配列のn番目を取得する|(array-get-n arr 2)|
181 | |array-set-n|配列のn番目に値を設定する|(array-set-n arr 2 100)|
182 | |array-slice|配列のスライスをとる|(array-slice '(1 2 3 4 5 6) 1 3)|
183 | |array-append|配列に値を追加する|(array-append '(1 2 3) 4)|
184 | |array-concat|配列を連結する|(array-concat '(1 2) '(3 4))|
185 | |array-length|配列の長さを取得する|(array-length '(1 2 3))|
186 | |array-flatten|配列を平坦化する|(array-flatten '('(1 2 3) '(4 5 6)))|
187 | |array-reverse|配列を反転させる|(array-reverse '(3 2 1))|
188 |
189 |
190 | ### ユーティリティ関数
191 | |関数名|説明|使用例|
192 | |:-----|:---|:-----|
193 | |eval|与えられた文字列をChickenClispのインタプリタで実行する|(eval "(+ 1 2)")|
194 | |load|文字列として与えられたpathのファイルを読み込む|(load "foo.ore")|
195 | |type|リテラルの型を得る|(type 0)|
196 | |alias|関数や変数のaliasをつくる|(alias x y)|
197 | |assert|与えられた式が真であるかを判定し,偽の場合,例外を投げる|(assert (list? l))|
198 | |is-null?|与えられたリテラルがnullであるかを判定する|(is-null? x)|
199 | |is-hash?|与えられたリテラルがhashであるかを判定する|(is-hash? x)|
200 | |transpile|与えられた文字列をChickenClispの内部表現にトランスパイルする|(transpile "(+ 1 2)")|
201 |
202 |
203 | ### ネットワークプログラミング用の関数(libcurlのラッパー)
204 | |関数名|説明|使用例|
205 | |:-----|:---|:-----|
206 | |curl-download|第1引数に与えられた文字列のURLを,
第2引数で与えられたパスにダウンロードする|(curl-download "https://example.com" "download\_test")|
207 | |curl-upload|第1引数に与えられたパスのファイルを,
第2引数で与えられたURLにアップロードする|(curl-upload "download\_test" "https://example.com")|
208 | |curl-get|引数に与えられたURLにGETリクエストをする(戻り値はバイト列)|(curl-get "https://httpbin.org/get")|
209 | |curl-get|引数に与えられたURLにGETリクエストをする(戻り値は文字列)|(curl-get-string "https://httpbin.org/get")|
210 | |curl-post|第1引数に与えられたURLに,第2引数に与えられたバイト列をペイロードとしてPOSTリクエストをする.(戻り値はバイト列)|(curl-post "https://httpbin.org/post"
(curl-get "https://httpbin.org/get"))|
211 | |curl-post-string|第1引数に与えられたURLに,第2引数に与えられたバイト列をペイロードとしてPOSTリクエストをする.(戻り値は文字列)|(curl-post-string "https://httpbin.org/post" (curl-get "https://httpbin.org/get"))|
212 |
213 |
214 | ### URLエンコードのための関数
215 | |関数名|説明|使用例|
216 | |:-----|:---|:-----|
217 | |url-encode-component|引数に与えられた文字列をURLエンコードする|(url-encode-component "あいう")|
218 |
219 |
220 | ### UUIDについての関数
221 | |関数名|説明|使用例|
222 | |:-----|:---|:-----|
223 | |random-uuid|ランダムなUUID文字列を生成する|(random-uuid)|
224 |
225 |
226 | ### 時刻処理についての関数
227 | |関数名|説明|使用例|
228 | |:-----|:---|:-----|
229 | |get-current-unixtime|現在時刻のUNIXTIMEを取得する|(get-current-unixtime)|
230 |
231 |
232 | ### ハッシュダイジェストについての関数
233 | |関数名|説明|使用例|
234 | |:-----|:---|:-----|
235 | |hmac-sha1|第2引数に与えられた文字列を,第1引数に与えられた文字列でhmac-sha1を計算する|(hmac-sha1 "key" "base")|
236 |
237 |
238 | ### デバッグのための関数
239 | |関数名|説明|使用例|
240 | |:-----|:---|:-----|
241 | |dump-variables|スコープ内の全ての関数(それまでに使われたものだけ)/変数(定義されたもの)をダンプする|(dump-variables)|
242 | |peek-closure|引数に与えられたクロージャについての情報を取得する)|(peek-closure peek-closure)|
243 | |call-closure|引数に与えられたクロージャをデバッグ情報付きで実行する|(call-closure println "a")|
244 | |toggle-ge-dbg|スタックトレースの表示をトグルする|(toggle-ge-dbg)|
245 |
246 |
247 | ### オブジェクト指向プログラミングにおけるクラスに関する関数
248 | |関数名|説明|使用例|
249 | |:-----|:---|:-----|
250 | |class|classを定義するための関数|(class TestClass
(def-var x 10)
(def constructor (k) (set-p x k))
(def memberFunc () (println "memberFunc is called!"))
(def add (x y) (+ x y)))|
251 | |new|クラスのインスタンスを生成する|(begin
(def-var tc (new TestClass 200))
(tc memberFunc)
(println (tc add 1 3))
(println (tc x))
(println ((new TestClass 400) x)))|
252 |
253 |
254 | ### ファイルパスについての関数
255 | |関数名|説明|使用例|
256 | |:-----|:---|:-----|
257 | |path-exists|与えられたファイルパスが存在するかを返す|(path-exists "foo")|
258 | |path-is-dir|与えられたパスがディレクトリであるかを返す|(path-exists "foo")|
259 | |path-is-file|与えられたパスがファイルであるかを返す|(path-is-file "foo")|
260 |
261 |
262 | ### ファイル操作のための関数
263 | |関数名|説明|使用例|
264 | |:-----|:---|:-----|
265 | |remove-file|与えられたパスのファイルを削除する|(remove-file "foo")|
266 | |remove-dir|与えられたパスのディレクトリを削除する|(remove-dir "foo")|
267 | |get-cwd|カレントディレクトリのパスを返す|(get-cwd)|
268 | |get-size|与えられたパスのファイルのサイズを返す|(get-size)|
269 |
270 |
271 | ### 標準入力に関数る関数
272 | |関数名|説明|使用例|
273 | |:-----|:---|:-----|
274 | |readln|標準入力から1行読み込む|(readln)|
275 | |stdin-by-line|標準入力からEOFに到達するまで読み込む|(stdin-by-line)|
276 | |stdin-eof|EOFを表す定数を返す|(stdin-eof)|
277 |
278 |
279 | ### 乱数についての関数
280 | |関数名|説明|使用例|
281 | |:-----|:---|:-----|
282 | |random-uniform|第1引数と第2引数で与えられた範囲内の乱数を返す(乱数生成アルゴリズムはMT19937)|(random-uniform 0 10)|
283 |
284 |
285 | ### なにもしないことを表す関数
286 | |関数名|説明|使用例|
287 | |:-----|:---|:-----|
288 | |nop|なにもしないことを表す関数(プレースホルダとして用いる)| (def fun () (nop)) |
289 |
290 |
291 | ### Cのsystem関数ラッパー
292 | |関数名|説明|使用例|
293 | |:-----|:---|:-----|
294 | |system|引数に与えられた文字列をシェルで実行する|(system "echo foo")|
295 |
296 |
297 | ### 標準ライブラリで提供されるクラス
298 | |関数名|説明|メンバ関数|
299 | |:-----|:---|:-----|
300 | |FileClass|ファイル操作についてのクラス|コンストラクタ:(new FileClass "ファイルパス" "モード(w,r,wb,rbのどれか)")
raw-read: バイト列としてファイルを読み込む
raw-write: バイト列をファイルに書き込む
write: 引数に与えられたリテラルをファイルに書き込む
writeln: 引数に与えられたリテラルをファイルに書き込み,末尾で改行する
readln: ファイルから1行読み込む
readall: ファイルの内容をすべて読み込む|
301 | |Regex|正規表現についてのクラス|コンストラクタ: (new Regex "正規表現のパターン")
reset:引数に与えられたパターンをインスタンスに再設定する
与えられた文字列のなかでパターンにマッチするものを返す
match-all: 与えられた文字列のなかでパターンにマッチするものを全て返す
show-ptn: コンストラクタ/resetで渡された正規表現のパターンを返す|
302 |
303 |
304 | ### 便利性のためのalias
305 | |alias|alias先|
306 | |:----|:------|
307 | |not|!|
308 | |and|&&|
309 | |or||||
310 | |begin|step|
311 |
312 | ## ChickenClispのサンプルプログラム
313 | `sample.d`と`samples`以下にサンプルコードを収録したが,以下にその中でも抜粋したソースコードを記載し,サンプルプログラムとする.
314 |
315 | samplesディレクトリに収録したサンプルコードの説明を以下の表で行う.
316 |
317 | |ファイル名|概要|
318 | |:---------|:---|
319 | |base64.ore|Base64エンコーダの実装|
320 | |base64\_sample.ore|base64.oreを用いて実際にBase64エンコードをする例|
321 | |fizzbuzz.ore|fizzbuzzの実装|
322 | |tak.ore|竹内関数の実装(ベンチマーク用)|
323 | |nqueen.ore|N-queenソルバーの実装|
324 | |nqueen.scm|N-queenソルバーのSchemeによる実装(ChickenClispとのコードの比較用)|
325 | |twitter.ore|標準ライブラリのネットワークプログラミング用の関数を用いたTwitter APIラッパーライブラリ|
326 | |twitter\_sample.ore|twitter.oreを用いて実際にTwitterのAPIを使用するサンプル|
327 | |befunge.ore|befungeという言語のインタプリタ|
328 |
329 |
330 | 以下にサンプルコードを記載する:
331 |
332 | ### [1から10までの和]
333 | #### 手続き型的な実装:
334 | ```scheme
335 | (step
336 | (set i 0)
337 | (set sum 0)
338 | (while (<= i 10)
339 | (step
340 | (set sum (+ i sum))
341 | (set i (+ i 1))))
342 | (println "sum 1 to 10 : " sum))
343 | ```
344 |
345 | #### 高階関数を用いた関数型的な実装
346 | ```scheme
347 | ; seq(n) creates a sequence of '(0 1 2 ... n)
348 | (println (fold + 0 (seq 11)))
349 | ```
350 |
351 | ### [map関数を用いた(foreach関数でも可)1から10までをそれぞれ平方する]
352 | ```scheme
353 | (def square (x) (* x x))
354 | (println (map square (cdr (seq 11))))
355 | ```
356 |
357 | 上でも述べたが,このサンプルコードから分かるように,ChickenClispでは関数は第1級オブジェクトである.
358 | また,関数を定義しなくてもラムダ式で以下のようにも書ける.
359 |
360 | ```scheme
361 | (println (map (lambda (x) (* x x)) (cdr (seq 11))))
362 | ```
363 |
364 |
365 | ### [Fibonacci数列]
366 | ```scheme
367 | (def fib (n)
368 | (step
369 | (if (= n 0) 0
370 | (if (= n 1) 1
371 | (+ (fib (- n 1)) (fib (- n 2)))))))
372 | ```
373 |
374 | #### 末尾呼び出しにしたもの
375 |
376 | ```scheme
377 | (def fib (n)
378 | (step
379 | (def fib-iter (n a b)
380 | (if (= n 0)
381 | a
382 | (fib-iter (- n 1) b (+ a b))))
383 | (fib-iter n 0 1)))
384 | ```
385 |
386 | 上のように定義したあとで,下のように書くことで,n=0~9までのfib(n)の列が得られる.
387 |
388 | ```scheme
389 | (println (map fib (seq 10)))
390 | ```
391 |
392 | ## 前提環境
393 | ChickenClispはLinux,BSD,macOS,Windowsでの動作を確認している.また,動作を確認したコンパイラとパッケージ管理システムのバージョンは
394 |
395 | * dmd v2.070
396 | * dub 1.0.0
397 |
398 | である.
399 |
400 |
401 | ## インストール
402 | gitが使える状態で,以下のコマンドをシェルで入力することでインストールができる.
403 |
404 | ```zsh:
405 | $ git clone https://github.com/alphaKAI/ChickenClisp
406 | $ cd ChickenClisp
407 | $ dub build
408 | ```
409 |
410 |
411 | ## ライセンス
412 | ChickenClispはMITライセンスのもとで公開しています.
413 | ライセンスについての詳細については同梱の`LICENSE`ファイルを見てください.
414 |
415 | Copyright (C) 2016-2018 Akihiro Shoji
416 |
--------------------------------------------------------------------------------
/dub.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chickenclisp",
3 | "authors": [
4 | "Akihiro Shoji"
5 | ],
6 | "dependencies": {
7 | "kontainer" : "*"
8 | },
9 | "configurations": [
10 | {
11 | "name": "default",
12 | "targetType": "executable"
13 | },
14 | {
15 | "name": "withffi",
16 | "targetType": "executable",
17 | "versions": [
18 | "WithFFI"
19 | ],
20 | "libs": [
21 | "ffi"
22 | ]
23 | }
24 | ],
25 | "description": "A scheme like programming language and interpreter",
26 | "copyright": "Copyright (C) 2016, Akihiro Shoji",
27 | "license": "MIT"
28 | }
29 |
--------------------------------------------------------------------------------
/sample.d:
--------------------------------------------------------------------------------
1 | import orelang.Transpiler,
2 | orelang.Engine,
3 | orelang.Value;
4 | import std.stdio;
5 | void main() {
6 | /**
7 | * sum of 1 to 10
8 | */
9 |
10 | enum codeINE = `
11 | (new Engine).eval(
12 | new Value([new Value("step"),
13 | new Value([new Value("set"), new Value("i"), new Value(10.0)]),
14 | new Value([new Value("set"), new Value("sum"), new Value(0.0)]),
15 | new Value([new Value("until"), new Value([new Value("="), new Value([new Value("get"), new Value("i")]), new Value(0.0)]), new Value([
16 | new Value("step"),
17 | new Value([new Value("set"), new Value("sum"), new Value([new Value("+"), new Value([new Value("get"), new Value("sum")]), new Value([new Value("get"), new Value("i")])])]),
18 | new Value([new Value("set"), new Value("i"), new Value([new Value("+"), new Value([new Value("get"), new Value("i")]), new Value(-1.0)])])
19 | ])]),
20 | new Value([new Value("get"), new Value("sum")])
21 | ])
22 | )`;
23 | Value x = mixin(codeINE);
24 | writeln("A sample code which written in Internal Expression, sum of 1 to 10)");
25 | write("Code: ");
26 | writeln(codeINE);
27 | writeln("result -> ", x.getNumeric);
28 | writeln("\n");
29 |
30 | /**
31 | * S Expression
32 | */
33 | // loop 10 times and square 10
34 | string code1 = `
35 | (step
36 | (def square (x)
37 | (step
38 | (set y (* x x))
39 | (set z (* x x))
40 | (* y z)))
41 | (set x 1)
42 | (while (< x 11)
43 | (step
44 | (println x)
45 | (set x (+ x 1))))
46 | (println (square 10)))
47 | `;
48 |
49 | // sum 1 to 10
50 | string code2 = `
51 | (step
52 | (set sum 0)
53 | (set i 1)
54 | (while (<= i 10)
55 | (step
56 | (set sum (+ sum i))
57 | (set i (+ i 1))))
58 | (println sum))
59 | `;
60 |
61 | string code3 = `
62 | (step
63 | (def fun (x) (* x 40))
64 | (set f fun)
65 | (println (f (fun 10))))
66 | `;
67 |
68 | string code4 = `
69 | (step
70 | (set x (lambda (y) (* y y)))
71 | (println (x 500))
72 | (println ((lambda (z) (* z 40)) 10)))
73 | `;
74 |
75 | string code5 = `
76 | (step
77 | (print '(1 2 3 4 5 6 789))
78 | (print (map (lambda (x) (* x x)) '(1 2 3 4 5))))
79 | `;
80 |
81 | string code6 = `
82 | (step
83 | (set arr (set-idx '(1 2 3 4 5) 2 100))
84 | (println (map (lambda (x) (* x 10)) arr)))
85 | `;
86 |
87 | string code7 = `
88 | (step
89 | (set x 10)
90 | (println x))
91 | `;
92 |
93 | string factor = `
94 | (step
95 | (def factor (x)
96 | (if (<= x 1)
97 | 1
98 | (* x (factor (- x 1)))))
99 | (println (factor 4))
100 | (println (factor 5)))
101 | `;
102 | string fib = `
103 | (step
104 | (def fib (n) (step
105 | (if (= n 0) 0
106 | (if (= n 1) 1
107 | (+ (fib (- n 1)) (fib (- n 2)))))))
108 | (def-var i 0)
109 | (while (< i 10) (step
110 | (println (fib i))
111 | (set i (+ i 1)))))
112 | `;
113 |
114 | string fold = "(println (fold + 0 (map (lambda (x) (* x x)) (seq 10))))";
115 |
116 | string[] codes = [
117 | code1,
118 | code2,
119 | code3,
120 | code4,
121 | code5,
122 | code6,
123 | code7,
124 | factor,
125 | fib,
126 | fold
127 | ];
128 |
129 |
130 | size_t idx;
131 |
132 | foreach (code; codes) {
133 | Engine engine = new Engine();
134 | writeln("Sample code", idx++, " :");
135 | writeln("CODE----------------------------------------");
136 | writeln(code);
137 | writeln("OUTPUTS--------------------------------------");
138 |
139 | engine.eval(Transpiler.transpile(code));
140 | writeln("\n");
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/samples/base64.ore:
--------------------------------------------------------------------------------
1 | (def zip (arr1 arr2)
2 | (map (lambda (i) (as-iv (cons (array-get-n arr1 i) (array-get-n arr2 i))))
3 | (seq (length arr1))))
4 |
5 | (def assocArray (zipped)
6 | (step
7 | (make-hash hashmap)
8 | (def-var idx 0)
9 | (while (< idx (length zipped))
10 | (step
11 | (def-var tuple (array-get-n zipped idx))
12 | (def-var key (array-get-n tuple 0))
13 | (def-var value (array-get-n tuple 1))
14 | (hash-set-value hashmap key value)
15 | (set idx (+ idx 1))))
16 | hashmap))
17 |
18 | (def convb (N base)
19 | (step
20 | (def _convb (N tmp stack base)
21 | (if (not (= tmp 0))
22 | (_convb N (float-to-integer (/ tmp base)) (array-append stack (% tmp base)) base)
23 | (string-join (map (lambda (n) (number-to-string n)) (array-reverse stack)))))
24 | (_convb N N '() base)))
25 |
26 | (def createTable ()
27 | (step
28 | (def-var charset (string-split "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"))
29 | (def-var ziparg (map (lambda (i)
30 | (step
31 | (def-var e (convb i 2))
32 | (if (= (string-length e) 6)
33 | e
34 | (while (< (string-length e) 6)
35 | (set e (string-concat "0" e))))))
36 | (seq (length charset))))
37 | (assocArray (zip ziparg charset))))
38 |
39 | (def convertDataInto8Bits (data)
40 | (map (lambda (i)
41 | (step
42 | (def-var e (convb i 2))
43 | (if (= (string-length e) 8)
44 | e
45 | (while (< (string-length e) 8)
46 | (set e (string-concat "0" e))))))
47 | data))
48 |
49 | (def-var table (createTable))
50 |
51 | (def base64encode (data)
52 | (step
53 | (def makePrepared (binaries)
54 | (step
55 | (def-var bLen (string-length binaries))
56 | (def-var quotients
57 | (map (lambda (i) (string-slice binaries (* i 6) (* (+ i 1) 6)))
58 | (seq (float-to-integer (/ bLen 6)))))
59 | (if (= (% bLen 6) 0)
60 | quotients
61 | (array-append quotients
62 | (step
63 | (def-var $ (string-length binaries))
64 | (def-var remainds (string-slice binaries (- $ (% bLen 6)) $))
65 | (while (< (string-length remainds) 6)
66 | (set remainds (string-concat remainds "0")))
67 | remainds)))))
68 |
69 | (def makeQuotients (prepared)
70 | (step
71 | (def-var pLen (array-length prepared))
72 | (map (lambda (i)
73 | (as-iv (step
74 | (def-var j (* i 4))
75 | (map (lambda (k) (hash-get-value table (array-get-n prepared (+ j k))))
76 | (seq 4)))))
77 | (seq (float-to-integer (/ pLen 4))))))
78 |
79 | (def finallize (prepared quotients)
80 | (step
81 | (def-var pLen (array-length prepared))
82 | (if (= (% (array-length prepared) 4) 0)
83 | quotients
84 | (array-append quotients (step
85 | (def-var $ (array-length prepared))
86 | (def-var remainds (array-slice prepared (- $ (% pLen 4)) $))
87 | (def-var fst (map (lambda (remaind) (hash-get-value table remaind)) remainds))
88 | (def-var fstlen (array-length fst))
89 | (def-var snd "")
90 | (while (< (+ (string-length snd) fstlen) 4)
91 | (set snd (string-concat snd "=")))
92 | (as-iv (array-append fst snd)))))))
93 |
94 | (def-var binaries (string-join (convertDataInto8Bits data)))
95 | (def-var prepared (makePrepared binaries))
96 | (def-var quotients (makeQuotients prepared))
97 | (string-concat (array-flatten (map (lambda (x) x) (finallize prepared quotients))))))
98 |
--------------------------------------------------------------------------------
/samples/base64_sample.ore:
--------------------------------------------------------------------------------
1 | (load "samples/base64")
2 | (def string-into-numbers (str)
3 | (map (lambda (e) (char-to-number e)) (string-split str)))
4 |
5 | (def str2b64 (str)
6 | (base64encode (string-into-numbers str)))
7 |
8 |
9 | (def-var from "abcdefghijklmnopqrstuvwxyz")
10 | (def-var dst (str2b64 from))
11 | (println "from - " from)
12 | (println "dst - " dst)
13 | (println "valid? - " (if (= "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=" dst) "yes" "no"))
--------------------------------------------------------------------------------
/samples/befunge.ore:
--------------------------------------------------------------------------------
1 | (class SourceStream
2 | (def-var UP 0)
3 | (def-var DOWN 1)
4 | (def-var RIGHT 2)
5 | (def-var LEFT 3)
6 |
7 | (def-var dir RIGHT)
8 | (def-var source null)
9 | (def-var pcx 0)
10 | (def-var pcy 0)
11 |
12 | (def constructor (code)
13 | (begin
14 | (set-p source (map (lambda (line) (string-split line "")) (string-split code "\n")))))
15 |
16 | (def change-direction (_dir)
17 | (set-p dir _dir))
18 |
19 | (def forward-pc ()
20 | (cond
21 | ((= dir UP) (begin
22 | (if (= pcy 0)
23 | (set-p pcy (- (array-length source) 1))
24 | (set-p pcy (- pcy 1)))))
25 | ((= dir DOWN) (begin
26 | (if (= pcy (- (array-length source) 1))
27 | (set-p pcy 0)
28 | (set-p pcy (+ pcy 1)))))
29 | ((= dir RIGHT) (begin
30 | (if (= pcx (- (array-length (array-get-n source pcy)) 1))
31 | (set-p pcx 0)
32 | (set-p pcx (+ pcx 1)))))
33 | ((= dir LEFT) (begin
34 | (if (= pcx 0)
35 | (set-p pcx (- (array-length (array-get-n source pcy)) 1))
36 | (set-p pcx (- pcx 1)))))))
37 |
38 | (def peek-front ()
39 | (array-get-n (array-get-n source pcy) pcx))
40 |
41 | (def get-char (x y)
42 | (array-get-n (array-get-n source y) x))
43 |
44 | (def change-char (x y z)
45 | (begin
46 | (def-var line (array-get-n source y))
47 | (set line (array-set-n line x z))
48 | (set-p source (array-set-n source y line)))))
49 |
50 | (class Stack
51 | (def-var stack (array-new))
52 |
53 | (def push (elem)
54 | (set-p stack (array-append stack elem)))
55 |
56 | (def pop ()
57 | (begin
58 | (def-var ret (array-get-n stack (- (array-length stack) 1)))
59 | (set-p stack (array-slice stack 0 (- (array-length stack) 1)))
60 | ret)))
61 |
62 | (class Interpreter
63 | (def-var ss null)
64 | (def-var stack (new Stack))
65 | (def-var nrgx (new Regex "[0-9]"))
66 |
67 | (def constructor (code)
68 | (set-p ss (new SourceStream code)))
69 |
70 | (def execute ()
71 | (begin
72 | (def-var exit-flag false)
73 | (def-var read-string false)
74 | (def-var skip-flag false)
75 |
76 | (while (! exit-flag)
77 | (begin
78 | (def-var ch (ss peek-front))
79 |
80 | (if skip-flag
81 | (set skip-flag false)
82 | (begin
83 | (if (&& (! (= ch '"')) read-string)
84 | (stack push (char-to-number ch))
85 | (begin
86 | (cond
87 | ((= ch '<') (ss change-direction (ss LEFT)))
88 | ((= ch '>') (ss change-direction (ss RIGHT)))
89 | ((= ch '^') (ss change-direction (ss UP)))
90 | ((= ch 'v') (ss change-direction (ss DOWN)))
91 | ((= ch '_') (begin
92 | (def-var x (stack pop))
93 | (def-var tdir (if (= x 0) (ss RIGHT) (ss LEFT)))
94 | (ss change-direction tdir)))
95 | ((= ch '|') (begin
96 | (def-var x (stack pop))
97 | (def-var tdir (if (= x 0) (ss DOWN) (ss UP)))
98 | (ss change-direction tdir)))
99 | ((= ch '?') (begin
100 | (def-var tdir (random-uniform 0 5))
101 | (ss change-direction tdir)))
102 | ((= ch ' ') (nop))
103 | ((= ch '#') (set skip-flag true))
104 | ((= ch '@') (set exit-flag true))
105 | ((= ch '"') (set read-string (! read-string)))
106 | ((= ch '&') (begin
107 | (def-var x (string-to-number (string-chomp (readln))))
108 | (stack push x)))
109 | ((= ch '~') (begin
110 | (def-var x (char-to-number (string-chomp (readln))))
111 | (stack push x)))
112 | ((= ch '.') (begin
113 | (def-var x (stack pop))
114 | (print x " ")))
115 | ((= ch ',') (begin
116 | (def-var x (stack pop))
117 | (print (number-to-char x))))
118 | ((= ch '+') (begin
119 | (def-var y (stack pop))
120 | (def-var x (stack pop))
121 | (def-var z (+ x y))
122 | (stack push z)))
123 | ((= ch '-') (begin
124 | (def-var y (stack pop))
125 | (def-var x (stack pop))
126 | (def-var z (- x y))
127 | (stack push z)))
128 | ((= ch '*') (begin
129 | (def-var y (stack pop))
130 | (def-var x (stack pop))
131 | (def-var z (* x y))
132 | (stack push z)))
133 | ((= ch '/') (begin
134 | (def-var y (stack pop))
135 | (def-var x (stack pop))
136 | (def-var z (%/ x y))
137 | (stack push z)))
138 | ((= ch '%') (begin
139 | (def-var y (stack pop))
140 | (def-var x (stack pop))
141 | (def-var z (% x y))
142 | (stack push z)))
143 | ((= ch '`') (begin
144 | (def-var y (stack pop))
145 | (def-var x (stack pop))
146 | (def-var z (if (> x y) 1 0))
147 | (stack push z)))
148 | ((= ch '!') (begin
149 | (def-var x (stack pop))
150 | (def-var y (if (= x 0) 1 0))
151 | (stack push y)))
152 | ((= ch ':') (begin
153 | (def-var x (stack pop))
154 | (stack push x)
155 | (stack push x)))
156 | ((= ch '\') (begin
157 | (def-var y (stack pop))
158 | (def-var x (stack pop))
159 | (for-each (lambda (e) (stack push e)) '(y x))))
160 | ((= ch '$') (begin
161 | (stack pop)))
162 | ((= ch 'g') (begin
163 | (def-var y (stack pop))
164 | (def-var x (stack pop))
165 | (def-var c (ss get-char x y))
166 | (stack push (char-to-number c))))
167 | ((= ch 'p') (begin
168 | (def-var y (stack pop))
169 | (def-var x (stack pop))
170 | (def-var v (stack pop))
171 | (ss change-char x y (number-to-char v))))
172 | (else (begin
173 | (if (nrgx match ch)
174 | (stack push (string-to-number ch))))))))))
175 |
176 | (ss forward-pc))))))
177 |
178 | (begin
179 | (def-var itpr (new Interpreter 'v @_ v\n
180 | >0"!dlroW"v \n
181 | v :# < \n
182 | >" ,olleH" v\n
183 | ^ <'))
184 |
185 | (itpr execute))
186 |
--------------------------------------------------------------------------------
/samples/ffi/ptr/build.sh:
--------------------------------------------------------------------------------
1 | gcc -c ptr.c -fpic
2 | gcc -shared -o libptr.so ptr.o
3 |
--------------------------------------------------------------------------------
/samples/ffi/ptr/libptr_test.ore:
--------------------------------------------------------------------------------
1 | (dll
2 | (dll-path "libptr.so")
3 | (dll-functions
4 | ("newS" pointer (string int))
5 | ("showS" void (pointer))))
6 |
7 | (println "newS")
8 | (def-var s (newS "alphaKAI" 20))
9 | (println "showS")
10 | (showS s)
11 |
--------------------------------------------------------------------------------
/samples/ffi/ptr/ptr.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | typedef struct S {
5 | char* name;
6 | int age;
7 | } S;
8 |
9 | S* newS(char* name, int age) {
10 | S* ret = malloc(sizeof(S));
11 |
12 | ret->name = name;
13 | ret->age = age;
14 |
15 | return ret;
16 | }
17 |
18 | void showS(S* s) {
19 | printf("s->name : %s\n", s->name);
20 | printf("s->age : %d\n", s->age);
21 | }
22 |
--------------------------------------------------------------------------------
/samples/ffi/sq/build.sh:
--------------------------------------------------------------------------------
1 | gcc -c sq.c -fpic
2 | gcc -shared -o libsq.so sq.o
3 |
--------------------------------------------------------------------------------
/samples/ffi/sq/libsq_test.ore:
--------------------------------------------------------------------------------
1 | (dll
2 | (dll-path "libsq.so")
3 | (dll-functions
4 | ("sq" int (int))))
5 |
6 | (println "sq 4 : " (sq 4))
--------------------------------------------------------------------------------
/samples/ffi/sq/sq.c:
--------------------------------------------------------------------------------
1 | int sq(int x) {
2 | return x * x;
3 | }
4 |
--------------------------------------------------------------------------------
/samples/ffi/str/build.sh:
--------------------------------------------------------------------------------
1 | gcc -c str.c -fpic
2 | gcc -shared -o libstr.so str.o
3 |
--------------------------------------------------------------------------------
/samples/ffi/str/libstr_test.ore:
--------------------------------------------------------------------------------
1 | (dll
2 | (dll-path "libstr.so")
3 | (dll-functions
4 | ("dub" string (string))))
5 |
6 | (println "dub abc: " (dub "abc"))
7 |
--------------------------------------------------------------------------------
/samples/ffi/str/str.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | char* dub(char* str) {
6 | size_t len = strlen(str) * 2 + 1;
7 | char* s = malloc(sizeof(char) * len);
8 | sprintf(s, "%s%s", str, str);
9 | s[len - 1] = '\0';
10 | return s;
11 | }
12 |
--------------------------------------------------------------------------------
/samples/fizzbuzz.ore:
--------------------------------------------------------------------------------
1 | (def _fizzbuzz (n)
2 | (cond
3 | ((= (% n 15) 0) (println "FizzBuzz"))
4 | ((= (% n 5) 0) (println "Fizz"))
5 | ((= (% n 3) 0) (println "Buzz"))
6 | (else (println n))
7 | ))
8 | (def fizzbuzz (n)
9 | (for-each (lambda (i) (_fizzbuzz i)) (seq n)))
10 |
11 | (def-var n 30)
12 | (fizzbuzz n)
--------------------------------------------------------------------------------
/samples/nqueen.ore:
--------------------------------------------------------------------------------
1 | (def null? (ls) (= (length ls) 0))
2 | (def pair? (ls) (and (list? ls) (> (length ls) 0)))
3 |
4 | (def print-board (board)
5 | (step
6 | (def print-line (q size)
7 | (step
8 | (print "| ")
9 | (let loop ((x 0))
10 | (when (< x size)
11 | (if (= x q)
12 | (print "Q ")
13 | (print ". "))
14 | (loop (+ x 1))))
15 | (println "|")))
16 |
17 | (def print-waku (size)
18 | (step
19 | (print "*-")
20 | (let loop ((x 0))
21 | (when (< x size)
22 | (print "--")
23 | (loop (+ x 1))))
24 | (println "*")))
25 |
26 | (let ((size (length board)))
27 | (step
28 | (print-waku size)
29 | (let loop ((ls board))
30 | (when (pair? ls)
31 | (print-line (car ls) size)
32 | (loop (cdr ls))))
33 | (print-waku size)
34 | (println)))))
35 |
36 | (def conflict? (column line board)
37 | (let loop ((x (- column 1)) (ls board))
38 | (cond ((null? ls) false)
39 | ((or (= (- column line) (- x (car ls)))
40 | (= (+ column line) (+ x (car ls))))
41 | true)
42 | (else
43 | (loop (- x 1) (cdr ls))))))
44 |
45 | (def safe? (line board)
46 | (cond ((null? board) true)
47 | ((conflict? (length board) line board) false)
48 | (else (safe? (car board) (cdr board)))))
49 |
50 | (def queen (ls board)
51 | (cond ((null? ls)
52 | (if (safe? (car board) (cdr board))
53 | (print-board board)))
54 | (else
55 | (for-each
56 | (lambda (n)
57 | (queen (remove (lambda (x) (= x n)) ls)
58 | (cons n board)))
59 | ls))))
60 |
61 | (def queen-fast (ls board)
62 | (if (null? ls)
63 | (step
64 | (println board)
65 | (print-board board))
66 | (for-each
67 | (lambda (n)
68 | (if (not (conflict? (length board) n board))
69 | (queen-fast
70 | (remove (lambda (x) (= x n)) ls)
71 | (cons n board))))
72 | ls)))
73 |
74 | (set n 8)
75 | (queen-fast (seq n) '())
76 |
--------------------------------------------------------------------------------
/samples/nqueen.scm:
--------------------------------------------------------------------------------
1 | ; 盤面の表示
2 | (define (print-board board)
3 | ;
4 | (define (print-line q size)
5 | (display "| ")
6 | (let loop ((x 0))
7 | (when (< x size)
8 | (if (= x q)
9 | (display "Q ")
10 | (display ". "))
11 | (loop (+ x 1))))
12 | (display "|\n"))
13 | ;
14 | (define (print-waku size)
15 | (display "*-")
16 | (let loop ((x 0))
17 | (when (< x size)
18 | (display "--")
19 | (loop (+ x 1))))
20 | (display "*\n"))
21 | ;
22 | (let ((size (length board)))
23 | (print-waku size)
24 | (let loop ((ls board))
25 | (when (pair? ls)
26 | (print-line (car ls) size)
27 | (loop (cdr ls))))
28 | (print-waku size)
29 | (newline)))
30 |
31 | (define (conflict? column line board)
32 | (let loop ((x (- column 1)) (ls board))
33 | (begin
34 | (cond ((null? ls) #f)
35 | ((or (= (- column line) (- x (car ls)))
36 | (= (+ column line) (+ x (car ls))))
37 | #t)
38 | (else
39 | (loop (- x 1) (cdr ls)))))))
40 |
41 | (define (safe? line board)
42 | (cond ((null? board) true)
43 | ((conflict? (length board) line board) false)
44 | (else (safe? (car board) (cdr board)))))
45 |
46 | (define (queen ls board)
47 | (cond ((null? ls)
48 | (if (safe? (car board) (cdr board))
49 | (print-board board)))
50 | (else
51 | (for-each
52 | (lambda (n)
53 | (queen (remove (lambda (x) (= x n)) ls)
54 | (cons n board)))
55 | ls))))
56 |
57 | ; 高速版
58 | (define (queen-fast ls board)
59 | (if (null? ls)
60 | (print-board board)
61 | (for-each
62 | (lambda (n)
63 | (if (not (conflict? (length board) n board))
64 | (queen-fast
65 | (remove (lambda (x) (= x n)) ls)
66 | (cons n board))))
67 | ls)))
68 |
69 | (queen-fast '(0 1 2 3 4 5 6 7) '())
70 |
--------------------------------------------------------------------------------
/samples/tak.ore:
--------------------------------------------------------------------------------
1 | (step
2 | (def tak (x y z)
3 | (if (<= x y)
4 | y
5 | (tak (tak (- x 1) y z)
6 | (tak (- y 1) z x)
7 | (tak (- z 1) x y))))
8 | (print (/(/ (time (tak 10 5 0)) 1000)1000))
9 | )
10 |
--------------------------------------------------------------------------------
/samples/twitter.ore:
--------------------------------------------------------------------------------
1 | (load "samples/base64")
2 |
3 | (def-var authorizeKeys '("oauth_consumer_key" "oauth_nonce" "oauth_signature_method" "oauth_timestamp" "oauth_token" "oauth_version"))
4 | (def-var baseUrl "https://api.twitter.com/1.1/")
5 |
6 | (def buildParams (additionalParam)
7 | (begin
8 | (def-var now (get-current-unixtime))
9 | (make-hash params)
10 | (for-each (lambda (pair)
11 | (begin
12 | (def-var key (car pair))
13 | (def-var value (car (cdr pair)))
14 | (hash-set-value params key value)))
15 | '((cons "oauth_consumer_key" consumerKey)
16 | (cons "oauth_nonce" (random-uuid))
17 | (cons "oauth_signature_method" "HMAC-SHA1")
18 | (cons "oauth_timestamp" now)
19 | (cons "oauth_token" accessToken)
20 | (cons "oauth_version" "1.0")))
21 |
22 | (def-var adp-is-null
23 | (if (is-hash? additionalParam)
24 | false
25 | (= "null" additionalParam)))
26 |
27 | (set params (if adp-is-null
28 | params
29 | (begin
30 | (for-each (lambda (key) (hash-set-value params key (hash-get-value additionalParam key)))
31 | (hash-get-keys additionalParam))
32 | params)))
33 |
34 | (for-each (lambda (key) (hash-set-value params key (url-encode-component (hash-get-value params key))))
35 | (hash-get-keys params))
36 |
37 | params))
38 |
39 | (def signature (method url params)
40 | (begin
41 | (def-var query (string-join (map (lambda (k) (string-concat k "=" (hash-get-value params k))) (sort (hash-get-keys params))) "&"))
42 | (def-var key (string-join (map (lambda (x) (url-encode-component x)) '(consumerSecret accessTokenSecret)) "&"))
43 | (def-var base (string-join (map (lambda (x) (url-encode-component x)) '(method url query)) "&"))
44 | (def-var oauthSignature (url-encode-component (base64encode (ubytes-to-integers (hmac-sha1 key base)))))
45 |
46 | oauthSignature))
47 |
48 | (def request (type endPoint paramsArgument)
49 | (begin
50 | (def-var method
51 | (if (|| (= type "GET") (= type "get"))
52 | "GET"
53 | "POST"))
54 |
55 | (def-var params (buildParams paramsArgument))
56 | (def-var url (string-concat baseUrl endPoint))
57 | (def-var oauthSignature (signature method url params))
58 | (hash-set-value params "oauth_signature" oauthSignature)
59 |
60 | (def-var authorize (string-concat "OAuth "
61 | (string-join (map (lambda (k) (string-concat k "=" (hash-get-value params k)))
62 | authorizeKeys)
63 | ",")))
64 | (def-var path (string-join (map (lambda (k) (string-concat k "=" (hash-get-value params k)))
65 | (hash-get-keys params))
66 | "&"))
67 |
68 | (def-var header (new-hash))
69 | (hash-set-value header "Authorization" authorize)
70 |
71 | (if (= method "GET")
72 | (curl-get-string (string-concat url "?" path) header)
73 | (curl-post-string url path header))))
--------------------------------------------------------------------------------
/samples/twitter_sample.ore:
--------------------------------------------------------------------------------
1 | (load "samples/twitter")
2 |
3 | (def-var consumerKey "")
4 | (def-var consumerSecret "")
5 | (def-var accessToken "")
6 | (def-var accessTokenSecret "")
7 |
8 | (make-hash args)
9 | (hash-set-value args "status" "Hello World!")
10 | (request "POST" "statuses/update.json" args)
--------------------------------------------------------------------------------
/source/app.d:
--------------------------------------------------------------------------------
1 | import orelang.Interpreter,
2 | orelang.Transpiler,
3 | orelang.Engine;
4 | import std.stdio,
5 | std.file;
6 |
7 | void main(string[] args) {
8 | if (args.length >= 2) {
9 | string fpath = args[1];
10 |
11 | if (!exists(fpath)) {
12 | writeln("No such file - ", fpath);
13 | } else {
14 | Interpreter itpr = new Interpreter();
15 | if (args.length > 2) {
16 | itpr.defineARGS(args[2..$]);
17 | }
18 | itpr.executer(readText(fpath));
19 | }
20 | } else if (args.length == 1) {
21 | Interpreter itpr = new Interpreter();
22 | itpr.interpreter();
23 | } else {
24 | writeln("error"); // this error comment needs improving
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/orelang/Closure.d:
--------------------------------------------------------------------------------
1 | module orelang.Closure;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class Closure {
7 | public {
8 | Engine engine;
9 | IOperator operator;
10 | }
11 |
12 | this (Engine engine, IOperator operator) {
13 | this.engine = engine;
14 | this.operator = operator;
15 | }
16 |
17 | Value eval(Value[] args) {
18 | return this.operator.call(this.engine, args);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/Engine.d:
--------------------------------------------------------------------------------
1 | module orelang.Engine;
2 |
3 | /**
4 | * Premitive Interfaces and Value Classes
5 | */
6 | import orelang.expression.ImmediateValue, orelang.expression.CallOperator,
7 | orelang.expression.IExpression, orelang.expression.ClassType,
8 | orelang.operator.IOperator, orelang.Closure, orelang.Value;
9 |
10 | /**
11 | * variables
12 | */
13 | import orelang.operator.DatetimeOperators, orelang.operator.IsHashMapOperator,
14 | orelang.operator.TranspileOperator, orelang.operator.DefmacroOperator,
15 | orelang.operator.HashMapOperators, orelang.operator
16 | .DigestOperators, orelang.operator.DynamicOperator,
17 | orelang.operator.ForeachOperator, orelang.operator.RandomOperators,
18 | orelang.operator.StringOperators, orelang.operator.ArrayOperators,
19 | orelang.operator.AssertOperator, orelang.operator.ClassOperators,
20 | orelang.operator.DebugOperators, orelang.operator.DeffunOperator,
21 | orelang.operator.DefineOperator, orelang.operator.DefvarOperator,
22 | orelang.operator.FilterOperator, orelang.operator.GetfunOperator,
23 | orelang.operator.IsListOperator, orelang.operator.IsNullOperator,
24 | orelang.operator.LambdaOperator, orelang.operator.LengthOperator,
25 | orelang.operator.RemoveOperator, orelang.operator.SetIdxOperator,
26 | orelang.operator.StdioOperators, orelang.operator.SystemOperator,
27 | orelang.operator.AliasOperator, orelang.operator.ConvOperators,
28 | orelang.operator.CurlOperators, orelang.operator.EqualOperator,
29 | orelang.operator.FileOperators, orelang.operator.LogicOperator,
30 | orelang.operator.PathOperators, orelang.operator.PrintOperator,
31 | orelang.operator.TimesOperator, orelang.operator.UntilOperator,
32 | orelang.operator.UUIDOperators, orelang.operator.WhileOperator,
33 | orelang.operator.AsIVOperator, orelang.operator.CondOperator,
34 | orelang.operator.ConsOperator, orelang.operator.EvalOperator,
35 | orelang.operator.FoldOperator, orelang.operator.LoadOperator,
36 | orelang.operator.SortOperator, orelang.operator.StepOperator,
37 | orelang.operator.TypeOperator, orelang.operator.UriOperators,
38 | orelang.operator.WhenOperator, orelang.operator.AddOperator,
39 | orelang.operator.CarOperator, orelang.operator.CdrOperator,
40 | orelang.operator.DivOperator,
41 | orelang.operator.GetOperator, orelang.operator.LetOperator,
42 | orelang.operator.MapOperator, orelang.operator.MulOperator,
43 | orelang.operator.ModOperator, orelang.operator.NopOperator,
44 | orelang.operator.SetOperator, orelang.operator.SeqOperator,
45 | orelang.operator.SubOperator, orelang.operator.IfOperator;
46 | import orelang.operator.RegexClass, orelang.operator.FileClass;
47 |
48 | version (WithFFI) {
49 | import orelang.operator.DllOperator;
50 | }
51 |
52 | import std.exception, std.format;
53 |
54 | /**
55 | * Lazed Associative Array
56 | *
57 | * For instance;
58 | * assocArray["key"] = new ValueType
59 | * The above code create a new instance of ValueType with some consts(memory amount and time).
60 | * However it likely to be a bobottleneck if the value isn't needed.
61 | * Then this class provides lazed associative array, this class willn't create an instance until the value become needed.
62 | * In other words, this is sort of lazy evaluation for performance.
63 | */
64 | class LazedAssocArray(T) {
65 | /**
66 | * Flags, indicates whether the instance of the key is already created
67 | */
68 | bool[string] called;
69 | /**
70 | * This variable holds the instance as a value of hashmap.
71 | */
72 | T[string] storage;
73 | /**
74 | * This variable holds the constructor calling delegate to make the instance which will be called when the isntance become needed.
75 | */
76 | T delegate()[string] constructors;
77 | bool[string] alwaysNew;
78 |
79 | alias storage this;
80 |
81 | /**
82 | * This function works like:
83 | * // laa is an instance of LazedAssocArray
84 | * laa["key"] = new T;
85 | * with following way:
86 | * laa.insert!("key", "new T");
87 | *
88 | * This function uses string-mixin for handling "new T", becase D can't allow make an alias of the expr liek `new T`
89 | */
90 | void insert(string key, string value, bool always = false)() {
91 | constructors[key] = mixin("delegate T () { return " ~ value ~ ";}");
92 | called[key] = false;
93 |
94 | if (always) {
95 | alwaysNew[key] = true;
96 | }
97 | }
98 |
99 | void insert(string key, T delegate() value, bool always = false)() {
100 | constructors[key] = value;
101 | called[key] = false;
102 |
103 | if (always) {
104 | alwaysNew[key] = true;
105 | }
106 | }
107 |
108 | void insert(string key, T function() value, bool always = false)() {
109 | constructors[key] = () => value();
110 | called[key] = false;
111 |
112 | if (always) {
113 | alwaysNew[key] = true;
114 | }
115 | }
116 |
117 | void insert(string key, T delegate() value, bool always = false) {
118 | constructors[key] = value;
119 | called[key] = false;
120 |
121 | if (always) {
122 | alwaysNew[key] = true;
123 | }
124 | }
125 |
126 | void insert(string key, T function() value, bool always = false) {
127 | constructors[key] = () => value();
128 | called[key] = false;
129 |
130 | if (always) {
131 | alwaysNew[key] = true;
132 | }
133 | }
134 |
135 | /**
136 | * Set the value with the key.
137 | * This function works like:
138 | * laa["key"] = value;
139 | * with
140 | * laa.set("key", value)
141 | */
142 | void set(string key, T value) {
143 | storage[key] = value;
144 | called[key] = true;
145 | }
146 |
147 | /**
148 | * Make an alias of the key
149 | */
150 | void link(string alternative, string key) {
151 | const flag = called[key];
152 | called[alternative] = flag;
153 |
154 | if (flag) {
155 | storage[alternative] = storage[key];
156 | } else {
157 | constructors[alternative] = constructors[key];
158 | }
159 | }
160 |
161 | /**
162 | * An overloaded function of opIndexAssing
163 | * This function hooks: laa["key"] = value; event but this function might be no use
164 | */
165 | T opIndexAssing(T value, string key) {
166 | storage[key] = value;
167 | called[key] = true;
168 |
169 | return value;
170 | }
171 |
172 | /**
173 | * An overloaded function of opIndex
174 | * This function hooks: laa["key"] event.
175 | */
176 | T opIndex(string key) {
177 | if (key in called && key in alwaysNew) {
178 | return constructors[key]();
179 | }
180 |
181 | if (!called[key]) {
182 | T newT = constructors[key]();
183 |
184 | storage[key] = newT;
185 | called[key] = true;
186 |
187 | return newT;
188 | }
189 |
190 | return storage[key];
191 | }
192 |
193 | bool has(string key) {
194 | return key in called ? true : false;
195 | }
196 |
197 | void setupWith(string name) {
198 | if (!called[name]) {
199 | T newT = constructors[name]();
200 |
201 | storage[name] = newT;
202 | called[name] = true;
203 | }
204 | }
205 |
206 | void setupAll() {
207 | foreach (key; this.constructors.keys) {
208 | this.setupWith(key);
209 | }
210 | }
211 | }
212 |
213 | /**
214 | * Script Engine of ChickenClisp
215 | */
216 | class Engine {
217 | enum ConstructorMode {
218 | CLONE
219 | }
220 |
221 | // Debug flags for Engine
222 | bool debug_get_expression = false;
223 |
224 | /**
225 | * This holds variables and operators.
226 | * You can distinguish A VALUE of the child of this from whether a varibale or an operator.
227 | */
228 | LazedAssocArray!Value variables;
229 |
230 | bool sync_storage;
231 |
232 | /**
233 | * Default Constructor
234 | */
235 | this() {
236 | this.variables = new LazedAssocArray!Value;
237 |
238 | // Arithmetic operations
239 | this.variables.insert!("+", q{new Value(cast(IOperator)(new AddOperator))});
240 | this.variables.insert!("-", q{new Value(cast(IOperator)(new SubOperator))});
241 | this.variables.insert!("*", q{new Value(cast(IOperator)(new MulOperator))});
242 | this.variables.insert!("/", q{new Value(cast(IOperator)(new DivOperator))});
243 | this.variables.insert!("%", q{new Value(cast(IOperator)(new ModOperator))});
244 |
245 | // Comparison operators
246 | this.variables.insert!("=", q{new Value(cast(IOperator)(new EqualOperator))});
247 | this.variables.insert!("<", q{new Value(cast(IOperator)(new LessOperator))});
248 | this.variables.insert!(">", q{new Value(cast(IOperator)(new GreatOperator))});
249 | this.variables.insert!("<=", q{new Value(cast(IOperator)(new LEqOperator))});
250 | this.variables.insert!(">=", q{new Value(cast(IOperator)(new GEqOperator))});
251 |
252 | // Varibale/Function operators
253 | this.variables.insert!("def", q{new Value(cast(IOperator)(new DeffunOperator))});
254 | this.variables.insert!("set", q{new Value(cast(IOperator)(new SetOperator))});
255 | this.variables.insert!("set-p", q{new Value(cast(IOperator)(new SetPOperator))});
256 | this.variables.insert!("set-c", q{new Value(cast(IOperator)(new SetCOperator))});
257 | this.variables.insert!("get", q{new Value(cast(IOperator)(new GetOperator))});
258 | this.variables.insert!("let", q{new Value(cast(IOperator)(new LetOperator))});
259 | this.variables.insert!("as-iv", q{new Value(cast(IOperator)(new AsIVOperator))});
260 | this.variables.insert!("define", q{new Value(cast(IOperator)(new DefineOperator))});
261 | this.variables.insert!("def-var", q{new Value(cast(IOperator)(new DefvarOperator))});
262 | this.variables.insert!("get-fun", q{new Value(cast(IOperator)(new GetfunOperator))});
263 | this.variables.insert!("set-idx", q{new Value(cast(IOperator)(new SetIdxOperator))});
264 |
265 | this.variables.insert!("def-macro", q{new Value(cast(IOperator)(new DefmacroOperator))});
266 |
267 | // Loop operators
268 | this.variables.insert!("step", q{new Value(cast(IOperator)(new StepOperator))});
269 | this.variables.insert!("times", q{new Value(cast(IOperator)(new TimesOperator))});
270 | this.variables.insert!("until", q{new Value(cast(IOperator)(new UntilOperator))});
271 | this.variables.insert!("while", q{new Value(cast(IOperator)(new WhileOperator))});
272 |
273 | // Logic operators
274 | this.variables.insert!("!", q{new Value(cast(IOperator)(new NotOperator))});
275 | this.variables.insert!("&&", q{new Value(cast(IOperator)(new AndOperator))});
276 | this.variables.insert!("||", q{new Value(cast(IOperator)(new OrOperator))});
277 |
278 | // I/O operators
279 | this.variables.insert!("print", q{new Value(cast(IOperator)(new PrintOperator))});
280 | this.variables.insert!("println", q{new Value(cast(IOperator)(new PrintlnOperator))});
281 |
282 | // Condition operators
283 | this.variables.insert!("if", q{new Value(cast(IOperator)(new IfOperator))});
284 | this.variables.insert!("cond", q{new Value(cast(IOperator)(new CondOperator))});
285 | this.variables.insert!("when", q{new Value(cast(IOperator)(new WhenOperator))});
286 |
287 | // Functional operators
288 | this.variables.insert!("lambda", q{new Value(cast(IOperator)(new LambdaOperator))});
289 | this.variables.insert!("map", q{new Value(cast(IOperator)(new MapOperator))});
290 | this.variables.insert!("for-each", q{new Value(cast(IOperator)(new ForeachOperator))});
291 | this.variables.insert!("fold", q{new Value(cast(IOperator)(new FoldOperator))});
292 | this.variables.insert!("filter", q{new Value(cast(IOperator)(new FilterOperator))});
293 |
294 | // List operators
295 | this.variables.insert!("car", q{new Value(cast(IOperator)(new CarOperator))});
296 | this.variables.insert!("cdr", q{new Value(cast(IOperator)(new CdrOperator))});
297 | this.variables.insert!("seq", q{new Value(cast(IOperator)(new SeqOperator))});
298 | this.variables.insert!("cons", q{new Value(cast(IOperator)(new ConsOperator))});
299 | this.variables.insert!("sort", q{new Value(cast(IOperator)(new SortOperator))});
300 | this.variables.insert!("list?", q{new Value(cast(IOperator)(new IsListOperator))});
301 | this.variables.insert!("remove", q{new Value(cast(IOperator)(new RemoveOperator))});
302 | this.variables.insert!("length", q{new Value(cast(IOperator)(new LengthOperator))});
303 |
304 | // HashMap operators
305 | this.variables.insert!("new-hash", q{new Value(cast(IOperator)(new NewHashOperator))});
306 | this.variables.insert!("make-hash", q{new Value(cast(IOperator)(new MakeHashOperator))});
307 | this.variables.insert!("hash-set-value",
308 | q{new Value(cast(IOperator)(new HashSetValueOperator))});
309 | this.variables.insert!("hash-get-value",
310 | q{new Value(cast(IOperator)(new HashGetValueOperator))});
311 | this.variables.insert!("hash-get-keys",
312 | q{new Value(cast(IOperator)(new HashGetKeysOperator))});
313 | this.variables.insert!("hash-get-values",
314 | q{new Value(cast(IOperator)(new HashGetValuesOperator))});
315 |
316 | // String operators
317 | this.variables.insert!("string-concat",
318 | q{new Value(cast(IOperator)(new StringConcatOperator))});
319 | this.variables.insert!("string-join", q{new Value(cast(IOperator)(new StringJoinOperator))});
320 | this.variables.insert!("string-split", q{new Value(cast(IOperator)(new StringSplitOperator))});
321 | this.variables.insert!("string-length",
322 | q{new Value(cast(IOperator)(new StringLengthOperator))});
323 | this.variables.insert!("string-slice", q{new Value(cast(IOperator)(new StringSliceOperator))});
324 | this.variables.insert!("as-string", q{new Value(cast(IOperator)(new AsStringOperator))});
325 | this.variables.insert!("string-repeat",
326 | q{new Value(cast(IOperator)(new StringRepeatOperator))});
327 | this.variables.insert!("string-chomp", q{new Value(cast(IOperator)(new StringChompOperator))});
328 |
329 | // Conversion operators
330 | this.variables.insert!("number-to-string",
331 | q{new Value(cast(IOperator)(new NumberToStringOperator))});
332 | this.variables.insert!("string-to-number",
333 | q{new Value(cast(IOperator)(new StringToNumberOperator))});
334 | this.variables.insert!("number-to-char",
335 | q{new Value(cast(IOperator)(new NumberToCharOperator))});
336 | this.variables.insert!("char-to-number",
337 | q{new Value(cast(IOperator)(new CharToNumberOperator))});
338 | this.variables.insert!("float-to-integer",
339 | q{new Value(cast(IOperator)(new FloatToIntegerOperator))});
340 | this.variables.insert!("ubytes-to-string",
341 | q{new Value(cast(IOperator)(new UbytesToStringOperator))});
342 | this.variables.insert!("ubytes-to-integers",
343 | q{new Value(cast(IOperator)(new UbytesToIntegersOperator))});
344 |
345 | // Array Operators
346 | this.variables.insert!("array-new", q{new Value(cast(IOperator)(new ArrayNewOperator))});
347 | this.variables.insert!("array-get-n", q{new Value(cast(IOperator)(new ArrayGetNOperator))});
348 | this.variables.insert!("array-set-n", q{new Value(cast(IOperator)(new ArraySetNOperator))});
349 | this.variables.insert!("array-slice", q{new Value(cast(IOperator)(new ArraySliceOperator))});
350 | this.variables.insert!("array-append", q{new Value(cast(IOperator)(new ArrayAppendOperator))});
351 | this.variables.insert!("array-concat", q{new Value(cast(IOperator)(new ArrayConcatOperator))});
352 | this.variables.insert!("array-length", q{new Value(cast(IOperator)(new ArrayLengthOperator))});
353 | this.variables.insert!("array-flatten",
354 | q{new Value(cast(IOperator)(new ArrayFlattenOperator))});
355 | this.variables.insert!("array-reverse",
356 | q{new Value(cast(IOperator)(new ArrayReverseOperator))});
357 |
358 | // Utility operators
359 | this.variables.insert!("eval", q{new Value(cast(IOperator)(new EvalOperator))});
360 | this.variables.insert!("load", q{new Value(cast(IOperator)(new LoadOperator))});
361 | this.variables.insert!("type", q{new Value(cast(IOperator)(new TypeOperator))});
362 | this.variables.insert!("alias", q{new Value(cast(IOperator)(new AliasOperator))});
363 | this.variables.insert!("assert", q{new Value(cast(IOperator)(new AssertOperator))});
364 | this.variables.insert!("is-null?", q{new Value(cast(IOperator)(new IsNullOperator))});
365 | this.variables.insert!("is-hash?", q{new Value(cast(IOperator)(new IsHashMapOperator))});
366 | this.variables.insert!("transpile", q{new Value(cast(IOperator)(new TranspileOperator))});
367 |
368 | // Curl Operators
369 | this.variables.insert!("curl-download",
370 | q{new Value(cast(IOperator)(new CurlDownloadOperator))});
371 | this.variables.insert!("curl-upload", q{new Value(cast(IOperator)(new CurlUploadOperator))});
372 | this.variables.insert!("curl-get", q{new Value(cast(IOperator)(new CurlGetOperator))});
373 | this.variables.insert!("curl-get-string",
374 | q{new Value(cast(IOperator)(new CurlGetStringOperator))});
375 | this.variables.insert!("curl-post", q{new Value(cast(IOperator)(new CurlPostOperator))});
376 | this.variables.insert!("curl-post-string",
377 | q{new Value(cast(IOperator)(new CurlPostStringOperator))});
378 |
379 | // Uri Operators
380 | this.variables.insert!("url-encode-component",
381 | q{new Value(cast(IOperator)(new UrlEncodeComponentOperator))});
382 |
383 | // UUID Operators
384 | this.variables.insert!("random-uuid", q{new Value(cast(IOperator)(new RandomUUIDOperator))});
385 |
386 | // Datetime Operators
387 | this.variables.insert!("get-current-unixtime",
388 | q{new Value(cast(IOperator)(new GetCurrentUNIXTime))});
389 |
390 | // Digest Operators
391 | this.variables.insert!("hmac-sha1", q{new Value(cast(IOperator)(new HMACSHA1Operator))});
392 |
393 | // Debug Operators
394 | this.variables.insert!("dump-variables",
395 | q{new Value(cast(IOperator)(new DumpVaribalesOperator))});
396 | this.variables.insert!("peek-closure", q{new Value(cast(IOperator)(new PeekClosureOperator))});
397 | this.variables.insert!("call-closure", q{new Value(cast(IOperator)(new CallClosureOperator))});
398 | this.variables.insert!("toggle-ge-dbg",
399 | q{new Value(cast(IOperator)(new ToggleGEDebugOperator))});
400 |
401 | // Class Operators
402 | this.variables.insert!("class", q{new Value(cast(IOperator)(new ClassOperator))});
403 | this.variables.insert!("new", q{new Value(cast(IOperator)(new NewOperator))});
404 |
405 | // Path Operators
406 | this.variables.insert!("path-exists", q{new Value(cast(IOperator)(new PathExistsOperator))});
407 | this.variables.insert!("path-is-dir", q{new Value(cast(IOperator)(new PathIsDirOperator))});
408 | this.variables.insert!("path-is-file", q{new Value(cast(IOperator)(new PathIsFileOperator))});
409 |
410 | // File Operators
411 | this.variables.insert!("remove-file", q{new Value(cast(IOperator)(new RemoveFileOperator))});
412 | this.variables.insert!("remove-dir", q{new Value(cast(IOperator)(new RemoveDirOperator))});
413 | this.variables.insert!("get-cwd", q{new Value(cast(IOperator)(new GetcwdOperator))});
414 | this.variables.insert!("get-size", q{new Value(cast(IOperator)(new GetsizeOperator))});
415 |
416 | // STDIO Operators
417 | this.variables.insert!("readln", q{new Value(cast(IOperator)(new ReadlnOperator))});
418 | this.variables.insert!("stdin-by-line",
419 | q{new Value(cast(IOperator)(new StdinByLINEOperator))});
420 | this.variables.insert!("stdin-eof", q{new Value(cast(IOperator)(new StdinEofOperator))});
421 |
422 | // Aliases
423 | this.variables.link("not", "!");
424 | this.variables.link("and", "&&");
425 | this.variables.link("or", "||");
426 | this.variables.link("begin", "step");
427 |
428 | // Classes
429 | this.variables.insert("FileClass", () => new Value(cast(ClassType)(new FileClass(this))), true);
430 | this.variables.insert("Regex", () => new Value(cast(ClassType)(new RegexClass(this))), true);
431 |
432 | // Random Operators
433 | this.variables.insert!("random-uniform",
434 | q{new Value(cast(IOperator)(new RandomUniformOperator))});
435 |
436 | // Nop Operator
437 | this.variables.insert!("nop", q{new Value(cast(IOperator)(new NopOperator))});
438 |
439 | // SystemOperator
440 | this.variables.insert!("system", q{new Value(cast(IOperator)(new SystemOperator))});
441 |
442 | version (WithFFI) {
443 | this.variables.insert!("dll", q{new Value(cast(IOperator)(new DllOperator))});
444 | }
445 | }
446 |
447 | /**
448 | * Constructor to make a clone
449 | */
450 | this(ConstructorMode mode) {
451 | }
452 |
453 | /**
454 | * Super Class for a cloned object
455 | */
456 | private Engine _super;
457 |
458 | Engine peekSuper() {
459 | return this._super;
460 | }
461 |
462 | /**
463 | * Clone this object
464 | */
465 | Engine clone() {
466 | Engine newEngine = new Engine(ConstructorMode.CLONE);
467 |
468 | newEngine._super = this;
469 |
470 | newEngine.variables = new LazedAssocArray!Value;
471 |
472 | if (!sync_storage) {
473 | newEngine.variables.called = this.variables.called.dup;
474 | newEngine.variables.constructors = this.variables.constructors;
475 | newEngine.variables.storage = this.variables.storage.dup;
476 | } else {
477 | newEngine.variables.called = this.variables.called;
478 | newEngine.variables.constructors = this.variables.constructors;
479 | newEngine.variables.storage = this.variables.storage;
480 | }
481 |
482 | return newEngine;
483 | }
484 |
485 | /**
486 | * Define new variable
487 | */
488 | public Value defineVariable(string name, Value value) {
489 | this.variables.set(name, value);
490 |
491 | return value;
492 | }
493 |
494 | /**
495 | * Set a value into certain variable
496 | */
497 | public Value setVariable(string name, Value value) {
498 | Engine engine = this;
499 |
500 | while (true) {
501 | if (name in engine.variables.called) {
502 | engine.variables.set(name, value);
503 | return value;
504 | } else if (engine._super !is null) {
505 | engine = engine._super;
506 | } else {
507 | engine.defineVariable(name, value);
508 | }
509 | }
510 | }
511 |
512 | /**
513 | * Get a value from variables table
514 | */
515 | public Value getVariable(string name) {
516 | Engine engine = this;
517 |
518 | while (true) {
519 | if (name in engine.variables.called) {
520 | return engine.variables[name];
521 | } else if (engine._super !is null) {
522 | engine = engine._super;
523 | } else {
524 | return new Value;
525 | }
526 | }
527 | }
528 |
529 | public bool hasVariable(string name) {
530 | Engine engine = this;
531 |
532 | while (true) {
533 | if (engine.variables.has(name)) {
534 | return true;
535 | } else if (engine._super !is null) {
536 | engine = engine._super;
537 | } else {
538 | return false;
539 | }
540 | }
541 | }
542 |
543 | /**
544 | * Evalute Object
545 | */
546 | public Value eval(Value script) {
547 | Value ret = new Value(this.getExpression(script));
548 |
549 | if (ret.type == ValueType.IOperator) {
550 | return ret;
551 | }
552 |
553 | enforce(ret.type == ValueType.IExpression);
554 |
555 | ret = ret.getIExpression.eval(this);
556 |
557 | if (ret.type == ValueType.IOperator) {
558 | return new Value(new Closure(this, ret.getIOperator));
559 | } else {
560 | return ret;
561 | }
562 | }
563 |
564 | /**
565 | * getExpression
566 | * Build Script Tree
567 | */
568 | public IExpression getExpression(Value script) {
569 | if (debug_get_expression) {
570 | import std.stdio;
571 |
572 | writeln("[getExpression] script -> ", script);
573 | }
574 |
575 | if (script.type == ValueType.ImmediateValue) {
576 | return script.getImmediateValue;
577 | }
578 |
579 | if (script.type == ValueType.Array) {
580 | Value[] scriptList = script.getArray;
581 |
582 | if (scriptList.length == 0) {
583 | return new ImmediateValue(new Value(ValueType.Null));
584 | }
585 |
586 | if (scriptList[0].type == ValueType.Array) {
587 | Value op = this.getVariable(scriptList[0][0].getString);
588 |
589 | if (op.type == ValueType.Closure) {
590 | Closure closure = op.getClosure;
591 | Engine engine = closure.engine;
592 | IOperator operator = closure.operator;
593 |
594 | Closure cls = operator.call(engine, scriptList[0].getArray[1 .. $]).getClosure;
595 |
596 | if (scriptList.length == 2) {
597 | return new ImmediateValue(cls.eval(scriptList[1 .. $]));
598 | } else {
599 | return new ImmediateValue(cls.eval([]));
600 | }
601 | } else if (op.type == ValueType.IOperator) {
602 | CallOperator ret = new CallOperator(this.variables[scriptList[0][0].getString].getIOperator,
603 | scriptList[0].getArray[1 .. $]);
604 | Value tmp = ret.eval(this);
605 |
606 | if (tmp.type == ValueType.Closure) {
607 | return new ImmediateValue(tmp.getClosure.eval(scriptList[1 .. $]));
608 | } else if (tmp.type == ValueType.IOperator) {
609 | return new ImmediateValue(tmp.getIOperator.call(this, scriptList[1 .. $]));
610 | } else if (tmp.type == ValueType.ClassType) {
611 | ClassType cls = tmp.getClassType;
612 |
613 | Engine tmp_super = cls._engine._super;
614 | cls._engine._super = this;
615 |
616 | auto _ret = new ImmediateValue(cls.call(cls._engine, scriptList[1 .. $]));
617 |
618 | cls._engine._super = tmp_super;
619 |
620 | return _ret;
621 | } else {
622 | throw new Exception("Invalid type was given as a first argument - " ~ op.toString);
623 | }
624 | } else {
625 | throw new Exception("Invalid Operator was given!");
626 | }
627 | } else if (scriptList[0].type == ValueType.SymbolValue
628 | && this.hasVariable(scriptList[0].getString)) {
629 | Value tmp = this.getVariable(scriptList[0].getString);
630 |
631 | if (tmp.type == ValueType.IOperator) {
632 | IOperator op = tmp.getIOperator;
633 | return new CallOperator(op, scriptList[1 .. $]);
634 | } else if (tmp.type == ValueType.Closure) {
635 | return new CallOperator(tmp.getClosure.operator, scriptList[1 .. $]);
636 | } else if (tmp.type == ValueType.ClassType) {
637 | ClassType cls = tmp.getClassType;
638 |
639 | Engine tmp_super = cls._engine._super;
640 | cls._engine._super = this;
641 |
642 | auto ret = new ImmediateValue(cls.call(cls._engine, scriptList[1 .. $]));
643 |
644 | cls._engine._super = tmp_super;
645 |
646 | return ret;
647 | } else if (tmp.type == ValueType.Macro) {
648 | import orelang.expression.Macro;
649 |
650 | Macro mcr = tmp.getMacro;
651 | return new ImmediateValue(mcr.call(this, scriptList[1 .. $]));
652 | } else {
653 | throw new Exception("Invalid Operator was given!");
654 | }
655 | } else {
656 | throw new Exception("The function or variable %s is undefined".format(scriptList[0]));
657 | }
658 | } else {
659 | if (script.type == ValueType.SymbolValue || script.type == ValueType.String) {
660 | if (script.type == ValueType.SymbolValue) {
661 | Value tmp;
662 | tmp = this.getVariable(script.getString).dup;
663 |
664 | if (tmp.type != ValueType.Null) {
665 | return new ImmediateValue(tmp);
666 | }
667 | } else {
668 | return new ImmediateValue(new Value(script.getString));
669 | }
670 | }
671 |
672 | return new ImmediateValue(script);
673 | }
674 | }
675 |
676 | public bool variableDefined(string name) {
677 | return this.getVariable(name).type != ValueType.Null;
678 | }
679 | }
680 |
--------------------------------------------------------------------------------
/source/orelang/Interpreter.d:
--------------------------------------------------------------------------------
1 | module orelang.Interpreter;
2 | import orelang.Transpiler,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.string,
6 | std.stdio,
7 | std.conv;
8 |
9 | // TODO: Need to implement exit operator
10 |
11 | class Interpreter {
12 | private {
13 | Engine engine;
14 | Transpiler transpiler;
15 | long bracketState;
16 | }
17 |
18 | this() {
19 | this.engine = new Engine();
20 | this.bracketState = 0;
21 | }
22 |
23 | this(Engine engine) {
24 | this.engine = engine;
25 | this.bracketState = 0;
26 | }
27 |
28 | Engine peekEngine() {
29 | return this.engine;
30 | }
31 |
32 | void defineARGS(string[] args) {
33 | Value[] vargs;
34 |
35 | foreach (arg; args) {
36 | vargs ~= new Value(arg);
37 | }
38 |
39 | this.engine.defineVariable("ARGS", new Value(vargs));
40 | }
41 |
42 | bool checkBracket(string code) {
43 | for (size_t i; i < code.length; ++i) {
44 | char ch = code[i];
45 |
46 | if (ch == '(') { this.bracketState++; }
47 | if (ch == ')') { this.bracketState--; }
48 | }
49 |
50 | if (this.bracketState == 0) {
51 | return true;
52 | } else {
53 | return false;
54 | }
55 | }
56 |
57 | void interpreter() {
58 | string buf;
59 | write("=> ");
60 |
61 | void e(char val) {
62 | if (checkBracket(val.to!string) && (buf.length != 0)) {
63 | // writeln("buf -> ", buf);
64 | auto transpiled = Transpiler.transpile(buf);
65 | // writeln("transpiled -> ", transpiled);
66 | writeln(engine.eval(transpiled));
67 | buf = [];
68 | }
69 | }
70 |
71 | while (true) {
72 | string input = readln.chomp;
73 |
74 | if (input == "exit" || input == "(exit)") {
75 | break;
76 | }
77 |
78 | foreach (char val; input) {
79 | if ('\n' == val) {
80 | e(val);
81 | } else {
82 | buf ~= val;
83 | e(val);
84 | }
85 | }
86 |
87 | for (size_t i; i < bracketState + 1; ++i) {
88 | write("=");
89 | }
90 | write("> ");
91 | }
92 | }
93 |
94 | Value executer(string code, bool showMsg = true) {
95 | string buf;
96 | Value ret;
97 |
98 | try {
99 | void e(char val) {
100 | if (checkBracket(val.to!string) && (buf.length != 0)) {
101 | auto transpiled = Transpiler.transpile(buf);
102 | ret = engine.eval(transpiled);
103 | buf = [];
104 | }
105 | }
106 |
107 | foreach(input; code.split("\n")) {
108 | if (input == "exit" || input == "(exit)") {
109 | break;
110 | }
111 |
112 | foreach (char val; input) {
113 | if ('\n' == val) {
114 | e(val);
115 | } else {
116 | buf ~= val;
117 | e(val);
118 | }
119 | }
120 | }
121 |
122 | return ret;
123 | } catch (Exception e) {
124 | if (showMsg) {
125 | writeln("[Exception] - ", e.msg);
126 | }
127 | return new Value(new CCException(e.msg));
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/source/orelang/Parser.d:
--------------------------------------------------------------------------------
1 | module orelang.Parser;
2 | import orelang.expression.ImmediateValue,
3 | orelang.expression.SymbolValue,
4 | orelang.Value;
5 | import std.regex,
6 | std.conv;
7 |
8 | auto nrgx = ctRegex!"[0-9]";
9 |
10 | class Parser {
11 | static size_t nextBracket(string code) {
12 | size_t index,
13 | leftCount = 1,
14 | rightCount;
15 |
16 | while (leftCount != rightCount) {
17 | if (code[index] == '(') { leftCount++; }
18 | if (code[index] == ')') { rightCount++; }
19 | ++index;
20 | }
21 |
22 | return index;
23 | }
24 |
25 | static Value[] parse(string code) {
26 | Value[] _out;
27 |
28 | for (size_t i; i < code.length; ++i) {
29 | dchar ch = code[i];
30 |
31 | if (ch == ' ') {
32 | continue;
33 | } else {
34 | if (ch == '(') {
35 | size_t j = nextBracket(code[i+1..$]);
36 |
37 | _out ~= new Value(parse(code[i+1..i+j]));
38 |
39 | i += j;
40 | } else if (ch == ')') {
41 | return _out;
42 | } else {
43 | if (ch.to!string.match(nrgx) || (i + 1 < code.length && ch == '-' && code[i + 1].to!string.match(nrgx))) {
44 | string tmp;
45 | size_t j = i;
46 |
47 | do {
48 | tmp ~= code[j];
49 | ++j;
50 | } while (
51 | j < code.length &&
52 | ((code[j] != ' ' && code[j].to!string.match(nrgx))
53 | || (code[j] == '.' && j + 1 < code.length && code[j + 1].to!string.match(nrgx)))
54 | );
55 |
56 | _out ~= new Value(tmp.to!double);
57 |
58 | i = j - 1;
59 | } else if (ch == '\"' || ch == '\'') {
60 | if (ch == '\'' && i + 1 < code.length && code[i + 1] == '(') {
61 | size_t j = nextBracket(code[i + 2..$]) + 1;
62 |
63 | _out ~= new Value(new ImmediateValue(new Value(parse(code[i+2..j+i]))));
64 |
65 | i += j;
66 | } else {
67 | string tmp;
68 | size_t j = i + 1;
69 |
70 | while (j < code.length && code[j] != ch) {
71 | if (j < code.length) {
72 | tmp ~= code[j];
73 | } else {
74 | throw new Exception("Syntax Error");
75 | }
76 |
77 | ++j;
78 | }
79 |
80 | _out ~= new Value(tmp);
81 | i = j;
82 | }
83 | } else {
84 | string tmp;
85 | size_t j = i;
86 |
87 | while (
88 | j < code.length && code[j] != '\"' && code[j] != '\'' &&
89 | code[j] != '(' && code[j] != ')' && code[j] != ' '
90 | ) {
91 | tmp ~= code[j];
92 | ++j;
93 | }
94 |
95 | if (tmp == "true") {
96 | _out ~= new Value(true);
97 | } else if (tmp == "false") {
98 | _out ~= new Value(false);
99 | } else if (tmp == "null") {
100 | _out ~= new Value;
101 | } else {
102 | _out ~= new Value(new SymbolValue(tmp));
103 | }
104 |
105 | i = j;
106 | }
107 | }
108 | }
109 | }
110 |
111 | return _out;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/source/orelang/Transpiler.d:
--------------------------------------------------------------------------------
1 | module orelang.Transpiler;
2 | import orelang.Parser,
3 | orelang.Value;
4 | import std.regex;
5 |
6 | class Transpiler {
7 | static Value transpile(string code) {
8 | import std.stdio;
9 | auto ret = Parser.parse(code.replaceAll(ctRegex!"\n", ""));
10 | if (ret.length) {
11 | return ret[0];
12 | } else {
13 | return new Value(0);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/source/orelang/Util.d:
--------------------------------------------------------------------------------
1 | module orelang.Util;
2 |
3 | version (WithFFI) {
4 | extern (C) {
5 | struct ffi_type {
6 | size_t size;
7 | ushort alignment;
8 | ushort type;
9 | ffi_type** elements;
10 | }
11 |
12 | extern __gshared {
13 | ffi_type ffi_type_void;
14 | ffi_type ffi_type_uint8;
15 | ffi_type ffi_type_sint8;
16 | ffi_type ffi_type_uint16;
17 | ffi_type ffi_type_sint16;
18 | ffi_type ffi_type_uint32;
19 | ffi_type ffi_type_sint32;
20 | ffi_type ffi_type_uint64;
21 | ffi_type ffi_type_sint64;
22 | ffi_type ffi_type_float;
23 | ffi_type ffi_type_double;
24 | ffi_type ffi_type_pointer;
25 |
26 | ffi_type ffi_type_longdouble;
27 | }
28 |
29 | enum ffi_status {
30 | FFI_OK = 0,
31 | FFI_BAD_TYPEDEF,
32 | FFI_BAD_ABI
33 | }
34 |
35 | struct ffi_cif {
36 | ffi_abi abi;
37 | uint nargs;
38 | ffi_type** arg_types;
39 | ffi_type* rtype;
40 | uint bytes;
41 | uint flags;
42 | }
43 |
44 | alias ffi_arg = ulong;
45 | alias ffi_sarg = long;
46 |
47 | enum ffi_abi {
48 | FFI_FIRST_ABI = 0,
49 | FFI_SYSV,
50 | FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
51 | FFI_THISCALL,
52 | FFI_FASTCALL,
53 | FFI_STDCALL,
54 | FFI_PASCAL,
55 | FFI_REGISTER,
56 | FFI_LAST_ABI,
57 | FFI_DEFAULT_ABI = FFI_UNIX64
58 | }
59 |
60 | ffi_status ffi_prep_cif(ffi_cif* cif, ffi_abi abi, uint nargs,
61 | ffi_type* rtype, ffi_type** atypes);
62 |
63 | ffi_status ffi_prep_cif_var(ffi_cif* cif, ffi_abi abi, uint nfixedargs,
64 | uint ntotalargs, ffi_type* rtype, ffi_type** atypes);
65 |
66 | void ffi_call(ffi_cif* cif, //void (*fn)(void),
67 | void* fn, void* rvalue, void** avalue);
68 | }
69 | }
--------------------------------------------------------------------------------
/source/orelang/Value.d:
--------------------------------------------------------------------------------
1 | module orelang.Value;
2 | import orelang.expression.ImmediateValue, orelang.operator.DynamicOperator,
3 | orelang.expression.IExpression, orelang.expression.SymbolValue,
4 | orelang.expression.ClassType, orelang.operator.IOperator,
5 | orelang.expression.Macro, orelang.Closure;
6 | import std.algorithm, std.exception, std.stdio, std.array, std.format,
7 | std.traits, std.regex, std.conv;
8 |
9 | enum ValueType {
10 | ImmediateValue,
11 | SymbolValue,
12 | IExpression,
13 | ClassType,
14 | IOperator,
15 | Closure,
16 | HashMap,
17 | Numeric,
18 | String,
19 | Ubyte,
20 | Bool,
21 | Null,
22 | Array,
23 | Macro,
24 | CCException,
25 | RAWPointer
26 | }
27 |
28 | class CCException {
29 | string msg;
30 |
31 | this(string msg) {
32 | this.msg = msg;
33 | }
34 | }
35 |
36 | class Value {
37 | ValueType type;
38 |
39 | private {
40 | double numeric_value;
41 | string string_value;
42 | bool bool_value;
43 | ubyte ubyte_value;
44 | Value[] array_value;
45 | ImmediateValue imv_value;
46 | SymbolValue sym_value;
47 | IExpression ie_value;
48 | ClassType class_value;
49 | IOperator io_value;
50 | Closure closure_value;
51 | Value[string] hashmap_value;
52 | Macro macro_value;
53 | CCException excep_value;
54 | void* raw_pointer;
55 | }
56 |
57 | this() {
58 | this.type = ValueType.Null;
59 | }
60 |
61 | this(ValueType type) {
62 | this.type = type;
63 | }
64 |
65 | this(T)(T value) if (isNumeric!T) {
66 | this.opAssign(value);
67 | }
68 |
69 | this(string value) {
70 | this.opAssign(value);
71 | }
72 |
73 | this(bool value) {
74 | this.opAssign(value);
75 | }
76 |
77 | this(ubyte value) {
78 | this.init;
79 | this.ubyte_value = value;
80 | this.type = ValueType.Ubyte;
81 | }
82 |
83 | this(Value[] value) {
84 | this.opAssign(value);
85 | }
86 |
87 | this(ImmediateValue value) {
88 | this.init;
89 | this.imv_value = value;
90 | this.type = ValueType.ImmediateValue;
91 | }
92 |
93 | this(SymbolValue value) {
94 | this.init;
95 | this.sym_value = value;
96 | this.type = ValueType.SymbolValue;
97 | }
98 |
99 | this(IExpression value) {
100 | this.opAssign(value);
101 | }
102 |
103 | this(ClassType value) {
104 | this.opAssign(value);
105 | }
106 |
107 | this(IOperator value) {
108 | this.opAssign(value);
109 | }
110 |
111 | this(Closure value) {
112 | this.opAssign(value);
113 | }
114 |
115 | this(Value[string] value) {
116 | this.opAssign(value);
117 | }
118 |
119 | this(Macro value) {
120 | this.init;
121 | this.macro_value = value;
122 | this.type = ValueType.Macro;
123 | }
124 |
125 | this(CCException excep) {
126 | this.init;
127 | this.excep_value = excep;
128 | this.type = ValueType.CCException;
129 | }
130 |
131 | this(void* ptr) {
132 | this.init;
133 | this.raw_pointer = ptr;
134 | this.type = ValueType.RAWPointer;
135 | }
136 |
137 | double getNumeric() {
138 | enforce(this.type == ValueType.Numeric);
139 | return this.numeric_value;
140 | }
141 |
142 | string getString() {
143 | enforce(this.type == ValueType.String || this.type == ValueType.SymbolValue);
144 | return this.type == ValueType.String ? this.string_value : this.sym_value.value;
145 | }
146 |
147 | bool getBool() {
148 | enforce(this.type == ValueType.Bool);
149 | return this.bool_value;
150 | }
151 |
152 | ubyte getUbyte() {
153 | enforce(this.type == ValueType.Ubyte);
154 | return this.ubyte_value;
155 | }
156 |
157 | auto getNull() {
158 | throw new Exception("Can't get from NULL value");
159 | }
160 |
161 | Value[] getArray() {
162 | enforce(this.type == ValueType.Array);
163 | return this.array_value;
164 | }
165 |
166 | ImmediateValue getImmediateValue() {
167 | enforce(this.type == ValueType.ImmediateValue);
168 | return this.imv_value;
169 | }
170 |
171 | SymbolValue getSymbolValue() {
172 | enforce(this.type == ValueType.SymbolValue);
173 | return this.sym_value;
174 | }
175 |
176 | IExpression getIExpression() {
177 | enforce(this.type == ValueType.IExpression);
178 | return this.ie_value;
179 | }
180 |
181 | ClassType getClassType() {
182 | enforce(this.type == ValueType.ClassType);
183 | return this.class_value;
184 | }
185 |
186 | IOperator getIOperator() {
187 | enforce(this.type == ValueType.IOperator);
188 | return this.io_value;
189 | }
190 |
191 | Closure getClosure() {
192 | enforce(this.type == ValueType.Closure);
193 | return this.closure_value;
194 | }
195 |
196 | Value[string] getHashMap() {
197 | enforce(this.type == ValueType.HashMap);
198 | return this.hashmap_value;
199 | }
200 |
201 | Macro getMacro() {
202 | enforce(this.type == ValueType.Macro);
203 | return this.macro_value;
204 | }
205 |
206 | CCException getCCException() {
207 | enforce(this.type == ValueType.CCException);
208 | return this.excep_value;
209 | }
210 |
211 | void* getRAWPointer() {
212 | enforce(this.type == ValueType.RAWPointer);
213 | return this.raw_pointer;
214 | }
215 |
216 | void opAssign(T)(T value) if (isNumeric!T) {
217 | this.init;
218 | this.numeric_value = value;
219 | this.type = ValueType.Numeric;
220 | }
221 |
222 | void opAssign(T)(T value) if (is(T == string)) {
223 | this.init;
224 | this.string_value = value;
225 | this.type = ValueType.String;
226 | }
227 |
228 | void opAssign(bool value) {
229 | this.init;
230 | this.bool_value = value;
231 | this.type = ValueType.Bool;
232 | }
233 |
234 | void opAssign(T)(T[] value) if (is(T == Value)) {
235 | this.init;
236 | this.array_value = value;
237 | this.type = ValueType.Array;
238 | }
239 |
240 | void opAssign(T)(T[] value) if (!is(T == Value) && !is(T == immutable(char))) {
241 | this.init;
242 | this.array_value = [];
243 |
244 | foreach (e; value)
245 | this.array_value ~= new Value(e);
246 |
247 | this.type = ValueType.Array;
248 | }
249 |
250 | void opAssign(IExpression value) {
251 | this.init;
252 | this.ie_value = value;
253 | this.type = ValueType.IExpression;
254 | }
255 |
256 | void opAssign(ClassType value) {
257 | this.init;
258 | this.class_value = value;
259 | this.type = ValueType.ClassType;
260 | }
261 |
262 | void opAssign(IOperator value) {
263 | this.init;
264 | this.io_value = value;
265 | this.type = ValueType.IOperator;
266 | }
267 |
268 | void opAssign(Closure value) {
269 | this.init;
270 | this.closure_value = value;
271 | this.type = ValueType.Closure;
272 | }
273 |
274 | void opAssign(Value[string] value) {
275 | this.init;
276 | this.hashmap_value = value;
277 | this.type = ValueType.HashMap;
278 | }
279 |
280 | override string toString() {
281 | final switch (this.type) with (ValueType) {
282 | case Numeric:
283 | return this.numeric_value.to!string;
284 | case String:
285 | return this.string_value;
286 | case Bool:
287 | return this.bool_value.to!string;
288 | case Ubyte:
289 | return this.ubyte_value.to!string;
290 | case Null:
291 | return "null";
292 | case Array:
293 | return "[" ~ this.array_value.map!(value => value.toString).array.join(", ") ~ "]";
294 | case HashMap:
295 | return this.hashmap_value.to!string;
296 | case ImmediateValue:
297 | return this.imv_value.toString;
298 | case SymbolValue:
299 | return this.sym_value.value;
300 | case IExpression:
301 | return this.ie_value.stringof;
302 | case ClassType:
303 | return this.class_value.stringof;
304 | case IOperator:
305 | return this.io_value.stringof;
306 | case Closure:
307 | return this.closure_value.stringof;
308 | case Macro:
309 | return this.macro_value.stringof;
310 | case CCException:
311 | return this.excep_value.msg;
312 | case RAWPointer:
313 | return "Pointer<%x>".format(this.raw_pointer);
314 | }
315 | }
316 |
317 | void addTo(Value value) {
318 | enforce(this.type == value.type && value.type == ValueType.Numeric);
319 | this.numeric_value += value.getNumeric;
320 | }
321 |
322 | void subTo(Value value) {
323 | enforce(this.type == value.type && value.type == ValueType.Numeric);
324 | this.numeric_value -= value.getNumeric;
325 | }
326 |
327 | void mulTo(Value value) {
328 | enforce(this.type == value.type && value.type == ValueType.Numeric);
329 | this.numeric_value *= value.getNumeric;
330 | }
331 |
332 | void divTo(Value value) {
333 | enforce(this.type == value.type && value.type == ValueType.Numeric);
334 | this.numeric_value /= value.getNumeric;
335 | }
336 |
337 | void modTo(Value value) {
338 | enforce(this.type == value.type && value.type == ValueType.Numeric);
339 | this.numeric_value %= value.getNumeric;
340 | }
341 |
342 | Value opBinary(string op)(Value value) if (op == "+") {
343 | enforce(value.type == ValueType.Numeric);
344 | return new Value(this.numeric_value + value.getNumeric);
345 | }
346 |
347 | Value opBinary(string op)(Value value) if (op == "-") {
348 | enforce(value.type == ValueType.Numeric);
349 |
350 | return new Value(this.numeric_value - value.getNumeric);
351 | }
352 |
353 | Value opBinary(string op)(Value value) if (op == "*") {
354 | enforce(value.type == ValueType.Numeric);
355 | return new Value(this.numeric_value * value.getNumeric);
356 | }
357 |
358 | Value opBinary(string op)(Value value) if (op == "/") {
359 | enforce(value.type == ValueType.Numeric);
360 | return new Value(this.numeric_value / value.getNumeric);
361 | }
362 |
363 | Value opBinary(string op)(Value value) if (op == "%") {
364 | enforce(value.type == ValueType.Numeric);
365 | return new Value(this.numeric_value % value.getNumeric);
366 | }
367 |
368 | void init() {
369 | if (this.type != ValueType.Null) {
370 | if (this.type == ValueType.Numeric) {
371 | this.numeric_value = 0;
372 | }
373 | if (this.type == ValueType.String) {
374 | this.string_value = "";
375 | }
376 | if (this.type == ValueType.Array) {
377 | this.array_value = [];
378 | }
379 | if (this.type == ValueType.Bool) {
380 | this.bool_value = false;
381 | }
382 | if (this.type == ValueType.Ubyte) {
383 | this.ubyte_value = 0;
384 | }
385 | if (this.type == ValueType.ImmediateValue) {
386 | this.imv_value = null;
387 | }
388 | if (this.type == ValueType.SymbolValue) {
389 | this.sym_value = null;
390 | }
391 | if (this.type == ValueType.IExpression) {
392 | this.ie_value = null;
393 | }
394 | if (this.type == ValueType.ClassType) {
395 | this.class_value = null;
396 | }
397 | if (this.type == ValueType.IOperator) {
398 | this.io_value = null;
399 | }
400 | if (this.type == ValueType.Closure) {
401 | this.closure_value = null;
402 | }
403 | if (this.type == ValueType.HashMap) {
404 | this.hashmap_value = null;
405 | }
406 | if (this.type == ValueType.Macro) {
407 | this.macro_value = null;
408 | }
409 | if (this.type == ValueType.CCException) {
410 | this.excep_value = null;
411 | }
412 | if (this.type == ValueType.RAWPointer) {
413 | this.raw_pointer = null;
414 | }
415 |
416 | this.type = ValueType.Null;
417 | }
418 | }
419 |
420 | Value opIndex() {
421 | enforce(this.type == ValueType.Array);
422 |
423 | return new Value;
424 | }
425 |
426 | Value opIndex(size_t idx) {
427 | enforce(this.type == ValueType.Array);
428 |
429 | if (!(idx < this.array_value.length)) {
430 | throw new Exception("Out of index of the Array, orded - " ~ idx.to!string
431 | ~ " but length of the array is " ~ this.array_value.length.to!string);
432 | }
433 |
434 | return this.array_value[idx];
435 | }
436 |
437 | Value opIndex(Value value) {
438 | enforce(this.type == ValueType.HashMap);
439 |
440 | if (value.getString !in this.hashmap_value) {
441 | throw new Exception(
442 | "No such a key in the hash, key - " ~ value.toString ~ ", hash - "
443 | ~ this.hashmap_value.stringof);
444 | }
445 |
446 | return this.hashmap_value[value.getString];
447 | }
448 |
449 | override bool opEquals(Object _value) {
450 | if ((cast(Value)_value) is null) {
451 | throw new Exception("Can not compare between incompatibility");
452 | }
453 |
454 | Value value = cast(Value)_value;
455 |
456 | if (this.type != value.type) {
457 | throw new Exception(
458 | "Can not compare between incompatibility type "
459 | ~ this.type.to!string ~ " and " ~ value.type.to!string);
460 | }
461 |
462 | final switch (this.type) with (ValueType) {
463 | case ImmediateValue:
464 | throw new Exception("Can't compare with ImmediateValue");
465 | case SymbolValue:
466 | return this.sym_value.value == value.getSymbolValue.value;
467 | case IExpression:
468 | throw new Exception("Can't compare with IExpression");
469 | case ClassType:
470 | throw new Exception("Can't compare with ClassType");
471 | case IOperator:
472 | throw new Exception("Can't compare with IOperator");
473 | case Closure:
474 | throw new Exception("Can't compare with Closure");
475 | case HashMap:
476 | throw new Exception("Can't compare with HashMap");
477 | case Macro:
478 | throw new Exception("Can't compare with Macro");
479 | case CCException:
480 | throw new Exception("Can't compare with CCException");
481 | case Numeric:
482 | return this.numeric_value == value.numeric_value;
483 | case String:
484 | return this.string_value == value.string_value;
485 | case Bool:
486 | return this.bool_value == value.bool_value;
487 | case Ubyte:
488 | return this.ubyte_value == value.ubyte_value;
489 | case Null:
490 | throw new Exception("Can't compare with Null");
491 | case Array:
492 | Value[] a = this.getArray, b = value.getArray;
493 |
494 | if (a.length != b.length) {
495 | return false;
496 | }
497 |
498 | foreach (idx; 0 .. (a.length)) {
499 | if (a[idx].opCmp(b[idx]) != 0) {
500 | return false;
501 | }
502 | }
503 |
504 | return true;
505 | case RAWPointer:
506 | return this.raw_pointer == value.raw_pointer;
507 | }
508 | }
509 |
510 | override int opCmp(Object _value) {
511 | if ((cast(Value)_value) is null) {
512 | throw new Exception("Can not compare between incompatibility");
513 | }
514 |
515 | Value value = cast(Value)_value;
516 |
517 | if (this.type != value.type) {
518 | throw new Exception(
519 | "Can not compare between incompatibility type "
520 | ~ this.type.to!string ~ " and " ~ value.type.to!string);
521 | }
522 |
523 | final switch (this.type) with (ValueType) {
524 | case ImmediateValue:
525 | throw new Exception("Can't compare with ImmediateValue");
526 | case SymbolValue:
527 | auto c = this.sym_value.value, d = value.getSymbolValue.value;
528 | if (c == d) {
529 | return 0;
530 | }
531 | if (c < d) {
532 | return -1;
533 | }
534 | return 1;
535 | case IExpression:
536 | throw new Exception("Can't compare with IExpression");
537 | case ClassType:
538 | throw new Exception("Can't compare with ClassType");
539 | case IOperator:
540 | throw new Exception("Can't compare with IOperator");
541 | case Closure:
542 | throw new Exception("Can't compare with Closure");
543 | case HashMap:
544 | throw new Exception("Can't compare with HashMap");
545 | case Macro:
546 | throw new Exception("Can't compare with Macro");
547 | case CCException:
548 | throw new Exception("Can't compare with CCException");
549 | case Numeric:
550 | auto c = this.numeric_value, d = value.numeric_value;
551 |
552 | if (c == d) {
553 | return 0;
554 | }
555 | if (c < d) {
556 | return -1;
557 | }
558 | return 1;
559 | case String:
560 | auto c = this.string_value, d = value.string_value;
561 |
562 | if (c == d) {
563 | return 0;
564 | }
565 | if (c < d) {
566 | return -1;
567 | }
568 | return 1;
569 | case Ubyte:
570 | auto c = this.ubyte_value, d = value.ubyte_value;
571 |
572 | if (c == d) {
573 | return 0;
574 | }
575 | if (c < d) {
576 | return -1;
577 | }
578 | return 1;
579 | case Bool:
580 | throw new Exception("Can't compare with Bool");
581 | case Null:
582 | throw new Exception("Can't compare with Null");
583 | case Array:
584 | Value[] a = this.getArray, b = value.getArray;
585 |
586 | if (a.length != b.length) {
587 | throw new Exception("Can't compare between different size array");
588 | }
589 |
590 | foreach (idx; 0 .. (a.length)) {
591 | if (a[idx].opCmp(b[idx]) != 0) {
592 | return 1;
593 | }
594 | }
595 |
596 | return 0;
597 | case RAWPointer:
598 | auto c = this.raw_pointer, d = value.raw_pointer;
599 |
600 | if (c == d) {
601 | return 0;
602 | }
603 | if (c < d) {
604 | return -1;
605 | }
606 | return 1;
607 | }
608 | }
609 |
610 | Value dup() {
611 | final switch (this.type) with (ValueType) {
612 | case ImmediateValue:
613 | return new Value(this.imv_value);
614 | case SymbolValue:
615 | return new Value(this.sym_value);
616 | case IExpression:
617 | return new Value(this.ie_value);
618 | case ClassType:
619 | return new Value(this.class_value);
620 | case IOperator:
621 | return new Value(this.io_value);
622 | case Closure:
623 | return new Value(this.closure_value);
624 | case HashMap:
625 | return new Value(this.hashmap_value);
626 | case Numeric:
627 | return new Value(this.numeric_value);
628 | case String:
629 | return new Value(this.string_value);
630 | case Bool:
631 | return new Value(this.bool_value);
632 | case Ubyte:
633 | return new Value(this.ubyte_value);
634 | case Null:
635 | return new Value;
636 | case Array:
637 | return new Value(this.array_value.dup);
638 | case Macro:
639 | return new Value(this.macro_value);
640 | case CCException:
641 | return new Value(this.excep_value);
642 | case RAWPointer:
643 | return new Value(this.raw_pointer);
644 | }
645 | }
646 | }
647 |
--------------------------------------------------------------------------------
/source/orelang/expression/CallOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.expression.CallOperator;
2 | import orelang.expression.IExpression,
3 | orelang.operator.IOperator,
4 | orelang.Closure,
5 | orelang.Engine,
6 | orelang.Value;
7 |
8 | class CallOperator : IExpression {
9 | private {
10 | IOperator operator;
11 | Value[] args;
12 | }
13 |
14 | this(IOperator operator, Value[] args) {
15 | this.operator = operator;
16 | this.args = args;
17 | }
18 |
19 | /**
20 | * eval
21 | */
22 | public Value eval(Engine engine) {
23 | Closure closure = engine.eval(new Value(this.operator)).getClosure;
24 |
25 | return closure.eval(this.args);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/source/orelang/expression/ClassType.d:
--------------------------------------------------------------------------------
1 | module orelang.expression.ClassType;
2 | import orelang.Engine,
3 | orelang.Value;
4 |
5 | class ClassType {
6 | Engine _engine;
7 |
8 | this(Engine _engine) {
9 | this._engine = _engine;
10 | }
11 |
12 | public Value call(Engine engine, Value[] args) {
13 | string funcName;
14 | if (args[0].type == ValueType.SymbolValue) {
15 | funcName = args[0].getString;
16 | } else {
17 | funcName = engine.eval(args[0]).getString;
18 | }
19 |
20 | Value member = this._engine.variables[funcName];
21 |
22 | if (member.type == ValueType.IOperator) {
23 | return member.getIOperator.call(this._engine, args.length > 1 ? args[1..$] : (Value[]).init);
24 | } else {
25 | return member;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/source/orelang/expression/IExpression.d:
--------------------------------------------------------------------------------
1 | module orelang.expression.IExpression;
2 | import orelang.Engine,
3 | orelang.Value;
4 |
5 | interface IExpression {
6 | Value eval(Engine engine);
7 | }
8 |
--------------------------------------------------------------------------------
/source/orelang/expression/ImmediateValue.d:
--------------------------------------------------------------------------------
1 | module orelang.expression.ImmediateValue;
2 | import orelang.expression.IExpression,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.string,
6 | std.conv;
7 |
8 | class ImmediateValue : IExpression {
9 | Value value;
10 |
11 | this(Value value) {
12 | this.value = value;
13 | }
14 |
15 | public Value eval(Engine engine) {
16 | return this.value;
17 | }
18 |
19 | override string toString() {
20 | string base = "ImmediateValue {";
21 | string _body;
22 |
23 | if (value.type == ValueType.Array) {
24 | string[] elems;
25 |
26 | foreach (elem; value.getArray) {
27 | elems ~= elem.toString;
28 | }
29 |
30 | _body = "[" ~ elems.join(", ") ~ "]";
31 | } else {
32 | _body = value.toString;
33 | }
34 |
35 | return base ~ _body ~ "}";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/source/orelang/expression/Macro.d:
--------------------------------------------------------------------------------
1 | module orelang.expression.Macro;
2 | import orelang.expression.IExpression,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.string,
6 | std.conv;
7 |
8 | class Macro {
9 | string macro_name;
10 | string[] macro_args;
11 | Value macro_body;
12 |
13 | this(string name, string[] args, Value _body) {
14 | this.macro_name = name;
15 | this.macro_args = args;
16 | this.macro_body = _body;
17 | }
18 |
19 | public Value call(Engine engine, Value[] args) {
20 | import std.stdio;
21 |
22 | Value[string] convList;
23 |
24 | foreach (idx, arg; macro_args) {
25 | convList[arg] = args[idx];
26 | }
27 |
28 | Value[] analysis(Value source) {
29 | Value[] dist;
30 |
31 | if (source.type == ValueType.Array) {
32 | foreach (elem; source.getArray) {
33 | if (elem.type == ValueType.Array) {
34 | dist ~= new Value(analysis(elem));
35 | } else {
36 | if (elem.type == ValueType.SymbolValue) {
37 | if (elem.getString in convList) {
38 | elem = convList[elem.getString];
39 | }
40 | }
41 |
42 | dist ~= elem;
43 | }
44 | }
45 | } else {
46 | dist ~= source;
47 | }
48 |
49 | return dist;
50 | }
51 |
52 | return engine.eval(new Value(analysis(this.macro_body)));
53 | }
54 |
55 | override string toString() {
56 | return "Macro";
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/source/orelang/expression/SymbolValue.d:
--------------------------------------------------------------------------------
1 | module orelang.expression.SymbolValue;
2 | import orelang.expression.IExpression,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.string,
6 | std.conv;
7 |
8 | class SymbolValue : IExpression {
9 | string value;
10 |
11 | this(string value) {
12 | this.value = value;
13 | }
14 |
15 | public Value eval(Engine engine) {
16 | return new Value(this.value);
17 | }
18 |
19 | override string toString() {
20 | return "SymbolValue(" ~ this.value ~ ")";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/source/orelang/operator/AddOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.AddOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class AddOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = new Value(0.0);
12 |
13 | foreach (arg; args) {
14 | Value v = engine.eval(arg);
15 | ret.addTo(v);
16 | }
17 |
18 | return ret;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/operator/AliasOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.AliasOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class AliasOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | string _new = args[0].getString;
12 | string base = args[1].getString;
13 |
14 | if (base in engine.variables) {
15 | Value v = engine.variables[base];
16 |
17 | engine.variables.set(_new, v);
18 |
19 | return v;
20 | } else {
21 | throw new Exception("No such variable or operator - " ~ base);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/orelang/operator/ArrayOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.ArrayOperators;
2 | import orelang.expression.ImmediateValue,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 | import std.algorithm,
7 | std.string,
8 | std.array,
9 | std.conv;
10 |
11 | /**
12 | * revese given array
13 | */
14 | class ArrayReverseOperator : IOperator {
15 | /**
16 | * call
17 | */
18 | public Value call(Engine engine, Value[] args) {
19 | Value[] ret;
20 | Value eargs0 = engine.eval(args[0]);
21 |
22 | if (eargs0.type == ValueType.Array) {
23 | foreach_reverse (elem; eargs0.getArray) {
24 | ret ~= elem;
25 | }
26 | } else if (eargs0.type == ValueType.ImmediateValue && eargs0.getImmediateValue.value.type == ValueType.Array) {
27 | foreach_reverse (elem; eargs0.getImmediateValue.value.getArray) {
28 | ret ~= elem;
29 | }
30 | } else {
31 | throw new Exception("[number-to-string] Invalid argument was given.");
32 | }
33 |
34 | return new Value(ret);
35 | }
36 | }
37 |
38 | /**
39 | * Set a value into the order of the array
40 | */
41 | class ArraySetNOperator : IOperator {
42 | /**
43 | * call
44 | */
45 | public Value call(Engine engine, Value[] args) {
46 | Value[] arr;
47 | Value eargs0 = engine.eval(args[0]);
48 |
49 | if (eargs0.type == ValueType.ImmediateValue) {
50 | arr = eargs0.getImmediateValue.value.getArray;
51 | } else {
52 | arr = eargs0.getArray;
53 | }
54 |
55 | long idx = engine.eval(args[1]).getNumeric.to!long;
56 | Value value = engine.eval(args[2]);
57 |
58 | if (0 <= idx && idx < arr.length) {
59 | arr[idx] = value;
60 |
61 | return new Value(arr);
62 | } else {
63 | throw new Exception("Invalid");
64 | }
65 | }
66 | }
67 |
68 | /**
69 | * Get a value from the order of the array
70 | */
71 | class ArrayGetNOperator : IOperator {
72 | /**
73 | * call
74 | */
75 | public Value call(Engine engine, Value[] args) {
76 | Value[] arr;
77 | Value eargs0 = engine.eval(args[0]);
78 |
79 | if (eargs0.type == ValueType.ImmediateValue) {
80 | arr = eargs0.getImmediateValue.value.getArray;
81 | } else {
82 | arr = eargs0.getArray;
83 | }
84 |
85 | long idx = engine.eval(args[1]).getNumeric.to!long;
86 |
87 | if (0 <= idx && idx < arr.length) {
88 | return arr[idx];
89 | } else {
90 | throw new Exception("[get] Invalid");
91 | }
92 | }
93 | }
94 |
95 | /**
96 | * Append a value from the order of the array
97 | */
98 | class ArrayAppendOperator : IOperator {
99 | /**
100 | * call
101 | */
102 | public Value call(Engine engine, Value[] args) {
103 | Value[] arr;
104 | Value eargs0 = engine.eval(args[0]);
105 |
106 | if (eargs0.type == ValueType.ImmediateValue) {
107 | arr = eargs0.getImmediateValue.value.getArray;
108 | } else {
109 | arr = eargs0.getArray;
110 | }
111 |
112 | foreach (arg; args[1..$]) {
113 | arr ~= engine.eval(arg);
114 | }
115 |
116 | return new Value(arr);
117 | }
118 | }
119 |
120 | /**
121 | * Tak a slice from the range of the array
122 | */
123 | class ArraySliceOperator : IOperator {
124 | /**
125 | * call
126 | */
127 | public Value call(Engine engine, Value[] args) {
128 | Value[] arr;
129 | Value eargs0 = engine.eval(args[0]);
130 |
131 | if (eargs0.type == ValueType.ImmediateValue) {
132 | arr = eargs0.getImmediateValue.value.getArray;
133 | } else {
134 | arr = eargs0.getArray;
135 | }
136 |
137 | long slice1 = engine.eval(args[1]).getNumeric.to!long,
138 | slice2 = engine.eval(args[2]).getNumeric.to!long;
139 |
140 | if ((0 <= slice1 && 0 <= slice2) && (slice1 <= arr.length && slice2 <= arr.length)) {
141 | return new Value(arr[slice1..slice2]);
142 | } else {
143 | throw new Exception("[get] Invalid");
144 | }
145 | }
146 | }
147 |
148 | /**
149 | * concat arrays
150 | */
151 | class ArrayConcatOperator : IOperator {
152 | /**
153 | * call
154 | */
155 | public Value call(Engine engine, Value[] args) {
156 | Value[] arr;
157 |
158 | foreach (arg; args) {
159 | Value earg = engine.eval(arg);
160 | Value[] tarr;
161 |
162 | if (earg.type == ValueType.ImmediateValue) {
163 | tarr = earg.getImmediateValue.value.getArray;
164 | } else {
165 | tarr = earg.getArray;
166 | }
167 |
168 | foreach (t; tarr) {
169 | arr ~= t;
170 | }
171 | }
172 |
173 | return new Value(arr);
174 | }
175 | }
176 |
177 | /**
178 | * return the length of the array
179 | */
180 | class ArrayLengthOperator : IOperator {
181 | /**
182 | * call
183 | */
184 | public Value call(Engine engine, Value[] args) {
185 | Value[] arr;
186 | Value eargs0 = engine.eval(args[0]);
187 |
188 | if (eargs0.type == ValueType.ImmediateValue) {
189 | arr = eargs0.getImmediateValue.value.getArray;
190 | } else {
191 | arr = eargs0.getArray;
192 | }
193 |
194 | return new Value(arr.length.to!double);
195 | }
196 | }
197 |
198 | /**
199 | * make a new array
200 | */
201 | class ArrayNewOperator : IOperator {
202 | /**
203 | * call
204 | */
205 | public Value call(Engine engine, Value[] args) {
206 | Value[] ret;
207 |
208 | foreach (arg; args) {
209 | ret ~= engine.eval(arg);
210 | }
211 |
212 | return new Value(ret);
213 | }
214 | }
215 |
216 | /**
217 | * return flattend array of the given array
218 | */
219 | class ArrayFlattenOperator : IOperator {
220 | /**
221 | * call
222 | */
223 | public Value call(Engine engine, Value[] args) {
224 | Value[] ret;
225 |
226 | foreach (arg; args) {
227 | if (arg.type == ValueType.Array) {
228 | foreach (elem; engine.eval(arg).getArray) {
229 | foreach (ee; elem.getArray) {
230 | ret ~= ee;
231 | }
232 | }
233 | } else {
234 | Value earg = engine.eval(arg);
235 | ret ~= earg;
236 | }
237 | }
238 |
239 | return new Value(ret);
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/source/orelang/operator/AsIVOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.AsIVOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 |
7 | class AsIVOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | return new Value(new ImmediateValue(engine.eval(args[0])));
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/source/orelang/operator/AssertOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.AssertOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class AssertOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value evaled = engine.eval(args[0]);
12 | bool flag;
13 |
14 | switch (evaled.type) with (ValueType) {
15 | case Bool:
16 | flag = evaled.getBool;
17 | break;
18 | case Numeric:
19 | flag = cast(bool)evaled.getNumeric;
20 | break;
21 | default:
22 | flag = true;
23 | break;
24 | }
25 |
26 | if (!flag) {
27 | throw new Exception("Assertion failed: " ~ args[0].toString);
28 | }
29 |
30 | return new Value(true);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/source/orelang/operator/CarOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.CarOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.conv;
6 |
7 | class CarOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | Value obj = engine.eval(args[0]);
13 |
14 | if (obj.type == ValueType.Array) {
15 | Value[] obx = obj.getArray;
16 |
17 | if (obx.length >= 1) {
18 | return obx[0];
19 | } else {
20 | throw new Exception("pair required, but got ()");
21 | }
22 | } else {
23 | throw new Exception("pair required, but got invalid data, the type of which is " ~ obj.type.to!string);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/orelang/operator/CdrOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.CdrOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.conv;
6 |
7 | class CdrOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | Value obj = engine.eval(args[0]);
13 |
14 | if (obj.type == ValueType.Array) {
15 | Value[] obx = obj.getArray;
16 |
17 | if (obx.length == 1) {
18 | Value[] arr;
19 | return new Value(arr);
20 | } else if (obx.length > 1) {
21 | return new Value(obx[1..$]);
22 | } else {
23 | throw new Exception("pair required, but got ()");
24 | }
25 | } else {
26 | throw new Exception("pair required, but got invalid data, the type of which is " ~ obj.type.to!string);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/source/orelang/operator/ClassOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.ClassOperators;
2 | import orelang.operator.DynamicOperator,
3 | orelang.expression.ClassType,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 |
9 | class ClassOperator : IOperator {
10 | public Value call(Engine engine, Value[] args) {
11 | string className = engine.eval(args[0]).getString;
12 | Engine cEngine = engine.clone;
13 |
14 | if (args.length > 1) {
15 | foreach (member; args[1..$]) {
16 | cEngine.eval(member);
17 | }
18 | }
19 |
20 | if ("constructor" !in cEngine.variables.called) {
21 | cEngine.defineVariable("constructor", new Value(cast(IOperator)(new DynamicOperator((string[]).init, new Value))));
22 | }
23 |
24 | ClassType clst = new ClassType(cEngine);
25 | Value cls = new Value(clst);
26 |
27 | engine.defineVariable(className, cls);
28 |
29 | return cls;
30 | }
31 | }
32 |
33 |
34 | class NewOperator : IOperator {
35 | public Value call(Engine engine, Value[] args) {
36 | string className;
37 |
38 | if (args[0].type == ValueType.SymbolValue) {
39 | className = args[0].getString;
40 | } else {
41 | className = engine.eval(args[0]).getString;
42 | }
43 |
44 | ClassType _cls = engine.getVariable(className).getClassType;
45 | ClassType cls = new ClassType(_cls._engine.clone);
46 |
47 | Value[] cArgs;
48 |
49 | if (args.length > 0) {
50 | foreach (arg; args[1..$]) {
51 | cArgs ~= engine.eval(arg);
52 | }
53 | }
54 |
55 | cls._engine.variables["constructor"].getIOperator.call(cls._engine, cArgs);
56 |
57 | return new Value(cls);
58 | }
59 | }
--------------------------------------------------------------------------------
/source/orelang/operator/CondOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.CondOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class CondOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | for (size_t i; i < args.length; ++i) {
12 | Value[] state = args[i].getArray;
13 | Value pred = state[0];
14 | Value expr = state[1];
15 |
16 | Value epred = engine.eval(pred);
17 |
18 | if ((epred.type == ValueType.Bool && epred.getBool) || ((pred.type == ValueType.SymbolValue || pred.type == ValueType.String) && pred.getString == "else")) {
19 | return engine.eval(expr);
20 | }
21 | }
22 |
23 | return new Value(0.0);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/orelang/operator/ConsOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.ConsOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class ConsOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value car = engine.eval(args[0]);
12 | Value cdr = engine.eval(args[1]);
13 |
14 | Value[] ret = [car];
15 |
16 | if (cdr.type == ValueType.Array) {
17 | foreach (elem; cdr.getArray) {
18 | ret ~= engine.eval(elem);
19 | }
20 | } else {
21 | ret ~= cdr;
22 | }
23 |
24 | return new Value(ret);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/orelang/operator/ConvOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.ConvOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.algorithm,
6 | std.string,
7 | std.array,
8 | std.conv;
9 |
10 | /**
11 | * convert number into string
12 | */
13 | class NumberToStringOperator : IOperator {
14 | /**
15 | * call
16 | */
17 | public Value call(Engine engine, Value[] args) {
18 | return new Value(engine.eval(args[0]).getNumeric.to!string);
19 | }
20 | }
21 |
22 | /**
23 | * convert string into number
24 | */
25 | class StringToNumberOperator : IOperator {
26 | /**
27 | * call
28 | */
29 | public Value call(Engine engine, Value[] args) {
30 | return new Value(engine.eval(args[0]).getString.to!ulong);
31 | }
32 | }
33 |
34 |
35 | /**
36 | * convert number into char
37 | */
38 | class NumberToCharOperator : IOperator {
39 | /**
40 | * call
41 | */
42 | public Value call(Engine engine, Value[] args) {
43 | return new Value(engine.eval(args[0]).getNumeric.to!char.to!string);
44 | }
45 | }
46 |
47 | /**
48 | * convert char into number
49 | */
50 | class CharToNumberOperator : IOperator {
51 | /**
52 | * call
53 | */
54 | public Value call(Engine engine, Value[] args) {
55 | return new Value(engine.eval(args[0]).getString[0].to!double);
56 | }
57 | }
58 |
59 | /**
60 | * convert float into integer
61 | */
62 | class FloatToIntegerOperator : IOperator {
63 | /**
64 | * call
65 | */
66 | public Value call(Engine engine, Value[] args) {
67 | return new Value(engine.eval(args[0]).getNumeric.to!long.to!double);
68 | }
69 | }
70 |
71 | /**
72 | * convert ubytes into string
73 | */
74 | class UbytesToStringOperator : IOperator {
75 | /**
76 | * call
77 | */
78 | public Value call(Engine engine, Value[] args) {
79 | Value[] array = engine.eval(args[0]).getArray;
80 | ubyte[] ubytes;
81 |
82 | foreach (elem; array) {
83 | ubytes ~= elem.getUbyte;
84 | }
85 |
86 | return new Value(cast(string)ubytes);
87 | }
88 | }
89 |
90 | /**
91 | * convert ubytes into string
92 | */
93 | class UbytesToIntegersOperator : IOperator {
94 | /**
95 | * call
96 | */
97 | public Value call(Engine engine, Value[] args) {
98 | Value[] array = engine.eval(args[0]).getArray;
99 | Value[] ret;
100 |
101 |
102 | foreach (elem; array) {
103 | ret ~= new Value(elem.getUbyte.to!double);
104 | }
105 |
106 | return new Value(ret);
107 | }
108 | }
--------------------------------------------------------------------------------
/source/orelang/operator/CurlOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.CurlOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.net.curl;
6 |
7 | class CurlDownloadOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | string url = engine.eval(args[0]).getString,
13 | saveToPath = engine.eval(args[1]).getString;
14 |
15 | try {
16 | download(url, saveToPath);
17 |
18 | return new Value(true);
19 | } catch(Exception e) {
20 | return new Value(false);
21 | }
22 | }
23 | }
24 |
25 | class CurlUploadOperator : IOperator {
26 | /**
27 | * call
28 | */
29 | public Value call(Engine engine, Value[] args) {
30 | string loadFromPath = engine.eval(args[0]).getString,
31 | url = engine.eval(args[1]).getString;
32 |
33 | try {
34 | upload(loadFromPath, url);
35 |
36 | return new Value(true);
37 | } catch(Exception e) {
38 | return new Value(false);
39 | }
40 | }
41 | }
42 |
43 | class CurlGetOperator : IOperator {
44 | /**
45 | * call
46 | */
47 | public Value call(Engine engine, Value[] args) {
48 | string url = engine.eval(args[0]).getString;
49 |
50 | try {
51 | auto contents = {
52 | if (args.length == 2) {
53 | auto http = HTTP();
54 | Value[string] headers = engine.eval(args[1]).getHashMap;
55 |
56 | foreach (key, value; headers) {
57 | http.addRequestHeader(key, value.getString);
58 | }
59 |
60 | return get(url, http);
61 | } else {
62 | return get(url);
63 | }
64 | }();
65 | Value[] ret;
66 |
67 | foreach (elem; contents) {
68 | ret ~= new Value(elem);
69 | }
70 |
71 | return new Value(ret);
72 | } catch(CurlException e) {
73 | return new Value;
74 | }
75 | }
76 | }
77 |
78 | class CurlGetStringOperator : IOperator {
79 | /**
80 | * call
81 | */
82 | public Value call(Engine engine, Value[] args) {
83 | CurlGetOperator cgo = new CurlGetOperator;
84 | Value[] ret = cgo.call(engine, args).getArray;
85 | ubyte[] data;
86 |
87 | foreach (e; ret) {
88 | if (e.type == ValueType.Ubyte) {
89 | data ~= e.getUbyte;
90 | } else {
91 | throw new Exception("Fatal internal error - Invalid typed data was given to curl-get-string");
92 | }
93 | }
94 |
95 | return new Value(cast(string)data);
96 | }
97 | }
98 |
99 | class CurlPostOperator : IOperator {
100 | /**
101 | * call
102 | */
103 | import std.algorithm,
104 | std.string,
105 | std.array,
106 | std.range,
107 | std.conv;
108 | public Value call(Engine engine, Value[] args) {
109 | string url = engine.eval(args[0]).getString;
110 | Value pargs = engine.eval(args[1]);
111 |
112 | if (pargs.type == ValueType.HashMap) {
113 | string[string] params;
114 | Value[string] dict = pargs.getHashMap;
115 |
116 | foreach (key, value; dict) {
117 | params[key] = value.getString;
118 | }
119 |
120 | auto contents = {
121 | if (args.length == 3) {
122 | auto http = HTTP();
123 | Value[string] headers = engine.eval(args[2]).getHashMap;
124 |
125 | foreach (key, value; headers) {
126 | http.addRequestHeader(key, value.getString);
127 | }
128 |
129 | return post(url, params.keys.map!(k => k ~ "=" ~ params[k]).join("&"), http);
130 | } else {
131 | return post(url, params.keys.map!(k => k ~ "=" ~ params[k]).join("&"));
132 | }
133 | }();
134 | Value[] ret;
135 |
136 | foreach (elem; contents) {
137 | ret ~= new Value(elem);
138 | }
139 |
140 | return new Value(ret);
141 | } else if (pargs.type == ValueType.Array || (pargs.type == ValueType.ImmediateValue && (pargs.getImmediateValue.value.type == ValueType.Array))) {
142 | Value[] array;
143 | if (pargs.type == ValueType.Array) {
144 | array = pargs.getArray;
145 | } else {
146 | array = pargs.getImmediateValue.value.getArray;
147 | }
148 |
149 | ubyte[] postData;
150 |
151 | foreach (value; array) {
152 | switch (value.type) with (ValueType) {
153 | case Ubyte:
154 | postData ~= value.getUbyte;
155 | break;
156 | case Numeric:
157 | postData ~= value.getNumeric.to!ubyte;
158 | break;
159 | default:
160 | throw new Exception("Invalid argument was given to curl-post");
161 | }
162 | }
163 |
164 | auto contents = {
165 | if (args.length == 3) {
166 | auto http = HTTP();
167 | Value[string] headers = engine.eval(args[2]).getHashMap;
168 |
169 | foreach (key, value; headers) {
170 | http.addRequestHeader(key, value.getString);
171 | }
172 |
173 | return post(url, postData, http);
174 | } else {
175 | return post(url, postData);
176 | }
177 | }();
178 | Value[] ret;
179 |
180 | foreach (elem; contents) {
181 | ret ~= new Value(elem);
182 | }
183 |
184 | return new Value(ret);
185 | } else if (pargs.type == ValueType.String) {
186 | auto contents = {
187 | if (args.length == 3) {
188 | auto http = HTTP();
189 | Value[string] headers = engine.eval(args[2]).getHashMap;
190 |
191 | foreach (key, value; headers) {
192 | http.addRequestHeader(key, value.getString);
193 | }
194 |
195 | return post(url, pargs.getString, http);
196 | } else {
197 | return post(url, pargs.getString);
198 | }
199 | }();
200 | Value[] ret;
201 |
202 | foreach (elem; contents) {
203 | ret ~= new Value(elem);
204 | }
205 |
206 | return new Value(ret);
207 | } else {
208 | throw new Exception("Invalid argument was given to curl-post");
209 | }
210 | }
211 | }
212 |
213 | class CurlPostStringOperator : IOperator {
214 | /**
215 | * call
216 | */
217 | public Value call(Engine engine, Value[] args) {
218 | CurlPostOperator cpo = new CurlPostOperator;
219 | Value[] ret = cpo.call(engine, args).getArray;
220 | ubyte[] data;
221 |
222 | foreach (e; ret) {
223 | if (e.type == ValueType.Ubyte) {
224 | data ~= e.getUbyte;
225 | } else {
226 | throw new Exception("Fatal internal error - Invalid typed data was given to curl-post-string");
227 | }
228 | }
229 |
230 | return new Value(cast(string)data);
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/source/orelang/operator/DatetimeOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DatetimeOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.datetime,
6 | std.conv;
7 |
8 | class GetCurrentUNIXTime : IOperator {
9 | /**
10 | * call
11 | */
12 | public Value call(Engine engine, Value[] args) {
13 | return new Value(Clock.currTime.toUnixTime.to!string);
14 | }
15 | }
--------------------------------------------------------------------------------
/source/orelang/operator/DebugOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DebugOperators;
2 | import orelang.operator.DynamicOperator,
3 | orelang.expression.SymbolValue,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 | import std.stdio;
9 |
10 | class DumpVaribalesOperator : IOperator {
11 | public Value call(Engine engine, Value[] args) {
12 | auto storage = engine.variables;
13 |
14 | writeln("[DEBUG - DumpVaribalesOperator]");
15 | foreach (key, value; storage) {
16 | writeln("[Varibale] ", key, " <=> ", value);
17 | }
18 |
19 | return new Value;
20 | }
21 | }
22 |
23 | class PeekClosureOperator : IOperator {
24 | public Value call(Engine engine, Value[] args) {
25 | Closure cls = engine.eval(args[0]).getClosure;
26 | auto storage = cls.engine.variables;
27 |
28 | writeln("[DEBUG - PeekClosureOperator]");
29 | writeln(" - cls.engine -> ", cls.engine);
30 | writeln(" - cls.operator -> ", cls.operator);
31 |
32 | foreach (key, value; storage) {
33 | writeln("[Varibale] ", key, " <=> ", value);
34 | }
35 |
36 | return new Value;
37 | }
38 | }
39 |
40 | class CallClosureOperator : IOperator {
41 | public Value call(Engine engine, Value[] args) {
42 | Closure cls = engine.eval(args[0]).getClosure;
43 | writeln("[DEBUG - CallClosureOperator]");
44 | writeln(" - cls.engine -> ", cls.engine);
45 | writeln(" - cls.operator -> ", cls.operator);
46 |
47 | return cls.eval(args[1..$]);
48 | }
49 | }
50 |
51 | class LookupSymbolOperator : IOperator {
52 | public Value call(Engine engine, Value[] args) {
53 | SymbolValue cls = engine.eval(args[0]).getSymbolValue;
54 |
55 | return new Value;
56 | }
57 | }
58 |
59 | class ToggleGEDebugOperator : IOperator {
60 | public Value call(Engine engine, Value[] args) {
61 | engine.debug_get_expression ^= 1;
62 |
63 | return new Value;
64 | }
65 | }
--------------------------------------------------------------------------------
/source/orelang/operator/DeffunOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DeffunOperator;
2 | import orelang.operator.DynamicOperator, orelang.operator.IOperator,
3 | orelang.Engine, orelang.Value;
4 | import std.algorithm, std.array;
5 | import kontainer.orderedAssocArray;
6 |
7 | class DeffunOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | string funcName = args[0].getString;
13 | string[] funcArgs;
14 | OrderedAssocArray!(string, Value) optionArgs = new OrderedAssocArray!(string, Value)();
15 |
16 | foreach (maybeArg; args[1].getArray) {
17 | if (maybeArg.type == ValueType.String || maybeArg.type == ValueType.SymbolValue) {
18 | funcArgs ~= maybeArg.getString;
19 | } else if (maybeArg.type == ValueType.Array) {
20 | auto pair = maybeArg.getArray;
21 | string name = pair[0].getString;
22 | Value value = pair[1];
23 | optionArgs[name] = value;
24 | } else {
25 | throw new Error("Invalid argument list");
26 | }
27 | }
28 |
29 | Value funcBody = args[2];
30 |
31 | return engine.defineVariable(funcName,
32 | new Value(cast(IOperator)(new DynamicOperator(funcArgs, funcBody, optionArgs))));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/source/orelang/operator/DefineOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DefineOperator;
2 | import orelang.operator.DynamicOperator,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 | import std.algorithm,
7 | std.array;
8 |
9 | class DefineOperator : IOperator {
10 | /**
11 | * call
12 | */
13 | public Value call(Engine engine, Value[] args) {
14 | if (args[0].type == ValueType.SymbolValue) {// variable
15 | string varName = args[0].getString;
16 | Value var = args[1];
17 |
18 | engine.defineVariable(varName, var);
19 |
20 | return var;
21 | } else if (args[0].type == ValueType.Array) {// function
22 | Value[] funcSignatures = args[0].getArray;
23 | string funcName = funcSignatures[0].getString;
24 | string[] funcArgs = funcSignatures[1..$].map!(value => value.getString).array;
25 | Value funcBody = args[1];
26 |
27 | return engine.defineVariable(funcName, new Value(cast(IOperator)(new DynamicOperator(funcArgs, funcBody))));
28 | } else {
29 | throw new Exception("Invalid");
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/source/orelang/operator/DefmacroOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DefmacroOperator;
2 | import orelang.operator.DynamicOperator,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 | import std.algorithm,
7 | std.array;
8 |
9 | class DefmacroOperator : IOperator {
10 | /**
11 | * call
12 | */
13 | public Value call(Engine engine, Value[] args) {
14 | string macro_name = args[0].getString;
15 | string[] macro_args = args[1].getArray.map!(value => value.getString).array;
16 | Value _body = args[2];
17 |
18 | import orelang.expression.Macro;
19 | auto mcr = new Macro(macro_name, macro_args, _body);
20 | Value vmcr = new Value(mcr);
21 |
22 | engine.defineVariable(macro_name, vmcr);
23 |
24 | return vmcr;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/source/orelang/operator/DefvarOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DefvarOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class DefvarOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | return engine.defineVariable(args[0].getString, engine.eval(args[1]));
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/source/orelang/operator/DigestOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DigestOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.digest.hmac,
6 | std.digest.sha,
7 | std.string;
8 |
9 | class HMACSHA1Operator : IOperator {
10 | public Value call(Engine engine, Value[] args) {
11 | string key = engine.eval(args[0]).getString,
12 | base = engine.eval(args[1]).getString;
13 | ubyte[20] dgst = base.representation.hmac!SHA1(key.representation);
14 | Value[] ret;
15 |
16 | foreach (e; dgst) {
17 | ret ~= new Value(e);
18 | }
19 |
20 | return new Value(ret);
21 | }
22 | }
--------------------------------------------------------------------------------
/source/orelang/operator/DivOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DivOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class DivOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = engine.eval(args[0]);
12 |
13 | foreach (arg; args[1..$]) {
14 | Value v = engine.eval(arg);
15 | ret.divTo(v);
16 | }
17 |
18 | return ret;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/operator/DllOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DllOperator;
2 | import orelang.operator.IOperator, orelang.Engine, orelang.Value;
3 | import orelang.Util;
4 | import core.sys.posix.dlfcn;
5 | import std.string, std.stdio, std.format, std.conv;
6 |
7 | version (WithFFI) {
8 | enum D_TYPE {
9 | VOID,
10 | UBYTE,
11 | BYTE,
12 | USHORT,
13 | SHORT,
14 | UINT,
15 | INT,
16 | ULONG,
17 | LONG,
18 | FLOAT,
19 | DOUBLE,
20 | POINTER,
21 | STRING,
22 | }
23 |
24 | D_TYPE string_to_dtype(string s) {
25 | final switch (s) with (D_TYPE) {
26 | case "void":
27 | return VOID;
28 | case "ubyte":
29 | return UBYTE;
30 | case "byte":
31 | return BYTE;
32 | case "ushort":
33 | return USHORT;
34 | case "short":
35 | return SHORT;
36 | case "uint":
37 | return UINT;
38 | case "int":
39 | return INT;
40 | case "ulong":
41 | return ULONG;
42 | case "long":
43 | return LONG;
44 | case "float":
45 | return FLOAT;
46 | case "double":
47 | return DOUBLE;
48 | case "pointer":
49 | return POINTER;
50 | case "string":
51 | return STRING;
52 | }
53 | }
54 |
55 | ffi_type* d_type_to_ffi_type(D_TYPE type) {
56 | return [&ffi_type_void, &ffi_type_uint8, &ffi_type_sint8,
57 | &ffi_type_uint16, &ffi_type_sint16, &ffi_type_uint32,
58 | &ffi_type_sint32, &ffi_type_uint64, &ffi_type_sint64, &ffi_type_float,
59 | &ffi_type_double, &ffi_type_pointer, &ffi_type_pointer][type];
60 | }
61 |
62 | ffi_type*[] d_types_to_ffi_types(D_TYPE[] types) {
63 | ffi_type*[] ret;
64 | foreach (type; types) {
65 | ret ~= d_type_to_ffi_type(type);
66 | }
67 | return ret;
68 | }
69 |
70 | struct Func {
71 | string name;
72 | void* ptr;
73 | D_TYPE[] arg_types;
74 | D_TYPE r_type;
75 | ffi_cif cif;
76 | }
77 |
78 | Func newFunc(void* lh, string name, D_TYPE[] arg_types, D_TYPE r_type) {
79 | import std.string;
80 |
81 | void* ptr = dlsym(lh, name.toStringz);
82 | char* error = dlerror();
83 |
84 | if (error) {
85 | throw new Error("dlsym error: %s\n".format(error));
86 | }
87 |
88 | ffi_cif cif;
89 | ffi_status status;
90 |
91 | auto _arg_types = d_types_to_ffi_types(arg_types);
92 | auto _r_type = d_type_to_ffi_type(r_type);
93 |
94 | if ((status = ffi_prep_cif(&cif, ffi_abi.FFI_DEFAULT_ABI,
95 | arg_types.length.to!uint, _r_type, cast(ffi_type**)_arg_types)) != ffi_status.FFI_OK) {
96 | throw new Error("ERROR : %d".format(status));
97 | }
98 |
99 | return Func(name, ptr, arg_types, r_type, cif);
100 | }
101 |
102 | bool checkCastable(T)(void* ptr) {
103 | return (cast(T*)ptr) !is null;
104 | }
105 |
106 | Value invokeFunc(Func func, void*[] args) {
107 | foreach (i, type; func.arg_types) {
108 | final switch (type) with (D_TYPE) {
109 | case VOID:
110 | break;
111 | case UBYTE:
112 | if (!checkCastable!(ubyte)(args[i])) {
113 | throw new Error("Invalid argument");
114 | }
115 | break;
116 | case BYTE:
117 | if (!checkCastable!(byte)(args[i])) {
118 | throw new Error("Invalid argument");
119 | }
120 | break;
121 | case USHORT:
122 | if (!checkCastable!(ushort)(args[i])) {
123 | throw new Error("Invalid argument");
124 | }
125 | break;
126 | case SHORT:
127 | if (!checkCastable!(short)(args[i])) {
128 | throw new Error("Invalid argument");
129 | }
130 | break;
131 | case UINT:
132 | if (!checkCastable!(uint)(args[i])) {
133 | throw new Error("Invalid argument");
134 | }
135 | break;
136 | case INT:
137 | if (!checkCastable!(int)(args[i])) {
138 | throw new Error("Invalid argument");
139 | }
140 | break;
141 | case ULONG:
142 | if (!checkCastable!(ulong)(args[i])) {
143 | throw new Error("Invalid argument");
144 | }
145 | break;
146 | case LONG:
147 | if (!checkCastable!(long)(args[i])) {
148 | throw new Error("Invalid argument");
149 | }
150 | break;
151 | case FLOAT:
152 | if (!checkCastable!(float)(args[i])) {
153 | throw new Error("Invalid argument");
154 | }
155 | break;
156 | case DOUBLE:
157 | if (!checkCastable!(double)(args[i])) {
158 | throw new Error("Invalid argument");
159 | }
160 | break;
161 | case POINTER:
162 | if (!checkCastable!(void)(args[i])) {
163 | throw new Error("Invalid argument");
164 | }
165 | break;
166 | case STRING:
167 | if (!checkCastable!(char)(args[i])) {
168 | throw new Error("Invalid argument");
169 | }
170 | break;
171 | }
172 | }
173 |
174 | ffi_arg result;
175 |
176 | ffi_call(&func.cif, func.ptr, &result, cast(void**)args);
177 |
178 | final switch (func.r_type) with (D_TYPE) {
179 | case VOID:
180 | return new Value;
181 | case UBYTE:
182 | auto v = cast(ubyte)result;
183 | return new Value(v);
184 | case BYTE:
185 | auto v = cast(byte)result;
186 | return new Value(v);
187 | case USHORT:
188 | auto v = cast(ushort)result;
189 | return new Value(v);
190 | case SHORT:
191 | auto v = cast(short)result;
192 | return new Value(v);
193 | case UINT:
194 | auto v = cast(uint)result;
195 | return new Value(v);
196 | case INT:
197 | auto v = cast(int)result;
198 | return new Value(v);
199 | case ULONG:
200 | auto v = cast(ulong)result;
201 | return new Value(v);
202 | case LONG:
203 | auto v = cast(long)result;
204 | return new Value(v);
205 | case FLOAT:
206 | auto v = cast(float)result;
207 | return new Value(v);
208 | case DOUBLE:
209 | auto v = cast(double)result;
210 | return new Value(v);
211 | case POINTER:
212 | void* ptr = cast(void*)result;
213 | return new Value(ptr);
214 | case STRING:
215 | auto v = cast(char*)result;
216 | return new Value(cast(string)v.fromStringz);
217 | }
218 | }
219 |
220 | class DllOperator : IOperator {
221 | /**
222 | * call
223 | */
224 | void*[] lhs;
225 |
226 | ~this() {
227 | foreach (lh; lhs) {
228 | dlclose(lh);
229 | }
230 | }
231 |
232 | void* open_dll(string dll_path) {
233 | void* lh = dlopen(dll_path.toStringz, RTLD_LAZY);
234 | if (!lh) {
235 | throw new Error("dlopen error: %s\n".format(dlerror()));
236 | }
237 | lhs ~= lh;
238 | return lh;
239 | }
240 |
241 | public Value call(Engine engine, Value[] args) {
242 | struct Func_Info {
243 | string name;
244 | D_TYPE r_type;
245 | D_TYPE[] arg_types;
246 | }
247 |
248 | string dll_path;
249 | Func_Info[] func_infos;
250 |
251 | foreach (arg; args) {
252 | if (arg.type == ValueType.Array) {
253 | Value[] array = arg.getArray;
254 | if (array[0].type != ValueType.SymbolValue) {
255 | throw new Error("<1>Invalid Syntax");
256 | }
257 | if (array[0].getSymbolValue.value == "dll-path") {
258 | if (array[1].type != ValueType.String) {
259 | throw new Error("<2>Invalid Syntax");
260 | }
261 | dll_path = array[1].getString;
262 | } else if (array[0].getSymbolValue.value == "dll-functions") {
263 | if (array[1].type != ValueType.Array) {
264 | throw new Error("<3>Invalid Syntax");
265 | }
266 | Value[] funcs = array[1 .. $];
267 |
268 | foreach (func; funcs) {
269 | if (func.type != ValueType.Array) {
270 | throw new Error("<4>Invalid Syntax");
271 | }
272 | Value[] info = func.getArray;
273 | if (info.length != 3) {
274 | throw new Error("<5>Invalid Syntax");
275 | }
276 | if (info[0].type != ValueType.String
277 | || info[1].type != ValueType.SymbolValue || info[2].type != ValueType.Array) {
278 | throw new Error("<6>Invalid Syntax");
279 | }
280 | string name = info[0].getString;
281 | D_TYPE r_type = info[1].getSymbolValue.value.string_to_dtype;
282 | D_TYPE[] arg_types;
283 |
284 | foreach (Value type; info[2].getArray) {
285 | if (type.type != ValueType.SymbolValue) {
286 | throw new Error("<7>Invalid Syntax");
287 | }
288 | arg_types ~= type.getSymbolValue.value.string_to_dtype;
289 | }
290 |
291 | func_infos ~= Func_Info(name, r_type, arg_types);
292 | }
293 | }
294 | } else {
295 | throw new Error("Invalid argument");
296 | }
297 | }
298 |
299 | if (dll_path.length == 0 || func_infos.length == 0) {
300 | throw new Error("Invalid Syntax");
301 | }
302 |
303 | void* lh = open_dll(dll_path);
304 |
305 | foreach (func_info; func_infos) {
306 | IOperator new_op = new class() IOperator {
307 | Func func;
308 |
309 | this() {
310 | func = newFunc(lh, func_info.name, func_info.arg_types, func_info.r_type);
311 | }
312 |
313 | ~this() {
314 | dlclose(lh);
315 | }
316 |
317 | public Value call(Engine engine, Value[] args) {
318 | void*[] f_args;
319 | foreach (i, arg_type; func.arg_types) {
320 | Value eargs = engine.eval(args[i]);
321 |
322 | final switch (arg_type) with (D_TYPE) {
323 | case VOID:
324 | break;
325 | case UBYTE:
326 | if (eargs.type != ValueType.Numeric) {
327 | throw new Error("Invalid Argument");
328 | }
329 | auto arg = eargs.getNumeric.to!(ubyte);
330 | auto ptr = &arg;
331 | f_args ~= ptr;
332 | break;
333 | case BYTE:
334 | if (eargs.type != ValueType.Numeric) {
335 | throw new Error("Invalid Argument");
336 | }
337 | auto arg = eargs.getNumeric.to!(byte);
338 | auto ptr = &arg;
339 | f_args ~= ptr;
340 | break;
341 | case USHORT:
342 | if (eargs.type != ValueType.Numeric) {
343 | throw new Error("Invalid Argument");
344 | }
345 | auto arg = eargs.getNumeric.to!(ushort);
346 | auto ptr = &arg;
347 | f_args ~= ptr;
348 | break;
349 | case SHORT:
350 | if (eargs.type != ValueType.Numeric) {
351 | throw new Error("Invalid Argument");
352 | }
353 | auto arg = eargs.getNumeric.to!(short);
354 | auto ptr = &arg;
355 | f_args ~= ptr;
356 | break;
357 | case UINT:
358 | if (eargs.type != ValueType.Numeric) {
359 | throw new Error("Invalid Argument");
360 | }
361 | auto arg = eargs.getNumeric.to!(uint);
362 | auto ptr = &arg;
363 | f_args ~= ptr;
364 | break;
365 | case INT:
366 | if (eargs.type != ValueType.Numeric) {
367 | throw new Error("Invalid Argument");
368 | }
369 | auto arg = eargs.getNumeric.to!(int);
370 | auto ptr = &arg;
371 | f_args ~= ptr;
372 | break;
373 | case ULONG:
374 | if (eargs.type != ValueType.Numeric) {
375 | throw new Error("Invalid Argument");
376 | }
377 | auto arg = eargs.getNumeric.to!(ulong);
378 | auto ptr = &arg;
379 | f_args ~= ptr;
380 | break;
381 | case LONG:
382 | if (eargs.type != ValueType.Numeric) {
383 | throw new Error("Invalid Argument");
384 | }
385 | auto arg = eargs.getNumeric.to!(long);
386 | auto ptr = &arg;
387 | f_args ~= ptr;
388 | break;
389 | case FLOAT:
390 | if (eargs.type != ValueType.Numeric) {
391 | throw new Error("Invalid Argument");
392 | }
393 | auto arg = eargs.getNumeric.to!(float);
394 | auto ptr = &arg;
395 | f_args ~= ptr;
396 | break;
397 | case DOUBLE:
398 | if (eargs.type != ValueType.Numeric) {
399 | throw new Error("Invalid Argument");
400 | }
401 | auto arg = eargs.getNumeric.to!(double);
402 | auto ptr = &arg;
403 | f_args ~= ptr;
404 | break;
405 | case POINTER:
406 | if (eargs.type != ValueType.RAWPointer) {
407 | throw new Error("Invalid Argument");
408 | }
409 | auto arg = eargs.getRAWPointer;
410 | void* ptr = &arg;
411 | f_args ~= ptr;
412 | break;
413 | case STRING:
414 | if (eargs.type != ValueType.String) {
415 | throw new Error("Invalid Argument");
416 | }
417 | auto arg = eargs.getString.toStringz;
418 | auto ptr = &arg;
419 | f_args ~= ptr;
420 | break;
421 | }
422 | }
423 |
424 | return invokeFunc(func, f_args);
425 | }
426 | };
427 |
428 | engine.defineVariable(func_info.name, new Value(new_op));
429 | }
430 |
431 | return new Value(true);
432 | }
433 | }
434 | }
435 |
--------------------------------------------------------------------------------
/source/orelang/operator/DynamicOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.DynamicOperator;
2 | import orelang.operator.IOperator, orelang.Engine, orelang.Value;
3 | import kontainer.orderedAssocArray;
4 |
5 | /**
6 | * Dynamic Operator
7 | */
8 |
9 | class DynamicOperator : IOperator {
10 | private {
11 | string[] funcArgs;
12 | Value funcBody;
13 | OrderedAssocArray!(string, Value) optionArgs;
14 | }
15 |
16 | this(string[] funcArgs, Value funcBody) {
17 | this.funcArgs = funcArgs;
18 | this.funcBody = funcBody;
19 | this.optionArgs = new OrderedAssocArray!(string, Value);
20 | }
21 |
22 | this(string[] funcArgs, Value funcBody, OrderedAssocArray!(string, Value) optionArgs) {
23 | this.funcArgs = funcArgs;
24 | this.funcBody = funcBody;
25 | this.optionArgs = optionArgs;
26 | }
27 |
28 | public Value call(Engine engine, Value[] args) {
29 | size_t i = 0;
30 | Engine _engine = engine.clone;
31 |
32 | size_t allFuncArgs = this.optionArgs.length + this.funcArgs.length;
33 |
34 | if (this.funcArgs.length < args.length && args.length <= allFuncArgs) {
35 | size_t j;
36 | size_t orders = args.length - this.funcArgs.length;
37 | foreach (arg; this.optionArgs) {
38 | if (j < orders) {
39 | _engine.defineVariable(arg.key, engine.eval(args[i++]));
40 | } else {
41 | _engine.defineVariable(arg.key, engine.eval(arg.value));
42 | }
43 | j++;
44 | }
45 | } else {
46 | foreach (arg; this.optionArgs) {
47 | _engine.defineVariable(arg.key, engine.eval(arg.value));
48 | }
49 | }
50 |
51 | foreach (arg; this.funcArgs) {
52 | // variadic args
53 | if (arg[0] == '&') {
54 | Value[] arr;
55 |
56 | arr = args[i .. $];
57 |
58 | _engine.defineVariable(arg[1 .. $], new Value(arr));
59 | break;
60 | } else {
61 | _engine.defineVariable(arg, engine.eval(args[i++]));
62 | }
63 | }
64 |
65 | return _engine.eval(this.funcBody);
66 | }
67 |
68 | override string toString() {
69 | string base = "orelang.operator.DynamicOperator.DynamicOperator {";
70 | import std.string;
71 |
72 | string _body = "[funcArgs : [" ~ funcArgs.join(
73 | ", ") ~ "], " ~ "funcBody : " ~ funcBody.toString ~ "]";
74 |
75 | return base ~ _body ~ "}";
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/source/orelang/operator/EqualOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.EqualOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class EqualOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | return new Value(engine.eval(args[0]) == engine.eval(args[1]));
12 | }
13 | }
14 |
15 | class NotEqualOperator : IOperator {
16 | /**
17 | * call
18 | */
19 | public Value call(Engine engine, Value[] args) {
20 | return new Value(engine.eval(args[0]) != engine.eval(args[1]));
21 | }
22 | }
23 |
24 | class LessOperator : IOperator {
25 | /**
26 | * call
27 | */
28 | public Value call(Engine engine, Value[] args) {
29 | return new Value(engine.eval(args[0]) < engine.eval(args[1]));
30 | }
31 | }
32 |
33 | class GreatOperator : IOperator {
34 | /**
35 | * call
36 | */
37 | public Value call(Engine engine, Value[] args) {
38 | return new Value(engine.eval(args[0]) > engine.eval(args[1]));
39 | }
40 | }
41 |
42 | class LEqOperator : IOperator {
43 | /**
44 | * call
45 | */
46 | public Value call(Engine engine, Value[] args) {
47 | return new Value(engine.eval(args[0]) <= engine.eval(args[1]));
48 | }
49 | }
50 |
51 | class GEqOperator : IOperator {
52 | /**
53 | * call
54 | */
55 | public Value call(Engine engine, Value[] args) {
56 | return new Value(engine.eval(args[0]) >= engine.eval(args[1]));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/source/orelang/operator/EvalOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.EvalOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Transpiler,
4 | orelang.Engine,
5 | orelang.Value;
6 |
7 | class EvalOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | string code = args[0].getString;
13 |
14 | return engine.eval(Transpiler.transpile(code));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/source/orelang/operator/FileClass.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.FileClass;
2 | import orelang.expression.ClassType,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 |
7 | import std.stdio,
8 | std.conv;
9 |
10 | class FileClass : ClassType {
11 | File fp;
12 |
13 | this (Engine _engine) {
14 | _engine = _engine.clone;
15 | super(_engine);
16 |
17 | _engine.defineVariable("constructor", new Value(cast(IOperator)(
18 | new class () IOperator {
19 | public Value call(Engine engine, Value[] args) {
20 | string fileName = engine.eval(args[0]).getString,
21 | openType = engine.eval(args[1]).getString;
22 | fp.open(fileName, openType);
23 | return new Value;
24 | }
25 | })));
26 |
27 | _engine.defineVariable("raw-read", new Value(cast(IOperator)(
28 | new class () IOperator {
29 | public Value call(Engine engine, Value[] args) {
30 | Value[] ret;
31 | ubyte[] buf;
32 | buf.length = fp.size;
33 | fp.rawRead(buf);
34 |
35 | foreach (e; buf) {
36 | ret ~= new Value(e);
37 | }
38 |
39 | return new Value(ret);
40 | }})));
41 |
42 | _engine.defineVariable("raw-write", new Value(cast(IOperator)(
43 | new class () IOperator {
44 | public Value call(Engine engine, Value[] args) {
45 | Value[] data = engine.eval(args[0]).getArray;
46 | ubyte[] buf;
47 |
48 | foreach (e; data) {
49 | switch (e.type) with (ValueType) {
50 | case Numeric:
51 | buf ~= e.getNumeric.to!ubyte;
52 | break;
53 | case Ubyte:
54 | buf ~= e.getUbyte;
55 | break;
56 | case String:
57 | buf ~= e.getString.to!(ubyte[]);
58 | break;
59 | default:
60 | throw new Exception("[raw-write] can't write non numeric/ubyte/string value");
61 | }
62 | }
63 |
64 | fp.rawWrite(buf);
65 | return new Value(data);
66 | }})));
67 |
68 | _engine.defineVariable("write", new Value(cast(IOperator)(
69 | new class () IOperator {
70 | public Value call(Engine engine, Value[] args) {
71 | Value data = engine.eval(args[0]);
72 |
73 | switch (data.type) with (ValueType) {
74 | case Numeric:
75 | fp.write(data.getNumeric);
76 | break;
77 | case Ubyte:
78 | fp.write(data.getUbyte);
79 | break;
80 | case String:
81 | fp.write(data.getString);
82 | break;
83 | default:
84 | throw new Exception("[raw-write] can't write non numeric/ubyte/string value");
85 | }
86 |
87 | return data;
88 | }})));
89 |
90 | _engine.defineVariable("writeln", new Value(cast(IOperator)(
91 | new class () IOperator {
92 | public Value call(Engine engine, Value[] args) {
93 | Value data = engine.eval(args[0]);
94 |
95 | switch (data.type) with (ValueType) {
96 | case Numeric:
97 | fp.writeln(data.getNumeric);
98 | break;
99 | case Ubyte:
100 | fp.writeln(data.getUbyte);
101 | break;
102 | case String:
103 | fp.writeln(data.getString);
104 | break;
105 | default:
106 | throw new Exception("[raw-writeln] can't write non numeric/ubyte/string value");
107 | }
108 |
109 | return new Value;
110 | }})));
111 |
112 | _engine.defineVariable("readln", new Value(cast(IOperator)(
113 | new class () IOperator {
114 | public Value call(Engine engine, Value[] args) {
115 | return new Value(fp.readln);
116 | }})));
117 |
118 | _engine.defineVariable("readall", new Value(cast(IOperator)(
119 | new class () IOperator {
120 | public Value call(Engine engine, Value[] args) {
121 | import std.string;
122 | static string[] buf;
123 | foreach (line; fp.byLine) {
124 | buf ~= line.to!string;
125 | }
126 | return new Value(buf.join("\n"));
127 | }})));
128 | }
129 | }
--------------------------------------------------------------------------------
/source/orelang/operator/FileOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.FileOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.conv,
6 | std.file;
7 |
8 | class RemoveFileOperator {
9 | public Value call(Engine engine, Value[] args) {
10 | string path = args[0].type == ValueType.SymbolValue ? engine.eval(args[0]).getString : args[0].getString;
11 |
12 | if (exists(path)) {
13 | if (isFile(path)) {
14 | remove(path);
15 | } else {
16 | throw new Exception("[remove-file]" ~ path ~ " is not a file, it is a directory, use remove-dir function instead.");
17 | }
18 | } else {
19 | throw new Exception("[remove-file] No such a file or directory: " ~ path);
20 | }
21 |
22 | return new Value;
23 | }
24 | }
25 |
26 | class RemoveDirOperator {
27 | public Value call(Engine engine, Value[] args) {
28 | string path = args[0].type == ValueType.SymbolValue ? engine.eval(args[0]).getString : args[0].getString;
29 |
30 | if (exists(path)) {
31 | if (isDir(path)) {
32 | rmdir(path);
33 | } else {
34 | throw new Exception("[remove-dir]" ~ path ~ " is not a directory, it is a file, use remove-file function instead.");
35 | }
36 | } else {
37 | throw new Exception("[remove-dir] No such a file or directory: " ~ path);
38 | }
39 |
40 | return new Value;
41 | }
42 | }
43 |
44 | class GetcwdOperator : IOperator {
45 | public Value call(Engine engine, Value[] args) {
46 | return new Value(getcwd);
47 | }
48 | }
49 |
50 | class GetsizeOperator : IOperator {
51 | public Value call(Engine engine, Value[] args) {
52 | float ret;
53 | string path = args[0].type == ValueType.SymbolValue ? engine.eval(args[0]).getString : args[0].getString;
54 |
55 | if (exists(path)) {
56 | if (isFile(path)) {
57 | ret = getSize(path).to!float;
58 | } else {
59 | throw new Exception("[get-size]" ~ path ~ " is not a file, it is a directory");
60 | }
61 | } else {
62 | throw new Exception("[get-size] No such a file or directory: " ~ path);
63 | }
64 |
65 |
66 | return new Value(ret);
67 | }
68 | }
--------------------------------------------------------------------------------
/source/orelang/operator/FilterOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.FilterOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.expression.IExpression,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 | import std.algorithm,
9 | std.array;
10 |
11 | class FilterOperator : IOperator {
12 | /**
13 | * call
14 | */
15 | public Value call(Engine engine, Value[] args) {
16 | engine.sync_storage = true;
17 | scope(exit) engine.sync_storage = false;
18 |
19 | Value efunc = engine.eval(args[0]);
20 | Value eargs1 = engine.eval(args[1]);
21 |
22 | if (eargs1.type == ValueType.Array) {
23 | Value[] array = eargs1.getArray;
24 |
25 | if (efunc.type == ValueType.Closure) {
26 | Value[] ret;
27 |
28 | foreach (elem; array) {
29 | //ret ~= efunc.getClosure.eval([elem]);
30 | if (efunc.getClosure.eval([elem]).getBool) {
31 | ret ~= elem;
32 | }
33 | }
34 |
35 | return new Value(ret);
36 | } else {
37 | Value[] ret;
38 |
39 | foreach (elem; array) {
40 | //ret ~= efunc.getIOperator.call(engine, [elem]);
41 | if (efunc.getIOperator.call(engine, [elem]).getBool) {
42 | ret ~= elem;
43 | }
44 | }
45 |
46 | return new Value(ret);
47 | }
48 | } else {
49 | if (!(eargs1.type == ValueType.ImmediateValue) && !(eargs1.getImmediateValue.value.type == ValueType.Array)) {
50 | throw new Exception("map requires array and function as a Operator");
51 | }
52 |
53 | Value[] array = eargs1.getImmediateValue.value.getArray;
54 |
55 | if (efunc.type == ValueType.Closure) {
56 | Value[] ret;
57 |
58 | foreach (elem; array) {
59 | //ret ~= efunc.getClosure.eval([elem]);
60 | if (efunc.getClosure.eval([elem]).getBool) {
61 | ret ~= elem;
62 | }
63 | }
64 |
65 | return new Value(ret);
66 | } else {
67 | Value[] ret;
68 |
69 | foreach (elem; array) {
70 | //ret ~= efunc.getIOperator.call(engine, [elem]);
71 | if (efunc.getIOperator.call(engine, [elem]).getBool) {
72 | ret ~= elem;
73 | }
74 | }
75 |
76 | return new Value(ret);
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/source/orelang/operator/FoldOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.FoldOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.expression.IExpression,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 | import std.algorithm,
9 | std.array;
10 |
11 | class FoldOperator : IOperator {
12 | public Value call(Engine engine, Value[] args) {
13 | Value func = args[0];
14 | Value tmp = args[1];
15 | Value eargs = engine.eval(args[2]);
16 |
17 | //if (eargs.convertsTo!(Value[])) {
18 | if (eargs.type == ValueType.Array) {
19 | Value[] array = eargs.getArray;
20 | Value efunc = engine.eval(func);
21 |
22 | if (efunc.type == ValueType.Closure) {
23 | foreach (elem; array) {
24 | tmp = efunc.getClosure.eval([tmp, elem]);
25 | }
26 | } else if (efunc.type == ValueType.IOperator) {
27 | foreach (elem; array) {
28 | tmp = efunc.getIOperator.call(engine, [tmp, elem]);
29 | }
30 | }
31 |
32 | return tmp;
33 | } else {
34 | if (!(eargs.type == ValueType.ImmediateValue) && !(eargs.getImmediateValue.value.type == ValueType.Array)) {
35 | throw new Exception("Fold requires array and function as a Operator");
36 | }
37 |
38 | Value[] array = eargs.getImmediateValue.value.getArray;
39 | Value efunc = engine.eval(func);
40 |
41 | if (efunc.type == ValueType.Closure) {
42 | foreach (elem; array) {
43 | tmp = efunc.getClosure.eval([tmp, elem]);
44 | }
45 | } else {
46 | foreach (elem; array) {
47 | tmp = efunc.getIOperator.call(engine, [tmp, elem]);
48 | }
49 | }
50 |
51 | return tmp;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/source/orelang/operator/ForeachOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.ForeachOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.expression.IExpression,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 | import std.algorithm,
9 | std.array;
10 |
11 | class ForeachOperator : IOperator {
12 | /**
13 | * call
14 | */
15 | public Value call(Engine engine, Value[] args) {
16 | engine.sync_storage = true;
17 | scope(exit) engine.sync_storage = false;
18 |
19 | Value efunc = engine.eval(args[0]);
20 | Value eargs1 = engine.eval(args[1]);
21 |
22 | if (eargs1.type == ValueType.Array) {
23 | Value[] array = eargs1.getArray;
24 |
25 | if (efunc.type == ValueType.Closure) {
26 | Value[] ret;
27 |
28 | foreach (elem; array) {
29 | ret ~= efunc.getClosure.eval([elem]);
30 | }
31 |
32 | return new Value(ret);
33 | } else {
34 | Value[] ret;
35 |
36 | foreach (elem; array) {
37 | ret ~= efunc.getIOperator.call(engine, [elem]);
38 | }
39 |
40 | return new Value(ret);
41 | }
42 | } else {
43 | if (!(eargs1.type == ValueType.ImmediateValue) && !(eargs1.getImmediateValue.value.type == ValueType.Array)) {
44 | throw new Exception("for-each requires array and function as a Operator");
45 | }
46 |
47 | Value[] array = eargs1.getImmediateValue.value.getArray;
48 |
49 | if (efunc.type == ValueType.Closure) {
50 | Value[] ret;
51 |
52 | foreach (elem; array) {
53 | ret ~= efunc.getClosure.eval([elem]);
54 | }
55 |
56 | return new Value(ret);
57 | } else {
58 | Value[] ret;
59 |
60 | foreach (elem; array) {
61 | ret ~= efunc.getIOperator.call(engine, [elem]);
62 | }
63 |
64 | return new Value(ret);
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/source/orelang/operator/GetOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.GetOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class GetOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | return engine.getVariable(args[0].getString);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/source/orelang/operator/GetfunOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.GetfunOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class GetfunOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | return engine.variables[args[0].getString];
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/source/orelang/operator/HashMapOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.HashMapOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class MakeHashOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | /*
11 | (make-hash name)
12 | */
13 | public Value call(Engine engine, Value[] args) {
14 | string name = args[0].getString;
15 | Value[string] hash = null;
16 | Value ret = new Value(hash);
17 |
18 | engine.defineVariable(name, ret);
19 |
20 | return ret;
21 | }
22 | }
23 |
24 | class NewHashOperator : IOperator {
25 | /**
26 | * call
27 | */
28 | /*
29 | (new-hash)
30 | */
31 | public Value call(Engine engine, Value[] args) {
32 | Value[string] hash = null;
33 | Value ret = new Value(hash);
34 |
35 | return ret;
36 | }
37 | }
38 |
39 | class HashSetValueOperator : IOperator {
40 | /**
41 | * call
42 | */
43 | /*
44 | (hash-set-value hash key value)
45 | */
46 | public Value call(Engine engine, Value[] args) {
47 | Value ret;
48 |
49 | if (args[0].type == ValueType.SymbolValue) {
50 | Value obj = engine.getVariable(args[0].getString);
51 |
52 | if (obj.type == ValueType.HashMap) {
53 | Value[string] hash = obj.getHashMap;
54 |
55 | hash[engine.eval(args[1]).getString] = engine.eval(args[2]);
56 | ret = new Value(hash);
57 |
58 | engine.setVariable(args[0].getString, ret);
59 | } else {
60 | throw new Exception("No such a HashMap - " ~ args[0].getString);
61 | }
62 | } else if (args[0].type == ValueType.HashMap) {
63 | Value[string] hash = args[0].getHashMap;
64 |
65 | hash[engine.eval(args[1]).getString] = engine.eval(args[2]);
66 | ret = new Value(hash);
67 |
68 | engine.setVariable(args[0].getString, ret);
69 | } else {
70 | throw new Exception("set-value accepts (HashName Key Value) or (HashValue Key Value) only");
71 | }
72 |
73 | return ret;
74 | }
75 | }
76 |
77 | class HashGetValueOperator : IOperator {
78 | /**
79 | * call
80 | */
81 | /*
82 | (hash-get-value hash key)
83 | */
84 | public Value call(Engine engine, Value[] args) {
85 | if (args[0].type == ValueType.SymbolValue) {
86 | Value obj = engine.getVariable(args[0].getString);
87 |
88 | if (obj.type == ValueType.HashMap) {
89 | Value[string] hash = obj.getHashMap;
90 | return hash[engine.eval(args[1]).getString];
91 | } else {
92 | throw new Exception("No such a HashMap - " ~ args[0].getString);
93 | }
94 | } else if (engine.eval(args[0]).type == ValueType.HashMap) {
95 | Value[string] hash = engine.eval(args[0]).getHashMap;
96 |
97 | return hash[engine.eval(args[1]).getString];
98 | } else {
99 | throw new Exception("hash-get-value accepts (HashName Key Value) or (HashValue Key Value) only");
100 | }
101 | }
102 | }
103 |
104 | class HashGetKeysOperator : IOperator {
105 | /**
106 | * call
107 | */
108 | /*
109 | (hash-get-keys hash)
110 | */
111 | public Value call(Engine engine, Value[] args) {
112 | if (args[0].type == ValueType.SymbolValue) {
113 | Value obj = engine.getVariable(args[0].getString);
114 |
115 | if (obj.type == ValueType.HashMap) {
116 | Value[string] hash = obj.getHashMap;
117 | Value[] keys;
118 |
119 | foreach (key; hash.keys) {
120 | keys ~= new Value(key);
121 | }
122 |
123 | return new Value(keys);
124 | } else {
125 | throw new Exception("No such a HashMap - " ~ args[0].getString);
126 | }
127 | } else if (engine.eval(args[0]).type == ValueType.HashMap) {
128 | Value[string] hash = engine.eval(args[0]).getHashMap;
129 | Value[] keys;
130 |
131 | foreach (key; hash.keys) {
132 | keys ~= new Value(key);
133 | }
134 |
135 | return new Value(keys);
136 | } else {
137 | throw new Exception("hash-get-keys accepts (HashName Key Value) or (HashValue Key Value) only");
138 | }
139 | }
140 | }
141 |
142 | class HashGetValuesOperator : IOperator {
143 | /**
144 | * call
145 | */
146 | /*
147 | (hash-get-values hash)
148 | */
149 | public Value call(Engine engine, Value[] args) {
150 | if (args[0].type == ValueType.SymbolValue) {
151 | Value obj = engine.getVariable(args[0].getString);
152 |
153 | if (obj.type == ValueType.HashMap) {
154 | Value[string] hash = obj.getHashMap;
155 | Value[] values;
156 |
157 | foreach (value; hash.values) {
158 | values ~= value;
159 | }
160 |
161 | return new Value(values);
162 | } else {
163 | throw new Exception("No such a HashMap - " ~ args[0].getString);
164 | }
165 | } else if (engine.eval(args[0]).type == ValueType.HashMap) {
166 | Value[string] hash = engine.eval(args[0]).getHashMap;
167 | Value[] values;
168 |
169 | foreach (value; hash.values) {
170 | values ~= value;
171 | }
172 |
173 | return new Value(values);
174 | } else {
175 | throw new Exception("hash-get-values accepts (HashName Key Value) or (HashValue Key Value) only");
176 | }
177 | }
178 | }
--------------------------------------------------------------------------------
/source/orelang/operator/IOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.IOperator;
2 | import orelang.Engine,
3 | orelang.Value;
4 |
5 | interface IOperator {
6 | Value call(Engine engine, Value[] args);
7 | }
8 |
--------------------------------------------------------------------------------
/source/orelang/operator/IfOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.IfOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class IfOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret;
12 |
13 | if (engine.eval(args[0]).getBool) {
14 | ret = engine.eval(args[1]);
15 | } else {
16 | if (args.length != 3) {
17 | ret = new Value;
18 | } else {
19 | ret = engine.eval(args[2]);
20 | }
21 | }
22 |
23 | return ret;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/source/orelang/operator/IsHashMapOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.IsHashMapOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class IsHashMapOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | if (engine.eval(args[0]).type == ValueType.HashMap) {
12 | return new Value(true);
13 | } else {
14 | return new Value(false);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/source/orelang/operator/IsListOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.IsListOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class IsListOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | if (engine.eval(args[0]).type == ValueType.Array) {
12 | return new Value(true);
13 | } else {
14 | return new Value(false);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/source/orelang/operator/IsNullOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.IsNullOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class IsNullOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | if (engine.eval(args[0]).type == ValueType.Null) {
12 | return new Value(true);
13 | } else {
14 | return new Value(false);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/source/orelang/operator/LambdaOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.LambdaOperator;
2 | import orelang.operator.DynamicOperator,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 | import std.algorithm,
7 | std.array;
8 |
9 | class LambdaOperator : IOperator {
10 | /**
11 | * call
12 | */
13 | public Value call(Engine engine, Value[] args) {
14 | string[] funcArgs = args[0].getArray.map!(value => value.getString).array;
15 | Value funcBody = args[1];
16 |
17 | return new Value(new DynamicOperator(funcArgs, funcBody));
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/source/orelang/operator/LengthOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.LengthOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.conv;
6 |
7 | class LengthOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | Value obj = engine.eval(args[0]);
13 |
14 | if (obj.type == ValueType.Array) {
15 | return new Value(obj.getArray.length.to!double);
16 | } else {
17 | throw new Exception("Given object is not an Array or List");
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/operator/LetOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.LetOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.operator.DynamicOperator,
4 | orelang.expression.IExpression,
5 | orelang.operator.IOperator,
6 | orelang.Closure,
7 | orelang.Engine,
8 | orelang.Value;
9 | import std.algorithm,
10 | std.array;
11 |
12 | class LetOperator : IOperator {
13 | /**
14 | * call
15 | */
16 | public Value call(Engine engine, Value[] args) {
17 | if (!(args[0].type == ValueType.Array)) {
18 | string name = args[0].getString;
19 | Value[] binds = args[1].getArray;
20 | Value _body = args[2];
21 | Engine _engine = engine.clone();
22 |
23 | string[] names;
24 | Value[] vars;
25 |
26 | foreach (bind; binds) {
27 | string bname = bind.getArray[0].getString;
28 | Value val = bind.getArray[1];
29 |
30 | names ~= bname;
31 | vars ~= val;
32 | }
33 |
34 | _engine.defineVariable(name, new Value(new DynamicOperator(names, _body)));
35 | Value ret = (_engine.getVariable(name).getIOperator).call(_engine, vars);
36 |
37 | if (ret.type == ValueType.Null) {
38 | return new Value(0.0);
39 | } else {
40 | return ret;
41 | }
42 | } else {
43 | Value[] binds = args[0].getArray;
44 | Value _body = args[1];
45 | Engine _engine = engine.clone();
46 |
47 | foreach (bind; binds) {
48 | string name = bind.getArray[0].getString;
49 | Value val = engine.eval(bind.getArray[1]);
50 |
51 | _engine.defineVariable(name, val);
52 | }
53 |
54 | return _engine.eval(_body);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/source/orelang/operator/LoadOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.LoadOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Interpreter,
4 | orelang.Transpiler,
5 | orelang.Engine,
6 | orelang.Value;
7 | import std.algorithm,
8 | std.array,
9 | std.file;
10 |
11 | class LoadOperator : IOperator {
12 | /**
13 | * call
14 | */
15 | public Value call(Engine engine, Value[] args) {
16 | string[] loaded;
17 | Value eargs0 = engine.eval(args[0]);
18 | Interpreter itpr = new Interpreter(engine);
19 |
20 | if (eargs0.type == ValueType.Array) {
21 | args = eargs0.getArray;
22 | }
23 |
24 | string[] fpaths = args.map!(arg => (engine.eval(arg)).getString ~ ".ore").array;
25 |
26 | foreach (fpath; fpaths) {
27 | if (!exists(fpath)) {
28 | throw new Exception("No such file - " ~ fpath);
29 | } else {
30 | itpr.executer(readText(fpath));
31 | loaded ~= fpath;
32 | }
33 | }
34 |
35 | Value[] ret;
36 |
37 | foreach (load; loaded) {
38 | ret ~= new Value(load);
39 | }
40 |
41 | return new Value(ret);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/source/orelang/operator/LogicOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.LogicOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.algorithm;
6 |
7 | class NotOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | return new Value(!engine.eval(args[0]).getBool);
13 | }
14 | }
15 |
16 | class AndOperator : IOperator {
17 | /**
18 | * call
19 | */
20 | public Value call(Engine engine, Value[] args) {
21 | return new Value(args.all!(arg => engine.eval(arg).getBool));
22 | }
23 | }
24 |
25 | class OrOperator : IOperator {
26 | /**
27 | * call
28 | */
29 | public Value call(Engine engine, Value[] args) {
30 | return new Value(args.any!(arg => engine.eval(arg).getBool));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/source/orelang/operator/MapOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.MapOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.expression.IExpression,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 | import std.algorithm,
9 | std.array;
10 |
11 | class MapOperator : IOperator {
12 | /**
13 | * call
14 | */
15 | public Value call(Engine engine, Value[] args) {
16 |
17 | Value efunc = engine.eval(args[0]);
18 | Value eargs1 = engine.eval(args[1]);
19 |
20 | if (eargs1.type == ValueType.Array) {
21 | Value[] array = eargs1.getArray;
22 |
23 | if (efunc.type == ValueType.Closure) {
24 | Value[] ret;
25 |
26 | foreach (elem; array) {
27 | ret ~= efunc.getClosure.eval([elem]);
28 | }
29 |
30 | return new Value(ret);
31 | } else {
32 | Value[] ret;
33 |
34 | foreach (elem; array) {
35 | ret ~= efunc.getIOperator.call(engine, [elem]);
36 | }
37 |
38 | return new Value(ret);
39 | }
40 | } else {
41 | if (!(eargs1.type == ValueType.ImmediateValue) && !(eargs1.getImmediateValue.value.type == ValueType.Array)) {
42 | throw new Exception("map requires array and function as a Operator");
43 | }
44 |
45 | Value[] array = eargs1.getImmediateValue.value.getArray;
46 |
47 | if (efunc.type == ValueType.Closure) {
48 | Value[] ret;
49 |
50 | foreach (elem; array) {
51 | ret ~= efunc.getClosure.eval([elem]);
52 | }
53 |
54 | return new Value(ret);
55 | } else {
56 | Value[] ret;
57 |
58 | foreach (elem; array) {
59 | ret ~= efunc.getIOperator.call(engine, [elem]);
60 | }
61 |
62 | return new Value(ret);
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/source/orelang/operator/ModOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.ModOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class ModOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = engine.eval(args[0]);
12 |
13 | foreach (arg; args[1..$]) {
14 | Value v = engine.eval(arg);
15 | ret.modTo(v);
16 | }
17 |
18 | return ret;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/operator/MulOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.MulOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class MulOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = new Value(1.0);
12 |
13 | foreach (arg; args) {
14 | Value v = engine.eval(arg);
15 | ret.mulTo(v);
16 | }
17 |
18 | return ret;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/operator/NopOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.NopOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class NopOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | return new Value;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/source/orelang/operator/PathOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.PathOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | /**
7 | * path-exists
8 | * path-is-dir
9 | * path-is-file
10 | */
11 | import std.file;
12 |
13 | class PathExistsOperator : IOperator {
14 | /**
15 | * call
16 | */
17 | public Value call(Engine engine, Value[] args) {
18 | return new Value(engine.eval(args[0]).getString.exists);
19 | }
20 | }
21 |
22 | class PathIsDirOperator : IOperator {
23 | /**
24 | * call
25 | */
26 | public Value call(Engine engine, Value[] args) {
27 | return new Value(engine.eval(args[0]).getString.isDir);
28 | }
29 | }
30 |
31 | class PathIsFileOperator : IOperator {
32 | /**
33 | * call
34 | */
35 | public Value call(Engine engine, Value[] args) {
36 | return new Value(engine.eval(args[0]).getString.isFile);
37 | }
38 | }
--------------------------------------------------------------------------------
/source/orelang/operator/PrintOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.PrintOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.algorithm,
6 | std.range,
7 | std.stdio,
8 | std.conv;
9 |
10 | class PrintOperator : IOperator {
11 | /**
12 | * call
13 | */
14 | public Value call(Engine engine, Value[] args) {
15 | foreach (arg; args) {
16 | Value item = engine.eval(arg);
17 |
18 | if (arg.type == ValueType.String || (arg.type == ValueType.SymbolValue && (item.type == ValueType.IExpression || item.type == ValueType.ImmediateValue || item.type == ValueType.IOperator))) {
19 | item = arg;
20 | }
21 |
22 | if (item.type == ValueType.Array) {
23 | write("(");
24 | write(item.getArray.map!(e => e.toString).join(" "));
25 | write(")");
26 | } else {
27 | write(item.toString());
28 | }
29 | }
30 |
31 | return new Value(0.0);
32 | }
33 | }
34 |
35 | class PrintlnOperator : IOperator {
36 | /**
37 | * call
38 | */
39 | public Value call(Engine engine, Value[] args) {
40 | foreach (arg; args) {
41 | Value item = engine.eval(arg);
42 |
43 | if (arg.type == ValueType.String || (arg.type == ValueType.SymbolValue && (item.type == ValueType.IExpression || item.type == ValueType.ImmediateValue || item.type == ValueType.IOperator))) {
44 | item = arg;
45 | }
46 |
47 | if (item.type == ValueType.Array) {
48 | write("(");
49 | write(item.getArray.map!(e => e.toString).join(" "));
50 | write(")");
51 | } else {
52 | write(item.toString());
53 | }
54 | }
55 |
56 | writeln;
57 |
58 | return new Value(0.0);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/source/orelang/operator/RandomOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.RandomOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.random,
6 | std.conv;
7 |
8 | class RandomUniformOperator : IOperator {
9 | /**
10 | * call
11 | */
12 | public Value call(Engine engine, Value[] args) {
13 | long fst = engine.eval(args[0]).getNumeric.to!long,
14 | snd = engine.eval(args[1]).getNumeric.to!long;
15 |
16 | long ret = uniform(fst, snd);
17 |
18 | return new Value(ret);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/orelang/operator/RegexClass.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.RegexClass;
2 | import orelang.expression.ClassType,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 |
7 | import std.stdio,
8 | std.conv;
9 | import std.regex;
10 | class RegexClass : ClassType {
11 | Regex!char rgx;
12 |
13 | this (Engine _engine) {
14 | _engine = _engine.clone;
15 | super(_engine);
16 |
17 | _engine.defineVariable("constructor", new Value(cast(IOperator)(
18 | new class () IOperator {
19 | public Value call(Engine engine, Value[] args) {
20 | string pattern = engine.eval(args[0]).getString;
21 |
22 | rgx = regex(pattern);
23 |
24 | return new Value;
25 | }
26 | })));
27 |
28 | _engine.defineVariable("reset", new Value(cast(IOperator)(
29 | new class () IOperator {
30 | public Value call(Engine engine, Value[] args) {
31 | string pattern = engine.eval(args[0]).getString;
32 |
33 | rgx = regex(pattern);
34 |
35 | return new Value;
36 | }})));
37 |
38 | _engine.defineVariable("match", new Value(cast(IOperator)(
39 | new class () IOperator {
40 | public Value call(Engine engine, Value[] args) {
41 | return new Value(cast(bool)(engine.eval(args[0]).getString.match(rgx)));
42 | }})));
43 |
44 | _engine.defineVariable("match-all", new Value(cast(IOperator)(
45 | new class () IOperator {
46 | public Value call(Engine engine, Value[] args) {
47 | writeln(engine.eval(args[0]).getString.matchAll(rgx));
48 | return new Value;
49 | }})));
50 |
51 | _engine.defineVariable("show-ptn", new Value(cast(IOperator)(
52 | new class () IOperator {
53 | public Value call(Engine engine, Value[] args) {
54 | import std.stdio;
55 | writeln(rgx);
56 | return new Value;
57 | }})));
58 | }
59 | }
--------------------------------------------------------------------------------
/source/orelang/operator/RemoveOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.RemoveOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.expression.IExpression,
4 | orelang.operator.IOperator,
5 | orelang.Closure,
6 | orelang.Engine,
7 | orelang.Value;
8 | import std.algorithm,
9 | std.array;
10 |
11 | class RemoveOperator : IOperator {
12 | /**
13 | * call
14 | */
15 | public Value call(Engine engine, Value[] args) {
16 | Value efunc = engine.eval(args[0]);
17 | Value[] eargs1 = engine.eval(args[1]).getArray;
18 | Value[] ret;
19 |
20 | foreach (elem; eargs1) {
21 | bool cnd;
22 |
23 | if (efunc.type == ValueType.Closure) {
24 | cnd = efunc.getClosure.eval([elem]).getBool;
25 | } else {
26 | cnd = efunc.getIOperator.call(engine, [elem]).getBool;
27 | }
28 |
29 | if (!cnd) {
30 | ret ~= elem;
31 | }
32 | }
33 |
34 | return new Value(ret);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/source/orelang/operator/SeqOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.SeqOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.conv;
6 |
7 | class SeqOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | long n = engine.eval(args[0]).getNumeric.to!long;
13 | Value[] array;
14 |
15 | for (long i; i < n; ++i) {
16 | array ~= new Value(i.to!double);
17 | }
18 |
19 | return new Value(array);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/source/orelang/operator/SetIdxOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.SetIdxOperator;
2 | import orelang.expression.ImmediateValue,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 | import std.conv;
7 |
8 | class SetIdxOperator : IOperator {
9 | /**
10 | * call
11 | */
12 | public Value call(Engine engine, Value[] args) {
13 | Value[] arr;
14 | if (args[0].type == ValueType.ImmediateValue) {
15 | arr = args[0].getImmediateValue.value.getArray;
16 | } else {
17 | arr = engine.eval(args[0]).getArray;
18 | }
19 | long idx = args[1].getNumeric.to!long;
20 | Value value = args[2];
21 |
22 | if (0 < idx && idx < arr.length) {
23 | arr[idx] = value;
24 |
25 | return new Value(arr);
26 | } else {
27 | throw new Exception("Invalid");
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/orelang/operator/SetOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.SetOperator;
2 | import orelang.expression.ClassType,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 |
7 | class SetOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | return engine.setVariable(args[0].getString, engine.eval(args[1]));
13 | }
14 | }
15 |
16 |
17 | /**
18 | * Set a value to the variable defined in parent scope
19 | */
20 | class SetPOperator : IOperator {
21 | /**
22 | * call
23 | */
24 | public Value call(Engine engine, Value[] args) {
25 | return engine.peekSuper.setVariable(args[0].getString, engine.eval(args[1]));
26 | }
27 | }
28 |
29 |
30 | /**
31 | * Set a value to the variable defined in class value
32 | */
33 | class SetCOperator : IOperator {
34 | /**
35 | * call
36 | */
37 | public Value call(Engine engine, Value[] args) {
38 | ClassType cls = engine.eval(args[0]).getClassType;
39 | string varName = args[1].type == ValueType.SymbolValue ? args[1].getString : engine.eval(args[1]).getString;
40 | Value value = engine.eval(args[2]);
41 |
42 | return cls._engine.setVariable(varName, value);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/source/orelang/operator/SortOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.SortOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.algorithm,
6 | std.array;
7 |
8 | class SortOperator : IOperator {
9 | public Value call(Engine engine, Value[] args) {
10 | Value eargs0 = engine.eval(args[0]);
11 | Value[] array,
12 | ret;
13 |
14 | if (eargs0.type == ValueType.Array) {
15 | array = eargs0.getArray;
16 | } else if (eargs0.type == ValueType.ImmediateValue && eargs0.getImmediateValue.value.type == ValueType.Array) {
17 | array = eargs0.getImmediateValue.value.getArray;
18 | } else {
19 | throw new Exception("[SortOperator] Invaild argument was given. SortOperator accepts list or array only.");
20 | }
21 |
22 | switch (array[0].type) with (ValueType) {
23 | case Numeric:
24 | double[] tmp = array.map!(value => value.getNumeric).array;
25 | std.algorithm.sort(tmp);
26 |
27 | foreach (t; tmp) {
28 | ret ~= new Value(t);
29 | }
30 | break;
31 | case String:
32 | string[] tmp = array.map!(value => value.getString).array;
33 | std.algorithm.sort(tmp);
34 |
35 | foreach (t; tmp) {
36 | ret ~= new Value(t);
37 | }
38 | break;
39 | default:
40 | throw new Exception("[SortOperator] Can't sort given array, all element of the array must be typed Numeric or String and the types are unified");
41 | }
42 |
43 | return new Value(ret);
44 | }
45 | }
--------------------------------------------------------------------------------
/source/orelang/operator/StdioOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.StdioOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.stdio,
6 | std.conv;
7 |
8 | class ReadlnOperator : IOperator {
9 | public Value call(Engine engine, Value[] args) {
10 | return new Value(stdin.readln);
11 | }
12 | }
13 |
14 | class StdinByLINEOperator : IOperator {
15 | public Value call(Engine engine, Value[] args) {
16 | Value[] ret;
17 |
18 | foreach (line; stdin.byLine) {
19 | ret ~= new Value(line.to!string);
20 | }
21 |
22 | return new Value(ret);
23 | }
24 | }
25 |
26 | class StdinEofOperator : IOperator {
27 | public Value call(Engine engine, Value[] args) {
28 | return new Value(stdin.eof);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/orelang/operator/StepOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.StepOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class StepOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = null;
12 |
13 | foreach (arg; args) {
14 | ret = engine.eval(arg);
15 | }
16 |
17 | return ret;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/source/orelang/operator/StringOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.StringOperators;
2 | import orelang.expression.ImmediateValue,
3 | orelang.operator.IOperator,
4 | orelang.Engine,
5 | orelang.Value;
6 | import std.algorithm,
7 | std.string,
8 | std.array;
9 |
10 | /**
11 | * This module provides operators with string.
12 | * Current provided operators:
13 | * - string-concat
14 | * - string-join
15 | * - string-split
16 | * - string-length
17 | * - string-slice
18 | * - as-string
19 | * - string-repeat
20 | */
21 |
22 | /**
23 | * concat strings into a string
24 | */
25 | class StringConcatOperator : IOperator {
26 | /**
27 | * call
28 | */
29 | public Value call(Engine engine, Value[] args) {
30 | if (args[0].type == ValueType.Array && args.length == 1) {
31 | return new Value(
32 | engine.eval(args[0]).getArray
33 | .map!(arg => (arg.type == ValueType.SymbolValue ? engine.eval(arg) : arg).getString)
34 | .join
35 | );
36 | } else if (args[0].type == ValueType.ImmediateValue && args[0].getImmediateValue.value.type == ValueType.Array && args.length == 1) {
37 | return new Value(
38 | args[0].getImmediateValue.value.getArray
39 | .map!(arg => (arg.type == ValueType.SymbolValue ? engine.eval(arg) : arg).getString)
40 | .join
41 | );
42 | } else {
43 | return new Value(
44 | args
45 | .map!(arg => engine.eval(arg).getString)
46 | .join
47 | );
48 | }
49 | }
50 | }
51 |
52 | /**
53 | * join strings into a string with a separator
54 | */
55 | class StringJoinOperator : IOperator {
56 | /**
57 | * call
58 | */
59 | public Value call(Engine engine, Value[] args) {
60 | if (args[0].type == ValueType.Array && args.length >= 1) {
61 | return new Value(
62 | engine.eval(args[0]).getArray
63 | .map!(arg => engine.eval(arg).getString)
64 | .join(args.length == 1 ? "" : engine.eval(args[1]).getString)
65 | );
66 | } else if (args[0].type == ValueType.ImmediateValue && args[0].getImmediateValue.value.type == ValueType.Array && args.length >= 1) {
67 | return new Value(
68 | args[0].getImmediateValue.value.getArray
69 | .map!(arg => (arg.type == ValueType.SymbolValue ? engine.eval(arg) : arg).getString)
70 | .join(args.length == 1 ? "" : engine.eval(args[1]).getString)
71 | );
72 | } else {
73 | return new Value(
74 | args[0..$-1]
75 | .map!(arg => engine.eval(arg).getString)
76 | .join(engine.eval(args[$-1]).getString)
77 | );
78 | }
79 | }
80 | }
81 |
82 | /**
83 | * split a string into strings with a separator
84 | */
85 | class StringSplitOperator : IOperator {
86 | /**
87 | * call
88 | */
89 | public Value call(Engine engine, Value[] args) {
90 | Value[] rets;
91 |
92 | foreach (value; engine.eval(args[0]).getString.split(args.length == 1 ? "" : engine.eval(args[1]).getString)) {
93 | rets ~= new Value(value);
94 | }
95 |
96 | return new Value(rets);
97 | }
98 | }
99 |
100 | /**
101 | * return a length of the string
102 | */
103 | class StringLengthOperator : IOperator {
104 | /**
105 | * call
106 | */
107 | public Value call(Engine engine, Value[] args) {
108 | import std.conv;
109 |
110 | if (args[0].type == ValueType.String) {
111 | return new Value(args[0].getString.length.to!double);
112 | } else {
113 | Value eargs0 = engine.eval(args[0]);
114 |
115 | if (eargs0.type == ValueType.String) {
116 | return new Value(eargs0.getString.length.to!double);
117 | } else {
118 | throw new Exception("[string-length] Invalid argument was given");
119 | }
120 | }
121 | }
122 | }
123 |
124 | /**
125 | * Tak a slice from the range of the string
126 | */
127 | class StringSliceOperator : IOperator {
128 | /**
129 | * call
130 | */
131 | import std.conv;
132 | public Value call(Engine engine, Value[] args) {
133 | string str;
134 | Value eargs0 = engine.eval(args[0]);
135 | str = eargs0.getString;
136 |
137 | long slice1 = engine.eval(args[1]).getNumeric.to!long,
138 | slice2 = engine.eval(args[2]).getNumeric.to!long;
139 |
140 | if ((0 <= slice1 && 0 <= slice2) && (slice1 <= str.length && slice2 <= str.length)) {
141 | return new Value(str[slice1..slice2]);
142 | } else {
143 | throw new Exception("[string-slice] Invalid");
144 | }
145 | }
146 | }
147 |
148 | class AsStringOperator : IOperator {
149 | /**
150 | * call
151 | */
152 | import std.conv;
153 | public Value call(Engine engine, Value[] args) {
154 | return new Value(new ImmediateValue(new Value((args[0].type == ValueType.SymbolValue ? engine.eval(args[0]) : args[0]).toString)));
155 | }
156 | }
157 |
158 | class StringRepeatOperator : IOperator {
159 | /**
160 | * call
161 | */
162 | import std.algorithm,
163 | std.string,
164 | std.array,
165 | std.range,
166 | std.conv;
167 | public Value call(Engine engine, Value[] args) {
168 | string pattern;
169 | long n;
170 |
171 | if (args[0].type == ValueType.SymbolValue) {
172 | pattern = engine.eval(args[0]).getString;
173 | } else if (args[0].type == ValueType.String) {
174 | pattern = args[0].getString;
175 | }
176 |
177 | if (args[1].type == ValueType.Numeric) {
178 | n = args[1].getNumeric.to!long;
179 | } else {
180 | n = engine.eval(args[1]).getNumeric.to!long;
181 | }
182 |
183 | return new Value(n.iota.map!(i => pattern).array.join);
184 | }
185 | }
186 |
187 | class StringChompOperator : IOperator {
188 | /**
189 | * call
190 | */
191 | import std.string;
192 |
193 | public Value call(Engine engine, Value[] args) {
194 | return new Value(engine.eval(args[0]).getString.chomp);
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/source/orelang/operator/SubOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.SubOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class SubOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = engine.eval(args[0]);
12 |
13 | if (args.length == 1) {
14 | ret.mulTo(new Value(-1));
15 | }
16 |
17 | foreach (arg; args[1..$]) {
18 | Value v = engine.eval(arg);
19 | ret.subTo(v);
20 | }
21 |
22 | return ret;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/source/orelang/operator/SystemOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.SystemOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | import std.process,
7 | std.string;
8 |
9 | class SystemOperator : IOperator {
10 | /**
11 | * call
12 | */
13 | public Value call(Engine engine, Value[] args) {
14 | string[] args_strs;
15 |
16 | foreach (arg; args) {
17 | args_strs ~= engine.eval(arg).toString;
18 | }
19 |
20 | try {
21 | auto pid = spawnProcess(args_strs);//execute(args_strs.join(" "));
22 |
23 | return new Value(wait(pid));
24 | } catch {
25 | return new Value(-1);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/source/orelang/operator/TimesOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.TimesOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.range,
6 | std.conv;
7 |
8 | class TimesOperator : IOperator {
9 | /**
10 | * call
11 | */
12 | public Value call(Engine engine, Value[] args) {
13 | Value ret = null;
14 | long n = engine.eval(args[0]).getNumeric.to!long;
15 |
16 | foreach (_; n.iota) {
17 | ret = engine.eval(args[1]);
18 | }
19 |
20 | return ret;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/source/orelang/operator/TranspileOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.TranspileOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Transpiler,
4 | orelang.Engine,
5 | orelang.Value;
6 |
7 | class TranspileOperator : IOperator {
8 | /**
9 | * call
10 | */
11 | public Value call(Engine engine, Value[] args) {
12 | string code = args[0].getString;
13 |
14 | return Transpiler.transpile(code);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/source/orelang/operator/TypeOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.TypeOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class TypeOperator : IOperator {
7 | /**
8 | * call
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | import std.conv;
12 | return new Value(engine.eval(args[0]).type.to!string);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/source/orelang/operator/UUIDOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.UUIDOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.conv,
6 | std.uuid : randomUUID;
7 |
8 | class RandomUUIDOperator : IOperator {
9 | /**
10 | * call
11 | */
12 |
13 | Value call(Engine engine, Value[] args) {
14 | return new Value(randomUUID.to!string);
15 | }
16 | }
--------------------------------------------------------------------------------
/source/orelang/operator/UntilOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.UntilOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class UntilOperator : IOperator {
7 | /**
8 | * Loop while the condition is false
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = null;
12 |
13 | while (!engine.eval(args[0]).getBool) {
14 | ret = engine.eval(args[1]);
15 | }
16 |
17 | return ret;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/source/orelang/operator/UriOperators.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.UriOperators;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 | import std.regex,
6 | std.uri : encodeComponentUnsafe = encodeComponent;
7 |
8 | static string encodeComponent(string s) {
9 | char hexChar(ubyte c) {
10 | assert(c >= 0 && c <= 15);
11 | if (c < 10)
12 | return cast(char)('0' + c);
13 | else
14 | return cast(char)('A' + c - 10);
15 | }
16 |
17 | enum InvalidChar = ctRegex!`[!\*'\(\)]`;
18 |
19 | return s.encodeComponentUnsafe.replaceAll!((s) {
20 | char c = s.hit[0];
21 | char[3] encoded;
22 | encoded[0] = '%';
23 | encoded[1] = hexChar((c >> 4) & 0xF);
24 | encoded[2] = hexChar(c & 0xF);
25 | return encoded[].idup;
26 | })(InvalidChar);
27 | }
28 |
29 | class UrlEncodeComponentOperator : IOperator {
30 | /**
31 | * call
32 | */
33 |
34 | Value call(Engine engine, Value[] args) {
35 | string s = engine.eval(args[0]).getString;
36 |
37 | return new Value(encodeComponent(s));
38 | }
39 | }
--------------------------------------------------------------------------------
/source/orelang/operator/WhenOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.WhenOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class WhenOperator : IOperator {
7 | /**
8 | * Loop while the condition is true.
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | if (engine.eval(args[0]).getBool) {
12 | Value ret = null;
13 |
14 | foreach (arg; args[1..$]) {
15 | ret = engine.eval(arg);
16 | }
17 |
18 | return ret;
19 | } else {
20 | return new Value;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/source/orelang/operator/WhileOperator.d:
--------------------------------------------------------------------------------
1 | module orelang.operator.WhileOperator;
2 | import orelang.operator.IOperator,
3 | orelang.Engine,
4 | orelang.Value;
5 |
6 | class WhileOperator : IOperator {
7 | /**
8 | * Loop while the condition is true.
9 | */
10 | public Value call(Engine engine, Value[] args) {
11 | Value ret = null;
12 |
13 | while (engine.eval(args[0]).getBool) {
14 | ret = engine.eval(args[1]);
15 | }
16 |
17 | return ret;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------