チェンジセット 4581

差分発生行の前後
無視リスト:
コミット日時:
2011/08/02 01:18:23 (2 年前)
コミッタ:
Mr.Grotesque
ログメッセージ:

--

ファイル:

凡例:

変更無し
追加
削除
更新
コピー
移動
  • air/clayg/jp/clayg/lisp/ConsFunc.as

    r4580 r4581  
    1111                public function execute(lisp:Lisp):Lisp 
    1212                { 
    13                         if ( lisp.length() != 2 ) throw new Error("引数は2つである必要があります!"); 
    1413                        var args:Array = lisp.toLispArray(); 
     14                        if ( args.length != 2 ) throw new Error("引数は2つである必要があります!"); 
     15 
    1516                        return args[1].cons(args[0]); 
    1617                } 
  • air/clayg/jp/clayg/lisp/EvalFunc.as

    r4580 r4581  
    1212                { 
    1313                        var result:Lisp; 
    14                         for each( var lisp:Lisp in lisp.toLispArray() ) result = Lisp.execute(lisp); 
     14                        for each( var lisp:Lisp in lisp.toLispArray() ) result = Lisp.eval(lisp); 
    1515                        return result; 
    1616                } 
  • air/clayg/jp/clayg/lisp/Lisp.as

    r4580 r4581  
    77        public class Lisp  
    88        { 
     9                public static const t:String = "t"; 
     10                public static const nil:String = "nil"; 
     11                 
    912                private static var funcs:Object = {}; 
    1013                private static var specials:Object = {}; 
    1114                private static var abbrevs:Object = {}; 
     15                private static var vars:Array = [ {} ]; 
    1216                 
    1317                addSpecial( "quote", new QuoteFunc() ); 
    14 //            addSpecial( "defmacro", new DefmacroFunc() ); 
    15 //            addSpecial( "defun", new DefunFunc( vars ) ); 
    16 //            addSpecial( "setf", new SetfFunc( vars ) ); 
     18              addSpecial( "defmacro", new DefmacroFunc() ); 
     19              addSpecial( "defun", new DefunFunc( vars ) ); 
     20              addSpecial( "setf", new SetfFunc( vars ) ); 
    1721                addSpecial( "progn", new EvalFunc() ); 
    1822                addSpecial( "eval", new EvalFunc() ); 
     
    2529                addFunction( "cdr", new CdrFunc() ); 
    2630                addFunction( "cons", new ConsFunc() ); 
    27 //            addFunction( "listp", new ListpFunc() ); 
    28                  
     31              addFunction( "listp", new ListpFunc() ); 
     32 
    2933                addAbbrev( "'", "quote" ); 
    3034                addAbbrev( "#'", "function" ); 
    3135                 
    32                 public static function execute( lisp:Lisp ):Lisp 
     36                /** 
     37                 * Lispを評価します. 
     38                 * @param       lisp 
     39                 * @return 
     40                 */ 
     41                public static function eval( lisp:Lisp ):Lisp 
    3342                { 
    3443                        trace("評価:" + lisp.toString()); 
     
    3645                        if ( !lisp.listp() ) 
    3746                        { 
    38                                 return lisp; 
     47                                // tを返す 
     48                                if ( lisp.toString() == "t" ) return new Lisp(t); 
     49                                 
     50                                // 数値を返す 
     51                                if ( lisp.numberp() ) return lisp; 
     52 
     53                                // 変数を返す 
     54                                var name:String = lisp.toString(); 
     55                                for (var i:int = vars.length-1; i >= 0; i--) if ( vars[i][name] != undefined ) return vars[i][name]; 
     56                                throw new Error( name+"という名前の変数はありません!") 
    3957                        } 
    4058                        else 
     
    4361                                var oper:String = ary.shift(); 
    4462                                var args:Lisp = new Lisp(ary); 
     63                                 
     64                                // nilを返す 
     65                                if ( ary.length == 0 ) return new Lisp(nil); 
    4566                                 
    4667                                // 特殊関数を実行 
     
    4869                                 
    4970                                // 引数を評価 
    50                                 args = new Lisp( args.toLispArray().map( function(e:Lisp, i:int, a:Array) { return execute(e); } )); 
     71                                args = new Lisp( args.toLispArray().map( function(e:Lisp, i:int, a:Array) { return eval(e); } )); 
    5172                                 
    5273                                // 関数を実行 
     
    5778                 
    5879                /** 
    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                { 
    13095                        // 括弧の数が正しいかチェック 
    13196                        var openNum:int = code.match(/\(/g).length; 
    13297                        var clseNum:int = code.match(/\)/g).length; 
    13398                        if ( openNum != clseNum ) throw new Error("括弧の数が不正なため、コードを正規化できませんでした!"); 
    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                         
    162171                        return code; 
    163172                } 
    164                  
    165                 /** 
    166                  * コードを数値に変換します. 
    167                  * @return 
    168                  */ 
    169                 public function toNumber():Number 
    170                 { 
    171                         if( !numberp() ) throw new Error(toString()+"は数値ではありません!"); 
    172                         return parseFloat(toString()); 
    173                 } 
    174                  
    175                 /** 
    176                  * コードを文字列の配列に変換します. 
    177                  * @return 
    178                  */ 
    179                 public function toStringArray():Array 
    180                 { 
    181                         if ( !listp() ) throw new Error(toString()+"はリストではありません!"); 
    182                          
    183                         var begin:int = 0; 
    184                         var end:int = 0; 
     173 
     174                /** 
     175                 * コードから配列を作成します. 
     176                 * @param       code 
     177                 * @return 
     178                 */ 
     179                public static function codeToAry( code:String ):Array 
     180                { 
     181                        if ( code == nil ) return []; 
     182                        if ( code.charAt() != "(" ) throw new Error(code+"はリストではありません!"); 
     183                         
    185184                        var ary:Array = []; 
    186  
    187                         // 外側の括弧をはずす 
    188                         var code:String = toString().slice(1, code.length - 1 ); 
    189                          
    190                         for ( end = 0; end < code.length; end++)  
    191                         { 
    192                                 switch( code.charAt(end) ) 
     185                        var str:String = code.slice(1, code.length-1); 
     186                        var anc:int = 0; 
     187                         
     188                        for ( var i:int = 0; i < str.length; i++ ) 
     189                        { 
     190                                switch( str.charAt(i) ) 
    193191                                { 
    194192                                case "(": 
    195                                         end = getClosedParenthesesIndex( code, end ) - 1; 
     193                                        anc = i; 
     194                                        var cnt:int = 0; 
     195                                        do 
     196                                        { 
     197                                                var char:String = str.charAt(i); 
     198                                                if ( char == "(" ) cnt++; 
     199                                                else if ( char == ")" ) cnt--; 
     200                                                i++; 
     201                                        } 
     202                                        while ( cnt > 0 ); 
     203                                        i--; 
    196204                                        break; 
    197205                                case "\"": 
    198                                         end = getClosedDoubleQuoteIndex( code, end ) - 1; 
     206                                        anc = i; 
     207                                        do { i++; } while ( str.charAt(i) != "\"" ); 
    199208                                        break; 
    200209                                case " ": 
    201                                         pushed(); 
    202                                         break; 
    203                                 case ")": 
    204                                         end = code.length; 
    205                                         break; 
     210                                        ary.push(str.slice(anc, i)); 
     211                                        anc = i+1; 
    206212                                } 
    207213                        } 
    208214                         
    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)); 
    257216                         
    258217                        return ary; 
    259218                } 
     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                } 
    260361 
    261362                /** 
     
    282383                public function listp():Boolean 
    283384                { 
    284                         if ( toString().charAt() == "(" ) return true; 
     385                        if ( code.charAt() == "(" ) return true; 
     386                        if ( code == nil ) return true; 
    285387                        return false; 
    286388                } 
     
    291393                public function numberp():Boolean 
    292394                { 
    293                         if ( !isNaN(parseFloat(toString())) ) return true; 
     395                        if ( !isNaN(parseFloat(code)) ) return true; 
    294396                        return false; 
    295397                } 
     
    301403                public function car():Lisp 
    302404                { 
    303                         return toLispArray().shift(); 
     405                        return new Lisp(toStringArray().shift()); 
    304406                } 
    305407                 
     
    310412                public function cdr():Lisp 
    311413                { 
    312                         trace( toString() ); 
    313414                        var ary:Array = toStringArray(); 
    314415                        ary.shift(); 
    315                         trace( ary.join(" ")); 
    316416                        return new Lisp( ary ); 
    317417                } 
     
    325425                { 
    326426                        var ary:Array = toStringArray(); 
    327                         ary.unshift( lisp.toString() ) 
     427                        ary.unshift( lisp ); 
    328428                        return new Lisp( ary ); 
    329429                }