mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Compare commits
986 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 58fb6f421a | |||
| 623436276e | |||
| f55df0da7b | |||
| bce811a53a | |||
| 6b09692684 | |||
| 3d7141b7fe | |||
| ad17ba0e11 | |||
| e4a9b4a3ad | |||
| 421819dc2c | |||
| df68a3345d | |||
| 2a5545cc25 | |||
| 6999e45742 | |||
| ca0f32a208 | |||
| aa8786f79c | |||
| 7e520838b3 | |||
| 44b4f69fce | |||
| 8d7e95282c | |||
| 7fbbd7ab9f | |||
| 7990bb7fa7 | |||
| 06f90a3b45 | |||
| 100f0e6759 | |||
| 73b05f0130 | |||
| 165e7b181b | |||
| d0f60182af | |||
| d9049c10fa | |||
| bba6c9a1ce | |||
| e5056d058a | |||
| 83d02bcd5a | |||
| 5e22e8e350 | |||
| c0914dbb65 | |||
| b4dcb8f286 | |||
| 615f296fcf | |||
| ae786b18d5 | |||
| a510564d6d | |||
| b83ff8ccd8 | |||
| 35185e69bf | |||
| ddb1aae41d | |||
| 03614ed918 | |||
| 05129ab9b3 | |||
| 7ecb96a00a | |||
| 41039524a9 | |||
| 5b304c156c | |||
| 7ac39333b5 | |||
| ebf49932c7 | |||
| e7e5db51de | |||
| f0379c8c45 | |||
| 16e473caad | |||
| 69ad12de06 | |||
| d2163d13a8 | |||
| 949bf6ca43 | |||
| 2300c9f737 | |||
| dc5de38414 | |||
| 1a150a6e48 | |||
| 0ab9ac6b22 | |||
| 584e4e413a | |||
| 9fac1a3f8b | |||
| 398da99d05 | |||
| 55fced30cd | |||
| a3925f3dec | |||
| aec65f2605 | |||
| 4353623b72 | |||
| 6123d653b7 | |||
| fa33bd86a8 | |||
| 7d940e3682 | |||
| 16c2ac2588 | |||
| e14387440e | |||
| 11b6696ce2 | |||
| e647b16d1d | |||
| ad06781107 | |||
| c66978521d | |||
| 5a5adafabf | |||
| b07269584c | |||
| e0e23b1765 | |||
| 7c8c9f9532 | |||
| 7ff907f680 | |||
| f1ea7a31c0 | |||
| df2c3771f8 | |||
| f6f8bb2416 | |||
| 06ec17de60 | |||
| d549603a8a | |||
| b8ca0b7cd8 | |||
| c863e0dac8 | |||
| c6ea948030 | |||
| 346ebfb0ea | |||
| 25bee356b1 | |||
| 17cd7a65e7 | |||
| bceb6640fa | |||
| 977f79478f | |||
| bbb0882343 | |||
| d4ff92bcf6 | |||
| 3d98fa2e46 | |||
| a5b8603aa2 | |||
| a9e434e69a | |||
| e71a6a7b2c | |||
| 5ef8f18e9b | |||
| 99328695e3 | |||
| 9c0426c990 | |||
| 2db06c471e | |||
| 08a508cbee | |||
| 5bf60b4837 | |||
| d96b2c9a76 | |||
| 85fc9b88d0 | |||
| f73ac4112f | |||
| 0e452a75ac | |||
| b763759972 | |||
| c76631d445 | |||
| 6d42195fb2 | |||
| 274884abe5 | |||
| 761218e70b | |||
| b103fa229d | |||
| bda273f35d | |||
| 6bc38f4637 | |||
| 0ded91c806 | |||
| 81dc383291 | |||
| 550c878216 | |||
| e17092debd | |||
| c47a1984b4 | |||
| 7f3bda5653 | |||
| 5de7dc2948 | |||
| 83065df67a | |||
| f9d1d72217 | |||
| 36a0b864ba | |||
| f1207573bd | |||
| 6ebcb7417a | |||
| 9df7bceb15 | |||
| b724e06cf2 | |||
| bc9e3e6fd0 | |||
| 764a568aa4 | |||
| ff1194c134 | |||
| a5412d48fd | |||
| 842e6945f2 | |||
| 73ef548c63 | |||
| d75266dd1b | |||
| 10ed730e4b | |||
| cdf173d32c | |||
| 0e46b14b9e | |||
| 6975258efd | |||
| ae44e80668 | |||
| b00d45b095 | |||
| 4a99f4949e | |||
| cbb6f29875 | |||
| 940133b627 | |||
| 1fea63429e | |||
| 0b5d97ec42 | |||
| 6f4d4bbcc7 | |||
| 5d04e3316b | |||
| ff8b608c52 | |||
| cd9f53d42e | |||
| c35a402676 | |||
| 86ef9a2806 | |||
| 2b9f762ba1 | |||
| d3e273ba4e | |||
| f3279b41e6 | |||
| 5f7cdecdc9 | |||
| b746a0f0d2 | |||
| 9c78a9bfa2 | |||
| b7c3a876f1 | |||
| 3e67a116d1 | |||
| afa53809e2 | |||
| f35f975d26 | |||
| d4fc980527 | |||
| 6bb5ad786c | |||
| 597149ae23 | |||
| b4f9b031de | |||
| 284a1d12ee | |||
| 0ab21a9a5e | |||
| fbafa78098 | |||
| 4665b07f7b | |||
| fe3ac50845 | |||
| cb4b042777 | |||
| 393133e741 | |||
| 8b7a8978e2 | |||
| 8f2c62407c | |||
| 6c06e77446 | |||
| 6a9efd6849 | |||
| 9b2454c94d | |||
| 7405821f5a | |||
| 86f9254df0 | |||
| 825e93eba4 | |||
| 31ce73ddc3 | |||
| a2d0ee59c6 | |||
| 269f9f2125 | |||
| e65fa4d7a2 | |||
| d01003ce3a | |||
| ddd32d74e1 | |||
| 74714c8fee | |||
| c8da602752 | |||
| 03a3bd9178 | |||
| c210a8adf9 | |||
| 181f980b6c | |||
| 41c8c419cf | |||
| f723832ebc | |||
| 7ae20e0785 | |||
| 37f6e42293 | |||
| d6cb4f9cf2 | |||
| a751f7f196 | |||
| fef4b394a7 | |||
| de2363a9f0 | |||
| 388d26d770 | |||
| ab27abe083 | |||
| 625f9f6fa3 | |||
| e7fe6ee263 | |||
| 12e38597c8 | |||
| d489b41c31 | |||
| e4662d77e7 | |||
| 13a318b0c7 | |||
| f6896751b4 | |||
| ddfb24908c | |||
| 022570ab8d | |||
| b6598e052f | |||
| 77edafb04c | |||
| 59dc7d0763 | |||
| 1b45e034ba | |||
| 6316e0c75d | |||
| 92e24f809b | |||
| c7c9543bed | |||
| 57dad6e3fd | |||
| 23d18bbd62 | |||
| 93f5f22577 | |||
| 3f9d00ded3 | |||
| 4614b9d632 | |||
| 5405b47f41 | |||
| 14877469d1 | |||
| 07cf7b16f3 | |||
| 6c966a1f86 | |||
| 0cf5a0ee37 | |||
| fda64be996 | |||
| 71eeb86a99 | |||
| d08205b40d | |||
| 7f4cc0de51 | |||
| 7a13e89509 | |||
| 8a9b6c4352 | |||
| 0c3ee0ba66 | |||
| f2394859e3 | |||
| 3c8e1f94c4 | |||
| fc930700b7 | |||
| ce916b99b8 | |||
| b5dfbce767 | |||
| 44f07045d1 | |||
| 913b83d579 | |||
| 3c20c96f84 | |||
| b890528a18 | |||
| 344a7ce20c | |||
| 4122c320bb | |||
| db8265f428 | |||
| 4e365156d1 | |||
| 061d804a59 | |||
| 332d8d2a1c | |||
| 1519616ecb | |||
| c96def7c96 | |||
| e59ad60327 | |||
| fb85855fa1 | |||
| be2c1592ed | |||
| 1988bec23e | |||
| c3710dbb96 | |||
| 6b0c22e395 | |||
| b70d69de09 | |||
| 9afd376fa4 | |||
| b0cdb93a3a | |||
| 9c1f21aaa1 | |||
| 44e2c97152 | |||
| 5d781312ca | |||
| fa974a1f6a | |||
| af3d5d6c8a | |||
| 0d92431061 | |||
| 81ea81e05c | |||
| 3eebe81b35 | |||
| dcd5d0ffec | |||
| acdc2d1f24 | |||
| 679dfd75a8 | |||
| be86d8b45f | |||
| 80e03f3ffb | |||
| 82983330a3 | |||
| 1c2a2827b3 | |||
| f8121953e7 | |||
| 43795cb1f1 | |||
| 4c255c7739 | |||
| c3c882f681 | |||
| 8c408379aa | |||
| 7edbe428ca | |||
| 473b7d0efd | |||
| 7b01b969f5 | |||
| 29a9e698e3 | |||
| 999ce87129 | |||
| 77d6a953ff | |||
| ebd45b1072 | |||
| 0bff4b6a09 | |||
| 885916c84b | |||
| e88fc10679 | |||
| ec7f478eda | |||
| 67ab8406b8 | |||
| 23cc698134 | |||
| 5ede90cdf4 | |||
| 53f934a7ee | |||
| ef8df492e9 | |||
| 027b8d8377 | |||
| 46ccabacf0 | |||
| 6cde950017 | |||
| 0e2976bf93 | |||
| b7e71e4cef | |||
| 490de9dbe1 | |||
| 220c628210 | |||
| f0c1074b07 | |||
| 4a0c9c9e31 | |||
| 332a04af73 | |||
| 971a4f9122 | |||
| 0e0c96096d | |||
| 7d98055862 | |||
| 8cef3f946c | |||
| 3e1d60ae0b | |||
| c7b663f2cf | |||
| b406e9f795 | |||
| 1dcf8ba488 | |||
| 7a2391b120 | |||
| 4d6b8dbcb9 | |||
| f4a17dd7b5 | |||
| 5ed76e381c | |||
| 9c5db48d1f | |||
| d8b37d0381 | |||
| 4146b5c2b5 | |||
| 7507d46992 | |||
| be81504770 | |||
| 0848407ee5 | |||
| d713f8d761 | |||
| 2640896911 | |||
| 8d816fa142 | |||
| d3819620ce | |||
| a94525d4ea | |||
| 1e2c962fa5 | |||
| 897eabb1bb | |||
| e10b329fa3 | |||
| 861077f779 | |||
| 553dbad2c6 | |||
| 49e96a2e19 | |||
| 536b95eb48 | |||
| 9d89f8c00b | |||
| 377d6a47ac | |||
| f632baddb1 | |||
| 49db1db81f | |||
| 2e239a296e | |||
| f1a02dff58 | |||
| 381850280c | |||
| e98823f189 | |||
| e01d35ef79 | |||
| 298177fd6a | |||
| e00b48be4a | |||
| 7450a774a5 | |||
| 0ceaa0960a | |||
| 5760226e71 | |||
| ab54185005 | |||
| a809d42f5a | |||
| d6e41c3e51 | |||
| 3d8c1a7e97 | |||
| 2a1e616e4d | |||
| cbfa2b3588 | |||
| f68f5f6b97 | |||
| 7f4b57bb20 | |||
| 15f4bdb529 | |||
| 5b6e4eda2a | |||
| 3acaa44a70 | |||
| 8a5d783f2e | |||
| 5d7e4957e0 | |||
| da97715e11 | |||
| e03042ec19 | |||
| 9f677b72db | |||
| 476af3c647 | |||
| ab99e2c293 | |||
| 57610091ce | |||
| f0f4a1088a | |||
| 35deaae776 | |||
| 71357ff1d8 | |||
| bf32265743 | |||
| fe3227cd5c | |||
| 483a038d39 | |||
| 2c85213298 | |||
| 79b4f61b02 | |||
| 4b0b8f7e1a | |||
| 8976f47e0a | |||
| c082249838 | |||
| 786cbf06c3 | |||
| 1260d3b68a | |||
| f1fa5bf1c6 | |||
| 15d48efa4b | |||
| fd927d786e | |||
| c956e17c02 | |||
| 6c9013e22b | |||
| f3fb43c729 | |||
| ccd555421a | |||
| 01b9b71902 | |||
| 85a400e43d | |||
| cec53ff77e | |||
| 1b545a6b63 | |||
| 60104ce41d | |||
| 43ec918be1 | |||
| 0e10a23d7a | |||
| 0c52112dd4 | |||
| 04dbbff3c1 | |||
| f2cc1239a5 | |||
| f7f1aca8b5 | |||
| 5f2c7e47bb | |||
| 17c249780f | |||
| 5d9b84ef40 | |||
| 78b13b3955 | |||
| ef6a762d41 | |||
| bac37a9f1a | |||
| b2a16d6bf7 | |||
| c8341dbf7c | |||
| 5d099e40e6 | |||
| 63f10a1ee5 | |||
| 3366894a40 | |||
| 499498a6a7 | |||
| 84d8ecc1d7 | |||
| 4aca9ef98e | |||
| 1221f7676e | |||
| c040c8d92b | |||
| c6596cf26a | |||
| 64e5208404 | |||
| 4c9a604877 | |||
| a65f4dbb32 | |||
| db437b04a4 | |||
| 0d865a77d5 | |||
| ab3b6dbd2a | |||
| 3f90af6b42 | |||
| a7d611fb23 | |||
| 5d0fc7e57a | |||
| 8cea1f8907 | |||
| a117ec771b | |||
| 834523945e | |||
| db098d3e0e | |||
| 2294ebdd44 | |||
| 9146d5c34f | |||
| 8b3298b2d6 | |||
| 29ad0a7964 | |||
| a8bd06904d | |||
| a06adb176f | |||
| 8b5be554c7 | |||
| 8fbc4bef55 | |||
| f1767fd079 | |||
| 722d123b87 | |||
| 198c898817 | |||
| 4c25738ac7 | |||
| 2adb0c201e | |||
| 11c3ad999e | |||
| f229ed917e | |||
| 75ec86ed00 | |||
| 6b0860ce61 | |||
| 5dc688fb12 | |||
| 0789ec71e0 | |||
| d5ac785b31 | |||
| 198df61039 | |||
| f2d4640998 | |||
| 3f591d71c6 | |||
| 8bf492f127 | |||
| baa5d2e3f7 | |||
| 0828a962c0 | |||
| 42f9af41fb | |||
| 731dd78aa0 | |||
| 58f5115b22 | |||
| d077a5f0a6 | |||
| 56d4e41d76 | |||
| 96d4c2d385 | |||
| 1d781da8a6 | |||
| db72cdae28 | |||
| ab39ed4f82 | |||
| 9feb069124 | |||
| 0ff28c9e60 | |||
| ef0b239704 | |||
| 67e2dddb82 | |||
| 8f6b2121d9 | |||
| 4e2f4f4280 | |||
| ae04005092 | |||
| 3e075a7b6c | |||
| 68470bef86 | |||
| 2249551c63 | |||
| ac42ccc1fc | |||
| a8658b0f2c | |||
| a7462a7f42 | |||
| 3d288ef0d8 | |||
| 78be0172f7 | |||
| 9826ca54f2 | |||
| 9e0c48ddc6 | |||
| 2fadddcd20 | |||
| 24c345fe5c | |||
| 6c61a60609 | |||
| 4d46f366ac | |||
| f9c3ebd29d | |||
| 0a61df1c34 | |||
| 8f62957888 | |||
| 66e2928bd4 | |||
| 8494557006 | |||
| e910cf6169 | |||
| 1358725738 | |||
| ec7475d88b | |||
| 0e5c3c4ebd | |||
| 1b9c4855a3 | |||
| 006661394d | |||
| 36dbfd9bda | |||
| e86c252a99 | |||
| 8095754e28 | |||
| 7bdc709da0 | |||
| 7b88c1a8e5 | |||
| da24af34b9 | |||
| 2170fad406 | |||
| 648e9ea51b | |||
| 3f6a098626 | |||
| 9e10afe1d0 | |||
| 16aafdd866 | |||
| facf5f99d4 | |||
| a4ff31eaf6 | |||
| 3359b86ec7 | |||
| c8fdab8725 | |||
| e821c25d38 | |||
| b290e98f3b | |||
| cf23a85333 | |||
| dda73da640 | |||
| a3bfd735a0 | |||
| 451574f142 | |||
| f937af5745 | |||
| c7018ea962 | |||
| b499ad6749 | |||
| 8a6ce74b4d | |||
| 4696093673 | |||
| 1e41026b28 | |||
| f26d00d9e8 | |||
| 5d44f8582e | |||
| 7d5cf8749a | |||
| 46ab8fdf07 | |||
| 9fa3d77114 | |||
| 7b8d784040 | |||
| 7f9e333647 | |||
| 308341b990 | |||
| 1fc9a3019d | |||
| 1c360965e7 | |||
| 5fee3f5869 | |||
| e2c9a30571 | |||
| 04c21d9d6b | |||
| 25a0a6b038 | |||
| 5a9eedf541 | |||
| aa3cb0466e | |||
| ca2cfc6fe9 | |||
| 645b0fb58c | |||
| 14a72b0800 | |||
| a8bffdae50 | |||
| 468cc34c93 | |||
| dd52b88101 | |||
| 329938ef15 | |||
| 52aafcd001 | |||
| 59eaad9d78 | |||
| 2730231e50 | |||
| 8fe2a6ce0f | |||
| 515a093213 | |||
| d7fef24a95 | |||
| 460d628490 | |||
| 1c02b8558f | |||
| de3edcc170 | |||
| bad807e7f0 | |||
| 70e99d6b57 | |||
| 7fa9321c18 | |||
| e5fbe350b3 | |||
| 9501b18362 | |||
| a18904a4c2 | |||
| e9b57124a0 | |||
| adf453a584 | |||
| 059d707e3a | |||
| e1de86134d | |||
| 495a2e605d | |||
| fc666bfe20 | |||
| 46dee5716f | |||
| 01fce3dc35 | |||
| bf48473cf6 | |||
| c76dc33116 | |||
| e581f2ed97 | |||
| ce6c05600a | |||
| 718a9ceb6e | |||
| 542f0f7b16 | |||
| 91868286be | |||
| cc04f03393 | |||
| 2ef5d22b60 | |||
| b68e7a605c | |||
| b643a1a8bc | |||
| bd66c5d716 | |||
| cc01dedc65 | |||
| c377d504f6 | |||
| c6bd8ceab7 | |||
| e9cdc88008 | |||
| 31bc2b0009 | |||
| 9b8956cdd0 | |||
| 7d99830211 | |||
| 466a18b0d3 | |||
| aee1476ebd | |||
| 15945e14b9 | |||
| f0abd4241f | |||
| 3554a41a54 | |||
| 877e16501c | |||
| 1a3b32343e | |||
| b30eba6a13 | |||
| d0717efda6 | |||
| 7944d9a6d4 | |||
| 9a59cd7af8 | |||
| b200c7475a | |||
| c41e262667 | |||
| af0bef6dd8 | |||
| e8a4e4262a | |||
| 464d3fc0a3 | |||
| 057be5ffb5 | |||
| d0a7e01d9c | |||
| bf1cb87b34 | |||
| 39779b339e | |||
| 0fa94f9ead | |||
| 615e7e44e3 | |||
| 455f3954dc | |||
| abca63c73b | |||
| 04774e5bf2 | |||
| 7c62d89348 | |||
| 3642fe4013 | |||
| 81a0dcdb7a | |||
| fe99819bc9 | |||
| c279f00109 | |||
| 0b41066e83 | |||
| 051d7bc8db | |||
| 1ebe1c8b1f | |||
| 27f422880f | |||
| 3a73a58493 | |||
| 383a9c79e1 | |||
| dab87cf960 | |||
| a3a4f4d061 | |||
| 0c0b34136e | |||
| 87771ecf92 | |||
| 0bbd60b523 | |||
| 86edc9ab85 | |||
| 844b2c368f | |||
| c43795c664 | |||
| 6836f424c5 | |||
| 728d313b2c | |||
| 311f4a230f | |||
| 7e014efe45 | |||
| 38db5e550f | |||
| 9c2db2e134 | |||
| 86b69d7c5d | |||
| d83e15e866 | |||
| 0dbd1d5992 | |||
| f691a73c26 | |||
| a80a745b69 | |||
| f8a3af8086 | |||
| 3ae5fea2b8 | |||
| 74fe87c289 | |||
| 86d58a2d37 | |||
| 88a7fedea4 | |||
| 3dad125a1c | |||
| caab1c203c | |||
| 69623078a8 | |||
| 1fac605e3f | |||
| 458b517c6f | |||
| b31b8022db | |||
| d1c48192cb | |||
| 7e89736291 | |||
| 698378f076 | |||
| f2d4880098 | |||
| 906b516cfa | |||
| 0eafb089c9 | |||
| 905203ef5e | |||
| b5e2dc9097 | |||
| f6a82772e6 | |||
| 2229a2aa0f | |||
| 51cf6b6048 | |||
| ff845be72c | |||
| 7c9d941003 | |||
| d8189c2b19 | |||
| 024b09de0c | |||
| b341ee7c12 | |||
| 9ccf03e5ae | |||
| d2c1f4d10b | |||
| b462ef4506 | |||
| 4cac5e9c70 | |||
| cc66bf94d1 | |||
| 13650747e7 | |||
| 26c1dedcab | |||
| b9f7daf5b6 | |||
| 93d481d4b4 | |||
| e90ecff671 | |||
| 2af2a4fff8 | |||
| b2a0c9c6bf | |||
| 4f6703203b | |||
| 2a80cccf30 | |||
| 11961b42ac | |||
| 777cf70cc5 | |||
| 18f7b45ad1 | |||
| be2ec608e2 | |||
| 1c4428880b | |||
| 7d6f2beaaa | |||
| c165e50193 | |||
| a25ec0a749 | |||
| bdc118304c | |||
| c8a2c636e0 | |||
| 99e10b8dc4 | |||
| 4acfd1c7d2 | |||
| dd754220ce | |||
| 68de1e4fc5 | |||
| 0f5b8b66b0 | |||
| 6c67120ed4 | |||
| b19c315148 | |||
| 7337bfa497 | |||
| 07ceb138fa | |||
| 07f1ebd26d | |||
| 11ffb93852 | |||
| ca495944b6 | |||
| a55accd736 | |||
| c9a4091b83 | |||
| 1f4bd9fd9f | |||
| 2cc674e58e | |||
| 14cdff075d | |||
| 44473fecdd | |||
| 828551f86c | |||
| db7d829679 | |||
| 21963f8fa1 | |||
| cac0035348 | |||
| 78fe65aec4 | |||
| 71197d2737 | |||
| 238704592a | |||
| e724c5af98 | |||
| 1f217ea82e | |||
| 9bbfc38bb4 | |||
| 1d6b7f9bba | |||
| f5560e8f17 | |||
| c26f998ed5 | |||
| 625995424c | |||
| f3016752bd | |||
| ecd7ef5924 | |||
| 02daa2509d | |||
| 5fa3c39145 | |||
| 6c4d39412f | |||
| 042e4a4313 | |||
| 2467332c93 | |||
| efaf74672e | |||
| 5323498033 | |||
| e8efd10bd9 | |||
| 4603047eb1 | |||
| 359d2ae6fd | |||
| d34db58797 | |||
| c43a08314e | |||
| ec4982b2d3 | |||
| 8527c78fb5 | |||
| 2929c629d4 | |||
| de60400c64 | |||
| f80a4fd0e8 | |||
| 2d1134e9ea | |||
| fe7784efb0 | |||
| bfb9cf7922 | |||
| 4ab922044d | |||
| 7ee9ab89f9 | |||
| a426f0e2b5 | |||
| 752f7c1526 | |||
| 7d8cbf1a9c | |||
| 1b5c68567e | |||
| 8da787be72 | |||
| b913e7eefd | |||
| 2ba4933158 | |||
| 15de80a7cd | |||
| dacb8b626b | |||
| ae4fc77675 | |||
| 6d6be18d4e | |||
| 7f8324a2ed | |||
| 36343cf098 | |||
| c0738a74c6 | |||
| cfbc8a8995 | |||
| e92fd76248 | |||
| 1629e86063 | |||
| e4006cb53a | |||
| 0d05a22602 | |||
| 7b17158f88 | |||
| a09858af61 | |||
| a960a6f931 | |||
| 3a22166c67 | |||
| 3a97a453c4 | |||
| c455544ee2 | |||
| 1d1f273ca9 | |||
| 42752bffce | |||
| e7dbe6e87a | |||
| e82c1d3f38 | |||
| 50721e9bf8 | |||
| 9b13a59a55 | |||
| ee347f3417 | |||
| be9e203563 | |||
| 723db886e1 | |||
| 121475638d | |||
| 2103bc99ba | |||
| 669fe705cc | |||
| e61c469724 | |||
| 9439b981d8 | |||
| d1fee5892a | |||
| e7cd024498 | |||
| 24007b80b4 | |||
| a2f45bf8d1 | |||
| a44ada616e | |||
| 379c5a6d88 | |||
| b50093ad28 | |||
| 190264b3c8 | |||
| 0761b17245 | |||
| 9a2cbc4122 | |||
| e60951a305 | |||
| 1768ee02e5 | |||
| 8c34a8d561 | |||
| 689541d0fb | |||
| 093f4e2cff | |||
| fa39825b1b | |||
| 66a92240de | |||
| 78f5f98710 | |||
| 7e689e8680 | |||
| 59b7c4eaf0 | |||
| 91c285fcfe | |||
| 04097348e8 | |||
| baa40ef2b1 | |||
| 9c3c267bef | |||
| f3c71cf5da | |||
| ddfc4eb5ef | |||
| 376af5bac3 | |||
| 5b65ca3ebb | |||
| 7b2611ea28 | |||
| 8f4b7ac15c | |||
| 514450e891 | |||
| 7dc2b4f59f | |||
| f4f968241b | |||
| a0c4ca2406 | |||
| 1997420a7f | |||
| d894de86f4 | |||
| cb84ce30e7 | |||
| 9ee9c271d1 | |||
| dc61ef1c65 | |||
| 077f39bd38 | |||
| 9a1b25bdd8 | |||
| 5aeb99ad49 | |||
| 9c00de59ce | |||
| c46cb1b5eb | |||
| e5f30f83ce | |||
| 99c67749ff | |||
| 7d7a549a4f | |||
| 36045ea96f | |||
| 1c4f46f324 | |||
| a11780f4f1 | |||
| a3e1e535dc | |||
| 9f5ff9ddec | |||
| ba9cb1f757 | |||
| 10be4cbb2c | |||
| 87ce12dfe3 | |||
| 810e37b1c3 | |||
| d5cf1de1ae | |||
| 1d987d2fcd | |||
| 9850e6a9d0 | |||
| cd168c6f32 | |||
| 28e00d82fb | |||
| a6ab2c54f3 | |||
| 706ef1337a | |||
| 572b404935 | |||
| 2bf49c9232 | |||
| 083cd9ca8c | |||
| 355723ebca | |||
| 80e01e3659 | |||
| 1094bbfff8 | |||
| eda9d1a8fc | |||
| ab9dcc766e | |||
| 719452b8d2 | |||
| 14031bdf44 | |||
| 279587c138 | |||
| a8558512ec | |||
| e345d4c68f | |||
| 11b47459e7 | |||
| 39bd240116 | |||
| 7ff049457f | |||
| d9f3fd868a | |||
| f7c054bd39 | |||
| e8706d4ee7 | |||
| b9dff44582 | |||
| 56a8c592dd | |||
| a90d8b8a73 | |||
| d28f042118 | |||
| 7fd585bae1 | |||
| daa65c15de | |||
| 40c52f58d0 | |||
| ee2859de6e | |||
| b3c6075dc5 | |||
| b74458a486 | |||
| 526608c8a2 | |||
| f10b73efa7 | |||
| a2af349959 | |||
| b744097511 | |||
| a613bce3f2 | |||
| 8cee36b1b5 | |||
| 23afaf02dc | |||
| a26ce35c64 | |||
| d12f436bdb | |||
| 5a59fd3a5c | |||
| e641e9a380 | |||
| 2245818f91 | |||
| 78d2d909cf | |||
| 87d878292d | |||
| e44da8a6cc | |||
| 1e8097a4b8 | |||
| e96cdeb2af | |||
| db14b8e7d4 | |||
| d8e5e7df3f | |||
| 78ebe1b427 | |||
| 823df14ff4 | |||
| ec443d45db | |||
| 93edd26b3e | |||
| 005f01f2fc | |||
| bf4c226232 | |||
| c608c26ab4 | |||
| 49494a7367 | |||
| 8b48e2b4a4 | |||
| 97899a6922 | |||
| adb3bd6698 | |||
| d75d23294d | |||
| b4f0a68fba | |||
| 140da1c6ca | |||
| e27fb544df | |||
| e2b0606752 | |||
| c4e3c46e86 | |||
| 47a610e688 | |||
| 713aa48cf9 | |||
| 9dc875f246 | |||
| 40adffc676 | |||
| 0345215465 | |||
| a9593e1f57 | |||
| 5e8021bedb | |||
| c49541058c | |||
| 76e1017f48 | |||
| a341b8e0ff | |||
| cf827ab0e7 | |||
| 4f3a749da1 | |||
| 216e32751e | |||
| 5625e44371 | |||
| 1272df7cb6 | |||
| 35defaf1c9 | |||
| f4aa3e7ae7 | |||
| 1411d5b974 | |||
| 12144b9ad2 | |||
| 0f2d7e8a99 | |||
| b8912c3508 | |||
| 4bebd4d70f | |||
| cfe18142cb | |||
| 89147066f8 | |||
| bc5feb39a1 | |||
| e459ecc934 | |||
| 49e53bca5d | |||
| 06f1c82f64 | |||
| 0a21d9ec92 | |||
| e277079616 | |||
| 55b6ef43c5 | |||
| 14e1992ed0 | |||
| d39a05e68e | |||
| 49cc9c7cfa | |||
| c25d386c41 | |||
| acc8995060 | |||
| df529a83d6 | |||
| 7a94d02e8d | |||
| 38f4086a52 | |||
| dce09fb7fd | |||
| c869bdedc0 | |||
| 8c5cb5e782 | |||
| f89ee88a6c | |||
| 7618ca6bb3 | |||
| 8bfbca234f | |||
| 62e1823187 | |||
| 814f3305ca | |||
| d5982b43c5 | |||
| da557fbc82 | |||
| cc40f93ac8 | |||
| 911003987b | |||
| 5a425f598b | |||
| b8a23e6be8 | |||
| e8ca5e5169 | |||
| 858d67c154 | |||
| fc43022c95 | |||
| abe9ccfe4b | |||
| 88fa5851f4 | |||
| a0c62dd4b8 | |||
| 53ff8bab17 | |||
| aadcbb1690 | |||
| 0786e37ed6 | |||
| a0161d69a8 | |||
| f70a45ad3a | |||
| 558f6fc090 | |||
| e734ab3f95 | |||
| 209ad3171d | |||
| fb79282a5b | |||
| e205905d02 |
@@ -16,6 +16,7 @@
|
||||
.ccmalloc
|
||||
.svn
|
||||
/.git
|
||||
cscope.files
|
||||
cscope.out
|
||||
tags
|
||||
/src/y.tab.c
|
||||
|
||||
@@ -14,5 +14,7 @@ addons:
|
||||
packages:
|
||||
- gperf
|
||||
|
||||
env:
|
||||
MRUBY_CONFIG=travis_config.rb
|
||||
env: MRUBY_CONFIG=travis_config.rb
|
||||
script: "./minirake all test"
|
||||
|
||||
@@ -35,3 +35,6 @@ Original Authors "mruby developers" are:
|
||||
Terence Lee
|
||||
Zachary Scott
|
||||
Tomasz Dąbrowski
|
||||
Christopher Aue
|
||||
Masahiro Wakame
|
||||
YAMAMOTO Masaya
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017 mruby developers
|
||||
Copyright (c) 2018 mruby developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
||||
@@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan.
|
||||
|
||||
## How to get mruby
|
||||
|
||||
The stable version 1.3.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.3.0.zip](https://github.com/mruby/mruby/archive/1.3.0.zip)
|
||||
The stable version 1.4.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.4.0.zip](https://github.com/mruby/mruby/archive/1.4.0.zip)
|
||||
|
||||
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
|
||||
|
||||
|
||||
@@ -5,10 +5,12 @@ MRUBY_ROOT = File.dirname(File.expand_path(__FILE__))
|
||||
MRUBY_BUILD_HOST_IS_CYGWIN = RUBY_PLATFORM.include?('cygwin')
|
||||
MRUBY_BUILD_HOST_IS_OPENBSD = RUBY_PLATFORM.include?('openbsd')
|
||||
|
||||
$LOAD_PATH << File.join(MRUBY_ROOT, "lib")
|
||||
|
||||
# load build systems
|
||||
load "#{MRUBY_ROOT}/tasks/ruby_ext.rake"
|
||||
load "#{MRUBY_ROOT}/tasks/mruby_build.rake"
|
||||
load "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"
|
||||
require "mruby-core-ext"
|
||||
require "mruby/build"
|
||||
require "mruby/gem"
|
||||
|
||||
# load configuration file
|
||||
MRUBY_CONFIG = (ENV['MRUBY_CONFIG'] && ENV['MRUBY_CONFIG'] != '') ? ENV['MRUBY_CONFIG'] : "#{MRUBY_ROOT}/build_config.rb"
|
||||
|
||||
+14
-3
@@ -5,6 +5,10 @@ os: Visual Studio 2015
|
||||
clone_depth: 50
|
||||
|
||||
|
||||
cache:
|
||||
- win_flex_bison-2.5.10.zip
|
||||
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
# Visual Studio 2015 64bit
|
||||
@@ -18,10 +22,17 @@ environment:
|
||||
|
||||
init:
|
||||
- call "%visualcpp%" %machine%
|
||||
# For using bison.exe
|
||||
- set PATH=%PATH%;C:\cygwin\bin;
|
||||
# For using Rubyinstaller's Ruby 2.4 64bit
|
||||
- set PATH=C:\Ruby24-x64\bin;%PATH%
|
||||
- ruby --version
|
||||
|
||||
|
||||
install:
|
||||
- if not exist win_flex_bison-2.5.10.zip appveyor DownloadFile "https://github.com/lexxmark/winflexbison/releases/download/v.2.5.10/win_flex_bison-2.5.10.zip"
|
||||
- 7z x -y -owin_flex_bison win_flex_bison-2.5.10.zip > nul
|
||||
|
||||
|
||||
build_script:
|
||||
- set YACC=.\win_flex_bison\win_bison.exe
|
||||
- set MRUBY_CONFIG=appveyor_config.rb
|
||||
- ruby .\minirake test
|
||||
- ruby .\minirake test all
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ MRuby::Build.new('debug') do |conf|
|
||||
# include all core GEMs
|
||||
conf.gembox 'full-core'
|
||||
conf.compilers.each do |c|
|
||||
c.defines += %w(MRB_GC_STRESS MRB_GC_FIXED_ARENA)
|
||||
c.defines += %w(MRB_GC_STRESS MRB_GC_FIXED_ARENA MRB_METHOD_CACHE)
|
||||
end
|
||||
|
||||
build_mrbc_exec
|
||||
|
||||
+15
-15
@@ -68,7 +68,7 @@ class Vec
|
||||
def vnormalize
|
||||
len = vlength
|
||||
v = Vec.new(@x, @y, @z)
|
||||
if len > 1.0e-17 then
|
||||
if len > 1.0e-17
|
||||
v.x = v.x / len
|
||||
v.y = v.y / len
|
||||
v.z = v.z / len
|
||||
@@ -92,10 +92,10 @@ class Sphere
|
||||
b = rs.vdot(ray.dir)
|
||||
c = rs.vdot(rs) - (@radius * @radius)
|
||||
d = b * b - c
|
||||
if d > 0.0 then
|
||||
if d > 0.0
|
||||
t = - b - Math.sqrt(d)
|
||||
|
||||
if t > 0.0 and t < isect.t then
|
||||
if t > 0.0 and t < isect.t
|
||||
isect.t = t
|
||||
isect.hit = true
|
||||
isect.pl = Vec.new(ray.org.x + ray.dir.x * t,
|
||||
@@ -118,16 +118,16 @@ class Plane
|
||||
d = -@p.vdot(@n)
|
||||
v = ray.dir.vdot(@n)
|
||||
v0 = v
|
||||
if v < 0.0 then
|
||||
if v < 0.0
|
||||
v0 = -v
|
||||
end
|
||||
if v0 < 1.0e-17 then
|
||||
if v0 < 1.0e-17
|
||||
return
|
||||
end
|
||||
|
||||
t = -(ray.org.vdot(@n) + d) / v
|
||||
|
||||
if t > 0.0 and t < isect.t then
|
||||
if t > 0.0 and t < isect.t
|
||||
isect.hit = true
|
||||
isect.t = t
|
||||
isect.n = @n
|
||||
@@ -170,10 +170,10 @@ end
|
||||
|
||||
def clamp(f)
|
||||
i = f * 255.5
|
||||
if i > 255.0 then
|
||||
if i > 255.0
|
||||
i = 255.0
|
||||
end
|
||||
if i < 0.0 then
|
||||
if i < 0.0
|
||||
i = 0.0
|
||||
end
|
||||
i.to_i
|
||||
@@ -183,11 +183,11 @@ def otherBasis(basis, n)
|
||||
basis[2] = Vec.new(n.x, n.y, n.z)
|
||||
basis[1] = Vec.new(0.0, 0.0, 0.0)
|
||||
|
||||
if n.x < 0.6 and n.x > -0.6 then
|
||||
if n.x < 0.6 and n.x > -0.6
|
||||
basis[1].x = 1.0
|
||||
elsif n.y < 0.6 and n.y > -0.6 then
|
||||
elsif n.y < 0.6 and n.y > -0.6
|
||||
basis[1].y = 1.0
|
||||
elsif n.z < 0.6 and n.z > -0.6 then
|
||||
elsif n.z < 0.6 and n.z > -0.6
|
||||
basis[1].z = 1.0
|
||||
else
|
||||
basis[1].x = 1.0
|
||||
@@ -221,8 +221,8 @@ class Scene
|
||||
p0 = Vec.new(isect.pl.x + eps * isect.n.x,
|
||||
isect.pl.y + eps * isect.n.y,
|
||||
isect.pl.z + eps * isect.n.z)
|
||||
nphi.times do |j|
|
||||
ntheta.times do |i|
|
||||
nphi.times do
|
||||
ntheta.times do
|
||||
r = Rand::rand
|
||||
phi = 2.0 * 3.14159265 * Rand::rand
|
||||
x = Math.cos(phi) * Math.sqrt(1.0 - r)
|
||||
@@ -241,7 +241,7 @@ class Scene
|
||||
@spheres[1].intersect(ray, occisect)
|
||||
@spheres[2].intersect(ray, occisect)
|
||||
@plane.intersect(ray, occisect)
|
||||
if occisect.hit then
|
||||
if occisect.hit
|
||||
occlusion = occlusion + 1.0
|
||||
else
|
||||
0.0
|
||||
@@ -283,7 +283,7 @@ class Scene
|
||||
@spheres[1].intersect(ray, isect)
|
||||
@spheres[2].intersect(ray, isect)
|
||||
@plane.intersect(ray, isect)
|
||||
if isect.hit then
|
||||
if isect.hit
|
||||
col = ambient_occlusion(isect)
|
||||
rad.x = rad.x + col.x
|
||||
rad.y = rad.y + col.y
|
||||
|
||||
@@ -17,19 +17,19 @@ def test_lists()
|
||||
# li2 must now be empty
|
||||
# remove each individual item from right side of li3 and
|
||||
# append to right side of li2 (reversing list)
|
||||
while (not li3.empty?)
|
||||
until li3.empty?
|
||||
li2.push(li3.pop)
|
||||
end
|
||||
# li3 must now be empty
|
||||
# reverse li1 in place
|
||||
li1.reverse!
|
||||
# check that first item is now SIZE
|
||||
if li1[0] != SIZE then
|
||||
if li1[0] != SIZE
|
||||
p "not SIZE"
|
||||
0
|
||||
else
|
||||
# compare li1 and li2 for equality
|
||||
if li1 != li2 then
|
||||
if li1 != li2
|
||||
return(0)
|
||||
else
|
||||
# return the length of the list
|
||||
|
||||
+11
-12
@@ -124,17 +124,17 @@ MRuby::Build.new('test') do |conf|
|
||||
conf.gembox 'default'
|
||||
end
|
||||
|
||||
MRuby::Build.new('bench') do |conf|
|
||||
# Gets set by the VS command prompts.
|
||||
if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
|
||||
toolchain :visualcpp
|
||||
else
|
||||
toolchain :gcc
|
||||
conf.cc.flags << '-O3'
|
||||
end
|
||||
|
||||
conf.gembox 'default'
|
||||
end
|
||||
#MRuby::Build.new('bench') do |conf|
|
||||
# # Gets set by the VS command prompts.
|
||||
# if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
|
||||
# toolchain :visualcpp
|
||||
# else
|
||||
# toolchain :gcc
|
||||
# conf.cc.flags << '-O3'
|
||||
# end
|
||||
#
|
||||
# conf.gembox 'default'
|
||||
#end
|
||||
|
||||
# Define cross build settings
|
||||
# MRuby::CrossBuild.new('32bit') do |conf|
|
||||
@@ -148,5 +148,4 @@ end
|
||||
# conf.gem 'examples/mrbgems/c_and_ruby_extension_example'
|
||||
#
|
||||
# conf.test_runner.command = 'env'
|
||||
#
|
||||
# end
|
||||
|
||||
@@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
|
||||
|
||||
```bash
|
||||
$ mrdb --version
|
||||
mruby 1.3.0 (2017-7-4)
|
||||
mruby 1.4.0 (2018-1-16)
|
||||
```
|
||||
|
||||
## 2.2 Basic Operation
|
||||
|
||||
@@ -114,14 +114,14 @@ inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
|
||||
|
||||
mrb_ary_push(mrb, list, ary);
|
||||
|
||||
arystr = mrb_str_buf_new(mrb, 64);
|
||||
mrb_str_buf_cat(mrb, arystr, head, sizeof(head));
|
||||
arystr = mrb_str_new_capa(mrb, 64);
|
||||
mrb_str_cat(mrb, arystr, head, sizeof(head));
|
||||
|
||||
for(i=0; i<RARRAY_LEN(ary); i++) {
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
|
||||
if (i > 0) {
|
||||
mrb_str_buf_cat(mrb, arystr, sep, sizeof(sep));
|
||||
mrb_str_cat(mrb, arystr, sep, sizeof(sep));
|
||||
}
|
||||
if (mrb_array_p(RARRAY_PTR(ary)[i])) {
|
||||
s = inspect_ary(mrb, RARRAY_PTR(ary)[i], list);
|
||||
@@ -129,11 +129,11 @@ inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
|
||||
else {
|
||||
s = mrb_inspect(mrb, RARRAY_PTR(ary)[i]);
|
||||
}
|
||||
mrb_str_buf_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s));
|
||||
mrb_str_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s));
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
|
||||
mrb_str_buf_cat(mrb, arystr, tail, sizeof(tail));
|
||||
mrb_str_cat(mrb, arystr, tail, sizeof(tail));
|
||||
mrb_ary_pop(mrb, list);
|
||||
|
||||
return arystr;
|
||||
|
||||
+1
-12
@@ -122,20 +122,9 @@ largest value of required alignment.
|
||||
* If defined `Float` will be a mruby object with `RBasic`.
|
||||
|
||||
## Instance variable configuration.
|
||||
`MRB_USE_IV_SEGLIST`
|
||||
* If defined enable segmented list in instance variable table instead of khash.
|
||||
* Segmented list is a linked list of key and value segments.
|
||||
* It will linear search instead of hash search.
|
||||
|
||||
`MRB_SEGMENT_SIZE`
|
||||
`MRB_IV_SEGMENT_SIZE`
|
||||
* Default value is `4`.
|
||||
* Specifies size of each segment in segment list.
|
||||
* Ignored when `MRB_USE_IV_SEGLIST` isn't defined.
|
||||
|
||||
`MRB_IVHASH_INIT_SIZE`
|
||||
* Default value is `8`.
|
||||
* Specifies initial size for instance variable table.
|
||||
* Ignored when `MRB_USE_IV_SEGLIST` is defined.
|
||||
|
||||
## Other configuration.
|
||||
`MRB_UTF8_STRING`
|
||||
|
||||
+7
-28
@@ -38,7 +38,7 @@ puts [1,2,3]
|
||||
3
|
||||
```
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
```
|
||||
[1, 2, 3]
|
||||
@@ -61,26 +61,10 @@ end
|
||||
|
||||
```ZeroDivisionError``` is raised.
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
No exception is raised.
|
||||
|
||||
## Check of infinite recursion
|
||||
|
||||
mruby does not check infinite recursion across C extensions.
|
||||
|
||||
```ruby
|
||||
def test; eval 'test'; end; test
|
||||
```
|
||||
|
||||
#### Ruby [ruby 2.0.0p645 (2015-04-13 revision 50299)]
|
||||
|
||||
```SystemStackError``` is raised.
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
|
||||
Segmentation fault.
|
||||
|
||||
## Fiber execution can't cross C function boundary
|
||||
|
||||
mruby's ```Fiber``` is implemented in a similar way to Lua's co-routine. This
|
||||
@@ -105,7 +89,7 @@ p Liste.new "foobar"
|
||||
|
||||
``` [] ```
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
```ArgumentError``` is raised.
|
||||
|
||||
@@ -135,7 +119,7 @@ false
|
||||
true
|
||||
```
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
```
|
||||
true
|
||||
@@ -158,7 +142,7 @@ defined?(Foo)
|
||||
nil
|
||||
```
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
```NameError``` is raised.
|
||||
|
||||
@@ -175,7 +159,7 @@ alias $a $__a__
|
||||
|
||||
``` nil ```
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
Syntax error
|
||||
|
||||
@@ -197,12 +181,7 @@ end
|
||||
```ArgumentError``` is raised.
|
||||
The re-defined ```+``` operator does not accept any arguments.
|
||||
|
||||
#### mruby [1.3.0 (2017-7-4)]
|
||||
#### mruby [1.4.0 (2018-1-16)]
|
||||
|
||||
``` 'ab' ```
|
||||
Behavior of the operator wasn't changed.
|
||||
|
||||
## ```Kernel.binding``` missing
|
||||
|
||||
```Kernel.binding``` is not implemented as it is not in the
|
||||
ISO standard.
|
||||
|
||||
@@ -46,7 +46,6 @@ MRuby::CrossBuild.new("ArduinoDue") do |conf|
|
||||
|
||||
#configuration for low memory environment
|
||||
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
|
||||
cc.defines << %w(MRB_USE_IV_SEGLIST)
|
||||
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
|
||||
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
|
||||
cc.defines << %w(MRB_GC_STRESS)
|
||||
|
||||
@@ -32,7 +32,6 @@ MRuby::CrossBuild.new("RX630") do |conf|
|
||||
#configuration for low memory environment
|
||||
cc.defines << %w(MRB_USE_FLOAT)
|
||||
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
|
||||
cc.defines << %w(MRB_USE_IV_SEGLIST)
|
||||
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
|
||||
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
|
||||
cc.defines << %w(MRB_GC_STRESS)
|
||||
|
||||
@@ -43,7 +43,6 @@ MRuby::CrossBuild.new("chipKITMax32") do |conf|
|
||||
|
||||
#configuration for low memory environment
|
||||
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
|
||||
cc.defines << %w(MRB_USE_IV_SEGLIST)
|
||||
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
|
||||
cc.defines << %w(MRB_STR_BUF_MIN_SIZE=20)
|
||||
cc.defines << %w(MRB_GC_STRESS)
|
||||
|
||||
+29
-9
@@ -28,13 +28,39 @@
|
||||
/* add -DMRB_USE_FLOAT to use float instead of double for floating point numbers */
|
||||
//#define MRB_USE_FLOAT
|
||||
|
||||
/* exclude floating point numbers */
|
||||
//#define MRB_WITHOUT_FLOAT
|
||||
|
||||
/* add -DMRB_METHOD_CACHE to use method cache to improve performance */
|
||||
//#define MRB_METHOD_CACHE
|
||||
/* size of the method cache (need to be the power of 2) */
|
||||
//#define MRB_METHOD_CACHE_SIZE (1<<7)
|
||||
|
||||
/* add -DMRB_METHOD_TABLE_INLINE unless platform uses MSB of pointers */
|
||||
//#define MRB_METHOD_TABLE_INLINE
|
||||
/* turn MRB_METHOD_TABLE_INLINE on for linux by default */
|
||||
#if !defined(MRB_METHOD_TABLE_INLINE) && defined(__linux__)
|
||||
# define MRB_METHOD_TABLE_INLINE
|
||||
#endif
|
||||
|
||||
/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */
|
||||
//#define MRB_INT16
|
||||
|
||||
/* add -DMRB_INT64 to use 64bit integer for mrb_int; conflict with MRB_INT16 */
|
||||
//#define MRB_INT64
|
||||
|
||||
/* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT */
|
||||
/* if no specific integer type is chosen */
|
||||
#if !defined(MRB_INT16) && !defined(MRB_INT32) && !defined(MRB_INT64)
|
||||
# if defined(MRB_64BIT) && !defined(MRB_NAN_BOXING)
|
||||
/* Use 64bit integers on 64bit architecture (without MRB_NAN_BOXING) */
|
||||
# define MRB_INT64
|
||||
# else
|
||||
/* Otherwise use 32bit integers */
|
||||
# define MRB_INT32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* represent mrb_value in boxed double; conflict with MRB_USE_FLOAT and MRB_WITHOUT_FLOAT */
|
||||
//#define MRB_NAN_BOXING
|
||||
|
||||
/* define on big endian machines; used by MRB_NAN_BOXING */
|
||||
@@ -52,12 +78,6 @@
|
||||
/* number of object per heap page */
|
||||
//#define MRB_HEAP_PAGE_SIZE 1024
|
||||
|
||||
/* use segmented list for IV table */
|
||||
//#define MRB_USE_IV_SEGLIST
|
||||
|
||||
/* initial size for IV khash; ignored when MRB_USE_IV_SEGLIST is set */
|
||||
//#define MRB_IVHASH_INIT_SIZE 8
|
||||
|
||||
/* if _etext and _edata available, mruby can reduce memory used by symbols */
|
||||
//#define MRB_USE_ETEXT_EDATA
|
||||
|
||||
@@ -93,10 +113,10 @@
|
||||
//#define MRB_FIXED_STATE_ATEXIT_STACK
|
||||
|
||||
/* -DMRB_DISABLE_XXXX to drop following features */
|
||||
//#define MRB_DISABLE_STDIO /* use of stdio */
|
||||
//#define MRB_DISABLE_STDIO /* use of stdio */
|
||||
|
||||
/* -DMRB_ENABLE_XXXX to enable following features */
|
||||
//#define MRB_ENABLE_DEBUG_HOOK /* hooks for debugger */
|
||||
//#define MRB_ENABLE_DEBUG_HOOK /* hooks for debugger */
|
||||
|
||||
/* end of configuration */
|
||||
|
||||
|
||||
+91
-21
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
** mruby - An embeddable Ruby implementation
|
||||
**
|
||||
** Copyright (c) mruby developers 2010-2017
|
||||
** Copyright (c) mruby developers 2010-2018
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining
|
||||
** a copy of this software and associated documentation files (the
|
||||
@@ -65,11 +65,23 @@
|
||||
|
||||
#include "mrbconf.h"
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#ifndef FLT_EPSILON
|
||||
#define FLT_EPSILON (1.19209290e-07f)
|
||||
#endif
|
||||
#ifndef DBL_EPSILON
|
||||
#define DBL_EPSILON ((double)2.22044604925031308085e-16L)
|
||||
#endif
|
||||
#ifndef LDBL_EPSILON
|
||||
#define LDBL_EPSILON (1.08420217248550443401e-19L)
|
||||
#endif
|
||||
|
||||
#ifdef MRB_USE_FLOAT
|
||||
#define MRB_FLOAT_EPSILON FLT_EPSILON
|
||||
#else
|
||||
#define MRB_FLOAT_EPSILON DBL_EPSILON
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "mruby/common.h"
|
||||
#include <mruby/value.h>
|
||||
@@ -150,6 +162,36 @@ struct mrb_context {
|
||||
struct RFiber *fib;
|
||||
};
|
||||
|
||||
#ifdef MRB_METHOD_CACHE_SIZE
|
||||
# define MRB_METHOD_CACHE
|
||||
#else
|
||||
/* default method cache size: 128 */
|
||||
/* cache size needs to be power of 2 */
|
||||
# define MRB_METHOD_CACHE_SIZE (1<<7)
|
||||
#endif
|
||||
|
||||
typedef mrb_value (*mrb_func_t)(struct mrb_state *mrb, mrb_value);
|
||||
|
||||
#ifdef MRB_METHOD_TABLE_INLINE
|
||||
typedef uintptr_t mrb_method_t;
|
||||
#else
|
||||
typedef struct {
|
||||
mrb_bool func_p;
|
||||
union {
|
||||
struct RProc *proc;
|
||||
mrb_func_t func;
|
||||
};
|
||||
} mrb_method_t;
|
||||
#endif
|
||||
|
||||
#ifdef MRB_METHOD_CACHE
|
||||
struct mrb_cache_entry {
|
||||
struct RClass *c, *c0;
|
||||
mrb_sym mid;
|
||||
mrb_method_t m;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mrb_jmpbuf;
|
||||
|
||||
typedef void (*mrb_atexit_func)(struct mrb_state*);
|
||||
@@ -178,8 +220,11 @@ typedef struct mrb_state {
|
||||
struct RClass *string_class;
|
||||
struct RClass *array_class;
|
||||
struct RClass *hash_class;
|
||||
struct RClass *range_class;
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
struct RClass *float_class;
|
||||
#endif
|
||||
struct RClass *fixnum_class;
|
||||
struct RClass *true_class;
|
||||
struct RClass *false_class;
|
||||
@@ -190,6 +235,10 @@ typedef struct mrb_state {
|
||||
struct alloca_header *mems;
|
||||
mrb_gc gc;
|
||||
|
||||
#ifdef MRB_METHOD_CACHE
|
||||
struct mrb_cache_entry cache[MRB_METHOD_CACHE_SIZE];
|
||||
#endif
|
||||
|
||||
mrb_sym symidx;
|
||||
struct kh_n2s *name2sym; /* symbol hash */
|
||||
struct symbol_name *symtbl; /* symbol table */
|
||||
@@ -222,9 +271,6 @@ typedef struct mrb_state {
|
||||
mrb_int atexit_stack_len;
|
||||
} mrb_state;
|
||||
|
||||
|
||||
typedef mrb_value (*mrb_func_t)(mrb_state *mrb, mrb_value);
|
||||
|
||||
/**
|
||||
* Defines a new class.
|
||||
*
|
||||
@@ -827,11 +873,14 @@ mrb_get_mid(mrb_state *mrb) /* get method symbol */
|
||||
return mrb->c->ci->mid;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mrb_get_argc(mrb_state *mrb) /* get argc */
|
||||
{
|
||||
return mrb->c->ci->argc;
|
||||
}
|
||||
/**
|
||||
* Retrieve number of arguments from mrb_state.
|
||||
*
|
||||
* Correctly handles *splat arguments.
|
||||
*/
|
||||
MRB_API mrb_int mrb_get_argc(mrb_state *mrb);
|
||||
|
||||
MRB_API mrb_value* mrb_get_argv(mrb_state *mrb);
|
||||
|
||||
/* `strlen` for character string literals (use with caution or `strlen` instead)
|
||||
Adjacent string literals are concatenated in C/C++ in translation phase 6.
|
||||
@@ -945,13 +994,13 @@ MRB_API mrb_value mrb_str_new_static(mrb_state *mrb, const char *p, size_t len);
|
||||
#define mrb_str_new_lit(mrb, lit) mrb_str_new_static(mrb, (lit), mrb_strlen_lit(lit))
|
||||
|
||||
#ifdef _WIN32
|
||||
char* mrb_utf8_from_locale(const char *p, size_t len);
|
||||
char* mrb_locale_from_utf8(const char *p, size_t len);
|
||||
char* mrb_utf8_from_locale(const char *p, int len);
|
||||
char* mrb_locale_from_utf8(const char *p, int len);
|
||||
#define mrb_locale_free(p) free(p)
|
||||
#define mrb_utf8_free(p) free(p)
|
||||
#else
|
||||
#define mrb_utf8_from_locale(p, l) (p)
|
||||
#define mrb_locale_from_utf8(p, l) (p)
|
||||
#define mrb_utf8_from_locale(p, l) ((char*)p)
|
||||
#define mrb_locale_from_utf8(p, l) ((char*)p)
|
||||
#define mrb_locale_free(p)
|
||||
#define mrb_utf8_free(p)
|
||||
#endif
|
||||
@@ -1023,17 +1072,35 @@ MRB_API mrb_sym mrb_obj_to_sym(mrb_state *mrb, mrb_value name);
|
||||
MRB_API mrb_bool mrb_obj_eq(mrb_state*, mrb_value, mrb_value);
|
||||
MRB_API mrb_bool mrb_obj_equal(mrb_state*, mrb_value, mrb_value);
|
||||
MRB_API mrb_bool mrb_equal(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
|
||||
MRB_API mrb_value mrb_convert_to_integer(mrb_state *mrb, mrb_value val, int base);
|
||||
MRB_API mrb_value mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base);
|
||||
MRB_API mrb_value mrb_Integer(mrb_state *mrb, mrb_value val);
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
MRB_API mrb_value mrb_Float(mrb_state *mrb, mrb_value val);
|
||||
#endif
|
||||
MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj);
|
||||
MRB_API mrb_bool mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2);
|
||||
|
||||
static inline int mrb_gc_arena_save(mrb_state*);
|
||||
static inline void mrb_gc_arena_restore(mrb_state*,int);
|
||||
|
||||
static inline int
|
||||
mrb_gc_arena_save(mrb_state *mrb)
|
||||
{
|
||||
return mrb->gc.arena_idx;
|
||||
}
|
||||
|
||||
static inline void
|
||||
mrb_gc_arena_restore(mrb_state *mrb, int idx)
|
||||
{
|
||||
mrb->gc.arena_idx = idx;
|
||||
}
|
||||
|
||||
MRB_API int mrb_gc_arena_save(mrb_state*);
|
||||
MRB_API void mrb_gc_arena_restore(mrb_state*,int);
|
||||
|
||||
MRB_API void mrb_garbage_collect(mrb_state*);
|
||||
MRB_API void mrb_full_gc(mrb_state*);
|
||||
MRB_API void mrb_incremental_gc(mrb_state *);
|
||||
MRB_API int mrb_gc_arena_save(mrb_state*);
|
||||
MRB_API void mrb_gc_arena_restore(mrb_state*,int);
|
||||
MRB_API void mrb_gc_mark(mrb_state*,struct RBasic*);
|
||||
#define mrb_gc_mark_value(mrb,val) do {\
|
||||
if (!mrb_immediate_p(val)) mrb_gc_mark((mrb), mrb_basic_ptr(val)); \
|
||||
@@ -1097,9 +1164,12 @@ MRB_API void mrb_print_error(mrb_state *mrb);
|
||||
#define E_SYNTAX_ERROR (mrb_exc_get(mrb, "SyntaxError"))
|
||||
#define E_LOCALJUMP_ERROR (mrb_exc_get(mrb, "LocalJumpError"))
|
||||
#define E_REGEXP_ERROR (mrb_exc_get(mrb, "RegexpError"))
|
||||
#define E_FROZEN_ERROR (mrb_exc_get(mrb, "FrozenError"))
|
||||
|
||||
#define E_NOTIMP_ERROR (mrb_exc_get(mrb, "NotImplementedError"))
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define E_FLOATDOMAIN_ERROR (mrb_exc_get(mrb, "FloatDomainError"))
|
||||
#endif
|
||||
|
||||
#define E_KEY_ERROR (mrb_exc_get(mrb, "KeyError"))
|
||||
|
||||
@@ -1183,21 +1253,21 @@ MRB_API mrb_value mrb_format(mrb_state *mrb, const char *format, ...);
|
||||
/* use naive memcpy and memset instead */
|
||||
#undef memcpy
|
||||
#undef memset
|
||||
static inline void*
|
||||
static void*
|
||||
mrbmemcpy(void *dst, const void *src, size_t n)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
char *d = (char*)dst;
|
||||
const char *s = (const char*)src;
|
||||
while (n--)
|
||||
*d++ = *s++;
|
||||
return d;
|
||||
}
|
||||
#define memcpy(a,b,c) mrbmemcpy(a,b,c)
|
||||
|
||||
static inline void*
|
||||
static void*
|
||||
mrbmemset(void *s, int c, size_t n)
|
||||
{
|
||||
char *t = s;
|
||||
char *t = (char*)s;
|
||||
while (n--)
|
||||
*t++ = c;
|
||||
return s;
|
||||
|
||||
+44
-26
@@ -21,22 +21,46 @@ typedef struct mrb_shared_array {
|
||||
mrb_value *ptr;
|
||||
} mrb_shared_array;
|
||||
|
||||
#define MRB_ARY_EMBED_LEN_MAX ((mrb_int)(sizeof(void*)*3/sizeof(mrb_value)))
|
||||
struct RArray {
|
||||
MRB_OBJECT_HEADER;
|
||||
mrb_int len;
|
||||
union {
|
||||
mrb_int capa;
|
||||
mrb_shared_array *shared;
|
||||
} aux;
|
||||
mrb_value *ptr;
|
||||
struct {
|
||||
mrb_int len;
|
||||
union {
|
||||
mrb_int capa;
|
||||
mrb_shared_array *shared;
|
||||
} aux;
|
||||
mrb_value *ptr;
|
||||
} heap;
|
||||
mrb_value embed[MRB_ARY_EMBED_LEN_MAX];
|
||||
} as;
|
||||
};
|
||||
|
||||
#define mrb_ary_ptr(v) ((struct RArray*)(mrb_ptr(v)))
|
||||
#define mrb_ary_value(p) mrb_obj_value((void*)(p))
|
||||
#define RARRAY(v) ((struct RArray*)(mrb_ptr(v)))
|
||||
|
||||
#define RARRAY_LEN(a) (RARRAY(a)->len)
|
||||
#define RARRAY_PTR(a) ((const mrb_value*)RARRAY(a)->ptr)
|
||||
#define MRB_ARY_EMBED_MASK 7
|
||||
#define ARY_EMBED_P(a) ((a)->flags & MRB_ARY_EMBED_MASK)
|
||||
#define ARY_UNSET_EMBED_FLAG(a) ((a)->flags &= ~(MRB_ARY_EMBED_MASK))
|
||||
#define ARY_EMBED_LEN(a) ((mrb_int)(((a)->flags & MRB_ARY_EMBED_MASK) - 1))
|
||||
#define ARY_SET_EMBED_LEN(a,len) ((a)->flags = ((a)->flags&~MRB_ARY_EMBED_MASK) | ((uint32_t)(len) + 1))
|
||||
#define ARY_EMBED_PTR(a) (&((a)->as.embed[0]))
|
||||
|
||||
#define ARY_LEN(a) (ARY_EMBED_P(a)?ARY_EMBED_LEN(a):(a)->as.heap.len)
|
||||
#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
|
||||
#define RARRAY_LEN(a) ARY_LEN(RARRAY(a))
|
||||
#define RARRAY_PTR(a) ARY_PTR(RARRAY(a))
|
||||
#define ARY_SET_LEN(a,n) do {\
|
||||
if (ARY_EMBED_P(a)) {\
|
||||
mrb_assert((n) <= MRB_ARY_EMBED_LEN_MAX); \
|
||||
ARY_SET_EMBED_LEN(a,n);\
|
||||
}\
|
||||
else\
|
||||
(a)->as.heap.len = (n);\
|
||||
} while (0)
|
||||
#define ARY_CAPA(a) (ARY_EMBED_P(a)?MRB_ARY_EMBED_LEN_MAX:(a)->as.heap.aux.capa)
|
||||
#define MRB_ARY_SHARED 256
|
||||
#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED)
|
||||
#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED)
|
||||
@@ -178,7 +202,7 @@ MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other);
|
||||
MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self);
|
||||
|
||||
/*
|
||||
* Unshift an element into an array
|
||||
* Unshift an element into the array
|
||||
*
|
||||
* Equivalent to:
|
||||
*
|
||||
@@ -189,6 +213,17 @@ MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self);
|
||||
* @param item The item to unshift.
|
||||
*/
|
||||
MRB_API mrb_value mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item);
|
||||
|
||||
/*
|
||||
* Get nth element in the array
|
||||
*
|
||||
* Equivalent to:
|
||||
*
|
||||
* ary[offset]
|
||||
*
|
||||
* @param ary The target array.
|
||||
* @param offset The element position (negative counts from the tail).
|
||||
*/
|
||||
MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset);
|
||||
|
||||
/*
|
||||
@@ -205,7 +240,7 @@ MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset);
|
||||
MRB_API mrb_value mrb_ary_shift(mrb_state *mrb, mrb_value self);
|
||||
|
||||
/*
|
||||
* Removes all elements from this array
|
||||
* Removes all elements from the array
|
||||
*
|
||||
* Equivalent to:
|
||||
*
|
||||
@@ -239,23 +274,6 @@ MRB_API mrb_value mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep);
|
||||
*/
|
||||
MRB_API mrb_value mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len);
|
||||
|
||||
static inline mrb_int
|
||||
mrb_ary_len(mrb_state *mrb, mrb_value ary)
|
||||
{
|
||||
(void)mrb;
|
||||
mrb_assert(mrb_array_p(ary));
|
||||
return RARRAY_LEN(ary);
|
||||
}
|
||||
|
||||
static inline mrb_value
|
||||
ary_elt(mrb_value ary, mrb_int offset)
|
||||
{
|
||||
if (offset < 0 || RARRAY_LEN(ary) <= offset) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
return RARRAY_PTR(ary)[offset];
|
||||
}
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
#endif /* MRUBY_ARRAY_H */
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
# error ---->> MRB_NAN_BOXING and MRB_USE_FLOAT conflict <<----
|
||||
#endif
|
||||
|
||||
#ifdef MRB_WITHOUT_FLOAT
|
||||
# error ---->> MRB_NAN_BOXING and MRB_WITHOUT_FLOAT conflict <<----
|
||||
#endif
|
||||
|
||||
#ifdef MRB_INT64
|
||||
# error ---->> MRB_NAN_BOXING and MRB_INT64 conflict <<----
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
typedef struct mrb_value {
|
||||
union {
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
mrb_float f;
|
||||
#endif
|
||||
void *p;
|
||||
mrb_int i;
|
||||
mrb_sym sym;
|
||||
@@ -20,11 +22,15 @@ typedef struct mrb_value {
|
||||
enum mrb_vtype tt;
|
||||
} mrb_value;
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f)
|
||||
#endif
|
||||
|
||||
#define mrb_ptr(o) (o).value.p
|
||||
#define mrb_cptr(o) mrb_ptr(o)
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define mrb_float(o) (o).value.f
|
||||
#endif
|
||||
#define mrb_fixnum(o) (o).value.i
|
||||
#define mrb_symbol(o) (o).value.sym
|
||||
#define mrb_type(o) (o).tt
|
||||
@@ -39,7 +45,9 @@ typedef struct mrb_value {
|
||||
#define SET_TRUE_VALUE(r) BOXNIX_SET_VALUE(r, MRB_TT_TRUE, value.i, 1)
|
||||
#define SET_BOOL_VALUE(r,b) BOXNIX_SET_VALUE(r, b ? MRB_TT_TRUE : MRB_TT_FALSE, value.i, 1)
|
||||
#define SET_INT_VALUE(r,n) BOXNIX_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n))
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define SET_FLOAT_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_FLOAT, value.f, (v))
|
||||
#endif
|
||||
#define SET_SYM_VALUE(r,v) BOXNIX_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v))
|
||||
#define SET_OBJ_VALUE(r,v) BOXNIX_SET_VALUE(r, (((struct RObject*)(v))->tt), value.p, (v))
|
||||
#define SET_CPTR_VALUE(mrb,r,v) BOXNIX_SET_VALUE(r, MRB_TT_CPTR, value.p, v)
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
#error MRB_INT64 cannot be used with MRB_WORD_BOXING in 32-bit mode.
|
||||
#endif
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
struct RFloat {
|
||||
MRB_OBJECT_HEADER;
|
||||
mrb_float f;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct RCptr {
|
||||
MRB_OBJECT_HEADER;
|
||||
@@ -26,7 +28,11 @@ struct RCptr {
|
||||
};
|
||||
|
||||
#define MRB_FIXNUM_SHIFT 1
|
||||
#ifdef MRB_WITHOUT_FLOAT
|
||||
#define MRB_TT_HAS_BASIC MRB_TT_CPTR
|
||||
#else
|
||||
#define MRB_TT_HAS_BASIC MRB_TT_FLOAT
|
||||
#endif
|
||||
|
||||
enum mrb_special_consts {
|
||||
MRB_Qnil = 0,
|
||||
@@ -51,21 +57,29 @@ typedef union mrb_value {
|
||||
mrb_sym sym : (sizeof(mrb_sym) * CHAR_BIT);
|
||||
};
|
||||
struct RBasic *bp;
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
struct RFloat *fp;
|
||||
#endif
|
||||
struct RCptr *vp;
|
||||
} value;
|
||||
unsigned long w;
|
||||
} mrb_value;
|
||||
|
||||
MRB_API mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*);
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
MRB_API mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float);
|
||||
MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float);
|
||||
#endif
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define mrb_float_pool(mrb,f) mrb_word_boxing_float_pool(mrb,f)
|
||||
#endif
|
||||
|
||||
#define mrb_ptr(o) (o).value.p
|
||||
#define mrb_cptr(o) (o).value.vp->p
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define mrb_float(o) (o).value.fp->f
|
||||
#endif
|
||||
#define mrb_fixnum(o) ((mrb_int)(o).value.i)
|
||||
#define mrb_symbol(o) (o).value.sym
|
||||
|
||||
@@ -106,7 +120,9 @@ mrb_type(mrb_value o)
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define SET_FLOAT_VALUE(mrb,r,v) r = mrb_word_boxing_float_value(mrb, v)
|
||||
#endif
|
||||
#define SET_CPTR_VALUE(mrb,r,v) r = mrb_word_boxing_cptr_value(mrb, v)
|
||||
#define SET_NIL_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 0)
|
||||
#define SET_FALSE_VALUE(r) BOXWORD_SET_VALUE(r, MRB_TT_FALSE, value.i, 1)
|
||||
|
||||
@@ -40,8 +40,10 @@ mrb_class(mrb_state *mrb, mrb_value v)
|
||||
return mrb->symbol_class;
|
||||
case MRB_TT_FIXNUM:
|
||||
return mrb->fixnum_class;
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
case MRB_TT_FLOAT:
|
||||
return mrb->float_class;
|
||||
#endif
|
||||
case MRB_TT_CPTR:
|
||||
return mrb->object_class;
|
||||
case MRB_TT_ENV:
|
||||
@@ -52,7 +54,7 @@ mrb_class(mrb_state *mrb, mrb_value v)
|
||||
}
|
||||
|
||||
/* TODO: figure out where to put user flags */
|
||||
#define MRB_FLAG_IS_FROZEN (1 << 18)
|
||||
/* flags bits >= 18 is reserved */
|
||||
#define MRB_FLAG_IS_PREPENDED (1 << 19)
|
||||
#define MRB_FLAG_IS_ORIGIN (1 << 20)
|
||||
#define MRB_CLASS_ORIGIN(c) do {\
|
||||
@@ -63,6 +65,7 @@ mrb_class(mrb_state *mrb, mrb_value v)
|
||||
}\
|
||||
}\
|
||||
} while (0)
|
||||
#define MRB_FLAG_IS_INHERITED (1 << 21)
|
||||
#define MRB_INSTANCE_TT_MASK (0xFF)
|
||||
#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt)
|
||||
#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK)
|
||||
@@ -71,16 +74,17 @@ MRB_API struct RClass* mrb_define_class_id(mrb_state*, mrb_sym, struct RClass*);
|
||||
MRB_API struct RClass* mrb_define_module_id(mrb_state*, mrb_sym);
|
||||
MRB_API struct RClass *mrb_vm_define_class(mrb_state*, mrb_value, mrb_value, mrb_sym);
|
||||
MRB_API struct RClass *mrb_vm_define_module(mrb_state*, mrb_value, mrb_sym);
|
||||
MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, struct RProc *);
|
||||
MRB_API void mrb_define_method_raw(mrb_state*, struct RClass*, mrb_sym, mrb_method_t);
|
||||
MRB_API void mrb_define_method_id(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_func_t func, mrb_aspec aspec);
|
||||
MRB_API void mrb_alias_method(mrb_state *mrb, struct RClass *c, mrb_sym a, mrb_sym b);
|
||||
|
||||
MRB_API struct RClass *mrb_class_outer_module(mrb_state*, struct RClass *);
|
||||
MRB_API struct RProc *mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
|
||||
MRB_API struct RProc *mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
|
||||
MRB_API mrb_method_t mrb_method_search_vm(mrb_state*, struct RClass**, mrb_sym);
|
||||
MRB_API mrb_method_t mrb_method_search(mrb_state*, struct RClass*, mrb_sym);
|
||||
|
||||
MRB_API struct RClass* mrb_class_real(struct RClass* cl);
|
||||
|
||||
void mrb_class_name_class(mrb_state*, struct RClass*, struct RClass*, mrb_sym);
|
||||
mrb_value mrb_class_find_path(mrb_state*, struct RClass*);
|
||||
void mrb_gc_mark_mt(mrb_state*, struct RClass*);
|
||||
size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*);
|
||||
void mrb_gc_free_mt(mrb_state*, struct RClass*);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#define MRB_END_DECL
|
||||
#else
|
||||
# define MRB_BEGIN_DECL extern "C" {
|
||||
# define MRB_END_DECL }
|
||||
# define MRB_END_DECL }
|
||||
#endif
|
||||
#else
|
||||
/** Start declarations in C mode */
|
||||
|
||||
@@ -33,6 +33,8 @@ typedef struct mrbc_context {
|
||||
mrb_bool no_exec:1;
|
||||
mrb_bool keep_lv:1;
|
||||
mrb_bool no_optimize:1;
|
||||
|
||||
size_t parser_nerr;
|
||||
} mrbc_context;
|
||||
|
||||
MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb);
|
||||
@@ -136,7 +138,7 @@ struct mrb_parser_state {
|
||||
int tidx;
|
||||
int tsiz;
|
||||
|
||||
mrb_ast_node *all_heredocs; /* list of mrb_parser_heredoc_info* */
|
||||
mrb_ast_node *all_heredocs; /* list of mrb_parser_heredoc_info* */
|
||||
mrb_ast_node *heredocs_from_nextline;
|
||||
mrb_ast_node *parsing_heredoc;
|
||||
mrb_ast_node *lex_strterm_before_heredoc;
|
||||
@@ -163,7 +165,6 @@ struct mrb_parser_state {
|
||||
MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*);
|
||||
MRB_API void mrb_parser_free(struct mrb_parser_state*);
|
||||
MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*);
|
||||
MRB_API double mrb_float_read(const char*, char**);
|
||||
|
||||
MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*);
|
||||
MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx);
|
||||
@@ -173,7 +174,7 @@ MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t i
|
||||
MRB_API struct mrb_parser_state* mrb_parse_file(mrb_state*,FILE*,mrbc_context*);
|
||||
#endif
|
||||
MRB_API struct mrb_parser_state* mrb_parse_string(mrb_state*,const char*,mrbc_context*);
|
||||
MRB_API struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,int,mrbc_context*);
|
||||
MRB_API struct mrb_parser_state* mrb_parse_nstring(mrb_state*,const char*,size_t,mrbc_context*);
|
||||
MRB_API struct RProc* mrb_generate_code(mrb_state*, struct mrb_parser_state*);
|
||||
MRB_API mrb_value mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c);
|
||||
|
||||
@@ -183,9 +184,9 @@ MRB_API mrb_value mrb_load_file(mrb_state*,FILE*);
|
||||
MRB_API mrb_value mrb_load_file_cxt(mrb_state*,FILE*, mrbc_context *cxt);
|
||||
#endif
|
||||
MRB_API mrb_value mrb_load_string(mrb_state *mrb, const char *s);
|
||||
MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, int len);
|
||||
MRB_API mrb_value mrb_load_nstring(mrb_state *mrb, const char *s, size_t len);
|
||||
MRB_API mrb_value mrb_load_string_cxt(mrb_state *mrb, const char *s, mrbc_context *cxt);
|
||||
MRB_API mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *cxt);
|
||||
MRB_API mrb_value mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *cxt);
|
||||
|
||||
/** @} */
|
||||
MRB_END_DECL
|
||||
|
||||
@@ -47,13 +47,13 @@ typedef struct mrb_irep_debug_info {
|
||||
* get line from irep's debug info and program counter
|
||||
* @return returns NULL if not found
|
||||
*/
|
||||
MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, uint32_t pc);
|
||||
MRB_API const char *mrb_debug_get_filename(mrb_irep *irep, ptrdiff_t pc);
|
||||
|
||||
/*
|
||||
* get line from irep's debug info and program counter
|
||||
* @return returns -1 if not found
|
||||
*/
|
||||
MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, uint32_t pc);
|
||||
MRB_API int32_t mrb_debug_get_line(mrb_irep *irep, ptrdiff_t pc);
|
||||
|
||||
MRB_API mrb_irep_debug_info_file *mrb_debug_info_append_file(
|
||||
mrb_state *mrb, mrb_irep *irep,
|
||||
|
||||
@@ -24,7 +24,7 @@ struct RException {
|
||||
MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg);
|
||||
MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
|
||||
#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
|
||||
MRB_API mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv);
|
||||
MRB_API mrb_value mrb_make_exception(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
|
||||
MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
|
||||
MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb);
|
||||
MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);
|
||||
@@ -34,7 +34,6 @@ MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value);
|
||||
|
||||
struct RBreak {
|
||||
MRB_OBJECT_HEADER;
|
||||
struct iv_tbl *iv;
|
||||
struct RProc *proc;
|
||||
mrb_value val;
|
||||
};
|
||||
|
||||
@@ -33,6 +33,13 @@ typedef enum {
|
||||
MRB_GC_STATE_SWEEP
|
||||
} mrb_gc_state;
|
||||
|
||||
/* Disable MSVC warning "C4200: nonstandard extension used: zero-sized array
|
||||
* in struct/union" when in C++ mode */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4200)
|
||||
#endif
|
||||
|
||||
typedef struct mrb_heap_page {
|
||||
struct RBasic *freelist;
|
||||
struct mrb_heap_page *prev;
|
||||
@@ -43,6 +50,10 @@ typedef struct mrb_heap_page {
|
||||
void *objects[];
|
||||
} mrb_heap_page;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
typedef struct mrb_gc {
|
||||
mrb_heap_page *heaps; /* heaps for GC */
|
||||
mrb_heap_page *sweeps;
|
||||
|
||||
@@ -44,7 +44,7 @@ typedef struct mrb_irep {
|
||||
uint16_t *lines;
|
||||
struct mrb_irep_debug_info* debug_info;
|
||||
|
||||
size_t ilen, plen, slen, rlen, refcnt;
|
||||
int ilen, plen, slen, rlen, refcnt;
|
||||
} mrb_irep;
|
||||
|
||||
#define MRB_ISEQ_NO_FREE 1
|
||||
@@ -55,6 +55,7 @@ MRB_API mrb_value mrb_load_irep_cxt(mrb_state*, const uint8_t*, mrbc_context*);
|
||||
void mrb_irep_free(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_incref(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_decref(mrb_state*, struct mrb_irep*);
|
||||
void mrb_irep_cutref(mrb_state*, struct mrb_irep*);
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
|
||||
+13
-9
@@ -16,21 +16,25 @@
|
||||
*/
|
||||
MRB_BEGIN_DECL
|
||||
|
||||
#define POSFIXABLE(f) ((f) <= MRB_INT_MAX)
|
||||
#define NEGFIXABLE(f) ((f) >= MRB_INT_MIN)
|
||||
#define FIXABLE(f) (POSFIXABLE(f) && NEGFIXABLE(f))
|
||||
|
||||
#ifdef MRB_INT64
|
||||
#define FIXABLE_FLOAT(f) FIXABLE((mrb_int)(f))
|
||||
#else
|
||||
#define FIXABLE_FLOAT(f) FIXABLE(f)
|
||||
#define TYPED_POSFIXABLE(f,t) ((f) <= (t)MRB_INT_MAX)
|
||||
#define TYPED_NEGFIXABLE(f,t) ((f) >= (t)MRB_INT_MIN)
|
||||
#define TYPED_FIXABLE(f,t) (TYPED_POSFIXABLE(f,t) && TYPED_NEGFIXABLE(f,t))
|
||||
#define POSFIXABLE(f) TYPED_POSFIXABLE(f,mrb_int)
|
||||
#define NEGFIXABLE(f) TYPED_NEGFIXABLE(f,mrb_int)
|
||||
#define FIXABLE(f) TYPED_FIXABLE(f,mrb_int)
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define FIXABLE_FLOAT(f) TYPED_FIXABLE(f,double)
|
||||
#endif
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value val);
|
||||
MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, int base);
|
||||
#endif
|
||||
MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base);
|
||||
/* ArgumentError if format string doesn't match /%(\.[0-9]+)?[aAeEfFgG]/ */
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt);
|
||||
MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x);
|
||||
#endif
|
||||
|
||||
mrb_value mrb_fixnum_plus(mrb_state *mrb, mrb_value x, mrb_value y);
|
||||
mrb_value mrb_fixnum_minus(mrb_state *mrb, mrb_value x, mrb_value y);
|
||||
|
||||
@@ -22,6 +22,8 @@ struct RBasic {
|
||||
};
|
||||
#define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v)))
|
||||
|
||||
/* flags bits >= 18 is reserved */
|
||||
#define MRB_FLAG_IS_FROZEN (1 << 18)
|
||||
#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN)
|
||||
#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN)
|
||||
#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN)
|
||||
|
||||
+63
-15
@@ -18,19 +18,20 @@ MRB_BEGIN_DECL
|
||||
struct REnv {
|
||||
MRB_OBJECT_HEADER;
|
||||
mrb_value *stack;
|
||||
ptrdiff_t cioff;
|
||||
union {
|
||||
mrb_sym mid;
|
||||
struct mrb_context *c;
|
||||
} cxt;
|
||||
struct mrb_context *cxt;
|
||||
mrb_sym mid;
|
||||
};
|
||||
|
||||
#define MRB_SET_ENV_STACK_LEN(e,len) (e)->flags = (unsigned int)(len)
|
||||
#define MRB_ENV_STACK_LEN(e) ((mrb_int)(e)->flags)
|
||||
#define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1)
|
||||
#define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0)
|
||||
/* flags (21bits): 1(shared flag):10(cioff/bidx):10(stack_len) */
|
||||
#define MRB_ENV_SET_STACK_LEN(e,len) (e)->flags = (((e)->flags & ~0x3ff)|((unsigned int)(len) & 0x3ff))
|
||||
#define MRB_ENV_STACK_LEN(e) ((mrb_int)((e)->flags & 0x3ff))
|
||||
#define MRB_ENV_STACK_UNSHARED (1<<20)
|
||||
#define MRB_ENV_UNSHARE_STACK(e) (e)->flags |= MRB_ENV_STACK_UNSHARED
|
||||
#define MRB_ENV_STACK_SHARED_P(e) (((e)->flags & MRB_ENV_STACK_UNSHARED) == 0)
|
||||
#define MRB_ENV_BIDX(e) (((e)->flags >> 10) & 0x3ff)
|
||||
#define MRB_ENV_SET_BIDX(e,idx) (e)->flags = (((e)->flags & ~(0x3ff<<10))|((unsigned int)(idx) & 0x3ff)<<10)
|
||||
|
||||
MRB_API void mrb_env_unshare(mrb_state*, struct REnv*);
|
||||
void mrb_env_unshare(mrb_state*, struct REnv*);
|
||||
|
||||
struct RProc {
|
||||
MRB_OBJECT_HEADER;
|
||||
@@ -38,8 +39,11 @@ struct RProc {
|
||||
mrb_irep *irep;
|
||||
mrb_func_t func;
|
||||
} body;
|
||||
struct RClass *target_class;
|
||||
struct REnv *env;
|
||||
struct RProc *upper;
|
||||
union {
|
||||
struct RClass *target_class;
|
||||
struct REnv *env;
|
||||
} e;
|
||||
};
|
||||
|
||||
/* aspec access */
|
||||
@@ -51,12 +55,29 @@ struct RProc {
|
||||
#define MRB_ASPEC_KDICT(a) ((a) & (1<<1))
|
||||
#define MRB_ASPEC_BLOCK(a) ((a) & 1)
|
||||
|
||||
#define MRB_PROC_CFUNC 128
|
||||
#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC) != 0)
|
||||
#define MRB_PROC_CFUNC_FL 128
|
||||
#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC_FL) != 0)
|
||||
#define MRB_PROC_CFUNC(p) (p)->body.func
|
||||
#define MRB_PROC_STRICT 256
|
||||
#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0)
|
||||
#define MRB_PROC_ORPHAN 512
|
||||
#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0)
|
||||
#define MRB_PROC_ENVSET 1024
|
||||
#define MRB_PROC_ENV_P(p) (((p)->flags & MRB_PROC_ENVSET) != 0)
|
||||
#define MRB_PROC_ENV(p) (MRB_PROC_ENV_P(p) ? (p)->e.env : NULL)
|
||||
#define MRB_PROC_TARGET_CLASS(p) (MRB_PROC_ENV_P(p) ? (p)->e.env->c : (p)->e.target_class)
|
||||
#define MRB_PROC_SET_TARGET_CLASS(p,tc) do {\
|
||||
if (MRB_PROC_ENV_P(p)) {\
|
||||
(p)->e.env->c = (tc);\
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)tc);\
|
||||
}\
|
||||
else {\
|
||||
(p)->e.target_class = (tc);\
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)tc);\
|
||||
}\
|
||||
} while (0)
|
||||
#define MRB_PROC_SCOPE 2048
|
||||
#define MRB_PROC_SCOPE_P(p) (((p)->flags & MRB_PROC_SCOPE) != 0)
|
||||
|
||||
#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v)))
|
||||
|
||||
@@ -75,8 +96,35 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int);
|
||||
/* old name */
|
||||
#define mrb_cfunc_env_get(mrb, idx) mrb_proc_cfunc_env_get(mrb, idx)
|
||||
|
||||
#ifdef MRB_METHOD_TABLE_INLINE
|
||||
|
||||
#define MRB_METHOD_FUNC_FL ((uintptr_t)1U<<(sizeof(uintptr_t)*8-1))
|
||||
#define MRB_METHOD_FUNC_P(m) ((uintptr_t)(m)&MRB_METHOD_FUNC_FL)
|
||||
#define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL)))
|
||||
#define MRB_METHOD_FROM_FUNC(m,fn) m=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL))
|
||||
#define MRB_METHOD_FROM_PROC(m,pr) m=(mrb_method_t)(struct RProc*)(pr)
|
||||
#define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m))
|
||||
#define MRB_METHOD_PROC(m) ((struct RProc*)(m))
|
||||
#define MRB_METHOD_UNDEF_P(m) ((m)==0)
|
||||
|
||||
#else
|
||||
|
||||
#define MRB_METHOD_FUNC_P(m) ((m).func_p)
|
||||
#define MRB_METHOD_FUNC(m) ((m).func)
|
||||
#define MRB_METHOD_FROM_FUNC(m,fn) do{(m).func_p=TRUE;(m).func=(fn);}while(0)
|
||||
#define MRB_METHOD_FROM_PROC(m,pr) do{(m).func_p=FALSE;(m).proc=(pr);}while(0)
|
||||
#define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m))
|
||||
#define MRB_METHOD_PROC(m) ((m).proc)
|
||||
#define MRB_METHOD_UNDEF_P(m) ((m).proc==NULL)
|
||||
|
||||
#endif /* MRB_METHOD_TABLE_INLINE */
|
||||
|
||||
#define MRB_METHOD_CFUNC_P(m) (MRB_METHOD_FUNC_P(m)?TRUE:(MRB_METHOD_PROC(m)?(MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m))):FALSE))
|
||||
#define MRB_METHOD_CFUNC(m) (MRB_METHOD_FUNC_P(m)?MRB_METHOD_FUNC(m):((MRB_METHOD_PROC(m)&&MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m)))?MRB_PROC_CFUNC(MRB_METHOD_PROC(m)):NULL))
|
||||
|
||||
|
||||
#include <mruby/khash.h>
|
||||
KHASH_DECLARE(mt, mrb_sym, struct RProc*, TRUE)
|
||||
KHASH_DECLARE(mt, mrb_sym, mrb_method_t, TRUE)
|
||||
|
||||
MRB_END_DECL
|
||||
|
||||
|
||||
+24
-6
@@ -26,6 +26,7 @@ struct RString {
|
||||
union {
|
||||
mrb_int capa;
|
||||
struct mrb_shared_string *shared;
|
||||
struct RString *fshared;
|
||||
} aux;
|
||||
char *ptr;
|
||||
} heap;
|
||||
@@ -59,10 +60,17 @@ struct RString {
|
||||
#define RSTR_SET_SHARED_FLAG(s) ((s)->flags |= MRB_STR_SHARED)
|
||||
#define RSTR_UNSET_SHARED_FLAG(s) ((s)->flags &= ~MRB_STR_SHARED)
|
||||
|
||||
#define RSTR_FSHARED_P(s) ((s)->flags & MRB_STR_FSHARED)
|
||||
#define RSTR_SET_FSHARED_FLAG(s) ((s)->flags |= MRB_STR_FSHARED)
|
||||
#define RSTR_UNSET_FSHARED_FLAG(s) ((s)->flags &= ~MRB_STR_FSHARED)
|
||||
|
||||
#define RSTR_NOFREE_P(s) ((s)->flags & MRB_STR_NOFREE)
|
||||
#define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE)
|
||||
#define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE)
|
||||
|
||||
#define RSTR_POOL_P(s) ((s)->flags & MRB_STR_POOL)
|
||||
#define RSTR_SET_POOL_FLAG(s) ((s)->flags |= MRB_STR_POOL)
|
||||
|
||||
/*
|
||||
* Returns a pointer from a Ruby string
|
||||
*/
|
||||
@@ -76,14 +84,23 @@ struct RString {
|
||||
MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*);
|
||||
|
||||
#define MRB_STR_SHARED 1
|
||||
#define MRB_STR_NOFREE 2
|
||||
#define MRB_STR_NO_UTF 8
|
||||
#define MRB_STR_EMBED 16
|
||||
#define MRB_STR_EMBED_LEN_MASK 0x3e0
|
||||
#define MRB_STR_EMBED_LEN_SHIFT 5
|
||||
#define MRB_STR_FSHARED 2
|
||||
#define MRB_STR_NOFREE 4
|
||||
#define MRB_STR_POOL 8
|
||||
#define MRB_STR_NO_UTF 16
|
||||
#define MRB_STR_EMBED 32
|
||||
#define MRB_STR_EMBED_LEN_MASK 0x7c0
|
||||
#define MRB_STR_EMBED_LEN_SHIFT 6
|
||||
|
||||
void mrb_gc_free_str(mrb_state*, struct RString*);
|
||||
MRB_API void mrb_str_modify(mrb_state*, struct RString*);
|
||||
|
||||
/*
|
||||
* Finds the index of a substring in a string
|
||||
*/
|
||||
MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_int);
|
||||
#define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off);
|
||||
|
||||
/*
|
||||
* Appends self to other. Returns self as a concatnated string.
|
||||
*
|
||||
@@ -297,6 +314,7 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb
|
||||
MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str);
|
||||
|
||||
MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str);
|
||||
MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa);
|
||||
MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa);
|
||||
|
||||
MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr);
|
||||
@@ -401,7 +419,7 @@ MRB_API int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2);
|
||||
MRB_API char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str);
|
||||
|
||||
mrb_value mrb_str_pool(mrb_state *mrb, mrb_value str);
|
||||
mrb_int mrb_str_hash(mrb_state *mrb, mrb_value str);
|
||||
uint32_t mrb_str_hash(mrb_state *mrb, mrb_value str);
|
||||
mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str);
|
||||
|
||||
/*
|
||||
|
||||
@@ -63,12 +63,14 @@ struct mrb_state;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
MRB_API double mrb_float_read(const char*, char**);
|
||||
#ifdef MRB_USE_FLOAT
|
||||
typedef float mrb_float;
|
||||
#else
|
||||
typedef double mrb_float;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER < 1900
|
||||
# ifndef __cplusplus
|
||||
@@ -79,7 +81,7 @@ MRB_API int mrb_msvc_vsnprintf(char *s, size_t n, const char *format, va_list ar
|
||||
MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...);
|
||||
# define vsnprintf(s, n, format, arg) mrb_msvc_vsnprintf(s, n, format, arg)
|
||||
# define snprintf(s, n, format, ...) mrb_msvc_snprintf(s, n, format, __VA_ARGS__)
|
||||
# if _MSC_VER < 1800
|
||||
# if _MSC_VER < 1800 && !defined MRB_WITHOUT_FLOAT
|
||||
# include <float.h>
|
||||
# define isfinite(n) _finite(n)
|
||||
# define isnan _isnan
|
||||
@@ -158,7 +160,9 @@ typedef void mrb_value;
|
||||
#ifndef mrb_bool
|
||||
#define mrb_bool(o) (mrb_type(o) != MRB_TT_FALSE)
|
||||
#endif
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
#define mrb_float_p(o) (mrb_type(o) == MRB_TT_FLOAT)
|
||||
#endif
|
||||
#define mrb_symbol_p(o) (mrb_type(o) == MRB_TT_SYMBOL)
|
||||
#define mrb_array_p(o) (mrb_type(o) == MRB_TT_ARRAY)
|
||||
#define mrb_string_p(o) (mrb_type(o) == MRB_TT_STRING)
|
||||
@@ -171,6 +175,7 @@ MRB_API mrb_bool mrb_regexp_p(struct mrb_state*, mrb_value);
|
||||
/*
|
||||
* Returns a float in Ruby.
|
||||
*/
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f)
|
||||
{
|
||||
mrb_value v;
|
||||
@@ -178,6 +183,7 @@ MRB_INLINE mrb_value mrb_float_value(struct mrb_state *mrb, mrb_float f)
|
||||
SET_FLOAT_VALUE(mrb, v, f);
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline mrb_value
|
||||
mrb_cptr_value(struct mrb_state *mrb, void *p)
|
||||
|
||||
@@ -47,7 +47,6 @@ MRB_API void mrb_iv_check(mrb_state *mrb, mrb_sym sym);
|
||||
MRB_API mrb_value mrb_obj_iv_get(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
|
||||
MRB_API void mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
|
||||
MRB_API mrb_bool mrb_obj_iv_defined(mrb_state *mrb, struct RObject *obj, mrb_sym sym);
|
||||
MRB_API void mrb_obj_iv_ifnone(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v);
|
||||
MRB_API mrb_value mrb_iv_get(mrb_state *mrb, mrb_value obj, mrb_sym sym);
|
||||
MRB_API void mrb_iv_set(mrb_state *mrb, mrb_value obj, mrb_sym sym, mrb_value v);
|
||||
MRB_API mrb_bool mrb_iv_defined(mrb_state*, mrb_value, mrb_sym);
|
||||
@@ -126,7 +125,6 @@ mrb_value mrb_obj_instance_variables(mrb_state*, mrb_value);
|
||||
mrb_value mrb_mod_class_variables(mrb_state*, mrb_value);
|
||||
mrb_value mrb_mod_cv_get(mrb_state *mrb, struct RClass * c, mrb_sym sym);
|
||||
mrb_bool mrb_mod_cv_defined(mrb_state *mrb, struct RClass * c, mrb_sym sym);
|
||||
mrb_sym mrb_class_sym(mrb_state *mrb, struct RClass *c, struct RClass *outer);
|
||||
|
||||
/* GC functions */
|
||||
void mrb_gc_mark_gv(mrb_state*);
|
||||
|
||||
@@ -42,7 +42,7 @@ MRB_BEGIN_DECL
|
||||
/*
|
||||
* Minor release version number.
|
||||
*/
|
||||
#define MRUBY_RELEASE_MINOR 3
|
||||
#define MRUBY_RELEASE_MINOR 4
|
||||
|
||||
/*
|
||||
* Tiny release version number.
|
||||
@@ -62,17 +62,17 @@ MRB_BEGIN_DECL
|
||||
/*
|
||||
* Release year.
|
||||
*/
|
||||
#define MRUBY_RELEASE_YEAR 2017
|
||||
#define MRUBY_RELEASE_YEAR 2018
|
||||
|
||||
/*
|
||||
* Release month.
|
||||
*/
|
||||
#define MRUBY_RELEASE_MONTH 7
|
||||
#define MRUBY_RELEASE_MONTH 1
|
||||
|
||||
/*
|
||||
* Release day.
|
||||
*/
|
||||
#define MRUBY_RELEASE_DAY 4
|
||||
#define MRUBY_RELEASE_DAY 16
|
||||
|
||||
/*
|
||||
* Release date as a string.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
load "#{MRUBY_ROOT}/tasks/mruby_build_gem.rake"
|
||||
load "#{MRUBY_ROOT}/tasks/mruby_build_commands.rake"
|
||||
require "mruby/build/load_gems"
|
||||
require "mruby/build/command"
|
||||
|
||||
module MRuby
|
||||
class << self
|
||||
@@ -241,7 +241,7 @@ EOS
|
||||
else
|
||||
compiler.defines += %w(DISABLE_GEMS)
|
||||
end
|
||||
compiler.define_rules build_dir, File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
compiler.define_rules build_dir, File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,9 +63,6 @@ module MRuby
|
||||
objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X"))
|
||||
end
|
||||
|
||||
@generate_functions = !(@rbfiles.empty? && @objs.empty?)
|
||||
@objs << objfile("#{build_dir}/gem_init") if @generate_functions
|
||||
|
||||
@test_rbfiles = Dir.glob("#{dir}/test/**/*.rb")
|
||||
@test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f|
|
||||
objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X"))
|
||||
@@ -83,6 +80,9 @@ module MRuby
|
||||
|
||||
instance_eval(&@initializer)
|
||||
|
||||
@generate_functions = !(@rbfiles.empty? && @objs.empty?)
|
||||
@objs << objfile("#{build_dir}/gem_init") if @generate_functions
|
||||
|
||||
if !name || !licenses || !authors
|
||||
fail "#{name || dir} required to set name, license(s) and author(s)"
|
||||
end
|
||||
@@ -14,6 +14,9 @@ MRuby::GemBox.new do |conf|
|
||||
# Use standard Struct class
|
||||
conf.gem :core => "mruby-struct"
|
||||
|
||||
# Use Comparable module extension
|
||||
conf.gem :core => "mruby-compar-ext"
|
||||
|
||||
# Use Enumerable module extension
|
||||
conf.gem :core => "mruby-enum-ext"
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ MRuby::Gem::Specification.new('mruby-array-ext') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Array class extension'
|
||||
spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
|
||||
end
|
||||
|
||||
@@ -81,11 +81,7 @@ class Array
|
||||
#
|
||||
def uniq(&block)
|
||||
ary = self.dup
|
||||
if block
|
||||
ary.uniq!(&block)
|
||||
else
|
||||
ary.uniq!
|
||||
end
|
||||
ary.uniq!(&block)
|
||||
ary
|
||||
end
|
||||
|
||||
@@ -105,8 +101,19 @@ class Array
|
||||
|
||||
hash = {}
|
||||
array = []
|
||||
elem.each { |x| hash[x] = true }
|
||||
self.each { |x| array << x unless hash[x] }
|
||||
idx = 0
|
||||
len = elem.size
|
||||
while idx < len
|
||||
hash[elem[idx]] = true
|
||||
idx += 1
|
||||
end
|
||||
idx = 0
|
||||
len = size
|
||||
while idx < len
|
||||
v = self[idx]
|
||||
array << v unless hash[v]
|
||||
idx += 1
|
||||
end
|
||||
array
|
||||
end
|
||||
|
||||
@@ -141,12 +148,21 @@ class Array
|
||||
|
||||
hash = {}
|
||||
array = []
|
||||
elem.each{|v| hash[v] = true }
|
||||
self.each do |v|
|
||||
idx = 0
|
||||
len = elem.size
|
||||
while idx < len
|
||||
hash[elem[idx]] = true
|
||||
idx += 1
|
||||
end
|
||||
idx = 0
|
||||
len = size
|
||||
while idx < len
|
||||
v = self[idx]
|
||||
if hash[v]
|
||||
array << v
|
||||
hash.delete v
|
||||
end
|
||||
idx += 1
|
||||
end
|
||||
array
|
||||
end
|
||||
@@ -169,15 +185,9 @@ class Array
|
||||
# a.flatten(1) #=> [1, 2, 3, [4, 5]]
|
||||
#
|
||||
def flatten(depth=nil)
|
||||
ar = []
|
||||
self.each do |e|
|
||||
if e.is_a?(Array) && (depth.nil? || depth > 0)
|
||||
ar += e.flatten(depth.nil? ? nil : depth - 1)
|
||||
else
|
||||
ar << e
|
||||
end
|
||||
end
|
||||
ar
|
||||
res = dup
|
||||
res.flatten! depth
|
||||
res
|
||||
end
|
||||
|
||||
##
|
||||
@@ -200,13 +210,17 @@ class Array
|
||||
def flatten!(depth=nil)
|
||||
modified = false
|
||||
ar = []
|
||||
self.each do |e|
|
||||
idx = 0
|
||||
len = size
|
||||
while idx < len
|
||||
e = self[idx]
|
||||
if e.is_a?(Array) && (depth.nil? || depth > 0)
|
||||
ar += e.flatten(depth.nil? ? nil : depth - 1)
|
||||
modified = true
|
||||
else
|
||||
ar << e
|
||||
end
|
||||
idx += 1
|
||||
end
|
||||
if modified
|
||||
self.replace(ar)
|
||||
@@ -252,7 +266,7 @@ class Array
|
||||
|
||||
# for efficiency
|
||||
def reverse_each(&block)
|
||||
return to_enum :reverse_each unless block_given?
|
||||
return to_enum :reverse_each unless block
|
||||
|
||||
i = self.size - 1
|
||||
while i>=0
|
||||
@@ -474,7 +488,7 @@ class Array
|
||||
# scores.delete_if {|score| score < 80 } #=> [97]
|
||||
|
||||
def delete_if(&block)
|
||||
return to_enum :delete_if unless block_given?
|
||||
return to_enum :delete_if unless block
|
||||
|
||||
idx = 0
|
||||
while idx < self.size do
|
||||
@@ -503,7 +517,7 @@ class Array
|
||||
# If no block is given, an Enumerator is returned instead.
|
||||
|
||||
def reject!(&block)
|
||||
return to_enum :reject! unless block_given?
|
||||
return to_enum :reject! unless block
|
||||
|
||||
len = self.size
|
||||
idx = 0
|
||||
@@ -593,33 +607,60 @@ class Array
|
||||
# undefined which value is actually picked up at each iteration.
|
||||
|
||||
def bsearch(&block)
|
||||
return to_enum :bsearch unless block_given?
|
||||
return to_enum :bsearch unless block
|
||||
|
||||
if idx = bsearch_index(&block)
|
||||
self[idx]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.bsearch_index {|x| block } -> int or nil
|
||||
#
|
||||
# By using binary search, finds an index of a value from this array which
|
||||
# meets the given condition in O(log n) where n is the size of the array.
|
||||
#
|
||||
# It supports two modes, depending on the nature of the block and they are
|
||||
# exactly the same as in the case of #bsearch method with the only difference
|
||||
# being that this method returns the index of the element instead of the
|
||||
# element itself. For more details consult the documentation for #bsearch.
|
||||
|
||||
def bsearch_index(&block)
|
||||
return to_enum :bsearch_index unless block
|
||||
|
||||
low = 0
|
||||
high = self.size
|
||||
high = size
|
||||
satisfied = false
|
||||
|
||||
while low < high
|
||||
mid = low + ((high - low) / 2).truncate
|
||||
val = self[mid]
|
||||
v = block.call(val)
|
||||
if v.is_a?(Integer)
|
||||
return val if v == 0
|
||||
smaller = v < 0
|
||||
elsif v == true
|
||||
mid = ((low+high)/2).truncate
|
||||
res = block.call self[mid]
|
||||
|
||||
case res
|
||||
when 0 # find-any mode: Found!
|
||||
return mid
|
||||
when Numeric # find-any mode: Continue...
|
||||
in_lower_half = res < 0
|
||||
when true # find-min mode
|
||||
in_lower_half = true
|
||||
satisfied = true
|
||||
smaller = true
|
||||
elsif v == false || v.nil?
|
||||
smaller = false
|
||||
when false, nil # find-min mode
|
||||
in_lower_half = false
|
||||
else
|
||||
raise TypeError, 'invalid block result (must be numeric, true, false or nil)'
|
||||
end
|
||||
if smaller
|
||||
|
||||
if in_lower_half
|
||||
high = mid
|
||||
else
|
||||
low = mid + 1
|
||||
end
|
||||
end
|
||||
return nil if low == self.size
|
||||
return nil unless satisfied
|
||||
self[low]
|
||||
|
||||
satisfied ? low : nil
|
||||
end
|
||||
|
||||
##
|
||||
@@ -640,7 +681,7 @@ class Array
|
||||
# scores.delete_if {|score| score < 80 } #=> [97]
|
||||
|
||||
def delete_if(&block)
|
||||
return to_enum :delete_if unless block_given?
|
||||
return to_enum :delete_if unless block
|
||||
|
||||
idx = 0
|
||||
while idx < self.size do
|
||||
@@ -669,7 +710,7 @@ class Array
|
||||
# a.keep_if { |val| val > 3 } #=> [4, 5]
|
||||
|
||||
def keep_if(&block)
|
||||
return to_enum :keep_if unless block_given?
|
||||
return to_enum :keep_if unless block
|
||||
|
||||
idx = 0
|
||||
len = self.size
|
||||
@@ -698,13 +739,17 @@ class Array
|
||||
# If no block is given, an Enumerator is returned instead.
|
||||
|
||||
def select!(&block)
|
||||
return to_enum :select! unless block_given?
|
||||
return to_enum :select! unless block
|
||||
|
||||
result = []
|
||||
self.each do |x|
|
||||
result << x if block.call(x)
|
||||
idx = 0
|
||||
len = size
|
||||
while idx < len
|
||||
elem = self[idx]
|
||||
result << elem if block.call(elem)
|
||||
idx += 1
|
||||
end
|
||||
return nil if self.size == result.size
|
||||
return nil if len == result.size
|
||||
self.replace(result)
|
||||
end
|
||||
|
||||
@@ -726,8 +771,9 @@ class Array
|
||||
|
||||
if block
|
||||
idx = 0
|
||||
self.each do |*e|
|
||||
return idx if block.call(*e)
|
||||
len = size
|
||||
while idx < len
|
||||
return idx if block.call self[idx]
|
||||
idx += 1
|
||||
end
|
||||
else
|
||||
@@ -762,4 +808,128 @@ class Array
|
||||
n
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.permutation { |p| block } -> ary
|
||||
# ary.permutation -> Enumerator
|
||||
# ary.permutation(n) { |p| block } -> ary
|
||||
# ary.permutation(n) -> Enumerator
|
||||
#
|
||||
# When invoked with a block, yield all permutations of length +n+ of the
|
||||
# elements of the array, then return the array itself.
|
||||
#
|
||||
# If +n+ is not specified, yield all permutations of all elements.
|
||||
#
|
||||
# The implementation makes no guarantees about the order in which the
|
||||
# permutations are yielded.
|
||||
#
|
||||
# If no block is given, an Enumerator is returned instead.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# a = [1, 2, 3]
|
||||
# a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
||||
# a.permutation(1).to_a #=> [[1],[2],[3]]
|
||||
# a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
|
||||
# a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
|
||||
# a.permutation(0).to_a #=> [[]] # one permutation of length 0
|
||||
# a.permutation(4).to_a #=> [] # no permutations of length 4
|
||||
def permutation(n=self.size, &block)
|
||||
size = self.size
|
||||
return to_enum(:permutation, n) unless block
|
||||
return if n > size
|
||||
if n == 0
|
||||
yield []
|
||||
else
|
||||
i = 0
|
||||
while i<size
|
||||
result = [self[i]]
|
||||
if n-1 > 0
|
||||
ary = self[0...i] + self[i+1..-1]
|
||||
ary.permutation(n-1) do |c|
|
||||
yield result + c
|
||||
end
|
||||
else
|
||||
yield result
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.combination(n) { |c| block } -> ary
|
||||
# ary.combination(n) -> Enumerator
|
||||
#
|
||||
# When invoked with a block, yields all combinations of length +n+ of elements
|
||||
# from the array and then returns the array itself.
|
||||
#
|
||||
# The implementation makes no guarantees about the order in which the
|
||||
# combinations are yielded.
|
||||
#
|
||||
# If no block is given, an Enumerator is returned instead.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# a = [1, 2, 3, 4]
|
||||
# a.combination(1).to_a #=> [[1],[2],[3],[4]]
|
||||
# a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
|
||||
# a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
|
||||
# a.combination(4).to_a #=> [[1,2,3,4]]
|
||||
# a.combination(0).to_a #=> [[]] # one combination of length 0
|
||||
# a.combination(5).to_a #=> [] # no combinations of length 5
|
||||
|
||||
def combination(n, &block)
|
||||
size = self.size
|
||||
return to_enum(:combination, n) unless block
|
||||
return if n > size
|
||||
if n == 0
|
||||
yield []
|
||||
elsif n == 1
|
||||
i = 0
|
||||
while i<size
|
||||
yield [self[i]]
|
||||
i += 1
|
||||
end
|
||||
else
|
||||
i = 0
|
||||
while i<size
|
||||
result = [self[i]]
|
||||
self[i+1..-1].combination(n-1) do |c|
|
||||
yield result + c
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# ary.transpose -> new_ary
|
||||
#
|
||||
# Assumes that self is an array of arrays and transposes the rows and columns.
|
||||
#
|
||||
# If the length of the subarrays don’t match, an IndexError is raised.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# a = [[1,2], [3,4], [5,6]]
|
||||
# a.transpose #=> [[1, 3, 5], [2, 4, 6]]
|
||||
|
||||
def transpose
|
||||
return [] if empty?
|
||||
|
||||
column_count = nil
|
||||
self.each do |row|
|
||||
raise TypeError unless row.is_a?(Array)
|
||||
column_count ||= row.count
|
||||
raise IndexError, 'element size differs' unless column_count == row.count
|
||||
end
|
||||
|
||||
Array.new(column_count) do |column_index|
|
||||
self.map { |row| row[column_index] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -127,19 +127,20 @@ mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
|
||||
hash = mrb_hash_new_capa(mrb, 0);
|
||||
|
||||
for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
||||
v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
|
||||
mrb_value elt = RARRAY_PTR(ary)[i];
|
||||
v = mrb_check_array_type(mrb, elt);
|
||||
|
||||
if (mrb_nil_p(v)) {
|
||||
mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
|
||||
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, ary_elt(ary, i))),
|
||||
mrb_fixnum_value(i)
|
||||
mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, elt)),
|
||||
mrb_fixnum_value(i)
|
||||
);
|
||||
}
|
||||
|
||||
if (RARRAY_LEN(v) != 2) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
|
||||
mrb_fixnum_value(i),
|
||||
mrb_fixnum_value(RARRAY_LEN(v))
|
||||
mrb_fixnum_value(i),
|
||||
mrb_fixnum_value(RARRAY_LEN(v))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,18 +175,20 @@ static mrb_value
|
||||
mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
struct RArray *a = mrb_ary_ptr(self);
|
||||
mrb_int i, j, k, len;
|
||||
mrb_value index;
|
||||
mrb_int i, j, k, len, alen = ARY_LEN(a);
|
||||
mrb_value val;
|
||||
mrb_value *ptr;
|
||||
mrb_value ary;
|
||||
|
||||
mrb_ary_modify(mrb, a);
|
||||
|
||||
if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
|
||||
if (mrb_get_argc(mrb) == 1) {
|
||||
mrb_value index;
|
||||
|
||||
mrb_get_args(mrb, "o|i", &index, &len);
|
||||
switch (mrb_type(index)) {
|
||||
case MRB_TT_RANGE:
|
||||
if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
|
||||
if (mrb_range_beg_len(mrb, index, &i, &len, alen, TRUE) == 1) {
|
||||
goto delete_pos_len;
|
||||
}
|
||||
else {
|
||||
@@ -200,27 +203,27 @@ mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
|
||||
}
|
||||
}
|
||||
|
||||
i = mrb_fixnum(index);
|
||||
mrb_get_args(mrb, "ii", &i, &len);
|
||||
delete_pos_len:
|
||||
if (i < 0) i += a->len;
|
||||
if (i < 0 || a->len < i) return mrb_nil_value();
|
||||
if (i < 0) i += alen;
|
||||
if (i < 0 || alen < i) return mrb_nil_value();
|
||||
if (len < 0) return mrb_nil_value();
|
||||
if (a->len == i) return mrb_ary_new(mrb);
|
||||
if (len > a->len - i) len = a->len - i;
|
||||
if (alen == i) return mrb_ary_new(mrb);
|
||||
if (len > alen - i) len = alen - i;
|
||||
|
||||
ary = mrb_ary_new_capa(mrb, len);
|
||||
|
||||
ptr = ARY_PTR(a);
|
||||
for (j = i, k = 0; k < len; ++j, ++k) {
|
||||
mrb_ary_push(mrb, ary, a->ptr[j]);
|
||||
mrb_ary_push(mrb, ary, ptr[j]);
|
||||
}
|
||||
|
||||
ptr = a->ptr + i;
|
||||
for (j = i; j < a->len - len; ++j) {
|
||||
ptr += i;
|
||||
for (j = i; j < alen - len; ++j) {
|
||||
*ptr = *(ptr+len);
|
||||
++ptr;
|
||||
}
|
||||
|
||||
mrb_ary_resize(mrb, self, a->len - len);
|
||||
mrb_ary_resize(mrb, self, alen - len);
|
||||
return ary;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,18 +228,47 @@ end
|
||||
|
||||
assert("Array#bsearch") do
|
||||
# Find minimum mode
|
||||
a = [0, 4, 7, 10, 12]
|
||||
assert_include [4, 7], a.bsearch {|x| x >= 4 }
|
||||
assert_equal 7, a.bsearch {|x| x >= 6 }
|
||||
assert_equal 0, a.bsearch {|x| x >= -1 }
|
||||
assert_nil a.bsearch {|x| x >= 100 }
|
||||
a = [0, 2, 4]
|
||||
assert_equal 0, a.bsearch{ |x| x >= -1 }
|
||||
assert_equal 0, a.bsearch{ |x| x >= 0 }
|
||||
assert_equal 2, a.bsearch{ |x| x >= 1 }
|
||||
assert_equal 2, a.bsearch{ |x| x >= 2 }
|
||||
assert_equal 4, a.bsearch{ |x| x >= 3 }
|
||||
assert_equal 4, a.bsearch{ |x| x >= 4 }
|
||||
assert_nil a.bsearch{ |x| x >= 5 }
|
||||
|
||||
# Find any mode
|
||||
a = [0, 4, 7, 10, 12]
|
||||
assert_include [4, 7], a.bsearch {|x| 1 - (x / 4).truncate }
|
||||
assert_nil a.bsearch {|x| 4 - (x / 2).truncate }
|
||||
assert_equal(nil, a.bsearch {|x| 1 })
|
||||
assert_equal(nil, a.bsearch {|x| -1 })
|
||||
a = [0, 4, 8]
|
||||
def between(lo, x, hi)
|
||||
if x < lo
|
||||
1
|
||||
elsif x > hi
|
||||
-1
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
assert_nil a.bsearch{ |x| between(-3, x, -1) }
|
||||
assert_equal 0, a.bsearch{ |x| between(-1, x, 1) }
|
||||
assert_nil a.bsearch{ |x| between( 1, x, 3) }
|
||||
assert_equal 4, a.bsearch{ |x| between( 3, x, 5) }
|
||||
assert_nil a.bsearch{ |x| between( 5, x, 7) }
|
||||
assert_equal 8, a.bsearch{ |x| between( 7, x, 9) }
|
||||
assert_nil a.bsearch{ |x| between( 9, x, 11) }
|
||||
|
||||
assert_equal 0, a.bsearch{ |x| between( 0, x, 3) }
|
||||
assert_equal 4, a.bsearch{ |x| between( 0, x, 4) }
|
||||
assert_equal 4, a.bsearch{ |x| between( 4, x, 8) }
|
||||
assert_equal 8, a.bsearch{ |x| between( 5, x, 8) }
|
||||
|
||||
# Invalid block result
|
||||
assert_raise TypeError, 'invalid block result (must be numeric, true, false or nil)' do
|
||||
a.bsearch{ 'I like to watch the world burn' }
|
||||
end
|
||||
end
|
||||
|
||||
assert("Array#bsearch_index") do
|
||||
# tested through Array#bsearch
|
||||
end
|
||||
|
||||
assert("Array#delete_if") do
|
||||
@@ -352,3 +381,42 @@ assert("Array#slice!") do
|
||||
assert_equal(i, [1, 2, 3])
|
||||
assert_equal(j, nil)
|
||||
end
|
||||
|
||||
assert("Array#permutation") do
|
||||
a = [1, 2, 3]
|
||||
assert_equal([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]],
|
||||
a.permutation.to_a)
|
||||
assert_equal([[1],[2],[3]],
|
||||
a.permutation(1).to_a)
|
||||
assert_equal([[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]],
|
||||
a.permutation(2).to_a)
|
||||
assert_equal([[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]],
|
||||
a.permutation(3).to_a)
|
||||
assert_equal([[]], a.permutation(0).to_a)
|
||||
assert_equal([], a.permutation(4).to_a)
|
||||
end
|
||||
|
||||
assert("Array#combination") do
|
||||
a = [1, 2, 3, 4]
|
||||
assert_equal([[1],[2],[3],[4]],
|
||||
a.combination(1).to_a)
|
||||
assert_equal([[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]],
|
||||
a.combination(2).to_a)
|
||||
assert_equal([[1,2,3],[1,2,4],[1,3,4],[2,3,4]],
|
||||
a.combination(3).to_a)
|
||||
assert_equal([[1,2,3,4]],
|
||||
a.combination(4).to_a)
|
||||
assert_equal([[]], a.combination(0).to_a)
|
||||
assert_equal([], a.combination(5).to_a)
|
||||
end
|
||||
|
||||
assert('Array#transpose') do
|
||||
assert_equal([].transpose, [])
|
||||
assert_equal([[]].transpose, [])
|
||||
assert_equal([[1]].transpose, [[1]])
|
||||
assert_equal([[1,2,3]].transpose, [[1], [2], [3]])
|
||||
assert_equal([[1], [2], [3]].transpose, [[1,2,3]])
|
||||
assert_equal([[1,2], [3,4], [5,6]].transpose, [[1,3,5], [2,4,6]])
|
||||
assert_raise(TypeError) { [1].transpose }
|
||||
assert_raise(IndexError) { [[1], [2,3,4]].transpose }
|
||||
end
|
||||
|
||||
@@ -341,8 +341,8 @@ assert('mruby-bin-debugger(print) Literal:Numeric') do
|
||||
tc << {:cmd=>"p +0100", :exp=>'$3 = 64'}
|
||||
tc << {:cmd=>"p 0x100", :exp=>'$4 = 256'}
|
||||
tc << {:cmd=>"p 1_234", :exp=>'$5 = 1234'}
|
||||
tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000.to_s}"}
|
||||
tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000.to_s}"}
|
||||
tc << {:cmd=>"p 0b1000_0000", :exp=>"$6 = #{0b1000_0000}"}
|
||||
tc << {:cmd=>"p 0x1000_0000", :exp=>"$7 = #{0x1000_0000}"}
|
||||
|
||||
tc << {:cmd=>"p 3.14", :exp=>'$8 = 3.14'}
|
||||
tc << {:cmd=>"p -12.3", :exp=>'$9 = -12.3'}
|
||||
|
||||
@@ -112,23 +112,12 @@ check_file_lineno(struct mrb_irep *irep, const char *file, uint16_t lineno)
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char*
|
||||
get_class_name(mrb_state *mrb, struct RClass *class_obj)
|
||||
{
|
||||
struct RClass *outer;
|
||||
mrb_sym class_sym;
|
||||
|
||||
outer = mrb_class_outer_module(mrb, class_obj);
|
||||
class_sym = mrb_class_sym(mrb, class_obj, outer);
|
||||
return mrb_sym2name(mrb, class_sym);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
compare_break_method(mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *class_obj, mrb_sym method_sym, mrb_bool* isCfunc)
|
||||
{
|
||||
const char* class_name;
|
||||
const char* method_name;
|
||||
struct RProc* m;
|
||||
mrb_method_t m;
|
||||
struct RClass* sc;
|
||||
const char* sn;
|
||||
mrb_sym ssym;
|
||||
@@ -139,7 +128,7 @@ compare_break_method(mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *cl
|
||||
|
||||
method_p = &bp->point.methodpoint;
|
||||
if (strcmp(method_p->method_name, method_name) == 0) {
|
||||
class_name = get_class_name(mrb, class_obj);
|
||||
class_name = mrb_class_name(mrb, class_obj);
|
||||
if (class_name == NULL) {
|
||||
if (method_p->class_name == NULL) {
|
||||
return bp->bpno;
|
||||
@@ -147,10 +136,10 @@ compare_break_method(mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *cl
|
||||
}
|
||||
else if (method_p->class_name != NULL) {
|
||||
m = mrb_method_search_vm(mrb, &class_obj, method_sym);
|
||||
if (m == NULL) {
|
||||
if (MRB_METHOD_UNDEF_P(m)) {
|
||||
return MRB_DEBUG_OK;
|
||||
}
|
||||
if (MRB_PROC_CFUNC_P(m)) {
|
||||
if (MRB_METHOD_CFUNC_P(m)) {
|
||||
*isCfunc = TRUE;
|
||||
}
|
||||
|
||||
@@ -162,12 +151,12 @@ compare_break_method(mrb_state *mrb, mrb_debug_breakpoint *bp, struct RClass *cl
|
||||
sc = mrb_class_get(mrb, method_p->class_name);
|
||||
ssym = mrb_symbol(mrb_check_intern_cstr(mrb, method_p->method_name));
|
||||
m = mrb_method_search_vm(mrb, &sc, ssym);
|
||||
if (m == NULL) {
|
||||
if (MRB_METHOD_UNDEF_P(m)) {
|
||||
return MRB_DEBUG_OK;
|
||||
}
|
||||
|
||||
class_name = get_class_name(mrb, class_obj);
|
||||
sn = get_class_name(mrb, sc);
|
||||
class_name = mrb_class_name(mrb, class_obj);
|
||||
sn = mrb_class_name(mrb, sc);
|
||||
if (strcmp(sn, class_name) == 0) {
|
||||
return bp->bpno;
|
||||
}
|
||||
@@ -204,7 +193,7 @@ mrb_debug_set_break_line(mrb_state *mrb, mrb_debug_context *dbg, const char *fil
|
||||
return MRB_DEBUG_BREAK_INVALID_LINENO;
|
||||
}
|
||||
|
||||
set_file = mrb_malloc(mrb, strlen(file) + 1);
|
||||
set_file = (char*)mrb_malloc(mrb, strlen(file) + 1);
|
||||
|
||||
index = dbg->bpnum;
|
||||
dbg->bp[index].bpno = dbg->next_bpno;
|
||||
@@ -241,14 +230,14 @@ mrb_debug_set_break_method(mrb_state *mrb, mrb_debug_context *dbg, const char *c
|
||||
}
|
||||
|
||||
if (class_name != NULL) {
|
||||
set_class = mrb_malloc(mrb, strlen(class_name) + 1);
|
||||
set_class = (char*)mrb_malloc(mrb, strlen(class_name) + 1);
|
||||
strncpy(set_class, class_name, strlen(class_name) + 1);
|
||||
}
|
||||
else {
|
||||
set_class = NULL;
|
||||
}
|
||||
|
||||
set_method = mrb_malloc(mrb, strlen(method_name) + 1);
|
||||
set_method = (char*)mrb_malloc(mrb, strlen(method_name) + 1);
|
||||
|
||||
strncpy(set_method, method_name, strlen(method_name) + 1);
|
||||
|
||||
@@ -440,7 +429,7 @@ static mrb_bool
|
||||
check_start_pc_for_line(mrb_irep *irep, mrb_code *pc, uint16_t line)
|
||||
{
|
||||
if (pc > irep->iseq) {
|
||||
if (line == mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq - 1))) {
|
||||
if (line == mrb_debug_get_line(irep, pc - irep->iseq - 1)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@@ -514,5 +503,3 @@ mrb_debug_check_breakpoint_method(mrb_state *mrb, mrb_debug_context *dbg, struct
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ build_path(mrb_state *mrb, const char *dir, const char *base)
|
||||
len += strlen(dir) + sizeof("/") - 1;
|
||||
}
|
||||
|
||||
path = mrb_malloc(mrb, len);
|
||||
path = (char*)mrb_malloc(mrb, len);
|
||||
memset(path, 0, len);
|
||||
|
||||
if (strcmp(dir, ".")) {
|
||||
@@ -64,7 +64,8 @@ static char*
|
||||
dirname(mrb_state *mrb, const char *path)
|
||||
{
|
||||
size_t len;
|
||||
char *p, *dir;
|
||||
const char *p;
|
||||
char *dir;
|
||||
|
||||
if (path == NULL) {
|
||||
return NULL;
|
||||
@@ -73,7 +74,7 @@ dirname(mrb_state *mrb, const char *path)
|
||||
p = strrchr(path, '/');
|
||||
len = p != NULL ? (size_t)(p - path) : strlen(path);
|
||||
|
||||
dir = mrb_malloc(mrb, len + 1);
|
||||
dir = (char*)mrb_malloc(mrb, len + 1);
|
||||
strncpy(dir, path, len);
|
||||
dir[len] = '\0';
|
||||
|
||||
@@ -83,9 +84,9 @@ dirname(mrb_state *mrb, const char *path)
|
||||
static source_file*
|
||||
source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
|
||||
{
|
||||
source_file *file = NULL;
|
||||
source_file *file;
|
||||
|
||||
file = mrb_malloc(mrb, sizeof(source_file));
|
||||
file = (source_file*)mrb_malloc(mrb, sizeof(source_file));
|
||||
|
||||
memset(file, '\0', sizeof(source_file));
|
||||
file->fp = fopen(filename, "rb");
|
||||
@@ -96,7 +97,7 @@ source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
|
||||
}
|
||||
|
||||
file->lineno = 1;
|
||||
file->path = mrb_malloc(mrb, strlen(filename) + 1);
|
||||
file->path = (char*)mrb_malloc(mrb, strlen(filename) + 1);
|
||||
strcpy(file->path, filename);
|
||||
return file;
|
||||
}
|
||||
@@ -174,9 +175,13 @@ mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, cons
|
||||
FILE *fp;
|
||||
const char *search_path[3];
|
||||
char *path = NULL;
|
||||
const char *srcname = strrchr(filename, '/');
|
||||
|
||||
if (srcname) srcname++;
|
||||
else srcname = filename;
|
||||
|
||||
search_path[0] = srcpath;
|
||||
search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->root_irep, 0));
|
||||
search_path[1] = dirname(mrb, mrb_debug_get_filename(mrdb->dbg->irep, 0));
|
||||
search_path[2] = ".";
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
@@ -184,7 +189,7 @@ mrb_debug_get_source(mrb_state *mrb, mrdb_state *mrdb, const char *srcpath, cons
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((path = build_path(mrb, search_path[i], filename)) == NULL) {
|
||||
if ((path = build_path(mrb, search_path[i], srcname)) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ parse_breakcommand(mrdb_state *mrdb, const char **file, uint32_t *line, char **c
|
||||
STRTOUL(l, body);
|
||||
if (l <= 65535) {
|
||||
*line = l;
|
||||
*file = (body == args)? mrb_debug_get_filename(dbg->irep, (uint32_t)(dbg->pc - dbg->irep->iseq)): args;
|
||||
*file = (body == args)? mrb_debug_get_filename(dbg->irep, dbg->pc - dbg->irep->iseq): args;
|
||||
}
|
||||
else {
|
||||
puts(BREAK_ERR_MSG_RANGEOVER);
|
||||
|
||||
@@ -133,7 +133,7 @@ typedef struct listcmd_parser_state {
|
||||
static listcmd_parser_state*
|
||||
listcmd_parser_state_new(mrb_state *mrb)
|
||||
{
|
||||
listcmd_parser_state *st = mrb_malloc(mrb, sizeof(listcmd_parser_state));
|
||||
listcmd_parser_state *st = (listcmd_parser_state*)mrb_malloc(mrb, sizeof(listcmd_parser_state));
|
||||
memset(st, 0, sizeof(listcmd_parser_state));
|
||||
return st;
|
||||
}
|
||||
@@ -227,7 +227,7 @@ parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st)
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
st->filename = mrb_malloc(mrb, len + 1);
|
||||
st->filename = (char*)mrb_malloc(mrb, len + 1);
|
||||
strncpy(st->filename, *sp, len);
|
||||
st->filename[len] = '\0';
|
||||
*sp += len;
|
||||
@@ -242,7 +242,8 @@ char*
|
||||
replace_ext(mrb_state *mrb, const char *filename, const char *ext)
|
||||
{
|
||||
size_t len;
|
||||
char *p, *s;
|
||||
const char *p;
|
||||
char *s;
|
||||
|
||||
if (filename == NULL) {
|
||||
return NULL;
|
||||
@@ -255,7 +256,7 @@ replace_ext(mrb_state *mrb, const char *filename, const char *ext)
|
||||
len = strlen(filename);
|
||||
}
|
||||
|
||||
s = mrb_malloc(mrb, len + strlen(ext) + 1);
|
||||
s = (char*)mrb_malloc(mrb, len + strlen(ext) + 1);
|
||||
memset(s, '\0', len + strlen(ext) + 1);
|
||||
strncpy(s, filename, len);
|
||||
strcat(s, ext);
|
||||
@@ -325,7 +326,7 @@ parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st)
|
||||
static mrb_bool
|
||||
check_cmd_pattern(const char *pattern, const char *cmd)
|
||||
{
|
||||
char *lbracket, *rbracket, *p, *q;
|
||||
const char *lbracket, *rbracket, *p, *q;
|
||||
|
||||
if (pattern == NULL && cmd == NULL) {
|
||||
return TRUE;
|
||||
|
||||
@@ -184,7 +184,7 @@ cleanup(mrb_state *mrb, struct _args *args)
|
||||
static mrb_debug_context*
|
||||
mrb_debug_context_new(mrb_state *mrb)
|
||||
{
|
||||
mrb_debug_context *dbg = mrb_malloc(mrb, sizeof(mrb_debug_context));
|
||||
mrb_debug_context *dbg = (mrb_debug_context*)mrb_malloc(mrb, sizeof(mrb_debug_context));
|
||||
|
||||
memset(dbg, 0, sizeof(mrb_debug_context));
|
||||
|
||||
@@ -223,12 +223,12 @@ mrb_debug_context_free(mrb_state *mrb)
|
||||
static mrdb_state*
|
||||
mrdb_state_new(mrb_state *mrb)
|
||||
{
|
||||
mrdb_state *mrdb = mrb_malloc(mrb, sizeof(mrdb_state));
|
||||
mrdb_state *mrdb = (mrdb_state*)mrb_malloc(mrb, sizeof(mrdb_state));
|
||||
|
||||
memset(mrdb, 0, sizeof(mrdb_state));
|
||||
|
||||
mrdb->dbg = mrb_debug_context_get(mrb);
|
||||
mrdb->command = mrb_malloc(mrb, MAX_COMMAND_LINE+1);
|
||||
mrdb->command = (char*)mrb_malloc(mrb, MAX_COMMAND_LINE+1);
|
||||
mrdb->print_no = 1;
|
||||
|
||||
return mrdb;
|
||||
@@ -566,8 +566,8 @@ mrb_code_fetch_hook(mrb_state *mrb, mrb_irep *irep, mrb_code *pc, mrb_value *reg
|
||||
dbg->xphase = DBG_PHASE_RUNNING;
|
||||
}
|
||||
|
||||
file = mrb_debug_get_filename(irep, (uint32_t)(pc - irep->iseq));
|
||||
line = mrb_debug_get_line(irep, (uint32_t)(pc - irep->iseq));
|
||||
file = mrb_debug_get_filename(irep, pc - irep->iseq);
|
||||
line = mrb_debug_get_line(irep, pc - irep->iseq);
|
||||
|
||||
switch (dbg->xm) {
|
||||
case DBG_STEP:
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
#include <readline/history.h>
|
||||
#define MIRB_ADD_HISTORY(line) add_history(line)
|
||||
#define MIRB_READLINE(ch) readline(ch)
|
||||
#if !defined(RL_READLINE_VERSION) || RL_READLINE_VERSION < 0x600
|
||||
/* libedit & older readline do not have rl_free() */
|
||||
#define MIRB_LINE_FREE(line) free(line)
|
||||
#else
|
||||
#define MIRB_LINE_FREE(line) rl_free(line)
|
||||
#endif
|
||||
#define MIRB_WRITE_HISTORY(path) write_history(path)
|
||||
#define MIRB_READ_HISTORY(path) read_history(path)
|
||||
#define MIRB_USING_HISTORY() using_history()
|
||||
@@ -27,6 +33,7 @@
|
||||
#include <linenoise.h>
|
||||
#define MIRB_ADD_HISTORY(line) linenoiseHistoryAdd(line)
|
||||
#define MIRB_READLINE(ch) linenoise(ch)
|
||||
#define MIRB_LINE_FREE(line) linenoiseFree(line)
|
||||
#define MIRB_WRITE_HISTORY(path) linenoiseHistorySave(path)
|
||||
#define MIRB_READ_HISTORY(path) linenoiseHistoryLoad(history_path)
|
||||
#define MIRB_USING_HISTORY()
|
||||
@@ -88,6 +95,7 @@ static void
|
||||
p(mrb_state *mrb, mrb_value obj, int prompt)
|
||||
{
|
||||
mrb_value val;
|
||||
char* msg;
|
||||
|
||||
val = mrb_funcall(mrb, obj, "inspect", 0);
|
||||
if (prompt) {
|
||||
@@ -101,7 +109,9 @@ p(mrb_state *mrb, mrb_value obj, int prompt)
|
||||
if (!mrb_string_p(val)) {
|
||||
val = mrb_obj_as_string(mrb, obj);
|
||||
}
|
||||
fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout);
|
||||
msg = mrb_locale_from_utf8(RSTRING_PTR(val), RSTRING_LEN(val));
|
||||
fwrite(msg, strlen(msg), 1, stdout);
|
||||
mrb_locale_free(msg);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
|
||||
@@ -489,7 +499,7 @@ main(int argc, char **argv)
|
||||
strcpy(last_code_line, line);
|
||||
strcat(last_code_line, "\n");
|
||||
MIRB_ADD_HISTORY(line);
|
||||
free(line);
|
||||
MIRB_LINE_FREE(line);
|
||||
#endif
|
||||
|
||||
done:
|
||||
@@ -528,9 +538,17 @@ done:
|
||||
/* no evaluation of code */
|
||||
}
|
||||
else {
|
||||
if (0 < parser->nwarn) {
|
||||
/* warning */
|
||||
char* msg = mrb_locale_from_utf8(parser->warn_buffer[0].message, -1);
|
||||
printf("line %d: %s\n", parser->warn_buffer[0].lineno, msg);
|
||||
mrb_utf8_free(msg);
|
||||
}
|
||||
if (0 < parser->nerr) {
|
||||
/* syntax error */
|
||||
printf("line %d: %s\n", parser->error_buffer[0].lineno, parser->error_buffer[0].message);
|
||||
char* msg = mrb_locale_from_utf8(parser->error_buffer[0].message, -1);
|
||||
printf("line %d: %s\n", parser->error_buffer[0].lineno, msg);
|
||||
mrb_utf8_free(msg);
|
||||
}
|
||||
else {
|
||||
/* generate bytecode */
|
||||
@@ -544,6 +562,13 @@ done:
|
||||
if (args.verbose) {
|
||||
mrb_codedump_all(mrb, proc);
|
||||
}
|
||||
/* adjust stack length of toplevel environment */
|
||||
if (mrb->c->cibase->env) {
|
||||
struct REnv *e = mrb->c->cibase->env;
|
||||
if (e && MRB_ENV_STACK_LEN(e) < proc->body.irep->nlocals) {
|
||||
MRB_ENV_SET_STACK_LEN(e, proc->body.irep->nlocals);
|
||||
}
|
||||
}
|
||||
/* pass a proc for evaluation */
|
||||
/* evaluate the bytecode */
|
||||
result = mrb_vm_run(mrb,
|
||||
@@ -577,6 +602,8 @@ done:
|
||||
mrb_free(mrb, history_path);
|
||||
#endif
|
||||
|
||||
if (args.rfp) fclose(args.rfp);
|
||||
mrb_free(mrb, args.argv);
|
||||
mrbc_context_free(mrb, cxt);
|
||||
mrb_close(mrb);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ MRuby::Gem::Specification.new('mruby-bin-mruby') do |spec|
|
||||
spec.add_dependency('mruby-error', :core => 'mruby-error')
|
||||
|
||||
if build.cxx_exception_enabled?
|
||||
@objs << build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
|
||||
@objs.delete_if { |v| v == objfile("#{spec.build_dir}/tools/mruby/mruby") }
|
||||
build.compile_as_cxx("#{spec.dir}/tools/mruby/mruby.c", "#{spec.build_dir}/tools/mruby/mruby.cxx")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ struct strip_args {
|
||||
static void
|
||||
irep_remove_lv(mrb_state *mrb, mrb_irep *irep)
|
||||
{
|
||||
size_t i;
|
||||
int i;
|
||||
|
||||
if (irep->lv) {
|
||||
mrb_free(mrb, irep->lv);
|
||||
|
||||
@@ -9,12 +9,57 @@ mrb_mod_name(mrb_state *mrb, mrb_value self)
|
||||
return mrb_nil_p(name)? name : mrb_str_dup(mrb, name);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_singleton_class_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return mrb_bool_value(mrb_type(self) == MRB_TT_SCLASS);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* module_exec(arg...) {|var...| block } -> obj
|
||||
* class_exec(arg...) {|var...| block } -> obj
|
||||
*
|
||||
* Evaluates the given block in the context of the
|
||||
* class/module. The method defined in the block will belong
|
||||
* to the receiver. Any arguments passed to the method will be
|
||||
* passed to the block. This can be used if the block needs to
|
||||
* access instance variables.
|
||||
*
|
||||
* class Thing
|
||||
* end
|
||||
* Thing.class_exec{
|
||||
* def hello() "Hello there!" end
|
||||
* }
|
||||
* puts Thing.new.hello()
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
mrb_mod_module_exec(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_int argc;
|
||||
mrb_value blk;
|
||||
|
||||
mrb_get_args(mrb, "*&", &argv, &argc, &blk);
|
||||
|
||||
if (mrb_nil_p(blk)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
|
||||
}
|
||||
|
||||
mrb->c->ci->target_class = mrb_class_ptr(self);
|
||||
return mrb_yield_cont(mrb, blk, self, argc, argv);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_class_ext_gem_init(mrb_state *mrb)
|
||||
{
|
||||
struct RClass *mod = mrb->module_class;
|
||||
|
||||
mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, mod, "module_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
|
||||
mrb_define_method(mrb, mod, "class_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,10 +1,55 @@
|
||||
assert 'Module#name' do
|
||||
module A
|
||||
class B
|
||||
end
|
||||
module Outer
|
||||
class Inner; end
|
||||
const_set :SetInner, Class.new
|
||||
end
|
||||
|
||||
assert_nil A::B.singleton_class.name
|
||||
assert_equal 'Fixnum', Fixnum.name
|
||||
assert_equal 'A::B', A::B.name
|
||||
assert_equal 'Outer', Outer.name
|
||||
assert_equal 'Outer::Inner', Outer::Inner.name
|
||||
assert_equal 'Outer::SetInner', Outer::SetInner.name
|
||||
|
||||
outer = Module.new do
|
||||
const_set :SetInner, Class.new
|
||||
end
|
||||
Object.const_set :SetOuter, outer
|
||||
|
||||
assert_equal 'SetOuter', SetOuter.name
|
||||
assert_equal 'SetOuter::SetInner', SetOuter::SetInner.name
|
||||
|
||||
mod = Module.new
|
||||
cls = Class.new
|
||||
|
||||
assert_nil mod.name
|
||||
assert_nil cls.name
|
||||
end
|
||||
|
||||
assert 'Module#singleton_class?' do
|
||||
mod = Module.new
|
||||
cls = Class.new
|
||||
scl = cls.singleton_class
|
||||
|
||||
assert_false mod.singleton_class?
|
||||
assert_false cls.singleton_class?
|
||||
assert_true scl.singleton_class?
|
||||
end
|
||||
|
||||
assert 'Module#module_eval' do
|
||||
mod = Module.new
|
||||
mod.class_exec(1,2,3) do |a,b,c|
|
||||
assert_equal([1,2,3], [a,b,c])
|
||||
def hi
|
||||
"hi"
|
||||
end
|
||||
end
|
||||
cls = Class.new
|
||||
cls.class_exec(42) do |x|
|
||||
assert_equal(42, x)
|
||||
include mod
|
||||
def hello
|
||||
"hello"
|
||||
end
|
||||
end
|
||||
obj = cls.new
|
||||
assert_equal("hi", obj.hi)
|
||||
assert_equal("hello", obj.hello)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
MRuby::Gem::Specification.new('mruby-compar-ext') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Enumerable module extension'
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
module Comparable
|
||||
##
|
||||
# Returns <i>min</i> if <i>obj</i> <code><=></code> <i>min</i> is less
|
||||
# than zero, <i>max</i> if <i>obj</i> <code><=></code> <i>max</i> is
|
||||
# greater than zero and <i>obj</i> otherwise.
|
||||
#
|
||||
# 12.clamp(0, 100) #=> 12
|
||||
# 523.clamp(0, 100) #=> 100
|
||||
# -3.123.clamp(0, 100) #=> 0
|
||||
#
|
||||
# 'd'.clamp('a', 'f') #=> 'd'
|
||||
# 'z'.clamp('a', 'f') #=> 'f'
|
||||
#
|
||||
def clamp(min, max)
|
||||
if (min <=> max) > 0
|
||||
raise ArgumentError, "min argument must be smaller than max argument"
|
||||
end
|
||||
c = self <=> min
|
||||
if c == 0
|
||||
return self
|
||||
elsif c < 0
|
||||
return min
|
||||
end
|
||||
c = self <=> max
|
||||
if c > 0
|
||||
return max
|
||||
else
|
||||
return self
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -66,9 +66,7 @@ typedef struct scope {
|
||||
int icapa;
|
||||
|
||||
mrb_irep *irep;
|
||||
size_t pcapa;
|
||||
size_t scapa;
|
||||
size_t rcapa;
|
||||
int pcapa, scapa, rcapa;
|
||||
|
||||
uint16_t nlocals;
|
||||
uint16_t nregs;
|
||||
@@ -280,6 +278,19 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_GETUPVAR:
|
||||
if (c0 == OP_SETUPVAR) {
|
||||
if (GETARG_B(i) == GETARG_B(i0) && GETARG_C(i) == GETARG_C(i0)) {
|
||||
if (GETARG_A(i) == GETARG_A(i0)) {
|
||||
/* just skip OP_SETUPVAR */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return genop(s, MKOP_AB(OP_MOVE, GETARG_A(i), GETARG_A(i0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_EPOP:
|
||||
if (c0 == OP_EPOP) {
|
||||
s->iseq[s->pc-1] = MKOP_A(OP_EPOP, GETARG_A(i0)+GETARG_A(i));
|
||||
@@ -337,6 +348,14 @@ genop_peep(codegen_scope *s, mrb_code i, int val)
|
||||
s->iseq[s->pc-1] = MKOP_ABC(OP_SUBI, GETARG_A(i), GETARG_B(i), -c);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case OP_ARYCAT:
|
||||
case OP_ARYPUSH:
|
||||
if (c0 == OP_MOVE && GETARG_A(i0) >= s->nlocals) {
|
||||
s->iseq[s->pc-1] = MKOP_AB(c1, GETARG_A(i), GETARG_B(i0));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case OP_STRCAT:
|
||||
if (c0 == OP_STRING) {
|
||||
mrb_value v = s->irep->pool[GETARG_Bx(i0)];
|
||||
@@ -373,6 +392,14 @@ scope_error(codegen_scope *s)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
distcheck(codegen_scope *s, int diff)
|
||||
{
|
||||
if (diff > MAXARG_sBx || diff < -MAXARG_sBx) {
|
||||
codegen_error(s, "too distant jump address");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
dispatch(codegen_scope *s, int pc)
|
||||
{
|
||||
@@ -394,9 +421,7 @@ dispatch(codegen_scope *s, int pc)
|
||||
scope_error(s);
|
||||
break;
|
||||
}
|
||||
if (diff > MAXARG_sBx) {
|
||||
codegen_error(s, "too distant jump address");
|
||||
}
|
||||
distcheck(s, diff);
|
||||
s->iseq[pc] = MKOP_AsBx(c, GETARG_A(i), diff);
|
||||
}
|
||||
|
||||
@@ -428,7 +453,7 @@ push_(codegen_scope *s)
|
||||
}
|
||||
|
||||
static void
|
||||
push_n_(codegen_scope *s, size_t n)
|
||||
push_n_(codegen_scope *s, int n)
|
||||
{
|
||||
if (s->sp+n > 511) {
|
||||
codegen_error(s, "too complex expression");
|
||||
@@ -447,7 +472,7 @@ push_n_(codegen_scope *s, size_t n)
|
||||
static inline int
|
||||
new_lit(codegen_scope *s, mrb_value val)
|
||||
{
|
||||
size_t i;
|
||||
int i;
|
||||
mrb_value *pv;
|
||||
|
||||
switch (mrb_type(val)) {
|
||||
@@ -462,6 +487,7 @@ new_lit(codegen_scope *s, mrb_value val)
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
case MRB_TT_FLOAT:
|
||||
for (i=0; i<s->irep->plen; i++) {
|
||||
pv = &s->irep->pool[i];
|
||||
@@ -469,6 +495,7 @@ new_lit(codegen_scope *s, mrb_value val)
|
||||
if (mrb_float(*pv) == mrb_float(val)) return i;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case MRB_TT_FIXNUM:
|
||||
for (i=0; i<s->irep->plen; i++) {
|
||||
pv = &s->irep->pool[i];
|
||||
@@ -494,10 +521,12 @@ new_lit(codegen_scope *s, mrb_value val)
|
||||
*pv = mrb_str_pool(s->mrb, val);
|
||||
break;
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
case MRB_TT_FLOAT:
|
||||
#ifdef MRB_WORD_BOXING
|
||||
*pv = mrb_float_pool(s->mrb, mrb_float(val));
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case MRB_TT_FIXNUM:
|
||||
*pv = val;
|
||||
@@ -518,7 +547,7 @@ new_lit(codegen_scope *s, mrb_value val)
|
||||
static int
|
||||
new_msym(codegen_scope *s, mrb_sym sym)
|
||||
{
|
||||
size_t i, len;
|
||||
int i, len;
|
||||
|
||||
mrb_assert(s->irep);
|
||||
|
||||
@@ -539,7 +568,7 @@ new_msym(codegen_scope *s, mrb_sym sym)
|
||||
static int
|
||||
new_sym(codegen_scope *s, mrb_sym sym)
|
||||
{
|
||||
size_t i;
|
||||
int i;
|
||||
|
||||
for (i=0; i<s->irep->slen; i++) {
|
||||
if (s->irep->syms[i] == sym) return i;
|
||||
@@ -573,8 +602,8 @@ node_len(node *tree)
|
||||
return n;
|
||||
}
|
||||
|
||||
#define sym(x) ((mrb_sym)(intptr_t)(x))
|
||||
#define lv_name(lv) sym((lv)->car)
|
||||
#define nsym(x) ((mrb_sym)(intptr_t)(x))
|
||||
#define lv_name(lv) nsym((lv)->car)
|
||||
static int
|
||||
lv_idx(codegen_scope *s, mrb_sym id)
|
||||
{
|
||||
@@ -633,6 +662,7 @@ for_body(codegen_scope *s, node *tree)
|
||||
scope_finish(s);
|
||||
s = prev;
|
||||
genop(s, MKOP_Abc(OP_LAMBDA, cursp(), s->irep->rlen-1, OP_L_BLOCK));
|
||||
push();pop(); /* space for a block */
|
||||
pop();
|
||||
idx = new_msym(s, mrb_intern_lit(s->mrb, "each"));
|
||||
genop(s, MKOP_ABC(OP_SENDB, cursp(), idx, 0));
|
||||
@@ -701,7 +731,7 @@ lambda_body(codegen_scope *s, node *tree, int blk)
|
||||
|
||||
dispatch(s, pos+i);
|
||||
codegen(s, opt->car->cdr, VAL);
|
||||
idx = lv_idx(s, (mrb_sym)(intptr_t)opt->car->car);
|
||||
idx = lv_idx(s, nsym(opt->car->car));
|
||||
pop();
|
||||
genop_peep(s, MKOP_AB(OP_MOVE, idx, cursp()), NOVAL);
|
||||
i++;
|
||||
@@ -764,11 +794,14 @@ scope_body(codegen_scope *s, node *tree, int val)
|
||||
return s->irep->rlen - 1;
|
||||
}
|
||||
|
||||
#define nint(x) ((int)(intptr_t)(x))
|
||||
#define nchar(x) ((char)(intptr_t)(x))
|
||||
|
||||
static mrb_bool
|
||||
nosplat(node *t)
|
||||
{
|
||||
while (t) {
|
||||
if ((intptr_t)t->car->car == NODE_SPLAT) return FALSE;
|
||||
if (nint(t->car->car) == NODE_SPLAT) return FALSE;
|
||||
t = t->cdr;
|
||||
}
|
||||
return TRUE;
|
||||
@@ -804,12 +837,12 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
|
||||
int is_splat;
|
||||
|
||||
while (t) {
|
||||
is_splat = (intptr_t)t->car->car == NODE_SPLAT; /* splat mode */
|
||||
is_splat = nint(t->car->car) == NODE_SPLAT; /* splat mode */
|
||||
if (
|
||||
n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */
|
||||
|| is_splat) {
|
||||
if (val) {
|
||||
if (is_splat && n == 0 && (intptr_t)t->car->cdr->car == NODE_ARRAY) {
|
||||
if (is_splat && n == 0 && nint(t->car->cdr->car) == NODE_ARRAY) {
|
||||
codegen(s, t->car->cdr, VAL);
|
||||
pop();
|
||||
}
|
||||
@@ -820,10 +853,10 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
|
||||
codegen(s, t->car, VAL);
|
||||
pop(); pop();
|
||||
if (is_splat) {
|
||||
genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
|
||||
genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL);
|
||||
}
|
||||
else {
|
||||
genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
|
||||
genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL);
|
||||
}
|
||||
}
|
||||
t = t->cdr;
|
||||
@@ -831,11 +864,11 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
|
||||
push();
|
||||
codegen(s, t->car, VAL);
|
||||
pop(); pop();
|
||||
if ((intptr_t)t->car->car == NODE_SPLAT) {
|
||||
genop(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1));
|
||||
if (nint(t->car->car) == NODE_SPLAT) {
|
||||
genop_peep(s, MKOP_AB(OP_ARYCAT, cursp(), cursp()+1), NOVAL);
|
||||
}
|
||||
else {
|
||||
genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
|
||||
genop_peep(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1), NOVAL);
|
||||
}
|
||||
t = t->cdr;
|
||||
}
|
||||
@@ -859,7 +892,7 @@ gen_values(codegen_scope *s, node *t, int val, int extra)
|
||||
static void
|
||||
gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
|
||||
{
|
||||
mrb_sym sym = name ? name : sym(tree->cdr->car);
|
||||
mrb_sym sym = name ? name : nsym(tree->cdr->car);
|
||||
int idx, skip = 0;
|
||||
int n = 0, noop = 0, sendv = 0, blk = 0;
|
||||
|
||||
@@ -869,7 +902,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe)
|
||||
genop(s, MKOP_A(OP_LOADNIL, cursp()));
|
||||
push();
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), recv));
|
||||
push(); pop(); /* space for a block */
|
||||
push_n(2); pop_n(2); /* space for one arg and a block */
|
||||
pop();
|
||||
idx = new_msym(s, mrb_intern_lit(s->mrb, "=="));
|
||||
genop(s, MKOP_ABC(OP_EQ, cursp(), idx, 1));
|
||||
@@ -959,16 +992,16 @@ static void
|
||||
gen_assignment(codegen_scope *s, node *tree, int sp, int val)
|
||||
{
|
||||
int idx;
|
||||
int type = (intptr_t)tree->car;
|
||||
int type = nint(tree->car);
|
||||
|
||||
tree = tree->cdr;
|
||||
switch (type) {
|
||||
case NODE_GVAR:
|
||||
idx = new_sym(s, sym(tree));
|
||||
idx = new_sym(s, nsym(tree));
|
||||
genop_peep(s, MKOP_ABx(OP_SETGLOBAL, sp, idx), val);
|
||||
break;
|
||||
case NODE_LVAR:
|
||||
idx = lv_idx(s, sym(tree));
|
||||
idx = lv_idx(s, nsym(tree));
|
||||
if (idx > 0) {
|
||||
if (idx != sp) {
|
||||
genop_peep(s, MKOP_AB(OP_MOVE, idx, sp), val);
|
||||
@@ -980,7 +1013,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
|
||||
codegen_scope *up = s->prev;
|
||||
|
||||
while (up) {
|
||||
idx = lv_idx(up, sym(tree));
|
||||
idx = lv_idx(up, nsym(tree));
|
||||
if (idx > 0) {
|
||||
genop_peep(s, MKOP_ABC(OP_SETUPVAR, sp, idx, lv), val);
|
||||
break;
|
||||
@@ -991,19 +1024,19 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
|
||||
}
|
||||
break;
|
||||
case NODE_IVAR:
|
||||
idx = new_sym(s, sym(tree));
|
||||
idx = new_sym(s, nsym(tree));
|
||||
genop_peep(s, MKOP_ABx(OP_SETIV, sp, idx), val);
|
||||
break;
|
||||
case NODE_CVAR:
|
||||
idx = new_sym(s, sym(tree));
|
||||
idx = new_sym(s, nsym(tree));
|
||||
genop_peep(s, MKOP_ABx(OP_SETCV, sp, idx), val);
|
||||
break;
|
||||
case NODE_CONST:
|
||||
idx = new_sym(s, sym(tree));
|
||||
idx = new_sym(s, nsym(tree));
|
||||
genop_peep(s, MKOP_ABx(OP_SETCONST, sp, idx), val);
|
||||
break;
|
||||
case NODE_COLON2:
|
||||
idx = new_sym(s, sym(tree->cdr));
|
||||
idx = new_sym(s, nsym(tree->cdr));
|
||||
genop_peep(s, MKOP_AB(OP_MOVE, cursp(), sp), NOVAL);
|
||||
push();
|
||||
codegen(s, tree->car, VAL);
|
||||
@@ -1014,7 +1047,7 @@ gen_assignment(codegen_scope *s, node *tree, int sp, int val)
|
||||
case NODE_CALL:
|
||||
case NODE_SCALL:
|
||||
push();
|
||||
gen_call(s, tree, attrsym(s, sym(tree->cdr->car)), sp, NOVAL,
|
||||
gen_call(s, tree, attrsym(s, nsym(tree->cdr->car)), sp, NOVAL,
|
||||
type == NODE_SCALL);
|
||||
pop();
|
||||
if (val) {
|
||||
@@ -1094,6 +1127,7 @@ gen_vmassignment(codegen_scope *s, node *tree, int rhs, int val)
|
||||
static void
|
||||
gen_send_intern(codegen_scope *s)
|
||||
{
|
||||
push();pop(); /* space for a block */
|
||||
pop();
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "intern")), 0));
|
||||
push();
|
||||
@@ -1105,9 +1139,9 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
|
||||
int i = 0, j = 0;
|
||||
|
||||
while (tree) {
|
||||
switch ((intptr_t)tree->car->car) {
|
||||
switch (nint(tree->car->car)) {
|
||||
case NODE_STR:
|
||||
if ((tree->cdr == NULL) && ((intptr_t)tree->car->cdr->cdr == 0))
|
||||
if ((tree->cdr == NULL) && (nint(tree->car->cdr->cdr) == 0))
|
||||
break;
|
||||
/* fall through */
|
||||
case NODE_BEGIN:
|
||||
@@ -1143,7 +1177,7 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val)
|
||||
}
|
||||
else {
|
||||
while (tree) {
|
||||
switch ((intptr_t)tree->car->car) {
|
||||
switch (nint(tree->car->car)) {
|
||||
case NODE_BEGIN: case NODE_BLOCK:
|
||||
codegen(s, tree->car, NOVAL);
|
||||
}
|
||||
@@ -1160,6 +1194,7 @@ raise_error(codegen_scope *s, const char *msg)
|
||||
genop(s, MKOP_ABx(OP_ERR, 1, idx));
|
||||
}
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
static double
|
||||
readint_float(codegen_scope *s, const char *p, int base)
|
||||
{
|
||||
@@ -1185,6 +1220,7 @@ readint_float(codegen_scope *s, const char *p, int base)
|
||||
}
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
static mrb_int
|
||||
readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_bool *overflow)
|
||||
@@ -1232,7 +1268,7 @@ readint_mrb_int(codegen_scope *s, const char *p, int base, mrb_bool neg, mrb_boo
|
||||
static void
|
||||
gen_retval(codegen_scope *s, node *tree)
|
||||
{
|
||||
if ((intptr_t)tree->car == NODE_SPLAT) {
|
||||
if (nint(tree->car) == NODE_SPLAT) {
|
||||
genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), 0));
|
||||
push();
|
||||
codegen(s, tree, VAL);
|
||||
@@ -1271,7 +1307,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
s->filename = mrb_parser_get_filename(s->parser, tree->filename_index);
|
||||
}
|
||||
|
||||
nt = (intptr_t)tree->car;
|
||||
nt = nint(tree->car);
|
||||
s->lineno = tree->lineno;
|
||||
tree = tree->cdr;
|
||||
switch (nt) {
|
||||
@@ -1316,9 +1352,10 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
if (pos1) dispatch(s, pos1);
|
||||
pos2 = 0;
|
||||
do {
|
||||
if (n4 && n4->car && (intptr_t)n4->car->car == NODE_SPLAT) {
|
||||
if (n4 && n4->car && nint(n4->car->car) == NODE_SPLAT) {
|
||||
codegen(s, n4->car, VAL);
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), exc));
|
||||
push_n(2); pop_n(2); /* space for one arg and a block */
|
||||
pop();
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
|
||||
}
|
||||
@@ -1333,6 +1370,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
pop();
|
||||
genop(s, MKOP_ABC(OP_RESCUE, exc, cursp(), 1));
|
||||
}
|
||||
distcheck(s, pos2);
|
||||
tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
|
||||
pos2 = tmp;
|
||||
if (n4) {
|
||||
@@ -1350,6 +1388,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen(s, n3->cdr->cdr->car, val);
|
||||
if (val) pop();
|
||||
}
|
||||
distcheck(s, exend);
|
||||
tmp = genop(s, MKOP_sBx(OP_JMP, exend));
|
||||
exend = tmp;
|
||||
n2 = n2->cdr;
|
||||
@@ -1377,7 +1416,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_ENSURE:
|
||||
if (!tree->cdr || !tree->cdr->cdr ||
|
||||
((intptr_t)tree->cdr->cdr->car == NODE_BEGIN &&
|
||||
(nint(tree->cdr->cdr->car) == NODE_BEGIN &&
|
||||
tree->cdr->cdr->cdr)) {
|
||||
int idx;
|
||||
int epush = s->pc;
|
||||
@@ -1422,7 +1461,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen(s, e, val);
|
||||
goto exit;
|
||||
}
|
||||
switch ((intptr_t)tree->car->car) {
|
||||
switch (nint(tree->car->car)) {
|
||||
case NODE_TRUE:
|
||||
case NODE_INT:
|
||||
case NODE_STR:
|
||||
@@ -1495,6 +1534,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
dispatch(s, lp->pc1);
|
||||
codegen(s, tree->car, VAL);
|
||||
pop();
|
||||
distcheck(s, lp->pc2 - s->pc);
|
||||
genop(s, MKOP_AsBx(OP_JMPIF, cursp(), lp->pc2 - s->pc));
|
||||
|
||||
loop_pop(s, val);
|
||||
@@ -1511,6 +1551,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
dispatch(s, lp->pc1);
|
||||
codegen(s, tree->car, VAL);
|
||||
pop();
|
||||
distcheck(s, lp->pc2 - s->pc);
|
||||
genop(s, MKOP_AsBx(OP_JMPNOT, cursp(), lp->pc2 - s->pc));
|
||||
|
||||
loop_pop(s, val);
|
||||
@@ -1541,8 +1582,9 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen(s, n->car, VAL);
|
||||
if (head) {
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), head));
|
||||
push_n(2); pop_n(2); /* space for one arg and a block */
|
||||
pop();
|
||||
if ((intptr_t)n->car->car == NODE_SPLAT) {
|
||||
if (nint(n->car->car) == NODE_SPLAT) {
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), new_msym(s, mrb_intern_lit(s->mrb, "__case_eqq")), 1));
|
||||
}
|
||||
else {
|
||||
@@ -1552,6 +1594,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
else {
|
||||
pop();
|
||||
}
|
||||
distcheck(s, pos2);
|
||||
tmp = genop(s, MKOP_AsBx(OP_JMPIF, cursp(), pos2));
|
||||
pos2 = tmp;
|
||||
n = n->cdr;
|
||||
@@ -1562,6 +1605,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
}
|
||||
codegen(s, tree->car->cdr, val);
|
||||
if (val) pop();
|
||||
distcheck(s, pos3);
|
||||
tmp = genop(s, MKOP_sBx(OP_JMP, pos3));
|
||||
pos3 = tmp;
|
||||
if (pos1) dispatch(s, pos1);
|
||||
@@ -1622,7 +1666,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_COLON2:
|
||||
{
|
||||
int sym = new_sym(s, sym(tree->cdr));
|
||||
int sym = new_sym(s, nsym(tree->cdr));
|
||||
|
||||
codegen(s, tree->car, VAL);
|
||||
pop();
|
||||
@@ -1633,7 +1677,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_COLON3:
|
||||
{
|
||||
int sym = new_sym(s, sym(tree));
|
||||
int sym = new_sym(s, nsym(tree));
|
||||
|
||||
genop(s, MKOP_A(OP_OCLASS, cursp()));
|
||||
genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
|
||||
@@ -1709,7 +1753,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
node *t = tree->cdr, *p;
|
||||
int rhs = cursp();
|
||||
|
||||
if ((intptr_t)t->car == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
|
||||
if (nint(t->car) == NODE_ARRAY && t->cdr && nosplat(t->cdr)) {
|
||||
/* fixed rhs */
|
||||
t = t->cdr;
|
||||
while (t) {
|
||||
@@ -1783,14 +1827,14 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_OP_ASGN:
|
||||
{
|
||||
mrb_sym sym = sym(tree->cdr->car);
|
||||
mrb_sym sym = nsym(tree->cdr->car);
|
||||
mrb_int len;
|
||||
const char *name = mrb_sym2name_len(s->mrb, sym, &len);
|
||||
int idx, callargs = -1, vsp = -1;
|
||||
|
||||
if ((len == 2 && name[0] == '|' && name[1] == '|') &&
|
||||
((intptr_t)tree->car->car == NODE_CONST ||
|
||||
(intptr_t)tree->car->car == NODE_CVAR)) {
|
||||
(nint(tree->car->car) == NODE_CONST ||
|
||||
nint(tree->car->car) == NODE_CVAR)) {
|
||||
int onerr, noexc, exc;
|
||||
struct loopinfo *lp;
|
||||
|
||||
@@ -1808,45 +1852,36 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
dispatch(s, noexc);
|
||||
loop_pop(s, NOVAL);
|
||||
}
|
||||
else if ((intptr_t)tree->car->car == NODE_CALL) {
|
||||
else if (nint(tree->car->car) == NODE_CALL) {
|
||||
node *n = tree->car->cdr;
|
||||
int base, i, nargs = 0;
|
||||
callargs = 0;
|
||||
|
||||
if (val) {
|
||||
vsp = cursp();
|
||||
push();
|
||||
}
|
||||
codegen(s, n->car, VAL); /* receiver */
|
||||
idx = new_msym(s, sym(n->cdr->car));
|
||||
idx = new_msym(s, nsym(n->cdr->car));
|
||||
base = cursp()-1;
|
||||
if (n->cdr->cdr->car) {
|
||||
int base = cursp()-1;
|
||||
int nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
|
||||
|
||||
/* copy receiver and arguments */
|
||||
nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1);
|
||||
if (nargs >= 0) {
|
||||
int i;
|
||||
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), base));
|
||||
for (i=0; i<nargs; i++) {
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
|
||||
}
|
||||
push_n(nargs+1);
|
||||
pop_n(nargs+1);
|
||||
callargs = nargs;
|
||||
}
|
||||
else {
|
||||
/* varargs */
|
||||
else { /* varargs */
|
||||
push();
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), base));
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp()+1, base+1));
|
||||
nargs = 1;
|
||||
callargs = CALL_MAXARGS;
|
||||
}
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
|
||||
}
|
||||
else {
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), cursp()-1));
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, 0));
|
||||
callargs = 0;
|
||||
/* copy receiver and arguments */
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp(), base));
|
||||
for (i=0; i<nargs; i++) {
|
||||
genop(s, MKOP_AB(OP_MOVE, cursp()+i+1, base+i+1));
|
||||
}
|
||||
push_n(nargs+2);pop_n(nargs+2); /* space for receiver, arguments and a block */
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
|
||||
push();
|
||||
}
|
||||
else {
|
||||
@@ -1872,21 +1907,18 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
if (val && vsp >= 0) {
|
||||
genop(s, MKOP_AB(OP_MOVE, vsp, cursp()));
|
||||
}
|
||||
if ((intptr_t)tree->car->car == NODE_CALL) {
|
||||
mrb_sym m = sym(tree->car->cdr->cdr->car);
|
||||
mrb_sym m2 = attrsym(s, m);
|
||||
|
||||
idx = new_msym(s, m2);
|
||||
pop();
|
||||
if (nint(tree->car->car) == NODE_CALL) {
|
||||
if (callargs == CALL_MAXARGS) {
|
||||
genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
|
||||
pop();
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
|
||||
genop(s, MKOP_AB(OP_ARYPUSH, cursp(), cursp()+1));
|
||||
}
|
||||
else {
|
||||
pop_n(callargs);
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs+1));
|
||||
callargs++;
|
||||
}
|
||||
pop();
|
||||
idx = new_msym(s, attrsym(s, nsym(tree->car->cdr->cdr->car)));
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
|
||||
}
|
||||
else {
|
||||
gen_assignment(s, tree->car, cursp(), val);
|
||||
@@ -1942,7 +1974,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
callargs++;
|
||||
}
|
||||
pop();
|
||||
idx = new_msym(s, attrsym(s,sym(tree->car->cdr->cdr->car)));
|
||||
idx = new_msym(s, attrsym(s,nsym(tree->car->cdr->cdr->car)));
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), idx, callargs));
|
||||
}
|
||||
}
|
||||
@@ -2048,6 +2080,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
push();
|
||||
}
|
||||
}
|
||||
push();pop(); /* space for a block */
|
||||
pop_n(n+1);
|
||||
genop(s, MKOP_ABx(OP_BLKPUSH, cursp(), (ainfo<<4)|(lv & 0xf)));
|
||||
if (sendv) n = CALL_MAXARGS;
|
||||
@@ -2070,6 +2103,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
|
||||
}
|
||||
codegen(s, tree, NOVAL);
|
||||
distcheck(s, s->loop->pc1 - s->pc);
|
||||
genop(s, MKOP_sBx(OP_JMP, s->loop->pc1 - s->pc));
|
||||
}
|
||||
else {
|
||||
@@ -2093,6 +2127,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
if (s->ensure_level > s->loop->ensure_level) {
|
||||
genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - s->loop->ensure_level), NOVAL);
|
||||
}
|
||||
distcheck(s, s->loop->pc2 - s->pc);
|
||||
genop(s, MKOP_sBx(OP_JMP, s->loop->pc2 - s->pc));
|
||||
}
|
||||
if (val) push();
|
||||
@@ -2120,13 +2155,12 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
}
|
||||
else {
|
||||
if (n > 0) {
|
||||
while (n--) {
|
||||
genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
|
||||
}
|
||||
genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL);
|
||||
}
|
||||
if (s->ensure_level > lp->ensure_level) {
|
||||
genop_peep(s, MKOP_A(OP_EPOP, s->ensure_level - lp->ensure_level), NOVAL);
|
||||
}
|
||||
distcheck(s, s->loop->pc1 - s->pc);
|
||||
genop(s, MKOP_sBx(OP_JMP, lp->pc1 - s->pc));
|
||||
}
|
||||
}
|
||||
@@ -2136,7 +2170,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_LVAR:
|
||||
if (val) {
|
||||
int idx = lv_idx(s, sym(tree));
|
||||
int idx = lv_idx(s, nsym(tree));
|
||||
|
||||
if (idx > 0) {
|
||||
genop_peep(s, MKOP_AB(OP_MOVE, cursp(), idx), NOVAL);
|
||||
@@ -2146,9 +2180,9 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen_scope *up = s->prev;
|
||||
|
||||
while (up) {
|
||||
idx = lv_idx(up, sym(tree));
|
||||
idx = lv_idx(up, nsym(tree));
|
||||
if (idx > 0) {
|
||||
genop(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv));
|
||||
genop_peep(s, MKOP_ABC(OP_GETUPVAR, cursp(), idx, lv), VAL);
|
||||
break;
|
||||
}
|
||||
lv++;
|
||||
@@ -2161,7 +2195,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_GVAR:
|
||||
if (val) {
|
||||
int sym = new_sym(s, sym(tree));
|
||||
int sym = new_sym(s, nsym(tree));
|
||||
|
||||
genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
|
||||
push();
|
||||
@@ -2170,7 +2204,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_IVAR:
|
||||
if (val) {
|
||||
int sym = new_sym(s, sym(tree));
|
||||
int sym = new_sym(s, nsym(tree));
|
||||
|
||||
genop(s, MKOP_ABx(OP_GETIV, cursp(), sym));
|
||||
push();
|
||||
@@ -2179,7 +2213,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_CVAR:
|
||||
if (val) {
|
||||
int sym = new_sym(s, sym(tree));
|
||||
int sym = new_sym(s, nsym(tree));
|
||||
|
||||
genop(s, MKOP_ABx(OP_GETCV, cursp(), sym));
|
||||
push();
|
||||
@@ -2188,7 +2222,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_CONST:
|
||||
{
|
||||
int sym = new_sym(s, sym(tree));
|
||||
int sym = new_sym(s, nsym(tree));
|
||||
|
||||
genop(s, MKOP_ABx(OP_GETCONST, cursp(), sym));
|
||||
if (val) {
|
||||
@@ -2207,7 +2241,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
int sym;
|
||||
|
||||
buf[0] = '$';
|
||||
buf[1] = (char)(intptr_t)tree;
|
||||
buf[1] = nchar(tree);
|
||||
buf[2] = 0;
|
||||
sym = new_sym(s, mrb_intern_cstr(s->mrb, buf));
|
||||
genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
|
||||
@@ -2221,7 +2255,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
mrb_value str;
|
||||
int sym;
|
||||
|
||||
str = mrb_format(mrb, "$%S", mrb_fixnum_value((mrb_int)(intptr_t)tree));
|
||||
str = mrb_format(mrb, "$%S", mrb_fixnum_value(nint(tree)));
|
||||
sym = new_sym(s, mrb_intern_str(mrb, str));
|
||||
genop(s, MKOP_ABx(OP_GETGLOBAL, cursp(), sym));
|
||||
push();
|
||||
@@ -2239,19 +2273,22 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
case NODE_INT:
|
||||
if (val) {
|
||||
char *p = (char*)tree->car;
|
||||
int base = (intptr_t)tree->cdr->car;
|
||||
int base = nint(tree->cdr->car);
|
||||
mrb_int i;
|
||||
mrb_code co;
|
||||
mrb_bool overflow;
|
||||
|
||||
i = readint_mrb_int(s, p, base, FALSE, &overflow);
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
if (overflow) {
|
||||
double f = readint_float(s, p, base);
|
||||
int off = new_lit(s, mrb_float_value(s->mrb, f));
|
||||
|
||||
genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
|
||||
}
|
||||
else {
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (i < MAXARG_sBx && i > -MAXARG_sBx) {
|
||||
co = MKOP_AsBx(OP_LOADI, cursp(), i);
|
||||
}
|
||||
@@ -2265,6 +2302,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
}
|
||||
break;
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
case NODE_FLOAT:
|
||||
if (val) {
|
||||
char *p = (char*)tree;
|
||||
@@ -2275,12 +2313,14 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
push();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NODE_NEGATE:
|
||||
{
|
||||
nt = (intptr_t)tree->car;
|
||||
nt = nint(tree->car);
|
||||
tree = tree->cdr;
|
||||
switch (nt) {
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
case NODE_FLOAT:
|
||||
if (val) {
|
||||
char *p = (char*)tree;
|
||||
@@ -2291,16 +2331,18 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
push();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case NODE_INT:
|
||||
if (val) {
|
||||
char *p = (char*)tree->car;
|
||||
int base = (intptr_t)tree->cdr->car;
|
||||
int base = nint(tree->cdr->car);
|
||||
mrb_int i;
|
||||
mrb_code co;
|
||||
mrb_bool overflow;
|
||||
|
||||
i = readint_mrb_int(s, p, base, TRUE, &overflow);
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
if (overflow) {
|
||||
double f = readint_float(s, p, base);
|
||||
int off = new_lit(s, mrb_float_value(s->mrb, -f));
|
||||
@@ -2308,6 +2350,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
genop(s, MKOP_ABx(OP_LOADL, cursp(), off));
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
if (i < MAXARG_sBx && i > -MAXARG_sBx) {
|
||||
co = MKOP_AsBx(OP_LOADI, cursp(), i);
|
||||
}
|
||||
@@ -2316,7 +2359,9 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
co = MKOP_ABx(OP_LOADL, cursp(), off);
|
||||
}
|
||||
genop(s, co);
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
}
|
||||
#endif
|
||||
push();
|
||||
}
|
||||
break;
|
||||
@@ -2378,7 +2423,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
node *n = tree;
|
||||
|
||||
while (n) {
|
||||
if ((intptr_t)n->car->car != NODE_STR) {
|
||||
if (nint(n->car->car) != NODE_STR) {
|
||||
codegen(s, n->car, NOVAL);
|
||||
}
|
||||
n = n->cdr;
|
||||
@@ -2405,7 +2450,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen(s, tree->car, VAL);
|
||||
n = tree->cdr;
|
||||
while (n) {
|
||||
if ((intptr_t)n->car->car == NODE_XSTR) {
|
||||
if (nint(n->car->car) == NODE_XSTR) {
|
||||
n->car->car = (struct mrb_ast_node*)(intptr_t)NODE_STR;
|
||||
mrb_assert(!n->cdr); /* must be the end */
|
||||
}
|
||||
@@ -2458,26 +2503,26 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
genop(s, MKOP_ABx(OP_GETMCNST, cursp(), sym));
|
||||
push();
|
||||
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
|
||||
push();
|
||||
if (p2 || p3) {
|
||||
push();
|
||||
if (p2) {
|
||||
if (p2) { /* opt */
|
||||
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
|
||||
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
|
||||
}
|
||||
else {
|
||||
genop(s, MKOP_A(OP_LOADNIL, cursp()));
|
||||
}
|
||||
push();
|
||||
argc++;
|
||||
if (p3) {
|
||||
push();
|
||||
if (p3) { /* enc */
|
||||
off = new_lit(s, mrb_str_new(s->mrb, p3, 1));
|
||||
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
|
||||
push();
|
||||
argc++;
|
||||
pop();
|
||||
}
|
||||
pop();
|
||||
}
|
||||
pop();
|
||||
push(); /* space for a block */
|
||||
pop_n(argc+2);
|
||||
sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
|
||||
mrb_gc_arena_restore(s->mrb, ai);
|
||||
@@ -2507,31 +2552,31 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
n = n->cdr;
|
||||
}
|
||||
n = tree->cdr->cdr;
|
||||
if (n->car) {
|
||||
if (n->car) { /* tail */
|
||||
p = (char*)n->car;
|
||||
off = new_lit(s, mrb_str_new_cstr(s->mrb, p));
|
||||
codegen(s, tree->car, VAL);
|
||||
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
|
||||
pop();
|
||||
genop_peep(s, MKOP_AB(OP_STRCAT, cursp(), cursp()+1), VAL);
|
||||
push();
|
||||
}
|
||||
if (n->cdr->car) {
|
||||
if (n->cdr->car) { /* opt */
|
||||
char *p2 = (char*)n->cdr->car;
|
||||
|
||||
push();
|
||||
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
|
||||
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
|
||||
push();
|
||||
argc++;
|
||||
}
|
||||
if (n->cdr->cdr) {
|
||||
if (n->cdr->cdr) { /* enc */
|
||||
char *p2 = (char*)n->cdr->cdr;
|
||||
|
||||
push();
|
||||
off = new_lit(s, mrb_str_new_cstr(s->mrb, p2));
|
||||
genop(s, MKOP_ABx(OP_STRING, cursp(), off));
|
||||
push();
|
||||
argc++;
|
||||
}
|
||||
pop_n(argc);
|
||||
push(); /* space for a block */
|
||||
pop_n(argc+2);
|
||||
sym = new_sym(s, mrb_intern_lit(s->mrb, "compile"));
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), sym, argc));
|
||||
mrb_gc_arena_restore(s->mrb, ai);
|
||||
@@ -2541,7 +2586,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
node *n = tree->car;
|
||||
|
||||
while (n) {
|
||||
if ((intptr_t)n->car->car != NODE_STR) {
|
||||
if (nint(n->car->car) != NODE_STR) {
|
||||
codegen(s, n->car, NOVAL);
|
||||
}
|
||||
n = n->cdr;
|
||||
@@ -2551,7 +2596,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_SYM:
|
||||
if (val) {
|
||||
int sym = new_sym(s, sym(tree));
|
||||
int sym = new_sym(s, nsym(tree));
|
||||
|
||||
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), sym));
|
||||
push();
|
||||
@@ -2595,8 +2640,8 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_ALIAS:
|
||||
{
|
||||
int a = new_msym(s, sym(tree->car));
|
||||
int b = new_msym(s, sym(tree->cdr));
|
||||
int a = new_msym(s, nsym(tree->car));
|
||||
int b = new_msym(s, nsym(tree->cdr));
|
||||
int c = new_msym(s, mrb_intern_lit(s->mrb, "alias_method"));
|
||||
|
||||
genop(s, MKOP_A(OP_TCLASS, cursp()));
|
||||
@@ -2606,7 +2651,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), b));
|
||||
push();
|
||||
genop(s, MKOP_A(OP_LOADNIL, cursp()));
|
||||
push();
|
||||
push(); /* space for a block */
|
||||
pop_n(4);
|
||||
genop(s, MKOP_ABC(OP_SEND, cursp(), c, 2));
|
||||
if (val) {
|
||||
@@ -2629,7 +2674,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
pop_n(num);
|
||||
genop(s, MKOP_ABC(OP_ARRAY, cursp(), cursp(), num));
|
||||
while (t) {
|
||||
symbol = new_msym(s, sym(t->car));
|
||||
symbol = new_msym(s, nsym(t->car));
|
||||
push();
|
||||
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
|
||||
pop();
|
||||
@@ -2639,12 +2684,13 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
num = CALL_MAXARGS;
|
||||
break;
|
||||
}
|
||||
symbol = new_msym(s, sym(t->car));
|
||||
symbol = new_msym(s, nsym(t->car));
|
||||
genop(s, MKOP_ABx(OP_LOADSYM, cursp(), symbol));
|
||||
push();
|
||||
t = t->cdr;
|
||||
num++;
|
||||
}
|
||||
push();pop(); /* space for a block */
|
||||
pop();
|
||||
if (num < CALL_MAXARGS) {
|
||||
pop_n(num);
|
||||
@@ -2679,7 +2725,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
push();
|
||||
}
|
||||
pop(); pop();
|
||||
idx = new_msym(s, sym(tree->car->cdr));
|
||||
idx = new_msym(s, nsym(tree->car->cdr));
|
||||
genop(s, MKOP_AB(OP_CLASS, cursp(), idx));
|
||||
idx = scope_body(s, tree->cdr->cdr->car, val);
|
||||
genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
|
||||
@@ -2705,7 +2751,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
codegen(s, tree->car->car, VAL);
|
||||
}
|
||||
pop();
|
||||
idx = new_msym(s, sym(tree->car->cdr));
|
||||
idx = new_msym(s, nsym(tree->car->cdr));
|
||||
genop(s, MKOP_AB(OP_MODULE, cursp(), idx));
|
||||
idx = scope_body(s, tree->cdr->car, val);
|
||||
genop(s, MKOP_ABx(OP_EXEC, cursp(), idx));
|
||||
@@ -2732,7 +2778,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
|
||||
case NODE_DEF:
|
||||
{
|
||||
int sym = new_msym(s, sym(tree->car));
|
||||
int sym = new_msym(s, nsym(tree->car));
|
||||
int idx = lambda_body(s, tree->cdr, 0);
|
||||
|
||||
genop(s, MKOP_A(OP_TCLASS, cursp()));
|
||||
@@ -2751,7 +2797,7 @@ codegen(codegen_scope *s, node *tree, int val)
|
||||
case NODE_SDEF:
|
||||
{
|
||||
node *recv = tree->car;
|
||||
int sym = new_msym(s, sym(tree->cdr->car));
|
||||
int sym = new_msym(s, nsym(tree->cdr->car));
|
||||
int idx = lambda_body(s, tree->cdr->cdr, 0);
|
||||
|
||||
codegen(s, recv, VAL);
|
||||
@@ -2938,23 +2984,32 @@ loop_break(codegen_scope *s, node *tree)
|
||||
}
|
||||
else {
|
||||
struct loopinfo *loop;
|
||||
int n = 0;
|
||||
|
||||
if (tree) {
|
||||
gen_retval(s, tree);
|
||||
}
|
||||
|
||||
loop = s->loop;
|
||||
while (loop && loop->type == LOOP_BEGIN) {
|
||||
genop_peep(s, MKOP_A(OP_POPERR, 1), NOVAL);
|
||||
loop = loop->prev;
|
||||
}
|
||||
while (loop && loop->type == LOOP_RESCUE) {
|
||||
loop = loop->prev;
|
||||
while (loop) {
|
||||
if (loop->type == LOOP_BEGIN) {
|
||||
n++;
|
||||
loop = loop->prev;
|
||||
}
|
||||
else if (loop->type == LOOP_RESCUE) {
|
||||
loop = loop->prev;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!loop) {
|
||||
raise_error(s, "unexpected break");
|
||||
return;
|
||||
}
|
||||
if (n > 0) {
|
||||
genop_peep(s, MKOP_A(OP_POPERR, n), NOVAL);
|
||||
}
|
||||
|
||||
if (loop->type == LOOP_NORMAL) {
|
||||
int tmp;
|
||||
@@ -2965,6 +3020,7 @@ loop_break(codegen_scope *s, node *tree)
|
||||
if (tree) {
|
||||
genop_peep(s, MKOP_AB(OP_MOVE, loop->acc, cursp()), NOVAL);
|
||||
}
|
||||
distcheck(s, s->loop->pc3);
|
||||
tmp = genop(s, MKOP_sBx(OP_JMP, loop->pc3));
|
||||
loop->pc3 = tmp;
|
||||
}
|
||||
@@ -2980,10 +3036,10 @@ loop_break(codegen_scope *s, node *tree)
|
||||
static void
|
||||
loop_pop(codegen_scope *s, int val)
|
||||
{
|
||||
dispatch_linked(s, s->loop->pc3);
|
||||
if (val) {
|
||||
genop(s, MKOP_A(OP_LOADNIL, cursp()));
|
||||
}
|
||||
dispatch_linked(s, s->loop->pc3);
|
||||
s->loop = s->loop->prev;
|
||||
if (val) push();
|
||||
}
|
||||
@@ -3011,6 +3067,9 @@ mrb_generate_code(mrb_state *mrb, parser_state *p)
|
||||
mrb_irep_decref(mrb, scope->irep);
|
||||
mrb_pool_close(scope->mpool);
|
||||
proc->c = NULL;
|
||||
if (mrb->c->cibase && mrb->c->cibase->proc == proc->upper) {
|
||||
proc->upper = NULL;
|
||||
}
|
||||
mrb->jmp = prev_jmp;
|
||||
return proc;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ inline
|
||||
#endif
|
||||
#endif
|
||||
static unsigned int
|
||||
hash (register const char *str, register unsigned int len)
|
||||
hash (const char *str, unsigned int len)
|
||||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
@@ -83,7 +83,7 @@ hash (register const char *str, register unsigned int len)
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51
|
||||
};
|
||||
register int hval = len;
|
||||
int hval = len;
|
||||
|
||||
switch (hval)
|
||||
{
|
||||
@@ -105,7 +105,7 @@ __attribute__ ((__gnu_inline__))
|
||||
#endif
|
||||
#endif
|
||||
const struct kwtable *
|
||||
mrb_reserved_word (register const char *str, register unsigned int len)
|
||||
mrb_reserved_word (const char *str, unsigned int len)
|
||||
{
|
||||
static const struct kwtable wordlist[] =
|
||||
{
|
||||
@@ -196,11 +196,11 @@ mrb_reserved_word (register const char *str, register unsigned int len)
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
{
|
||||
register int key = hash (str, len);
|
||||
int key = hash (str, len);
|
||||
|
||||
if (key <= MAX_HASH_VALUE && key >= 0)
|
||||
{
|
||||
register const char *s = wordlist[key].name;
|
||||
const char *s = wordlist[key].name;
|
||||
|
||||
if (*str == *s && !strcmp (str + 1, s + 1))
|
||||
return &wordlist[key];
|
||||
@@ -209,4 +209,3 @@ mrb_reserved_word (register const char *str, register unsigned int len)
|
||||
return 0;
|
||||
}
|
||||
#line 50 "/home/matz/work/mruby/mrbgems/mruby-compiler/core/keywords"
|
||||
|
||||
|
||||
@@ -740,16 +740,18 @@ new_int(parser_state *p, const char *s, int base)
|
||||
return list3((node*)NODE_INT, (node*)strdup(s), nint(base));
|
||||
}
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
/* (:float . i) */
|
||||
static node*
|
||||
new_float(parser_state *p, const char *s)
|
||||
{
|
||||
return cons((node*)NODE_FLOAT, (node*)strdup(s));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* (:str . (s . len)) */
|
||||
static node*
|
||||
new_str(parser_state *p, const char *s, int len)
|
||||
new_str(parser_state *p, const char *s, size_t len)
|
||||
{
|
||||
return cons((node*)NODE_STR, cons((node*)strndup(s, len), nint(len)));
|
||||
}
|
||||
@@ -1384,7 +1386,7 @@ command_asgn : lhs '=' command_rhs
|
||||
backref_error(p, $1);
|
||||
$$ = new_begin(p, 0);
|
||||
}
|
||||
;
|
||||
;
|
||||
|
||||
command_rhs : command_call %prec tOP_ASGN
|
||||
| command_call modifier_rescue stmt
|
||||
@@ -2577,7 +2579,7 @@ do_block : keyword_do_block
|
||||
local_nest(p);
|
||||
}
|
||||
opt_block_param
|
||||
compstmt
|
||||
bodystmt
|
||||
keyword_end
|
||||
{
|
||||
$$ = new_block(p,$3,$4);
|
||||
@@ -2667,7 +2669,7 @@ brace_block : '{'
|
||||
$<num>$ = p->lineno;
|
||||
}
|
||||
opt_block_param
|
||||
compstmt keyword_end
|
||||
bodystmt keyword_end
|
||||
{
|
||||
$$ = new_block(p,$3,$4);
|
||||
SET_LINENO($$, $<num>2);
|
||||
@@ -2853,18 +2855,18 @@ words : tWORDS_BEG tSTRING
|
||||
|
||||
symbol : basic_symbol
|
||||
{
|
||||
p->lstate = EXPR_ENDARG;
|
||||
$$ = new_sym(p, $1);
|
||||
}
|
||||
| tSYMBEG tSTRING_BEG string_rep tSTRING
|
||||
{
|
||||
p->lstate = EXPR_END;
|
||||
p->lstate = EXPR_ENDARG;
|
||||
$$ = new_dsym(p, push($3, $4));
|
||||
}
|
||||
;
|
||||
|
||||
basic_symbol : tSYMBEG sym
|
||||
{
|
||||
p->lstate = EXPR_END;
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
@@ -2968,6 +2970,15 @@ var_ref : variable
|
||||
snprintf(buf, sizeof(buf), "%d", p->lineno);
|
||||
$$ = new_int(p, buf, 10);
|
||||
}
|
||||
| keyword__ENCODING__
|
||||
{
|
||||
#ifdef MRB_UTF8_STRING
|
||||
const char *enc = "UTF-8";
|
||||
#else
|
||||
const char *enc = "ASCII-8BIT";
|
||||
#endif
|
||||
$$ = new_str(p, enc, strlen(enc));
|
||||
}
|
||||
;
|
||||
|
||||
backref : tNTH_REF
|
||||
@@ -3361,7 +3372,7 @@ static void
|
||||
yyerror(parser_state *p, const char *s)
|
||||
{
|
||||
char* c;
|
||||
int n;
|
||||
size_t n;
|
||||
|
||||
if (! p->capture_errors) {
|
||||
#ifndef MRB_DISABLE_STDIO
|
||||
@@ -3397,7 +3408,7 @@ static void
|
||||
yywarn(parser_state *p, const char *s)
|
||||
{
|
||||
char* c;
|
||||
int n;
|
||||
size_t n;
|
||||
|
||||
if (! p->capture_errors) {
|
||||
#ifndef MRB_DISABLE_STDIO
|
||||
@@ -3443,7 +3454,7 @@ backref_error(parser_state *p, node *n)
|
||||
c = (int)(intptr_t)n->car;
|
||||
|
||||
if (c == NODE_NTH_REF) {
|
||||
yyerror_i(p, "can't set variable $%" MRB_PRId, (mrb_int)(intptr_t)n->cdr);
|
||||
yyerror_i(p, "can't set variable $%" MRB_PRId, (int)(intptr_t)n->cdr);
|
||||
}
|
||||
else if (c == NODE_BACK_REF) {
|
||||
yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr);
|
||||
@@ -3593,7 +3604,7 @@ peek_n(parser_state *p, int c, int n)
|
||||
static mrb_bool
|
||||
peeks(parser_state *p, const char *s)
|
||||
{
|
||||
int len = strlen(s);
|
||||
size_t len = strlen(s);
|
||||
|
||||
#ifndef MRB_DISABLE_STDIO
|
||||
if (p->f) {
|
||||
@@ -3629,7 +3640,7 @@ skips(parser_state *p, const char *s)
|
||||
}
|
||||
s++;
|
||||
if (peeks(p, s)) {
|
||||
int len = strlen(s);
|
||||
size_t len = strlen(s);
|
||||
|
||||
while (len--) {
|
||||
if (nextc(p) == '\n') {
|
||||
@@ -3751,28 +3762,28 @@ toklen(parser_state *p)
|
||||
#define IS_LABEL_POSSIBLE() ((p->lstate == EXPR_BEG && !cmd_state) || IS_ARG())
|
||||
#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
|
||||
|
||||
static int
|
||||
static int32_t
|
||||
scan_oct(const int *start, int len, int *retlen)
|
||||
{
|
||||
const int *s = start;
|
||||
int retval = 0;
|
||||
int32_t retval = 0;
|
||||
|
||||
/* mrb_assert(len <= 3) */
|
||||
while (len-- && *s >= '0' && *s <= '7') {
|
||||
retval <<= 3;
|
||||
retval |= *s++ - '0';
|
||||
}
|
||||
*retlen = s - start;
|
||||
*retlen = (int)(s - start);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
scan_hex(const int *start, int len, int *retlen)
|
||||
scan_hex(parser_state *p, const int *start, int len, int *retlen)
|
||||
{
|
||||
static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
|
||||
const int *s = start;
|
||||
int32_t retval = 0;
|
||||
uint32_t retval = 0;
|
||||
char *tmp;
|
||||
|
||||
/* mrb_assert(len <= 8) */
|
||||
@@ -3781,22 +3792,26 @@ scan_hex(const int *start, int len, int *retlen)
|
||||
retval |= (tmp - hexdigit) & 15;
|
||||
s++;
|
||||
}
|
||||
*retlen = s - start;
|
||||
*retlen = (int)(s - start);
|
||||
|
||||
return retval;
|
||||
return (int32_t)retval;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
read_escape_unicode(parser_state *p, int limit)
|
||||
{
|
||||
int32_t c;
|
||||
int buf[9];
|
||||
int i;
|
||||
int32_t hex;
|
||||
|
||||
/* Look for opening brace */
|
||||
i = 0;
|
||||
buf[0] = nextc(p);
|
||||
if (buf[0] < 0) goto eof;
|
||||
if (buf[0] < 0) {
|
||||
eof:
|
||||
yyerror(p, "invalid escape character syntax");
|
||||
return -1;
|
||||
}
|
||||
if (ISXDIGIT(buf[0])) {
|
||||
/* \uxxxx form */
|
||||
for (i=1; i<limit; i++) {
|
||||
@@ -3811,17 +3826,12 @@ read_escape_unicode(parser_state *p, int limit)
|
||||
else {
|
||||
pushback(p, buf[0]);
|
||||
}
|
||||
c = scan_hex(buf, i, &i);
|
||||
if (i == 0) {
|
||||
eof:
|
||||
yyerror(p, "Invalid escape character syntax");
|
||||
hex = scan_hex(p, buf, i, &i);
|
||||
if (i == 0 || hex > 0x10FFFF || (hex & 0xFFFFF800) == 0xD800) {
|
||||
yyerror(p, "invalid Unicode code point");
|
||||
return -1;
|
||||
}
|
||||
if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) {
|
||||
yyerror(p, "Invalid Unicode code point");
|
||||
return -1;
|
||||
}
|
||||
return c;
|
||||
return hex;
|
||||
}
|
||||
|
||||
/* Return negative to indicate Unicode code point */
|
||||
@@ -3887,13 +3897,12 @@ read_escape(parser_state *p)
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = scan_hex(buf, i, &i);
|
||||
if (i == 0) {
|
||||
yyerror(p, "Invalid escape character syntax");
|
||||
return 0;
|
||||
yyerror(p, "invalid hex escape");
|
||||
return -1;
|
||||
}
|
||||
return scan_hex(p, buf, i, &i);
|
||||
}
|
||||
return c;
|
||||
|
||||
case 'u': /* Unicode */
|
||||
if (peek(p, '{')) {
|
||||
@@ -3960,9 +3969,9 @@ parse_string(parser_state *p)
|
||||
{
|
||||
int c;
|
||||
string_type type = (string_type)(intptr_t)p->lex_strterm->car;
|
||||
int nest_level = (intptr_t)p->lex_strterm->cdr->car;
|
||||
int beg = (intptr_t)p->lex_strterm->cdr->cdr->car;
|
||||
int end = (intptr_t)p->lex_strterm->cdr->cdr->cdr;
|
||||
int nest_level = intn(p->lex_strterm->cdr->car);
|
||||
int beg = intn(p->lex_strterm->cdr->cdr->car);
|
||||
int end = intn(p->lex_strterm->cdr->cdr->cdr);
|
||||
parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
|
||||
int cmd_state = p->cmd_start;
|
||||
|
||||
@@ -4118,7 +4127,7 @@ parse_string(parser_state *p)
|
||||
}
|
||||
|
||||
tokfix(p);
|
||||
p->lstate = EXPR_END;
|
||||
p->lstate = EXPR_ENDARG;
|
||||
end_strterm(p);
|
||||
|
||||
if (type & STR_FUNC_XQUOTE) {
|
||||
@@ -4605,7 +4614,7 @@ parser_yylex(parser_state *p)
|
||||
}
|
||||
tokfix(p);
|
||||
pylval.nd = new_str(p, tok(p), toklen(p));
|
||||
p->lstate = EXPR_END;
|
||||
p->lstate = EXPR_ENDARG;
|
||||
return tCHAR;
|
||||
|
||||
case '&':
|
||||
@@ -4754,7 +4763,7 @@ parser_yylex(parser_state *p)
|
||||
int is_float, seen_point, seen_e, nondigit;
|
||||
|
||||
is_float = seen_point = seen_e = nondigit = 0;
|
||||
p->lstate = EXPR_END;
|
||||
p->lstate = EXPR_ENDARG;
|
||||
newtok(p);
|
||||
if (c == '-' || c == '+') {
|
||||
tokadd(p, c);
|
||||
@@ -4955,6 +4964,11 @@ parser_yylex(parser_state *p)
|
||||
}
|
||||
tokfix(p);
|
||||
if (is_float) {
|
||||
#ifdef MRB_WITHOUT_FLOAT
|
||||
yywarning_s(p, "floating point numbers are not supported", tok(p));
|
||||
pylval.nd = new_int(p, "0", 10);
|
||||
return tINTEGER;
|
||||
#else
|
||||
double d;
|
||||
char *endp;
|
||||
|
||||
@@ -4969,6 +4983,7 @@ parser_yylex(parser_state *p)
|
||||
}
|
||||
pylval.nd = new_float(p, tok(p));
|
||||
return tFLOAT;
|
||||
#endif
|
||||
}
|
||||
pylval.nd = new_int(p, tok(p), 10);
|
||||
return tINTEGER;
|
||||
@@ -4984,7 +4999,7 @@ parser_yylex(parser_state *p)
|
||||
if (c == ')')
|
||||
p->lstate = EXPR_ENDFN;
|
||||
else
|
||||
p->lstate = EXPR_ENDARG;
|
||||
p->lstate = EXPR_END;
|
||||
return c;
|
||||
|
||||
case ':':
|
||||
@@ -5071,6 +5086,9 @@ parser_yylex(parser_state *p)
|
||||
else if (IS_SPCARG(-1)) {
|
||||
c = tLPAREN_ARG;
|
||||
}
|
||||
else if (p->lstate == EXPR_END && space_seen) {
|
||||
c = tLPAREN_ARG;
|
||||
}
|
||||
p->paren_nest++;
|
||||
COND_PUSH(0);
|
||||
CMDARG_PUSH(0);
|
||||
@@ -5490,11 +5508,9 @@ parser_yylex(parser_state *p)
|
||||
mrb_sym ident = intern_cstr(tok(p));
|
||||
|
||||
pylval.id = ident;
|
||||
#if 0
|
||||
if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) {
|
||||
if (last_state != EXPR_DOT && islower(tok(p)[0]) && local_var_p(p, ident)) {
|
||||
p->lstate = EXPR_END;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -5558,7 +5574,7 @@ mrb_parser_parse(parser_state *p, mrbc_context *c)
|
||||
p->jmp = &buf1;
|
||||
|
||||
MRB_TRY(p->jmp) {
|
||||
int n;
|
||||
int n = 1;
|
||||
|
||||
p->cmd_start = TRUE;
|
||||
p->in_def = p->in_single = 0;
|
||||
@@ -5674,7 +5690,7 @@ MRB_API const char*
|
||||
mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s)
|
||||
{
|
||||
if (s) {
|
||||
int len = strlen(s);
|
||||
size_t len = strlen(s);
|
||||
char *p = (char *)mrb_malloc(mrb, len + 1);
|
||||
|
||||
memcpy(p, s, len + 1);
|
||||
@@ -5706,16 +5722,16 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
|
||||
|
||||
for (i = 0; i < p->filename_table_length; ++i) {
|
||||
if (p->filename_table[i] == sym) {
|
||||
p->current_filename_index = i;
|
||||
p->current_filename_index = (int)i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
p->current_filename_index = p->filename_table_length++;
|
||||
p->current_filename_index = (int)p->filename_table_length++;
|
||||
|
||||
new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length);
|
||||
if (p->filename_table) {
|
||||
memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length);
|
||||
memmove(new_table, p->filename_table, sizeof(mrb_sym) * p->current_filename_index);
|
||||
}
|
||||
p->filename_table = new_table;
|
||||
p->filename_table[p->filename_table_length - 1] = sym;
|
||||
@@ -5746,7 +5762,7 @@ mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c)
|
||||
#endif
|
||||
|
||||
MRB_API parser_state*
|
||||
mrb_parse_nstring(mrb_state *mrb, const char *s, int len, mrbc_context *c)
|
||||
mrb_parse_nstring(mrb_state *mrb, const char *s, size_t len, mrbc_context *c)
|
||||
{
|
||||
parser_state *p;
|
||||
|
||||
@@ -5777,6 +5793,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
|
||||
return mrb_undef_value();
|
||||
}
|
||||
if (!p->tree || p->nerr) {
|
||||
if (c) c->parser_nerr = p->nerr;
|
||||
if (p->capture_errors) {
|
||||
char buf[256];
|
||||
int n;
|
||||
@@ -5816,7 +5833,7 @@ mrb_load_exec(mrb_state *mrb, struct mrb_parser_state *p, mrbc_context *c)
|
||||
c->keep_lv = TRUE;
|
||||
}
|
||||
}
|
||||
proc->target_class = target;
|
||||
MRB_PROC_SET_TARGET_CLASS(proc, target);
|
||||
if (mrb->c->ci) {
|
||||
mrb->c->ci->target_class = target;
|
||||
}
|
||||
@@ -5840,13 +5857,13 @@ mrb_load_file(mrb_state *mrb, FILE *f)
|
||||
#endif
|
||||
|
||||
MRB_API mrb_value
|
||||
mrb_load_nstring_cxt(mrb_state *mrb, const char *s, int len, mrbc_context *c)
|
||||
mrb_load_nstring_cxt(mrb_state *mrb, const char *s, size_t len, mrbc_context *c)
|
||||
{
|
||||
return mrb_load_exec(mrb, mrb_parse_nstring(mrb, s, len, c), c);
|
||||
}
|
||||
|
||||
MRB_API mrb_value
|
||||
mrb_load_nstring(mrb_state *mrb, const char *s, int len)
|
||||
mrb_load_nstring(mrb_state *mrb, const char *s, size_t len)
|
||||
{
|
||||
return mrb_load_nstring_cxt(mrb, s, len, NULL);
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ module Enumerable
|
||||
ary.push([block.call(e), i])
|
||||
}
|
||||
if ary.size > 1
|
||||
__sort_sub__(ary, ::Array.new(ary.size), 0, 0, ary.size - 1) do |a,b|
|
||||
__sort_sub__(ary, 0, ary.size - 1) do |a,b|
|
||||
a <=> b
|
||||
end
|
||||
end
|
||||
@@ -451,20 +451,30 @@ module Enumerable
|
||||
##
|
||||
# call-seq:
|
||||
# enum.none? [{ |obj| block }] -> true or false
|
||||
# enum.none?(pattern) -> true or false
|
||||
#
|
||||
# Passes each element of the collection to the given block. The method
|
||||
# returns <code>true</code> if the block never returns <code>true</code>
|
||||
# for all elements. If the block is not given, <code>none?</code> will return
|
||||
# <code>true</code> only if none of the collection members is true.
|
||||
#
|
||||
# If a pattern is supplied instead, the method returns whether
|
||||
# <code>pattern === element</code> for none of the collection members.
|
||||
#
|
||||
# %w(ant bear cat).none? { |word| word.length == 5 } #=> true
|
||||
# %w(ant bear cat).none? { |word| word.length >= 4 } #=> false
|
||||
# %w{ant bear cat}.none?(/d/) #=> true
|
||||
# [1, 3.14, 42].none?(Float) #=> false
|
||||
# [].none? #=> true
|
||||
# [nil, false].none? #=> true
|
||||
# [nil, true].none? #=> false
|
||||
|
||||
def none?(&block)
|
||||
if block
|
||||
def none?(pat=NONE, &block)
|
||||
if pat != NONE
|
||||
self.each do |*val|
|
||||
return false if pat === val.__svalue
|
||||
end
|
||||
elsif block
|
||||
self.each do |*val|
|
||||
return false if block.call(*val)
|
||||
end
|
||||
@@ -479,6 +489,7 @@ module Enumerable
|
||||
##
|
||||
# call-seq:
|
||||
# enum.one? [{ |obj| block }] -> true or false
|
||||
# enum.one?(pattern) -> true or false
|
||||
#
|
||||
# Passes each element of the collection to the given block. The method
|
||||
# returns <code>true</code> if the block returns <code>true</code>
|
||||
@@ -486,16 +497,26 @@ module Enumerable
|
||||
# <code>true</code> only if exactly one of the collection members is
|
||||
# true.
|
||||
#
|
||||
# If a pattern is supplied instead, the method returns whether
|
||||
# <code>pattern === element</code> for exactly one collection member.
|
||||
#
|
||||
# %w(ant bear cat).one? { |word| word.length == 4 } #=> true
|
||||
# %w(ant bear cat).one? { |word| word.length > 4 } #=> false
|
||||
# %w(ant bear cat).one? { |word| word.length < 4 } #=> false
|
||||
# %w{ant bear cat}.one?(/t/) #=> false
|
||||
# [nil, true, 99].one? #=> false
|
||||
# [nil, true, false].one? #=> true
|
||||
#
|
||||
# [ nil, true, 99 ].one?(Integer) #=> true
|
||||
# [].one? #=> false
|
||||
|
||||
def one?(&block)
|
||||
def one?(pat=NONE, &block)
|
||||
count = 0
|
||||
if block
|
||||
if pat!=NONE
|
||||
self.each do |*val|
|
||||
count += 1 if pat === val.__svalue
|
||||
return false if count > 1
|
||||
end
|
||||
elsif block
|
||||
self.each do |*val|
|
||||
count += 1 if block.call(*val)
|
||||
return false if count > 1
|
||||
@@ -510,6 +531,71 @@ module Enumerable
|
||||
count == 1 ? true : false
|
||||
end
|
||||
|
||||
# ISO 15.3.2.2.1
|
||||
# call-seq:
|
||||
# enum.all? [{ |obj| block } ] -> true or false
|
||||
# enum.all?(pattern) -> true or false
|
||||
#
|
||||
# Passes each element of the collection to the given block. The method
|
||||
# returns <code>true</code> if the block never returns
|
||||
# <code>false</code> or <code>nil</code>. If the block is not given,
|
||||
# Ruby adds an implicit block of <code>{ |obj| obj }</code> which will
|
||||
# cause #all? to return +true+ when none of the collection members are
|
||||
# +false+ or +nil+.
|
||||
#
|
||||
# If a pattern is supplied instead, the method returns whether
|
||||
# <code>pattern === element</code> for every collection member.
|
||||
#
|
||||
# %w[ant bear cat].all? { |word| word.length >= 3 } #=> true
|
||||
# %w[ant bear cat].all? { |word| word.length >= 4 } #=> false
|
||||
# %w[ant bear cat].all?(/t/) #=> false
|
||||
# [1, 2i, 3.14].all?(Numeric) #=> true
|
||||
# [nil, true, 99].all? #=> false
|
||||
#
|
||||
def all?(pat=NONE, &block)
|
||||
if pat != NONE
|
||||
self.each{|*val| return false unless pat === val.__svalue}
|
||||
elsif block
|
||||
self.each{|*val| return false unless block.call(*val)}
|
||||
else
|
||||
self.each{|*val| return false unless val.__svalue}
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# ISO 15.3.2.2.2
|
||||
# call-seq:
|
||||
# enum.any? [{ |obj| block }] -> true or false
|
||||
# enum.any?(pattern) -> true or false
|
||||
#
|
||||
# Passes each element of the collection to the given block. The method
|
||||
# returns <code>true</code> if the block ever returns a value other
|
||||
# than <code>false</code> or <code>nil</code>. If the block is not
|
||||
# given, Ruby adds an implicit block of <code>{ |obj| obj }</code> that
|
||||
# will cause #any? to return +true+ if at least one of the collection
|
||||
# members is not +false+ or +nil+.
|
||||
#
|
||||
# If a pattern is supplied instead, the method returns whether
|
||||
# <code>pattern === element</code> for any collection member.
|
||||
#
|
||||
# %w[ant bear cat].any? { |word| word.length >= 3 } #=> true
|
||||
# %w[ant bear cat].any? { |word| word.length >= 4 } #=> true
|
||||
# %w[ant bear cat].any?(/d/) #=> false
|
||||
# [nil, true, 99].any?(Integer) #=> true
|
||||
# [nil, true, 99].any? #=> true
|
||||
# [].any? #=> false
|
||||
#
|
||||
def any?(pat=NONE, &block)
|
||||
if pat != NONE
|
||||
self.each{|*val| return true if pat === val.__svalue}
|
||||
elsif block
|
||||
self.each{|*val| return true if block.call(*val)}
|
||||
else
|
||||
self.each{|*val| return true if val.__svalue}
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj
|
||||
@@ -708,4 +794,20 @@ module Enumerable
|
||||
def nil.to_h
|
||||
{}
|
||||
end
|
||||
|
||||
def uniq(&block)
|
||||
hash = {}
|
||||
if block
|
||||
self.each do|*v|
|
||||
v = v.__svalue
|
||||
hash[block.call(v)] ||= v
|
||||
end
|
||||
else
|
||||
self.each do|*v|
|
||||
v = v.__svalue
|
||||
hash[v] ||= v
|
||||
end
|
||||
end
|
||||
hash.values
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,6 +100,7 @@ end
|
||||
assert("Enumerable#none?") do
|
||||
assert_true %w(ant bear cat).none? { |word| word.length == 5 }
|
||||
assert_false %w(ant bear cat).none? { |word| word.length >= 4 }
|
||||
assert_false [1, 3.14, 42].none?(Float)
|
||||
assert_true [].none?
|
||||
assert_true [nil, false].none?
|
||||
assert_false [nil, true].none?
|
||||
@@ -109,8 +110,21 @@ assert("Enumerable#one?") do
|
||||
assert_true %w(ant bear cat).one? { |word| word.length == 4 }
|
||||
assert_false %w(ant bear cat).one? { |word| word.length > 4 }
|
||||
assert_false %w(ant bear cat).one? { |word| word.length < 4 }
|
||||
assert_true [1, 3.14, 42].one?(Float)
|
||||
assert_false [nil, true, 99].one?
|
||||
assert_true [nil, true, false].one?
|
||||
assert_true [ nil, true, 99 ].one?(Integer)
|
||||
assert_false [].one?
|
||||
end
|
||||
|
||||
assert("Enumerable#all? (enhancement)") do
|
||||
assert_false [1, 2, 3.14].all?(Integer)
|
||||
assert_true [1, 2, 3.14].all?(Numeric)
|
||||
end
|
||||
|
||||
assert("Enumerable#any? (enhancement)") do
|
||||
assert_false [1, 2, 3].all?(Float)
|
||||
assert_true [nil, true, 99].any?(Integer)
|
||||
end
|
||||
|
||||
assert("Enumerable#each_with_object") do
|
||||
|
||||
@@ -43,6 +43,9 @@ class Enumerator
|
||||
end
|
||||
|
||||
def to_enum(meth=:each, *args, &block)
|
||||
unless self.respond_to?(meth)
|
||||
raise NoMethodError, "undefined method #{meth}"
|
||||
end
|
||||
lz = Lazy.new(self, &block)
|
||||
lz.obj = self
|
||||
lz.meth = meth
|
||||
@@ -69,7 +72,7 @@ class Enumerator
|
||||
|
||||
def reject(&block)
|
||||
Lazy.new(self){|yielder, val|
|
||||
if not block.call(val)
|
||||
unless block.call(val)
|
||||
yielder << val
|
||||
end
|
||||
}
|
||||
@@ -155,6 +158,21 @@ class Enumerator
|
||||
}
|
||||
end
|
||||
|
||||
def uniq(&block)
|
||||
hash = {}
|
||||
Lazy.new(self){|yielder, val|
|
||||
if block
|
||||
v = block.call(val)
|
||||
else
|
||||
v = val
|
||||
end
|
||||
unless hash.include?(v)
|
||||
yielder << val
|
||||
hash[v] = val
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
alias force to_a
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,11 +110,14 @@ class Enumerator
|
||||
# p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
|
||||
#
|
||||
def initialize(obj=nil, meth=:each, *args, &block)
|
||||
if block_given?
|
||||
if block
|
||||
obj = Generator.new(&block)
|
||||
else
|
||||
raise ArgumentError unless obj
|
||||
end
|
||||
if @obj and !self.respond_to?(meth)
|
||||
raise NoMethodError, "undefined method #{meth}"
|
||||
end
|
||||
|
||||
@obj = obj
|
||||
@meth = meth
|
||||
@@ -151,8 +154,9 @@ class Enumerator
|
||||
#
|
||||
# +offset+:: the starting index to use
|
||||
#
|
||||
def with_index(offset=0)
|
||||
return to_enum :with_index, offset unless block_given?
|
||||
def with_index(offset=0, &block)
|
||||
return to_enum :with_index, offset unless block
|
||||
|
||||
offset = if offset.nil?
|
||||
0
|
||||
elsif offset.respond_to?(:to_int)
|
||||
@@ -164,7 +168,7 @@ class Enumerator
|
||||
n = offset - 1
|
||||
enumerator_block_call do |*i|
|
||||
n += 1
|
||||
yield i.__svalue, n
|
||||
block.call i.__svalue, n
|
||||
end
|
||||
end
|
||||
|
||||
@@ -209,11 +213,11 @@ class Enumerator
|
||||
# # => foo:1
|
||||
# # => foo:2
|
||||
#
|
||||
def with_object(object)
|
||||
return to_enum(:with_object, object) unless block_given?
|
||||
def with_object(object, &block)
|
||||
return to_enum(:with_object, object) unless block
|
||||
|
||||
enumerator_block_call do |i|
|
||||
yield [i,object]
|
||||
block.call [i,object]
|
||||
end
|
||||
object
|
||||
end
|
||||
@@ -277,7 +281,7 @@ class Enumerator
|
||||
end
|
||||
obj.args = args
|
||||
end
|
||||
return obj unless block_given?
|
||||
return obj unless block
|
||||
enumerator_block_call(&block)
|
||||
end
|
||||
|
||||
@@ -538,7 +542,7 @@ class Enumerator
|
||||
# just for internal
|
||||
class Yielder
|
||||
def initialize(&block)
|
||||
raise LocalJumpError, "no block given" unless block_given?
|
||||
raise LocalJumpError, "no block given" unless block
|
||||
|
||||
@proc = block
|
||||
end
|
||||
@@ -612,7 +616,7 @@ module Kernel
|
||||
def to_enum(meth=:each, *args)
|
||||
Enumerator.new self, meth, *args
|
||||
end
|
||||
alias :enum_for :to_enum
|
||||
alias enum_for to_enum
|
||||
end
|
||||
|
||||
module Enumerable
|
||||
|
||||
@@ -33,7 +33,7 @@ assert 'Enumerator.new' do
|
||||
a, b = b, a + b
|
||||
end
|
||||
end
|
||||
assert_equal fib.take(10), [1,1,2,3,5,8,13,21,34,55]
|
||||
assert_equal [1,1,2,3,5,8,13,21,34,55], fib.take(10)
|
||||
end
|
||||
|
||||
assert 'Enumerator#initialize_copy' do
|
||||
@@ -509,28 +509,28 @@ end
|
||||
|
||||
assert 'Hash#select' do
|
||||
h = {1=>2,3=>4,5=>6}
|
||||
hret = h.select.with_index {|a,b| a[1] == 4}
|
||||
hret = h.select.with_index {|a,_b| a[1] == 4}
|
||||
assert_equal({3=>4}, hret)
|
||||
assert_equal({1=>2,3=>4,5=>6}, h)
|
||||
end
|
||||
|
||||
assert 'Hash#select!' do
|
||||
h = {1=>2,3=>4,5=>6}
|
||||
hret = h.select!.with_index {|a,b| a[1] == 4}
|
||||
hret = h.select!.with_index {|a,_b| a[1] == 4}
|
||||
assert_equal h, hret
|
||||
assert_equal({3=>4}, h)
|
||||
end
|
||||
|
||||
assert 'Hash#reject' do
|
||||
h = {1=>2,3=>4,5=>6}
|
||||
hret = h.reject.with_index {|a,b| a[1] == 4}
|
||||
hret = h.reject.with_index {|a,_b| a[1] == 4}
|
||||
assert_equal({1=>2,5=>6}, hret)
|
||||
assert_equal({1=>2,3=>4,5=>6}, h)
|
||||
end
|
||||
|
||||
assert 'Hash#reject!' do
|
||||
h = {1=>2,3=>4,5=>6}
|
||||
hret = h.reject!.with_index {|a,b| a[1] == 4}
|
||||
hret = h.reject!.with_index {|a,_b| a[1] == 4}
|
||||
assert_equal h, hret
|
||||
assert_equal({1=>2,5=>6}, h)
|
||||
end
|
||||
|
||||
+110
-56
@@ -12,34 +12,38 @@ mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
|
||||
static struct mrb_irep *
|
||||
get_closure_irep(mrb_state *mrb, int level)
|
||||
{
|
||||
struct mrb_context *c = mrb->c;
|
||||
struct REnv *e = c->ci[-1].proc->env;
|
||||
struct RProc *proc;
|
||||
struct RProc *proc = mrb->c->ci[-1].proc;
|
||||
|
||||
if (level == 0) {
|
||||
proc = c->ci[-1].proc;
|
||||
if (MRB_PROC_CFUNC_P(proc)) {
|
||||
return NULL;
|
||||
}
|
||||
return proc->body.irep;
|
||||
while (level--) {
|
||||
if (!proc) return NULL;
|
||||
proc = proc->upper;
|
||||
}
|
||||
|
||||
while (--level) {
|
||||
e = (struct REnv*)e->c;
|
||||
if (!e) return NULL;
|
||||
}
|
||||
|
||||
if (!e) return NULL;
|
||||
if (!MRB_ENV_STACK_SHARED_P(e)) return NULL;
|
||||
c = e->cxt.c;
|
||||
proc = c->cibase[e->cioff].proc;
|
||||
|
||||
if (!proc || MRB_PROC_CFUNC_P(proc)) {
|
||||
if (!proc) return NULL;
|
||||
if (MRB_PROC_CFUNC_P(proc)) {
|
||||
return NULL;
|
||||
}
|
||||
return proc->body.irep;
|
||||
}
|
||||
|
||||
/* search for irep lev above the bottom */
|
||||
static mrb_irep*
|
||||
search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<top->rlen; i++) {
|
||||
mrb_irep* tmp = top->reps[i];
|
||||
|
||||
if (tmp == bottom) return top;
|
||||
tmp = search_irep(tmp, bnest-1, lev, bottom);
|
||||
if (tmp) {
|
||||
if (bnest == lev) return top;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline mrb_code
|
||||
search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
|
||||
{
|
||||
@@ -48,7 +52,7 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
|
||||
int pos;
|
||||
|
||||
for (level = 0; (virep = get_closure_irep(mrb, level)); level++) {
|
||||
if (!virep || virep->lv == NULL) {
|
||||
if (virep->lv == NULL) {
|
||||
continue;
|
||||
}
|
||||
for (pos = 0; pos < virep->nlocals - 1; pos++) {
|
||||
@@ -61,6 +65,20 @@ search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
irep_argc(mrb_irep *irep)
|
||||
{
|
||||
mrb_code c;
|
||||
|
||||
c = irep->iseq[0];
|
||||
if (GET_OPCODE(c) == OP_ENTER) {
|
||||
mrb_aspec ax = GETARG_Ax(c);
|
||||
/* extra 1 means a slot for block */
|
||||
return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static mrb_bool
|
||||
potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
|
||||
{
|
||||
@@ -71,32 +89,24 @@ potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
|
||||
}
|
||||
|
||||
static void
|
||||
patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
|
||||
patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top)
|
||||
{
|
||||
size_t i;
|
||||
int i;
|
||||
mrb_code c;
|
||||
int argc = 0;
|
||||
int argc = irep_argc(irep);
|
||||
|
||||
for (i = 0; i < irep->ilen; i++) {
|
||||
c = irep->iseq[i];
|
||||
switch(GET_OPCODE(c)){
|
||||
case OP_ENTER:
|
||||
{
|
||||
mrb_aspec ax = GETARG_Ax(c);
|
||||
/* extra 1 means a slot for block */
|
||||
argc = MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_EPUSH:
|
||||
patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1);
|
||||
patch_irep(mrb, irep->reps[GETARG_Bx(c)], bnest + 1, top);
|
||||
break;
|
||||
|
||||
case OP_LAMBDA:
|
||||
{
|
||||
int arg_c = GETARG_c(c);
|
||||
if (arg_c & OP_L_CAPTURE) {
|
||||
patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1);
|
||||
patch_irep(mrb, irep->reps[GETARG_b(c)], bnest + 1, top);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -105,7 +115,7 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
|
||||
if (GETARG_C(c) != 0) {
|
||||
break;
|
||||
}
|
||||
{
|
||||
else {
|
||||
mrb_code arg = search_variable(mrb, irep->syms[GETARG_B(c)], bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
@@ -133,6 +143,34 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_GETUPVAR:
|
||||
{
|
||||
int lev = GETARG_C(c)+1;
|
||||
mrb_irep *tmp = search_irep(top, bnest, lev, irep);
|
||||
if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
|
||||
mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_GETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SETUPVAR:
|
||||
{
|
||||
int lev = GETARG_C(c)+1;
|
||||
mrb_irep *tmp = search_irep(top, bnest, lev, irep);
|
||||
if (potential_upvar_p(tmp->lv, GETARG_B(c), irep_argc(tmp), tmp->nlocals)) {
|
||||
mrb_code arg = search_variable(mrb, tmp->lv[GETARG_B(c)-1].name, bnest);
|
||||
if (arg != 0) {
|
||||
/* must replace */
|
||||
irep->iseq[i] = MKOPCODE(OP_SETUPVAR) | MKARG_A(GETARG_A(c)) | arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_STOP:
|
||||
if (mrb->c->ci->acc >= 0) {
|
||||
irep->iseq[i] = MKOP_AB(OP_RETURN, irep->nlocals, OP_R_NORMAL);
|
||||
@@ -145,20 +183,22 @@ patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest)
|
||||
void mrb_codedump_all(mrb_state*, struct RProc*);
|
||||
|
||||
static struct RProc*
|
||||
create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, const char *file, mrb_int line)
|
||||
create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, const char *file, mrb_int line)
|
||||
{
|
||||
mrbc_context *cxt;
|
||||
struct mrb_parser_state *p;
|
||||
struct RProc *proc;
|
||||
struct REnv *e;
|
||||
struct mrb_context *c = mrb->c;
|
||||
mrb_callinfo *ci = &mrb->c->ci[-1]; /* callinfo of eval caller */
|
||||
struct RClass *target_class = NULL;
|
||||
int bidx;
|
||||
|
||||
if (!mrb_nil_p(binding)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil.");
|
||||
}
|
||||
|
||||
cxt = mrbc_context_new(mrb);
|
||||
cxt->lineno = line;
|
||||
cxt->lineno = (short)line;
|
||||
|
||||
mrbc_filename(mrb, cxt, file ? file : "(eval)");
|
||||
cxt->capture_errors = TRUE;
|
||||
@@ -198,20 +238,31 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
|
||||
mrbc_context_free(mrb, cxt);
|
||||
mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
|
||||
}
|
||||
if (c->ci[-1].proc->target_class) {
|
||||
proc->target_class = c->ci[-1].proc->target_class;
|
||||
target_class = MRB_PROC_TARGET_CLASS(ci->proc);
|
||||
if (!MRB_PROC_CFUNC_P(ci->proc)) {
|
||||
if (ci->env) {
|
||||
e = ci->env;
|
||||
}
|
||||
else {
|
||||
e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV,
|
||||
(struct RClass*)target_class);
|
||||
e->mid = ci->mid;
|
||||
e->stack = ci[1].stackent;
|
||||
e->cxt = mrb->c;
|
||||
MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals);
|
||||
bidx = ci->argc;
|
||||
if (ci->argc < 0) bidx = 2;
|
||||
else bidx += 1;
|
||||
MRB_ENV_SET_BIDX(e, bidx);
|
||||
}
|
||||
proc->e.env = e;
|
||||
proc->flags |= MRB_PROC_ENVSET;
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)proc, (struct RBasic*)e);
|
||||
}
|
||||
e = c->ci[-1].proc->env;
|
||||
if (!e) e = c->ci[-1].env;
|
||||
e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV, (struct RClass*)e);
|
||||
e->cxt.c = c;
|
||||
e->cioff = c->ci - c->cibase;
|
||||
e->stack = c->ci->stackent;
|
||||
MRB_SET_ENV_STACK_LEN(e, c->ci->proc->body.irep->nlocals);
|
||||
c->ci->target_class = proc->target_class;
|
||||
c->ci->env = 0;
|
||||
proc->env = e;
|
||||
patch_irep(mrb, proc->body.irep, 0);
|
||||
proc->upper = ci->proc;
|
||||
mrb->c->ci->target_class = target_class;
|
||||
patch_irep(mrb, proc->body.irep, 0, proc->body.irep);
|
||||
/* mrb_codedump_all(mrb, proc); */
|
||||
|
||||
mrb_parser_free(p);
|
||||
mrbc_context_free(mrb, cxt);
|
||||
@@ -222,13 +273,17 @@ create_proc_from_string(mrb_state *mrb, char *s, int len, mrb_value binding, con
|
||||
static mrb_value
|
||||
exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc)
|
||||
{
|
||||
/* no argument passed from eval() */
|
||||
mrb->c->ci->argc = 0;
|
||||
if (mrb->c->ci->acc < 0) {
|
||||
mrb_value ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
|
||||
mrb_value ret = mrb_top_run(mrb, proc, self, 0);
|
||||
if (mrb->exc) {
|
||||
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/* clear block */
|
||||
mrb->c->stack[1] = mrb_nil_value();
|
||||
return mrb_exec_irep(mrb, self, proc);
|
||||
}
|
||||
|
||||
@@ -255,7 +310,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
|
||||
mrb_value b;
|
||||
mrb_int argc; mrb_value *argv;
|
||||
|
||||
mrb_get_args(mrb, "*&", &argv, &argc, &b);
|
||||
mrb_get_args(mrb, "*!&", &argv, &argc, &b);
|
||||
|
||||
if (mrb_nil_p(b)) {
|
||||
char *s;
|
||||
@@ -268,8 +323,7 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
|
||||
mrb_get_args(mrb, "s|zi", &s, &len, &file, &line);
|
||||
cv = mrb_singleton_class(mrb, self);
|
||||
proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
|
||||
proc->target_class = mrb_class_ptr(cv);
|
||||
mrb->c->ci->env = NULL;
|
||||
MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(cv));
|
||||
mrb_assert(!MRB_PROC_CFUNC_P(proc));
|
||||
return exec_irep(mrb, self, proc);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ f_exit(mrb_state *mrb, mrb_value self)
|
||||
mrb_int i = EXIT_SUCCESS;
|
||||
|
||||
mrb_get_args(mrb, "|i", &i);
|
||||
exit(i);
|
||||
exit((int)i);
|
||||
/* not reached */
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
@@ -123,8 +123,9 @@ fiber_init(mrb_state *mrb, mrb_value self)
|
||||
|
||||
/* adjust return callinfo */
|
||||
ci = c->ci;
|
||||
ci->target_class = p->target_class;
|
||||
ci->target_class = MRB_PROC_TARGET_CLASS(p);
|
||||
ci->proc = p;
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)mrb_obj_ptr(self), (struct RBasic*)p);
|
||||
ci->pc = p->body.irep->iseq;
|
||||
ci->nregs = p->body.irep->nregs;
|
||||
ci[1] = ci[0];
|
||||
@@ -211,8 +212,8 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
|
||||
while (b<e) {
|
||||
*b++ = *a++;
|
||||
}
|
||||
c->cibase->argc = len;
|
||||
value = c->stack[0] = c->ci->proc->env->stack[0];
|
||||
c->cibase->argc = (int)len;
|
||||
value = c->stack[0] = MRB_PROC_ENV(c->ci->proc)->stack[0];
|
||||
}
|
||||
else {
|
||||
value = fiber_result(mrb, a, len);
|
||||
@@ -252,7 +253,7 @@ fiber_resume(mrb_state *mrb, mrb_value self)
|
||||
mrb_int len;
|
||||
mrb_bool vmexec = FALSE;
|
||||
|
||||
mrb_get_args(mrb, "*", &a, &len);
|
||||
mrb_get_args(mrb, "*!", &a, &len);
|
||||
if (mrb->c->ci->acc < 0) {
|
||||
vmexec = TRUE;
|
||||
}
|
||||
@@ -312,7 +313,7 @@ fiber_transfer(mrb_state *mrb, mrb_value self)
|
||||
mrb_int len;
|
||||
|
||||
fiber_check_cfunc(mrb, mrb->c);
|
||||
mrb_get_args(mrb, "*", &a, &len);
|
||||
mrb_get_args(mrb, "*!", &a, &len);
|
||||
|
||||
if (c == mrb->root_c) {
|
||||
mrb->c->status = MRB_FIBER_TRANSFERRED;
|
||||
@@ -370,7 +371,7 @@ fiber_yield(mrb_state *mrb, mrb_value self)
|
||||
mrb_value *a;
|
||||
mrb_int len;
|
||||
|
||||
mrb_get_args(mrb, "*", &a, &len);
|
||||
mrb_get_args(mrb, "*!", &a, &len);
|
||||
return mrb_fiber_yield(mrb, len, a);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ MRuby::Gem::Specification.new('mruby-hash-ext') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Hash class extension'
|
||||
spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
|
||||
spec.add_dependency 'mruby-array-ext', :core => 'mruby-array-ext'
|
||||
spec.add_dependency 'mruby-enum-ext', core: 'mruby-enum-ext'
|
||||
spec.add_dependency 'mruby-array-ext', core: 'mruby-array-ext'
|
||||
spec.add_test_dependency 'mruby-enumerator', core: 'mruby-enumerator'
|
||||
end
|
||||
|
||||
@@ -114,6 +114,22 @@ class Hash
|
||||
|
||||
alias update merge!
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.compact -> new_hsh
|
||||
#
|
||||
# Returns a new hash with the nil values/key pairs removed
|
||||
#
|
||||
# h = { a: 1, b: false, c: nil }
|
||||
# h.compact #=> { a: 1, b: false }
|
||||
# h #=> { a: 1, b: false, c: nil }
|
||||
#
|
||||
def compact
|
||||
result = self.dup
|
||||
result.compact!
|
||||
result
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.fetch(key [, default] ) -> obj
|
||||
@@ -149,7 +165,7 @@ class Hash
|
||||
elsif none != NONE
|
||||
none
|
||||
else
|
||||
raise KeyError, "Key not found: #{key}"
|
||||
raise KeyError, "Key not found: #{key.inspect}"
|
||||
end
|
||||
else
|
||||
self[key]
|
||||
@@ -171,7 +187,7 @@ class Hash
|
||||
#
|
||||
|
||||
def delete_if(&block)
|
||||
return to_enum :delete_if unless block_given?
|
||||
return to_enum :delete_if unless block
|
||||
|
||||
self.each do |k, v|
|
||||
self.delete(k) if block.call(k, v)
|
||||
@@ -228,7 +244,7 @@ class Hash
|
||||
#
|
||||
|
||||
def keep_if(&block)
|
||||
return to_enum :keep_if unless block_given?
|
||||
return to_enum :keep_if unless block
|
||||
|
||||
keys = []
|
||||
self.each do |k, v|
|
||||
@@ -382,4 +398,105 @@ class Hash
|
||||
n
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.transform_keys {|key| block } -> new_hash
|
||||
# hsh.transform_keys -> an_enumerator
|
||||
#
|
||||
# Returns a new hash, with the keys computed from running the block
|
||||
# once for each key in the hash, and the values unchanged.
|
||||
#
|
||||
# If no block is given, an enumerator is returned instead.
|
||||
#
|
||||
def transform_keys(&block)
|
||||
return to_enum :transform_keys unless block
|
||||
hash = {}
|
||||
self.keys.each do |k|
|
||||
new_key = block.call(k)
|
||||
hash[new_key] = self[k]
|
||||
end
|
||||
hash
|
||||
end
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.transform_keys! {|key| block } -> hsh
|
||||
# hsh.transform_keys! -> an_enumerator
|
||||
#
|
||||
# Invokes the given block once for each key in <i>hsh</i>, replacing it
|
||||
# with the new key returned by the block, and then returns <i>hsh</i>.
|
||||
#
|
||||
# If no block is given, an enumerator is returned instead.
|
||||
#
|
||||
def transform_keys!(&block)
|
||||
return to_enum :transform_keys! unless block
|
||||
self.keys.each do |k|
|
||||
value = self[k]
|
||||
new_key = block.call(k)
|
||||
self.__delete(k)
|
||||
self[new_key] = value
|
||||
end
|
||||
self
|
||||
end
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.transform_values {|value| block } -> new_hash
|
||||
# hsh.transform_values -> an_enumerator
|
||||
#
|
||||
# Returns a new hash with the results of running the block once for
|
||||
# every value.
|
||||
# This method does not change the keys.
|
||||
#
|
||||
# If no block is given, an enumerator is returned instead.
|
||||
#
|
||||
def transform_values(&b)
|
||||
return to_enum :transform_values unless block_given?
|
||||
hash = {}
|
||||
self.keys.each do |k|
|
||||
hash[k] = yield(self[k])
|
||||
end
|
||||
hash
|
||||
end
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.transform_values! {|key| block } -> hsh
|
||||
# hsh.transform_values! -> an_enumerator
|
||||
#
|
||||
# Invokes the given block once for each value in the hash, replacing
|
||||
# with the new value returned by the block, and then returns <i>hsh</i>.
|
||||
#
|
||||
# If no block is given, an enumerator is returned instead.
|
||||
#
|
||||
def transform_values!(&b)
|
||||
return to_enum :transform_values! unless block_given?
|
||||
self.keys.each do |k|
|
||||
self[k] = yield(self[k])
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def to_proc
|
||||
->x{self[x]}
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# hsh.fetch_values(key, ...) -> array
|
||||
# hsh.fetch_values(key, ...) { |key| block } -> array
|
||||
#
|
||||
# Returns an array containing the values associated with the given keys
|
||||
# but also raises <code>KeyError</code> when one of keys can't be found.
|
||||
# Also see <code>Hash#values_at</code> and <code>Hash#fetch</code>.
|
||||
#
|
||||
# h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
|
||||
#
|
||||
# h.fetch_values("cow", "cat") #=> ["bovine", "feline"]
|
||||
# h.fetch_values("cow", "bird") # raises KeyError
|
||||
# h.fetch_values("cow", "bird") { |k| k.upcase } #=> ["bovine", "BIRD"]
|
||||
#
|
||||
def fetch_values(*keys, &block)
|
||||
keys.map do |k|
|
||||
self.fetch(k, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,81 @@ hash_values_at(mrb_state *mrb, mrb_value hash)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.compact! -> hsh
|
||||
*
|
||||
* Removes all nil values from the hash. Returns the hash.
|
||||
*
|
||||
* h = { a: 1, b: false, c: nil }
|
||||
* h.compact! #=> { a: 1, b: false }
|
||||
*/
|
||||
static mrb_value
|
||||
hash_compact_bang(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
khiter_t k;
|
||||
khash_t(ht) *h = RHASH_TBL(hash);
|
||||
mrb_int n = -1;
|
||||
|
||||
if (!h) return mrb_nil_value();
|
||||
for (k = kh_begin(h); k != kh_end(h); k++) {
|
||||
if (kh_exist(h, k)) {
|
||||
mrb_value val = kh_value(h, k).v;
|
||||
khiter_t k2;
|
||||
|
||||
if (mrb_nil_p(val)) {
|
||||
kh_del(ht, mrb, h, k);
|
||||
n = kh_value(h, k).n;
|
||||
for (k2 = kh_begin(h); k2 != kh_end(h); k2++) {
|
||||
if (!kh_exist(h, k2)) continue;
|
||||
if (kh_value(h, k2).n > n) kh_value(h, k2).n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n < 0) return mrb_nil_value();
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.slice(*keys) -> a_hash
|
||||
*
|
||||
* Returns a hash containing only the given keys and their values.
|
||||
*
|
||||
* h = { a: 100, b: 200, c: 300 }
|
||||
* h.slice(:a) #=> {:a=>100}
|
||||
* h.slice(:b, :c, :d) #=> {:b=>200, :c=>300}
|
||||
*/
|
||||
static mrb_value
|
||||
hash_slice(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
khash_t(ht) *h = RHASH_TBL(hash);
|
||||
mrb_value *argv, result;
|
||||
mrb_int argc, i;
|
||||
khiter_t k;
|
||||
int ai;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
if (argc == 0 || h == NULL) {
|
||||
return mrb_hash_new_capa(mrb, argc);
|
||||
}
|
||||
result = mrb_hash_new_capa(mrb, argc);
|
||||
ai = mrb_gc_arena_save(mrb);
|
||||
for (i = 0; i < argc; i++) {
|
||||
mrb_value key = argv[i];
|
||||
|
||||
k = kh_get(ht, mrb, h, key);
|
||||
if (k != kh_end(h)) {
|
||||
mrb_value val = kh_value(h, k).v;
|
||||
|
||||
mrb_hash_set(mrb, result, key, val);
|
||||
}
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
|
||||
{
|
||||
@@ -43,6 +118,8 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
|
||||
|
||||
h = mrb->hash_class;
|
||||
mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY());
|
||||
mrb_define_method(mrb, h, "compact!", hash_compact_bang, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, h, "slice", hash_slice, MRB_ARGS_ANY());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -82,6 +82,20 @@ assert('Hash#values_at') do
|
||||
assert_equal keys, h.values_at(*keys)
|
||||
end
|
||||
|
||||
assert('Hash#compact') do
|
||||
h = { "cat" => "feline", "dog" => nil, "cow" => false }
|
||||
|
||||
assert_equal({ "cat" => "feline", "cow" => false }, h.compact)
|
||||
assert_equal({ "cat" => "feline", "dog" => nil, "cow" => false }, h)
|
||||
end
|
||||
|
||||
assert('Hash#compact!') do
|
||||
h = { "cat" => "feline", "dog" => nil, "cow" => false }
|
||||
|
||||
h.compact!
|
||||
assert_equal({ "cat" => "feline", "cow" => false }, h)
|
||||
end
|
||||
|
||||
assert('Hash#fetch') do
|
||||
h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }
|
||||
assert_equal "feline", h.fetch("cat")
|
||||
@@ -254,3 +268,33 @@ assert("Hash#dig") do
|
||||
assert_equal(1, h.dig(:a, :b, :c))
|
||||
assert_nil(h.dig(:d))
|
||||
end
|
||||
|
||||
assert("Hash#transform_keys") do
|
||||
h = {"1" => 100, "2" => 200}
|
||||
assert_equal({"1!" => 100, "2!" => 200},
|
||||
h.transform_keys{|k| k+"!"})
|
||||
assert_equal({1 => 100, 2 => 200},
|
||||
h.transform_keys{|k|k.to_i})
|
||||
assert_equal({"1.0" => 100, "2.1" => 200},
|
||||
h.transform_keys.with_index{|k, i| "#{k}.#{i}"})
|
||||
assert_equal(h, h.transform_keys!{|k|k.to_i})
|
||||
assert_equal(h, {1 => 100, 2 => 200})
|
||||
end
|
||||
|
||||
assert("Hash#transform_values") do
|
||||
h = {a: 1, b: 2, c: 3}
|
||||
assert_equal({a: 2, b: 5, c: 10},
|
||||
h.transform_values{|v| v * v + 1})
|
||||
assert_equal({a: "1", b: "2", c: "3"},
|
||||
h.transform_values{|v|v.to_s})
|
||||
assert_equal({a: "1.0", b: "2.1", c: "3.2"},
|
||||
h.transform_values.with_index{|v, i| "#{v}.#{i}"})
|
||||
assert_equal(h, h.transform_values!{|v|v.to_s})
|
||||
assert_equal({a: "1", b: "2", c: "3"}, h)
|
||||
end
|
||||
|
||||
assert("Hash#slice") do
|
||||
h = { a: 100, b: 200, c: 300 }
|
||||
assert_equal({:a=>100}, h.slice(:a))
|
||||
assert_equal({:b=>200, :c=>300}, h.slice(:b, :c, :d))
|
||||
end
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/tmp
|
||||
@@ -0,0 +1,2 @@
|
||||
script:
|
||||
- "ruby run_test.rb all test"
|
||||
@@ -0,0 +1,193 @@
|
||||
mruby-io
|
||||
========
|
||||
[](https://travis-ci.org/iij/mruby-io)
|
||||
|
||||
|
||||
`IO` and `File` classes for mruby
|
||||
|
||||
## Installation
|
||||
Add the line below to your `build_config.rb`:
|
||||
|
||||
```
|
||||
conf.gem :github => 'iij/mruby-io'
|
||||
```
|
||||
|
||||
## Implemented methods
|
||||
|
||||
### IO
|
||||
- http://doc.ruby-lang.org/ja/1.9.3/class/IO.html
|
||||
|
||||
| method | mruby-io | memo |
|
||||
| ------------------------- | -------- | ---- |
|
||||
| IO.binread | | |
|
||||
| IO.binwrite | | |
|
||||
| IO.copy_stream | | |
|
||||
| IO.new, IO.for_fd, IO.open | o | |
|
||||
| IO.foreach | | |
|
||||
| IO.pipe | o | |
|
||||
| IO.popen | o | |
|
||||
| IO.read | o | |
|
||||
| IO.readlines | | |
|
||||
| IO.select | o | |
|
||||
| IO.sysopen | o | |
|
||||
| IO.try_convert | | |
|
||||
| IO.write | | |
|
||||
| IO#<< | | |
|
||||
| IO#advise | | |
|
||||
| IO#autoclose= | | |
|
||||
| IO#autoclose? | | |
|
||||
| IO#binmode | | |
|
||||
| IO#binmode? | | |
|
||||
| IO#bytes | | obsolete |
|
||||
| IO#chars | | obsolete |
|
||||
| IO#clone, IO#dup | o | |
|
||||
| IO#close | o | |
|
||||
| IO#close_on_exec= | o | |
|
||||
| IO#close_on_exec? | o | |
|
||||
| IO#close_read | | |
|
||||
| IO#close_write | | |
|
||||
| IO#closed? | o | |
|
||||
| IO#codepoints | | obsolete |
|
||||
| IO#each_byte | o | |
|
||||
| IO#each_char | o | |
|
||||
| IO#each_codepoint | | |
|
||||
| IO#each_line | o | |
|
||||
| IO#eof, IO#eof? | o | |
|
||||
| IO#external_encoding | | |
|
||||
| IO#fcntl | | |
|
||||
| IO#fdatasync | | |
|
||||
| IO#fileno, IO#to_i | o | |
|
||||
| IO#flush | o | |
|
||||
| IO#fsync | | |
|
||||
| IO#getbyte | | |
|
||||
| IO#getc | o | |
|
||||
| IO#gets | o | |
|
||||
| IO#internal_encoding | | |
|
||||
| IO#ioctl | | |
|
||||
| IO#isatty, IO#tty? | o | |
|
||||
| IO#lineno | | |
|
||||
| IO#lineno= | | |
|
||||
| IO#lines | | obsolete |
|
||||
| IO#pid | o | |
|
||||
| IO#pos, IO#tell | o | |
|
||||
| IO#pos= | o | |
|
||||
| IO#print | o | |
|
||||
| IO#printf | o | |
|
||||
| IO#putc | | |
|
||||
| IO#puts | o | |
|
||||
| IO#read | o | |
|
||||
| IO#read_nonblock | | |
|
||||
| IO#readbyte | | |
|
||||
| IO#readchar | o | |
|
||||
| IO#readline | o | |
|
||||
| IO#readlines | o | |
|
||||
| IO#readpartial | | |
|
||||
| IO#reopen | | |
|
||||
| IO#rewind | | |
|
||||
| IO#seek | o | |
|
||||
| IO#set_encoding | | |
|
||||
| IO#stat | | |
|
||||
| IO#sync | o | |
|
||||
| IO#sync= | o | |
|
||||
| IO#sysread | o | |
|
||||
| IO#sysseek | o | |
|
||||
| IO#syswrite | o | |
|
||||
| IO#to_io | | |
|
||||
| IO#ungetbyte | | |
|
||||
| IO#ungetc | o | |
|
||||
| IO#write | o | |
|
||||
| IO#write_nonblock | | |
|
||||
|
||||
### File
|
||||
- http://doc.ruby-lang.org/ja/1.9.3/class/File.html
|
||||
|
||||
| method | mruby-io | memo |
|
||||
| --------------------------- | -------- | ---- |
|
||||
| File.absolute_path | | |
|
||||
| File.atime | | |
|
||||
| File.basename | o | |
|
||||
| File.blockdev? | | FileTest |
|
||||
| File.chardev? | | FileTest |
|
||||
| File.chmod | o | |
|
||||
| File.chown | | |
|
||||
| File.ctime | | |
|
||||
| File.delete, File.unlink | o | |
|
||||
| File.directory? | o | FileTest |
|
||||
| File.dirname | o | |
|
||||
| File.executable? | | FileTest |
|
||||
| File.executable_real? | | FileTest |
|
||||
| File.exist?, exists? | o | FileTest |
|
||||
| File.expand_path | o | |
|
||||
| File.extname | o | |
|
||||
| File.file? | o | FileTest |
|
||||
| File.fnmatch, File.fnmatch? | | |
|
||||
| File.ftype | | |
|
||||
| File.grpowned? | | FileTest |
|
||||
| File.identical? | | FileTest |
|
||||
| File.join | o | |
|
||||
| File.lchmod | | |
|
||||
| File.lchown | | |
|
||||
| File.link | | |
|
||||
| File.lstat | | |
|
||||
| File.mtime | | |
|
||||
| File.new, File.open | o | |
|
||||
| File.owned? | | FileTest |
|
||||
| File.path | | |
|
||||
| File.pipe? | o | FileTest |
|
||||
| File.readable? | | FileTest |
|
||||
| File.readable_real? | | FileTest |
|
||||
| File.readlink | o | |
|
||||
| File.realdirpath | | |
|
||||
| File.realpath | o | |
|
||||
| File.rename | o | |
|
||||
| File.setgid? | | FileTest |
|
||||
| File.setuid? | | FileTest |
|
||||
| File.size | o | |
|
||||
| File.size? | o | FileTest |
|
||||
| File.socket? | o | FileTest |
|
||||
| File.split | | |
|
||||
| File.stat | | |
|
||||
| File.sticky? | | FileTest |
|
||||
| File.symlink | | |
|
||||
| File.symlink? | o | FileTest |
|
||||
| File.truncate | | |
|
||||
| File.umask | o | |
|
||||
| File.utime | | |
|
||||
| File.world_readable? | | |
|
||||
| File.world_writable? | | |
|
||||
| File.writable? | | FileTest |
|
||||
| File.writable_real? | | FileTest |
|
||||
| File.zero? | o | FileTest |
|
||||
| File#atime | | |
|
||||
| File#chmod | | |
|
||||
| File#chown | | |
|
||||
| File#ctime | | |
|
||||
| File#flock | o | |
|
||||
| File#lstat | | |
|
||||
| File#mtime | | |
|
||||
| File#path, File#to_path | o | |
|
||||
| File#size | | |
|
||||
| File#truncate | | |
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2013 Internet Initiative Japan Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
** io.h - IO class
|
||||
*/
|
||||
|
||||
#ifndef MRUBY_IO_H
|
||||
#define MRUBY_IO_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct mrb_io {
|
||||
int fd; /* file descriptor, or -1 */
|
||||
int fd2; /* file descriptor to write if it's different from fd, or -1 */
|
||||
int pid; /* child's pid (for pipes) */
|
||||
unsigned int readable:1,
|
||||
writable:1,
|
||||
sync:1,
|
||||
is_socket:1;
|
||||
};
|
||||
|
||||
#define FMODE_READABLE 0x00000001
|
||||
#define FMODE_WRITABLE 0x00000002
|
||||
#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE)
|
||||
#define FMODE_BINMODE 0x00000004
|
||||
#define FMODE_APPEND 0x00000040
|
||||
#define FMODE_CREATE 0x00000080
|
||||
#define FMODE_TRUNC 0x00000800
|
||||
|
||||
#define E_IO_ERROR (mrb_class_get(mrb, "IOError"))
|
||||
#define E_EOF_ERROR (mrb_class_get(mrb, "EOFError"))
|
||||
|
||||
mrb_value mrb_io_fileno(mrb_state *mrb, mrb_value io);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
#endif /* MRUBY_IO_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
MRuby::Gem::Specification.new('mruby-io') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = 'Internet Initiative Japan Inc.'
|
||||
spec.summary = 'IO and File class'
|
||||
|
||||
spec.cc.include_paths << "#{build.root}/src"
|
||||
|
||||
case RUBY_PLATFORM
|
||||
when /mingw|mswin/
|
||||
spec.linker.libraries += ['Ws2_32']
|
||||
#spec.cc.include_paths += ["C:/Windows/system/include"]
|
||||
spec.linker.library_paths += ["C:/Windows/system"]
|
||||
end
|
||||
if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target)
|
||||
spec.linker.libraries += ['ws2_32']
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,208 @@
|
||||
class File < IO
|
||||
class FileError < Exception; end
|
||||
class NoFileError < FileError; end
|
||||
class UnableToStat < FileError; end
|
||||
class PermissionError < FileError; end
|
||||
|
||||
attr_accessor :path
|
||||
|
||||
def initialize(fd_or_path, mode = "r", perm = 0666)
|
||||
if fd_or_path.kind_of? Fixnum
|
||||
super(fd_or_path, mode)
|
||||
else
|
||||
@path = fd_or_path
|
||||
fd = IO.sysopen(@path, mode, perm)
|
||||
super(fd, mode)
|
||||
end
|
||||
end
|
||||
|
||||
def self.join(*names)
|
||||
return "" if names.empty?
|
||||
|
||||
names.map! do |name|
|
||||
case name
|
||||
when String
|
||||
name
|
||||
when Array
|
||||
if names == name
|
||||
raise ArgumentError, "recursive array"
|
||||
end
|
||||
join(*name)
|
||||
else
|
||||
raise TypeError, "no implicit conversion of #{name.class} into String"
|
||||
end
|
||||
end
|
||||
|
||||
return names[0] if names.size == 1
|
||||
|
||||
if names[0][-1] == File::SEPARATOR
|
||||
s = names[0][0..-2]
|
||||
else
|
||||
s = names[0].dup
|
||||
end
|
||||
|
||||
(1..names.size-2).each { |i|
|
||||
t = names[i]
|
||||
if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR
|
||||
t = t[1..-2]
|
||||
elsif t[0] == File::SEPARATOR
|
||||
t = t[1..-1]
|
||||
elsif t[-1] == File::SEPARATOR
|
||||
t = t[0..-2]
|
||||
end
|
||||
s += File::SEPARATOR + t if t != ""
|
||||
}
|
||||
if names[-1][0] == File::SEPARATOR
|
||||
s += File::SEPARATOR + names[-1][1..-1]
|
||||
else
|
||||
s += File::SEPARATOR + names[-1]
|
||||
end
|
||||
s
|
||||
end
|
||||
|
||||
def self.expand_path(path, default_dir = '.')
|
||||
def concat_path(path, base_path)
|
||||
if path[0] == "/" || path[1] == ':' # Windows root!
|
||||
expanded_path = path
|
||||
elsif path[0] == "~"
|
||||
if (path[1] == "/" || path[1] == nil)
|
||||
dir = path[1, path.size]
|
||||
home_dir = _gethome
|
||||
|
||||
unless home_dir
|
||||
raise ArgumentError, "couldn't find HOME environment -- expanding '~'"
|
||||
end
|
||||
|
||||
expanded_path = home_dir
|
||||
expanded_path += dir if dir
|
||||
expanded_path += "/"
|
||||
else
|
||||
splitted_path = path.split("/")
|
||||
user = splitted_path[0][1, splitted_path[0].size]
|
||||
dir = "/" + splitted_path[1, splitted_path.size].join("/")
|
||||
|
||||
home_dir = _gethome(user)
|
||||
|
||||
unless home_dir
|
||||
raise ArgumentError, "user #{user} doesn't exist"
|
||||
end
|
||||
|
||||
expanded_path = home_dir
|
||||
expanded_path += dir if dir
|
||||
expanded_path += "/"
|
||||
end
|
||||
else
|
||||
expanded_path = concat_path(base_path, _getwd)
|
||||
expanded_path += "/" + path
|
||||
end
|
||||
|
||||
expanded_path
|
||||
end
|
||||
|
||||
expanded_path = concat_path(path, default_dir)
|
||||
drive_prefix = ""
|
||||
if File::ALT_SEPARATOR && expanded_path.size > 2 &&
|
||||
("A".."Z").include?(expanded_path[0].upcase) && expanded_path[1] == ":"
|
||||
drive_prefix = expanded_path[0, 2]
|
||||
expanded_path = expanded_path[2, expanded_path.size]
|
||||
end
|
||||
expand_path_array = []
|
||||
if File::ALT_SEPARATOR && expanded_path.include?(File::ALT_SEPARATOR)
|
||||
expanded_path.gsub!(File::ALT_SEPARATOR, '/')
|
||||
end
|
||||
while expanded_path.include?('//')
|
||||
expanded_path = expanded_path.gsub('//', '/')
|
||||
end
|
||||
|
||||
if expanded_path != "/"
|
||||
expanded_path.split('/').each do |path_token|
|
||||
if path_token == '..'
|
||||
if expand_path_array.size > 1
|
||||
expand_path_array.pop
|
||||
end
|
||||
elsif path_token == '.'
|
||||
# nothing to do.
|
||||
else
|
||||
expand_path_array << path_token
|
||||
end
|
||||
end
|
||||
|
||||
expanded_path = expand_path_array.join("/")
|
||||
if expanded_path.empty?
|
||||
expanded_path = '/'
|
||||
end
|
||||
end
|
||||
if drive_prefix.empty?
|
||||
expanded_path
|
||||
else
|
||||
drive_prefix + expanded_path.gsub("/", File::ALT_SEPARATOR)
|
||||
end
|
||||
end
|
||||
|
||||
def self.foreach(file)
|
||||
if block_given?
|
||||
self.open(file) do |f|
|
||||
f.each {|l| yield l}
|
||||
end
|
||||
else
|
||||
return self.new(file)
|
||||
end
|
||||
end
|
||||
|
||||
def self.directory?(file)
|
||||
FileTest.directory?(file)
|
||||
end
|
||||
|
||||
def self.exist?(file)
|
||||
FileTest.exist?(file)
|
||||
end
|
||||
|
||||
def self.exists?(file)
|
||||
FileTest.exists?(file)
|
||||
end
|
||||
|
||||
def self.file?(file)
|
||||
FileTest.file?(file)
|
||||
end
|
||||
|
||||
def self.pipe?(file)
|
||||
FileTest.pipe?(file)
|
||||
end
|
||||
|
||||
def self.size(file)
|
||||
FileTest.size(file)
|
||||
end
|
||||
|
||||
def self.size?(file)
|
||||
FileTest.size?(file)
|
||||
end
|
||||
|
||||
def self.socket?(file)
|
||||
FileTest.socket?(file)
|
||||
end
|
||||
|
||||
def self.symlink?(file)
|
||||
FileTest.symlink?(file)
|
||||
end
|
||||
|
||||
def self.zero?(file)
|
||||
FileTest.zero?(file)
|
||||
end
|
||||
|
||||
def self.extname(filename)
|
||||
fname = self.basename(filename)
|
||||
return '' if fname[0] == '.' || fname.index('.').nil?
|
||||
ext = fname.split('.').last
|
||||
ext.empty? ? '' : ".#{ext}"
|
||||
end
|
||||
|
||||
def self.path(filename)
|
||||
if filename.kind_of?(String)
|
||||
filename
|
||||
elsif filename.respond_to?(:to_path)
|
||||
filename.to_path
|
||||
else
|
||||
raise TypeError, "no implicit conversion of #{filename.class} into String"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
class File
|
||||
module Constants
|
||||
RDONLY = 0
|
||||
WRONLY = 1
|
||||
RDWR = 2
|
||||
NONBLOCK = 4
|
||||
APPEND = 8
|
||||
|
||||
BINARY = 0
|
||||
SYNC = 128
|
||||
NOFOLLOW = 256
|
||||
CREAT = 512
|
||||
TRUNC = 1024
|
||||
EXCL = 2048
|
||||
|
||||
NOCTTY = 131072
|
||||
DSYNC = 4194304
|
||||
|
||||
FNM_SYSCASE = 0
|
||||
FNM_NOESCAPE = 1
|
||||
FNM_PATHNAME = 2
|
||||
FNM_DOTMATCH = 4
|
||||
FNM_CASEFOLD = 8
|
||||
end
|
||||
end
|
||||
|
||||
class File
|
||||
include File::Constants
|
||||
end
|
||||
@@ -0,0 +1,387 @@
|
||||
##
|
||||
# IO
|
||||
|
||||
class IOError < StandardError; end
|
||||
class EOFError < IOError; end
|
||||
|
||||
class IO
|
||||
SEEK_SET = 0
|
||||
SEEK_CUR = 1
|
||||
SEEK_END = 2
|
||||
|
||||
BUF_SIZE = 4096
|
||||
|
||||
def self.open(*args, &block)
|
||||
io = self.new(*args)
|
||||
|
||||
return io unless block
|
||||
|
||||
begin
|
||||
yield io
|
||||
ensure
|
||||
begin
|
||||
io.close unless io.closed?
|
||||
rescue StandardError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.popen(command, mode = 'r', opts={}, &block)
|
||||
if !self.respond_to?(:_popen)
|
||||
raise NotImplementedError, "popen is not supported on this platform"
|
||||
end
|
||||
io = self._popen(command, mode, opts)
|
||||
return io unless block
|
||||
|
||||
begin
|
||||
yield io
|
||||
ensure
|
||||
begin
|
||||
io.close unless io.closed?
|
||||
rescue IOError
|
||||
# nothing
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.pipe(&block)
|
||||
if !self.respond_to?(:_pipe)
|
||||
raise NotImplementedError, "pipe is not supported on this platform"
|
||||
end
|
||||
if block
|
||||
begin
|
||||
r, w = IO._pipe
|
||||
yield r, w
|
||||
ensure
|
||||
r.close unless r.closed?
|
||||
w.close unless w.closed?
|
||||
end
|
||||
else
|
||||
IO._pipe
|
||||
end
|
||||
end
|
||||
|
||||
def self.read(path, length=nil, offset=nil, opt=nil)
|
||||
if not opt.nil? # 4 arguments
|
||||
offset ||= 0
|
||||
elsif not offset.nil? # 3 arguments
|
||||
if offset.is_a? Hash
|
||||
opt = offset
|
||||
offset = 0
|
||||
else
|
||||
opt = {}
|
||||
end
|
||||
elsif not length.nil? # 2 arguments
|
||||
if length.is_a? Hash
|
||||
opt = length
|
||||
offset = 0
|
||||
length = nil
|
||||
else
|
||||
offset = 0
|
||||
opt = {}
|
||||
end
|
||||
else # only 1 argument
|
||||
opt = {}
|
||||
offset = 0
|
||||
length = nil
|
||||
end
|
||||
|
||||
str = ""
|
||||
fd = -1
|
||||
io = nil
|
||||
begin
|
||||
if path[0] == "|"
|
||||
io = IO.popen(path[1..-1], (opt[:mode] || "r"))
|
||||
else
|
||||
fd = IO.sysopen(path)
|
||||
io = IO.open(fd, opt[:mode] || "r")
|
||||
end
|
||||
io.seek(offset) if offset > 0
|
||||
str = io.read(length)
|
||||
ensure
|
||||
if io
|
||||
io.close
|
||||
elsif fd != -1
|
||||
IO._sysclose(fd)
|
||||
end
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
def flush
|
||||
# mruby-io always writes immediately (no output buffer).
|
||||
raise IOError, "closed stream" if self.closed?
|
||||
self
|
||||
end
|
||||
|
||||
def hash
|
||||
# We must define IO#hash here because IO includes Enumerable and
|
||||
# Enumerable#hash will call IO#read...
|
||||
self.__id__
|
||||
end
|
||||
|
||||
def write(string)
|
||||
str = string.is_a?(String) ? string : string.to_s
|
||||
return str.size unless str.size > 0
|
||||
if 0 < @buf.length
|
||||
# reset real pos ignore buf
|
||||
seek(pos, SEEK_SET)
|
||||
end
|
||||
len = syswrite(str)
|
||||
len
|
||||
end
|
||||
|
||||
def <<(str)
|
||||
write(str)
|
||||
self
|
||||
end
|
||||
|
||||
def eof?
|
||||
_check_readable
|
||||
begin
|
||||
buf = _read_buf
|
||||
return buf.size == 0
|
||||
rescue EOFError
|
||||
return true
|
||||
end
|
||||
end
|
||||
alias_method :eof, :eof?
|
||||
|
||||
def pos
|
||||
raise IOError if closed?
|
||||
sysseek(0, SEEK_CUR) - @buf.length
|
||||
end
|
||||
alias_method :tell, :pos
|
||||
|
||||
def pos=(i)
|
||||
seek(i, SEEK_SET)
|
||||
end
|
||||
|
||||
def rewind
|
||||
seek(0, SEEK_SET)
|
||||
end
|
||||
|
||||
def seek(i, whence = SEEK_SET)
|
||||
raise IOError if closed?
|
||||
sysseek(i, whence)
|
||||
@buf = ''
|
||||
0
|
||||
end
|
||||
|
||||
def _read_buf
|
||||
return @buf if @buf && @buf.size > 0
|
||||
@buf = sysread(BUF_SIZE)
|
||||
end
|
||||
|
||||
def ungetc(substr)
|
||||
raise TypeError.new "expect String, got #{substr.class}" unless substr.is_a?(String)
|
||||
if @buf.empty?
|
||||
@buf = substr.dup
|
||||
else
|
||||
@buf = substr + @buf
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def read(length = nil, outbuf = "")
|
||||
unless length.nil?
|
||||
unless length.is_a? Fixnum
|
||||
raise TypeError.new "can't convert #{length.class} into Integer"
|
||||
end
|
||||
if length < 0
|
||||
raise ArgumentError.new "negative length: #{length} given"
|
||||
end
|
||||
if length == 0
|
||||
return "" # easy case
|
||||
end
|
||||
end
|
||||
|
||||
array = []
|
||||
while 1
|
||||
begin
|
||||
_read_buf
|
||||
rescue EOFError
|
||||
array = nil if array.empty? and (not length.nil?) and length != 0
|
||||
break
|
||||
end
|
||||
|
||||
if length
|
||||
consume = (length <= @buf.size) ? length : @buf.size
|
||||
array.push @buf[0, consume]
|
||||
@buf = @buf[consume, @buf.size - consume]
|
||||
length -= consume
|
||||
break if length == 0
|
||||
else
|
||||
array.push @buf
|
||||
@buf = ''
|
||||
end
|
||||
end
|
||||
|
||||
if array.nil?
|
||||
outbuf.replace("")
|
||||
nil
|
||||
else
|
||||
outbuf.replace(array.join)
|
||||
end
|
||||
end
|
||||
|
||||
def readline(arg = $/, limit = nil)
|
||||
case arg
|
||||
when String
|
||||
rs = arg
|
||||
when Fixnum
|
||||
rs = $/
|
||||
limit = arg
|
||||
else
|
||||
raise ArgumentError
|
||||
end
|
||||
|
||||
if rs.nil?
|
||||
return read
|
||||
end
|
||||
|
||||
if rs == ""
|
||||
rs = $/ + $/
|
||||
end
|
||||
|
||||
array = []
|
||||
while 1
|
||||
begin
|
||||
_read_buf
|
||||
rescue EOFError
|
||||
array = nil if array.empty?
|
||||
break
|
||||
end
|
||||
|
||||
if limit && limit <= @buf.size
|
||||
array.push @buf[0, limit]
|
||||
@buf = @buf[limit, @buf.size - limit]
|
||||
break
|
||||
elsif idx = @buf.index(rs)
|
||||
len = idx + rs.size
|
||||
array.push @buf[0, len]
|
||||
@buf = @buf[len, @buf.size - len]
|
||||
break
|
||||
else
|
||||
array.push @buf
|
||||
@buf = ''
|
||||
end
|
||||
end
|
||||
|
||||
raise EOFError.new "end of file reached" if array.nil?
|
||||
|
||||
array.join
|
||||
end
|
||||
|
||||
def gets(*args)
|
||||
begin
|
||||
readline(*args)
|
||||
rescue EOFError
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def readchar
|
||||
_read_buf
|
||||
c = @buf[0]
|
||||
@buf = @buf[1, @buf.size]
|
||||
c
|
||||
end
|
||||
|
||||
def getc
|
||||
begin
|
||||
readchar
|
||||
rescue EOFError
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# 15.2.20.5.3
|
||||
def each(&block)
|
||||
while line = self.gets
|
||||
block.call(line)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# 15.2.20.5.4
|
||||
def each_byte(&block)
|
||||
while char = self.getc
|
||||
block.call(char)
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
# 15.2.20.5.5
|
||||
alias each_line each
|
||||
|
||||
alias each_char each_byte
|
||||
|
||||
def readlines
|
||||
ary = []
|
||||
while (line = gets)
|
||||
ary << line
|
||||
end
|
||||
ary
|
||||
end
|
||||
|
||||
def puts(*args)
|
||||
i = 0
|
||||
len = args.size
|
||||
while i < len
|
||||
s = args[i].to_s
|
||||
write s
|
||||
write "\n" if (s[-1] != "\n")
|
||||
i += 1
|
||||
end
|
||||
write "\n" if len == 0
|
||||
nil
|
||||
end
|
||||
|
||||
def print(*args)
|
||||
i = 0
|
||||
len = args.size
|
||||
while i < len
|
||||
write args[i].to_s
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
|
||||
def printf(*args)
|
||||
write sprintf(*args)
|
||||
nil
|
||||
end
|
||||
|
||||
alias_method :to_i, :fileno
|
||||
alias_method :tty?, :isatty
|
||||
end
|
||||
|
||||
STDIN = IO.open(0, "r")
|
||||
STDOUT = IO.open(1, "w")
|
||||
STDERR = IO.open(2, "w")
|
||||
|
||||
$stdin = STDIN
|
||||
$stdout = STDOUT
|
||||
$stderr = STDERR
|
||||
|
||||
module Kernel
|
||||
def print(*args)
|
||||
$stdout.print(*args)
|
||||
end
|
||||
|
||||
def puts(*args)
|
||||
$stdout.puts(*args)
|
||||
end
|
||||
|
||||
def printf(*args)
|
||||
$stdout.printf(*args)
|
||||
end
|
||||
|
||||
def gets(*args)
|
||||
$stdin.gets(*args)
|
||||
end
|
||||
|
||||
def getc(*args)
|
||||
$stdin.getc(*args)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
module Kernel
|
||||
def `(cmd)
|
||||
IO.popen(cmd) { |io| io.read }
|
||||
end
|
||||
|
||||
def open(file, *rest, &block)
|
||||
raise ArgumentError unless file.is_a?(String)
|
||||
|
||||
if file[0] == "|"
|
||||
IO.popen(file[1..-1], *rest, &block)
|
||||
else
|
||||
File.open(file, *rest, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env ruby
|
||||
#
|
||||
# mrbgems test runner
|
||||
#
|
||||
|
||||
if __FILE__ == $0
|
||||
repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
|
||||
build_args = ARGV
|
||||
|
||||
Dir.mkdir 'tmp' unless File.exist?('tmp')
|
||||
unless File.exist?(dir)
|
||||
system "git clone #{repository} #{dir}"
|
||||
end
|
||||
|
||||
exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
|
||||
end
|
||||
|
||||
MRuby::Build.new do |conf|
|
||||
toolchain :gcc
|
||||
conf.gembox 'default'
|
||||
|
||||
conf.gem :git => 'https://github.com/iij/mruby-env.git'
|
||||
conf.enable_test
|
||||
|
||||
conf.gem File.expand_path(File.dirname(__FILE__))
|
||||
end
|
||||
@@ -0,0 +1,489 @@
|
||||
/*
|
||||
** file.c - File class
|
||||
*/
|
||||
|
||||
#include "mruby.h"
|
||||
#include "mruby/class.h"
|
||||
#include "mruby/data.h"
|
||||
#include "mruby/string.h"
|
||||
#include "mruby/ext/io.h"
|
||||
|
||||
#if MRUBY_RELEASE_NO < 10000
|
||||
#include "error.h"
|
||||
#else
|
||||
#include "mruby/error.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#define NULL_FILE "NUL"
|
||||
#define UNLINK _unlink
|
||||
#define GETCWD _getcwd
|
||||
#define CHMOD(a, b) 0
|
||||
#define MAXPATHLEN 1024
|
||||
#if !defined(PATH_MAX)
|
||||
#define PATH_MAX _MAX_PATH
|
||||
#endif
|
||||
#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
|
||||
#include <direct.h>
|
||||
#else
|
||||
#define NULL_FILE "/dev/null"
|
||||
#include <unistd.h>
|
||||
#define UNLINK unlink
|
||||
#define GETCWD getcwd
|
||||
#define CHMOD(a, b) chmod(a,b)
|
||||
#include <sys/file.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/param.h>
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#define FILE_SEPARATOR "/"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define PATH_SEPARATOR ";"
|
||||
#define FILE_ALT_SEPARATOR "\\"
|
||||
#else
|
||||
#define PATH_SEPARATOR ":"
|
||||
#endif
|
||||
|
||||
#ifndef LOCK_SH
|
||||
#define LOCK_SH 1
|
||||
#endif
|
||||
#ifndef LOCK_EX
|
||||
#define LOCK_EX 2
|
||||
#endif
|
||||
#ifndef LOCK_NB
|
||||
#define LOCK_NB 4
|
||||
#endif
|
||||
#ifndef LOCK_UN
|
||||
#define LOCK_UN 8
|
||||
#endif
|
||||
|
||||
#define STAT(p, s) stat(p, s)
|
||||
|
||||
#ifdef _WIN32
|
||||
static int
|
||||
flock(int fd, int operation) {
|
||||
OVERLAPPED ov;
|
||||
HANDLE h = (HANDLE)_get_osfhandle(fd);
|
||||
DWORD flags;
|
||||
flags = ((operation & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0)
|
||||
| ((operation & LOCK_SH) ? LOCKFILE_EXCLUSIVE_LOCK : 0);
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
return LockFileEx(h, flags, 0, 0xffffffff, 0xffffffff, &ov) ? 0 : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
mrb_value
|
||||
mrb_file_s_umask(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
/* nothing to do on windows */
|
||||
return mrb_fixnum_value(0);
|
||||
|
||||
#else
|
||||
mrb_int mask, omask;
|
||||
if (mrb_get_args(mrb, "|i", &mask) == 0) {
|
||||
omask = umask(0);
|
||||
umask(omask);
|
||||
} else {
|
||||
omask = umask(mask);
|
||||
}
|
||||
return mrb_fixnum_value(omask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
mrb_value *argv;
|
||||
mrb_value pathv;
|
||||
mrb_int argc, i;
|
||||
char *path;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str");
|
||||
path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathv), -1);
|
||||
if (UNLINK(path) < 0) {
|
||||
mrb_locale_free(path);
|
||||
mrb_sys_fail(mrb, path);
|
||||
}
|
||||
mrb_locale_free(path);
|
||||
}
|
||||
return mrb_fixnum_value(argc);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_s_rename(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
mrb_value from, to;
|
||||
char *src, *dst;
|
||||
|
||||
mrb_get_args(mrb, "SS", &from, &to);
|
||||
src = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &from), -1);
|
||||
dst = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &to), -1);
|
||||
if (rename(src, dst) < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (CHMOD(dst, 0666) == 0 && UNLINK(dst) == 0 && rename(src, dst) == 0) {
|
||||
mrb_locale_free(src);
|
||||
mrb_locale_free(dst);
|
||||
return mrb_fixnum_value(0);
|
||||
}
|
||||
#endif
|
||||
mrb_locale_free(src);
|
||||
mrb_locale_free(dst);
|
||||
mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
|
||||
}
|
||||
mrb_locale_free(src);
|
||||
mrb_locale_free(dst);
|
||||
return mrb_fixnum_value(0);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_dirname(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
char dname[_MAX_DIR], vname[_MAX_DRIVE];
|
||||
char buffer[_MAX_DRIVE + _MAX_DIR];
|
||||
char *path;
|
||||
size_t ridx;
|
||||
mrb_value s;
|
||||
mrb_get_args(mrb, "S", &s);
|
||||
path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, s), -1);
|
||||
_splitpath((const char*)path, vname, dname, NULL, NULL);
|
||||
snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname);
|
||||
mrb_locale_free(path);
|
||||
ridx = strlen(buffer);
|
||||
if (ridx == 0) {
|
||||
strncpy(buffer, ".", 2); /* null terminated */
|
||||
} else if (ridx > 1) {
|
||||
ridx--;
|
||||
while (ridx > 0 && (buffer[ridx] == '/' || buffer[ridx] == '\\')) {
|
||||
buffer[ridx] = '\0'; /* remove last char */
|
||||
ridx--;
|
||||
}
|
||||
}
|
||||
return mrb_str_new_cstr(mrb, buffer);
|
||||
#else
|
||||
char *dname, *path;
|
||||
mrb_value s;
|
||||
mrb_get_args(mrb, "S", &s);
|
||||
path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, s), -1);
|
||||
|
||||
if ((dname = dirname(path)) == NULL) {
|
||||
mrb_locale_free(path);
|
||||
mrb_sys_fail(mrb, "dirname");
|
||||
}
|
||||
mrb_locale_free(path);
|
||||
return mrb_str_new_cstr(mrb, dname);
|
||||
#endif
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_basename(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
// NOTE: Do not use mrb_locale_from_utf8 here
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
char bname[_MAX_DIR];
|
||||
char extname[_MAX_EXT];
|
||||
char *path;
|
||||
size_t ridx;
|
||||
char buffer[_MAX_DIR + _MAX_EXT];
|
||||
mrb_value s;
|
||||
|
||||
mrb_get_args(mrb, "S", &s);
|
||||
path = mrb_str_to_cstr(mrb, s);
|
||||
ridx = strlen(path);
|
||||
if (ridx > 0) {
|
||||
ridx--;
|
||||
while (ridx > 0 && (path[ridx] == '/' || path[ridx] == '\\')) {
|
||||
path[ridx] = '\0';
|
||||
ridx--;
|
||||
}
|
||||
if (strncmp(path, "/", 2) == 0) {
|
||||
return mrb_str_new_cstr(mrb, path);
|
||||
}
|
||||
}
|
||||
_splitpath((const char*)path, NULL, NULL, bname, extname);
|
||||
snprintf(buffer, _MAX_DIR + _MAX_EXT, "%s%s", bname, extname);
|
||||
return mrb_str_new_cstr(mrb, buffer);
|
||||
#else
|
||||
char *bname, *path;
|
||||
mrb_value s;
|
||||
mrb_get_args(mrb, "S", &s);
|
||||
path = mrb_str_to_cstr(mrb, s);
|
||||
if ((bname = basename(path)) == NULL) {
|
||||
mrb_sys_fail(mrb, "basename");
|
||||
}
|
||||
if (strncmp(bname, "//", 3) == 0) bname[1] = '\0'; /* patch for Cygwin */
|
||||
return mrb_str_new_cstr(mrb, bname);
|
||||
#endif
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_realpath(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value pathname, dir_string, s, result;
|
||||
mrb_int argc;
|
||||
char *cpath;
|
||||
|
||||
argc = mrb_get_args(mrb, "S|S", &pathname, &dir_string);
|
||||
if (argc == 2) {
|
||||
s = mrb_str_dup(mrb, dir_string);
|
||||
s = mrb_str_append(mrb, s, mrb_str_new_cstr(mrb, FILE_SEPARATOR));
|
||||
s = mrb_str_append(mrb, s, pathname);
|
||||
pathname = s;
|
||||
}
|
||||
cpath = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, pathname), -1);
|
||||
result = mrb_str_buf_new(mrb, PATH_MAX);
|
||||
if (realpath(cpath, RSTRING_PTR(result)) == NULL) {
|
||||
mrb_locale_free(cpath);
|
||||
mrb_sys_fail(mrb, cpath);
|
||||
}
|
||||
mrb_locale_free(cpath);
|
||||
mrb_str_resize(mrb, result, strlen(RSTRING_PTR(result)));
|
||||
return result;
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_file__getwd(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value path;
|
||||
char buf[MAXPATHLEN], *utf8;
|
||||
|
||||
if (GETCWD(buf, MAXPATHLEN) == NULL) {
|
||||
mrb_sys_fail(mrb, "getcwd(2)");
|
||||
}
|
||||
utf8 = mrb_utf8_from_locale(buf, -1);
|
||||
path = mrb_str_new_cstr(mrb, utf8);
|
||||
mrb_utf8_free(utf8);
|
||||
return path;
|
||||
}
|
||||
|
||||
static int
|
||||
mrb_file_is_absolute_path(const char *path)
|
||||
{
|
||||
return (path[0] == '/');
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file__gethome(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int argc;
|
||||
char *home;
|
||||
mrb_value path;
|
||||
|
||||
#ifndef _WIN32
|
||||
mrb_value username;
|
||||
|
||||
argc = mrb_get_args(mrb, "|S", &username);
|
||||
if (argc == 0) {
|
||||
home = getenv("HOME");
|
||||
if (home == NULL) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
if (!mrb_file_is_absolute_path(home)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home");
|
||||
}
|
||||
} else {
|
||||
const char *cuser = mrb_str_to_cstr(mrb, username);
|
||||
struct passwd *pwd = getpwnam(cuser);
|
||||
if (pwd == NULL) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
home = pwd->pw_dir;
|
||||
if (!mrb_file_is_absolute_path(home)) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "non-absolute home of ~%S", username);
|
||||
}
|
||||
}
|
||||
home = mrb_locale_from_utf8(home, -1);
|
||||
path = mrb_str_new_cstr(mrb, home);
|
||||
mrb_utf8_free(home);
|
||||
return path;
|
||||
#else
|
||||
argc = mrb_get_argc(mrb);
|
||||
if (argc == 0) {
|
||||
home = getenv("USERPROFILE");
|
||||
if (home == NULL) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
if (!mrb_file_is_absolute_path(home)) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home");
|
||||
}
|
||||
} else {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
home = mrb_locale_from_utf8(home, -1);
|
||||
path = mrb_str_new_cstr(mrb, home);
|
||||
mrb_utf8_free(home);
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_file_flock(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
#if defined(sun)
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "flock is not supported on Illumos/Solaris/Windows");
|
||||
#else
|
||||
mrb_int operation;
|
||||
int fd;
|
||||
|
||||
mrb_get_args(mrb, "i", &operation);
|
||||
fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self));
|
||||
|
||||
while (flock(fd, (int)operation) == -1) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
/* retry */
|
||||
break;
|
||||
case EAGAIN: /* NetBSD */
|
||||
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK: /* FreeBSD OpenBSD Linux */
|
||||
#endif
|
||||
if (operation & LOCK_NB) {
|
||||
return mrb_false_value();
|
||||
}
|
||||
/* FALLTHRU - should not happen */
|
||||
default:
|
||||
mrb_sys_fail(mrb, "flock failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return mrb_fixnum_value(0);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_s_symlink(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
|
||||
#else
|
||||
mrb_value from, to;
|
||||
const char *src, *dst;
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
|
||||
mrb_get_args(mrb, "SS", &from, &to);
|
||||
src = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, from), -1);
|
||||
dst = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, to), -1);
|
||||
|
||||
if (symlink(src, dst) == -1) {
|
||||
mrb_locale_free(src);
|
||||
mrb_locale_free(dst);
|
||||
mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to)));
|
||||
}
|
||||
mrb_locale_free(src);
|
||||
mrb_locale_free(dst);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
#endif
|
||||
return mrb_fixnum_value(0);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) {
|
||||
mrb_int mode;
|
||||
mrb_int argc, i;
|
||||
mrb_value *filenames;
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
|
||||
mrb_get_args(mrb, "i*", &mode, &filenames, &argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, filenames[i]), -1);
|
||||
if (CHMOD(path, mode) == -1) {
|
||||
mrb_locale_free(path);
|
||||
mrb_sys_fail(mrb, path);
|
||||
}
|
||||
mrb_locale_free(path);
|
||||
}
|
||||
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
return mrb_fixnum_value(argc);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_file_s_readlink(mrb_state *mrb, mrb_value klass) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "readlink is not supported on this platform");
|
||||
return mrb_nil_value(); // unreachable
|
||||
#else
|
||||
char *path, *buf, *tmp;
|
||||
size_t bufsize = 100;
|
||||
ssize_t rc;
|
||||
mrb_value ret;
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
|
||||
mrb_get_args(mrb, "z", &path);
|
||||
tmp = mrb_locale_from_utf8(path, -1);
|
||||
|
||||
buf = (char *)mrb_malloc(mrb, bufsize);
|
||||
while ((rc = readlink(tmp, buf, bufsize)) == (ssize_t)bufsize && rc != -1) {
|
||||
bufsize *= 2;
|
||||
buf = (char *)mrb_realloc(mrb, buf, bufsize);
|
||||
}
|
||||
mrb_locale_free(tmp);
|
||||
if (rc == -1) {
|
||||
mrb_free(mrb, buf);
|
||||
mrb_sys_fail(mrb, path);
|
||||
}
|
||||
tmp = mrb_utf8_from_locale(buf, -1);
|
||||
ret = mrb_str_new(mrb, tmp, rc);
|
||||
mrb_locale_free(tmp);
|
||||
mrb_free(mrb, buf);
|
||||
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mrb_init_file(mrb_state *mrb)
|
||||
{
|
||||
struct RClass *io, *file, *cnst;
|
||||
|
||||
io = mrb_class_get(mrb, "IO");
|
||||
file = mrb_define_class(mrb, "File", io);
|
||||
MRB_SET_INSTANCE_TT(file, MRB_TT_DATA);
|
||||
mrb_define_class_method(mrb, file, "umask", mrb_file_s_umask, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, file, "delete", mrb_file_s_unlink, MRB_ARGS_ANY());
|
||||
mrb_define_class_method(mrb, file, "unlink", mrb_file_s_unlink, MRB_ARGS_ANY());
|
||||
mrb_define_class_method(mrb, file, "rename", mrb_file_s_rename, MRB_ARGS_REQ(2));
|
||||
mrb_define_class_method(mrb, file, "symlink", mrb_file_s_symlink, MRB_ARGS_REQ(2));
|
||||
mrb_define_class_method(mrb, file, "chmod", mrb_file_s_chmod, MRB_ARGS_REQ(1) | MRB_ARGS_REST());
|
||||
mrb_define_class_method(mrb, file, "readlink", mrb_file_s_readlink, MRB_ARGS_REQ(1));
|
||||
|
||||
mrb_define_class_method(mrb, file, "dirname", mrb_file_dirname, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, file, "basename", mrb_file_basename, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, file, "realpath", mrb_file_realpath, MRB_ARGS_REQ(1)|MRB_ARGS_OPT(1));
|
||||
mrb_define_class_method(mrb, file, "_getwd", mrb_file__getwd, MRB_ARGS_NONE());
|
||||
mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1));
|
||||
|
||||
mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
|
||||
|
||||
cnst = mrb_define_module_under(mrb, file, "Constants");
|
||||
mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
|
||||
mrb_define_const(mrb, cnst, "LOCK_EX", mrb_fixnum_value(LOCK_EX));
|
||||
mrb_define_const(mrb, cnst, "LOCK_UN", mrb_fixnum_value(LOCK_UN));
|
||||
mrb_define_const(mrb, cnst, "LOCK_NB", mrb_fixnum_value(LOCK_NB));
|
||||
mrb_define_const(mrb, cnst, "SEPARATOR", mrb_str_new_cstr(mrb, FILE_SEPARATOR));
|
||||
mrb_define_const(mrb, cnst, "PATH_SEPARATOR", mrb_str_new_cstr(mrb, PATH_SEPARATOR));
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_str_new_cstr(mrb, FILE_ALT_SEPARATOR));
|
||||
#else
|
||||
mrb_define_const(mrb, cnst, "ALT_SEPARATOR", mrb_nil_value());
|
||||
#endif
|
||||
mrb_define_const(mrb, cnst, "NULL", mrb_str_new_cstr(mrb, NULL_FILE));
|
||||
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
** file.c - File class
|
||||
*/
|
||||
|
||||
#include "mruby.h"
|
||||
#include "mruby/class.h"
|
||||
#include "mruby/data.h"
|
||||
#include "mruby/string.h"
|
||||
#include "mruby/ext/io.h"
|
||||
|
||||
#if MRUBY_RELEASE_NO < 10000
|
||||
#include "error.h"
|
||||
#else
|
||||
#include "mruby/error.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define LSTAT stat
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#define LSTAT lstat
|
||||
#include <sys/file.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/wait.h>
|
||||
#include <libgen.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern struct mrb_data_type mrb_io_type;
|
||||
|
||||
static int
|
||||
mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat)
|
||||
{
|
||||
mrb_value tmp;
|
||||
mrb_value io_klass, str_klass;
|
||||
|
||||
io_klass = mrb_obj_value(mrb_class_get(mrb, "IO"));
|
||||
str_klass = mrb_obj_value(mrb_class_get(mrb, "String"));
|
||||
|
||||
tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass);
|
||||
if (mrb_test(tmp)) {
|
||||
struct mrb_io *fptr;
|
||||
fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type);
|
||||
|
||||
if (fptr && fptr->fd >= 0) {
|
||||
return fstat(fptr->fd, st);
|
||||
}
|
||||
|
||||
mrb_raise(mrb, E_IO_ERROR, "closed stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass);
|
||||
if (mrb_test(tmp)) {
|
||||
char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, obj), -1);
|
||||
int ret;
|
||||
if (do_lstat) {
|
||||
ret = LSTAT(path, st);
|
||||
} else {
|
||||
ret = stat(path, st);
|
||||
}
|
||||
mrb_locale_free(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
mrb_stat(mrb_state *mrb, mrb_value obj, struct stat *st)
|
||||
{
|
||||
return mrb_stat0(mrb, obj, st, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
mrb_lstat(mrb_state *mrb, mrb_value obj, struct stat *st)
|
||||
{
|
||||
return mrb_stat0(mrb, obj, st, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: directory?
|
||||
*
|
||||
* call-seq:
|
||||
* File.directory?(file_name) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the named file is a directory,
|
||||
* or a symlink that points at a directory, and <code>false</code>
|
||||
* otherwise.
|
||||
*
|
||||
* File.directory?(".")
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_directory_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#ifndef S_ISDIR
|
||||
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_false_value();
|
||||
if (S_ISDIR(st.st_mode))
|
||||
return mrb_true_value();
|
||||
|
||||
return mrb_false_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.pipe?(file_name) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the named file is a pipe.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_pipe_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "pipe is not supported on this platform");
|
||||
#else
|
||||
#ifdef S_IFIFO
|
||||
# ifndef S_ISFIFO
|
||||
# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
|
||||
# endif
|
||||
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_false_value();
|
||||
if (S_ISFIFO(st.st_mode))
|
||||
return mrb_true_value();
|
||||
|
||||
#endif
|
||||
return mrb_false_value();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.symlink?(file_name) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the named file is a symbolic link.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_symlink_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "symlink is not supported on this platform");
|
||||
#else
|
||||
#ifndef S_ISLNK
|
||||
# ifdef _S_ISLNK
|
||||
# define S_ISLNK(m) _S_ISLNK(m)
|
||||
# else
|
||||
# ifdef _S_IFLNK
|
||||
# define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK)
|
||||
# else
|
||||
# ifdef S_IFLNK
|
||||
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef S_ISLNK
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_lstat(mrb, obj, &st) == -1)
|
||||
return mrb_false_value();
|
||||
if (S_ISLNK(st.st_mode))
|
||||
return mrb_true_value();
|
||||
#endif
|
||||
|
||||
return mrb_false_value();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.socket?(file_name) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the named file is a socket.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_socket_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
mrb_raise(mrb, E_NOTIMP_ERROR, "socket is not supported on this platform");
|
||||
#else
|
||||
#ifndef S_ISSOCK
|
||||
# ifdef _S_ISSOCK
|
||||
# define S_ISSOCK(m) _S_ISSOCK(m)
|
||||
# else
|
||||
# ifdef _S_IFSOCK
|
||||
# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
|
||||
# else
|
||||
# ifdef S_IFSOCK
|
||||
# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef S_ISSOCK
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_false_value();
|
||||
if (S_ISSOCK(st.st_mode))
|
||||
return mrb_true_value();
|
||||
#endif
|
||||
|
||||
return mrb_false_value();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.exist?(file_name) -> true or false
|
||||
* File.exists?(file_name) -> true or false
|
||||
*
|
||||
* Return <code>true</code> if the named file exists.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_exist_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_false_value();
|
||||
|
||||
return mrb_true_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.file?(file_name) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the named file exists and is a
|
||||
* regular file.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_file_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_false_value();
|
||||
if (S_ISREG(st.st_mode))
|
||||
return mrb_true_value();
|
||||
|
||||
return mrb_false_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.zero?(file_name) -> true or false
|
||||
*
|
||||
* Returns <code>true</code> if the named file exists and has
|
||||
* a zero size.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_zero_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_false_value();
|
||||
if (st.st_size == 0)
|
||||
return mrb_true_value();
|
||||
|
||||
return mrb_false_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.size(file_name) -> integer
|
||||
*
|
||||
* Returns the size of <code>file_name</code>.
|
||||
*
|
||||
* _file_name_ can be an IO object.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_size(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
mrb_sys_fail(mrb, "mrb_stat");
|
||||
|
||||
return mrb_fixnum_value(st.st_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* File.size?(file_name) -> Integer or nil
|
||||
*
|
||||
* Returns +nil+ if +file_name+ doesn't exist or has zero size, the size of the
|
||||
* file otherwise.
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_filetest_s_size_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
struct stat st;
|
||||
mrb_value obj;
|
||||
|
||||
mrb_get_args(mrb, "o", &obj);
|
||||
|
||||
if (mrb_stat(mrb, obj, &st) < 0)
|
||||
return mrb_nil_value();
|
||||
if (st.st_size == 0)
|
||||
return mrb_nil_value();
|
||||
|
||||
return mrb_fixnum_value(st.st_size);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_init_file_test(mrb_state *mrb)
|
||||
{
|
||||
struct RClass *f;
|
||||
|
||||
f = mrb_define_class(mrb, "FileTest", mrb->object_class);
|
||||
|
||||
mrb_define_class_method(mrb, f, "directory?", mrb_filetest_s_directory_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "exist?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "exists?", mrb_filetest_s_exist_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "file?", mrb_filetest_s_file_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "pipe?", mrb_filetest_s_pipe_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "size", mrb_filetest_s_size, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "size?", mrb_filetest_s_size_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "socket?", mrb_filetest_s_socket_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "symlink?", mrb_filetest_s_symlink_p, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, f, "zero?", mrb_filetest_s_zero_p, MRB_ARGS_REQ(1));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
#include "mruby.h"
|
||||
|
||||
void mrb_init_io(mrb_state *mrb);
|
||||
void mrb_init_file(mrb_state *mrb);
|
||||
void mrb_init_file_test(mrb_state *mrb);
|
||||
|
||||
#define DONE mrb_gc_arena_restore(mrb, 0)
|
||||
|
||||
void
|
||||
mrb_mruby_io_gem_init(mrb_state* mrb)
|
||||
{
|
||||
mrb_init_io(mrb); DONE;
|
||||
mrb_init_file(mrb); DONE;
|
||||
mrb_init_file_test(mrb); DONE;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_io_gem_final(mrb_state* mrb)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
##
|
||||
# IO Test
|
||||
|
||||
assert('File', '15.2.21') do
|
||||
File.class == Class
|
||||
end
|
||||
|
||||
assert('File', '15.2.21.2') do
|
||||
File.superclass == IO
|
||||
end
|
||||
|
||||
assert('File TEST SETUP') do
|
||||
MRubyIOTestUtil.io_test_setup
|
||||
end
|
||||
|
||||
assert('File#initialize', '15.2.21.4.1') do
|
||||
io = File.open($mrbtest_io_rfname, "r")
|
||||
assert_nil io.close
|
||||
assert_raise IOError do
|
||||
io.close
|
||||
end
|
||||
end
|
||||
|
||||
assert('File#path', '15.2.21.4.2') do
|
||||
io = File.open($mrbtest_io_rfname, "r")
|
||||
assert_equal $mrbtest_io_msg, io.read
|
||||
assert_equal $mrbtest_io_rfname, io.path
|
||||
io.close
|
||||
assert_equal $mrbtest_io_rfname, io.path
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('File.basename') do
|
||||
assert_equal '/', File.basename('//')
|
||||
assert_equal 'a', File.basename('/a/')
|
||||
assert_equal 'b', File.basename('/a/b')
|
||||
assert_equal 'b', File.basename('../a/b')
|
||||
end
|
||||
|
||||
assert('File.dirname') do
|
||||
assert_equal '.', File.dirname('')
|
||||
assert_equal '.', File.dirname('a')
|
||||
assert_equal '/', File.dirname('/a')
|
||||
assert_equal 'a', File.dirname('a/b')
|
||||
assert_equal '/a', File.dirname('/a/b')
|
||||
end
|
||||
|
||||
assert('File.extname') do
|
||||
assert_equal '.txt', File.extname('foo/foo.txt')
|
||||
assert_equal '.gz', File.extname('foo/foo.tar.gz')
|
||||
assert_equal '', File.extname('foo/bar')
|
||||
assert_equal '', File.extname('foo/.bar')
|
||||
assert_equal '', File.extname('foo.txt/bar')
|
||||
assert_equal '', File.extname('.foo')
|
||||
end
|
||||
|
||||
assert('IO#flock') do
|
||||
f = File.open $mrbtest_io_rfname
|
||||
begin
|
||||
assert_equal(f.flock(File::LOCK_SH), 0)
|
||||
assert_equal(f.flock(File::LOCK_UN), 0)
|
||||
assert_equal(f.flock(File::LOCK_EX | File::LOCK_NB), 0)
|
||||
assert_equal(f.flock(File::LOCK_UN), 0)
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
ensure
|
||||
f.close
|
||||
end
|
||||
end
|
||||
|
||||
assert('File.join') do
|
||||
assert_equal "", File.join()
|
||||
assert_equal "a", File.join("a")
|
||||
assert_equal "/a", File.join("/a")
|
||||
assert_equal "a/", File.join("a/")
|
||||
assert_equal "a/b/c", File.join("a", "b", "c")
|
||||
assert_equal "/a/b/c", File.join("/a", "b", "c")
|
||||
assert_equal "a/b/c/", File.join("a", "b", "c/")
|
||||
assert_equal "a/b/c", File.join("a/", "/b/", "/c")
|
||||
assert_equal "a/b/c", File.join(["a", "b", "c"])
|
||||
assert_equal "a/b/c", File.join("a", ["b", ["c"]])
|
||||
end
|
||||
|
||||
assert('File.realpath') do
|
||||
if File::ALT_SEPARATOR
|
||||
readme_path = File._getwd + File::ALT_SEPARATOR + "README.md"
|
||||
assert_equal readme_path, File.realpath("README.md")
|
||||
else
|
||||
dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
|
||||
begin
|
||||
dir1 = File.realpath($mrbtest_io_rfname)
|
||||
dir2 = File.realpath("./#{dir}//./../#{$mrbtest_io_symlinkname}")
|
||||
assert_equal dir1, dir2
|
||||
ensure
|
||||
MRubyIOTestUtil.rmdir dir
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert("File.readlink") do
|
||||
begin
|
||||
assert_equal $mrbtest_io_rfname, File.readlink($mrbtest_io_symlinkname)
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert("File.readlink fails with non-symlink") do
|
||||
skip "readlink is not supported on this platform" if MRubyIOTestUtil.win?
|
||||
begin
|
||||
e2 = nil
|
||||
assert_raise(RuntimeError) {
|
||||
begin
|
||||
File.readlink($mrbtest_io_rfname)
|
||||
rescue => e
|
||||
if Object.const_defined?(:SystemCallError) and e.kind_of?(SystemCallError)
|
||||
raise RuntimeError, "SystemCallError converted to RuntimeError"
|
||||
end
|
||||
raise e
|
||||
rescue NotImplementedError => e
|
||||
e2 = e
|
||||
end
|
||||
}
|
||||
raise e2 if e2
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('File.expand_path') do
|
||||
assert_equal "/", File.expand_path("..", "/tmp"), "parent path with base_dir (1)"
|
||||
assert_equal "/tmp", File.expand_path("..", "/tmp/mruby"), "parent path with base_dir (2)"
|
||||
|
||||
assert_equal "/home", File.expand_path("/home"), "absolute"
|
||||
assert_equal "/home", File.expand_path("/home", "."), "absolute with base_dir"
|
||||
|
||||
assert_equal "/hoge", File.expand_path("/tmp/..//hoge")
|
||||
assert_equal "/hoge", File.expand_path("////tmp/..///////hoge")
|
||||
|
||||
assert_equal "/", File.expand_path("../../../..", "/")
|
||||
if File._getwd[1] == ":"
|
||||
drive_letter = File._getwd[0]
|
||||
assert_equal drive_letter + ":\\", File.expand_path(([".."] * 100).join("/"))
|
||||
else
|
||||
assert_equal "/", File.expand_path(([".."] * 100).join("/"))
|
||||
end
|
||||
end
|
||||
|
||||
assert('File.expand_path (with ENV)') do
|
||||
skip unless Object.const_defined?(:ENV) && ENV['HOME']
|
||||
|
||||
assert_equal ENV['HOME'], File.expand_path("~/"), "home"
|
||||
assert_equal ENV['HOME'], File.expand_path("~/", "/"), "home with base_dir"
|
||||
|
||||
assert_equal "#{ENV['HOME']}/user", File.expand_path("user", ENV['HOME']), "relative with base_dir"
|
||||
end
|
||||
|
||||
assert('File.path') do
|
||||
assert_equal "", File.path("")
|
||||
assert_equal "a/b/c", File.path("a/b/c")
|
||||
assert_equal "a/../b/./c", File.path("a/../b/./c")
|
||||
assert_raise(TypeError) { File.path(nil) }
|
||||
assert_raise(TypeError) { File.path(123) }
|
||||
|
||||
end
|
||||
|
||||
assert('File.symlink') do
|
||||
target_name = "/usr/bin"
|
||||
symlink_name = "test-bin-dummy"
|
||||
if !File.exist?(target_name)
|
||||
skip("target directory of File.symlink is not found")
|
||||
else
|
||||
begin
|
||||
assert_equal 0, File.symlink(target_name, symlink_name)
|
||||
begin
|
||||
assert_equal true, File.symlink?(symlink_name)
|
||||
ensure
|
||||
File.delete symlink_name
|
||||
end
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assert('File.chmod') do
|
||||
File.open('chmod-test', 'w') {}
|
||||
begin
|
||||
assert_equal 1, File.chmod(0400, 'chmod-test')
|
||||
ensure
|
||||
File.delete('chmod-test')
|
||||
end
|
||||
end
|
||||
|
||||
assert('File TEST CLEANUP') do
|
||||
assert_nil MRubyIOTestUtil.io_test_cleanup
|
||||
end
|
||||
@@ -0,0 +1,117 @@
|
||||
##
|
||||
# FileTest
|
||||
|
||||
assert('FileTest TEST SETUP') do
|
||||
MRubyIOTestUtil.io_test_setup
|
||||
end
|
||||
|
||||
assert("FileTest.directory?") do
|
||||
dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
|
||||
begin
|
||||
assert_true FileTest.directory?(dir)
|
||||
assert_false FileTest.directory?($mrbtest_io_rfname)
|
||||
ensure
|
||||
MRubyIOTestUtil.rmdir dir
|
||||
end
|
||||
end
|
||||
|
||||
assert("FileTest.exist?") do
|
||||
assert_equal true, FileTest.exist?($mrbtest_io_rfname), "filename - exist"
|
||||
assert_equal false, FileTest.exist?($mrbtest_io_rfname + "-"), "filename - not exist"
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
assert_equal true, FileTest.exist?(io), "io obj - exist"
|
||||
io.close
|
||||
assert_equal true, io.closed?
|
||||
assert_raise IOError do
|
||||
FileTest.exist?(io)
|
||||
end
|
||||
end
|
||||
|
||||
assert("FileTest.file?") do
|
||||
dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX")
|
||||
begin
|
||||
assert_true FileTest.file?($mrbtest_io_rfname)
|
||||
assert_false FileTest.file?(dir)
|
||||
ensure
|
||||
MRubyIOTestUtil.rmdir dir
|
||||
end
|
||||
end
|
||||
|
||||
assert("FileTest.pipe?") do
|
||||
begin
|
||||
assert_equal false, FileTest.pipe?("/tmp")
|
||||
io = IO.popen("ls")
|
||||
assert_equal true, FileTest.pipe?(io)
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('FileTest.size') do
|
||||
assert_equal FileTest.size($mrbtest_io_rfname), $mrbtest_io_msg.size
|
||||
assert_equal FileTest.size($mrbtest_io_wfname), 0
|
||||
end
|
||||
|
||||
assert("FileTest.size?") do
|
||||
assert_equal $mrbtest_io_msg.size, FileTest.size?($mrbtest_io_rfname)
|
||||
assert_equal nil, FileTest.size?($mrbtest_io_wfname)
|
||||
assert_equal nil, FileTest.size?("not-exist-test-target-file")
|
||||
|
||||
fp1 = File.open($mrbtest_io_rfname)
|
||||
fp2 = File.open($mrbtest_io_wfname)
|
||||
assert_equal $mrbtest_io_msg.size, FileTest.size?(fp1)
|
||||
assert_equal nil, FileTest.size?(fp2)
|
||||
fp1.close
|
||||
fp2.close
|
||||
|
||||
assert_raise IOError do
|
||||
FileTest.size?(fp1)
|
||||
end
|
||||
assert_raise IOError do
|
||||
FileTest.size?(fp2)
|
||||
end
|
||||
|
||||
fp1.closed? && fp2.closed?
|
||||
end
|
||||
|
||||
assert("FileTest.socket?") do
|
||||
begin
|
||||
assert_true FileTest.socket?($mrbtest_io_socketname)
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert("FileTest.symlink?") do
|
||||
begin
|
||||
assert_true FileTest.symlink?($mrbtest_io_symlinkname)
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert("FileTest.zero?") do
|
||||
assert_equal false, FileTest.zero?($mrbtest_io_rfname)
|
||||
assert_equal true, FileTest.zero?($mrbtest_io_wfname)
|
||||
assert_equal false, FileTest.zero?("not-exist-test-target-file")
|
||||
|
||||
fp1 = File.open($mrbtest_io_rfname)
|
||||
fp2 = File.open($mrbtest_io_wfname)
|
||||
assert_equal false, FileTest.zero?(fp1)
|
||||
assert_equal true, FileTest.zero?(fp2)
|
||||
fp1.close
|
||||
fp2.close
|
||||
|
||||
assert_raise IOError do
|
||||
FileTest.zero?(fp1)
|
||||
end
|
||||
assert_raise IOError do
|
||||
FileTest.zero?(fp2)
|
||||
end
|
||||
|
||||
fp1.closed? && fp2.closed?
|
||||
end
|
||||
|
||||
assert('FileTest TEST CLEANUP') do
|
||||
assert_nil MRubyIOTestUtil.io_test_cleanup
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
ulimit -n 20
|
||||
mruby -e '100.times { File.open "'$0'" }'
|
||||
@@ -0,0 +1,642 @@
|
||||
##
|
||||
# IO Test
|
||||
|
||||
unless Object.respond_to? :assert_nothing_raised
|
||||
def assert_nothing_raised(*exp)
|
||||
ret = true
|
||||
if $mrbtest_assert
|
||||
$mrbtest_assert_idx += 1
|
||||
msg = exp.last.class == String ? exp.pop : ""
|
||||
begin
|
||||
yield
|
||||
rescue Exception => e
|
||||
msg = "#{msg} exception raised."
|
||||
diff = " Class: <#{e.class}>\n" +
|
||||
" Message: #{e.message}"
|
||||
$mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
|
||||
ret = false
|
||||
end
|
||||
end
|
||||
ret
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO TEST SETUP') do
|
||||
MRubyIOTestUtil.io_test_setup
|
||||
$cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not
|
||||
end
|
||||
|
||||
assert('IO', '15.2.20') do
|
||||
assert_equal(Class, IO.class)
|
||||
end
|
||||
|
||||
assert('IO', '15.2.20.2') do
|
||||
assert_equal(Object, IO.superclass)
|
||||
end
|
||||
|
||||
assert('IO', '15.2.20.3') do
|
||||
assert_include(IO.included_modules, Enumerable)
|
||||
end
|
||||
|
||||
assert('IO.open', '15.2.20.4.1') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
assert_equal Fixnum, fd.class
|
||||
io = IO.open fd
|
||||
assert_equal IO, io.class
|
||||
assert_equal $mrbtest_io_msg, io.read
|
||||
io.close
|
||||
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
IO.open(fd) do |io|
|
||||
assert_equal $mrbtest_io_msg, io.read
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#close', '15.2.20.5.1') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
assert_nil io.close
|
||||
end
|
||||
|
||||
assert('IO#closed?', '15.2.20.5.2') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
assert_false io.closed?
|
||||
io.close
|
||||
assert_true io.closed?
|
||||
end
|
||||
|
||||
#assert('IO#each', '15.2.20.5.3') do
|
||||
#assert('IO#each_byte', '15.2.20.5.4') do
|
||||
#assert('IO#each_line', '15.2.20.5.5') do
|
||||
|
||||
assert('IO#eof?', '15.2.20.5.6') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_wfname, 'w'), 'w')
|
||||
assert_raise(IOError) do
|
||||
io.eof?
|
||||
end
|
||||
io.close
|
||||
|
||||
# empty file
|
||||
io = IO.open(IO.sysopen($mrbtest_io_wfname, 'w'), 'w')
|
||||
io.close
|
||||
io = IO.open(IO.sysopen($mrbtest_io_wfname, 'r'), 'r')
|
||||
assert_true io.eof?
|
||||
io.close
|
||||
|
||||
# nonempty file
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
assert_false io.eof?
|
||||
io.readchar
|
||||
assert_false io.eof?
|
||||
io.read
|
||||
assert_true io.eof?
|
||||
io.close
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#flush', '15.2.20.5.7') do
|
||||
# Note: mruby-io does not have any buffer to be flushed now.
|
||||
io = IO.new(IO.sysopen($mrbtest_io_wfname))
|
||||
assert_equal io, io.flush
|
||||
io.close
|
||||
assert_raise(IOError) do
|
||||
io.flush
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO#getc', '15.2.20.5.8') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
$mrbtest_io_msg.each_char { |ch|
|
||||
assert_equal ch, io.getc
|
||||
}
|
||||
assert_equal nil, io.getc
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
#assert('IO#gets', '15.2.20.5.9') do
|
||||
#assert('IO#initialize_copy', '15.2.20.5.10') do
|
||||
#assert('IO#print', '15.2.20.5.11') do
|
||||
#assert('IO#putc', '15.2.20.5.12') do
|
||||
#assert('IO#puts', '15.2.20.5.13') do
|
||||
|
||||
assert('IO#read', '15.2.20.5.14') do
|
||||
IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
|
||||
assert_raise(ArgumentError) { io.read(-5) }
|
||||
assert_raise(TypeError) { io.read("str") }
|
||||
|
||||
len = $mrbtest_io_msg.length
|
||||
assert_equal '', io.read(0)
|
||||
assert_equal 'mruby', io.read(5)
|
||||
assert_equal $mrbtest_io_msg[5,len], io.read(len)
|
||||
|
||||
assert_equal "", io.read
|
||||
assert_nil io.read(1)
|
||||
end
|
||||
|
||||
IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
|
||||
assert_equal $mrbtest_io_msg, io.read
|
||||
end
|
||||
end
|
||||
|
||||
assert "IO#read(n) with n > IO::BUF_SIZE" do
|
||||
skip "pipe is not supported on this platform" if MRubyIOTestUtil.win?
|
||||
r,w = IO.pipe
|
||||
n = IO::BUF_SIZE+1
|
||||
w.write 'a'*n
|
||||
assert_equal r.read(n), 'a'*n
|
||||
end
|
||||
|
||||
assert('IO#readchar', '15.2.20.5.15') do
|
||||
# almost same as IO#getc
|
||||
IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
|
||||
$mrbtest_io_msg.each_char { |ch|
|
||||
assert_equal ch, io.readchar
|
||||
}
|
||||
assert_raise(EOFError) do
|
||||
io.readchar
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#assert('IO#readline', '15.2.20.5.16') do
|
||||
#assert('IO#readlines', '15.2.20.5.17') do
|
||||
|
||||
assert('IO#sync', '15.2.20.5.18') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
s = io.sync
|
||||
assert_true(s == true || s == false)
|
||||
io.close
|
||||
assert_raise(IOError) do
|
||||
io.sync
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO#sync=', '15.2.20.5.19') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
io.sync = true
|
||||
assert_true io.sync
|
||||
io.sync = false
|
||||
assert_false io.sync
|
||||
io.close
|
||||
assert_raise(IOError) do
|
||||
io.sync = true
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO#write', '15.2.20.5.20') do
|
||||
io = IO.open(IO.sysopen($mrbtest_io_wfname))
|
||||
assert_equal 0, io.write("")
|
||||
io.close
|
||||
|
||||
io = IO.open(IO.sysopen($mrbtest_io_wfname, "r+"), "r+")
|
||||
assert_equal 7, io.write("abcdefg")
|
||||
io.rewind
|
||||
assert_equal "ab", io.read(2)
|
||||
assert_equal 3, io.write("123")
|
||||
io.rewind
|
||||
assert_equal "ab123fg", io.read
|
||||
io.close
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#<<') do
|
||||
io = IO.open(IO.sysopen($mrbtest_io_wfname))
|
||||
io << "" << ""
|
||||
assert_equal 0, io.pos
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#dup for readable') do
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname))
|
||||
dup = io.dup
|
||||
assert_true io != dup
|
||||
assert_true io.fileno != dup.fileno
|
||||
assert_equal 'm', dup.sysread(1)
|
||||
assert_equal 'r', io.sysread(1)
|
||||
assert_equal 'u', dup.sysread(1)
|
||||
assert_equal 'b', io.sysread(1)
|
||||
assert_equal 'y', dup.sysread(1)
|
||||
dup.close
|
||||
assert_false io.closed?
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#dup for writable') do
|
||||
io = IO.open(IO.sysopen($mrbtest_io_wfname, 'w+'), 'w+')
|
||||
dup = io.dup
|
||||
io.syswrite "mruby"
|
||||
assert_equal 5, dup.sysseek(0, IO::SEEK_CUR)
|
||||
io.sysseek 0, IO::SEEK_SET
|
||||
assert_equal 0, dup.sysseek(0, IO::SEEK_CUR)
|
||||
assert_equal "mruby", dup.sysread(5)
|
||||
dup.close
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO.for_fd') do
|
||||
fd = IO.sysopen($mrbtest_io_rfname)
|
||||
io = IO.for_fd(fd)
|
||||
assert_equal $mrbtest_io_msg, io.read
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO.new') do
|
||||
io = IO.new(0)
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO gc check') do
|
||||
100.times { IO.new(0) }
|
||||
end
|
||||
|
||||
assert('IO.sysopen("./nonexistent")') do
|
||||
if Object.const_defined? :Errno
|
||||
eclass = Errno::ENOENT
|
||||
else
|
||||
eclass = RuntimeError
|
||||
end
|
||||
assert_raise eclass do
|
||||
fd = IO.sysopen "./nonexistent"
|
||||
IO._sysclose fd
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.sysopen, IO#sysread') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
io = IO.new fd
|
||||
str1 = " "
|
||||
str2 = io.sysread(5, str1)
|
||||
assert_equal $mrbtest_io_msg[0,5], str1
|
||||
assert_equal $mrbtest_io_msg[0,5], str2
|
||||
assert_raise EOFError do
|
||||
io.sysread(10000)
|
||||
io.sysread(10000)
|
||||
end
|
||||
|
||||
assert_raise RuntimeError do
|
||||
io.sysread(5, "abcde".freeze)
|
||||
end
|
||||
|
||||
io.close
|
||||
assert_equal "", io.sysread(0)
|
||||
assert_raise(IOError) { io.sysread(1) }
|
||||
assert_raise(ArgumentError) { io.sysread(-1) }
|
||||
io.closed?
|
||||
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
assert_raise(IOError) { io.sysread(1) }
|
||||
io.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO.sysopen, IO#syswrite') do
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
str = "abcdefg"
|
||||
len = io.syswrite(str)
|
||||
assert_equal str.size, len
|
||||
io.close
|
||||
|
||||
io = IO.new(IO.sysopen($mrbtest_io_rfname), "r")
|
||||
assert_raise(IOError) { io.syswrite("a") }
|
||||
io.close
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#_read_buf') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
io = IO.new fd
|
||||
def io._buf
|
||||
@buf
|
||||
end
|
||||
msg_len = $mrbtest_io_msg.size
|
||||
assert_equal '', io._buf
|
||||
assert_equal $mrbtest_io_msg, io._read_buf
|
||||
assert_equal $mrbtest_io_msg, io._buf
|
||||
assert_equal 'mruby', io.read(5)
|
||||
assert_equal 5, io.pos
|
||||
assert_equal msg_len - 5, io._buf.size
|
||||
assert_equal $mrbtest_io_msg[5,100], io.read
|
||||
assert_equal 0, io._buf.size
|
||||
assert_raise EOFError do
|
||||
io._read_buf
|
||||
end
|
||||
assert_equal true, io.eof
|
||||
assert_equal true, io.eof?
|
||||
io.close
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('IO#isatty') do
|
||||
skip "isatty is not supported on this platform" if MRubyIOTestUtil.win?
|
||||
f1 = File.open("/dev/tty")
|
||||
f2 = File.open($mrbtest_io_rfname)
|
||||
|
||||
assert_true f1.isatty
|
||||
assert_false f2.isatty
|
||||
|
||||
f1.close
|
||||
f2.close
|
||||
true
|
||||
end
|
||||
|
||||
assert('IO#pos=, IO#seek') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
io = IO.new fd
|
||||
def io._buf
|
||||
@buf
|
||||
end
|
||||
assert_equal 'm', io.getc
|
||||
assert_equal 1, io.pos
|
||||
assert_equal 0, io.seek(0)
|
||||
assert_equal 0, io.pos
|
||||
io.close
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('IO#rewind') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
io = IO.new fd
|
||||
assert_equal 'm', io.getc
|
||||
assert_equal 1, io.pos
|
||||
assert_equal 0, io.rewind
|
||||
assert_equal 0, io.pos
|
||||
io.close
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('IO#gets') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
io = IO.new fd
|
||||
|
||||
# gets without arguments
|
||||
assert_equal $mrbtest_io_msg, io.gets, "gets without arguments"
|
||||
assert_equal nil, io.gets, "gets returns nil, when EOF"
|
||||
|
||||
# gets with limit
|
||||
io.pos = 0
|
||||
assert_equal $mrbtest_io_msg[0, 5], io.gets(5), "gets with limit"
|
||||
|
||||
# gets with rs
|
||||
io.pos = 0
|
||||
assert_equal $mrbtest_io_msg[0, 6], io.gets(' '), "gets with rs"
|
||||
|
||||
# gets with rs, limit
|
||||
io.pos = 0
|
||||
assert_equal $mrbtest_io_msg[0, 5], io.gets(' ', 5), "gets with rs, limit"
|
||||
io.close
|
||||
assert_equal true, io.closed?, "close success"
|
||||
|
||||
# reading many-lines file.
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
io.write "0123456789" * 2 + "\na"
|
||||
assert_equal 22 + $cr, io.pos
|
||||
io.close
|
||||
assert_equal true, io.closed?
|
||||
|
||||
fd = IO.sysopen $mrbtest_io_wfname
|
||||
io = IO.new fd
|
||||
line = io.gets
|
||||
|
||||
# gets first line
|
||||
assert_equal "0123456789" * 2 + "\n", line, "gets first line"
|
||||
assert_equal 21, line.size
|
||||
assert_equal 21 + $cr, io.pos
|
||||
|
||||
# gets second line
|
||||
assert_equal "a", io.gets, "gets second line"
|
||||
|
||||
# gets third line
|
||||
assert_equal nil, io.gets, "gets third line; returns nil"
|
||||
|
||||
io.close
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('IO#gets - paragraph mode') do
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
io.write "0" * 10 + "\n"
|
||||
io.write "1" * 10 + "\n\n"
|
||||
io.write "2" * 10 + "\n"
|
||||
assert_equal 34 + $cr * 4, io.pos
|
||||
io.close
|
||||
assert_equal true, io.closed?
|
||||
|
||||
fd = IO.sysopen $mrbtest_io_wfname
|
||||
io = IO.new fd
|
||||
para1 = "#{'0' * 10}\n#{'1' * 10}\n\n"
|
||||
text1 = io.gets("")
|
||||
assert_equal para1, text1
|
||||
para2 = "#{'2' * 10}\n"
|
||||
text2 = io.gets("")
|
||||
assert_equal para2, text2
|
||||
io.close
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('IO.popen') do
|
||||
begin
|
||||
$? = nil
|
||||
io = IO.popen("echo mruby-io")
|
||||
assert_true io.close_on_exec?
|
||||
assert_equal Fixnum, io.pid.class
|
||||
|
||||
out = io.read
|
||||
assert_equal out.class, String
|
||||
assert_include out, 'mruby-io'
|
||||
|
||||
io.close
|
||||
if Object.const_defined? :Process
|
||||
assert_true $?.success?
|
||||
else
|
||||
assert_equal 0, $?
|
||||
end
|
||||
|
||||
assert_true io.closed?
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.popen with in option') do
|
||||
begin
|
||||
IO.pipe do |r, w|
|
||||
w.write 'hello'
|
||||
w.close
|
||||
assert_equal "hello", IO.popen("cat", "r", in: r) { |i| i.read }
|
||||
assert_equal "", r.read
|
||||
end
|
||||
assert_raise(ArgumentError) { IO.popen("hello", "r", in: Object.new) }
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.popen with out option') do
|
||||
begin
|
||||
IO.pipe do |r, w|
|
||||
IO.popen("echo 'hello'", "w", out: w) {}
|
||||
w.close
|
||||
assert_equal "hello\n", r.read
|
||||
end
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.popen with err option') do
|
||||
begin
|
||||
IO.pipe do |r, w|
|
||||
assert_equal "", IO.popen("echo 'hello' 1>&2", "r", err: w) { |i| i.read }
|
||||
w.close
|
||||
assert_equal "hello\n", r.read
|
||||
end
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.read') do
|
||||
# empty file
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
io.close
|
||||
assert_equal "", IO.read($mrbtest_io_wfname)
|
||||
assert_equal nil, IO.read($mrbtest_io_wfname, 1)
|
||||
|
||||
# one byte file
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
io.write "123"
|
||||
io.close
|
||||
assert_equal "123", IO.read($mrbtest_io_wfname)
|
||||
assert_equal "", IO.read($mrbtest_io_wfname, 0)
|
||||
assert_equal "1", IO.read($mrbtest_io_wfname, 1)
|
||||
assert_equal "", IO.read($mrbtest_io_wfname, 0, 10)
|
||||
assert_equal "23", IO.read($mrbtest_io_wfname, 2, 1)
|
||||
assert_equal "23", IO.read($mrbtest_io_wfname, 10, 1)
|
||||
assert_equal "", IO.read($mrbtest_io_wfname, nil, 10)
|
||||
assert_equal nil, IO.read($mrbtest_io_wfname, 1, 10)
|
||||
end
|
||||
|
||||
assert('IO#fileno') do
|
||||
fd = IO.sysopen $mrbtest_io_rfname
|
||||
io = IO.new fd
|
||||
assert_equal io.fileno, fd
|
||||
assert_equal io.to_i, fd
|
||||
io.close
|
||||
io.closed?
|
||||
end
|
||||
|
||||
assert('IO#close_on_exec') do
|
||||
fd = IO.sysopen $mrbtest_io_wfname, "w"
|
||||
io = IO.new fd, "w"
|
||||
begin
|
||||
# IO.sysopen opens a file descripter with O_CLOEXEC flag.
|
||||
assert_true io.close_on_exec?
|
||||
rescue ScriptError
|
||||
io.close
|
||||
skip "IO\#close_on_exec is not implemented."
|
||||
end
|
||||
|
||||
io.close_on_exec = false
|
||||
assert_equal(false, io.close_on_exec?)
|
||||
io.close_on_exec = true
|
||||
assert_equal(true, io.close_on_exec?)
|
||||
io.close_on_exec = false
|
||||
assert_equal(false, io.close_on_exec?)
|
||||
|
||||
io.close
|
||||
io.closed?
|
||||
|
||||
begin
|
||||
r, w = IO.pipe
|
||||
assert_equal(true, r.close_on_exec?)
|
||||
r.close_on_exec = false
|
||||
assert_equal(false, r.close_on_exec?)
|
||||
r.close_on_exec = true
|
||||
assert_equal(true, r.close_on_exec?)
|
||||
|
||||
assert_equal(true, w.close_on_exec?)
|
||||
w.close_on_exec = false
|
||||
assert_equal(false, w.close_on_exec?)
|
||||
w.close_on_exec = true
|
||||
assert_equal(true, w.close_on_exec?)
|
||||
ensure
|
||||
r.close unless r.closed?
|
||||
w.close unless w.closed?
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO#sysseek') do
|
||||
IO.open(IO.sysopen($mrbtest_io_rfname)) do |io|
|
||||
assert_equal 2, io.sysseek(2)
|
||||
assert_equal 5, io.sysseek(3, IO::SEEK_CUR) # 2 + 3 => 5
|
||||
assert_equal $mrbtest_io_msg.size - 4, io.sysseek(-4, IO::SEEK_END)
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO.pipe') do
|
||||
begin
|
||||
called = false
|
||||
IO.pipe do |r, w|
|
||||
assert_true r.kind_of?(IO)
|
||||
assert_true w.kind_of?(IO)
|
||||
assert_false r.closed?
|
||||
assert_false w.closed?
|
||||
assert_true FileTest.pipe?(r)
|
||||
assert_true FileTest.pipe?(w)
|
||||
assert_nil r.pid
|
||||
assert_nil w.pid
|
||||
assert_true 2 < r.fileno
|
||||
assert_true 2 < w.fileno
|
||||
assert_true r.fileno != w.fileno
|
||||
assert_false r.sync
|
||||
assert_true w.sync
|
||||
assert_equal 8, w.write('test for')
|
||||
assert_equal 'test', r.read(4)
|
||||
assert_equal ' for', r.read(4)
|
||||
assert_equal 5, w.write(' pipe')
|
||||
assert_equal nil, w.close
|
||||
assert_equal ' pipe', r.read
|
||||
called = true
|
||||
assert_raise(IOError) { r.write 'test' }
|
||||
# TODO:
|
||||
# This assert expect raise IOError but got RuntimeError
|
||||
# Because mruby-io not have flag for I/O readable
|
||||
# assert_raise(IOError) { w.read }
|
||||
end
|
||||
assert_true called
|
||||
|
||||
assert_nothing_raised do
|
||||
IO.pipe { |r, w| r.close; w.close }
|
||||
end
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('`cmd`') do
|
||||
begin
|
||||
assert_equal `echo foo`, "foo\n"
|
||||
rescue NotImplementedError => e
|
||||
skip e.message
|
||||
end
|
||||
end
|
||||
|
||||
assert('IO TEST CLEANUP') do
|
||||
assert_nil MRubyIOTestUtil.io_test_cleanup
|
||||
end
|
||||
@@ -0,0 +1,256 @@
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <direct.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#if (!defined __MINGW64__) && (!defined __MINGW32__)
|
||||
typedef int mode_t;
|
||||
#endif
|
||||
|
||||
#define open _open
|
||||
#define close _close
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <sys/stat.h>
|
||||
|
||||
static int
|
||||
mkstemp(char *p)
|
||||
{
|
||||
int fd;
|
||||
char* fname = _mktemp(p);
|
||||
if (fname == NULL)
|
||||
return -1;
|
||||
fd = open(fname, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char*
|
||||
mkdtemp(char *temp)
|
||||
{
|
||||
char *path = _mktemp(temp);
|
||||
if (path[0] == 0) return NULL;
|
||||
if (_mkdir(path) < 0) return NULL;
|
||||
return path;
|
||||
}
|
||||
|
||||
#define umask(mode) _umask(mode)
|
||||
#define rmdir(path) _rmdir(path)
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mruby.h"
|
||||
#include "mruby/array.h"
|
||||
#include "mruby/error.h"
|
||||
#include "mruby/string.h"
|
||||
#include "mruby/variable.h"
|
||||
|
||||
static mrb_value
|
||||
mrb_io_test_io_setup(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
char rfname[] = "tmp.mruby-io-test-r.XXXXXXXX";
|
||||
char wfname[] = "tmp.mruby-io-test-w.XXXXXXXX";
|
||||
char symlinkname[] = "tmp.mruby-io-test-l.XXXXXXXX";
|
||||
char socketname[] = "tmp.mruby-io-test-s.XXXXXXXX";
|
||||
char msg[] = "mruby io test\n";
|
||||
mode_t mask;
|
||||
int fd0, fd1;
|
||||
FILE *fp;
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
int fd2, fd3;
|
||||
struct sockaddr_un sun0;
|
||||
#endif
|
||||
|
||||
mask = umask(077);
|
||||
fd0 = mkstemp(rfname);
|
||||
fd1 = mkstemp(wfname);
|
||||
if (fd0 == -1 || fd1 == -1) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file");
|
||||
return mrb_nil_value();
|
||||
}
|
||||
close(fd0);
|
||||
close(fd1);
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
fd2 = mkstemp(symlinkname);
|
||||
fd3 = mkstemp(socketname);
|
||||
if (fd2 == -1 || fd3 == -1) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't create temporary file");
|
||||
return mrb_nil_value();
|
||||
}
|
||||
#endif
|
||||
umask(mask);
|
||||
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_str_new_cstr(mrb, rfname));
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_str_new_cstr(mrb, wfname));
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_str_new_cstr(mrb, symlinkname));
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_str_new_cstr(mrb, socketname));
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_str_new_cstr(mrb, msg));
|
||||
|
||||
fp = fopen(rfname, "wb");
|
||||
if (fp == NULL) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file");
|
||||
return mrb_nil_value();
|
||||
}
|
||||
fputs(msg, fp);
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(wfname, "wb");
|
||||
if (fp == NULL) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't open temporary file");
|
||||
return mrb_nil_value();
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
unlink(symlinkname);
|
||||
close(fd2);
|
||||
if (symlink(rfname, symlinkname) == -1) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link");
|
||||
}
|
||||
|
||||
unlink(socketname);
|
||||
close(fd3);
|
||||
fd3 = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd3 == -1) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a socket");
|
||||
}
|
||||
sun0.sun_family = AF_UNIX;
|
||||
snprintf(sun0.sun_path, sizeof(sun0.sun_path), "%s", socketname);
|
||||
if (bind(fd3, (struct sockaddr *)&sun0, sizeof(sun0)) == -1) {
|
||||
mrb_raisef(mrb, E_RUNTIME_ERROR, "can't bind AF_UNIX socket to %S: %S",
|
||||
mrb_str_new_cstr(mrb, sun0.sun_path),
|
||||
mrb_fixnum_value(errno));
|
||||
}
|
||||
close(fd3);
|
||||
#endif
|
||||
|
||||
return mrb_true_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_io_test_io_cleanup(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value rfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"));
|
||||
mrb_value wfname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"));
|
||||
mrb_value symlinkname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"));
|
||||
mrb_value socketname = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"));
|
||||
|
||||
if (mrb_type(rfname) == MRB_TT_STRING) {
|
||||
remove(RSTRING_PTR(rfname));
|
||||
}
|
||||
if (mrb_type(wfname) == MRB_TT_STRING) {
|
||||
remove(RSTRING_PTR(wfname));
|
||||
}
|
||||
if (mrb_type(symlinkname) == MRB_TT_STRING) {
|
||||
remove(RSTRING_PTR(symlinkname));
|
||||
}
|
||||
if (mrb_type(socketname) == MRB_TT_STRING) {
|
||||
remove(RSTRING_PTR(socketname));
|
||||
}
|
||||
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_rfname"), mrb_nil_value());
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_wfname"), mrb_nil_value());
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_symlinkname"), mrb_nil_value());
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_socketname"), mrb_nil_value());
|
||||
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$mrbtest_io_msg"), mrb_nil_value());
|
||||
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_io_test_file_setup(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_value ary = mrb_io_test_io_setup(mrb, self);
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (symlink("/usr/bin", "test-bin") == -1) {
|
||||
mrb_raise(mrb, E_RUNTIME_ERROR, "can't make a symbolic link");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_io_test_file_cleanup(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_io_test_io_cleanup(mrb, self);
|
||||
remove("test-bin");
|
||||
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value str;
|
||||
char *cp;
|
||||
|
||||
mrb_get_args(mrb, "S", &str);
|
||||
cp = mrb_str_to_cstr(mrb, str);
|
||||
if (mkdtemp(cp) == NULL) {
|
||||
mrb_sys_fail(mrb, "mkdtemp");
|
||||
}
|
||||
return mrb_str_new_cstr(mrb, cp);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value str;
|
||||
char *cp;
|
||||
|
||||
mrb_get_args(mrb, "S", &str);
|
||||
cp = mrb_str_to_cstr(mrb, str);
|
||||
if (rmdir(cp) == -1) {
|
||||
mrb_sys_fail(mrb, "rmdir");
|
||||
}
|
||||
return mrb_true_value();
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_io_win_p(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
# if defined(__CYGWIN__) || defined(__CYGWIN32__)
|
||||
return mrb_false_value();
|
||||
# else
|
||||
return mrb_true_value();
|
||||
# endif
|
||||
#else
|
||||
return mrb_false_value();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_io_gem_test(mrb_state* mrb)
|
||||
{
|
||||
struct RClass *io_test = mrb_define_module(mrb, "MRubyIOTestUtil");
|
||||
mrb_define_class_method(mrb, io_test, "io_test_setup", mrb_io_test_io_setup, MRB_ARGS_NONE());
|
||||
mrb_define_class_method(mrb, io_test, "io_test_cleanup", mrb_io_test_io_cleanup, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_class_method(mrb, io_test, "file_test_setup", mrb_io_test_file_setup, MRB_ARGS_NONE());
|
||||
mrb_define_class_method(mrb, io_test, "file_test_cleanup", mrb_io_test_file_cleanup, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_class_method(mrb, io_test, "mkdtemp", mrb_io_test_mkdtemp, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, io_test, "rmdir", mrb_io_test_rmdir, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method(mrb, io_test, "win?", mrb_io_win_p, MRB_ARGS_NONE());
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
module Kernel
|
||||
# call-seq:
|
||||
# obj.yield_self {|_obj|...} -> an_object
|
||||
#
|
||||
# Yields <i>obj</i> and returns the result.
|
||||
#
|
||||
# 'my string'.yield_self {|s|s.upcase} #=> "MY STRING"
|
||||
#
|
||||
def yield_self(&block)
|
||||
return to_enum :yield_self unless block
|
||||
block.call(self)
|
||||
end
|
||||
end
|
||||
@@ -114,6 +114,7 @@ mrb_f_integer(mrb_state *mrb, mrb_value self)
|
||||
return mrb_convert_to_integer(mrb, arg, base);
|
||||
}
|
||||
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
/*
|
||||
* call-seq:
|
||||
* Float(arg) -> float
|
||||
@@ -134,6 +135,7 @@ mrb_f_float(mrb_state *mrb, mrb_value self)
|
||||
mrb_get_args(mrb, "o", &arg);
|
||||
return mrb_Float(mrb, arg);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
@@ -222,6 +224,22 @@ mrb_f_hash(mrb_state *mrb, mrb_value self)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* obj.itself -> an_object
|
||||
*
|
||||
* Returns <i>obj</i>.
|
||||
*
|
||||
* string = 'my string' #=> "my string"
|
||||
* string.itself.object_id == string.object_id #=> true
|
||||
*
|
||||
*/
|
||||
static mrb_value
|
||||
mrb_f_itself(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_kernel_ext_gem_init(mrb_state *mrb)
|
||||
{
|
||||
@@ -231,10 +249,13 @@ mrb_mruby_kernel_ext_gem_init(mrb_state *mrb)
|
||||
mrb_define_module_function(mrb, krn, "caller", mrb_f_caller, MRB_ARGS_OPT(2));
|
||||
mrb_define_method(mrb, krn, "__method__", mrb_f_method, MRB_ARGS_NONE());
|
||||
mrb_define_module_function(mrb, krn, "Integer", mrb_f_integer, MRB_ARGS_ANY());
|
||||
#ifndef MRB_WITHOUT_FLOAT
|
||||
mrb_define_module_function(mrb, krn, "Float", mrb_f_float, MRB_ARGS_REQ(1));
|
||||
#endif
|
||||
mrb_define_module_function(mrb, krn, "String", mrb_f_string, MRB_ARGS_REQ(1));
|
||||
mrb_define_module_function(mrb, krn, "Array", mrb_f_array, MRB_ARGS_REQ(1));
|
||||
mrb_define_module_function(mrb, krn, "Hash", mrb_f_hash, MRB_ARGS_REQ(1));
|
||||
mrb_define_module_function(mrb, krn, "itself", mrb_f_itself, MRB_ARGS_NONE());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -49,7 +49,7 @@ assert('Kernel#__method__') do
|
||||
end
|
||||
|
||||
assert('Kernel#Integer') do
|
||||
assert_equal(123, Integer(123.999))
|
||||
assert_equal(123, Integer(123.999)) if class_defined?("Float")
|
||||
assert_equal(26, Integer("0x1a"))
|
||||
assert_equal(930, Integer("0930", 10))
|
||||
assert_equal(7, Integer("111", 2))
|
||||
@@ -63,7 +63,7 @@ assert('Kernel#Float') do
|
||||
assert_equal(123.456, Float(123.456))
|
||||
assert_equal(123.456, Float("123.456"))
|
||||
assert_raise(TypeError) { Float(nil) }
|
||||
end
|
||||
end if class_defined?("Float")
|
||||
|
||||
assert('Kernel#String') do
|
||||
assert_equal("main", String(self))
|
||||
|
||||
@@ -486,7 +486,7 @@ static mrb_value
|
||||
math_log(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
mrb_float x, base;
|
||||
int argc;
|
||||
mrb_int argc;
|
||||
|
||||
argc = mrb_get_args(mrb, "f|f", &x, &base);
|
||||
if (x < 0.0) {
|
||||
@@ -657,7 +657,7 @@ math_ldexp(mrb_state *mrb, mrb_value obj)
|
||||
mrb_int i;
|
||||
|
||||
mrb_get_args(mrb, "fi", &x, &i);
|
||||
x = ldexp(x, i);
|
||||
x = ldexp(x, (int)i);
|
||||
|
||||
return mrb_float_value(mrb, x);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
mruby-method
|
||||
===
|
||||
|
||||
A implementetion of class **Method** and **UnboundMethod** for mruby
|
||||
|
||||
```ruby
|
||||
p Enumerable.instance_method(:find_all).source_location
|
||||
#=> ["mruby/mruby/mrblib/enum.rb", 148]
|
||||
```
|
||||
|
||||
# Note
|
||||
|
||||
`source_location` method need this configuration in build_config.rb
|
||||
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
enable_debug
|
||||
end
|
||||
```
|
||||
|
||||
# Supported Methods
|
||||
|
||||
## Kernel
|
||||
|
||||
- `Kernel#method`
|
||||
- `Kernel#singleton_method`
|
||||
|
||||
## Module
|
||||
|
||||
- `Module#instance_method`
|
||||
|
||||
## Method class
|
||||
|
||||
- `Method#name`
|
||||
- `Method#call`
|
||||
- `Method#super_method`
|
||||
- `Method#arity`
|
||||
- `Method#unbind`
|
||||
- `Method#[]`
|
||||
- `Method#owner`
|
||||
- `Method#receiver`
|
||||
- `Method#parameters`
|
||||
- `Method#source_location`
|
||||
- `Method#to_proc`
|
||||
|
||||
## UnboundMethod class
|
||||
|
||||
- `UnboundMethod#name`
|
||||
- `UnboundMethod#bind`
|
||||
- `UnboundMethod#super_method`
|
||||
- `UnboundMethod#arity`
|
||||
- `UnboundMethod#owner`
|
||||
- `UnboundMethod#parameters`
|
||||
- `UnboundMethod#source_location`
|
||||
|
||||
# See also
|
||||
|
||||
- https://ruby-doc.org/core-2.3.3/Method.html
|
||||
- https://ruby-doc.org/core-2.3.3/UnboundMethod.html
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user