| 59 | | * 関数を登録します. |
|---|
| 60 | | * @param name 関数名 |
|---|
| 61 | | * @param func 関数 |
|---|
| 62 | | */ |
|---|
| 63 | | public static function addFunction( name:String, func:ILispFunc ):void |
|---|
| 64 | | { |
|---|
| 65 | | funcs[name] = func; |
|---|
| 66 | | } |
|---|
| 67 | | |
|---|
| 68 | | /** |
|---|
| 69 | | * 関数を削除します. |
|---|
| 70 | | * @param name 関数名 |
|---|
| 71 | | */ |
|---|
| 72 | | public static function removeFunction( name:String ):void |
|---|
| 73 | | { |
|---|
| 74 | | delete funcs[name]; |
|---|
| 75 | | } |
|---|
| 76 | | |
|---|
| 77 | | /** |
|---|
| 78 | | * 新しい特殊関数を登録します |
|---|
| 79 | | * @param name 特殊関数名 |
|---|
| 80 | | * @param func 関数 |
|---|
| 81 | | */ |
|---|
| 82 | | public static function addSpecial( name:String, func:ILispFunc ):void |
|---|
| 83 | | { |
|---|
| 84 | | specials[ name ] = func; |
|---|
| 85 | | } |
|---|
| 86 | | |
|---|
| 87 | | /** |
|---|
| 88 | | * 特殊関数を削除します. |
|---|
| 89 | | * @param name 関数名 |
|---|
| 90 | | */ |
|---|
| 91 | | public static function removeSpecial( name:String ):void |
|---|
| 92 | | { |
|---|
| 93 | | delete specials[name]; |
|---|
| 94 | | } |
|---|
| 95 | | |
|---|
| 96 | | /** |
|---|
| 97 | | * 省略形を追加します. |
|---|
| 98 | | * @param abbrev 省略形の文字 |
|---|
| 99 | | * @param funcName 展開したときの関数名 |
|---|
| 100 | | */ |
|---|
| 101 | | public static function addAbbrev( abbrev:String, funcName:String ):void |
|---|
| 102 | | { |
|---|
| 103 | | abbrevs[abbrev] = funcName; |
|---|
| 104 | | } |
|---|
| 105 | | |
|---|
| 106 | | /** |
|---|
| 107 | | * 省略形を削除します. |
|---|
| 108 | | * @param abbrev 省略形文字 |
|---|
| 109 | | */ |
|---|
| 110 | | public static function removeAbbrev( abbrev:String ):void |
|---|
| 111 | | { |
|---|
| 112 | | delete abbrevs[abbrev]; |
|---|
| 113 | | } |
|---|
| 114 | | |
|---|
| 115 | | private var code:String; |
|---|
| 116 | | |
|---|
| 117 | | public function Lisp( data:* = "nil" ) |
|---|
| 118 | | { |
|---|
| 119 | | // 様々なデータ型をコードに変換 |
|---|
| 120 | | // if ( data is Array ) code = "("+data.map( function(e:*,i:int,a:Array ){return new Lisp( e ).toString();}).join(" ")+")"; |
|---|
| 121 | | if ( data is Array ) code = "(" + data.join(" ") + ")"; |
|---|
| 122 | | else if ( data is String ) code = data; |
|---|
| 123 | | else if ( data is Lisp ) code = data.toString(); |
|---|
| 124 | | else if ( data is int ) code = String(data); |
|---|
| 125 | | else if ( data is Number ) code = String(data); |
|---|
| 126 | | else throw new Error(data + "はLispに変換できない形式です!"); |
|---|
| 127 | | |
|---|
| 128 | | trace("新規:" + data); |
|---|
| 129 | | |
|---|
| | 80 | * コードを実行します. |
|---|
| | 81 | * @param code |
|---|
| | 82 | * @return |
|---|
| | 83 | */ |
|---|
| | 84 | public static function execute( code:String ):String |
|---|
| | 85 | { |
|---|
| | 86 | return eval( new Lisp( normalize( code ) ) ).toString(); |
|---|
| | 87 | } |
|---|
| | 88 | |
|---|
| | 89 | /** |
|---|
| | 90 | * コードを正規化します. |
|---|
| | 91 | * @return |
|---|
| | 92 | */ |
|---|
| | 93 | public static function normalize( code:String ):String |
|---|
| | 94 | { |
|---|
| 134 | | |
|---|
| 135 | | // コードを正規化 |
|---|
| 136 | | code = code.replace(/;.*/g, ""); |
|---|
| 137 | | code = code.replace(/\n/g, ""); |
|---|
| 138 | | code = code.replace(/\r/g, ""); |
|---|
| 139 | | code = code.replace(/\t/g, " "); |
|---|
| 140 | | code = code.replace(/ +/g, " "); |
|---|
| 141 | | code = code.replace(/^ /, ""); |
|---|
| 142 | | code = code.replace(/\( /g, "("); |
|---|
| 143 | | code = code.replace(/ \)/g, ")"); |
|---|
| 144 | | code = code.replace(/\)\(/g, ") ("); |
|---|
| 145 | | code = code.replace(/\)'/g, ") '"); |
|---|
| 146 | | // code = code.replace(/\( *\)/g, "nil"); |
|---|
| 147 | | |
|---|
| 148 | | // abbrev変換 |
|---|
| 149 | | if ( !listp() ) |
|---|
| 150 | | for ( var abbrev:String in abbrevs ) |
|---|
| 151 | | if ( code.slice(0,abbrev.length) == abbrev ) |
|---|
| 152 | | if ( code.length == abbrev.length ) code = "("+abbrevs[abbrev]+")"; |
|---|
| 153 | | else code = "(" + abbrevs[abbrev] + " " + code.slice(abbrev.length) + ")"; |
|---|
| 154 | | } |
|---|
| 155 | | |
|---|
| 156 | | /** |
|---|
| 157 | | * コードを文字列に変換します. |
|---|
| 158 | | * @return |
|---|
| 159 | | */ |
|---|
| 160 | | public function toString():String |
|---|
| 161 | | { |
|---|
| | 99 | |
|---|
| | 100 | code = code.replace(/;.*/g, ""); // コメント削除 |
|---|
| | 101 | code = code.replace(/[\n\r]/g, ""); // 改行削除 |
|---|
| | 102 | code = code.replace(/\t/g, " "); // タブをスペースに変換 |
|---|
| | 103 | |
|---|
| | 104 | // リストかどうか |
|---|
| | 105 | var listp:Boolean; |
|---|
| | 106 | if ( code.match(/^ *\(/) ) |
|---|
| | 107 | { |
|---|
| | 108 | listp = true; |
|---|
| | 109 | } |
|---|
| | 110 | else |
|---|
| | 111 | { |
|---|
| | 112 | code = code.replace(/^ */, ""); // 先頭のスペースを削除 |
|---|
| | 113 | code = code.replace(/ *$/, ""); // 後頭のスペースを削除 |
|---|
| | 114 | if ( code.match(/[ \(\)]/) ) throw new Error("不正なコードです!"); |
|---|
| | 115 | } |
|---|
| | 116 | |
|---|
| | 117 | trace(listp); |
|---|
| | 118 | |
|---|
| | 119 | |
|---|
| | 120 | // 文字数順の省略形配列を作る |
|---|
| | 121 | var abbary:Array = []; |
|---|
| | 122 | for ( var abb:String in abbrevs ) abbary.push(abb); |
|---|
| | 123 | abbary.sort( Array.length ); |
|---|
| | 124 | |
|---|
| | 125 | // 省略形を探す |
|---|
| | 126 | var finds:Array = []; |
|---|
| | 127 | code:for ( var i:int = 0; i < code.length; i++ ) |
|---|
| | 128 | { |
|---|
| | 129 | abb:for each( abb in abbary ) |
|---|
| | 130 | { |
|---|
| | 131 | var j:int; |
|---|
| | 132 | for ( j = 0; j < abb.length; j++ ) |
|---|
| | 133 | if ( abb.charAt(j) != code.charAt(i + j) ) continue abb; |
|---|
| | 134 | finds.unshift( { begin:i, abbrev:abb, end:i+j } ); |
|---|
| | 135 | i += j-1; |
|---|
| | 136 | continue code; |
|---|
| | 137 | } |
|---|
| | 138 | } |
|---|
| | 139 | |
|---|
| | 140 | // 省略形の両端にスペースを挿入 |
|---|
| | 141 | for each( var find:Object in finds ) |
|---|
| | 142 | { |
|---|
| | 143 | code = insert(code, " ", find.end); |
|---|
| | 144 | code = insert(code, " ", find.begin); |
|---|
| | 145 | } |
|---|
| | 146 | |
|---|
| | 147 | code = code.replace(/\(/g, " ("); // かっこ前にスペースを挿入 |
|---|
| | 148 | code = code.replace(/\)/g, ") "); // こっか後にスペースを挿入 |
|---|
| | 149 | code = code.replace(/ +/g, " "); // 連続スペースを一つにする |
|---|
| | 150 | code = code.replace(/^ /, ""); // 先頭のスペースを削除 |
|---|
| | 151 | code = code.replace(/ $/, ""); // 最後のスペースを削除 |
|---|
| | 152 | code = code.replace(/\( /g, "("); // かっこ後のスペースを削除 |
|---|
| | 153 | code = code.replace(/ \)/g, ")"); // こっか前のスペースを削除 |
|---|
| | 154 | code = code.replace(/\( *\)/g, nil); // 空かっこをnilに変換 |
|---|
| | 155 | |
|---|
| | 156 | |
|---|
| | 157 | // 省略形を置換 |
|---|
| | 158 | if ( !listp ) code = "(" + code + ")"; |
|---|
| | 159 | var ary:Array = codeToAry( code ); |
|---|
| | 160 | for ( var k:int = ary.length-1; k >= 0 ; k-- ) |
|---|
| | 161 | for ( var abb:String in abbrevs ) |
|---|
| | 162 | if ( ary[k].charAt() == "(" ) ary[k] = normalize( ary[k] ); |
|---|
| | 163 | else if ( ary[k] == abb ) |
|---|
| | 164 | { |
|---|
| | 165 | ary[k+1] = "("+abbrevs[abb]+" "+ary[k+1]+")"; |
|---|
| | 166 | ary.splice(k, 1); |
|---|
| | 167 | } |
|---|
| | 168 | if( listp ) code = "("+ary.join(" ")+")"; |
|---|
| | 169 | else code = ary.join(" "); |
|---|
| | 170 | |
|---|
| 209 | | pushed(); |
|---|
| 210 | | |
|---|
| 211 | | function pushed():void |
|---|
| 212 | | { |
|---|
| 213 | | ary.push( code.slice( begin, end ) ); |
|---|
| 214 | | begin = end + 1; |
|---|
| 215 | | } |
|---|
| 216 | | |
|---|
| 217 | | // 指定したindexの"("に対応する")"のインデックスを取得します. |
|---|
| 218 | | function getClosedParenthesesIndex( code:String, index:uint ):uint |
|---|
| 219 | | { |
|---|
| 220 | | if ( code.charAt(index) != "(" ) throw new Error("指定したインデックス"+index+"番目の文字は\"(\"ではありませんでした!"); |
|---|
| 221 | | if ( index > code.length ) throw new Error("指定したインデックス"+index+"番目の文字は存在しません!"); |
|---|
| 222 | | |
|---|
| 223 | | var count:uint = 0; |
|---|
| 224 | | while ( index < code.length ) |
|---|
| 225 | | { |
|---|
| 226 | | switch(code.charAt( index )) |
|---|
| 227 | | { |
|---|
| 228 | | case "(": count++; break; |
|---|
| 229 | | case ")": count--; break; |
|---|
| 230 | | } |
|---|
| 231 | | |
|---|
| 232 | | if ( count == 0 ) break; |
|---|
| 233 | | |
|---|
| 234 | | index++; |
|---|
| 235 | | } |
|---|
| 236 | | |
|---|
| 237 | | if ( ++index > code.length ) return 0; |
|---|
| 238 | | |
|---|
| 239 | | return index; |
|---|
| 240 | | } |
|---|
| 241 | | |
|---|
| 242 | | // 指定したindexの"""に対応する"""のインデックスを取得します. |
|---|
| 243 | | function getClosedDoubleQuoteIndex( code:String, index:uint ):uint |
|---|
| 244 | | { |
|---|
| 245 | | if ( code.charAt(index) != "\"" ) throw new Error("指定したインデックス"+index+"番目の文字は\"\"\"ではありませんでした!"); |
|---|
| 246 | | if ( index > code.length ) throw new Error("指定したインデックス" + index + "番目の文字は存在しません!"); |
|---|
| 247 | | |
|---|
| 248 | | var prevChar:String = "\""; |
|---|
| 249 | | while ( ++index < code.length ) |
|---|
| 250 | | { |
|---|
| 251 | | if ( code.charAt(index) == "\"" && prevChar != "\\" ) break; |
|---|
| 252 | | prevChar = code.charAt(index); |
|---|
| 253 | | } |
|---|
| 254 | | |
|---|
| 255 | | return ++index; |
|---|
| 256 | | } |
|---|
| | 215 | if( anc != str.length ) ary.push(str.slice(anc, str.length)); |
|---|
| | 219 | |
|---|
| | 220 | /** |
|---|
| | 221 | * 配列からコードを作成します. |
|---|
| | 222 | * @param ary |
|---|
| | 223 | * @return |
|---|
| | 224 | */ |
|---|
| | 225 | public static function aryToCode( ary:Array ):String |
|---|
| | 226 | { |
|---|
| | 227 | return "(" + ary.join(" ") + ")"; |
|---|
| | 228 | } |
|---|
| | 229 | |
|---|
| | 230 | /** |
|---|
| | 231 | * 関数を登録します. |
|---|
| | 232 | * @param name 関数名 |
|---|
| | 233 | * @param func 関数 |
|---|
| | 234 | */ |
|---|
| | 235 | public static function addFunction( name:String, func:ILispFunc ):void |
|---|
| | 236 | { |
|---|
| | 237 | funcs[name] = func; |
|---|
| | 238 | } |
|---|
| | 239 | |
|---|
| | 240 | /** |
|---|
| | 241 | * 関数を削除します. |
|---|
| | 242 | * @param name 関数名 |
|---|
| | 243 | */ |
|---|
| | 244 | public static function removeFunction( name:String ):void |
|---|
| | 245 | { |
|---|
| | 246 | delete funcs[name]; |
|---|
| | 247 | } |
|---|
| | 248 | |
|---|
| | 249 | /** |
|---|
| | 250 | * 新しい特殊関数を登録します |
|---|
| | 251 | * @param name 特殊関数名 |
|---|
| | 252 | * @param func 関数 |
|---|
| | 253 | */ |
|---|
| | 254 | public static function addSpecial( name:String, func:ILispFunc ):void |
|---|
| | 255 | { |
|---|
| | 256 | specials[ name ] = func; |
|---|
| | 257 | } |
|---|
| | 258 | |
|---|
| | 259 | /** |
|---|
| | 260 | * 特殊関数を削除します. |
|---|
| | 261 | * @param name 関数名 |
|---|
| | 262 | */ |
|---|
| | 263 | public static function removeSpecial( name:String ):void |
|---|
| | 264 | { |
|---|
| | 265 | delete specials[name]; |
|---|
| | 266 | } |
|---|
| | 267 | |
|---|
| | 268 | /** |
|---|
| | 269 | * 省略形を追加します. |
|---|
| | 270 | * @param abbrev 省略形の文字 |
|---|
| | 271 | * @param funcName 展開したときの関数名 |
|---|
| | 272 | */ |
|---|
| | 273 | public static function addAbbrev( abbrev:String, funcName:String ):void |
|---|
| | 274 | { |
|---|
| | 275 | abbrevs[abbrev] = funcName; |
|---|
| | 276 | } |
|---|
| | 277 | |
|---|
| | 278 | /** |
|---|
| | 279 | * 省略形を削除します. |
|---|
| | 280 | * @param abbrev 省略形文字 |
|---|
| | 281 | */ |
|---|
| | 282 | public static function removeAbbrev( abbrev:String ):void |
|---|
| | 283 | { |
|---|
| | 284 | delete abbrevs[abbrev]; |
|---|
| | 285 | } |
|---|
| | 286 | |
|---|
| | 287 | private var code:String; |
|---|
| | 288 | |
|---|
| | 289 | /** |
|---|
| | 290 | * 新しいインスタンスを作成します. |
|---|
| | 291 | * @param data |
|---|
| | 292 | */ |
|---|
| | 293 | public function Lisp( data:* = "nil" ) |
|---|
| | 294 | { |
|---|
| | 295 | trace("作成1:" + data); |
|---|
| | 296 | code = convert( data ); |
|---|
| | 297 | |
|---|
| | 298 | trace("作成2:" + code); |
|---|
| | 299 | } |
|---|
| | 300 | |
|---|
| | 301 | /** |
|---|
| | 302 | * データをコードに変換します. |
|---|
| | 303 | * @param data |
|---|
| | 304 | * @return |
|---|
| | 305 | */ |
|---|
| | 306 | private function convert( data:* ):String |
|---|
| | 307 | { |
|---|
| | 308 | var str:String; |
|---|
| | 309 | if ( data is String ) str = String(data); |
|---|
| | 310 | else if ( data is Lisp ) str = data.toString(); |
|---|
| | 311 | else if ( data is int ) str = String(data); |
|---|
| | 312 | else if ( data is Number ) str = String(data); |
|---|
| | 313 | else if ( data is Boolean ) str = data ? t : nil; |
|---|
| | 314 | else if ( data is Array ) str = data.length ? "(" + data.map( function(e:*, i:int, a:Array ){ return convert( e ); } ).join(" ") + ")" : nil; |
|---|
| | 315 | else throw new Error(data + "はLispに変換できない形式です!"); |
|---|
| | 316 | |
|---|
| | 317 | return str; |
|---|
| | 318 | } |
|---|
| | 319 | |
|---|
| | 320 | /** |
|---|
| | 321 | * 文字列を挿入 |
|---|
| | 322 | * @param code 対象文字列 |
|---|
| | 323 | * @param ins 挿入する文字列 |
|---|
| | 324 | * @param begin 挿入する位置 |
|---|
| | 325 | * @param cutLen 挿入位置から削除する文字数 |
|---|
| | 326 | * @return |
|---|
| | 327 | */ |
|---|
| | 328 | private static function insert( code:String, ins:String, begin:uint, cutLen:uint = 0 ):String |
|---|
| | 329 | { |
|---|
| | 330 | code = code.slice(0, begin) + ins + code.slice(begin+cutLen); |
|---|
| | 331 | return code; |
|---|
| | 332 | } |
|---|
| | 333 | |
|---|
| | 334 | /** |
|---|
| | 335 | * コードを文字列に変換します. |
|---|
| | 336 | * @return |
|---|
| | 337 | */ |
|---|
| | 338 | public function toString():String |
|---|
| | 339 | { |
|---|
| | 340 | return code; |
|---|
| | 341 | } |
|---|
| | 342 | |
|---|
| | 343 | /** |
|---|
| | 344 | * コードを数値に変換します. |
|---|
| | 345 | * @return |
|---|
| | 346 | */ |
|---|
| | 347 | public function toNumber():Number |
|---|
| | 348 | { |
|---|
| | 349 | if( !numberp() ) throw new Error(code+"は数値ではありません!"); |
|---|
| | 350 | return parseFloat(toString()); |
|---|
| | 351 | } |
|---|
| | 352 | |
|---|
| | 353 | /** |
|---|
| | 354 | * コードを文字列の配列に変換します. |
|---|
| | 355 | * @return |
|---|
| | 356 | */ |
|---|
| | 357 | public function toStringArray():Array |
|---|
| | 358 | { |
|---|
| | 359 | return codeToAry(code); |
|---|
| | 360 | } |
|---|