├── .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 | --------------------------------------------------------------------------------