mirror of
https://github.com/lua/lua.git
synced 2026-08-30 06:58:16 +00:00
Compare commits
569 Commits
v4.1-alpha
...
v5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
762c737037 | ||
|
|
de57dc2653 | ||
|
|
d1df829f8d | ||
|
|
2ad947fe03 | ||
|
|
f0cc013afa | ||
|
|
0d88545b82 | ||
|
|
f84c5a5fc6 | ||
|
|
05d35d8f3c | ||
|
|
3a6230ef7c | ||
|
|
a424a112b5 | ||
|
|
b858161fbc | ||
|
|
80bac182db | ||
|
|
30a411ab3c | ||
|
|
5bb5a1831d | ||
|
|
b518d14071 | ||
|
|
15dbb53461 | ||
|
|
abc304f9da | ||
|
|
1a553f9199 | ||
|
|
0ca225d33a | ||
|
|
70e2b7ab86 | ||
|
|
5a144e891a | ||
|
|
b12776f29c | ||
|
|
ab9e062928 | ||
|
|
81cdbabf09 | ||
|
|
40cfb0691e | ||
|
|
9b7af7e45b | ||
|
|
2e66248f8a | ||
|
|
79db75101e | ||
|
|
b0c40e2405 | ||
|
|
4734e2de05 | ||
|
|
7ea180af6e | ||
|
|
05d567d52e | ||
|
|
d8a3a00d84 | ||
|
|
c9ea94ec92 | ||
|
|
fa4b4c1100 | ||
|
|
4039bf457d | ||
|
|
034de1fe73 | ||
|
|
430d6db928 | ||
|
|
7c3857cded | ||
|
|
8ce6f0b418 | ||
|
|
572bddc0b0 | ||
|
|
3684f67771 | ||
|
|
69dd9461e5 | ||
|
|
6b6bc532a4 | ||
|
|
ea16ee41a8 | ||
|
|
60d11ec316 | ||
|
|
e1a424e8a3 | ||
|
|
59ce42dbd5 | ||
|
|
92f6e0c1bf | ||
|
|
5cd99b82b7 | ||
|
|
07e210e655 | ||
|
|
feb724c122 | ||
|
|
67f9a2a98f | ||
|
|
c4f9c887fc | ||
|
|
9866fb0ef1 | ||
|
|
60c83ded30 | ||
|
|
07948c3181 | ||
|
|
dce9a49a08 | ||
|
|
15db58a2f5 | ||
|
|
d6826dbc80 | ||
|
|
e75a6ae9ee | ||
|
|
2866fb2dd0 | ||
|
|
4b6f436d67 | ||
|
|
8f105d6b59 | ||
|
|
2fef8c772b | ||
|
|
7285fa393b | ||
|
|
5085f09ce5 | ||
|
|
d674626392 | ||
|
|
7a40cdbda0 | ||
|
|
3cdeacbbfb | ||
|
|
6f207b15fb | ||
|
|
3184314bf3 | ||
|
|
7964f7cbbd | ||
|
|
383a6e88f9 | ||
|
|
871166d7db | ||
|
|
592cf2334e | ||
|
|
0175f8d5d1 | ||
|
|
e79bf02f33 | ||
|
|
41ed3c4771 | ||
|
|
635b7c707d | ||
|
|
83f0d6ef1a | ||
|
|
3088ebd95b | ||
|
|
797d964df9 | ||
|
|
e44e579dc1 | ||
|
|
a153cafd8d | ||
|
|
3b5158f2a1 | ||
|
|
60a8b94fd0 | ||
|
|
c499442e5f | ||
|
|
9a5bab82ff | ||
|
|
32fd039bb5 | ||
|
|
75f73172c4 | ||
|
|
754c630754 | ||
|
|
dd8edecae1 | ||
|
|
28021c5c66 | ||
|
|
73517e86b0 | ||
|
|
9e8face8d8 | ||
|
|
64864f094b | ||
|
|
9bd3fc1039 | ||
|
|
cc4a22ebe2 | ||
|
|
acf62ddfbe | ||
|
|
04f95ce879 | ||
|
|
27c6b4d422 | ||
|
|
0bb8eb5151 | ||
|
|
38da8c0d7d | ||
|
|
76de732745 | ||
|
|
90d7892007 | ||
|
|
041cb96992 | ||
|
|
c75c3cfd19 | ||
|
|
24471525d7 | ||
|
|
1f55dbc699 | ||
|
|
c194a46bc5 | ||
|
|
8954bdc706 | ||
|
|
5a228bb1d8 | ||
|
|
5f698f8b6f | ||
|
|
9b1c586b2f | ||
|
|
d9340154ac | ||
|
|
e47baca75a | ||
|
|
b8a680c114 | ||
|
|
709b27b456 | ||
|
|
dbc5451bea | ||
|
|
2d2d45976c | ||
|
|
0050d983fc | ||
|
|
04b143ddf9 | ||
|
|
007f229568 | ||
|
|
84488c5670 | ||
|
|
5142e630bf | ||
|
|
010bbd9d9c | ||
|
|
be00cd2a6b | ||
|
|
2e4e888de0 | ||
|
|
ddc144e4d2 | ||
|
|
b48c6e7680 | ||
|
|
aff97fffc4 | ||
|
|
1648674653 | ||
|
|
d404f0c276 | ||
|
|
48e42261ac | ||
|
|
be762f38bd | ||
|
|
c8a79057f7 | ||
|
|
642af82e81 | ||
|
|
636c629e56 | ||
|
|
96ba5d0bc2 | ||
|
|
f0185f7628 | ||
|
|
9bab2cf55d | ||
|
|
c4ae00a3d1 | ||
|
|
f4d3bc52f4 | ||
|
|
18765d900e | ||
|
|
43013b39cc | ||
|
|
94912d99fc | ||
|
|
b40c9f7a3c | ||
|
|
41fd639cab | ||
|
|
a845a46cc8 | ||
|
|
097edd3884 | ||
|
|
5c5d9b2703 | ||
|
|
43d1a6af12 | ||
|
|
3010eb0536 | ||
|
|
2f91f95d94 | ||
|
|
42dd080a2e | ||
|
|
9957f7d598 | ||
|
|
ac27b7a842 | ||
|
|
81e142fc14 | ||
|
|
63633c5b5f | ||
|
|
dff9be4224 | ||
|
|
118347d8c3 | ||
|
|
6820da5096 | ||
|
|
c3eb4675b9 | ||
|
|
7e0f880bc5 | ||
|
|
118e9cd843 | ||
|
|
de00d0d0ad | ||
|
|
1713b64065 | ||
|
|
671dc6eec2 | ||
|
|
e356a43dc0 | ||
|
|
f36038e42a | ||
|
|
96e15b8501 | ||
|
|
0fd91b1b08 | ||
|
|
a2b353e044 | ||
|
|
92a2ef9dca | ||
|
|
4fb9110a6e | ||
|
|
11886dc7b0 | ||
|
|
81bc5711a8 | ||
|
|
6a77a6b73f | ||
|
|
84e0b1bc97 | ||
|
|
6823a2f57f | ||
|
|
313b2fe902 | ||
|
|
425e5813b0 | ||
|
|
6505503b49 | ||
|
|
ec748fcb0a | ||
|
|
c196348717 | ||
|
|
669129a6d8 | ||
|
|
46b063ef59 | ||
|
|
e1d5153a33 | ||
|
|
b3d0682fb9 | ||
|
|
02afc892d5 | ||
|
|
fa2f1ec7ba | ||
|
|
829befcc41 | ||
|
|
d477e4ffd6 | ||
|
|
ce09af1e25 | ||
|
|
98d0b79613 | ||
|
|
e8f35fc4ff | ||
|
|
6fb0fd5063 | ||
|
|
565e6d74e1 | ||
|
|
f6bc7884be | ||
|
|
32a5d96dfc | ||
|
|
8dae071f42 | ||
|
|
afe1305b1a | ||
|
|
728fa167d2 | ||
|
|
1bdde38bd2 | ||
|
|
b2bc3b44b6 | ||
|
|
7c0ccdfd61 | ||
|
|
4964e7c8a0 | ||
|
|
2c670baf24 | ||
|
|
fdafd4f4a8 | ||
|
|
beeff4ccaf | ||
|
|
12c4e48506 | ||
|
|
c78aaa9a70 | ||
|
|
4d7a554921 | ||
|
|
fbc23d0245 | ||
|
|
81a8845e4f | ||
|
|
6c283b2f4f | ||
|
|
576bded513 | ||
|
|
ecc7769de2 | ||
|
|
da19c436cc | ||
|
|
0039feb9da | ||
|
|
aa5b15f271 | ||
|
|
653416d5c0 | ||
|
|
82a3be0671 | ||
|
|
94b5ad31f4 | ||
|
|
90d26b9266 | ||
|
|
a048d71ef3 | ||
|
|
27f8a4a69e | ||
|
|
8e4ac679ff | ||
|
|
221b5be7b7 | ||
|
|
b6791f5fa5 | ||
|
|
3b058177af | ||
|
|
586e510577 | ||
|
|
9998082839 | ||
|
|
08da48a73c | ||
|
|
00a40f4d6a | ||
|
|
3bb5079dd4 | ||
|
|
5016f43aa4 | ||
|
|
c1c100a0c0 | ||
|
|
b6e2f1a86e | ||
|
|
260e35f576 | ||
|
|
a56e01a9a0 | ||
|
|
4664f2e927 | ||
|
|
2e38c6ae5a | ||
|
|
d3dd337fca | ||
|
|
634344d61f | ||
|
|
a2fa48a570 | ||
|
|
8b2b8790b5 | ||
|
|
0b3d380f9f | ||
|
|
4e23699aa6 | ||
|
|
1c0ac3c0f5 | ||
|
|
4a4f243795 | ||
|
|
0417a4bb0b | ||
|
|
5037196f6f | ||
|
|
9fb80bde3c | ||
|
|
2dcc31574f | ||
|
|
390fc99a5c | ||
|
|
79c8edb6c4 | ||
|
|
e5146fb01f | ||
|
|
ce6b930464 | ||
|
|
ac7006d374 | ||
|
|
12bee999dd | ||
|
|
a8c9eec426 | ||
|
|
a885b826b3 | ||
|
|
a960e62c3e | ||
|
|
c51aa6ee33 | ||
|
|
d88860131a | ||
|
|
44752fc9ce | ||
|
|
39b2d58c39 | ||
|
|
d2d24f0971 | ||
|
|
0436c96866 | ||
|
|
f8279f6cd8 | ||
|
|
1fe280df72 | ||
|
|
1ede98157d | ||
|
|
3e52573c72 | ||
|
|
84ad1eea81 | ||
|
|
b30ec2532c | ||
|
|
68ee518e81 | ||
|
|
76a73cb2ee | ||
|
|
aa3da1605c | ||
|
|
9f4b5b5232 | ||
|
|
5fabed21a1 | ||
|
|
f67ccfbdeb | ||
|
|
cfcf200806 | ||
|
|
f32a8c0477 | ||
|
|
88607acc2c | ||
|
|
6de93e2932 | ||
|
|
25dc9b7faf | ||
|
|
78c507b7b8 | ||
|
|
69906cb56f | ||
|
|
9d6556fd87 | ||
|
|
35707e94f3 | ||
|
|
89b102bd1d | ||
|
|
fdfd5b44ee | ||
|
|
1a4c428d6d | ||
|
|
2394604d10 | ||
|
|
922f36a05b | ||
|
|
ad41fc11eb | ||
|
|
e182cf452f | ||
|
|
e34f282365 | ||
|
|
3941af53ad | ||
|
|
5610fdd776 | ||
|
|
b449a5e574 | ||
|
|
e572dffa15 | ||
|
|
5893fcb71a | ||
|
|
eec0905173 | ||
|
|
a44f37513b | ||
|
|
6ee2dbdfe9 | ||
|
|
1dbe708aa8 | ||
|
|
8f080fd683 | ||
|
|
d8678edddc | ||
|
|
e812aa2002 | ||
|
|
c31494df26 | ||
|
|
8fd0f6a82b | ||
|
|
eb3de8768a | ||
|
|
864c96f36c | ||
|
|
0052930ffe | ||
|
|
eeab473fc8 | ||
|
|
6b8cdc9cdd | ||
|
|
000d081fd0 | ||
|
|
65d66ba275 | ||
|
|
cff22f57dd | ||
|
|
168ea16acb | ||
|
|
dc6e6c48bb | ||
|
|
e3cddc950c | ||
|
|
630acb2048 | ||
|
|
16f4723398 | ||
|
|
f1c43bbe19 | ||
|
|
5a8f383e60 | ||
|
|
711b936849 | ||
|
|
5b8ee9fa8d | ||
|
|
2cd6161060 | ||
|
|
a102221a0b | ||
|
|
6dd0b6c62b | ||
|
|
fa23301251 | ||
|
|
94c2449d25 | ||
|
|
c398a02110 | ||
|
|
ad7103ea3a | ||
|
|
0079e0f57c | ||
|
|
cfff013586 | ||
|
|
35a22ed1ab | ||
|
|
ff91b355f4 | ||
|
|
5094c37988 | ||
|
|
46c471d7e9 | ||
|
|
859ecf36b6 | ||
|
|
a1700bbc50 | ||
|
|
8876a1bf92 | ||
|
|
f53fd8d5f5 | ||
|
|
955def0348 | ||
|
|
9c3b3f82fe | ||
|
|
b7a0503c1d | ||
|
|
1c328a191a | ||
|
|
58bf77bc7f | ||
|
|
8da6fe62d8 | ||
|
|
c18fe57e54 | ||
|
|
af19d55635 | ||
|
|
b55fded18c | ||
|
|
2dadc81822 | ||
|
|
b487975344 | ||
|
|
94e5545806 | ||
|
|
78b40bf57d | ||
|
|
01f1ac36b1 | ||
|
|
a4d06736d4 | ||
|
|
dea6b6da94 | ||
|
|
71144e3ff0 | ||
|
|
0dbf0c5953 | ||
|
|
85dcb411a8 | ||
|
|
3c6a383d62 | ||
|
|
9a0f0dcc77 | ||
|
|
751cd867d3 | ||
|
|
b36b2a061c | ||
|
|
ab52fc6097 | ||
|
|
e68d0df1c6 | ||
|
|
9b38a696d5 | ||
|
|
383e8b9e77 | ||
|
|
f1a1bb23fe | ||
|
|
151ba1cc7b | ||
|
|
ee4859b3e3 | ||
|
|
f388ee4a82 | ||
|
|
30ad4c75db | ||
|
|
3ee1efa7b2 | ||
|
|
c11d374c59 | ||
|
|
13230c451b | ||
|
|
391c5459cb | ||
|
|
62dd4cbe91 | ||
|
|
ae5283dc36 | ||
|
|
1ce6cb6032 | ||
|
|
11c63bc3af | ||
|
|
f1f271ae76 | ||
|
|
6c7334a9ac | ||
|
|
8e1e618606 | ||
|
|
af4721f7a3 | ||
|
|
018e50ad7f | ||
|
|
7b65328c8e | ||
|
|
d2e05589d7 | ||
|
|
237969724f | ||
|
|
f438d00ef3 | ||
|
|
c3b90061ea | ||
|
|
a2e414d679 | ||
|
|
93bcb65a9b | ||
|
|
49c95648a0 | ||
|
|
13ab5a6bb1 | ||
|
|
cd99bbcd0d | ||
|
|
2cbbf7e95a | ||
|
|
e5919be1a7 | ||
|
|
b795d4b561 | ||
|
|
c371413530 | ||
|
|
d1f220217b | ||
|
|
405e3a4597 | ||
|
|
81215cd59f | ||
|
|
0b9b53e21c | ||
|
|
44a5484d73 | ||
|
|
801aaf37b1 | ||
|
|
00af2faae7 | ||
|
|
e9ef7ed2d3 | ||
|
|
2626708b72 | ||
|
|
19ac0fadc9 | ||
|
|
ca2ceef659 | ||
|
|
5023aaee0a | ||
|
|
88c9bf99de | ||
|
|
63a614e145 | ||
|
|
48e732e07d | ||
|
|
938092489b | ||
|
|
578d1da00d | ||
|
|
24d6d0528d | ||
|
|
0b00e7f1a2 | ||
|
|
b7ed502dea | ||
|
|
58badbab99 | ||
|
|
da81845cd5 | ||
|
|
9681ff09db | ||
|
|
7ff21273d6 | ||
|
|
207dad8606 | ||
|
|
c97dc294a9 | ||
|
|
71c716e5a8 | ||
|
|
51ad2f1162 | ||
|
|
ecda9c1972 | ||
|
|
e19eba7219 | ||
|
|
bd8b9c94b3 | ||
|
|
4db04555f0 | ||
|
|
c16a35d669 | ||
|
|
8f837e83b2 | ||
|
|
6658b9588f | ||
|
|
457d88eaaa | ||
|
|
8a1a512c64 | ||
|
|
6b0c38c2e7 | ||
|
|
1a3f175640 | ||
|
|
88c7b574cb | ||
|
|
51bf91a970 | ||
|
|
1b6315ba10 | ||
|
|
3b001d9a9d | ||
|
|
c36b5cc726 | ||
|
|
2c1eb62a08 | ||
|
|
63e2d92123 | ||
|
|
e966dd93be | ||
|
|
2f8e3c5543 | ||
|
|
b0a5e156b8 | ||
|
|
ac178ee478 | ||
|
|
1e602a61b3 | ||
|
|
57fb51f975 | ||
|
|
1c423d2661 | ||
|
|
b3ffaca638 | ||
|
|
bee86e23be | ||
|
|
0056ed4135 | ||
|
|
e01f5e6809 | ||
|
|
cbfc581990 | ||
|
|
d3651c1d88 | ||
|
|
57a7baafb9 | ||
|
|
252e01e398 | ||
|
|
87b0e3d477 | ||
|
|
cb50fcf42d | ||
|
|
c6a108e012 | ||
|
|
d5ceb369b1 | ||
|
|
86a4de256e | ||
|
|
53aaee6ee6 | ||
|
|
67bda7e136 | ||
|
|
7c8f1823e7 | ||
|
|
ca181f31e4 | ||
|
|
38b0e6128d | ||
|
|
addbe8c8b0 | ||
|
|
6bb5cb1cbd | ||
|
|
d070506a25 | ||
|
|
0a87d9d334 | ||
|
|
f856fdeabd | ||
|
|
653977a0ac | ||
|
|
d6fd33e76f | ||
|
|
50e2952593 | ||
|
|
b217ae644e | ||
|
|
a048cc9676 | ||
|
|
eb262bc617 | ||
|
|
74907fb71e | ||
|
|
b38e594ed7 | ||
|
|
448517e47e | ||
|
|
931ee346e3 | ||
|
|
dea98702c9 | ||
|
|
7ab7703b53 | ||
|
|
566310fa04 | ||
|
|
6272c843de | ||
|
|
5d14ce612b | ||
|
|
d56d4cf776 | ||
|
|
b7ae43d457 | ||
|
|
f083812c02 | ||
|
|
3533382a1e | ||
|
|
ea2a75d19e | ||
|
|
b3bb0f132b | ||
|
|
facfec0687 | ||
|
|
34df9976a9 | ||
|
|
cfaa8fbf1d | ||
|
|
f42cc90d2d | ||
|
|
9d2e454d6f | ||
|
|
09e15692f3 | ||
|
|
42754c0f15 | ||
|
|
18afb90349 | ||
|
|
22dd271cbb | ||
|
|
e04f7ed450 | ||
|
|
101cee3032 | ||
|
|
eb7312d9be | ||
|
|
21259a50e1 | ||
|
|
9aff171f3b | ||
|
|
ed9be5e1f0 | ||
|
|
9d801f43d4 | ||
|
|
e043b72a55 | ||
|
|
a4c35a3269 | ||
|
|
9cd36059ad | ||
|
|
592a309177 | ||
|
|
413fc7334b | ||
|
|
fca0a12e23 | ||
|
|
72659a0605 | ||
|
|
dfaf8c5291 | ||
|
|
657f65211a | ||
|
|
39395e1211 | ||
|
|
26bf2adace | ||
|
|
fd48dcc7c8 | ||
|
|
617008f552 | ||
|
|
ec9d8308b4 | ||
|
|
af59848219 | ||
|
|
46347d768e | ||
|
|
36eb665859 | ||
|
|
070204300c | ||
|
|
21aa7e55f2 | ||
|
|
fffb6f3814 | ||
|
|
0b551a24f8 | ||
|
|
8069f77ca4 | ||
|
|
1e81da51ba | ||
|
|
7cd37142f4 | ||
|
|
e7c2eebd87 | ||
|
|
0c3ea96541 | ||
|
|
babaa96eab | ||
|
|
15462edb0f | ||
|
|
6f936bc793 | ||
|
|
b840a7518d | ||
|
|
f54cdb33a5 | ||
|
|
8e9b1e4ae9 | ||
|
|
328d53e77b | ||
|
|
c04d9b9ecb | ||
|
|
c44c68450a | ||
|
|
abdbe883a8 | ||
|
|
4d0935ec0f | ||
|
|
e1d072571e | ||
|
|
7651a5c6b2 | ||
|
|
8c8ad5f3ff | ||
|
|
34a09b65f3 | ||
|
|
29d883b9bd | ||
|
|
b0d5bd8c70 | ||
|
|
9fca43f5b0 | ||
|
|
33d820d41d | ||
|
|
c3d72096c4 | ||
|
|
7afc74ff07 | ||
|
|
022bf27202 | ||
|
|
fd40af92e4 |
64
bugs
64
bugs
@@ -270,3 +270,67 @@ Tue Jul 10 16:59:18 EST 2001
|
|||||||
>> error message for `%a' gave wrong line number
|
>> error message for `%a' gave wrong line number
|
||||||
(by Leonardo Constantino; since 4.0)
|
(by Leonardo Constantino; since 4.0)
|
||||||
|
|
||||||
|
** lbaselib.c
|
||||||
|
Fri Dec 21 15:21:05 EDT 2001
|
||||||
|
>> seg. fault when rawget/rawset get extra arguments
|
||||||
|
(by Eric Mauger; since 4.0b)
|
||||||
|
|
||||||
|
** lvm.c
|
||||||
|
Wed Jun 19 13:28:20 EST 2002
|
||||||
|
>> line hook gets wrong `ar'
|
||||||
|
(by Daniel C. Sinclair; since 4.0.b)
|
||||||
|
|
||||||
|
** ldo.c
|
||||||
|
Wed Jun 19 13:31:49 EST 2002
|
||||||
|
>> `protectedparser' may run GC, and then collect `filename'
|
||||||
|
>> (in function `parse_file')
|
||||||
|
(by Alex Bilyk; since 4.0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=================================================================
|
||||||
|
--- Version 5.0 alpha
|
||||||
|
|
||||||
|
** lgc.c
|
||||||
|
Fri Aug 30 13:49:14 EST 2002
|
||||||
|
>> GC metamethod stored in a weak metatable being collected together with
|
||||||
|
>> userdata may not be cleared properly
|
||||||
|
(by Roberto; since 5.0a)
|
||||||
|
|
||||||
|
** lapi.c
|
||||||
|
Thu Nov 21 11:00:00 EST 2002
|
||||||
|
>> ULONG_MAX>>10 may not fit into an int
|
||||||
|
(by Jeff Petkau; since 4.0)
|
||||||
|
|
||||||
|
** lparser.c
|
||||||
|
Fri Dec 6 17:06:40 UTC 2002
|
||||||
|
>> scope of generic for variables is not sound
|
||||||
|
(by Gavin Wraith; since 5.0a)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=================================================================
|
||||||
|
--- Version 5.0 beta
|
||||||
|
** lbaselib.c
|
||||||
|
Fri Dec 20 09:53:19 UTC 2002
|
||||||
|
>> `resume' was checking the wrong value for stack overflow
|
||||||
|
(by Maik Zimmermann; since 5.0b)
|
||||||
|
|
||||||
|
** ldo.c
|
||||||
|
Thu Jan 23 11:29:06 UTC 2003
|
||||||
|
>> error during garbage collection in luaD_protectedparser is not being
|
||||||
|
>> protected
|
||||||
|
(by Benoit Germain; since 5.0a)
|
||||||
|
|
||||||
|
** ldo.c (and others)
|
||||||
|
Fri Feb 28 14:20:33 EST 2003
|
||||||
|
>> GC metamethod calls could mess C/Lua stack syncronization
|
||||||
|
(by Roberto; since 5.0b)
|
||||||
|
|
||||||
|
** lzio.h/zlio.c
|
||||||
|
Thu Mar 20 11:40:12 EST 2003
|
||||||
|
>> zio mixes a 255 as first char in a buffer with EOZ
|
||||||
|
(by lhf; since 5.0a)
|
||||||
|
|
||||||
|
|||||||
3
lapi.h
3
lapi.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lapi.h,v 1.19 2000/08/28 17:57:04 roberto Exp roberto $
|
** $Id: lapi.h,v 1.20 2000/08/31 14:08:27 roberto Exp roberto $
|
||||||
** Auxiliary functions from Lua API
|
** Auxiliary functions from Lua API
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
TObject *luaA_index (lua_State *L, int index);
|
|
||||||
void luaA_pushobject (lua_State *L, const TObject *o);
|
void luaA_pushobject (lua_State *L, const TObject *o);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
502
lauxlib.c
502
lauxlib.c
@@ -1,29 +1,103 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lauxlib.c,v 1.50 2001/04/23 16:35:45 roberto Exp roberto $
|
** $Id: lauxlib.c,v 1.99 2003/04/03 13:35:34 roberto Exp roberto $
|
||||||
** Auxiliary functions for building Lua libraries
|
** Auxiliary functions for building Lua libraries
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
/* This file uses only the official API of Lua.
|
/* This file uses only the official API of Lua.
|
||||||
** Any function declared here could be written as an application function.
|
** Any function declared here could be written as an application function.
|
||||||
** With care, these functions can be used by other libraries.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lauxlib_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "luadebug.h"
|
|
||||||
#include "lualib.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
/* number of prereserved references (for internal use) */
|
||||||
|
#define RESERVED_REFS 2
|
||||||
|
|
||||||
LUALIB_API int luaL_findstring (const l_char *name, const l_char *const list[]) {
|
/* reserved references */
|
||||||
|
#define FREELIST_REF 1 /* free list of references */
|
||||||
|
#define ARRAYSIZE_REF 2 /* array sizes */
|
||||||
|
|
||||||
|
|
||||||
|
/* convert a stack index to positive */
|
||||||
|
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \
|
||||||
|
lua_gettop(L) + (i) + 1)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** Error-report functions
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
|
||||||
|
lua_Debug ar;
|
||||||
|
lua_getstack(L, 0, &ar);
|
||||||
|
lua_getinfo(L, "n", &ar);
|
||||||
|
if (strcmp(ar.namewhat, "method") == 0) {
|
||||||
|
narg--; /* do not count `self' */
|
||||||
|
if (narg == 0) /* error is in the self argument itself? */
|
||||||
|
return luaL_error(L, "calling `%s' on bad self (%s)", ar.name, extramsg);
|
||||||
|
}
|
||||||
|
if (ar.name == NULL)
|
||||||
|
ar.name = "?";
|
||||||
|
return luaL_error(L, "bad argument #%d to `%s' (%s)",
|
||||||
|
narg, ar.name, extramsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) {
|
||||||
|
const char *msg = lua_pushfstring(L, "%s expected, got %s",
|
||||||
|
tname, lua_typename(L, lua_type(L,narg)));
|
||||||
|
return luaL_argerror(L, narg, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void tag_error (lua_State *L, int narg, int tag) {
|
||||||
|
luaL_typerror(L, narg, lua_typename(L, tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API void luaL_where (lua_State *L, int level) {
|
||||||
|
lua_Debug ar;
|
||||||
|
if (lua_getstack(L, level, &ar)) { /* check function at level */
|
||||||
|
lua_getinfo(L, "Snl", &ar); /* get info about it */
|
||||||
|
if (ar.currentline > 0) { /* is there info? */
|
||||||
|
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushliteral(L, ""); /* else, no information available... */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
||||||
|
va_list argp;
|
||||||
|
va_start(argp, fmt);
|
||||||
|
luaL_where(L, 1);
|
||||||
|
lua_pushvfstring(L, fmt, argp);
|
||||||
|
va_end(argp);
|
||||||
|
lua_concat(L, 2);
|
||||||
|
return lua_error(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_findstring (const char *name, const char *const list[]) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0; list[i]; i++)
|
for (i=0; list[i]; i++)
|
||||||
if (strcmp(list[i], name) == 0)
|
if (strcmp(list[i], name) == 0)
|
||||||
@@ -31,74 +105,84 @@ LUALIB_API int luaL_findstring (const l_char *name, const l_char *const list[])
|
|||||||
return -1; /* name not found */
|
return -1; /* name not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
LUALIB_API void luaL_argerror (lua_State *L, int narg, const l_char *extramsg) {
|
|
||||||
lua_Debug ar;
|
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
|
||||||
lua_getstack(L, 0, &ar);
|
lua_pushstring(L, tname);
|
||||||
lua_getinfo(L, l_s("n"), &ar);
|
lua_rawget(L, LUA_REGISTRYINDEX); /* get registry.name */
|
||||||
if (ar.name == NULL)
|
if (!lua_isnil(L, -1)) /* name already in use? */
|
||||||
ar.name = l_s("?");
|
return 0; /* leave previous value on top, but return 0 */
|
||||||
luaL_verror(L, l_s("bad argument #%d to `%.50s' (%.100s)"),
|
lua_pop(L, 1);
|
||||||
narg, ar.name, extramsg);
|
lua_newtable(L); /* create metatable */
|
||||||
|
lua_pushstring(L, tname);
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_rawset(L, LUA_REGISTRYINDEX); /* registry.name = metatable */
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_pushstring(L, tname);
|
||||||
|
lua_rawset(L, LUA_REGISTRYINDEX); /* registry[metatable] = name */
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void type_error (lua_State *L, int narg, const l_char *tname) {
|
LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname) {
|
||||||
l_char buff[80];
|
lua_pushstring(L, tname);
|
||||||
sprintf(buff, l_s("%.25s expected, got %.25s"), tname, lua_type(L,narg));
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||||
luaL_argerror(L, narg, buff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void tag_error (lua_State *L, int narg, int tag) {
|
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
|
||||||
type_error(L, narg, lua_typename(L, tag));
|
const char *tn;
|
||||||
|
if (!lua_getmetatable(L, ud)) return NULL; /* no metatable? */
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX); /* get registry[metatable] */
|
||||||
|
tn = lua_tostring(L, -1);
|
||||||
|
if (tn && (strcmp(tn, tname) == 0)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return lua_touserdata(L, ud);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_checkstack (lua_State *L, int space, const l_char *mes) {
|
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) {
|
||||||
if (space > lua_stackspace(L))
|
if (!lua_checkstack(L, space))
|
||||||
luaL_verror(L, l_s("stack overflow (%.30s)"), mes);
|
luaL_error(L, "stack overflow (%s)", mes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_checktype(lua_State *L, int narg, int t) {
|
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
|
||||||
if (lua_rawtag(L, narg) != t)
|
if (lua_type(L, narg) != t)
|
||||||
tag_error(L, narg, t);
|
tag_error(L, narg, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
|
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
|
||||||
if (lua_rawtag(L, narg) == LUA_TNONE)
|
if (lua_type(L, narg) == LUA_TNONE)
|
||||||
luaL_argerror(L, narg, l_s("value expected"));
|
luaL_argerror(L, narg, "value expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void *luaL_check_userdata (lua_State *L, int narg,
|
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
|
||||||
const l_char *name) {
|
const char *s = lua_tostring(L, narg);
|
||||||
if (strcmp(lua_type(L, narg), name) != 0)
|
|
||||||
type_error(L, narg, name);
|
|
||||||
return lua_touserdata(L, narg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API const l_char *luaL_check_lstr (lua_State *L, int narg, size_t *len) {
|
|
||||||
const l_char *s = lua_tostring(L, narg);
|
|
||||||
if (!s) tag_error(L, narg, LUA_TSTRING);
|
if (!s) tag_error(L, narg, LUA_TSTRING);
|
||||||
if (len) *len = lua_strlen(L, narg);
|
if (len) *len = lua_strlen(L, narg);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API const l_char *luaL_opt_lstr (lua_State *L, int narg, const l_char *def, size_t *len) {
|
LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
|
||||||
if (lua_isnull(L, narg)) {
|
const char *def, size_t *len) {
|
||||||
|
if (lua_isnoneornil(L, narg)) {
|
||||||
if (len)
|
if (len)
|
||||||
*len = (def ? strlen(def) : 0);
|
*len = (def ? strlen(def) : 0);
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
else return luaL_check_lstr(L, narg, len);
|
else return luaL_checklstring(L, narg, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API lua_Number luaL_check_number (lua_State *L, int narg) {
|
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
|
||||||
lua_Number d = lua_tonumber(L, narg);
|
lua_Number d = lua_tonumber(L, narg);
|
||||||
if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
|
if (d == 0 && !lua_isnumber(L, narg)) /* avoid extra test when d is not 0 */
|
||||||
tag_error(L, narg, LUA_TNUMBER);
|
tag_error(L, narg, LUA_TNUMBER);
|
||||||
@@ -106,29 +190,137 @@ LUALIB_API lua_Number luaL_check_number (lua_State *L, int narg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API lua_Number luaL_opt_number (lua_State *L, int narg, lua_Number def) {
|
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
|
||||||
if (lua_isnull(L, narg)) return def;
|
if (lua_isnoneornil(L, narg)) return def;
|
||||||
else return luaL_check_number(L, narg);
|
else return luaL_checknumber(L, narg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_openlib (lua_State *L, const luaL_reg *l, int n) {
|
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
|
||||||
int i;
|
if (!lua_getmetatable(L, obj)) /* no metatable? */
|
||||||
for (i=0; i<n; i++)
|
return 0;
|
||||||
lua_register(L, l[i].name, l[i].func);
|
lua_pushstring(L, event);
|
||||||
|
lua_rawget(L, -2);
|
||||||
|
if (lua_isnil(L, -1)) {
|
||||||
|
lua_pop(L, 2); /* remove metatable and metafield */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_remove(L, -2); /* remove only metatable */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_verror (lua_State *L, const l_char *fmt, ...) {
|
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
|
||||||
l_char buff[500];
|
obj = abs_index(L, obj);
|
||||||
va_list argp;
|
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
|
||||||
va_start(argp, fmt);
|
return 0;
|
||||||
vsprintf(buff, fmt, argp);
|
lua_pushvalue(L, obj);
|
||||||
va_end(argp);
|
lua_call(L, 1, 1);
|
||||||
lua_error(L, buff);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
|
||||||
|
const luaL_reg *l, int nup) {
|
||||||
|
if (libname) {
|
||||||
|
lua_pushstring(L, libname);
|
||||||
|
lua_gettable(L, LUA_GLOBALSINDEX); /* check whether lib already exists */
|
||||||
|
if (lua_isnil(L, -1)) { /* no? */
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_newtable(L); /* create it */
|
||||||
|
lua_pushstring(L, libname);
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_settable(L, LUA_GLOBALSINDEX); /* register it with given name */
|
||||||
|
}
|
||||||
|
lua_insert(L, -(nup+1)); /* move library table to below upvalues */
|
||||||
|
}
|
||||||
|
for (; l->name; l++) {
|
||||||
|
int i;
|
||||||
|
lua_pushstring(L, l->name);
|
||||||
|
for (i=0; i<nup; i++) /* copy upvalues to the top */
|
||||||
|
lua_pushvalue(L, -(nup+1));
|
||||||
|
lua_pushcclosure(L, l->func, nup);
|
||||||
|
lua_settable(L, -(nup+3));
|
||||||
|
}
|
||||||
|
lua_pop(L, nup); /* remove upvalues */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** getn-setn: size for arrays
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int checkint (lua_State *L, int topop) {
|
||||||
|
int n = (int)lua_tonumber(L, -1);
|
||||||
|
if (n == 0 && !lua_isnumber(L, -1)) n = -1;
|
||||||
|
lua_pop(L, topop);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void getsizes (lua_State *L) {
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF);
|
||||||
|
if (lua_isnil(L, -1)) { /* no `size' table? */
|
||||||
|
lua_pop(L, 1); /* remove nil */
|
||||||
|
lua_newtable(L); /* create it */
|
||||||
|
lua_pushvalue(L, -1); /* `size' will be its own metatable */
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
lua_pushliteral(L, "__mode");
|
||||||
|
lua_pushliteral(L, "k");
|
||||||
|
lua_rawset(L, -3); /* metatable(N).__mode = "k" */
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_rawseti(L, LUA_REGISTRYINDEX, ARRAYSIZE_REF); /* store in register */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaL_setn (lua_State *L, int t, int n) {
|
||||||
|
t = abs_index(L, t);
|
||||||
|
lua_pushliteral(L, "n");
|
||||||
|
lua_rawget(L, t);
|
||||||
|
if (checkint(L, 1) >= 0) { /* is there a numeric field `n'? */
|
||||||
|
lua_pushliteral(L, "n"); /* use it */
|
||||||
|
lua_pushnumber(L, (lua_Number)n);
|
||||||
|
lua_rawset(L, t);
|
||||||
|
}
|
||||||
|
else { /* use `sizes' */
|
||||||
|
getsizes(L);
|
||||||
|
lua_pushvalue(L, t);
|
||||||
|
lua_pushnumber(L, (lua_Number)n);
|
||||||
|
lua_rawset(L, -3); /* sizes[t] = n */
|
||||||
|
lua_pop(L, 1); /* remove `sizes' */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaL_getn (lua_State *L, int t) {
|
||||||
|
int n;
|
||||||
|
t = abs_index(L, t);
|
||||||
|
lua_pushliteral(L, "n"); /* try t.n */
|
||||||
|
lua_rawget(L, t);
|
||||||
|
if ((n = checkint(L, 1)) >= 0) return n;
|
||||||
|
getsizes(L); /* else try sizes[t] */
|
||||||
|
lua_pushvalue(L, t);
|
||||||
|
lua_rawget(L, -2);
|
||||||
|
if ((n = checkint(L, 2)) >= 0) return n;
|
||||||
|
for (n = 1; ; n++) { /* else must count elements */
|
||||||
|
lua_rawgeti(L, t, n);
|
||||||
|
if (lua_isnil(L, -1)) break;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return n - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {======================================================
|
** {======================================================
|
||||||
** Generic Buffer manipulation
|
** Generic Buffer manipulation
|
||||||
@@ -136,7 +328,6 @@ LUALIB_API void luaL_verror (lua_State *L, const l_char *fmt, ...) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define buffempty(B) ((B)->p == (B)->buffer)
|
|
||||||
#define bufflen(B) ((B)->p - (B)->buffer)
|
#define bufflen(B) ((B)->p - (B)->buffer)
|
||||||
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
|
#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
|
||||||
|
|
||||||
@@ -149,53 +340,53 @@ static int emptybuffer (luaL_Buffer *B) {
|
|||||||
else {
|
else {
|
||||||
lua_pushlstring(B->L, B->buffer, l);
|
lua_pushlstring(B->L, B->buffer, l);
|
||||||
B->p = B->buffer;
|
B->p = B->buffer;
|
||||||
B->level++;
|
B->lvl++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void adjuststack (luaL_Buffer *B) {
|
static void adjuststack (luaL_Buffer *B) {
|
||||||
if (B->level > 1) {
|
if (B->lvl > 1) {
|
||||||
lua_State *L = B->L;
|
lua_State *L = B->L;
|
||||||
int toget = 1; /* number of levels to concat */
|
int toget = 1; /* number of levels to concat */
|
||||||
size_t toplen = lua_strlen(L, -1);
|
size_t toplen = lua_strlen(L, -1);
|
||||||
do {
|
do {
|
||||||
size_t l = lua_strlen(L, -(toget+1));
|
size_t l = lua_strlen(L, -(toget+1));
|
||||||
if (B->level - toget + 1 >= LIMIT || toplen > l) {
|
if (B->lvl - toget + 1 >= LIMIT || toplen > l) {
|
||||||
toplen += l;
|
toplen += l;
|
||||||
toget++;
|
toget++;
|
||||||
}
|
}
|
||||||
else break;
|
else break;
|
||||||
} while (toget < B->level);
|
} while (toget < B->lvl);
|
||||||
lua_concat(L, toget);
|
lua_concat(L, toget);
|
||||||
B->level = B->level - toget + 1;
|
B->lvl = B->lvl - toget + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API l_char *luaL_prepbuffer (luaL_Buffer *B) {
|
LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) {
|
||||||
if (emptybuffer(B))
|
if (emptybuffer(B))
|
||||||
adjuststack(B);
|
adjuststack(B);
|
||||||
return B->buffer;
|
return B->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const l_char *s, size_t l) {
|
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
|
||||||
while (l--)
|
while (l--)
|
||||||
luaL_putchar(B, *s++);
|
luaL_putchar(B, *s++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_addstring (luaL_Buffer *B, const l_char *s) {
|
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
||||||
luaL_addlstring(B, s, strlen(s));
|
luaL_addlstring(B, s, strlen(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
||||||
emptybuffer(B);
|
emptybuffer(B);
|
||||||
lua_concat(B->L, B->level);
|
lua_concat(B->L, B->lvl);
|
||||||
B->level = 1;
|
B->lvl = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -210,7 +401,7 @@ LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
|
|||||||
else {
|
else {
|
||||||
if (emptybuffer(B))
|
if (emptybuffer(B))
|
||||||
lua_insert(L, -2); /* put buffer before new value */
|
lua_insert(L, -2); /* put buffer before new value */
|
||||||
B->level++; /* add new value into B stack */
|
B->lvl++; /* add new value into B stack */
|
||||||
adjuststack(B);
|
adjuststack(B);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,7 +410,182 @@ LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
|
|||||||
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
|
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
|
||||||
B->L = L;
|
B->L = L;
|
||||||
B->p = B->buffer;
|
B->p = B->buffer;
|
||||||
B->level = 0;
|
B->lvl = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_ref (lua_State *L, int t) {
|
||||||
|
int ref;
|
||||||
|
t = abs_index(L, t);
|
||||||
|
if (lua_isnil(L, -1)) {
|
||||||
|
lua_pop(L, 1); /* remove from stack */
|
||||||
|
return LUA_REFNIL; /* `nil' has a unique fixed reference */
|
||||||
|
}
|
||||||
|
lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
|
||||||
|
ref = (int)lua_tonumber(L, -1); /* ref = t[FREELIST_REF] */
|
||||||
|
lua_pop(L, 1); /* remove it from stack */
|
||||||
|
if (ref != 0) { /* any free element? */
|
||||||
|
lua_rawgeti(L, t, ref); /* remove it from list */
|
||||||
|
lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
|
||||||
|
}
|
||||||
|
else { /* no free elements */
|
||||||
|
ref = luaL_getn(L, t);
|
||||||
|
if (ref < RESERVED_REFS)
|
||||||
|
ref = RESERVED_REFS; /* skip reserved references */
|
||||||
|
ref++; /* create new reference */
|
||||||
|
luaL_setn(L, t, ref);
|
||||||
|
}
|
||||||
|
lua_rawseti(L, t, ref);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
||||||
|
if (ref >= 0) {
|
||||||
|
t = abs_index(L, t);
|
||||||
|
lua_rawgeti(L, t, FREELIST_REF);
|
||||||
|
lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
|
||||||
|
lua_pushnumber(L, (lua_Number)ref);
|
||||||
|
lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** Load functions
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct LoadF {
|
||||||
|
FILE *f;
|
||||||
|
char buff[LUAL_BUFFERSIZE];
|
||||||
|
} LoadF;
|
||||||
|
|
||||||
|
|
||||||
|
static const char *getF (lua_State *L, void *ud, size_t *size) {
|
||||||
|
LoadF *lf = (LoadF *)ud;
|
||||||
|
(void)L;
|
||||||
|
if (feof(lf->f)) return NULL;
|
||||||
|
*size = fread(lf->buff, 1, LUAL_BUFFERSIZE, lf->f);
|
||||||
|
return (*size > 0) ? lf->buff : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int errfile (lua_State *L, int fnameindex) {
|
||||||
|
const char *filename = lua_tostring(L, fnameindex) + 1;
|
||||||
|
lua_pushfstring(L, "cannot read %s: %s", filename, strerror(errno));
|
||||||
|
lua_remove(L, fnameindex);
|
||||||
|
return LUA_ERRFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
|
||||||
|
LoadF lf;
|
||||||
|
int status, readstatus;
|
||||||
|
int c;
|
||||||
|
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
|
||||||
|
if (filename == NULL) {
|
||||||
|
lua_pushliteral(L, "=stdin");
|
||||||
|
lf.f = stdin;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushfstring(L, "@%s", filename);
|
||||||
|
lf.f = fopen(filename, "r");
|
||||||
|
}
|
||||||
|
if (lf.f == NULL) return errfile(L, fnameindex); /* unable to open file */
|
||||||
|
c = ungetc(getc(lf.f), lf.f);
|
||||||
|
if (!(isspace(c) || isprint(c)) && lf.f != stdin) { /* binary file? */
|
||||||
|
fclose(lf.f);
|
||||||
|
lf.f = fopen(filename, "rb"); /* reopen in binary mode */
|
||||||
|
if (lf.f == NULL) return errfile(L, fnameindex); /* unable to reopen file */
|
||||||
|
}
|
||||||
|
status = lua_load(L, getF, &lf, lua_tostring(L, -1));
|
||||||
|
readstatus = ferror(lf.f);
|
||||||
|
if (lf.f != stdin) fclose(lf.f); /* close file (even in case of errors) */
|
||||||
|
if (readstatus) {
|
||||||
|
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
|
||||||
|
return errfile(L, fnameindex);
|
||||||
|
}
|
||||||
|
lua_remove(L, fnameindex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct LoadS {
|
||||||
|
const char *s;
|
||||||
|
size_t size;
|
||||||
|
} LoadS;
|
||||||
|
|
||||||
|
|
||||||
|
static const char *getS (lua_State *L, void *ud, size_t *size) {
|
||||||
|
LoadS *ls = (LoadS *)ud;
|
||||||
|
(void)L;
|
||||||
|
if (ls->size == 0) return NULL;
|
||||||
|
*size = ls->size;
|
||||||
|
ls->size = 0;
|
||||||
|
return ls->s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t size,
|
||||||
|
const char *name) {
|
||||||
|
LoadS ls;
|
||||||
|
ls.s = buff;
|
||||||
|
ls.size = size;
|
||||||
|
return lua_load(L, getS, &ls, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** compatibility code
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void callalert (lua_State *L, int status) {
|
||||||
|
if (status != 0) {
|
||||||
|
lua_getglobal(L, "_ALERT");
|
||||||
|
if (lua_isfunction(L, -1)) {
|
||||||
|
lua_insert(L, -2);
|
||||||
|
lua_call(L, 1, 0);
|
||||||
|
}
|
||||||
|
else { /* no _ALERT function; print it on stderr */
|
||||||
|
fprintf(stderr, "%s\n", lua_tostring(L, -2));
|
||||||
|
lua_pop(L, 2); /* remove error message and _ALERT */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int aux_do (lua_State *L, int status) {
|
||||||
|
if (status == 0) { /* parse OK? */
|
||||||
|
status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */
|
||||||
|
}
|
||||||
|
callalert(L, status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int lua_dofile (lua_State *L, const char *filename) {
|
||||||
|
return aux_do(L, luaL_loadfile(L, filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size,
|
||||||
|
const char *name) {
|
||||||
|
return aux_do(L, luaL_loadbuffer(L, buff, size, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int lua_dostring (lua_State *L, const char *str) {
|
||||||
|
return lua_dobuffer(L, str, strlen(str), str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|||||||
105
lauxlib.h
105
lauxlib.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lauxlib.h,v 1.35 2001/04/06 21:17:37 roberto Exp roberto $
|
** $Id: lauxlib.h,v 1.59 2003/03/18 12:25:32 roberto Exp roberto $
|
||||||
** Auxiliary functions for building Lua libraries
|
** Auxiliary functions for building Lua libraries
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -16,35 +16,51 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef LUALIB_API
|
#ifndef LUALIB_API
|
||||||
#define LUALIB_API extern
|
#define LUALIB_API LUA_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct luaL_reg {
|
typedef struct luaL_reg {
|
||||||
const lua_char *name;
|
const char *name;
|
||||||
lua_CFunction func;
|
lua_CFunction func;
|
||||||
} luaL_reg;
|
} luaL_reg;
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API void luaL_openlib (lua_State *L, const luaL_reg *l, int n);
|
LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
|
||||||
LUALIB_API void luaL_argerror (lua_State *L, int numarg,
|
const luaL_reg *l, int nup);
|
||||||
const lua_char *extramsg);
|
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *e);
|
||||||
LUALIB_API const lua_char *luaL_check_lstr (lua_State *L, int numArg,
|
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *e);
|
||||||
size_t *len);
|
LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname);
|
||||||
LUALIB_API const lua_char *luaL_opt_lstr (lua_State *L, int numArg,
|
LUALIB_API int luaL_argerror (lua_State *L, int numarg, const char *extramsg);
|
||||||
const lua_char *def, size_t *len);
|
LUALIB_API const char *luaL_checklstring (lua_State *L, int numArg, size_t *l);
|
||||||
LUALIB_API lua_Number luaL_check_number (lua_State *L, int numArg);
|
LUALIB_API const char *luaL_optlstring (lua_State *L, int numArg,
|
||||||
LUALIB_API lua_Number luaL_opt_number (lua_State *L, int nArg, lua_Number def);
|
const char *def, size_t *l);
|
||||||
|
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int numArg);
|
||||||
|
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int nArg, lua_Number def);
|
||||||
|
|
||||||
LUALIB_API void luaL_checkstack (lua_State *L, int space, const lua_char *msg);
|
LUALIB_API void luaL_checkstack (lua_State *L, int sz, const char *msg);
|
||||||
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t);
|
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t);
|
||||||
LUALIB_API void luaL_checkany (lua_State *L, int narg);
|
LUALIB_API void luaL_checkany (lua_State *L, int narg);
|
||||||
LUALIB_API void *luaL_check_userdata (lua_State *L, int narg,
|
|
||||||
const lua_char *name);
|
|
||||||
|
|
||||||
LUALIB_API void luaL_verror (lua_State *L, const lua_char *fmt, ...);
|
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname);
|
||||||
LUALIB_API int luaL_findstring (const lua_char *name,
|
LUALIB_API void luaL_getmetatable (lua_State *L, const char *tname);
|
||||||
const lua_char *const list[]);
|
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname);
|
||||||
|
|
||||||
|
LUALIB_API void luaL_where (lua_State *L, int lvl);
|
||||||
|
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...);
|
||||||
|
|
||||||
|
LUALIB_API int luaL_findstring (const char *st, const char *const lst[]);
|
||||||
|
|
||||||
|
LUALIB_API int luaL_ref (lua_State *L, int t);
|
||||||
|
LUALIB_API void luaL_unref (lua_State *L, int t, int ref);
|
||||||
|
|
||||||
|
LUALIB_API int luaL_getn (lua_State *L, int t);
|
||||||
|
LUALIB_API void luaL_setn (lua_State *L, int t, int n);
|
||||||
|
|
||||||
|
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename);
|
||||||
|
LUALIB_API int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -54,15 +70,14 @@ LUALIB_API int luaL_findstring (const lua_char *name,
|
|||||||
** ===============================================================
|
** ===============================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define luaL_arg_check(L, cond,numarg,extramsg) if (!(cond)) \
|
#define luaL_argcheck(L, cond,numarg,extramsg) if (!(cond)) \
|
||||||
luaL_argerror(L, numarg,extramsg)
|
luaL_argerror(L, numarg,extramsg)
|
||||||
#define luaL_check_string(L,n) (luaL_check_lstr(L, (n), NULL))
|
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||||
#define luaL_opt_string(L,n,d) (luaL_opt_lstr(L, (n), (d), NULL))
|
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||||
#define luaL_check_int(L,n) ((int)luaL_check_number(L, n))
|
#define luaL_checkint(L,n) ((int)luaL_checknumber(L, n))
|
||||||
#define luaL_check_long(L,n) ((long)luaL_check_number(L, n))
|
#define luaL_checklong(L,n) ((long)luaL_checknumber(L, n))
|
||||||
#define luaL_opt_int(L,n,d) ((int)luaL_opt_number(L, n,d))
|
#define luaL_optint(L,n,d) ((int)luaL_optnumber(L, n,(lua_Number)(d)))
|
||||||
#define luaL_opt_long(L,n,d) ((long)luaL_opt_number(L, n,d))
|
#define luaL_optlong(L,n,d) ((long)luaL_optnumber(L, n,(lua_Number)(d)))
|
||||||
#define luaL_openl(L,a) luaL_openlib(L, a, (sizeof(a)/sizeof(a[0])))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -78,22 +93,22 @@ LUALIB_API int luaL_findstring (const lua_char *name,
|
|||||||
|
|
||||||
|
|
||||||
typedef struct luaL_Buffer {
|
typedef struct luaL_Buffer {
|
||||||
lua_char *p; /* current position in buffer */
|
char *p; /* current position in buffer */
|
||||||
int level;
|
int lvl; /* number of strings in the stack (level) */
|
||||||
lua_State *L;
|
lua_State *L;
|
||||||
lua_char buffer[LUAL_BUFFERSIZE];
|
char buffer[LUAL_BUFFERSIZE];
|
||||||
} luaL_Buffer;
|
} luaL_Buffer;
|
||||||
|
|
||||||
#define luaL_putchar(B,c) \
|
#define luaL_putchar(B,c) \
|
||||||
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
|
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
|
||||||
(*(B)->p++ = (lua_char)(c)))
|
(*(B)->p++ = (char)(c)))
|
||||||
|
|
||||||
#define luaL_addsize(B,n) ((B)->p += (n))
|
#define luaL_addsize(B,n) ((B)->p += (n))
|
||||||
|
|
||||||
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B);
|
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B);
|
||||||
LUALIB_API lua_char *luaL_prepbuffer (luaL_Buffer *B);
|
LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B);
|
||||||
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const lua_char *s, size_t l);
|
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
|
||||||
LUALIB_API void luaL_addstring (luaL_Buffer *B, const lua_char *s);
|
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s);
|
||||||
LUALIB_API void luaL_addvalue (luaL_Buffer *B);
|
LUALIB_API void luaL_addvalue (luaL_Buffer *B);
|
||||||
LUALIB_API void luaL_pushresult (luaL_Buffer *B);
|
LUALIB_API void luaL_pushresult (luaL_Buffer *B);
|
||||||
|
|
||||||
@@ -101,6 +116,30 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B);
|
|||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Compatibility macros and functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
LUALIB_API int lua_dofile (lua_State *L, const char *filename);
|
||||||
|
LUALIB_API int lua_dostring (lua_State *L, const char *str);
|
||||||
|
LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t sz,
|
||||||
|
const char *n);
|
||||||
|
|
||||||
|
|
||||||
|
#define luaL_check_lstr luaL_checklstring
|
||||||
|
#define luaL_opt_lstr luaL_optlstring
|
||||||
|
#define luaL_check_number luaL_checknumber
|
||||||
|
#define luaL_opt_number luaL_optnumber
|
||||||
|
#define luaL_arg_check luaL_argcheck
|
||||||
|
#define luaL_check_string luaL_checkstring
|
||||||
|
#define luaL_opt_string luaL_optstring
|
||||||
|
#define luaL_check_int luaL_checkint
|
||||||
|
#define luaL_check_long luaL_checklong
|
||||||
|
#define luaL_opt_int luaL_optint
|
||||||
|
#define luaL_opt_long luaL_optlong
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1023
lbaselib.c
1023
lbaselib.c
File diff suppressed because it is too large
Load Diff
607
lcode.c
607
lcode.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lcode.c,v 1.77 2001/07/17 14:30:44 roberto Exp roberto $
|
** $Id: lcode.c,v 1.116 2003/02/27 12:33:07 roberto Exp roberto $
|
||||||
** Code generator for Lua
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lcode_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lcode.h"
|
#include "lcode.h"
|
||||||
@@ -18,40 +19,21 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lopcodes.h"
|
#include "lopcodes.h"
|
||||||
#include "lparser.h"
|
#include "lparser.h"
|
||||||
|
#include "ltable.h"
|
||||||
|
|
||||||
|
|
||||||
#define hasjumps(e) ((e)->t != (e)->f)
|
#define hasjumps(e) ((e)->t != (e)->f)
|
||||||
|
|
||||||
#define getcode(fs,e) ((fs)->f->code[(e)->u.i.info])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void luaK_error (LexState *ls, const l_char *msg) {
|
|
||||||
luaX_error(ls, msg, ls->t.token);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Returns the the previous instruction, for optimizations.
|
|
||||||
** If there is a jump target between this and the current instruction,
|
|
||||||
** returns a dummy instruction to avoid wrong optimizations.
|
|
||||||
*/
|
|
||||||
static Instruction previous_instruction (FuncState *fs) {
|
|
||||||
if (fs->pc > fs->lasttarget) /* no jumps to current position? */
|
|
||||||
return fs->f->code[fs->pc-1]; /* returns previous instruction */
|
|
||||||
else
|
|
||||||
return (Instruction)(-1);/* no optimizations after an invalid instruction */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaK_nil (FuncState *fs, int from, int n) {
|
void luaK_nil (FuncState *fs, int from, int n) {
|
||||||
Instruction previous = previous_instruction(fs);
|
Instruction *previous;
|
||||||
if (GET_OPCODE(previous) == OP_LOADNIL) {
|
if (fs->pc > fs->lasttarget && /* no jumps to current position? */
|
||||||
int pfrom = GETARG_A(previous);
|
GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) {
|
||||||
int pto = GETARG_B(previous);
|
int pfrom = GETARG_A(*previous);
|
||||||
|
int pto = GETARG_B(*previous);
|
||||||
if (pfrom <= from && from <= pto+1) { /* can connect both? */
|
if (pfrom <= from && from <= pto+1) { /* can connect both? */
|
||||||
if (from+n-1 > pto)
|
if (from+n-1 > pto)
|
||||||
SETARG_B(fs->f->code[fs->pc-1], from+n-1);
|
SETARG_B(*previous, from+n-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,63 +42,43 @@ void luaK_nil (FuncState *fs, int from, int n) {
|
|||||||
|
|
||||||
|
|
||||||
int luaK_jump (FuncState *fs) {
|
int luaK_jump (FuncState *fs) {
|
||||||
int j = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP);
|
int jpc = fs->jpc; /* save list of jumps to here */
|
||||||
if (j == fs->lasttarget) { /* possible jumps to this jump? */
|
int j;
|
||||||
luaK_concat(fs, &j, fs->jlt); /* keep them on hold */
|
fs->jpc = NO_JUMP;
|
||||||
fs->jlt = NO_JUMP;
|
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
|
||||||
}
|
luaK_concat(fs, &j, jpc); /* keep them on hold */
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
|
static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
|
||||||
luaK_codeABC(fs, op, A, B, C);
|
luaK_codeABC(fs, op, A, B, C);
|
||||||
return luaK_codeAsBc(fs, OP_CJMP, 0, NO_JUMP);
|
return luaK_jump(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void luaK_fixjump (FuncState *fs, int pc, int dest) {
|
static void luaK_fixjump (FuncState *fs, int pc, int dest) {
|
||||||
Instruction *jmp = &fs->f->code[pc];
|
|
||||||
if (dest == NO_JUMP)
|
|
||||||
SETARG_sBc(*jmp, NO_JUMP); /* point to itself to represent end of list */
|
|
||||||
else { /* jump is relative to position following jump instruction */
|
|
||||||
int offset = dest-(pc+1);
|
|
||||||
if (abs(offset) > MAXARG_sBc)
|
|
||||||
luaK_error(fs->ls, l_s("control structure too long"));
|
|
||||||
SETARG_sBc(*jmp, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** prep-for instructions (OP_FORPREP & OP_TFORPREP) have a negated jump,
|
|
||||||
** as they simulate the real jump...
|
|
||||||
*/
|
|
||||||
void luaK_fixfor (FuncState *fs, int pc, int dest) {
|
|
||||||
Instruction *jmp = &fs->f->code[pc];
|
Instruction *jmp = &fs->f->code[pc];
|
||||||
int offset = dest-(pc+1);
|
int offset = dest-(pc+1);
|
||||||
SETARG_sBc(*jmp, -offset);
|
lua_assert(dest != NO_JUMP);
|
||||||
|
if (abs(offset) > MAXARG_sBx)
|
||||||
|
luaX_syntaxerror(fs->ls, "control structure too long");
|
||||||
|
SETARG_sBx(*jmp, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** returns current `pc' and marks it as a jump target (to avoid wrong
|
** returns current `pc' and marks it as a jump target (to avoid wrong
|
||||||
** optimizations with consecutive instructions not in the same basic block).
|
** optimizations with consecutive instructions not in the same basic block).
|
||||||
** discharge list of jumps to last target.
|
|
||||||
*/
|
*/
|
||||||
int luaK_getlabel (FuncState *fs) {
|
int luaK_getlabel (FuncState *fs) {
|
||||||
if (fs->pc != fs->lasttarget) {
|
fs->lasttarget = fs->pc;
|
||||||
int lasttarget = fs->lasttarget;
|
|
||||||
fs->lasttarget = fs->pc;
|
|
||||||
luaK_patchlist(fs, fs->jlt, lasttarget); /* discharge old list `jlt' */
|
|
||||||
fs->jlt = NO_JUMP; /* nobody jumps to this new label (yet) */
|
|
||||||
}
|
|
||||||
return fs->pc;
|
return fs->pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaK_getjump (FuncState *fs, int pc) {
|
static int luaK_getjump (FuncState *fs, int pc) {
|
||||||
int offset = GETARG_sBc(fs->f->code[pc]);
|
int offset = GETARG_sBx(fs->f->code[pc]);
|
||||||
if (offset == NO_JUMP) /* point to itself represents end of list */
|
if (offset == NO_JUMP) /* point to itself represents end of list */
|
||||||
return NO_JUMP; /* end of list */
|
return NO_JUMP; /* end of list */
|
||||||
else
|
else
|
||||||
@@ -126,20 +88,22 @@ static int luaK_getjump (FuncState *fs, int pc) {
|
|||||||
|
|
||||||
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
|
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
|
||||||
Instruction *pi = &fs->f->code[pc];
|
Instruction *pi = &fs->f->code[pc];
|
||||||
OpCode op = GET_OPCODE(*pi);
|
if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT))
|
||||||
if (op == OP_CJMP)
|
|
||||||
return pi-1;
|
return pi-1;
|
||||||
else {
|
else
|
||||||
lua_assert(op == OP_JMP || op == OP_FORLOOP || op == OP_TFORLOOP);
|
|
||||||
return pi;
|
return pi;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int need_value (FuncState *fs, int list, OpCode op) {
|
/*
|
||||||
/* check whether list has any jump different from `op' */
|
** check whether list has any jump that do not produce a value
|
||||||
for (; list != NO_JUMP; list = luaK_getjump(fs, list))
|
** (or produce an inverted value)
|
||||||
if (GET_OPCODE(*getjumpcontrol(fs, list)) != op) return 1;
|
*/
|
||||||
|
static int need_value (FuncState *fs, int list, int cond) {
|
||||||
|
for (; list != NO_JUMP; list = luaK_getjump(fs, list)) {
|
||||||
|
Instruction i = *getjumpcontrol(fs, list);
|
||||||
|
if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1;
|
||||||
|
}
|
||||||
return 0; /* not found */
|
return 0; /* not found */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,20 +119,20 @@ static void luaK_patchlistaux (FuncState *fs, int list,
|
|||||||
while (list != NO_JUMP) {
|
while (list != NO_JUMP) {
|
||||||
int next = luaK_getjump(fs, list);
|
int next = luaK_getjump(fs, list);
|
||||||
Instruction *i = getjumpcontrol(fs, list);
|
Instruction *i = getjumpcontrol(fs, list);
|
||||||
switch (GET_OPCODE(*i)) {
|
if (GET_OPCODE(*i) != OP_TEST) {
|
||||||
case OP_TESTT: {
|
lua_assert(dtarget != NO_JUMP);
|
||||||
|
luaK_fixjump(fs, list, dtarget); /* jump to default target */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (GETARG_C(*i)) {
|
||||||
|
lua_assert(ttarget != NO_JUMP);
|
||||||
patchtestreg(i, treg);
|
patchtestreg(i, treg);
|
||||||
luaK_fixjump(fs, list, ttarget);
|
luaK_fixjump(fs, list, ttarget);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case OP_TESTF: {
|
else {
|
||||||
|
lua_assert(ftarget != NO_JUMP);
|
||||||
patchtestreg(i, freg);
|
patchtestreg(i, freg);
|
||||||
luaK_fixjump(fs, list, ftarget);
|
luaK_fixjump(fs, list, ftarget);
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
luaK_fixjump(fs, list, dtarget); /* jump to default target */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
list = next;
|
list = next;
|
||||||
@@ -176,16 +140,31 @@ static void luaK_patchlistaux (FuncState *fs, int list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void luaK_dischargejpc (FuncState *fs) {
|
||||||
|
luaK_patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc);
|
||||||
|
fs->jpc = NO_JUMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_patchlist (FuncState *fs, int list, int target) {
|
void luaK_patchlist (FuncState *fs, int list, int target) {
|
||||||
if (target == fs->lasttarget) /* same target that list `jlt'? */
|
if (target == fs->pc)
|
||||||
luaK_concat(fs, &fs->jlt, list); /* delay fixing */
|
luaK_patchtohere(fs, list);
|
||||||
else
|
else {
|
||||||
|
lua_assert(target < fs->pc);
|
||||||
luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
|
luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaK_patchtohere (FuncState *fs, int list) {
|
||||||
|
luaK_getlabel(fs);
|
||||||
|
luaK_concat(fs, &fs->jpc, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_concat (FuncState *fs, int *l1, int l2) {
|
void luaK_concat (FuncState *fs, int *l1, int l2) {
|
||||||
if (*l1 == NO_JUMP)
|
if (l2 == NO_JUMP) return;
|
||||||
|
else if (*l1 == NO_JUMP)
|
||||||
*l1 = l2;
|
*l1 = l2;
|
||||||
else {
|
else {
|
||||||
int list = *l1;
|
int list = *l1;
|
||||||
@@ -197,18 +176,24 @@ void luaK_concat (FuncState *fs, int *l1, int l2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_reserveregs (FuncState *fs, int n) {
|
void luaK_checkstack (FuncState *fs, int n) {
|
||||||
fs->freereg += n;
|
int newstack = fs->freereg + n;
|
||||||
if (fs->freereg > fs->f->maxstacksize) {
|
if (newstack > fs->f->maxstacksize) {
|
||||||
if (fs->freereg >= MAXSTACK)
|
if (newstack >= MAXSTACK)
|
||||||
luaK_error(fs->ls, l_s("function or expression too complex"));
|
luaX_syntaxerror(fs->ls, "function or expression too complex");
|
||||||
fs->f->maxstacksize = (short)fs->freereg;
|
fs->f->maxstacksize = cast(lu_byte, newstack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaK_reserveregs (FuncState *fs, int n) {
|
||||||
|
luaK_checkstack(fs, n);
|
||||||
|
fs->freereg += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void freereg (FuncState *fs, int reg) {
|
static void freereg (FuncState *fs, int reg) {
|
||||||
if (reg >= fs->nactloc && reg < MAXSTACK) {
|
if (reg >= fs->nactvar && reg < MAXSTACK) {
|
||||||
fs->freereg--;
|
fs->freereg--;
|
||||||
lua_assert(reg == fs->freereg);
|
lua_assert(reg == fs->freereg);
|
||||||
}
|
}
|
||||||
@@ -217,55 +202,55 @@ static void freereg (FuncState *fs, int reg) {
|
|||||||
|
|
||||||
static void freeexp (FuncState *fs, expdesc *e) {
|
static void freeexp (FuncState *fs, expdesc *e) {
|
||||||
if (e->k == VNONRELOC)
|
if (e->k == VNONRELOC)
|
||||||
freereg(fs, e->u.i.info);
|
freereg(fs, e->info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int addk (FuncState *fs, TObject *k) {
|
static int addk (FuncState *fs, TObject *k, TObject *v) {
|
||||||
Proto *f = fs->f;
|
const TObject *idx = luaH_get(fs->h, k);
|
||||||
luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject,
|
if (ttisnumber(idx)) {
|
||||||
MAXARG_Bc, l_s("constant table overflow"));
|
lua_assert(luaO_rawequalObj(&fs->f->k[cast(int, nvalue(idx))], v));
|
||||||
setobj(&f->k[fs->nk], k);
|
return cast(int, nvalue(idx));
|
||||||
return fs->nk++;
|
}
|
||||||
}
|
else { /* constant not found; create a new entry */
|
||||||
|
Proto *f = fs->f;
|
||||||
|
luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject,
|
||||||
int luaK_stringk (FuncState *fs, TString *s) {
|
MAXARG_Bx, "constant table overflow");
|
||||||
Proto *f = fs->f;
|
setobj2n(&f->k[fs->nk], v);
|
||||||
int c = s->tsv.constindex;
|
setnvalue(luaH_set(fs->L, fs->h, k), cast(lua_Number, fs->nk));
|
||||||
if (c >= fs->nk || ttype(&f->k[c]) != LUA_TSTRING || tsvalue(&f->k[c]) != s) {
|
return fs->nk++;
|
||||||
TObject o;
|
|
||||||
setsvalue(&o, s);
|
|
||||||
c = addk(fs, &o);
|
|
||||||
s->tsv.constindex = (unsigned short)c; /* hint for next time */
|
|
||||||
}
|
}
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int number_constant (FuncState *fs, lua_Number r) {
|
int luaK_stringK (FuncState *fs, TString *s) {
|
||||||
/* check whether `r' has appeared within the last LOOKBACKNUMS entries */
|
TObject o;
|
||||||
|
setsvalue(&o, s);
|
||||||
|
return addk(fs, &o, &o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaK_numberK (FuncState *fs, lua_Number r) {
|
||||||
TObject o;
|
TObject o;
|
||||||
Proto *f = fs->f;
|
|
||||||
int c = fs->nk;
|
|
||||||
int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
|
|
||||||
while (--c >= lim) {
|
|
||||||
if (ttype(&f->k[c]) == LUA_TNUMBER && nvalue(&f->k[c]) == r)
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
/* not found; create a new entry */
|
|
||||||
setnvalue(&o, r);
|
setnvalue(&o, r);
|
||||||
return addk(fs, &o);
|
return addk(fs, &o, &o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int nil_constant (FuncState *fs) {
|
||||||
|
TObject k, v;
|
||||||
|
setnilvalue(&v);
|
||||||
|
sethvalue(&k, fs->h); /* cannot use nil as key; instead use table itself */
|
||||||
|
return addk(fs, &k, &v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
|
void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
|
||||||
if (e->k == VCALL) { /* expression is an open function call? */
|
if (e->k == VCALL) { /* expression is an open function call? */
|
||||||
if (nresults == LUA_MULTRET) nresults = NO_REG;
|
SETARG_C(getcode(fs, e), nresults+1);
|
||||||
SETARG_C(getcode(fs, e), nresults);
|
|
||||||
if (nresults == 1) { /* `regular' expression? */
|
if (nresults == 1) { /* `regular' expression? */
|
||||||
e->k = VNONRELOC;
|
e->k = VNONRELOC;
|
||||||
e->u.i.info = GETARG_A(getcode(fs, e));
|
e->info = GETARG_A(getcode(fs, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,15 +262,20 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
|||||||
e->k = VNONRELOC;
|
e->k = VNONRELOC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case VUPVAL: {
|
||||||
|
e->info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->info, 0);
|
||||||
|
e->k = VRELOCABLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case VGLOBAL: {
|
case VGLOBAL: {
|
||||||
e->u.i.info = luaK_codeABc(fs, OP_GETGLOBAL, 0, e->u.i.info);
|
e->info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->info);
|
||||||
e->k = VRELOCABLE;
|
e->k = VRELOCABLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VINDEXED: {
|
case VINDEXED: {
|
||||||
freereg(fs, e->u.i.aux);
|
freereg(fs, e->aux);
|
||||||
freereg(fs, e->u.i.info);
|
freereg(fs, e->info);
|
||||||
e->u.i.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.i.info, e->u.i.aux);
|
e->info = luaK_codeABC(fs, OP_GETTABLE, 0, e->info, e->aux);
|
||||||
e->k = VRELOCABLE;
|
e->k = VRELOCABLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -298,29 +288,9 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int code_label (FuncState *fs, OpCode op, int A, int sBc) {
|
static int code_label (FuncState *fs, int A, int b, int jump) {
|
||||||
luaK_getlabel(fs); /* those instructions may be jump targets */
|
luaK_getlabel(fs); /* those instructions may be jump targets */
|
||||||
return luaK_codeAsBc(fs, op, A, sBc);
|
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dischargejumps (FuncState *fs, expdesc *e, int reg) {
|
|
||||||
if (hasjumps(e)) {
|
|
||||||
int final; /* position after whole expression */
|
|
||||||
int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */
|
|
||||||
int p_1 = NO_JUMP; /* position of an eventual PUSHINT */
|
|
||||||
if (need_value(fs, e->f, OP_TESTF) || need_value(fs, e->t, OP_TESTT)) {
|
|
||||||
/* expression needs values */
|
|
||||||
if (e->k != VJMP)
|
|
||||||
code_label(fs, OP_JMP, 0, 2); /* to jump over both pushes */
|
|
||||||
p_nil = code_label(fs, OP_NILJMP, reg, 0);
|
|
||||||
p_1 = code_label(fs, OP_LOADINT, reg, 1);
|
|
||||||
}
|
|
||||||
final = luaK_getlabel(fs);
|
|
||||||
luaK_patchlistaux(fs, e->f, p_nil, NO_REG, final, reg, p_nil);
|
|
||||||
luaK_patchlistaux(fs, e->t, final, reg, p_1, NO_REG, p_1);
|
|
||||||
}
|
|
||||||
e->f = e->t = NO_JUMP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -331,17 +301,12 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
|||||||
luaK_nil(fs, reg, 1);
|
luaK_nil(fs, reg, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VNUMBER: {
|
case VFALSE: case VTRUE: {
|
||||||
lua_Number f = e->u.n;
|
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
|
||||||
int i = (int)f;
|
|
||||||
if ((lua_Number)i == f && -MAXARG_sBc <= i && i <= MAXARG_sBc)
|
|
||||||
luaK_codeAsBc(fs, OP_LOADINT, reg, i); /* f has a small int value */
|
|
||||||
else
|
|
||||||
luaK_codeABc(fs, OP_LOADK, reg, number_constant(fs, f));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VK: {
|
case VK: {
|
||||||
luaK_codeABc(fs, OP_LOADK, reg, e->u.i.info);
|
luaK_codeABx(fs, OP_LOADK, reg, e->info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VRELOCABLE: {
|
case VRELOCABLE: {
|
||||||
@@ -349,9 +314,17 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
|
|||||||
SETARG_A(*pc, reg);
|
SETARG_A(*pc, reg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: return;
|
case VNONRELOC: {
|
||||||
|
if (reg != e->info)
|
||||||
|
luaK_codeABC(fs, OP_MOVE, reg, e->info, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
lua_assert(e->k == VVOID || e->k == VJMP);
|
||||||
|
return; /* nothing to do... */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e->u.i.info = reg;
|
e->info = reg;
|
||||||
e->k = VNONRELOC;
|
e->k = VNONRELOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,51 +339,49 @@ static void discharge2anyreg (FuncState *fs, expdesc *e) {
|
|||||||
|
|
||||||
static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
|
static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
|
||||||
discharge2reg(fs, e, reg);
|
discharge2reg(fs, e, reg);
|
||||||
switch (e->k) {
|
if (e->k == VJMP)
|
||||||
case VVOID: {
|
luaK_concat(fs, &e->t, e->info); /* put this jump in `t' list */
|
||||||
return; /* nothing to do... */
|
if (hasjumps(e)) {
|
||||||
}
|
int final; /* position after whole expression */
|
||||||
case VNONRELOC: {
|
int p_f = NO_JUMP; /* position of an eventual LOAD false */
|
||||||
if (reg != e->u.i.info)
|
int p_t = NO_JUMP; /* position of an eventual LOAD true */
|
||||||
luaK_codeABC(fs, OP_MOVE, reg, e->u.i.info, 0);
|
if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) {
|
||||||
break;
|
int fj = NO_JUMP; /* first jump (over LOAD ops.) */
|
||||||
}
|
if (e->k != VJMP)
|
||||||
case VJMP: {
|
fj = luaK_jump(fs);
|
||||||
luaK_concat(fs, &e->t, e->u.i.info); /* put this jump in `t' list */
|
p_f = code_label(fs, reg, 0, 1);
|
||||||
break;
|
p_t = code_label(fs, reg, 1, 0);
|
||||||
}
|
luaK_patchtohere(fs, fj);
|
||||||
default: {
|
|
||||||
lua_assert(0); /* cannot happen */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
final = luaK_getlabel(fs);
|
||||||
|
luaK_patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f);
|
||||||
|
luaK_patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t);
|
||||||
}
|
}
|
||||||
dischargejumps(fs, e, reg);
|
e->f = e->t = NO_JUMP;
|
||||||
e->u.i.info = reg;
|
e->info = reg;
|
||||||
e->k = VNONRELOC;
|
e->k = VNONRELOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
|
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
|
||||||
int reg;
|
|
||||||
luaK_dischargevars(fs, e);
|
luaK_dischargevars(fs, e);
|
||||||
freeexp(fs, e);
|
freeexp(fs, e);
|
||||||
reg = fs->freereg;
|
|
||||||
luaK_reserveregs(fs, 1);
|
luaK_reserveregs(fs, 1);
|
||||||
luaK_exp2reg(fs, e, reg);
|
luaK_exp2reg(fs, e, fs->freereg - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
|
||||||
luaK_dischargevars(fs, e);
|
luaK_dischargevars(fs, e);
|
||||||
if (e->k == VNONRELOC) {
|
if (e->k == VNONRELOC) {
|
||||||
if (!hasjumps(e)) return e->u.i.info; /* exp is already in a register */
|
if (!hasjumps(e)) return e->info; /* exp is already in a register */
|
||||||
if (e->u.i.info >= fs->nactloc) { /* reg. is not a local? */
|
if (e->info >= fs->nactvar) { /* reg. is not a local? */
|
||||||
dischargejumps(fs, e, e->u.i.info); /* put value on it */
|
luaK_exp2reg(fs, e, e->info); /* put value on it */
|
||||||
return e->u.i.info;
|
return e->info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaK_exp2nextreg(fs, e); /* default */
|
luaK_exp2nextreg(fs, e); /* default */
|
||||||
return e->u.i.info;
|
return e->info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -424,13 +395,24 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
|
|||||||
|
|
||||||
int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
int luaK_exp2RK (FuncState *fs, expdesc *e) {
|
||||||
luaK_exp2val(fs, e);
|
luaK_exp2val(fs, e);
|
||||||
if (e->k == VNUMBER && fs->nk + MAXSTACK <= MAXARG_C) {
|
switch (e->k) {
|
||||||
e->u.i.info = number_constant(fs, e->u.n);
|
case VNIL: {
|
||||||
e->k = VK;
|
if (fs->nk + MAXSTACK <= MAXARG_C) { /* constant fit in argC? */
|
||||||
|
e->info = nil_constant(fs);
|
||||||
|
e->k = VK;
|
||||||
|
return e->info + MAXSTACK;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
case VK: {
|
||||||
|
if (e->info + MAXSTACK <= MAXARG_C) /* constant fit in argC? */
|
||||||
|
return e->info + MAXSTACK;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
else if (!(e->k == VK && e->u.i.info + MAXSTACK <= MAXARG_C))
|
/* not a constant in the right range: put it in a register */
|
||||||
luaK_exp2anyreg(fs, e); /* not a constant in the right range */
|
return luaK_exp2anyreg(fs, e);
|
||||||
return (e->k == VK) ? e->u.i.info+MAXSTACK : e->u.i.info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -438,19 +420,22 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) {
|
|||||||
switch (var->k) {
|
switch (var->k) {
|
||||||
case VLOCAL: {
|
case VLOCAL: {
|
||||||
freeexp(fs, exp);
|
freeexp(fs, exp);
|
||||||
luaK_exp2reg(fs, exp, var->u.i.info);
|
luaK_exp2reg(fs, exp, var->info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case VUPVAL: {
|
||||||
|
int e = luaK_exp2anyreg(fs, exp);
|
||||||
|
luaK_codeABC(fs, OP_SETUPVAL, e, var->info, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VGLOBAL: {
|
case VGLOBAL: {
|
||||||
int e = luaK_exp2anyreg(fs, exp);
|
int e = luaK_exp2anyreg(fs, exp);
|
||||||
freereg(fs, e);
|
luaK_codeABx(fs, OP_SETGLOBAL, e, var->info);
|
||||||
luaK_codeABc(fs, OP_SETGLOBAL, e, var->u.i.info);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VINDEXED: {
|
case VINDEXED: {
|
||||||
int e = luaK_exp2anyreg(fs, exp);
|
int e = luaK_exp2RK(fs, exp);
|
||||||
freereg(fs, e);
|
luaK_codeABC(fs, OP_SETTABLE, var->info, var->aux, e);
|
||||||
luaK_codeABC(fs, OP_SETTABLE, e, var->u.i.info, var->u.i.aux);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -458,6 +443,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
freeexp(fs, exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -467,47 +453,33 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
|
|||||||
freeexp(fs, e);
|
freeexp(fs, e);
|
||||||
func = fs->freereg;
|
func = fs->freereg;
|
||||||
luaK_reserveregs(fs, 2);
|
luaK_reserveregs(fs, 2);
|
||||||
luaK_codeABC(fs, OP_SELF, func, e->u.i.info, luaK_exp2RK(fs, key));
|
luaK_codeABC(fs, OP_SELF, func, e->info, luaK_exp2RK(fs, key));
|
||||||
freeexp(fs, key);
|
freeexp(fs, key);
|
||||||
e->u.i.info = func;
|
e->info = func;
|
||||||
e->k = VNONRELOC;
|
e->k = VNONRELOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static OpCode invertoperator (OpCode op) {
|
|
||||||
switch (op) {
|
|
||||||
case OP_TESTNE: return OP_TESTEQ;
|
|
||||||
case OP_TESTEQ: return OP_TESTNE;
|
|
||||||
case OP_TESTLT: return OP_TESTGE;
|
|
||||||
case OP_TESTLE: return OP_TESTGT;
|
|
||||||
case OP_TESTGT: return OP_TESTLE;
|
|
||||||
case OP_TESTGE: return OP_TESTLT;
|
|
||||||
case OP_TESTT: return OP_TESTF;
|
|
||||||
case OP_TESTF: return OP_TESTT;
|
|
||||||
default: lua_assert(0); return op; /* invalid jump instruction */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void invertjump (FuncState *fs, expdesc *e) {
|
static void invertjump (FuncState *fs, expdesc *e) {
|
||||||
Instruction *pc = getjumpcontrol(fs, e->u.i.info);
|
Instruction *pc = getjumpcontrol(fs, e->info);
|
||||||
*pc = SET_OPCODE(*pc, invertoperator(GET_OPCODE(*pc)));
|
lua_assert(testOpMode(GET_OPCODE(*pc), OpModeT) &&
|
||||||
|
GET_OPCODE(*pc) != OP_TEST);
|
||||||
|
SETARG_A(*pc, !(GETARG_A(*pc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int jumponcond (FuncState *fs, expdesc *e, OpCode op) {
|
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
|
||||||
if (e->k == VRELOCABLE) {
|
if (e->k == VRELOCABLE) {
|
||||||
Instruction ie = getcode(fs, e);
|
Instruction ie = getcode(fs, e);
|
||||||
if (GET_OPCODE(ie) == OP_NOT) {
|
if (GET_OPCODE(ie) == OP_NOT) {
|
||||||
op = invertoperator(op);
|
|
||||||
fs->pc--; /* remove previous OP_NOT */
|
fs->pc--; /* remove previous OP_NOT */
|
||||||
return luaK_condjump(fs, op, NO_REG, GETARG_B(ie), 0);
|
return luaK_condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond);
|
||||||
}
|
}
|
||||||
/* else go through */
|
/* else go through */
|
||||||
}
|
}
|
||||||
discharge2anyreg(fs, e);
|
discharge2anyreg(fs, e);
|
||||||
freeexp(fs, e);
|
freeexp(fs, e);
|
||||||
return luaK_condjump(fs, op, NO_REG, e->u.i.info, 0);
|
return luaK_condjump(fs, OP_TEST, NO_REG, e->info, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -515,76 +487,62 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
|||||||
int pc; /* pc of last jump */
|
int pc; /* pc of last jump */
|
||||||
luaK_dischargevars(fs, e);
|
luaK_dischargevars(fs, e);
|
||||||
switch (e->k) {
|
switch (e->k) {
|
||||||
case VK: case VNUMBER: {
|
case VK: case VTRUE: {
|
||||||
pc = NO_JUMP; /* always true; do nothing */
|
pc = NO_JUMP; /* always true; do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VNIL: {
|
case VFALSE: {
|
||||||
pc = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP); /* always jump */
|
pc = luaK_jump(fs); /* always jump */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VJMP: {
|
case VJMP: {
|
||||||
invertjump(fs, e);
|
invertjump(fs, e);
|
||||||
pc = e->u.i.info;
|
pc = e->info;
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VRELOCABLE:
|
|
||||||
case VNONRELOC: {
|
|
||||||
pc = jumponcond(fs, e, OP_TESTF);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
pc = 0; /* to avoid warnings */
|
pc = jumponcond(fs, e, 0);
|
||||||
lua_assert(0); /* cannot happen */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
|
luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
|
||||||
luaK_patchlist(fs, e->t, luaK_getlabel(fs));
|
|
||||||
e->t = NO_JUMP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
||||||
int pc; /* pc of last jump */
|
int pc; /* pc of last jump */
|
||||||
luaK_dischargevars(fs, e);
|
luaK_dischargevars(fs, e);
|
||||||
switch (e->k) {
|
switch (e->k) {
|
||||||
case VNIL: {
|
case VNIL: case VFALSE: {
|
||||||
pc = NO_JUMP; /* always false; do nothing */
|
pc = NO_JUMP; /* always false; do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VJMP: {
|
case VTRUE: {
|
||||||
pc = e->u.i.info;
|
pc = luaK_jump(fs); /* always jump */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VK: case VNUMBER: /* cannot optimize it (`or' must keep value) */
|
case VJMP: {
|
||||||
case VRELOCABLE:
|
pc = e->info;
|
||||||
case VNONRELOC: {
|
|
||||||
pc = jumponcond(fs, e, OP_TESTT);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
pc = 0; /* to avoid warnings */
|
pc = jumponcond(fs, e, 1);
|
||||||
lua_assert(0); /* cannot happen */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
|
luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
|
||||||
luaK_patchlist(fs, e->f, luaK_getlabel(fs));
|
|
||||||
e->f = NO_JUMP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void codenot (FuncState *fs, expdesc *e) {
|
static void codenot (FuncState *fs, expdesc *e) {
|
||||||
luaK_dischargevars(fs, e);
|
luaK_dischargevars(fs, e);
|
||||||
switch (e->k) {
|
switch (e->k) {
|
||||||
case VNIL: {
|
case VNIL: case VFALSE: {
|
||||||
e->u.n = 1;
|
e->k = VTRUE;
|
||||||
e->k = VNUMBER;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VK: case VNUMBER: {
|
case VK: case VTRUE: {
|
||||||
e->k = VNIL;
|
e->k = VFALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VJMP: {
|
case VJMP: {
|
||||||
@@ -595,7 +553,7 @@ static void codenot (FuncState *fs, expdesc *e) {
|
|||||||
case VNONRELOC: {
|
case VNONRELOC: {
|
||||||
discharge2anyreg(fs, e);
|
discharge2anyreg(fs, e);
|
||||||
freeexp(fs, e);
|
freeexp(fs, e);
|
||||||
e->u.i.info = luaK_codeABC(fs, OP_NOT, 0, e->u.i.info, 0);
|
e->info = luaK_codeABC(fs, OP_NOT, 0, e->info, 0);
|
||||||
e->k = VRELOCABLE;
|
e->k = VRELOCABLE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -610,7 +568,7 @@ static void codenot (FuncState *fs, expdesc *e) {
|
|||||||
|
|
||||||
|
|
||||||
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
||||||
t->u.i.aux = luaK_exp2RK(fs, k);
|
t->aux = luaK_exp2RK(fs, k);
|
||||||
t->k = VINDEXED;
|
t->k = VINDEXED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,12 +576,12 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
|
|||||||
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
|
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
|
||||||
if (op == OPR_MINUS) {
|
if (op == OPR_MINUS) {
|
||||||
luaK_exp2val(fs, e);
|
luaK_exp2val(fs, e);
|
||||||
if (e->k == VNUMBER)
|
if (e->k == VK && ttisnumber(&fs->f->k[e->info]))
|
||||||
e->u.n = -e->u.n;
|
e->info = luaK_numberK(fs, -nvalue(&fs->f->k[e->info]));
|
||||||
else {
|
else {
|
||||||
luaK_exp2anyreg(fs, e);
|
luaK_exp2anyreg(fs, e);
|
||||||
freeexp(fs, e);
|
freeexp(fs, e);
|
||||||
e->u.i.info = luaK_codeABC(fs, OP_UNM, 0, e->u.i.info, 0);
|
e->info = luaK_codeABC(fs, OP_UNM, 0, e->info, 0);
|
||||||
e->k = VRELOCABLE;
|
e->k = VRELOCABLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -636,21 +594,20 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
|||||||
switch (op) {
|
switch (op) {
|
||||||
case OPR_AND: {
|
case OPR_AND: {
|
||||||
luaK_goiftrue(fs, v);
|
luaK_goiftrue(fs, v);
|
||||||
|
luaK_patchtohere(fs, v->t);
|
||||||
|
v->t = NO_JUMP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_OR: {
|
case OPR_OR: {
|
||||||
luaK_goiffalse(fs, v);
|
luaK_goiffalse(fs, v);
|
||||||
|
luaK_patchtohere(fs, v->f);
|
||||||
|
v->f = NO_JUMP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_CONCAT: {
|
case OPR_CONCAT: {
|
||||||
luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
|
luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_SUB: case OPR_DIV: case OPR_POW: {
|
|
||||||
/* non-comutative operators */
|
|
||||||
luaK_exp2anyreg(fs, v); /* first operand must be a register */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
default: {
|
||||||
luaK_exp2RK(fs, v);
|
luaK_exp2RK(fs, v);
|
||||||
break;
|
break;
|
||||||
@@ -659,24 +616,25 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void codebinop (FuncState *fs, expdesc *res, BinOpr op,
|
||||||
/* opcode for each binary operator */
|
int o1, int o2) {
|
||||||
static const OpCode codes[] = { /* ORDER OPR */
|
if (op <= OPR_POW) { /* arithmetic operator? */
|
||||||
OP_ADD, OP_SUB, OP_MUL, OP_DIV,
|
OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD); /* ORDER OP */
|
||||||
OP_POW, OP_CONCAT,
|
res->info = luaK_codeABC(fs, opc, 0, o1, o2);
|
||||||
OP_TESTNE, OP_TESTEQ,
|
res->k = VRELOCABLE;
|
||||||
OP_TESTLT, OP_TESTLE, OP_TESTGT, OP_TESTGE
|
}
|
||||||
};
|
else { /* test operator */
|
||||||
|
static const OpCode ops[] = {OP_EQ, OP_EQ, OP_LT, OP_LE, OP_LT, OP_LE};
|
||||||
|
int cond = 1;
|
||||||
/* `inverted' opcode for each binary operator */
|
if (op >= OPR_GT) { /* `>' or `>='? */
|
||||||
/* ( -1 means operator has no inverse) */
|
int temp; /* exchange args and replace by `<' or `<=' */
|
||||||
static const OpCode invcodes[] = { /* ORDER OPR */
|
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
|
||||||
OP_ADD, (OpCode)-1, OP_MUL, (OpCode)-1,
|
}
|
||||||
(OpCode)-1, (OpCode)-1,
|
else if (op == OPR_NE) cond = 0;
|
||||||
OP_TESTNE, OP_TESTEQ,
|
res->info = luaK_condjump(fs, ops[op - OPR_NE], cond, o1, o2);
|
||||||
OP_TESTGT, OP_TESTGE, OP_TESTLT, OP_TESTLE
|
res->k = VJMP;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
|
void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
|
||||||
@@ -685,117 +643,72 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
|
|||||||
lua_assert(e1->t == NO_JUMP); /* list must be closed */
|
lua_assert(e1->t == NO_JUMP); /* list must be closed */
|
||||||
luaK_dischargevars(fs, e2);
|
luaK_dischargevars(fs, e2);
|
||||||
luaK_concat(fs, &e1->f, e2->f);
|
luaK_concat(fs, &e1->f, e2->f);
|
||||||
e1->k = e2->k; e1->u = e2->u; e1->t = e2->t;
|
e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->t = e2->t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_OR: {
|
case OPR_OR: {
|
||||||
lua_assert(e1->f == NO_JUMP); /* list must be closed */
|
lua_assert(e1->f == NO_JUMP); /* list must be closed */
|
||||||
luaK_dischargevars(fs, e2);
|
luaK_dischargevars(fs, e2);
|
||||||
luaK_concat(fs, &e1->t, e2->t);
|
luaK_concat(fs, &e1->t, e2->t);
|
||||||
e1->k = e2->k; e1->u = e2->u; e1->f = e2->f;
|
e1->k = e2->k; e1->info = e2->info; e1->aux = e2->aux; e1->f = e2->f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_CONCAT: {
|
case OPR_CONCAT: {
|
||||||
luaK_exp2val(fs, e2);
|
luaK_exp2val(fs, e2);
|
||||||
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
|
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
|
||||||
lua_assert(e1->u.i.info == GETARG_B(getcode(fs, e2))-1);
|
lua_assert(e1->info == GETARG_B(getcode(fs, e2))-1);
|
||||||
freeexp(fs, e1);
|
freeexp(fs, e1);
|
||||||
SETARG_B(getcode(fs, e2), e1->u.i.info);
|
SETARG_B(getcode(fs, e2), e1->info);
|
||||||
e1->k = e2->k; e1->u.i.info = e2->u.i.info;
|
e1->k = e2->k; e1->info = e2->info;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
luaK_exp2nextreg(fs, e2);
|
luaK_exp2nextreg(fs, e2);
|
||||||
freeexp(fs, e2);
|
freeexp(fs, e2);
|
||||||
freeexp(fs, e1);
|
freeexp(fs, e1);
|
||||||
e1->u.i.info = luaK_codeABC(fs, codes[op], 0, e1->u.i.info,
|
e1->info = luaK_codeABC(fs, OP_CONCAT, 0, e1->info, e2->info);
|
||||||
e2->u.i.info);
|
|
||||||
e1->k = VRELOCABLE;
|
e1->k = VRELOCABLE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OPR_EQ: case OPR_NE: {
|
|
||||||
luaK_exp2val(fs, e2);
|
|
||||||
if (e2->k == VNIL) { /* exp x= nil ? */
|
|
||||||
if (e1->k == VK) { /* constant x= nil ? */
|
|
||||||
if (op == OPR_EQ) /* constant == nil ? */
|
|
||||||
e1->k = VNIL; /* always false */
|
|
||||||
/* else always true (leave the constant itself) */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OpCode opc = (op == OPR_EQ) ? OP_TESTF : OP_TESTT;
|
|
||||||
e1->u.i.info = jumponcond(fs, e1, opc);
|
|
||||||
e1->k = VJMP;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* else go through */
|
|
||||||
}
|
|
||||||
default: {
|
default: {
|
||||||
int o1, o2;
|
int o1 = luaK_exp2RK(fs, e1);
|
||||||
OpCode opc;
|
int o2 = luaK_exp2RK(fs, e2);
|
||||||
if (e1->k != VK) { /* not a constant operator? */
|
|
||||||
o1 = e1->u.i.info;
|
|
||||||
o2 = luaK_exp2RK(fs, e2); /* maybe other operator is constant... */
|
|
||||||
opc = codes[op];
|
|
||||||
}
|
|
||||||
else { /* invert operands */
|
|
||||||
o2 = luaK_exp2RK(fs, e1); /* constant must be 2nd operand */
|
|
||||||
o1 = luaK_exp2anyreg(fs, e2); /* other operator must be in register */
|
|
||||||
opc = invcodes[op]; /* use inverted operator */
|
|
||||||
}
|
|
||||||
freeexp(fs, e2);
|
freeexp(fs, e2);
|
||||||
freeexp(fs, e1);
|
freeexp(fs, e1);
|
||||||
if (op < OPR_NE) { /* ORDER OPR */
|
codebinop(fs, e1, op, o1, o2);
|
||||||
e1->u.i.info = luaK_codeABC(fs, opc, 0, o1, o2);
|
|
||||||
e1->k = VRELOCABLE;
|
|
||||||
}
|
|
||||||
else { /* jump */
|
|
||||||
e1->u.i.info = luaK_condjump(fs, opc, o1, 0, o2);
|
|
||||||
e1->k = VJMP;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void codelineinfo (FuncState *fs) {
|
void luaK_fixline (FuncState *fs, int line) {
|
||||||
|
fs->f->lineinfo[fs->pc - 1] = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaK_code (FuncState *fs, Instruction i, int line) {
|
||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
LexState *ls = fs->ls;
|
luaK_dischargejpc(fs); /* `pc' will change */
|
||||||
if (ls->lastline > fs->lastline) {
|
|
||||||
if (ls->lastline > fs->lastline+1) {
|
|
||||||
luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
|
|
||||||
MAX_INT, l_s("line info overflow"));
|
|
||||||
f->lineinfo[fs->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
|
|
||||||
}
|
|
||||||
luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
|
|
||||||
MAX_INT, l_s("line info overflow"));
|
|
||||||
f->lineinfo[fs->nlineinfo++] = fs->pc;
|
|
||||||
fs->lastline = ls->lastline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int luaK_code (FuncState *fs, Instruction i) {
|
|
||||||
Proto *f;
|
|
||||||
codelineinfo(fs);
|
|
||||||
f = fs->f;
|
|
||||||
/* put new instruction in code array */
|
/* put new instruction in code array */
|
||||||
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
|
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
|
||||||
MAX_INT, l_s("code size overflow"));
|
MAX_INT, "code size overflow");
|
||||||
f->code[fs->pc] = i;
|
f->code[fs->pc] = i;
|
||||||
/*printf("free: %d ", fs->freereg); printopcode(f, fs->pc);*/
|
/* save corresponding line information */
|
||||||
|
luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
|
||||||
|
MAX_INT, "code size overflow");
|
||||||
|
f->lineinfo[fs->pc] = line;
|
||||||
return fs->pc++;
|
return fs->pc++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
|
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
|
||||||
lua_assert(getOpMode(o) == iABC);
|
lua_assert(getOpMode(o) == iABC);
|
||||||
return luaK_code(fs, CREATE_ABC(o, a, b, c));
|
return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaK_codeABc (FuncState *fs, OpCode o, int a, unsigned int bc) {
|
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
|
||||||
lua_assert(getOpMode(o) == iABc || getOpMode(o) == iAsBc);
|
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
|
||||||
return luaK_code(fs, CREATE_ABc(o, a, bc));
|
return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
lcode.h
21
lcode.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lcode.h,v 1.23 2001/06/12 14:36:48 roberto Exp roberto $
|
** $Id: lcode.h,v 1.37 2002/06/12 19:16:00 roberto Exp roberto $
|
||||||
** Code generator for Lua
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -26,7 +26,8 @@
|
|||||||
typedef enum BinOpr {
|
typedef enum BinOpr {
|
||||||
OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW,
|
OPR_ADD, OPR_SUB, OPR_MULT, OPR_DIV, OPR_POW,
|
||||||
OPR_CONCAT,
|
OPR_CONCAT,
|
||||||
OPR_NE, OPR_EQ, OPR_LT, OPR_LE, OPR_GT, OPR_GE,
|
OPR_NE, OPR_EQ,
|
||||||
|
OPR_LT, OPR_LE, OPR_GT, OPR_GE,
|
||||||
OPR_AND, OPR_OR,
|
OPR_AND, OPR_OR,
|
||||||
OPR_NOBINOPR
|
OPR_NOBINOPR
|
||||||
} BinOpr;
|
} BinOpr;
|
||||||
@@ -36,14 +37,19 @@ typedef enum BinOpr {
|
|||||||
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
|
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
|
||||||
|
|
||||||
|
|
||||||
#define luaK_codeAsBc(fs,o,A,sBc) luaK_codeABc(fs,o,A,(sBc)+MAXARG_sBc)
|
#define getcode(fs,e) ((fs)->f->code[(e)->info])
|
||||||
|
|
||||||
void luaK_error (LexState *ls, const l_char *msg);
|
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
|
||||||
int luaK_codeABc (FuncState *fs, OpCode o, int A, unsigned int Bc);
|
|
||||||
|
int luaK_code (FuncState *fs, Instruction i, int line);
|
||||||
|
int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
||||||
int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
|
int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
|
||||||
|
void luaK_fixline (FuncState *fs, int line);
|
||||||
void luaK_nil (FuncState *fs, int from, int n);
|
void luaK_nil (FuncState *fs, int from, int n);
|
||||||
void luaK_reserveregs (FuncState *fs, int n);
|
void luaK_reserveregs (FuncState *fs, int n);
|
||||||
int luaK_stringk (FuncState *fs, TString *s);
|
void luaK_checkstack (FuncState *fs, int n);
|
||||||
|
int luaK_stringK (FuncState *fs, TString *s);
|
||||||
|
int luaK_numberK (FuncState *fs, lua_Number r);
|
||||||
void luaK_dischargevars (FuncState *fs, expdesc *e);
|
void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||||
int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||||
void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||||
@@ -52,11 +58,12 @@ int luaK_exp2RK (FuncState *fs, expdesc *e);
|
|||||||
void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||||
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||||
void luaK_goiftrue (FuncState *fs, expdesc *e);
|
void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||||
|
void luaK_goiffalse (FuncState *fs, expdesc *e);
|
||||||
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||||
void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
|
void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
|
||||||
int luaK_jump (FuncState *fs);
|
int luaK_jump (FuncState *fs);
|
||||||
void luaK_patchlist (FuncState *fs, int list, int target);
|
void luaK_patchlist (FuncState *fs, int list, int target);
|
||||||
void luaK_fixfor (FuncState *fs, int pc, int dest);
|
void luaK_patchtohere (FuncState *fs, int list);
|
||||||
void luaK_concat (FuncState *fs, int *l1, int l2);
|
void luaK_concat (FuncState *fs, int *l1, int l2);
|
||||||
int luaK_getlabel (FuncState *fs);
|
int luaK_getlabel (FuncState *fs);
|
||||||
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
|
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
|
||||||
|
|||||||
275
ldblib.c
275
ldblib.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ldblib.c,v 1.36 2001/03/26 14:31:49 roberto Exp roberto $
|
** $Id: ldblib.c,v 1.79 2003/03/11 12:24:34 roberto Exp roberto $
|
||||||
** Interface from Lua to its debug API
|
** Interface from Lua to its debug API
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -9,72 +9,70 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define ldblib_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "luadebug.h"
|
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void settabss (lua_State *L, const l_char *i, const l_char *v) {
|
static void settabss (lua_State *L, const char *i, const char *v) {
|
||||||
lua_pushstring(L, i);
|
lua_pushstring(L, i);
|
||||||
lua_pushstring(L, v);
|
lua_pushstring(L, v);
|
||||||
lua_settable(L, -3);
|
lua_rawset(L, -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void settabsi (lua_State *L, const l_char *i, int v) {
|
static void settabsi (lua_State *L, const char *i, int v) {
|
||||||
lua_pushstring(L, i);
|
lua_pushstring(L, i);
|
||||||
lua_pushnumber(L, v);
|
lua_pushnumber(L, (lua_Number)v);
|
||||||
lua_settable(L, -3);
|
lua_rawset(L, -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int getinfo (lua_State *L) {
|
static int getinfo (lua_State *L) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
const l_char *options = luaL_opt_string(L, 2, l_s("flnSu"));
|
const char *options = luaL_optstring(L, 2, "flnSu");
|
||||||
l_char buff[20];
|
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) {
|
if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) {
|
||||||
lua_pushnil(L); /* level out of range */
|
lua_pushnil(L); /* level out of range */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (lua_isfunction(L, 1)) {
|
else if (lua_isfunction(L, 1)) {
|
||||||
|
lua_pushfstring(L, ">%s", options);
|
||||||
|
options = lua_tostring(L, -1);
|
||||||
lua_pushvalue(L, 1);
|
lua_pushvalue(L, 1);
|
||||||
sprintf(buff, l_s(">%.10s"), options);
|
|
||||||
options = buff;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
luaL_argerror(L, 1, l_s("function or level expected"));
|
return luaL_argerror(L, 1, "function or level expected");
|
||||||
if (!lua_getinfo(L, options, &ar))
|
if (!lua_getinfo(L, options, &ar))
|
||||||
luaL_argerror(L, 2, l_s("invalid option"));
|
return luaL_argerror(L, 2, "invalid option");
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
for (; *options; options++) {
|
for (; *options; options++) {
|
||||||
switch (*options) {
|
switch (*options) {
|
||||||
case l_c('S'):
|
case 'S':
|
||||||
settabss(L, l_s("source"), ar.source);
|
settabss(L, "source", ar.source);
|
||||||
if (ar.source)
|
settabss(L, "short_src", ar.short_src);
|
||||||
settabss(L, l_s("short_src"), ar.short_src);
|
settabsi(L, "linedefined", ar.linedefined);
|
||||||
settabsi(L, l_s("linedefined"), ar.linedefined);
|
settabss(L, "what", ar.what);
|
||||||
settabss(L, l_s("what"), ar.what);
|
|
||||||
break;
|
break;
|
||||||
case l_c('l'):
|
case 'l':
|
||||||
settabsi(L, l_s("currentline"), ar.currentline);
|
settabsi(L, "currentline", ar.currentline);
|
||||||
break;
|
break;
|
||||||
case l_c('u'):
|
case 'u':
|
||||||
settabsi(L, l_s("nups"), ar.nups);
|
settabsi(L, "nups", ar.nups);
|
||||||
break;
|
break;
|
||||||
case l_c('n'):
|
case 'n':
|
||||||
settabss(L, l_s("name"), ar.name);
|
settabss(L, "name", ar.name);
|
||||||
settabss(L, l_s("namewhat"), ar.namewhat);
|
settabss(L, "namewhat", ar.namewhat);
|
||||||
break;
|
break;
|
||||||
case l_c('f'):
|
case 'f':
|
||||||
lua_pushliteral(L, l_s("func"));
|
lua_pushliteral(L, "func");
|
||||||
lua_pushvalue(L, -3);
|
lua_pushvalue(L, -3);
|
||||||
lua_settable(L, -3);
|
lua_rawset(L, -3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,10 +82,10 @@ static int getinfo (lua_State *L) {
|
|||||||
|
|
||||||
static int getlocal (lua_State *L) {
|
static int getlocal (lua_State *L) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
const l_char *name;
|
const char *name;
|
||||||
if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */
|
if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */
|
||||||
luaL_argerror(L, 1, l_s("level out of range"));
|
return luaL_argerror(L, 1, "level out of range");
|
||||||
name = lua_getlocal(L, &ar, luaL_check_int(L, 2));
|
name = lua_getlocal(L, &ar, luaL_checkint(L, 2));
|
||||||
if (name) {
|
if (name) {
|
||||||
lua_pushstring(L, name);
|
lua_pushstring(L, name);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
@@ -102,87 +100,200 @@ static int getlocal (lua_State *L) {
|
|||||||
|
|
||||||
static int setlocal (lua_State *L) {
|
static int setlocal (lua_State *L) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */
|
if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */
|
||||||
luaL_argerror(L, 1, l_s("level out of range"));
|
return luaL_argerror(L, 1, "level out of range");
|
||||||
luaL_checkany(L, 3);
|
luaL_checkany(L, 3);
|
||||||
lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2)));
|
lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int auxupvalue (lua_State *L, int get) {
|
||||||
#define KEY_CALLHOOK l_s("luadblibCallhook")
|
const char *name;
|
||||||
#define KEY_LINEHOOK l_s("luadblibLinehook")
|
int n = luaL_checkint(L, 2);
|
||||||
|
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||||
|
if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
|
||||||
|
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
|
||||||
|
if (name == NULL) return 0;
|
||||||
|
lua_pushstring(L, name);
|
||||||
|
lua_insert(L, -(get+1));
|
||||||
|
return get + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void hookf (lua_State *L, const l_char *key) {
|
static int getupvalue (lua_State *L) {
|
||||||
lua_getregistry(L);
|
return auxupvalue(L, 1);
|
||||||
lua_pushstring(L, key);
|
}
|
||||||
lua_gettable(L, -2);
|
|
||||||
|
|
||||||
|
static int setupvalue (lua_State *L) {
|
||||||
|
luaL_checkany(L, 3);
|
||||||
|
return auxupvalue(L, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const char KEY_HOOK = 'h';
|
||||||
|
|
||||||
|
|
||||||
|
static void hookf (lua_State *L, lua_Debug *ar) {
|
||||||
|
static const char *const hooknames[] =
|
||||||
|
{"call", "return", "line", "count", "tail return"};
|
||||||
|
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||||
if (lua_isfunction(L, -1)) {
|
if (lua_isfunction(L, -1)) {
|
||||||
lua_pushvalue(L, -3); /* original argument (below table and function) */
|
lua_pushstring(L, hooknames[(int)ar->event]);
|
||||||
lua_rawcall(L, 1, 0);
|
if (ar->currentline >= 0)
|
||||||
|
lua_pushnumber(L, (lua_Number)ar->currentline);
|
||||||
|
else lua_pushnil(L);
|
||||||
|
lua_assert(lua_getinfo(L, "lS", ar));
|
||||||
|
lua_call(L, 2, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lua_pop(L, 1); /* pop result from gettable */
|
lua_pop(L, 1); /* pop result from gettable */
|
||||||
lua_pop(L, 1); /* pop table */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void callf (lua_State *L, lua_Debug *ar) {
|
static int makemask (const char *smask, int count) {
|
||||||
lua_pushstring(L, ar->event);
|
int mask = 0;
|
||||||
hookf(L, KEY_CALLHOOK);
|
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
|
||||||
|
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
|
||||||
|
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
|
||||||
|
if (count > 0) mask |= LUA_MASKCOUNT;
|
||||||
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void linef (lua_State *L, lua_Debug *ar) {
|
static char *unmakemask (int mask, char *smask) {
|
||||||
lua_pushnumber(L, ar->currentline);
|
int i = 0;
|
||||||
hookf(L, KEY_LINEHOOK);
|
if (mask & LUA_MASKCALL) smask[i++] = 'c';
|
||||||
|
if (mask & LUA_MASKRET) smask[i++] = 'r';
|
||||||
|
if (mask & LUA_MASKLINE) smask[i++] = 'l';
|
||||||
|
smask[i] = '\0';
|
||||||
|
return smask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void sethook (lua_State *L, const l_char *key, lua_Hook hook,
|
static int sethook (lua_State *L) {
|
||||||
lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) {
|
if (lua_isnoneornil(L, 1)) {
|
||||||
lua_settop(L, 1);
|
lua_settop(L, 1);
|
||||||
if (lua_isnil(L, 1))
|
lua_sethook(L, NULL, 0, 0); /* turn off hooks */
|
||||||
(*sethookf)(L, NULL);
|
}
|
||||||
else if (lua_isfunction(L, 1))
|
else {
|
||||||
(*sethookf)(L, hook);
|
const char *smask = luaL_checkstring(L, 2);
|
||||||
else
|
int count = luaL_optint(L, 3, 0);
|
||||||
luaL_argerror(L, 1, l_s("function expected"));
|
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||||
lua_getregistry(L);
|
lua_sethook(L, hookf, makemask(smask, count), count);
|
||||||
lua_pushstring(L, key);
|
}
|
||||||
lua_pushvalue(L, -1); /* dup key */
|
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||||
lua_gettable(L, -3); /* get old value */
|
|
||||||
lua_pushvalue(L, -2); /* key (again) */
|
|
||||||
lua_pushvalue(L, 1);
|
lua_pushvalue(L, 1);
|
||||||
lua_settable(L, -5); /* set new value */
|
lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int setcallhook (lua_State *L) {
|
static int gethook (lua_State *L) {
|
||||||
sethook(L, KEY_CALLHOOK, callf, lua_setcallhook);
|
char buff[5];
|
||||||
return 1;
|
int mask = lua_gethookmask(L);
|
||||||
|
lua_Hook hook = lua_gethook(L);
|
||||||
|
if (hook != NULL && hook != hookf) /* external hook? */
|
||||||
|
lua_pushliteral(L, "external hook");
|
||||||
|
else {
|
||||||
|
lua_pushlightuserdata(L, (void *)&KEY_HOOK);
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
|
||||||
|
}
|
||||||
|
lua_pushstring(L, unmakemask(mask, buff));
|
||||||
|
lua_pushnumber(L, (lua_Number)lua_gethookcount(L));
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int setlinehook (lua_State *L) {
|
static int debug (lua_State *L) {
|
||||||
sethook(L, KEY_LINEHOOK, linef, lua_setlinehook);
|
for (;;) {
|
||||||
|
char buffer[250];
|
||||||
|
fputs("lua_debug> ", stderr);
|
||||||
|
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
|
||||||
|
strcmp(buffer, "cont\n") == 0)
|
||||||
|
return 0;
|
||||||
|
lua_dostring(L, buffer);
|
||||||
|
lua_settop(L, 0); /* remove eventual returns */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define LEVELS1 12 /* size of the first part of the stack */
|
||||||
|
#define LEVELS2 10 /* size of the second part of the stack */
|
||||||
|
|
||||||
|
static int errorfb (lua_State *L) {
|
||||||
|
int level = 1; /* skip level 0 (it's this function) */
|
||||||
|
int firstpart = 1; /* still before eventual `...' */
|
||||||
|
lua_Debug ar;
|
||||||
|
if (lua_gettop(L) == 0)
|
||||||
|
lua_pushliteral(L, "");
|
||||||
|
else if (!lua_isstring(L, 1)) return 1; /* no string message */
|
||||||
|
else lua_pushliteral(L, "\n");
|
||||||
|
lua_pushliteral(L, "stack traceback:");
|
||||||
|
while (lua_getstack(L, level++, &ar)) {
|
||||||
|
if (level > LEVELS1 && firstpart) {
|
||||||
|
/* no more than `LEVELS2' more levels? */
|
||||||
|
if (!lua_getstack(L, level+LEVELS2, &ar))
|
||||||
|
level--; /* keep going */
|
||||||
|
else {
|
||||||
|
lua_pushliteral(L, "\n\t..."); /* too many levels */
|
||||||
|
while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */
|
||||||
|
level++;
|
||||||
|
}
|
||||||
|
firstpart = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lua_pushliteral(L, "\n\t");
|
||||||
|
lua_getinfo(L, "Snl", &ar);
|
||||||
|
lua_pushfstring(L, "%s:", ar.short_src);
|
||||||
|
if (ar.currentline > 0)
|
||||||
|
lua_pushfstring(L, "%d:", ar.currentline);
|
||||||
|
switch (*ar.namewhat) {
|
||||||
|
case 'g': /* global */
|
||||||
|
case 'l': /* local */
|
||||||
|
case 'f': /* field */
|
||||||
|
case 'm': /* method */
|
||||||
|
lua_pushfstring(L, " in function `%s'", ar.name);
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
if (*ar.what == 'm') /* main? */
|
||||||
|
lua_pushfstring(L, " in main chunk");
|
||||||
|
else if (*ar.what == 'C' || *ar.what == 't')
|
||||||
|
lua_pushliteral(L, " ?"); /* C function or tail call */
|
||||||
|
else
|
||||||
|
lua_pushfstring(L, " in function <%s:%d>",
|
||||||
|
ar.short_src, ar.linedefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_concat(L, lua_gettop(L));
|
||||||
|
}
|
||||||
|
lua_concat(L, lua_gettop(L));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const luaL_reg dblib[] = {
|
static const luaL_reg dblib[] = {
|
||||||
{l_s("getlocal"), getlocal},
|
{"getlocal", getlocal},
|
||||||
{l_s("getinfo"), getinfo},
|
{"getinfo", getinfo},
|
||||||
{l_s("setcallhook"), setcallhook},
|
{"gethook", gethook},
|
||||||
{l_s("setlinehook"), setlinehook},
|
{"getupvalue", getupvalue},
|
||||||
{l_s("setlocal"), setlocal}
|
{"sethook", sethook},
|
||||||
|
{"setlocal", setlocal},
|
||||||
|
{"setupvalue", setupvalue},
|
||||||
|
{"debug", debug},
|
||||||
|
{"traceback", errorfb},
|
||||||
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
LUALIB_API int lua_dblibopen (lua_State *L) {
|
LUALIB_API int luaopen_debug (lua_State *L) {
|
||||||
luaL_openl(L, dblib);
|
luaL_openlib(L, LUA_DBLIBNAME, dblib, 0);
|
||||||
return 0;
|
lua_pushliteral(L, "_TRACEBACK");
|
||||||
|
lua_pushcfunction(L, errorfb);
|
||||||
|
lua_settable(L, LUA_GLOBALSINDEX);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
603
ldebug.c
603
ldebug.c
@@ -1,13 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ldebug.c,v 1.86 2001/06/28 19:58:57 roberto Exp roberto $
|
** $Id: ldebug.c,v 1.149 2003/03/18 12:50:04 roberto Exp roberto $
|
||||||
** Debug Interface
|
** Debug Interface
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ldebug_c
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lapi.h"
|
#include "lapi.h"
|
||||||
@@ -21,131 +23,109 @@
|
|||||||
#include "lstring.h"
|
#include "lstring.h"
|
||||||
#include "ltable.h"
|
#include "ltable.h"
|
||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
#include "luadebug.h"
|
|
||||||
#include "lvm.h"
|
#include "lvm.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const l_char *getfuncname (lua_State *L, CallInfo *ci,
|
static const char *getfuncname (CallInfo *ci, const char **name);
|
||||||
const l_char **name);
|
|
||||||
|
|
||||||
|
|
||||||
|
#define isLua(ci) (!((ci)->state & CI_C))
|
||||||
|
|
||||||
static int isLmark (CallInfo *ci) {
|
|
||||||
lua_assert(ci == NULL || ttype(ci->base - 1) == LUA_TFUNCTION);
|
static int currentpc (CallInfo *ci) {
|
||||||
return (ci && ci->prev && !ci_func(ci)->isC);
|
if (!isLua(ci)) return -1; /* function is not a Lua function? */
|
||||||
|
if (ci->state & CI_HASFRAME) /* function has a frame? */
|
||||||
|
ci->u.l.savedpc = *ci->u.l.pc; /* use `pc' from there */
|
||||||
|
/* function's pc is saved */
|
||||||
|
return pcRel(ci->u.l.savedpc, ci_func(ci)->l.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) {
|
static int currentline (CallInfo *ci) {
|
||||||
lua_Hook oldhook;
|
int pc = currentpc(ci);
|
||||||
lua_lock(L);
|
if (pc < 0)
|
||||||
oldhook = L->callhook;
|
return -1; /* only active lua functions have current-line information */
|
||||||
L->callhook = func;
|
else
|
||||||
lua_unlock(L);
|
return getline(ci_func(ci)->l.p, pc);
|
||||||
return oldhook;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) {
|
void luaG_inithooks (lua_State *L) {
|
||||||
lua_Hook oldhook;
|
CallInfo *ci;
|
||||||
lua_lock(L);
|
for (ci = L->ci; ci != L->base_ci; ci--) /* update all `savedpc's */
|
||||||
oldhook = L->linehook;
|
currentpc(ci);
|
||||||
L->linehook = func;
|
L->hookinit = 1;
|
||||||
lua_unlock(L);
|
|
||||||
return oldhook;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static CallInfo *ci_stack (lua_State *L, StkId obj) {
|
/*
|
||||||
CallInfo *ci = L->ci;
|
** this function can be called asynchronous (e.g. during a signal)
|
||||||
while (ci->base > obj) ci = ci->prev;
|
*/
|
||||||
return (ci != &L->basefunc) ? ci : NULL;
|
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
|
||||||
|
if (func == NULL || mask == 0) { /* turn off hooks? */
|
||||||
|
mask = 0;
|
||||||
|
func = NULL;
|
||||||
|
}
|
||||||
|
L->hook = func;
|
||||||
|
L->basehookcount = count;
|
||||||
|
resethookcount(L);
|
||||||
|
L->hookmask = cast(lu_byte, mask);
|
||||||
|
L->hookinit = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API lua_Hook lua_gethook (lua_State *L) {
|
||||||
|
return L->hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API int lua_gethookmask (lua_State *L) {
|
||||||
|
return L->hookmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API int lua_gethookcount (lua_State *L) {
|
||||||
|
return L->basehookcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
||||||
CallInfo *ci;
|
|
||||||
int status;
|
int status;
|
||||||
|
CallInfo *ci;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
ci = L->ci;
|
for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) {
|
||||||
while (level-- && ci != &L->basefunc) {
|
level--;
|
||||||
lua_assert(ci->base > ci->prev->base);
|
if (!(ci->state & CI_C)) /* Lua function? */
|
||||||
ci = ci->prev;
|
level -= ci->u.l.tailcalls; /* skip lost tail calls */
|
||||||
}
|
}
|
||||||
if (ci == &L->basefunc) status = 0; /* there is no such level */
|
if (level > 0 || ci == L->base_ci) status = 0; /* there is no such level */
|
||||||
else {
|
else if (level < 0) { /* level is of a lost tail call */
|
||||||
ar->_ci = ci;
|
|
||||||
status = 1;
|
status = 1;
|
||||||
|
ar->i_ci = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status = 1;
|
||||||
|
ar->i_ci = ci - L->base_ci;
|
||||||
}
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaG_getline (int *lineinfo, int pc, int refline, int *prefi) {
|
|
||||||
int refi;
|
|
||||||
if (lineinfo == NULL || pc == -1)
|
|
||||||
return -1; /* no line info or function is not active */
|
|
||||||
refi = prefi ? *prefi : 0;
|
|
||||||
if (lineinfo[refi] < 0)
|
|
||||||
refline += -lineinfo[refi++];
|
|
||||||
lua_assert(lineinfo[refi] >= 0);
|
|
||||||
while (lineinfo[refi] > pc) {
|
|
||||||
refline--;
|
|
||||||
refi--;
|
|
||||||
if (lineinfo[refi] < 0)
|
|
||||||
refline -= -lineinfo[refi--];
|
|
||||||
lua_assert(lineinfo[refi] >= 0);
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
int nextline = refline + 1;
|
|
||||||
int nextref = refi + 1;
|
|
||||||
if (lineinfo[nextref] < 0)
|
|
||||||
nextline += -lineinfo[nextref++];
|
|
||||||
lua_assert(lineinfo[nextref] >= 0);
|
|
||||||
if (lineinfo[nextref] > pc)
|
|
||||||
break;
|
|
||||||
refline = nextline;
|
|
||||||
refi = nextref;
|
|
||||||
}
|
|
||||||
if (prefi) *prefi = refi;
|
|
||||||
return refline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int currentpc (CallInfo *ci) {
|
|
||||||
lua_assert(isLmark(ci));
|
|
||||||
if (ci->pc)
|
|
||||||
return (*ci->pc - ci_func(ci)->f.l->code) - 1;
|
|
||||||
else
|
|
||||||
return -1; /* function is not active */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int currentline (CallInfo *ci) {
|
|
||||||
if (!isLmark(ci))
|
|
||||||
return -1; /* only active lua functions have current-line information */
|
|
||||||
else {
|
|
||||||
int *lineinfo = ci_func(ci)->f.l->lineinfo;
|
|
||||||
return luaG_getline(lineinfo, currentpc(ci), 1, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Proto *getluaproto (CallInfo *ci) {
|
static Proto *getluaproto (CallInfo *ci) {
|
||||||
return (isLmark(ci) ? ci_func(ci)->f.l : NULL);
|
return (isLua(ci) ? ci_func(ci)->l.p : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API const l_char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||||
const l_char *name;
|
const char *name;
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
Proto *fp;
|
Proto *fp;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
name = NULL;
|
name = NULL;
|
||||||
ci = ar->_ci;
|
ci = L->base_ci + ar->i_ci;
|
||||||
fp = getluaproto(ci);
|
fp = getluaproto(ci);
|
||||||
if (fp) { /* is a Lua function? */
|
if (fp) { /* is a Lua function? */
|
||||||
name = luaF_getlocalname(fp, n, currentpc(ci));
|
name = luaF_getlocalname(fp, n, currentpc(ci));
|
||||||
@@ -157,135 +137,122 @@ LUA_API const l_char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API const l_char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||||
const l_char *name;
|
const char *name;
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
Proto *fp;
|
Proto *fp;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
name = NULL;
|
name = NULL;
|
||||||
ci = ar->_ci;
|
ci = L->base_ci + ar->i_ci;
|
||||||
fp = getluaproto(ci);
|
fp = getluaproto(ci);
|
||||||
L->top--; /* pop new value */
|
L->top--; /* pop new value */
|
||||||
if (fp) { /* is a Lua function? */
|
if (fp) { /* is a Lua function? */
|
||||||
name = luaF_getlocalname(fp, n, currentpc(ci));
|
name = luaF_getlocalname(fp, n, currentpc(ci));
|
||||||
if (!name || name[0] == l_c('(')) /* `(' starts private locals */
|
if (!name || name[0] == '(') /* `(' starts private locals */
|
||||||
name = NULL;
|
name = NULL;
|
||||||
else
|
else
|
||||||
setobj(ci->base+(n-1), L->top);
|
setobjs2s(ci->base+(n-1), L->top);
|
||||||
}
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void infoLproto (lua_Debug *ar, Proto *f) {
|
static void funcinfo (lua_Debug *ar, StkId func) {
|
||||||
ar->source = getstr(f->source);
|
Closure *cl = clvalue(func);
|
||||||
ar->linedefined = f->lineDefined;
|
if (cl->c.isC) {
|
||||||
ar->what = l_s("Lua");
|
ar->source = "=[C]";
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void funcinfo (lua_State *L, lua_Debug *ar, StkId func) {
|
|
||||||
Closure *cl;
|
|
||||||
if (ttype(func) == LUA_TFUNCTION)
|
|
||||||
cl = clvalue(func);
|
|
||||||
else {
|
|
||||||
luaD_error(L, l_s("value for `lua_getinfo' is not a function"));
|
|
||||||
cl = NULL; /* to avoid warnings */
|
|
||||||
}
|
|
||||||
if (cl->isC) {
|
|
||||||
ar->source = l_s("=C");
|
|
||||||
ar->linedefined = -1;
|
ar->linedefined = -1;
|
||||||
ar->what = l_s("C");
|
ar->what = "C";
|
||||||
}
|
|
||||||
else
|
|
||||||
infoLproto(ar, cl->f.l);
|
|
||||||
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
|
||||||
if (ar->linedefined == 0)
|
|
||||||
ar->what = l_s("main");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const l_char *travtagmethods (global_State *G, const TObject *o) {
|
|
||||||
if (ttype(o) == LUA_TFUNCTION) {
|
|
||||||
int e;
|
|
||||||
for (e=0; e<TM_N; e++) {
|
|
||||||
int t;
|
|
||||||
for (t=0; t<G->ntag; t++)
|
|
||||||
if (clvalue(o) == luaT_gettm(G, t, e))
|
|
||||||
return luaT_eventname[e];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const l_char *travglobals (lua_State *L, const TObject *o) {
|
|
||||||
Hash *g = L->gt;
|
|
||||||
int i;
|
|
||||||
for (i=0; i<g->size; i++) {
|
|
||||||
if (luaO_equalObj(o, val(node(g, i))) &&
|
|
||||||
ttype(key(node(g, i))) == LUA_TSTRING)
|
|
||||||
return getstr(tsvalue(key(node(g, i))));
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void getname (lua_State *L, const TObject *f, lua_Debug *ar) {
|
|
||||||
/* try to find a name for given function */
|
|
||||||
if ((ar->name = travglobals(L, f)) != NULL)
|
|
||||||
ar->namewhat = l_s("global");
|
|
||||||
/* not found: try tag methods */
|
|
||||||
else if ((ar->name = travtagmethods(G(L), f)) != NULL)
|
|
||||||
ar->namewhat = l_s("tag-method");
|
|
||||||
else ar->namewhat = l_s(""); /* not found at all */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_getinfo (lua_State *L, const l_char *what, lua_Debug *ar) {
|
|
||||||
StkId f;
|
|
||||||
CallInfo *ci;
|
|
||||||
int status = 1;
|
|
||||||
lua_lock(L);
|
|
||||||
if (*what != l_c('>')) { /* function is active? */
|
|
||||||
ci = ar->_ci;
|
|
||||||
f = ci->base - 1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
what++; /* skip the `>' */
|
ar->source = getstr(cl->l.p->source);
|
||||||
ci = NULL;
|
ar->linedefined = cl->l.p->lineDefined;
|
||||||
f = L->top - 1;
|
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
|
||||||
}
|
}
|
||||||
|
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *travglobals (lua_State *L, const TObject *o) {
|
||||||
|
Table *g = hvalue(gt(L));
|
||||||
|
int i = sizenode(g);
|
||||||
|
while (i--) {
|
||||||
|
Node *n = gnode(g, i);
|
||||||
|
if (luaO_rawequalObj(o, gval(n)) && ttisstring(gkey(n)))
|
||||||
|
return getstr(tsvalue(gkey(n)));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void info_tailcall (lua_State *L, lua_Debug *ar) {
|
||||||
|
ar->name = ar->namewhat = "";
|
||||||
|
ar->what = "tail";
|
||||||
|
ar->linedefined = ar->currentline = -1;
|
||||||
|
ar->source = "=(tail call)";
|
||||||
|
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
|
||||||
|
ar->nups = 0;
|
||||||
|
setnilvalue(L->top);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||||
|
StkId f, CallInfo *ci) {
|
||||||
|
int status = 1;
|
||||||
for (; *what; what++) {
|
for (; *what; what++) {
|
||||||
switch (*what) {
|
switch (*what) {
|
||||||
case l_c('S'): {
|
case 'S': {
|
||||||
funcinfo(L, ar, f);
|
funcinfo(ar, f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case l_c('l'): {
|
case 'l': {
|
||||||
ar->currentline = currentline(ci);
|
ar->currentline = (ci) ? currentline(ci) : -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case l_c('u'): {
|
case 'u': {
|
||||||
ar->nups = (ttype(f) == LUA_TFUNCTION) ? clvalue(f)->nupvalues : 0;
|
ar->nups = clvalue(f)->c.nupvalues;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case l_c('n'): {
|
case 'n': {
|
||||||
ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
|
ar->namewhat = (ci) ? getfuncname(ci, &ar->name) : NULL;
|
||||||
if (ar->namewhat == NULL)
|
if (ar->namewhat == NULL) {
|
||||||
getname(L, f, ar);
|
/* try to find a global name */
|
||||||
|
if ((ar->name = travglobals(L, f)) != NULL)
|
||||||
|
ar->namewhat = "global";
|
||||||
|
else ar->namewhat = ""; /* not found */
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case l_c('f'): {
|
case 'f': {
|
||||||
setobj(L->top, f);
|
setobj2s(L->top, f);
|
||||||
incr_top; /* push function */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: status = 0; /* invalid option */
|
default: status = 0; /* invalid option */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ci) L->top--; /* pop function */
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||||
|
int status = 1;
|
||||||
|
lua_lock(L);
|
||||||
|
if (*what == '>') {
|
||||||
|
StkId f = L->top - 1;
|
||||||
|
if (!ttisfunction(f))
|
||||||
|
luaG_runerror(L, "value for `lua_getinfo' is not a function");
|
||||||
|
status = auxgetinfo(L, what + 1, ar, f, NULL);
|
||||||
|
L->top--; /* pop function */
|
||||||
|
}
|
||||||
|
else if (ar->i_ci != 0) { /* no tail call? */
|
||||||
|
CallInfo *ci = L->base_ci + ar->i_ci;
|
||||||
|
lua_assert(ttisfunction(ci->base - 1));
|
||||||
|
status = auxgetinfo(L, what, ar, ci->base - 1, ci);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
info_tailcall(L, ar);
|
||||||
|
if (strchr(what, 'f')) incr_top(L);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -304,31 +271,23 @@ LUA_API int lua_getinfo (lua_State *L, const l_char *what, lua_Debug *ar) {
|
|||||||
#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
|
#define checkreg(pt,reg) check((reg) < (pt)->maxstacksize)
|
||||||
|
|
||||||
|
|
||||||
static int checklineinfo (const Proto *pt) {
|
|
||||||
int *lineinfo = pt->lineinfo;
|
|
||||||
if (lineinfo == NULL) return 1;
|
|
||||||
check(pt->sizelineinfo >= 2 && lineinfo[pt->sizelineinfo-1] == MAX_INT);
|
|
||||||
if (*lineinfo < 0) lineinfo++;
|
|
||||||
check(*lineinfo == 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int precheck (const Proto *pt) {
|
static int precheck (const Proto *pt) {
|
||||||
check(checklineinfo(pt));
|
|
||||||
check(pt->maxstacksize <= MAXSTACK);
|
check(pt->maxstacksize <= MAXSTACK);
|
||||||
check(pt->numparams+pt->is_vararg <= pt->maxstacksize);
|
check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
|
||||||
|
lua_assert(pt->numparams+pt->is_vararg <= pt->maxstacksize);
|
||||||
check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
|
check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int checkopenop (Instruction i) {
|
static int checkopenop (const Proto *pt, int pc) {
|
||||||
OpCode op = GET_OPCODE(i);
|
Instruction i = pt->code[pc+1];
|
||||||
switch (op) {
|
switch (GET_OPCODE(i)) {
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
|
case OP_TAILCALL:
|
||||||
case OP_RETURN: {
|
case OP_RETURN: {
|
||||||
check(GETARG_B(i) == NO_REG);
|
check(GETARG_B(i) == 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case OP_SETLISTO: return 1;
|
case OP_SETLISTO: return 1;
|
||||||
@@ -337,12 +296,16 @@ static int checkopenop (Instruction i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int checkRK (const Proto *pt, int r) {
|
||||||
|
return (r < pt->maxstacksize || (r >= MAXSTACK && r-MAXSTACK < pt->sizek));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
||||||
int pc;
|
int pc;
|
||||||
int last; /* stores position of last instruction that changed `reg' */
|
int last; /* stores position of last instruction that changed `reg' */
|
||||||
last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
|
last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */
|
||||||
if (reg == NO_REG) /* full check? */
|
check(precheck(pt));
|
||||||
check(precheck(pt));
|
|
||||||
for (pc = 0; pc < lastpc; pc++) {
|
for (pc = 0; pc < lastpc; pc++) {
|
||||||
const Instruction i = pt->code[pc];
|
const Instruction i = pt->code[pc];
|
||||||
OpCode op = GET_OPCODE(i);
|
OpCode op = GET_OPCODE(i);
|
||||||
@@ -354,41 +317,50 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
|||||||
case iABC: {
|
case iABC: {
|
||||||
b = GETARG_B(i);
|
b = GETARG_B(i);
|
||||||
c = GETARG_C(i);
|
c = GETARG_C(i);
|
||||||
if (testOpMode(op, OpModeBreg))
|
if (testOpMode(op, OpModeBreg)) {
|
||||||
checkreg(pt, b);
|
checkreg(pt, b);
|
||||||
if (testOpMode(op, OpModeCreg))
|
}
|
||||||
check(c < pt->maxstacksize ||
|
else if (testOpMode(op, OpModeBrk))
|
||||||
(c >= MAXSTACK && c-MAXSTACK < pt->sizek));
|
check(checkRK(pt, b));
|
||||||
|
if (testOpMode(op, OpModeCrk))
|
||||||
|
check(checkRK(pt, c));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case iABc: {
|
case iABx: {
|
||||||
b = GETARG_Bc(i);
|
b = GETARG_Bx(i);
|
||||||
if (testOpMode(op, OpModeK)) check(b < pt->sizek);
|
if (testOpMode(op, OpModeK)) check(b < pt->sizek);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case iAsBc: {
|
case iAsBx: {
|
||||||
b = GETARG_sBc(i);
|
b = GETARG_sBx(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (testOpMode(op, OpModesetA)) {
|
if (testOpMode(op, OpModesetA)) {
|
||||||
if (a == reg) last = pc; /* change register `a' */
|
if (a == reg) last = pc; /* change register `a' */
|
||||||
}
|
}
|
||||||
if (testOpMode(op, OpModeT))
|
if (testOpMode(op, OpModeT)) {
|
||||||
check(GET_OPCODE(pt->code[pc+1]) == OP_CJMP);
|
check(pc+2 < pt->sizecode); /* check skip */
|
||||||
|
check(GET_OPCODE(pt->code[pc+1]) == OP_JMP);
|
||||||
|
}
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
case OP_LOADBOOL: {
|
||||||
|
check(c == 0 || pc+2 < pt->sizecode); /* check its jump */
|
||||||
|
break;
|
||||||
|
}
|
||||||
case OP_LOADNIL: {
|
case OP_LOADNIL: {
|
||||||
if (a <= reg && reg <= b)
|
if (a <= reg && reg <= b)
|
||||||
last = pc; /* set registers from `a' to `b' */
|
last = pc; /* set registers from `a' to `b' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_LOADUPVAL: {
|
case OP_GETUPVAL:
|
||||||
check(b < pt->nupvalues);
|
case OP_SETUPVAL: {
|
||||||
|
check(b < pt->nups);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_GETGLOBAL:
|
case OP_GETGLOBAL:
|
||||||
case OP_SETGLOBAL: {
|
case OP_SETGLOBAL: {
|
||||||
check(ttype(&pt->k[b]) == LUA_TSTRING);
|
check(ttisstring(&pt->k[b]));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_SELF: {
|
case OP_SELF: {
|
||||||
@@ -401,8 +373,14 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
|||||||
check(c < MAXSTACK && b < c);
|
check(c < MAXSTACK && b < c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_JMP:
|
case OP_TFORLOOP:
|
||||||
case OP_CJMP: {
|
checkreg(pt, a+c+5);
|
||||||
|
if (reg >= a) last = pc; /* affect all registers above base */
|
||||||
|
/* go through */
|
||||||
|
case OP_FORLOOP:
|
||||||
|
checkreg(pt, a+2);
|
||||||
|
/* go through */
|
||||||
|
case OP_JMP: {
|
||||||
int dest = pc+1+b;
|
int dest = pc+1+b;
|
||||||
check(0 <= dest && dest < pt->sizecode);
|
check(0 <= dest && dest < pt->sizecode);
|
||||||
/* not full check and jump is forward and do not skip `lastpc'? */
|
/* not full check and jump is forward and do not skip `lastpc'? */
|
||||||
@@ -410,16 +388,14 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
|||||||
pc += b; /* do the jump */
|
pc += b; /* do the jump */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_NILJMP: {
|
case OP_CALL:
|
||||||
check(pc+2 < pt->sizecode); /* check its jump */
|
case OP_TAILCALL: {
|
||||||
break;
|
if (b != 0) {
|
||||||
}
|
checkreg(pt, a+b-1);
|
||||||
case OP_CALL: {
|
|
||||||
if (b != NO_REG) {
|
|
||||||
checkreg(pt, a+b);
|
|
||||||
}
|
}
|
||||||
if (c == NO_REG) {
|
c--; /* c = num. returns */
|
||||||
check(checkopenop(pt->code[pc+1]));
|
if (c == LUA_MULTRET) {
|
||||||
|
check(checkopenop(pt, pc));
|
||||||
}
|
}
|
||||||
else if (c != 0)
|
else if (c != 0)
|
||||||
checkreg(pt, a+c-1);
|
checkreg(pt, a+c-1);
|
||||||
@@ -427,23 +403,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_RETURN: {
|
case OP_RETURN: {
|
||||||
if (b != NO_REG && b != 0)
|
b--; /* b = num. returns */
|
||||||
checkreg(pt, a+b-1);
|
if (b > 0) checkreg(pt, a+b-1);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_FORPREP:
|
|
||||||
case OP_TFORPREP: {
|
|
||||||
int dest = pc-b; /* jump is negated here */
|
|
||||||
check(0 <= dest && dest < pt->sizecode &&
|
|
||||||
GET_OPCODE(pt->code[dest]) == op+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_FORLOOP:
|
|
||||||
case OP_TFORLOOP: {
|
|
||||||
int dest = pc+b;
|
|
||||||
check(0 <= dest && dest < pt->sizecode &&
|
|
||||||
pt->code[dest] == SET_OPCODE(i, op-1));
|
|
||||||
checkreg(pt, a + ((op == OP_FORLOOP) ? 2 : 3));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_SETLIST: {
|
case OP_SETLIST: {
|
||||||
@@ -451,8 +412,14 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_CLOSURE: {
|
case OP_CLOSURE: {
|
||||||
|
int nup;
|
||||||
check(b < pt->sizep);
|
check(b < pt->sizep);
|
||||||
checkreg(pt, a + pt->p[b]->nupvalues - 1);
|
nup = pt->p[b]->nups;
|
||||||
|
check(pc + nup < pt->sizecode);
|
||||||
|
for (; nup>0; nup--) {
|
||||||
|
OpCode op1 = GET_OPCODE(pt->code[pc+nup]);
|
||||||
|
check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
@@ -461,6 +428,10 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
|
|||||||
return pt->code[last];
|
return pt->code[last];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef check
|
||||||
|
#undef checkjump
|
||||||
|
#undef checkreg
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
@@ -469,39 +440,48 @@ int luaG_checkcode (const Proto *pt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *getobjname (lua_State *L, StkId obj, const l_char **name) {
|
static const char *kname (Proto *p, int c) {
|
||||||
CallInfo *ci = ci_stack(L, obj);
|
c = c - MAXSTACK;
|
||||||
if (isLmark(ci)) { /* an active Lua function? */
|
if (c >= 0 && ttisstring(&p->k[c]))
|
||||||
Proto *p = ci_func(ci)->f.l;
|
return svalue(&p->k[c]);
|
||||||
|
else
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *getobjname (CallInfo *ci, int stackpos, const char **name) {
|
||||||
|
if (isLua(ci)) { /* a Lua function? */
|
||||||
|
Proto *p = ci_func(ci)->l.p;
|
||||||
int pc = currentpc(ci);
|
int pc = currentpc(ci);
|
||||||
int stackpos = obj - ci->base;
|
|
||||||
Instruction i;
|
Instruction i;
|
||||||
*name = luaF_getlocalname(p, stackpos+1, pc);
|
*name = luaF_getlocalname(p, stackpos+1, pc);
|
||||||
if (*name) /* is a local? */
|
if (*name) /* is a local? */
|
||||||
return l_s("local");
|
return "local";
|
||||||
i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */
|
i = luaG_symbexec(p, pc, stackpos); /* try symbolic execution */
|
||||||
lua_assert(pc != -1);
|
lua_assert(pc != -1);
|
||||||
switch (GET_OPCODE(i)) {
|
switch (GET_OPCODE(i)) {
|
||||||
case OP_GETGLOBAL: {
|
case OP_GETGLOBAL: {
|
||||||
lua_assert(ttype(&p->k[GETARG_Bc(i)]) == LUA_TSTRING);
|
int g = GETARG_Bx(i); /* global index */
|
||||||
*name = svalue(&p->k[GETARG_Bc(i)]);
|
lua_assert(ttisstring(&p->k[g]));
|
||||||
return l_s("global");
|
*name = svalue(&p->k[g]);
|
||||||
|
return "global";
|
||||||
}
|
}
|
||||||
case OP_MOVE: {
|
case OP_MOVE: {
|
||||||
int a = GETARG_A(i);
|
int a = GETARG_A(i);
|
||||||
int b = GETARG_B(i); /* move from `b' to `a' */
|
int b = GETARG_B(i); /* move from `b' to `a' */
|
||||||
if (b < a)
|
if (b < a)
|
||||||
return getobjname(L, ci->base+b, name); /* get name for `b' */
|
return getobjname(ci, b, name); /* get name for `b' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_GETTABLE:
|
case OP_GETTABLE: {
|
||||||
|
int k = GETARG_C(i); /* key index */
|
||||||
|
*name = kname(p, k);
|
||||||
|
return "field";
|
||||||
|
}
|
||||||
case OP_SELF: {
|
case OP_SELF: {
|
||||||
int c = GETARG_C(i) - MAXSTACK;
|
int k = GETARG_C(i); /* key index */
|
||||||
if (c >= 0 && ttype(&p->k[c]) == LUA_TSTRING) {
|
*name = kname(p, k);
|
||||||
*name = svalue(&p->k[c]);
|
return "method";
|
||||||
return l_s("field");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
@@ -510,57 +490,96 @@ static const l_char *getobjname (lua_State *L, StkId obj, const l_char **name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *getfuncname (lua_State *L, CallInfo *ci,
|
static const char *getfuncname (CallInfo *ci, const char **name) {
|
||||||
const l_char **name) {
|
Instruction i;
|
||||||
ci = ci->prev; /* calling function */
|
if ((isLua(ci) && ci->u.l.tailcalls > 0) || !isLua(ci - 1))
|
||||||
if (ci == &L->basefunc || !isLmark(ci))
|
return NULL; /* calling function is not Lua (or is unknown) */
|
||||||
return NULL; /* not an active Lua function */
|
ci--; /* calling function */
|
||||||
else {
|
i = ci_func(ci)->l.p->code[currentpc(ci)];
|
||||||
Proto *p = ci_func(ci)->f.l;
|
if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL)
|
||||||
int pc = currentpc(ci);
|
return getobjname(ci, GETARG_A(i), name);
|
||||||
Instruction i;
|
else
|
||||||
if (pc == -1) return NULL; /* function is not activated */
|
return NULL; /* no useful name can be found */
|
||||||
i = p->code[pc];
|
|
||||||
return (GET_OPCODE(i) == OP_CALL
|
|
||||||
? getobjname(L, ci->base+GETARG_A(i), name)
|
|
||||||
: NULL); /* no useful name found */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaG_typeerror (lua_State *L, StkId o, const l_char *op) {
|
/* only ANSI way to check whether a pointer points to an array */
|
||||||
const l_char *name;
|
static int isinstack (CallInfo *ci, const TObject *o) {
|
||||||
const l_char *kind = getobjname(L, o, &name);
|
StkId p;
|
||||||
const l_char *t = luaT_typename(G(L), o);
|
for (p = ci->base; p < ci->top; p++)
|
||||||
|
if (o == p) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaG_typeerror (lua_State *L, const TObject *o, const char *op) {
|
||||||
|
const char *name = NULL;
|
||||||
|
const char *t = luaT_typenames[ttype(o)];
|
||||||
|
const char *kind = (isinstack(L->ci, o)) ?
|
||||||
|
getobjname(L->ci, o - L->base, &name) : NULL;
|
||||||
if (kind)
|
if (kind)
|
||||||
luaO_verror(L, l_s("attempt to %.30s %.20s `%.40s' (a %.10s value)"),
|
luaG_runerror(L, "attempt to %s %s `%s' (a %s value)",
|
||||||
op, kind, name, t);
|
op, kind, name, t);
|
||||||
else
|
else
|
||||||
luaO_verror(L, l_s("attempt to %.30s a %.10s value"), op, t);
|
luaG_runerror(L, "attempt to %s a %s value", op, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
|
void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
|
||||||
if (ttype(p1) == LUA_TSTRING) p1 = p2;
|
if (ttisstring(p1)) p1 = p2;
|
||||||
lua_assert(ttype(p1) != LUA_TSTRING);
|
lua_assert(!ttisstring(p1));
|
||||||
luaG_typeerror(L, p1, l_s("concat"));
|
luaG_typeerror(L, p1, "concatenate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaG_aritherror (lua_State *L, StkId p1, TObject *p2) {
|
void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2) {
|
||||||
TObject temp;
|
TObject temp;
|
||||||
if (luaV_tonumber(p1, &temp) != NULL)
|
if (luaV_tonumber(p1, &temp) == NULL)
|
||||||
p1 = p2; /* first operand is OK; error is in the second */
|
p2 = p1; /* first operand is wrong */
|
||||||
luaG_typeerror(L, p1, l_s("perform arithmetic on"));
|
luaG_typeerror(L, p2, "perform arithmetic on");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) {
|
int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) {
|
||||||
const l_char *t1 = luaT_typename(G(L), p1);
|
const char *t1 = luaT_typenames[ttype(p1)];
|
||||||
const l_char *t2 = luaT_typename(G(L), p2);
|
const char *t2 = luaT_typenames[ttype(p2)];
|
||||||
if (t1[2] == t2[2])
|
if (t1[2] == t2[2])
|
||||||
luaO_verror(L, l_s("attempt to compare two %.10s values"), t1);
|
luaG_runerror(L, "attempt to compare two %s values", t1);
|
||||||
else
|
else
|
||||||
luaO_verror(L, l_s("attempt to compare %.10s with %.10s"), t1, t2);
|
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void addinfo (lua_State *L, const char *msg) {
|
||||||
|
CallInfo *ci = L->ci;
|
||||||
|
if (isLua(ci)) { /* is Lua code? */
|
||||||
|
char buff[LUA_IDSIZE]; /* add file:line information */
|
||||||
|
int line = currentline(ci);
|
||||||
|
luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE);
|
||||||
|
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaG_errormsg (lua_State *L) {
|
||||||
|
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||||
|
StkId errfunc = restorestack(L, L->errfunc);
|
||||||
|
if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
|
||||||
|
setobjs2s(L->top, L->top - 1); /* move argument */
|
||||||
|
setobjs2s(L->top - 1, errfunc); /* push function */
|
||||||
|
incr_top(L);
|
||||||
|
luaD_call(L, L->top - 2, 1); /* call it */
|
||||||
|
}
|
||||||
|
luaD_throw(L, LUA_ERRRUN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||||
|
va_list argp;
|
||||||
|
va_start(argp, fmt);
|
||||||
|
addinfo(L, luaO_pushvfstring(L, fmt, argp));
|
||||||
|
va_end(argp);
|
||||||
|
luaG_errormsg(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
ldebug.h
20
ldebug.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ldebug.h,v 1.14 2001/06/11 14:56:42 roberto Exp roberto $
|
** $Id: ldebug.h,v 1.31 2002/08/20 20:03:05 roberto Exp roberto $
|
||||||
** Auxiliary functions from Debug Interface module
|
** Auxiliary functions from Debug Interface module
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -9,14 +9,22 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
#include "luadebug.h"
|
|
||||||
|
|
||||||
|
|
||||||
void luaG_typeerror (lua_State *L, StkId o, const l_char *op);
|
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
|
||||||
|
|
||||||
|
#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
|
||||||
|
|
||||||
|
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||||
|
|
||||||
|
|
||||||
|
void luaG_inithooks (lua_State *L);
|
||||||
|
void luaG_typeerror (lua_State *L, const TObject *o, const char *opname);
|
||||||
void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
|
void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
|
||||||
void luaG_aritherror (lua_State *L, StkId p1, TObject *p2);
|
void luaG_aritherror (lua_State *L, const TObject *p1, const TObject *p2);
|
||||||
int luaG_getline (int *lineinfo, int pc, int refline, int *refi);
|
int luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2);
|
||||||
void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2);
|
void luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||||
|
void luaG_errormsg (lua_State *L);
|
||||||
int luaG_checkcode (const Proto *pt);
|
int luaG_checkcode (const Proto *pt);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
632
ldo.c
632
ldo.c
@@ -1,23 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ldo.c,v 1.137 2001/07/12 19:34:03 roberto Exp roberto $
|
** $Id: ldo.c,v 1.216 2003/02/28 19:45:15 roberto Exp roberto $
|
||||||
** Stack and Call structure of Lua
|
** Stack and Call structure of Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define ldo_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "ldebug.h"
|
#include "ldebug.h"
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
|
#include "lfunc.h"
|
||||||
#include "lgc.h"
|
#include "lgc.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
#include "lopcodes.h"
|
||||||
#include "lparser.h"
|
#include "lparser.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
#include "lstring.h"
|
#include "lstring.h"
|
||||||
@@ -28,105 +30,266 @@
|
|||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
|
|
||||||
|
|
||||||
/* space to handle stack overflow errors */
|
|
||||||
#define EXTRA_STACK (2*LUA_MINSTACK)
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** Error-recovery functions (based on long jumps)
|
||||||
|
** =======================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* chain list of long jump buffers */
|
||||||
|
struct lua_longjmp {
|
||||||
|
struct lua_longjmp *previous;
|
||||||
|
jmp_buf b;
|
||||||
|
volatile int status; /* error code */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
|
||||||
|
switch (errcode) {
|
||||||
|
case LUA_ERRMEM: {
|
||||||
|
setsvalue2s(oldtop, luaS_new(L, MEMERRMSG));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_ERRERR: {
|
||||||
|
setsvalue2s(oldtop, luaS_new(L, "error in error handling"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_ERRSYNTAX:
|
||||||
|
case LUA_ERRRUN: {
|
||||||
|
setobjs2s(oldtop, L->top - 1); /* error message on current top */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
L->top = oldtop + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaD_throw (lua_State *L, int errcode) {
|
||||||
|
if (L->errorJmp) {
|
||||||
|
L->errorJmp->status = errcode;
|
||||||
|
longjmp(L->errorJmp->b, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
G(L)->panic(L);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||||
|
struct lua_longjmp lj;
|
||||||
|
lj.status = 0;
|
||||||
|
lj.previous = L->errorJmp; /* chain new error handler */
|
||||||
|
L->errorJmp = &lj;
|
||||||
|
if (setjmp(lj.b) == 0)
|
||||||
|
(*f)(L, ud);
|
||||||
|
L->errorJmp = lj.previous; /* restore old error handler */
|
||||||
|
return lj.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void restore_stack_limit (lua_State *L) {
|
static void restore_stack_limit (lua_State *L) {
|
||||||
StkId limit = L->stack+(L->stacksize-EXTRA_STACK)-1;
|
L->stack_last = L->stack+L->stacksize-1;
|
||||||
if (L->top < limit)
|
if (L->size_ci > LUA_MAXCALLS) { /* there was an overflow? */
|
||||||
L->stack_last = limit;
|
int inuse = (L->ci - L->base_ci);
|
||||||
}
|
if (inuse + 1 < LUA_MAXCALLS) /* can `undo' overflow? */
|
||||||
|
luaD_reallocCI(L, LUA_MAXCALLS);
|
||||||
|
|
||||||
void luaD_init (lua_State *L, int stacksize) {
|
|
||||||
stacksize += EXTRA_STACK;
|
|
||||||
L->stack = luaM_newvector(L, stacksize, TObject);
|
|
||||||
L->stacksize = stacksize;
|
|
||||||
L->basefunc.base = L->top = L->stack;
|
|
||||||
restore_stack_limit(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaD_stackerror (lua_State *L) {
|
|
||||||
if (L->stack_last == L->stack+L->stacksize-1) {
|
|
||||||
/* overflow while handling overflow */
|
|
||||||
luaD_breakrun(L, LUA_ERRERR); /* break run without error message */
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
static void correctstack (lua_State *L, TObject *oldstack) {
|
||||||
|
CallInfo *ci;
|
||||||
|
GCObject *up;
|
||||||
|
L->top = (L->top - oldstack) + L->stack;
|
||||||
|
for (up = L->openupval; up != NULL; up = up->gch.next)
|
||||||
|
gcotouv(up)->v = (gcotouv(up)->v - oldstack) + L->stack;
|
||||||
|
for (ci = L->base_ci; ci <= L->ci; ci++) {
|
||||||
|
ci->top = (ci->top - oldstack) + L->stack;
|
||||||
|
ci->base = (ci->base - oldstack) + L->stack;
|
||||||
|
}
|
||||||
|
L->base = L->ci->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaD_reallocstack (lua_State *L, int newsize) {
|
||||||
|
TObject *oldstack = L->stack;
|
||||||
|
luaM_reallocvector(L, L->stack, L->stacksize, newsize, TObject);
|
||||||
|
L->stacksize = newsize;
|
||||||
|
L->stack_last = L->stack+newsize-1-EXTRA_STACK;
|
||||||
|
correctstack(L, oldstack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaD_reallocCI (lua_State *L, int newsize) {
|
||||||
|
CallInfo *oldci = L->base_ci;
|
||||||
|
luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo);
|
||||||
|
L->size_ci = cast(unsigned short, newsize);
|
||||||
|
L->ci = (L->ci - oldci) + L->base_ci;
|
||||||
|
L->end_ci = L->base_ci + L->size_ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaD_growstack (lua_State *L, int n) {
|
||||||
|
if (n <= L->stacksize) /* double size is enough? */
|
||||||
|
luaD_reallocstack(L, 2*L->stacksize);
|
||||||
|
else
|
||||||
|
luaD_reallocstack(L, L->stacksize + n + EXTRA_STACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void luaD_growCI (lua_State *L) {
|
||||||
|
if (L->size_ci > LUA_MAXCALLS) /* overflow while handling overflow? */
|
||||||
|
luaD_throw(L, LUA_ERRERR);
|
||||||
else {
|
else {
|
||||||
L->stack_last += EXTRA_STACK; /* to be used by error message */
|
luaD_reallocCI(L, 2*L->size_ci);
|
||||||
lua_assert(L->stack_last == L->stack+L->stacksize-1);
|
if (L->size_ci > LUA_MAXCALLS)
|
||||||
luaD_error(L, l_s("stack overflow"));
|
luaG_runerror(L, "stack overflow");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
void luaD_callhook (lua_State *L, int event, int line) {
|
||||||
** adjust top to new value; assume that new top is valid
|
lua_Hook hook = L->hook;
|
||||||
*/
|
if (hook && L->allowhook) {
|
||||||
void luaD_adjusttop (lua_State *L, StkId newtop) {
|
ptrdiff_t top = savestack(L, L->top);
|
||||||
while (L->top < newtop)
|
ptrdiff_t ci_top = savestack(L, L->ci->top);
|
||||||
setnilvalue(L->top++);
|
|
||||||
L->top = newtop; /* `newtop' could be lower than `top' */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Open a hole inside the stack at `pos'
|
|
||||||
*/
|
|
||||||
static void luaD_openstack (lua_State *L, StkId pos) {
|
|
||||||
int i = L->top-pos;
|
|
||||||
while (i--) setobj(pos+i+1, pos+i);
|
|
||||||
incr_top;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) {
|
|
||||||
StkId old_top = L->top;
|
|
||||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
|
||||||
L->allowhooks = 0; /* cannot call hooks inside a hook */
|
|
||||||
lua_unlock(L);
|
|
||||||
(*hook)(L, ar);
|
|
||||||
lua_lock(L);
|
|
||||||
lua_assert(L->allowhooks == 0);
|
|
||||||
L->allowhooks = 1;
|
|
||||||
L->top = old_top;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaD_lineHook (lua_State *L, int line, lua_Hook linehook) {
|
|
||||||
if (L->allowhooks) {
|
|
||||||
lua_Debug ar;
|
|
||||||
ar.event = l_s("line");
|
|
||||||
ar._ci = L->ci;
|
|
||||||
ar.currentline = line;
|
|
||||||
dohook(L, &ar, linehook);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void luaD_callHook (lua_State *L, lua_Hook callhook,
|
|
||||||
const l_char *event) {
|
|
||||||
if (L->allowhooks) {
|
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
ar.event = event;
|
ar.event = event;
|
||||||
ar._ci = L->ci;
|
ar.currentline = line;
|
||||||
L->ci->pc = NULL; /* function is not active */
|
if (event == LUA_HOOKTAILRET)
|
||||||
dohook(L, &ar, callhook);
|
ar.i_ci = 0; /* tail call; no debug information about it */
|
||||||
|
else
|
||||||
|
ar.i_ci = L->ci - L->base_ci;
|
||||||
|
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||||
|
L->ci->top = L->top + LUA_MINSTACK;
|
||||||
|
L->allowhook = 0; /* cannot call hooks inside a hook */
|
||||||
|
lua_unlock(L);
|
||||||
|
(*hook)(L, &ar);
|
||||||
|
lua_lock(L);
|
||||||
|
lua_assert(!L->allowhook);
|
||||||
|
L->allowhook = 1;
|
||||||
|
L->ci->top = restorestack(L, ci_top);
|
||||||
|
L->top = restorestack(L, top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static StkId callCclosure (lua_State *L, const struct Closure *cl) {
|
static void adjust_varargs (lua_State *L, int nfixargs, StkId base) {
|
||||||
int nup = cl->nupvalues; /* number of upvalues */
|
int i;
|
||||||
int n;
|
Table *htab;
|
||||||
luaD_checkstack(L, nup+LUA_MINSTACK); /* ensure minimum stack size */
|
TObject nname;
|
||||||
for (n=0; n<nup; n++) /* copy upvalues as extra arguments */
|
int actual = L->top - base; /* actual number of arguments */
|
||||||
setobj(L->top++, &cl->upvalue[n]);
|
if (actual < nfixargs) {
|
||||||
lua_unlock(L);
|
luaD_checkstack(L, nfixargs - actual);
|
||||||
n = (*cl->f.c)(L); /* do the actual call */
|
for (; actual < nfixargs; ++actual)
|
||||||
lua_lock(L);
|
setnilvalue(L->top++);
|
||||||
return L->top - n; /* return index of first result */
|
}
|
||||||
|
actual -= nfixargs; /* number of extra arguments */
|
||||||
|
htab = luaH_new(L, actual, 1); /* create `arg' table */
|
||||||
|
for (i=0; i<actual; i++) /* put extra arguments into `arg' table */
|
||||||
|
setobj2n(luaH_setnum(L, htab, i+1), L->top - actual + i);
|
||||||
|
/* store counter in field `n' */
|
||||||
|
setsvalue(&nname, luaS_newliteral(L, "n"));
|
||||||
|
setnvalue(luaH_set(L, htab, &nname), cast(lua_Number, actual));
|
||||||
|
L->top -= actual; /* remove extra elements from the stack */
|
||||||
|
sethvalue(L->top, htab);
|
||||||
|
incr_top(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static StkId tryfuncTM (lua_State *L, StkId func) {
|
||||||
|
const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL);
|
||||||
|
StkId p;
|
||||||
|
ptrdiff_t funcr = savestack(L, func);
|
||||||
|
if (!ttisfunction(tm))
|
||||||
|
luaG_typeerror(L, func, "call");
|
||||||
|
/* Open a hole inside the stack at `func' */
|
||||||
|
for (p = L->top; p > func; p--) setobjs2s(p, p-1);
|
||||||
|
incr_top(L);
|
||||||
|
func = restorestack(L, funcr); /* previous call may change stack */
|
||||||
|
setobj2s(func, tm); /* tag method is the new function to be called */
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StkId luaD_precall (lua_State *L, StkId func) {
|
||||||
|
LClosure *cl;
|
||||||
|
ptrdiff_t funcr = savestack(L, func);
|
||||||
|
if (!ttisfunction(func)) /* `func' is not a function? */
|
||||||
|
func = tryfuncTM(L, func); /* check the `function' tag method */
|
||||||
|
if (L->ci + 1 == L->end_ci) luaD_growCI(L);
|
||||||
|
else condhardstacktests(luaD_reallocCI(L, L->size_ci));
|
||||||
|
cl = &clvalue(func)->l;
|
||||||
|
if (!cl->isC) { /* Lua function? prepare its call */
|
||||||
|
CallInfo *ci;
|
||||||
|
Proto *p = cl->p;
|
||||||
|
if (p->is_vararg) /* varargs? */
|
||||||
|
adjust_varargs(L, p->numparams, func+1);
|
||||||
|
luaD_checkstack(L, p->maxstacksize);
|
||||||
|
ci = ++L->ci; /* now `enter' new function */
|
||||||
|
L->base = L->ci->base = restorestack(L, funcr) + 1;
|
||||||
|
ci->top = L->base + p->maxstacksize;
|
||||||
|
ci->u.l.savedpc = p->code; /* starting point */
|
||||||
|
ci->u.l.tailcalls = 0;
|
||||||
|
ci->state = CI_SAVEDPC;
|
||||||
|
while (L->top < ci->top)
|
||||||
|
setnilvalue(L->top++);
|
||||||
|
L->top = ci->top;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else { /* if is a C function, call it */
|
||||||
|
CallInfo *ci;
|
||||||
|
int n;
|
||||||
|
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||||
|
ci = ++L->ci; /* now `enter' new function */
|
||||||
|
L->base = L->ci->base = restorestack(L, funcr) + 1;
|
||||||
|
ci->top = L->top + LUA_MINSTACK;
|
||||||
|
ci->state = CI_C; /* a C function */
|
||||||
|
if (L->hookmask & LUA_MASKCALL)
|
||||||
|
luaD_callhook(L, LUA_HOOKCALL, -1);
|
||||||
|
lua_unlock(L);
|
||||||
|
#ifdef LUA_COMPATUPVALUES
|
||||||
|
lua_pushupvalues(L);
|
||||||
|
#endif
|
||||||
|
n = (*clvalue(L->base - 1)->c.f)(L); /* do the actual call */
|
||||||
|
lua_lock(L);
|
||||||
|
return L->top - n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static StkId callrethooks (lua_State *L, StkId firstResult) {
|
||||||
|
ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
|
||||||
|
luaD_callhook(L, LUA_HOOKRET, -1);
|
||||||
|
if (!(L->ci->state & CI_C)) { /* Lua function? */
|
||||||
|
while (L->ci->u.l.tailcalls--) /* call hook for eventual tail calls */
|
||||||
|
luaD_callhook(L, LUA_HOOKTAILRET, -1);
|
||||||
|
}
|
||||||
|
return restorestack(L, fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
|
||||||
|
StkId res;
|
||||||
|
if (L->hookmask & LUA_MASKRET)
|
||||||
|
firstResult = callrethooks(L, firstResult);
|
||||||
|
res = L->base - 1; /* res == final position of 1st result */
|
||||||
|
L->ci--;
|
||||||
|
L->base = L->ci->base; /* restore base */
|
||||||
|
/* move results to correct place */
|
||||||
|
while (wanted != 0 && firstResult < L->top) {
|
||||||
|
setobjs2s(res++, firstResult++);
|
||||||
|
wanted--;
|
||||||
|
}
|
||||||
|
while (wanted-- > 0)
|
||||||
|
setnilvalue(res++);
|
||||||
|
L->top = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,213 +299,160 @@ static StkId callCclosure (lua_State *L, const struct Closure *cl) {
|
|||||||
** When returns, all the results are on the stack, starting at the original
|
** When returns, all the results are on the stack, starting at the original
|
||||||
** function position.
|
** function position.
|
||||||
*/
|
*/
|
||||||
void luaD_call (lua_State *L, StkId func) {
|
void luaD_call (lua_State *L, StkId func, int nResults) {
|
||||||
lua_Hook callhook;
|
|
||||||
StkId firstResult;
|
StkId firstResult;
|
||||||
CallInfo ci;
|
lua_assert(!(L->ci->state & CI_CALLING));
|
||||||
if (ttype(func) != LUA_TFUNCTION) {
|
if (++L->nCcalls >= LUA_MAXCCALLS) {
|
||||||
/* `func' is not a function; check the `function' tag method */
|
if (L->nCcalls == LUA_MAXCCALLS)
|
||||||
Closure *tm = luaT_gettmbyObj(G(L), func, TM_FUNCTION);
|
luaG_runerror(L, "C stack overflow");
|
||||||
if (tm == NULL)
|
else if (L->nCcalls >= (LUA_MAXCCALLS + (LUA_MAXCCALLS>>3)))
|
||||||
luaG_typeerror(L, func, l_s("call"));
|
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
||||||
luaD_openstack(L, func);
|
|
||||||
setclvalue(func, tm); /* tag method is the new function to be called */
|
|
||||||
}
|
}
|
||||||
ci.prev = L->ci; /* chain new callinfo */
|
firstResult = luaD_precall(L, func);
|
||||||
L->ci = &ci;
|
if (firstResult == NULL) /* is a Lua function? */
|
||||||
ci.base = func+1;
|
firstResult = luaV_execute(L); /* call it */
|
||||||
callhook = L->callhook;
|
luaD_poscall(L, nResults, firstResult);
|
||||||
if (callhook)
|
L->nCcalls--;
|
||||||
luaD_callHook(L, callhook, l_s("call"));
|
|
||||||
firstResult = (clvalue(func)->isC ? callCclosure(L, clvalue(func)) :
|
|
||||||
luaV_execute(L, clvalue(func), func+1));
|
|
||||||
if (callhook) /* same hook that was active at entry */
|
|
||||||
luaD_callHook(L, callhook, l_s("return"));
|
|
||||||
L->ci = ci.prev; /* unchain callinfo */
|
|
||||||
/* move results to `func' (to erase parameters and function) */
|
|
||||||
while (firstResult < L->top)
|
|
||||||
setobj(func++, firstResult++);
|
|
||||||
L->top = func;
|
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
static void resume (lua_State *L, void *ud) {
|
||||||
** Execute a protected call.
|
StkId firstResult;
|
||||||
*/
|
int nargs = *cast(int *, ud);
|
||||||
struct CallS { /* data to `f_call' */
|
CallInfo *ci = L->ci;
|
||||||
StkId func;
|
if (ci == L->base_ci) { /* no activation record? */
|
||||||
int nresults;
|
if (nargs >= L->top - L->base)
|
||||||
};
|
luaG_runerror(L, "cannot resume dead coroutine");
|
||||||
|
luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */
|
||||||
static void f_call (lua_State *L, void *ud) {
|
}
|
||||||
struct CallS *c = (struct CallS *)ud;
|
else if (ci->state & CI_YIELD) { /* inside a yield? */
|
||||||
luaD_call(L, c->func);
|
if (ci->state & CI_C) { /* `common' yield? */
|
||||||
if (c->nresults != LUA_MULTRET)
|
/* finish interrupted execution of `OP_CALL' */
|
||||||
luaD_adjusttop(L, c->func + c->nresults);
|
int nresults;
|
||||||
|
lua_assert((ci-1)->state & CI_SAVEDPC);
|
||||||
|
lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL ||
|
||||||
|
GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL);
|
||||||
|
nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1;
|
||||||
|
luaD_poscall(L, nresults, L->top - nargs); /* complete it */
|
||||||
|
if (nresults >= 0) L->top = L->ci->top;
|
||||||
|
}
|
||||||
|
else { /* yielded inside a hook: just continue its execution */
|
||||||
|
ci->state &= ~CI_YIELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
luaG_runerror(L, "cannot resume non-suspended coroutine");
|
||||||
|
firstResult = luaV_execute(L);
|
||||||
|
if (firstResult != NULL) /* return? */
|
||||||
|
luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_call (lua_State *L, int nargs, int nresults) {
|
LUA_API int lua_resume (lua_State *L, int nargs) {
|
||||||
StkId func;
|
|
||||||
struct CallS c;
|
|
||||||
int status;
|
int status;
|
||||||
|
lu_byte old_allowhooks;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
func = L->top - (nargs+1); /* function to be called */
|
old_allowhooks = L->allowhook;
|
||||||
c.func = func; c.nresults = nresults;
|
lua_assert(L->errfunc == 0 && L->nCcalls == 0);
|
||||||
status = luaD_runprotected(L, f_call, &c);
|
status = luaD_rawrunprotected(L, resume, &nargs);
|
||||||
if (status != 0) /* an error occurred? */
|
if (status != 0) { /* error? */
|
||||||
L->top = func; /* remove parameters from the stack */
|
L->ci = L->base_ci; /* go back to initial level */
|
||||||
|
L->base = L->ci->base;
|
||||||
|
L->nCcalls = 0;
|
||||||
|
luaF_close(L, L->base); /* close eventual pending closures */
|
||||||
|
seterrorobj(L, status, L->base);
|
||||||
|
L->allowhook = old_allowhooks;
|
||||||
|
restore_stack_limit(L);
|
||||||
|
}
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API int lua_yield (lua_State *L, int nresults) {
|
||||||
|
CallInfo *ci;
|
||||||
|
lua_lock(L);
|
||||||
|
ci = L->ci;
|
||||||
|
if (L->nCcalls > 0)
|
||||||
|
luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
|
||||||
|
if (ci->state & CI_C) { /* usual yield */
|
||||||
|
if ((ci-1)->state & CI_C)
|
||||||
|
luaG_runerror(L, "cannot yield a C function");
|
||||||
|
if (L->top - nresults > L->base) { /* is there garbage in the stack? */
|
||||||
|
int i;
|
||||||
|
for (i=0; i<nresults; i++) /* move down results */
|
||||||
|
setobjs2s(L->base + i, L->top - nresults + i);
|
||||||
|
L->top = L->base + nresults;
|
||||||
|
}
|
||||||
|
} /* else it's an yield inside a hook: nothing to do */
|
||||||
|
ci->state |= CI_YIELD;
|
||||||
|
lua_unlock(L);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||||
|
ptrdiff_t old_top, ptrdiff_t ef) {
|
||||||
|
int status;
|
||||||
|
unsigned short oldnCcalls = L->nCcalls;
|
||||||
|
ptrdiff_t old_ci = saveci(L, L->ci);
|
||||||
|
lu_byte old_allowhooks = L->allowhook;
|
||||||
|
ptrdiff_t old_errfunc = L->errfunc;
|
||||||
|
L->errfunc = ef;
|
||||||
|
status = luaD_rawrunprotected(L, func, u);
|
||||||
|
if (status != 0) { /* an error occurred? */
|
||||||
|
StkId oldtop = restorestack(L, old_top);
|
||||||
|
luaF_close(L, oldtop); /* close eventual pending closures */
|
||||||
|
seterrorobj(L, status, oldtop);
|
||||||
|
L->nCcalls = oldnCcalls;
|
||||||
|
L->ci = restoreci(L, old_ci);
|
||||||
|
L->base = L->ci->base;
|
||||||
|
L->allowhook = old_allowhooks;
|
||||||
|
restore_stack_limit(L);
|
||||||
|
}
|
||||||
|
L->errfunc = old_errfunc;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Execute a protected parser.
|
** Execute a protected parser.
|
||||||
*/
|
*/
|
||||||
struct SParser { /* data to `f_parser' */
|
struct SParser { /* data to `f_parser' */
|
||||||
ZIO *z;
|
ZIO *z;
|
||||||
|
Mbuffer buff; /* buffer to be used by the scanner */
|
||||||
int bin;
|
int bin;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void f_parser (lua_State *L, void *ud) {
|
static void f_parser (lua_State *L, void *ud) {
|
||||||
struct SParser *p = (struct SParser *)ud;
|
struct SParser *p;
|
||||||
Proto *tf = p->bin ? luaU_undump(L, p->z) : luaY_parser(L, p->z);
|
Proto *tf;
|
||||||
luaV_Lclosure(L, tf, 0);
|
Closure *cl;
|
||||||
|
luaC_checkGC(L);
|
||||||
|
p = cast(struct SParser *, ud);
|
||||||
|
tf = p->bin ? luaU_undump(L, p->z, &p->buff) : luaY_parser(L, p->z, &p->buff);
|
||||||
|
cl = luaF_newLclosure(L, 0, gt(L));
|
||||||
|
cl->l.p = tf;
|
||||||
|
setclvalue(L->top, cl);
|
||||||
|
incr_top(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int protectedparser (lua_State *L, ZIO *z, int bin) {
|
int luaD_protectedparser (lua_State *L, ZIO *z, int bin) {
|
||||||
struct SParser p;
|
struct SParser p;
|
||||||
lu_mem old_blocks;
|
|
||||||
int status;
|
int status;
|
||||||
lua_lock(L);
|
ptrdiff_t oldtopr = savestack(L, L->top); /* save current top */
|
||||||
p.z = z; p.bin = bin;
|
p.z = z; p.bin = bin;
|
||||||
/* before parsing, give a (good) chance to GC */
|
luaZ_initbuffer(L, &p.buff);
|
||||||
if (G(L)->nblocks/8 >= G(L)->GCthreshold/10)
|
status = luaD_rawrunprotected(L, f_parser, &p);
|
||||||
luaC_collectgarbage(L);
|
luaZ_freebuffer(L, &p.buff);
|
||||||
old_blocks = G(L)->nblocks;
|
if (status != 0) { /* error? */
|
||||||
status = luaD_runprotected(L, f_parser, &p);
|
StkId oldtop = restorestack(L, oldtopr);
|
||||||
if (status == 0) {
|
seterrorobj(L, status, oldtop);
|
||||||
/* add new memory to threshold (as it probably will stay) */
|
|
||||||
lua_assert(G(L)->nblocks >= old_blocks);
|
|
||||||
G(L)->GCthreshold += (G(L)->nblocks - old_blocks);
|
|
||||||
}
|
}
|
||||||
else if (status == LUA_ERRRUN) /* an error occurred: correct error code */
|
|
||||||
status = LUA_ERRSYNTAX;
|
|
||||||
lua_unlock(L);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_loadfile (lua_State *L, const l_char *filename) {
|
|
||||||
ZIO z;
|
|
||||||
int status;
|
|
||||||
int bin; /* flag for file mode */
|
|
||||||
int nlevel; /* level on the stack of filename */
|
|
||||||
FILE *f = (filename == NULL) ? stdin : fopen(filename, l_s("r"));
|
|
||||||
if (f == NULL) return LUA_ERRFILE; /* unable to open file */
|
|
||||||
bin = (ungetc(getc(f), f) == LUA_SIGNATURE[0]);
|
|
||||||
if (bin && f != stdin) {
|
|
||||||
fclose(f);
|
|
||||||
f = fopen(filename, l_s("rb")); /* reopen in binary mode */
|
|
||||||
if (f == NULL) return LUA_ERRFILE; /* unable to reopen file */
|
|
||||||
}
|
|
||||||
lua_pushliteral(L, l_s("@"));
|
|
||||||
lua_pushstring(L, (filename == NULL) ? l_s("(stdin)") : filename);
|
|
||||||
lua_concat(L, 2);
|
|
||||||
nlevel = lua_gettop(L);
|
|
||||||
filename = lua_tostring(L, -1); /* filename = `@'..filename */
|
|
||||||
luaZ_Fopen(&z, f, filename);
|
|
||||||
status = protectedparser(L, &z, bin);
|
|
||||||
lua_remove(L, nlevel); /* remove filename */
|
|
||||||
if (f != stdin)
|
|
||||||
fclose(f);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_loadbuffer (lua_State *L, const l_char *buff, size_t size,
|
|
||||||
const l_char *name) {
|
|
||||||
ZIO z;
|
|
||||||
int status;
|
|
||||||
if (!name) name = l_s("?");
|
|
||||||
luaZ_mopen(&z, buff, size, name);
|
|
||||||
status = protectedparser(L, &z, buff[0]==LUA_SIGNATURE[0]);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** {======================================================
|
|
||||||
** Error-recover functions (based on long jumps)
|
|
||||||
** =======================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* chain list of long jump buffers */
|
|
||||||
struct lua_longjmp {
|
|
||||||
jmp_buf b;
|
|
||||||
struct lua_longjmp *previous;
|
|
||||||
volatile int status; /* error code */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void message (lua_State *L, const l_char *s) {
|
|
||||||
StkId top = L->top;
|
|
||||||
luaV_getglobal(L, luaS_newliteral(L, l_s(LUA_ERRORMESSAGE)), top);
|
|
||||||
if (ttype(top) == LUA_TFUNCTION) {
|
|
||||||
incr_top;
|
|
||||||
setsvalue(top+1, luaS_new(L, s));
|
|
||||||
incr_top;
|
|
||||||
luaD_call(L, top);
|
|
||||||
L->top = top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Reports an error, and jumps up to the available recovery label
|
|
||||||
*/
|
|
||||||
void luaD_error (lua_State *L, const l_char *s) {
|
|
||||||
if (s) message(L, s);
|
|
||||||
luaD_breakrun(L, LUA_ERRRUN);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaD_breakrun (lua_State *L, int errcode) {
|
|
||||||
if (L->errorJmp) {
|
|
||||||
L->errorJmp->status = errcode;
|
|
||||||
longjmp(L->errorJmp->b, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (errcode != LUA_ERRMEM)
|
|
||||||
message(L, l_s("unable to recover; exiting\n"));
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud) {
|
|
||||||
CallInfo *oldci = L->ci;
|
|
||||||
StkId oldtop = L->top;
|
|
||||||
struct lua_longjmp lj;
|
|
||||||
int allowhooks = L->allowhooks;
|
|
||||||
lj.status = 0;
|
|
||||||
lj.previous = L->errorJmp; /* chain new error handler */
|
|
||||||
L->errorJmp = &lj;
|
|
||||||
if (setjmp(lj.b) == 0)
|
|
||||||
(*f)(L, ud);
|
|
||||||
else { /* an error occurred: restore the state */
|
|
||||||
L->allowhooks = allowhooks;
|
|
||||||
L->ci = oldci;
|
|
||||||
L->top = oldtop;
|
|
||||||
restore_stack_limit(L);
|
|
||||||
}
|
|
||||||
L->errorJmp = lj.previous; /* restore old error handler */
|
|
||||||
return lj.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* }====================================================== */
|
|
||||||
|
|
||||||
|
|||||||
50
ldo.h
50
ldo.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ldo.h,v 1.33 2001/06/05 19:41:24 roberto Exp roberto $
|
** $Id: ldo.h,v 1.55 2002/11/21 17:41:25 roberto Exp roberto $
|
||||||
** Stack and Call structure of Lua
|
** Stack and Call structure of Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -10,27 +10,51 @@
|
|||||||
|
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
#include "lzio.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** macro to increment stack top.
|
** macro to control inclusion of some hard tests on stack reallocation
|
||||||
** There must be always an empty slot at the L->stack.top
|
|
||||||
*/
|
*/
|
||||||
#define incr_top {if (L->top == L->stack_last) luaD_checkstack(L, 1); L->top++;}
|
#ifndef HARDSTACKTESTS
|
||||||
|
#define condhardstacktests(x) { /* empty */ }
|
||||||
|
#else
|
||||||
|
#define condhardstacktests(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define luaD_checkstack(L,n) if (L->stack_last-(n)<=L->top) luaD_stackerror(L)
|
#define luaD_checkstack(L,n) \
|
||||||
|
if ((char *)L->stack_last - (char *)L->top <= (n)*(int)sizeof(TObject)) \
|
||||||
|
luaD_growstack(L, n); \
|
||||||
|
else condhardstacktests(luaD_reallocstack(L, L->stacksize));
|
||||||
|
|
||||||
|
|
||||||
void luaD_init (lua_State *L, int stacksize);
|
#define incr_top(L) {luaD_checkstack(L,1); L->top++;}
|
||||||
void luaD_adjusttop (lua_State *L, StkId newtop);
|
|
||||||
void luaD_lineHook (lua_State *L, int line, lua_Hook linehook);
|
|
||||||
void luaD_call (lua_State *L, StkId func);
|
|
||||||
void luaD_stackerror (lua_State *L);
|
|
||||||
|
|
||||||
void luaD_error (lua_State *L, const l_char *s);
|
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
|
||||||
void luaD_breakrun (lua_State *L, int errcode);
|
#define restorestack(L,n) ((TObject *)((char *)L->stack + (n)))
|
||||||
int luaD_runprotected (lua_State *L, void (*f)(lua_State *, void *), void *ud);
|
|
||||||
|
#define saveci(L,p) ((char *)(p) - (char *)L->base_ci)
|
||||||
|
#define restoreci(L,n) ((CallInfo *)((char *)L->base_ci + (n)))
|
||||||
|
|
||||||
|
|
||||||
|
/* type of protected functions, to be ran by `runprotected' */
|
||||||
|
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||||
|
|
||||||
|
void luaD_resetprotection (lua_State *L);
|
||||||
|
int luaD_protectedparser (lua_State *L, ZIO *z, int bin);
|
||||||
|
void luaD_callhook (lua_State *L, int event, int line);
|
||||||
|
StkId luaD_precall (lua_State *L, StkId func);
|
||||||
|
void luaD_call (lua_State *L, StkId func, int nResults);
|
||||||
|
int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||||
|
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||||
|
void luaD_poscall (lua_State *L, int wanted, StkId firstResult);
|
||||||
|
void luaD_reallocCI (lua_State *L, int newsize);
|
||||||
|
void luaD_reallocstack (lua_State *L, int newsize);
|
||||||
|
void luaD_growstack (lua_State *L, int n);
|
||||||
|
|
||||||
|
void luaD_throw (lua_State *L, int errcode);
|
||||||
|
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
170
ldump.c
Normal file
170
ldump.c
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
** $Id: ldump.c,v 1.4 2003/02/11 23:52:12 lhf Exp $
|
||||||
|
** save bytecodes
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define ldump_c
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lobject.h"
|
||||||
|
#include "lopcodes.h"
|
||||||
|
#include "lstate.h"
|
||||||
|
#include "lundump.h"
|
||||||
|
|
||||||
|
#define DumpVector(b,n,size,D) DumpBlock(b,(n)*(size),D)
|
||||||
|
#define DumpLiteral(s,D) DumpBlock("" s,(sizeof(s))-1,D)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lua_State* L;
|
||||||
|
lua_Chunkwriter write;
|
||||||
|
void* data;
|
||||||
|
} DumpState;
|
||||||
|
|
||||||
|
static void DumpBlock(const void* b, size_t size, DumpState* D)
|
||||||
|
{
|
||||||
|
lua_unlock(D->L);
|
||||||
|
(*D->write)(D->L,b,size,D->data);
|
||||||
|
lua_lock(D->L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpByte(int y, DumpState* D)
|
||||||
|
{
|
||||||
|
char x=(char)y;
|
||||||
|
DumpBlock(&x,sizeof(x),D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpInt(int x, DumpState* D)
|
||||||
|
{
|
||||||
|
DumpBlock(&x,sizeof(x),D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpSize(size_t x, DumpState* D)
|
||||||
|
{
|
||||||
|
DumpBlock(&x,sizeof(x),D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpNumber(lua_Number x, DumpState* D)
|
||||||
|
{
|
||||||
|
DumpBlock(&x,sizeof(x),D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpString(TString* s, DumpState* D)
|
||||||
|
{
|
||||||
|
if (s==NULL || getstr(s)==NULL)
|
||||||
|
DumpSize(0,D);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t size=s->tsv.len+1; /* include trailing '\0' */
|
||||||
|
DumpSize(size,D);
|
||||||
|
DumpBlock(getstr(s),size,D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpCode(const Proto* f, DumpState* D)
|
||||||
|
{
|
||||||
|
DumpInt(f->sizecode,D);
|
||||||
|
DumpVector(f->code,f->sizecode,sizeof(*f->code),D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpLocals(const Proto* f, DumpState* D)
|
||||||
|
{
|
||||||
|
int i,n=f->sizelocvars;
|
||||||
|
DumpInt(n,D);
|
||||||
|
for (i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
DumpString(f->locvars[i].varname,D);
|
||||||
|
DumpInt(f->locvars[i].startpc,D);
|
||||||
|
DumpInt(f->locvars[i].endpc,D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpLines(const Proto* f, DumpState* D)
|
||||||
|
{
|
||||||
|
DumpInt(f->sizelineinfo,D);
|
||||||
|
DumpVector(f->lineinfo,f->sizelineinfo,sizeof(*f->lineinfo),D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpUpvalues(const Proto* f, DumpState* D)
|
||||||
|
{
|
||||||
|
int i,n=f->sizeupvalues;
|
||||||
|
DumpInt(n,D);
|
||||||
|
for (i=0; i<n; i++) DumpString(f->upvalues[i],D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpFunction(const Proto* f, const TString* p, DumpState* D);
|
||||||
|
|
||||||
|
static void DumpConstants(const Proto* f, DumpState* D)
|
||||||
|
{
|
||||||
|
int i,n;
|
||||||
|
DumpInt(n=f->sizek,D);
|
||||||
|
for (i=0; i<n; i++)
|
||||||
|
{
|
||||||
|
const TObject* o=&f->k[i];
|
||||||
|
DumpByte(ttype(o),D);
|
||||||
|
switch (ttype(o))
|
||||||
|
{
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
DumpNumber(nvalue(o),D);
|
||||||
|
break;
|
||||||
|
case LUA_TSTRING:
|
||||||
|
DumpString(tsvalue(o),D);
|
||||||
|
break;
|
||||||
|
case LUA_TNIL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lua_assert(0); /* cannot happen */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DumpInt(n=f->sizep,D);
|
||||||
|
for (i=0; i<n; i++) DumpFunction(f->p[i],f->source,D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpFunction(const Proto* f, const TString* p, DumpState* D)
|
||||||
|
{
|
||||||
|
DumpString((f->source==p) ? NULL : f->source,D);
|
||||||
|
DumpInt(f->lineDefined,D);
|
||||||
|
DumpByte(f->nups,D);
|
||||||
|
DumpByte(f->numparams,D);
|
||||||
|
DumpByte(f->is_vararg,D);
|
||||||
|
DumpByte(f->maxstacksize,D);
|
||||||
|
DumpLines(f,D);
|
||||||
|
DumpLocals(f,D);
|
||||||
|
DumpUpvalues(f,D);
|
||||||
|
DumpConstants(f,D);
|
||||||
|
DumpCode(f,D);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DumpHeader(DumpState* D)
|
||||||
|
{
|
||||||
|
DumpLiteral(LUA_SIGNATURE,D);
|
||||||
|
DumpByte(VERSION,D);
|
||||||
|
DumpByte(luaU_endianness(),D);
|
||||||
|
DumpByte(sizeof(int),D);
|
||||||
|
DumpByte(sizeof(size_t),D);
|
||||||
|
DumpByte(sizeof(Instruction),D);
|
||||||
|
DumpByte(SIZE_OP,D);
|
||||||
|
DumpByte(SIZE_A,D);
|
||||||
|
DumpByte(SIZE_B,D);
|
||||||
|
DumpByte(SIZE_C,D);
|
||||||
|
DumpByte(sizeof(lua_Number),D);
|
||||||
|
DumpNumber(TEST_NUMBER,D);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** dump function as precompiled chunk
|
||||||
|
*/
|
||||||
|
void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data)
|
||||||
|
{
|
||||||
|
DumpState D;
|
||||||
|
D.L=L;
|
||||||
|
D.write=w;
|
||||||
|
D.data=data;
|
||||||
|
DumpHeader(&D);
|
||||||
|
DumpFunction(Main,NULL,&D);
|
||||||
|
}
|
||||||
|
|
||||||
87
lfunc.c
87
lfunc.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lfunc.c,v 1.44 2001/06/05 18:17:01 roberto Exp roberto $
|
** $Id: lfunc.c,v 1.66 2003/02/11 10:46:24 roberto Exp roberto $
|
||||||
** Auxiliary functions to manipulate prototypes and closures
|
** Auxiliary functions to manipulate prototypes and closures
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -7,64 +7,113 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lfunc_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lfunc.h"
|
#include "lfunc.h"
|
||||||
|
#include "lgc.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
|
||||||
|
|
||||||
#define sizeclosure(n) ((int)sizeof(Closure) + (int)sizeof(TObject)*((n)-1))
|
#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
|
||||||
|
cast(int, sizeof(TObject)*((n)-1)))
|
||||||
|
|
||||||
|
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
|
||||||
|
cast(int, sizeof(TObject *)*((n)-1)))
|
||||||
|
|
||||||
|
|
||||||
Closure *luaF_newclosure (lua_State *L, int nelems) {
|
|
||||||
Closure *c = (Closure *)luaM_malloc(L, sizeclosure(nelems));
|
Closure *luaF_newCclosure (lua_State *L, int nelems) {
|
||||||
c->next = G(L)->rootcl;
|
Closure *c = cast(Closure *, luaM_malloc(L, sizeCclosure(nelems)));
|
||||||
G(L)->rootcl = c;
|
luaC_link(L, valtogco(c), LUA_TFUNCTION);
|
||||||
c->mark = c;
|
c->c.isC = 1;
|
||||||
c->nupvalues = nelems;
|
c->c.nupvalues = cast(lu_byte, nelems);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e) {
|
||||||
|
Closure *c = cast(Closure *, luaM_malloc(L, sizeLclosure(nelems)));
|
||||||
|
luaC_link(L, valtogco(c), LUA_TFUNCTION);
|
||||||
|
c->l.isC = 0;
|
||||||
|
c->l.g = *e;
|
||||||
|
c->l.nupvalues = cast(lu_byte, nelems);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||||
|
GCObject **pp = &L->openupval;
|
||||||
|
UpVal *p;
|
||||||
|
UpVal *v;
|
||||||
|
while ((p = ngcotouv(*pp)) != NULL && p->v >= level) {
|
||||||
|
if (p->v == level) return p;
|
||||||
|
pp = &p->next;
|
||||||
|
}
|
||||||
|
v = luaM_new(L, UpVal); /* not found: create a new one */
|
||||||
|
v->tt = LUA_TUPVAL;
|
||||||
|
v->marked = 1; /* open upvalues should not be collected */
|
||||||
|
v->v = level; /* current value lives in the stack */
|
||||||
|
v->next = *pp; /* chain it in the proper position */
|
||||||
|
*pp = valtogco(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaF_close (lua_State *L, StkId level) {
|
||||||
|
UpVal *p;
|
||||||
|
while ((p = ngcotouv(L->openupval)) != NULL && p->v >= level) {
|
||||||
|
setobj(&p->value, p->v); /* save current value (write barrier) */
|
||||||
|
p->v = &p->value; /* now current value lives here */
|
||||||
|
L->openupval = p->next; /* remove from `open' list */
|
||||||
|
luaC_link(L, valtogco(p), LUA_TUPVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Proto *luaF_newproto (lua_State *L) {
|
Proto *luaF_newproto (lua_State *L) {
|
||||||
Proto *f = luaM_new(L, Proto);
|
Proto *f = luaM_new(L, Proto);
|
||||||
|
luaC_link(L, valtogco(f), LUA_TPROTO);
|
||||||
f->k = NULL;
|
f->k = NULL;
|
||||||
f->sizek = 0;
|
f->sizek = 0;
|
||||||
f->p = NULL;
|
f->p = NULL;
|
||||||
f->sizep = 0;
|
f->sizep = 0;
|
||||||
f->code = NULL;
|
f->code = NULL;
|
||||||
f->sizecode = 0;
|
f->sizecode = 0;
|
||||||
f->nupvalues = 0;
|
f->sizelineinfo = 0;
|
||||||
|
f->sizeupvalues = 0;
|
||||||
|
f->nups = 0;
|
||||||
|
f->upvalues = NULL;
|
||||||
f->numparams = 0;
|
f->numparams = 0;
|
||||||
f->is_vararg = 0;
|
f->is_vararg = 0;
|
||||||
f->maxstacksize = 0;
|
f->maxstacksize = 0;
|
||||||
f->marked = 0;
|
|
||||||
f->lineinfo = NULL;
|
f->lineinfo = NULL;
|
||||||
f->sizelocvars = 0;
|
f->sizelocvars = 0;
|
||||||
f->sizelineinfo = 0;
|
|
||||||
f->locvars = NULL;
|
f->locvars = NULL;
|
||||||
f->lineDefined = 0;
|
f->lineDefined = 0;
|
||||||
f->source = NULL;
|
f->source = NULL;
|
||||||
f->next = G(L)->rootproto; /* chain in list of protos */
|
|
||||||
G(L)->rootproto = f;
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaF_freeproto (lua_State *L, Proto *f) {
|
void luaF_freeproto (lua_State *L, Proto *f) {
|
||||||
luaM_freearray(L, f->code, f->sizecode, Instruction);
|
luaM_freearray(L, f->code, f->sizecode, Instruction);
|
||||||
luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
|
|
||||||
luaM_freearray(L, f->k, f->sizek, TObject);
|
|
||||||
luaM_freearray(L, f->p, f->sizep, Proto *);
|
luaM_freearray(L, f->p, f->sizep, Proto *);
|
||||||
|
luaM_freearray(L, f->k, f->sizek, TObject);
|
||||||
luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
|
luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
|
||||||
luaM_freelem(L, f, Proto);
|
luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
|
||||||
|
luaM_freearray(L, f->upvalues, f->sizeupvalues, TString *);
|
||||||
|
luaM_freelem(L, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaF_freeclosure (lua_State *L, Closure *c) {
|
void luaF_freeclosure (lua_State *L, Closure *c) {
|
||||||
luaM_free(L, c, sizeclosure(c->nupvalues));
|
int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) :
|
||||||
|
sizeLclosure(c->l.nupvalues);
|
||||||
|
luaM_free(L, c, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +121,7 @@ void luaF_freeclosure (lua_State *L, Closure *c) {
|
|||||||
** Look for n-th local variable at line `line' in function `func'.
|
** Look for n-th local variable at line `line' in function `func'.
|
||||||
** Returns NULL if not found.
|
** Returns NULL if not found.
|
||||||
*/
|
*/
|
||||||
const l_char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
|
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
|
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
|
||||||
if (pc < f->locvars[i].endpc) { /* is variable active? */
|
if (pc < f->locvars[i].endpc) { /* is variable active? */
|
||||||
|
|||||||
10
lfunc.h
10
lfunc.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lfunc.h,v 1.14 2000/12/28 12:55:41 roberto Exp roberto $
|
** $Id: lfunc.h,v 1.20 2002/06/20 20:41:46 roberto Exp roberto $
|
||||||
** Auxiliary functions to manipulate prototypes and closures
|
** Auxiliary functions to manipulate prototypes and closures
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -11,13 +11,15 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Proto *luaF_newproto (lua_State *L);
|
Proto *luaF_newproto (lua_State *L);
|
||||||
Closure *luaF_newclosure (lua_State *L, int nelems);
|
Closure *luaF_newCclosure (lua_State *L, int nelems);
|
||||||
|
Closure *luaF_newLclosure (lua_State *L, int nelems, TObject *e);
|
||||||
|
UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||||
|
void luaF_close (lua_State *L, StkId level);
|
||||||
void luaF_freeproto (lua_State *L, Proto *f);
|
void luaF_freeproto (lua_State *L, Proto *f);
|
||||||
void luaF_freeclosure (lua_State *L, Closure *c);
|
void luaF_freeclosure (lua_State *L, Closure *c);
|
||||||
|
|
||||||
const l_char *luaF_getlocalname (const Proto *func, int local_number, int pc);
|
const char *luaF_getlocalname (const Proto *func, int local_number, int pc);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
695
lgc.c
695
lgc.c
@@ -1,12 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lgc.c,v 1.108 2001/06/26 13:20:45 roberto Exp roberto $
|
** $Id: lgc.c,v 1.170 2003/03/18 12:50:04 roberto Exp roberto $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#include <string.h>
|
||||||
|
|
||||||
|
#define lgc_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldebug.h"
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
#include "lfunc.h"
|
#include "lfunc.h"
|
||||||
#include "lgc.h"
|
#include "lgc.h"
|
||||||
@@ -18,369 +22,472 @@
|
|||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct GCState {
|
typedef struct GCState {
|
||||||
Hash *tmark; /* list of marked tables to be visited */
|
GCObject *tmark; /* list of marked objects to be traversed */
|
||||||
Closure *cmark; /* list of marked closures to be visited */
|
GCObject *wk; /* list of traversed key-weak tables (to be cleared) */
|
||||||
|
GCObject *wv; /* list of traversed value-weak tables */
|
||||||
|
GCObject *wkv; /* list of traversed key-value weak tables */
|
||||||
|
global_State *g;
|
||||||
} GCState;
|
} GCState;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** some userful bit tricks
|
||||||
|
*/
|
||||||
|
#define setbit(x,b) ((x) |= (1<<(b)))
|
||||||
|
#define resetbit(x,b) ((x) &= cast(lu_byte, ~(1<<(b))))
|
||||||
|
#define testbit(x,b) ((x) & (1<<(b)))
|
||||||
|
|
||||||
/* mark a string; marks larger than 1 cannot be changed */
|
#define unmark(x) resetbit((x)->gch.marked, 0)
|
||||||
#define strmark(s) {if ((s)->tsv.marked == 0) (s)->tsv.marked = 1;}
|
#define ismarked(x) ((x)->gch.marked & ((1<<4)|1))
|
||||||
|
|
||||||
|
#define stringmark(s) setbit((s)->tsv.marked, 0)
|
||||||
|
|
||||||
|
|
||||||
|
#define isfinalized(u) (!testbit((u)->uv.marked, 1))
|
||||||
|
#define markfinalized(u) resetbit((u)->uv.marked, 1)
|
||||||
|
|
||||||
|
|
||||||
|
#define KEYWEAKBIT 1
|
||||||
|
#define VALUEWEAKBIT 2
|
||||||
|
#define KEYWEAK (1<<KEYWEAKBIT)
|
||||||
|
#define VALUEWEAK (1<<VALUEWEAKBIT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void protomark (Proto *f) {
|
#define markobject(st,o) { checkconsistency(o); \
|
||||||
if (!f->marked) {
|
if (iscollectable(o) && !ismarked(gcvalue(o))) reallymarkobject(st,gcvalue(o)); }
|
||||||
int i;
|
|
||||||
f->marked = 1;
|
#define condmarkobject(st,o,c) { checkconsistency(o); \
|
||||||
strmark(f->source);
|
if (iscollectable(o) && !ismarked(gcvalue(o)) && (c)) \
|
||||||
for (i=0; i<f->sizek; i++) {
|
reallymarkobject(st,gcvalue(o)); }
|
||||||
if (ttype(f->k+i) == LUA_TSTRING)
|
|
||||||
strmark(tsvalue(f->k+i));
|
#define markvalue(st,t) { if (!ismarked(valtogco(t))) \
|
||||||
|
reallymarkobject(st, valtogco(t)); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void reallymarkobject (GCState *st, GCObject *o) {
|
||||||
|
lua_assert(!ismarked(o));
|
||||||
|
setbit(o->gch.marked, 0); /* mark object */
|
||||||
|
switch (o->gch.tt) {
|
||||||
|
case LUA_TUSERDATA: {
|
||||||
|
markvalue(st, gcotou(o)->uv.metatable);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
for (i=0; i<f->sizep; i++)
|
case LUA_TFUNCTION: {
|
||||||
protomark(f->p[i]);
|
gcotocl(o)->c.gclist = st->tmark;
|
||||||
for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */
|
st->tmark = o;
|
||||||
strmark(f->locvars[i].varname);
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void markclosure (GCState *st, Closure *cl) {
|
|
||||||
if (!ismarked(cl)) {
|
|
||||||
if (!cl->isC) {
|
|
||||||
lua_assert(cl->nupvalues == cl->f.l->nupvalues);
|
|
||||||
protomark(cl->f.l);
|
|
||||||
}
|
}
|
||||||
cl->mark = st->cmark; /* chain it for later traversal */
|
|
||||||
st->cmark = cl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void marktable (GCState *st, Hash *h) {
|
|
||||||
if (!ismarked(h)) {
|
|
||||||
h->mark = st->tmark; /* chain it for later traversal */
|
|
||||||
st->tmark = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void markobject (GCState *st, TObject *o) {
|
|
||||||
switch (ttype(o)) {
|
|
||||||
case LUA_TSTRING:
|
|
||||||
strmark(tsvalue(o));
|
|
||||||
break;
|
|
||||||
case LUA_TUSERDATA:
|
|
||||||
if (!ismarkedudata(uvalue(o)))
|
|
||||||
switchudatamark(uvalue(o));
|
|
||||||
break;
|
|
||||||
case LUA_TFUNCTION:
|
|
||||||
markclosure(st, clvalue(o));
|
|
||||||
break;
|
|
||||||
case LUA_TTABLE: {
|
case LUA_TTABLE: {
|
||||||
marktable(st, hvalue(o));
|
gcotoh(o)->gclist = st->tmark;
|
||||||
|
st->tmark = o;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break; /* numbers, etc */
|
case LUA_TTHREAD: {
|
||||||
|
gcototh(o)->gclist = st->tmark;
|
||||||
|
st->tmark = o;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TPROTO: {
|
||||||
|
gcotop(o)->gclist = st->tmark;
|
||||||
|
st->tmark = o;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: lua_assert(o->gch.tt == LUA_TSTRING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void markstacks (lua_State *L, GCState *st) {
|
static void marktmu (GCState *st) {
|
||||||
lua_State *L1 = L;
|
GCObject *u;
|
||||||
do { /* for each thread */
|
for (u = st->g->tmudata; u; u = u->gch.next) {
|
||||||
StkId o, lim;
|
unmark(u); /* may be marked, if left from previous GC */
|
||||||
marktable(st, L1->gt); /* mark table of globals */
|
reallymarkobject(st, u);
|
||||||
for (o=L1->stack; o<L1->top; o++)
|
}
|
||||||
markobject(st, o);
|
|
||||||
lim = (L1->stack_last - L1->ci->base > MAXSTACK) ? L1->ci->base+MAXSTACK
|
|
||||||
: L1->stack_last;
|
|
||||||
for (; o<=lim; o++) setnilvalue(o);
|
|
||||||
lua_assert(L1->previous->next == L1 && L1->next->previous == L1);
|
|
||||||
L1 = L1->next;
|
|
||||||
} while (L1 != L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void marktagmethods (global_State *G, GCState *st) {
|
/* move `dead' udata that need finalization to list `tmudata' */
|
||||||
int t;
|
void luaC_separateudata (lua_State *L) {
|
||||||
for (t=0; t<G->ntag; t++) {
|
GCObject **p = &G(L)->rootudata;
|
||||||
struct TM *tm = &G->TMtable[t];
|
GCObject *curr;
|
||||||
int e;
|
GCObject *collected = NULL; /* to collect udata with gc event */
|
||||||
if (tm->name) strmark(tm->name);
|
GCObject **lastcollected = &collected;
|
||||||
for (e=0; e<TM_N; e++) {
|
while ((curr = *p) != NULL) {
|
||||||
Closure *cl = tm->method[e];
|
lua_assert(curr->gch.tt == LUA_TUSERDATA);
|
||||||
if (cl) markclosure(st, cl);
|
if (ismarked(curr) || isfinalized(gcotou(curr)))
|
||||||
|
p = &curr->gch.next; /* don't bother with them */
|
||||||
|
|
||||||
|
else if (fasttm(L, gcotou(curr)->uv.metatable, TM_GC) == NULL) {
|
||||||
|
markfinalized(gcotou(curr)); /* don't need finalization */
|
||||||
|
p = &curr->gch.next;
|
||||||
|
}
|
||||||
|
else { /* must call its gc method */
|
||||||
|
*p = curr->gch.next;
|
||||||
|
curr->gch.next = NULL; /* link `curr' at the end of `collected' list */
|
||||||
|
*lastcollected = curr;
|
||||||
|
lastcollected = &curr->gch.next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
/* insert collected udata with gc event into `tmudata' list */
|
||||||
|
*lastcollected = G(L)->tmudata;
|
||||||
|
G(L)->tmudata = collected;
|
||||||
static void traverseclosure (GCState *st, Closure *f) {
|
|
||||||
int i;
|
|
||||||
for (i=0; i<f->nupvalues; i++) /* mark its upvalues */
|
|
||||||
markobject(st, &f->upvalue[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void removekey (Node *n) {
|
static void removekey (Node *n) {
|
||||||
lua_assert(ttype(val(n)) == LUA_TNIL);
|
setnilvalue(gval(n)); /* remove corresponding value ... */
|
||||||
if (ttype(key(n)) != LUA_TNIL && ttype(key(n)) != LUA_TNUMBER)
|
if (iscollectable(gkey(n)))
|
||||||
setttype(key(n), LUA_TNONE); /* dead key; remove it */
|
setttype(gkey(n), LUA_TNONE); /* dead key; remove it */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void traversetable (GCState *st, Hash *h) {
|
static void traversetable (GCState *st, Table *h) {
|
||||||
int i;
|
int i;
|
||||||
int mode = h->weakmode;
|
int weakkey = 0;
|
||||||
if (mode == (LUA_WEAK_KEY | LUA_WEAK_VALUE))
|
int weakvalue = 0;
|
||||||
return; /* avoid traversing if both keys and values are weak */
|
const TObject *mode;
|
||||||
for (i=0; i<h->size; i++) {
|
markvalue(st, h->metatable);
|
||||||
Node *n = node(h, i);
|
lua_assert(h->lsizenode || h->node == st->g->dummynode);
|
||||||
if (ttype(val(n)) == LUA_TNIL)
|
mode = gfasttm(st->g, h->metatable, TM_MODE);
|
||||||
removekey(n);
|
if (mode && ttisstring(mode)) { /* is there a weak mode? */
|
||||||
else {
|
weakkey = (strchr(svalue(mode), 'k') != NULL);
|
||||||
lua_assert(ttype(key(n)) != LUA_TNIL);
|
weakvalue = (strchr(svalue(mode), 'v') != NULL);
|
||||||
if (ttype(key(n)) != LUA_TNUMBER && !(mode & LUA_WEAK_KEY))
|
if (weakkey || weakvalue) { /* is really weak? */
|
||||||
markobject(st, key(n));
|
GCObject **weaklist;
|
||||||
if (!(mode & LUA_WEAK_VALUE))
|
h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
|
||||||
markobject(st, val(n));
|
h->marked |= cast(lu_byte, (weakkey << KEYWEAKBIT) |
|
||||||
|
(weakvalue << VALUEWEAKBIT));
|
||||||
|
weaklist = (weakkey && weakvalue) ? &st->wkv :
|
||||||
|
(weakkey) ? &st->wk :
|
||||||
|
&st->wv;
|
||||||
|
h->gclist = *weaklist; /* must be cleared after GC, ... */
|
||||||
|
*weaklist = valtogco(h); /* ... so put in the appropriate list */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!weakvalue) {
|
||||||
|
i = h->sizearray;
|
||||||
|
while (i--)
|
||||||
|
markobject(st, &h->array[i]);
|
||||||
|
}
|
||||||
|
i = sizenode(h);
|
||||||
|
while (i--) {
|
||||||
|
Node *n = gnode(h, i);
|
||||||
|
if (!ttisnil(gval(n))) {
|
||||||
|
lua_assert(!ttisnil(gkey(n)));
|
||||||
|
condmarkobject(st, gkey(n), !weakkey);
|
||||||
|
condmarkobject(st, gval(n), !weakvalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void markall (lua_State *L) {
|
static void traverseproto (GCState *st, Proto *f) {
|
||||||
GCState st;
|
|
||||||
st.cmark = NULL;
|
|
||||||
st.tmark = NULL;
|
|
||||||
marktagmethods(G(L), &st); /* mark tag methods */
|
|
||||||
markstacks(L, &st); /* mark all stacks */
|
|
||||||
marktable(&st, G(L)->type2tag);
|
|
||||||
marktable(&st, G(L)->registry);
|
|
||||||
marktable(&st, G(L)->weakregistry);
|
|
||||||
for (;;) { /* mark tables and closures */
|
|
||||||
if (st.cmark) {
|
|
||||||
Closure *f = st.cmark; /* get first closure from list */
|
|
||||||
st.cmark = f->mark; /* remove it from list */
|
|
||||||
traverseclosure(&st, f);
|
|
||||||
}
|
|
||||||
else if (st.tmark) {
|
|
||||||
Hash *h = st.tmark; /* get first table from list */
|
|
||||||
st.tmark = h->mark; /* remove it from list */
|
|
||||||
traversetable(&st, h);
|
|
||||||
}
|
|
||||||
else break; /* nothing else to mark */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int hasmark (const TObject *o) {
|
|
||||||
switch (ttype(o)) {
|
|
||||||
case LUA_TSTRING:
|
|
||||||
return tsvalue(o)->tsv.marked;
|
|
||||||
case LUA_TUSERDATA:
|
|
||||||
return ismarkedudata(uvalue(o));
|
|
||||||
case LUA_TTABLE:
|
|
||||||
return ismarked(hvalue(o));
|
|
||||||
case LUA_TFUNCTION:
|
|
||||||
return ismarked(clvalue(o));
|
|
||||||
default: /* number, nil */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void cleardeadnodes (Hash *h) {
|
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<h->size; i++) {
|
stringmark(f->source);
|
||||||
Node *n = node(h, i);
|
for (i=0; i<f->sizek; i++) { /* mark literal strings */
|
||||||
if (ttype(val(n)) == LUA_TNIL) continue; /* empty node */
|
if (ttisstring(f->k+i))
|
||||||
if (!hasmark(val(n)) || !hasmark(key(n))) {
|
stringmark(tsvalue(f->k+i));
|
||||||
setnilvalue(val(n)); /* remove value */
|
|
||||||
removekey(n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for (i=0; i<f->sizeupvalues; i++) /* mark upvalue names */
|
||||||
|
stringmark(f->upvalues[i]);
|
||||||
|
for (i=0; i<f->sizep; i++) /* mark nested protos */
|
||||||
|
markvalue(st, f->p[i]);
|
||||||
|
for (i=0; i<f->sizelocvars; i++) /* mark local-variable names */
|
||||||
|
stringmark(f->locvars[i].varname);
|
||||||
|
lua_assert(luaG_checkcode(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void cleartables (global_State *G) {
|
|
||||||
Hash *h;
|
static void traverseclosure (GCState *st, Closure *cl) {
|
||||||
for (h = G->roottable; h; h = h->next) {
|
if (cl->c.isC) {
|
||||||
if (h->weakmode && ismarked(h))
|
int i;
|
||||||
cleardeadnodes(h);
|
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */
|
||||||
|
markobject(st, &cl->c.upvalue[i]);
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
int i;
|
||||||
|
lua_assert(cl->l.nupvalues == cl->l.p->nups);
|
||||||
static void collectproto (lua_State *L) {
|
markvalue(st, hvalue(&cl->l.g));
|
||||||
Proto **p = &G(L)->rootproto;
|
markvalue(st, cl->l.p);
|
||||||
Proto *curr;
|
for (i=0; i<cl->l.nupvalues; i++) { /* mark its upvalues */
|
||||||
while ((curr = *p) != NULL) {
|
UpVal *u = cl->l.upvals[i];
|
||||||
if (curr->marked) {
|
if (!u->marked) {
|
||||||
curr->marked = 0;
|
markobject(st, &u->value);
|
||||||
p = &curr->next;
|
u->marked = 1;
|
||||||
}
|
|
||||||
else {
|
|
||||||
*p = curr->next;
|
|
||||||
luaF_freeproto(L, curr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void collectclosure (lua_State *L) {
|
|
||||||
Closure **p = &G(L)->rootcl;
|
|
||||||
Closure *curr;
|
|
||||||
while ((curr = *p) != NULL) {
|
|
||||||
if (ismarked(curr)) {
|
|
||||||
curr->mark = curr; /* unmark */
|
|
||||||
p = &curr->next;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*p = curr->next;
|
|
||||||
luaF_freeclosure(L, curr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void collecttable (lua_State *L) {
|
|
||||||
Hash **p = &G(L)->roottable;
|
|
||||||
Hash *curr;
|
|
||||||
while ((curr = *p) != NULL) {
|
|
||||||
if (ismarked(curr)) {
|
|
||||||
curr->mark = curr; /* unmark */
|
|
||||||
p = &curr->next;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
*p = curr->next;
|
|
||||||
luaH_free(L, curr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void collectudata (lua_State *L, int keep) {
|
|
||||||
Udata **p = &G(L)->rootudata;
|
|
||||||
Udata *curr;
|
|
||||||
while ((curr = *p) != NULL) {
|
|
||||||
if (ismarkedudata(curr)) {
|
|
||||||
switchudatamark(curr); /* unmark */
|
|
||||||
p = &curr->uv.next;
|
|
||||||
}
|
|
||||||
else { /* collect */
|
|
||||||
int tag = curr->uv.tag;
|
|
||||||
*p = curr->uv.next;
|
|
||||||
if (keep || /* must keep all of them (to close state)? */
|
|
||||||
luaT_gettm(G(L), tag, TM_GC)) { /* or is there a GC tag method? */
|
|
||||||
curr->uv.next = G(L)->TMtable[tag].collected; /* chain udata ... */
|
|
||||||
G(L)->TMtable[tag].collected = curr; /* ... to call its TM later */
|
|
||||||
}
|
}
|
||||||
else /* no tag method; delete udata */
|
|
||||||
luaM_free(L, curr, sizeudata(curr->uv.len));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void collectstrings (lua_State *L, int all) {
|
static void checkstacksizes (lua_State *L, StkId max) {
|
||||||
|
int used = L->ci - L->base_ci; /* number of `ci' in use */
|
||||||
|
if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
|
||||||
|
luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
|
||||||
|
else condhardstacktests(luaD_reallocCI(L, L->size_ci));
|
||||||
|
used = max - L->stack; /* part of stack in use */
|
||||||
|
if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
|
||||||
|
luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
|
||||||
|
else condhardstacktests(luaD_reallocstack(L, L->stacksize));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void traversestack (GCState *st, lua_State *L1) {
|
||||||
|
StkId o, lim;
|
||||||
|
CallInfo *ci;
|
||||||
|
markobject(st, gt(L1));
|
||||||
|
lim = L1->top;
|
||||||
|
for (ci = L1->base_ci; ci <= L1->ci; ci++) {
|
||||||
|
lua_assert(ci->top <= L1->stack_last);
|
||||||
|
lua_assert(ci->state & (CI_C | CI_HASFRAME | CI_SAVEDPC));
|
||||||
|
if (!(ci->state & CI_C) && lim < ci->top)
|
||||||
|
lim = ci->top;
|
||||||
|
}
|
||||||
|
for (o = L1->stack; o < L1->top; o++)
|
||||||
|
markobject(st, o);
|
||||||
|
for (; o <= lim; o++)
|
||||||
|
setnilvalue(o);
|
||||||
|
checkstacksizes(L1, lim);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void propagatemarks (GCState *st) {
|
||||||
|
while (st->tmark) { /* traverse marked objects */
|
||||||
|
switch (st->tmark->gch.tt) {
|
||||||
|
case LUA_TTABLE: {
|
||||||
|
Table *h = gcotoh(st->tmark);
|
||||||
|
st->tmark = h->gclist;
|
||||||
|
traversetable(st, h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TFUNCTION: {
|
||||||
|
Closure *cl = gcotocl(st->tmark);
|
||||||
|
st->tmark = cl->c.gclist;
|
||||||
|
traverseclosure(st, cl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TTHREAD: {
|
||||||
|
lua_State *th = gcototh(st->tmark);
|
||||||
|
st->tmark = th->gclist;
|
||||||
|
traversestack(st, th);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TPROTO: {
|
||||||
|
Proto *p = gcotop(st->tmark);
|
||||||
|
st->tmark = p->gclist;
|
||||||
|
traverseproto(st, p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: lua_assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int valismarked (const TObject *o) {
|
||||||
|
if (ttisstring(o))
|
||||||
|
stringmark(tsvalue(o)); /* strings are `values', so are never weak */
|
||||||
|
return !iscollectable(o) || testbit(o->value.gc->gch.marked, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** clear collected keys from weaktables
|
||||||
|
*/
|
||||||
|
static void cleartablekeys (GCObject *l) {
|
||||||
|
while (l) {
|
||||||
|
Table *h = gcotoh(l);
|
||||||
|
int i = sizenode(h);
|
||||||
|
lua_assert(h->marked & KEYWEAK);
|
||||||
|
while (i--) {
|
||||||
|
Node *n = gnode(h, i);
|
||||||
|
if (!valismarked(gkey(n))) /* key was collected? */
|
||||||
|
removekey(n); /* remove entry from table */
|
||||||
|
}
|
||||||
|
l = h->gclist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** clear collected values from weaktables
|
||||||
|
*/
|
||||||
|
static void cleartablevalues (GCObject *l) {
|
||||||
|
while (l) {
|
||||||
|
Table *h = gcotoh(l);
|
||||||
|
int i = h->sizearray;
|
||||||
|
lua_assert(h->marked & VALUEWEAK);
|
||||||
|
while (i--) {
|
||||||
|
TObject *o = &h->array[i];
|
||||||
|
if (!valismarked(o)) /* value was collected? */
|
||||||
|
setnilvalue(o); /* remove value */
|
||||||
|
}
|
||||||
|
i = sizenode(h);
|
||||||
|
while (i--) {
|
||||||
|
Node *n = gnode(h, i);
|
||||||
|
if (!valismarked(gval(n))) /* value was collected? */
|
||||||
|
removekey(n); /* remove entry from table */
|
||||||
|
}
|
||||||
|
l = h->gclist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void freeobj (lua_State *L, GCObject *o) {
|
||||||
|
switch (o->gch.tt) {
|
||||||
|
case LUA_TPROTO: luaF_freeproto(L, gcotop(o)); break;
|
||||||
|
case LUA_TFUNCTION: luaF_freeclosure(L, gcotocl(o)); break;
|
||||||
|
case LUA_TUPVAL: luaM_freelem(L, gcotouv(o)); break;
|
||||||
|
case LUA_TTABLE: luaH_free(L, gcotoh(o)); break;
|
||||||
|
case LUA_TTHREAD: {
|
||||||
|
lua_assert(gcototh(o) != L && gcototh(o) != G(L)->mainthread);
|
||||||
|
luaE_freethread(L, gcototh(o));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TSTRING: {
|
||||||
|
luaM_free(L, o, sizestring(gcotots(o)->tsv.len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LUA_TUSERDATA: {
|
||||||
|
luaM_free(L, o, sizeudata(gcotou(o)->uv.len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: lua_assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int sweeplist (lua_State *L, GCObject **p, int limit) {
|
||||||
|
GCObject *curr;
|
||||||
|
int count = 0; /* number of collected items */
|
||||||
|
while ((curr = *p) != NULL) {
|
||||||
|
if (curr->gch.marked > limit) {
|
||||||
|
unmark(curr);
|
||||||
|
p = &curr->gch.next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
count++;
|
||||||
|
*p = curr->gch.next;
|
||||||
|
freeobj(L, curr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sweepstrings (lua_State *L, int all) {
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<G(L)->strt.size; i++) { /* for each list */
|
for (i=0; i<G(L)->strt.size; i++) { /* for each list */
|
||||||
TString **p = &G(L)->strt.hash[i];
|
G(L)->strt.nuse -= sweeplist(L, &G(L)->strt.hash[i], all);
|
||||||
TString *curr;
|
|
||||||
while ((curr = *p) != NULL) {
|
|
||||||
if (curr->tsv.marked && !all) { /* preserve? */
|
|
||||||
if (curr->tsv.marked < FIXMARK) /* does not change FIXMARKs */
|
|
||||||
curr->tsv.marked = 0;
|
|
||||||
p = &curr->tsv.nexthash;
|
|
||||||
}
|
|
||||||
else { /* collect */
|
|
||||||
*p = curr->tsv.nexthash;
|
|
||||||
G(L)->strt.nuse--;
|
|
||||||
luaM_free(L, curr, sizestring(curr->tsv.len));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (G(L)->strt.nuse < (ls_nstr)(G(L)->strt.size/4) &&
|
}
|
||||||
G(L)->strt.size > MINPOWER2)
|
|
||||||
|
|
||||||
|
static void checkSizes (lua_State *L) {
|
||||||
|
/* check size of string hash */
|
||||||
|
if (G(L)->strt.nuse < cast(ls_nstr, G(L)->strt.size/4) &&
|
||||||
|
G(L)->strt.size > MINSTRTABSIZE*2)
|
||||||
luaS_resize(L, G(L)->strt.size/2); /* table is too big */
|
luaS_resize(L, G(L)->strt.size/2); /* table is too big */
|
||||||
}
|
/* check size of buffer */
|
||||||
|
if (luaZ_sizebuffer(&G(L)->buff) > LUA_MINBUFFER*2) { /* buffer too big? */
|
||||||
|
size_t newsize = luaZ_sizebuffer(&G(L)->buff) / 2;
|
||||||
|
luaZ_resizebuffer(L, &G(L)->buff, newsize);
|
||||||
#define MINBUFFER 256
|
|
||||||
static void checkMbuffer (lua_State *L) {
|
|
||||||
if (G(L)->Mbuffsize > MINBUFFER*2) { /* is buffer too big? */
|
|
||||||
size_t newsize = G(L)->Mbuffsize/2; /* still larger than MINBUFFER */
|
|
||||||
luaM_reallocvector(L, G(L)->Mbuffer, G(L)->Mbuffsize, newsize, l_char);
|
|
||||||
G(L)->Mbuffsize = newsize;
|
|
||||||
}
|
}
|
||||||
|
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void callgcTM (lua_State *L, const TObject *obj) {
|
static void do1gcTM (lua_State *L, Udata *udata) {
|
||||||
Closure *tm = luaT_gettmbyObj(G(L), obj, TM_GC);
|
const TObject *tm = fasttm(L, udata->uv.metatable, TM_GC);
|
||||||
if (tm != NULL) {
|
if (tm != NULL) {
|
||||||
int oldah = L->allowhooks;
|
setobj2s(L->top, tm);
|
||||||
StkId top = L->top;
|
setuvalue(L->top+1, udata);
|
||||||
L->allowhooks = 0; /* stop debug hooks during GC tag methods */
|
|
||||||
setclvalue(top, tm);
|
|
||||||
setobj(top+1, obj);
|
|
||||||
L->top += 2;
|
L->top += 2;
|
||||||
luaD_call(L, top);
|
luaD_call(L, L->top - 2, 0);
|
||||||
L->top = top; /* restore top */
|
|
||||||
L->allowhooks = oldah; /* restore hooks */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void callgcTMudata (lua_State *L) {
|
void luaC_callGCTM (lua_State *L) {
|
||||||
int tag;
|
lu_byte oldah = L->allowhook;
|
||||||
luaD_checkstack(L, 3);
|
L->allowhook = 0; /* stop debug hooks during GC tag methods */
|
||||||
for (tag=G(L)->ntag-1; tag>=0; tag--) { /* for each tag (in reverse order) */
|
L->top++; /* reserve space to keep udata while runs its gc method */
|
||||||
Udata *udata;
|
while (G(L)->tmudata != NULL) {
|
||||||
while ((udata = G(L)->TMtable[tag].collected) != NULL) {
|
GCObject *o = G(L)->tmudata;
|
||||||
G(L)->TMtable[tag].collected = udata->uv.next; /* remove it from list */
|
Udata *udata = gcotou(o);
|
||||||
udata->uv.next = G(L)->rootudata; /* resurect it */
|
G(L)->tmudata = udata->uv.next; /* remove udata from `tmudata' */
|
||||||
G(L)->rootudata = udata;
|
udata->uv.next = G(L)->rootudata; /* return it to `root' list */
|
||||||
setuvalue(L->top, udata);
|
G(L)->rootudata = o;
|
||||||
L->top++; /* keep it in stack to avoid being (recursively) collected */
|
setuvalue(L->top - 1, udata); /* keep a reference to it */
|
||||||
callgcTM(L, L->top-1);
|
unmark(o);
|
||||||
uvalue(L->top-1)->uv.tag = 0; /* default tag (udata is `finalized') */
|
markfinalized(udata);
|
||||||
L->top--;
|
do1gcTM(L, udata);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
L->top--;
|
||||||
|
L->allowhook = oldah; /* restore hooks */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaC_callallgcTM (lua_State *L) {
|
void luaC_sweep (lua_State *L, int all) {
|
||||||
if (G(L)->rootudata) { /* avoid problems with incomplete states */
|
if (all) all = 256; /* larger than any mark */
|
||||||
collectudata(L, 1); /* collect all udata into tag lists */
|
sweeplist(L, &G(L)->rootudata, all);
|
||||||
callgcTMudata(L); /* call their GC tag methods */
|
sweepstrings(L, all);
|
||||||
}
|
sweeplist(L, &G(L)->rootgc, all);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaC_collect (lua_State *L, int all) {
|
/* mark root set */
|
||||||
collectudata(L, 0);
|
static void markroot (GCState *st, lua_State *L) {
|
||||||
collectstrings(L, all);
|
global_State *g = st->g;
|
||||||
collecttable(L);
|
markobject(st, defaultmeta(L));
|
||||||
collectproto(L);
|
markobject(st, registry(L));
|
||||||
collectclosure(L);
|
traversestack(st, g->mainthread);
|
||||||
|
if (L != g->mainthread) /* another thread is running? */
|
||||||
|
markvalue(st, L); /* cannot collect it */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void mark (lua_State *L) {
|
||||||
|
GCState st;
|
||||||
|
GCObject *wkv;
|
||||||
|
st.g = G(L);
|
||||||
|
st.tmark = NULL;
|
||||||
|
st.wkv = st.wk = st.wv = NULL;
|
||||||
|
markroot(&st, L);
|
||||||
|
propagatemarks(&st); /* mark all reachable objects */
|
||||||
|
cleartablevalues(st.wkv);
|
||||||
|
cleartablevalues(st.wv);
|
||||||
|
wkv = st.wkv; /* keys must be cleared after preserving udata */
|
||||||
|
st.wkv = NULL;
|
||||||
|
st.wv = NULL;
|
||||||
|
luaC_separateudata(L); /* separate userdata to be preserved */
|
||||||
|
marktmu(&st); /* mark `preserved' userdata */
|
||||||
|
propagatemarks(&st); /* remark, to propagate `preserveness' */
|
||||||
|
cleartablekeys(wkv);
|
||||||
|
/* `propagatemarks' may resuscitate some weak tables; clear them too */
|
||||||
|
cleartablekeys(st.wk);
|
||||||
|
cleartablevalues(st.wv);
|
||||||
|
cleartablekeys(st.wkv);
|
||||||
|
cleartablevalues(st.wkv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaC_collectgarbage (lua_State *L) {
|
void luaC_collectgarbage (lua_State *L) {
|
||||||
markall(L);
|
mark(L);
|
||||||
cleartables(G(L));
|
luaC_sweep(L, 0);
|
||||||
luaC_collect(L, 0);
|
checkSizes(L);
|
||||||
checkMbuffer(L);
|
luaC_callGCTM(L);
|
||||||
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
|
}
|
||||||
callgcTMudata(L);
|
|
||||||
callgcTM(L, &luaO_nilobject);
|
|
||||||
|
void luaC_link (lua_State *L, GCObject *o, lu_byte tt) {
|
||||||
|
o->gch.next = G(L)->rootgc;
|
||||||
|
G(L)->rootgc = o;
|
||||||
|
o->gch.marked = 0;
|
||||||
|
o->gch.tt = tt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
lgc.h
12
lgc.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lgc.h,v 1.11 2001/06/12 18:43:13 roberto Exp roberto $
|
** $Id: lgc.h,v 1.18 2003/02/10 17:32:50 roberto Exp roberto $
|
||||||
** Garbage Collector
|
** Garbage Collector
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -11,13 +11,15 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
#define luaC_checkGC(L) if (G(L)->nblocks >= G(L)->GCthreshold) \
|
#define luaC_checkGC(L) { lua_assert(!(L->ci->state & CI_CALLING)); \
|
||||||
luaC_collectgarbage(L)
|
if (G(L)->nblocks >= G(L)->GCthreshold) luaC_collectgarbage(L); }
|
||||||
|
|
||||||
|
|
||||||
void luaC_callallgcTM (lua_State *L);
|
void luaC_separateudata (lua_State *L);
|
||||||
void luaC_collect (lua_State *L, int all);
|
void luaC_callGCTM (lua_State *L);
|
||||||
|
void luaC_sweep (lua_State *L, int all);
|
||||||
void luaC_collectgarbage (lua_State *L);
|
void luaC_collectgarbage (lua_State *L);
|
||||||
|
void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
373
llex.c
373
llex.c
@@ -1,17 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: llex.c,v 1.88 2001/06/20 21:07:57 roberto Exp roberto $
|
** $Id: llex.c,v 1.118 2003/02/28 17:19:47 roberto Exp roberto $
|
||||||
** Lexical Analyzer
|
** Lexical Analyzer
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define llex_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldo.h"
|
||||||
#include "llex.h"
|
#include "llex.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lparser.h"
|
#include "lparser.h"
|
||||||
@@ -26,13 +27,13 @@
|
|||||||
|
|
||||||
|
|
||||||
/* ORDER RESERVED */
|
/* ORDER RESERVED */
|
||||||
static const l_char *const token2string [] = {
|
static const char *const token2string [] = {
|
||||||
l_s("and"), l_s("break"), l_s("do"), l_s("else"), l_s("elseif"),
|
"and", "break", "do", "else", "elseif",
|
||||||
l_s("end"), l_s("for"), l_s("function"), l_s("global"), l_s("if"),
|
"end", "false", "for", "function", "if",
|
||||||
l_s("in"), l_s("local"), l_s("nil"), l_s("not"), l_s("or"), l_s("repeat"),
|
"in", "local", "nil", "not", "or", "repeat",
|
||||||
l_s("return"), l_s("then"), l_s("until"), l_s("while"), l_s(""),
|
"return", "then", "true", "until", "while", "*name",
|
||||||
l_s(".."), l_s("..."), l_s("=="), l_s(">="), l_s("<="), l_s("~="),
|
"..", "...", "==", ">=", "<=", "~=",
|
||||||
l_s(""), l_s(""), l_s("<eof>")
|
"*number", "*string", "<eof>"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -40,8 +41,9 @@ void luaX_init (lua_State *L) {
|
|||||||
int i;
|
int i;
|
||||||
for (i=0; i<NUM_RESERVED; i++) {
|
for (i=0; i<NUM_RESERVED; i++) {
|
||||||
TString *ts = luaS_new(L, token2string[i]);
|
TString *ts = luaS_new(L, token2string[i]);
|
||||||
|
luaS_fix(ts); /* reserved words are never collected */
|
||||||
lua_assert(strlen(token2string[i])+1 <= TOKEN_LEN);
|
lua_assert(strlen(token2string[i])+1 <= TOKEN_LEN);
|
||||||
ts->tsv.marked = (unsigned short)(RESERVEDMARK+i); /* reserved word */
|
ts->tsv.reserved = cast(lu_byte, i+1); /* reserved word */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,55 +51,68 @@ void luaX_init (lua_State *L) {
|
|||||||
#define MAXSRC 80
|
#define MAXSRC 80
|
||||||
|
|
||||||
|
|
||||||
void luaX_checklimit (LexState *ls, int val, int limit, const l_char *msg) {
|
void luaX_checklimit (LexState *ls, int val, int limit, const char *msg) {
|
||||||
if (val > limit) {
|
if (val > limit) {
|
||||||
l_char buff[90];
|
msg = luaO_pushfstring(ls->L, "too many %s (limit=%d)", msg, limit);
|
||||||
sprintf(buff, l_s("too many %.40s (limit=%d)"), msg, limit);
|
luaX_syntaxerror(ls, msg);
|
||||||
luaX_error(ls, buff, ls->t.token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaX_syntaxerror (LexState *ls, const l_char *s, const l_char *token) {
|
void luaX_errorline (LexState *ls, const char *s, const char *token, int line) {
|
||||||
l_char buff[MAXSRC];
|
lua_State *L = ls->L;
|
||||||
|
char buff[MAXSRC];
|
||||||
luaO_chunkid(buff, getstr(ls->source), MAXSRC);
|
luaO_chunkid(buff, getstr(ls->source), MAXSRC);
|
||||||
luaO_verror(ls->L,
|
luaO_pushfstring(L, "%s:%d: %s near `%s'", buff, line, s, token);
|
||||||
l_s("%.99s;\n last token read: `%.30s' at line %d in %.80s"),
|
luaD_throw(L, LUA_ERRSYNTAX);
|
||||||
s, token, ls->linenumber, buff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaX_error (LexState *ls, const l_char *s, int token) {
|
static void luaX_error (LexState *ls, const char *s, const char *token) {
|
||||||
l_char buff[TOKEN_LEN];
|
luaX_errorline(ls, s, token, ls->linenumber);
|
||||||
luaX_token2str(token, buff);
|
|
||||||
if (buff[0] == l_c('\0'))
|
|
||||||
luaX_syntaxerror(ls, s, (l_char *)G(ls->L)->Mbuffer);
|
|
||||||
else
|
|
||||||
luaX_syntaxerror(ls, s, buff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaX_token2str (int token, l_char *s) {
|
void luaX_syntaxerror (LexState *ls, const char *msg) {
|
||||||
if (token < 256) {
|
const char *lasttoken;
|
||||||
s[0] = (l_char)token;
|
switch (ls->t.token) {
|
||||||
s[1] = l_c('\0');
|
case TK_NAME:
|
||||||
|
lasttoken = getstr(ls->t.seminfo.ts);
|
||||||
|
break;
|
||||||
|
case TK_STRING:
|
||||||
|
case TK_NUMBER:
|
||||||
|
lasttoken = luaZ_buffer(ls->buff);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lasttoken = luaX_token2str(ls, ls->t.token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
luaX_error(ls, msg, lasttoken);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *luaX_token2str (LexState *ls, int token) {
|
||||||
|
if (token < FIRST_RESERVED) {
|
||||||
|
lua_assert(token == (unsigned char)token);
|
||||||
|
return luaO_pushfstring(ls->L, "%c", token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
strcpy(s, token2string[token-FIRST_RESERVED]);
|
return token2string[token-FIRST_RESERVED];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void luaX_invalidchar (LexState *ls, int c) {
|
static void luaX_lexerror (LexState *ls, const char *s, int token) {
|
||||||
l_char buff[8];
|
if (token == TK_EOS)
|
||||||
sprintf(buff, l_s("0x%02X"), uchar(c));
|
luaX_error(ls, s, luaX_token2str(ls, token));
|
||||||
luaX_syntaxerror(ls, l_s("invalid control char"), buff);
|
else
|
||||||
|
luaX_error(ls, s, luaZ_buffer(ls->buff));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void inclinenumber (LexState *LS) {
|
static void inclinenumber (LexState *LS) {
|
||||||
next(LS); /* skip `\n' */
|
next(LS); /* skip `\n' */
|
||||||
++LS->linenumber;
|
++LS->linenumber;
|
||||||
luaX_checklimit(LS, LS->linenumber, MAX_INT, l_s("lines in a chunk"));
|
luaX_checklimit(LS, LS->linenumber, MAX_INT, "lines in a chunk");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -110,10 +125,10 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) {
|
|||||||
LS->lastline = 1;
|
LS->lastline = 1;
|
||||||
LS->source = source;
|
LS->source = source;
|
||||||
next(LS); /* read first char */
|
next(LS); /* read first char */
|
||||||
if (LS->current == l_c('#')) {
|
if (LS->current == '#') {
|
||||||
do { /* skip first line */
|
do { /* skip first line */
|
||||||
next(LS);
|
next(LS);
|
||||||
} while (LS->current != l_c('\n') && LS->current != EOZ);
|
} while (LS->current != '\n' && LS->current != EOZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,163 +141,173 @@ void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* use Mbuffer to store names, literal strings and numbers */
|
/* use buffer to store names, literal strings and numbers */
|
||||||
|
|
||||||
#define EXTRABUFF 128
|
/* extra space to allocate when growing buffer */
|
||||||
#define checkbuffer(L, n, len) \
|
#define EXTRABUFF 32
|
||||||
if (((len)+(n))*sizeof(l_char) > G(L)->Mbuffsize) \
|
|
||||||
luaO_openspace(L, (len)+(n)+EXTRABUFF, l_char)
|
|
||||||
|
|
||||||
#define save(L, c, l) (((l_char *)G(L)->Mbuffer)[l++] = (l_char)c)
|
/* maximum number of chars that can be read without checking buffer size */
|
||||||
#define save_and_next(L, LS, l) (save(L, LS->current, l), next(LS))
|
#define MAXNOCHECK 5
|
||||||
|
|
||||||
|
#define checkbuffer(LS, len) \
|
||||||
|
if (((len)+MAXNOCHECK)*sizeof(char) > luaZ_sizebuffer((LS)->buff)) \
|
||||||
|
luaZ_openspace((LS)->L, (LS)->buff, (len)+EXTRABUFF)
|
||||||
|
|
||||||
|
#define save(LS, c, l) \
|
||||||
|
(luaZ_buffer((LS)->buff)[l++] = cast(char, c))
|
||||||
|
#define save_and_next(LS, l) (save(LS, LS->current, l), next(LS))
|
||||||
|
|
||||||
|
|
||||||
static size_t readname (LexState *LS) {
|
static size_t readname (LexState *LS) {
|
||||||
lua_State *L = LS->L;
|
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
do {
|
do {
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
} while (isalnum(LS->current) || LS->current == l_c('_'));
|
} while (isalnum(LS->current) || LS->current == '_');
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
return l-1;
|
return l-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* LUA_NUMBER */
|
/* LUA_NUMBER */
|
||||||
static void read_number (LexState *LS, int comma, SemInfo *seminfo) {
|
static void read_numeral (LexState *LS, int comma, SemInfo *seminfo) {
|
||||||
lua_State *L = LS->L;
|
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
if (comma) save(L, l_c('.'), l);
|
if (comma) save(LS, '.', l);
|
||||||
while (isdigit(LS->current)) {
|
while (isdigit(LS->current)) {
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
if (LS->current == l_c('.')) {
|
if (LS->current == '.') {
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
if (LS->current == l_c('.')) {
|
if (LS->current == '.') {
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
luaX_error(LS,
|
luaX_lexerror(LS,
|
||||||
l_s("ambiguous syntax (decimal point x string concatenation)"),
|
"ambiguous syntax (decimal point x string concatenation)",
|
||||||
TK_NUMBER);
|
TK_NUMBER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (isdigit(LS->current)) {
|
while (isdigit(LS->current)) {
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
if (LS->current == l_c('e') || LS->current == l_c('E')) {
|
if (LS->current == 'e' || LS->current == 'E') {
|
||||||
save_and_next(L, LS, l); /* read `E' */
|
save_and_next(LS, l); /* read `E' */
|
||||||
if (LS->current == l_c('+') || LS->current == l_c('-'))
|
if (LS->current == '+' || LS->current == '-')
|
||||||
save_and_next(L, LS, l); /* optional exponent sign */
|
save_and_next(LS, l); /* optional exponent sign */
|
||||||
while (isdigit(LS->current)) {
|
while (isdigit(LS->current)) {
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
if (!luaO_str2d((l_char *)G(L)->Mbuffer, &seminfo->r))
|
if (!luaO_str2d(luaZ_buffer(LS->buff), &seminfo->r))
|
||||||
luaX_error(LS, l_s("malformed number"), TK_NUMBER);
|
luaX_lexerror(LS, "malformed number", TK_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void read_long_string (LexState *LS, SemInfo *seminfo) {
|
static void read_long_string (LexState *LS, SemInfo *seminfo) {
|
||||||
lua_State *L = LS->L;
|
|
||||||
int cont = 0;
|
int cont = 0;
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
save(L, l_c('['), l); /* save first `[' */
|
save(LS, '[', l); /* save first `[' */
|
||||||
save_and_next(L, LS, l); /* pass the second `[' */
|
save_and_next(LS, l); /* pass the second `[' */
|
||||||
if (LS->current == l_c('\n')) /* string starts with a newline? */
|
if (LS->current == '\n') /* string starts with a newline? */
|
||||||
inclinenumber(LS); /* skip it */
|
inclinenumber(LS); /* skip it */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
switch (LS->current) {
|
switch (LS->current) {
|
||||||
case EOZ:
|
case EOZ:
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
luaX_error(LS, l_s("unfinished long string"), TK_STRING);
|
luaX_lexerror(LS, (seminfo) ? "unfinished long string" :
|
||||||
|
"unfinished long comment", TK_EOS);
|
||||||
break; /* to avoid warnings */
|
break; /* to avoid warnings */
|
||||||
case l_c('['):
|
case '[':
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
if (LS->current == l_c('[')) {
|
if (LS->current == '[') {
|
||||||
cont++;
|
cont++;
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case l_c(']'):
|
case ']':
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
if (LS->current == l_c(']')) {
|
if (LS->current == ']') {
|
||||||
if (cont == 0) goto endloop;
|
if (cont == 0) goto endloop;
|
||||||
cont--;
|
cont--;
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case l_c('\n'):
|
case '\n':
|
||||||
save(L, l_c('\n'), l);
|
save(LS, '\n', l);
|
||||||
inclinenumber(LS);
|
inclinenumber(LS);
|
||||||
|
if (!seminfo) l = 0; /* reset buffer to avoid wasting space */
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
} endloop:
|
} endloop:
|
||||||
save_and_next(L, LS, l); /* skip the second `]' */
|
save_and_next(LS, l); /* skip the second `]' */
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
seminfo->ts = luaS_newlstr(L, (l_char *)G(L)->Mbuffer+2, l-5);
|
if (seminfo)
|
||||||
|
seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 2, l - 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void read_string (LexState *LS, int del, SemInfo *seminfo) {
|
static void read_string (LexState *LS, int del, SemInfo *seminfo) {
|
||||||
lua_State *L = LS->L;
|
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
while (LS->current != del) {
|
while (LS->current != del) {
|
||||||
checkbuffer(L, 10, l);
|
checkbuffer(LS, l);
|
||||||
switch (LS->current) {
|
switch (LS->current) {
|
||||||
case EOZ: case l_c('\n'):
|
case EOZ:
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
luaX_error(LS, l_s("unfinished string"), TK_STRING);
|
luaX_lexerror(LS, "unfinished string", TK_EOS);
|
||||||
break; /* to avoid warnings */
|
break; /* to avoid warnings */
|
||||||
case l_c('\\'):
|
case '\n':
|
||||||
|
save(LS, '\0', l);
|
||||||
|
luaX_lexerror(LS, "unfinished string", TK_STRING);
|
||||||
|
break; /* to avoid warnings */
|
||||||
|
case '\\':
|
||||||
next(LS); /* do not save the `\' */
|
next(LS); /* do not save the `\' */
|
||||||
switch (LS->current) {
|
switch (LS->current) {
|
||||||
case l_c('a'): save(L, l_c('\a'), l); next(LS); break;
|
case 'a': save(LS, '\a', l); next(LS); break;
|
||||||
case l_c('b'): save(L, l_c('\b'), l); next(LS); break;
|
case 'b': save(LS, '\b', l); next(LS); break;
|
||||||
case l_c('f'): save(L, l_c('\f'), l); next(LS); break;
|
case 'f': save(LS, '\f', l); next(LS); break;
|
||||||
case l_c('n'): save(L, l_c('\n'), l); next(LS); break;
|
case 'n': save(LS, '\n', l); next(LS); break;
|
||||||
case l_c('r'): save(L, l_c('\r'), l); next(LS); break;
|
case 'r': save(LS, '\r', l); next(LS); break;
|
||||||
case l_c('t'): save(L, l_c('\t'), l); next(LS); break;
|
case 't': save(LS, '\t', l); next(LS); break;
|
||||||
case l_c('v'): save(L, l_c('\v'), l); next(LS); break;
|
case 'v': save(LS, '\v', l); next(LS); break;
|
||||||
case l_c('\n'): save(L, l_c('\n'), l); inclinenumber(LS); break;
|
case '\n': save(LS, '\n', l); inclinenumber(LS); break;
|
||||||
|
case EOZ: break; /* will raise an error next loop */
|
||||||
default: {
|
default: {
|
||||||
if (!isdigit(LS->current))
|
if (!isdigit(LS->current))
|
||||||
save_and_next(L, LS, l); /* handles \\, \", \', and \? */
|
save_and_next(LS, l); /* handles \\, \", \', and \? */
|
||||||
else { /* \xxx */
|
else { /* \xxx */
|
||||||
int c = 0;
|
int c = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
do {
|
do {
|
||||||
c = 10*c + (LS->current-l_c('0'));
|
c = 10*c + (LS->current-'0');
|
||||||
next(LS);
|
next(LS);
|
||||||
} while (++i<3 && isdigit(LS->current));
|
} while (++i<3 && isdigit(LS->current));
|
||||||
if (c > UCHAR_MAX) {
|
if (c > UCHAR_MAX) {
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
luaX_error(LS, l_s("escape sequence too large"), TK_STRING);
|
luaX_lexerror(LS, "escape sequence too large", TK_STRING);
|
||||||
}
|
}
|
||||||
save(L, c, l);
|
save(LS, c, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
save_and_next(L, LS, l);
|
save_and_next(LS, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
save_and_next(L, LS, l); /* skip delimiter */
|
save_and_next(LS, l); /* skip delimiter */
|
||||||
save(L, l_c('\0'), l);
|
save(LS, '\0', l);
|
||||||
seminfo->ts = luaS_newlstr(L, (l_char *)G(L)->Mbuffer+1, l-3);
|
seminfo->ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff) + 1, l - 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -290,96 +315,97 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
switch (LS->current) {
|
switch (LS->current) {
|
||||||
|
|
||||||
case l_c(' '): case l_c('\t'): case l_c('\r'): /* `\r' to avoid problems with DOS */
|
case '\n': {
|
||||||
next(LS);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
case l_c('\n'):
|
|
||||||
inclinenumber(LS);
|
inclinenumber(LS);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
case l_c('$'):
|
case '-': {
|
||||||
luaX_error(LS,
|
|
||||||
l_s("unexpected `$' (pragmas are no longer supported)"),
|
|
||||||
LS->current);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case l_c('-'):
|
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current != l_c('-')) return l_c('-');
|
if (LS->current != '-') return '-';
|
||||||
do { next(LS); } while (LS->current != l_c('\n') && LS->current != EOZ);
|
/* else is a comment */
|
||||||
|
next(LS);
|
||||||
|
if (LS->current == '[' && (next(LS), LS->current == '['))
|
||||||
|
read_long_string(LS, NULL); /* long comment */
|
||||||
|
else /* short comment */
|
||||||
|
while (LS->current != '\n' && LS->current != EOZ)
|
||||||
|
next(LS);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
case l_c('['):
|
case '[': {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current != l_c('[')) return l_c('[');
|
if (LS->current != '[') return '[';
|
||||||
else {
|
else {
|
||||||
read_long_string(LS, seminfo);
|
read_long_string(LS, seminfo);
|
||||||
return TK_STRING;
|
return TK_STRING;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case l_c('='):
|
case '=': {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current != l_c('=')) return l_c('=');
|
if (LS->current != '=') return '=';
|
||||||
else { next(LS); return TK_EQ; }
|
else { next(LS); return TK_EQ; }
|
||||||
|
}
|
||||||
case l_c('<'):
|
case '<': {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current != l_c('=')) return l_c('<');
|
if (LS->current != '=') return '<';
|
||||||
else { next(LS); return TK_LE; }
|
else { next(LS); return TK_LE; }
|
||||||
|
}
|
||||||
case l_c('>'):
|
case '>': {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current != l_c('=')) return l_c('>');
|
if (LS->current != '=') return '>';
|
||||||
else { next(LS); return TK_GE; }
|
else { next(LS); return TK_GE; }
|
||||||
|
}
|
||||||
case l_c('~'):
|
case '~': {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current != l_c('=')) return l_c('~');
|
if (LS->current != '=') return '~';
|
||||||
else { next(LS); return TK_NE; }
|
else { next(LS); return TK_NE; }
|
||||||
|
}
|
||||||
case l_c('"'):
|
case '"':
|
||||||
case l_c('\''):
|
case '\'': {
|
||||||
read_string(LS, LS->current, seminfo);
|
read_string(LS, LS->current, seminfo);
|
||||||
return TK_STRING;
|
return TK_STRING;
|
||||||
|
}
|
||||||
case l_c('.'):
|
case '.': {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current == l_c('.')) {
|
if (LS->current == '.') {
|
||||||
next(LS);
|
next(LS);
|
||||||
if (LS->current == l_c('.')) {
|
if (LS->current == '.') {
|
||||||
next(LS);
|
next(LS);
|
||||||
return TK_DOTS; /* ... */
|
return TK_DOTS; /* ... */
|
||||||
}
|
}
|
||||||
else return TK_CONCAT; /* .. */
|
else return TK_CONCAT; /* .. */
|
||||||
}
|
}
|
||||||
else if (!isdigit(LS->current)) return l_c('.');
|
else if (!isdigit(LS->current)) return '.';
|
||||||
else {
|
else {
|
||||||
read_number(LS, 1, seminfo);
|
read_numeral(LS, 1, seminfo);
|
||||||
return TK_NUMBER;
|
return TK_NUMBER;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case EOZ:
|
case EOZ: {
|
||||||
return TK_EOS;
|
return TK_EOS;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
if (isdigit(LS->current)) {
|
if (isspace(LS->current)) {
|
||||||
read_number(LS, 0, seminfo);
|
next(LS);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (isdigit(LS->current)) {
|
||||||
|
read_numeral(LS, 0, seminfo);
|
||||||
return TK_NUMBER;
|
return TK_NUMBER;
|
||||||
}
|
}
|
||||||
else if (isalpha(LS->current) || LS->current == l_c('_')) {
|
else if (isalpha(LS->current) || LS->current == '_') {
|
||||||
/* identifier or reserved word */
|
/* identifier or reserved word */
|
||||||
size_t l = readname(LS);
|
size_t l = readname(LS);
|
||||||
TString *ts = luaS_newlstr(LS->L, (l_char *)G(LS->L)->Mbuffer, l);
|
TString *ts = luaS_newlstr(LS->L, luaZ_buffer(LS->buff), l);
|
||||||
if (ts->tsv.marked >= RESERVEDMARK) /* reserved word? */
|
if (ts->tsv.reserved > 0) /* reserved word? */
|
||||||
return ts->tsv.marked-RESERVEDMARK+FIRST_RESERVED;
|
return ts->tsv.reserved - 1 + FIRST_RESERVED;
|
||||||
seminfo->ts = ts;
|
seminfo->ts = ts;
|
||||||
return TK_NAME;
|
return TK_NAME;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
l_charint c = LS->current;
|
int c = LS->current;
|
||||||
if (iscntrl(c))
|
if (iscntrl(c))
|
||||||
luaX_invalidchar(LS, c);
|
luaX_error(LS, "invalid control char",
|
||||||
|
luaO_pushfstring(LS->L, "char(%d)", c));
|
||||||
next(LS);
|
next(LS);
|
||||||
return c; /* single-char tokens (+ - / ...) */
|
return c; /* single-char tokens (+ - / ...) */
|
||||||
}
|
}
|
||||||
@@ -388,3 +414,4 @@ int luaX_lex (LexState *LS, SemInfo *seminfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef next
|
||||||
|
|||||||
30
llex.h
30
llex.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: llex.h,v 1.36 2001/06/20 21:07:57 roberto Exp roberto $
|
** $Id: llex.h,v 1.46 2002/11/22 16:35:20 roberto Exp roberto $
|
||||||
** Lexical Analyzer
|
** Lexical Analyzer
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#define FIRST_RESERVED 257
|
#define FIRST_RESERVED 257
|
||||||
|
|
||||||
/* maximum length of a reserved word */
|
/* maximum length of a reserved word */
|
||||||
#define TOKEN_LEN (sizeof(l_s("function"))/sizeof(l_char))
|
#define TOKEN_LEN (sizeof("function")/sizeof(char))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -24,16 +24,16 @@
|
|||||||
enum RESERVED {
|
enum RESERVED {
|
||||||
/* terminal symbols denoted by reserved words */
|
/* terminal symbols denoted by reserved words */
|
||||||
TK_AND = FIRST_RESERVED, TK_BREAK,
|
TK_AND = FIRST_RESERVED, TK_BREAK,
|
||||||
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FOR, TK_FUNCTION, TK_GLOBAL, TK_IF,
|
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
|
||||||
TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN,
|
TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
|
||||||
TK_UNTIL, TK_WHILE,
|
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
|
||||||
/* other terminal symbols */
|
/* other terminal symbols */
|
||||||
TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
|
TK_NAME, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER,
|
||||||
TK_STRING, TK_EOS
|
TK_STRING, TK_EOS
|
||||||
};
|
};
|
||||||
|
|
||||||
/* number of reserved words */
|
/* number of reserved words */
|
||||||
#define NUM_RESERVED ((int)(TK_WHILE-FIRST_RESERVED+1))
|
#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
|
||||||
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@@ -49,25 +49,27 @@ typedef struct Token {
|
|||||||
|
|
||||||
|
|
||||||
typedef struct LexState {
|
typedef struct LexState {
|
||||||
l_charint current; /* current character */
|
int current; /* current character (charint) */
|
||||||
|
int linenumber; /* input line counter */
|
||||||
|
int lastline; /* line of last token `consumed' */
|
||||||
Token t; /* current token */
|
Token t; /* current token */
|
||||||
Token lookahead; /* look ahead token */
|
Token lookahead; /* look ahead token */
|
||||||
struct FuncState *fs; /* `FuncState' is private to the parser */
|
struct FuncState *fs; /* `FuncState' is private to the parser */
|
||||||
struct lua_State *L;
|
struct lua_State *L;
|
||||||
struct zio *z; /* input stream */
|
ZIO *z; /* input stream */
|
||||||
int linenumber; /* input line counter */
|
Mbuffer *buff; /* buffer for tokens */
|
||||||
int lastline; /* line of last token `consumed' */
|
|
||||||
TString *source; /* current source name */
|
TString *source; /* current source name */
|
||||||
|
int nestlevel; /* level of nested non-terminals */
|
||||||
} LexState;
|
} LexState;
|
||||||
|
|
||||||
|
|
||||||
void luaX_init (lua_State *L);
|
void luaX_init (lua_State *L);
|
||||||
void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source);
|
void luaX_setinput (lua_State *L, LexState *LS, ZIO *z, TString *source);
|
||||||
int luaX_lex (LexState *LS, SemInfo *seminfo);
|
int luaX_lex (LexState *LS, SemInfo *seminfo);
|
||||||
void luaX_checklimit (LexState *ls, int val, int limit, const l_char *msg);
|
void luaX_checklimit (LexState *ls, int val, int limit, const char *msg);
|
||||||
void luaX_syntaxerror (LexState *ls, const l_char *s, const l_char *token);
|
void luaX_syntaxerror (LexState *ls, const char *s);
|
||||||
void luaX_error (LexState *ls, const l_char *s, int token);
|
void luaX_errorline (LexState *ls, const char *s, const char *token, int line);
|
||||||
void luaX_token2str (int token, l_char *s);
|
const char *luaX_token2str (LexState *ls, int token);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
110
llimits.h
110
llimits.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: llimits.h,v 1.29 2001/06/05 18:17:01 roberto Exp roberto $
|
** $Id: llimits.h,v 1.51 2002/11/25 17:47:13 roberto Exp roberto $
|
||||||
** Limits, basic types, and some other `installation-dependent' definitions
|
** Limits, basic types, and some other `installation-dependent' definitions
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -45,14 +45,17 @@ typedef unsigned int lu_hash;
|
|||||||
/* its signed equivalent */
|
/* its signed equivalent */
|
||||||
typedef int ls_hash;
|
typedef int ls_hash;
|
||||||
|
|
||||||
/* an unsigned integer big enough to count the total memory used by Lua */
|
/* an unsigned integer big enough to count the total memory used by Lua; */
|
||||||
|
/* it should be at least as large as size_t */
|
||||||
typedef unsigned long lu_mem;
|
typedef unsigned long lu_mem;
|
||||||
|
|
||||||
|
#define MAX_LUMEM ULONG_MAX
|
||||||
|
|
||||||
|
|
||||||
/* an integer big enough to count the number of strings in use */
|
/* an integer big enough to count the number of strings in use */
|
||||||
typedef long ls_nstr;
|
typedef long ls_nstr;
|
||||||
|
|
||||||
|
/* chars used as small naturals (so that `char' is reserved for characters) */
|
||||||
/* chars used as small naturals (so that `char' is reserved for characteres) */
|
|
||||||
typedef unsigned char lu_byte;
|
typedef unsigned char lu_byte;
|
||||||
|
|
||||||
|
|
||||||
@@ -65,27 +68,45 @@ typedef unsigned char lu_byte;
|
|||||||
** conversion of pointer to integer
|
** conversion of pointer to integer
|
||||||
** this is for hashing only; there is no problem if the integer
|
** this is for hashing only; there is no problem if the integer
|
||||||
** cannot hold the whole pointer value
|
** cannot hold the whole pointer value
|
||||||
** (the shift removes bits that are usually 0 because of alignment)
|
|
||||||
*/
|
*/
|
||||||
#define IntPoint(p) ((((lu_hash)(p)) >> 4) ^ (lu_hash)(p))
|
#define IntPoint(p) ((lu_hash)(p))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MINPOWER2 4 /* minimum size for `growing' vectors */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DEFAULT_STACK_SIZE
|
|
||||||
#define DEFAULT_STACK_SIZE 1024
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* type to ensure maximum alignment */
|
/* type to ensure maximum alignment */
|
||||||
#ifndef LUSER_ALIGNMENT_T
|
#ifndef LUSER_ALIGNMENT_T
|
||||||
#define LUSER_ALIGNMENT_T double
|
typedef union { double u; void *s; long l; } L_Umaxalign;
|
||||||
|
#else
|
||||||
|
typedef LUSER_ALIGNMENT_T L_Umaxalign;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* result of `usual argument conversion' over lua_Number */
|
||||||
|
#ifndef LUA_UACNUMBER
|
||||||
|
typedef double l_uacNumber;
|
||||||
|
#else
|
||||||
|
typedef LUA_UACNUMBER l_uacNumber;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef lua_assert
|
||||||
|
#define lua_assert(c) /* empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef check_exp
|
||||||
|
#define check_exp(c,e) (e)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef UNUSED
|
||||||
|
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef cast
|
||||||
|
#define cast(t, exp) ((t)(exp))
|
||||||
#endif
|
#endif
|
||||||
union L_Umaxalign { LUSER_ALIGNMENT_T u; void *s; long l; };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -96,19 +117,41 @@ union L_Umaxalign { LUSER_ALIGNMENT_T u; void *s; long l; };
|
|||||||
typedef unsigned long Instruction;
|
typedef unsigned long Instruction;
|
||||||
|
|
||||||
|
|
||||||
|
/* maximum depth for calls (unsigned short) */
|
||||||
|
#ifndef LUA_MAXCALLS
|
||||||
|
#define LUA_MAXCALLS 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** maximum depth for C calls (unsigned short): Not too big, or may
|
||||||
|
** overflow the C stack...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LUA_MAXCCALLS
|
||||||
|
#define LUA_MAXCCALLS 200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* maximum size for the C stack */
|
||||||
|
#ifndef LUA_MAXCSTACK
|
||||||
|
#define LUA_MAXCSTACK 2048
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* maximum stack for a Lua function */
|
/* maximum stack for a Lua function */
|
||||||
#define MAXSTACK 250
|
#define MAXSTACK 250
|
||||||
|
|
||||||
|
|
||||||
/* maximum number of local variables */
|
/* maximum number of variables declared in a function */
|
||||||
#ifndef MAXLOCALS
|
#ifndef MAXVARS
|
||||||
#define MAXLOCALS 200 /* arbitrary limit (<MAXSTACK) */
|
#define MAXVARS 200 /* arbitrary limit (<MAXSTACK) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* maximum number of upvalues */
|
/* maximum number of upvalues per function */
|
||||||
#ifndef MAXUPVALUES
|
#ifndef MAXUPVALUES
|
||||||
#define MAXUPVALUES 32 /* arbitrary limit (<MAXSTACK) */
|
#define MAXUPVALUES 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -118,15 +161,24 @@ typedef unsigned long Instruction;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* number of list items to accumulate before a SETLIST instruction */
|
/* minimum size for the string table (must be power of 2) */
|
||||||
/* (must be a power of 2) */
|
#ifndef MINSTRTABSIZE
|
||||||
#define LFIELDS_PER_FLUSH 64
|
#define MINSTRTABSIZE 32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* minimum size for string buffer */
|
||||||
|
#ifndef LUA_MINBUFFER
|
||||||
|
#define LUA_MINBUFFER 32
|
||||||
|
#endif
|
||||||
|
|
||||||
/* maximum lookback to find a real constant (for code generation) */
|
|
||||||
#ifndef LOOKBACKNUMS
|
/*
|
||||||
#define LOOKBACKNUMS 40 /* arbitrary constant */
|
** maximum number of syntactical nested non-terminals: Not too big,
|
||||||
|
** or may overflow the C stack...
|
||||||
|
*/
|
||||||
|
#ifndef LUA_MAXPARSERLEVEL
|
||||||
|
#define LUA_MAXPARSERLEVEL 200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
146
lmathlib.c
146
lmathlib.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lmathlib.c,v 1.37 2001/03/06 20:09:38 roberto Exp roberto $
|
** $Id: lmathlib.c,v 1.55 2003/03/11 12:24:34 roberto Exp roberto $
|
||||||
** Standard mathematical library
|
** Standard mathematical library
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -8,7 +8,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lmathlib_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
@@ -22,117 +23,117 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** If you want Lua to operate in radians (instead of degrees),
|
** If you want Lua to operate in degrees (instead of radians),
|
||||||
** define RADIANS
|
** define USE_DEGREES
|
||||||
*/
|
*/
|
||||||
#ifdef RADIANS
|
#ifdef USE_DEGREES
|
||||||
#define FROMRAD(a) (a)
|
|
||||||
#define TORAD(a) (a)
|
|
||||||
#else
|
|
||||||
#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE)
|
#define FROMRAD(a) ((a)/RADIANS_PER_DEGREE)
|
||||||
#define TORAD(a) ((a)*RADIANS_PER_DEGREE)
|
#define TORAD(a) ((a)*RADIANS_PER_DEGREE)
|
||||||
|
#else
|
||||||
|
#define FROMRAD(a) (a)
|
||||||
|
#define TORAD(a) (a)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int math_abs (lua_State *L) {
|
static int math_abs (lua_State *L) {
|
||||||
lua_pushnumber(L, fabs(luaL_check_number(L, 1)));
|
lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_sin (lua_State *L) {
|
static int math_sin (lua_State *L) {
|
||||||
lua_pushnumber(L, sin(TORAD(luaL_check_number(L, 1))));
|
lua_pushnumber(L, sin(TORAD(luaL_checknumber(L, 1))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_cos (lua_State *L) {
|
static int math_cos (lua_State *L) {
|
||||||
lua_pushnumber(L, cos(TORAD(luaL_check_number(L, 1))));
|
lua_pushnumber(L, cos(TORAD(luaL_checknumber(L, 1))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_tan (lua_State *L) {
|
static int math_tan (lua_State *L) {
|
||||||
lua_pushnumber(L, tan(TORAD(luaL_check_number(L, 1))));
|
lua_pushnumber(L, tan(TORAD(luaL_checknumber(L, 1))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_asin (lua_State *L) {
|
static int math_asin (lua_State *L) {
|
||||||
lua_pushnumber(L, FROMRAD(asin(luaL_check_number(L, 1))));
|
lua_pushnumber(L, FROMRAD(asin(luaL_checknumber(L, 1))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_acos (lua_State *L) {
|
static int math_acos (lua_State *L) {
|
||||||
lua_pushnumber(L, FROMRAD(acos(luaL_check_number(L, 1))));
|
lua_pushnumber(L, FROMRAD(acos(luaL_checknumber(L, 1))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_atan (lua_State *L) {
|
static int math_atan (lua_State *L) {
|
||||||
lua_pushnumber(L, FROMRAD(atan(luaL_check_number(L, 1))));
|
lua_pushnumber(L, FROMRAD(atan(luaL_checknumber(L, 1))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_atan2 (lua_State *L) {
|
static int math_atan2 (lua_State *L) {
|
||||||
lua_pushnumber(L, FROMRAD(atan2(luaL_check_number(L, 1), luaL_check_number(L, 2))));
|
lua_pushnumber(L, FROMRAD(atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_ceil (lua_State *L) {
|
static int math_ceil (lua_State *L) {
|
||||||
lua_pushnumber(L, ceil(luaL_check_number(L, 1)));
|
lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_floor (lua_State *L) {
|
static int math_floor (lua_State *L) {
|
||||||
lua_pushnumber(L, floor(luaL_check_number(L, 1)));
|
lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_mod (lua_State *L) {
|
static int math_mod (lua_State *L) {
|
||||||
lua_pushnumber(L, fmod(luaL_check_number(L, 1), luaL_check_number(L, 2)));
|
lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_sqrt (lua_State *L) {
|
static int math_sqrt (lua_State *L) {
|
||||||
lua_pushnumber(L, sqrt(luaL_check_number(L, 1)));
|
lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_pow (lua_State *L) {
|
static int math_pow (lua_State *L) {
|
||||||
lua_pushnumber(L, pow(luaL_check_number(L, 1), luaL_check_number(L, 2)));
|
lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_log (lua_State *L) {
|
static int math_log (lua_State *L) {
|
||||||
lua_pushnumber(L, log(luaL_check_number(L, 1)));
|
lua_pushnumber(L, log(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_log10 (lua_State *L) {
|
static int math_log10 (lua_State *L) {
|
||||||
lua_pushnumber(L, log10(luaL_check_number(L, 1)));
|
lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_exp (lua_State *L) {
|
static int math_exp (lua_State *L) {
|
||||||
lua_pushnumber(L, exp(luaL_check_number(L, 1)));
|
lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_deg (lua_State *L) {
|
static int math_deg (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_check_number(L, 1)/RADIANS_PER_DEGREE);
|
lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_rad (lua_State *L) {
|
static int math_rad (lua_State *L) {
|
||||||
lua_pushnumber(L, luaL_check_number(L, 1)*RADIANS_PER_DEGREE);
|
lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_frexp (lua_State *L) {
|
static int math_frexp (lua_State *L) {
|
||||||
int e;
|
int e;
|
||||||
lua_pushnumber(L, frexp(luaL_check_number(L, 1), &e));
|
lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
|
||||||
lua_pushnumber(L, e);
|
lua_pushnumber(L, e);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int math_ldexp (lua_State *L) {
|
static int math_ldexp (lua_State *L) {
|
||||||
lua_pushnumber(L, ldexp(luaL_check_number(L, 1), luaL_check_int(L, 2)));
|
lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,10 +141,10 @@ static int math_ldexp (lua_State *L) {
|
|||||||
|
|
||||||
static int math_min (lua_State *L) {
|
static int math_min (lua_State *L) {
|
||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
lua_Number dmin = luaL_check_number(L, 1);
|
lua_Number dmin = luaL_checknumber(L, 1);
|
||||||
int i;
|
int i;
|
||||||
for (i=2; i<=n; i++) {
|
for (i=2; i<=n; i++) {
|
||||||
lua_Number d = luaL_check_number(L, i);
|
lua_Number d = luaL_checknumber(L, i);
|
||||||
if (d < dmin)
|
if (d < dmin)
|
||||||
dmin = d;
|
dmin = d;
|
||||||
}
|
}
|
||||||
@@ -154,10 +155,10 @@ static int math_min (lua_State *L) {
|
|||||||
|
|
||||||
static int math_max (lua_State *L) {
|
static int math_max (lua_State *L) {
|
||||||
int n = lua_gettop(L); /* number of arguments */
|
int n = lua_gettop(L); /* number of arguments */
|
||||||
lua_Number dmax = luaL_check_number(L, 1);
|
lua_Number dmax = luaL_checknumber(L, 1);
|
||||||
int i;
|
int i;
|
||||||
for (i=2; i<=n; i++) {
|
for (i=2; i<=n; i++) {
|
||||||
lua_Number d = luaL_check_number(L, i);
|
lua_Number d = luaL_checknumber(L, i);
|
||||||
if (d > dmax)
|
if (d > dmax)
|
||||||
dmax = d;
|
dmax = d;
|
||||||
}
|
}
|
||||||
@@ -176,65 +177,70 @@ static int math_random (lua_State *L) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 1: { /* only upper limit */
|
case 1: { /* only upper limit */
|
||||||
int u = luaL_check_int(L, 1);
|
int u = luaL_checkint(L, 1);
|
||||||
luaL_arg_check(L, 1<=u, 1, l_s("interval is empty"));
|
luaL_argcheck(L, 1<=u, 1, "interval is empty");
|
||||||
lua_pushnumber(L, (int)(r*u)+1); /* integer between 1 and `u' */
|
lua_pushnumber(L, (int)floor(r*u)+1); /* int between 1 and `u' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: { /* lower and upper limits */
|
case 2: { /* lower and upper limits */
|
||||||
int l = luaL_check_int(L, 1);
|
int l = luaL_checkint(L, 1);
|
||||||
int u = luaL_check_int(L, 2);
|
int u = luaL_checkint(L, 2);
|
||||||
luaL_arg_check(L, l<=u, 2, l_s("interval is empty"));
|
luaL_argcheck(L, l<=u, 2, "interval is empty");
|
||||||
lua_pushnumber(L, (int)(r*(u-l+1))+l); /* integer between `l' and `u' */
|
lua_pushnumber(L, (int)floor(r*(u-l+1))+l); /* int between `l' and `u' */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: lua_error(L, l_s("wrong number of arguments"));
|
default: return luaL_error(L, "wrong number of arguments");
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int math_randomseed (lua_State *L) {
|
static int math_randomseed (lua_State *L) {
|
||||||
srand(luaL_check_int(L, 1));
|
srand(luaL_checkint(L, 1));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const luaL_reg mathlib[] = {
|
static const luaL_reg mathlib[] = {
|
||||||
{l_s("abs"), math_abs},
|
{"abs", math_abs},
|
||||||
{l_s("sin"), math_sin},
|
{"sin", math_sin},
|
||||||
{l_s("cos"), math_cos},
|
{"cos", math_cos},
|
||||||
{l_s("tan"), math_tan},
|
{"tan", math_tan},
|
||||||
{l_s("asin"), math_asin},
|
{"asin", math_asin},
|
||||||
{l_s("acos"), math_acos},
|
{"acos", math_acos},
|
||||||
{l_s("atan"), math_atan},
|
{"atan", math_atan},
|
||||||
{l_s("atan2"), math_atan2},
|
{"atan2", math_atan2},
|
||||||
{l_s("ceil"), math_ceil},
|
{"ceil", math_ceil},
|
||||||
{l_s("floor"), math_floor},
|
{"floor", math_floor},
|
||||||
{l_s("mod"), math_mod},
|
{"mod", math_mod},
|
||||||
{l_s("frexp"), math_frexp},
|
{"frexp", math_frexp},
|
||||||
{l_s("ldexp"), math_ldexp},
|
{"ldexp", math_ldexp},
|
||||||
{l_s("sqrt"), math_sqrt},
|
{"sqrt", math_sqrt},
|
||||||
{l_s("min"), math_min},
|
{"min", math_min},
|
||||||
{l_s("max"), math_max},
|
{"max", math_max},
|
||||||
{l_s("log"), math_log},
|
{"log", math_log},
|
||||||
{l_s("log10"), math_log10},
|
{"log10", math_log10},
|
||||||
{l_s("exp"), math_exp},
|
{"exp", math_exp},
|
||||||
{l_s("deg"), math_deg},
|
{"deg", math_deg},
|
||||||
{l_s("rad"), math_rad},
|
{"pow", math_pow},
|
||||||
{l_s("random"), math_random},
|
{"rad", math_rad},
|
||||||
{l_s("randomseed"), math_randomseed}
|
{"random", math_random},
|
||||||
|
{"randomseed", math_randomseed},
|
||||||
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Open math library
|
** Open math library
|
||||||
*/
|
*/
|
||||||
LUALIB_API int lua_mathlibopen (lua_State *L) {
|
LUALIB_API int luaopen_math (lua_State *L) {
|
||||||
luaL_openl(L, mathlib);
|
luaL_openlib(L, LUA_MATHLIBNAME, mathlib, 0);
|
||||||
lua_pushcfunction(L, math_pow);
|
lua_pushliteral(L, "pi");
|
||||||
lua_settagmethod(L, LUA_TNUMBER, l_s("pow"));
|
|
||||||
lua_pushnumber(L, PI);
|
lua_pushnumber(L, PI);
|
||||||
lua_setglobal(L, l_s("PI"));
|
lua_settable(L, -3);
|
||||||
return 0;
|
lua_pushliteral(L, "__pow");
|
||||||
|
lua_pushcfunction(L, math_pow);
|
||||||
|
lua_settable(L, LUA_GLOBALSINDEX);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
55
lmem.c
55
lmem.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lmem.c,v 1.48 2001/02/23 17:17:25 roberto Exp roberto $
|
** $Id: lmem.c,v 1.60 2002/11/21 14:14:42 roberto Exp roberto $
|
||||||
** Interface to Memory Manager
|
** Interface to Memory Manager
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -7,9 +7,11 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lmem_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldebug.h"
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
@@ -17,25 +19,41 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** definition for realloc function. It must assure that l_realloc(NULL,
|
||||||
|
** 0, x) allocates a new block (ANSI C assures that). (`os' is the old
|
||||||
|
** block size; some allocators may use that.)
|
||||||
|
*/
|
||||||
#ifndef l_realloc
|
#ifndef l_realloc
|
||||||
#define l_realloc(b,os,s) realloc(b,s)
|
#define l_realloc(b,os,s) realloc(b,s)
|
||||||
#define l_free(b,s) free(b)
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** definition for free function. (`os' is the old block size; some
|
||||||
|
** allocators may use that.)
|
||||||
|
*/
|
||||||
|
#ifndef l_free
|
||||||
|
#define l_free(b,os) free(b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define MINSIZEARRAY 4
|
||||||
|
|
||||||
|
|
||||||
void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems,
|
void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems,
|
||||||
int limit, const l_char *errormsg) {
|
int limit, const char *errormsg) {
|
||||||
void *newblock;
|
void *newblock;
|
||||||
int newsize = (*size)*2;
|
int newsize = (*size)*2;
|
||||||
if (newsize < MINPOWER2)
|
if (newsize < MINSIZEARRAY)
|
||||||
newsize = MINPOWER2; /* minimum size */
|
newsize = MINSIZEARRAY; /* minimum size */
|
||||||
else if (*size >= limit/2) { /* cannot double it? */
|
else if (*size >= limit/2) { /* cannot double it? */
|
||||||
if (*size < limit - MINPOWER2) /* try something smaller... */
|
if (*size < limit - MINSIZEARRAY) /* try something smaller... */
|
||||||
newsize = limit; /* still have at least MINPOWER2 free places */
|
newsize = limit; /* still have at least MINSIZEARRAY free places */
|
||||||
else luaD_error(L, errormsg);
|
else luaG_runerror(L, errormsg);
|
||||||
}
|
}
|
||||||
newblock = luaM_realloc(L, block, (lu_mem)(*size)*(lu_mem)size_elems,
|
newblock = luaM_realloc(L, block,
|
||||||
(lu_mem)newsize*(lu_mem)size_elems);
|
cast(lu_mem, *size)*cast(lu_mem, size_elems),
|
||||||
|
cast(lu_mem, newsize)*cast(lu_mem, size_elems));
|
||||||
*size = newsize; /* update only when everything else is OK */
|
*size = newsize; /* update only when everything else is OK */
|
||||||
return newblock;
|
return newblock;
|
||||||
}
|
}
|
||||||
@@ -45,21 +63,26 @@ void *luaM_growaux (lua_State *L, void *block, int *size, int size_elems,
|
|||||||
** generic allocation routine.
|
** generic allocation routine.
|
||||||
*/
|
*/
|
||||||
void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) {
|
void *luaM_realloc (lua_State *L, void *block, lu_mem oldsize, lu_mem size) {
|
||||||
|
lua_assert((oldsize == 0) == (block == NULL));
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
l_free(block, oldsize); /* block may be NULL; that is OK for free */
|
if (block != NULL) {
|
||||||
block = NULL;
|
l_free(block, oldsize);
|
||||||
|
block = NULL;
|
||||||
|
}
|
||||||
|
else return NULL; /* avoid `nblocks' computations when oldsize==size==0 */
|
||||||
}
|
}
|
||||||
else if (size >= MAX_SIZET)
|
else if (size >= MAX_SIZET)
|
||||||
luaD_error(L, l_s("memory allocation error: block too big"));
|
luaG_runerror(L, "memory allocation error: block too big");
|
||||||
else {
|
else {
|
||||||
block = l_realloc(block, oldsize, size);
|
block = l_realloc(block, oldsize, size);
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
if (L)
|
if (L)
|
||||||
luaD_breakrun(L, LUA_ERRMEM); /* break run without error message */
|
luaD_throw(L, LUA_ERRMEM);
|
||||||
else return NULL; /* error before creating state! */
|
else return NULL; /* error before creating state! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (L && G(L)) {
|
if (L) {
|
||||||
|
lua_assert(G(L) != NULL && G(L)->nblocks > 0);
|
||||||
G(L)->nblocks -= oldsize;
|
G(L)->nblocks -= oldsize;
|
||||||
G(L)->nblocks += size;
|
G(L)->nblocks += size;
|
||||||
}
|
}
|
||||||
|
|||||||
23
lmem.h
23
lmem.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lmem.h,v 1.21 2001/02/20 18:15:33 roberto Exp roberto $
|
** $Id: lmem.h,v 1.25 2001/11/28 20:13:13 roberto Exp roberto $
|
||||||
** Interface to Memory Manager
|
** Interface to Memory Manager
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -13,28 +13,31 @@
|
|||||||
#include "llimits.h"
|
#include "llimits.h"
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#define MEMERRMSG "not enough memory"
|
||||||
|
|
||||||
|
|
||||||
void *luaM_realloc (lua_State *L, void *oldblock, lu_mem oldsize, lu_mem size);
|
void *luaM_realloc (lua_State *L, void *oldblock, lu_mem oldsize, lu_mem size);
|
||||||
|
|
||||||
void *luaM_growaux (lua_State *L, void *block, int *size, int size_elem,
|
void *luaM_growaux (lua_State *L, void *block, int *size, int size_elem,
|
||||||
int limit, const l_char *errormsg);
|
int limit, const char *errormsg);
|
||||||
|
|
||||||
#define luaM_free(L, b, s) luaM_realloc(L, (b), (s), 0)
|
#define luaM_free(L, b, s) luaM_realloc(L, (b), (s), 0)
|
||||||
#define luaM_freelem(L, b, t) luaM_realloc(L, (b), sizeof(t), 0)
|
#define luaM_freelem(L, b) luaM_realloc(L, (b), sizeof(*(b)), 0)
|
||||||
#define luaM_freearray(L, b, n, t) luaM_realloc(L, (b), \
|
#define luaM_freearray(L, b, n, t) luaM_realloc(L, (b), \
|
||||||
((lu_mem)(n)*(lu_mem)sizeof(t)), 0)
|
cast(lu_mem, n)*cast(lu_mem, sizeof(t)), 0)
|
||||||
|
|
||||||
#define luaM_malloc(L, t) luaM_realloc(L, NULL, 0, (t))
|
#define luaM_malloc(L, t) luaM_realloc(L, NULL, 0, (t))
|
||||||
#define luaM_new(L, t) ((t *)luaM_malloc(L, sizeof(t)))
|
#define luaM_new(L, t) cast(t *, luaM_malloc(L, sizeof(t)))
|
||||||
#define luaM_newvector(L, n,t) ((t *)luaM_malloc(L, \
|
#define luaM_newvector(L, n,t) cast(t *, luaM_malloc(L, \
|
||||||
(lu_mem)(n)*(lu_mem)sizeof(t)))
|
cast(lu_mem, n)*cast(lu_mem, sizeof(t))))
|
||||||
|
|
||||||
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
|
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
|
||||||
if (((nelems)+1) > (size)) \
|
if (((nelems)+1) > (size)) \
|
||||||
((v)=(t *)luaM_growaux(L,v,&(size),sizeof(t),limit,e))
|
((v)=cast(t *, luaM_growaux(L,v,&(size),sizeof(t),limit,e)))
|
||||||
|
|
||||||
#define luaM_reallocvector(L, v,oldn,n,t) \
|
#define luaM_reallocvector(L, v,oldn,n,t) \
|
||||||
((v)=(t *)luaM_realloc(L, v,(lu_mem)(oldn)*(lu_mem)sizeof(t), \
|
((v)=cast(t *, luaM_realloc(L, v,cast(lu_mem, oldn)*cast(lu_mem, sizeof(t)), \
|
||||||
(lu_mem)(n)*(lu_mem)sizeof(t)))
|
cast(lu_mem, n)*cast(lu_mem, sizeof(t)))))
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
205
loadlib.c
Normal file
205
loadlib.c
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
** $Id: loadlib.c,v 1.3 2003/04/02 13:09:14 roberto Exp roberto $
|
||||||
|
** Dynamic library loader for Lua
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*
|
||||||
|
* This Lua library exports a single function, called loadlib, which is
|
||||||
|
* called from Lua as loadlib(lib,init), where lib is the full name of the
|
||||||
|
* library to be loaded (including the complete path) and init is the name
|
||||||
|
* of a function to be called after the library is loaded. Typically, this
|
||||||
|
* function will register other functions, thus making the complete library
|
||||||
|
* available to Lua. The init function is *not* automatically called by
|
||||||
|
* loadlib. Instead, loadlib returns the init function as a Lua function
|
||||||
|
* that the client can call when it thinks is appropriate. In the case of
|
||||||
|
* errors, loadlib returns nil and two strings describing the error.
|
||||||
|
* The first string is supplied by the operating system; it should be
|
||||||
|
* informative and useful for error messages. The second string is "open",
|
||||||
|
* "init", or "absent" to identify the error and is meant to be used for
|
||||||
|
* making decisions without having to look into the first string (whose
|
||||||
|
* format is system-dependent).
|
||||||
|
*
|
||||||
|
* This module contains an implementation of loadlib for Unix systems that
|
||||||
|
* have dlfcn, an implementation for Windows, and a stub for other systems.
|
||||||
|
* See the list at the end of this file for some links to available
|
||||||
|
* implementations of dlfcn and interfaces to other native dynamic loaders
|
||||||
|
* on top of which loadlib could be implemented.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
|
#undef LOADLIB
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_DLOPEN
|
||||||
|
#define LOADLIB
|
||||||
|
/*
|
||||||
|
* This is an implementation of loadlib based on the dlfcn interface.
|
||||||
|
* The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
|
||||||
|
* NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
|
||||||
|
* as an emulation layer on top of native functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
static int loadlib(lua_State *L)
|
||||||
|
{
|
||||||
|
const char *path=luaL_checkstring(L,1);
|
||||||
|
const char *init=luaL_checkstring(L,2);
|
||||||
|
void *lib=dlopen(path,RTLD_NOW);
|
||||||
|
if (lib!=NULL)
|
||||||
|
{
|
||||||
|
lua_CFunction f=(lua_CFunction) dlsym(lib,init);
|
||||||
|
if (f!=NULL)
|
||||||
|
{
|
||||||
|
lua_pushlightuserdata(L,lib);
|
||||||
|
lua_pushcclosure(L,f,1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* else return appropriate error messages */
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L,dlerror());
|
||||||
|
lua_pushstring(L,(lib!=NULL) ? "init" : "open");
|
||||||
|
if (lib!=NULL) dlclose(lib);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** In Windows, default is to use dll; otherwise, default is not to use dll
|
||||||
|
*/
|
||||||
|
#ifndef USE_DLL
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define USE_DLL 1
|
||||||
|
#else
|
||||||
|
#define USE_DLL 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if USE_DLL
|
||||||
|
#define LOADLIB
|
||||||
|
/*
|
||||||
|
* This is an implementation of loadlib for Windows using native functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
static void pusherror(lua_State *L)
|
||||||
|
{
|
||||||
|
int error=GetLastError();
|
||||||
|
char buffer[128];
|
||||||
|
if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
0, error, 0, buffer, sizeof(buffer), 0))
|
||||||
|
lua_pushstring(L,buffer);
|
||||||
|
else
|
||||||
|
lua_pushfstring(L,"system error %d\n",error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loadlib(lua_State *L)
|
||||||
|
{
|
||||||
|
const char *path=luaL_checkstring(L,1);
|
||||||
|
const char *init=luaL_checkstring(L,2);
|
||||||
|
HINSTANCE lib=LoadLibrary(path);
|
||||||
|
if (lib!=NULL)
|
||||||
|
{
|
||||||
|
lua_CFunction f=(lua_CFunction) GetProcAddress(lib,init);
|
||||||
|
if (f!=NULL)
|
||||||
|
{
|
||||||
|
lua_pushlightuserdata(L,lib);
|
||||||
|
lua_pushcclosure(L,f,1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pushnil(L);
|
||||||
|
pusherror(L);
|
||||||
|
lua_pushstring(L,(lib!=NULL) ? "init" : "open");
|
||||||
|
if (lib!=NULL) FreeLibrary(lib);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LOADLIB
|
||||||
|
/* Fallback for other systems */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Those systems support dlopen, so they should have defined USE_DLOPEN.
|
||||||
|
** The default (no)implementation gives them a special error message.
|
||||||
|
*/
|
||||||
|
#ifdef linux
|
||||||
|
#define LOADLIB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef sun
|
||||||
|
#define LOADLIB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef sgi
|
||||||
|
#define LOADLIB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BSD
|
||||||
|
#define LOADLIB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define LOADLIB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LOADLIB
|
||||||
|
#undef LOADLIB
|
||||||
|
#define LOADLIB "`loadlib' not installed (check your Lua configuration)"
|
||||||
|
#else
|
||||||
|
#define LOADLIB "`loadlib' not supported"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int loadlib(lua_State *L)
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushliteral(L,LOADLIB);
|
||||||
|
lua_pushliteral(L,"absent");
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LUALIB_API int luaopen_loadlib (lua_State *L)
|
||||||
|
{
|
||||||
|
lua_register(L,"loadlib",loadlib);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here are some links to available implementations of dlfcn and
|
||||||
|
* interfaces to other native dynamic loaders on top of which loadlib
|
||||||
|
* could be implemented. Please send contributions and corrections to us.
|
||||||
|
*
|
||||||
|
* AIX
|
||||||
|
* Starting with AIX 4.2, dlfcn is included in the base OS.
|
||||||
|
* There is also an emulation package available.
|
||||||
|
* http://www.faqs.org/faqs/aix-faq/part4/section-21.html
|
||||||
|
*
|
||||||
|
* HPUX
|
||||||
|
* HPUX 11 has dlfcn. For HPUX 10 use shl_*.
|
||||||
|
* http://www.geda.seul.org/mailinglist/geda-dev37/msg00094.html
|
||||||
|
* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html
|
||||||
|
*
|
||||||
|
* Macintosh, Windows
|
||||||
|
* http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html
|
||||||
|
*
|
||||||
|
* Mac OS X/Darwin
|
||||||
|
* http://www.opendarwin.org/projects/dlcompat/
|
||||||
|
*
|
||||||
|
* GLIB has wrapper code for BeOS, OS2, Unix and Windows
|
||||||
|
* http://cvs.gnome.org/lxr/source/glib/gmodule/
|
||||||
|
*
|
||||||
|
*/
|
||||||
192
lobject.c
192
lobject.c
@@ -1,105 +1,195 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lobject.c,v 1.69 2001/03/07 12:27:06 roberto Exp roberto $
|
** $Id: lobject.c,v 1.96 2003/02/18 16:02:56 roberto Exp roberto $
|
||||||
** Some generic functions over Lua objects
|
** Some generic functions over Lua objects
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lobject_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
|
#include "lstring.h"
|
||||||
|
#include "lvm.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* function to convert a string to a lua_Number */
|
||||||
|
#ifndef lua_str2number
|
||||||
|
#define lua_str2number(s,p) strtod((s), (p))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
const TObject luaO_nilobject = {LUA_TNIL, {NULL}};
|
const TObject luaO_nilobject = {LUA_TNIL, {NULL}};
|
||||||
|
|
||||||
|
|
||||||
int luaO_equalObj (const TObject *t1, const TObject *t2) {
|
/*
|
||||||
|
** converts an integer to a "floating point byte", represented as
|
||||||
|
** (mmmmmxxx), where the real value is (xxx) * 2^(mmmmm)
|
||||||
|
*/
|
||||||
|
int luaO_int2fb (unsigned int x) {
|
||||||
|
int m = 0; /* mantissa */
|
||||||
|
while (x >= (1<<3)) {
|
||||||
|
x = (x+1) >> 1;
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
return (m << 3) | cast(int, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaO_log2 (unsigned int x) {
|
||||||
|
static const lu_byte log_8[255] = {
|
||||||
|
0,
|
||||||
|
1,1,
|
||||||
|
2,2,2,2,
|
||||||
|
3,3,3,3,3,3,3,3,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||||
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||||
|
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||||
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
||||||
|
};
|
||||||
|
if (x >= 0x00010000) {
|
||||||
|
if (x >= 0x01000000) return log_8[((x>>24) & 0xff) - 1]+24;
|
||||||
|
else return log_8[((x>>16) & 0xff) - 1]+16;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (x >= 0x00000100) return log_8[((x>>8) & 0xff) - 1]+8;
|
||||||
|
else if (x) return log_8[(x & 0xff) - 1];
|
||||||
|
return -1; /* special `log' for 0 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int luaO_rawequalObj (const TObject *t1, const TObject *t2) {
|
||||||
if (ttype(t1) != ttype(t2)) return 0;
|
if (ttype(t1) != ttype(t2)) return 0;
|
||||||
switch (ttype(t1)) {
|
else switch (ttype(t1)) {
|
||||||
case LUA_TNUMBER:
|
|
||||||
return nvalue(t1) == nvalue(t2);
|
|
||||||
case LUA_TNIL:
|
case LUA_TNIL:
|
||||||
return 1;
|
return 1;
|
||||||
default: /* all other types are equal if pointers are equal */
|
case LUA_TNUMBER:
|
||||||
return tsvalue(t1) == tsvalue(t2);
|
return nvalue(t1) == nvalue(t2);
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
return bvalue(t1) == bvalue(t2); /* boolean true must be 1 !! */
|
||||||
|
case LUA_TLIGHTUSERDATA:
|
||||||
|
return pvalue(t1) == pvalue(t2);
|
||||||
|
default:
|
||||||
|
lua_assert(iscollectable(t1));
|
||||||
|
return gcvalue(t1) == gcvalue(t2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *luaO_openspaceaux (lua_State *L, size_t n) {
|
int luaO_str2d (const char *s, lua_Number *result) {
|
||||||
if (n > G(L)->Mbuffsize) {
|
char *endptr;
|
||||||
G(L)->Mbuffer = luaM_realloc(L, G(L)->Mbuffer, G(L)->Mbuffsize, n);
|
|
||||||
G(L)->Mbuffsize = n;
|
|
||||||
}
|
|
||||||
return G(L)->Mbuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaO_str2d (const l_char *s, lua_Number *result) {
|
|
||||||
l_char *endptr;
|
|
||||||
lua_Number res = lua_str2number(s, &endptr);
|
lua_Number res = lua_str2number(s, &endptr);
|
||||||
if (endptr == s) return 0; /* no conversion */
|
if (endptr == s) return 0; /* no conversion */
|
||||||
while (isspace(uchar(*endptr))) endptr++;
|
while (isspace((unsigned char)(*endptr))) endptr++;
|
||||||
if (*endptr != l_c('\0')) return 0; /* invalid trailing characters? */
|
if (*endptr != '\0') return 0; /* invalid trailing characters? */
|
||||||
*result = res;
|
*result = res;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* maximum length of a string format for `luaO_verror' */
|
|
||||||
#define MAX_VERROR 280
|
|
||||||
|
|
||||||
/* this function needs to handle only '%d' and '%.XXs' formats */
|
static void pushstr (lua_State *L, const char *str) {
|
||||||
void luaO_verror (lua_State *L, const l_char *fmt, ...) {
|
setsvalue2s(L->top, luaS_new(L, str));
|
||||||
va_list argp;
|
incr_top(L);
|
||||||
l_char buff[MAX_VERROR]; /* to hold formatted message */
|
|
||||||
va_start(argp, fmt);
|
|
||||||
vsprintf(buff, fmt, argp);
|
|
||||||
va_end(argp);
|
|
||||||
luaD_error(L, buff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaO_chunkid (l_char *out, const l_char *source, int bufflen) {
|
/* this function handles only `%d', `%c', %f, and `%s' formats */
|
||||||
if (*source == l_c('=')) {
|
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||||
strncpy(out, source+1, bufflen); /* remove first char */
|
int n = 1;
|
||||||
out[bufflen-1] = l_c('\0'); /* ensures null termination */
|
pushstr(L, "");
|
||||||
|
for (;;) {
|
||||||
|
const char *e = strchr(fmt, '%');
|
||||||
|
if (e == NULL) break;
|
||||||
|
setsvalue2s(L->top, luaS_newlstr(L, fmt, e-fmt));
|
||||||
|
incr_top(L);
|
||||||
|
switch (*(e+1)) {
|
||||||
|
case 's':
|
||||||
|
pushstr(L, va_arg(argp, char *));
|
||||||
|
break;
|
||||||
|
case 'c': {
|
||||||
|
char buff[2];
|
||||||
|
buff[0] = cast(char, va_arg(argp, int));
|
||||||
|
buff[1] = '\0';
|
||||||
|
pushstr(L, buff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
setnvalue(L->top, cast(lua_Number, va_arg(argp, int)));
|
||||||
|
incr_top(L);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
setnvalue(L->top, cast(lua_Number, va_arg(argp, l_uacNumber)));
|
||||||
|
incr_top(L);
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
pushstr(L, "%");
|
||||||
|
break;
|
||||||
|
default: lua_assert(0);
|
||||||
|
}
|
||||||
|
n += 2;
|
||||||
|
fmt = e+2;
|
||||||
}
|
}
|
||||||
else {
|
pushstr(L, fmt);
|
||||||
if (*source == l_c('@')) {
|
luaV_concat(L, n+1, L->top - L->base - 1);
|
||||||
|
L->top -= n;
|
||||||
|
return svalue(L->top - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) {
|
||||||
|
const char *msg;
|
||||||
|
va_list argp;
|
||||||
|
va_start(argp, fmt);
|
||||||
|
msg = luaO_pushvfstring(L, fmt, argp);
|
||||||
|
va_end(argp);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaO_chunkid (char *out, const char *source, int bufflen) {
|
||||||
|
if (*source == '=') {
|
||||||
|
strncpy(out, source+1, bufflen); /* remove first char */
|
||||||
|
out[bufflen-1] = '\0'; /* ensures null termination */
|
||||||
|
}
|
||||||
|
else { /* out = "source", or "...source" */
|
||||||
|
if (*source == '@') {
|
||||||
int l;
|
int l;
|
||||||
source++; /* skip the `@' */
|
source++; /* skip the `@' */
|
||||||
bufflen -= sizeof(l_s("file `...%s'"));
|
bufflen -= sizeof(" `...' ");
|
||||||
l = strlen(source);
|
l = strlen(source);
|
||||||
|
strcpy(out, "");
|
||||||
if (l>bufflen) {
|
if (l>bufflen) {
|
||||||
source += (l-bufflen); /* get last part of file name */
|
source += (l-bufflen); /* get last part of file name */
|
||||||
sprintf(out, l_s("file `...%.99s'"), source);
|
strcat(out, "...");
|
||||||
}
|
}
|
||||||
else
|
strcat(out, source);
|
||||||
sprintf(out, l_s("file `%.99s'"), source);
|
|
||||||
}
|
}
|
||||||
else {
|
else { /* out = [string "string"] */
|
||||||
int len = strcspn(source, l_s("\n")); /* stop at first newline */
|
int len = strcspn(source, "\n"); /* stop at first newline */
|
||||||
bufflen -= sizeof(l_s("string \"%.*s...\""));
|
bufflen -= sizeof(" [string \"...\"] ");
|
||||||
if (len > bufflen) len = bufflen;
|
if (len > bufflen) len = bufflen;
|
||||||
if (source[len] != l_c('\0')) { /* must truncate? */
|
strcpy(out, "[string \"");
|
||||||
strcpy(out, l_s("string \""));
|
if (source[len] != '\0') { /* must truncate? */
|
||||||
out += strlen(out);
|
strncat(out, source, len);
|
||||||
strncpy(out, source, len);
|
strcat(out, "...");
|
||||||
strcpy(out+len, l_s("...\""));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sprintf(out, l_s("string \"%.99s\""), source);
|
strcat(out, source);
|
||||||
|
strcat(out, "\"]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
301
lobject.h
301
lobject.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lobject.h,v 1.108 2001/06/28 14:48:44 roberto Exp roberto $
|
** $Id: lobject.h,v 1.158 2003/02/18 16:02:56 roberto Exp roberto $
|
||||||
** Type definitions for Lua objects
|
** Type definitions for Lua objects
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -12,72 +12,163 @@
|
|||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef lua_assert
|
/* tags for values visible from Lua */
|
||||||
#define lua_assert(c) /* empty */
|
#define NUM_TAGS LUA_TTHREAD
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef UNUSED
|
/*
|
||||||
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
|
** Extra tags for non-values
|
||||||
#endif
|
*/
|
||||||
|
#define LUA_TPROTO (NUM_TAGS+1)
|
||||||
|
#define LUA_TUPVAL (NUM_TAGS+2)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Union of all collectable objects
|
||||||
|
*/
|
||||||
|
typedef union GCObject GCObject;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Common Header for all collectable objects (in macro form, to be
|
||||||
|
** included in other objects)
|
||||||
|
*/
|
||||||
|
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Common header in struct form
|
||||||
|
*/
|
||||||
|
typedef struct GCheader {
|
||||||
|
CommonHeader;
|
||||||
|
} GCheader;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* tags for values visible from Lua == first user-created tag */
|
|
||||||
#define NUM_TAGS 6
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Union of all Lua values
|
||||||
|
*/
|
||||||
typedef union {
|
typedef union {
|
||||||
union TString *ts;
|
GCObject *gc;
|
||||||
union Udata *u;
|
void *p;
|
||||||
struct Closure *cl;
|
lua_Number n;
|
||||||
struct Hash *h;
|
int b;
|
||||||
lua_Number n; /* LUA_TNUMBER */
|
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Lua values (or `tagged objects')
|
||||||
|
*/
|
||||||
typedef struct lua_TObject {
|
typedef struct lua_TObject {
|
||||||
int tt;
|
int tt;
|
||||||
Value value;
|
Value value;
|
||||||
} TObject;
|
} TObject;
|
||||||
|
|
||||||
|
|
||||||
/* Macros to access values */
|
/* Macros to test type */
|
||||||
#define ttype(o) ((o)->tt)
|
#define ttisnil(o) (ttype(o) == LUA_TNIL)
|
||||||
#define nvalue(o) ((o)->value.n)
|
#define ttisnumber(o) (ttype(o) == LUA_TNUMBER)
|
||||||
#define tsvalue(o) ((o)->value.ts)
|
#define ttisstring(o) (ttype(o) == LUA_TSTRING)
|
||||||
#define uvalue(o) ((o)->value.u)
|
#define ttistable(o) (ttype(o) == LUA_TTABLE)
|
||||||
#define clvalue(o) ((o)->value.cl)
|
#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
|
||||||
#define hvalue(o) ((o)->value.h)
|
#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
|
||||||
|
#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
|
||||||
|
#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
|
||||||
|
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
|
||||||
|
|
||||||
|
/* Macros to access values */
|
||||||
|
#define ttype(o) ((o)->tt)
|
||||||
|
#define gcvalue(o) check_exp(iscollectable(o), (o)->value.gc)
|
||||||
|
#define pvalue(o) check_exp(ttislightuserdata(o), (o)->value.p)
|
||||||
|
#define nvalue(o) check_exp(ttisnumber(o), (o)->value.n)
|
||||||
|
#define tsvalue(o) check_exp(ttisstring(o), &(o)->value.gc->ts)
|
||||||
|
#define uvalue(o) check_exp(ttisuserdata(o), &(o)->value.gc->u)
|
||||||
|
#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl)
|
||||||
|
#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h)
|
||||||
|
#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b)
|
||||||
|
#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th)
|
||||||
|
|
||||||
|
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
|
||||||
|
|
||||||
/* Macros to set values */
|
/* Macros to set values */
|
||||||
#define setnvalue(obj,x) \
|
#define setnvalue(obj,x) \
|
||||||
{ TObject *_o=(obj); _o->tt=LUA_TNUMBER; _o->value.n=(x); }
|
{ TObject *i_o=(obj); i_o->tt=LUA_TNUMBER; i_o->value.n=(x); }
|
||||||
|
|
||||||
#define chgnvalue(obj,x) ((obj)->value.n=(x))
|
#define chgnvalue(obj,x) \
|
||||||
|
check_exp(ttype(obj)==LUA_TNUMBER, (obj)->value.n=(x))
|
||||||
|
|
||||||
|
#define setpvalue(obj,x) \
|
||||||
|
{ TObject *i_o=(obj); i_o->tt=LUA_TLIGHTUSERDATA; i_o->value.p=(x); }
|
||||||
|
|
||||||
|
#define setbvalue(obj,x) \
|
||||||
|
{ TObject *i_o=(obj); i_o->tt=LUA_TBOOLEAN; i_o->value.b=(x); }
|
||||||
|
|
||||||
#define setsvalue(obj,x) \
|
#define setsvalue(obj,x) \
|
||||||
{ TObject *_o=(obj); _o->tt=LUA_TSTRING; _o->value.ts=(x); }
|
{ TObject *i_o=(obj); i_o->tt=LUA_TSTRING; \
|
||||||
|
i_o->value.gc=cast(GCObject *, (x)); \
|
||||||
|
lua_assert(i_o->value.gc->gch.tt == LUA_TSTRING); }
|
||||||
|
|
||||||
#define setuvalue(obj,x) \
|
#define setuvalue(obj,x) \
|
||||||
{ TObject *_o=(obj); _o->tt=LUA_TUSERDATA; _o->value.u=(x); }
|
{ TObject *i_o=(obj); i_o->tt=LUA_TUSERDATA; \
|
||||||
|
i_o->value.gc=cast(GCObject *, (x)); \
|
||||||
|
lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); }
|
||||||
|
|
||||||
|
#define setthvalue(obj,x) \
|
||||||
|
{ TObject *i_o=(obj); i_o->tt=LUA_TTHREAD; \
|
||||||
|
i_o->value.gc=cast(GCObject *, (x)); \
|
||||||
|
lua_assert(i_o->value.gc->gch.tt == LUA_TTHREAD); }
|
||||||
|
|
||||||
#define setclvalue(obj,x) \
|
#define setclvalue(obj,x) \
|
||||||
{ TObject *_o=(obj); _o->tt=LUA_TFUNCTION; _o->value.cl=(x); }
|
{ TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \
|
||||||
|
i_o->value.gc=cast(GCObject *, (x)); \
|
||||||
|
lua_assert(i_o->value.gc->gch.tt == LUA_TFUNCTION); }
|
||||||
|
|
||||||
#define sethvalue(obj,x) \
|
#define sethvalue(obj,x) \
|
||||||
{ TObject *_o=(obj); _o->tt=LUA_TTABLE; _o->value.h=(x); }
|
{ TObject *i_o=(obj); i_o->tt=LUA_TTABLE; \
|
||||||
|
i_o->value.gc=cast(GCObject *, (x)); \
|
||||||
|
lua_assert(i_o->value.gc->gch.tt == LUA_TTABLE); }
|
||||||
|
|
||||||
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
|
#define setnilvalue(obj) ((obj)->tt=LUA_TNIL)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** for internal debug only
|
||||||
|
*/
|
||||||
|
#define checkconsistency(obj) \
|
||||||
|
lua_assert(!iscollectable(obj) || (ttype(obj) == (obj)->value.gc->gch.tt))
|
||||||
|
|
||||||
|
|
||||||
#define setobj(obj1,obj2) \
|
#define setobj(obj1,obj2) \
|
||||||
{ TObject *o1=(obj1); const TObject *o2=(obj2); \
|
{ const TObject *o2=(obj2); TObject *o1=(obj1); \
|
||||||
|
checkconsistency(o2); \
|
||||||
o1->tt=o2->tt; o1->value = o2->value; }
|
o1->tt=o2->tt; o1->value = o2->value; }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** different types of sets, according to destination
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* from stack to (same) stack */
|
||||||
|
#define setobjs2s setobj
|
||||||
|
/* to stack (not from same stack) */
|
||||||
|
#define setobj2s setobj
|
||||||
|
#define setsvalue2s setsvalue
|
||||||
|
/* from table to same table */
|
||||||
|
#define setobjt2t setobj
|
||||||
|
/* to table */
|
||||||
|
#define setobj2t setobj
|
||||||
|
/* to new object */
|
||||||
|
#define setobj2n setobj
|
||||||
|
#define setsvalue2n setsvalue
|
||||||
|
|
||||||
#define setttype(obj, tt) (ttype(obj) = (tt))
|
#define setttype(obj, tt) (ttype(obj) = (tt))
|
||||||
|
|
||||||
|
|
||||||
|
#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef TObject *StkId; /* index to stack elements */
|
typedef TObject *StkId; /* index to stack elements */
|
||||||
|
|
||||||
@@ -86,61 +177,57 @@ typedef TObject *StkId; /* index to stack elements */
|
|||||||
** String headers for string table
|
** String headers for string table
|
||||||
*/
|
*/
|
||||||
typedef union TString {
|
typedef union TString {
|
||||||
union L_Umaxalign dummy; /* ensures maximum alignment for strings */
|
L_Umaxalign dummy; /* ensures maximum alignment for strings */
|
||||||
struct {
|
struct {
|
||||||
|
CommonHeader;
|
||||||
|
lu_byte reserved;
|
||||||
lu_hash hash;
|
lu_hash hash;
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned short constindex; /* hint to reuse constants */
|
|
||||||
short marked;
|
|
||||||
union TString *nexthash; /* chain for hash table */
|
|
||||||
} tsv;
|
} tsv;
|
||||||
} TString;
|
} TString;
|
||||||
|
|
||||||
|
|
||||||
#define getstr(ts) ((l_char *)((ts) + 1))
|
#define getstr(ts) cast(const char *, (ts) + 1)
|
||||||
#define svalue(o) getstr(tsvalue(o))
|
#define svalue(o) getstr(tsvalue(o))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef union Udata {
|
typedef union Udata {
|
||||||
union L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
|
L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
|
||||||
struct {
|
struct {
|
||||||
int tag; /* negative means `marked' (only during GC) */
|
CommonHeader;
|
||||||
void *value;
|
struct Table *metatable;
|
||||||
size_t len;
|
size_t len;
|
||||||
union Udata *next; /* chain for list of all udata */
|
|
||||||
} uv;
|
} uv;
|
||||||
} Udata;
|
} Udata;
|
||||||
|
|
||||||
|
|
||||||
#define switchudatamark(u) ((u)->uv.tag = (-((u)->uv.tag+1)))
|
|
||||||
#define ismarkedudata(u) ((u)->uv.tag < 0)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Function Prototypes
|
** Function Prototypes
|
||||||
*/
|
*/
|
||||||
typedef struct Proto {
|
typedef struct Proto {
|
||||||
|
CommonHeader;
|
||||||
TObject *k; /* constants used by the function */
|
TObject *k; /* constants used by the function */
|
||||||
int sizek; /* size of `k' */
|
|
||||||
struct Proto **p; /* functions defined inside the function */
|
|
||||||
int sizep; /* size of `p' */
|
|
||||||
Instruction *code;
|
Instruction *code;
|
||||||
int sizecode;
|
struct Proto **p; /* functions defined inside the function */
|
||||||
short nupvalues;
|
|
||||||
short numparams;
|
|
||||||
short is_vararg;
|
|
||||||
short maxstacksize;
|
|
||||||
short marked;
|
|
||||||
struct Proto *next;
|
|
||||||
/* debug information */
|
|
||||||
int *lineinfo; /* map from opcodes to source lines */
|
int *lineinfo; /* map from opcodes to source lines */
|
||||||
int sizelineinfo; /* size of `lineinfo' */
|
|
||||||
struct LocVar *locvars; /* information about local variables */
|
struct LocVar *locvars; /* information about local variables */
|
||||||
|
TString **upvalues; /* upvalue names */
|
||||||
|
TString *source;
|
||||||
|
int sizeupvalues;
|
||||||
|
int sizek; /* size of `k' */
|
||||||
|
int sizecode;
|
||||||
|
int sizelineinfo;
|
||||||
|
int sizep; /* size of `p' */
|
||||||
int sizelocvars;
|
int sizelocvars;
|
||||||
int lineDefined;
|
int lineDefined;
|
||||||
TString *source;
|
GCObject *gclist;
|
||||||
|
lu_byte nups; /* number of upvalues */
|
||||||
|
lu_byte numparams;
|
||||||
|
lu_byte is_vararg;
|
||||||
|
lu_byte maxstacksize;
|
||||||
} Proto;
|
} Proto;
|
||||||
|
|
||||||
|
|
||||||
@@ -151,81 +238,99 @@ typedef struct LocVar {
|
|||||||
} LocVar;
|
} LocVar;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Upvalues
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct UpVal {
|
||||||
|
CommonHeader;
|
||||||
|
TObject *v; /* points to stack or to its own value */
|
||||||
|
TObject value; /* the value (when closed) */
|
||||||
|
} UpVal;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Closures
|
** Closures
|
||||||
*/
|
*/
|
||||||
typedef struct Closure {
|
|
||||||
int isC; /* 0 for Lua functions, 1 for C functions */
|
#define ClosureHeader \
|
||||||
int nupvalues;
|
CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist
|
||||||
union {
|
|
||||||
lua_CFunction c; /* C functions */
|
typedef struct CClosure {
|
||||||
struct Proto *l; /* Lua functions */
|
ClosureHeader;
|
||||||
} f;
|
lua_CFunction f;
|
||||||
struct Closure *next;
|
|
||||||
struct Closure *mark; /* marked closures (point to itself when not marked) */
|
|
||||||
TObject upvalue[1];
|
TObject upvalue[1];
|
||||||
|
} CClosure;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct LClosure {
|
||||||
|
ClosureHeader;
|
||||||
|
struct Proto *p;
|
||||||
|
TObject g; /* global table for this closure */
|
||||||
|
UpVal *upvals[1];
|
||||||
|
} LClosure;
|
||||||
|
|
||||||
|
|
||||||
|
typedef union Closure {
|
||||||
|
CClosure c;
|
||||||
|
LClosure l;
|
||||||
} Closure;
|
} Closure;
|
||||||
|
|
||||||
|
|
||||||
#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->isC)
|
#define iscfunction(o) (ttype(o) == LUA_TFUNCTION && clvalue(o)->c.isC)
|
||||||
|
#define isLfunction(o) (ttype(o) == LUA_TFUNCTION && !clvalue(o)->c.isC)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Tables
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct Node {
|
typedef struct Node {
|
||||||
|
TObject i_key;
|
||||||
|
TObject i_val;
|
||||||
struct Node *next; /* for chaining */
|
struct Node *next; /* for chaining */
|
||||||
TObject key;
|
|
||||||
TObject val;
|
|
||||||
} Node;
|
} Node;
|
||||||
|
|
||||||
|
|
||||||
typedef struct Hash {
|
typedef struct Table {
|
||||||
|
CommonHeader;
|
||||||
|
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
|
||||||
|
lu_byte lsizenode; /* log2 of size of `node' array */
|
||||||
|
struct Table *metatable;
|
||||||
|
TObject *array; /* array part */
|
||||||
Node *node;
|
Node *node;
|
||||||
int htag;
|
|
||||||
int size;
|
|
||||||
Node *firstfree; /* this position is free; all positions after it are full */
|
Node *firstfree; /* this position is free; all positions after it are full */
|
||||||
struct Hash *next;
|
GCObject *gclist;
|
||||||
struct Hash *mark; /* marked tables (point to itself when not marked) */
|
int sizearray; /* size of `array' array */
|
||||||
int weakmode;
|
} Table;
|
||||||
} Hash;
|
|
||||||
|
|
||||||
|
|
||||||
/* unmarked tables and closures are represented by pointing `mark' to
|
|
||||||
** themselves
|
|
||||||
*/
|
|
||||||
#define ismarked(x) ((x)->mark != (x))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** `module' operation for hashing (size is always a power of 2)
|
** `module' operation for hashing (size is always a power of 2)
|
||||||
*/
|
*/
|
||||||
#define lmod(s,size) ((int)((s) & ((size)-1)))
|
#define lmod(s,size) \
|
||||||
|
check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1))))
|
||||||
|
|
||||||
|
|
||||||
/*
|
#define twoto(x) (1<<(x))
|
||||||
** informations about a call (for debugging)
|
#define sizenode(t) (twoto((t)->lsizenode))
|
||||||
*/
|
|
||||||
typedef struct CallInfo {
|
|
||||||
struct CallInfo *prev; /* linked list */
|
|
||||||
StkId base; /* base for called function */
|
|
||||||
const Instruction **pc; /* current pc of called function */
|
|
||||||
int lastpc; /* last pc traced */
|
|
||||||
int line; /* current line */
|
|
||||||
int refi; /* current index in `lineinfo' */
|
|
||||||
} CallInfo;
|
|
||||||
|
|
||||||
#define ci_func(ci) (clvalue((ci)->base - 1))
|
|
||||||
|
|
||||||
|
|
||||||
extern const TObject luaO_nilobject;
|
extern const TObject luaO_nilobject;
|
||||||
|
|
||||||
|
int luaO_log2 (unsigned int x);
|
||||||
|
int luaO_int2fb (unsigned int x);
|
||||||
|
#define fb2int(x) (((x) & 7) << ((x) >> 3))
|
||||||
|
|
||||||
#define luaO_openspace(L,n,t) ((t *)luaO_openspaceaux(L,(n)*sizeof(t)))
|
int luaO_rawequalObj (const TObject *t1, const TObject *t2);
|
||||||
void *luaO_openspaceaux (lua_State *L, size_t n);
|
int luaO_str2d (const char *s, lua_Number *result);
|
||||||
|
|
||||||
int luaO_equalObj (const TObject *t1, const TObject *t2);
|
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp);
|
||||||
int luaO_str2d (const l_char *s, lua_Number *result);
|
const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
|
||||||
|
void luaO_chunkid (char *out, const char *source, int len);
|
||||||
void luaO_verror (lua_State *L, const l_char *fmt, ...);
|
|
||||||
void luaO_chunkid (l_char *out, const l_char *source, int len);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
165
lopcodes.c
165
lopcodes.c
@@ -1,107 +1,102 @@
|
|||||||
/*
|
/*
|
||||||
** $Id:$
|
** $Id: lopcodes.c,v 1.21 2002/08/20 20:03:05 roberto Exp roberto $
|
||||||
** extracted automatically from lopcodes.h by mkprint.lua
|
** extracted automatically from lopcodes.h by mkprint.lua
|
||||||
** DO NOT EDIT
|
** DO NOT EDIT
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lopcodes_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lobject.h"
|
||||||
#include "lopcodes.h"
|
#include "lopcodes.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef LUA_OPNAMES
|
#ifdef LUA_OPNAMES
|
||||||
|
|
||||||
const l_char *const luaP_opnames[] = {
|
const char *const luaP_opnames[] = {
|
||||||
l_s("MOVE"),
|
"MOVE",
|
||||||
l_s("LOADK"),
|
"LOADK",
|
||||||
l_s("LOADINT"),
|
"LOADBOOL",
|
||||||
l_s("LOADNIL"),
|
"LOADNIL",
|
||||||
l_s("LOADUPVAL"),
|
"GETUPVAL",
|
||||||
l_s("GETGLOBAL"),
|
"GETGLOBAL",
|
||||||
l_s("GETTABLE"),
|
"GETTABLE",
|
||||||
l_s("SETGLOBAL"),
|
"SETGLOBAL",
|
||||||
l_s("SETTABLE"),
|
"SETUPVAL",
|
||||||
l_s("NEWTABLE"),
|
"SETTABLE",
|
||||||
l_s("SELF"),
|
"NEWTABLE",
|
||||||
l_s("ADD"),
|
"SELF",
|
||||||
l_s("SUB"),
|
"ADD",
|
||||||
l_s("MUL"),
|
"SUB",
|
||||||
l_s("DIV"),
|
"MUL",
|
||||||
l_s("POW"),
|
"DIV",
|
||||||
l_s("UNM"),
|
"POW",
|
||||||
l_s("NOT"),
|
"UNM",
|
||||||
l_s("CONCAT"),
|
"NOT",
|
||||||
l_s("JMP"),
|
"CONCAT",
|
||||||
l_s("CJMP"),
|
"JMP",
|
||||||
l_s("TESTEQ"),
|
"EQ",
|
||||||
l_s("TESTNE"),
|
"LT",
|
||||||
l_s("TESTLT"),
|
"LE",
|
||||||
l_s("TESTLE"),
|
"TEST",
|
||||||
l_s("TESTGT"),
|
"CALL",
|
||||||
l_s("TESTGE"),
|
"TAILCALL",
|
||||||
l_s("TESTT"),
|
"RETURN",
|
||||||
l_s("TESTF"),
|
"FORLOOP",
|
||||||
l_s("NILJMP"),
|
"TFORLOOP",
|
||||||
l_s("CALL"),
|
"TFORPREP",
|
||||||
l_s("RETURN"),
|
"SETLIST",
|
||||||
l_s("FORPREP"),
|
"SETLISTO",
|
||||||
l_s("FORLOOP"),
|
"CLOSE",
|
||||||
l_s("TFORPREP"),
|
"CLOSURE"
|
||||||
l_s("TFORLOOP"),
|
|
||||||
l_s("SETLIST"),
|
|
||||||
l_s("SETLISTO"),
|
|
||||||
l_s("CLOSURE")
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define opmode(t,x,b,c,sa,k,m) (((t)<<OpModeT) | \
|
#define opmode(t,b,bk,ck,sa,k,m) (((t)<<OpModeT) | \
|
||||||
((b)<<OpModeBreg) | ((c)<<OpModeCreg) | \
|
((b)<<OpModeBreg) | ((bk)<<OpModeBrk) | ((ck)<<OpModeCrk) | \
|
||||||
((sa)<<OpModesetA) | ((k)<<OpModeK) | (m))
|
((sa)<<OpModesetA) | ((k)<<OpModeK) | (m))
|
||||||
|
|
||||||
const lu_byte luaP_opmodes[] = {
|
|
||||||
/* T _ B C sA K mode opcode */
|
const lu_byte luaP_opmodes[NUM_OPCODES] = {
|
||||||
opmode(0,0,1,0, 1,0,iABC) /* OP_MOVE */
|
/* T B Bk Ck sA K mode opcode */
|
||||||
,opmode(0,0,0,0, 1,1,iABc) /* OP_LOADK */
|
opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_MOVE */
|
||||||
,opmode(0,0,0,0, 1,0,iAsBc) /* OP_LOADINT */
|
,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_LOADK */
|
||||||
,opmode(0,0,1,0, 1,0,iABC) /* OP_LOADNIL */
|
,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_LOADBOOL */
|
||||||
,opmode(0,0,0,0, 1,0,iABc) /* OP_LOADUPVAL */
|
,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_LOADNIL */
|
||||||
,opmode(0,0,0,0, 1,1,iABc) /* OP_GETGLOBAL */
|
,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_GETUPVAL */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_GETTABLE */
|
,opmode(0, 0, 0, 0, 1, 1, iABx) /* OP_GETGLOBAL */
|
||||||
,opmode(0,0,0,0, 0,1,iABc) /* OP_SETGLOBAL */
|
,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_GETTABLE */
|
||||||
,opmode(0,0,1,1, 0,0,iABC) /* OP_SETTABLE */
|
,opmode(0, 0, 0, 0, 0, 1, iABx) /* OP_SETGLOBAL */
|
||||||
,opmode(0,0,0,0, 1,0,iABc) /* OP_NEWTABLE */
|
,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_SETUPVAL */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_SELF */
|
,opmode(0, 0, 1, 1, 0, 0, iABC) /* OP_SETTABLE */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_ADD */
|
,opmode(0, 0, 0, 0, 1, 0, iABC) /* OP_NEWTABLE */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_SUB */
|
,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_SELF */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_MUL */
|
,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_ADD */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_DIV */
|
,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_SUB */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_POW */
|
,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_MUL */
|
||||||
,opmode(0,0,1,0, 1,0,iABC) /* OP_UNM */
|
,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_DIV */
|
||||||
,opmode(0,0,1,0, 1,0,iABC) /* OP_NOT */
|
,opmode(0, 0, 1, 1, 1, 0, iABC) /* OP_POW */
|
||||||
,opmode(0,0,1,1, 1,0,iABC) /* OP_CONCAT */
|
,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_UNM */
|
||||||
,opmode(0,0,0,0, 0,0,iAsBc) /* OP_JMP */
|
,opmode(0, 1, 0, 0, 1, 0, iABC) /* OP_NOT */
|
||||||
,opmode(0,0,0,0, 0,0,iAsBc) /* OP_CJMP */
|
,opmode(0, 1, 0, 1, 1, 0, iABC) /* OP_CONCAT */
|
||||||
,opmode(1,0,0,1, 0,0,iABC) /* OP_TESTEQ */
|
,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_JMP */
|
||||||
,opmode(1,0,0,1, 0,0,iABC) /* OP_TESTNE */
|
,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_EQ */
|
||||||
,opmode(1,0,0,1, 0,0,iABC) /* OP_TESTLT */
|
,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LT */
|
||||||
,opmode(1,0,0,1, 0,0,iABC) /* OP_TESTLE */
|
,opmode(1, 0, 1, 1, 0, 0, iABC) /* OP_LE */
|
||||||
,opmode(1,0,0,1, 0,0,iABC) /* OP_TESTGT */
|
,opmode(1, 1, 0, 0, 1, 0, iABC) /* OP_TEST */
|
||||||
,opmode(1,0,0,1, 0,0,iABC) /* OP_TESTGE */
|
,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CALL */
|
||||||
,opmode(1,0,1,0, 1,0,iABC) /* OP_TESTT */
|
,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_TAILCALL */
|
||||||
,opmode(1,0,1,0, 1,0,iABC) /* OP_TESTF */
|
,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_RETURN */
|
||||||
,opmode(0,0,0,0, 1,0,iABc) /* OP_NILJMP */
|
,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_FORLOOP */
|
||||||
,opmode(0,0,0,0, 0,0,iABC) /* OP_CALL */
|
,opmode(1, 0, 0, 0, 0, 0, iABC) /* OP_TFORLOOP */
|
||||||
,opmode(0,0,0,0, 0,0,iABC) /* OP_RETURN */
|
,opmode(0, 0, 0, 0, 0, 0, iAsBx) /* OP_TFORPREP */
|
||||||
,opmode(0,0,0,0, 0,0,iAsBc) /* OP_FORPREP */
|
,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLIST */
|
||||||
,opmode(0,0,0,0, 0,0,iAsBc) /* OP_FORLOOP */
|
,opmode(0, 0, 0, 0, 0, 0, iABx) /* OP_SETLISTO */
|
||||||
,opmode(0,0,0,0, 0,0,iAsBc) /* OP_TFORPREP */
|
,opmode(0, 0, 0, 0, 0, 0, iABC) /* OP_CLOSE */
|
||||||
,opmode(0,0,0,0, 0,0,iAsBc) /* OP_TFORLOOP */
|
,opmode(0, 0, 0, 0, 1, 0, iABx) /* OP_CLOSURE */
|
||||||
,opmode(0,0,0,0, 0,0,iABc) /* OP_SETLIST */
|
|
||||||
,opmode(0,0,0,0, 0,0,iABc) /* OP_SETLISTO */
|
|
||||||
,opmode(0,0,0,0, 1,0,iABc) /* OP_CLOSURE */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
190
lopcodes.h
190
lopcodes.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lopcodes.h,v 1.77 2001/07/03 17:01:34 roberto Exp roberto $
|
** $Id: lopcodes.h,v 1.101 2002/08/20 20:03:05 roberto Exp roberto $
|
||||||
** Opcodes for Lua virtual machine
|
** Opcodes for Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -14,11 +14,11 @@
|
|||||||
We assume that instructions are unsigned numbers.
|
We assume that instructions are unsigned numbers.
|
||||||
All instructions have an opcode in the first 6 bits.
|
All instructions have an opcode in the first 6 bits.
|
||||||
Instructions can have the following fields:
|
Instructions can have the following fields:
|
||||||
`A' : 8 bits (25-32)
|
`A' : 8 bits
|
||||||
`B' : 8 bits (17-24)
|
`B' : 9 bits
|
||||||
`C' : 10 bits (7-16)
|
`C' : 9 bits
|
||||||
`Bc' : 18 bits (`B' and `C' together)
|
`Bx' : 18 bits (`B' and `C' together)
|
||||||
`sBc' : signed Bc
|
`sBx' : signed Bx
|
||||||
|
|
||||||
A signed argument is represented in excess K; that is, the number
|
A signed argument is represented in excess K; that is, the number
|
||||||
value is the unsigned value minus K. K is exactly the maximum value
|
value is the unsigned value minus K. K is exactly the maximum value
|
||||||
@@ -28,22 +28,22 @@
|
|||||||
===========================================================================*/
|
===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
enum OpMode {iABC, iABc, iAsBc}; /* basic instruction format */
|
enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** size and position of opcode arguments.
|
** size and position of opcode arguments.
|
||||||
*/
|
*/
|
||||||
#define SIZE_C 10
|
#define SIZE_C 9
|
||||||
#define SIZE_B 8
|
#define SIZE_B 9
|
||||||
#define SIZE_Bc (SIZE_C + SIZE_B)
|
#define SIZE_Bx (SIZE_C + SIZE_B)
|
||||||
#define SIZE_A 8
|
#define SIZE_A 8
|
||||||
|
|
||||||
#define SIZE_OP 6
|
#define SIZE_OP 6
|
||||||
|
|
||||||
#define POS_C SIZE_OP
|
#define POS_C SIZE_OP
|
||||||
#define POS_B (POS_C + SIZE_C)
|
#define POS_B (POS_C + SIZE_C)
|
||||||
#define POS_Bc POS_C
|
#define POS_Bx POS_C
|
||||||
#define POS_A (POS_B + SIZE_B)
|
#define POS_A (POS_B + SIZE_B)
|
||||||
|
|
||||||
|
|
||||||
@@ -52,12 +52,12 @@ enum OpMode {iABC, iABc, iAsBc}; /* basic instruction format */
|
|||||||
** we use (signed) int to manipulate most arguments,
|
** we use (signed) int to manipulate most arguments,
|
||||||
** so they must fit in BITS_INT-1 bits (-1 for sign)
|
** so they must fit in BITS_INT-1 bits (-1 for sign)
|
||||||
*/
|
*/
|
||||||
#if SIZE_Bc < BITS_INT-1
|
#if SIZE_Bx < BITS_INT-1
|
||||||
#define MAXARG_Bc ((1<<SIZE_Bc)-1)
|
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
|
||||||
#define MAXARG_sBc (MAXARG_Bc>>1) /* `sBc' is signed */
|
#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */
|
||||||
#else
|
#else
|
||||||
#define MAXARG_Bc MAX_INT
|
#define MAXARG_Bx MAX_INT
|
||||||
#define MAXARG_sBc MAX_INT
|
#define MAXARG_sBx MAX_INT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -76,43 +76,43 @@ enum OpMode {iABC, iABc, iAsBc}; /* basic instruction format */
|
|||||||
** the following macros help to manipulate instructions
|
** the following macros help to manipulate instructions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define GET_OPCODE(i) ((OpCode)((i)&MASK1(SIZE_OP,0)))
|
#define GET_OPCODE(i) (cast(OpCode, (i)&MASK1(SIZE_OP,0)))
|
||||||
#define SET_OPCODE(i,o) (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o))
|
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,0)) | cast(Instruction, o)))
|
||||||
|
|
||||||
#define GETARG_A(i) ((int)((i)>>POS_A))
|
#define GETARG_A(i) (cast(int, (i)>>POS_A))
|
||||||
#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
|
#define SETARG_A(i,u) ((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
|
||||||
((Instruction)(u)<<POS_A)))
|
((cast(Instruction, u)<<POS_A)&MASK1(SIZE_A,POS_A))))
|
||||||
|
|
||||||
#define GETARG_B(i) ((int)(((i)>>POS_B) & MASK1(SIZE_B,0)))
|
#define GETARG_B(i) (cast(int, ((i)>>POS_B) & MASK1(SIZE_B,0)))
|
||||||
#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
|
#define SETARG_B(i,b) ((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
|
||||||
((Instruction)(b)<<POS_B)))
|
((cast(Instruction, b)<<POS_B)&MASK1(SIZE_B,POS_B))))
|
||||||
|
|
||||||
#define GETARG_C(i) ((int)(((i)>>POS_C) & MASK1(SIZE_C,0)))
|
#define GETARG_C(i) (cast(int, ((i)>>POS_C) & MASK1(SIZE_C,0)))
|
||||||
#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
|
#define SETARG_C(i,b) ((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
|
||||||
((Instruction)(b)<<POS_C)))
|
((cast(Instruction, b)<<POS_C)&MASK1(SIZE_C,POS_C))))
|
||||||
|
|
||||||
#define GETARG_Bc(i) ((int)(((i)>>POS_Bc) & MASK1(SIZE_Bc,0)))
|
#define GETARG_Bx(i) (cast(int, ((i)>>POS_Bx) & MASK1(SIZE_Bx,0)))
|
||||||
#define SETARG_Bc(i,b) ((i) = (((i)&MASK0(SIZE_Bc,POS_Bc)) | \
|
#define SETARG_Bx(i,b) ((i) = (((i)&MASK0(SIZE_Bx,POS_Bx)) | \
|
||||||
((Instruction)(b)<<POS_Bc)))
|
((cast(Instruction, b)<<POS_Bx)&MASK1(SIZE_Bx,POS_Bx))))
|
||||||
|
|
||||||
#define GETARG_sBc(i) (GETARG_Bc(i)-MAXARG_sBc)
|
#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
|
||||||
#define SETARG_sBc(i,b) SETARG_Bc((i),(unsigned int)((b)+MAXARG_sBc))
|
#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
|
||||||
|
|
||||||
|
|
||||||
#define CREATE_ABC(o,a,b,c) ((Instruction)(o) \
|
#define CREATE_ABC(o,a,b,c) (cast(Instruction, o) \
|
||||||
| ((Instruction)(a)<<POS_A) \
|
| (cast(Instruction, a)<<POS_A) \
|
||||||
| ((Instruction)(b)<<POS_B) \
|
| (cast(Instruction, b)<<POS_B) \
|
||||||
| ((Instruction)(c)<<POS_C))
|
| (cast(Instruction, c)<<POS_C))
|
||||||
|
|
||||||
#define CREATE_ABc(o,a,bc) ((Instruction)(o) \
|
#define CREATE_ABx(o,a,bc) (cast(Instruction, o) \
|
||||||
| ((Instruction)(a)<<POS_A) \
|
| (cast(Instruction, a)<<POS_A) \
|
||||||
| ((Instruction)(bc)<<POS_Bc))
|
| (cast(Instruction, bc)<<POS_Bx))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** an invalid register that fits in 8 bits
|
** invalid register that fits in 8 bits
|
||||||
*/
|
*/
|
||||||
#define NO_REG MAXARG_A
|
#define NO_REG MAXARG_A
|
||||||
|
|
||||||
@@ -120,7 +120,12 @@ enum OpMode {iABC, iABc, iAsBc}; /* basic instruction format */
|
|||||||
/*
|
/*
|
||||||
** R(x) - register
|
** R(x) - register
|
||||||
** Kst(x) - constant (in constant table)
|
** Kst(x) - constant (in constant table)
|
||||||
** R/K(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
|
** RK(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** grep "ORDER OP" if you change these enums
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -128,78 +133,75 @@ typedef enum {
|
|||||||
name args description
|
name args description
|
||||||
------------------------------------------------------------------------*/
|
------------------------------------------------------------------------*/
|
||||||
OP_MOVE,/* A B R(A) := R(B) */
|
OP_MOVE,/* A B R(A) := R(B) */
|
||||||
OP_LOADK,/* A Bc R(A) := Kst(Bc) */
|
OP_LOADK,/* A Bx R(A) := Kst(Bx) */
|
||||||
OP_LOADINT,/* A sBc R(A) := (Number)sBc */
|
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) PC++ */
|
||||||
OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
|
OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */
|
||||||
OP_LOADUPVAL,/* A Bc R(A) := UpValue[Bc] */
|
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
|
||||||
|
|
||||||
OP_GETGLOBAL,/* A Bc R(A) := Gbl[Kst(Bc)] */
|
OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */
|
||||||
OP_GETTABLE,/* A B C R(A) := R(B)[R/K(C)] */
|
OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
|
||||||
|
|
||||||
OP_SETGLOBAL,/* A Bc Gbl[Kst(Bc)] := R(A) */
|
OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */
|
||||||
OP_SETTABLE,/* A B C R(B)[R/K(C)] := R(A) */
|
OP_SETUPVAL,/* A B UpValue[B] := R(A) */
|
||||||
|
OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
|
||||||
|
|
||||||
OP_NEWTABLE,/* A Bc R(A) := {} (size = Bc) */
|
OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
|
||||||
|
|
||||||
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[R/K(C)] */
|
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
|
||||||
|
|
||||||
OP_ADD,/* A B C R(A) := R(B) + R/K(C) */
|
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
|
||||||
OP_SUB,/* A B C R(A) := R(B) - R/K(C) */
|
OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
|
||||||
OP_MUL,/* A B C R(A) := R(B) * R/K(C) */
|
OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
|
||||||
OP_DIV,/* A B C R(A) := R(B) / R/K(C) */
|
OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
|
||||||
OP_POW,/* A B C R(A) := R(B) ^ R/K(C) */
|
OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
|
||||||
OP_UNM,/* A B R(A) := -R(B) */
|
OP_UNM,/* A B R(A) := -R(B) */
|
||||||
OP_NOT,/* A B R(A) := not R(B) */
|
OP_NOT,/* A B R(A) := not R(B) */
|
||||||
|
|
||||||
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
|
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
|
||||||
|
|
||||||
OP_JMP,/* sBc PC += sBc */
|
OP_JMP,/* sBx PC += sBx */
|
||||||
OP_CJMP,/* sBc if test then PC += sBc (see (1)) */
|
|
||||||
|
|
||||||
OP_TESTEQ,/* A C test := (R(A) == R/K(C)) */
|
OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
|
||||||
OP_TESTNE,/* A C test := (R(A) ~= R/K(C)) */
|
OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
|
||||||
OP_TESTLT,/* A C test := (R(A) < R/K(C)) */
|
OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
|
||||||
OP_TESTLE,/* A C test := (R(A) <= R/K(C)) */
|
|
||||||
OP_TESTGT,/* A C test := (R(A) > R/K(C)) */
|
|
||||||
OP_TESTGE,/* A C test := (R(A) >= R/K(C)) */
|
|
||||||
|
|
||||||
OP_TESTT,/* A B test := R(B); if (test) R(A) := R(B) */
|
OP_TEST,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
|
||||||
OP_TESTF,/* A B test := not R(B); if (test) R(A) := nil */
|
|
||||||
|
|
||||||
OP_NILJMP,/* A Bc R(A) := nil; PC++; */
|
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||||
|
OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
|
||||||
|
OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */
|
||||||
|
|
||||||
OP_CALL,/* A B C R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(A+B))*/
|
OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then PC+= sBx */
|
||||||
OP_RETURN,/* A B return R(A), ... ,R(A+B-1) (see (3)) */
|
|
||||||
|
|
||||||
OP_FORPREP,/* A sBc */
|
OP_TFORLOOP,/* A C R(A+2), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
|
||||||
OP_FORLOOP,/* A sBc */
|
if R(A+2) ~= nil then pc++ */
|
||||||
|
OP_TFORPREP,/* A sBx if type(R(A)) == table then R(A+1):=R(A), R(A):=next;
|
||||||
|
PC += sBx */
|
||||||
|
|
||||||
OP_TFORPREP,/* A sBc */
|
OP_SETLIST,/* A Bx R(A)[Bx-Bx%FPF+i] := R(A+i), 1 <= i <= Bx%FPF+1 */
|
||||||
OP_TFORLOOP,/* A sBc */
|
OP_SETLISTO,/* A Bx */
|
||||||
|
|
||||||
OP_SETLIST,/* A Bc R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1 */
|
OP_CLOSE,/* A close all variables in the stack up to (>=) R(A)*/
|
||||||
OP_SETLISTO,/* A Bc */
|
OP_CLOSURE/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
|
||||||
|
|
||||||
OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */
|
|
||||||
} OpCode;
|
} OpCode;
|
||||||
|
|
||||||
|
|
||||||
#define NUM_OPCODES ((int)OP_CLOSURE+1)
|
#define NUM_OPCODES (cast(int, OP_CLOSURE+1))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
Notes:
|
Notes:
|
||||||
(1) In the current implementation there is no `test' variable;
|
(1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
|
||||||
instructions OP_TEST* and OP_CJMP must always occur together.
|
and can be 0: OP_CALL then sets `top' to last_result+1, so
|
||||||
|
|
||||||
(2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns,
|
|
||||||
and can be NO_REG. OP_CALL can set `top' to last_result+1, so
|
|
||||||
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
|
next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
|
||||||
|
|
||||||
(3) In OP_RETURN, if (B == NO_REG) then return up to `top'
|
(2) In OP_RETURN, if (B == 0) then return up to `top'
|
||||||
===========================================================================*/
|
|
||||||
|
|
||||||
|
(3) For comparisons, B specifies what conditions the test should accept.
|
||||||
|
|
||||||
|
(4) All `skips' (pc++) assume that next instruction is a jump
|
||||||
|
===========================================================================*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -207,22 +209,30 @@ OP_CLOSURE /* A Bc R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n)) */
|
|||||||
*/
|
*/
|
||||||
enum OpModeMask {
|
enum OpModeMask {
|
||||||
OpModeBreg = 2, /* B is a register */
|
OpModeBreg = 2, /* B is a register */
|
||||||
OpModeCreg, /* C is a register/constant */
|
OpModeBrk, /* B is a register/constant */
|
||||||
|
OpModeCrk, /* C is a register/constant */
|
||||||
OpModesetA, /* instruction set register A */
|
OpModesetA, /* instruction set register A */
|
||||||
OpModeK, /* Bc is a constant */
|
OpModeK, /* Bx is a constant */
|
||||||
OpModeT /* operator is a test */
|
OpModeT /* operator is a test */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const lu_byte luaP_opmodes[];
|
|
||||||
|
|
||||||
#define getOpMode(m) ((enum OpMode)(luaP_opmodes[m] & 3))
|
extern const lu_byte luaP_opmodes[NUM_OPCODES];
|
||||||
|
|
||||||
|
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
|
||||||
#define testOpMode(m, b) (luaP_opmodes[m] & (1 << (b)))
|
#define testOpMode(m, b) (luaP_opmodes[m] & (1 << (b)))
|
||||||
|
|
||||||
|
|
||||||
/*
|
#ifdef LUA_OPNAMES
|
||||||
** opcode names (only included when compiled with LUA_OPNAMES)
|
extern const char *const luaP_opnames[]; /* opcode names */
|
||||||
*/
|
#endif
|
||||||
extern const l_char *const luaP_opnames[];
|
|
||||||
|
|
||||||
|
|
||||||
|
/* number of list items to accumulate before a SETLIST instruction */
|
||||||
|
/* (must be a power of 2) */
|
||||||
|
#define LFIELDS_PER_FLUSH 32
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
37
lparser.h
37
lparser.h
@@ -1,13 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lparser.h,v 1.31 2001/06/05 18:17:01 roberto Exp roberto $
|
** $Id: lparser.h,v 1.46 2002/12/19 11:11:55 roberto Exp roberto $
|
||||||
** LL(1) Parser and code generator for Lua
|
** Lua Parser
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef lparser_h
|
#ifndef lparser_h
|
||||||
#define lparser_h
|
#define lparser_h
|
||||||
|
|
||||||
|
#include "llimits.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
#include "ltable.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -18,53 +20,52 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
VVOID, /* no value */
|
VVOID, /* no value */
|
||||||
VNIL,
|
VNIL,
|
||||||
VNUMBER, /* n = value */
|
VTRUE,
|
||||||
|
VFALSE,
|
||||||
VK, /* info = index of constant in `k' */
|
VK, /* info = index of constant in `k' */
|
||||||
VGLOBAL, /* info = index of global name in `k' */
|
|
||||||
VLOCAL, /* info = local register */
|
VLOCAL, /* info = local register */
|
||||||
|
VUPVAL, /* info = index of upvalue in `upvalues' */
|
||||||
|
VGLOBAL, /* info = index of table; aux = index of global name in `k' */
|
||||||
VINDEXED, /* info = table register; aux = index register (or `k') */
|
VINDEXED, /* info = table register; aux = index register (or `k') */
|
||||||
|
VJMP, /* info = instruction pc */
|
||||||
VRELOCABLE, /* info = instruction pc */
|
VRELOCABLE, /* info = instruction pc */
|
||||||
VNONRELOC, /* info = result register */
|
VNONRELOC, /* info = result register */
|
||||||
VJMP, /* info = result register */
|
|
||||||
VCALL /* info = result register */
|
VCALL /* info = result register */
|
||||||
} expkind;
|
} expkind;
|
||||||
|
|
||||||
typedef struct expdesc {
|
typedef struct expdesc {
|
||||||
expkind k;
|
expkind k;
|
||||||
union {
|
int info, aux;
|
||||||
struct {
|
|
||||||
int info, aux;
|
|
||||||
} i;
|
|
||||||
lua_Number n;
|
|
||||||
} u;
|
|
||||||
int t; /* patch list of `exit when true' */
|
int t; /* patch list of `exit when true' */
|
||||||
int f; /* patch list of `exit when false' */
|
int f; /* patch list of `exit when false' */
|
||||||
} expdesc;
|
} expdesc;
|
||||||
|
|
||||||
|
|
||||||
|
struct BlockCnt; /* defined in lparser.c */
|
||||||
|
|
||||||
|
|
||||||
/* state needed to generate code for a given function */
|
/* state needed to generate code for a given function */
|
||||||
typedef struct FuncState {
|
typedef struct FuncState {
|
||||||
Proto *f; /* current function header */
|
Proto *f; /* current function header */
|
||||||
|
Table *h; /* table to find (and reuse) elements in `k' */
|
||||||
struct FuncState *prev; /* enclosing function */
|
struct FuncState *prev; /* enclosing function */
|
||||||
struct LexState *ls; /* lexical state */
|
struct LexState *ls; /* lexical state */
|
||||||
struct lua_State *L; /* copy of the Lua state */
|
struct lua_State *L; /* copy of the Lua state */
|
||||||
|
struct BlockCnt *bl; /* chain of current blocks */
|
||||||
int pc; /* next position to code (equivalent to `ncode') */
|
int pc; /* next position to code (equivalent to `ncode') */
|
||||||
int lasttarget; /* `pc' of last `jump target' */
|
int lasttarget; /* `pc' of last `jump target' */
|
||||||
int jlt; /* list of jumps to `lasttarget' */
|
int jpc; /* list of pending jumps to `pc' */
|
||||||
int freereg; /* first free register */
|
int freereg; /* first free register */
|
||||||
int nk; /* number of elements in `k' */
|
int nk; /* number of elements in `k' */
|
||||||
int np; /* number of elements in `p' */
|
int np; /* number of elements in `p' */
|
||||||
int nlineinfo; /* number of elements in `lineinfo' */
|
|
||||||
int nlocvars; /* number of elements in `locvars' */
|
int nlocvars; /* number of elements in `locvars' */
|
||||||
int nactloc; /* number of active local variables */
|
int nactvar; /* number of active local variables */
|
||||||
int lastline; /* line where last `lineinfo' was generated */
|
|
||||||
struct Breaklabel *bl; /* chain of breakable blocks */
|
|
||||||
expdesc upvalues[MAXUPVALUES]; /* upvalues */
|
expdesc upvalues[MAXUPVALUES]; /* upvalues */
|
||||||
int actloc[MAXLOCALS]; /* local-variable stack (indices to locvars) */
|
int actvar[MAXVARS]; /* declared-variable stack */
|
||||||
} FuncState;
|
} FuncState;
|
||||||
|
|
||||||
|
|
||||||
Proto *luaY_parser (lua_State *L, ZIO *z);
|
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
272
lstate.c
272
lstate.c
@@ -1,16 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstate.c,v 1.65 2001/06/21 16:41:34 roberto Exp roberto $
|
** $Id: lstate.c,v 1.122 2003/03/18 12:50:04 roberto Exp roberto $
|
||||||
** Global State
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define lstate_c
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldebug.h"
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
|
#include "lfunc.h"
|
||||||
#include "lgc.h"
|
#include "lgc.h"
|
||||||
#include "llex.h"
|
#include "llex.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
@@ -20,123 +23,198 @@
|
|||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
|
|
||||||
|
|
||||||
struct Sopen {
|
/*
|
||||||
int stacksize;
|
** macro to allow the inclusion of user information in Lua state
|
||||||
lua_State *L;
|
*/
|
||||||
};
|
#ifndef LUA_USERSTATE
|
||||||
|
#define EXTRASPACE 0
|
||||||
|
#else
|
||||||
|
union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;};
|
||||||
|
#define EXTRASPACE (sizeof(union UEXTRASPACE))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void close_state (lua_State *L, lua_State *OL);
|
|
||||||
|
/*
|
||||||
|
** you can change this function through the official API:
|
||||||
|
** call `lua_setpanicf'
|
||||||
|
*/
|
||||||
|
static int default_panic (lua_State *L) {
|
||||||
|
UNUSED(L);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lua_State *mallocstate (lua_State *L) {
|
||||||
|
lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE);
|
||||||
|
if (block == NULL) return NULL;
|
||||||
|
else {
|
||||||
|
block += EXTRASPACE;
|
||||||
|
return cast(lua_State *, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void freestate (lua_State *L, lua_State *L1) {
|
||||||
|
luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE,
|
||||||
|
sizeof(lua_State) + EXTRASPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void stack_init (lua_State *L1, lua_State *L) {
|
||||||
|
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject);
|
||||||
|
L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
|
||||||
|
L1->top = L1->stack;
|
||||||
|
L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
|
||||||
|
L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
|
||||||
|
L1->ci = L1->base_ci;
|
||||||
|
L1->ci->state = CI_C; /* not a Lua function */
|
||||||
|
setnilvalue(L1->top++); /* `function' entry for this `ci' */
|
||||||
|
L1->base = L1->ci->base = L1->top;
|
||||||
|
L1->ci->top = L1->top + LUA_MINSTACK;
|
||||||
|
L1->size_ci = BASIC_CI_SIZE;
|
||||||
|
L1->end_ci = L1->base_ci + L1->size_ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void freestack (lua_State *L, lua_State *L1) {
|
||||||
|
luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
|
||||||
|
luaM_freearray(L, L1->stack, L1->stacksize, TObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** open parts that may cause memory-allocation errors
|
** open parts that may cause memory-allocation errors
|
||||||
*/
|
*/
|
||||||
static void f_luaopen (lua_State *L, void *ud) {
|
static void f_luaopen (lua_State *L, void *ud) {
|
||||||
struct Sopen *so = (struct Sopen *)ud;
|
/* create a new global state */
|
||||||
if (so->stacksize == 0)
|
global_State *g = luaM_new(NULL, global_State);
|
||||||
so->stacksize = DEFAULT_STACK_SIZE;
|
UNUSED(ud);
|
||||||
else
|
if (g == NULL) luaD_throw(L, LUA_ERRMEM);
|
||||||
so->stacksize += LUA_MINSTACK;
|
L->l_G = g;
|
||||||
if (so->L != NULL) { /* shared global state? */
|
g->mainthread = L;
|
||||||
L->G = G(so->L);
|
g->GCthreshold = 0; /* mark it as unfinished state */
|
||||||
L->gt = so->L->gt; /* share table of globals */
|
g->strt.size = 0;
|
||||||
so->L->next->previous = L; /* insert L into linked list */
|
g->strt.nuse = 0;
|
||||||
L->next = so->L->next;
|
g->strt.hash = NULL;
|
||||||
so->L->next = L;
|
setnilvalue(defaultmeta(L));
|
||||||
L->previous = so->L;
|
setnilvalue(registry(L));
|
||||||
luaD_init(L, so->stacksize); /* init stack */
|
luaZ_initbuffer(L, &g->buff);
|
||||||
}
|
g->panic = default_panic;
|
||||||
else { /* create a new global state */
|
g->rootgc = NULL;
|
||||||
L->G = luaM_new(L, global_State);
|
g->rootudata = NULL;
|
||||||
G(L)->strt.size = 0;
|
g->tmudata = NULL;
|
||||||
G(L)->strt.nuse = 0;
|
setnilvalue(gkey(g->dummynode));
|
||||||
G(L)->strt.hash = NULL;
|
setnilvalue(gval(g->dummynode));
|
||||||
G(L)->Mbuffer = NULL;
|
g->dummynode->next = NULL;
|
||||||
G(L)->Mbuffsize = 0;
|
g->nblocks = sizeof(lua_State) + sizeof(global_State);
|
||||||
G(L)->rootproto = NULL;
|
stack_init(L, L); /* init stack */
|
||||||
G(L)->rootcl = NULL;
|
/* create default meta table with a dummy table, and then close the loop */
|
||||||
G(L)->roottable = NULL;
|
defaultmeta(L)->tt = LUA_TTABLE;
|
||||||
G(L)->rootudata = NULL;
|
sethvalue(defaultmeta(L), luaH_new(L, 0, 0));
|
||||||
G(L)->TMtable = NULL;
|
hvalue(defaultmeta(L))->metatable = hvalue(defaultmeta(L));
|
||||||
G(L)->sizeTM = 0;
|
sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */
|
||||||
G(L)->ntag = 0;
|
sethvalue(registry(L), luaH_new(L, 4, 4)); /* registry */
|
||||||
G(L)->nblocks = sizeof(lua_State) + sizeof(global_State);
|
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
|
||||||
luaD_init(L, so->stacksize); /* init stack */
|
luaT_init(L);
|
||||||
L->gt = luaH_new(L, 10); /* table of globals */
|
luaX_init(L);
|
||||||
G(L)->type2tag = luaH_new(L, 10);
|
luaS_fix(luaS_newliteral(L, MEMERRMSG));
|
||||||
G(L)->registry = luaH_new(L, 0);
|
g->GCthreshold = 4*G(L)->nblocks;
|
||||||
G(L)->weakregistry = luaH_new(L, 0);
|
|
||||||
/* make weakregistry weak */
|
|
||||||
G(L)->weakregistry->weakmode = LUA_WEAK_KEY | LUA_WEAK_VALUE;
|
|
||||||
luaS_resize(L, MINPOWER2);
|
|
||||||
luaX_init(L);
|
|
||||||
luaT_init(L);
|
|
||||||
G(L)->GCthreshold = 4*G(L)->nblocks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) {
|
static void preinit_state (lua_State *L) {
|
||||||
struct Sopen so;
|
L->stack = NULL;
|
||||||
lua_State *L;
|
L->stacksize = 0;
|
||||||
if (OL) lua_lock(OL);
|
L->errorJmp = NULL;
|
||||||
L = luaM_new(OL, lua_State);
|
L->hook = NULL;
|
||||||
|
L->hookmask = L->hookinit = 0;
|
||||||
|
L->basehookcount = 0;
|
||||||
|
L->allowhook = 1;
|
||||||
|
resethookcount(L);
|
||||||
|
L->openupval = NULL;
|
||||||
|
L->size_ci = 0;
|
||||||
|
L->nCcalls = 0;
|
||||||
|
L->base_ci = L->ci = NULL;
|
||||||
|
L->errfunc = 0;
|
||||||
|
setnilvalue(gt(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void close_state (lua_State *L) {
|
||||||
|
luaF_close(L, L->stack); /* close all upvalues for this thread */
|
||||||
|
if (G(L)) { /* close global state */
|
||||||
|
luaC_sweep(L, 1); /* collect all elements */
|
||||||
|
lua_assert(G(L)->rootgc == NULL);
|
||||||
|
lua_assert(G(L)->rootudata == NULL);
|
||||||
|
luaS_freeall(L);
|
||||||
|
luaZ_freebuffer(L, &G(L)->buff);
|
||||||
|
}
|
||||||
|
freestack(L, L);
|
||||||
|
if (G(L)) {
|
||||||
|
lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State));
|
||||||
|
luaM_freelem(NULL, G(L));
|
||||||
|
}
|
||||||
|
freestate(NULL, L);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lua_State *luaE_newthread (lua_State *L) {
|
||||||
|
lua_State *L1 = mallocstate(L);
|
||||||
|
luaC_link(L, valtogco(L1), LUA_TTHREAD);
|
||||||
|
preinit_state(L1);
|
||||||
|
L1->l_G = L->l_G;
|
||||||
|
stack_init(L1, L); /* init stack */
|
||||||
|
setobj2n(gt(L1), gt(L)); /* share table of globals */
|
||||||
|
return L1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaE_freethread (lua_State *L, lua_State *L1) {
|
||||||
|
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
|
||||||
|
lua_assert(L1->openupval == NULL);
|
||||||
|
freestack(L, L1);
|
||||||
|
freestate(L, L1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API lua_State *lua_open (void) {
|
||||||
|
lua_State *L = mallocstate(NULL);
|
||||||
if (L) { /* allocation OK? */
|
if (L) { /* allocation OK? */
|
||||||
L->G = NULL;
|
L->tt = LUA_TTHREAD;
|
||||||
L->stack = NULL;
|
L->marked = 0;
|
||||||
L->stacksize = 0;
|
L->next = L->gclist = NULL;
|
||||||
L->ci = &L->basefunc;
|
preinit_state(L);
|
||||||
L->basefunc.prev = NULL;
|
L->l_G = NULL;
|
||||||
L->errorJmp = NULL;
|
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
|
||||||
L->callhook = NULL;
|
|
||||||
L->linehook = NULL;
|
|
||||||
L->allowhooks = 1;
|
|
||||||
L->next = L->previous = L;
|
|
||||||
so.stacksize = stacksize;
|
|
||||||
so.L = OL;
|
|
||||||
if (luaD_runprotected(L, f_luaopen, &so) != 0) {
|
|
||||||
/* memory allocation error: free partial state */
|
/* memory allocation error: free partial state */
|
||||||
close_state(L, OL);
|
close_state(L);
|
||||||
L = NULL;
|
L = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (OL) lua_unlock(OL);
|
lua_userstateopen(L);
|
||||||
return L;
|
return L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void close_state (lua_State *L, lua_State *OL) {
|
static void callallgcTM (lua_State *L, void *ud) {
|
||||||
if (OL != NULL) { /* are there other threads? */
|
UNUSED(ud);
|
||||||
lua_assert(L->previous != L);
|
luaC_callGCTM(L); /* call GC metamethods for all udata */
|
||||||
L->previous->next = L->next;
|
|
||||||
L->next->previous = L->previous;
|
|
||||||
}
|
|
||||||
else if (G(L)) { /* last thread; close global state */
|
|
||||||
luaC_callallgcTM(L); /* call GC tag methods for all udata */
|
|
||||||
luaC_collect(L, 1); /* collect all elements */
|
|
||||||
lua_assert(G(L)->rootproto == NULL);
|
|
||||||
lua_assert(G(L)->rootudata == NULL);
|
|
||||||
lua_assert(G(L)->rootcl == NULL);
|
|
||||||
lua_assert(G(L)->roottable == NULL);
|
|
||||||
luaS_freeall(L);
|
|
||||||
luaM_freearray(L, G(L)->TMtable, G(L)->sizeTM, struct TM);
|
|
||||||
luaM_freearray(L, G(L)->Mbuffer, G(L)->Mbuffsize, l_char);
|
|
||||||
luaM_freelem(NULL, L->G, global_State);
|
|
||||||
}
|
|
||||||
luaM_freearray(OL, L->stack, L->stacksize, TObject);
|
|
||||||
luaM_freelem(OL, L, lua_State);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LUA_API void lua_close (lua_State *L) {
|
LUA_API void lua_close (lua_State *L) {
|
||||||
lua_State *OL;
|
|
||||||
lua_assert(L != lua_state || lua_gettop(L) == 0);
|
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
OL = L->next; /* any surviving thread (if there is one) */
|
L = G(L)->mainthread; /* only the main thread can be closed */
|
||||||
if (OL == L) OL = NULL; /* no surviving threads */
|
luaF_close(L, L->stack); /* close all upvalues for this thread */
|
||||||
close_state(L, OL);
|
luaC_separateudata(L); /* separate udata that have GC metamethods */
|
||||||
if (OL) lua_unlock(OL); /* cannot unlock over a freed state */
|
L->errfunc = 0; /* no error function during GC metamethods */
|
||||||
lua_assert(L != lua_state || memdebug_numblocks == 0);
|
do { /* repeat until no more errors */
|
||||||
lua_assert(L != lua_state || memdebug_total == 0);
|
L->ci = L->base_ci;
|
||||||
|
L->base = L->top = L->ci->base;
|
||||||
|
L->nCcalls = 0;
|
||||||
|
} while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0);
|
||||||
|
lua_assert(G(L)->tmudata == NULL);
|
||||||
|
close_state(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
168
lstate.h
168
lstate.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstate.h,v 1.57 2001/06/06 18:00:19 roberto Exp roberto $
|
** $Id: lstate.h,v 1.108 2002/11/25 17:47:13 roberto Exp roberto $
|
||||||
** Global State
|
** Global State
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -7,18 +7,20 @@
|
|||||||
#ifndef lstate_h
|
#ifndef lstate_h
|
||||||
#define lstate_h
|
#define lstate_h
|
||||||
|
|
||||||
#include "lobject.h"
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
#include "luadebug.h"
|
|
||||||
|
#include "lobject.h"
|
||||||
|
#include "ltm.h"
|
||||||
|
#include "lzio.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** macros for thread syncronization inside Lua core machine:
|
** macros for thread synchronization inside Lua core machine:
|
||||||
** all accesses to the global state and to global objects are syncronized.
|
** all accesses to the global state and to global objects are synchronized.
|
||||||
** Because threads can read the stack of other threads
|
** Because threads can read the stack of other threads
|
||||||
** (when running garbage collection),
|
** (when running garbage collection),
|
||||||
** a thread must also syncronize any write-access to its own stack.
|
** a thread must also synchronize any write-access to its own stack.
|
||||||
** Unsyncronized accesses are allowed only when reading its own stack,
|
** Unsynchronized accesses are allowed only when reading its own stack,
|
||||||
** or when reading immutable fields from global objects
|
** or when reading immutable fields from global objects
|
||||||
** (such as string values and udata values).
|
** (such as string values and udata values).
|
||||||
*/
|
*/
|
||||||
@@ -30,45 +32,96 @@
|
|||||||
#define lua_unlock(L) ((void) 0)
|
#define lua_unlock(L) ((void) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
** macro to allow the inclusion of user information in Lua state
|
#ifndef lua_userstateopen
|
||||||
*/
|
#define lua_userstateopen(l)
|
||||||
#ifndef LUA_USERSTATE
|
|
||||||
#define LUA_USERSTATE
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct lua_longjmp; /* defined in ldo.c */
|
struct lua_longjmp; /* defined in ldo.c */
|
||||||
struct TM; /* defined in ltm.h */
|
|
||||||
|
|
||||||
|
/* default meta table (both for tables and udata) */
|
||||||
|
#define defaultmeta(L) (&G(L)->_defaultmeta)
|
||||||
|
|
||||||
|
/* table of globals */
|
||||||
|
#define gt(L) (&L->_gt)
|
||||||
|
|
||||||
|
/* registry */
|
||||||
|
#define registry(L) (&G(L)->_registry)
|
||||||
|
|
||||||
|
|
||||||
|
/* extra stack space to handle TM calls and some other extras */
|
||||||
|
#define EXTRA_STACK 5
|
||||||
|
|
||||||
|
|
||||||
|
#define BASIC_CI_SIZE 8
|
||||||
|
|
||||||
|
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct stringtable {
|
typedef struct stringtable {
|
||||||
int size;
|
GCObject **hash;
|
||||||
ls_nstr nuse; /* number of elements */
|
ls_nstr nuse; /* number of elements */
|
||||||
TString **hash;
|
int size;
|
||||||
} stringtable;
|
} stringtable;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** informations about a call
|
||||||
|
*/
|
||||||
|
typedef struct CallInfo {
|
||||||
|
StkId base; /* base for called function */
|
||||||
|
StkId top; /* top for this function */
|
||||||
|
int state; /* bit fields; see below */
|
||||||
|
union {
|
||||||
|
struct { /* for Lua functions */
|
||||||
|
const Instruction *savedpc;
|
||||||
|
const Instruction **pc; /* points to `pc' variable in `luaV_execute' */
|
||||||
|
int tailcalls; /* number of tail calls lost under this entry */
|
||||||
|
} l;
|
||||||
|
struct { /* for C functions */
|
||||||
|
int dummy; /* just to avoid an empty struct */
|
||||||
|
} c;
|
||||||
|
} u;
|
||||||
|
} CallInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** bit fields for `CallInfo.state'
|
||||||
|
*/
|
||||||
|
#define CI_C (1<<0) /* 1 if function is a C function */
|
||||||
|
/* 1 if (Lua) function has an active `luaV_execute' running it */
|
||||||
|
#define CI_HASFRAME (1<<1)
|
||||||
|
/* 1 if Lua function is calling another Lua function (and therefore its
|
||||||
|
`pc' is being used by the other, and therefore CI_SAVEDPC is 1 too) */
|
||||||
|
#define CI_CALLING (1<<2)
|
||||||
|
#define CI_SAVEDPC (1<<3) /* 1 if `savedpc' is updated */
|
||||||
|
#define CI_YIELD (1<<4) /* 1 if thread is suspended */
|
||||||
|
|
||||||
|
|
||||||
|
#define ci_func(ci) (clvalue((ci)->base - 1))
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** `global state', shared by all threads of this state
|
** `global state', shared by all threads of this state
|
||||||
*/
|
*/
|
||||||
typedef struct global_State {
|
typedef struct global_State {
|
||||||
void *Mbuffer; /* global buffer */
|
|
||||||
size_t Mbuffsize; /* size of Mbuffer */
|
|
||||||
Proto *rootproto; /* list of all prototypes */
|
|
||||||
Closure *rootcl; /* list of all closures */
|
|
||||||
Hash *roottable; /* list of all tables */
|
|
||||||
Udata *rootudata; /* list of all userdata */
|
|
||||||
stringtable strt; /* hash table for strings */
|
stringtable strt; /* hash table for strings */
|
||||||
Hash *type2tag; /* hash table from type names to tags */
|
GCObject *rootgc; /* list of (almost) all collectable objects */
|
||||||
Hash *registry; /* (strong) registry table */
|
GCObject *rootudata; /* (separated) list of all userdata */
|
||||||
Hash *weakregistry; /* weakregistry table */
|
GCObject *tmudata; /* list of userdata to be GC */
|
||||||
struct TM *TMtable; /* table for tag methods */
|
Mbuffer buff; /* temporary buffer for string concatentation */
|
||||||
int sizeTM; /* size of TMtable */
|
|
||||||
int ntag; /* number of tags in TMtable */
|
|
||||||
lu_mem GCthreshold;
|
lu_mem GCthreshold;
|
||||||
lu_mem nblocks; /* number of `bytes' currently allocated */
|
lu_mem nblocks; /* number of `bytes' currently allocated */
|
||||||
|
lua_CFunction panic; /* to be called in unprotected errors */
|
||||||
|
TObject _registry;
|
||||||
|
TObject _defaultmeta;
|
||||||
|
struct lua_State *mainthread;
|
||||||
|
Node dummynode[1]; /* common node array for all empty tables */
|
||||||
|
TString *tmname[TM_N]; /* array with tag-method names */
|
||||||
} global_State;
|
} global_State;
|
||||||
|
|
||||||
|
|
||||||
@@ -76,26 +129,67 @@ typedef struct global_State {
|
|||||||
** `per thread' state
|
** `per thread' state
|
||||||
*/
|
*/
|
||||||
struct lua_State {
|
struct lua_State {
|
||||||
LUA_USERSTATE
|
CommonHeader;
|
||||||
StkId top; /* first free slot in the stack */
|
StkId top; /* first free slot in the stack */
|
||||||
|
StkId base; /* base of current function */
|
||||||
|
global_State *l_G;
|
||||||
CallInfo *ci; /* call info for current function */
|
CallInfo *ci; /* call info for current function */
|
||||||
StkId stack_last; /* last free slot in the stack */
|
StkId stack_last; /* last free slot in the stack */
|
||||||
Hash *gt; /* table for globals */
|
|
||||||
global_State *G;
|
|
||||||
StkId stack; /* stack base */
|
StkId stack; /* stack base */
|
||||||
int stacksize;
|
int stacksize;
|
||||||
lua_Hook callhook;
|
CallInfo *end_ci; /* points after end of ci array*/
|
||||||
lua_Hook linehook;
|
CallInfo *base_ci; /* array of CallInfo's */
|
||||||
int allowhooks;
|
unsigned short size_ci; /* size of array `base_ci' */
|
||||||
|
unsigned short nCcalls; /* number of nested C calls */
|
||||||
|
lu_byte hookmask;
|
||||||
|
lu_byte allowhook;
|
||||||
|
lu_byte hookinit;
|
||||||
|
int basehookcount;
|
||||||
|
int hookcount;
|
||||||
|
lua_Hook hook;
|
||||||
|
TObject _gt; /* table of globals */
|
||||||
|
GCObject *openupval; /* list of open upvalues in this stack */
|
||||||
|
GCObject *gclist;
|
||||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||||
lua_State *next; /* circular double linked list of states */
|
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||||
lua_State *previous;
|
|
||||||
CallInfo basefunc;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define G(L) (L->G)
|
#define G(L) (L->l_G)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Union of all collectable objects
|
||||||
|
*/
|
||||||
|
union GCObject {
|
||||||
|
GCheader gch;
|
||||||
|
union TString ts;
|
||||||
|
union Udata u;
|
||||||
|
union Closure cl;
|
||||||
|
struct Table h;
|
||||||
|
struct Proto p;
|
||||||
|
struct UpVal uv;
|
||||||
|
struct lua_State th; /* thread */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* macros to convert a GCObject into a specific value */
|
||||||
|
#define gcotots(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))
|
||||||
|
#define gcotou(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
|
||||||
|
#define gcotocl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))
|
||||||
|
#define gcotoh(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
|
||||||
|
#define gcotop(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
|
||||||
|
#define gcotouv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
|
||||||
|
#define ngcotouv(o) \
|
||||||
|
check_exp((o) == NULL || (o)->gch.tt == LUA_TUPVAL, &((o)->uv))
|
||||||
|
#define gcototh(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
|
||||||
|
|
||||||
|
/* macro to convert any value into a GCObject */
|
||||||
|
#define valtogco(v) (cast(GCObject *, (v)))
|
||||||
|
|
||||||
|
|
||||||
|
lua_State *luaE_newthread (lua_State *L);
|
||||||
|
void luaE_freethread (lua_State *L, lua_State *L1);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
60
lstring.c
60
lstring.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstring.c,v 1.64 2001/06/07 15:01:21 roberto Exp roberto $
|
** $Id: lstring.c,v 1.77 2002/11/13 11:32:26 roberto Exp roberto $
|
||||||
** String table (keeps all strings handled by Lua)
|
** String table (keeps all strings handled by Lua)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lstring_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
@@ -24,19 +25,19 @@ void luaS_freeall (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
void luaS_resize (lua_State *L, int newsize) {
|
void luaS_resize (lua_State *L, int newsize) {
|
||||||
TString **newhash = luaM_newvector(L, newsize, TString *);
|
GCObject **newhash = luaM_newvector(L, newsize, GCObject *);
|
||||||
stringtable *tb = &G(L)->strt;
|
stringtable *tb = &G(L)->strt;
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<newsize; i++) newhash[i] = NULL;
|
for (i=0; i<newsize; i++) newhash[i] = NULL;
|
||||||
/* rehash */
|
/* rehash */
|
||||||
for (i=0; i<tb->size; i++) {
|
for (i=0; i<tb->size; i++) {
|
||||||
TString *p = tb->hash[i];
|
GCObject *p = tb->hash[i];
|
||||||
while (p) { /* for each node in the list */
|
while (p) { /* for each node in the list */
|
||||||
TString *next = p->tsv.nexthash; /* save next */
|
GCObject *next = p->gch.next; /* save next */
|
||||||
lu_hash h = p->tsv.hash;
|
lu_hash h = gcotots(p)->tsv.hash;
|
||||||
int h1 = lmod(h, newsize); /* new position */
|
int h1 = lmod(h, newsize); /* new position */
|
||||||
lua_assert((int)(h%newsize) == lmod(h, newsize));
|
lua_assert(cast(int, h%newsize) == lmod(h, newsize));
|
||||||
p->tsv.nexthash = newhash[h1]; /* chain it in new position */
|
p->gch.next = newhash[h1]; /* chain it */
|
||||||
newhash[h1] = p;
|
newhash[h1] = p;
|
||||||
p = next;
|
p = next;
|
||||||
}
|
}
|
||||||
@@ -47,37 +48,38 @@ void luaS_resize (lua_State *L, int newsize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static TString *newlstr (lua_State *L, const l_char *str, size_t l, lu_hash h) {
|
static TString *newlstr (lua_State *L, const char *str, size_t l, lu_hash h) {
|
||||||
TString *ts = (TString *)luaM_malloc(L, sizestring(l));
|
TString *ts = cast(TString *, luaM_malloc(L, sizestring(l)));
|
||||||
stringtable *tb;
|
stringtable *tb;
|
||||||
ts->tsv.nexthash = NULL;
|
|
||||||
ts->tsv.len = l;
|
ts->tsv.len = l;
|
||||||
ts->tsv.hash = h;
|
ts->tsv.hash = h;
|
||||||
ts->tsv.marked = 0;
|
ts->tsv.marked = 0;
|
||||||
ts->tsv.constindex = 0;
|
ts->tsv.tt = LUA_TSTRING;
|
||||||
memcpy(getstr(ts), str, l*sizeof(l_char));
|
ts->tsv.reserved = 0;
|
||||||
getstr(ts)[l] = l_c('\0'); /* ending 0 */
|
memcpy(ts+1, str, l*sizeof(char));
|
||||||
|
((char *)(ts+1))[l] = '\0'; /* ending 0 */
|
||||||
tb = &G(L)->strt;
|
tb = &G(L)->strt;
|
||||||
h = lmod(h, tb->size);
|
h = lmod(h, tb->size);
|
||||||
ts->tsv.nexthash = tb->hash[h]; /* chain new entry */
|
ts->tsv.next = tb->hash[h]; /* chain new entry */
|
||||||
tb->hash[h] = ts;
|
tb->hash[h] = valtogco(ts);
|
||||||
tb->nuse++;
|
tb->nuse++;
|
||||||
if (tb->nuse > (ls_nstr)tb->size && tb->size <= MAX_INT/2)
|
if (tb->nuse > cast(ls_nstr, tb->size) && tb->size <= MAX_INT/2)
|
||||||
luaS_resize(L, tb->size*2); /* too crowded */
|
luaS_resize(L, tb->size*2); /* too crowded */
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TString *luaS_newlstr (lua_State *L, const l_char *str, size_t l) {
|
TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
|
||||||
TString *ts;
|
GCObject *o;
|
||||||
lu_hash h = l; /* seed */
|
lu_hash h = (lu_hash)l; /* seed */
|
||||||
size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
|
size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */
|
||||||
size_t l1;
|
size_t l1;
|
||||||
for (l1=l; l1>=step; l1-=step) /* compute hash */
|
for (l1=l; l1>=step; l1-=step) /* compute hash */
|
||||||
h = h ^ ((h<<5)+(h>>2)+uchar(str[l1-1]));
|
h = h ^ ((h<<5)+(h>>2)+(unsigned char)(str[l1-1]));
|
||||||
for (ts = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
|
for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)];
|
||||||
ts != NULL;
|
o != NULL;
|
||||||
ts = ts->tsv.nexthash) {
|
o = o->gch.next) {
|
||||||
|
TString *ts = gcotots(o);
|
||||||
if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0))
|
if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0))
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
@@ -86,13 +88,15 @@ TString *luaS_newlstr (lua_State *L, const l_char *str, size_t l) {
|
|||||||
|
|
||||||
|
|
||||||
Udata *luaS_newudata (lua_State *L, size_t s) {
|
Udata *luaS_newudata (lua_State *L, size_t s) {
|
||||||
Udata *u = (Udata *)luaM_malloc(L, sizeudata(s));
|
Udata *u;
|
||||||
|
u = cast(Udata *, luaM_malloc(L, sizeudata(s)));
|
||||||
|
u->uv.marked = (1<<1); /* is not finalized */
|
||||||
|
u->uv.tt = LUA_TUSERDATA;
|
||||||
u->uv.len = s;
|
u->uv.len = s;
|
||||||
u->uv.tag = 0;
|
u->uv.metatable = hvalue(defaultmeta(L));
|
||||||
u->uv.value = u + 1;
|
|
||||||
/* chain it on udata list */
|
/* chain it on udata list */
|
||||||
u->uv.next = G(L)->rootudata;
|
u->uv.next = G(L)->rootudata;
|
||||||
G(L)->rootudata = u;
|
G(L)->rootudata = valtogco(u);
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
lstring.h
24
lstring.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstring.h,v 1.32 2001/06/06 18:00:19 roberto Exp roberto $
|
** $Id: lstring.h,v 1.36 2002/04/30 13:01:48 roberto Exp roberto $
|
||||||
** String table (keep all strings handled by Lua)
|
** String table (keep all strings handled by Lua)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -13,27 +13,21 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
#define sizestring(l) (cast(lu_mem, sizeof(union TString))+ \
|
||||||
** any TString with mark>=FIXMARK is never collected.
|
(cast(lu_mem, l)+1)*sizeof(char))
|
||||||
** Marks>=RESERVEDMARK are used to identify reserved words.
|
|
||||||
*/
|
|
||||||
#define FIXMARK 2
|
|
||||||
#define RESERVEDMARK 3
|
|
||||||
|
|
||||||
|
#define sizeudata(l) (cast(lu_mem, sizeof(union Udata))+(l))
|
||||||
#define sizestring(l) ((lu_mem)sizeof(union TString)+ \
|
|
||||||
((lu_mem)(l)+1)*sizeof(l_char))
|
|
||||||
|
|
||||||
#define sizeudata(l) ((lu_mem)sizeof(union Udata)+(l))
|
|
||||||
|
|
||||||
#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s)))
|
#define luaS_new(L, s) (luaS_newlstr(L, s, strlen(s)))
|
||||||
#define luaS_newliteral(L, s) (luaS_newlstr(L, l_s("") s, \
|
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
|
||||||
(sizeof(s)/sizeof(l_char))-1))
|
(sizeof(s)/sizeof(char))-1))
|
||||||
|
|
||||||
|
#define luaS_fix(s) ((s)->tsv.marked |= (1<<4))
|
||||||
|
|
||||||
void luaS_resize (lua_State *L, int newsize);
|
void luaS_resize (lua_State *L, int newsize);
|
||||||
Udata *luaS_newudata (lua_State *L, size_t s);
|
Udata *luaS_newudata (lua_State *L, size_t s);
|
||||||
void luaS_freeall (lua_State *L);
|
void luaS_freeall (lua_State *L);
|
||||||
TString *luaS_newlstr (lua_State *L, const l_char *str, size_t l);
|
TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
505
lstrlib.c
505
lstrlib.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lstrlib.c,v 1.68 2001/03/26 14:31:49 roberto Exp roberto $
|
** $Id: lstrlib.c,v 1.97 2003/03/19 21:16:12 roberto Exp roberto $
|
||||||
** Standard library for string operations and pattern-matching
|
** Standard library for string operations and pattern-matching
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -11,20 +11,27 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lstrlib_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* macro to `unsign' a character */
|
||||||
|
#ifndef uchar
|
||||||
|
#define uchar(c) ((unsigned char)(c))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef long sint32; /* a signed version for size_t */
|
typedef long sint32; /* a signed version for size_t */
|
||||||
|
|
||||||
|
|
||||||
static int str_len (lua_State *L) {
|
static int str_len (lua_State *L) {
|
||||||
size_t l;
|
size_t l;
|
||||||
luaL_check_lstr(L, 1, &l);
|
luaL_checklstring(L, 1, &l);
|
||||||
lua_pushnumber(L, l);
|
lua_pushnumber(L, (lua_Number)l);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,14 +44,14 @@ static sint32 posrelat (sint32 pos, size_t len) {
|
|||||||
|
|
||||||
static int str_sub (lua_State *L) {
|
static int str_sub (lua_State *L) {
|
||||||
size_t l;
|
size_t l;
|
||||||
const l_char *s = luaL_check_lstr(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
sint32 start = posrelat(luaL_check_long(L, 2), l);
|
sint32 start = posrelat(luaL_checklong(L, 2), l);
|
||||||
sint32 end = posrelat(luaL_opt_long(L, 3, -1), l);
|
sint32 end = posrelat(luaL_optlong(L, 3, -1), l);
|
||||||
if (start < 1) start = 1;
|
if (start < 1) start = 1;
|
||||||
if (end > (sint32)l) end = l;
|
if (end > (sint32)l) end = (sint32)l;
|
||||||
if (start <= end)
|
if (start <= end)
|
||||||
lua_pushlstring(L, s+start-1, end-start+1);
|
lua_pushlstring(L, s+start-1, end-start+1);
|
||||||
else lua_pushliteral(L, l_s(""));
|
else lua_pushliteral(L, "");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +60,7 @@ static int str_lower (lua_State *L) {
|
|||||||
size_t l;
|
size_t l;
|
||||||
size_t i;
|
size_t i;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
const l_char *s = luaL_check_lstr(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for (i=0; i<l; i++)
|
for (i=0; i<l; i++)
|
||||||
luaL_putchar(&b, tolower(uchar(s[i])));
|
luaL_putchar(&b, tolower(uchar(s[i])));
|
||||||
@@ -66,7 +73,7 @@ static int str_upper (lua_State *L) {
|
|||||||
size_t l;
|
size_t l;
|
||||||
size_t i;
|
size_t i;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
const l_char *s = luaL_check_lstr(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for (i=0; i<l; i++)
|
for (i=0; i<l; i++)
|
||||||
luaL_putchar(&b, toupper(uchar(s[i])));
|
luaL_putchar(&b, toupper(uchar(s[i])));
|
||||||
@@ -77,8 +84,8 @@ static int str_upper (lua_State *L) {
|
|||||||
static int str_rep (lua_State *L) {
|
static int str_rep (lua_State *L) {
|
||||||
size_t l;
|
size_t l;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
const l_char *s = luaL_check_lstr(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
int n = luaL_check_int(L, 2);
|
int n = luaL_checkint(L, 2);
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (n-- > 0)
|
while (n-- > 0)
|
||||||
luaL_addlstring(&b, s, l);
|
luaL_addlstring(&b, s, l);
|
||||||
@@ -89,9 +96,10 @@ static int str_rep (lua_State *L) {
|
|||||||
|
|
||||||
static int str_byte (lua_State *L) {
|
static int str_byte (lua_State *L) {
|
||||||
size_t l;
|
size_t l;
|
||||||
const l_char *s = luaL_check_lstr(L, 1, &l);
|
const char *s = luaL_checklstring(L, 1, &l);
|
||||||
sint32 pos = posrelat(luaL_opt_long(L, 2, 1), l);
|
sint32 pos = posrelat(luaL_optlong(L, 2, 1), l);
|
||||||
luaL_arg_check(L, 0<pos && (size_t)pos<=l, 2, l_s("out of range"));
|
if (pos <= 0 || (size_t)(pos) > l) /* index out of range? */
|
||||||
|
return 0; /* no answer */
|
||||||
lua_pushnumber(L, uchar(s[pos-1]));
|
lua_pushnumber(L, uchar(s[pos-1]));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -103,8 +111,8 @@ static int str_char (lua_State *L) {
|
|||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
for (i=1; i<=n; i++) {
|
for (i=1; i<=n; i++) {
|
||||||
int c = luaL_check_int(L, i);
|
int c = luaL_checkint(L, i);
|
||||||
luaL_arg_check(L, uchar(c) == c, i, l_s("invalid value"));
|
luaL_argcheck(L, uchar(c) == c, i, "invalid value");
|
||||||
luaL_putchar(&b, uchar(c));
|
luaL_putchar(&b, uchar(c));
|
||||||
}
|
}
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
@@ -112,6 +120,24 @@ static int str_char (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int writer (lua_State *L, const void* b, size_t size, void* B) {
|
||||||
|
(void)L;
|
||||||
|
luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int str_dump (lua_State *L) {
|
||||||
|
luaL_Buffer b;
|
||||||
|
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||||
|
luaL_buffinit(L,&b);
|
||||||
|
if (!lua_dump(L, writer, &b))
|
||||||
|
luaL_error(L, "unable to dump given function");
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {======================================================
|
** {======================================================
|
||||||
@@ -128,25 +154,25 @@ static int str_char (lua_State *L) {
|
|||||||
#define CAP_POSITION (-2)
|
#define CAP_POSITION (-2)
|
||||||
|
|
||||||
typedef struct MatchState {
|
typedef struct MatchState {
|
||||||
const l_char *src_init; /* init of source string */
|
const char *src_init; /* init of source string */
|
||||||
const l_char *src_end; /* end (`\0') of source string */
|
const char *src_end; /* end (`\0') of source string */
|
||||||
|
lua_State *L;
|
||||||
int level; /* total number of captures (finished or unfinished) */
|
int level; /* total number of captures (finished or unfinished) */
|
||||||
struct {
|
struct {
|
||||||
const l_char *init;
|
const char *init;
|
||||||
sint32 len;
|
sint32 len;
|
||||||
} capture[MAX_CAPTURES];
|
} capture[MAX_CAPTURES];
|
||||||
lua_State *L;
|
|
||||||
} MatchState;
|
} MatchState;
|
||||||
|
|
||||||
|
|
||||||
#define ESC l_c('%')
|
#define ESC '%'
|
||||||
#define SPECIALS l_s("^$*+?.([%-")
|
#define SPECIALS "^$*+?.([%-"
|
||||||
|
|
||||||
|
|
||||||
static int check_capture (MatchState *ms, int l) {
|
static int check_capture (MatchState *ms, int l) {
|
||||||
l -= l_c('1');
|
l -= '1';
|
||||||
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
|
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
|
||||||
lua_error(ms->L, l_s("invalid capture index"));
|
return luaL_error(ms->L, "invalid capture index");
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,54 +181,56 @@ static int capture_to_close (MatchState *ms) {
|
|||||||
int level = ms->level;
|
int level = ms->level;
|
||||||
for (level--; level>=0; level--)
|
for (level--; level>=0; level--)
|
||||||
if (ms->capture[level].len == CAP_UNFINISHED) return level;
|
if (ms->capture[level].len == CAP_UNFINISHED) return level;
|
||||||
lua_error(ms->L, l_s("invalid pattern capture"));
|
return luaL_error(ms->L, "invalid pattern capture");
|
||||||
return 0; /* to avoid warnings */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *luaI_classend (MatchState *ms, const l_char *p) {
|
static const char *luaI_classend (MatchState *ms, const char *p) {
|
||||||
switch (*p++) {
|
switch (*p++) {
|
||||||
case ESC:
|
case ESC: {
|
||||||
if (*p == l_c('\0'))
|
if (*p == '\0')
|
||||||
lua_error(ms->L, l_s("malformed pattern (ends with `%')"));
|
luaL_error(ms->L, "malformed pattern (ends with `%')");
|
||||||
return p+1;
|
return p+1;
|
||||||
case l_c('['):
|
}
|
||||||
if (*p == l_c('^')) p++;
|
case '[': {
|
||||||
|
if (*p == '^') p++;
|
||||||
do { /* look for a `]' */
|
do { /* look for a `]' */
|
||||||
if (*p == l_c('\0'))
|
if (*p == '\0')
|
||||||
lua_error(ms->L, l_s("malformed pattern (missing `]')"));
|
luaL_error(ms->L, "malformed pattern (missing `]')");
|
||||||
if (*(p++) == ESC && *p != l_c('\0'))
|
if (*(p++) == ESC && *p != '\0')
|
||||||
p++; /* skip escapes (e.g. `%]') */
|
p++; /* skip escapes (e.g. `%]') */
|
||||||
} while (*p != l_c(']'));
|
} while (*p != ']');
|
||||||
return p+1;
|
return p+1;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
return p;
|
return p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int match_class (l_char c, l_char cl) {
|
static int match_class (int c, int cl) {
|
||||||
int res;
|
int res;
|
||||||
switch (tolower(uchar(cl))) {
|
switch (tolower(cl)) {
|
||||||
case l_c('a') : res = isalpha(uchar(c)); break;
|
case 'a' : res = isalpha(c); break;
|
||||||
case l_c('c') : res = iscntrl(uchar(c)); break;
|
case 'c' : res = iscntrl(c); break;
|
||||||
case l_c('d') : res = isdigit(uchar(c)); break;
|
case 'd' : res = isdigit(c); break;
|
||||||
case l_c('l') : res = islower(uchar(c)); break;
|
case 'l' : res = islower(c); break;
|
||||||
case l_c('p') : res = ispunct(uchar(c)); break;
|
case 'p' : res = ispunct(c); break;
|
||||||
case l_c('s') : res = isspace(uchar(c)); break;
|
case 's' : res = isspace(c); break;
|
||||||
case l_c('u') : res = isupper(uchar(c)); break;
|
case 'u' : res = isupper(c); break;
|
||||||
case l_c('w') : res = isalnum(uchar(c)); break;
|
case 'w' : res = isalnum(c); break;
|
||||||
case l_c('x') : res = isxdigit(uchar(c)); break;
|
case 'x' : res = isxdigit(c); break;
|
||||||
case l_c('z') : res = (c == l_c('\0')); break;
|
case 'z' : res = (c == 0); break;
|
||||||
default: return (cl == c);
|
default: return (cl == c);
|
||||||
}
|
}
|
||||||
return (islower(uchar(cl)) ? res : !res);
|
return (islower(cl) ? res : !res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int matchbracketclass (l_char c, const l_char *p, const l_char *ec) {
|
static int matchbracketclass (int c, const char *p, const char *ec) {
|
||||||
int sig = 1;
|
int sig = 1;
|
||||||
if (*(p+1) == l_c('^')) {
|
if (*(p+1) == '^') {
|
||||||
sig = 0;
|
sig = 0;
|
||||||
p++; /* skip the `^' */
|
p++; /* skip the `^' */
|
||||||
}
|
}
|
||||||
@@ -212,38 +240,34 @@ static int matchbracketclass (l_char c, const l_char *p, const l_char *ec) {
|
|||||||
if (match_class(c, *p))
|
if (match_class(c, *p))
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
else if ((*(p+1) == l_c('-')) && (p+2 < ec)) {
|
else if ((*(p+1) == '-') && (p+2 < ec)) {
|
||||||
p+=2;
|
p+=2;
|
||||||
if (uchar(*(p-2)) <= uchar(c) && uchar(c) <= uchar(*p))
|
if (uchar(*(p-2)) <= c && c <= uchar(*p))
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
else if (*p == c) return sig;
|
else if (uchar(*p) == c) return sig;
|
||||||
}
|
}
|
||||||
return !sig;
|
return !sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaI_singlematch (l_char c, const l_char *p, const l_char *ep) {
|
static int luaI_singlematch (int c, const char *p, const char *ep) {
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case l_c('.'): /* matches any char */
|
case '.': return 1; /* matches any char */
|
||||||
return 1;
|
case ESC: return match_class(c, *(p+1));
|
||||||
case ESC:
|
case '[': return matchbracketclass(c, p, ep-1);
|
||||||
return match_class(c, *(p+1));
|
default: return (uchar(*p) == c);
|
||||||
case l_c('['):
|
|
||||||
return matchbracketclass(c, p, ep-1);
|
|
||||||
default:
|
|
||||||
return (*p == c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *match (MatchState *ms, const l_char *s, const l_char *p);
|
static const char *match (MatchState *ms, const char *s, const char *p);
|
||||||
|
|
||||||
|
|
||||||
static const l_char *matchbalance (MatchState *ms, const l_char *s,
|
static const char *matchbalance (MatchState *ms, const char *s,
|
||||||
const l_char *p) {
|
const char *p) {
|
||||||
if (*p == 0 || *(p+1) == 0)
|
if (*p == 0 || *(p+1) == 0)
|
||||||
lua_error(ms->L, l_s("unbalanced pattern"));
|
luaL_error(ms->L, "unbalanced pattern");
|
||||||
if (*s != *p) return NULL;
|
if (*s != *p) return NULL;
|
||||||
else {
|
else {
|
||||||
int b = *p;
|
int b = *p;
|
||||||
@@ -260,14 +284,14 @@ static const l_char *matchbalance (MatchState *ms, const l_char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *max_expand (MatchState *ms, const l_char *s,
|
static const char *max_expand (MatchState *ms, const char *s,
|
||||||
const l_char *p, const l_char *ep) {
|
const char *p, const char *ep) {
|
||||||
sint32 i = 0; /* counts maximum expand for item */
|
sint32 i = 0; /* counts maximum expand for item */
|
||||||
while ((s+i)<ms->src_end && luaI_singlematch(*(s+i), p, ep))
|
while ((s+i)<ms->src_end && luaI_singlematch(uchar(*(s+i)), p, ep))
|
||||||
i++;
|
i++;
|
||||||
/* keeps trying to match with the maximum repetitions */
|
/* keeps trying to match with the maximum repetitions */
|
||||||
while (i>=0) {
|
while (i>=0) {
|
||||||
const l_char *res = match(ms, (s+i), ep+1);
|
const char *res = match(ms, (s+i), ep+1);
|
||||||
if (res) return res;
|
if (res) return res;
|
||||||
i--; /* else didn't match; reduce 1 repetition to try again */
|
i--; /* else didn't match; reduce 1 repetition to try again */
|
||||||
}
|
}
|
||||||
@@ -275,24 +299,24 @@ static const l_char *max_expand (MatchState *ms, const l_char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *min_expand (MatchState *ms, const l_char *s,
|
static const char *min_expand (MatchState *ms, const char *s,
|
||||||
const l_char *p, const l_char *ep) {
|
const char *p, const char *ep) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const l_char *res = match(ms, s, ep+1);
|
const char *res = match(ms, s, ep+1);
|
||||||
if (res != NULL)
|
if (res != NULL)
|
||||||
return res;
|
return res;
|
||||||
else if (s<ms->src_end && luaI_singlematch(*s, p, ep))
|
else if (s<ms->src_end && luaI_singlematch(uchar(*s), p, ep))
|
||||||
s++; /* try with one more repetition */
|
s++; /* try with one more repetition */
|
||||||
else return NULL;
|
else return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *start_capture (MatchState *ms, const l_char *s,
|
static const char *start_capture (MatchState *ms, const char *s,
|
||||||
const l_char *p, int what) {
|
const char *p, int what) {
|
||||||
const l_char *res;
|
const char *res;
|
||||||
int level = ms->level;
|
int level = ms->level;
|
||||||
if (level >= MAX_CAPTURES) lua_error(ms->L, l_s("too many captures"));
|
if (level >= MAX_CAPTURES) luaL_error(ms->L, "too many captures");
|
||||||
ms->capture[level].init = s;
|
ms->capture[level].init = s;
|
||||||
ms->capture[level].len = what;
|
ms->capture[level].len = what;
|
||||||
ms->level = level+1;
|
ms->level = level+1;
|
||||||
@@ -302,10 +326,10 @@ static const l_char *start_capture (MatchState *ms, const l_char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *end_capture (MatchState *ms, const l_char *s,
|
static const char *end_capture (MatchState *ms, const char *s,
|
||||||
const l_char *p) {
|
const char *p) {
|
||||||
int l = capture_to_close(ms);
|
int l = capture_to_close(ms);
|
||||||
const l_char *res;
|
const char *res;
|
||||||
ms->capture[l].len = s - ms->capture[l].init; /* close capture */
|
ms->capture[l].len = s - ms->capture[l].init; /* close capture */
|
||||||
if ((res = match(ms, s, p)) == NULL) /* match failed? */
|
if ((res = match(ms, s, p)) == NULL) /* match failed? */
|
||||||
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
|
ms->capture[l].len = CAP_UNFINISHED; /* undo capture */
|
||||||
@@ -313,7 +337,7 @@ static const l_char *end_capture (MatchState *ms, const l_char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *match_capture (MatchState *ms, const l_char *s, int l) {
|
static const char *match_capture (MatchState *ms, const char *s, int l) {
|
||||||
size_t len;
|
size_t len;
|
||||||
l = check_capture(ms, l);
|
l = check_capture(ms, l);
|
||||||
len = ms->capture[l].len;
|
len = ms->capture[l].len;
|
||||||
@@ -324,53 +348,77 @@ static const l_char *match_capture (MatchState *ms, const l_char *s, int l) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *match (MatchState *ms, const l_char *s, const l_char *p) {
|
static const char *match (MatchState *ms, const char *s, const char *p) {
|
||||||
init: /* using goto's to optimize tail recursion */
|
init: /* using goto's to optimize tail recursion */
|
||||||
switch (*p) {
|
switch (*p) {
|
||||||
case l_c('('): /* start capture */
|
case '(': { /* start capture */
|
||||||
if (*(p+1) == l_c(')')) /* position capture? */
|
if (*(p+1) == ')') /* position capture? */
|
||||||
return start_capture(ms, s, p+2, CAP_POSITION);
|
return start_capture(ms, s, p+2, CAP_POSITION);
|
||||||
else
|
else
|
||||||
return start_capture(ms, s, p+1, CAP_UNFINISHED);
|
return start_capture(ms, s, p+1, CAP_UNFINISHED);
|
||||||
case l_c(')'): /* end capture */
|
}
|
||||||
|
case ')': { /* end capture */
|
||||||
return end_capture(ms, s, p+1);
|
return end_capture(ms, s, p+1);
|
||||||
case ESC: /* may be %[0-9] or %b */
|
}
|
||||||
if (isdigit(uchar(*(p+1)))) { /* capture? */
|
case ESC: {
|
||||||
s = match_capture(ms, s, *(p+1));
|
switch (*(p+1)) {
|
||||||
if (s == NULL) return NULL;
|
case 'b': { /* balanced string? */
|
||||||
p+=2; goto init; /* else return match(ms, s, p+2) */
|
s = matchbalance(ms, s, p+2);
|
||||||
|
if (s == NULL) return NULL;
|
||||||
|
p+=4; goto init; /* else return match(ms, s, p+4); */
|
||||||
|
}
|
||||||
|
case 'f': { /* frontier? */
|
||||||
|
const char *ep; char previous;
|
||||||
|
p += 2;
|
||||||
|
if (*p != '[')
|
||||||
|
luaL_error(ms->L, "missing `[' after `%%f' in pattern");
|
||||||
|
ep = luaI_classend(ms, p); /* points to what is next */
|
||||||
|
previous = (s == ms->src_init) ? '\0' : *(s-1);
|
||||||
|
if (matchbracketclass(uchar(previous), p, ep-1) ||
|
||||||
|
!matchbracketclass(uchar(*s), p, ep-1)) return NULL;
|
||||||
|
p=ep; goto init; /* else return match(ms, s, ep); */
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
if (isdigit(uchar(*(p+1)))) { /* capture results (%0-%9)? */
|
||||||
|
s = match_capture(ms, s, *(p+1));
|
||||||
|
if (s == NULL) return NULL;
|
||||||
|
p+=2; goto init; /* else return match(ms, s, p+2) */
|
||||||
|
}
|
||||||
|
goto dflt; /* case default */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (*(p+1) == l_c('b')) { /* balanced string? */
|
}
|
||||||
s = matchbalance(ms, s, p+2);
|
case '\0': { /* end of pattern */
|
||||||
if (s == NULL) return NULL;
|
|
||||||
p+=4; goto init; /* else return match(ms, s, p+4); */
|
|
||||||
}
|
|
||||||
else goto dflt; /* case default */
|
|
||||||
case l_c('\0'): /* end of pattern */
|
|
||||||
return s; /* match succeeded */
|
return s; /* match succeeded */
|
||||||
case l_c('$'):
|
}
|
||||||
if (*(p+1) == l_c('\0')) /* is the `$' the last char in pattern? */
|
case '$': {
|
||||||
|
if (*(p+1) == '\0') /* is the `$' the last char in pattern? */
|
||||||
return (s == ms->src_end) ? s : NULL; /* check end of string */
|
return (s == ms->src_end) ? s : NULL; /* check end of string */
|
||||||
else goto dflt;
|
else goto dflt;
|
||||||
|
}
|
||||||
default: dflt: { /* it is a pattern item */
|
default: dflt: { /* it is a pattern item */
|
||||||
const l_char *ep = luaI_classend(ms, p); /* points to what is next */
|
const char *ep = luaI_classend(ms, p); /* points to what is next */
|
||||||
int m = s<ms->src_end && luaI_singlematch(*s, p, ep);
|
int m = s<ms->src_end && luaI_singlematch(uchar(*s), p, ep);
|
||||||
switch (*ep) {
|
switch (*ep) {
|
||||||
case l_c('?'): { /* optional */
|
case '?': { /* optional */
|
||||||
const l_char *res;
|
const char *res;
|
||||||
if (m && ((res=match(ms, s+1, ep+1)) != NULL))
|
if (m && ((res=match(ms, s+1, ep+1)) != NULL))
|
||||||
return res;
|
return res;
|
||||||
p=ep+1; goto init; /* else return match(ms, s, ep+1); */
|
p=ep+1; goto init; /* else return match(ms, s, ep+1); */
|
||||||
}
|
}
|
||||||
case l_c('*'): /* 0 or more repetitions */
|
case '*': { /* 0 or more repetitions */
|
||||||
return max_expand(ms, s, p, ep);
|
return max_expand(ms, s, p, ep);
|
||||||
case l_c('+'): /* 1 or more repetitions */
|
}
|
||||||
|
case '+': { /* 1 or more repetitions */
|
||||||
return (m ? max_expand(ms, s+1, p, ep) : NULL);
|
return (m ? max_expand(ms, s+1, p, ep) : NULL);
|
||||||
case l_c('-'): /* 0 or more repetitions (minimum) */
|
}
|
||||||
|
case '-': { /* 0 or more repetitions (minimum) */
|
||||||
return min_expand(ms, s, p, ep);
|
return min_expand(ms, s, p, ep);
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
if (!m) return NULL;
|
if (!m) return NULL;
|
||||||
s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
|
s++; p=ep; goto init; /* else return match(ms, s+1, ep); */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,15 +426,15 @@ static const l_char *match (MatchState *ms, const l_char *s, const l_char *p) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const l_char *lmemfind (const l_char *s1, size_t l1,
|
static const char *lmemfind (const char *s1, size_t l1,
|
||||||
const l_char *s2, size_t l2) {
|
const char *s2, size_t l2) {
|
||||||
if (l2 == 0) return s1; /* empty strings are everywhere */
|
if (l2 == 0) return s1; /* empty strings are everywhere */
|
||||||
else if (l2 > l1) return NULL; /* avoids a negative `l1' */
|
else if (l2 > l1) return NULL; /* avoids a negative `l1' */
|
||||||
else {
|
else {
|
||||||
const l_char *init; /* to search for a `*s2' inside `s1' */
|
const char *init; /* to search for a `*s2' inside `s1' */
|
||||||
l2--; /* 1st char will be checked by `memchr' */
|
l2--; /* 1st char will be checked by `memchr' */
|
||||||
l1 = l1-l2; /* `s2' cannot be found after that */
|
l1 = l1-l2; /* `s2' cannot be found after that */
|
||||||
while (l1 > 0 && (init = (const l_char *)memchr(s1, *s2, l1)) != NULL) {
|
while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) {
|
||||||
init++; /* 1st char is already checked */
|
init++; /* 1st char is already checked */
|
||||||
if (memcmp(init, s2+1, l2) == 0)
|
if (memcmp(init, s2+1, l2) == 0)
|
||||||
return init-1;
|
return init-1;
|
||||||
@@ -402,52 +450,60 @@ static const l_char *lmemfind (const l_char *s1, size_t l1,
|
|||||||
|
|
||||||
static void push_onecapture (MatchState *ms, int i) {
|
static void push_onecapture (MatchState *ms, int i) {
|
||||||
int l = ms->capture[i].len;
|
int l = ms->capture[i].len;
|
||||||
if (l == CAP_UNFINISHED) lua_error(ms->L, l_s("unfinished capture"));
|
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
|
||||||
if (l == CAP_POSITION)
|
if (l == CAP_POSITION)
|
||||||
lua_pushnumber(ms->L, ms->capture[i].init - ms->src_init + 1);
|
lua_pushnumber(ms->L, (lua_Number)(ms->capture[i].init - ms->src_init + 1));
|
||||||
else
|
else
|
||||||
lua_pushlstring(ms->L, ms->capture[i].init, l);
|
lua_pushlstring(ms->L, ms->capture[i].init, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int push_captures (MatchState *ms) {
|
static int push_captures (MatchState *ms, const char *s, const char *e) {
|
||||||
int i;
|
int i;
|
||||||
luaL_checkstack(ms->L, ms->level, l_s("too many captures"));
|
luaL_checkstack(ms->L, ms->level, "too many captures");
|
||||||
for (i=0; i<ms->level; i++)
|
if (ms->level == 0 && s) { /* no explicit captures? */
|
||||||
push_onecapture(ms, i);
|
lua_pushlstring(ms->L, s, e-s); /* return whole match */
|
||||||
return ms->level; /* number of strings pushed */
|
return 1;
|
||||||
|
}
|
||||||
|
else { /* return all captures */
|
||||||
|
for (i=0; i<ms->level; i++)
|
||||||
|
push_onecapture(ms, i);
|
||||||
|
return ms->level; /* number of strings pushed */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int str_find (lua_State *L) {
|
static int str_find (lua_State *L) {
|
||||||
size_t l1, l2;
|
size_t l1, l2;
|
||||||
const l_char *s = luaL_check_lstr(L, 1, &l1);
|
const char *s = luaL_checklstring(L, 1, &l1);
|
||||||
const l_char *p = luaL_check_lstr(L, 2, &l2);
|
const char *p = luaL_checklstring(L, 2, &l2);
|
||||||
sint32 init = posrelat(luaL_opt_long(L, 3, 1), l1) - 1;
|
sint32 init = posrelat(luaL_optlong(L, 3, 1), l1) - 1;
|
||||||
luaL_arg_check(L, 0 <= init && (size_t)init <= l1, 3, l_s("out of range"));
|
if (init < 0) init = 0;
|
||||||
if (lua_gettop(L) > 3 || /* extra argument? */
|
else if ((size_t)(init) > l1) init = (sint32)l1;
|
||||||
|
if (lua_toboolean(L, 4) || /* explicit request? */
|
||||||
strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */
|
strpbrk(p, SPECIALS) == NULL) { /* or no special characters? */
|
||||||
const l_char *s2 = lmemfind(s+init, l1-init, p, l2);
|
/* do a plain search */
|
||||||
|
const char *s2 = lmemfind(s+init, l1-init, p, l2);
|
||||||
if (s2) {
|
if (s2) {
|
||||||
lua_pushnumber(L, s2-s+1);
|
lua_pushnumber(L, (lua_Number)(s2-s+1));
|
||||||
lua_pushnumber(L, s2-s+l2);
|
lua_pushnumber(L, (lua_Number)(s2-s+l2));
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MatchState ms;
|
MatchState ms;
|
||||||
int anchor = (*p == l_c('^')) ? (p++, 1) : 0;
|
int anchor = (*p == '^') ? (p++, 1) : 0;
|
||||||
const l_char *s1=s+init;
|
const char *s1=s+init;
|
||||||
ms.L = L;
|
ms.L = L;
|
||||||
ms.src_init = s;
|
ms.src_init = s;
|
||||||
ms.src_end = s+l1;
|
ms.src_end = s+l1;
|
||||||
do {
|
do {
|
||||||
const l_char *res;
|
const char *res;
|
||||||
ms.level = 0;
|
ms.level = 0;
|
||||||
if ((res=match(&ms, s1, p)) != NULL) {
|
if ((res=match(&ms, s1, p)) != NULL) {
|
||||||
lua_pushnumber(L, s1-s+1); /* start */
|
lua_pushnumber(L, (lua_Number)(s1-s+1)); /* start */
|
||||||
lua_pushnumber(L, res-s); /* end */
|
lua_pushnumber(L, (lua_Number)(res-s)); /* end */
|
||||||
return push_captures(&ms) + 2;
|
return push_captures(&ms, NULL, 0) + 2;
|
||||||
}
|
}
|
||||||
} while (s1++<ms.src_end && !anchor);
|
} while (s1++<ms.src_end && !anchor);
|
||||||
}
|
}
|
||||||
@@ -456,10 +512,47 @@ static int str_find (lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void add_s (MatchState *ms, luaL_Buffer *b) {
|
static int gfind_aux (lua_State *L) {
|
||||||
|
MatchState ms;
|
||||||
|
const char *s = lua_tostring(L, lua_upvalueindex(1));
|
||||||
|
size_t ls = lua_strlen(L, lua_upvalueindex(1));
|
||||||
|
const char *p = lua_tostring(L, lua_upvalueindex(2));
|
||||||
|
const char *src;
|
||||||
|
ms.L = L;
|
||||||
|
ms.src_init = s;
|
||||||
|
ms.src_end = s+ls;
|
||||||
|
for (src = s + (size_t)lua_tonumber(L, lua_upvalueindex(3));
|
||||||
|
src <= ms.src_end;
|
||||||
|
src++) {
|
||||||
|
const char *e;
|
||||||
|
ms.level = 0;
|
||||||
|
if ((e = match(&ms, src, p)) != NULL) {
|
||||||
|
int newstart = e-s;
|
||||||
|
if (e == src) newstart++; /* empty match? go at least one position */
|
||||||
|
lua_pushnumber(L, (lua_Number)newstart);
|
||||||
|
lua_replace(L, lua_upvalueindex(3));
|
||||||
|
return push_captures(&ms, src, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; /* not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int gfind (lua_State *L) {
|
||||||
|
luaL_checkstring(L, 1);
|
||||||
|
luaL_checkstring(L, 2);
|
||||||
|
lua_settop(L, 2);
|
||||||
|
lua_pushnumber(L, 0);
|
||||||
|
lua_pushcclosure(L, gfind_aux, 3);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void add_s (MatchState *ms, luaL_Buffer *b,
|
||||||
|
const char *s, const char *e) {
|
||||||
lua_State *L = ms->L;
|
lua_State *L = ms->L;
|
||||||
if (lua_isstring(L, 3)) {
|
if (lua_isstring(L, 3)) {
|
||||||
const l_char *news = lua_tostring(L, 3);
|
const char *news = lua_tostring(L, 3);
|
||||||
size_t l = lua_strlen(L, 3);
|
size_t l = lua_strlen(L, 3);
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i=0; i<l; i++) {
|
for (i=0; i<l; i++) {
|
||||||
@@ -480,8 +573,8 @@ static void add_s (MatchState *ms, luaL_Buffer *b) {
|
|||||||
else { /* is a function */
|
else { /* is a function */
|
||||||
int n;
|
int n;
|
||||||
lua_pushvalue(L, 3);
|
lua_pushvalue(L, 3);
|
||||||
n = push_captures(ms);
|
n = push_captures(ms, s, e);
|
||||||
lua_rawcall(L, n, 1);
|
lua_call(L, n, 1);
|
||||||
if (lua_isstring(L, -1))
|
if (lua_isstring(L, -1))
|
||||||
luaL_addvalue(b); /* add return to accumulated result */
|
luaL_addvalue(b); /* add return to accumulated result */
|
||||||
else
|
else
|
||||||
@@ -492,27 +585,27 @@ static void add_s (MatchState *ms, luaL_Buffer *b) {
|
|||||||
|
|
||||||
static int str_gsub (lua_State *L) {
|
static int str_gsub (lua_State *L) {
|
||||||
size_t srcl;
|
size_t srcl;
|
||||||
const l_char *src = luaL_check_lstr(L, 1, &srcl);
|
const char *src = luaL_checklstring(L, 1, &srcl);
|
||||||
const l_char *p = luaL_check_string(L, 2);
|
const char *p = luaL_checkstring(L, 2);
|
||||||
int max_s = luaL_opt_int(L, 4, srcl+1);
|
int max_s = luaL_optint(L, 4, srcl+1);
|
||||||
int anchor = (*p == l_c('^')) ? (p++, 1) : 0;
|
int anchor = (*p == '^') ? (p++, 1) : 0;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
MatchState ms;
|
MatchState ms;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_arg_check(L,
|
luaL_argcheck(L,
|
||||||
lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
|
lua_gettop(L) >= 3 && (lua_isstring(L, 3) || lua_isfunction(L, 3)),
|
||||||
3, l_s("string or function expected"));
|
3, "string or function expected");
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
ms.L = L;
|
ms.L = L;
|
||||||
ms.src_init = src;
|
ms.src_init = src;
|
||||||
ms.src_end = src+srcl;
|
ms.src_end = src+srcl;
|
||||||
while (n < max_s) {
|
while (n < max_s) {
|
||||||
const l_char *e;
|
const char *e;
|
||||||
ms.level = 0;
|
ms.level = 0;
|
||||||
e = match(&ms, src, p);
|
e = match(&ms, src, p);
|
||||||
if (e) {
|
if (e) {
|
||||||
n++;
|
n++;
|
||||||
add_s(&ms, &b);
|
add_s(&ms, &b, src, e);
|
||||||
}
|
}
|
||||||
if (e && e>src) /* non empty match? */
|
if (e && e>src) /* non empty match? */
|
||||||
src = e; /* skip it */
|
src = e; /* skip it */
|
||||||
@@ -523,7 +616,7 @@ static int str_gsub (lua_State *L) {
|
|||||||
}
|
}
|
||||||
luaL_addlstring(&b, src, ms.src_end-src);
|
luaL_addlstring(&b, src, ms.src_end-src);
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
lua_pushnumber(L, n); /* number of substitutions */
|
lua_pushnumber(L, (lua_Number)n); /* number of substitutions */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,40 +631,47 @@ static int str_gsub (lua_State *L) {
|
|||||||
|
|
||||||
static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
|
static void luaI_addquoted (lua_State *L, luaL_Buffer *b, int arg) {
|
||||||
size_t l;
|
size_t l;
|
||||||
const l_char *s = luaL_check_lstr(L, arg, &l);
|
const char *s = luaL_checklstring(L, arg, &l);
|
||||||
luaL_putchar(b, l_c('"'));
|
luaL_putchar(b, '"');
|
||||||
while (l--) {
|
while (l--) {
|
||||||
switch (*s) {
|
switch (*s) {
|
||||||
case l_c('"'): case l_c('\\'): case l_c('\n'):
|
case '"': case '\\': case '\n': {
|
||||||
luaL_putchar(b, l_c('\\'));
|
luaL_putchar(b, '\\');
|
||||||
luaL_putchar(b, *s);
|
luaL_putchar(b, *s);
|
||||||
break;
|
break;
|
||||||
case l_c('\0'): luaL_addlstring(b, l_s("\\000"), 4); break;
|
}
|
||||||
default: luaL_putchar(b, *s);
|
case '\0': {
|
||||||
|
luaL_addlstring(b, "\\000", 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
luaL_putchar(b, *s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
luaL_putchar(b, l_c('"'));
|
luaL_putchar(b, '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const l_char *scanformat (lua_State *L, const l_char *strfrmt,
|
static const char *scanformat (lua_State *L, const char *strfrmt,
|
||||||
l_char *form, int *hasprecision) {
|
char *form, int *hasprecision) {
|
||||||
const l_char *p = strfrmt;
|
const char *p = strfrmt;
|
||||||
while (strchr(l_s("-+ #0"), *p)) p++; /* skip flags */
|
while (strchr("-+ #0", *p)) p++; /* skip flags */
|
||||||
if (isdigit(uchar(*p))) p++; /* skip width */
|
if (isdigit(uchar(*p))) p++; /* skip width */
|
||||||
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
||||||
if (*p == l_c('.')) {
|
if (*p == '.') {
|
||||||
p++;
|
p++;
|
||||||
*hasprecision = 1;
|
*hasprecision = 1;
|
||||||
if (isdigit(uchar(*p))) p++; /* skip precision */
|
if (isdigit(uchar(*p))) p++; /* skip precision */
|
||||||
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
||||||
}
|
}
|
||||||
if (isdigit(uchar(*p)))
|
if (isdigit(uchar(*p)))
|
||||||
lua_error(L, l_s("invalid format (width or precision too long)"));
|
luaL_error(L, "invalid format (width or precision too long)");
|
||||||
if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */
|
if (p-strfrmt+2 > MAX_FORMAT) /* +2 to include `%' and the specifier */
|
||||||
lua_error(L, l_s("invalid format (too long)"));
|
luaL_error(L, "invalid format (too long)");
|
||||||
form[0] = l_c('%');
|
form[0] = '%';
|
||||||
strncpy(form+1, strfrmt, p-strfrmt+1);
|
strncpy(form+1, strfrmt, p-strfrmt+1);
|
||||||
form[p-strfrmt+2] = 0;
|
form[p-strfrmt+2] = 0;
|
||||||
return p;
|
return p;
|
||||||
@@ -581,40 +681,44 @@ static const l_char *scanformat (lua_State *L, const l_char *strfrmt,
|
|||||||
static int str_format (lua_State *L) {
|
static int str_format (lua_State *L) {
|
||||||
int arg = 1;
|
int arg = 1;
|
||||||
size_t sfl;
|
size_t sfl;
|
||||||
const l_char *strfrmt = luaL_check_lstr(L, arg, &sfl);
|
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
|
||||||
const l_char *strfrmt_end = strfrmt+sfl;
|
const char *strfrmt_end = strfrmt+sfl;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (strfrmt < strfrmt_end) {
|
while (strfrmt < strfrmt_end) {
|
||||||
if (*strfrmt != l_c('%'))
|
if (*strfrmt != '%')
|
||||||
luaL_putchar(&b, *strfrmt++);
|
luaL_putchar(&b, *strfrmt++);
|
||||||
else if (*++strfrmt == l_c('%'))
|
else if (*++strfrmt == '%')
|
||||||
luaL_putchar(&b, *strfrmt++); /* %% */
|
luaL_putchar(&b, *strfrmt++); /* %% */
|
||||||
else { /* format item */
|
else { /* format item */
|
||||||
l_char form[MAX_FORMAT]; /* to store the format (`%...') */
|
char form[MAX_FORMAT]; /* to store the format (`%...') */
|
||||||
l_char buff[MAX_ITEM]; /* to store the formatted item */
|
char buff[MAX_ITEM]; /* to store the formatted item */
|
||||||
int hasprecision = 0;
|
int hasprecision = 0;
|
||||||
if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == l_c('$'))
|
if (isdigit(uchar(*strfrmt)) && *(strfrmt+1) == '$')
|
||||||
lua_error(L, l_s("obsolete `format' option (d$)"));
|
return luaL_error(L, "obsolete option (d$) to `format'");
|
||||||
arg++;
|
arg++;
|
||||||
strfrmt = scanformat(L, strfrmt, form, &hasprecision);
|
strfrmt = scanformat(L, strfrmt, form, &hasprecision);
|
||||||
switch (*strfrmt++) {
|
switch (*strfrmt++) {
|
||||||
case l_c('c'): case l_c('d'): case l_c('i'):
|
case 'c': case 'd': case 'i': {
|
||||||
sprintf(buff, form, luaL_check_int(L, arg));
|
sprintf(buff, form, luaL_checkint(L, arg));
|
||||||
break;
|
break;
|
||||||
case l_c('o'): case l_c('u'): case l_c('x'): case l_c('X'):
|
}
|
||||||
sprintf(buff, form, (unsigned int)luaL_check_number(L, arg));
|
case 'o': case 'u': case 'x': case 'X': {
|
||||||
|
sprintf(buff, form, (unsigned int)(luaL_checknumber(L, arg)));
|
||||||
break;
|
break;
|
||||||
case l_c('e'): case l_c('E'): case l_c('f'):
|
}
|
||||||
case l_c('g'): case l_c('G'):
|
case 'e': case 'E': case 'f':
|
||||||
sprintf(buff, form, luaL_check_number(L, arg));
|
case 'g': case 'G': {
|
||||||
|
sprintf(buff, form, luaL_checknumber(L, arg));
|
||||||
break;
|
break;
|
||||||
case l_c('q'):
|
}
|
||||||
|
case 'q': {
|
||||||
luaI_addquoted(L, &b, arg);
|
luaI_addquoted(L, &b, arg);
|
||||||
continue; /* skip the `addsize' at the end */
|
continue; /* skip the `addsize' at the end */
|
||||||
case l_c('s'): {
|
}
|
||||||
|
case 's': {
|
||||||
size_t l;
|
size_t l;
|
||||||
const l_char *s = luaL_check_lstr(L, arg, &l);
|
const char *s = luaL_checklstring(L, arg, &l);
|
||||||
if (!hasprecision && l >= 100) {
|
if (!hasprecision && l >= 100) {
|
||||||
/* no precision and string is too long to be formatted;
|
/* no precision and string is too long to be formatted;
|
||||||
keep original string */
|
keep original string */
|
||||||
@@ -627,8 +731,9 @@ static int str_format (lua_State *L) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: /* also treat cases `pnLlh' */
|
default: { /* also treat cases `pnLlh' */
|
||||||
lua_error(L, l_s("invalid option in `format'"));
|
return luaL_error(L, "invalid option to `format'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
luaL_addlstring(&b, buff, strlen(buff));
|
luaL_addlstring(&b, buff, strlen(buff));
|
||||||
}
|
}
|
||||||
@@ -639,23 +744,27 @@ static int str_format (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
static const luaL_reg strlib[] = {
|
static const luaL_reg strlib[] = {
|
||||||
{l_s("strlen"), str_len},
|
{"len", str_len},
|
||||||
{l_s("strsub"), str_sub},
|
{"sub", str_sub},
|
||||||
{l_s("strlower"), str_lower},
|
{"lower", str_lower},
|
||||||
{l_s("strupper"), str_upper},
|
{"upper", str_upper},
|
||||||
{l_s("strchar"), str_char},
|
{"char", str_char},
|
||||||
{l_s("strrep"), str_rep},
|
{"rep", str_rep},
|
||||||
{l_s("strbyte"), str_byte},
|
{"byte", str_byte},
|
||||||
{l_s("format"), str_format},
|
{"format", str_format},
|
||||||
{l_s("strfind"), str_find},
|
{"dump", str_dump},
|
||||||
{l_s("gsub"), str_gsub}
|
{"find", str_find},
|
||||||
|
{"gfind", gfind},
|
||||||
|
{"gsub", str_gsub},
|
||||||
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Open string library
|
** Open string library
|
||||||
*/
|
*/
|
||||||
LUALIB_API int lua_strlibopen (lua_State *L) {
|
LUALIB_API int luaopen_string (lua_State *L) {
|
||||||
luaL_openl(L, strlib);
|
luaL_openlib(L, LUA_STRLIBNAME, strlib, 0);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
483
ltable.c
483
ltable.c
@@ -1,13 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ltable.c,v 1.82 2001/06/26 13:20:45 roberto Exp roberto $
|
** $Id: ltable.c,v 1.131 2003/03/24 14:18:42 roberto Exp roberto $
|
||||||
** Lua tables (hash)
|
** Lua tables (hash)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Implementation of tables (aka arrays, objects, or hash tables);
|
** Implementation of tables (aka arrays, objects, or hash tables).
|
||||||
** uses a mix of chained scatter table with Brent's variation.
|
** Tables keep its elements in two parts: an array part and a hash part.
|
||||||
|
** Non-negative integer keys are all candidates to be kept in the array
|
||||||
|
** part. The actual size of the array is the largest `n' such that at
|
||||||
|
** least half the slots between 0 and n are in use.
|
||||||
|
** Hash uses a mix of chained scatter table with Brent's variation.
|
||||||
** A main invariant of these tables is that, if an element is not
|
** A main invariant of these tables is that, if an element is not
|
||||||
** in its main position (i.e. the `original' position that its hash gives
|
** in its main position (i.e. the `original' position that its hash gives
|
||||||
** to it), then the colliding element is in its own main position.
|
** to it), then the colliding element is in its own main position.
|
||||||
@@ -17,157 +21,352 @@
|
|||||||
** performance penalties.
|
** performance penalties.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ltable_c
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "ldebug.h"
|
||||||
#include "ldo.h"
|
#include "ldo.h"
|
||||||
|
#include "lgc.h"
|
||||||
#include "lmem.h"
|
#include "lmem.h"
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
#include "ltable.h"
|
#include "ltable.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** max size of array part is 2^MAXBITS
|
||||||
|
*/
|
||||||
|
#if BITS_INT > 26
|
||||||
|
#define MAXBITS 24
|
||||||
|
#else
|
||||||
|
#define MAXBITS (BITS_INT-2)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TagDefault LUA_TTABLE
|
/* check whether `x' < 2^MAXBITS */
|
||||||
|
#define toobig(x) ((((x)-1) >> MAXBITS) != 0)
|
||||||
|
|
||||||
|
|
||||||
#define hashnum(t,n) (node(t, lmod((lu_hash)(ls_hash)(n), t->size)))
|
/* function to convert a lua_Number to int (with any rounding method) */
|
||||||
#define hashstr(t,str) (node(t, lmod((str)->tsv.hash, t->size)))
|
#ifndef lua_number2int
|
||||||
#define hashpointer(t,p) (node(t, lmod(IntPoint(p), t->size)))
|
#define lua_number2int(i,n) ((i)=(int)(n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
|
||||||
|
|
||||||
|
#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
|
||||||
|
#define hashboolean(t,p) hashpow2(t, p)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** for some types, it is better to avoid modulus by power of 2, as
|
||||||
|
** they tend to have many 2 factors.
|
||||||
|
*/
|
||||||
|
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
|
||||||
|
|
||||||
|
|
||||||
|
#define hashpointer(t,p) hashmod(t, IntPoint(p))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** number of ints inside a lua_Number
|
||||||
|
*/
|
||||||
|
#define numints cast(int, sizeof(lua_Number)/sizeof(int))
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** hash for lua_Numbers
|
||||||
|
*/
|
||||||
|
static Node *hashnum (const Table *t, lua_Number n) {
|
||||||
|
unsigned int a[numints];
|
||||||
|
int i;
|
||||||
|
n += 1; /* normalize number (avoid -0) */
|
||||||
|
lua_assert(sizeof(a) <= sizeof(n));
|
||||||
|
memcpy(a, &n, sizeof(a));
|
||||||
|
for (i = 1; i < numints; i++) a[0] += a[i];
|
||||||
|
return hashmod(t, cast(lu_hash, a[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** returns the `main' position of an element in a table (that is, the index
|
** returns the `main' position of an element in a table (that is, the index
|
||||||
** of its hash value)
|
** of its hash value)
|
||||||
*/
|
*/
|
||||||
Node *luaH_mainposition (const Hash *t, const TObject *key) {
|
Node *luaH_mainposition (const Table *t, const TObject *key) {
|
||||||
switch (ttype(key)) {
|
switch (ttype(key)) {
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
return hashnum(t, nvalue(key));
|
return hashnum(t, nvalue(key));
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
return hashstr(t, tsvalue(key));
|
return hashstr(t, tsvalue(key));
|
||||||
default: /* all other types are hashed as (void *) */
|
case LUA_TBOOLEAN:
|
||||||
return hashpointer(t, tsvalue(key));
|
return hashboolean(t, bvalue(key));
|
||||||
|
case LUA_TLIGHTUSERDATA:
|
||||||
|
return hashpointer(t, pvalue(key));
|
||||||
|
default:
|
||||||
|
return hashpointer(t, gcvalue(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Node *luaH_next (lua_State *L, Hash *t, const TObject *key) {
|
/*
|
||||||
|
** returns the index for `key' if `key' is an appropriate key to live in
|
||||||
|
** the array part of the table, -1 otherwise.
|
||||||
|
*/
|
||||||
|
static int arrayindex (const TObject *key) {
|
||||||
|
if (ttisnumber(key)) {
|
||||||
|
int k;
|
||||||
|
lua_number2int(k, (nvalue(key)));
|
||||||
|
if (cast(lua_Number, k) == nvalue(key) && k >= 1 && !toobig(k))
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
return -1; /* `key' did not match some condition */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** returns the index of a `key' for table traversals. First goes all
|
||||||
|
** elements in the array part, then elements in the hash part. The
|
||||||
|
** beginning and end of a traversal are signalled by -1.
|
||||||
|
*/
|
||||||
|
static int luaH_index (lua_State *L, Table *t, StkId key) {
|
||||||
int i;
|
int i;
|
||||||
if (ttype(key) == LUA_TNIL)
|
if (ttisnil(key)) return -1; /* first iteration */
|
||||||
i = 0; /* first iteration */
|
i = arrayindex(key);
|
||||||
|
if (0 <= i && i <= t->sizearray) { /* is `key' inside array part? */
|
||||||
|
return i-1; /* yes; that's the index (corrected to C) */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
const TObject *v = luaH_get(t, key);
|
const TObject *v = luaH_get(t, key);
|
||||||
if (v == &luaO_nilobject)
|
if (v == &luaO_nilobject)
|
||||||
luaD_error(L, l_s("invalid key for `next'"));
|
luaG_runerror(L, "invalid key for `next'");
|
||||||
i = (int)(((const lu_byte *)v -
|
i = cast(int, (cast(const lu_byte *, v) -
|
||||||
(const lu_byte *)(val(node(t, 0)))) / sizeof(Node)) + 1;
|
cast(const lu_byte *, gval(gnode(t, 0)))) / sizeof(Node));
|
||||||
|
return i + t->sizearray; /* hash elements are numbered after array ones */
|
||||||
}
|
}
|
||||||
for (; i<t->size; i++) {
|
|
||||||
Node *n = node(t, i);
|
|
||||||
if (ttype(val(n)) != LUA_TNIL)
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
return NULL; /* no more elements */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int luaH_nexti (Hash *t, int i) {
|
int luaH_next (lua_State *L, Table *t, StkId key) {
|
||||||
while ((++i)<t->size) {
|
int i = luaH_index(L, t, key); /* find original element */
|
||||||
if (ttype(val(node(t, i))) != LUA_TNIL) /* a non-nil value? */
|
for (i++; i < t->sizearray; i++) { /* try first array part */
|
||||||
return i;
|
if (!ttisnil(&t->array[i])) { /* a non-nil value? */
|
||||||
|
setnvalue(key, cast(lua_Number, i+1));
|
||||||
|
setobj2s(key+1, &t->array[i]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -1; /* no more elements */
|
for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */
|
||||||
|
if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
|
||||||
|
setobj2s(key, gkey(gnode(t, i)));
|
||||||
|
setobj2s(key+1, gval(gnode(t, i)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; /* no more elements */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define check_grow(L, p, n) \
|
|
||||||
if ((p) >= MAX_INT/(n)) luaD_error(L, l_s("table overflow"));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** returns smaller power of 2 larger than `n' (minimum is MINPOWER2)
|
** {=============================================================
|
||||||
|
** Rehash
|
||||||
|
** ==============================================================
|
||||||
*/
|
*/
|
||||||
static int power2 (lua_State *L, int n) {
|
|
||||||
int p = MINPOWER2;
|
|
||||||
while (p <= n) {
|
|
||||||
check_grow(L, p, 2);
|
|
||||||
p *= 2;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void setnodevector (lua_State *L, Hash *t, int size) {
|
static void computesizes (int nums[], int ntotal, int *narray, int *nhash) {
|
||||||
int i;
|
int i;
|
||||||
t->node = luaM_newvector(L, size, Node);
|
int a = nums[0]; /* number of elements smaller than 2^i */
|
||||||
for (i=0; i<size; i++) {
|
int na = a; /* number of elements to go to array part */
|
||||||
t->node[i].next = NULL;
|
int n = (na == 0) ? -1 : 0; /* (log of) optimal size for array part */
|
||||||
setnilvalue(key(node(t, i)));
|
for (i = 1; a < *narray && *narray >= twoto(i-1); i++) {
|
||||||
setnilvalue(val(node(t, i)));
|
if (nums[i] > 0) {
|
||||||
|
a += nums[i];
|
||||||
|
if (a >= twoto(i-1)) { /* more than half elements in use? */
|
||||||
|
n = i;
|
||||||
|
na = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t->size = size;
|
lua_assert(na <= *narray && *narray <= ntotal);
|
||||||
t->firstfree = node(t, size-1); /* first free position to be used */
|
*nhash = ntotal - na;
|
||||||
|
*narray = (n == -1) ? 0 : twoto(n);
|
||||||
|
lua_assert(na <= *narray && na >= *narray/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Hash *luaH_new (lua_State *L, int size) {
|
static void numuse (const Table *t, int *narray, int *nhash) {
|
||||||
Hash *t = luaM_new(L, Hash);
|
int nums[MAXBITS+1];
|
||||||
t->htag = TagDefault;
|
int i, lg;
|
||||||
t->next = G(L)->roottable;
|
int totaluse = 0;
|
||||||
G(L)->roottable = t;
|
/* count elements in array part */
|
||||||
t->mark = t;
|
for (i=0, lg=0; lg<=MAXBITS; lg++) { /* for each slice [2^(lg-1) to 2^lg) */
|
||||||
t->size = 0;
|
int ttlg = twoto(lg); /* 2^lg */
|
||||||
t->weakmode = 0;
|
if (ttlg > t->sizearray) {
|
||||||
|
ttlg = t->sizearray;
|
||||||
|
if (i >= ttlg) break;
|
||||||
|
}
|
||||||
|
nums[lg] = 0;
|
||||||
|
for (; i<ttlg; i++) {
|
||||||
|
if (!ttisnil(&t->array[i])) {
|
||||||
|
nums[lg]++;
|
||||||
|
totaluse++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (; lg<=MAXBITS; lg++) nums[lg] = 0; /* reset other counts */
|
||||||
|
*narray = totaluse; /* all previous uses were in array part */
|
||||||
|
/* count elements in hash part */
|
||||||
|
i = sizenode(t);
|
||||||
|
while (i--) {
|
||||||
|
Node *n = &t->node[i];
|
||||||
|
if (!ttisnil(gval(n))) {
|
||||||
|
int k = arrayindex(gkey(n));
|
||||||
|
if (k >= 0) { /* is `key' an appropriate array index? */
|
||||||
|
nums[luaO_log2(k-1)+1]++; /* count as such */
|
||||||
|
(*narray)++;
|
||||||
|
}
|
||||||
|
totaluse++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
computesizes(nums, totaluse, narray, nhash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setarrayvector (lua_State *L, Table *t, int size) {
|
||||||
|
int i;
|
||||||
|
luaM_reallocvector(L, t->array, t->sizearray, size, TObject);
|
||||||
|
for (i=t->sizearray; i<size; i++)
|
||||||
|
setnilvalue(&t->array[i]);
|
||||||
|
t->sizearray = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void setnodevector (lua_State *L, Table *t, int lsize) {
|
||||||
|
int i;
|
||||||
|
int size = twoto(lsize);
|
||||||
|
if (lsize > MAXBITS)
|
||||||
|
luaG_runerror(L, "table overflow");
|
||||||
|
if (lsize == 0) { /* no elements to hash part? */
|
||||||
|
t->node = G(L)->dummynode; /* use common `dummynode' */
|
||||||
|
lua_assert(ttisnil(gkey(t->node))); /* assert invariants: */
|
||||||
|
lua_assert(ttisnil(gval(t->node)));
|
||||||
|
lua_assert(t->node->next == NULL); /* (`dummynode' must be empty) */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t->node = luaM_newvector(L, size, Node);
|
||||||
|
for (i=0; i<size; i++) {
|
||||||
|
t->node[i].next = NULL;
|
||||||
|
setnilvalue(gkey(gnode(t, i)));
|
||||||
|
setnilvalue(gval(gnode(t, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t->lsizenode = cast(lu_byte, lsize);
|
||||||
|
t->firstfree = gnode(t, size-1); /* first free position to be used */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
|
||||||
|
int i;
|
||||||
|
int oldasize = t->sizearray;
|
||||||
|
int oldhsize = t->lsizenode;
|
||||||
|
Node *nold;
|
||||||
|
Node temp[1];
|
||||||
|
if (oldhsize)
|
||||||
|
nold = t->node; /* save old hash ... */
|
||||||
|
else { /* old hash is `dummynode' */
|
||||||
|
lua_assert(t->node == G(L)->dummynode);
|
||||||
|
temp[0] = t->node[0]; /* copy it to `temp' */
|
||||||
|
nold = temp;
|
||||||
|
setnilvalue(gkey(G(L)->dummynode)); /* restate invariant */
|
||||||
|
setnilvalue(gval(G(L)->dummynode));
|
||||||
|
lua_assert(G(L)->dummynode->next == NULL);
|
||||||
|
}
|
||||||
|
if (nasize > oldasize) /* array part must grow? */
|
||||||
|
setarrayvector(L, t, nasize);
|
||||||
|
/* create new hash part with appropriate size */
|
||||||
|
setnodevector(L, t, nhsize);
|
||||||
|
/* re-insert elements */
|
||||||
|
if (nasize < oldasize) { /* array part must shrink? */
|
||||||
|
t->sizearray = nasize;
|
||||||
|
/* re-insert elements from vanishing slice */
|
||||||
|
for (i=nasize; i<oldasize; i++) {
|
||||||
|
if (!ttisnil(&t->array[i]))
|
||||||
|
setobjt2t(luaH_setnum(L, t, i+1), &t->array[i]);
|
||||||
|
}
|
||||||
|
/* shrink array */
|
||||||
|
luaM_reallocvector(L, t->array, oldasize, nasize, TObject);
|
||||||
|
}
|
||||||
|
/* re-insert elements in hash part */
|
||||||
|
for (i = twoto(oldhsize) - 1; i >= 0; i--) {
|
||||||
|
Node *old = nold+i;
|
||||||
|
if (!ttisnil(gval(old)))
|
||||||
|
setobjt2t(luaH_set(L, t, gkey(old)), gval(old));
|
||||||
|
}
|
||||||
|
if (oldhsize)
|
||||||
|
luaM_freearray(L, nold, twoto(oldhsize), Node); /* free old array */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void rehash (lua_State *L, Table *t) {
|
||||||
|
int nasize, nhsize;
|
||||||
|
numuse(t, &nasize, &nhsize); /* compute new sizes for array and hash parts */
|
||||||
|
resize(L, t, nasize, luaO_log2(nhsize)+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** }=============================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
Table *luaH_new (lua_State *L, int narray, int lnhash) {
|
||||||
|
Table *t = luaM_new(L, Table);
|
||||||
|
luaC_link(L, valtogco(t), LUA_TTABLE);
|
||||||
|
t->metatable = hvalue(defaultmeta(L));
|
||||||
|
t->flags = cast(lu_byte, ~0);
|
||||||
|
/* temporary values (kept only if some malloc fails) */
|
||||||
|
t->array = NULL;
|
||||||
|
t->sizearray = 0;
|
||||||
|
t->lsizenode = 0;
|
||||||
t->node = NULL;
|
t->node = NULL;
|
||||||
setnodevector(L, t, power2(L, size));
|
setarrayvector(L, t, narray);
|
||||||
|
setnodevector(L, t, lnhash);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaH_free (lua_State *L, Hash *t) {
|
void luaH_free (lua_State *L, Table *t) {
|
||||||
luaM_freearray(L, t->node, t->size, Node);
|
if (t->lsizenode)
|
||||||
luaM_freelem(L, t, Hash);
|
luaM_freearray(L, t->node, sizenode(t), Node);
|
||||||
|
luaM_freearray(L, t->array, t->sizearray, TObject);
|
||||||
|
luaM_freelem(L, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int numuse (const Hash *t) {
|
#if 0
|
||||||
Node *v = t->node;
|
/*
|
||||||
int size = t->size;
|
** try to remove an element from a hash table; cannot move any element
|
||||||
int realuse = 0;
|
** (because gc can call `remove' during a table traversal)
|
||||||
int i;
|
*/
|
||||||
for (i=0; i<size; i++) {
|
void luaH_remove (Table *t, Node *e) {
|
||||||
if (ttype(&v[i].val) != LUA_TNIL)
|
Node *mp = luaH_mainposition(t, gkey(e));
|
||||||
realuse++;
|
if (e != mp) { /* element not in its main position? */
|
||||||
|
while (mp->next != e) mp = mp->next; /* find previous */
|
||||||
|
mp->next = e->next; /* remove `e' from its list */
|
||||||
}
|
}
|
||||||
return realuse;
|
else {
|
||||||
}
|
if (e->next != NULL) ??
|
||||||
|
}
|
||||||
|
lua_assert(ttisnil(gval(node)));
|
||||||
static void rehash (lua_State *L, Hash *t) {
|
setnilvalue(gkey(e)); /* clear node `e' */
|
||||||
int oldsize = t->size;
|
e->next = NULL;
|
||||||
Node *nold = t->node;
|
|
||||||
int nelems = numuse(t);
|
|
||||||
int i;
|
|
||||||
lua_assert(nelems<=oldsize);
|
|
||||||
if (nelems >= oldsize-oldsize/4) { /* using more than 3/4? */
|
|
||||||
check_grow(L, oldsize, 2);
|
|
||||||
setnodevector(L, t, oldsize*2); /* grow array */
|
|
||||||
}
|
|
||||||
else if (nelems <= oldsize/4 && /* less than 1/4? */
|
|
||||||
oldsize > MINPOWER2)
|
|
||||||
setnodevector(L, t, oldsize/2); /* shrink array */
|
|
||||||
else
|
|
||||||
setnodevector(L, t, oldsize); /* just rehash; keep the same size */
|
|
||||||
for (i=0; i<oldsize; i++) {
|
|
||||||
Node *old = nold+i;
|
|
||||||
if (ttype(val(old)) != LUA_TNIL) {
|
|
||||||
TObject *v = luaH_set(L, t, key(old));
|
|
||||||
setobj(v, val(old));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
luaM_freearray(L, nold, oldsize, Node); /* free old array */
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -177,10 +376,11 @@ static void rehash (lua_State *L, Hash *t) {
|
|||||||
** put new key in its main position; otherwise (colliding node is in its main
|
** put new key in its main position; otherwise (colliding node is in its main
|
||||||
** position), new key goes to an empty position.
|
** position), new key goes to an empty position.
|
||||||
*/
|
*/
|
||||||
static TObject *newkey (lua_State *L, Hash *t, const TObject *key) {
|
static TObject *newkey (lua_State *L, Table *t, const TObject *key) {
|
||||||
|
TObject *val;
|
||||||
Node *mp = luaH_mainposition(t, key);
|
Node *mp = luaH_mainposition(t, key);
|
||||||
if (ttype(val(mp)) != LUA_TNIL) { /* main position is not free? */
|
if (!ttisnil(gval(mp))) { /* main position is not free? */
|
||||||
Node *othern = luaH_mainposition(t, key(mp)); /* `mp' of colliding node */
|
Node *othern = luaH_mainposition(t, gkey(mp)); /* `mp' of colliding node */
|
||||||
Node *n = t->firstfree; /* get a free place */
|
Node *n = t->firstfree; /* get a free place */
|
||||||
if (othern != mp) { /* is colliding node out of its main position? */
|
if (othern != mp) { /* is colliding node out of its main position? */
|
||||||
/* yes; move colliding node into free position */
|
/* yes; move colliding node into free position */
|
||||||
@@ -188,7 +388,7 @@ static TObject *newkey (lua_State *L, Hash *t, const TObject *key) {
|
|||||||
othern->next = n; /* redo the chain with `n' in place of `mp' */
|
othern->next = n; /* redo the chain with `n' in place of `mp' */
|
||||||
*n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
|
*n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
|
||||||
mp->next = NULL; /* now `mp' is free */
|
mp->next = NULL; /* now `mp' is free */
|
||||||
setnilvalue(val(mp));
|
setnilvalue(gval(mp));
|
||||||
}
|
}
|
||||||
else { /* colliding node is in its own main position */
|
else { /* colliding node is in its own main position */
|
||||||
/* new node will go into free position */
|
/* new node will go into free position */
|
||||||
@@ -197,28 +397,33 @@ static TObject *newkey (lua_State *L, Hash *t, const TObject *key) {
|
|||||||
mp = n;
|
mp = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setobj(key(mp), key);
|
setobj2t(gkey(mp), key); /* write barrier */
|
||||||
lua_assert(ttype(val(mp)) == LUA_TNIL);
|
lua_assert(ttisnil(gval(mp)));
|
||||||
for (;;) { /* correct `firstfree' */
|
for (;;) { /* correct `firstfree' */
|
||||||
if (ttype(key(t->firstfree)) == LUA_TNIL)
|
if (ttisnil(gkey(t->firstfree)))
|
||||||
return val(mp); /* OK; table still has a free place */
|
return gval(mp); /* OK; table still has a free place */
|
||||||
else if (t->firstfree == t->node) break; /* cannot decrement from here */
|
else if (t->firstfree == t->node) break; /* cannot decrement from here */
|
||||||
else (t->firstfree)--;
|
else (t->firstfree)--;
|
||||||
}
|
}
|
||||||
rehash(L, t); /* no more free places */
|
/* no more free places; must create one */
|
||||||
return luaH_set(L, t, key); /* `rehash' invalidates this insertion */
|
setbvalue(gval(mp), 0); /* avoid new key being removed */
|
||||||
|
rehash(L, t); /* grow table */
|
||||||
|
val = cast(TObject *, luaH_get(t, key)); /* get new position */
|
||||||
|
lua_assert(ttisboolean(val));
|
||||||
|
setnilvalue(val);
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** generic search function
|
** generic search function
|
||||||
*/
|
*/
|
||||||
static const TObject *luaH_getany (Hash *t, const TObject *key) {
|
static const TObject *luaH_getany (Table *t, const TObject *key) {
|
||||||
if (ttype(key) == LUA_TNIL) return &luaO_nilobject;
|
if (ttisnil(key)) return &luaO_nilobject;
|
||||||
else {
|
else {
|
||||||
Node *n = luaH_mainposition(t, key);
|
Node *n = luaH_mainposition(t, key);
|
||||||
do { /* check whether `key' is somewhere in the chain */
|
do { /* check whether `key' is somewhere in the chain */
|
||||||
if (luaO_equalObj(key(n), key)) return val(n); /* that's it */
|
if (luaO_rawequalObj(gkey(n), key)) return gval(n); /* that's it */
|
||||||
else n = n->next;
|
else n = n->next;
|
||||||
} while (n);
|
} while (n);
|
||||||
return &luaO_nilobject;
|
return &luaO_nilobject;
|
||||||
@@ -229,25 +434,30 @@ static const TObject *luaH_getany (Hash *t, const TObject *key) {
|
|||||||
/*
|
/*
|
||||||
** search function for integers
|
** search function for integers
|
||||||
*/
|
*/
|
||||||
const TObject *luaH_getnum (Hash *t, int key) {
|
const TObject *luaH_getnum (Table *t, int key) {
|
||||||
Node *n = hashnum(t, key);
|
if (1 <= key && key <= t->sizearray)
|
||||||
do { /* check whether `key' is somewhere in the chain */
|
return &t->array[key-1];
|
||||||
if (ttype(key(n)) == LUA_TNUMBER && nvalue(key(n)) == (lua_Number)key)
|
else {
|
||||||
return val(n); /* that's it */
|
lua_Number nk = cast(lua_Number, key);
|
||||||
else n = n->next;
|
Node *n = hashnum(t, nk);
|
||||||
} while (n);
|
do { /* check whether `key' is somewhere in the chain */
|
||||||
return &luaO_nilobject;
|
if (ttisnumber(gkey(n)) && nvalue(gkey(n)) == nk)
|
||||||
|
return gval(n); /* that's it */
|
||||||
|
else n = n->next;
|
||||||
|
} while (n);
|
||||||
|
return &luaO_nilobject;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** search function for strings
|
** search function for strings
|
||||||
*/
|
*/
|
||||||
const TObject *luaH_getstr (Hash *t, TString *key) {
|
const TObject *luaH_getstr (Table *t, TString *key) {
|
||||||
Node *n = hashstr(t, key);
|
Node *n = hashstr(t, key);
|
||||||
do { /* check whether `key' is somewhere in the chain */
|
do { /* check whether `key' is somewhere in the chain */
|
||||||
if (ttype(key(n)) == LUA_TSTRING && tsvalue(key(n)) == key)
|
if (ttisstring(gkey(n)) && tsvalue(gkey(n)) == key)
|
||||||
return val(n); /* that's it */
|
return gval(n); /* that's it */
|
||||||
else n = n->next;
|
else n = n->next;
|
||||||
} while (n);
|
} while (n);
|
||||||
return &luaO_nilobject;
|
return &luaO_nilobject;
|
||||||
@@ -257,12 +467,13 @@ const TObject *luaH_getstr (Hash *t, TString *key) {
|
|||||||
/*
|
/*
|
||||||
** main search function
|
** main search function
|
||||||
*/
|
*/
|
||||||
const TObject *luaH_get (Hash *t, const TObject *key) {
|
const TObject *luaH_get (Table *t, const TObject *key) {
|
||||||
switch (ttype(key)) {
|
switch (ttype(key)) {
|
||||||
case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
|
case LUA_TSTRING: return luaH_getstr(t, tsvalue(key));
|
||||||
case LUA_TNUMBER: {
|
case LUA_TNUMBER: {
|
||||||
int k = (int)nvalue(key);
|
int k;
|
||||||
if ((lua_Number)k == nvalue(key)) /* is an integer index? */
|
lua_number2int(k, (nvalue(key)));
|
||||||
|
if (cast(lua_Number, k) == nvalue(key)) /* is an integer index? */
|
||||||
return luaH_getnum(t, k); /* use specialized version */
|
return luaH_getnum(t, k); /* use specialized version */
|
||||||
/* else go through */
|
/* else go through */
|
||||||
}
|
}
|
||||||
@@ -271,31 +482,27 @@ const TObject *luaH_get (Hash *t, const TObject *key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TObject *luaH_set (lua_State *L, Hash *t, const TObject *key) {
|
TObject *luaH_set (lua_State *L, Table *t, const TObject *key) {
|
||||||
const TObject *p = luaH_get(t, key);
|
const TObject *p = luaH_get(t, key);
|
||||||
if (p != &luaO_nilobject) return (TObject *)p;
|
t->flags = 0;
|
||||||
else if (ttype(key) == LUA_TNIL) luaD_error(L, l_s("table index is nil"));
|
if (p != &luaO_nilobject)
|
||||||
return newkey(L, t, key);
|
return cast(TObject *, p);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TObject *luaH_setstr (lua_State *L, Hash *t, TString *key) {
|
|
||||||
const TObject *p = luaH_getstr(t, key);
|
|
||||||
if (p != &luaO_nilobject) return (TObject *)p;
|
|
||||||
else {
|
else {
|
||||||
TObject k;
|
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
|
||||||
setsvalue(&k, key);
|
else if (ttisnumber(key) && nvalue(key) != nvalue(key))
|
||||||
return newkey(L, t, &k);
|
luaG_runerror(L, "table index is NaN");
|
||||||
|
return newkey(L, t, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TObject *luaH_setnum (lua_State *L, Hash *t, int key) {
|
TObject *luaH_setnum (lua_State *L, Table *t, int key) {
|
||||||
const TObject *p = luaH_getnum(t, key);
|
const TObject *p = luaH_getnum(t, key);
|
||||||
if (p != &luaO_nilobject) return (TObject *)p;
|
if (p != &luaO_nilobject)
|
||||||
|
return cast(TObject *, p);
|
||||||
else {
|
else {
|
||||||
TObject k;
|
TObject k;
|
||||||
setnvalue(&k, key);
|
setnvalue(&k, cast(lua_Number, key));
|
||||||
return newkey(L, t, &k);
|
return newkey(L, t, &k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
ltable.h
29
ltable.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ltable.h,v 1.33 2001/06/26 13:20:45 roberto Exp roberto $
|
** $Id: ltable.h,v 1.43 2002/11/07 16:03:33 roberto Exp roberto $
|
||||||
** Lua tables (hash)
|
** Lua tables (hash)
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -10,23 +10,22 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
|
|
||||||
|
|
||||||
#define node(_t,_i) (&(_t)->node[_i])
|
#define gnode(t,i) (&(t)->node[i])
|
||||||
#define key(_n) (&(_n)->key)
|
#define gkey(n) (&(n)->i_key)
|
||||||
#define val(_n) (&(_n)->val)
|
#define gval(n) (&(n)->i_val)
|
||||||
|
|
||||||
const TObject *luaH_getnum (Hash *t, int key);
|
|
||||||
TObject *luaH_setnum (lua_State *L, Hash *t, int key);
|
const TObject *luaH_getnum (Table *t, int key);
|
||||||
const TObject *luaH_getstr (Hash *t, TString *key);
|
TObject *luaH_setnum (lua_State *L, Table *t, int key);
|
||||||
TObject *luaH_setstr (lua_State *L, Hash *t, TString *key);
|
const TObject *luaH_getstr (Table *t, TString *key);
|
||||||
const TObject *luaH_get (Hash *t, const TObject *key);
|
const TObject *luaH_get (Table *t, const TObject *key);
|
||||||
TObject *luaH_set (lua_State *L, Hash *t, const TObject *key);
|
TObject *luaH_set (lua_State *L, Table *t, const TObject *key);
|
||||||
Hash *luaH_new (lua_State *L, int nhash);
|
Table *luaH_new (lua_State *L, int narray, int lnhash);
|
||||||
void luaH_free (lua_State *L, Hash *t);
|
void luaH_free (lua_State *L, Table *t);
|
||||||
Node *luaH_next (lua_State *L, Hash *t, const TObject *r);
|
int luaH_next (lua_State *L, Table *t, StkId key);
|
||||||
int luaH_nexti (Hash *t, int i);
|
|
||||||
|
|
||||||
/* exported only for debugging */
|
/* exported only for debugging */
|
||||||
Node *luaH_mainposition (const Hash *t, const TObject *key);
|
Node *luaH_mainposition (const Table *t, const TObject *key);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
250
ltablib.c
Normal file
250
ltablib.c
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
** $Id: ltablib.c,v 1.20 2003/03/11 12:24:34 roberto Exp roberto $
|
||||||
|
** Library for Table Manipulation
|
||||||
|
** See Copyright Notice in lua.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define ltablib_c
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_getn(L, n))
|
||||||
|
|
||||||
|
|
||||||
|
static int luaB_foreachi (lua_State *L) {
|
||||||
|
int i;
|
||||||
|
int n = aux_getn(L, 1);
|
||||||
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||||
|
for (i=1; i<=n; i++) {
|
||||||
|
lua_pushvalue(L, 2); /* function */
|
||||||
|
lua_pushnumber(L, (lua_Number)i); /* 1st argument */
|
||||||
|
lua_rawgeti(L, 1, i); /* 2nd argument */
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
return 1;
|
||||||
|
lua_pop(L, 1); /* remove nil result */
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int luaB_foreach (lua_State *L) {
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||||
|
lua_pushnil(L); /* first key */
|
||||||
|
for (;;) {
|
||||||
|
if (lua_next(L, 1) == 0)
|
||||||
|
return 0;
|
||||||
|
lua_pushvalue(L, 2); /* function */
|
||||||
|
lua_pushvalue(L, -3); /* key */
|
||||||
|
lua_pushvalue(L, -3); /* value */
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
if (!lua_isnil(L, -1))
|
||||||
|
return 1;
|
||||||
|
lua_pop(L, 2); /* remove value and result */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int luaB_getn (lua_State *L) {
|
||||||
|
lua_pushnumber(L, (lua_Number)aux_getn(L, 1));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int luaB_setn (lua_State *L) {
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
luaL_setn(L, 1, luaL_checkint(L, 2));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int luaB_tinsert (lua_State *L) {
|
||||||
|
int v = lua_gettop(L); /* number of arguments */
|
||||||
|
int n = aux_getn(L, 1) + 1;
|
||||||
|
int pos; /* where to insert new element */
|
||||||
|
if (v == 2) /* called with only 2 arguments */
|
||||||
|
pos = n; /* insert new element at the end */
|
||||||
|
else {
|
||||||
|
pos = luaL_checkint(L, 2); /* 2nd argument is the position */
|
||||||
|
if (pos > n) n = pos; /* `grow' array if necessary */
|
||||||
|
v = 3; /* function may be called with more than 3 args */
|
||||||
|
}
|
||||||
|
luaL_setn(L, 1, n); /* new size */
|
||||||
|
while (--n >= pos) { /* move up elements */
|
||||||
|
lua_rawgeti(L, 1, n);
|
||||||
|
lua_rawseti(L, 1, n+1); /* t[n+1] = t[n] */
|
||||||
|
}
|
||||||
|
lua_pushvalue(L, v);
|
||||||
|
lua_rawseti(L, 1, pos); /* t[pos] = v */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int luaB_tremove (lua_State *L) {
|
||||||
|
int n = aux_getn(L, 1);
|
||||||
|
int pos = luaL_optint(L, 2, n);
|
||||||
|
if (n <= 0) return 0; /* table is `empty' */
|
||||||
|
luaL_setn(L, 1, n-1); /* t.n = n-1 */
|
||||||
|
lua_rawgeti(L, 1, pos); /* result = t[pos] */
|
||||||
|
for ( ;pos<n; pos++) {
|
||||||
|
lua_rawgeti(L, 1, pos+1);
|
||||||
|
lua_rawseti(L, 1, pos); /* t[pos] = t[pos+1] */
|
||||||
|
}
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_rawseti(L, 1, n); /* t[n] = nil */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int str_concat (lua_State *L) {
|
||||||
|
luaL_Buffer b;
|
||||||
|
size_t lsep;
|
||||||
|
const char *sep = luaL_optlstring(L, 2, "", &lsep);
|
||||||
|
int i = luaL_optint(L, 3, 1);
|
||||||
|
int n = luaL_optint(L, 4, 0);
|
||||||
|
luaL_checktype(L, 1, LUA_TTABLE);
|
||||||
|
if (n == 0) n = luaL_getn(L, 1);
|
||||||
|
luaL_buffinit(L, &b);
|
||||||
|
for (; i <= n; i++) {
|
||||||
|
lua_rawgeti(L, 1, i);
|
||||||
|
luaL_argcheck(L, lua_isstring(L, -1), 1, "table contains non-strings");
|
||||||
|
luaL_addvalue(&b);
|
||||||
|
if (i != n)
|
||||||
|
luaL_addlstring(&b, sep, lsep);
|
||||||
|
}
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================
|
||||||
|
** Quicksort
|
||||||
|
** (based on `Algorithms in MODULA-3', Robert Sedgewick;
|
||||||
|
** Addison-Wesley, 1993.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void set2 (lua_State *L, int i, int j) {
|
||||||
|
lua_rawseti(L, 1, i);
|
||||||
|
lua_rawseti(L, 1, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sort_comp (lua_State *L, int a, int b) {
|
||||||
|
if (!lua_isnil(L, 2)) { /* function? */
|
||||||
|
int res;
|
||||||
|
lua_pushvalue(L, 2);
|
||||||
|
lua_pushvalue(L, a-1); /* -1 to compensate function */
|
||||||
|
lua_pushvalue(L, b-2); /* -2 to compensate function and `a' */
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
res = lua_toboolean(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else /* a < b? */
|
||||||
|
return lua_lessthan(L, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void auxsort (lua_State *L, int l, int u) {
|
||||||
|
while (l < u) { /* for tail recursion */
|
||||||
|
int i, j;
|
||||||
|
/* sort elements a[l], a[(l+u)/2] and a[u] */
|
||||||
|
lua_rawgeti(L, 1, l);
|
||||||
|
lua_rawgeti(L, 1, u);
|
||||||
|
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
|
||||||
|
set2(L, l, u); /* swap a[l] - a[u] */
|
||||||
|
else
|
||||||
|
lua_pop(L, 2);
|
||||||
|
if (u-l == 1) break; /* only 2 elements */
|
||||||
|
i = (l+u)/2;
|
||||||
|
lua_rawgeti(L, 1, i);
|
||||||
|
lua_rawgeti(L, 1, l);
|
||||||
|
if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
|
||||||
|
set2(L, i, l);
|
||||||
|
else {
|
||||||
|
lua_pop(L, 1); /* remove a[l] */
|
||||||
|
lua_rawgeti(L, 1, u);
|
||||||
|
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
|
||||||
|
set2(L, i, u);
|
||||||
|
else
|
||||||
|
lua_pop(L, 2);
|
||||||
|
}
|
||||||
|
if (u-l == 2) break; /* only 3 elements */
|
||||||
|
lua_rawgeti(L, 1, i); /* Pivot */
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_rawgeti(L, 1, u-1);
|
||||||
|
set2(L, i, u-1);
|
||||||
|
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
|
||||||
|
i = l; j = u-1;
|
||||||
|
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
|
||||||
|
/* repeat ++i until a[i] >= P */
|
||||||
|
while (lua_rawgeti(L, 1, ++i), sort_comp(L, -1, -2)) {
|
||||||
|
if (i>u) luaL_error(L, "invalid order function for sorting");
|
||||||
|
lua_pop(L, 1); /* remove a[i] */
|
||||||
|
}
|
||||||
|
/* repeat --j until a[j] <= P */
|
||||||
|
while (lua_rawgeti(L, 1, --j), sort_comp(L, -3, -1)) {
|
||||||
|
if (j<l) luaL_error(L, "invalid order function for sorting");
|
||||||
|
lua_pop(L, 1); /* remove a[j] */
|
||||||
|
}
|
||||||
|
if (j<i) {
|
||||||
|
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
set2(L, i, j);
|
||||||
|
}
|
||||||
|
lua_rawgeti(L, 1, u-1);
|
||||||
|
lua_rawgeti(L, 1, i);
|
||||||
|
set2(L, u-1, i); /* swap pivot (a[u-1]) with a[i] */
|
||||||
|
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
|
||||||
|
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
|
||||||
|
if (i-l < u-i) {
|
||||||
|
j=l; i=i-1; l=i+2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
j=i+1; i=u; u=j-2;
|
||||||
|
}
|
||||||
|
auxsort(L, j, i); /* call recursively the smaller one */
|
||||||
|
} /* repeat the routine for the larger one */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int luaB_sort (lua_State *L) {
|
||||||
|
int n = aux_getn(L, 1);
|
||||||
|
luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */
|
||||||
|
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
|
||||||
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
||||||
|
lua_settop(L, 2); /* make sure there is two arguments */
|
||||||
|
auxsort(L, 1, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
static const luaL_reg tab_funcs[] = {
|
||||||
|
{"concat", str_concat},
|
||||||
|
{"foreach", luaB_foreach},
|
||||||
|
{"foreachi", luaB_foreachi},
|
||||||
|
{"getn", luaB_getn},
|
||||||
|
{"setn", luaB_setn},
|
||||||
|
{"sort", luaB_sort},
|
||||||
|
{"insert", luaB_tinsert},
|
||||||
|
{"remove", luaB_tremove},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaopen_table (lua_State *L) {
|
||||||
|
luaL_openlib(L, LUA_TABLIBNAME, tab_funcs, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
28
ltests.h
28
ltests.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ltests.h,v 1.6 2001/03/02 17:27:50 roberto Exp roberto $
|
** $Id: ltests.h,v 1.19 2002/11/19 17:42:32 roberto Exp roberto $
|
||||||
** Internal Header for Debugging of the Lua Implementation
|
** Internal Header for Debugging of the Lua Implementation
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#define lua_assert(c) assert(c)
|
#define lua_assert(c) assert(c)
|
||||||
|
#define check_exp(c,e) (lua_assert(c), (e))
|
||||||
#define api_check(L, o) lua_assert(o)
|
#define api_check(L, o) lua_assert(o)
|
||||||
|
|
||||||
|
|
||||||
@@ -32,27 +33,36 @@ extern unsigned long memdebug_maxmem;
|
|||||||
extern unsigned long memdebug_memlimit;
|
extern unsigned long memdebug_memlimit;
|
||||||
|
|
||||||
|
|
||||||
#define l_malloc(s) debug_realloc(NULL, 0, s)
|
|
||||||
#define l_realloc(b, os, s) debug_realloc(b, os, s)
|
#define l_realloc(b, os, s) debug_realloc(b, os, s)
|
||||||
#define l_free(b, s) debug_realloc(b, s, 0)
|
#define l_free(b, os) debug_realloc(b, os, 0)
|
||||||
|
|
||||||
void *debug_realloc (void *block, size_t oldsize, size_t size);
|
void *debug_realloc (void *block, size_t oldsize, size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* test for lock/unlock */
|
/* test for lock/unlock */
|
||||||
#define LUA_USERSTATE int *lock;
|
|
||||||
extern int islocked;
|
extern int islocked;
|
||||||
#define lua_lock(L) lua_assert((**((int **)L))++ == 0)
|
#define LUA_USERSTATE int *
|
||||||
#define lua_unlock(L) lua_assert(--(**((int **)L)) == 0)
|
#define getlock(l) (*(cast(LUA_USERSTATE *, l) - 1))
|
||||||
|
#define lua_userstateopen(l) if (l != NULL) getlock(l) = &islocked;
|
||||||
|
#define lua_lock(l) lua_assert((*getlock(l))++ == 0)
|
||||||
|
#define lua_unlock(l) lua_assert(--(*getlock(l)) == 0)
|
||||||
|
|
||||||
|
|
||||||
extern lua_State *lua_state;
|
int luaB_opentests (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_EXTRALIBS { "tests", luaB_opentests },
|
||||||
|
|
||||||
|
|
||||||
void luaB_opentests (lua_State *L);
|
/* real main will be defined at `ltests.c' */
|
||||||
|
int l_main (int argc, char *argv[]);
|
||||||
|
#define main l_main
|
||||||
|
|
||||||
#define LUA_USERINIT(L) (luaB_opentests(L), openstdlibs(L))
|
|
||||||
|
|
||||||
|
|
||||||
|
/* change some sizes to give some bugs a chance */
|
||||||
|
|
||||||
|
#define LUAL_BUFFERSIZE 27
|
||||||
|
#define MINSTRTABSIZE 2
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
198
ltm.c
198
ltm.c
@@ -1,18 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ltm.c,v 1.75 2001/07/23 19:56:00 roberto Exp roberto $
|
** $Id: ltm.c,v 1.105 2002/12/04 17:38:31 roberto Exp roberto $
|
||||||
** Tag methods
|
** Tag methods
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define ltm_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "ldo.h"
|
|
||||||
#include "lmem.h"
|
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
#include "lstate.h"
|
||||||
#include "lstring.h"
|
#include "lstring.h"
|
||||||
@@ -20,173 +18,53 @@
|
|||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
|
|
||||||
|
|
||||||
const l_char *const luaT_eventname[] = { /* ORDER TM */
|
|
||||||
l_s("gettable"), l_s("settable"), l_s("index"), l_s("getglobal"),
|
const char *const luaT_typenames[] = {
|
||||||
l_s("setglobal"), l_s("add"), l_s("sub"), l_s("mul"), l_s("div"),
|
"nil", "boolean", "userdata", "number",
|
||||||
l_s("pow"), l_s("unm"), l_s("lt"), l_s("concat"), l_s("gc"),
|
"string", "table", "function", "userdata", "thread"
|
||||||
l_s("function"),
|
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int findevent (const l_char *name) {
|
|
||||||
int i;
|
|
||||||
for (i=0; luaT_eventname[i]; i++)
|
|
||||||
if (strcmp(luaT_eventname[i], name) == 0)
|
|
||||||
return i;
|
|
||||||
return -1; /* name not found */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int luaI_checkevent (lua_State *L, const l_char *name) {
|
|
||||||
int e = findevent(name);
|
|
||||||
if (e < 0)
|
|
||||||
luaO_verror(L, l_s("`%.50s' is not a valid event name"), name);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* events in LUA_TNIL are all allowed, since this is used as a
|
|
||||||
* `placeholder' for default fallbacks
|
|
||||||
*/
|
|
||||||
/* ORDER LUA_T, ORDER TM */
|
|
||||||
static const lu_byte luaT_validevents[NUM_TAGS][TM_N] = {
|
|
||||||
{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TUSERDATA */
|
|
||||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_TNIL */
|
|
||||||
{1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, /* LUA_TNUMBER */
|
|
||||||
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_TSTRING */
|
|
||||||
{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_TTABLE */
|
|
||||||
{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0} /* LUA_TFUNCTION */
|
|
||||||
};
|
|
||||||
|
|
||||||
int luaT_validevent (int t, int e) { /* ORDER LUA_T */
|
|
||||||
return (t >= NUM_TAGS) ? 1 : (int)luaT_validevents[t][e];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void luaT_init (lua_State *L) {
|
void luaT_init (lua_State *L) {
|
||||||
static const l_char *const typenames[NUM_TAGS] = {
|
static const char *const luaT_eventname[] = { /* ORDER TM */
|
||||||
l_s("userdata"), l_s("nil"), l_s("number"), l_s("string"),
|
"__index", "__newindex",
|
||||||
l_s("table"), l_s("function")
|
"__gc", "__mode", "__eq",
|
||||||
|
"__add", "__sub", "__mul", "__div",
|
||||||
|
"__pow", "__unm", "__lt", "__le",
|
||||||
|
"__concat", "__call"
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i<NUM_TAGS; i++)
|
for (i=0; i<TM_N; i++) {
|
||||||
luaT_newtag(L, typenames[i], i);
|
G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
|
||||||
}
|
luaS_fix(G(L)->tmname[i]); /* never collect these names */
|
||||||
|
|
||||||
|
|
||||||
int luaT_newtag (lua_State *L, const l_char *name, int basictype) {
|
|
||||||
int tag;
|
|
||||||
int i;
|
|
||||||
TString *ts = NULL;
|
|
||||||
luaM_growvector(L, G(L)->TMtable, G(L)->ntag, G(L)->sizeTM, struct TM,
|
|
||||||
MAX_INT, l_s("tag table overflow"));
|
|
||||||
tag = G(L)->ntag;
|
|
||||||
if (name) {
|
|
||||||
TObject *v;
|
|
||||||
ts = luaS_new(L, name);
|
|
||||||
v = luaH_setstr(L, G(L)->type2tag, ts);
|
|
||||||
if (ttype(v) == LUA_TNUMBER) return (int)nvalue(v);
|
|
||||||
setnvalue(v, tag);
|
|
||||||
}
|
|
||||||
for (i=0; i<TM_N; i++)
|
|
||||||
luaT_gettm(G(L), tag, i) = NULL;
|
|
||||||
G(L)->TMtable[tag].collected = NULL;
|
|
||||||
G(L)->TMtable[tag].name = ts;
|
|
||||||
G(L)->TMtable[tag].basictype = basictype;
|
|
||||||
G(L)->ntag++;
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void checktag (lua_State *L, int tag) {
|
|
||||||
if (!(0 <= tag && tag < G(L)->ntag))
|
|
||||||
luaO_verror(L, l_s("%d is not a valid tag"), tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom) {
|
|
||||||
int e;
|
|
||||||
lua_lock(L);
|
|
||||||
checktag(L, tagto);
|
|
||||||
checktag(L, tagfrom);
|
|
||||||
for (e=0; e<TM_N; e++) {
|
|
||||||
if (luaT_validevent(tagto, e))
|
|
||||||
luaT_gettm(G(L), tagto, e) = luaT_gettm(G(L), tagfrom, e);
|
|
||||||
}
|
|
||||||
lua_unlock(L);
|
|
||||||
return tagto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int luaT_tag (const TObject *o) {
|
|
||||||
int t = ttype(o);
|
|
||||||
switch (t) {
|
|
||||||
case LUA_TUSERDATA: return uvalue(o)->uv.tag;
|
|
||||||
case LUA_TTABLE: return hvalue(o)->htag;
|
|
||||||
default: return t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const l_char *luaT_typename (global_State *G, const TObject *o) {
|
/*
|
||||||
int t = ttype(o);
|
** function to be used with macro "fasttm": optimized for absence of
|
||||||
int tag;
|
** tag methods
|
||||||
TString *ts;
|
*/
|
||||||
switch (t) {
|
const TObject *luaT_gettm (Table *events, TMS event, TString *ename) {
|
||||||
case LUA_TUSERDATA:
|
const TObject *tm = luaH_getstr(events, ename);
|
||||||
tag = uvalue(o)->uv.tag;
|
lua_assert(event <= TM_EQ);
|
||||||
break;
|
if (ttisnil(tm)) { /* no tag method? */
|
||||||
|
events->flags |= cast(lu_byte, 1u<<event); /* cache this fact */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event) {
|
||||||
|
TString *ename = G(L)->tmname[event];
|
||||||
|
switch (ttype(o)) {
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
tag = hvalue(o)->htag;
|
return luaH_getstr(hvalue(o)->metatable, ename);
|
||||||
break;
|
case LUA_TUSERDATA:
|
||||||
|
return luaH_getstr(uvalue(o)->uv.metatable, ename);
|
||||||
default:
|
default:
|
||||||
tag = t;
|
return &luaO_nilobject;
|
||||||
}
|
}
|
||||||
ts = G->TMtable[tag].name;
|
|
||||||
if (ts == NULL)
|
|
||||||
ts = G->TMtable[t].name;
|
|
||||||
return getstr(ts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API void lua_gettagmethod (lua_State *L, int t, const l_char *event) {
|
|
||||||
int e;
|
|
||||||
lua_lock(L);
|
|
||||||
e = luaI_checkevent(L, event);
|
|
||||||
checktag(L, t);
|
|
||||||
if (luaT_validevent(t, e) && luaT_gettm(G(L), t, e)) {
|
|
||||||
setclvalue(L->top, luaT_gettm(G(L), t, e));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
setnilvalue(L->top);
|
|
||||||
incr_top;
|
|
||||||
lua_unlock(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API void lua_settagmethod (lua_State *L, int t, const l_char *event) {
|
|
||||||
int e;
|
|
||||||
lua_lock(L);
|
|
||||||
e = luaI_checkevent(L, event);
|
|
||||||
checktag(L, t);
|
|
||||||
if (!luaT_validevent(t, e))
|
|
||||||
luaO_verror(L, l_s("cannot change `%.20s' tag method for type `%.20s'%.20s"),
|
|
||||||
luaT_eventname[e], typenamebytag(G(L), t),
|
|
||||||
(t == LUA_TTABLE || t == LUA_TUSERDATA) ?
|
|
||||||
l_s(" with default tag") : l_s(""));
|
|
||||||
switch (ttype(L->top - 1)) {
|
|
||||||
case LUA_TNIL:
|
|
||||||
luaT_gettm(G(L), t, e) = NULL;
|
|
||||||
break;
|
|
||||||
case LUA_TFUNCTION:
|
|
||||||
luaT_gettm(G(L), t, e) = clvalue(L->top - 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
luaD_error(L, l_s("tag method must be a function (or nil)"));
|
|
||||||
}
|
|
||||||
L->top--;
|
|
||||||
lua_unlock(L);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
57
ltm.h
57
ltm.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: ltm.h,v 1.25 2001/06/06 18:00:19 roberto Exp roberto $
|
** $Id: ltm.h,v 1.40 2002/09/19 20:12:47 roberto Exp roberto $
|
||||||
** Tag methods
|
** Tag methods
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -9,18 +9,18 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lstate.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* WARNING: if you change the order of this enumeration,
|
* WARNING: if you change the order of this enumeration,
|
||||||
* grep "ORDER TM"
|
* grep "ORDER TM"
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TM_GETTABLE = 0,
|
|
||||||
TM_SETTABLE,
|
|
||||||
TM_INDEX,
|
TM_INDEX,
|
||||||
TM_GETGLOBAL,
|
TM_NEWINDEX,
|
||||||
TM_SETGLOBAL,
|
TM_GC,
|
||||||
|
TM_MODE,
|
||||||
|
TM_EQ, /* last tag method with `fast' access */
|
||||||
TM_ADD,
|
TM_ADD,
|
||||||
TM_SUB,
|
TM_SUB,
|
||||||
TM_MUL,
|
TM_MUL,
|
||||||
@@ -28,53 +28,24 @@ typedef enum {
|
|||||||
TM_POW,
|
TM_POW,
|
||||||
TM_UNM,
|
TM_UNM,
|
||||||
TM_LT,
|
TM_LT,
|
||||||
|
TM_LE,
|
||||||
TM_CONCAT,
|
TM_CONCAT,
|
||||||
TM_GC,
|
TM_CALL,
|
||||||
TM_FUNCTION,
|
|
||||||
TM_N /* number of elements in the enum */
|
TM_N /* number of elements in the enum */
|
||||||
} TMS;
|
} TMS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
#define gfasttm(g,et,e) \
|
||||||
** masks for allowable tag methods
|
(((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
|
||||||
** (see `luaT_validevents')
|
|
||||||
*/
|
|
||||||
#define HAS_TM_GETGLOBAL(L,t) (1<<(t) & ((1<<LUA_TUSERDATA) | \
|
|
||||||
(1<<LUA_TTABLE) | \
|
|
||||||
(1<<LUA_TNIL)))
|
|
||||||
|
|
||||||
#define HAS_TM_SETGLOBAL(L,t) (1<<(t) & ((1<<LUA_TUSERDATA) | \
|
#define fasttm(l,et,e) gfasttm(G(l), et, e)
|
||||||
(1<<LUA_TTABLE) | \
|
|
||||||
(1<<LUA_TNIL) | \
|
|
||||||
(1<<LUA_TFUNCTION)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct TM {
|
|
||||||
Closure *method[TM_N];
|
|
||||||
Udata *collected; /* list of garbage-collected udata with this tag */
|
|
||||||
TString *name; /* type name */
|
|
||||||
int basictype;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define luaT_gettm(G,tag,event) (G->TMtable[tag].method[event])
|
|
||||||
#define luaT_gettmbyObj(G,o,e) (luaT_gettm((G),luaT_tag(o),(e)))
|
|
||||||
|
|
||||||
#define typenamebytag(G, t) getstr(G->TMtable[t].name)
|
|
||||||
|
|
||||||
|
|
||||||
#define validtag(G,t) (NUM_TAGS <= (t) && (t) < G->ntag)
|
|
||||||
|
|
||||||
extern const l_char *const luaT_eventname[];
|
|
||||||
|
|
||||||
|
|
||||||
|
const TObject *luaT_gettm (Table *events, TMS event, TString *ename);
|
||||||
|
const TObject *luaT_gettmbyobj (lua_State *L, const TObject *o, TMS event);
|
||||||
void luaT_init (lua_State *L);
|
void luaT_init (lua_State *L);
|
||||||
int luaT_newtag (lua_State *L, const l_char *name, int basictype);
|
|
||||||
const l_char *luaT_typename (global_State *G, const TObject *o);
|
|
||||||
int luaT_tag (const TObject *o);
|
|
||||||
int luaT_validevent (int t, int e); /* used by compatibility module */
|
|
||||||
|
|
||||||
|
extern const char *const luaT_typenames[];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
563
lua.c
563
lua.c
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lua.c,v 1.67 2001/06/06 18:00:19 roberto Exp roberto $
|
** $Id: lua.c,v 1.121 2003/03/24 12:40:01 roberto Exp roberto $
|
||||||
** Lua stand-alone interpreter
|
** Lua stand-alone interpreter
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -10,326 +10,429 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lua_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "luadebug.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lualib.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef _POSIX_SOURCE
|
/*
|
||||||
|
** generic extra include file
|
||||||
|
*/
|
||||||
|
#ifdef LUA_USERCONFIG
|
||||||
|
#include LUA_USERCONFIG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** definition of `isatty'
|
||||||
|
*/
|
||||||
|
#ifdef _POSIX_C_SOURCE
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#define stdin_is_tty() isatty(0)
|
||||||
#else
|
#else
|
||||||
static int isatty (int x) { return x==0; } /* assume stdin is a tty */
|
#define stdin_is_tty() 1 /* assume stdin is a tty */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef PROMPT
|
#ifndef PROMPT
|
||||||
#define PROMPT l_s("> ")
|
#define PROMPT "> "
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef LUA_USERINIT
|
#ifndef PROMPT2
|
||||||
#define LUA_USERINIT(L) openstdlibs(L)
|
#define PROMPT2 ">> "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PROGNAME
|
||||||
|
#define PROGNAME "lua"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef lua_userinit
|
||||||
|
#define lua_userinit(L) openstdlibs(L)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LUA_EXTRALIBS
|
||||||
/*
|
#define LUA_EXTRALIBS /* empty */
|
||||||
** global options
|
#endif
|
||||||
*/
|
|
||||||
struct Options {
|
|
||||||
int toclose;
|
|
||||||
int stacksize;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static lua_State *L = NULL;
|
static lua_State *L = NULL;
|
||||||
|
|
||||||
|
static const char *progname = PROGNAME;
|
||||||
typedef void (*handler)(int); /* type for signal actions */
|
|
||||||
|
|
||||||
static void laction (int i);
|
|
||||||
|
|
||||||
|
|
||||||
static lua_Hook old_linehook = NULL;
|
|
||||||
static lua_Hook old_callhook = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static handler lreset (void) {
|
static const luaL_reg lualibs[] = {
|
||||||
return signal(SIGINT, laction);
|
{"base", luaopen_base},
|
||||||
}
|
{"table", luaopen_table},
|
||||||
|
{"io", luaopen_io},
|
||||||
|
{"string", luaopen_string},
|
||||||
|
{"math", luaopen_math},
|
||||||
|
{"debug", luaopen_debug},
|
||||||
|
{"loadlib", luaopen_loadlib},
|
||||||
|
/* add your libraries here */
|
||||||
|
LUA_EXTRALIBS
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void lstop (void) {
|
|
||||||
lua_setlinehook(L, old_linehook);
|
static void lstop (lua_State *l, lua_Debug *ar) {
|
||||||
lua_setcallhook(L, old_callhook);
|
(void)ar; /* unused arg. */
|
||||||
lreset();
|
lua_sethook(l, NULL, 0, 0);
|
||||||
lua_error(L, l_s("interrupted!"));
|
luaL_error(l, "interrupted!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void laction (int i) {
|
static void laction (int i) {
|
||||||
(void)i; /* to avoid warnings */
|
signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
|
||||||
signal(SIGINT, SIG_DFL); /* if another SIGINT happens before lstop,
|
|
||||||
terminate process (default action) */
|
terminate process (default action) */
|
||||||
old_linehook = lua_setlinehook(L, (lua_Hook)lstop);
|
lua_sethook(L, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
|
||||||
old_callhook = lua_setcallhook(L, (lua_Hook)lstop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ldo (int (*f)(lua_State *l, const l_char *), const l_char *name) {
|
static void print_usage (void) {
|
||||||
int res;
|
|
||||||
handler h = lreset();
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
res = f(L, name); /* dostring | dofile */
|
|
||||||
lua_settop(L, top); /* remove eventual results */
|
|
||||||
signal(SIGINT, h); /* restore old action */
|
|
||||||
/* Lua gives no message in such cases, so lua.c provides one */
|
|
||||||
if (res == LUA_ERRMEM) {
|
|
||||||
fprintf(stderr, l_s("lua: memory allocation error\n"));
|
|
||||||
}
|
|
||||||
else if (res == LUA_ERRERR)
|
|
||||||
fprintf(stderr, l_s("lua: error in error message\n"));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void print_message (void) {
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
l_s("usage: lua [options]. Available options are:\n")
|
"usage: %s [options] [script [args]].\n"
|
||||||
l_s(" - execute stdin as a file\n")
|
"Available options are:\n"
|
||||||
l_s(" -c close Lua when exiting\n")
|
" - execute stdin as a file\n"
|
||||||
l_s(" -e stat execute string `stat'\n")
|
" -e stat execute string `stat'\n"
|
||||||
l_s(" -f name execute file `name' with remaining arguments in table `arg'\n")
|
" -i enter interactive mode after executing `script'\n"
|
||||||
l_s(" -i enter interactive mode with prompt\n")
|
" -l name load and run library `name'\n"
|
||||||
l_s(" -q enter interactive mode without prompt\n")
|
" -v show version information\n"
|
||||||
l_s(" -sNUM set stack size to NUM (must be the first option)\n")
|
" -- stop handling options\n" ,
|
||||||
l_s(" -v print version information\n")
|
progname);
|
||||||
l_s(" a=b set global `a' to string `b'\n")
|
}
|
||||||
l_s(" name execute file `name'\n")
|
|
||||||
);
|
|
||||||
|
static void l_message (const char *pname, const char *msg) {
|
||||||
|
if (pname) fprintf(stderr, "%s: ", pname);
|
||||||
|
fprintf(stderr, "%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int report (int status) {
|
||||||
|
const char *msg;
|
||||||
|
if (status) {
|
||||||
|
msg = lua_tostring(L, -1);
|
||||||
|
if (msg == NULL) msg = "(error with no message)";
|
||||||
|
l_message(progname, msg);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int lcall (int narg, int clear) {
|
||||||
|
int status;
|
||||||
|
int base = lua_gettop(L) - narg; /* function index */
|
||||||
|
lua_pushliteral(L, "_TRACEBACK");
|
||||||
|
lua_rawget(L, LUA_GLOBALSINDEX); /* get traceback function */
|
||||||
|
lua_insert(L, base); /* put it under chunk and args */
|
||||||
|
signal(SIGINT, laction);
|
||||||
|
status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
|
||||||
|
signal(SIGINT, SIG_DFL);
|
||||||
|
lua_remove(L, base); /* remove traceback function */
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void print_version (void) {
|
static void print_version (void) {
|
||||||
printf(l_s("%.80s %.80s\n"), l_s(LUA_VERSION), l_s(LUA_COPYRIGHT));
|
l_message(NULL, LUA_VERSION " " LUA_COPYRIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void assign (l_char *arg) {
|
static void getargs (char *argv[], int n) {
|
||||||
l_char *eq = strchr(arg, l_c('='));
|
|
||||||
*eq = l_c('\0'); /* spilt `arg' in two strings (name & value) */
|
|
||||||
lua_pushstring(L, eq+1);
|
|
||||||
lua_setglobal(L, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void getargs (l_char *argv[]) {
|
|
||||||
int i;
|
int i;
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
for (i=0; argv[i]; i++) {
|
for (i=0; argv[i]; i++) {
|
||||||
/* arg[i] = argv[i] */
|
lua_pushnumber(L, i - n);
|
||||||
lua_pushnumber(L, i);
|
|
||||||
lua_pushstring(L, argv[i]);
|
lua_pushstring(L, argv[i]);
|
||||||
lua_settable(L, -3);
|
lua_rawset(L, -3);
|
||||||
}
|
}
|
||||||
/* arg.n = maximum index in table `arg' */
|
/* arg.n = maximum index in table `arg' */
|
||||||
lua_pushliteral(L, l_s("n"));
|
lua_pushliteral(L, "n");
|
||||||
lua_pushnumber(L, i-1);
|
lua_pushnumber(L, i-n-1);
|
||||||
lua_settable(L, -3);
|
lua_rawset(L, -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int l_getargs (lua_State *l) {
|
static int docall (int status) {
|
||||||
l_char **argv = (l_char **)lua_touserdata(l, -1);
|
if (status == 0) status = lcall(0, 1);
|
||||||
getargs(argv);
|
return report(status);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int file_input (const l_char *argv) {
|
static int file_input (const char *name) {
|
||||||
int result = ldo(lua_dofile, argv);
|
return docall(luaL_loadfile(L, name));
|
||||||
if (result) {
|
}
|
||||||
if (result == LUA_ERRFILE) {
|
|
||||||
fprintf(stderr, l_s("lua: cannot execute file "));
|
|
||||||
perror(argv);
|
static int dostring (const char *s, const char *name) {
|
||||||
}
|
return docall(luaL_loadbuffer(L, s, strlen(s), name));
|
||||||
return EXIT_FAILURE;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int load_file (const char *name) {
|
||||||
|
lua_pushliteral(L, "require");
|
||||||
|
lua_rawget(L, LUA_GLOBALSINDEX);
|
||||||
|
if (!lua_isfunction(L, -1)) { /* no `require' defined? */
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return file_input(name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushstring(L, name);
|
||||||
|
return report(lcall(1, 1));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** this macro can be used by some `history' system to save lines
|
||||||
|
** read in manual input
|
||||||
|
*/
|
||||||
|
#ifndef lua_saveline
|
||||||
|
#define lua_saveline(L,line) /* empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** this macro defines a function to show the prompt and reads the
|
||||||
|
** next line for manual input
|
||||||
|
*/
|
||||||
|
#ifndef lua_readline
|
||||||
|
#define lua_readline(L,prompt) readline(L,prompt)
|
||||||
|
|
||||||
/* maximum length of an input line */
|
/* maximum length of an input line */
|
||||||
#ifndef MAXINPUT
|
#ifndef MAXINPUT
|
||||||
#define MAXINPUT 512
|
#define MAXINPUT 512
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const l_char *get_prompt (int prompt) {
|
static int readline (lua_State *l, const char *prompt) {
|
||||||
if (!prompt)
|
static char buffer[MAXINPUT];
|
||||||
return l_s("");
|
if (prompt) {
|
||||||
|
fputs(prompt, stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
if (fgets(buffer, sizeof(buffer), stdin) == NULL)
|
||||||
|
return 0; /* read fails */
|
||||||
else {
|
else {
|
||||||
const l_char *s;
|
lua_pushstring(l, buffer);
|
||||||
lua_getglobal(L, l_s("_PROMPT"));
|
return 1;
|
||||||
s = lua_tostring(L, -1);
|
|
||||||
if (!s) s = PROMPT;
|
|
||||||
lua_pop(L, 1); /* remove global */
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void manual_input (int version, int prompt) {
|
|
||||||
if (version) print_version();
|
static const char *get_prompt (int firstline) {
|
||||||
for (;;) {
|
const char *p = NULL;
|
||||||
fputs(get_prompt(prompt), stdout); /* show prompt */
|
lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2");
|
||||||
for(;;) {
|
lua_rawget(L, LUA_GLOBALSINDEX);
|
||||||
l_char buffer[MAXINPUT];
|
p = lua_tostring(L, -1);
|
||||||
size_t l;
|
if (p == NULL) p = (firstline ? PROMPT : PROMPT2);
|
||||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
|
lua_pop(L, 1); /* remove global */
|
||||||
printf(l_s("\n"));
|
return p;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
l = strlen(buffer);
|
|
||||||
if (buffer[l-1] == l_c('\n') && buffer[l-2] == l_c('\\')) {
|
static int incomplete (int status) {
|
||||||
buffer[l-2] = l_c('\n');
|
if (status == LUA_ERRSYNTAX &&
|
||||||
lua_pushlstring(L, buffer, l-1);
|
strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
|
||||||
}
|
lua_pop(L, 1);
|
||||||
else {
|
return 1;
|
||||||
lua_pushlstring(L, buffer, l);
|
}
|
||||||
break;
|
else
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int load_string (void) {
|
||||||
|
int status;
|
||||||
|
lua_settop(L, 0);
|
||||||
|
if (lua_readline(L, get_prompt(1)) == 0) /* no input? */
|
||||||
|
return -1;
|
||||||
|
if (lua_tostring(L, -1)[0] == '=') { /* line starts with `=' ? */
|
||||||
|
lua_pushfstring(L, "return %s", lua_tostring(L, -1)+1);/* `=' -> `return' */
|
||||||
|
lua_remove(L, -2); /* remove original line */
|
||||||
|
}
|
||||||
|
for (;;) { /* repeat until gets a complete line */
|
||||||
|
status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
|
||||||
|
if (!incomplete(status)) break; /* cannot try to add lines? */
|
||||||
|
if (lua_readline(L, get_prompt(0)) == 0) /* no more input? */
|
||||||
|
return -1;
|
||||||
|
lua_concat(L, lua_gettop(L)); /* join lines */
|
||||||
|
}
|
||||||
|
lua_saveline(L, lua_tostring(L, 1));
|
||||||
|
lua_remove(L, 1); /* remove line */
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void manual_input (void) {
|
||||||
|
int status;
|
||||||
|
const char *oldprogname = progname;
|
||||||
|
progname = NULL;
|
||||||
|
while ((status = load_string()) != -1) {
|
||||||
|
if (status == 0) status = lcall(0, 0);
|
||||||
|
report(status);
|
||||||
|
if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
|
||||||
|
lua_getglobal(L, "print");
|
||||||
|
lua_insert(L, 1);
|
||||||
|
if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
|
||||||
|
l_message(progname, lua_pushfstring(L, "error calling `print' (%s)",
|
||||||
|
lua_tostring(L, -1)));
|
||||||
}
|
}
|
||||||
lua_concat(L, lua_gettop(L));
|
|
||||||
ldo(lua_dostring, lua_tostring(L, -1));
|
|
||||||
lua_settop(L, 0); /* remove eventual results */
|
|
||||||
}
|
}
|
||||||
|
lua_settop(L, 0); /* clear stack */
|
||||||
|
fputs("\n", stdout);
|
||||||
|
progname = oldprogname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int handle_argv (l_char *argv[], struct Options *opt) {
|
static int handle_argv (char *argv[], int *interactive) {
|
||||||
if (opt->stacksize > 0) argv++; /* skip option `-s' (if present) */
|
if (argv[1] == NULL) { /* no more arguments? */
|
||||||
if (*argv == NULL) { /* no more arguments? */
|
if (stdin_is_tty()) {
|
||||||
if (isatty(0)) {
|
print_version();
|
||||||
manual_input(1, 1);
|
manual_input();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ldo(lua_dofile, NULL); /* executes stdin as a file */
|
file_input(NULL); /* executes stdin as a file */
|
||||||
}
|
}
|
||||||
else { /* other arguments; loop over them */
|
else { /* other arguments; loop over them */
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; argv[i] != NULL; i++) {
|
for (i = 1; argv[i] != NULL; i++) {
|
||||||
if (argv[i][0] != l_c('-')) { /* not an option? */
|
if (argv[i][0] != '-') break; /* not an option? */
|
||||||
if (strchr(argv[i], l_c('=')))
|
switch (argv[i][1]) { /* option */
|
||||||
assign(argv[i]);
|
case '-': { /* `--' */
|
||||||
else
|
if (argv[i][2] != '\0') {
|
||||||
if (file_input(argv[i]) != EXIT_SUCCESS)
|
print_usage();
|
||||||
return EXIT_FAILURE; /* stop if file fails */
|
return 1;
|
||||||
|
}
|
||||||
|
i++; /* skip this argument */
|
||||||
|
goto endloop; /* stop handling arguments */
|
||||||
}
|
}
|
||||||
else switch (argv[i][1]) { /* option */
|
case '\0': {
|
||||||
case 0: {
|
file_input(NULL); /* executes stdin as a file */
|
||||||
ldo(lua_dofile, NULL); /* executes stdin as a file */
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
case l_c('i'): {
|
|
||||||
manual_input(0, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case l_c('q'): {
|
|
||||||
manual_input(0, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case l_c('c'): {
|
|
||||||
opt->toclose = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case l_c('v'): {
|
|
||||||
print_version();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case l_c('e'): {
|
|
||||||
i++;
|
|
||||||
if (argv[i] == NULL) {
|
|
||||||
print_message();
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
if (ldo(lua_dostring, argv[i]) != 0) {
|
|
||||||
fprintf(stderr, l_s("lua: error running argument `%.99s'\n"), argv[i]);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case l_c('f'): {
|
|
||||||
i++;
|
|
||||||
if (argv[i] == NULL) {
|
|
||||||
print_message();
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
getargs(argv+i); /* collect remaining arguments */
|
|
||||||
lua_setglobal(L, l_s("arg"));
|
|
||||||
return file_input(argv[i]); /* stop scanning arguments */
|
|
||||||
}
|
|
||||||
case l_c('s'): {
|
|
||||||
fprintf(stderr, l_s("lua: stack size (`-s') must be the first option\n"));
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
print_message();
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
case 'i': {
|
||||||
|
*interactive = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'v': {
|
||||||
|
print_version();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'e': {
|
||||||
|
const char *chunk = argv[i] + 2;
|
||||||
|
if (*chunk == '\0') chunk = argv[++i];
|
||||||
|
if (chunk == NULL) {
|
||||||
|
print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (dostring(chunk, "=<command line>") != 0)
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'l': {
|
||||||
|
const char *filename = argv[i] + 2;
|
||||||
|
if (*filename == '\0') filename = argv[++i];
|
||||||
|
if (filename == NULL) {
|
||||||
|
print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (load_file(filename))
|
||||||
|
return 1; /* stop if file fails */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c': {
|
||||||
|
l_message(progname, "option `-c' is deprecated");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
l_message(progname, "option `-s' is deprecated");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} endloop:
|
||||||
|
if (argv[i] != NULL) {
|
||||||
|
const char *filename = argv[i];
|
||||||
|
getargs(argv, i); /* collect arguments */
|
||||||
|
lua_setglobal(L, "arg");
|
||||||
|
return file_input(filename); /* stop scanning arguments */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void getstacksize (int argc, l_char *argv[], struct Options *opt) {
|
|
||||||
if (argc >= 2 && argv[1][0] == l_c('-') && argv[1][1] == l_c('s')) {
|
|
||||||
int stacksize = strtol(&argv[1][2], NULL, 10);
|
|
||||||
if (stacksize <= 0) {
|
|
||||||
fprintf(stderr, l_s("lua: invalid stack size ('%.20s')\n"), &argv[1][2]);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
opt->stacksize = stacksize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
opt->stacksize = 0; /* no stack size */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void register_getargs (l_char *argv[]) {
|
|
||||||
lua_newuserdatabox(L, argv);
|
|
||||||
lua_pushcclosure(L, l_getargs, 1);
|
|
||||||
lua_setglobal(L, l_s("getargs"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void openstdlibs (lua_State *l) {
|
static void openstdlibs (lua_State *l) {
|
||||||
lua_baselibopen(l);
|
const luaL_reg *lib = lualibs;
|
||||||
lua_iolibopen(l);
|
for (; lib->func; lib++) {
|
||||||
lua_strlibopen(l);
|
lib->func(l); /* open library */
|
||||||
lua_mathlibopen(l);
|
lua_settop(l, 0); /* discard any results */
|
||||||
lua_dblibopen(l);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, l_char *argv[]) {
|
static int handle_luainit (void) {
|
||||||
struct Options opt;
|
const char *init = getenv("LUA_INIT");
|
||||||
|
if (init == NULL) return 0; /* status OK */
|
||||||
|
else if (init[0] == '@')
|
||||||
|
return file_input(init+1);
|
||||||
|
else
|
||||||
|
return dostring(init, "=LUA_INIT");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Smain {
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
int status;
|
int status;
|
||||||
opt.toclose = 0;
|
};
|
||||||
getstacksize(argc, argv, &opt); /* handle option `-s' */
|
|
||||||
L = lua_open(opt.stacksize); /* create state */
|
|
||||||
LUA_USERINIT(L); /* open libraries */
|
static int pmain (lua_State *l) {
|
||||||
register_getargs(argv); /* create `getargs' function */
|
struct Smain *s = (struct Smain *)lua_touserdata(l, 1);
|
||||||
status = handle_argv(argv+1, &opt);
|
int status;
|
||||||
if (opt.toclose)
|
int interactive = 0;
|
||||||
lua_close(L);
|
if (s->argv[0] && s->argv[0][0]) progname = s->argv[0];
|
||||||
return status;
|
L = l;
|
||||||
|
lua_userinit(l); /* open libraries */
|
||||||
|
status = handle_luainit();
|
||||||
|
if (status == 0) {
|
||||||
|
status = handle_argv(s->argv, &interactive);
|
||||||
|
if (status == 0 && interactive) manual_input();
|
||||||
|
}
|
||||||
|
s->status = status;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
int status;
|
||||||
|
struct Smain s;
|
||||||
|
lua_State *l = lua_open(); /* create state */
|
||||||
|
if (l == NULL) {
|
||||||
|
l_message(argv[0], "cannot create state: not enough memory");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
s.argc = argc;
|
||||||
|
s.argv = argv;
|
||||||
|
status = lua_cpcall(l, &pmain, &s);
|
||||||
|
report(status);
|
||||||
|
lua_close(l);
|
||||||
|
return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
414
lua.h
414
lua.h
@@ -1,9 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lua.h,v 1.101 2001/07/12 18:11:58 roberto Exp roberto $
|
** $Id: lua.h,v 1.174 2003/02/27 11:52:30 roberto Exp roberto $
|
||||||
** Lua - An Extensible Extension Language
|
** Lua - An Extensible Extension Language
|
||||||
** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil
|
** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
|
||||||
** e-mail: info@lua.org
|
** http://www.lua.org mailto:info@lua.org
|
||||||
** www: http://www.lua.org
|
|
||||||
** See Copyright Notice at the end of this file
|
** See Copyright Notice at the end of this file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -11,41 +10,35 @@
|
|||||||
#ifndef lua_h
|
#ifndef lua_h
|
||||||
#define lua_h
|
#define lua_h
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
/* definition of `size_t' */
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define LUA_VERSION "Lua 5.0"
|
||||||
#define LUA_VERSION "Lua 4.1 (alpha)"
|
#define LUA_COPYRIGHT "Copyright (C) 1994-2003 Tecgraf, PUC-Rio"
|
||||||
#define LUA_COPYRIGHT "Copyright (C) 1994-2001 TeCGraf, PUC-Rio"
|
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
|
||||||
#define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo"
|
|
||||||
|
|
||||||
|
|
||||||
/* name of global variable with error handler */
|
|
||||||
#define LUA_ERRORMESSAGE "_ERRORMESSAGE"
|
|
||||||
|
|
||||||
|
/* option for multiple returns in `lua_pcall' and `lua_call' */
|
||||||
/* pre-defined references */
|
|
||||||
#define LUA_NOREF (-2)
|
|
||||||
#define LUA_REFNIL (-1)
|
|
||||||
|
|
||||||
|
|
||||||
/* option for multiple returns in `lua_call' */
|
|
||||||
#define LUA_MULTRET (-1)
|
#define LUA_MULTRET (-1)
|
||||||
|
|
||||||
|
|
||||||
/* error codes for `lua_do*' and the like */
|
/*
|
||||||
|
** pseudo-indices
|
||||||
|
*/
|
||||||
|
#define LUA_REGISTRYINDEX (-10000)
|
||||||
|
#define LUA_GLOBALSINDEX (-10001)
|
||||||
|
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
|
||||||
|
|
||||||
|
|
||||||
|
/* error codes for `lua_load' and `lua_pcall' */
|
||||||
#define LUA_ERRRUN 1
|
#define LUA_ERRRUN 1
|
||||||
#define LUA_ERRFILE 2
|
#define LUA_ERRFILE 2
|
||||||
#define LUA_ERRSYNTAX 3
|
#define LUA_ERRSYNTAX 3
|
||||||
#define LUA_ERRMEM 4
|
#define LUA_ERRMEM 4
|
||||||
#define LUA_ERRERR 5
|
#define LUA_ERRERR 5
|
||||||
|
|
||||||
/* weak-table modes */
|
|
||||||
#define LUA_WEAK_KEY 1
|
|
||||||
#define LUA_WEAK_VALUE 2
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct lua_State lua_State;
|
typedef struct lua_State lua_State;
|
||||||
|
|
||||||
@@ -53,21 +46,28 @@ typedef int (*lua_CFunction) (lua_State *L);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** an invalid `tag'
|
** functions that read/write blocks when loading/dumping Lua chunks
|
||||||
*/
|
*/
|
||||||
#define LUA_NOTAG (-1)
|
typedef const char * (*lua_Chunkreader) (lua_State *L, void *ud, size_t *sz);
|
||||||
|
|
||||||
|
typedef int (*lua_Chunkwriter) (lua_State *L, const void* p,
|
||||||
|
size_t sz, void* ud);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** tags for basic types
|
** basic types
|
||||||
*/
|
*/
|
||||||
#define LUA_TNONE LUA_NOTAG
|
#define LUA_TNONE (-1)
|
||||||
|
|
||||||
#define LUA_TUSERDATA 0
|
#define LUA_TNIL 0
|
||||||
#define LUA_TNIL 1
|
#define LUA_TBOOLEAN 1
|
||||||
#define LUA_TNUMBER 2
|
#define LUA_TLIGHTUSERDATA 2
|
||||||
#define LUA_TSTRING 3
|
#define LUA_TNUMBER 3
|
||||||
#define LUA_TTABLE 4
|
#define LUA_TSTRING 4
|
||||||
#define LUA_TFUNCTION 5
|
#define LUA_TTABLE 5
|
||||||
|
#define LUA_TFUNCTION 6
|
||||||
|
#define LUA_TUSERDATA 7
|
||||||
|
#define LUA_TTHREAD 8
|
||||||
|
|
||||||
|
|
||||||
/* minimum Lua stack available to a C function */
|
/* minimum Lua stack available to a C function */
|
||||||
@@ -82,17 +82,12 @@ typedef int (*lua_CFunction) (lua_State *L);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Lua numerical type */
|
/* type of numbers in Lua */
|
||||||
#ifndef LUA_NUMBER
|
#ifndef LUA_NUMBER
|
||||||
#define LUA_NUMBER double
|
typedef double lua_Number;
|
||||||
#endif
|
#else
|
||||||
typedef LUA_NUMBER lua_Number;
|
typedef LUA_NUMBER lua_Number;
|
||||||
|
|
||||||
/* Lua character type */
|
|
||||||
#ifndef L_CHAR
|
|
||||||
#define L_CHAR char
|
|
||||||
#endif
|
#endif
|
||||||
typedef L_CHAR lua_char;
|
|
||||||
|
|
||||||
|
|
||||||
/* mark for all API functions */
|
/* mark for all API functions */
|
||||||
@@ -104,41 +99,50 @@ typedef L_CHAR lua_char;
|
|||||||
/*
|
/*
|
||||||
** state manipulation
|
** state manipulation
|
||||||
*/
|
*/
|
||||||
LUA_API lua_State *lua_newthread (lua_State *L, int stacksize);
|
LUA_API lua_State *lua_open (void);
|
||||||
LUA_API void lua_close (lua_State *L);
|
LUA_API void lua_close (lua_State *L);
|
||||||
|
LUA_API lua_State *lua_newthread (lua_State *L);
|
||||||
|
|
||||||
|
LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** basic stack manipulation
|
** basic stack manipulation
|
||||||
*/
|
*/
|
||||||
LUA_API int lua_gettop (lua_State *L);
|
LUA_API int lua_gettop (lua_State *L);
|
||||||
LUA_API void lua_settop (lua_State *L, int index);
|
LUA_API void lua_settop (lua_State *L, int idx);
|
||||||
LUA_API void lua_pushvalue (lua_State *L, int index);
|
LUA_API void lua_pushvalue (lua_State *L, int idx);
|
||||||
LUA_API void lua_remove (lua_State *L, int index);
|
LUA_API void lua_remove (lua_State *L, int idx);
|
||||||
LUA_API void lua_insert (lua_State *L, int index);
|
LUA_API void lua_insert (lua_State *L, int idx);
|
||||||
LUA_API int lua_stackspace (lua_State *L);
|
LUA_API void lua_replace (lua_State *L, int idx);
|
||||||
|
LUA_API int lua_checkstack (lua_State *L, int sz);
|
||||||
|
|
||||||
|
LUA_API void lua_xmove (lua_State *from, lua_State *to, int n);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** access functions (stack -> C)
|
** access functions (stack -> C)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LUA_API const lua_char *lua_type (lua_State *L, int index);
|
LUA_API int lua_isnumber (lua_State *L, int idx);
|
||||||
LUA_API int lua_isnumber (lua_State *L, int index);
|
LUA_API int lua_isstring (lua_State *L, int idx);
|
||||||
LUA_API int lua_isstring (lua_State *L, int index);
|
LUA_API int lua_iscfunction (lua_State *L, int idx);
|
||||||
LUA_API int lua_iscfunction (lua_State *L, int index);
|
LUA_API int lua_isuserdata (lua_State *L, int idx);
|
||||||
LUA_API int lua_tag (lua_State *L, int index);
|
LUA_API int lua_type (lua_State *L, int idx);
|
||||||
LUA_API int lua_rawtag (lua_State *L, int index);
|
LUA_API const char *lua_typename (lua_State *L, int tp);
|
||||||
|
|
||||||
LUA_API int lua_equal (lua_State *L, int index1, int index2);
|
LUA_API int lua_equal (lua_State *L, int idx1, int idx2);
|
||||||
LUA_API int lua_lessthan (lua_State *L, int index1, int index2);
|
LUA_API int lua_rawequal (lua_State *L, int idx1, int idx2);
|
||||||
|
LUA_API int lua_lessthan (lua_State *L, int idx1, int idx2);
|
||||||
|
|
||||||
LUA_API lua_Number lua_tonumber (lua_State *L, int index);
|
LUA_API lua_Number lua_tonumber (lua_State *L, int idx);
|
||||||
LUA_API const lua_char *lua_tostring (lua_State *L, int index);
|
LUA_API int lua_toboolean (lua_State *L, int idx);
|
||||||
LUA_API size_t lua_strlen (lua_State *L, int index);
|
LUA_API const char *lua_tostring (lua_State *L, int idx);
|
||||||
LUA_API lua_CFunction lua_tocfunction (lua_State *L, int index);
|
LUA_API size_t lua_strlen (lua_State *L, int idx);
|
||||||
LUA_API void *lua_touserdata (lua_State *L, int index);
|
LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx);
|
||||||
LUA_API const void *lua_topointer (lua_State *L, int index);
|
LUA_API void *lua_touserdata (lua_State *L, int idx);
|
||||||
|
LUA_API lua_State *lua_tothread (lua_State *L, int idx);
|
||||||
|
LUA_API const void *lua_topointer (lua_State *L, int idx);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -146,53 +150,58 @@ LUA_API const void *lua_topointer (lua_State *L, int index);
|
|||||||
*/
|
*/
|
||||||
LUA_API void lua_pushnil (lua_State *L);
|
LUA_API void lua_pushnil (lua_State *L);
|
||||||
LUA_API void lua_pushnumber (lua_State *L, lua_Number n);
|
LUA_API void lua_pushnumber (lua_State *L, lua_Number n);
|
||||||
LUA_API void lua_pushlstring (lua_State *L, const lua_char *s, size_t len);
|
LUA_API void lua_pushlstring (lua_State *L, const char *s, size_t l);
|
||||||
LUA_API void lua_pushstring (lua_State *L, const lua_char *s);
|
LUA_API void lua_pushstring (lua_State *L, const char *s);
|
||||||
|
LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
|
||||||
|
va_list argp);
|
||||||
|
LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
|
||||||
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
|
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
|
||||||
|
LUA_API void lua_pushboolean (lua_State *L, int b);
|
||||||
|
LUA_API void lua_pushlightuserdata (lua_State *L, void *p);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** get functions (Lua -> stack)
|
** get functions (Lua -> stack)
|
||||||
*/
|
*/
|
||||||
LUA_API void lua_getglobal (lua_State *L, const lua_char *name);
|
LUA_API void lua_gettable (lua_State *L, int idx);
|
||||||
LUA_API void lua_gettable (lua_State *L, int index);
|
LUA_API void lua_rawget (lua_State *L, int idx);
|
||||||
LUA_API void lua_rawget (lua_State *L, int index);
|
LUA_API void lua_rawgeti (lua_State *L, int idx, int n);
|
||||||
LUA_API void lua_rawgeti (lua_State *L, int index, int n);
|
|
||||||
LUA_API void lua_getglobals (lua_State *L);
|
|
||||||
LUA_API void lua_gettagmethod (lua_State *L, int tag, const lua_char *event);
|
|
||||||
LUA_API int lua_getref (lua_State *L, int ref);
|
|
||||||
LUA_API void lua_newtable (lua_State *L);
|
LUA_API void lua_newtable (lua_State *L);
|
||||||
LUA_API void lua_getregistry (lua_State *L);
|
LUA_API void *lua_newuserdata (lua_State *L, size_t sz);
|
||||||
LUA_API void lua_getweakregistry (lua_State *L);
|
LUA_API int lua_getmetatable (lua_State *L, int objindex);
|
||||||
|
LUA_API void lua_getfenv (lua_State *L, int idx);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** set functions (stack -> Lua)
|
** set functions (stack -> Lua)
|
||||||
*/
|
*/
|
||||||
LUA_API void lua_setglobal (lua_State *L, const lua_char *name);
|
LUA_API void lua_settable (lua_State *L, int idx);
|
||||||
LUA_API void lua_settable (lua_State *L, int index);
|
LUA_API void lua_rawset (lua_State *L, int idx);
|
||||||
LUA_API void lua_rawset (lua_State *L, int index);
|
LUA_API void lua_rawseti (lua_State *L, int idx, int n);
|
||||||
LUA_API void lua_rawseti (lua_State *L, int index, int n);
|
LUA_API int lua_setmetatable (lua_State *L, int objindex);
|
||||||
LUA_API void lua_setglobals (lua_State *L);
|
LUA_API int lua_setfenv (lua_State *L, int idx);
|
||||||
LUA_API void lua_settagmethod (lua_State *L, int tag, const lua_char *event);
|
|
||||||
LUA_API int lua_ref (lua_State *L, int lock);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** `load' and `do' functions (load and run Lua code)
|
** `load' and `call' functions (load and run Lua code)
|
||||||
*/
|
*/
|
||||||
LUA_API int lua_call (lua_State *L, int nargs, int nresults);
|
LUA_API void lua_call (lua_State *L, int nargs, int nresults);
|
||||||
LUA_API void lua_rawcall (lua_State *L, int nargs, int nresults);
|
LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
|
||||||
LUA_API int lua_loadfile (lua_State *L, const lua_char *filename);
|
LUA_API int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);
|
||||||
LUA_API int lua_dofile (lua_State *L, const lua_char *filename);
|
LUA_API int lua_load (lua_State *L, lua_Chunkreader reader, void *dt,
|
||||||
LUA_API int lua_dostring (lua_State *L, const lua_char *str);
|
const char *chunkname);
|
||||||
LUA_API int lua_loadbuffer (lua_State *L, const lua_char *buff, size_t size,
|
|
||||||
const lua_char *name);
|
LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data);
|
||||||
LUA_API int lua_dobuffer (lua_State *L, const lua_char *buff, size_t size,
|
|
||||||
const lua_char *name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Garbage-collection functions
|
** coroutine functions
|
||||||
|
*/
|
||||||
|
LUA_API int lua_yield (lua_State *L, int nresults);
|
||||||
|
LUA_API int lua_resume (lua_State *L, int narg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** garbage-collection functions
|
||||||
*/
|
*/
|
||||||
LUA_API int lua_getgcthreshold (lua_State *L);
|
LUA_API int lua_getgcthreshold (lua_State *L);
|
||||||
LUA_API int lua_getgccount (lua_State *L);
|
LUA_API int lua_getgccount (lua_State *L);
|
||||||
@@ -201,28 +210,15 @@ LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold);
|
|||||||
/*
|
/*
|
||||||
** miscellaneous functions
|
** miscellaneous functions
|
||||||
*/
|
*/
|
||||||
LUA_API int lua_newtype (lua_State *L, const lua_char *name, int basictype);
|
|
||||||
LUA_API int lua_copytagmethods (lua_State *L, int tagto, int tagfrom);
|
|
||||||
LUA_API void lua_settag (lua_State *L, int tag);
|
|
||||||
|
|
||||||
LUA_API int lua_name2tag (lua_State *L, const lua_char *name);
|
LUA_API const char *lua_version (void);
|
||||||
LUA_API const lua_char *lua_tag2name (lua_State *L, int tag);
|
|
||||||
|
|
||||||
LUA_API void lua_error (lua_State *L, const lua_char *s);
|
LUA_API int lua_error (lua_State *L);
|
||||||
|
|
||||||
LUA_API void lua_unref (lua_State *L, int ref);
|
LUA_API int lua_next (lua_State *L, int idx);
|
||||||
|
|
||||||
LUA_API int lua_next (lua_State *L, int index);
|
|
||||||
LUA_API int lua_getn (lua_State *L, int index);
|
|
||||||
|
|
||||||
LUA_API void lua_concat (lua_State *L, int n);
|
LUA_API void lua_concat (lua_State *L, int n);
|
||||||
|
|
||||||
LUA_API void *lua_newuserdata (lua_State *L, size_t size);
|
|
||||||
LUA_API void lua_newuserdatabox (lua_State *L, void *u);
|
|
||||||
|
|
||||||
LUA_API void lua_setweakmode (lua_State *L, int mode);
|
|
||||||
LUA_API int lua_getweakmode (lua_State *L, int index);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -231,119 +227,165 @@ LUA_API int lua_getweakmode (lua_State *L, int index);
|
|||||||
** ===============================================================
|
** ===============================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define lua_open(n) lua_newthread(NULL, (n))
|
#define lua_boxpointer(L,u) \
|
||||||
|
(*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
|
||||||
|
|
||||||
|
#define lua_unboxpointer(L,i) (*(void **)(lua_touserdata(L, i)))
|
||||||
|
|
||||||
#define lua_pop(L,n) lua_settop(L, -(n)-1)
|
#define lua_pop(L,n) lua_settop(L, -(n)-1)
|
||||||
|
|
||||||
#define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n))
|
#define lua_register(L,n,f) \
|
||||||
|
(lua_pushstring(L, n), \
|
||||||
|
lua_pushcfunction(L, f), \
|
||||||
|
lua_settable(L, LUA_GLOBALSINDEX))
|
||||||
|
|
||||||
#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0)
|
#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0)
|
||||||
#define lua_clonetag(L,t) lua_copytagmethods(L, lua_newtag(L), (t))
|
|
||||||
|
|
||||||
#define lua_isfunction(L,n) (lua_rawtag(L,n) == LUA_TFUNCTION)
|
#define lua_isfunction(L,n) (lua_type(L,n) == LUA_TFUNCTION)
|
||||||
#define lua_istable(L,n) (lua_rawtag(L,n) == LUA_TTABLE)
|
#define lua_istable(L,n) (lua_type(L,n) == LUA_TTABLE)
|
||||||
#define lua_isuserdata(L,n) (lua_rawtag(L,n) == LUA_TUSERDATA)
|
#define lua_islightuserdata(L,n) (lua_type(L,n) == LUA_TLIGHTUSERDATA)
|
||||||
#define lua_isnil(L,n) (lua_rawtag(L,n) == LUA_TNIL)
|
#define lua_isnil(L,n) (lua_type(L,n) == LUA_TNIL)
|
||||||
#define lua_isnull(L,n) (lua_rawtag(L,n) == LUA_TNONE)
|
#define lua_isboolean(L,n) (lua_type(L,n) == LUA_TBOOLEAN)
|
||||||
|
#define lua_isnone(L,n) (lua_type(L,n) == LUA_TNONE)
|
||||||
|
#define lua_isnoneornil(L, n) (lua_type(L,n) <= 0)
|
||||||
|
|
||||||
#define lua_pushliteral(L, s) lua_pushlstring(L, s, \
|
#define lua_pushliteral(L, s) \
|
||||||
(sizeof(s)/sizeof(lua_char))-1)
|
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** compatibility macros
|
** compatibility macros and functions
|
||||||
*/
|
*/
|
||||||
#define lua_newtag(L) lua_newtype(L, NULL, LUA_TNONE)
|
|
||||||
#define lua_typename lua_tag2name
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
LUA_API int lua_pushupvalues (lua_State *L);
|
||||||
|
|
||||||
|
#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
|
||||||
|
#define lua_setglobal(L,s) \
|
||||||
|
(lua_pushstring(L, s), lua_insert(L, -2), lua_settable(L, LUA_GLOBALSINDEX))
|
||||||
|
|
||||||
|
#define lua_getglobal(L,s) \
|
||||||
|
(lua_pushstring(L, s), lua_gettable(L, LUA_GLOBALSINDEX))
|
||||||
|
|
||||||
|
|
||||||
|
/* compatibility with ref system */
|
||||||
|
|
||||||
|
/* pre-defined references */
|
||||||
|
#define LUA_NOREF (-2)
|
||||||
|
#define LUA_REFNIL (-1)
|
||||||
|
|
||||||
|
#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \
|
||||||
|
(lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0))
|
||||||
|
|
||||||
|
#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref))
|
||||||
|
|
||||||
|
#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, ref)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {======================================================================
|
** {======================================================================
|
||||||
** useful definitions for Lua kernel and libraries
|
** useful definitions for Lua kernel and libraries
|
||||||
|
** =======================================================================
|
||||||
*/
|
*/
|
||||||
#ifdef LUA_PRIVATE
|
|
||||||
|
|
||||||
#define l_char lua_char
|
/* formats for Lua numbers */
|
||||||
|
|
||||||
/* macro to control type of literal strings */
|
|
||||||
#ifndef l_s
|
|
||||||
#define l_s(x) x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* macro to control type of literal chars */
|
|
||||||
#ifndef l_c
|
|
||||||
#define l_c(x) x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* macro to `unsign' a character */
|
|
||||||
#ifndef uchar
|
|
||||||
#define uchar(c) ((unsigned char)(c))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* integer type to hold the result of fgetc */
|
|
||||||
#ifndef l_charint
|
|
||||||
#define l_charint int
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
** formats for Lua numbers
|
|
||||||
*/
|
|
||||||
#ifndef LUA_NUMBER_SCAN
|
#ifndef LUA_NUMBER_SCAN
|
||||||
#define LUA_NUMBER_SCAN "%lf"
|
#define LUA_NUMBER_SCAN "%lf"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LUA_NUMBER_FMT
|
#ifndef LUA_NUMBER_FMT
|
||||||
#define LUA_NUMBER_FMT "%.16g"
|
#define LUA_NUMBER_FMT "%.14g"
|
||||||
#endif
|
|
||||||
/* function to convert a lua_Number to a string */
|
|
||||||
#ifndef lua_number2str
|
|
||||||
#define lua_number2str(s,n) sprintf((s), l_s(LUA_NUMBER_FMT), (n))
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* function to convert a string to a lua_Number */
|
|
||||||
#ifndef lua_str2number
|
|
||||||
#define lua_str2number(s,p) strtod((s), (p))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** {======================================================================
|
||||||
|
** Debug API
|
||||||
|
** =======================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Event codes
|
||||||
|
*/
|
||||||
|
#define LUA_HOOKCALL 0
|
||||||
|
#define LUA_HOOKRET 1
|
||||||
|
#define LUA_HOOKLINE 2
|
||||||
|
#define LUA_HOOKCOUNT 3
|
||||||
|
#define LUA_HOOKTAILRET 4
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Event masks
|
||||||
|
*/
|
||||||
|
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
|
||||||
|
#define LUA_MASKRET (1 << LUA_HOOKRET)
|
||||||
|
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||||
|
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||||
|
|
||||||
|
typedef struct lua_Debug lua_Debug; /* activation record */
|
||||||
|
|
||||||
|
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
||||||
|
|
||||||
|
|
||||||
|
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
|
||||||
|
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
|
||||||
|
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
|
||||||
|
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
|
||||||
|
LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
|
||||||
|
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
|
||||||
|
|
||||||
|
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
|
||||||
|
LUA_API lua_Hook lua_gethook (lua_State *L);
|
||||||
|
LUA_API int lua_gethookmask (lua_State *L);
|
||||||
|
LUA_API int lua_gethookcount (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
|
#define LUA_IDSIZE 60
|
||||||
|
|
||||||
|
struct lua_Debug {
|
||||||
|
int event;
|
||||||
|
const char *name; /* (n) */
|
||||||
|
const char *namewhat; /* (n) `global', `local', `field', `method' */
|
||||||
|
const char *what; /* (S) `Lua', `C', `main', `tail' */
|
||||||
|
const char *source; /* (S) */
|
||||||
|
int currentline; /* (l) */
|
||||||
|
int nups; /* (u) number of upvalues */
|
||||||
|
int linedefined; /* (S) */
|
||||||
|
char short_src[LUA_IDSIZE]; /* (S) */
|
||||||
|
/* private part */
|
||||||
|
int i_ci; /* active function */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (C) 1994-2001 TeCGraf, PUC-Rio. All rights reserved.
|
* Copyright (C) 1994-2003 Tecgraf, PUC-Rio. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, without written agreement and without license
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* or royalty fees, to use, copy, modify, and distribute this software and its
|
* a copy of this software and associated documentation files (the
|
||||||
* documentation for any purpose, including commercial applications, subject to
|
* "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 following conditions:
|
||||||
*
|
*
|
||||||
* - The above copyright notice and this permission notice shall appear in all
|
* The above copyright notice and this permission notice shall be
|
||||||
* copies or substantial portions of this software.
|
* included in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* - The origin of this software must not be misrepresented; you must not
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* claim that you wrote the original software. If you use this software in a
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* product, an acknowledgment in the product documentation would be greatly
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* appreciated (but it is not required).
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
*
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
* - Altered source versions must be plainly marked as such, and must not be
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
* misrepresented as being the original software.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*
|
|
||||||
* The authors specifically disclaim any warranties, including, but not limited
|
|
||||||
* to, the implied warranties of merchantability and fitness for a particular
|
|
||||||
* purpose. The software provided hereunder is on an "as is" basis, and the
|
|
||||||
* authors have no obligation to provide maintenance, support, updates,
|
|
||||||
* enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the
|
|
||||||
* authors be held liable to any party for direct, indirect, special,
|
|
||||||
* incidental, or consequential damages arising out of the use of this software
|
|
||||||
* and its documentation.
|
|
||||||
*
|
|
||||||
* The Lua language and this implementation have been entirely designed and
|
|
||||||
* written by Waldemar Celes Filho, Roberto Ierusalimschy and
|
|
||||||
* Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio.
|
|
||||||
*
|
|
||||||
* This implementation contains no third-party code.
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
46
luadebug.h
46
luadebug.h
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
** $Id: luadebug.h,v 1.19 2001/03/07 18:09:25 roberto Exp roberto $
|
|
||||||
** Debugging API
|
|
||||||
** See Copyright Notice in lua.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef luadebug_h
|
|
||||||
#define luadebug_h
|
|
||||||
|
|
||||||
|
|
||||||
#include "lua.h"
|
|
||||||
|
|
||||||
typedef struct lua_Debug lua_Debug; /* activation record */
|
|
||||||
typedef struct lua_Localvar lua_Localvar;
|
|
||||||
|
|
||||||
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
|
||||||
|
|
||||||
|
|
||||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
|
|
||||||
LUA_API int lua_getinfo (lua_State *L, const lua_char *what, lua_Debug *ar);
|
|
||||||
LUA_API const lua_char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
|
|
||||||
LUA_API const lua_char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
|
|
||||||
|
|
||||||
LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
|
|
||||||
LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
|
|
||||||
|
|
||||||
|
|
||||||
#define LUA_IDSIZE 60
|
|
||||||
|
|
||||||
struct lua_Debug {
|
|
||||||
const lua_char *event; /* `call', `return' */
|
|
||||||
int currentline; /* (l) */
|
|
||||||
const lua_char *name; /* (n) */
|
|
||||||
const lua_char *namewhat; /* (n) `global', `tag method', `local', `field' */
|
|
||||||
int nups; /* (u) number of upvalues */
|
|
||||||
int linedefined; /* (S) */
|
|
||||||
const lua_char *what; /* (S) `Lua' function, `C' function, Lua `main' */
|
|
||||||
const lua_char *source; /* (S) */
|
|
||||||
lua_char short_src[LUA_IDSIZE]; /* (S) */
|
|
||||||
/* private part */
|
|
||||||
struct CallInfo *_ci; /* active function */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
44
lualib.h
44
lualib.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lualib.h,v 1.20 2001/03/06 20:09:38 roberto Exp roberto $
|
** $Id: lualib.h,v 1.27 2003/03/17 13:04:58 roberto Exp roberto $
|
||||||
** Lua standard libraries
|
** Lua standard libraries
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -12,17 +12,45 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef LUALIB_API
|
#ifndef LUALIB_API
|
||||||
#define LUALIB_API extern
|
#define LUALIB_API LUA_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define LUA_ALERT "_ALERT"
|
#define LUA_COLIBNAME "coroutine"
|
||||||
|
LUALIB_API int luaopen_base (lua_State *L);
|
||||||
|
|
||||||
LUALIB_API int lua_baselibopen (lua_State *L);
|
#define LUA_TABLIBNAME "table"
|
||||||
LUALIB_API int lua_iolibopen (lua_State *L);
|
LUALIB_API int luaopen_table (lua_State *L);
|
||||||
LUALIB_API int lua_strlibopen (lua_State *L);
|
|
||||||
LUALIB_API int lua_mathlibopen (lua_State *L);
|
|
||||||
LUALIB_API int lua_dblibopen (lua_State *L);
|
|
||||||
|
|
||||||
|
#define LUA_IOLIBNAME "io"
|
||||||
|
#define LUA_OSLIBNAME "os"
|
||||||
|
LUALIB_API int luaopen_io (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_STRLIBNAME "string"
|
||||||
|
LUALIB_API int luaopen_string (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_MATHLIBNAME "math"
|
||||||
|
LUALIB_API int luaopen_math (lua_State *L);
|
||||||
|
|
||||||
|
#define LUA_DBLIBNAME "debug"
|
||||||
|
LUALIB_API int luaopen_debug (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
|
LUALIB_API int luaopen_loadlib (lua_State *L);
|
||||||
|
|
||||||
|
|
||||||
|
/* to help testing the libraries */
|
||||||
|
#ifndef lua_assert
|
||||||
|
#define lua_assert(c) /* empty */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* compatibility code */
|
||||||
|
#define lua_baselibopen luaopen_base
|
||||||
|
#define lua_tablibopen luaopen_table
|
||||||
|
#define lua_iolibopen luaopen_io
|
||||||
|
#define lua_strlibopen luaopen_string
|
||||||
|
#define lua_mathlibopen luaopen_math
|
||||||
|
#define lua_dblibopen luaopen_debug
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
278
lundump.c
278
lundump.c
@@ -1,13 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lundump.c,v 1.36 2001/07/19 14:34:06 lhf Exp lhf $
|
** $Id: lundump.c,v 1.49 2003/04/07 20:34:20 lhf Exp $
|
||||||
** load pre-compiled Lua chunks
|
** load pre-compiled Lua chunks
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#define lundump_c
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
#include "ldebug.h"
|
#include "ldebug.h"
|
||||||
@@ -16,242 +14,266 @@
|
|||||||
#include "lopcodes.h"
|
#include "lopcodes.h"
|
||||||
#include "lstring.h"
|
#include "lstring.h"
|
||||||
#include "lundump.h"
|
#include "lundump.h"
|
||||||
|
#include "lzio.h"
|
||||||
|
|
||||||
#define LoadByte ezgetc
|
#define LoadByte (lu_byte) ezgetc
|
||||||
#define LoadShort (short) LoadInt
|
|
||||||
|
|
||||||
static const l_char* ZNAME (ZIO* Z)
|
typedef struct {
|
||||||
|
lua_State* L;
|
||||||
|
ZIO* Z;
|
||||||
|
Mbuffer* b;
|
||||||
|
int swap;
|
||||||
|
const char* name;
|
||||||
|
} LoadState;
|
||||||
|
|
||||||
|
static void unexpectedEOZ (LoadState* S)
|
||||||
{
|
{
|
||||||
const l_char* s=zname(Z);
|
luaG_runerror(S->L,"unexpected end of file in %s",S->name);
|
||||||
return (*s==l_c('@')) ? s+1 : s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unexpectedEOZ (lua_State* L, ZIO* Z)
|
static int ezgetc (LoadState* S)
|
||||||
{
|
{
|
||||||
luaO_verror(L,l_s("unexpected end of file in `%.99s'"),ZNAME(Z));
|
int c=zgetc(S->Z);
|
||||||
}
|
if (c==EOZ) unexpectedEOZ(S);
|
||||||
|
|
||||||
static int ezgetc (lua_State* L, ZIO* Z)
|
|
||||||
{
|
|
||||||
int c=zgetc(Z);
|
|
||||||
if (c==EOZ) unexpectedEOZ(L,Z);
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ezread (lua_State* L, ZIO* Z, void* b, int n)
|
static void ezread (LoadState* S, void* b, int n)
|
||||||
{
|
{
|
||||||
int r=zread(Z,b,n);
|
int r=luaZ_read(S->Z,b,n);
|
||||||
if (r!=0) unexpectedEOZ(L,Z);
|
if (r!=0) unexpectedEOZ(S);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadBlock (lua_State* L, void* b, size_t size, ZIO* Z, int swap)
|
static void LoadBlock (LoadState* S, void* b, size_t size)
|
||||||
{
|
{
|
||||||
if (swap)
|
if (S->swap)
|
||||||
{
|
{
|
||||||
l_char *p=(l_char*) b+size-1;
|
char* p=(char*) b+size-1;
|
||||||
int n=size;
|
int n=size;
|
||||||
while (n--) *p--=(l_char)ezgetc(L,Z);
|
while (n--) *p--=(char)ezgetc(S);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ezread(L,Z,b,size);
|
ezread(S,b,size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadVector (lua_State* L, void* b, int m, size_t size, ZIO* Z, int swap)
|
static void LoadVector (LoadState* S, void* b, int m, size_t size)
|
||||||
{
|
{
|
||||||
if (swap)
|
if (S->swap)
|
||||||
{
|
{
|
||||||
l_char *q=(l_char*) b;
|
char* q=(char*) b;
|
||||||
while (m--)
|
while (m--)
|
||||||
{
|
{
|
||||||
l_char *p=q+size-1;
|
char* p=q+size-1;
|
||||||
int n=size;
|
int n=size;
|
||||||
while (n--) *p--=(l_char)ezgetc(L,Z);
|
while (n--) *p--=(char)ezgetc(S);
|
||||||
q+=size;
|
q+=size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ezread(L,Z,b,m*size);
|
ezread(S,b,m*size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int LoadInt (lua_State* L, ZIO* Z, int swap)
|
static int LoadInt (LoadState* S)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
LoadBlock(L,&x,sizeof(x),Z,swap);
|
LoadBlock(S,&x,sizeof(x));
|
||||||
|
if (x<0) luaG_runerror(S->L,"bad integer in %s",S->name);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t LoadSize (lua_State* L, ZIO* Z, int swap)
|
static size_t LoadSize (LoadState* S)
|
||||||
{
|
{
|
||||||
size_t x;
|
size_t x;
|
||||||
LoadBlock(L,&x,sizeof(x),Z,swap);
|
LoadBlock(S,&x,sizeof(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static lua_Number LoadNumber (lua_State* L, ZIO* Z, int swap)
|
static lua_Number LoadNumber (LoadState* S)
|
||||||
{
|
{
|
||||||
lua_Number x;
|
lua_Number x;
|
||||||
LoadBlock(L,&x,sizeof(x),Z,swap);
|
LoadBlock(S,&x,sizeof(x));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TString* LoadString (lua_State* L, ZIO* Z, int swap)
|
static TString* LoadString (LoadState* S)
|
||||||
{
|
{
|
||||||
size_t size=LoadSize(L,Z,swap);
|
size_t size=LoadSize(S);
|
||||||
if (size==0)
|
if (size==0)
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
l_char* s=luaO_openspace(L,size,l_char);
|
char* s=luaZ_openspace(S->L,S->b,size);
|
||||||
LoadBlock(L,s,size,Z,0);
|
ezread(S,s,size);
|
||||||
return luaS_newlstr(L,s,size-1); /* remove trailing '\0' */
|
return luaS_newlstr(S->L,s,size-1); /* remove trailing '\0' */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadCode (lua_State* L, Proto* f, ZIO* Z, int swap)
|
static void LoadCode (LoadState* S, Proto* f)
|
||||||
{
|
{
|
||||||
int size=LoadInt(L,Z,swap);
|
int size=LoadInt(S);
|
||||||
f->code=luaM_newvector(L,size,Instruction);
|
f->code=luaM_newvector(S->L,size,Instruction);
|
||||||
f->sizecode=size;
|
f->sizecode=size;
|
||||||
LoadVector(L,f->code,size,sizeof(*f->code),Z,swap);
|
LoadVector(S,f->code,size,sizeof(*f->code));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadLocals (lua_State* L, Proto* f, ZIO* Z, int swap)
|
static void LoadLocals (LoadState* S, Proto* f)
|
||||||
{
|
{
|
||||||
int i,n;
|
int i,n;
|
||||||
n=LoadInt(L,Z,swap);
|
n=LoadInt(S);
|
||||||
f->locvars=luaM_newvector(L,n,LocVar);
|
f->locvars=luaM_newvector(S->L,n,LocVar);
|
||||||
f->sizelocvars=n;
|
f->sizelocvars=n;
|
||||||
for (i=0; i<n; i++)
|
for (i=0; i<n; i++)
|
||||||
{
|
{
|
||||||
f->locvars[i].varname=LoadString(L,Z,swap);
|
f->locvars[i].varname=LoadString(S);
|
||||||
f->locvars[i].startpc=LoadInt(L,Z,swap);
|
f->locvars[i].startpc=LoadInt(S);
|
||||||
f->locvars[i].endpc=LoadInt(L,Z,swap);
|
f->locvars[i].endpc=LoadInt(S);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadLines (lua_State* L, Proto* f, ZIO* Z, int swap)
|
static void LoadLines (LoadState* S, Proto* f)
|
||||||
{
|
{
|
||||||
int n;
|
int size=LoadInt(S);
|
||||||
n=LoadInt(L,Z,swap);
|
f->lineinfo=luaM_newvector(S->L,size,int);
|
||||||
f->lineinfo=luaM_newvector(L,n,int);
|
f->sizelineinfo=size;
|
||||||
f->sizelineinfo=n;
|
LoadVector(S,f->lineinfo,size,sizeof(*f->lineinfo));
|
||||||
LoadVector(L,f->lineinfo,n,sizeof(*f->lineinfo),Z,swap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Proto* LoadFunction (lua_State* L, TString* p, ZIO* Z, int swap);
|
static void LoadUpvalues (LoadState* S, Proto* f)
|
||||||
|
|
||||||
static void LoadConstants (lua_State* L, Proto* f, ZIO* Z, int swap)
|
|
||||||
{
|
{
|
||||||
int i,n;
|
int i,n;
|
||||||
n=LoadInt(L,Z,swap);
|
n=LoadInt(S);
|
||||||
f->k=luaM_newvector(L,n,TObject);
|
if (n!=0 && n!=f->nups)
|
||||||
|
luaG_runerror(S->L,"bad nupvalues in %s: read %d; expected %d",
|
||||||
|
S->name,n,f->nups);
|
||||||
|
f->upvalues=luaM_newvector(S->L,n,TString*);
|
||||||
|
f->sizeupvalues=n;
|
||||||
|
for (i=0; i<n; i++) f->upvalues[i]=LoadString(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Proto* LoadFunction (LoadState* S, TString* p);
|
||||||
|
|
||||||
|
static void LoadConstants (LoadState* S, Proto* f)
|
||||||
|
{
|
||||||
|
int i,n;
|
||||||
|
n=LoadInt(S);
|
||||||
|
f->k=luaM_newvector(S->L,n,TObject);
|
||||||
f->sizek=n;
|
f->sizek=n;
|
||||||
for (i=0; i<n; i++)
|
for (i=0; i<n; i++)
|
||||||
{
|
{
|
||||||
TObject* o=&f->k[i];
|
TObject* o=&f->k[i];
|
||||||
ttype(o)=LoadByte(L,Z);
|
int t=LoadByte(S);
|
||||||
switch (ttype(o))
|
switch (t)
|
||||||
{
|
{
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
nvalue(o)=LoadNumber(L,Z,swap);
|
setnvalue(o,LoadNumber(S));
|
||||||
break;
|
break;
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
tsvalue(o)=LoadString(L,Z,swap);
|
setsvalue2n(o,LoadString(S));
|
||||||
|
break;
|
||||||
|
case LUA_TNIL:
|
||||||
|
setnilvalue(o);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
luaO_verror(L,l_s("bad constant type (%d) in `%.99s'"),ttype(o),ZNAME(Z));
|
luaG_runerror(S->L,"bad constant type (%d) in %s",t,S->name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n=LoadInt(L,Z,swap);
|
n=LoadInt(S);
|
||||||
f->p=luaM_newvector(L,n,Proto*);
|
f->p=luaM_newvector(S->L,n,Proto*);
|
||||||
f->sizep=n;
|
f->sizep=n;
|
||||||
for (i=0; i<n; i++) f->p[i]=LoadFunction(L,f->source,Z,swap);
|
for (i=0; i<n; i++) f->p[i]=LoadFunction(S,f->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Proto* LoadFunction (lua_State* L, TString* p, ZIO* Z, int swap)
|
static Proto* LoadFunction (LoadState* S, TString* p)
|
||||||
{
|
{
|
||||||
Proto* f=luaF_newproto(L);
|
Proto* f=luaF_newproto(S->L);
|
||||||
f->source=LoadString(L,Z,swap); if (f->source==NULL) f->source=p;
|
f->source=LoadString(S); if (f->source==NULL) f->source=p;
|
||||||
f->lineDefined=LoadInt(L,Z,swap);
|
f->lineDefined=LoadInt(S);
|
||||||
f->nupvalues=LoadShort(L,Z,swap);
|
f->nups=LoadByte(S);
|
||||||
f->numparams=LoadShort(L,Z,swap);
|
f->numparams=LoadByte(S);
|
||||||
f->is_vararg=LoadShort(L,Z,swap);
|
f->is_vararg=LoadByte(S);
|
||||||
f->maxstacksize=LoadShort(L,Z,swap);
|
f->maxstacksize=LoadByte(S);
|
||||||
LoadLocals(L,f,Z,swap);
|
LoadLines(S,f);
|
||||||
LoadLines(L,f,Z,swap);
|
LoadLocals(S,f);
|
||||||
LoadConstants(L,f,Z,swap);
|
LoadUpvalues(S,f);
|
||||||
LoadCode(L,f,Z,swap);
|
LoadConstants(S,f);
|
||||||
|
LoadCode(S,f);
|
||||||
#ifndef TRUST_BINARIES
|
#ifndef TRUST_BINARIES
|
||||||
if (!luaG_checkcode(f)) luaO_verror(L,l_s("bad code in `%.99s'"),ZNAME(Z));
|
if (!luaG_checkcode(f)) luaG_runerror(S->L,"bad code in %s",S->name);
|
||||||
#endif
|
#endif
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadSignature (lua_State* L, ZIO* Z)
|
static void LoadSignature (LoadState* S)
|
||||||
{
|
{
|
||||||
const l_char* s=l_s(LUA_SIGNATURE);
|
const char* s=LUA_SIGNATURE;
|
||||||
while (*s!=0 && ezgetc(L,Z)==*s)
|
while (*s!=0 && ezgetc(S)==*s)
|
||||||
++s;
|
++s;
|
||||||
if (*s!=0) luaO_verror(L,l_s("bad signature in `%.99s'"),ZNAME(Z));
|
if (*s!=0) luaG_runerror(S->L,"bad signature in %s",S->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestSize (lua_State* L, int s, const l_char* what, ZIO* Z)
|
static void TestSize (LoadState* S, int s, const char* what)
|
||||||
{
|
{
|
||||||
int r=LoadByte(L,Z);
|
int r=LoadByte(S);
|
||||||
if (r!=s)
|
if (r!=s)
|
||||||
luaO_verror(L,l_s("virtual machine mismatch in `%.99s':\n")
|
luaG_runerror(S->L,"virtual machine mismatch in %s: "
|
||||||
l_s(" size of %.20s is %d but read %d"),ZNAME(Z),what,s,r);
|
"size of %s is %d but read %d",S->name,what,s,r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TESTSIZE(s,w) TestSize(L,s,w,Z)
|
#define TESTSIZE(s,w) TestSize(S,s,w)
|
||||||
#define V(v) v/16,v%16
|
#define V(v) v/16,v%16
|
||||||
|
|
||||||
static int LoadHeader (lua_State* L, ZIO* Z)
|
static void LoadHeader (LoadState* S)
|
||||||
{
|
{
|
||||||
int version,swap;
|
int version;
|
||||||
lua_Number x=0,tx=TEST_NUMBER;
|
lua_Number x,tx=TEST_NUMBER;
|
||||||
LoadSignature(L,Z);
|
LoadSignature(S);
|
||||||
version=LoadByte(L,Z);
|
version=LoadByte(S);
|
||||||
if (version>VERSION)
|
if (version>VERSION)
|
||||||
luaO_verror(L,l_s("`%.99s' too new:\n")
|
luaG_runerror(S->L,"%s too new: "
|
||||||
l_s(" read version %d.%d; expected at most %d.%d"),
|
"read version %d.%d; expected at most %d.%d",
|
||||||
ZNAME(Z),V(version),V(VERSION));
|
S->name,V(version),V(VERSION));
|
||||||
if (version<VERSION0) /* check last major change */
|
if (version<VERSION0) /* check last major change */
|
||||||
luaO_verror(L,l_s("`%.99s' too old:\n")
|
luaG_runerror(S->L,"%s too old: "
|
||||||
l_s(" read version %d.%d; expected at least %d.%d"),
|
"read version %d.%d; expected at least %d.%d",
|
||||||
ZNAME(Z),V(version),V(VERSION));
|
S->name,V(version),V(VERSION0));
|
||||||
swap=(luaU_endianness()!=LoadByte(L,Z)); /* need to swap bytes? */
|
S->swap=(luaU_endianness()!=LoadByte(S)); /* need to swap bytes? */
|
||||||
TESTSIZE(sizeof(int),l_s("int"));
|
TESTSIZE(sizeof(int),"int");
|
||||||
TESTSIZE(sizeof(size_t), l_s("size_t"));
|
TESTSIZE(sizeof(size_t), "size_t");
|
||||||
TESTSIZE(sizeof(Instruction), l_s("size_t"));
|
TESTSIZE(sizeof(Instruction), "Instruction");
|
||||||
TESTSIZE(SIZE_OP, l_s("OP"));
|
TESTSIZE(SIZE_OP, "OP");
|
||||||
TESTSIZE(SIZE_A, l_s("A"));
|
TESTSIZE(SIZE_A, "A");
|
||||||
TESTSIZE(SIZE_B, l_s("B"));
|
TESTSIZE(SIZE_B, "B");
|
||||||
TESTSIZE(SIZE_C, l_s("C"));
|
TESTSIZE(SIZE_C, "C");
|
||||||
TESTSIZE(sizeof(lua_Number), l_s("number"));
|
TESTSIZE(sizeof(lua_Number), "number");
|
||||||
x=LoadNumber(L,Z,swap);
|
x=LoadNumber(S);
|
||||||
if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */
|
if ((long)x!=(long)tx) /* disregard errors in last bits of fraction */
|
||||||
luaO_verror(L,l_s("unknown number format in `%.99s':\n")
|
luaG_runerror(S->L,"unknown number format in %s",S->name);
|
||||||
l_s(" read ") l_s(LUA_NUMBER_FMT) l_s("; expected ") l_s(LUA_NUMBER_FMT),
|
|
||||||
ZNAME(Z),x,tx);
|
|
||||||
return swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Proto* LoadChunk (lua_State* L, ZIO* Z)
|
static Proto* LoadChunk (LoadState* S)
|
||||||
{
|
{
|
||||||
return LoadFunction(L,NULL,Z,LoadHeader(L,Z));
|
LoadHeader(S);
|
||||||
|
return LoadFunction(S,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** load one chunk from a file or buffer
|
** load precompiled chunk
|
||||||
*/
|
*/
|
||||||
Proto* luaU_undump (lua_State* L, ZIO* Z)
|
Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff)
|
||||||
{
|
{
|
||||||
Proto* f=LoadChunk(L,Z);
|
LoadState S;
|
||||||
if (zgetc(Z)!=EOZ)
|
const char* s=zname(Z);
|
||||||
luaO_verror(L,l_s("`%.99s' apparently contains more than one chunk"),ZNAME(Z));
|
if (*s=='@' || *s=='=')
|
||||||
return f;
|
S.name=s+1;
|
||||||
|
else if (*s==LUA_SIGNATURE[0])
|
||||||
|
S.name="binary string";
|
||||||
|
else
|
||||||
|
S.name=s;
|
||||||
|
S.L=L;
|
||||||
|
S.Z=Z;
|
||||||
|
S.b=buff;
|
||||||
|
return LoadChunk(&S);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -260,5 +282,5 @@ Proto* luaU_undump (lua_State* L, ZIO* Z)
|
|||||||
int luaU_endianness (void)
|
int luaU_endianness (void)
|
||||||
{
|
{
|
||||||
int x=1;
|
int x=1;
|
||||||
return *(l_char*)&x;
|
return *(char*)&x;
|
||||||
}
|
}
|
||||||
|
|||||||
24
lundump.h
24
lundump.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lundump.h,v 1.23 2001/06/28 13:55:17 lhf Exp lhf $
|
** $Id: lundump.h,v 1.30 2003/04/07 20:34:20 lhf Exp $
|
||||||
** load pre-compiled Lua chunks
|
** load pre-compiled Lua chunks
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -10,19 +10,25 @@
|
|||||||
#include "lobject.h"
|
#include "lobject.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
|
|
||||||
/* load one chunk */
|
/* load one chunk; from lundump.c */
|
||||||
Proto* luaU_undump (lua_State* L, ZIO* Z);
|
Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff);
|
||||||
|
|
||||||
/* find byte order */
|
/* find byte order; from lundump.c */
|
||||||
int luaU_endianness (void);
|
int luaU_endianness (void);
|
||||||
|
|
||||||
|
/* dump one chunk; from ldump.c */
|
||||||
|
void luaU_dump (lua_State* L, const Proto* Main, lua_Chunkwriter w, void* data);
|
||||||
|
|
||||||
|
/* print one chunk; from print.c */
|
||||||
|
void luaU_print (const Proto* Main);
|
||||||
|
|
||||||
/* definitions for headers of binary files */
|
/* definitions for headers of binary files */
|
||||||
#define VERSION 0x41 /* last format change was in 4.1 */
|
#define LUA_SIGNATURE "\033Lua" /* binary files start with "<esc>Lua" */
|
||||||
#define VERSION0 0x41 /* last major change was in 4.1 */
|
#define VERSION 0x50 /* last format change was in 5.0 */
|
||||||
#define LUA_SIGNATURE "\033Lua" /* binary files start with <esc>Lua */
|
#define VERSION0 0x50 /* last major change was in 5.0 */
|
||||||
|
|
||||||
/* a multiple of PI for testing native format */
|
/* a multiple of PI for testing native format */
|
||||||
/* multiplying by 1E8 gives non-trivial integer values */
|
/* multiplying by 1E7 gives non-trivial integer values */
|
||||||
#define TEST_NUMBER 3.14159265358979323846E8
|
#define TEST_NUMBER ((lua_Number)3.14159265358979323846E7)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
28
lvm.h
28
lvm.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lvm.h,v 1.29 2001/02/07 18:13:49 roberto Exp roberto $
|
** $Id: lvm.h,v 1.46 2002/08/07 19:22:39 roberto Exp roberto $
|
||||||
** Lua virtual machine
|
** Lua virtual machine
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -13,19 +13,23 @@
|
|||||||
#include "ltm.h"
|
#include "ltm.h"
|
||||||
|
|
||||||
|
|
||||||
#define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0))
|
#define tostring(L,o) ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o)))
|
||||||
|
|
||||||
|
#define tonumber(o,n) (ttype(o) == LUA_TNUMBER || \
|
||||||
|
(((o) = luaV_tonumber(o,n)) != NULL))
|
||||||
|
|
||||||
|
#define equalobj(L,o1,o2) \
|
||||||
|
(ttype(o1) == ttype(o2) && luaV_equalval(L, o1, o2))
|
||||||
|
|
||||||
|
|
||||||
const TObject *luaV_tonumber (const TObject *obj, TObject *n);
|
|
||||||
int luaV_tostring (lua_State *L, TObject *obj);
|
|
||||||
void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
|
|
||||||
void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val);
|
|
||||||
void luaV_getglobal (lua_State *L, TString *s, StkId res);
|
|
||||||
void luaV_setglobal (lua_State *L, TString *s, StkId val);
|
|
||||||
StkId luaV_execute (lua_State *L, const Closure *cl, StkId base);
|
|
||||||
void luaV_Cclosure (lua_State *L, lua_CFunction c, int nelems);
|
|
||||||
void luaV_Lclosure (lua_State *L, Proto *l, int nelems);
|
|
||||||
int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r);
|
int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r);
|
||||||
void luaV_strconc (lua_State *L, int total, StkId top);
|
int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2);
|
||||||
|
const TObject *luaV_tonumber (const TObject *obj, TObject *n);
|
||||||
|
int luaV_tostring (lua_State *L, StkId obj);
|
||||||
|
const TObject *luaV_gettable (lua_State *L, const TObject *t, TObject *key,
|
||||||
|
int loop);
|
||||||
|
void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val);
|
||||||
|
StkId luaV_execute (lua_State *L);
|
||||||
|
void luaV_concat (lua_State *L, int total, int last);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
89
lzio.c
89
lzio.c
@@ -1,76 +1,57 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lzio.c,v 1.13 2000/06/12 13:52:05 roberto Exp roberto $
|
** $Id: lzio.c,v 1.23 2002/12/04 17:38:31 roberto Exp roberto $
|
||||||
** a generic input stream interface
|
** a generic input stream interface
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define LUA_PRIVATE
|
#define lzio_c
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
#include "llimits.h"
|
||||||
|
#include "lmem.h"
|
||||||
#include "lzio.h"
|
#include "lzio.h"
|
||||||
|
|
||||||
|
|
||||||
|
int luaZ_fill (ZIO *z) {
|
||||||
/* ----------------------------------------------------- memory buffers --- */
|
size_t size;
|
||||||
|
const char *buff = z->reader(NULL, z->data, &size);
|
||||||
static int zmfilbuf (ZIO* z) {
|
if (buff == NULL || size == 0) return EOZ;
|
||||||
(void)z; /* to avoid warnings */
|
z->n = size - 1;
|
||||||
return EOZ;
|
z->p = buff;
|
||||||
|
return char2int(*(z->p++));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name) {
|
int luaZ_lookahead (ZIO *z) {
|
||||||
if (b==NULL) return NULL;
|
if (z->n == 0) {
|
||||||
z->n = size;
|
int c = luaZ_fill(z);
|
||||||
z->p = (const unsigned char *)b;
|
if (c == EOZ) return c;
|
||||||
z->filbuf = zmfilbuf;
|
z->n++;
|
||||||
z->u = NULL;
|
z->p--;
|
||||||
|
}
|
||||||
|
return char2int(*z->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name) {
|
||||||
|
z->reader = reader;
|
||||||
|
z->data = data;
|
||||||
z->name = name;
|
z->name = name;
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ strings --- */
|
|
||||||
|
|
||||||
ZIO* zsopen (ZIO* z, const char* s, const char *name) {
|
|
||||||
if (s==NULL) return NULL;
|
|
||||||
return zmopen(z, s, strlen(s), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- FILEs --- */
|
|
||||||
|
|
||||||
static int zffilbuf (ZIO* z) {
|
|
||||||
size_t n;
|
|
||||||
if (feof((FILE *)z->u)) return EOZ;
|
|
||||||
n = fread(z->buffer, 1, ZBSIZE, (FILE *)z->u);
|
|
||||||
if (n==0) return EOZ;
|
|
||||||
z->n = n-1;
|
|
||||||
z->p = z->buffer;
|
|
||||||
return *(z->p++);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ZIO* zFopen (ZIO* z, FILE* f, const char *name) {
|
|
||||||
if (f==NULL) return NULL;
|
|
||||||
z->n = 0;
|
z->n = 0;
|
||||||
z->p = z->buffer;
|
z->p = NULL;
|
||||||
z->filbuf = zffilbuf;
|
|
||||||
z->u = f;
|
|
||||||
z->name = name;
|
|
||||||
return z;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------- read --- */
|
/* --------------------------------------------------------------- read --- */
|
||||||
size_t zread (ZIO *z, void *b, size_t n) {
|
size_t luaZ_read (ZIO *z, void *b, size_t n) {
|
||||||
while (n) {
|
while (n) {
|
||||||
size_t m;
|
size_t m;
|
||||||
if (z->n == 0) {
|
if (z->n == 0) {
|
||||||
if (z->filbuf(z) == EOZ)
|
if (luaZ_fill(z) == EOZ)
|
||||||
return n; /* return number of missing bytes */
|
return n; /* return number of missing bytes */
|
||||||
else {
|
else {
|
||||||
++z->n; /* filbuf removed first byte; put back it */
|
++z->n; /* filbuf removed first byte; put back it */
|
||||||
@@ -86,3 +67,15 @@ size_t zread (ZIO *z, void *b, size_t n) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
|
||||||
|
if (n > buff->buffsize) {
|
||||||
|
if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
|
||||||
|
luaM_reallocvector(L, buff->buffer, buff->buffsize, n, char);
|
||||||
|
buff->buffsize = n;
|
||||||
|
}
|
||||||
|
return buff->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
62
lzio.h
62
lzio.h
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
** $Id: lzio.h,v 1.7 2000/10/20 16:36:32 roberto Exp roberto $
|
** $Id: lzio.h,v 1.14 2002/10/08 18:46:08 roberto Exp roberto $
|
||||||
** Buffered streams
|
** Buffered streams
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@@ -8,45 +8,57 @@
|
|||||||
#ifndef lzio_h
|
#ifndef lzio_h
|
||||||
#define lzio_h
|
#define lzio_h
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* For Lua only */
|
|
||||||
#define zFopen luaZ_Fopen
|
|
||||||
#define zsopen luaZ_sopen
|
|
||||||
#define zmopen luaZ_mopen
|
|
||||||
#define zread luaZ_read
|
|
||||||
|
|
||||||
#define EOZ (-1) /* end of stream */
|
#define EOZ (-1) /* end of stream */
|
||||||
|
|
||||||
typedef struct zio ZIO;
|
typedef struct Zio ZIO;
|
||||||
|
|
||||||
ZIO* zFopen (ZIO* z, FILE* f, const char *name); /* open FILEs */
|
|
||||||
ZIO* zsopen (ZIO* z, const char* s, const char *name); /* string */
|
|
||||||
ZIO* zmopen (ZIO* z, const char* b, size_t size, const char *name); /* memory */
|
|
||||||
|
|
||||||
size_t zread (ZIO* z, void* b, size_t n); /* read next n bytes */
|
#define char2int(c) cast(int, cast(unsigned char, (c)))
|
||||||
|
|
||||||
|
#define zgetc(z) (((z)->n--)>0 ? char2int(*(z)->p++) : luaZ_fill(z))
|
||||||
|
|
||||||
#define zgetc(z) (((z)->n--)>0 ? ((int)*(z)->p++): (z)->filbuf(z))
|
|
||||||
#define zname(z) ((z)->name)
|
#define zname(z) ((z)->name)
|
||||||
|
|
||||||
|
void luaZ_init (ZIO *z, lua_Chunkreader reader, void *data, const char *name);
|
||||||
|
size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */
|
||||||
|
int luaZ_lookahead (ZIO *z);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Mbuffer {
|
||||||
|
char *buffer;
|
||||||
|
size_t buffsize;
|
||||||
|
} Mbuffer;
|
||||||
|
|
||||||
|
|
||||||
|
char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
|
||||||
|
|
||||||
|
#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
|
||||||
|
|
||||||
|
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
|
||||||
|
#define luaZ_buffer(buff) ((buff)->buffer)
|
||||||
|
|
||||||
|
#define luaZ_resizebuffer(L, buff, size) \
|
||||||
|
(luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
|
||||||
|
(buff)->buffsize = size)
|
||||||
|
|
||||||
|
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
|
||||||
|
|
||||||
|
|
||||||
/* --------- Private Part ------------------ */
|
/* --------- Private Part ------------------ */
|
||||||
|
|
||||||
#ifndef ZBSIZE
|
struct Zio {
|
||||||
#define ZBSIZE 256 /* buffer size */
|
size_t n; /* bytes still unread */
|
||||||
#endif
|
const char *p; /* current position in buffer */
|
||||||
|
lua_Chunkreader reader;
|
||||||
struct zio {
|
void* data; /* additional data */
|
||||||
size_t n; /* bytes still unread */
|
|
||||||
const unsigned char* p; /* current position in buffer */
|
|
||||||
int (*filbuf)(ZIO* z);
|
|
||||||
void* u; /* additional data */
|
|
||||||
const char *name;
|
const char *name;
|
||||||
unsigned char buffer[ZBSIZE]; /* buffer */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int luaZ_fill (ZIO *z);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
128
makefile
128
makefile
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
## $Id: makefile,v 1.31 2001/07/24 17:25:30 roberto Exp roberto $
|
## $Id: makefile,v 1.40 2003/03/19 21:27:30 roberto Exp roberto $
|
||||||
## Makefile
|
## Makefile
|
||||||
## See Copyright Notice in lua.h
|
## See Copyright Notice in lua.h
|
||||||
#
|
#
|
||||||
@@ -7,39 +7,31 @@
|
|||||||
|
|
||||||
#CONFIGURATION
|
#CONFIGURATION
|
||||||
|
|
||||||
# define (undefine) POPEN if your system (does not) support piped I/O
|
# -DEXTERNMEMCHECK -DHARDSTACKTESTS
|
||||||
#
|
# DEBUG = -g -DLUA_USER_H='"ltests.h"'
|
||||||
# define (undefine) _POSIX_SOURCE if your system is (not) POSIX compliant
|
OPTIMIZE = -O2 \
|
||||||
#
|
-D'lua_number2int(i,d)=__asm__("fldl %1\nfistpl %0":"=m"(i):"m"(d))' \
|
||||||
# define (undefine) OLD_ANSI if your system does NOT have some new ANSI
|
# -fomit-frame-pointer
|
||||||
# facilities (e.g. strerror, locale.h, memmove). SunOS does not comply;
|
|
||||||
# so, add "-DOLD_ANSI" on SunOS
|
|
||||||
#
|
|
||||||
# define LUA_NUM_TYPE if you need numbers to be different from double
|
|
||||||
# (for instance, -DLUA_NUM_TYPE=float)
|
|
||||||
# you may need to adapat the code, too.
|
|
||||||
#
|
|
||||||
|
|
||||||
#EXTRA_H=-DLUA_USER_H='"ltests.h"'
|
|
||||||
|
|
||||||
CONFIG = -DPOPEN -D_POSIX_SOURCE $(EXTRA_H)
|
CONFIG = $(DEBUG) $(OPTIMIZE) -DLUA_COMPATUPSYNTAX -DUSE_TMPNAME -DUSE_DLOPEN
|
||||||
#CONFIG = -DOLD_ANSI
|
|
||||||
|
|
||||||
|
|
||||||
# Compilation parameters
|
# Compilation parameters
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CWARNS = -Wall -W -pedantic \
|
CWARNS = -Wall -pedantic \
|
||||||
-Waggregate-return \
|
-Waggregate-return \
|
||||||
-Wcast-align \
|
-Wcast-align \
|
||||||
-Wmissing-prototypes \
|
-Wmissing-prototypes \
|
||||||
|
-Wstrict-prototypes \
|
||||||
-Wnested-externs \
|
-Wnested-externs \
|
||||||
-Wpointer-arith \
|
-Wpointer-arith \
|
||||||
-Wshadow \
|
-Wshadow \
|
||||||
-Wwrite-strings \
|
-Wwrite-strings \
|
||||||
|
# -Wtraditional \
|
||||||
# -Wcast-qual
|
# -Wcast-qual
|
||||||
# -Wtraditional
|
|
||||||
|
|
||||||
CFLAGS = $(CONFIG) $(CWARNS) -ansi -O3 -fomit-frame-pointer
|
CFLAGS = $(CONFIG) $(CWARNS) # -ansi
|
||||||
|
|
||||||
|
|
||||||
# To make early versions
|
# To make early versions
|
||||||
@@ -68,6 +60,7 @@ LUAOBJS = \
|
|||||||
llex.o \
|
llex.o \
|
||||||
lopcodes.o \
|
lopcodes.o \
|
||||||
lundump.o \
|
lundump.o \
|
||||||
|
ldump.o \
|
||||||
lzio.o \
|
lzio.o \
|
||||||
ldebug.o \
|
ldebug.o \
|
||||||
ltests.o
|
ltests.o
|
||||||
@@ -75,14 +68,16 @@ LUAOBJS = \
|
|||||||
LIBOBJS = \
|
LIBOBJS = \
|
||||||
lauxlib.o \
|
lauxlib.o \
|
||||||
lbaselib.o \
|
lbaselib.o \
|
||||||
liolib.o \
|
ltablib.o \
|
||||||
lmathlib.o \
|
lmathlib.o \
|
||||||
|
liolib.o \
|
||||||
lstrlib.o \
|
lstrlib.o \
|
||||||
ldblib.o
|
ldblib.o \
|
||||||
|
loadlib.o
|
||||||
|
|
||||||
|
|
||||||
lua : lua.o liblua.a liblualib.a
|
lua : lua.o liblua.a liblualib.a
|
||||||
$(CC) $(CFLAGS) -o $@ lua.o -L. -llua -llualib -lm
|
$(CC) $(CFLAGS) -o $@ lua.o -Wl,-E -L. -llua -llualib -lm -ldl
|
||||||
|
|
||||||
liblua.a : $(LUAOBJS)
|
liblua.a : $(LUAOBJS)
|
||||||
$(AR) $(ARFLAGS) $@ $?
|
$(AR) $(ARFLAGS) $@ $?
|
||||||
@@ -108,51 +103,54 @@ clear :
|
|||||||
co $(CO_OPTIONS) $@
|
co $(CO_OPTIONS) $@
|
||||||
|
|
||||||
|
|
||||||
lapi.o: lapi.c lua.h lapi.h lobject.h llimits.h ldo.h lstate.h \
|
lapi.o: lapi.c lua.h lapi.h lobject.h llimits.h ldebug.h lstate.h ltm.h \
|
||||||
luadebug.h lfunc.h lgc.h lmem.h lstring.h ltable.h ltm.h lvm.h
|
lzio.h ldo.h lfunc.h lgc.h lmem.h lstring.h ltable.h lundump.h lvm.h
|
||||||
lauxlib.o: lauxlib.c lua.h lauxlib.h luadebug.h lualib.h
|
lauxlib.o: lauxlib.c lua.h lauxlib.h
|
||||||
lbaselib.o: lbaselib.c lua.h lauxlib.h luadebug.h lualib.h
|
lbaselib.o: lbaselib.c lua.h lauxlib.h lualib.h
|
||||||
lcode.o: lcode.c lua.h lcode.h llex.h lobject.h llimits.h lzio.h \
|
lcode.o: lcode.c lua.h lcode.h llex.h lobject.h llimits.h lzio.h \
|
||||||
lopcodes.h lparser.h ldebug.h lstate.h luadebug.h ldo.h lmem.h
|
lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h ldo.h lmem.h
|
||||||
ldblib.o: ldblib.c lua.h lauxlib.h luadebug.h lualib.h
|
ldblib.o: ldblib.c lua.h lauxlib.h lualib.h
|
||||||
ldebug.o: ldebug.c lua.h lapi.h lobject.h llimits.h lcode.h llex.h \
|
ldebug.o: ldebug.c lua.h lapi.h lobject.h llimits.h lcode.h llex.h lzio.h \
|
||||||
lzio.h lopcodes.h lparser.h ldebug.h lstate.h luadebug.h ldo.h \
|
lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h ldo.h lfunc.h \
|
||||||
lfunc.h lstring.h ltable.h ltm.h lvm.h
|
lstring.h lvm.h
|
||||||
ldo.o: ldo.c lua.h ldebug.h lstate.h lobject.h llimits.h luadebug.h \
|
ldo.o: ldo.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h lzio.h \
|
||||||
ldo.h lgc.h lmem.h lparser.h lzio.h lstring.h ltable.h ltm.h \
|
ldo.h lfunc.h lgc.h lmem.h lopcodes.h lparser.h ltable.h lstring.h \
|
||||||
lundump.h lvm.h
|
lundump.h lvm.h
|
||||||
lfunc.o: lfunc.c lua.h lfunc.h lobject.h llimits.h lmem.h lstate.h \
|
ldump.o: ldump.c lua.h lobject.h llimits.h lopcodes.h lstate.h ltm.h \
|
||||||
luadebug.h
|
lzio.h lundump.h
|
||||||
lgc.o: lgc.c lua.h ldo.h lobject.h llimits.h lstate.h luadebug.h \
|
lfunc.o: lfunc.c lua.h lfunc.h lobject.h llimits.h lgc.h lmem.h lstate.h \
|
||||||
lfunc.h lgc.h lmem.h lstring.h ltable.h ltm.h
|
ltm.h lzio.h
|
||||||
liolib.o: liolib.c lua.h lauxlib.h luadebug.h lualib.h
|
lgc.o: lgc.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h lzio.h \
|
||||||
llex.o: llex.c lua.h llex.h lobject.h llimits.h lzio.h lparser.h \
|
ldo.h lfunc.h lgc.h lmem.h lstring.h ltable.h
|
||||||
lstate.h luadebug.h lstring.h
|
liolib.o: liolib.c lua.h lauxlib.h lualib.h
|
||||||
|
llex.o: llex.c lua.h ldo.h lobject.h llimits.h lstate.h ltm.h lzio.h \
|
||||||
|
llex.h lparser.h ltable.h lstring.h
|
||||||
lmathlib.o: lmathlib.c lua.h lauxlib.h lualib.h
|
lmathlib.o: lmathlib.c lua.h lauxlib.h lualib.h
|
||||||
lmem.o: lmem.c lua.h ldo.h lobject.h llimits.h lstate.h luadebug.h \
|
lmem.o: lmem.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h lzio.h \
|
||||||
lmem.h
|
ldo.h lmem.h
|
||||||
lobject.o: lobject.c lua.h ldo.h lobject.h llimits.h lstate.h \
|
lobject.o: lobject.c lua.h ldo.h lobject.h llimits.h lstate.h ltm.h \
|
||||||
luadebug.h lmem.h
|
lzio.h lmem.h lstring.h lvm.h
|
||||||
lopcodes.o: lopcodes.c lua.h lopcodes.h llimits.h
|
loadlib.o: loadlib.c lua.h lauxlib.h lualib.h
|
||||||
|
lopcodes.o: lopcodes.c lua.h lobject.h llimits.h lopcodes.h
|
||||||
lparser.o: lparser.c lua.h lcode.h llex.h lobject.h llimits.h lzio.h \
|
lparser.o: lparser.c lua.h lcode.h llex.h lobject.h llimits.h lzio.h \
|
||||||
lopcodes.h lparser.h ldebug.h lstate.h luadebug.h lfunc.h lmem.h \
|
lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h lfunc.h lmem.h \
|
||||||
lstring.h
|
lstring.h
|
||||||
lstate.o: lstate.c lua.h ldo.h lobject.h llimits.h lstate.h luadebug.h \
|
lstate.o: lstate.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
|
||||||
lgc.h llex.h lzio.h lmem.h lstring.h ltable.h ltm.h
|
lzio.h ldo.h lfunc.h lgc.h llex.h lmem.h lstring.h ltable.h
|
||||||
lstring.o: lstring.c lua.h lmem.h llimits.h lobject.h lstate.h \
|
lstring.o: lstring.c lua.h lmem.h llimits.h lobject.h lstate.h ltm.h \
|
||||||
luadebug.h lstring.h
|
lzio.h lstring.h
|
||||||
lstrlib.o: lstrlib.c lua.h lauxlib.h lualib.h
|
lstrlib.o: lstrlib.c lua.h lauxlib.h lualib.h
|
||||||
ltable.o: ltable.c lua.h ldo.h lobject.h llimits.h lstate.h luadebug.h \
|
ltable.o: ltable.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
|
||||||
lmem.h ltable.h
|
lzio.h ldo.h lgc.h lmem.h ltable.h
|
||||||
|
ltablib.o: ltablib.c lua.h lauxlib.h lualib.h
|
||||||
ltests.o: ltests.c lua.h lapi.h lobject.h llimits.h lauxlib.h lcode.h \
|
ltests.o: ltests.c lua.h lapi.h lobject.h llimits.h lauxlib.h lcode.h \
|
||||||
llex.h lzio.h lopcodes.h lparser.h ldebug.h lstate.h luadebug.h ldo.h \
|
llex.h lzio.h lopcodes.h lparser.h ltable.h ldebug.h lstate.h ltm.h \
|
||||||
lfunc.h lmem.h lstring.h ltable.h lualib.h
|
ldo.h lfunc.h lmem.h lstring.h lualib.h
|
||||||
ltm.o: ltm.c lua.h ldo.h lobject.h llimits.h lstate.h luadebug.h \
|
ltm.o: ltm.c lua.h lobject.h llimits.h lstate.h ltm.h lzio.h lstring.h \
|
||||||
lmem.h lstring.h ltable.h ltm.h
|
ltable.h
|
||||||
lua.o: lua.c lua.h luadebug.h lualib.h
|
lua.o: lua.c lua.h lauxlib.h lualib.h
|
||||||
lundump.o: lundump.c lua.h ldebug.h lstate.h lobject.h llimits.h \
|
lundump.o: lundump.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h \
|
||||||
luadebug.h lfunc.h lmem.h lopcodes.h lstring.h lundump.h lzio.h
|
lzio.h lfunc.h lmem.h lopcodes.h lstring.h lundump.h
|
||||||
lvm.o: lvm.c lua.h lapi.h lobject.h llimits.h ldebug.h lstate.h \
|
lvm.o: lvm.c lua.h ldebug.h lstate.h lobject.h llimits.h ltm.h lzio.h \
|
||||||
luadebug.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h ltm.h \
|
ldo.h lfunc.h lgc.h lopcodes.h lstring.h ltable.h lvm.h
|
||||||
lvm.h
|
lzio.o: lzio.c lua.h llimits.h lmem.h lzio.h
|
||||||
lzio.o: lzio.c lua.h lzio.h
|
|
||||||
|
|||||||
4171
manual.tex
4171
manual.tex
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user