Compare commits
1056 Commits
Release-5.
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f9d9cae4a | ||
|
|
468d65a661 | ||
|
|
9847618cf3 | ||
|
|
a281d9571e | ||
|
|
204faa82c1 | ||
|
|
be2fec02d9 | ||
|
|
491b95099d | ||
|
|
561c5bc981 | ||
|
|
12829ee5d2 | ||
|
|
f53a1ed951 | ||
|
|
12100cce99 | ||
|
|
d22c27b627 | ||
|
|
60c43233c6 | ||
|
|
c2f7ca3aa2 | ||
|
|
72cb9bd940 | ||
|
|
84f9c44ab6 | ||
|
|
698dfb06db | ||
|
|
244b5b224b | ||
|
|
534897d835 | ||
|
|
fac5a39066 | ||
|
|
064a385a64 | ||
|
|
e342243193 | ||
|
|
283785faaf | ||
|
|
c0c0bd3172 | ||
|
|
40fb8d257e | ||
|
|
f5f6ddf219 | ||
|
|
87f1242ed4 | ||
|
|
faba0f1317 | ||
|
|
077c93ab27 | ||
|
|
914bca6295 | ||
|
|
2549b4e983 | ||
|
|
1cb15d8b22 | ||
|
|
2ce155237d | ||
|
|
dca3ce4ea6 | ||
|
|
ca7d4ab734 | ||
|
|
f5ced799cf | ||
|
|
1499061f86 | ||
|
|
24352c62e8 | ||
|
|
6b4c47c5ba | ||
|
|
396d43a13f | ||
|
|
18cf09b512 | ||
|
|
2782cdd33b | ||
|
|
d8d7bc79b7 | ||
|
|
3e04210027 | ||
|
|
c82c9ccb6e | ||
|
|
efd37a7071 | ||
|
|
83b7973cb8 | ||
|
|
e7a6b2306c | ||
|
|
0a18f0a809 | ||
|
|
8efba903c3 | ||
|
|
ca87c05cd4 | ||
|
|
94fb7c2453 | ||
|
|
c54d84fae6 | ||
|
|
574f4a9664 | ||
|
|
b7e8897a43 | ||
|
|
7a588ed5cf | ||
|
|
89f373d21c | ||
|
|
037335a0ea | ||
|
|
2431362e54 | ||
|
|
9c59600b9f | ||
|
|
51663df1ba | ||
|
|
624c7c435b | ||
|
|
cf89bdd804 | ||
|
|
a8e70a4cfe | ||
|
|
f79de06e0b | ||
|
|
cee57f998a | ||
|
|
ce62706fea | ||
|
|
92c2ade1cd | ||
|
|
6b7481e6a1 | ||
|
|
d096f926d3 | ||
|
|
fb7f8f194c | ||
|
|
78f885ec61 | ||
|
|
d6d50478de | ||
|
|
defdb53a55 | ||
|
|
0dea62dd54 | ||
|
|
590905f4b3 | ||
|
|
9218dda001 | ||
|
|
9e17514b57 | ||
|
|
5f402e71dd | ||
|
|
95e119fffe | ||
|
|
f17439a9d3 | ||
|
|
940e0c2d86 | ||
|
|
e8c03b33c6 | ||
|
|
b68f917677 | ||
|
|
7f4af72244 | ||
|
|
6757b66f95 | ||
|
|
c9034a0485 | ||
|
|
50dcbc8c7e | ||
|
|
1ea91faf52 | ||
|
|
745e0c0f0b | ||
|
|
c42477f2eb | ||
|
|
335a02f165 | ||
|
|
012f1ffff5 | ||
|
|
9925b20fad | ||
|
|
28122f7cb0 | ||
|
|
b1f1803759 | ||
|
|
359897a442 | ||
|
|
ffcd7e3a76 | ||
|
|
2c99e6cd32 | ||
|
|
332a62769b | ||
|
|
a38b254a98 | ||
|
|
77231461ca | ||
|
|
eefd50a6bc | ||
|
|
0d4a99af82 | ||
|
|
9f30d84f39 | ||
|
|
8b18e301d2 | ||
|
|
508729ec77 | ||
|
|
0fe78f7ba5 | ||
|
|
6202149b4f | ||
|
|
4ad661475b | ||
|
|
6d309b7516 | ||
|
|
7d9e1b3af7 | ||
|
|
b99ccafa07 | ||
|
|
c97a69537d | ||
|
|
fac8f3ec90 | ||
|
|
ab07872857 | ||
|
|
23c13e6570 | ||
|
|
aa9267726f | ||
|
|
396e78d295 | ||
|
|
7339ff2c2f | ||
|
|
1efcddd335 | ||
|
|
21ccb1d1d0 | ||
|
|
c37c901a0c | ||
|
|
690b96d9ee | ||
|
|
d638d87a0f | ||
|
|
b091439567 | ||
|
|
665125665a | ||
|
|
d1c7645a4e | ||
|
|
58faea1cf2 | ||
|
|
8b7fe33bf1 | ||
|
|
7cc100e3d7 | ||
|
|
21495ebb40 | ||
|
|
b2907fc608 | ||
|
|
bec1b91b7b | ||
|
|
4b81a24a0a | ||
|
|
3b2c82ba2c | ||
|
|
8cb3bd4af8 | ||
|
|
26e6f51fa8 | ||
|
|
87294fc89d | ||
|
|
9cc0ce01b9 | ||
|
|
c9ee707972 | ||
|
|
cefb4d3c78 | ||
|
|
4e6e63ab5d | ||
|
|
7561aa8828 | ||
|
|
e44724c780 | ||
|
|
b0f07cbe5d | ||
|
|
62639a4359 | ||
|
|
176d608bb4 | ||
|
|
a1d90c95f0 | ||
|
|
a14f1983e8 | ||
|
|
5642e062e6 | ||
|
|
9e16cc2a79 | ||
|
|
201fef49c6 | ||
|
|
58ebb22c55 | ||
|
|
830b7c93ca | ||
|
|
368a3b78a2 | ||
|
|
e3e90de02a | ||
|
|
8478ddc470 | ||
|
|
2adefaf46d | ||
|
|
bd26355516 | ||
|
|
19a730b78b | ||
|
|
e3d1741c63 | ||
|
|
09bdec4882 | ||
|
|
c31ebb5665 | ||
|
|
52a191df9e | ||
|
|
228c942b6c | ||
|
|
09ed0ca573 | ||
|
|
ee68ff20ed | ||
|
|
b72eed3921 | ||
|
|
039d0edce3 | ||
|
|
7b3f06b269 | ||
|
|
5373bbd52e | ||
|
|
17821be1e2 | ||
|
|
9a526bc1ec | ||
|
|
03803ee4c4 | ||
|
|
dcedd64032 | ||
|
|
d34d74205c | ||
|
|
41c1c490c8 | ||
|
|
70cdbef693 | ||
|
|
f6c69f2826 | ||
|
|
184ca7f7b2 | ||
|
|
71caf5006f | ||
|
|
4dbf1ee2bd | ||
|
|
4324a700ad | ||
|
|
5b78d5a898 | ||
|
|
ff2ab6bb8d | ||
|
|
25575564c0 | ||
|
|
683164650a | ||
|
|
647f8842fd | ||
|
|
6d6f79b1a4 | ||
|
|
06b2893bfb | ||
|
|
7ab6bce7fa | ||
|
|
f9294c8cbe | ||
|
|
80cc18bf2f | ||
|
|
c68488388e | ||
|
|
7d5a97aa2f | ||
|
|
83c6df11f0 | ||
|
|
10b984556d | ||
|
|
cf2fa09d6c | ||
|
|
f3f84594ee | ||
|
|
57aa874c6e | ||
|
|
32bd936a18 | ||
|
|
498339c202 | ||
|
|
56b4f465a1 | ||
|
|
1a42614441 | ||
|
|
6fa83bca85 | ||
|
|
fd57bec676 | ||
|
|
14307194e9 | ||
|
|
62e34c097c | ||
|
|
cdb9dcc154 | ||
|
|
14d429853b | ||
|
|
e8ff1f9d7e | ||
|
|
49ef5306a9 | ||
|
|
7d9dbc3d86 | ||
|
|
49dfdfd15a | ||
|
|
720395e47a | ||
|
|
5e0a882b18 | ||
|
|
9603d3910a | ||
|
|
6f0d02f158 | ||
|
|
8d808f75c0 | ||
|
|
2a1632f213 | ||
|
|
e57f11fcf4 | ||
|
|
2fe794fcae | ||
|
|
b594043eef | ||
|
|
fe8f8a89a7 | ||
|
|
40694c798c | ||
|
|
443828fa23 | ||
|
|
866db4ee8b | ||
|
|
5e97f459d8 | ||
|
|
e02ac78195 | ||
|
|
62cd8031ac | ||
|
|
61dfcb00c0 | ||
|
|
4bf619c80f | ||
|
|
08a68f310a | ||
|
|
641ac1a1ae | ||
|
|
2400c64c82 | ||
|
|
1e584048ce | ||
|
|
7865f8e7f2 | ||
|
|
5ff97979fd | ||
|
|
5567e767a3 | ||
|
|
5a947b5035 | ||
|
|
6ecbaab2fe | ||
|
|
dd6b38cafb | ||
|
|
1e62eb4e12 | ||
|
|
6e6795e914 | ||
|
|
33c966b8d6 | ||
|
|
c07c2a9cc2 | ||
|
|
46c45e8fc7 | ||
|
|
91a3ae1f14 | ||
|
|
328aef10d7 | ||
|
|
f7b52f6c39 | ||
|
|
2f2f789f48 | ||
|
|
06783b7f65 | ||
|
|
a45c76721f | ||
|
|
3627efe03b | ||
|
|
1cd7a1b972 | ||
|
|
df9466e2a7 | ||
|
|
dc8aa372c1 | ||
|
|
bcc25222dd | ||
|
|
6507a6e68e | ||
|
|
5872b020fa | ||
|
|
c57ea79d0d | ||
|
|
b424d1f9cb | ||
|
|
7dcd6b8447 | ||
|
|
de63529887 | ||
|
|
d95f59fa97 | ||
|
|
d5ae30191d | ||
|
|
16ffbca6d6 | ||
|
|
afa3f2249c | ||
|
|
c5f4a4dfd8 | ||
|
|
34a2001a7b | ||
|
|
16c4a11990 | ||
|
|
6f01568a9a | ||
|
|
a363ef5e0e | ||
|
|
a3365a9c4a | ||
|
|
9a5ef38d4a | ||
|
|
5247de7d1b | ||
|
|
cd1b3f8887 | ||
|
|
11ee71ba27 | ||
|
|
91ba9e25c0 | ||
|
|
978f80751f | ||
|
|
0ac5657661 | ||
|
|
cfc8a3d214 | ||
|
|
85163e08cc | ||
|
|
019c6b2830 | ||
|
|
c71dd8051b | ||
|
|
fe8f571f47 | ||
|
|
947d7c2591 | ||
|
|
6f6227879a | ||
|
|
e014308154 | ||
|
|
467392e17d | ||
|
|
cf5913f890 | ||
|
|
71c67bc763 | ||
|
|
539ee3c84f | ||
|
|
594958ea8b | ||
|
|
83b966df47 | ||
|
|
c24004c70e | ||
|
|
a0ee8d1137 | ||
|
|
765e6ed8df | ||
|
|
0cb4c18638 | ||
|
|
ad7e2138d9 | ||
|
|
0eee23109e | ||
|
|
b663654a6d | ||
|
|
2a8c248167 | ||
|
|
457367ea7b | ||
|
|
33e27b4f85 | ||
|
|
b5b6e5a5a3 | ||
|
|
a0f3eafe30 | ||
|
|
8feff5bc76 | ||
|
|
463f688978 | ||
|
|
70c6ed713b | ||
|
|
a6dcbb1f1c | ||
|
|
d4f02b5e67 | ||
|
|
645377e191 | ||
|
|
5a03c88ee3 | ||
|
|
abc30ba573 | ||
|
|
f36b1fc5eb | ||
|
|
feb7775d21 | ||
|
|
8d50160cd9 | ||
|
|
871ad10e0e | ||
|
|
649edf1dd1 | ||
|
|
c0664d778c | ||
|
|
6c483bd6f6 | ||
|
|
7f8a6f24f9 | ||
|
|
07fa8010e4 | ||
|
|
e024b99b36 | ||
|
|
ed65ad72d0 | ||
|
|
bc0eaa5d15 | ||
|
|
e0827634bb | ||
|
|
08ba646200 | ||
|
|
caf0a8b5d1 | ||
|
|
357df5c8ec | ||
|
|
d0630d5edd | ||
|
|
c562d0d78b | ||
|
|
bff30278e1 | ||
|
|
b104b26f11 | ||
|
|
03ef44f415 | ||
|
|
1a06e53c58 | ||
|
|
c438a388d7 | ||
|
|
7923c3e0c7 | ||
|
|
872f16e45a | ||
|
|
7688c14d43 | ||
|
|
bde2a45384 | ||
|
|
7f4ef8d8fd | ||
|
|
0dab950ebf | ||
|
|
485482b2be | ||
|
|
b2ae317877 | ||
|
|
5b1b1dbcb4 | ||
|
|
7222390c96 | ||
|
|
b33f0a08bc | ||
|
|
140a90f72a | ||
|
|
f697384028 | ||
|
|
dfd04c8291 | ||
|
|
209d6ed2e4 | ||
|
|
d8fa6061a2 | ||
|
|
651eed8d7a | ||
|
|
af1eba1b0e | ||
|
|
f82f6c2068 | ||
|
|
fcca453223 | ||
|
|
7ed5c18a86 | ||
|
|
c067575ac4 | ||
|
|
52c96de6a8 | ||
|
|
907e6d74e0 | ||
|
|
12cbbd2097 | ||
|
|
4aa370fbfd | ||
|
|
3587c3e165 | ||
|
|
acc4345b65 | ||
|
|
43def57852 | ||
|
|
561b47e463 | ||
|
|
9885534b5b | ||
|
|
ad3f111e13 | ||
|
|
452f71b51f | ||
|
|
a97cb1530d | ||
|
|
21048b9e65 | ||
|
|
d73e715997 | ||
|
|
353a077c6b | ||
|
|
373a3688c9 | ||
|
|
208107fd7e | ||
|
|
e19a8e31ea | ||
|
|
b55eff95cf | ||
|
|
b6287a194c | ||
|
|
888d897a3e | ||
|
|
e32714c456 | ||
|
|
e1c40f3e8f | ||
|
|
d7489358f3 | ||
|
|
316ba45e3c | ||
|
|
f0796b51c8 | ||
|
|
e638d450ed | ||
|
|
e60eabbeb2 | ||
|
|
c249bef27d | ||
|
|
4e69e5a3d2 | ||
|
|
49c89a3b88 | ||
|
|
7507223c8b | ||
|
|
681b7db727 | ||
|
|
4826bddb5b | ||
|
|
49436e5740 | ||
|
|
202204a82a | ||
|
|
34c6b17215 | ||
|
|
6fe7f5ce98 | ||
|
|
d9f86a96f0 | ||
|
|
da1511a092 | ||
|
|
8bd7ccfa9f | ||
|
|
0806df11d2 | ||
|
|
40b1549b3b | ||
|
|
c9a5bf6f83 | ||
|
|
8496a86043 | ||
|
|
bc388e59da | ||
|
|
09748275db | ||
|
|
eec0299cbc | ||
|
|
19ecfdfec5 | ||
|
|
7ba7b81a5c | ||
|
|
882cbf2dfb | ||
|
|
38b98c55cc | ||
|
|
3a675bf379 | ||
|
|
985b62705f | ||
|
|
5aecb7f17b | ||
|
|
ad69bf7d38 | ||
|
|
84554ed0a5 | ||
|
|
36765df3c0 | ||
|
|
b11ebf9e8f | ||
|
|
84e2d449b9 | ||
|
|
3e62a99f82 | ||
|
|
64dd349e32 | ||
|
|
1add4c4b0f | ||
|
|
14b3870efb | ||
|
|
d2cf12f948 | ||
|
|
e221ceaa4c | ||
|
|
beedf13d01 | ||
|
|
9d18360333 | ||
|
|
18e5ee0ba2 | ||
|
|
41e9027d9a | ||
|
|
8d9dc2b0a3 | ||
|
|
6a4647af43 | ||
|
|
5a651e2b8a | ||
|
|
d9fa5605ac | ||
|
|
3a8cb581cc | ||
|
|
b434d26a5d | ||
|
|
ba30d4f483 | ||
|
|
b4ffcd594d | ||
|
|
ca35128503 | ||
|
|
681f18ee62 | ||
|
|
e62a38b39f | ||
|
|
85ac1052dd | ||
|
|
8024edeadf | ||
|
|
f9f1d5807a | ||
|
|
14227475b2 | ||
|
|
e1a80fb5ce | ||
|
|
aabe53c934 | ||
|
|
f3dbb7ed87 | ||
|
|
52e11bf001 | ||
|
|
f06e5cdcd6 | ||
|
|
15eb78bd8f | ||
|
|
9f362608b7 | ||
|
|
e21c8f87b4 | ||
|
|
0a143d1cd3 | ||
|
|
08935beaf3 | ||
|
|
c9625b09b0 | ||
|
|
800c7fb37b | ||
|
|
179eaefafe | ||
|
|
28f5a74e98 | ||
|
|
781d62d3a5 | ||
|
|
8ed2158709 | ||
|
|
8f98e16e5e | ||
|
|
3a595ef912 | ||
|
|
5aa0bfcea4 | ||
|
|
04e2256c92 | ||
|
|
38ba00e55c | ||
|
|
8931346230 | ||
|
|
8bdd2deb19 | ||
|
|
535055eff8 | ||
|
|
913d2fd20f | ||
|
|
0c4951d742 | ||
|
|
9d17b18f26 | ||
|
|
31b3195c17 | ||
|
|
0d4e4090a0 | ||
|
|
b946af42cc | ||
|
|
22339d10db | ||
|
|
b3d2350f33 | ||
|
|
3cae2aed1d | ||
|
|
c6f262c675 | ||
|
|
8239206ec5 | ||
|
|
a2ff672b34 | ||
|
|
9a0a12d230 | ||
|
|
7d3c23fc22 | ||
|
|
63ab117e7d | ||
|
|
93e7eb3fe5 | ||
|
|
419c2d72a8 | ||
|
|
e1c382211a | ||
|
|
6a7a934e3e | ||
|
|
1f72afc8f5 | ||
|
|
2fbc377119 | ||
|
|
563999f3b8 | ||
|
|
1ea608babe | ||
|
|
51355343f1 | ||
|
|
fe33a6aacb | ||
|
|
e117f50db0 | ||
|
|
37120f486f | ||
|
|
484ff7a98b | ||
|
|
496f5aff7a | ||
|
|
b270a198dc | ||
|
|
9e93d61236 | ||
|
|
72aedca39c | ||
|
|
748c18f465 | ||
|
|
b9875e2844 | ||
|
|
902f48cd4c | ||
|
|
1526ac96c1 | ||
|
|
e339055e0b | ||
|
|
4890b47460 | ||
|
|
b53432cf28 | ||
|
|
a112d97141 | ||
|
|
83281bff52 | ||
|
|
05bec3b4a8 | ||
|
|
cd2fb1ec66 | ||
|
|
ec33cf2709 | ||
|
|
c7689f18ec | ||
|
|
3eb7700912 | ||
|
|
c4633436ba | ||
|
|
2870874d91 | ||
|
|
a147278a7e | ||
|
|
a2577b983c | ||
|
|
646563eb3f | ||
|
|
f9860216c9 | ||
|
|
b7eb469ac1 | ||
|
|
bcf573cf26 | ||
|
|
1bf4170d8f | ||
|
|
6d632f6aa4 | ||
|
|
835b5a90af | ||
|
|
9e743e3147 | ||
|
|
7adbc11869 | ||
|
|
2442e9ae20 | ||
|
|
0dcac05f2f | ||
|
|
60a497b0a6 | ||
|
|
11b372f526 | ||
|
|
3d36ea6199 | ||
|
|
cebeebdb7a | ||
|
|
e5ccec0e89 | ||
|
|
62ca26c36c | ||
|
|
68fa049d6c | ||
|
|
88ab00679f | ||
|
|
86482b0103 | ||
|
|
f9e0193353 | ||
|
|
ba492308f4 | ||
|
|
d4e22c2c2c | ||
|
|
b95526951f | ||
|
|
e4be97eb79 | ||
|
|
59eecab0e8 | ||
|
|
be159759ea | ||
|
|
1e41e73af2 | ||
|
|
78819fd3a8 | ||
|
|
c6c2bcc023 | ||
|
|
e759a0c544 | ||
|
|
b163065b3c | ||
|
|
ecafb4aad0 | ||
|
|
38a83e3e56 | ||
|
|
bacf546dff | ||
|
|
85a6d85c1f | ||
|
|
7522a19af5 | ||
|
|
26a0034176 | ||
|
|
cb5fbff1e6 | ||
|
|
ff378abf84 | ||
|
|
520f9bc0d2 | ||
|
|
cf3db70d5d | ||
|
|
7026229273 | ||
|
|
da8fa77558 | ||
|
|
9fe8150861 | ||
|
|
d56e32e2c4 | ||
|
|
7f871374fa | ||
|
|
2848e16ea1 | ||
|
|
916708ce29 | ||
|
|
cff635fb65 | ||
|
|
f6600c90e4 | ||
|
|
3701477f7f | ||
|
|
d13d080dee | ||
|
|
61d5e2ad85 | ||
|
|
023a3edf40 | ||
|
|
4b577f1f2a | ||
|
|
ac280a6971 | ||
|
|
d2f855e3f9 | ||
|
|
114e3939f6 | ||
|
|
ee672f5132 | ||
|
|
aa60cffe85 | ||
|
|
bb0d100513 | ||
|
|
70326a5dff | ||
|
|
cfc67f619a | ||
|
|
1a02903b99 | ||
|
|
f274d6beb3 | ||
|
|
a04fe9d5a5 | ||
|
|
f54bd484e6 | ||
|
|
8ed4e6fad8 | ||
|
|
c9312c0b7a | ||
|
|
bb2938307c | ||
|
|
919c3f2b4a | ||
|
|
e0234d942e | ||
|
|
df724b5c33 | ||
|
|
0b812942d4 | ||
|
|
48933bc32c | ||
|
|
630c618ae7 | ||
|
|
03143a9f83 | ||
|
|
33a929ef93 | ||
|
|
e608d14a4f | ||
|
|
e43b1b8d0d | ||
|
|
c32af523c3 | ||
|
|
37b73f0e3c | ||
|
|
13381ffa43 | ||
|
|
2129c5318b | ||
|
|
515ee711ce | ||
|
|
bc8a4c42fa | ||
|
|
051f483d20 | ||
|
|
da39b8403b | ||
|
|
5fa44d5eef | ||
|
|
dec88db26c | ||
|
|
9da9012701 | ||
|
|
f35c2fdb03 | ||
|
|
bb74d06b18 | ||
|
|
c21c21dfda | ||
|
|
ef92b6619e | ||
|
|
fd2539145a | ||
|
|
25f9dcf13e | ||
|
|
fc4b739839 | ||
|
|
bd176cfde2 | ||
|
|
04f01eee98 | ||
|
|
cf4efacbe8 | ||
|
|
b818799800 | ||
|
|
fdcc5959c7 | ||
|
|
74a992fad9 | ||
|
|
d210f0e4e1 | ||
|
|
c0dd0a3041 | ||
|
|
45baf6f8e9 | ||
|
|
e64e4b0877 | ||
|
|
e286b9a9aa | ||
|
|
d77921f1b5 | ||
|
|
ebc6468178 | ||
|
|
3e5034ecf8 | ||
|
|
c52ad3d827 | ||
|
|
8fc61bf51c | ||
|
|
dc6d039a72 | ||
|
|
2e72fde0ba | ||
|
|
d762ef08b6 | ||
|
|
8bbcceed88 | ||
|
|
aaf80ac8cf | ||
|
|
86ec14c2c8 | ||
|
|
dbe546fefb | ||
|
|
50e0ce36be | ||
|
|
986699a3fe | ||
|
|
8889324b2d | ||
|
|
7a13b6b801 | ||
|
|
b2b604e2ad | ||
|
|
4f5f46a2e5 | ||
|
|
dde7d27b96 | ||
|
|
fa16bcd08e | ||
|
|
5c4de7e43c | ||
|
|
bc7668c700 | ||
|
|
a9d94968d0 | ||
|
|
1a37343e8b | ||
|
|
ddc6ac8e00 | ||
|
|
0e41e373c6 | ||
|
|
9ab0b1108a | ||
|
|
606c1d9d00 | ||
|
|
28f89475b0 | ||
|
|
1a396be69d | ||
|
|
a542ec01f6 | ||
|
|
f3943f215f | ||
|
|
0f4bd2b889 | ||
|
|
650889eae7 | ||
|
|
90102cebd7 | ||
|
|
dc746ee131 | ||
|
|
059c7bcca1 | ||
|
|
1b7b7d6e2c | ||
|
|
7830085f5e | ||
|
|
0ed9602ba9 | ||
|
|
2f531355cd | ||
|
|
db34899225 | ||
|
|
71245aa703 | ||
|
|
ecd2e523f7 | ||
|
|
d2ed8fdcf1 | ||
|
|
2f444542ab | ||
|
|
268868f102 | ||
|
|
f3090c3857 | ||
|
|
3c7b0ea069 | ||
|
|
2e769d81cf | ||
|
|
a3f88b43ce | ||
|
|
b489ffe3ed | ||
|
|
cbeeadd6f3 | ||
|
|
63684d0042 | ||
|
|
1f74bfd9b3 | ||
|
|
5114ca9d35 | ||
|
|
79181fe41e | ||
|
|
962bdf4b3c | ||
|
|
f953f9b297 | ||
|
|
1557dabf4f | ||
|
|
9422bc7b2d | ||
|
|
7f1cd29a2c | ||
|
|
8f2e56a681 | ||
|
|
88e765bd4e | ||
|
|
59103b5a22 | ||
|
|
b67dc4e09a | ||
|
|
d514fa3346 | ||
|
|
95ead0dbfb | ||
|
|
c32a944b9d | ||
|
|
62337062bf | ||
|
|
a75117c007 | ||
|
|
4fe536e65b | ||
|
|
d396f8e6a0 | ||
|
|
6ba3e92d6e | ||
|
|
bd1b5c0687 | ||
|
|
40e2bf4099 | ||
|
|
5b9878b070 | ||
|
|
0b28603cdc | ||
|
|
91bcaaa037 | ||
|
|
04bceedf64 | ||
|
|
9326539f3b | ||
|
|
1113cafca2 | ||
|
|
98e36ab836 | ||
|
|
976e4ec46c | ||
|
|
c416ca1e4d | ||
|
|
9963933f51 | ||
|
|
4e614729dc | ||
|
|
d0e763d77e | ||
|
|
63c243dec8 | ||
|
|
c15e0174c9 | ||
|
|
ec47a35e9f | ||
|
|
9c1f5b6830 | ||
|
|
735088dc96 | ||
|
|
f14be9660a | ||
|
|
6a5f78240a | ||
|
|
230e399d92 | ||
|
|
dace26cae1 | ||
|
|
e6d71373b8 | ||
|
|
27e861c7b9 | ||
|
|
516ca8eec2 | ||
|
|
b71f9db5c2 | ||
|
|
aa0ed17e43 | ||
|
|
34e3551ebd | ||
|
|
c584c29951 | ||
|
|
c285c4d40b | ||
|
|
b5188b9eda | ||
|
|
d558019bb3 | ||
|
|
722e9ed3d1 | ||
|
|
76ac7c36fe | ||
|
|
f0ed3a5cf7 | ||
|
|
343264944a | ||
|
|
b436791272 | ||
|
|
9b19aa3b6e | ||
|
|
e86fc96b2f | ||
|
|
66801349a8 | ||
|
|
bde4eb04b6 | ||
|
|
c3f343450d | ||
|
|
8dc2c55acd | ||
|
|
adfc56db8b | ||
|
|
c7b2b3095a | ||
|
|
9449fca22f | ||
|
|
759d6fc42f | ||
|
|
f95ca75aca | ||
|
|
41a45ce8b5 | ||
|
|
5b6e6042f3 | ||
|
|
1552d36d7a | ||
|
|
26bf531cab | ||
|
|
7761ceb736 | ||
|
|
497dd89046 | ||
|
|
ef69e4a2f1 | ||
|
|
3f23e57a3d | ||
|
|
f66b4aafc1 | ||
|
|
3d1edbf38f | ||
|
|
c1f47cbc16 | ||
|
|
4761a68d06 | ||
|
|
31ef683ced | ||
|
|
9b3bb493e9 | ||
|
|
2f90b3ae6b | ||
|
|
420ba68b94 | ||
|
|
576816e3b1 | ||
|
|
25b15a3449 | ||
|
|
8746a9eea5 | ||
|
|
0695eec3ca | ||
|
|
1a4dec0df0 | ||
|
|
de09489355 | ||
|
|
440ceeebbb | ||
|
|
12533ce3e1 | ||
|
|
2e02273673 | ||
|
|
d91294b989 | ||
|
|
52d03a66b1 | ||
|
|
a32a180a06 | ||
|
|
e61612e416 | ||
|
|
7478d57264 | ||
|
|
bab3701c2f | ||
|
|
e225654289 | ||
|
|
019ea57cb6 | ||
|
|
60fe242fb6 | ||
|
|
6c10f18e4c | ||
|
|
d5a221a468 | ||
|
|
6ec3afc687 | ||
|
|
049cd12127 | ||
|
|
8b34066dd5 | ||
|
|
9fb74762ad | ||
|
|
7b7e7176f5 | ||
|
|
81146d6b0f | ||
|
|
423e872720 | ||
|
|
1e8c0ab93e | ||
|
|
c90fe16858 | ||
|
|
161652b5d9 | ||
|
|
cc5bf45b3b | ||
|
|
28124e4b33 | ||
|
|
db207b345b | ||
|
|
684d724103 | ||
|
|
283152a880 | ||
|
|
dc3ef087e2 | ||
|
|
032ba63b8a | ||
|
|
cf49b1b30c | ||
|
|
63a083b47b | ||
|
|
4a3315cfd1 | ||
|
|
8a30581eaf | ||
|
|
a51281a5be | ||
|
|
e0919f7228 | ||
|
|
fa5966bd04 | ||
|
|
f4f2391801 | ||
|
|
5daf837037 | ||
|
|
99396ba05c | ||
|
|
f5304ac75c | ||
|
|
3f460fdd20 | ||
|
|
4f972bcf67 | ||
|
|
5d5e881971 | ||
|
|
5515d058bb | ||
|
|
79c5f71975 | ||
|
|
c876a89030 | ||
|
|
20c0e6016e | ||
|
|
dd12785b72 | ||
|
|
87cee688a8 | ||
|
|
e2cf8a48be | ||
|
|
7c766f87a4 | ||
|
|
e85be6eb3d | ||
|
|
7b42d5307a | ||
|
|
43d6f0cf16 | ||
|
|
86e26966c1 | ||
|
|
b41c0f432b | ||
|
|
9e8b833d11 | ||
|
|
48c97bce9c | ||
|
|
021e2a7949 | ||
|
|
78cd980067 | ||
|
|
58d9e69479 | ||
|
|
935e9de19e | ||
|
|
f547b4bb10 | ||
|
|
87e40237d3 | ||
|
|
5619f2602d | ||
|
|
5986531bba | ||
|
|
8ecc11c275 | ||
|
|
81dc4949d2 | ||
|
|
9a7d03df05 | ||
|
|
4f5a6da280 | ||
|
|
e4b9be6e09 | ||
|
|
0a7e7b3a0d | ||
|
|
e1b80abac4 | ||
|
|
b6e8605aee | ||
|
|
0e381e333e | ||
|
|
8c31255012 | ||
|
|
01cf906e18 | ||
|
|
e55700b86b | ||
|
|
81184cbbd7 | ||
|
|
c00c38bc22 | ||
|
|
ae1897e2ea | ||
|
|
93c1cfde99 | ||
|
|
2321f1d709 | ||
|
|
cfd4a73a89 | ||
|
|
04782b6a33 | ||
|
|
5861c45fc1 | ||
|
|
d62a452a9d | ||
|
|
3ccb155358 | ||
|
|
6c2ccf3869 | ||
|
|
f02a9fa885 | ||
|
|
0036ebfe5d | ||
|
|
7b28f9ef57 | ||
|
|
bd8a78eccc | ||
|
|
9436533ddb | ||
|
|
243f4001d1 | ||
|
|
3bd2a9c00d | ||
|
|
fde90ad980 | ||
|
|
308eb34d05 | ||
|
|
4a70ffe599 | ||
|
|
52179d8333 | ||
|
|
eed90b521d | ||
|
|
166f3501c3 | ||
|
|
29b1fca76c | ||
|
|
8d36b66c89 | ||
|
|
f78fb77128 | ||
|
|
bb08cc3699 | ||
|
|
6692607507 | ||
|
|
6bea42c1c0 | ||
|
|
251790f144 | ||
|
|
4ee9ba9c96 | ||
|
|
a71903f185 | ||
|
|
3fe80d70c6 | ||
|
|
9c05779fac | ||
|
|
a6e3fd5b42 | ||
|
|
6a3f19d575 | ||
|
|
9b7e4d2e78 | ||
|
|
f546e46582 | ||
|
|
fa1f4b795b | ||
|
|
cb1c7730cf | ||
|
|
3a775097dd | ||
|
|
5692dfc58a | ||
|
|
c5f6c549ec | ||
|
|
14a280713f | ||
|
|
e7b6ee6cf9 | ||
|
|
32a9aa9c3c | ||
|
|
f57a14e3de | ||
|
|
4018c873dc | ||
|
|
b4ea27d28a | ||
|
|
e5d723621f | ||
|
|
46e7d0ab99 | ||
|
|
d5378f50af | ||
|
|
be9632d0ad | ||
|
|
61cd633084 | ||
|
|
c35b35e4f8 | ||
|
|
bcb7172037 | ||
|
|
3c552db548 | ||
|
|
37982cbdaa | ||
|
|
28a016b51d | ||
|
|
c0bf6ee99d | ||
|
|
f29af4618a | ||
|
|
ee17a184c2 | ||
|
|
6eab8ddfe1 | ||
|
|
a7e8c6fe1f | ||
|
|
5f2796868b | ||
|
|
c2d08457ad | ||
|
|
d3084ed136 | ||
|
|
62b8977abe | ||
|
|
b87c37032b | ||
|
|
7932cb18f3 | ||
|
|
706b5aaa45 | ||
|
|
41bf96c42e | ||
|
|
67b5d989cb | ||
|
|
fcc9bd9bbb | ||
|
|
825c28521e | ||
|
|
5da1475082 | ||
|
|
c9a244019e | ||
|
|
2bd1910c70 | ||
|
|
4ace508339 | ||
|
|
926e962fc0 | ||
|
|
caf4495cff | ||
|
|
6b0e0dc7ae | ||
|
|
65b0846e41 | ||
|
|
296769ee24 | ||
|
|
d9bdad714f | ||
|
|
12de955a47 | ||
|
|
a652a7e564 | ||
|
|
611692646f | ||
|
|
96acf5e833 | ||
|
|
656b438002 | ||
|
|
56b036052f | ||
|
|
7fade8e841 | ||
|
|
db8be03cee | ||
|
|
372cf73548 | ||
|
|
0213039ee7 | ||
|
|
e8fcb3f68b | ||
|
|
8d8df1f5bd | ||
|
|
f40f9d8441 | ||
|
|
8879a89490 | ||
|
|
e4a3b3f620 | ||
|
|
d6c8b36eeb | ||
|
|
de86e79df2 | ||
|
|
8d96abe730 | ||
|
|
c021cc931c | ||
|
|
782c3040cc | ||
|
|
4dbe9df21e | ||
|
|
a1fc7416e1 | ||
|
|
bf0737a35c | ||
|
|
00c8bf4973 | ||
|
|
593ce462f7 | ||
|
|
304e34002b | ||
|
|
385465cf3f | ||
|
|
27307b17d1 | ||
|
|
4bdf854a9c | ||
|
|
0162757158 | ||
|
|
b0a882d57e | ||
|
|
d22fb19e0e | ||
|
|
8b134c65d1 | ||
|
|
ee35eb1512 | ||
|
|
ebbcc5cbdb | ||
|
|
dbd9534bd9 | ||
|
|
daf5480c48 | ||
|
|
1f2c9b0c77 | ||
|
|
a38d89cb41 | ||
|
|
3d76e980cc | ||
|
|
cb42bffbf9 | ||
|
|
b2b9efebe3 | ||
|
|
b97c5c13c1 | ||
|
|
8c70fff02b | ||
|
|
9cf5064a3b | ||
|
|
af44da916a | ||
|
|
20b40d3970 | ||
|
|
1e0cd4f63a | ||
|
|
04131d208b | ||
|
|
9c35ede59a | ||
|
|
8aedd80e1a | ||
|
|
52bb08f4d5 | ||
|
|
71348b7967 | ||
|
|
3a6caeb1c5 | ||
|
|
3f78af9a3d | ||
|
|
31a4900765 | ||
|
|
eb1a1c0275 | ||
|
|
8724e0cb80 | ||
|
|
a195fac4ca | ||
|
|
2a2a469a1b | ||
|
|
ac21c8b063 | ||
|
|
5272a64be9 | ||
|
|
3b1213a2b0 | ||
|
|
b872a50acc | ||
|
|
c6a1d1ea75 | ||
|
|
36466a4ac5 | ||
|
|
e667b4df5f | ||
|
|
7cebc8d748 | ||
|
|
189ae82cb7 | ||
|
|
bf83969723 | ||
|
|
5cb78ecd68 | ||
|
|
41f6ca18ea | ||
|
|
a26d628e5c | ||
|
|
d5fef3121a | ||
|
|
16f09794cf | ||
|
|
26722d648d | ||
|
|
95e3093df3 | ||
|
|
510d550d64 | ||
|
|
73b3762f7a | ||
|
|
d44de49fb1 | ||
|
|
21e3d1cc0a | ||
|
|
1708024372 | ||
|
|
101225aa68 | ||
|
|
6e71409a52 | ||
|
|
feb344e744 | ||
|
|
494a67c9a0 | ||
|
|
1a48dd9480 | ||
|
|
12d842ca5a | ||
|
|
9ac58a942e | ||
|
|
d0ce78061c | ||
|
|
e68599920a | ||
|
|
58a8854009 | ||
|
|
1e1385bc52 | ||
|
|
ae1221d46d | ||
|
|
9d59098015 | ||
|
|
6fea178f5d | ||
|
|
81edebc074 | ||
|
|
4fc51dfe05 | ||
|
|
241ca75204 | ||
|
|
88f7bffc4f | ||
|
|
1f1656a6c2 | ||
|
|
47e44d2f9e | ||
|
|
2afc09dad4 | ||
|
|
95b69b7572 | ||
|
|
1858885010 | ||
|
|
f338066298 | ||
|
|
d068ce472c | ||
|
|
380b94a8d2 | ||
|
|
dd79534de1 | ||
|
|
fd72b2951a | ||
|
|
48f538438d | ||
|
|
c9995480e6 | ||
|
|
e298333ac6 | ||
|
|
d225e09d5d | ||
|
|
abcc6c9e3e |
53
.decent_ci-Linux.yaml
Normal file
53
.decent_ci-Linux.yaml
Normal file
@@ -0,0 +1,53 @@
|
||||
compilers:
|
||||
- name: "clang"
|
||||
version: "3.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: "clang"
|
||||
build_tag: "LibC++"
|
||||
version: "3.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||
- name: "clang"
|
||||
build_tag: AddressSanitizer
|
||||
version: "3.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DRUN_FUZZY_TESTS:BOOL=TRUE -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_ADDRESS_SANITIZER:BOOL=ON
|
||||
- name: "clang"
|
||||
build_tag: ThreadSanitizer
|
||||
version: "3.6"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DENABLE_THREAD_SANITIZER:BOOL=ON
|
||||
- name: "clang"
|
||||
version: "3.7"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=OFF -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: "clang"
|
||||
build_tag: "LibC++"
|
||||
version: "3.7"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DUSE_LIBCXX:BOOL=ON -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON
|
||||
- name: "gcc"
|
||||
version: "4.9"
|
||||
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: "gcc"
|
||||
version: "4.9"
|
||||
skip_packaging: true
|
||||
build_tag: "NoThreads"
|
||||
cmake_extra_flags: -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON -DMULTITHREAD_SUPPORT_ENABLED:BOOL=OFF
|
||||
collect_performance_results: true
|
||||
- name: "gcc"
|
||||
version: "5"
|
||||
skip_packaging: true
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DRUN_PERFORMANCE_TESTS:BOOL=ON
|
||||
collect_performance_results: true
|
||||
- name: cppcheck
|
||||
compiler_extra_flags: --enable=all -I include --inline-suppr -Umax --suppress="*:unittests/catch.hpp" --force --suppress="unusedFunction:*"
|
||||
- name: custom_check
|
||||
commands:
|
||||
- ./contrib/check_for_tabs.rb
|
||||
- ./contrib/check_for_todos.rb
|
||||
|
||||
5
.decent_ci-MacOS.yaml
Normal file
5
.decent_ci-MacOS.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
compilers:
|
||||
- name: clang
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=$COMMIT_SHA
|
||||
build_package_generator: TBZ2
|
||||
|
||||
21
.decent_ci-Windows.yaml
Normal file
21
.decent_ci-Windows.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
compilers:
|
||||
- name: Visual Studio
|
||||
version: 14
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
||||
compiler_extra_flags: /analyze
|
||||
skip_packaging: true
|
||||
- name: Visual Studio
|
||||
version: 14
|
||||
architecture: Win64
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
||||
compiler_extra_flags: /analyze
|
||||
skip_packaging: true
|
||||
- name: Visual Studio
|
||||
version: 14
|
||||
build_type: Debug
|
||||
architecture: Win64
|
||||
cmake_extra_flags: -DBUILD_SAMPLES:BOOL=ON -DBUILD_PACKAGE:BOOL=ON -DBUILD_TESTING:BOOL=ON -DCOMMIT_SHA=%COMMIT_SHA%
|
||||
compiler_extra_flags: /analyze
|
||||
skip_packaging: true
|
||||
|
||||
|
||||
4
.decent_ci.yaml
Normal file
4
.decent_ci.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
results_repository : ChaiScript/ChaiScript-BuildResults
|
||||
results_path : _posts
|
||||
results_base_url : https://chaiscript.github.io/ChaiScript-BuildResults
|
||||
aging_pull_requests_notification: true
|
||||
41
.github/CONTRIBUTING.md
vendored
Normal file
41
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
# Contributing to ChaiScript
|
||||
|
||||
Thank you for contributing!
|
||||
|
||||
# Pull Requests
|
||||
|
||||
Please follow the existing style in the code you are patching.
|
||||
|
||||
- two space indent
|
||||
- no tabs EVER
|
||||
- match the existing indentation level
|
||||
|
||||
All ChaiScript commits are run through a large set of builds and analysis on all supported platforms. Those results are posted on the
|
||||
[build dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html). No PR will be accepted until all tests pass.
|
||||
|
||||
The build system has full integration with GitHub and you will be notified automatically if all tests have passed.
|
||||
|
||||
# Issues
|
||||
|
||||
Please do not post a "chaiscript is too slow", "chaiscript compiles too slowly", or "chaiscript needs more documentation" issue
|
||||
without first reading the following notes.
|
||||
|
||||
## ChaiScript is Too Slow
|
||||
|
||||
We are actively working on constently improving the runtime performance of ChaiScript. With the performance being
|
||||
[monitored with each commit](http://chaiscript.com/ChaiScript-BuildResults/performance.html).
|
||||
|
||||
If you feel you *must* post an issue about performance, please post a complete example that illustrates the exact case you
|
||||
feel should be better optimized.
|
||||
|
||||
Any issue request regarding performance without a complete example of the issue experienced will be closed.
|
||||
|
||||
## ChaiScript Compiles Too Slowly
|
||||
|
||||
This is also something we are actively working on. If you need highly optimized build times, please see [this discussion
|
||||
on the discourse site](http://discourse.chaiscript.com/t/slow-build-times/94).
|
||||
|
||||
## ChaiScript Needs More Documentation
|
||||
|
||||
If you have a question that is not addressed in the [cheatsheet](https://github.com/ChaiScript/ChaiScript/blob/develop/cheatsheet.md)
|
||||
please open an issue so we can get the Cheatsheet updated.
|
||||
10
.github/ISSUE_TEMPLATE.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
* Compiler Used:
|
||||
* Operating System:
|
||||
* Architecture (ARM/x86/32bit/64bit/etc):
|
||||
|
||||
|
||||
### Expected Behavior
|
||||
|
||||
### Actual Behavior
|
||||
|
||||
### Minimal Example to Reproduce Behavior
|
||||
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
Issue this pull request references: #
|
||||
|
||||
Changes proposed in this pull request
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
|
||||
73
.travis.yml
Normal file
73
.travis.yml
Normal file
@@ -0,0 +1,73 @@
|
||||
language: cpp
|
||||
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.9
|
||||
- g++-5
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "ChaiScript/ChaiScript"
|
||||
description: "Build submitted via Travis CI"
|
||||
notification_email: jason@emptycrate.com
|
||||
build_command_prepend: "cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug . "
|
||||
build_command: "cmake --build . -- -j2"
|
||||
branch_pattern: coverity_scan
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="4.9"
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="4.9" CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
sudo: false
|
||||
env: GCC_VER="5" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: clang
|
||||
osx_image: xcode8
|
||||
- os: osx
|
||||
compiler: clang
|
||||
osx_image: xcode8
|
||||
env: CMAKE_OPTIONS="-D DYNLOAD_ENABLED:BOOL=FALSE -D MULTITHREAD_SUPPORT_ENABLED:BOOL=FALSE -D USE_STD_MAKE_SHARED:BOOL=TRUE" BUILD_ONLY=1
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
- secure: "LfolGjP8tWm3yAwthfu3yp8Zn40aueFae580UUR34gusG87cyglq2tQDtxdy+63gWEeNfArbv9n5rZv+bDW3ggHyPjuCKKc1PlZAy07lfXUXf1uz+SFhNvNoYTn3mQG3VZ08o116p4Le2p8yqu4bylJ8wckEq7PrTwvSGVQWTWM="
|
||||
|
||||
before_install:
|
||||
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
|
||||
- pip install --user cpp-coveralls
|
||||
|
||||
script:
|
||||
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
|
||||
- cmake --build . -- -j2
|
||||
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; fi
|
||||
- if [ "${COVERAGE}" = "1" ]; then bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -x $GCOV -a "-s `pwd`" ; fi
|
||||
|
||||
#after_script:
|
||||
# - if [ ${CPPCHECK} = 1 ]; then contrib/codeanalysis/runcppcheck.sh ; fi
|
||||
|
||||
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- jason@emptycrate.com
|
||||
on_success: always
|
||||
on_failure: always
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/4be9a2720eaa1bb2a6c9
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
515
CMakeLists.txt
515
CMakeLists.txt
@@ -1,16 +1,96 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
|
||||
IF(BIICODE)
|
||||
INIT_BIICODE_BLOCK()
|
||||
ADD_BIICODE_TARGETS()
|
||||
ELSE()
|
||||
# Your regular CMakeLists configuration here
|
||||
|
||||
|
||||
project(chaiscript)
|
||||
|
||||
# MINGW does not yet support C++11's concurrency features
|
||||
if (MINGW)
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE)
|
||||
else()
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
|
||||
|
||||
|
||||
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE)
|
||||
option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE)
|
||||
option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE)
|
||||
|
||||
mark_as_advanced(USE_STD_MAKE_SHARED)
|
||||
|
||||
if(USE_STD_MAKE_SHARED)
|
||||
add_definitions(-DCHAISCRIPT_USE_STD_MAKE_SHARED)
|
||||
endif()
|
||||
|
||||
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
|
||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
|
||||
|
||||
if(ENABLE_COVERAGE)
|
||||
add_definitions(--coverage -O0)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} --coverage")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer testing in gcc/clang" FALSE)
|
||||
if(ENABLE_THREAD_SANITIZER)
|
||||
add_definitions(-fsanitize=thread -g)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=thread")
|
||||
endif()
|
||||
|
||||
option(ENABLE_ADDRESS_SANITIZER "Enable address sanitizer testing in gcc/clang" FALSE)
|
||||
if(ENABLE_ADDRESS_SANITIZER)
|
||||
add_definitions(-fsanitize=address -g)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=address")
|
||||
endif()
|
||||
|
||||
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
|
||||
if(ENABLE_MEMORY_SANITIZER)
|
||||
add_definitions(-fsanitize=memory -g)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory")
|
||||
endif()
|
||||
|
||||
option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE)
|
||||
if(ENABLE_UNDEFINED_SANITIZER)
|
||||
add_definitions(-fsanitize=undefined -g)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=undefined")
|
||||
endif()
|
||||
|
||||
option(ENABLE_LTO "Enable Link Time Optimization" FALSE)
|
||||
|
||||
if (ENABLE_LTO)
|
||||
add_definitions(-flto)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -flto")
|
||||
endif()
|
||||
|
||||
option(GPROF_OUTPUT "Generate profile data" FALSE)
|
||||
if (GPROF_OUTPUT)
|
||||
add_definitions(-pg)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -pg")
|
||||
endif()
|
||||
|
||||
|
||||
option(PROFILE_GENERATE "Generate profile data" FALSE)
|
||||
if (PROFILE_GENERATE)
|
||||
add_definitions(-fprofile-generate)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-generate")
|
||||
endif()
|
||||
|
||||
option(PROFILE_USE "Use profile data" FALSE)
|
||||
if (PROFILE_USE)
|
||||
add_definitions(-fprofile-use)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -fprofile-use")
|
||||
endif()
|
||||
|
||||
|
||||
endif()
|
||||
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
|
||||
@@ -22,8 +102,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt")
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 2)
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 6)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 0)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||
@@ -44,206 +124,337 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
|
||||
include(CTest)
|
||||
include(CPack)
|
||||
|
||||
include(cmake/CheckCXX11Features.cmake)
|
||||
|
||||
if(NOT MINGW)
|
||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||
endif()
|
||||
|
||||
if(HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
message(STATUS "Variadic Template support detected")
|
||||
else()
|
||||
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
|
||||
message(STATUS "Detecting readline support")
|
||||
if (READLINE_LIBRARY)
|
||||
message(STATUS "Found: ${READLINE_LIBRARY}")
|
||||
set (READLINE_LIB readline)
|
||||
add_definitions(/DREADLINE_AVAILABLE)
|
||||
else(READLINE_LIBRARY)
|
||||
message(STATUS "Not Found")
|
||||
set (READLINE_LIB )
|
||||
set (READLINE_FLAG )
|
||||
endif(READLINE_LIBRARY)
|
||||
if(READLINE_LIBRARY)
|
||||
message(STATUS "Found: ${READLINE_LIBRARY}")
|
||||
set(READLINE_LIB readline)
|
||||
add_definitions(/DREADLINE_AVAILABLE)
|
||||
else()
|
||||
message(STATUS "Not Found")
|
||||
set(READLINE_LIB)
|
||||
set(READLINE_FLAG)
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||
|
||||
if(GCC_VERSION VERSION_LESS 4.9)
|
||||
set(CPP11_FLAG "-std=c++1y")
|
||||
else()
|
||||
set(CPP11_FLAG "-std=c++14")
|
||||
endif()
|
||||
else()
|
||||
set(CPP11_FLAG "-std=c++14")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(/W4)
|
||||
if(CMAKE_CL_64)
|
||||
add_definitions(/bigobj)
|
||||
endif()
|
||||
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
||||
|
||||
if (MSVC_VERSION STREQUAL "1800")
|
||||
# VS2013 doesn't have magic statics
|
||||
add_definitions(/w44640)
|
||||
else()
|
||||
# enum warnings are too noisy on MSVC2013
|
||||
add_definitions(/w34062)
|
||||
endif()
|
||||
|
||||
add_definitions(/bigobj)
|
||||
# Note on MSVC compiler flags.
|
||||
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
||||
# about something that is perfectly valid, or there is simply no technical way around it
|
||||
# This particular warning, C4503 is in regards to the decorated names that MSVC generates internally.
|
||||
# The error did not come up until the move to C++11, but the compiler doesn't give enough information
|
||||
# to determine where the error is coming from, and the internet provides no real information for
|
||||
# how to workaround or fix the error. So I'm disabling it globally.
|
||||
add_definitions(/wd4503)
|
||||
else()
|
||||
add_definitions(-Wall -Wextra -Wshadow -pedantic -std=c++0x)
|
||||
|
||||
if (APPLE)
|
||||
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command)
|
||||
else()
|
||||
add_definitions(-Wnoexcept)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
add_definitions(-Wno-sign-compare)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER MATCHES ".*clang")
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
option(USE_LIBCXX "Use clang's libcxx" TRUE)
|
||||
|
||||
if (USE_LIBCXX)
|
||||
if(USE_LIBCXX)
|
||||
add_definitions(-stdlib=libc++)
|
||||
set (EXTRA_LINKER_FLAGS -std=c++0x -stdlib=libc++)
|
||||
else ()
|
||||
set (EXTRA_LINKER_FLAGS -std=c++0x )
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++")
|
||||
else()
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
|
||||
endif()
|
||||
else()
|
||||
set (EXTRA_LINKER_FLAGS )
|
||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} ${CPP11_FLAG}")
|
||||
endif()
|
||||
|
||||
# limitations in MinGW require us to make an optimized build
|
||||
# for the sake of object sizes or something
|
||||
if (MINGW)
|
||||
if(MINGW OR CYGWIN)
|
||||
add_definitions(-O3)
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
|
||||
|
||||
set (Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.chai include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp)
|
||||
set(Chai_INCLUDES include/chaiscript/chaiscript.hpp include/chaiscript/chaiscript_threading.hpp include/chaiscript/dispatchkit/bad_boxed_cast.hpp include/chaiscript/dispatchkit/bind_first.hpp include/chaiscript/dispatchkit/bootstrap.hpp include/chaiscript/dispatchkit/bootstrap_stl.hpp include/chaiscript/dispatchkit/boxed_cast.hpp include/chaiscript/dispatchkit/boxed_cast_helper.hpp include/chaiscript/dispatchkit/boxed_number.hpp include/chaiscript/dispatchkit/boxed_value.hpp include/chaiscript/dispatchkit/dispatchkit.hpp include/chaiscript/dispatchkit/type_conversions.hpp include/chaiscript/dispatchkit/dynamic_object.hpp include/chaiscript/dispatchkit/exception_specification.hpp include/chaiscript/dispatchkit/function_call.hpp include/chaiscript/dispatchkit/function_call_detail.hpp include/chaiscript/dispatchkit/handle_return.hpp include/chaiscript/dispatchkit/operators.hpp include/chaiscript/dispatchkit/proxy_constructors.hpp include/chaiscript/dispatchkit/proxy_functions.hpp include/chaiscript/dispatchkit/proxy_functions_detail.hpp include/chaiscript/dispatchkit/register_function.hpp include/chaiscript/dispatchkit/type_info.hpp include/chaiscript/language/chaiscript_algebraic.hpp include/chaiscript/language/chaiscript_common.hpp include/chaiscript/language/chaiscript_engine.hpp include/chaiscript/language/chaiscript_eval.hpp include/chaiscript/language/chaiscript_parser.hpp include/chaiscript/language/chaiscript_prelude.hpp include/chaiscript/language/chaiscript_prelude_docs.hpp include/chaiscript/utility/utility.hpp include/chaiscript/utility/json.hpp include/chaiscript/utility/json_wrap.hpp)
|
||||
|
||||
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
||||
else()
|
||||
if(NOT MULTITHREAD_SUPPORT_ENABLED)
|
||||
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
||||
endif()
|
||||
|
||||
if (CMAKE_HOST_UNIX)
|
||||
list(APPEND LIBS "dl")
|
||||
if(NOT DYNLOAD_ENABLED)
|
||||
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_UNIX)
|
||||
if(DYNLOAD_ENABLED)
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku")
|
||||
list(APPEND LIBS "dl")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE GCC_FULL_VERSION)
|
||||
if(GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu")
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--no-as-needed -pthread")
|
||||
else()
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
|
||||
endif()
|
||||
else()
|
||||
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
|
||||
endif()
|
||||
|
||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
||||
list(APPEND LIBS "pthread")
|
||||
add_definitions(-pthread)
|
||||
endif()
|
||||
endif(CMAKE_HOST_UNIX)
|
||||
|
||||
|
||||
endif()
|
||||
|
||||
list(APPEND LIBS ${READLINE_LIB})
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
|
||||
|
||||
if (CMAKE_COMPILER_2005)
|
||||
# vs2005 is a bit too loud about possible loss of data warnings
|
||||
# ADD_DEFINITIONS(/wd4244)
|
||||
endif()
|
||||
add_library(stdlib STATIC static_libs/chaiscript_stdlib.cpp)
|
||||
add_library(parser STATIC static_libs/chaiscript_parser.cpp)
|
||||
|
||||
add_library(chaiscript_stdlib MODULE src/chaiscript_stdlib.cpp)
|
||||
target_link_libraries(chaiscript_stdlib ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
|
||||
target_link_libraries(chaiscript_stdlib-${CHAI_VERSION} ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
set(CHAISCRIPT_LIBS stdlib parser)
|
||||
|
||||
add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||
target_link_libraries(chai ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_dependencies(chai chaiscript_stdlib)
|
||||
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
|
||||
if (BUILD_SAMPLES)
|
||||
if(BUILD_SAMPLES)
|
||||
add_executable(example samples/example.cpp)
|
||||
target_link_libraries(example ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
target_link_libraries(example ${LIBS})
|
||||
add_executable(test_num_exceptions samples/test_num_exceptions.cpp)
|
||||
target_link_libraries(test_num_exceptions ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(memory_leak_test samples/memory_leak_test.cpp)
|
||||
target_link_libraries(memory_leak_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
target_link_libraries(memory_leak_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(inheritance samples/inheritance.cpp)
|
||||
target_link_libraries(inheritance ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(factory samples/factory.cpp)
|
||||
target_link_libraries(factory ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_executable(fun_call_performance samples/fun_call_performance.cpp)
|
||||
target_link_libraries(fun_call_performance ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
endif()
|
||||
|
||||
|
||||
if (BUILD_MODULES)
|
||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||
target_link_libraries(stl_extra ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
if(BUILD_MODULES)
|
||||
add_library(test_module MODULE src/test_module.cpp)
|
||||
target_link_libraries(test_module ${LIBS})
|
||||
|
||||
add_library(reflection MODULE src/reflection.cpp)
|
||||
target_link_libraries(reflection ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
set(MODULES stl_extra reflection)
|
||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||
target_link_libraries(stl_extra ${LIBS})
|
||||
|
||||
set(MODULES stl_extra)
|
||||
endif()
|
||||
|
||||
file(GLOB UNIT_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/unittests/ ${CMAKE_CURRENT_SOURCE_DIR}/unittests/*.chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/3.x/*.chai)
|
||||
|
||||
list(SORT UNIT_TESTS)
|
||||
|
||||
file(GLOB PERFORMANCE_TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/ ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/*.chai)
|
||||
list(SORT PERFORMANCE_TESTS)
|
||||
|
||||
|
||||
if (RUN_FUZZY_TESTS)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/unittests")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzzy_tests-2016-06-29.tar.bz2
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||
)
|
||||
|
||||
|
||||
file(GLOB FUZZY_CRASH_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/id*)
|
||||
list(SORT FUZZY_CRASH_TESTS)
|
||||
|
||||
file(GLOB FUZZY_EXCEPTION_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/id*)
|
||||
list(SORT FUZZY_EXCEPTION_TESTS)
|
||||
|
||||
|
||||
foreach(filename ${FUZZY_CRASH_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai "-e" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/crashes/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${FUZZY_CRASH_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_BINARY_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
foreach(filename ${FUZZY_EXCEPTION_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai "--exception" ${CMAKE_BINARY_DIR}/unittests/fuzzy_tests/exceptions/unit_test.inc ${CMAKE_BINARY_DIR}/unittests/${filename})
|
||||
endforeach()
|
||||
|
||||
set_property(TEST ${FUZZY_EXCEPTION_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
# Add catch tests macro
|
||||
macro(ADD_CATCH_TESTS executable)
|
||||
if (MSVC)
|
||||
file(TO_NATIVE_PATH "${QT_LIBRARY_DIR}" QT_LIB_PATH)
|
||||
set(NEWPATH "${QT_LIB_PATH};$ENV{PATH}")
|
||||
else()
|
||||
set(NEWPATH $ENV{PATH})
|
||||
endif()
|
||||
|
||||
get_target_property(target_files ${executable} SOURCES)
|
||||
|
||||
foreach(source ${target_files})
|
||||
if(NOT "${source}" MATCHES "/moc_.*cxx")
|
||||
string(REGEX MATCH .*cpp source "${source}")
|
||||
if(source)
|
||||
file(READ "${source}" contents)
|
||||
string(REGEX MATCHALL "TEST_CASE\\([ ]*\"[^\"]+\"" found_tests ${contents})
|
||||
foreach(hit ${found_tests})
|
||||
string(REGEX REPLACE "TEST_CASE\\([ ]*(\"[^\"]+\").*" "\\1" test_name ${hit})
|
||||
add_test(compiled.${test_name} "${executable}" ${test_name})
|
||||
set_tests_properties(compiled.${test_name} PROPERTIES TIMEOUT 660 ENVIRONMENT "PATH=${NEWPATH}")
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
||||
|
||||
foreach(filename ${UNIT_TESTS})
|
||||
message(STATUS "Adding test ${filename}")
|
||||
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
||||
endforeach(filename)
|
||||
|
||||
set_property(TEST ${UNIT_TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
add_test(version_check chai -c "if(\"\\\${ version() };\\\${version_major()};\\\${version_minor()};\\\${version_patch()}\" != \"${CHAI_VERSION};${CPACK_PACKAGE_VERSION_MAJOR};${CPACK_PACKAGE_VERSION_MINOR};${CPACK_PACKAGE_VERSION_PATCH}\") { exit(-1) }")
|
||||
set_property(TEST version_check
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
if (NOT UNIT_TEST_LIGHT)
|
||||
add_executable(utility_test unittests/utility_test.cpp)
|
||||
target_link_libraries(utility_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Utility_Test COMMAND utility_test)
|
||||
add_test(version_check_2 chai --version )
|
||||
set_property(TEST version_check_2
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
|
||||
)
|
||||
|
||||
add_executable(dynamic_object_test unittests/dynamic_object_test.cpp)
|
||||
target_link_libraries(dynamic_object_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
|
||||
add_test(help chai --help )
|
||||
set_property(TEST help
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
add_executable(functor_creation_test unittests/functor_creation_test.cpp)
|
||||
target_link_libraries(functor_creation_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Functor_Creation_Test COMMAND functor_creation_test)
|
||||
|
||||
add_executable(functor_cast_test unittests/functor_cast_test.cpp)
|
||||
target_link_libraries(functor_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
|
||||
set(TESTS "")
|
||||
|
||||
foreach(filename ${UNIT_TESTS})
|
||||
message(STATUS "Adding unit test ${filename}")
|
||||
add_test(unit.${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
||||
list(APPEND TESTS unit.${filename})
|
||||
endforeach()
|
||||
|
||||
if (RUN_PERFORMANCE_TESTS)
|
||||
foreach(filename ${PERFORMANCE_TESTS})
|
||||
message(STATUS "Adding performance test ${filename}")
|
||||
|
||||
add_test(NAME performance.${filename} COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.${filename} $<TARGET_FILE:chai> ${CMAKE_CURRENT_SOURCE_DIR}/performance_tests/${filename})
|
||||
list(APPEND TESTS performance.${filename})
|
||||
endforeach()
|
||||
|
||||
add_executable(profile_cpp_calls_2 performance_tests/profile_cpp_calls_2.cpp)
|
||||
target_link_libraries(profile_cpp_calls_2 ${LIBS})
|
||||
add_test(NAME performance.profile_cpp_calls_2 COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_cpp_calls_2 $<TARGET_FILE:profile_cpp_calls_2>)
|
||||
|
||||
add_executable(profile_fun_wrappers performance_tests/profile_fun_wrappers.cpp)
|
||||
target_link_libraries(profile_fun_wrappers ${LIBS})
|
||||
add_test(NAME performance.profile_fun_wrappers COMMAND ${VALGRIND} --tool=callgrind --callgrind-out-file=callgrind.performance.profile_fun_wrappers $<TARGET_FILE:profile_fun_wrappers>)
|
||||
endif()
|
||||
|
||||
set_property(TEST ${TESTS}
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
|
||||
if(NOT UNIT_TEST_LIGHT)
|
||||
add_executable(compiled_tests unittests/compiled_tests.cpp)
|
||||
target_link_libraries(compiled_tests ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
ADD_CATCH_TESTS(compiled_tests)
|
||||
|
||||
add_executable(static_chaiscript_test unittests/static_chaiscript.cpp)
|
||||
target_link_libraries(static_chaiscript_test ${LIBS})
|
||||
add_test(NAME Static_ChaiScript_Test COMMAND static_chaiscript_test)
|
||||
|
||||
add_executable(boxed_cast_test unittests/boxed_cast_test.cpp)
|
||||
target_link_libraries(boxed_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
target_link_libraries(boxed_cast_test ${LIBS})
|
||||
add_test(NAME Boxed_Cast_Test COMMAND boxed_cast_test)
|
||||
|
||||
add_executable(object_lifetime_test unittests/object_lifetime_test.cpp)
|
||||
target_link_libraries(object_lifetime_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Object_Lifetime_Test COMMAND object_lifetime_test)
|
||||
|
||||
add_executable(function_ordering_test unittests/function_ordering_test.cpp)
|
||||
target_link_libraries(function_ordering_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Function_Ordering_Test COMMAND function_ordering_test)
|
||||
|
||||
add_executable(type_info_test unittests/type_info_test.cpp)
|
||||
target_link_libraries(type_info_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
target_link_libraries(type_info_test ${LIBS})
|
||||
add_test(NAME Type_Info_Test COMMAND type_info_test)
|
||||
|
||||
add_executable(eval_catch_exception_test unittests/eval_catch_exception_test.cpp)
|
||||
target_link_libraries(eval_catch_exception_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Eval_Catch_Exception_Test COMMAND eval_catch_exception_test)
|
||||
|
||||
add_executable(short_comparison_test unittests/short_comparison_test.cpp)
|
||||
target_link_libraries(short_comparison_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME Short_Comparison_Test COMMAND short_comparison_test)
|
||||
|
||||
add_executable(cpp_lambda_test unittests/cpp_lambda_test.cpp)
|
||||
target_link_libraries(cpp_lambda_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_test(NAME cpp_lambda_test COMMAND cpp_lambda_test)
|
||||
|
||||
add_executable(expected_eval_errors_test unittests/expected_eval_errors_test.cpp)
|
||||
target_link_libraries(expected_eval_errors_test ${LIBS})
|
||||
add_test(NAME Expected_Eval_Errors_Test COMMAND expected_eval_errors_test)
|
||||
|
||||
add_executable(set_state_test unittests/set_state_test.cpp)
|
||||
target_link_libraries(set_state_test ${LIBS})
|
||||
add_test(NAME Set_State_Test COMMAND set_state_test)
|
||||
|
||||
add_executable(simultaneous_chaiscript_test unittests/simultaneous_chaiscript_test.cpp)
|
||||
target_link_libraries(simultaneous_chaiscript_test ${LIBS})
|
||||
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_test)
|
||||
|
||||
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
||||
target_link_libraries(c_linkage_test ${LIBS})
|
||||
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
|
||||
|
||||
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
|
||||
target_link_libraries(integer_literal_test ${LIBS})
|
||||
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
|
||||
|
||||
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
|
||||
target_link_libraries(arithmetic_conversions_test ${LIBS})
|
||||
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
|
||||
|
||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
||||
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
|
||||
target_link_libraries(multithreaded_test ${LIBS})
|
||||
add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
|
||||
@@ -251,42 +462,46 @@ if(BUILD_TESTING)
|
||||
PROPERTY ENVIRONMENT
|
||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||
)
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
|
||||
unittests/multifile_test_module.cpp)
|
||||
target_link_libraries(multifile_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
add_executable(multifile_test
|
||||
unittests/multifile_test_main.cpp
|
||||
unittests/multifile_test_chai.cpp
|
||||
unittests/multifile_test_module.cpp
|
||||
)
|
||||
target_link_libraries(multifile_test ${LIBS})
|
||||
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
||||
|
||||
add_library(test_module MODULE src/test_module.cpp)
|
||||
target_link_libraries(test_module ${LIBS} ${EXTRA_LINKER_FLAGS})
|
||||
|
||||
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||
endif()
|
||||
endif(BUILD_TESTING)
|
||||
endif()
|
||||
|
||||
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
||||
|
||||
install(TARGETS chai ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
|
||||
install(DIRECTORY include/chaiscript DESTINATION include
|
||||
PATTERN "*.hpp"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
PATTERN "*.hpp"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
install(DIRECTORY unittests DESTINATION share/chaiscript
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*.inc"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
install(DIRECTORY samples DESTINATION share/chaiscript
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
PATTERN "*.chai"
|
||||
PATTERN "*/.svn*" EXCLUDE
|
||||
PATTERN "*/.git*" EXCLUDE
|
||||
PATTERN "*~" EXCLUDE)
|
||||
|
||||
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
|
||||
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
||||
DESTINATION lib/pkgconfig)
|
||||
|
||||
|
||||
ENDIF()
|
||||
|
||||
|
||||
28
DesignGoals.md
Normal file
28
DesignGoals.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Introduction
|
||||
|
||||
This document outlines the principles that drive the development of ChaiScript. ChaiScript does not intent to be the perfect tool for *every* situation, but it does intend to be a good general purpose tool for *most* situations.
|
||||
|
||||
# Goals
|
||||
|
||||
1. Trivially easy to integrate with C++ projects
|
||||
2. 0 external depenencies
|
||||
3. "Perfect" integration with C++
|
||||
* Direct mapping between ChaiScript objects and C++ objects
|
||||
* Direct mapping between ChaiScript functions and C++ functions
|
||||
* Direct mapping between ChaiScript exceptions and C++ exceptions
|
||||
3. Never surprise the C++ developer
|
||||
* Object lifetimes managed by the stack
|
||||
* Familiar syntax to C++ developers
|
||||
4. Perform "well enough" to not get in the way
|
||||
|
||||
|
||||
# Alternatives
|
||||
|
||||
## Sol2
|
||||
|
||||
If you are looking for the fastest performing scripting language and don't mind Lua, you might want to consider [sol2](https://github.com/ThePhD/sol2).
|
||||
|
||||
## SWIG
|
||||
|
||||
If you are looking for the most flexible solution to be able to support multiple target languages, consider [SWIG](http://swig.org)
|
||||
|
||||
1861
Doxyfile.in
1861
Doxyfile.in
File diff suppressed because it is too large
Load Diff
29
LICENSE
Normal file
29
LICENSE
Normal file
@@ -0,0 +1,29 @@
|
||||
Copyright 2009-2016 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
|
||||
All Rights Reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Jason Turner nor Jonathan Turner nor the
|
||||
name of contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
22
appveyor.yml
Normal file
22
appveyor.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
version: 5.8.x.{build}
|
||||
os: Visual Studio 2015
|
||||
environment:
|
||||
matrix:
|
||||
- {}
|
||||
build_script:
|
||||
- cmd: >-
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
cmake c:\Projects\chaiscript -G "Visual Studio 14"
|
||||
|
||||
cmake --build . --config Debug
|
||||
test_script:
|
||||
- cmd: ctest -C Debug
|
||||
notifications:
|
||||
- provider: Webhook
|
||||
url: https://webhooks.gitter.im/e/9ff725a985b5679d1d5d
|
||||
on_build_success: true
|
||||
on_build_failure: true
|
||||
on_build_status_changed: false
|
||||
5
biicode.conf
Normal file
5
biicode.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
[paths]
|
||||
include
|
||||
|
||||
[parent]
|
||||
ChaiScript/ChaiScript: 0
|
||||
552
cheatsheet.md
Normal file
552
cheatsheet.md
Normal file
@@ -0,0 +1,552 @@
|
||||
# ChaiScript Versioning
|
||||
|
||||
ChaiScript tries to follow the [Semantic Versioning](http://semver.org/) scheme. This basically means:
|
||||
|
||||
* Major Version Number: API changes / breaking changes
|
||||
* Minor Version Number: New Features
|
||||
* Patch Version Number: Minor changes / enhancements
|
||||
|
||||
|
||||
|
||||
# Initializing ChaiScript
|
||||
|
||||
```
|
||||
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
|
||||
```
|
||||
|
||||
# Adding Things To The Engine
|
||||
|
||||
## Adding a Function / Method / Member
|
||||
|
||||
### General
|
||||
|
||||
```
|
||||
chai.add(chaiscript::fun(&function_name), "function_name");
|
||||
chai.add(chaiscript::fun(&Class::method_name), "method_name");
|
||||
chai.add(chaiscript::fun(&Class::member_name), "member_name");
|
||||
```
|
||||
|
||||
### Bound Member Functions
|
||||
|
||||
```
|
||||
chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name");
|
||||
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
|
||||
```
|
||||
|
||||
### With Overloads
|
||||
|
||||
#### Preferred
|
||||
|
||||
```
|
||||
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
|
||||
```
|
||||
|
||||
#### Alternative
|
||||
|
||||
```
|
||||
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
|
||||
```
|
||||
This overload technique is also used when exposing base member using derived type
|
||||
|
||||
```
|
||||
struct Base
|
||||
{
|
||||
int data;
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{};
|
||||
|
||||
chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
|
||||
```
|
||||
|
||||
### Lambda
|
||||
|
||||
```
|
||||
chai.add(
|
||||
chaiscript::fun<std::string (bool)>(
|
||||
[](bool type) {
|
||||
if (type) { return "x"; }
|
||||
else { return "y"; }
|
||||
}), "function_name");
|
||||
```
|
||||
|
||||
### Constructors
|
||||
|
||||
```
|
||||
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
|
||||
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
|
||||
```
|
||||
|
||||
## Adding Types
|
||||
|
||||
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
|
||||
|
||||
```
|
||||
chai.add(chaiscript::user_type<MyClass>(), "MyClass");
|
||||
```
|
||||
|
||||
## Adding Type Conversions
|
||||
|
||||
User defined type conversions are possible, defined in either script or in C++.
|
||||
|
||||
|
||||
|
||||
### ChaiScript Defined Conversions
|
||||
|
||||
Function objects (including lambdas) can be used to add type conversions
|
||||
from inside of ChaiScript:
|
||||
|
||||
```
|
||||
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
|
||||
```
|
||||
|
||||
### C++ Defined Conversions
|
||||
|
||||
Invoking a C++ type conversion possible with `static_cast`
|
||||
|
||||
```
|
||||
chai.add(chaiscript::type_conversion<T, bool>());
|
||||
```
|
||||
|
||||
Calling a user defined type conversion that takes a lambda
|
||||
|
||||
```
|
||||
chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
|
||||
```
|
||||
|
||||
### Class Hierarchies
|
||||
|
||||
If you want objects to be convertable between base and derived classes, you must tell ChaiScritp about the relationship.
|
||||
|
||||
```
|
||||
chai.add(chaiscript::base_class<Base, Derived>());
|
||||
```
|
||||
|
||||
If you have multiple classes in your inheritance graph, you will probably want to tell ChaiScript about all relationships.
|
||||
|
||||
```
|
||||
chai.add(chaiscript::base_class<Base, Derived>());
|
||||
chai.add(chaiscript::base_class<Derived, MoreDerived>());
|
||||
chai.add(chaiscript::base_class<Base, MoreDerived>());
|
||||
```
|
||||
|
||||
### Helpers
|
||||
|
||||
A helper function exists for strongly typed and ChaiScript `Vector` function conversion definition:
|
||||
|
||||
```
|
||||
chai.add(chaiscript::vector_conversion<std::vector<int>>());
|
||||
```
|
||||
|
||||
A helper function also exists for strongly typed and ChaiScript `Map` function conversion definition:
|
||||
|
||||
```
|
||||
chai.add(chaiscript::map_conversion<std::map<std::string, int>>());
|
||||
```
|
||||
|
||||
|
||||
|
||||
This allows you to pass a ChaiScript function to a function requiring `std::vector<int>`
|
||||
|
||||
## Adding Objects
|
||||
|
||||
```
|
||||
chai.add(chaiscript::var(somevar), "somevar"); // copied in
|
||||
chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared between C++ and chai
|
||||
auto shareddouble = std::make_shared<double>(4.3);
|
||||
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
|
||||
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
|
||||
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const, throws if object exists
|
||||
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const, throws if object exists
|
||||
chai.set_global(chaiscript::var(somevar), "somevar"); // global non-const, overwrites existing object
|
||||
```
|
||||
|
||||
# Using STL
|
||||
ChaiScript recognize many types from STL, but you have to add specific instantiation yourself.
|
||||
|
||||
```
|
||||
typedef std::vector<std::pair<int, std::string>> data_list;
|
||||
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
|
||||
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
|
||||
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
|
||||
chai.add(chaiscript::var(&my_list), "data_list");
|
||||
chai.eval(R"_(
|
||||
for(var i=0; i<data_list.size(); ++i)
|
||||
{
|
||||
print(to_string(data_list[i].first) + " " + data_list[i].second)
|
||||
}
|
||||
)_");
|
||||
```
|
||||
|
||||
# Executing Script
|
||||
|
||||
## General
|
||||
|
||||
```
|
||||
chai.eval("print(\"Hello World\")");
|
||||
chai.eval(R"(print("Hello World"))");
|
||||
```
|
||||
|
||||
## Unboxing Return Values
|
||||
|
||||
Returns values are of the type `Boxed_Value` which is meant to be opaque to the programmer. Use one of the unboxing methods to access the internal data.
|
||||
|
||||
### Prefered
|
||||
|
||||
```
|
||||
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
|
||||
```
|
||||
|
||||
### Alternative
|
||||
|
||||
```
|
||||
auto v = chai.eval("5.3 + 2.1");
|
||||
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions
|
||||
chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
|
||||
```
|
||||
|
||||
### Converting Between Algebraic Types
|
||||
|
||||
```
|
||||
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type
|
||||
// which is equivalent to, but much more automatic than:
|
||||
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
|
||||
```
|
||||
|
||||
### Conversion Caveats
|
||||
|
||||
Conversion to `std::shared_ptr<T> &` is supported for function calls, but if you attempt to keep a reference to a `shared_ptr<>` you might invoke undefined behavior
|
||||
|
||||
```cpp
|
||||
// ok this is supported, you can register it with chaiscript engine
|
||||
void nullify_shared_ptr(std::shared_ptr<int> &t) {
|
||||
t = nullptr
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
int main()
|
||||
{
|
||||
// do some stuff and create a chaiscript instance
|
||||
std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
|
||||
// DO NOT do this. Taking a non-const reference to a shared_ptr is not
|
||||
// supported and causes undefined behavior in the chaiscript engine
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Sharing Values
|
||||
|
||||
```
|
||||
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script
|
||||
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
|
||||
|
||||
d = 3;
|
||||
chai.eval("print(i)"); // prints 3
|
||||
```
|
||||
|
||||
## Catching Eval Errors
|
||||
|
||||
```
|
||||
try {
|
||||
chai.eval("2.3 + \"String\"");
|
||||
} catch (const chaiscript::exception::eval_error &e) {
|
||||
std::cout << "Error\n" << e.pretty_print() << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
## Catching Errors Thrown From Script
|
||||
|
||||
```
|
||||
try {
|
||||
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||
} catch (const double e) {
|
||||
} catch (int) {
|
||||
} catch (float) {
|
||||
} catch (const std::string &) {
|
||||
} catch (const std::exception &e) {
|
||||
// This is the one what will be called in the specific throw() above
|
||||
}
|
||||
```
|
||||
|
||||
## Sharing Functions
|
||||
|
||||
|
||||
```
|
||||
auto p = chai.eval<std::function<std::string (double)>>("to_string");
|
||||
p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
|
||||
```
|
||||
|
||||
Note: backtick treats operators as normal functions
|
||||
|
||||
```
|
||||
auto p = chai.eval<std::function<int (int, int)>>(`+`);
|
||||
p(5, 6); // calls chaiscript's '+' function, returning 11
|
||||
```
|
||||
|
||||
```
|
||||
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }");
|
||||
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
|
||||
```
|
||||
|
||||
# Language Reference
|
||||
|
||||
## Variables
|
||||
|
||||
```
|
||||
var i; // uninitialized variable, can take any value on first assignment;
|
||||
auto j; // equiv to var
|
||||
|
||||
var k = 5; // initialized to 5 (integer)
|
||||
var l := k; // reference to k
|
||||
auto &m = k; // reference to k
|
||||
|
||||
global g = 5; // creates a global variable. If global already exists, it is not re-added
|
||||
global g = 2; // global 'g' now equals 2
|
||||
|
||||
global g2;
|
||||
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once
|
||||
|
||||
GLOBAL g3; // all upper case version also accepted
|
||||
```
|
||||
|
||||
## Looping
|
||||
|
||||
```
|
||||
// c-style for loops
|
||||
for (var i = 0; i < 100; ++i) { print(i); }
|
||||
```
|
||||
|
||||
```
|
||||
// while
|
||||
while (some_condition()) { /* do something */ }
|
||||
```
|
||||
|
||||
```
|
||||
// ranged for
|
||||
for (x : [1,2,3]) { print(i); }
|
||||
```
|
||||
|
||||
Each of the loop styles can be broken using the `break` statement. For example:
|
||||
|
||||
```
|
||||
while (some_condition()) {
|
||||
/* do something */
|
||||
if (another_condition()) { break; }
|
||||
}
|
||||
```
|
||||
|
||||
## Conditionals
|
||||
|
||||
```
|
||||
if (expression) { }
|
||||
```
|
||||
|
||||
```
|
||||
// C++17-style init-if blocks
|
||||
// Value of 'statement' is scoped for entire `if` block
|
||||
if (statement; expression) { }
|
||||
```
|
||||
|
||||
## Built in Types
|
||||
|
||||
```
|
||||
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
|
||||
var m = ["a":1, "b":2]; // map of string:value pairs
|
||||
```
|
||||
|
||||
Floating point values default to `double` type and integers default to `int` type. All C++ suffixes
|
||||
such as `f`, `ll`, `u` as well as scientific notation are supported
|
||||
|
||||
```
|
||||
1.0 // double
|
||||
1.0f // float
|
||||
1.0l // long double
|
||||
1 // int
|
||||
1u // unsigned int
|
||||
1ul // unsigned long
|
||||
1ull // unsigned long long
|
||||
```
|
||||
|
||||
Literals are automatically sized, just as in C++. For example: `10000000000` is > 32bits and the appropriate type is used to hold it
|
||||
on your platform.
|
||||
|
||||
|
||||
## Functions
|
||||
|
||||
Note that any type of ChaiScript function can be passed freely to C++ and automatically
|
||||
converted into an `std::function` object.
|
||||
|
||||
### General
|
||||
|
||||
```
|
||||
def myfun(x, y) { x + y; } // last statement in body is the return value
|
||||
def myfun(x, y) { return x + y; } // equiv
|
||||
```
|
||||
|
||||
### Optionally Typed
|
||||
|
||||
```
|
||||
def myfun(x, int y) { x + y; } // requires y to be an int
|
||||
```
|
||||
|
||||
### With Guards
|
||||
|
||||
```
|
||||
def myfun(x, int y) : y > 5 { x - y; } // only called if y > 5
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
Methods and functions are mostly equivalent
|
||||
|
||||
```
|
||||
def string::add(int y) { this + to_string(y); }
|
||||
def add(string s, int y) { s + to_string(y); } //equiv functionality
|
||||
|
||||
// calling new function/method
|
||||
"a".add(1); // returns a1
|
||||
add("a", 1); // returns a1, either calling syntax works with either def above
|
||||
```
|
||||
|
||||
### Lambdas
|
||||
|
||||
```
|
||||
var l = fun(x) { x * 15; }
|
||||
l(2) // returns 30
|
||||
|
||||
var a = 13
|
||||
var m = fun[a](x) { x * a; }
|
||||
m(3); // a was captured (by reference), returns 39
|
||||
|
||||
var n = bind(fun(x,y) { x * y; }, _, 10);
|
||||
n(2); // returns 20
|
||||
```
|
||||
|
||||
|
||||
|
||||
## ChaiScript Defined Types
|
||||
|
||||
Define a type called "MyType" with one member value "a" and a getter
|
||||
|
||||
### Preferred
|
||||
|
||||
```
|
||||
class MyType {
|
||||
var value;
|
||||
def MyType() { this.value = "a"; }
|
||||
def get_value() { "Value Is: " + this.value; }
|
||||
};
|
||||
```
|
||||
|
||||
### Alternative
|
||||
|
||||
```
|
||||
attr MyType::value;
|
||||
def MyType::MyType() { this.value = "a"; }
|
||||
def MyType::get_value() { "Value Is: " + this.value; }
|
||||
```
|
||||
|
||||
### Using
|
||||
|
||||
```
|
||||
var m = MyType(); // calls constructor
|
||||
print(m.get_value()); // prints "Value Is: a"
|
||||
print(get_value(m)); // prints "Value Is: a"
|
||||
```
|
||||
|
||||
## Dynamic Objects
|
||||
|
||||
All ChaiScript defined types and generic Dynamic_Object support dynamic parameters
|
||||
|
||||
```
|
||||
var o = Dynamic_Object();
|
||||
o.f = fun(x) { print(x); }
|
||||
o.f(3); // prints "3"
|
||||
```
|
||||
|
||||
Implicit 'this' is allowed:
|
||||
|
||||
```
|
||||
var o = Dynamic_Object();
|
||||
o.x = 3;
|
||||
o.f = fun(y) { print(this.x + y); }
|
||||
o.f(10); // prints 13
|
||||
```
|
||||
|
||||
### Option Explicit
|
||||
|
||||
If you want to disable dynamic parameter definitions, you can `set_explicit`.
|
||||
|
||||
```
|
||||
class My_Class {
|
||||
def My_Class() {
|
||||
this.set_explicit(true);
|
||||
this.x = 2; // this would fail with explicit set to true
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## method_missing
|
||||
|
||||
A function of the signature `method_missing(object, name, param1, param2, param3)` will be called if an appropriate
|
||||
method cannot be found
|
||||
|
||||
```
|
||||
def method_missing(int i, string name, Vector v) {
|
||||
print("method_missing(${i}, ${name}), ${v.size()} params");
|
||||
}
|
||||
|
||||
5.bob(1,2,3); // prints "method_missing(5, bob, 3 params)"
|
||||
```
|
||||
|
||||
`method_missing` signature can be either 2 parameters or 3 parameters. If the signature contains two parameters
|
||||
it is treated as a property. If the property contains a function then additional parameters are passed to
|
||||
the contained function.
|
||||
|
||||
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
|
||||
|
||||
## Context
|
||||
|
||||
* `__LINE__` Current file line number
|
||||
* `__FILE__` Full path of current file
|
||||
* `__CLASS__` Name of current class
|
||||
* `__FUNC__` Mame of current function
|
||||
|
||||
|
||||
# Built In Functions
|
||||
|
||||
## Disabling Built-Ins
|
||||
|
||||
When constructing a ChaiScript object, a vector of parameters can be passed in to disable or enable various built-in methods.
|
||||
|
||||
Current options:
|
||||
|
||||
```
|
||||
enum class Options
|
||||
{
|
||||
Load_Modules,
|
||||
No_Load_Modules,
|
||||
External_Scripts,
|
||||
No_External_Scripts
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Evaluation
|
||||
|
||||
```
|
||||
eval("4 + 5") // dynamically eval script string and returns value of last statement
|
||||
eval_file("filename") // evals file and returns value of last statement
|
||||
use("filename") // evals file exactly once and returns value of last statement
|
||||
// if the file had already been 'used' nothing happens and undefined is returned
|
||||
```
|
||||
|
||||
Both `use` and `eval_file` search the 'usepaths' passed to the ChaiScript constructor
|
||||
|
||||
## JSON
|
||||
|
||||
* `from_json` converts a JSON string into its strongly typed (map, vector, int, double, string) representations
|
||||
* `to_json` converts a ChaiScript object (either a `Object` or one of map, vector, int, double, string) tree into its JSON string representation
|
||||
@@ -1,103 +0,0 @@
|
||||
# Checks for C++11 features
|
||||
# CXX11_FEATURE_LIST - a list containing all supported features
|
||||
# HAS_CXX11_AUTO - auto keyword
|
||||
# HAS_CXX11_NULLPTR - nullptr
|
||||
# HAS_CXX11_LAMBDA - lambdas
|
||||
# HAS_CXX11_STATIC_ASSERT - static_assert()
|
||||
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
|
||||
# HAS_CXX11_DECLTYPE - decltype keyword
|
||||
# HAS_CXX11_CSTDINT_H - cstdint header
|
||||
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
|
||||
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
|
||||
# HAS_CXX11_CONSTEXPR - constexpr keyword
|
||||
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
|
||||
# HAS_CXX11_FUNC - __func__ preprocessor constant
|
||||
#
|
||||
# Original script by Rolf Eike Beer
|
||||
# Modifications by Andreas Weis
|
||||
#
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
|
||||
|
||||
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||
endif()
|
||||
|
||||
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
|
||||
IF (NOT DEFINED ${RESULT_VAR})
|
||||
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
|
||||
|
||||
IF (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
|
||||
ELSE (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
|
||||
ENDIF (${FEATURE_NUMBER})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
|
||||
|
||||
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
|
||||
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
|
||||
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
|
||||
|
||||
IF (CROSS_COMPILING)
|
||||
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ELSE (CROSS_COMPILING)
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}" "${_SRCFILE}")
|
||||
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ENDIF (CROSS_COMPILING)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
|
||||
IF (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ELSE (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ENDIF (_TMP_RESULT)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
|
||||
IF (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
|
||||
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
|
||||
ELSE (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
|
||||
ENDIF (${RESULT_VAR})
|
||||
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
|
||||
ENDIF (NOT DEFINED ${RESULT_VAR})
|
||||
ENDMACRO(CXX11_CHECK_FEATURE)
|
||||
|
||||
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
|
||||
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
|
||||
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
|
||||
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
|
||||
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
|
||||
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
|
||||
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
|
||||
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
|
||||
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
|
||||
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
|
||||
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
|
||||
|
||||
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
|
||||
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
|
||||
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
if (!__func__) { return 1; }
|
||||
if(std::strlen(__func__) <= 0) { return 1; }
|
||||
return 0;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
auto i = 5;
|
||||
auto f = 3.14159f;
|
||||
auto d = 3.14159;
|
||||
bool ret = (
|
||||
(sizeof(f) < sizeof(d)) &&
|
||||
(sizeof(i) == sizeof(int))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
constexpr int square(int x)
|
||||
{
|
||||
return x*x;
|
||||
}
|
||||
|
||||
constexpr int the_answer()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int test_arr[square(3)];
|
||||
bool ret = (
|
||||
(square(the_answer()) == 1764) &&
|
||||
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <cstdint>
|
||||
int main()
|
||||
{
|
||||
bool test =
|
||||
(sizeof(int8_t) == 1) &&
|
||||
(sizeof(int16_t) == 2) &&
|
||||
(sizeof(int32_t) == 4) &&
|
||||
(sizeof(int64_t) == 8);
|
||||
return test ? 0 : 1;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
bool check_size(int i)
|
||||
{
|
||||
return sizeof(int) == sizeof(decltype(i));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ret = check_size(42);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
return ([&ret]() -> int { return ret; })();
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
int main(void)
|
||||
{
|
||||
long long l;
|
||||
unsigned long long ul;
|
||||
|
||||
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
int* test = nullptr;
|
||||
return test ? 1 : 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
int i = nullptr;
|
||||
return 1;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
int foo(int& lvalue)
|
||||
{
|
||||
return 123;
|
||||
}
|
||||
|
||||
int foo(int&& rvalue)
|
||||
{
|
||||
return 321;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i = 42;
|
||||
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
struct foo {
|
||||
char bar;
|
||||
int baz;
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bool ret = (
|
||||
(sizeof(foo::bar) == 1) &&
|
||||
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
|
||||
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
static_assert(0 < 1, "your ordering of integers is screwed");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
int main()
|
||||
{
|
||||
static_assert(1 < 0, "this should fail");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
int Accumulate()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
int Accumulate(T v, Ts... vs)
|
||||
{
|
||||
return v + Accumulate(vs...);
|
||||
}
|
||||
|
||||
template<int... Is>
|
||||
int CountElements()
|
||||
{
|
||||
return sizeof...(Is);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int acc = Accumulate(1, 2, 3, 4, -5);
|
||||
int count = CountElements<1,2,3,4,5>();
|
||||
return ((acc == 5) && (count == 5)) ? 0 : 1;
|
||||
}
|
||||
11
contrib/check_for_tabs.rb
Executable file
11
contrib/check_for_tabs.rb
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
|
||||
`grep -rPIHn '\t' src/* include/* samples/*`.lines { |line|
|
||||
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
|
||||
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "tab_checker", :message => "Source Code Line Contains Tabs", :messagetype => "warning"}))
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
11
contrib/check_for_todos.rb
Executable file
11
contrib/check_for_todos.rb
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
|
||||
`grep -rPIHni 'todo' src/* include/* samples/*`.lines { |line|
|
||||
if /(?<filename>.+(hpp|cpp|chai)):(?<linenumber>[0-9]+):(?<restofline>.+)/ =~ line
|
||||
puts(JSON.dump({:line => linenumber, :filename => filename, :tool => "todo_checker", :message => "todo: #{restofline.strip}", :messagetype => "info"}))
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
61
contrib/codeanalysis/fuzzy_tests/chaiscript.dict
Normal file
61
contrib/codeanalysis/fuzzy_tests/chaiscript.dict
Normal file
@@ -0,0 +1,61 @@
|
||||
# My dict
|
||||
|
||||
|
||||
for="for"
|
||||
while="while"
|
||||
def="def"
|
||||
fun="fun"
|
||||
if="if"
|
||||
else="else"
|
||||
and="&&"
|
||||
or="||"
|
||||
auto="auto"
|
||||
var="var"
|
||||
begin_block="{"
|
||||
end_block="}"
|
||||
empty_vec="[]"
|
||||
string="string"
|
||||
vector="Vector"
|
||||
map="Map"
|
||||
return="return"
|
||||
break="break"
|
||||
true="true"
|
||||
false="false"
|
||||
class="class"
|
||||
attr="attr"
|
||||
var="var"
|
||||
global="global"
|
||||
empty_lambda=" fun(){} "
|
||||
empty_fun=" def empty_fun() {} "
|
||||
continue="continue"
|
||||
float=" 1.1f "
|
||||
double=" 2.2 "
|
||||
long_double=" 2.2ll "
|
||||
unsigned=" 3u "
|
||||
unsigned_long=" 4ul "
|
||||
unsigned_long_long=" 4ull "
|
||||
long_long=" 5ll "
|
||||
attr="attr"
|
||||
reference_del="auto &"
|
||||
int8=" int8_t(1) "
|
||||
int16=" int16_t(2) "
|
||||
int32=" int32_t(3) "
|
||||
int64=" int64_t(4) "
|
||||
uint8=" uint8_t(1) "
|
||||
uint16=" uint16_t(2) "
|
||||
uint32=" uint32_t(3) "
|
||||
uint64=" uint64_t(4) "
|
||||
int8t="int8_t"
|
||||
int16t="int16_t"
|
||||
int32t="int32_t"
|
||||
int64t="int64_t"
|
||||
uint8t="uint8_t"
|
||||
uint16t="uint16_t"
|
||||
uint32t="uint32_t"
|
||||
uint64t="uint64_t"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
17
contrib/codeanalysis/fuzzy_tests/notes.txt
Normal file
17
contrib/codeanalysis/fuzzy_tests/notes.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
Command line used to find this crash:
|
||||
|
||||
../../Downloads/afl-1.80b/afl-fuzz -i- -o findings -x chaiscript.dict -- ../a.out unit_test.inc @@
|
||||
|
||||
If you can't reproduce a bug outside of afl-fuzz, be sure to set the same
|
||||
memory limit. The limit used for this fuzzing session was 50.0 MB.
|
||||
|
||||
Need a tool to minimize test cases before investigating the crashes or sending
|
||||
them to a vendor? Check out the afl-tmin that comes with the fuzzer!
|
||||
|
||||
Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop
|
||||
me a mail at <lcamtuf@coredump.cx> once the issues are fixed - I'd love to
|
||||
add your finds to the gallery at:
|
||||
|
||||
http://lcamtuf.coredump.cx/afl/
|
||||
|
||||
Thanks :-)
|
||||
5
contrib/codeanalysis/fuzzy_tests/use.inc
Normal file
5
contrib/codeanalysis/fuzzy_tests/use.inc
Normal file
@@ -0,0 +1,5 @@
|
||||
def greet {
|
||||
return("hello")
|
||||
}
|
||||
|
||||
fun(){ "world" }
|
||||
16
contrib/codeanalysis/runcppcheck.sh
Executable file
16
contrib/codeanalysis/runcppcheck.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
pushd ..
|
||||
wget http://sourceforge.net/projects/cppcheck/files/cppcheck/1.66/cppcheck-1.66.tar.bz2
|
||||
tar -xvf cppcheck-1.66.tar.bz2
|
||||
cd cppcheck-1.66
|
||||
make -j2
|
||||
popd
|
||||
../cppcheck-1.66/cppcheck --enable=all -I include --inline-suppr --suppress=missingIncludeSystem --std=c++11 --platform=unix64 src/main.cpp src/chai*.cpp --template ' - __{severity}__: [{file}:{line}](../blob/TRAVIS_COMMIT/{file}#L{line}) {message} ({id})' 2>output
|
||||
sed -i "s/TRAVIS_COMMIT/${TRAVIS_COMMIT}/g" output
|
||||
echo -n '{ "body": " ' > output.json
|
||||
echo -n `awk '{printf "%s\\\\n", $0;}' output` >> output.json
|
||||
echo -n '"}' >> output.json
|
||||
if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then curl -H "Authorization: token ${TOKEN}" --request POST --data @output.json https://api.github.com/repos/ChaiScript/ChaiScript/commits/${TRAVIS_COMMIT}/comments; else curl -H "Authorization: token ${TOKEN}" --request POST --data @output.json https://api.github.com/repos/ChaiScript/ChaiScript/issues/${TRAVIS_PULL_REQUEST}/comments; fi
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
************************************************************************************/
|
||||
|
||||
$language_data = array (
|
||||
'LANG_NAME' => 'Chaiscript',
|
||||
'LANG_NAME' => 'ChaiScript',
|
||||
'COMMENT_SINGLE' => array(1 => '//'),
|
||||
'COMMENT_MULTI' => array('/*' => '*/'),
|
||||
//Regular Expressions
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_HPP_
|
||||
#define CHAISCRIPT_HPP_
|
||||
|
||||
|
||||
|
||||
/// \mainpage
|
||||
/// <a href="http://www.chaiscript.com">ChaiScript</a> is a scripting language designed specifically for integration with C++. It provides
|
||||
/// @mainpage
|
||||
/// [ChaiScript](http://www.chaiscript.com") is a scripting language designed specifically for integration with C++. It provides
|
||||
/// seamless integration with C++ on all levels, including shared_ptr objects, functors and exceptions.
|
||||
///
|
||||
/// The parts of the ChaiScript API that the average user will be concerned with are contained in the
|
||||
@@ -18,42 +22,42 @@
|
||||
///
|
||||
/// The end user parts of the API are extremely simple both in size and ease of use.
|
||||
///
|
||||
/// Currently, all source control and project management aspects of ChaiScript occur on <a href="http://www.github.com/ChaiScript/ChaiScript">github</a>.
|
||||
/// Currently, all source control and project management aspects of ChaiScript occur on [github](http://www.github.com/ChaiScript/ChaiScript").
|
||||
///
|
||||
/// <hr>
|
||||
/// ------------------------------------------------------------
|
||||
///
|
||||
/// \sa chaiscript
|
||||
/// \sa chaiscript::ChaiScript
|
||||
/// \sa ChaiScript_Language for Built in Functions
|
||||
/// \sa \ref LangGettingStarted
|
||||
/// \sa \ref LangKeywordRef
|
||||
/// \sa \ref LangInPlaceRef
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
/// \sa http://www.chaiscript.com
|
||||
/// \sa http://www.github.com/ChaiScript/ChaiScript
|
||||
/// @sa chaiscript
|
||||
/// @sa chaiscript::ChaiScript
|
||||
/// @sa ChaiScript_Language for Built in Functions
|
||||
/// @sa @ref LangGettingStarted
|
||||
/// @sa @ref LangKeywordRef
|
||||
/// @sa @ref LangInPlaceRef
|
||||
/// @sa @ref LangObjectSystemRef
|
||||
/// @sa http://www.chaiscript.com
|
||||
/// @sa http://www.github.com/ChaiScript/ChaiScript
|
||||
///
|
||||
/// <hr>
|
||||
/// -----------------------------------------------------------
|
||||
///
|
||||
/// \section gettingstarted API Getting Started
|
||||
/// @section gettingstarted API Getting Started
|
||||
///
|
||||
/// \li \ref basics
|
||||
/// \li \ref compiling
|
||||
/// \li \ref eval
|
||||
/// \li \ref addingitems
|
||||
/// \li \ref operatoroverloading
|
||||
/// \li \ref helpermacro
|
||||
/// \li \ref pointerconversions
|
||||
/// \li \ref baseclasses
|
||||
/// \li \ref functionobjects
|
||||
/// \li \ref threading
|
||||
/// \li \ref exceptions
|
||||
/// - @ref basics
|
||||
/// - @ref compiling
|
||||
/// - @ref eval
|
||||
/// - @ref adding_items
|
||||
/// - @ref operatoroverloading
|
||||
/// - @ref add_class
|
||||
/// - @ref pointer_conversions
|
||||
/// - @ref baseclasses
|
||||
/// - @ref functionobjects
|
||||
/// - @ref threading
|
||||
/// - @ref exceptions
|
||||
///
|
||||
///
|
||||
/// \subsection basics Basics
|
||||
/// @subsection basics Basics
|
||||
///
|
||||
/// Basic simple example:
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~{.cpp}
|
||||
/// //main.cpp
|
||||
/// #include <chaiscript/chaiscript.hpp>
|
||||
///
|
||||
@@ -65,115 +69,119 @@
|
||||
/// int main()
|
||||
/// {
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(&function, "function");
|
||||
/// chai.add(chaiscript::fun(&function), "function");
|
||||
///
|
||||
/// double d = chai.eval<double>("function(3, 4.75);");
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection compiling Compiling ChaiScript Applications
|
||||
/// ------------------------------------------------------
|
||||
///
|
||||
/// ChaiScript is a header only library with only one dependecy: The
|
||||
/// @subsection compiling Compiling ChaiScript Applications
|
||||
///
|
||||
/// ChaiScript is a header only library with only one dependency: The
|
||||
/// operating system provided dynamic library loader, which has to be specified on some platforms.
|
||||
///
|
||||
/// \subsubsection compilinggcc Compiling with GCC
|
||||
/// @subsubsection compilinggcc Compiling with GCC
|
||||
///
|
||||
/// To compile the above application on a Unix like operating system (MacOS, Linux) with GCC you need to link
|
||||
/// the dynamic loader. For example:
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// Alternatively, you may compile without threading support.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// gcc main.cpp -I/path/to/chaiscript/headers -ldl -DCHAISCRIPT_NO_THREADS
|
||||
/// \endcode
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection eval Evaluating Scripts
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// ------------------------------------------
|
||||
///
|
||||
/// @subsection eval Evaluating Scripts
|
||||
///
|
||||
/// Scripts can be evaluated with the () operator, eval method or eval_file method.
|
||||
///
|
||||
/// \subsubsection parenoperator () Operator
|
||||
/// @subsubsection parenoperator () Operator
|
||||
///
|
||||
/// operator() can be used as a handy shortcut for evaluating ChaiScript snippets.
|
||||
/// \code
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai("print(\"hello world\")");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa chaiscript::ChaiScript::operator()(const std::string &)
|
||||
///
|
||||
/// \subsubsection evalmethod Method 'eval'
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai("print(@"hello world@")");
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// The eval method is somewhat more verbose and can be used to get typesafely return values
|
||||
/// @sa chaiscript::ChaiScript::operator()(const std::string &)
|
||||
///
|
||||
/// @subsubsection evalmethod Method 'eval'
|
||||
///
|
||||
/// The eval method is somewhat more verbose and can be used to get type safely return values
|
||||
/// from the script.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.eval("callsomefunc()");
|
||||
/// int result = chai.eval<int>("1 + 3");
|
||||
/// // result now equals 4
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa chaiscript::ChaiScript::eval
|
||||
/// @sa chaiscript::ChaiScript::eval
|
||||
///
|
||||
/// \subsubsection evalfilemethod Method 'eval_file'
|
||||
/// @subsubsection evalfilemethod Method 'eval_file'
|
||||
///
|
||||
/// The 'eval_file' method loads a file from disk and executes the script in it
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.eval_file("myfile.chai");
|
||||
/// std::string result = chai.eval_file<std::string>("myfile.chai") // extract the last value returned from the file
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa chaiscript::ChaiScript::eval_file
|
||||
/// @sa chaiscript::ChaiScript::eval_file
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection addingitems Adding Items to ChaiScript
|
||||
/// --------------------------------------------------
|
||||
///
|
||||
/// @subsection adding_items Adding Items to ChaiScript
|
||||
///
|
||||
/// ChaiScript supports 4 basic things that can be added: objects, functions, type infos and Modules
|
||||
///
|
||||
/// \subsubsection addingobjects Adding Objects
|
||||
/// @subsubsection adding_objects Adding Objects
|
||||
///
|
||||
/// Named objects can be created with the chaiscript::var function. Note: adding a object
|
||||
/// adds it to the current thread scope, not to a global scope. If you have multiple
|
||||
/// threads that need to access the same variables you will need to add them
|
||||
/// separately for each thread, from the thread itself.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~{.cpp}
|
||||
/// using namespace chaiscript;
|
||||
/// ChaiScript chai;
|
||||
/// int i = 5;
|
||||
/// chai.add(var(i), "i");
|
||||
/// chai("print(i)");
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// Immutable objects can be created with the chaiscript::const_var function.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~{.cpp}
|
||||
/// chai.add(const_var(i), "i");
|
||||
/// chai("i = 5"); // exception throw, cannot assign const var
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// Named variables can only be accessed from the context they are created in.
|
||||
/// If you want a global variable, it must be const, and created with the
|
||||
/// chaiscript::ChaiScript::add_global_const function.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~{.cpp}
|
||||
/// chai.add_global_const(const_var(i), "i");
|
||||
/// chai("def somefun() { print(i); }; sumfun();");
|
||||
/// \endcode
|
||||
/// chai("def somefun() { print(i); }; somefun();");
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// \subsubsection addingfunctions Adding Functions
|
||||
/// @subsubsection adding_functions Adding Functions
|
||||
///
|
||||
/// Functions, methods and members are all added using the same function: chaiscript::fun.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~{.cpp}
|
||||
/// using namespace chaiscript;
|
||||
///
|
||||
/// class MyClass {
|
||||
@@ -190,26 +198,26 @@
|
||||
/// chai.add(fun(&MyClass::memberdata), "memberdata");
|
||||
/// chai.add(fun(&MyClass::method), "method");
|
||||
/// chai.add(fun(&MyClass::staticmethod), "staticmethod");
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// Overloaded methods will need some help, to hint the compiler as to which overload you want:
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~{.cpp}
|
||||
/// chai.add(fun<void (MyClass::*)()>(&MyClass::overloadedmethod), "overloadedmethod");
|
||||
/// chai.add(fun<void (MyClass::*)(const std::string &)>(&MyClass::overloadedmethod), "overloadedmethod");
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// There are also shortcuts built into chaiscript::fun for binding up to the first two parameters of the function.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~{.cpp}
|
||||
/// MyClass obj;
|
||||
/// chai.add(fun(&MyClass::method, &obj), "method");
|
||||
/// chai("method()"); // equiv to obj.method()
|
||||
/// chai.add(fun(&MyClass::method2, &obj, 3), "method2");
|
||||
/// chai("method2()"); // equiv to obj.method2(3)
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// \subsubsection addingtypeinfo Adding Type Info
|
||||
/// @subsubsection addingtypeinfo Adding Type Info
|
||||
///
|
||||
/// ChaiScript will automatically support any type implicitly provided to it in the form
|
||||
/// of objects and function parameters / return types. However, it can be nice to let ChaiScript
|
||||
@@ -219,27 +227,28 @@
|
||||
///
|
||||
/// Continuing with the example "MyClass" from above:
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// chai.add(user_type<MyClass>(), "MyClass");
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \subsubsection addingmodules Adding Modules
|
||||
/// @subsubsection adding_modules Adding Modules
|
||||
///
|
||||
/// Modules are holders for collections of ChaiScript registrations.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// ModulePtr module = get_sum_module();
|
||||
/// chai.add(module);
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa chaiscript::Module
|
||||
/// @sa chaiscript::Module
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection operatoroverloading Operator Overloading
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @subsection operatoroverloading Operator Overloading
|
||||
///
|
||||
/// Operators are just like any other function in ChaiScript, to overload an operator, simply register it.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// class MyClass {
|
||||
/// MyClass operator+(const MyClass &) const;
|
||||
/// };
|
||||
@@ -254,17 +263,18 @@
|
||||
/// }
|
||||
///
|
||||
/// chai.add(fun(append_string_int), "+");
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
/// @sa @ref adding_functions
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection helpermacro Class Helper Macro
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @subsection add_class Class Helper Utility
|
||||
///
|
||||
/// Much of the work of adding new classes to ChaiScript can be reduced with the help
|
||||
/// of the CHAISCRIPT_CLASS helper macro.
|
||||
/// of the add_class helper utility.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// class Test
|
||||
/// {
|
||||
/// public:
|
||||
@@ -277,40 +287,40 @@
|
||||
///
|
||||
/// int main()
|
||||
/// {
|
||||
///
|
||||
/// chaiscript::ModulePtr m = chaiscript::ModulePtr(new chaiscript::Module());
|
||||
///
|
||||
/// CHAISCRIPT_CLASS( m,
|
||||
/// Test,
|
||||
/// (Test ())
|
||||
/// (Test (const Test &)),
|
||||
/// ((function))
|
||||
/// ((function2))
|
||||
/// ((function3))
|
||||
/// ((functionOverload)(std::string (Test::*)(double)))
|
||||
/// ((functionOverload)(std::string (Test::*)(int)))
|
||||
/// ((operator=))
|
||||
/// );
|
||||
///
|
||||
/// chaiscript::utility::add_class<chaiscript::Test>(*m,
|
||||
/// "Test",
|
||||
/// { constructor<Test()>(),
|
||||
/// constructor<Test(const Test &)>() },
|
||||
/// { {fun(&Test::function), "function"},
|
||||
/// {fun(&Test::function2), "function2"},
|
||||
/// {fun(&Test::function2), "function3"}
|
||||
/// {fun(static_cast<std::string Test::*(double)>(&Test::functionOverload)), "functionOverload"}
|
||||
/// {fun(static_cast<std::string Test::*(int)>(&Test::functionOverload)), "functionOverload"} }
|
||||
/// );
|
||||
///
|
||||
///
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(m);
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref addingmodules
|
||||
/// @sa @ref adding_modules
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection pointerconversions Pointer / Object Conversions
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @subsection pointer_conversions Pointer / Object Conversions
|
||||
///
|
||||
/// As much as possible, ChaiScript attempts to convert between &, *, const &, const *, std::shared_ptr<T>,
|
||||
/// std::shared_ptr<const T>, std::reference_wrapper<T>, std::reference_wrapper<const T> and value types automatically.
|
||||
///
|
||||
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be convered to a shared_ptr (this would add invalid reference counting).
|
||||
/// If a chaiscript::var object was created in C++ from a pointer, it cannot be converted to a shared_ptr (this would add invalid reference counting).
|
||||
/// Const may be added, but never removed.
|
||||
///
|
||||
/// The take away is that you can pretty much expect function calls to Just Work when you need them to.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// void fun1(const int *);
|
||||
/// void fun2(int *);
|
||||
/// void fun3(int);
|
||||
@@ -350,18 +360,19 @@
|
||||
/// chai("fun9(i)");
|
||||
/// chai("fun10(i)");
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// See the unit test unittests/boxed_cast_test.cpp for a complete breakdown of the automatic casts that
|
||||
/// available and tested.
|
||||
///
|
||||
/// <hr>
|
||||
/// \subsection baseclasses Base Classes
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @subsection baseclasses Base Classes
|
||||
///
|
||||
/// ChaiScript supports handling of passing a derived class object to a function expecting a base class object.
|
||||
/// For the process to work, the base/derived relationship must be registered with the engine.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// class Base {};
|
||||
/// class Derived : public Base {};
|
||||
/// void myfunction(Base *b);
|
||||
@@ -375,16 +386,17 @@
|
||||
/// chai.add(chaiscript::fun(&myfunction), "myfunction");
|
||||
/// chai("myfunction(d)");
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// <hr>
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// \subsection functionobjects Function Objects
|
||||
///
|
||||
/// Functions are first class objects in Chaiscript and ChaiScript supports automatic conversion
|
||||
/// @subsection functionobjects Function Objects
|
||||
///
|
||||
/// Functions are first class objects in ChaiScript and ChaiScript supports automatic conversion
|
||||
/// between ChaiScript functions and std::function objects.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// void callafunc(const std::function<void (const std::string &)> &t_func)
|
||||
/// {
|
||||
/// t_func("bob");
|
||||
@@ -400,11 +412,12 @@
|
||||
/// std::function<void ()> f = chai.eval<std::function<void ()> >("dump_system");
|
||||
/// f(); // call the ChaiScript function dump_system, from C++
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// <hr>
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// \subsection threading Threading
|
||||
///
|
||||
/// @subsection threading Threading
|
||||
///
|
||||
/// Thread safety is automatically handled within the ChaiScript system. Objects can be added
|
||||
/// and scripts executed from multiple threads. For each thread that executes scripts, a new
|
||||
@@ -414,16 +427,17 @@
|
||||
///
|
||||
/// Disabling thread safety increases performance in many cases.
|
||||
///
|
||||
/// <hr>
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// \subsection exceptions Exception Handling
|
||||
///
|
||||
/// @subsection exceptions Exception Handling
|
||||
///
|
||||
/// \subsubsection exceptionsbasics Exception Handling Basics
|
||||
/// @subsubsection exceptionsbasics Exception Handling Basics
|
||||
///
|
||||
/// Exceptions can be thrown in ChaiScript and caught in C++ or thrown in C++ and caught in
|
||||
/// ChaiScript.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// void throwexception()
|
||||
/// {
|
||||
/// throw std::runtime_error("err");
|
||||
@@ -444,19 +458,19 @@
|
||||
/// // i == 1
|
||||
/// }
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
|
||||
/// @subsubsection exceptionsautomatic Exception Handling Automatic Unboxing
|
||||
///
|
||||
/// As an alternative to the manual unboxing of exceptions shown above, exception specifications allow the user to tell
|
||||
/// ChaiScript what possible exceptions are expected from the script being executed.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// ~~~~~~~~{.cpp}
|
||||
/// chaiscript::ChaiScript chai;
|
||||
///
|
||||
/// try {
|
||||
/// chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||
/// chai.eval("throw(runtime_error(@"error@"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||
/// } catch (const double e) {
|
||||
/// } catch (int) {
|
||||
/// } catch (float) {
|
||||
@@ -464,19 +478,19 @@
|
||||
/// } catch (const std::exception &e) {
|
||||
/// // This is the one what will be called in the specific throw() above
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa chaiscript::Exception_Handler for details on automatic exception unboxing
|
||||
/// \sa chaiscript::exception_specification
|
||||
/// @sa chaiscript::Exception_Handler for details on automatic exception unboxing
|
||||
/// @sa chaiscript::exception_specification
|
||||
|
||||
|
||||
|
||||
/// \page LangObjectSystemRef ChaiScript Language Object Model Reference
|
||||
/// @page LangObjectSystemRef ChaiScript Language Object Model Reference
|
||||
///
|
||||
///
|
||||
/// ChaiScript has an object system built in, for types defined within the ChaiScript system.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~
|
||||
/// attr Rectangle::height
|
||||
/// attr Rectangle::width
|
||||
/// def Rectangle::Rectangle() { this.height = 10; this.width = 20 }
|
||||
@@ -485,67 +499,84 @@
|
||||
/// var rect = Rectangle()
|
||||
/// rect.height = 30
|
||||
/// print(rect.area())
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// \sa \ref keywordattr
|
||||
/// \sa \ref keyworddef
|
||||
/// Since ChaiScript 5.4.0 it has been possible to use the "class" keyword to simplify this code.
|
||||
///
|
||||
/// ~~~~~~~~~
|
||||
/// class Rectangle {
|
||||
/// attr height
|
||||
/// attr width
|
||||
/// def Rectangle() { this.height = 10; this.width = 20 }
|
||||
/// def area() { this.height * this.width }
|
||||
/// }
|
||||
///
|
||||
/// var rect = Rectangle()
|
||||
/// rect.height = 30
|
||||
/// print(rect.area())
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// @sa @ref keywordattr
|
||||
/// @sa @ref keyworddef
|
||||
|
||||
/// \page LangInPlaceRef ChaiScript Language In-Place Creation Reference
|
||||
/// \section inplacevector Vector
|
||||
/// @page LangInPlaceRef ChaiScript Language In-Place Creation Reference
|
||||
/// @section inplacevector Vector
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~
|
||||
/// In-place Vector ::= "[" [expression ("," expression)*] "]"
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// \section inplacerangedvector Ranged Vector
|
||||
/// @section inplacerangedvector Ranged Vector
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~~
|
||||
/// In-place Ranged Vector ::= "[" value ".." value "]"
|
||||
/// \endcode
|
||||
/// ~~~~~~~~~
|
||||
///
|
||||
/// Creates a vector over a range (eg. 1..10)
|
||||
///
|
||||
/// \section inplacemap Map
|
||||
/// @section inplacemap Map
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// In-place Map ::= "[" (string ":" expression)+ "]"
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
|
||||
/// \page LangGettingStarted ChaiScript Language Getting Started
|
||||
/// @page LangGettingStarted ChaiScript Language Getting Started
|
||||
///
|
||||
/// ChaiScript is a simple language that should feel familiar to anyone who knows
|
||||
/// C++ or ECMAScript (JavaScript).
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptloops Loops
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section chaiscriptloops Loops
|
||||
///
|
||||
/// Common looping constructs exist in ChaiScript
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// var i = 0;
|
||||
/// while (i < 10)
|
||||
/// {
|
||||
/// // do something
|
||||
/// ++i;
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// for (var i = 0; i < 10; ++i)
|
||||
/// {
|
||||
/// // do something
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref keywordfor
|
||||
/// \sa \ref keywordwhile
|
||||
/// @sa @ref keywordfor
|
||||
/// @sa @ref keywordwhile
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptifs Conditionals
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section chaiscriptifs Conditionals
|
||||
///
|
||||
/// If statements work as expected
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// var b = true;
|
||||
///
|
||||
/// if (b) {
|
||||
@@ -555,107 +586,125 @@
|
||||
/// } else {
|
||||
/// // or do this
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref keywordif
|
||||
/// @sa @ref keywordif
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptfunctions Functions
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section chaiscriptfunctions Functions
|
||||
///
|
||||
/// Functions are defined with the def keyword
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// def myfun(x) { print(x); }
|
||||
///
|
||||
/// myfun(10);
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// Functions may have "guards" which determine if which is called.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// eval> def myfun2(x) : x < 10 { print("less than 10"); }
|
||||
/// eval> def myfun2(x) : x >= 10 { print("10 or greater"); }
|
||||
/// eval> myfun2(5)
|
||||
/// less than 10
|
||||
/// eval> myfun2(12)
|
||||
/// 10 or greater
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref keyworddef
|
||||
/// \sa \ref keywordattr
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
/// @sa @ref keyworddef
|
||||
/// @sa @ref keywordattr
|
||||
/// @sa @ref LangObjectSystemRef
|
||||
///
|
||||
/// <hr>
|
||||
/// \section chaiscriptfunctionobjects Function Objects
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section chaiscriptfunctionobjects Function Objects
|
||||
///
|
||||
/// Functions are first class types in ChaiScript and can be used as variables.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// eval> var p = print;
|
||||
/// eval> p(1);
|
||||
/// 1
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// They can also be passed to functions.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// eval> def callfunc(f, lhs, rhs) { return f(lhs, rhs); }
|
||||
/// eval> def dosomething(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
|
||||
/// eval> callfunc(dosomething, 1, 2);
|
||||
/// eval> def do_something(lhs, rhs) { print("lhs: ${lhs}, rhs: ${rhs}"); }
|
||||
/// eval> callfunc(do_something, 1, 2);
|
||||
/// lhs: 1, rhs: 2
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// Operators can also be treated as functions by using the back tick operator. Building on the above example:
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// eval> callfunc(`+`, 1, 4);
|
||||
/// 5
|
||||
/// eval> callfunc(`*`, 3, 2);
|
||||
/// 6
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// <hr>
|
||||
/// \sa \ref LangKeywordRef
|
||||
/// \sa ChaiScript_Language for Built in Functions
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @sa @ref LangKeywordRef
|
||||
/// @sa ChaiScript_Language for Built in Functions
|
||||
|
||||
|
||||
/// \page LangKeywordRef ChaiScript Language Keyword Reference
|
||||
/// @page LangKeywordRef ChaiScript Language Keyword Reference
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordattr attr
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordattr attr
|
||||
/// Defines a ChaiScript object attribute
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// Attribute Definition ::= "attr" class_name "::" attribute_name
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
/// @sa @ref LangObjectSystemRef
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordbreak break
|
||||
///
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordauto auto
|
||||
///
|
||||
/// Defines a variable
|
||||
///
|
||||
/// ~~~~~~~~
|
||||
/// Variable ::= "auto" identifier
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// Synonym for @ref keywordvar
|
||||
///
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordbreak break
|
||||
/// Stops execution of a looping block.
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// Break Statement ::= "break"
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref keywordfor
|
||||
/// \sa \ref keywordwhile
|
||||
/// @sa @ref keywordfor
|
||||
/// @sa @ref keywordwhile
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keyworddef def
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keyworddef def
|
||||
/// Begins a function or method definition
|
||||
///
|
||||
/// \code
|
||||
/// Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= [annotation + CR/LF] "def" class_name "::" method_name "(" [arg ("," arg)*] ")" [":" guard] block
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
/// Function Definition ::= "def" identifier "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// Method Definition ::= "def" class_name "::" method_name "(" [[type] arg ("," [type] arg)*] ")" [":" guard] block
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// annotation: meta-annotation on function, currently used as documentation. Optional.
|
||||
/// identifier: name of function. Required.
|
||||
/// args: comma-delimited list of parameter names. Optional.
|
||||
/// args: comma-delimited list of parameter names with optional type specifiers. Optional.
|
||||
/// guards: guarding statement that act as a prerequisite for the function. Optional.
|
||||
/// { }: scoped block as function body. Required.
|
||||
///
|
||||
@@ -667,50 +716,56 @@
|
||||
/// Method definitions for known types extend those types with new methods. This includes C++ and ChaiScript defined types.
|
||||
/// Method definitions for unknown types implicitly define the named type.
|
||||
///
|
||||
/// \sa \ref LangObjectSystemRef
|
||||
/// @sa @ref LangObjectSystemRef
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordelse else
|
||||
/// \sa \ref keywordif
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordelse else
|
||||
/// @sa @ref keywordif
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordfor for
|
||||
/// \code
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordfor for
|
||||
/// ~~~~~~~~
|
||||
/// For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block
|
||||
/// \endcode
|
||||
/// This loop can be broken using the \ref keywordbreak command.
|
||||
/// ~~~~~~~~
|
||||
/// This loop can be broken using the @ref keywordbreak command.
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordfun fun
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordfun fun
|
||||
/// Begins an anonymous function declaration (sometimes called a lambda).
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// Lambda ::= "fun" "(" [variable] ("," variable)* ")" block
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \b Examples:
|
||||
/// _Example_
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// // Generate an anonymous function object that adds 2 to its parameter
|
||||
/// var f = fun(x) { x + 2; }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa \ref keyworddef for more details on ChaiScript functions
|
||||
/// @sa @ref keyworddef for more details on ChaiScript functions
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordif if
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordif if
|
||||
/// Begins a conditional block of code that only executes if the condition evaluates as true.
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// If Block ::= "if" "(" condition ")" block
|
||||
/// Else If Block ::= "else if" "(" condition ")" block
|
||||
/// Else Block ::= "else" block
|
||||
/// \endcode
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// _Example_
|
||||
///
|
||||
/// ~~~~~~~~
|
||||
/// if (true) {
|
||||
/// // do something
|
||||
/// } else if (false) {
|
||||
@@ -718,46 +773,73 @@
|
||||
/// } else {
|
||||
/// // otherwise do this
|
||||
/// }
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordtry try
|
||||
/// \code
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordtry try
|
||||
/// ~~~~~~~~
|
||||
/// Try Block ::= "try" block
|
||||
/// ("catch" ["(" variable ")"] [":" guards] block)+
|
||||
/// ("catch" ["(" [type] variable ")"] [":" guards] block)+
|
||||
/// ["finally" block]
|
||||
/// \endcode
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// \sa ChaiScript_Language::throw
|
||||
/// @sa ChaiScript_Language::throw
|
||||
///
|
||||
/// <hr>
|
||||
/// \section keywordwhile while
|
||||
///
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordwhile while
|
||||
///
|
||||
/// Begins a conditional block of code that loops 0 or more times, as long as the condition is true
|
||||
///
|
||||
/// \code
|
||||
/// ~~~~~~~~
|
||||
/// While Block ::= "while" "(" condition ")" block
|
||||
/// \endcode
|
||||
/// This loop can be broken using the \ref keywordbreak command.
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// This loop can be broken using the @ref keywordbreak command.
|
||||
///
|
||||
///
|
||||
/// -----------------------------------------------------------------------
|
||||
///
|
||||
/// @section keywordvar var
|
||||
///
|
||||
/// Defines a variable
|
||||
///
|
||||
/// ~~~~~~~~
|
||||
/// Variable ::= "var" identifier
|
||||
/// ~~~~~~~~
|
||||
///
|
||||
/// Synonym for @ref keywordauto
|
||||
|
||||
|
||||
/// \namespace chaiscript
|
||||
/// \brief Namespace chaiscript contains every API call that the average user will be concerned with.
|
||||
/// @namespace chaiscript
|
||||
/// @brief Namespace chaiscript contains every API call that the average user will be concerned with.
|
||||
|
||||
/// \namespace chaiscript::detail
|
||||
/// \brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
||||
/// @namespace chaiscript::detail
|
||||
/// @brief Classes and functions reserved for internal use. Items in this namespace are not supported.
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/boxed_number.hpp"
|
||||
|
||||
#include "language/chaiscript_eval.hpp"
|
||||
#include "language/chaiscript_engine.hpp"
|
||||
#include "chaiscript_basic.hpp"
|
||||
#include "language/chaiscript_parser.hpp"
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class ChaiScript : public ChaiScript_Basic
|
||||
{
|
||||
public:
|
||||
ChaiScript(std::vector<std::string> t_modulepaths = {},
|
||||
std::vector<std::string> t_usepaths = {},
|
||||
const std::vector<Options> &t_opts = {})
|
||||
: ChaiScript_Basic(
|
||||
chaiscript::Std_Lib::library(),
|
||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>(),
|
||||
t_modulepaths, t_usepaths, t_opts)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CHAISCRIPT_HPP_ */
|
||||
|
||||
39
include/chaiscript/chaiscript_basic.hpp
Normal file
39
include/chaiscript/chaiscript_basic.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_BASIC_HPP_
|
||||
#define CHAISCRIPT_BASIC_HPP_
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
#include "dispatchkit/dynamic_object.hpp"
|
||||
#include "dispatchkit/boxed_number.hpp"
|
||||
|
||||
#include "language/chaiscript_eval.hpp"
|
||||
#include "language/chaiscript_engine.hpp"
|
||||
|
||||
// This file includes all of the basic requirements for ChaiScript,
|
||||
// to use, you might do something like:
|
||||
//
|
||||
|
||||
/*
|
||||
|
||||
#include "chaiscript_stdlib.hpp"
|
||||
#include "language/chaiscript_parser.hpp"
|
||||
|
||||
ChaiScript_Basic chai(
|
||||
chaiscript::Std_Lib::library(),
|
||||
std::make_unique<parser::ChaiScript_Parser<eval::Noop_Tracer, optimizer::Optimizer_Default>>());
|
||||
|
||||
*/
|
||||
|
||||
// If you want a fully packaged ready to go ChaiScript, use chaiscript.hpp
|
||||
|
||||
|
||||
|
||||
#endif /* CHAISCRIPT_BASIC_HPP_ */
|
||||
@@ -1,21 +1,58 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||
#define CHAISCRIPT_DEFINES_HPP_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define CHAISCRIPT_STRINGIZE(x) "" #x
|
||||
#define CHAISCRIPT_STRINGIZE_EXPANDED(x) CHAISCRIPT_STRINGIZE(x)
|
||||
#define CHAISCRIPT_COMPILER_VERSION CHAISCRIPT_STRINGIZE_EXPANDED(_MSC_FULL_VER)
|
||||
#define CHAISCRIPT_MSVC _MSC_VER
|
||||
#define CHAISCRIPT_HAS_DECLSPEc
|
||||
#define CHAISCRIPT_HAS_DECLSPEC
|
||||
|
||||
static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later required");
|
||||
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_VERSION __VERSION__
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <vector>
|
||||
|
||||
#if defined( _LIBCPP_VERSION )
|
||||
#define CHAISCRIPT_LIBCPP
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define CHAISCRIPT_WINDOWS
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "clang(windows)"
|
||||
#elif defined(__GNUC__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "gcc(mingw)"
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_NAME "msvc"
|
||||
#endif
|
||||
#else
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "clang"
|
||||
#elif defined(__GNUC__)
|
||||
#define CHAISCRIPT_COMPILER_NAME "gcc"
|
||||
#else
|
||||
#define CHAISCRIPT_COMPILER_NAME "unknown"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__llvm__)
|
||||
#define CHAISCRIPT_CLANG
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||
@@ -23,6 +60,168 @@
|
||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
|
||||
#define CHAISCRIPT_UTF16_UTF32
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define CHAISCRIPT_DEBUG true
|
||||
#else
|
||||
#define CHAISCRIPT_DEBUG false
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
|
||||
namespace chaiscript {
|
||||
static const int version_major = 6;
|
||||
static const int version_minor = 0;
|
||||
static const int version_patch = 0;
|
||||
|
||||
static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
|
||||
static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
|
||||
static const bool debug_build = CHAISCRIPT_DEBUG;
|
||||
|
||||
template<typename B, typename D, typename ...Arg>
|
||||
inline std::shared_ptr<B> make_shared(Arg && ... arg)
|
||||
{
|
||||
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
|
||||
return std::make_shared<D>(std::forward<Arg>(arg)...);
|
||||
#else
|
||||
return std::shared_ptr<B>(static_cast<B*>(new D(std::forward<Arg>(arg)...)));
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Build_Info {
|
||||
static int version_major()
|
||||
{
|
||||
return chaiscript::version_major;
|
||||
}
|
||||
|
||||
static int version_minor()
|
||||
{
|
||||
return chaiscript::version_minor;
|
||||
}
|
||||
|
||||
static int version_patch()
|
||||
{
|
||||
return chaiscript::version_patch;
|
||||
}
|
||||
|
||||
static std::string version()
|
||||
{
|
||||
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||
}
|
||||
|
||||
static std::string compiler_id()
|
||||
{
|
||||
return compiler_name() + '-' + compiler_version();
|
||||
}
|
||||
|
||||
static std::string build_id()
|
||||
{
|
||||
return compiler_id() + (debug_build()?"-Debug":"-Release");
|
||||
}
|
||||
|
||||
static std::string compiler_version()
|
||||
{
|
||||
return chaiscript::compiler_version;
|
||||
}
|
||||
|
||||
static std::string compiler_name()
|
||||
{
|
||||
return chaiscript::compiler_name;
|
||||
}
|
||||
|
||||
static bool debug_build()
|
||||
{
|
||||
return chaiscript::debug_build;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
for (char c = *t_str; (c = *t_str) != 0; ++t_str) {
|
||||
if (c < '0' || c > '9') {
|
||||
return t;
|
||||
}
|
||||
t *= 10;
|
||||
t += c - '0';
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto parse_num(const char *t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type
|
||||
{
|
||||
T t = 0;
|
||||
T base = 0;
|
||||
T decimal_place = 0;
|
||||
bool exponent = false;
|
||||
bool neg_exponent = false;
|
||||
|
||||
const auto final_value = [](const T val, const T baseval, const bool hasexp, const bool negexp) -> T {
|
||||
if (!hasexp) {
|
||||
return val;
|
||||
} else {
|
||||
return baseval * std::pow(T(10), val*T(negexp?-1:1));
|
||||
}
|
||||
};
|
||||
|
||||
for(; *t_str != '\0'; ++t_str) {
|
||||
char c = *t_str;
|
||||
if (c == '.') {
|
||||
decimal_place = 10;
|
||||
} else if (c == 'e' || c == 'E') {
|
||||
exponent = true;
|
||||
decimal_place = 0;
|
||||
base = t;
|
||||
t = 0;
|
||||
} else if (c == '-' && exponent) {
|
||||
neg_exponent = true;
|
||||
} else if (c == '+' && exponent) {
|
||||
neg_exponent = false;
|
||||
} else if (c < '0' || c > '9') {
|
||||
return final_value(t, base, exponent, neg_exponent);
|
||||
} else if (decimal_place < T(10)) {
|
||||
t *= T(10);
|
||||
t += T(c - '0');
|
||||
} else {
|
||||
t += (T(c - '0') / (T(decimal_place)));
|
||||
decimal_place *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
return final_value(t, base, exponent, neg_exponent);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T parse_num(const std::string &t_str)
|
||||
{
|
||||
return parse_num<T>(t_str.c_str());
|
||||
}
|
||||
|
||||
enum class Options
|
||||
{
|
||||
No_Load_Modules,
|
||||
Load_Modules,
|
||||
No_External_Scripts,
|
||||
External_Scripts
|
||||
};
|
||||
|
||||
static inline std::vector<Options> default_options()
|
||||
{
|
||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||
return {Options::No_Load_Modules, Options::External_Scripts};
|
||||
#else
|
||||
return {Options::Load_Modules, Options::External_Scripts};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,11 +7,32 @@
|
||||
#ifndef CHAISCRIPT_STDLIB_HPP_
|
||||
#define CHAISCRIPT_STDLIB_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
#include "language/chaiscript_common.hpp"
|
||||
|
||||
#include "dispatchkit/function_call.hpp"
|
||||
|
||||
//#include "dispatchkit/dispatchkit.hpp"
|
||||
#include "dispatchkit/operators.hpp"
|
||||
#include "dispatchkit/bootstrap.hpp"
|
||||
#include "dispatchkit/bootstrap_stl.hpp"
|
||||
//#include "dispatchkit/boxed_value.hpp"
|
||||
#include "language/chaiscript_prelude.hpp"
|
||||
#include "dispatchkit/register_function.hpp"
|
||||
#include "utility/json_wrap.hpp"
|
||||
|
||||
/// \file
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
|
||||
/// @file
|
||||
///
|
||||
/// This file generates the standard library that normal ChaiScript usage requires.
|
||||
|
||||
@@ -23,14 +44,22 @@ namespace chaiscript
|
||||
|
||||
static ModulePtr library()
|
||||
{
|
||||
using namespace bootstrap;
|
||||
auto lib = std::make_shared<Module>();
|
||||
bootstrap::Bootstrap::bootstrap(*lib);
|
||||
|
||||
ModulePtr lib = Bootstrap::bootstrap();
|
||||
bootstrap::standard_library::vector_type<std::vector<Boxed_Value> >("Vector", *lib);
|
||||
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
||||
bootstrap::standard_library::map_type<std::map<std::string, Boxed_Value> >("Map", *lib);
|
||||
bootstrap::standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair", *lib);
|
||||
|
||||
lib->add(standard_library::vector_type<std::vector<Boxed_Value> >("Vector"));
|
||||
lib->add(standard_library::string_type<std::string>("string"));
|
||||
lib->add(standard_library::map_type<std::map<std::string, Boxed_Value> >("Map"));
|
||||
lib->add(standard_library::pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
bootstrap::standard_library::future_type<std::future<chaiscript::Boxed_Value>>("future", *lib);
|
||||
lib->add(chaiscript::fun([](const std::function<chaiscript::Boxed_Value ()> &t_func){ return std::async(std::launch::async, t_func);}), "async");
|
||||
#endif
|
||||
|
||||
json_wrap::library(*lib);
|
||||
|
||||
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/ );
|
||||
|
||||
return lib;
|
||||
}
|
||||
@@ -38,7 +67,5 @@ namespace chaiscript
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_THREADING_HPP_
|
||||
#define CHAISCRIPT_THREADING_HPP_
|
||||
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#else
|
||||
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "chaiscript_defines.hpp"
|
||||
|
||||
/// \file
|
||||
///
|
||||
@@ -37,98 +46,102 @@ namespace chaiscript
|
||||
#ifndef CHAISCRIPT_NO_THREADS
|
||||
|
||||
template<typename T>
|
||||
class unique_lock : public std::unique_lock<T>
|
||||
{
|
||||
public:
|
||||
unique_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
};
|
||||
using unique_lock = std::unique_lock<T>;
|
||||
|
||||
template<typename T>
|
||||
class shared_lock : public std::unique_lock<T>
|
||||
{
|
||||
public:
|
||||
shared_lock(T &t) : std::unique_lock<T>(t) {}
|
||||
void unlock() {}
|
||||
};
|
||||
using shared_lock = std::unique_lock<T>;
|
||||
|
||||
template<typename T>
|
||||
class lock_guard : public std::lock_guard<T>
|
||||
{
|
||||
public:
|
||||
lock_guard(T &t) : std::lock_guard<T>(t) {}
|
||||
};
|
||||
using lock_guard = std::lock_guard<T>;
|
||||
|
||||
class shared_mutex : public std::mutex { };
|
||||
|
||||
using shared_mutex = std::mutex;
|
||||
|
||||
using std::mutex;
|
||||
|
||||
using std::recursive_mutex;
|
||||
|
||||
|
||||
|
||||
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
||||
/// threading is not enabled, the class always returns the same data, regardless of which thread it is called from.
|
||||
///
|
||||
/// \todo move to thread_local when it exists
|
||||
template<typename T>
|
||||
class Thread_Storage
|
||||
{
|
||||
public:
|
||||
inline T *operator->() const
|
||||
Thread_Storage() = default;
|
||||
Thread_Storage(const Thread_Storage &) = delete;
|
||||
Thread_Storage(Thread_Storage &&) = delete;
|
||||
Thread_Storage &operator=(const Thread_Storage &) = delete;
|
||||
Thread_Storage &operator=(Thread_Storage &&) = delete;
|
||||
|
||||
~Thread_Storage()
|
||||
{
|
||||
return get_tls().get();
|
||||
if (!destroyed) {
|
||||
t().erase(this);
|
||||
}
|
||||
}
|
||||
|
||||
inline T &operator*() const
|
||||
inline const T *operator->() const
|
||||
{
|
||||
return *get_tls();
|
||||
return &(t()[const_cast<Thread_Storage *>(this)]);
|
||||
}
|
||||
|
||||
inline const T &operator*() const
|
||||
{
|
||||
return t()[const_cast<Thread_Storage *>(this)];
|
||||
}
|
||||
|
||||
inline T *operator->()
|
||||
{
|
||||
return &(t()[this]);
|
||||
}
|
||||
|
||||
inline T &operator*()
|
||||
{
|
||||
return t()[this];
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<T> get_tls() const
|
||||
struct Map_Holder {
|
||||
std::unordered_map<Thread_Storage<T> *, T> map;
|
||||
|
||||
Map_Holder() = default;
|
||||
Map_Holder(const Map_Holder &) = delete;
|
||||
Map_Holder(Map_Holder &&) = delete;
|
||||
Map_Holder& operator=(Map_Holder &&) = delete;
|
||||
Map_Holder& operator=(const Map_Holder &&) = delete;
|
||||
~Map_Holder() {
|
||||
// here is the theory:
|
||||
// * If the Map_Holder is destroyed before the Thread_Storage, a flag will get set
|
||||
// * If destroyed after the Thread_Storage, the * will have been removed from `map` and nothing will happen
|
||||
for(auto &elem : map) { elem.first->destroyed = true; }
|
||||
}
|
||||
};
|
||||
|
||||
static std::unordered_map<Thread_Storage<T> *, T> &t()
|
||||
{
|
||||
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
|
||||
auto itr = m_instances.find(std::this_thread::get_id());
|
||||
|
||||
if (itr != m_instances.end()) { return itr->second; }
|
||||
|
||||
std::shared_ptr<T> new_instance(new T());
|
||||
|
||||
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
||||
|
||||
return new_instance;
|
||||
|
||||
|
||||
/*
|
||||
static __thread std::shared_ptr<T> *m_data = 0;
|
||||
|
||||
if (!m_data) { m_data = new std::shared_ptr<T>(new T()); }
|
||||
|
||||
return *m_data;
|
||||
*/
|
||||
thread_local Map_Holder my_map;
|
||||
return my_map.map;
|
||||
}
|
||||
|
||||
|
||||
mutable mutex m_mutex;
|
||||
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
|
||||
bool destroyed{false};
|
||||
};
|
||||
|
||||
#else
|
||||
#else // threading disabled
|
||||
template<typename T>
|
||||
class unique_lock
|
||||
{
|
||||
public:
|
||||
unique_lock(T &) {}
|
||||
explicit unique_lock(T &) {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class shared_lock
|
||||
{
|
||||
public:
|
||||
shared_lock(T &) {}
|
||||
explicit shared_lock(T &) {}
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
};
|
||||
|
||||
@@ -136,7 +149,7 @@ namespace chaiscript
|
||||
class lock_guard
|
||||
{
|
||||
public:
|
||||
lock_guard(T &) {}
|
||||
explicit lock_guard(T &) {}
|
||||
};
|
||||
|
||||
class shared_mutex { };
|
||||
@@ -148,6 +161,10 @@ namespace chaiscript
|
||||
class Thread_Storage
|
||||
{
|
||||
public:
|
||||
explicit Thread_Storage(void *)
|
||||
{
|
||||
}
|
||||
|
||||
inline T *operator->() const
|
||||
{
|
||||
return &obj;
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef CHAISCRIPT_ANY_HPP_
|
||||
#define CHAISCRIPT_ANY_HPP_
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace detail {
|
||||
namespace exception
|
||||
@@ -19,21 +21,20 @@ namespace chaiscript {
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
bad_any_cast() noexcept
|
||||
: m_what("bad any cast")
|
||||
{
|
||||
}
|
||||
bad_any_cast() = default;
|
||||
|
||||
virtual ~bad_any_cast() noexcept {}
|
||||
bad_any_cast(const bad_any_cast &) = default;
|
||||
|
||||
/// \brief Description of what error occured
|
||||
virtual const char * what() const noexcept
|
||||
~bad_any_cast() noexcept override = default;
|
||||
|
||||
/// \brief Description of what error occurred
|
||||
const char * what() const noexcept override
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
std::string m_what = "bad any cast";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,44 +43,57 @@ namespace chaiscript {
|
||||
private:
|
||||
struct Data
|
||||
{
|
||||
explicit Data(const std::type_info &t_type)
|
||||
: m_type(t_type)
|
||||
{
|
||||
}
|
||||
|
||||
Data &operator=(const Data &) = delete;
|
||||
|
||||
virtual ~Data() = default;
|
||||
|
||||
virtual void *data() = 0;
|
||||
virtual const std::type_info &type() const = 0;
|
||||
virtual std::shared_ptr<Data> clone() const = 0;
|
||||
|
||||
const std::type_info &type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<Data> clone() const = 0;
|
||||
const std::type_info &m_type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Data_Impl : Data
|
||||
{
|
||||
Data_Impl(const T &t_type)
|
||||
: m_type(typeid(T)),
|
||||
m_data(t_type)
|
||||
explicit Data_Impl(T t_type)
|
||||
: Data(typeid(T)),
|
||||
m_data(std::move(t_type))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void *data()
|
||||
void *data() override
|
||||
{
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
const std::type_info &type() const
|
||||
std::unique_ptr<Data> clone() const override
|
||||
{
|
||||
return m_type;
|
||||
return std::unique_ptr<Data>(new Data_Impl<T>(m_data));
|
||||
}
|
||||
|
||||
std::shared_ptr<Data> clone() const
|
||||
{
|
||||
return std::shared_ptr<Data>(new Data_Impl<T>(m_data));
|
||||
}
|
||||
Data_Impl &operator=(const Data_Impl&) = delete;
|
||||
|
||||
const std::type_info &m_type;
|
||||
T m_data;
|
||||
};
|
||||
|
||||
std::shared_ptr<Data> m_data;
|
||||
std::unique_ptr<Data> m_data;
|
||||
|
||||
public:
|
||||
// construct/copy/destruct
|
||||
Any() = default;
|
||||
Any(Any &&) = default;
|
||||
Any &operator=(Any &&t_any) = default;
|
||||
|
||||
Any(const Any &t_any)
|
||||
{
|
||||
@@ -91,12 +105,15 @@ namespace chaiscript {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any(const ValueType &t_value)
|
||||
|
||||
template<typename ValueType,
|
||||
typename = typename std::enable_if<!std::is_same<Any, typename std::decay<ValueType>::type>::value>::type>
|
||||
explicit Any(ValueType &&t_value)
|
||||
: m_data(std::unique_ptr<Data>(new Data_Impl<typename std::decay<ValueType>::type>(std::forward<ValueType>(t_value))))
|
||||
{
|
||||
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
|
||||
}
|
||||
|
||||
|
||||
Any & operator=(const Any &t_any)
|
||||
{
|
||||
Any copy(t_any);
|
||||
@@ -104,13 +121,6 @@ namespace chaiscript {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any & operator=(const ValueType &t_value)
|
||||
{
|
||||
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ToType>
|
||||
ToType &cast() const
|
||||
{
|
||||
@@ -120,20 +130,13 @@ namespace chaiscript {
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
~Any()
|
||||
{
|
||||
}
|
||||
|
||||
// modifiers
|
||||
Any & swap(Any &t_other)
|
||||
{
|
||||
std::shared_ptr<Data> data = t_other.m_data;
|
||||
t_other.m_data = m_data;
|
||||
m_data = data;
|
||||
std::swap(t_other.m_data, m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -145,8 +148,7 @@ namespace chaiscript {
|
||||
|
||||
const std::type_info & type() const
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
if (m_data) {
|
||||
return m_data->type();
|
||||
} else {
|
||||
return typeid(void);
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Info;
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
@@ -21,32 +33,33 @@ namespace chaiscript
|
||||
class bad_boxed_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||
const std::string &t_what) noexcept
|
||||
: from(t_from), to(&t_to), m_what(t_what)
|
||||
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to,
|
||||
std::string t_what) noexcept
|
||||
: from(t_from), to(&t_to), m_what(std::move(t_what))
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
||||
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
|
||||
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to)
|
||||
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name())
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_cast(const std::string &t_what) noexcept
|
||||
: to(0), m_what(t_what)
|
||||
explicit bad_boxed_cast(std::string t_what) noexcept
|
||||
: m_what(std::move(t_what))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_cast() noexcept {}
|
||||
bad_boxed_cast(const bad_boxed_cast &) = default;
|
||||
~bad_boxed_cast() noexcept override = default;
|
||||
|
||||
/// \brief Description of what error occured
|
||||
virtual const char * what() const noexcept
|
||||
/// \brief Description of what error occurred
|
||||
const char * what() const noexcept override
|
||||
{
|
||||
return m_what.c_str();
|
||||
}
|
||||
|
||||
Type_Info from; ///< Type_Info contained in the Boxed_Value
|
||||
const std::type_info *to; ///< std::type_info of the desired (but failed) result type
|
||||
const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type
|
||||
|
||||
private:
|
||||
std::string m_what;
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
||||
#define CHAISCRIPT_BIND_FIRST_HPP_
|
||||
|
||||
@@ -14,117 +18,65 @@ namespace chaiscript
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<int>
|
||||
struct Placeholder
|
||||
template<typename T>
|
||||
T* get_pointer(T *t)
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<1>
|
||||
{
|
||||
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<2>
|
||||
{
|
||||
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<3>
|
||||
{
|
||||
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<4>
|
||||
{
|
||||
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<5>
|
||||
{
|
||||
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<6>
|
||||
{
|
||||
static decltype(std::placeholders::_6) value() { return std::placeholders::_6; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<7>
|
||||
{
|
||||
static decltype(std::placeholders::_7) value() { return std::placeholders::_7; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<8>
|
||||
{
|
||||
static decltype(std::placeholders::_8) value() { return std::placeholders::_8; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<9>
|
||||
{
|
||||
static decltype(std::placeholders::_9) value() { return std::placeholders::_9; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Placeholder<10>
|
||||
{
|
||||
static decltype(std::placeholders::_10) value() { return std::placeholders::_10; }
|
||||
};
|
||||
|
||||
|
||||
template<int count, int maxcount, typename Sig>
|
||||
struct Bind_First
|
||||
{
|
||||
template<typename F, typename ... InnerParams>
|
||||
static std::function<Sig> bind(F f, InnerParams ... innerparams)
|
||||
{
|
||||
return Bind_First<count - 1, maxcount, Sig>::bind(f, innerparams..., Placeholder<maxcount - count + 1>::value());
|
||||
}
|
||||
};
|
||||
|
||||
template<int maxcount, typename Sig>
|
||||
struct Bind_First<0, maxcount, Sig>
|
||||
{
|
||||
template<typename F, typename ... InnerParams>
|
||||
static std::function<Sig> bind(F f, InnerParams ... innerparams)
|
||||
{
|
||||
return std::bind(f, innerparams...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (*f)(P1, Param...), O o)
|
||||
{
|
||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
|
||||
template<typename T>
|
||||
T* get_pointer(const std::reference_wrapper<T> &t)
|
||||
{
|
||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...) const, O o)
|
||||
{
|
||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
||||
return &t.get();
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o)
|
||||
auto bind_first(Ret (*f)(P1, Param...), O&& o)
|
||||
{
|
||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(std::forward<O>(o), std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
auto bind_first(Ret (Class::*f)(Param...), O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
||||
auto bind_first(Ret (Class::*f)(Param...) const, O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return (get_pointer(o)->*f)(std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
||||
auto bind_first(const std::function<Ret (P1, Param...)> &f, O&& o)
|
||||
{
|
||||
return [f, o](Param...param) -> Ret {
|
||||
return f(o, std::forward<Param>(param)...);
|
||||
};
|
||||
}
|
||||
|
||||
template<typename F, typename O, typename Ret, typename Class, typename P1, typename ... Param>
|
||||
auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const)
|
||||
{
|
||||
return [fo, o, f](Param ...param) -> Ret {
|
||||
return (fo.*f)(o, std::forward<Param>(param)...);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename F, typename O>
|
||||
auto bind_first(const F &f, O&& o)
|
||||
{
|
||||
return bind_first(f, std::forward<O>(o), &F::operator());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +1,75 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
#include "../utility/utility.hpp"
|
||||
#include "register_function.hpp"
|
||||
#include "operators.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
||||
namespace bootstrap
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// \brief Constructs a new POD value object from a Boxed_Number
|
||||
/// \param[in] v Boxed_Number to copy into the new object
|
||||
/// \returns The newly created object.
|
||||
template<typename P1>
|
||||
std::shared_ptr<P1> construct_pod(Boxed_Number v)
|
||||
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type >
|
||||
void array(const std::string &type, Module& m)
|
||||
{
|
||||
std::shared_ptr<P1> p(new P1());
|
||||
Boxed_Value bv(p);
|
||||
Boxed_Number nb(bv);
|
||||
nb = v;
|
||||
return p;
|
||||
typedef typename std::remove_extent<T>::type ReturnType;
|
||||
const auto extent = std::extent<T>::value;
|
||||
m.add(user_type<T>(), type);
|
||||
m.add(fun(
|
||||
[extent](T& t, size_t index)->ReturnType &{
|
||||
if (extent > 0 && index >= extent) {
|
||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||
} else {
|
||||
return t[index];
|
||||
}
|
||||
}
|
||||
), "[]"
|
||||
);
|
||||
|
||||
m.add(fun(
|
||||
[extent](const T &t, size_t index)->const ReturnType &{
|
||||
if (extent > 0 && index >= extent) {
|
||||
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent));
|
||||
} else {
|
||||
return t[index];
|
||||
}
|
||||
}
|
||||
), "[]"
|
||||
);
|
||||
|
||||
m.add(fun(
|
||||
[extent](const T &) {
|
||||
return extent;
|
||||
}), "size");
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Adds a copy constructor for the given type to the given Model
|
||||
/// \param[in] type The name of the type. The copy constructor will be named "type".
|
||||
/// \param[in,out] m The Module to add the copy constructor to
|
||||
/// \tparam T The type to add a copy constructor for
|
||||
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
||||
/// \returns The passed in Module
|
||||
template<typename T>
|
||||
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void copy_constructor(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(constructor<T (const T &)>(), type);
|
||||
return m;
|
||||
m.add(constructor<T (const T &)>(), type);
|
||||
}
|
||||
|
||||
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
||||
/// \tparam T Type to create comparison operators for
|
||||
/// \param[in,out] m module to add comparison operators to
|
||||
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
|
||||
/// \returns the passed in Module.
|
||||
template<typename T>
|
||||
ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module()))
|
||||
void opers_comparison(Module& m)
|
||||
{
|
||||
operators::equal<T>(m);
|
||||
operators::greater_than<T>(m);
|
||||
@@ -61,7 +77,6 @@ namespace chaiscript
|
||||
operators::less_than<T>(m);
|
||||
operators::less_than_equal<T>(m);
|
||||
operators::not_equal<T>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,15 +85,14 @@ namespace chaiscript
|
||||
/// \param[in] type The name of the type to add the constructors for.
|
||||
/// \param[in,out] m The Module to add the basic constructors to
|
||||
/// \tparam T Type to generate basic constructors for
|
||||
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
||||
/// \returns The passed in Module
|
||||
/// \sa copy_constructor
|
||||
/// \sa constructor
|
||||
template<typename T>
|
||||
ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void basic_constructors(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(constructor<T ()>(), type);
|
||||
m.add(constructor<T ()>(), type);
|
||||
copy_constructor<T>(type, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/// \brief Adds a constructor for a POD type
|
||||
@@ -86,85 +100,76 @@ namespace chaiscript
|
||||
/// \param[in] type The name of the type
|
||||
/// \param[in,out] m The Module to add the constructor to
|
||||
template<typename T>
|
||||
ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void construct_pod(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(fun(&detail::construct_pod<T>), type);
|
||||
return m;
|
||||
m.add(fun([](const Boxed_Number &bn){ return bn.get_as<T>(); }), type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* to_string function for internal use. Uses ostream operator<<
|
||||
*/
|
||||
/// Internal function for converting from a string to a value
|
||||
/// uses ostream operator >> to perform the conversion
|
||||
template<typename Input>
|
||||
std::string to_string(Input i)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function for converting from a string to a value
|
||||
* uses ostream operator >> to perform the conversion
|
||||
*/
|
||||
template<typename Input>
|
||||
Input parse_string(const std::string &i)
|
||||
auto parse_string(const std::string &i)
|
||||
-> typename std::enable_if<
|
||||
!std::is_same<Input, wchar_t>::value
|
||||
&& !std::is_same<Input, char16_t>::value
|
||||
&& !std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
std::stringstream ss(i);
|
||||
Input t;
|
||||
ss >> t;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add all common functions for a POD type. All operators, and
|
||||
* common conversions
|
||||
*/
|
||||
template<typename T>
|
||||
ModulePtr bootstrap_pod_type(const std::string &name, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(user_type<T>(), name);
|
||||
m->add(constructor<T ()>(), name);
|
||||
construct_pod<T>(name, m);
|
||||
|
||||
m->add(fun(&to_string<T>), "to_string");
|
||||
m->add(fun(&parse_string<T>), "to_" + name);
|
||||
return m;
|
||||
template<typename Input>
|
||||
auto parse_string(const std::string &)
|
||||
-> typename std::enable_if<
|
||||
std::is_same<Input, wchar_t>::value
|
||||
|| std::is_same<Input, char16_t>::value
|
||||
|| std::is_same<Input, char32_t>::value,
|
||||
Input>::type
|
||||
{
|
||||
throw std::runtime_error("Parsing of wide characters is not yet supported");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* "clone" function for a shared_ptr type. This is used in the case
|
||||
* where you do not want to make a deep copy of an object during cloning
|
||||
* but want to instead maintain the shared_ptr. It is needed internally
|
||||
* for handling of Proxy_Function object (that is,
|
||||
* function variables.
|
||||
*/
|
||||
/// Add all common functions for a POD type. All operators, and
|
||||
/// common conversions
|
||||
template<typename T>
|
||||
void bootstrap_pod_type(const std::string &name, Module& m)
|
||||
{
|
||||
m.add(user_type<T>(), name);
|
||||
m.add(constructor<T()>(), name);
|
||||
construct_pod<T>(name, m);
|
||||
|
||||
m.add(fun(&parse_string<T>), "to_" + name);
|
||||
}
|
||||
|
||||
|
||||
/// "clone" function for a shared_ptr type. This is used in the case
|
||||
/// where you do not want to make a deep copy of an object during cloning
|
||||
/// but want to instead maintain the shared_ptr. It is needed internally
|
||||
/// for handling of Proxy_Function object (that is,
|
||||
/// function variables.
|
||||
template<typename Type>
|
||||
std::shared_ptr<Type> shared_ptr_clone(const std::shared_ptr<Type> &p)
|
||||
auto shared_ptr_clone(const std::shared_ptr<Type> &p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific version of shared_ptr_clone just for Proxy_Functions
|
||||
*/
|
||||
/// Specific version of shared_ptr_clone just for Proxy_Functions
|
||||
template<typename Type>
|
||||
std::shared_ptr<typename std::remove_const<Type>::type>
|
||||
shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||
std::shared_ptr<typename std::remove_const<Type>::type> shared_ptr_unconst_clone(const std::shared_ptr<typename std::add_const<Type>::type> &p)
|
||||
{
|
||||
return std::const_pointer_cast<typename std::remove_const<Type>::type>(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Assignment function for shared_ptr objects, does not perform a copy of the
|
||||
* object pointed to, instead maintains the shared_ptr concept.
|
||||
* Similar to shared_ptr_clone. Used for Proxy_Function.
|
||||
*/
|
||||
/// Assignment function for shared_ptr objects, does not perform a copy of the
|
||||
/// object pointed to, instead maintains the shared_ptr concept.
|
||||
/// Similar to shared_ptr_clone. Used for Proxy_Function.
|
||||
template<typename Type>
|
||||
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
|
||||
{
|
||||
@@ -178,16 +183,12 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class consisting of only static functions. All default bootstrapping occurs
|
||||
* from this class.
|
||||
*/
|
||||
/// Class consisting of only static functions. All default bootstrapping occurs
|
||||
/// from this class.
|
||||
class Bootstrap
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Function allowing for assignment of an unknown type to any other value
|
||||
*/
|
||||
/// Function allowing for assignment of an unknown type to any other value
|
||||
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
|
||||
{
|
||||
if (lhs.is_undef())
|
||||
@@ -200,148 +201,90 @@ namespace chaiscript
|
||||
|
||||
static void print(const std::string &s)
|
||||
{
|
||||
std::cout << s;
|
||||
fwrite(s.c_str(), 1, s.size(), stdout);
|
||||
}
|
||||
|
||||
static void println(const std::string &s)
|
||||
{
|
||||
std::cout << s << std::endl;
|
||||
puts(s.c_str());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add all arithmetic operators for PODs
|
||||
*/
|
||||
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
|
||||
/// Add all arithmetic operators for PODs
|
||||
static void opers_arithmetic_pod(Module& m)
|
||||
{
|
||||
m->add(fun(&Boxed_Number::equals), "==");
|
||||
m->add(fun(&Boxed_Number::less_than), "<");
|
||||
m->add(fun(&Boxed_Number::greater_than), ">");
|
||||
m->add(fun(&Boxed_Number::greater_than_equal), ">=");
|
||||
m->add(fun(&Boxed_Number::less_than_equal), "<=");
|
||||
m->add(fun(&Boxed_Number::not_equal), "!=");
|
||||
|
||||
m->add(fun(&Boxed_Number::pre_decrement), "--");
|
||||
m->add(fun(&Boxed_Number::pre_increment), "++");
|
||||
m->add(fun(&Boxed_Number::sum), "+");
|
||||
m->add(fun(&Boxed_Number::unary_plus), "+");
|
||||
m->add(fun(&Boxed_Number::unary_minus), "-");
|
||||
m->add(fun(&Boxed_Number::difference), "-");
|
||||
m->add(fun(&Boxed_Number::assign_bitwise_and), "&=");
|
||||
m->add(fun(&Boxed_Number::assign), "=");
|
||||
m->add(fun(&Boxed_Number::assign_bitwise_or), "|=");
|
||||
m->add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
|
||||
m->add(fun(&Boxed_Number::assign_remainder), "%=");
|
||||
m->add(fun(&Boxed_Number::assign_shift_left), "<<=");
|
||||
m->add(fun(&Boxed_Number::assign_shift_right), ">>=");
|
||||
m->add(fun(&Boxed_Number::bitwise_and), "&");
|
||||
m->add(fun(&Boxed_Number::bitwise_complement), "~");
|
||||
m->add(fun(&Boxed_Number::bitwise_xor), "^");
|
||||
m->add(fun(&Boxed_Number::bitwise_or), "|");
|
||||
m->add(fun(&Boxed_Number::assign_product), "*=");
|
||||
m->add(fun(&Boxed_Number::assign_quotient), "/=");
|
||||
m->add(fun(&Boxed_Number::assign_sum), "+=");
|
||||
m->add(fun(&Boxed_Number::assign_difference), "-=");
|
||||
m->add(fun(&Boxed_Number::quotient), "/");
|
||||
m->add(fun(&Boxed_Number::shift_left), "<<");
|
||||
m->add(fun(&Boxed_Number::product), "*");
|
||||
m->add(fun(&Boxed_Number::remainder), "%");
|
||||
m->add(fun(&Boxed_Number::shift_right), ">>");
|
||||
|
||||
m.add(fun(&Boxed_Number::equals), "==");
|
||||
m.add(fun(&Boxed_Number::less_than), "<");
|
||||
m.add(fun(&Boxed_Number::greater_than), ">");
|
||||
m.add(fun(&Boxed_Number::greater_than_equal), ">=");
|
||||
m.add(fun(&Boxed_Number::less_than_equal), "<=");
|
||||
m.add(fun(&Boxed_Number::not_equal), "!=");
|
||||
|
||||
m.add(fun(&Boxed_Number::pre_decrement), "--");
|
||||
m.add(fun(&Boxed_Number::pre_increment), "++");
|
||||
m.add(fun(&Boxed_Number::sum), "+");
|
||||
m.add(fun(&Boxed_Number::unary_plus), "+");
|
||||
m.add(fun(&Boxed_Number::unary_minus), "-");
|
||||
m.add(fun(&Boxed_Number::difference), "-");
|
||||
m.add(fun(&Boxed_Number::assign_bitwise_and), "&=");
|
||||
m.add(fun(&Boxed_Number::assign), "=");
|
||||
m.add(fun(&Boxed_Number::assign_bitwise_or), "|=");
|
||||
m.add(fun(&Boxed_Number::assign_bitwise_xor), "^=");
|
||||
m.add(fun(&Boxed_Number::assign_remainder), "%=");
|
||||
m.add(fun(&Boxed_Number::assign_shift_left), "<<=");
|
||||
m.add(fun(&Boxed_Number::assign_shift_right), ">>=");
|
||||
m.add(fun(&Boxed_Number::bitwise_and), "&");
|
||||
m.add(fun(&Boxed_Number::bitwise_complement), "~");
|
||||
m.add(fun(&Boxed_Number::bitwise_xor), "^");
|
||||
m.add(fun(&Boxed_Number::bitwise_or), "|");
|
||||
m.add(fun(&Boxed_Number::assign_product), "*=");
|
||||
m.add(fun(&Boxed_Number::assign_quotient), "/=");
|
||||
m.add(fun(&Boxed_Number::assign_sum), "+=");
|
||||
m.add(fun(&Boxed_Number::assign_difference), "-=");
|
||||
m.add(fun(&Boxed_Number::quotient), "/");
|
||||
m.add(fun(&Boxed_Number::shift_left), "<<");
|
||||
m.add(fun(&Boxed_Number::product), "*");
|
||||
m.add(fun(&Boxed_Number::remainder), "%");
|
||||
m.add(fun(&Boxed_Number::shift_right), ">>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bound function object. The first param is the function to bind
|
||||
* the remaining parameters are the args to bind into the
|
||||
* result
|
||||
*/
|
||||
/// Create a bound function object. The first param is the function to bind
|
||||
/// the remaining parameters are the args to bind into the result
|
||||
static Boxed_Value bind_function(const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 2);
|
||||
if (params.empty()) {
|
||||
throw exception::arity_error(0, 1);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
|
||||
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
|
||||
if (f->get_arity() != -1 && size_t(f->get_arity()) != params.size() - 1)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), f->get_arity());
|
||||
}
|
||||
|
||||
return Boxed_Value(Const_Proxy_Function(std::make_shared<dispatch::Bound_Function>(std::move(f),
|
||||
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a call can be made that consists of the first parameter
|
||||
* (the function) with the remaining parameters as its arguments.
|
||||
*/
|
||||
static Boxed_Value call_exists(const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() < 1)
|
||||
{
|
||||
throw exception::arity_error(static_cast<int>(params.size()), 1);
|
||||
}
|
||||
|
||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||
|
||||
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
|
||||
}
|
||||
|
||||
static bool has_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
{
|
||||
return bool(pf->get_guard());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return pf && pf->get_guard();
|
||||
}
|
||||
|
||||
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf)
|
||||
{
|
||||
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf)
|
||||
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf && pf->get_guard())
|
||||
{
|
||||
if (pf->get_guard())
|
||||
{
|
||||
return pf->get_guard();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a guard");
|
||||
}
|
||||
return pf->get_guard();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a guard");
|
||||
}
|
||||
}
|
||||
|
||||
static void throw_exception(const Boxed_Value &bv) {
|
||||
throw bv;
|
||||
}
|
||||
|
||||
static std::shared_ptr<chaiscript::detail::Dispatch_Engine> bootstrap2(
|
||||
std::shared_ptr<chaiscript::detail::Dispatch_Engine> e
|
||||
= std::shared_ptr<chaiscript::detail::Dispatch_Engine> (new chaiscript::detail::Dispatch_Engine()))
|
||||
{
|
||||
e->add(user_type<void>(), "void");
|
||||
return e;
|
||||
}
|
||||
|
||||
static std::string what(const std::exception &e)
|
||||
{
|
||||
return e.what();
|
||||
}
|
||||
|
||||
/**
|
||||
* Boolean specialization of internal to_string function
|
||||
*/
|
||||
static std::string bool_to_string(bool b)
|
||||
{
|
||||
if (b)
|
||||
{
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FunctionType>
|
||||
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f,
|
||||
const dispatch::Proxy_Function_Base *b)
|
||||
@@ -358,87 +301,169 @@ namespace chaiscript
|
||||
return vbv;
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
||||
|
||||
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
|
||||
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
return pf && pf->get_parse_tree();
|
||||
}
|
||||
|
||||
static chaiscript::AST_NodePtr get_parse_tree(const chaiscript::Const_Proxy_Function &t_pf)
|
||||
{
|
||||
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||
if (pf && pf->get_parse_tree())
|
||||
{
|
||||
return pf->get_parse_tree();
|
||||
} else {
|
||||
throw std::runtime_error("Function does not have a parse tree");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Function>
|
||||
static auto return_boxed_value_vector(const Function &f)
|
||||
{
|
||||
return [f](const dispatch::Proxy_Function_Base *b) {
|
||||
return do_return_boxed_value_vector(f, b);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
/// \brief perform all common bootstrap functions for std::string, void and POD types
|
||||
/// \param[in,out] m Module to add bootstrapped functions to
|
||||
/// \returns passed in ModulePtr, or newly created one if default argument is used
|
||||
static ModulePtr bootstrap(ModulePtr m = ModulePtr(new Module()))
|
||||
/// \returns passed in Module
|
||||
static void bootstrap(Module& m)
|
||||
{
|
||||
m->add(user_type<void>(), "void");
|
||||
m->add(user_type<bool>(), "bool");
|
||||
m->add(user_type<Boxed_Value>(), "Object");
|
||||
m->add(user_type<Boxed_Number>(), "Number");
|
||||
m->add(user_type<Proxy_Function>(), "Function");
|
||||
m->add(user_type<std::exception>(), "exception");
|
||||
m.add(user_type<void>(), "void");
|
||||
m.add(user_type<bool>(), "bool");
|
||||
m.add(user_type<Boxed_Value>(), "Object");
|
||||
m.add(user_type<Boxed_Number>(), "Number");
|
||||
m.add(user_type<Proxy_Function>(), "Function");
|
||||
m.add(user_type<dispatch::Assignable_Proxy_Function>(), "Assignable_Function");
|
||||
m.add(user_type<std::exception>(), "exception");
|
||||
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::annotation), "get_annotation");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::operator()), "call");
|
||||
m->add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
||||
|
||||
|
||||
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
|
||||
m->add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::get_arity), "get_arity");
|
||||
m.add(fun(&dispatch::Proxy_Function_Base::operator==), "==");
|
||||
|
||||
|
||||
m->add(user_type<std::runtime_error>(), "runtime_error");
|
||||
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_param_types)), "get_param_types");
|
||||
m.add(fun(return_boxed_value_vector(&dispatch::Proxy_Function_Base::get_contained_functions)), "get_contained_functions");
|
||||
|
||||
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
m->add(fun(std::function<std::string (const std::runtime_error &)>(&what)), "what");
|
||||
m.add(fun([](const std::exception &e){ return std::string(e.what()); }), "what");
|
||||
|
||||
m->add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
||||
m->add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
||||
m->add(fun(&dispatch::Dynamic_Object::get_attr), "get_attr");
|
||||
m.add(user_type<std::out_of_range>(), "out_of_range");
|
||||
m.add(user_type<std::logic_error>(), "logic_error");
|
||||
m.add(chaiscript::base_class<std::exception, std::logic_error>());
|
||||
m.add(chaiscript::base_class<std::logic_error, std::out_of_range>());
|
||||
m.add(chaiscript::base_class<std::exception, std::out_of_range>());
|
||||
|
||||
m->eval("def Dynamic_Object::clone() { auto &new_o = Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
|
||||
m.add(user_type<std::runtime_error>(), "runtime_error");
|
||||
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||
|
||||
m->add(fun(&has_guard), "has_guard");
|
||||
m->add(fun(&get_guard), "get_guard");
|
||||
m.add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
|
||||
|
||||
m->add(fun(&Boxed_Value::is_undef), "is_var_undef");
|
||||
m->add(fun(&Boxed_Value::is_null), "is_var_null");
|
||||
m->add(fun(&Boxed_Value::is_const), "is_var_const");
|
||||
m->add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
||||
m->add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
||||
m->add(fun(&Boxed_Value::is_type), "is_type");
|
||||
m.add(user_type<dispatch::Dynamic_Object>(), "Dynamic_Object");
|
||||
m.add(constructor<dispatch::Dynamic_Object (const std::string &)>(), "Dynamic_Object");
|
||||
m.add(constructor<dispatch::Dynamic_Object ()>(), "Dynamic_Object");
|
||||
m.add(fun(&dispatch::Dynamic_Object::get_type_name), "get_type_name");
|
||||
m.add(fun(&dispatch::Dynamic_Object::get_attrs), "get_attrs");
|
||||
m.add(fun(&dispatch::Dynamic_Object::set_explicit), "set_explicit");
|
||||
m.add(fun(&dispatch::Dynamic_Object::is_explicit), "is_explicit");
|
||||
m.add(fun(&dispatch::Dynamic_Object::has_attr), "has_attr");
|
||||
|
||||
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
||||
m->add(user_type<Type_Info>(), "Type_Info");
|
||||
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "get_attr");
|
||||
|
||||
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
|
||||
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::method_missing)), "method_missing");
|
||||
|
||||
m.add(fun(static_cast<Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &)>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||
m.add(fun(static_cast<const Boxed_Value & (dispatch::Dynamic_Object::*)(const std::string &) const>(&dispatch::Dynamic_Object::get_attr)), "[]");
|
||||
|
||||
m.eval(R"chaiscript(
|
||||
def Dynamic_Object::clone() {
|
||||
auto &new_o = Dynamic_Object(this.get_type_name());
|
||||
for_each(this.get_attrs(), fun[new_o](x) { new_o.get_attr(x.first) = x.second; } );
|
||||
new_o;
|
||||
}
|
||||
|
||||
def `=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
|
||||
{
|
||||
for_each(rhs.get_attrs(), fun[lhs](x) { lhs.get_attr(x.first) = clone(x.second); } );
|
||||
}
|
||||
|
||||
def `!=`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
|
||||
{
|
||||
var rhs_attrs := rhs.get_attrs();
|
||||
var lhs_attrs := lhs.get_attrs();
|
||||
|
||||
if (rhs_attrs.size() != lhs_attrs.size()) {
|
||||
true;
|
||||
} else {
|
||||
return any_of(rhs_attrs, fun[lhs](x) { !lhs.has_attr(x.first) || lhs.get_attr(x.first) != x.second; } );
|
||||
}
|
||||
}
|
||||
|
||||
def `==`(Dynamic_Object lhs, Dynamic_Object rhs) : lhs.get_type_name() == rhs.get_type_name()
|
||||
{
|
||||
var rhs_attrs := rhs.get_attrs();
|
||||
var lhs_attrs := lhs.get_attrs();
|
||||
|
||||
if (rhs_attrs.size() != lhs_attrs.size()) {
|
||||
false;
|
||||
} else {
|
||||
return all_of(rhs_attrs, fun[lhs](x) { lhs.has_attr(x.first) && lhs.get_attr(x.first) == x.second; } );
|
||||
}
|
||||
}
|
||||
)chaiscript");
|
||||
|
||||
m.add(fun(&has_guard), "has_guard");
|
||||
m.add(fun(&get_guard), "get_guard");
|
||||
|
||||
m.add(fun(&Boxed_Value::is_undef), "is_var_undef");
|
||||
m.add(fun(&Boxed_Value::is_null), "is_var_null");
|
||||
m.add(fun(&Boxed_Value::is_const), "is_var_const");
|
||||
m.add(fun(&Boxed_Value::is_ref), "is_var_reference");
|
||||
m.add(fun(&Boxed_Value::is_pointer), "is_var_pointer");
|
||||
m.add(fun(&Boxed_Value::is_return_value), "is_var_return_value");
|
||||
m.add(fun(&Boxed_Value::reset_return_value), "reset_var_return_value");
|
||||
m.add(fun(&Boxed_Value::is_type), "is_type");
|
||||
m.add(fun(&Boxed_Value::get_attr), "get_var_attr");
|
||||
m.add(fun(&Boxed_Value::copy_attrs), "copy_var_attrs");
|
||||
m.add(fun(&Boxed_Value::clone_attrs), "clone_var_attrs");
|
||||
|
||||
m.add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
||||
m.add(user_type<Type_Info>(), "Type_Info");
|
||||
m.add(constructor<Type_Info (const Type_Info &)>(), "Type_Info");
|
||||
|
||||
|
||||
operators::equal<Type_Info>(m);
|
||||
|
||||
m->add(fun(&Type_Info::is_const), "is_type_const");
|
||||
m->add(fun(&Type_Info::is_reference), "is_type_reference");
|
||||
m->add(fun(&Type_Info::is_void), "is_type_void");
|
||||
m->add(fun(&Type_Info::is_undef), "is_type_undef");
|
||||
m->add(fun(&Type_Info::is_pointer), "is_type_pointer");
|
||||
m->add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
|
||||
m->add(fun(&Type_Info::name), "cpp_name");
|
||||
m->add(fun(&Type_Info::bare_name), "cpp_bare_name");
|
||||
m->add(fun(&Type_Info::bare_equal), "bare_equal");
|
||||
m.add(fun(&Type_Info::is_const), "is_type_const");
|
||||
m.add(fun(&Type_Info::is_reference), "is_type_reference");
|
||||
m.add(fun(&Type_Info::is_void), "is_type_void");
|
||||
m.add(fun(&Type_Info::is_undef), "is_type_undef");
|
||||
m.add(fun(&Type_Info::is_pointer), "is_type_pointer");
|
||||
m.add(fun(&Type_Info::is_arithmetic), "is_type_arithmetic");
|
||||
m.add(fun(&Type_Info::name), "cpp_name");
|
||||
m.add(fun(&Type_Info::bare_name), "cpp_bare_name");
|
||||
m.add(fun(&Type_Info::bare_equal), "bare_equal");
|
||||
|
||||
|
||||
basic_constructors<bool>("bool", m);
|
||||
operators::assign<bool>(m);
|
||||
operators::equal<bool>(m);
|
||||
operators::not_equal<bool>(m);
|
||||
|
||||
m->add(fun(&to_string<const std::string &>), "internal_to_string");
|
||||
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
|
||||
m->add(fun(&unknown_assign), "=");
|
||||
m->add(fun(&throw_exception), "throw");
|
||||
m->add(fun(&what), "what");
|
||||
m.add(fun([](const std::string &s) { return s; }), "to_string");
|
||||
m.add(fun([](const bool b) { return std::string(b?"true":"false"); }), "to_string");
|
||||
m.add(fun(&unknown_assign), "=");
|
||||
m.add(fun([](const Boxed_Value &bv) { throw bv; }), "throw");
|
||||
|
||||
m.add(fun([](const char c) { return std::string(1, c); }), "to_string");
|
||||
m.add(fun(&Boxed_Number::to_string), "to_string");
|
||||
|
||||
|
||||
bootstrap_pod_type<double>("double", m);
|
||||
bootstrap_pod_type<long double>("long_double", m);
|
||||
bootstrap_pod_type<float>("float", m);
|
||||
@@ -446,8 +471,13 @@ namespace chaiscript
|
||||
bootstrap_pod_type<long>("long", m);
|
||||
bootstrap_pod_type<unsigned int>("unsigned_int", m);
|
||||
bootstrap_pod_type<unsigned long>("unsigned_long", m);
|
||||
bootstrap_pod_type<long long>("long_long", m);
|
||||
bootstrap_pod_type<unsigned long long>("unsigned_long_long", m);
|
||||
bootstrap_pod_type<size_t>("size_t", m);
|
||||
bootstrap_pod_type<char>("char", m);
|
||||
bootstrap_pod_type<wchar_t>("wchar_t", m);
|
||||
bootstrap_pod_type<char16_t>("char16_t", m);
|
||||
bootstrap_pod_type<char32_t>("char32_t", m);
|
||||
bootstrap_pod_type<std::int8_t>("int8_t", m);
|
||||
bootstrap_pod_type<std::int16_t>("int16_t", m);
|
||||
bootstrap_pod_type<std::int32_t>("int32_t", m);
|
||||
@@ -457,27 +487,99 @@ namespace chaiscript
|
||||
bootstrap_pod_type<std::uint32_t>("uint32_t", m);
|
||||
bootstrap_pod_type<std::uint64_t>("uint64_t", m);
|
||||
|
||||
|
||||
operators::logical_compliment<bool>(m);
|
||||
|
||||
opers_arithmetic_pod(m);
|
||||
|
||||
|
||||
m.add(fun(&Build_Info::version_major), "version_major");
|
||||
m.add(fun(&Build_Info::version_minor), "version_minor");
|
||||
m.add(fun(&Build_Info::version_patch), "version_patch");
|
||||
m.add(fun(&Build_Info::version), "version");
|
||||
m.add(fun(&Build_Info::compiler_version), "compiler_version");
|
||||
m.add(fun(&Build_Info::compiler_name), "compiler_name");
|
||||
m.add(fun(&Build_Info::compiler_id), "compiler_id");
|
||||
m.add(fun(&Build_Info::debug_build), "debug_build");
|
||||
|
||||
m->add(fun(&print), "print_string");
|
||||
m->add(fun(&println), "println_string");
|
||||
|
||||
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&bind_function, std::placeholders::_1))),
|
||||
"bind");
|
||||
m.add(fun(&print), "print_string");
|
||||
m.add(fun(&println), "println_string");
|
||||
|
||||
m->add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
||||
m->add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m->add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m.add(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
||||
|
||||
m->add(Proxy_Function(new dispatch::Dynamic_Proxy_Function(std::bind(&call_exists, std::placeholders::_1))),
|
||||
"call_exists");
|
||||
m.add(fun(&shared_ptr_unconst_clone<dispatch::Proxy_Function_Base>), "clone");
|
||||
m.add(fun(&ptr_assign<std::remove_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m.add(fun(&ptr_assign<std::add_const<dispatch::Proxy_Function_Base>::type>), "=");
|
||||
m.add(chaiscript::base_class<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function>());
|
||||
m.add(fun(
|
||||
[](dispatch::Assignable_Proxy_Function &t_lhs, const std::shared_ptr<const dispatch::Proxy_Function_Base> &t_rhs) {
|
||||
t_lhs.assign(t_rhs);
|
||||
}
|
||||
), "="
|
||||
);
|
||||
|
||||
m->add(fun(&Boxed_Value::type_match), "type_match");
|
||||
m.add(fun(&Boxed_Value::type_match), "type_match");
|
||||
|
||||
|
||||
m.add(chaiscript::fun(&has_parse_tree), "has_parse_tree");
|
||||
m.add(chaiscript::fun(&get_parse_tree), "get_parse_tree");
|
||||
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::eval_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::eval_error>());
|
||||
|
||||
m.add(chaiscript::user_type<chaiscript::exception::arithmetic_error>(), "arithmetic_error");
|
||||
m.add(chaiscript::base_class<std::runtime_error, chaiscript::exception::arithmetic_error>());
|
||||
m.add(chaiscript::base_class<std::exception, chaiscript::exception::arithmetic_error>());
|
||||
|
||||
|
||||
// chaiscript::bootstrap::standard_library::vector_type<std::vector<std::shared_ptr<chaiscript::AST_Node> > >("AST_NodeVector", m);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::exception::eval_error>(m,
|
||||
"eval_error",
|
||||
{ },
|
||||
{ {fun(&chaiscript::exception::eval_error::reason), "reason"},
|
||||
{fun(&chaiscript::exception::eval_error::pretty_print), "pretty_print"},
|
||||
{fun([](const chaiscript::exception::eval_error &t_eval_error) {
|
||||
std::vector<Boxed_Value> retval;
|
||||
std::transform(t_eval_error.call_stack.begin(), t_eval_error.call_stack.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<const chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
}), "call_stack"} }
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<chaiscript::File_Position>(m,
|
||||
"File_Position",
|
||||
{ constructor<File_Position()>(),
|
||||
constructor<File_Position(int, int)>() },
|
||||
{ {fun(&File_Position::line), "line"},
|
||||
{fun(&File_Position::column), "column"} }
|
||||
);
|
||||
|
||||
|
||||
chaiscript::utility::add_class<AST_Node>(m,
|
||||
"AST_Node",
|
||||
{ },
|
||||
{ {fun(&AST_Node::text), "text"},
|
||||
{fun(&AST_Node::identifier), "identifier"},
|
||||
{fun(&AST_Node::filename), "filename"},
|
||||
{fun(&AST_Node::start), "start"},
|
||||
{fun(&AST_Node::end), "end"},
|
||||
{fun(&AST_Node::to_string), "to_string"},
|
||||
{fun([](const chaiscript::AST_Node &t_node) -> std::vector<Boxed_Value> {
|
||||
std::vector<Boxed_Value> retval;
|
||||
const auto children = t_node.get_children();
|
||||
std::transform(children.begin(), children.end(),
|
||||
std::back_inserter(retval),
|
||||
&chaiscript::var<const std::shared_ptr<chaiscript::AST_Node> &>);
|
||||
return retval;
|
||||
}), "children"}
|
||||
}
|
||||
);
|
||||
|
||||
return m;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
/**
|
||||
* \file
|
||||
* This file contains utility functions for registration of STL container
|
||||
* classes. The methodology used is based on the SGI STL concepts.
|
||||
* http://www.sgi.com/tech/stl/table_of_contents.html
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
/// \file
|
||||
/// This file contains utility functions for registration of STL container
|
||||
/// classes. The methodology used is based on the SGI STL concepts.
|
||||
/// http://www.sgi.com/tech/stl/table_of_contents.html
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
||||
#define CHAISCRIPT_BOOTSTRAP_STL_HPP_
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
#include "bootstrap.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "dispatchkit.hpp"
|
||||
#include "operators.hpp"
|
||||
#include "proxy_constructors.hpp"
|
||||
#include "register_function.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -26,16 +37,14 @@ namespace chaiscript
|
||||
{
|
||||
namespace standard_library
|
||||
{
|
||||
/**
|
||||
* Bidir_Range, based on the D concept of ranges.
|
||||
* \todo Update the Range code to base its capabilities on
|
||||
* the user_typetraits of the iterator passed in
|
||||
*/
|
||||
template<typename Container>
|
||||
|
||||
/// Bidir_Range, based on the D concept of ranges.
|
||||
/// \todo Update the Range code to base its capabilities on
|
||||
/// the user_typetraits of the iterator passed in
|
||||
template<typename Container, typename IterType>
|
||||
struct Bidir_Range
|
||||
{
|
||||
typedef Container container_type;
|
||||
typedef typename std::iterator_traits<typename Container::iterator>::reference reference_type;
|
||||
|
||||
Bidir_Range(Container &c)
|
||||
: m_begin(c.begin()), m_end(c.end())
|
||||
@@ -65,90 +74,38 @@ namespace chaiscript
|
||||
--m_end;
|
||||
}
|
||||
|
||||
reference_type front() const
|
||||
decltype(auto) front() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
return *m_begin;
|
||||
return (*m_begin);
|
||||
}
|
||||
|
||||
reference_type back() const
|
||||
decltype(auto) back() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
typename Container::iterator pos = m_end;
|
||||
auto pos = m_end;
|
||||
--pos;
|
||||
return *(pos);
|
||||
return (*(pos));
|
||||
}
|
||||
|
||||
typename Container::iterator m_begin;
|
||||
typename Container::iterator m_end;
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
struct Const_Bidir_Range
|
||||
{
|
||||
typedef const Container container_type;
|
||||
typedef typename std::iterator_traits<typename Container::const_iterator>::reference const_reference_type;
|
||||
|
||||
Const_Bidir_Range(const Container &c)
|
||||
: m_begin(c.begin()), m_end(c.end())
|
||||
{
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return m_begin == m_end;
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
++m_begin;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
--m_end;
|
||||
}
|
||||
|
||||
const_reference_type front() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
return *m_begin;
|
||||
}
|
||||
|
||||
const_reference_type back() const
|
||||
{
|
||||
if (empty())
|
||||
{
|
||||
throw std::range_error("Range empty");
|
||||
}
|
||||
typename Container::const_iterator pos = m_end;
|
||||
--pos;
|
||||
return *(pos);
|
||||
}
|
||||
|
||||
typename Container::const_iterator m_begin;
|
||||
typename Container::const_iterator m_end;
|
||||
IterType m_begin;
|
||||
IterType m_end;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename T>
|
||||
size_t count(const T &t_target, const typename T::key_type &t_key)
|
||||
{
|
||||
return t_target.count(t_key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void insert(T &t_target, const T &t_other)
|
||||
{
|
||||
@@ -163,35 +120,30 @@ namespace chaiscript
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add Bidir_Range support for the given ContainerType
|
||||
*/
|
||||
/// Add Bidir_Range support for the given ContainerType
|
||||
template<typename Bidir_Type>
|
||||
ModulePtr input_range_type_impl(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void input_range_type_impl(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(user_type<Bidir_Type>(), type + "_Range");
|
||||
m.add(user_type<Bidir_Type>(), type + "_Range");
|
||||
|
||||
copy_constructor<Bidir_Type>(type + "_Range", m);
|
||||
|
||||
m->add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range");
|
||||
m.add(constructor<Bidir_Type (typename Bidir_Type::container_type &)>(), "range_internal");
|
||||
|
||||
m->add(fun(&Bidir_Type::empty), "empty");
|
||||
m->add(fun(&Bidir_Type::pop_front), "pop_front");
|
||||
m->add(fun(&Bidir_Type::front), "front");
|
||||
m->add(fun(&Bidir_Type::pop_back), "pop_back");
|
||||
m->add(fun(&Bidir_Type::back), "back");
|
||||
m.add(fun(&Bidir_Type::empty), "empty");
|
||||
m.add(fun(&Bidir_Type::pop_front), "pop_front");
|
||||
m.add(fun(&Bidir_Type::front), "front");
|
||||
m.add(fun(&Bidir_Type::pop_back), "pop_back");
|
||||
m.add(fun(&Bidir_Type::back), "back");
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Algorithm for inserting at a specific position into a container
|
||||
*/
|
||||
/// Algorithm for inserting at a specific position into a container
|
||||
template<typename Type>
|
||||
void insert_at(Type &container, int pos, const typename Type::value_type &v)
|
||||
{
|
||||
typename Type::iterator itr = container.begin();
|
||||
typename Type::iterator end = container.end();
|
||||
auto itr = container.begin();
|
||||
auto end = container.end();
|
||||
|
||||
if (pos < 0 || std::distance(itr, end) < pos)
|
||||
{
|
||||
@@ -202,14 +154,13 @@ namespace chaiscript
|
||||
container.insert(itr, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Algorithm for erasing a specific position from a container
|
||||
*/
|
||||
|
||||
/// Algorithm for erasing a specific position from a container
|
||||
template<typename Type>
|
||||
void erase_at(Type &container, int pos)
|
||||
{
|
||||
typename Type::iterator itr = container.begin();
|
||||
typename Type::iterator end = container.end();
|
||||
auto itr = container.begin();
|
||||
auto end = container.end();
|
||||
|
||||
if (pos < 0 || std::distance(itr, end) < (pos-1))
|
||||
{
|
||||
@@ -218,271 +169,426 @@ namespace chaiscript
|
||||
|
||||
std::advance(itr, pos);
|
||||
container.erase(itr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ContainerType>
|
||||
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void input_range_type(const std::string &type, Module& m)
|
||||
{
|
||||
detail::input_range_type_impl<Bidir_Range<ContainerType> >(type,m);
|
||||
detail::input_range_type_impl<Const_Bidir_Range<ContainerType> >("Const_" + type, m);
|
||||
detail::input_range_type_impl<Bidir_Range<ContainerType, typename ContainerType::iterator> >(type,m);
|
||||
detail::input_range_type_impl<Bidir_Range<const ContainerType, typename ContainerType::const_iterator> >("Const_" + type,m);
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr input_range_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
input_range_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add random_access_container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/RandomAccessContainer.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
typedef typename ContainerType::reference(ContainerType::*indexoper)(size_t);
|
||||
typedef typename ContainerType::const_reference(ContainerType::*constindexoper)(size_t) const;
|
||||
|
||||
/// Add random_access_container concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/RandomAccessContainer.html
|
||||
template<typename ContainerType>
|
||||
void random_access_container_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
||||
//to throw an exception in an out of bounds condition.
|
||||
m->add(
|
||||
fun(std::function<typename ContainerType::reference (ContainerType *, int)>
|
||||
(std::mem_fn(static_cast<indexoper>(&ContainerType::at)))), "[]");
|
||||
m->add(
|
||||
fun(std::function<typename ContainerType::const_reference (const ContainerType *, int)>
|
||||
(std::mem_fn(static_cast<constindexoper>(&ContainerType::at)))), "[]");
|
||||
m.add(
|
||||
fun(
|
||||
[](ContainerType &c, int index) -> typename ContainerType::reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
/// during dispatch. reevaluate
|
||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
||||
}), "[]");
|
||||
|
||||
m.add(
|
||||
fun(
|
||||
[](const ContainerType &c, int index) -> typename ContainerType::const_reference {
|
||||
/// \todo we are prefering to keep the key as 'int' to avoid runtime conversions
|
||||
/// during dispatch. reevaluate
|
||||
return c.at(static_cast<typename ContainerType::size_type>(index));
|
||||
}), "[]");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr random_access_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
random_access_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add assignable concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Assignable.html
|
||||
*/
|
||||
|
||||
|
||||
/// Add assignable concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/Assignable.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr assignable_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void assignable_type(const std::string &type, Module& m)
|
||||
{
|
||||
basic_constructors<ContainerType>(type, m);
|
||||
copy_constructor<ContainerType>(type, m);
|
||||
operators::assign<ContainerType>(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Container.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
ModulePtr assignable_type(const std::string &type)
|
||||
{
|
||||
m->add(fun( std::function<int (const ContainerType *)>( [](const ContainerType *a) { return a->size(); } ) ), "size");
|
||||
m->add(fun( std::function<bool (const ContainerType *)>( [](const ContainerType *a) { return a->empty(); } ) ), "empty");
|
||||
m->add(fun( std::function<void (ContainerType *)>( [](ContainerType *a) { a->clear(); } ) ), "clear");
|
||||
auto m = std::make_shared<Module>();
|
||||
assignable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default constructable concept to the given Type
|
||||
* http://www.sgi.com/tech/stl/DefaultConstructible.html
|
||||
*/
|
||||
|
||||
/// Add container resize concept to the given ContainerType
|
||||
/// http://www.cplusplus.com/reference/stl/
|
||||
template<typename ContainerType>
|
||||
void resizable_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n, const typename ContainerType::value_type& val) { return a->resize(n, val); } ), "resize");
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->resize(n); } ), "resize");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr resizable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
resizable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container reserve concept to the given ContainerType
|
||||
/// http://www.cplusplus.com/reference/stl/
|
||||
template<typename ContainerType>
|
||||
void reservable_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
m.add(fun([](ContainerType *a, typename ContainerType::size_type n) { return a->reserve(n); } ), "reserve");
|
||||
m.add(fun([](const ContainerType *a) { return a->capacity(); } ), "capacity");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr reservable_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
reservable_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add container concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/Container.html
|
||||
template<typename ContainerType>
|
||||
void container_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
m.add(fun([](const ContainerType *a) { return a->size(); } ), "size");
|
||||
m.add(fun([](const ContainerType *a) { return a->empty(); } ), "empty");
|
||||
m.add(fun([](ContainerType *a) { a->clear(); } ), "clear");
|
||||
}
|
||||
template <typename ContainerType>
|
||||
ModulePtr container_type(const std::string& type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/// Add default constructable concept to the given Type
|
||||
/// http://www.sgi.com/tech/stl/DefaultConstructible.html
|
||||
template<typename Type>
|
||||
ModulePtr default_constructible_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void default_constructible_type(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(constructor<Type ()>(), type);
|
||||
m.add(constructor<Type ()>(), type);
|
||||
}
|
||||
template <typename Type>
|
||||
ModulePtr default_constructible_type(const std::string& type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
default_constructible_type<Type>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add sequence concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/Sequence.html
|
||||
*/
|
||||
/// Add sequence concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/Sequence.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
void sequence_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
std::string insert_name;
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
|
||||
{
|
||||
insert_name = "insert_ref_at";
|
||||
} else {
|
||||
insert_name = "insert_at";
|
||||
}
|
||||
|
||||
m->add(fun(&detail::insert_at<ContainerType>), insert_name);
|
||||
m->add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
||||
m.add(fun(&detail::insert_at<ContainerType>),
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
return "insert_ref_at";
|
||||
} else {
|
||||
return "insert_at";
|
||||
}
|
||||
}());
|
||||
|
||||
m.add(fun(&detail::erase_at<ContainerType>), "erase_at");
|
||||
}
|
||||
template <typename ContainerType>
|
||||
ModulePtr sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add back insertion sequence concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
||||
*/
|
||||
/// Add back insertion sequence concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/BackInsertionSequence.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr back_insertion_sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
void back_insertion_sequence_type(const std::string &type, Module& m)
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*backptr)();
|
||||
|
||||
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
|
||||
m.add(fun(static_cast<backptr>(&ContainerType::back)), "back");
|
||||
|
||||
std::string push_back_name;
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
|
||||
{
|
||||
push_back_name = "push_back_ref";
|
||||
} else {
|
||||
push_back_name = "push_back";
|
||||
}
|
||||
|
||||
typedef void (ContainerType::*pushback)(const typename ContainerType::value_type &);
|
||||
m->add(fun(static_cast<pushback>(&ContainerType::push_back)), push_back_name);
|
||||
m->add(fun(&ContainerType::pop_back), "pop_back");
|
||||
return m;
|
||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||
m.add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||
[&]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
m.eval(
|
||||
"# Pushes the second value onto the container while making a clone of the value\n"
|
||||
"def push_back(" + type + " container, x)\n"
|
||||
"{ \n"
|
||||
" if (x.is_var_return_value()) {\n"
|
||||
" x.reset_var_return_value() \n"
|
||||
" container.push_back_ref(x) \n"
|
||||
" } else { \n"
|
||||
" container.push_back_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
return "push_back";
|
||||
}
|
||||
}());
|
||||
|
||||
m.add(fun(&ContainerType::pop_back), "pop_back");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*Front insertion sequence
|
||||
*http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
||||
*/
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &, ModulePtr m = ModulePtr(new Module()))
|
||||
ModulePtr back_insertion_sequence_type(const std::string &type)
|
||||
{
|
||||
typedef typename ContainerType::reference (ContainerType::*frontptr)();
|
||||
typedef void (ContainerType::*pushptr)(typename ContainerType::const_reference);
|
||||
typedef void (ContainerType::*popptr)();
|
||||
|
||||
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
|
||||
|
||||
std::string push_front_name;
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
|
||||
{
|
||||
push_front_name = "push_front_ref";
|
||||
} else {
|
||||
push_front_name = "push_front";
|
||||
}
|
||||
|
||||
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)), push_front_name);
|
||||
m->add(fun(static_cast<popptr>(&ContainerType::pop_front)), "pop_front");
|
||||
auto m = std::make_shared<Module>();
|
||||
back_insertion_sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* bootstrap a given PairType
|
||||
* http://www.sgi.com/tech/stl/pair.html
|
||||
*/
|
||||
template<typename PairType>
|
||||
ModulePtr pair_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
|
||||
|
||||
/// Front insertion sequence
|
||||
/// http://www.sgi.com/tech/stl/FrontInsertionSequence.html
|
||||
template<typename ContainerType>
|
||||
void front_insertion_sequence_type(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(user_type<PairType>(), type);
|
||||
typedef typename ContainerType::reference (ContainerType::*front_ptr)();
|
||||
typedef typename ContainerType::const_reference (ContainerType::*const_front_ptr)() const;
|
||||
typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference);
|
||||
typedef void (ContainerType::*pop_ptr)();
|
||||
|
||||
m.add(fun(static_cast<front_ptr>(&ContainerType::front)), "front");
|
||||
m.add(fun(static_cast<const_front_ptr>(&ContainerType::front)), "front");
|
||||
|
||||
m.add(fun(static_cast<push_ptr>(&ContainerType::push_front)),
|
||||
[&]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
m.eval(
|
||||
"# Pushes the second value onto the front of container while making a clone of the value\n"
|
||||
"def push_front(" + type + " container, x)\n"
|
||||
"{ \n"
|
||||
" if (x.is_var_return_value()) {\n"
|
||||
" x.reset_var_return_value() \n"
|
||||
" container.push_front_ref(x) \n"
|
||||
" } else { \n"
|
||||
" container.push_front_ref(clone(x)); \n"
|
||||
" }\n"
|
||||
"} \n"
|
||||
);
|
||||
return "push_front_ref";
|
||||
} else {
|
||||
return "push_front";
|
||||
}
|
||||
}());
|
||||
|
||||
m.add(fun(static_cast<pop_ptr>(&ContainerType::pop_front)), "pop_front");
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr front_insertion_sequence_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
front_insertion_sequence_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
typename PairType::first_type PairType::* f = &PairType::first;
|
||||
typename PairType::second_type PairType::* s = &PairType::second;
|
||||
/// bootstrap a given PairType
|
||||
/// http://www.sgi.com/tech/stl/pair.html
|
||||
template<typename PairType>
|
||||
void pair_type(const std::string &type, Module& m)
|
||||
{
|
||||
m.add(user_type<PairType>(), type);
|
||||
|
||||
m->add(fun(f), "first");
|
||||
m->add(fun(s), "second");
|
||||
m.add(fun(&PairType::first), "first");
|
||||
m.add(fun(&PairType::second), "second");
|
||||
|
||||
basic_constructors<PairType>(type, m);
|
||||
m->add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
||||
|
||||
m.add(constructor<PairType (const typename PairType::first_type &, const typename PairType::second_type &)>(), type);
|
||||
}
|
||||
template<typename PairType>
|
||||
ModulePtr pair_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
pair_type<PairType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add pair associative container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/PairAssociativeContainer.html
|
||||
*/
|
||||
|
||||
/// Add pair associative container concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/PairAssociativeContainer.html
|
||||
|
||||
template<typename ContainerType>
|
||||
ModulePtr pair_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void pair_associative_container_type(const std::string &type, Module& m)
|
||||
{
|
||||
pair_type<typename ContainerType::value_type>(type + "_Pair", m);
|
||||
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr pair_associative_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
pair_associative_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add unique associative container concept to the given ContainerType
|
||||
* http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
||||
*/
|
||||
|
||||
/// Add unique associative container concept to the given ContainerType
|
||||
/// http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
|
||||
template<typename ContainerType>
|
||||
ModulePtr unique_associative_container_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
void unique_associative_container_type(const std::string &/*type*/, Module& m)
|
||||
{
|
||||
m->add(fun<int (const ContainerType *, const typename ContainerType::key_type &)>(&ContainerType::count), "count");
|
||||
m.add(fun(detail::count<ContainerType>), "count");
|
||||
|
||||
typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &);
|
||||
|
||||
m->add(fun<int (ContainerType *, const typename ContainerType::key_type &)>(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
|
||||
m.add(fun(static_cast<erase_ptr>(&ContainerType::erase)), "erase");
|
||||
|
||||
m->add(fun(&detail::insert<ContainerType>), "insert");
|
||||
m.add(fun(&detail::insert<ContainerType>), "insert");
|
||||
|
||||
std::string insert_name;
|
||||
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value))
|
||||
{
|
||||
insert_name = "insert_ref";
|
||||
} else {
|
||||
insert_name = "insert";
|
||||
}
|
||||
|
||||
m->add(fun(&detail::insert_ref<ContainerType>), insert_name);
|
||||
m.add(fun(&detail::insert_ref<ContainerType>),
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
||||
return "insert_ref";
|
||||
} else {
|
||||
return "insert";
|
||||
}
|
||||
}());
|
||||
}
|
||||
template<typename ContainerType>
|
||||
ModulePtr unique_associative_container_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
unique_associative_container_type<ContainerType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a MapType container
|
||||
* http://www.sgi.com/tech/stl/Map.html
|
||||
*/
|
||||
|
||||
/// Add a MapType container
|
||||
/// http://www.sgi.com/tech/stl/Map.html
|
||||
template<typename MapType>
|
||||
ModulePtr map_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void map_type(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(user_type<MapType>(), type);
|
||||
m.add(user_type<MapType>(), type);
|
||||
|
||||
typedef typename MapType::mapped_type &(MapType::*elemaccess)(const typename MapType::key_type &);
|
||||
typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &);
|
||||
typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const;
|
||||
|
||||
m->add(fun(static_cast<elemaccess>(&MapType::operator[])), "[]");
|
||||
m.add(fun(static_cast<elem_access>(&MapType::operator[])), "[]");
|
||||
|
||||
m.add(fun(static_cast<elem_access>(&MapType::at)), "at");
|
||||
m.add(fun(static_cast<const_elem_access>(&MapType::at)), "at");
|
||||
|
||||
if (typeid(MapType) == typeid(std::map<std::string, Boxed_Value>))
|
||||
{
|
||||
m.eval(R"(
|
||||
def Map::`==`(Map rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
return false;
|
||||
} else {
|
||||
auto r1 = range(this);
|
||||
auto r2 = range(rhs);
|
||||
while (!r1.empty())
|
||||
{
|
||||
if (!eq(r1.front().first, r2.front().first) || !eq(r1.front().second, r2.front().second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
r1.pop_front();
|
||||
r2.pop_front();
|
||||
}
|
||||
true;
|
||||
}
|
||||
} )"
|
||||
);
|
||||
}
|
||||
|
||||
container_type<MapType>(type, m);
|
||||
default_constructible_type<MapType>(type, m);
|
||||
assignable_type<MapType>(type, m);
|
||||
unique_associative_container_type<MapType>(type, m);
|
||||
pair_associative_container_type<MapType>(type, m);
|
||||
input_range_type<MapType>(type, m);
|
||||
|
||||
}
|
||||
template<typename MapType>
|
||||
ModulePtr map_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
map_type<MapType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* hopefully working List type
|
||||
* http://www.sgi.com/tech/stl/List.html
|
||||
*/
|
||||
|
||||
/// http://www.sgi.com/tech/stl/List.html
|
||||
template<typename ListType>
|
||||
ModulePtr list_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void list_type(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(user_type<ListType>(), type);
|
||||
m.add(user_type<ListType>(), type);
|
||||
|
||||
front_insertion_sequence_type<ListType>(type, m);
|
||||
back_insertion_sequence_type<ListType>(type, m);
|
||||
sequence_type<ListType>(type, m);
|
||||
resizable_type<ListType>(type, m);
|
||||
container_type<ListType>(type, m);
|
||||
default_constructible_type<ListType>(type, m);
|
||||
assignable_type<ListType>(type, m);
|
||||
input_range_type<ListType>(type, m);
|
||||
|
||||
}
|
||||
template<typename ListType>
|
||||
ModulePtr list_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
list_type<ListType>(type, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a vector type with associated concepts
|
||||
* http://www.sgi.com/tech/stl/Vector.html
|
||||
*/
|
||||
|
||||
/// Create a vector type with associated concepts
|
||||
/// http://www.sgi.com/tech/stl/Vector.html
|
||||
template<typename VectorType>
|
||||
ModulePtr vector_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void vector_type(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(user_type<VectorType>(), type);
|
||||
m.add(user_type<VectorType>(), type);
|
||||
|
||||
typedef typename VectorType::reference (VectorType::*frontptr)();
|
||||
m->add(fun(static_cast<frontptr>(&VectorType::front)), "front");
|
||||
typedef typename VectorType::const_reference (VectorType::*constfrontptr)() const;
|
||||
|
||||
m.add(fun(static_cast<frontptr>(&VectorType::front)), "front");
|
||||
m.add(fun(static_cast<constfrontptr>(&VectorType::front)), "front");
|
||||
|
||||
|
||||
back_insertion_sequence_type<VectorType>(type, m);
|
||||
sequence_type<VectorType>(type, m);
|
||||
random_access_container_type<VectorType>(type, m);
|
||||
resizable_type<VectorType>(type, m);
|
||||
reservable_type<VectorType>(type, m);
|
||||
container_type<VectorType>(type, m);
|
||||
default_constructible_type<VectorType>(type, m);
|
||||
assignable_type<VectorType>(type, m);
|
||||
@@ -490,71 +596,104 @@ namespace chaiscript
|
||||
|
||||
if (typeid(VectorType) == typeid(std::vector<Boxed_Value>))
|
||||
{
|
||||
m->eval("def Vector::`==`(rhs) : type_match(rhs, this) { \
|
||||
if ( rhs.size() != this.size() ) { \
|
||||
return false; \
|
||||
} else { \
|
||||
auto r1 = range(this); \
|
||||
auto r2 = range(rhs); \
|
||||
while (!r1.empty()) \
|
||||
{ \
|
||||
if (!eq(r1.front(), r2.front())) \
|
||||
{ \
|
||||
return false; \
|
||||
} \
|
||||
r1.pop_front(); \
|
||||
r2.pop_front(); \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
}");
|
||||
m.eval(R"(
|
||||
def Vector::`==`(Vector rhs) {
|
||||
if ( rhs.size() != this.size() ) {
|
||||
return false;
|
||||
} else {
|
||||
auto r1 = range(this);
|
||||
auto r2 = range(rhs);
|
||||
while (!r1.empty())
|
||||
{
|
||||
if (!eq(r1.front(), r2.front()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
r1.pop_front();
|
||||
r2.pop_front();
|
||||
}
|
||||
true;
|
||||
}
|
||||
} )"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
template<typename VectorType>
|
||||
ModulePtr vector_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
vector_type<VectorType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a String container
|
||||
* http://www.sgi.com/tech/stl/basic_string.html
|
||||
*/
|
||||
/// Add a String container
|
||||
/// http://www.sgi.com/tech/stl/basic_string.html
|
||||
template<typename String>
|
||||
ModulePtr string_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
||||
void string_type(const std::string &type, Module& m)
|
||||
{
|
||||
m->add(user_type<String>(), type);
|
||||
m.add(user_type<String>(), type);
|
||||
operators::addition<String>(m);
|
||||
operators::assign_sum<String>(m);
|
||||
opers_comparison<String>(m);
|
||||
random_access_container_type<String>(type, m);
|
||||
sequence_type<String>(type, m);
|
||||
default_constructible_type<String>(type, m);
|
||||
container_type<String>(type, m);
|
||||
// container_type<String>(type, m);
|
||||
assignable_type<String>(type, m);
|
||||
input_range_type<String>(type, m);
|
||||
|
||||
//Special case: add push_back to string (which doesn't support other back_insertion operations
|
||||
std::string push_back_name;
|
||||
if (typeid(typename String::value_type) == typeid(Boxed_Value))
|
||||
{
|
||||
push_back_name = "push_back_ref";
|
||||
} else {
|
||||
push_back_name = "push_back";
|
||||
}
|
||||
m->add(fun(&String::push_back), push_back_name);
|
||||
|
||||
typedef std::function<int (const String *, const String &, int)> find_func;
|
||||
m.add(fun(&String::push_back),
|
||||
[]()->std::string{
|
||||
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
return "push_back";
|
||||
}
|
||||
}());
|
||||
|
||||
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find(f, pos); } )), "find");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->rfind(f, pos); } ) ), "rfind");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_of(f, pos); } ) ), "find_first_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_of(f, pos); } ) ), "find_last_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_last_not_of(f, pos); } ) ), "find_last_not_of");
|
||||
m->add(fun(find_func( [](const String *s, const String &f, int pos) { return s->find_first_not_of(f, pos); } ) ), "find_first_not_of");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find(f, pos); } ), "find");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->rfind(f, pos); } ), "rfind");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_of(f, pos); } ), "find_first_of");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_of(f, pos); } ), "find_last_of");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_last_not_of(f, pos); } ), "find_last_not_of");
|
||||
m.add(fun([](const String *s, const String &f, size_t pos) { return s->find_first_not_of(f, pos); } ), "find_first_not_of");
|
||||
|
||||
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->c_str(); } ) ), "c_str");
|
||||
m->add(fun( std::function<const char *(const String *)>( [](const String *s) { return s->data(); } ) ), "data");
|
||||
m->add(fun( std::function<String (const String *, int, int)>( [](const String *s, int pos, int len) { return s->substr(pos, len); } ) ), "substr");
|
||||
m.add(fun([](String *s) { s->clear(); } ), "clear");
|
||||
m.add(fun([](const String *s) { return s->empty(); } ), "empty");
|
||||
m.add(fun([](const String *s) { return s->size(); } ), "size");
|
||||
|
||||
m.add(fun([](const String *s) { return s->c_str(); } ), "c_str");
|
||||
m.add(fun([](const String *s) { return s->data(); } ), "data");
|
||||
m.add(fun([](const String *s, size_t pos, size_t len) { return s->substr(pos, len); } ), "substr");
|
||||
}
|
||||
template<typename String>
|
||||
ModulePtr string_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
string_type<String>(type, *m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Add a MapType container
|
||||
/// http://www.sgi.com/tech/stl/Map.html
|
||||
template<typename FutureType>
|
||||
void future_type(const std::string &type, Module& m)
|
||||
{
|
||||
m.add(user_type<FutureType>(), type);
|
||||
|
||||
m.add(fun([](const FutureType &t) { return t.valid(); }), "valid");
|
||||
m.add(fun(&FutureType::get), "get");
|
||||
m.add(fun(&FutureType::wait), "wait");
|
||||
}
|
||||
template<typename FutureType>
|
||||
ModulePtr future_type(const std::string &type)
|
||||
{
|
||||
auto m = std::make_shared<Module>();
|
||||
future_type<FutureType>(type, *m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
@@ -563,3 +702,5 @@ namespace chaiscript
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,31 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
|
||||
#define CHAISCRIPT_BOXED_CAST_HPP_
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "bad_boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "dynamic_cast_conversion.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_conversions.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
#include "../chaiscript_threading.hpp"
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace detail {
|
||||
namespace exception {
|
||||
class bad_any_cast;
|
||||
} // namespace exception
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -62,41 +73,36 @@ namespace chaiscript
|
||||
/// assert(i == 5);
|
||||
/// \endcode
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr)
|
||||
{
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
|
||||
try {
|
||||
return(detail::Cast_Helper<Type>::cast(bv, t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
||||
// statment in THIS VERSION of the template instantiation
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value)
|
||||
{
|
||||
if (t_conversions && (*t_conversions)->convertable_type<Type>())
|
||||
{
|
||||
try {
|
||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||
// either way, we are not responsible if it doesn't work
|
||||
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||
} catch (...) {
|
||||
try {
|
||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||
// either way, we are not responsible if it doesn't work
|
||||
return detail::Cast_Helper<Type>::cast(detail::boxed_dynamic_cast<Type>(bv));
|
||||
// try going the other way
|
||||
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
} else {
|
||||
// If it's not polymorphic, just throw the error, don't waste the time on the
|
||||
// attempted dynamic_cast
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
} else {
|
||||
// If it's not convertable, just throw the error, don't waste the time on the
|
||||
// attempted dynamic_cast
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,155 +1,203 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||
#define CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class Type_Conversions_State;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Cast_Helper_Inner helper classes
|
||||
|
||||
/**
|
||||
* Generic Cast_Helper_Inner, for casting to any type
|
||||
*/
|
||||
template<typename T>
|
||||
T* throw_if_null(T *t)
|
||||
{
|
||||
if (t) { return t; }
|
||||
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static const T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
||||
if (ob.get_type_info() == ti) {
|
||||
return ptr;
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *verify_type_no_throw(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
||||
if (!ob.is_const() && ob.get_type_info() == ti) {
|
||||
return ptr;
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static const T *verify_type(const Boxed_Value &ob, const std::type_info &ti, const T *ptr) {
|
||||
if (ob.get_type_info().bare_equal_type_info(ti)) {
|
||||
return throw_if_null(ptr);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *verify_type(const Boxed_Value &ob, const std::type_info &ti, T *ptr) {
|
||||
if (!ob.is_const() && ob.get_type_info().bare_equal_type_info(ti)) {
|
||||
return throw_if_null(ptr);
|
||||
} else {
|
||||
throw chaiscript::detail::exception::bad_any_cast();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic Cast_Helper_Inner, for casting to any type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner
|
||||
{
|
||||
typedef typename std::reference_wrapper<typename std::add_const<Result>::type > Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return std::cref((ob.get().cast<std::reference_wrapper<Result> >()).get());
|
||||
} else {
|
||||
return ob.get().cast<std::reference_wrapper<const Result> >();
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return std::cref(*(ob.get().cast<std::shared_ptr<Result> >()));
|
||||
} else {
|
||||
return std::cref(*(ob.get().cast<std::shared_ptr<const Result> >()));
|
||||
}
|
||||
}
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &> : Cast_Helper_Inner<Result>
|
||||
struct Cast_Helper_Inner<const Result> : Cast_Helper_Inner<Result>
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const * type
|
||||
*/
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const * type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
typedef const Result * Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static const Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
||||
} else {
|
||||
return &(ob.get().cast<std::reference_wrapper<const Result> >()).get();
|
||||
}
|
||||
} else {
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
||||
} else {
|
||||
return (ob.get().cast<std::shared_ptr<const Result> >()).get();
|
||||
}
|
||||
}
|
||||
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a * type
|
||||
*/
|
||||
/// Cast_Helper_Inner for casting to a * type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result *>
|
||||
{
|
||||
typedef Result * Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static Result * cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
||||
} else {
|
||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
||||
}
|
||||
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a & type
|
||||
*/
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result * const &> : public Cast_Helper_Inner<Result *>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result * const &> : public Cast_Helper_Inner<const Result *>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const Result &>
|
||||
{
|
||||
static const Result & cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return *static_cast<const Result *>(verify_type(ob, typeid(Result), ob.get_const_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<Result &>
|
||||
{
|
||||
typedef Result& Result_Type;
|
||||
|
||||
static Result &cast(const Boxed_Value &ob)
|
||||
static Result& cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (ob.is_ref())
|
||||
{
|
||||
return ob.get().cast<std::reference_wrapper<Result> >();
|
||||
} else {
|
||||
Result &r = *(ob.get().cast<std::shared_ptr<Result> >());
|
||||
return r;
|
||||
}
|
||||
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
|
||||
*/
|
||||
/// Cast_Helper_Inner for casting to a && type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
|
||||
struct Cast_Helper_Inner<Result &&>
|
||||
{
|
||||
typedef typename std::shared_ptr<Result> Result_Type;
|
||||
static Result&& cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return std::move(*static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr())));
|
||||
}
|
||||
};
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
/// Cast_Helper_Inner for casting to a std::unique_ptr<> && type
|
||||
/// \todo Fix the fact that this has to be in a shared_ptr for now
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::unique_ptr<Result> &&>
|
||||
{
|
||||
static std::unique_ptr<Result> &&cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return std::move(*(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>()));
|
||||
}
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
|
||||
/// \todo Fix the fact that this has to be in a shared_ptr for now
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::unique_ptr<Result> &>
|
||||
{
|
||||
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
|
||||
}
|
||||
};
|
||||
|
||||
/// Cast_Helper_Inner for casting to a std::unique_ptr<> & type
|
||||
/// \todo Fix the fact that this has to be in a shared_ptr for now
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::unique_ptr<Result> &>
|
||||
{
|
||||
static std::unique_ptr<Result> &cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return *(ob.get().cast<std::shared_ptr<std::unique_ptr<Result>>>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a std::shared_ptr<> type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||
{
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob.get().cast<std::shared_ptr<Result> >();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a std::shared_ptr<const> type
|
||||
*/
|
||||
/// Cast_Helper_Inner for casting to a std::shared_ptr<const> type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<typename std::shared_ptr<const Result> >
|
||||
struct Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
typedef typename std::shared_ptr<const Result> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
if (!ob.get_type_info().is_const())
|
||||
{
|
||||
@@ -160,9 +208,7 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
|
||||
*/
|
||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<> & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<Result> > : Cast_Helper_Inner<std::shared_ptr<Result> >
|
||||
{
|
||||
@@ -173,10 +219,19 @@ namespace chaiscript
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::shared_ptr<Result> &>
|
||||
{
|
||||
static_assert(!std::is_const<Result>::value, "Non-const reference to std::shared_ptr<const T> is not supported");
|
||||
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
std::shared_ptr<Result> &res = ob.get().cast<std::shared_ptr<Result> >();
|
||||
return ob.pointer_sentinel(res);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||
*/
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const std::shared_ptr<const> & type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> > : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
||||
{
|
||||
@@ -188,24 +243,28 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a Boxed_Value type
|
||||
*/
|
||||
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
typedef const Boxed_Value & Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return ob;
|
||||
return ob;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a const Boxed_Value & type
|
||||
*/
|
||||
/// Cast_Helper_Inner for casting to a Boxed_Value & type
|
||||
template<>
|
||||
struct Cast_Helper_Inner<Boxed_Value &>
|
||||
{
|
||||
static std::reference_wrapper<Boxed_Value> cast(const Boxed_Value &ob, const Type_Conversions_State *)
|
||||
{
|
||||
return std::ref(const_cast<Boxed_Value &>(ob));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Cast_Helper_Inner for casting to a const Boxed_Value & type
|
||||
template<>
|
||||
struct Cast_Helper_Inner<const Boxed_Value> : Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
@@ -215,11 +274,9 @@ namespace chaiscript
|
||||
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cast_Helper_Inner for casting to a std::reference_wrapper type
|
||||
*/
|
||||
|
||||
/// Cast_Helper_Inner for casting to a std::reference_wrapper type
|
||||
template<typename Result>
|
||||
struct Cast_Helper_Inner<std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
||||
{
|
||||
@@ -250,17 +307,13 @@ namespace chaiscript
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
||||
*/
|
||||
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
||||
template<typename T>
|
||||
struct Cast_Helper
|
||||
{
|
||||
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return Cast_Helper_Inner<T>::cast(ob);
|
||||
return(Cast_Helper_Inner<T>::cast(ob, t_conversions));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,23 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
|
||||
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
|
||||
#include "../chaiscript_threading.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "any.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -22,25 +27,23 @@ namespace chaiscript
|
||||
class Boxed_Value
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* used for explicitly creating a "void" object
|
||||
*/
|
||||
/// used for explicitly creating a "void" object
|
||||
struct Void_Type
|
||||
{
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* structure which holds the internal state of a Boxed_Value
|
||||
*/
|
||||
/// structure which holds the internal state of a Boxed_Value
|
||||
/// \todo Get rid of Any and merge it with this, reducing an allocation in the process
|
||||
struct Data
|
||||
{
|
||||
Data(const Type_Info &ti,
|
||||
const chaiscript::detail::Any &to,
|
||||
bool tr,
|
||||
const void *t_void_ptr)
|
||||
: m_type_info(ti), m_obj(to), m_data_ptr(ti.is_const()?0:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
|
||||
m_is_ref(tr)
|
||||
chaiscript::detail::Any to,
|
||||
bool is_ref,
|
||||
const void *t_void_ptr,
|
||||
bool t_return_value)
|
||||
: m_type_info(ti), m_obj(std::move(to)), m_data_ptr(ti.is_const()?nullptr:const_cast<void *>(t_void_ptr)), m_const_data_ptr(t_void_ptr),
|
||||
m_is_ref(is_ref), m_return_value(t_return_value)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -51,76 +54,127 @@ namespace chaiscript
|
||||
m_is_ref = rhs.m_is_ref;
|
||||
m_data_ptr = rhs.m_data_ptr;
|
||||
m_const_data_ptr = rhs.m_const_data_ptr;
|
||||
m_return_value = rhs.m_return_value;
|
||||
|
||||
if (rhs.m_attrs)
|
||||
{
|
||||
m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*rhs.m_attrs);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Data()
|
||||
{
|
||||
}
|
||||
Data(const Data &) = delete;
|
||||
|
||||
Data(Data &&) = default;
|
||||
Data &operator=(Data &&rhs) = default;
|
||||
|
||||
|
||||
Type_Info m_type_info;
|
||||
chaiscript::detail::Any m_obj;
|
||||
void *m_data_ptr;
|
||||
const void *m_const_data_ptr;
|
||||
std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
|
||||
bool m_is_ref;
|
||||
bool m_return_value;
|
||||
};
|
||||
|
||||
struct Object_Data
|
||||
{
|
||||
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
|
||||
static auto get(Boxed_Value::Void_Type, bool t_return_value)
|
||||
{
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<void>::get(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
nullptr)
|
||||
nullptr,
|
||||
t_return_value)
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
|
||||
static auto get(const std::shared_ptr<T> *obj, bool t_return_value)
|
||||
{
|
||||
return get(*obj);
|
||||
return get(*obj, t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
|
||||
static auto get(const std::shared_ptr<T> &obj, bool t_return_value)
|
||||
{
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(obj),
|
||||
false,
|
||||
obj.get()
|
||||
obj.get(),
|
||||
t_return_value
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::shared_ptr<Data> get(T *t)
|
||||
static auto get(std::shared_ptr<T> &&obj, bool t_return_value)
|
||||
{
|
||||
return get(std::ref(*t));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::shared_ptr<Data> get(std::reference_wrapper<T> obj)
|
||||
{
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(obj),
|
||||
true,
|
||||
&obj.get()
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::shared_ptr<Data> get(const T& t)
|
||||
{
|
||||
auto p = std::make_shared<T>(t);
|
||||
auto ptr = obj.get();
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(p),
|
||||
chaiscript::detail::Any(std::move(obj)),
|
||||
false,
|
||||
p.get()
|
||||
ptr,
|
||||
t_return_value
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
static auto get(T *t, bool t_return_value)
|
||||
{
|
||||
return get(std::ref(*t), t_return_value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(const T *t, bool t_return_value)
|
||||
{
|
||||
return get(std::cref(*t), t_return_value);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static auto get(std::reference_wrapper<T> obj, bool t_return_value)
|
||||
{
|
||||
auto p = &obj.get();
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(obj)),
|
||||
true,
|
||||
p,
|
||||
t_return_value
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(std::unique_ptr<T> &&obj, bool t_return_value)
|
||||
{
|
||||
auto ptr = obj.get();
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::make_shared<std::unique_ptr<T>>(std::move(obj))),
|
||||
true,
|
||||
ptr,
|
||||
t_return_value
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static auto get(T t, bool t_return_value)
|
||||
{
|
||||
auto p = std::make_shared<T>(std::move(t));
|
||||
auto ptr = p.get();
|
||||
return std::make_shared<Data>(
|
||||
detail::Get_Type_Info<T>::get(),
|
||||
chaiscript::detail::Any(std::move(p)),
|
||||
false,
|
||||
ptr,
|
||||
t_return_value
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,147 +184,209 @@ namespace chaiscript
|
||||
Type_Info(),
|
||||
chaiscript::detail::Any(),
|
||||
false,
|
||||
nullptr
|
||||
nullptr,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* Basic Boxed_Value constructor
|
||||
*/
|
||||
template<typename T>
|
||||
explicit Boxed_Value(T t)
|
||||
: m_data(Object_Data::get(t))
|
||||
/// Basic Boxed_Value constructor
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<!std::is_same<Boxed_Value, typename std::decay<T>::type>::value>::type>
|
||||
explicit Boxed_Value(T &&t, bool t_return_value = false)
|
||||
: m_data(Object_Data::get(std::forward<T>(t), t_return_value))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor - each copy shares the same data pointer
|
||||
*/
|
||||
Boxed_Value(const Boxed_Value &t_so)
|
||||
: m_data(t_so.m_data)
|
||||
{
|
||||
}
|
||||
/// Unknown-type constructor
|
||||
Boxed_Value() = default;
|
||||
|
||||
/**
|
||||
* Unknown-type constructor
|
||||
*/
|
||||
Boxed_Value()
|
||||
: m_data(Object_Data::get())
|
||||
{
|
||||
}
|
||||
|
||||
~Boxed_Value()
|
||||
{
|
||||
}
|
||||
Boxed_Value(Boxed_Value&&) = default;
|
||||
Boxed_Value& operator=(Boxed_Value&&) = default;
|
||||
Boxed_Value(const Boxed_Value&) = default;
|
||||
Boxed_Value& operator=(const Boxed_Value&) = default;
|
||||
|
||||
void swap(Boxed_Value &rhs)
|
||||
{
|
||||
std::swap(m_data, rhs.m_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* copy the values stored in rhs.m_data to m_data
|
||||
* m_data pointers are not shared in this case
|
||||
*/
|
||||
/// Copy the values stored in rhs.m_data to m_data.
|
||||
/// m_data pointers are not shared in this case
|
||||
Boxed_Value assign(const Boxed_Value &rhs)
|
||||
{
|
||||
(*m_data) = (*rhs.m_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* shared data assignment, same as copy construction
|
||||
*/
|
||||
Boxed_Value &operator=(const Boxed_Value &rhs)
|
||||
{
|
||||
Boxed_Value temp(rhs);
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Type_Info &get_type_info() const
|
||||
const Type_Info &get_type_info() const noexcept
|
||||
{
|
||||
return m_data->m_type_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the object is uninitialized
|
||||
*/
|
||||
bool is_undef() const
|
||||
/// return true if the object is uninitialized
|
||||
bool is_undef() const noexcept
|
||||
{
|
||||
return m_data->m_type_info.is_undef();
|
||||
}
|
||||
|
||||
bool is_const() const
|
||||
bool is_const() const noexcept
|
||||
{
|
||||
return m_data->m_type_info.is_const();
|
||||
}
|
||||
|
||||
bool is_type(const Type_Info &ti) const
|
||||
bool is_type(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return m_data->m_type_info.bare_equal(ti);
|
||||
}
|
||||
|
||||
bool is_null() const
|
||||
|
||||
template<typename T>
|
||||
auto pointer_sentinel(std::shared_ptr<T> &ptr) const
|
||||
{
|
||||
return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
|
||||
struct Sentinel {
|
||||
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
|
||||
: m_ptr(t_ptr), m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
~Sentinel()
|
||||
{
|
||||
// save new pointer data
|
||||
const auto ptr_ = m_ptr.get().get();
|
||||
m_data.get().m_data_ptr = ptr_;
|
||||
m_data.get().m_const_data_ptr = ptr_;
|
||||
}
|
||||
|
||||
Sentinel& operator=(Sentinel&&s) = default;
|
||||
Sentinel(Sentinel &&s) = default;
|
||||
|
||||
operator std::shared_ptr<T>&() const
|
||||
{
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
Sentinel &operator=(const Sentinel &) = delete;
|
||||
Sentinel(Sentinel&) = delete;
|
||||
|
||||
std::reference_wrapper<std::shared_ptr<T>> m_ptr;
|
||||
std::reference_wrapper<Data> m_data;
|
||||
};
|
||||
|
||||
return Sentinel(ptr, *(m_data.get()));
|
||||
}
|
||||
|
||||
const chaiscript::detail::Any & get() const
|
||||
bool is_null() const noexcept
|
||||
{
|
||||
return (m_data->m_data_ptr == nullptr && m_data->m_const_data_ptr == nullptr);
|
||||
}
|
||||
|
||||
const chaiscript::detail::Any & get() const noexcept
|
||||
{
|
||||
return m_data->m_obj;
|
||||
}
|
||||
|
||||
bool is_ref() const
|
||||
bool is_ref() const noexcept
|
||||
{
|
||||
return m_data->m_is_ref;
|
||||
}
|
||||
|
||||
bool is_pointer() const
|
||||
bool is_return_value() const noexcept
|
||||
{
|
||||
return m_data->m_return_value;
|
||||
}
|
||||
|
||||
void reset_return_value() const noexcept
|
||||
{
|
||||
m_data->m_return_value = false;
|
||||
}
|
||||
|
||||
bool is_pointer() const noexcept
|
||||
{
|
||||
return !is_ref();
|
||||
}
|
||||
|
||||
void *get_ptr() const
|
||||
void *get_ptr() const noexcept
|
||||
{
|
||||
return m_data->m_data_ptr;
|
||||
}
|
||||
|
||||
const void *get_const_ptr() const
|
||||
const void *get_const_ptr() const noexcept
|
||||
{
|
||||
return m_data->m_const_data_ptr;
|
||||
}
|
||||
|
||||
Boxed_Value get_attr(const std::string &t_name)
|
||||
{
|
||||
if (!m_data->m_attrs)
|
||||
{
|
||||
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>();
|
||||
}
|
||||
|
||||
auto &attr = (*m_data->m_attrs)[t_name];
|
||||
if (attr) {
|
||||
return Boxed_Value(attr, Internal_Construction());
|
||||
} else {
|
||||
Boxed_Value bv; //default construct a new one
|
||||
attr = bv.m_data;
|
||||
return bv;
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value ©_attrs(const Boxed_Value &t_obj)
|
||||
{
|
||||
if (t_obj.m_data->m_attrs)
|
||||
{
|
||||
m_data->m_attrs = std::make_unique<std::map<std::string, std::shared_ptr<Data>>>(*t_obj.m_data->m_attrs);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Boxed_Value &clone_attrs(const Boxed_Value &t_obj)
|
||||
{
|
||||
copy_attrs(t_obj);
|
||||
reset_return_value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// \returns true if the two Boxed_Values share the same internal type
|
||||
static bool type_match(Boxed_Value l, Boxed_Value r)
|
||||
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept
|
||||
{
|
||||
return l.get_type_info() == r.get_type_info();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Data> m_data;
|
||||
// necessary to avoid hitting the templated && constructor of Boxed_Value
|
||||
struct Internal_Construction{};
|
||||
|
||||
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
|
||||
: m_data(std::move(t_data)) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Data> m_data = Object_Data::get();
|
||||
};
|
||||
|
||||
/// \brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
|
||||
/// @brief Creates a Boxed_Value. If the object passed in is a value type, it is copied. If it is a pointer, std::shared_ptr, or std::reference_type
|
||||
/// a copy is not made.
|
||||
/// \param t The value to box
|
||||
///
|
||||
/// @param t The value to box
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
///
|
||||
/// ~~~{.cpp}
|
||||
/// int i;
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::var(i), "i");
|
||||
/// chai.add(chaiscript::var(&i), "ip");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingobjects
|
||||
/// ~~~
|
||||
///
|
||||
/// @sa @ref adding_objects
|
||||
template<typename T>
|
||||
Boxed_Value var(T t)
|
||||
Boxed_Value var(T &&t)
|
||||
{
|
||||
return Boxed_Value(t);
|
||||
return Boxed_Value(std::forward<T>(t));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -281,7 +397,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
Boxed_Value const_var_impl(const T &t)
|
||||
{
|
||||
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t)));
|
||||
return Boxed_Value(std::make_shared<typename std::add_const<T>::type >(t));
|
||||
}
|
||||
|
||||
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||
@@ -339,14 +455,29 @@ namespace chaiscript
|
||||
/// chai.add(chaiscript::const_var(Green), "Green");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingobjects
|
||||
/// \todo support C++11 strongly typed enums
|
||||
/// \sa \ref adding_objects
|
||||
template<typename T>
|
||||
Boxed_Value const_var(const T &t)
|
||||
{
|
||||
return detail::const_var_impl(t);
|
||||
}
|
||||
|
||||
inline Boxed_Value void_var() {
|
||||
static const auto v = Boxed_Value(Boxed_Value::Void_Type());
|
||||
return v;
|
||||
}
|
||||
|
||||
inline Boxed_Value const_var(bool b) {
|
||||
static const auto t = detail::const_var_impl(true);
|
||||
static const auto f = detail::const_var_impl(false);
|
||||
|
||||
if (b) {
|
||||
return t;
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
107
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
107
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
#define CHAISCRIPT_CALLABLE_TRAITS_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace chaiscript {
|
||||
namespace dispatch {
|
||||
namespace detail {
|
||||
|
||||
template<typename Class, typename ... Param>
|
||||
struct Constructor
|
||||
{
|
||||
template<typename ... Inner>
|
||||
std::shared_ptr<Class> operator()(Inner&& ... inner) const {
|
||||
return std::make_shared<Class>(std::forward<Inner>(inner)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Const_Caller
|
||||
{
|
||||
explicit Const_Caller(Ret (Class::*t_func)(Param...) const) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(const Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...) const;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Fun_Caller
|
||||
{
|
||||
explicit Fun_Caller(Ret( * t_func)(Param...) ) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Inner&& ... inner) const {
|
||||
return (m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret(*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
struct Caller
|
||||
{
|
||||
explicit Caller(Ret (Class::*t_func)(Param...)) : m_func(t_func) {}
|
||||
|
||||
template<typename ... Inner>
|
||||
Ret operator()(Class &o, Inner&& ... inner) const {
|
||||
return (o.*m_func)(std::forward<Inner>(inner)...);
|
||||
}
|
||||
|
||||
Ret (Class::*m_func)(Param...);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Arity
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Arity<Ret (Params...)>
|
||||
{
|
||||
static const size_t arity = sizeof...(Params);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Function_Signature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Function_Signature<Ret (Params...)>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename ... Params>
|
||||
struct Function_Signature<Ret (T::*)(Params...) const>
|
||||
{
|
||||
typedef Ret Return_Type;
|
||||
typedef Ret (Signature)(Params...);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Callable_Traits
|
||||
{
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Signature Signature;
|
||||
typedef typename Function_Signature<decltype(&T::operator())>::Return_Type Return_Type;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,287 +0,0 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
|
||||
#include "type_info.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "bad_boxed_cast.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
class bad_boxed_dynamic_cast : public bad_boxed_cast
|
||||
{
|
||||
public:
|
||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||
const std::string &t_what) noexcept
|
||||
: bad_boxed_cast(t_from, t_to, t_what)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
||||
: bad_boxed_cast(t_from, t_to)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const std::string &w) noexcept
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~bad_boxed_dynamic_cast() noexcept {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class Dynamic_Conversion
|
||||
{
|
||||
public:
|
||||
virtual Boxed_Value convert(const Boxed_Value &derived) = 0;
|
||||
|
||||
const Type_Info &base()
|
||||
{
|
||||
return m_base;
|
||||
}
|
||||
const Type_Info &derived()
|
||||
{
|
||||
return m_derived;
|
||||
}
|
||||
|
||||
protected:
|
||||
Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived)
|
||||
: m_base(t_base), m_derived(t_derived)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Conversion() {}
|
||||
|
||||
private:
|
||||
Type_Info m_base;
|
||||
Type_Info m_derived;
|
||||
|
||||
};
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
class Dynamic_Conversion_Impl : public Dynamic_Conversion
|
||||
{
|
||||
public:
|
||||
Dynamic_Conversion_Impl()
|
||||
: Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
|
||||
{
|
||||
}
|
||||
|
||||
virtual Boxed_Value convert(const Boxed_Value &t_derived)
|
||||
{
|
||||
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
|
||||
{
|
||||
if (t_derived.is_pointer())
|
||||
{
|
||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||
if (t_derived.is_const())
|
||||
{
|
||||
std::shared_ptr<const Base> data
|
||||
= std::dynamic_pointer_cast<const Base>(detail::Cast_Helper<std::shared_ptr<const Derived> >::cast(t_derived));
|
||||
if (!data)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
|
||||
return Boxed_Value(data);
|
||||
} else {
|
||||
std::shared_ptr<Base> data
|
||||
= std::dynamic_pointer_cast<Base>(detail::Cast_Helper<std::shared_ptr<Derived> >::cast(t_derived));
|
||||
|
||||
if (!data)
|
||||
{
|
||||
throw std::bad_cast();
|
||||
}
|
||||
|
||||
return Boxed_Value(data);
|
||||
}
|
||||
} else {
|
||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||
if (t_derived.is_const())
|
||||
{
|
||||
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived);
|
||||
const Base &data = dynamic_cast<const Base &>(d);
|
||||
return Boxed_Value(std::cref(data));
|
||||
} else {
|
||||
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived);
|
||||
Base &data = dynamic_cast<Base &>(d);
|
||||
return Boxed_Value(std::ref(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Dynamic_Conversions
|
||||
{
|
||||
public:
|
||||
static inline Dynamic_Conversions &get()
|
||||
{
|
||||
static Dynamic_Conversions obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
static std::shared_ptr<Dynamic_Conversion> create()
|
||||
{
|
||||
std::shared_ptr<Dynamic_Conversion> conversion(new Dynamic_Conversion_Impl<Base, Derived>());
|
||||
|
||||
/// \todo this is a hack and a kludge. The idea is to make sure that
|
||||
/// the conversion is registered both in the module's notion of the static conversion object
|
||||
/// and in the global notion of the static conversion object
|
||||
/// someday this will almost certainly have to change. Maybe it is time for ChaiScript
|
||||
/// to become a library?
|
||||
Dynamic_Conversions::get().add_conversion(conversion);
|
||||
return conversion;
|
||||
}
|
||||
|
||||
template<typename InItr>
|
||||
void cleanup(InItr begin, const InItr &end)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
while (begin != end)
|
||||
{
|
||||
if (begin->unique())
|
||||
{
|
||||
m_conversions.erase(begin->get());
|
||||
}
|
||||
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
void add_conversion(const std::shared_ptr<Dynamic_Conversion> &conversion)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
m_conversions.insert(conversion.get());
|
||||
}
|
||||
|
||||
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
return find(base, derived) != m_conversions.end();
|
||||
}
|
||||
|
||||
|
||||
Dynamic_Conversion *get_conversion(const Type_Info &base, const Type_Info &derived) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
std::set<Dynamic_Conversion *>::const_iterator itr =
|
||||
find(base, derived);
|
||||
|
||||
if (itr != m_conversions.end())
|
||||
{
|
||||
return *itr;
|
||||
} else {
|
||||
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Dynamic_Conversions() {}
|
||||
|
||||
std::set<Dynamic_Conversion *>::const_iterator find(
|
||||
const Type_Info &base, const Type_Info &derived) const
|
||||
{
|
||||
for (std::set<Dynamic_Conversion *>::const_iterator itr = m_conversions.begin();
|
||||
itr != m_conversions.end();
|
||||
++itr)
|
||||
{
|
||||
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
}
|
||||
|
||||
return m_conversions.end();
|
||||
}
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
std::set<Dynamic_Conversion *> m_conversions;
|
||||
};
|
||||
}
|
||||
|
||||
typedef std::shared_ptr<chaiscript::detail::Dynamic_Conversion> Dynamic_Cast_Conversion;
|
||||
|
||||
/// \brief Used to register a base / parent class relationship with ChaiScript. Necessary if you
|
||||
/// want automatic conversions up your inheritance hierarchy.
|
||||
///
|
||||
/// Create a new base class registration for applying to a module or to the chaiscript engine
|
||||
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
|
||||
/// if you have a type that is introduced in a loadable module and is used by multiple modules
|
||||
/// (through a tertiary dll that is shared between the modules, static linking the new type
|
||||
/// into both loadable modules would not be portable), you need to register the base type
|
||||
/// relationship in all modules that use the newly added type in a polymorphic way.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// class Base
|
||||
/// {};
|
||||
/// class Derived : public Base
|
||||
/// {};
|
||||
///
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::base_class<Base, Derived>());
|
||||
/// \endcode
|
||||
///
|
||||
/// \todo Move share static type registration code into a mechanism that allows it to be properly
|
||||
/// shared by all modules
|
||||
template<typename Base, typename Derived>
|
||||
Dynamic_Cast_Conversion base_class()
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
static_assert(std::is_polymorphic<Base>::value, "Base class must be polymorphic");
|
||||
static_assert(std::is_polymorphic<Derived>::value, "Derived class must be polymorphic");
|
||||
|
||||
return detail::Dynamic_Conversions::create<Base, Derived>();
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Base, typename Derived>
|
||||
bool dynamic_cast_converts()
|
||||
{
|
||||
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
|
||||
}
|
||||
|
||||
static bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
|
||||
{
|
||||
return detail::Dynamic_Conversions::get().has_conversion(base, derived);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
|
||||
{
|
||||
try {
|
||||
return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
|
||||
} catch (const std::out_of_range &) {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
|
||||
} catch (const std::bad_cast &) {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,271 +1,130 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
struct option_explicit_set : std::runtime_error {
|
||||
explicit option_explicit_set(const std::string &t_param_name)
|
||||
: std::runtime_error("option explicit set and parameter '" + t_param_name + "' does not exist")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
option_explicit_set(const option_explicit_set &) = default;
|
||||
|
||||
~option_explicit_set() noexcept override = default;
|
||||
};
|
||||
|
||||
class Dynamic_Object
|
||||
{
|
||||
public:
|
||||
Dynamic_Object(const std::string &t_type_name)
|
||||
: m_type_name(t_type_name)
|
||||
explicit Dynamic_Object(std::string t_type_name)
|
||||
: m_type_name(std::move(t_type_name)), m_option_explicit(false)
|
||||
{
|
||||
}
|
||||
|
||||
Dynamic_Object() = default;
|
||||
|
||||
bool is_explicit() const
|
||||
{
|
||||
return m_option_explicit;
|
||||
}
|
||||
|
||||
void set_explicit(const bool t_explicit)
|
||||
{
|
||||
m_option_explicit = t_explicit;
|
||||
}
|
||||
|
||||
std::string get_type_name() const
|
||||
{
|
||||
return m_type_name;
|
||||
}
|
||||
|
||||
Boxed_Value get_attr(const std::string &t_attr_name)
|
||||
const Boxed_Value &operator[](const std::string &t_attr_name) const
|
||||
{
|
||||
return get_attr(t_attr_name);
|
||||
}
|
||||
|
||||
Boxed_Value &operator[](const std::string &t_attr_name)
|
||||
{
|
||||
return get_attr(t_attr_name);
|
||||
}
|
||||
|
||||
const Boxed_Value &get_attr(const std::string &t_attr_name) const
|
||||
{
|
||||
auto a = m_attrs.find(t_attr_name);
|
||||
|
||||
if (a != m_attrs.end()) {
|
||||
return a->second;
|
||||
} else {
|
||||
throw std::range_error("Attr not found '" + t_attr_name + "' and cannot be added to const obj");
|
||||
}
|
||||
}
|
||||
|
||||
bool has_attr(const std::string &t_attr_name) const {
|
||||
return m_attrs.find(t_attr_name) != m_attrs.end();
|
||||
}
|
||||
|
||||
Boxed_Value &get_attr(const std::string &t_attr_name)
|
||||
{
|
||||
return m_attrs[t_attr_name];
|
||||
}
|
||||
|
||||
std::map<std::string, Boxed_Value> get_attrs()
|
||||
Boxed_Value &method_missing(const std::string &t_method_name)
|
||||
{
|
||||
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||
throw option_explicit_set(t_method_name);
|
||||
}
|
||||
|
||||
return get_attr(t_method_name);
|
||||
}
|
||||
|
||||
const Boxed_Value &method_missing(const std::string &t_method_name) const
|
||||
{
|
||||
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||
throw option_explicit_set(t_method_name);
|
||||
}
|
||||
|
||||
return get_attr(t_method_name);
|
||||
}
|
||||
|
||||
std::map<std::string, Boxed_Value> get_attrs() const
|
||||
{
|
||||
return m_attrs;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
const std::string m_type_name = "";
|
||||
bool m_option_explicit = false;
|
||||
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* A Proxy_Function implementation designed for calling a function
|
||||
* that is automatically guarded based on the first param based on the
|
||||
* param's type name
|
||||
*/
|
||||
class Dynamic_Object_Function : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Function(
|
||||
const std::string &t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(t_func->get_param_types()),
|
||||
m_type_name(t_type_name), m_func(t_func)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
Dynamic_Object_Function(
|
||||
const std::string &t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const Type_Info &t_ti)
|
||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti)),
|
||||
m_type_name(t_type_name), m_func(t_func), m_ti(new Type_Info(t_ti))
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Object_Function() {}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const
|
||||
{
|
||||
const Dynamic_Object_Function *df = dynamic_cast<const Dynamic_Object_Function *>(&f);
|
||||
if (df)
|
||||
{
|
||||
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti))
|
||||
{
|
||||
return m_func->call_match(vals);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
|
||||
{
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
return m_func->get_arity();
|
||||
}
|
||||
|
||||
virtual std::string annotation() const
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti))
|
||||
{
|
||||
return (*m_func)(params);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv) const
|
||||
{
|
||||
return dynamic_object_typename_match(bv, m_type_name, m_ti);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_types(
|
||||
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
|
||||
{
|
||||
std::vector<Type_Info> types(t_inner_types);
|
||||
|
||||
assert(types.size() > 1);
|
||||
assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||
types[1] = t_objectti;
|
||||
return types;
|
||||
}
|
||||
|
||||
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::shared_ptr<Type_Info> &ti)
|
||||
{
|
||||
static Type_Info doti = user_type<Dynamic_Object>();
|
||||
if (bv.get_type_info().bare_equal(doti))
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ti)
|
||||
{
|
||||
return bv.get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::shared_ptr<Type_Info> &ti)
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
{
|
||||
return dynamic_object_typename_match(bvs[0], name, ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
std::shared_ptr<Type_Info> m_ti;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Proxy_Function implementation designed for creating a new
|
||||
* Dynamic_Object
|
||||
* that is automatically guarded based on the first param based on the
|
||||
* param's type name
|
||||
*/
|
||||
class Dynamic_Object_Constructor : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Constructor(
|
||||
const std::string &t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
|
||||
m_type_name(t_type_name), m_func(t_func)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
|
||||
{
|
||||
std::vector<Type_Info>::const_iterator begin = tl.begin();
|
||||
std::vector<Type_Info>::const_iterator end = tl.end();
|
||||
|
||||
if (begin != end)
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
return std::vector<Type_Info>(begin, end);
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Object_Constructor() {}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const
|
||||
{
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
if (dc)
|
||||
{
|
||||
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
||||
{
|
||||
std::vector<Boxed_Value> new_vals;
|
||||
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
|
||||
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
||||
|
||||
return m_func->call_match(new_vals);
|
||||
}
|
||||
|
||||
|
||||
virtual int get_arity() const
|
||||
{
|
||||
// "this" is not considered part of the arity
|
||||
return m_func->get_arity() - 1;
|
||||
}
|
||||
|
||||
virtual std::string annotation() const
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms) const
|
||||
{
|
||||
std::vector<Boxed_Value> new_params;
|
||||
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
|
||||
new_params.push_back(bv);
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
237
include/chaiscript/dispatchkit/dynamic_object_detail.hpp
Normal file
237
include/chaiscript/dispatchkit/dynamic_object_detail.hpp
Normal file
@@ -0,0 +1,237 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// A Proxy_Function implementation designed for calling a function
|
||||
/// that is automatically guarded based on the first param based on the
|
||||
/// param's type name
|
||||
class Dynamic_Object_Function final : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Function(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
bool t_is_attribute = false)
|
||||
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>()),
|
||||
m_is_attribute(t_is_attribute)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
Dynamic_Object_Function(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const Type_Info &t_ti,
|
||||
bool t_is_attribute = false)
|
||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(t_ti.is_undef()?nullptr:new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>()),
|
||||
m_is_attribute(t_is_attribute)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
|
||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||
|
||||
bool operator==(const Proxy_Function_Base &f) const override
|
||||
{
|
||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||
{
|
||||
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_attribute_function() const override { return m_is_attribute; }
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
return m_func->call_match(vals, t_conversions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Const_Proxy_Function> get_contained_functions() const override
|
||||
{
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
return (*m_func)(params, t_conversions);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_types(
|
||||
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
|
||||
{
|
||||
std::vector<Type_Info> types(t_inner_types);
|
||||
|
||||
assert(types.size() > 1);
|
||||
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||
types[1] = t_objectti;
|
||||
return types;
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (bv.get_type_info().bare_equal(m_doti))
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ti)
|
||||
{
|
||||
return bv.get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions_State &t_conversions) const
|
||||
{
|
||||
if (!bvs.empty())
|
||||
{
|
||||
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
std::unique_ptr<Type_Info> m_ti;
|
||||
const Type_Info m_doti;
|
||||
const bool m_is_attribute;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Proxy_Function implementation designed for creating a new
|
||||
* Dynamic_Object
|
||||
* that is automatically guarded based on the first param based on the
|
||||
* param's type name
|
||||
*/
|
||||
class Dynamic_Object_Constructor final : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Constructor(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
|
||||
{
|
||||
auto begin = tl.begin();
|
||||
auto end = tl.end();
|
||||
|
||||
if (begin != end)
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
return std::vector<Type_Info>(begin, end);
|
||||
}
|
||||
|
||||
bool operator==(const Proxy_Function_Base &f) const override
|
||||
{
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
}
|
||||
|
||||
bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
|
||||
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
||||
|
||||
return m_func->call_match(new_vals, t_conversions);
|
||||
}
|
||||
|
||||
protected:
|
||||
Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions) const override
|
||||
{
|
||||
auto bv = Boxed_Value(Dynamic_Object(m_type_name), true);
|
||||
std::vector<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params, t_conversions);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string m_type_name;
|
||||
const Proxy_Function m_func;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,79 +1,52 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Value;
|
||||
namespace exception {
|
||||
class bad_boxed_cast;
|
||||
} // namespace exception
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv) = 0;
|
||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
|
||||
|
||||
virtual ~Exception_Handler_Base() = default;
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
void throw_type(const Boxed_Value &bv)
|
||||
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
||||
{
|
||||
try { T t = boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
|
||||
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1>
|
||||
struct Exception_Handler_Impl1 : Exception_Handler_Base
|
||||
template<typename ... T>
|
||||
struct Exception_Handler_Impl : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2>
|
||||
struct Exception_Handler_Impl2 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename T3>
|
||||
struct Exception_Handler_Impl3 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
throw_type<T3>(bv);
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2, typename T3, typename T4>
|
||||
struct Exception_Handler_Impl4 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
throw_type<T3>(bv);
|
||||
throw_type<T4>(bv);
|
||||
}
|
||||
};
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
struct Exception_Handler_Impl5 : Exception_Handler_Base
|
||||
{
|
||||
virtual void handle(const Boxed_Value &bv)
|
||||
{
|
||||
throw_type<T1>(bv);
|
||||
throw_type<T2>(bv);
|
||||
throw_type<T3>(bv);
|
||||
throw_type<T4>(bv);
|
||||
throw_type<T5>(bv);
|
||||
(void)std::initializer_list<int>{(throw_type<T>(bv, t_engine), 0)...};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -132,42 +105,10 @@ namespace chaiscript
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1>
|
||||
template<typename ... T>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles two types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl2<T1, T2>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles three types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2, typename T3>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl3<T1, T2, T3>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles four types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2, typename T3, typename T4>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl4<T1, T2, T3, T4>());
|
||||
}
|
||||
|
||||
/// \brief creates a chaiscript::Exception_Handler which handles five types of exception unboxing
|
||||
/// \sa \ref exceptions
|
||||
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
Exception_Handler exception_specification()
|
||||
{
|
||||
return Exception_Handler(new detail::Exception_Handler_Impl5<T1, T2, T3, T4, T5>());
|
||||
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,128 +1,127 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
#include "boxed_cast.hpp"
|
||||
#include "function_call_detail.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
namespace chaiscript {
|
||||
class Boxed_Value;
|
||||
class Type_Conversions_State;
|
||||
namespace detail {
|
||||
template <typename T> struct Cast_Helper;
|
||||
} // namespace detail
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
/**
|
||||
* Build a function caller that knows how to dispatch on a set of functions
|
||||
* example:
|
||||
* std::function<void (int)> f =
|
||||
* build_function_caller(dispatchkit.get_function("print"));
|
||||
* \returns A std::function object for dispatching
|
||||
* \param[in] funcs the set of functions to dispatch on.
|
||||
*/
|
||||
/// Build a function caller that knows how to dispatch on a set of functions
|
||||
/// example:
|
||||
/// std::function<void (int)> f =
|
||||
/// build_function_caller(dispatchkit.get_function("print"));
|
||||
/// \returns A std::function object for dispatching
|
||||
/// \param[in] funcs the set of functions to dispatch on.
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(const std::vector<Const_Proxy_Function> &funcs)
|
||||
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
FunctionType *p=0;
|
||||
return detail::build_function_caller_helper(p, funcs);
|
||||
const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(),
|
||||
[](const Const_Proxy_Function &f) {
|
||||
return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity<FunctionType>::arity;
|
||||
});
|
||||
|
||||
if (!has_arity_match) {
|
||||
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
|
||||
}
|
||||
|
||||
FunctionType *p=nullptr;
|
||||
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a function caller for a particular Proxy_Function object
|
||||
* useful in the case that a function is being pass out from scripting back
|
||||
* into code
|
||||
* example:
|
||||
* void my_function(Proxy_Function f)
|
||||
* {
|
||||
* std::function<void (int)> local_f =
|
||||
* build_function_caller(f);
|
||||
* }
|
||||
* \returns A std::function object for dispatching
|
||||
* \param[in] func A function to execute.
|
||||
*/
|
||||
/// Build a function caller for a particular Proxy_Function object
|
||||
/// useful in the case that a function is being pass out from scripting back
|
||||
/// into code
|
||||
/// example:
|
||||
/// void my_function(Proxy_Function f)
|
||||
/// {
|
||||
/// std::function<void (int)> local_f =
|
||||
/// build_function_caller(f);
|
||||
/// }
|
||||
/// \returns A std::function object for dispatching
|
||||
/// \param[in] func A function to execute.
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(Const_Proxy_Function func)
|
||||
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
std::vector<Const_Proxy_Function> funcs;
|
||||
funcs.push_back(func);
|
||||
return functor<FunctionType>(funcs);
|
||||
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for automatically unboxing a Boxed_Value that contains a function object
|
||||
* and creating a typesafe C++ function caller from it.
|
||||
*/
|
||||
/// Helper for automatically unboxing a Boxed_Value that contains a function object
|
||||
/// and creating a typesafe C++ function caller from it.
|
||||
template<typename FunctionType>
|
||||
std::function<FunctionType>
|
||||
functor(const Boxed_Value &bv)
|
||||
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv));
|
||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
/**
|
||||
* Cast helper to handle automatic casting to const std::function &
|
||||
*/
|
||||
/// Cast helper to handle automatic casting to const std::function &
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> &>
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
return dispatch::functor<Signature>(ob);
|
||||
return dispatch::functor<Signature>(ob, t_conversions);
|
||||
} else {
|
||||
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob);
|
||||
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast helper to handle automatic casting to std::function
|
||||
*/
|
||||
/// Cast helper to handle automatic casting to std::function
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
return dispatch::functor<Signature>(ob);
|
||||
return dispatch::functor<Signature>(ob, t_conversions);
|
||||
} else {
|
||||
return Cast_Helper_Inner<std::function<Signature> >::cast(ob);
|
||||
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast helper to handle automatic casting to const std::function
|
||||
*/
|
||||
/// Cast helper to handle automatic casting to const std::function
|
||||
template<typename Signature>
|
||||
struct Cast_Helper<const std::function<Signature> >
|
||||
{
|
||||
typedef std::function<Signature> Result_Type;
|
||||
|
||||
static Result_Type cast(const Boxed_Value &ob)
|
||||
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
||||
{
|
||||
return dispatch::functor<Signature>(ob);
|
||||
return dispatch::functor<Signature>(ob, t_conversions);
|
||||
} else {
|
||||
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob);
|
||||
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_conversions.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
@@ -17,31 +29,60 @@ namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/**
|
||||
* Internal helper class for handling the return
|
||||
* value of a build_function_caller
|
||||
*/
|
||||
template<typename Ret>
|
||||
/// Internal helper class for handling the return
|
||||
/// value of a build_function_caller
|
||||
template<typename Ret, bool is_arithmetic>
|
||||
struct Function_Caller_Ret
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params));
|
||||
if (t_conversions != nullptr) {
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, *t_conversions), t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, state), t_conversions);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization for arithmetic return types
|
||||
*/
|
||||
template<typename Ret>
|
||||
struct Function_Caller_Ret<Ret, true>
|
||||
{
|
||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
if (t_conversions != nullptr) {
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, *t_conversions)).get_as<Ret>();
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
return Boxed_Number(dispatch::dispatch(t_funcs, params, state)).get_as<Ret>();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Specialization for void return types
|
||||
*/
|
||||
template<>
|
||||
struct Function_Caller_Ret<void>
|
||||
struct Function_Caller_Ret<void, false>
|
||||
{
|
||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
dispatch::dispatch(t_funcs, params);
|
||||
if (t_conversions != nullptr) {
|
||||
dispatch::dispatch(t_funcs, params, *t_conversions);
|
||||
} else {
|
||||
Type_Conversions conv;
|
||||
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||
dispatch::dispatch(t_funcs, params, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -51,29 +92,60 @@ namespace chaiscript
|
||||
template<typename Ret, typename ... Param>
|
||||
struct Build_Function_Caller_Helper
|
||||
{
|
||||
Build_Function_Caller_Helper(const std::vector<Const_Proxy_Function> &t_funcs)
|
||||
: m_funcs(t_funcs)
|
||||
Build_Function_Caller_Helper(std::vector<Const_Proxy_Function> t_funcs, const Type_Conversions *t_conversions)
|
||||
: m_funcs(std::move(t_funcs)),
|
||||
m_conversions(t_conversions)
|
||||
{
|
||||
}
|
||||
|
||||
Ret operator()(Param...param)
|
||||
template<typename ... P>
|
||||
Ret operator()(P&& ... param)
|
||||
{
|
||||
return Function_Caller_Ret<Ret>::call(m_funcs, {
|
||||
(std::is_reference<Param>::value&&!(std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<Param>::type>::type>::value))?Boxed_Value(std::ref(param)):Boxed_Value(param)...
|
||||
}
|
||||
|
||||
);
|
||||
if (m_conversions) {
|
||||
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, &state
|
||||
);
|
||||
} else {
|
||||
return Function_Caller_Ret<Ret, std::is_arithmetic<Ret>::value && !std::is_same<Ret, bool>::value>::call(m_funcs, {
|
||||
box<P>(std::forward<P>(param))...
|
||||
}, nullptr
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||
}
|
||||
|
||||
template<typename P, typename Q>
|
||||
static auto box(Q&& q) -> typename std::enable_if<!std::is_reference<P>::value&&!std::is_same<chaiscript::Boxed_Value, typename std::remove_const<typename std::remove_reference<P>::type>::type>::value, Boxed_Value>::type
|
||||
{
|
||||
return Boxed_Value(std::forward<Q>(q));
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
static Boxed_Value box(Boxed_Value bv)
|
||||
{
|
||||
return bv;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Const_Proxy_Function> m_funcs;
|
||||
const Type_Conversions *m_conversions;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// \todo what happens if t_conversions is deleted out from under us?!
|
||||
template<typename Ret, typename ... Params>
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs)
|
||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions)
|
||||
{
|
||||
/*
|
||||
if (funcs.size() == 1)
|
||||
{
|
||||
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
|
||||
@@ -87,8 +159,9 @@ namespace chaiscript
|
||||
// looks like this either wasn't a Proxy_Function_Impl or the types didn't match
|
||||
// we cannot make any other guesses or assumptions really, so continuing
|
||||
}
|
||||
*/
|
||||
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs));
|
||||
return std::function<Ret (Params...)>(Build_Function_Caller_Helper<Ret, Params...>(funcs, t_conversions?t_conversions->get():nullptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,122 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_number.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include "boxed_number.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Boxed_Number;
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
template<class T, class U> class Proxy_Function_Callable_Impl;
|
||||
template<class T> class Assignable_Proxy_Function_Impl;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
/// Used internally for handling a return value from a Proxy_Function call
|
||||
template<typename Ret>
|
||||
struct Handle_Return
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||
static Boxed_Value handle(T r)
|
||||
{
|
||||
return const_var(r);
|
||||
return Boxed_Value(std::move(r), true);
|
||||
}
|
||||
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<!std::is_pod<typename std::decay<T>::type>::value>::type>
|
||||
static Boxed_Value handle(T &&r)
|
||||
{
|
||||
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::function<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::shared_ptr<std::function<Ret>>>
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||
return Boxed_Value(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f),f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::function<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(f),
|
||||
std::shared_ptr<std::function<Ret>>())
|
||||
);
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||
return Boxed_Value(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret *&>
|
||||
{
|
||||
static Boxed_Value handle(const Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,7 +125,16 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(Ret *p)
|
||||
{
|
||||
return Boxed_Value(p);
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret *>
|
||||
{
|
||||
static Boxed_Value handle(const Ret *p)
|
||||
{
|
||||
return Boxed_Value(p, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -47,30 +143,43 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
return Boxed_Value(r, true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::shared_ptr<Ret> >
|
||||
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const std::shared_ptr<Ret> &>
|
||||
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
||||
};
|
||||
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<std::unique_ptr<Ret>> : Handle_Return<std::unique_ptr<Ret> &>
|
||||
{
|
||||
static Boxed_Value handle(std::unique_ptr<Ret> &&r)
|
||||
{
|
||||
return Boxed_Value(r);
|
||||
return Boxed_Value(std::move(r), true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret &>
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::cref(r), true);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret>
|
||||
struct Handle_Return<const Ret>
|
||||
{
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
@@ -78,10 +187,6 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<typename Ret>
|
||||
struct Handle_Return<Ret &>
|
||||
{
|
||||
@@ -89,16 +194,8 @@ namespace chaiscript
|
||||
{
|
||||
return Boxed_Value(std::ref(r));
|
||||
}
|
||||
|
||||
static Boxed_Value handle(const Ret &r)
|
||||
{
|
||||
return Boxed_Value(std::cref(r));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<Boxed_Value>
|
||||
{
|
||||
@@ -108,40 +205,19 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<const Boxed_Value>
|
||||
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Value &r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<Boxed_Value &>
|
||||
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Value &r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<const Boxed_Value &>
|
||||
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Value &r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -156,16 +232,9 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used internally for handling a return value from a Proxy_Function call
|
||||
*/
|
||||
template<>
|
||||
struct Handle_Return<const Boxed_Number>
|
||||
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number>
|
||||
{
|
||||
static Boxed_Value handle(const Boxed_Number &r)
|
||||
{
|
||||
return r.bv;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -177,7 +246,7 @@ namespace chaiscript
|
||||
{
|
||||
static Boxed_Value handle()
|
||||
{
|
||||
return Boxed_Value(Boxed_Value::Void_Type());
|
||||
return void_var();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
||||
#define CHAISCRIPT_OPERATORS_HPP_
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "register_function.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -15,443 +20,202 @@ namespace chaiscript
|
||||
{
|
||||
namespace operators
|
||||
{
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign(L l, R r)
|
||||
{
|
||||
return (l = r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_bitwise_and(L l, R r)
|
||||
{
|
||||
return (l &= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_xor(L l, R r)
|
||||
{
|
||||
return (l ^= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_bitwise_or(L l, R r)
|
||||
{
|
||||
return (l |= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_difference(L l, R r)
|
||||
{
|
||||
return (l -= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_left_shift(L l, R r)
|
||||
{
|
||||
return (l <<= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_product(L l, R r)
|
||||
{
|
||||
return (l *= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_quotient(L l, R r)
|
||||
{
|
||||
return (l /= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_remainder(L l, R r)
|
||||
{
|
||||
return (l %= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_right_shift(L l, R r)
|
||||
{
|
||||
return (l >>= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret assign_sum(L l, R r)
|
||||
{
|
||||
return (l += r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L>
|
||||
Ret prefix_decrement(L l)
|
||||
{
|
||||
return (--l);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L>
|
||||
Ret prefix_increment(L l)
|
||||
{
|
||||
return (++l);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret equal(L l, R r)
|
||||
{
|
||||
return (l == r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret greater_than(L l, R r)
|
||||
{
|
||||
return (l > r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret greater_than_equal(L l, R r)
|
||||
{
|
||||
return (l >= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret less_than(L l, R r)
|
||||
{
|
||||
return (l < r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret less_than_equal(L l, R r)
|
||||
{
|
||||
return (l <= r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L>
|
||||
Ret logical_compliment(L l)
|
||||
{
|
||||
return (!l);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret not_equal(L l, R r)
|
||||
{
|
||||
return (l != r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret addition(L l, R r)
|
||||
{
|
||||
return (l + r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L>
|
||||
Ret unary_plus(L l)
|
||||
{
|
||||
return (+l);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret subtraction(L l, R r)
|
||||
{
|
||||
return (l - r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L>
|
||||
Ret unary_minus(L l)
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
return (-l);
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
return (-l);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret bitwise_and(L l, R r)
|
||||
{
|
||||
return (l & r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L>
|
||||
Ret bitwise_compliment(L l)
|
||||
{
|
||||
return (~l);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret bitwise_xor(L l, R r)
|
||||
{
|
||||
return (l ^ r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret bitwise_or(L l, R r)
|
||||
{
|
||||
return (l | r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret division(L l, R r)
|
||||
{
|
||||
return (l / r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret left_shift(L l, R r)
|
||||
{
|
||||
return l << r;
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret multiplication(L l, R r)
|
||||
{
|
||||
return l * r;
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret remainder(L l, R r)
|
||||
{
|
||||
return (l % r);
|
||||
}
|
||||
|
||||
template<typename Ret, typename L, typename R>
|
||||
Ret right_shift(L l, R r)
|
||||
{
|
||||
return (l >> r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign(Module& m)
|
||||
{
|
||||
m->add(fun(&assign<T &, T &, const T&>), "=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs = rhs;}), "=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_bitwise_and(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs &= rhs;}), "&=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_xor(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_xor<T &, T &, const T&>), "^=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs ^= rhs;}), "^=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_bitwise_or(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs |= rhs;}), "|=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_difference(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_difference<T &, T &, const T&>), "-=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs -= rhs;}), "-=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_left_shift(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "<<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_product(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_product<T &, T &, const T&>), "*=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs <<= rhs;}), "*=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_quotient(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_quotient<T &, T &, const T&>), "/=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs /= rhs;}), "/=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_remainder(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_remainder<T &, T &, const T&>), "%=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs %= rhs;}), "%=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_right_shift(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs >>= rhs;}), ">>=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
|
||||
void assign_sum(Module& m)
|
||||
{
|
||||
m->add(fun(&assign_sum<T &, T &, const T&>), "+=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs, const T&rhs)->T&{return lhs += rhs;}), "+=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
|
||||
void prefix_decrement(Module& m)
|
||||
{
|
||||
m->add(fun(&prefix_decrement<T &, T &>), "--");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return --lhs;}), "--");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
|
||||
void prefix_increment(Module& m)
|
||||
{
|
||||
m->add(fun(&prefix_increment<T &, T &>), "++");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](T &lhs)->T&{return ++lhs;}), "++");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
|
||||
void equal(Module& m)
|
||||
{
|
||||
m->add(fun(&equal<bool, const T&, const T&>), "==");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs==rhs;}), "==");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
|
||||
void greater_than(Module& m)
|
||||
{
|
||||
m->add(fun(&greater_than<bool, const T&, const T&>), ">");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>rhs;}), ">");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
|
||||
void greater_than_equal(Module& m)
|
||||
{
|
||||
m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>=rhs;}), ">=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
|
||||
void less_than(Module& m)
|
||||
{
|
||||
m->add(fun(&less_than<bool, const T&, const T&>), "<");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<rhs;}), "<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
|
||||
void less_than_equal(Module& m)
|
||||
{
|
||||
m->add(fun(&less_than_equal<bool, const T&, const T&>), "<=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<=rhs;}), "<=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
|
||||
void logical_compliment(Module& m)
|
||||
{
|
||||
m->add(fun(&logical_compliment<bool, const T &>), "!");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs){return !lhs;}), "!");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
|
||||
void not_equal(Module& m)
|
||||
{
|
||||
m->add(fun(¬_equal<bool, const T &, const T &>), "!=");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs!=rhs;}), "!=");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
|
||||
void addition(Module& m)
|
||||
{
|
||||
m->add(fun(&addition<T, const T &, const T &>), "+");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs+rhs;}), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
|
||||
void unary_plus(Module& m)
|
||||
{
|
||||
m->add(fun(&unary_plus<T, const T &>), "+");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs){return +lhs;}), "+");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
|
||||
void subtraction(Module& m)
|
||||
{
|
||||
m->add(fun(&subtraction<T, const T &, const T &>), "-");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs-rhs;}), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
|
||||
void unary_minus(Module& m)
|
||||
{
|
||||
m->add(fun(&unary_minus<T, const T &>), "-");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs){return -lhs;}), "-");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
|
||||
void bitwise_and(Module& m)
|
||||
{
|
||||
m->add(fun(&bitwise_and<T, const T &, const T &>), "&");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs&rhs;}), "&");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
|
||||
void bitwise_compliment(Module& m)
|
||||
{
|
||||
m->add(fun(&bitwise_compliment<T, const T &>), "~");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs){return ~lhs;}), "~");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
|
||||
void bitwise_xor(Module& m)
|
||||
{
|
||||
m->add(fun(&bitwise_xor<T, const T &, const T &>), "^");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs^rhs;}), "^");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
|
||||
void bitwise_or(Module& m)
|
||||
{
|
||||
m->add(fun(&bitwise_or<T, const T &, const T &>), "|");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs|rhs;}), "|");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr division(ModulePtr m = ModulePtr(new Module()))
|
||||
void division(Module& m)
|
||||
{
|
||||
m->add(fun(&division<T, const T &, const T &>), "/");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs/rhs;}), "/");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
|
||||
void left_shift(Module& m)
|
||||
{
|
||||
m->add(fun(&left_shift<T, const T &, const T &>), "<<");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs<<rhs;}), "<<");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
|
||||
void multiplication(Module& m)
|
||||
{
|
||||
m->add(fun(&multiplication<T, const T &, const T &>), "*");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs*rhs;}), "*");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
|
||||
void remainder(Module& m)
|
||||
{
|
||||
m->add(fun(&remainder<T, const T &, const T &>), "%");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs%rhs;}), "%");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
|
||||
void right_shift(Module& m)
|
||||
{
|
||||
m->add(fun(&right_shift<T, const T &, const T &>), ">>");
|
||||
return m;
|
||||
m.add(chaiscript::fun([](const T &lhs, const T &rhs){return lhs>>rhs;}), ">>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* A constructor function, used for creating a new object
|
||||
* of a given type with a given set of params
|
||||
*/
|
||||
template<typename Class, typename ... Params>
|
||||
std::shared_ptr<Class> constructor_(Params ... params)
|
||||
{
|
||||
return std::shared_ptr<Class>(new Class(params...));
|
||||
}
|
||||
|
||||
template<typename Class, typename ... Params >
|
||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||
{
|
||||
typedef std::shared_ptr<Class> (sig)(Params...);
|
||||
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
|
||||
auto call = dispatch::detail::Constructor<Class, Params...>();
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class> (Params...), decltype(call)>>(call));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +46,7 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
Proxy_Function constructor()
|
||||
{
|
||||
T *f = 0;
|
||||
T *f = nullptr;
|
||||
return (dispatch::detail::build_constructor_(f));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,34 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||
|
||||
#include "boxed_value.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include <string>
|
||||
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "handle_return.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "callable_traits.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions_State;
|
||||
namespace exception {
|
||||
class bad_boxed_cast;
|
||||
} // namespace exception
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -32,7 +46,9 @@ namespace chaiscript
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~arity_error() noexcept {}
|
||||
arity_error(const arity_error &) = default;
|
||||
|
||||
~arity_error() noexcept override = default;
|
||||
|
||||
int got;
|
||||
int expected;
|
||||
@@ -50,130 +66,74 @@ namespace chaiscript
|
||||
template<typename Ret, typename ... Params>
|
||||
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
|
||||
{
|
||||
return std::vector<Type_Info> { chaiscript::detail::Get_Type_Info<Ret>::get(),
|
||||
chaiscript::detail::Get_Type_Info<Params>::get()... };
|
||||
/// \note somehow this is responsible for a large part of the code generation
|
||||
return { user_type<Ret>(), user_type<Params>()... };
|
||||
}
|
||||
|
||||
|
||||
// Forward declaration
|
||||
template<typename ... Rest>
|
||||
struct Try_Cast;
|
||||
|
||||
// implementation
|
||||
template<typename Param, typename ... Rest>
|
||||
struct Try_Cast<Param, Rest...>
|
||||
{
|
||||
static void do_try(const std::vector<Boxed_Value> ¶ms, int generation)
|
||||
{
|
||||
boxed_cast<Param>(params[generation]);
|
||||
Try_Cast<Rest...>::do_try(params, generation+1);
|
||||
}
|
||||
};
|
||||
|
||||
// 0th case
|
||||
template<>
|
||||
struct Try_Cast<>
|
||||
{
|
||||
static void do_try(const std::vector<Boxed_Value> &, int)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||
* Proxy_Function_Impl object. This function is primarly used to prevent
|
||||
* Proxy_Function_Impl object. This function is primarily used to prevent
|
||||
* registration of two functions with the exact same signatures
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
bool compare_types_cast(Ret (*)(Params...),
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
try {
|
||||
Try_Cast<Params...>::do_try(params, 0);
|
||||
std::vector<Boxed_Value>::size_type i = 0;
|
||||
(void)i;
|
||||
(void)params; (void)t_conversions;
|
||||
// this is ok because the order of evaluation of initializer lists is well defined
|
||||
(void)std::initializer_list<int>{(boxed_cast<Params>(params[i++], &t_conversions), 0)...};
|
||||
return true;
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ret, int count, typename ... Params>
|
||||
struct Call_Func
|
||||
|
||||
template<typename Callable, typename Ret, typename ... Params, size_t ... I>
|
||||
Ret call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &,
|
||||
std::index_sequence<I...>, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> ¶ms, InnerParams &&... innerparams)
|
||||
{
|
||||
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Params>
|
||||
struct Call_Func<Ret, 0, Params...>
|
||||
{
|
||||
template<typename ... InnerParams>
|
||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> &, InnerParams &&... innerparams)
|
||||
{
|
||||
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams))...);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
* The function attempts to unbox each paramter to the expected type.
|
||||
* if any unboxing fails the execution of the function fails and
|
||||
* the bad_boxed_cast is passed up to the caller.
|
||||
*/
|
||||
template<typename Ret, typename ... Params>
|
||||
Ret call_func(const std::function<Ret (Params...)> &f,
|
||||
const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
if (params.size() == sizeof...(Params))
|
||||
{
|
||||
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params);
|
||||
}
|
||||
|
||||
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
|
||||
(void)params; (void)t_conversions;
|
||||
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||
/// The function attempts to unbox each parameter to the expected type.
|
||||
/// if any unboxing fails the execution of the function fails and
|
||||
/// the bad_boxed_cast is passed up to the caller.
|
||||
template<typename Callable, typename Ret, typename ... Params>
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<Ret (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
||||
}
|
||||
|
||||
template<typename Callable, typename ... Params>
|
||||
Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature<void (Params...)> &sig, const Callable &f,
|
||||
const std::vector<Boxed_Value> ¶ms, const Type_Conversions_State &t_conversions)
|
||||
{
|
||||
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702)
|
||||
#endif
|
||||
// MSVC is reporting that this is unreachable code - and it's wrong.
|
||||
return Handle_Return<void>::handle();
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename Ret>
|
||||
struct Do_Call
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
return Handle_Return<Ret>::handle(call_func(fun, params));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Do_Call<void>
|
||||
{
|
||||
template<typename Fun>
|
||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms)
|
||||
{
|
||||
call_func(fun, params);
|
||||
return Handle_Return<void>::handle();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,89 +1,23 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include <type_traits>
|
||||
|
||||
#include "bind_first.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct FunctionSignature
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Sig>
|
||||
struct FunctionSignature<std::function<Sig> >
|
||||
{
|
||||
typedef Sig Signature;
|
||||
};
|
||||
|
||||
template<typename Ret, typename ... Args>
|
||||
std::function<Ret (Args...) > to_function(Ret (*func)(Args...))
|
||||
{
|
||||
return std::function<Ret (Args...)>(func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
|
||||
{
|
||||
return std::function<Ret (Class &, Args...)>(func);
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Args>
|
||||
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
||||
{
|
||||
return std::function<Ret (const Class &, Args...)>(func);
|
||||
}
|
||||
|
||||
template<bool Object>
|
||||
struct Fun_Helper
|
||||
{
|
||||
template<typename T>
|
||||
static Proxy_Function go(T t)
|
||||
{
|
||||
return Proxy_Function(
|
||||
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Fun_Helper<true>
|
||||
{
|
||||
template<typename T, typename Class>
|
||||
static Proxy_Function go(T Class::* m)
|
||||
{
|
||||
return Proxy_Function(new Attribute_Access<T, Class>(m));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a std::function object
|
||||
/// \param[in] f std::function to expose to ChaiScript
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::function<int (char, float, std::string)> f = get_some_function();
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(fun(f), "some_function");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
template<typename T>
|
||||
Proxy_Function fun(const std::function<T> &f)
|
||||
{
|
||||
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||
/// \param[in] t Function / member to expose
|
||||
@@ -104,13 +38,55 @@ namespace chaiscript
|
||||
/// chai.add(fun(&MyClass::memberdata), "memberdata");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
/// \sa \ref adding_functions
|
||||
template<typename T>
|
||||
Proxy_Function fun(T t)
|
||||
Proxy_Function fun(const T &t)
|
||||
{
|
||||
return dispatch::detail::Fun_Helper<std::is_member_object_pointer<T>::value>::go(t);
|
||||
typedef typename dispatch::detail::Callable_Traits<T>::Signature Signature;
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Signature, T>>(t));
|
||||
}
|
||||
|
||||
template<typename Ret, typename ... Param>
|
||||
Proxy_Function fun(Ret (*func)(Param...))
|
||||
{
|
||||
auto fun_call = dispatch::detail::Fun_Caller<Ret, Param...>(func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Param...), decltype(fun_call)>>(fun_call));
|
||||
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...) const)
|
||||
{
|
||||
auto call = dispatch::detail::Const_Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (const Class &, Param...), decltype(call)>>(call));
|
||||
}
|
||||
|
||||
template<typename Ret, typename Class, typename ... Param>
|
||||
Proxy_Function fun(Ret (Class::*t_func)(Param...))
|
||||
{
|
||||
auto call = dispatch::detail::Caller<Ret, Class, Param...>(t_func);
|
||||
|
||||
return Proxy_Function(
|
||||
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret (Class &, Param...), decltype(call)>>(call));
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename Class /*, typename = typename std::enable_if<std::is_member_object_pointer<T>::value>::type*/>
|
||||
Proxy_Function fun(T Class::* m /*, typename std::enable_if<std::is_member_object_pointer<T>::value>::type* = 0*/ )
|
||||
{
|
||||
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<T, Class>>(m));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it
|
||||
/// \param[in] t Function / member to expose
|
||||
/// \param[in] q Value to bind to first parameter
|
||||
@@ -128,39 +104,14 @@ namespace chaiscript
|
||||
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
/// \sa \ref adding_functions
|
||||
template<typename T, typename Q>
|
||||
Proxy_Function fun(T t, const Q &q)
|
||||
Proxy_Function fun(T &&t, const Q &q)
|
||||
{
|
||||
return fun(detail::bind_first(t, q));
|
||||
return fun(detail::bind_first(std::forward<T>(t), q));
|
||||
}
|
||||
|
||||
/// \brief Creates a new Proxy_Function object from a free function or member function and binds the first and second parameters of it
|
||||
/// \param[in] t Function / member to expose
|
||||
/// \param[in] q Value to bind to first parameter
|
||||
/// \param[in] r Value to bind to second parameter
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct MyClass
|
||||
/// {
|
||||
/// void memberfunction(int);
|
||||
/// };
|
||||
///
|
||||
/// MyClass obj;
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// // Add function taking only no arguments, and permanently bound to "obj" and "1"
|
||||
/// // memberfunction() will be equivalent to obj.memberfunction(1)
|
||||
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj), 1), "memberfunction");
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingfunctions
|
||||
template<typename T, typename Q, typename R>
|
||||
Proxy_Function fun(T t, const Q &q, const R &r)
|
||||
{
|
||||
return fun(detail::bind_first(detail::bind_first(t, q), r));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
159
include/chaiscript/dispatchkit/short_alloc.hpp
Normal file
159
include/chaiscript/dispatchkit/short_alloc.hpp
Normal file
@@ -0,0 +1,159 @@
|
||||
#ifndef SHORT_ALLOC_H
|
||||
#define SHORT_ALLOC_H
|
||||
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2015 Howard Hinnant
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
|
||||
template <std::size_t N, std::size_t alignment = alignof(std::max_align_t)>
|
||||
class arena
|
||||
{
|
||||
alignas(alignment) char buf_[N];
|
||||
char* ptr_;
|
||||
|
||||
public:
|
||||
~arena() {ptr_ = nullptr;}
|
||||
arena() noexcept : ptr_(buf_) {}
|
||||
arena(const arena&) = delete;
|
||||
arena& operator=(const arena&) = delete;
|
||||
|
||||
template <std::size_t ReqAlign> char* allocate(std::size_t n);
|
||||
void deallocate(char* p, std::size_t n) noexcept;
|
||||
|
||||
static constexpr std::size_t size() noexcept {return N;}
|
||||
std::size_t used() const noexcept {return static_cast<std::size_t>(ptr_ - buf_);}
|
||||
void reset() noexcept {ptr_ = buf_;}
|
||||
|
||||
private:
|
||||
static
|
||||
std::size_t
|
||||
align_up(std::size_t n) noexcept
|
||||
{return (n + (alignment-1)) & ~(alignment-1);}
|
||||
|
||||
bool
|
||||
pointer_in_buffer(char* p) noexcept
|
||||
{return buf_ <= p && p <= buf_ + N;}
|
||||
};
|
||||
|
||||
template <std::size_t N, std::size_t alignment>
|
||||
template <std::size_t ReqAlign>
|
||||
char*
|
||||
arena<N, alignment>::allocate(std::size_t n)
|
||||
{
|
||||
static_assert(ReqAlign <= alignment, "alignment is too small for this arena");
|
||||
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
|
||||
auto const aligned_n = align_up(n);
|
||||
if (static_cast<decltype(aligned_n)>(buf_ + N - ptr_) >= aligned_n)
|
||||
{
|
||||
char* r = ptr_;
|
||||
ptr_ += aligned_n;
|
||||
return r;
|
||||
}
|
||||
|
||||
static_assert(alignment <= alignof(std::max_align_t), "you've chosen an "
|
||||
"alignment that is larger than alignof(std::max_align_t), and "
|
||||
"cannot be guaranteed by normal operator new");
|
||||
return static_cast<char*>(::operator new(n));
|
||||
}
|
||||
|
||||
template <std::size_t N, std::size_t alignment>
|
||||
void
|
||||
arena<N, alignment>::deallocate(char* p, std::size_t n) noexcept
|
||||
{
|
||||
assert(pointer_in_buffer(ptr_) && "short_alloc has outlived arena");
|
||||
if (pointer_in_buffer(p))
|
||||
{
|
||||
n = align_up(n);
|
||||
if (p + n == ptr_) {
|
||||
ptr_ = p;
|
||||
}
|
||||
}
|
||||
else {
|
||||
::operator delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, std::size_t N, std::size_t Align = alignof(std::max_align_t)>
|
||||
class short_alloc
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
static auto constexpr alignment = Align;
|
||||
static auto constexpr size = N;
|
||||
using arena_type = arena<size, alignment>;
|
||||
|
||||
private:
|
||||
arena_type& a_;
|
||||
|
||||
public:
|
||||
short_alloc(const short_alloc&) = default;
|
||||
short_alloc& operator=(const short_alloc&) = delete;
|
||||
|
||||
explicit short_alloc(arena_type& a) noexcept : a_(a)
|
||||
{
|
||||
static_assert(size % alignment == 0,
|
||||
"size N needs to be a multiple of alignment Align");
|
||||
}
|
||||
template <class U>
|
||||
explicit short_alloc(const short_alloc<U, N, alignment>& a) noexcept
|
||||
: a_(a.a_) {}
|
||||
|
||||
template <class _Up> struct rebind {using other = short_alloc<_Up, N, alignment>;};
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
return reinterpret_cast<T*>(a_.template allocate<alignof(T)>(n*sizeof(T)));
|
||||
}
|
||||
void deallocate(T* p, std::size_t n) noexcept
|
||||
{
|
||||
a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
|
||||
}
|
||||
|
||||
template <class T1, std::size_t N1, std::size_t A1,
|
||||
class U, std::size_t M, std::size_t A2>
|
||||
friend
|
||||
bool
|
||||
operator==(const short_alloc<T1, N1, A1>& x, const short_alloc<U, M, A2>& y) noexcept;
|
||||
|
||||
template <class U, std::size_t M, std::size_t A> friend class short_alloc;
|
||||
};
|
||||
|
||||
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
||||
inline
|
||||
bool
|
||||
operator==(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
|
||||
{
|
||||
return N == M && A1 == A2 && &x.a_ == &y.a_;
|
||||
}
|
||||
|
||||
template <class T, std::size_t N, std::size_t A1, class U, std::size_t M, std::size_t A2>
|
||||
inline
|
||||
bool
|
||||
operator!=(const short_alloc<T, N, A1>& x, const short_alloc<U, M, A2>& y) noexcept
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
#endif // SHORT_ALLOC_HPP
|
||||
|
||||
649
include/chaiscript/dispatchkit/type_conversions.hpp
Normal file
649
include/chaiscript/dispatchkit/type_conversions.hpp
Normal file
@@ -0,0 +1,649 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../chaiscript_threading.hpp"
|
||||
#include "bad_boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
class bad_boxed_dynamic_cast : public bad_boxed_cast
|
||||
{
|
||||
public:
|
||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||
const std::string &t_what) noexcept
|
||||
: bad_boxed_cast(t_from, t_to, t_what)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
||||
: bad_boxed_cast(t_from, t_to)
|
||||
{
|
||||
}
|
||||
|
||||
explicit bad_boxed_dynamic_cast(const std::string &w) noexcept
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
|
||||
|
||||
~bad_boxed_dynamic_cast() noexcept override = default;
|
||||
};
|
||||
|
||||
class bad_boxed_type_cast : public bad_boxed_cast
|
||||
{
|
||||
public:
|
||||
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
|
||||
const std::string &t_what) noexcept
|
||||
: bad_boxed_cast(t_from, t_to, t_what)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
|
||||
: bad_boxed_cast(t_from, t_to)
|
||||
{
|
||||
}
|
||||
|
||||
explicit bad_boxed_type_cast(const std::string &w) noexcept
|
||||
: bad_boxed_cast(w)
|
||||
{
|
||||
}
|
||||
|
||||
bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
|
||||
|
||||
~bad_boxed_type_cast() noexcept override = default;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class Type_Conversion_Base
|
||||
{
|
||||
public:
|
||||
virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
|
||||
virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
|
||||
|
||||
const Type_Info &to() const
|
||||
{
|
||||
return m_to;
|
||||
}
|
||||
const Type_Info &from() const
|
||||
{
|
||||
return m_from;
|
||||
}
|
||||
|
||||
virtual bool bidir() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual ~Type_Conversion_Base() = default;
|
||||
|
||||
protected:
|
||||
Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
|
||||
: m_to(std::move(t_to)), m_from(std::move(t_from))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
const Type_Info m_to;
|
||||
const Type_Info m_from;
|
||||
|
||||
};
|
||||
|
||||
template<typename From, typename To>
|
||||
class Static_Caster
|
||||
{
|
||||
public:
|
||||
static Boxed_Value cast(const Boxed_Value &t_from)
|
||||
{
|
||||
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
|
||||
{
|
||||
if (t_from.is_pointer())
|
||||
{
|
||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||
if (t_from.is_const())
|
||||
{
|
||||
return Boxed_Value(
|
||||
[&](){
|
||||
if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
} else {
|
||||
return Boxed_Value(
|
||||
[&](){
|
||||
if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||
if (t_from.is_const())
|
||||
{
|
||||
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
||||
const To &data = static_cast<const To &>(d);
|
||||
return Boxed_Value(std::cref(data));
|
||||
} else {
|
||||
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
|
||||
To &data = static_cast<To &>(d);
|
||||
return Boxed_Value(std::ref(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename From, typename To>
|
||||
class Dynamic_Caster
|
||||
{
|
||||
public:
|
||||
static Boxed_Value cast(const Boxed_Value &t_from)
|
||||
{
|
||||
if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
|
||||
{
|
||||
if (t_from.is_pointer())
|
||||
{
|
||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||
if (t_from.is_const())
|
||||
{
|
||||
return Boxed_Value(
|
||||
[&](){
|
||||
if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
} else {
|
||||
return Boxed_Value(
|
||||
[&](){
|
||||
if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
|
||||
{
|
||||
return data;
|
||||
} else {
|
||||
#ifdef CHAISCRIPT_LIBCPP
|
||||
/// \todo fix this someday after libc++ is fixed.
|
||||
if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
|
||||
auto from = detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr);
|
||||
if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
|
||||
return std::static_pointer_cast<To>(from);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
throw std::bad_cast();
|
||||
}
|
||||
}()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||
if (t_from.is_const())
|
||||
{
|
||||
const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
|
||||
const To &data = dynamic_cast<const To &>(d);
|
||||
return Boxed_Value(std::cref(data));
|
||||
} else {
|
||||
From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
|
||||
To &data = dynamic_cast<To &>(d);
|
||||
return Boxed_Value(std::ref(data));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
class Dynamic_Conversion_Impl : public Type_Conversion_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Conversion_Impl()
|
||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||
{
|
||||
}
|
||||
|
||||
Boxed_Value convert_down(const Boxed_Value &t_base) const override
|
||||
{
|
||||
return Dynamic_Caster<Base, Derived>::cast(t_base);
|
||||
}
|
||||
|
||||
Boxed_Value convert(const Boxed_Value &t_derived) const override
|
||||
{
|
||||
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
class Static_Conversion_Impl : public Type_Conversion_Base
|
||||
{
|
||||
public:
|
||||
Static_Conversion_Impl()
|
||||
: Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
|
||||
{
|
||||
}
|
||||
|
||||
Boxed_Value convert_down(const Boxed_Value &t_base) const override
|
||||
{
|
||||
throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived),
|
||||
"Unable to cast down inheritance hierarchy with non-polymorphic types");
|
||||
}
|
||||
|
||||
bool bidir() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Boxed_Value convert(const Boxed_Value &t_derived) const override
|
||||
{
|
||||
return Static_Caster<Derived, Base>::cast(t_derived);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
class Type_Conversion_Impl : public Type_Conversion_Base
|
||||
{
|
||||
public:
|
||||
Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
|
||||
: Type_Conversion_Base(t_to, t_from),
|
||||
m_func(std::move(t_func))
|
||||
{
|
||||
}
|
||||
|
||||
Boxed_Value convert_down(const Boxed_Value &) const override
|
||||
{
|
||||
throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
|
||||
}
|
||||
|
||||
Boxed_Value convert(const Boxed_Value &t_from) const override
|
||||
{
|
||||
/// \todo better handling of errors from the conversion function
|
||||
return m_func(t_from);
|
||||
}
|
||||
|
||||
bool bidir() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Callable m_func;
|
||||
};
|
||||
}
|
||||
|
||||
class Type_Conversions
|
||||
{
|
||||
public:
|
||||
struct Conversion_Saves
|
||||
{
|
||||
bool enabled = false;
|
||||
std::vector<Boxed_Value> saves;
|
||||
};
|
||||
|
||||
struct Less_Than
|
||||
{
|
||||
bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const
|
||||
{
|
||||
return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
|
||||
}
|
||||
};
|
||||
|
||||
Type_Conversions()
|
||||
: m_mutex(),
|
||||
m_conversions(),
|
||||
m_convertableTypes(),
|
||||
m_num_types(0)
|
||||
{
|
||||
}
|
||||
|
||||
Type_Conversions(const Type_Conversions &t_other) = delete;
|
||||
Type_Conversions(Type_Conversions &&) = default;
|
||||
|
||||
Type_Conversions &operator=(const Type_Conversions &) = delete;
|
||||
Type_Conversions &operator=(Type_Conversions &&) = default;
|
||||
|
||||
const std::set<const std::type_info *, Less_Than> &thread_cache() const
|
||||
{
|
||||
auto &cache = *m_thread_cache;
|
||||
if (cache.size() != m_num_types)
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
cache = m_convertableTypes;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
|
||||
{
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
/// \todo error if a conversion already exists
|
||||
m_conversions.insert(conversion);
|
||||
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
|
||||
m_num_types = m_convertableTypes.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool convertable_type() const
|
||||
{
|
||||
return thread_cache().count(user_type<T>().bare_type_info()) != 0;
|
||||
}
|
||||
|
||||
template<typename To, typename From>
|
||||
bool converts() const
|
||||
{
|
||||
return converts(user_type<To>(), user_type<From>());
|
||||
}
|
||||
|
||||
bool converts(const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
const auto &types = thread_cache();
|
||||
if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
|
||||
{
|
||||
return has_conversion(to, from);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
|
||||
{
|
||||
return boxed_type_conversion(user_type<To>(), t_saves, from);
|
||||
}
|
||||
|
||||
template<typename From>
|
||||
Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
|
||||
{
|
||||
return boxed_type_down_conversion(user_type<From>(), t_saves, to);
|
||||
}
|
||||
|
||||
|
||||
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
|
||||
{
|
||||
try {
|
||||
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
|
||||
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
|
||||
return ret;
|
||||
} catch (const std::out_of_range &) {
|
||||
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
|
||||
} catch (const std::bad_cast &) {
|
||||
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
|
||||
}
|
||||
}
|
||||
|
||||
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
|
||||
{
|
||||
try {
|
||||
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
|
||||
if (t_saves.enabled) { t_saves.saves.push_back(ret); }
|
||||
return ret;
|
||||
} catch (const std::out_of_range &) {
|
||||
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
|
||||
} catch (const std::bad_cast &) {
|
||||
throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val)
|
||||
{
|
||||
t_saves.enabled = t_val;
|
||||
}
|
||||
|
||||
std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
|
||||
{
|
||||
std::vector<Boxed_Value> ret;
|
||||
std::swap(ret, t_saves.saves);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool has_conversion(const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
return find_bidir(to, from) != m_conversions.end();
|
||||
}
|
||||
|
||||
std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
const auto itr = find(to, from);
|
||||
|
||||
if (itr != m_conversions.end())
|
||||
{
|
||||
return *itr;
|
||||
} else {
|
||||
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
|
||||
}
|
||||
}
|
||||
|
||||
Conversion_Saves &conversion_saves() const {
|
||||
return *m_conversion_saves;
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
|
||||
const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
return std::find_if(m_conversions.begin(), m_conversions.end(),
|
||||
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
|
||||
{
|
||||
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|
||||
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
|
||||
const Type_Info &to, const Type_Info &from) const
|
||||
{
|
||||
return std::find_if(m_conversions.begin(), m_conversions.end(),
|
||||
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
|
||||
{
|
||||
return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
|
||||
{
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||
|
||||
return m_conversions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
|
||||
std::set<const std::type_info *, Less_Than> m_convertableTypes;
|
||||
std::atomic_size_t m_num_types;
|
||||
mutable chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
|
||||
mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
|
||||
};
|
||||
|
||||
class Type_Conversions_State
|
||||
{
|
||||
public:
|
||||
Type_Conversions_State(const Type_Conversions &t_conversions,
|
||||
Type_Conversions::Conversion_Saves &t_saves)
|
||||
: m_conversions(t_conversions),
|
||||
m_saves(t_saves)
|
||||
{
|
||||
}
|
||||
|
||||
const Type_Conversions *operator->() const {
|
||||
return &m_conversions.get();
|
||||
}
|
||||
|
||||
const Type_Conversions *get() const {
|
||||
return &m_conversions.get();
|
||||
}
|
||||
|
||||
Type_Conversions::Conversion_Saves &saves() const {
|
||||
return m_saves;
|
||||
}
|
||||
|
||||
private:
|
||||
std::reference_wrapper<const Type_Conversions> m_conversions;
|
||||
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<chaiscript::detail::Type_Conversion_Base> Type_Conversion;
|
||||
|
||||
/// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
|
||||
/// want automatic conversions up your inheritance hierarchy.
|
||||
///
|
||||
/// Create a new to class registration for applying to a module or to the ChaiScript engine
|
||||
/// Currently, due to limitations in module loading on Windows, and for the sake of portability,
|
||||
/// if you have a type that is introduced in a loadable module and is used by multiple modules
|
||||
/// (through a tertiary dll that is shared between the modules, static linking the new type
|
||||
/// into both loadable modules would not be portable), you need to register the type
|
||||
/// relationship in all modules that use the newly added type in a polymorphic way.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// class Base
|
||||
/// {};
|
||||
/// class Derived : public Base
|
||||
/// {};
|
||||
///
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::to_class<Base, Derived>());
|
||||
/// \endcode
|
||||
///
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class(typename std::enable_if<std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
Type_Conversion base_class(typename std::enable_if<!std::is_polymorphic<Base>::value || !std::is_polymorphic<Derived>::value>::type* = nullptr)
|
||||
{
|
||||
//Can only be used with related polymorphic types
|
||||
//may be expanded some day to support conversions other than child -> parent
|
||||
static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
|
||||
}
|
||||
|
||||
|
||||
template<typename Callable>
|
||||
Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to,
|
||||
const Callable &t_func)
|
||||
{
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
|
||||
}
|
||||
|
||||
template<typename From, typename To, typename Callable>
|
||||
Type_Conversion type_conversion(const Callable &t_function)
|
||||
{
|
||||
auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
|
||||
return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
template<typename From, typename To>
|
||||
Type_Conversion type_conversion()
|
||||
{
|
||||
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
|
||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
|
||||
return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Type_Conversion vector_conversion()
|
||||
{
|
||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
|
||||
|
||||
To vec;
|
||||
vec.reserve(from_vec.size());
|
||||
for (const Boxed_Value &bv : from_vec) {
|
||||
vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
|
||||
}
|
||||
|
||||
return Boxed_Value(std::move(vec));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
|
||||
}
|
||||
|
||||
template<typename To>
|
||||
Type_Conversion map_conversion()
|
||||
{
|
||||
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
|
||||
const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
|
||||
|
||||
To map;
|
||||
for (const std::pair<std::string, Boxed_Value> &p : from_map) {
|
||||
map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
|
||||
}
|
||||
|
||||
return Boxed_Value(std::move(map));
|
||||
};
|
||||
|
||||
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,16 +1,20 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
|
||||
#define CHAISCRIPT_TYPE_INFO_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <string>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
@@ -24,88 +28,71 @@ namespace chaiscript
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// \brief Compile time deduced information about a type
|
||||
class Type_Info
|
||||
{
|
||||
public:
|
||||
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bareti)
|
||||
: m_type_info(t_ti), m_bare_type_info(t_bareti),
|
||||
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
||||
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
|
||||
m_is_undef(false)
|
||||
constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void,
|
||||
const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti)
|
||||
: m_type_info(t_ti), m_bare_type_info(t_bare_ti),
|
||||
m_flags((static_cast<unsigned int>(t_is_const) << is_const_flag)
|
||||
+ (static_cast<unsigned int>(t_is_reference) << is_reference_flag)
|
||||
+ (static_cast<unsigned int>(t_is_pointer) << is_pointer_flag)
|
||||
+ (static_cast<unsigned int>(t_is_void) << is_void_flag)
|
||||
+ (static_cast<unsigned int>(t_is_arithmetic) << is_arithmetic_flag))
|
||||
{
|
||||
}
|
||||
|
||||
Type_Info()
|
||||
: m_type_info(0), m_bare_type_info(0),
|
||||
m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
||||
m_is_void(false), m_is_arithmetic(false),
|
||||
m_is_undef(true)
|
||||
{
|
||||
}
|
||||
constexpr Type_Info() = default;
|
||||
|
||||
Type_Info(const Type_Info &ti)
|
||||
: m_type_info(ti.m_type_info),
|
||||
m_bare_type_info(ti.m_bare_type_info),
|
||||
m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
|
||||
m_is_pointer(ti.m_is_pointer),
|
||||
m_is_void(ti.m_is_void), m_is_arithmetic(ti.m_is_arithmetic),
|
||||
m_is_undef(ti.m_is_undef)
|
||||
{
|
||||
}
|
||||
|
||||
Type_Info &operator=(const Type_Info &ti)
|
||||
{
|
||||
m_type_info = ti.m_type_info;
|
||||
m_bare_type_info = ti.m_bare_type_info;
|
||||
m_is_const = ti.m_is_const;
|
||||
m_is_reference = ti.m_is_reference;
|
||||
m_is_pointer = ti.m_is_pointer;
|
||||
m_is_void = ti.m_is_void;
|
||||
m_is_arithmetic = ti.m_is_arithmetic;
|
||||
m_is_undef = ti.m_is_undef;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(const Type_Info &ti) const
|
||||
constexpr bool operator<(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return m_type_info < ti.m_type_info;
|
||||
}
|
||||
|
||||
bool operator==(const Type_Info &ti) const
|
||||
constexpr bool operator!=(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return ti.m_type_info == m_type_info
|
||||
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
|
||||
return !(operator==(ti));
|
||||
}
|
||||
|
||||
bool operator==(const std::type_info &ti) const
|
||||
constexpr bool operator!=(const std::type_info &ti) const noexcept
|
||||
{
|
||||
return m_type_info != 0 && (*m_type_info) == ti;
|
||||
return !(operator==(ti));
|
||||
}
|
||||
|
||||
bool bare_equal(const Type_Info &ti) const
|
||||
constexpr bool operator==(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return ti.m_bare_type_info == m_bare_type_info
|
||||
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
|
||||
return ti.m_type_info == m_type_info
|
||||
|| *ti.m_type_info == *m_type_info;
|
||||
}
|
||||
|
||||
bool bare_equal_type_info(const std::type_info &ti) const
|
||||
constexpr bool operator==(const std::type_info &ti) const noexcept
|
||||
{
|
||||
return m_bare_type_info != 0
|
||||
&& (*m_bare_type_info) == ti;
|
||||
return !is_undef() && (*m_type_info) == ti;
|
||||
}
|
||||
|
||||
bool is_const() const { return m_is_const; }
|
||||
bool is_reference() const { return m_is_reference; }
|
||||
bool is_void() const { return m_is_void; }
|
||||
bool is_arithmetic() const { return m_is_arithmetic; }
|
||||
bool is_undef() const { return m_is_undef || m_bare_type_info == 0; }
|
||||
bool is_pointer() const { return m_is_pointer; }
|
||||
constexpr bool bare_equal(const Type_Info &ti) const noexcept
|
||||
{
|
||||
return ti.m_bare_type_info == m_bare_type_info
|
||||
|| *ti.m_bare_type_info == *m_bare_type_info;
|
||||
}
|
||||
|
||||
constexpr bool bare_equal_type_info(const std::type_info &ti) const noexcept
|
||||
{
|
||||
return !is_undef() && (*m_bare_type_info) == ti;
|
||||
}
|
||||
|
||||
constexpr bool is_const() const noexcept { return (m_flags & (1 << is_const_flag)) != 0; }
|
||||
constexpr bool is_reference() const noexcept { return (m_flags & (1 << is_reference_flag)) != 0; }
|
||||
constexpr bool is_void() const noexcept { return (m_flags & (1 << is_void_flag)) != 0; }
|
||||
constexpr bool is_arithmetic() const noexcept { return (m_flags & (1 << is_arithmetic_flag)) != 0; }
|
||||
constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; }
|
||||
constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; }
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
if (m_type_info)
|
||||
if (!is_undef())
|
||||
{
|
||||
return m_type_info->name();
|
||||
} else {
|
||||
@@ -115,7 +102,7 @@ namespace chaiscript
|
||||
|
||||
std::string bare_name() const
|
||||
{
|
||||
if (m_bare_type_info)
|
||||
if (!is_undef())
|
||||
{
|
||||
return m_bare_type_info->name();
|
||||
} else {
|
||||
@@ -123,33 +110,39 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const std::type_info *bare_type_info() const
|
||||
{
|
||||
return m_bare_type_info;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::type_info *m_type_info;
|
||||
const std::type_info *m_bare_type_info;
|
||||
bool m_is_const;
|
||||
bool m_is_reference;
|
||||
bool m_is_pointer;
|
||||
bool m_is_void;
|
||||
bool m_is_arithmetic;
|
||||
bool m_is_undef;
|
||||
struct Unknown_Type {};
|
||||
|
||||
const std::type_info *m_type_info = &typeid(Unknown_Type);
|
||||
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
|
||||
static const int is_const_flag = 0;
|
||||
static const int is_reference_flag = 1;
|
||||
static const int is_pointer_flag = 2;
|
||||
static const int is_void_flag = 3;
|
||||
static const int is_arithmetic_flag = 4;
|
||||
static const int is_undef_flag = 5;
|
||||
unsigned int m_flags = (1 << is_undef_flag);
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Helper used to create a Type_Info object
|
||||
*/
|
||||
/// Helper used to create a Type_Info object
|
||||
template<typename T>
|
||||
struct Get_Type_Info
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||
std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
&typeid(T),
|
||||
(std::is_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
|
||||
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(T),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
@@ -157,28 +150,31 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::shared_ptr<T> >
|
||||
{
|
||||
typedef T type;
|
||||
// typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::shared_ptr<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::shared_ptr<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@@ -187,13 +183,11 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<std::reference_wrapper<T> >
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(std::reference_wrapper<T> ),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
@@ -202,23 +196,16 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
||||
{
|
||||
typedef T type;
|
||||
|
||||
constexpr static Type_Info get()
|
||||
static constexpr Type_Info get()
|
||||
{
|
||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
||||
std::is_void<T>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||
&typeid(const std::reference_wrapper<T> &),
|
||||
&typeid(typename Bare_Type<T>::type));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct Stripped_Type
|
||||
{
|
||||
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Creates a Type_Info object representing the type passed in
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
|
||||
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
||||
|
||||
#include "../utility/fnv1a.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
struct Operators {
|
||||
enum Opers
|
||||
enum class Opers
|
||||
{
|
||||
boolean_flag,
|
||||
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
|
||||
@@ -31,7 +37,7 @@ namespace chaiscript
|
||||
};
|
||||
|
||||
static const char *to_string(Opers t_oper) {
|
||||
const char *opers[] = {
|
||||
static const char *opers[] = {
|
||||
"",
|
||||
"==", "<", ">", "<=", ">=", "!=",
|
||||
"",
|
||||
@@ -46,85 +52,57 @@ namespace chaiscript
|
||||
"+", "/", "*", "-", "+", "-",
|
||||
""
|
||||
};
|
||||
return opers[t_oper];
|
||||
return opers[static_cast<int>(t_oper)];
|
||||
}
|
||||
|
||||
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
||||
{
|
||||
if (t_str == "==")
|
||||
{
|
||||
return equals;
|
||||
} else if (t_str == "<") {
|
||||
return less_than;
|
||||
} else if (t_str == ">") {
|
||||
return greater_than;
|
||||
} else if (t_str == "<=") {
|
||||
return less_than_equal;
|
||||
} else if (t_str == ">=") {
|
||||
return greater_than_equal;
|
||||
} else if (t_str == "!=") {
|
||||
return not_equal;
|
||||
} else if (t_str == "=") {
|
||||
return assign;
|
||||
} else if (t_str == "++") {
|
||||
return pre_increment;
|
||||
} else if (t_str == "--") {
|
||||
return pre_decrement;
|
||||
} else if (t_str == "*=") {
|
||||
return assign_product;
|
||||
} else if (t_str == "+=") {
|
||||
return assign_sum;
|
||||
} else if (t_str == "-=") {
|
||||
return assign_difference;
|
||||
} else if (t_str == "&=") {
|
||||
return assign_bitwise_and;
|
||||
} else if (t_str == "|=") {
|
||||
return assign_bitwise_or;
|
||||
} else if (t_str == "<<=") {
|
||||
return assign_shift_left;
|
||||
} else if (t_str == ">>=") {
|
||||
return assign_shift_right;
|
||||
} else if (t_str == "%=") {
|
||||
return assign_remainder;
|
||||
} else if (t_str == "^=") {
|
||||
return assign_bitwise_xor;
|
||||
} else if (t_str == "<<") {
|
||||
return shift_left;
|
||||
} else if (t_str == ">>") {
|
||||
return shift_right;
|
||||
} else if (t_str == "%") {
|
||||
return remainder;
|
||||
} else if (t_str == "&") {
|
||||
return bitwise_and;
|
||||
} else if (t_str == "|") {
|
||||
return bitwise_or;
|
||||
} else if (t_str == "^") {
|
||||
return bitwise_xor;
|
||||
} else if (t_str == "~") {
|
||||
return bitwise_complement;
|
||||
} else if (t_str == "+") {
|
||||
if (t_is_unary) {
|
||||
return unary_plus;
|
||||
} else {
|
||||
return sum;
|
||||
}
|
||||
} else if (t_str == "-") {
|
||||
if (t_is_unary) {
|
||||
return unary_minus;
|
||||
} else {
|
||||
return difference;
|
||||
}
|
||||
} else if (t_str == "/") {
|
||||
return quotient;
|
||||
} else if (t_str == "*") {
|
||||
return product;
|
||||
} else {
|
||||
return invalid;
|
||||
}
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4307)
|
||||
#endif
|
||||
|
||||
const auto op_hash = utility::fnv1a_32(t_str.c_str());
|
||||
switch (op_hash) {
|
||||
case utility::fnv1a_32("=="): { return Opers::equals; }
|
||||
case utility::fnv1a_32("<"): { return Opers::less_than; }
|
||||
case utility::fnv1a_32(">"): { return Opers::greater_than; }
|
||||
case utility::fnv1a_32("<="): { return Opers::less_than_equal; }
|
||||
case utility::fnv1a_32(">="): { return Opers::greater_than_equal; }
|
||||
case utility::fnv1a_32("!="): { return Opers::not_equal; }
|
||||
case utility::fnv1a_32("="): { return Opers::assign; }
|
||||
case utility::fnv1a_32("++"): { return Opers::pre_increment; }
|
||||
case utility::fnv1a_32("--"): { return Opers::pre_decrement; }
|
||||
case utility::fnv1a_32("*="): { return Opers::assign_product; }
|
||||
case utility::fnv1a_32("+="): { return Opers::assign_sum; }
|
||||
case utility::fnv1a_32("-="): { return Opers::assign_difference; }
|
||||
case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; }
|
||||
case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; }
|
||||
case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; }
|
||||
case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; }
|
||||
case utility::fnv1a_32("%="): { return Opers::assign_remainder; }
|
||||
case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; }
|
||||
case utility::fnv1a_32("<<"): { return Opers::shift_left; }
|
||||
case utility::fnv1a_32(">>"): { return Opers::shift_right; }
|
||||
case utility::fnv1a_32("%"): { return Opers::remainder; }
|
||||
case utility::fnv1a_32("&"): { return Opers::bitwise_and; }
|
||||
case utility::fnv1a_32("|"): { return Opers::bitwise_or; }
|
||||
case utility::fnv1a_32("^"): { return Opers::bitwise_xor; }
|
||||
case utility::fnv1a_32("~"): { return Opers::bitwise_complement; }
|
||||
case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; }
|
||||
case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; }
|
||||
case utility::fnv1a_32("/"): { return Opers::quotient; }
|
||||
case utility::fnv1a_32("*"): { return Opers::product; }
|
||||
default: { return Opers::invalid; }
|
||||
}
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
||||
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
||||
|
||||
|
||||
@@ -1,45 +1,89 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_COMMON_HPP_
|
||||
#define CHAISCRIPT_COMMON_HPP_
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_COMMON_HPP_
|
||||
#define CHAISCRIPT_COMMON_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../dispatchkit/boxed_value.hpp"
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/type_info.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
struct AST_Node;
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
struct Name_Validator {
|
||||
static bool is_reserved_word(const std::string &name)
|
||||
{
|
||||
static const std::set<std::string> m_reserved_words
|
||||
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
|
||||
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
|
||||
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
|
||||
return m_reserved_words.count(name) > 0;
|
||||
}
|
||||
|
||||
static bool valid_object_name(const std::string &name)
|
||||
{
|
||||
return name.find("::") == std::string::npos && !is_reserved_word(name);
|
||||
}
|
||||
|
||||
static void validate_object_name(const std::string &name)
|
||||
{
|
||||
if (is_reserved_word(name)) {
|
||||
throw exception::reserved_word_error(name);
|
||||
}
|
||||
|
||||
if (name.find("::") != std::string::npos) {
|
||||
throw exception::illegal_name_error(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Signature of module entry point that all binary loadable modules must implement.
|
||||
typedef ModulePtr (*Create_Module_Func)();
|
||||
|
||||
|
||||
/// Types of AST nodes available to the parser and eval
|
||||
class AST_Node_Type {
|
||||
public:
|
||||
enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond
|
||||
};
|
||||
enum class AST_Node_Type { Id, Fun_Call, Unused_Return_Fun_Call, Arg_List, Equation, Var_Decl,
|
||||
Array_Call, Dot_Access,
|
||||
Lambda, Block, Scopeless_Block, Def, While, If, For, Ranged_For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||
Inline_Range, Try, Catch, Finally, Method, Attr_Decl,
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Noop, Class, Binary, Arg, Global_Decl, Constant, Compiled
|
||||
};
|
||||
|
||||
enum class Operator_Precidence { Ternary_Cond, Logical_Or,
|
||||
Logical_And, Bitwise_Or, Bitwise_Xor, Bitwise_And,
|
||||
Equality, Comparison, Shift, Addition, Multiplication, Prefix };
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Helper lookup to get the name of each node type
|
||||
*/
|
||||
const char *ast_node_type_to_string(int ast_node_type) {
|
||||
const char *ast_node_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition"};
|
||||
/// Helper lookup to get the name of each node type
|
||||
inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) {
|
||||
static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl",
|
||||
"Array_Call", "Dot_Access",
|
||||
"Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl",
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Noop", "Class", "Binary", "Arg", "Global_Decl", "Constant", "Compiled"};
|
||||
|
||||
return ast_node_types[ast_node_type];
|
||||
return ast_node_types[static_cast<int>(ast_node_type)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,30 +98,84 @@ namespace chaiscript
|
||||
File_Position() : line(0), column(0) { }
|
||||
};
|
||||
|
||||
struct Parse_Location {
|
||||
Parse_Location(std::string t_fname="", const int t_start_line=0, const int t_start_col=0,
|
||||
const int t_end_line=0, const int t_end_col=0)
|
||||
: start(t_start_line, t_start_col),
|
||||
end(t_end_line, t_end_col),
|
||||
filename(std::make_shared<std::string>(std::move(t_fname)))
|
||||
{
|
||||
}
|
||||
|
||||
Parse_Location(std::shared_ptr<std::string> t_fname, const int t_start_line=0, const int t_start_col=0,
|
||||
const int t_end_line=0, const int t_end_col=0)
|
||||
: start(t_start_line, t_start_col),
|
||||
end(t_end_line, t_end_col),
|
||||
filename(std::move(t_fname))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
File_Position start;
|
||||
File_Position end;
|
||||
std::shared_ptr<std::string> filename;
|
||||
};
|
||||
|
||||
|
||||
/// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree
|
||||
typedef std::shared_ptr<struct AST_Node> AST_NodePtr;
|
||||
typedef std::shared_ptr<AST_Node> AST_NodePtr;
|
||||
typedef std::shared_ptr<const AST_Node> AST_NodePtr_Const;
|
||||
|
||||
|
||||
/// \brief Classes which may be thrown during error cases when ChaiScript is executing.
|
||||
namespace exception
|
||||
{
|
||||
/**
|
||||
* Errors generated during parsing or evaluation
|
||||
*/
|
||||
struct eval_error : public std::runtime_error {
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
explicit load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
|
||||
: std::runtime_error(format_error(t_name, t_errors))
|
||||
{
|
||||
}
|
||||
|
||||
load_module_error(const load_module_error &) = default;
|
||||
~load_module_error() noexcept override = default;
|
||||
|
||||
static std::string format_error(const std::string &t_name, const std::vector<load_module_error> &t_errors)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Error loading module '" << t_name << "'\n"
|
||||
<< " The following locations were searched:\n";
|
||||
|
||||
for (const auto &err : t_errors) {
|
||||
ss << " " << err.what() << "\n";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Errors generated during parsing or evaluation
|
||||
struct eval_error : std::runtime_error {
|
||||
std::string reason;
|
||||
File_Position start_position;
|
||||
File_Position end_position;
|
||||
std::string filename;
|
||||
std::string detail;
|
||||
std::vector<AST_NodePtr> call_stack;
|
||||
std::vector<AST_NodePtr_Const> call_stack;
|
||||
|
||||
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname,
|
||||
const std::vector<Boxed_Value> &t_parameters, const std::vector<chaiscript::Const_Proxy_Function> &t_functions,
|
||||
bool t_dot_notation,
|
||||
const chaiscript::detail::Dispatch_Engine &t_ss) noexcept :
|
||||
std::runtime_error(format(t_why, t_where, t_fname, t_parameters, t_dot_notation, t_ss)),
|
||||
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||
reason(t_why), start_position(t_where), filename(t_fname), detail(format_detail(t_functions, t_dot_notation, t_ss))
|
||||
{}
|
||||
|
||||
eval_error(const std::string &t_why,
|
||||
@@ -91,42 +189,44 @@ namespace chaiscript
|
||||
|
||||
eval_error(const std::string &t_why, const File_Position &t_where, const std::string &t_fname) noexcept :
|
||||
std::runtime_error(format(t_why, t_where, t_fname)),
|
||||
reason(t_why), start_position(t_where), end_position(t_where), filename(t_fname)
|
||||
reason(t_why), start_position(t_where), filename(t_fname)
|
||||
{}
|
||||
|
||||
eval_error(const std::string &t_why) noexcept
|
||||
explicit eval_error(const std::string &t_why) noexcept
|
||||
: std::runtime_error("Error: \"" + t_why + "\" "),
|
||||
reason(t_why)
|
||||
{}
|
||||
|
||||
eval_error(const eval_error &) = default;
|
||||
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
|
||||
ss << what();
|
||||
if (call_stack.size() > 0) {
|
||||
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")" << std::endl;
|
||||
ss << std::endl << detail << std::endl;
|
||||
if (!call_stack.empty()) {
|
||||
ss << "during evaluation at (" << fname(call_stack[0]) << " " << startpos(call_stack[0]) << ")\n";
|
||||
ss << '\n' << detail << '\n';
|
||||
ss << " " << fname(call_stack[0]) << " (" << startpos(call_stack[0]) << ") '" << pretty(call_stack[0]) << "'";
|
||||
for (size_t j = 1; j < call_stack.size(); ++j) {
|
||||
if (id(call_stack[j]) != chaiscript::AST_Node_Type::Block
|
||||
&& id(call_stack[j]) != chaiscript::AST_Node_Type::File)
|
||||
{
|
||||
ss << std::endl;
|
||||
ss << '\n';
|
||||
ss << " from " << fname(call_stack[j]) << " (" << startpos(call_stack[j]) << ") '" << pretty(call_stack[j]) << "'";
|
||||
}
|
||||
}
|
||||
}
|
||||
ss << std::endl;
|
||||
ss << '\n';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
virtual ~eval_error() noexcept {}
|
||||
~eval_error() noexcept override = default;
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
static int id(const T& t)
|
||||
static AST_Node_Type id(const T& t)
|
||||
{
|
||||
return t->identifier;
|
||||
}
|
||||
@@ -138,16 +238,16 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string fname(const T& t)
|
||||
static const std::string &fname(const T& t)
|
||||
{
|
||||
return *t->filename;
|
||||
return t->filename();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string startpos(const T& t)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << t->start.line << ", " << t->start.column;
|
||||
oss << t->start().line << ", " << t->start().column;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@@ -214,8 +314,7 @@ namespace chaiscript
|
||||
|
||||
if (f)
|
||||
{
|
||||
std::shared_ptr<const dispatch::Dynamic_Proxy_Function> dynfunguard
|
||||
= std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
||||
auto dynfunguard = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(f);
|
||||
if (dynfunguard)
|
||||
{
|
||||
retval += " : " + format_guard(dynfunguard->get_parse_tree());
|
||||
@@ -237,10 +336,13 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
static std::string format_location(const T &t)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "(" << *t->filename << " " << t->start.line << ", " << t->start.column << ")";
|
||||
|
||||
return oss.str();
|
||||
if (t) {
|
||||
std::ostringstream oss;
|
||||
oss << "(" << t->filename() << " " << t->start().line << ", " << t->start().column << ")";
|
||||
return oss.str();
|
||||
} else {
|
||||
return "(internal)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -251,15 +353,13 @@ namespace chaiscript
|
||||
std::stringstream ss;
|
||||
if (t_functions.size() == 1)
|
||||
{
|
||||
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << std::endl;
|
||||
ss << " Expected: " << format_types(t_functions[0], t_dot_notation, t_ss) << '\n';
|
||||
} else {
|
||||
ss << " " << t_functions.size() << " overloads available:" << std::endl;
|
||||
ss << " " << t_functions.size() << " overloads available:\n";
|
||||
|
||||
for (std::vector<chaiscript::Const_Proxy_Function>::const_iterator itr = t_functions.begin();
|
||||
itr != t_functions.end();
|
||||
++itr)
|
||||
for (const auto & t_function : t_functions)
|
||||
{
|
||||
ss << " " << format_types((*itr), t_dot_notation, t_ss) << std::endl;
|
||||
ss << " " << format_types((t_function), t_dot_notation, t_ss) << '\n';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -279,7 +379,7 @@ namespace chaiscript
|
||||
{
|
||||
std::string paramstr;
|
||||
|
||||
for (std::vector<Boxed_Value>::const_iterator itr = t_parameters.begin();
|
||||
for (auto itr = t_parameters.begin();
|
||||
itr != t_parameters.end();
|
||||
++itr)
|
||||
{
|
||||
@@ -377,15 +477,15 @@ namespace chaiscript
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Errors generated when loading a file
|
||||
*/
|
||||
struct file_not_found_error : public std::runtime_error {
|
||||
file_not_found_error(const std::string &t_filename) noexcept
|
||||
|
||||
/// Errors generated when loading a file
|
||||
struct file_not_found_error : std::runtime_error {
|
||||
explicit file_not_found_error(const std::string &t_filename) noexcept
|
||||
: std::runtime_error("File Not Found: " + t_filename)
|
||||
{ }
|
||||
|
||||
virtual ~file_not_found_error() noexcept {}
|
||||
file_not_found_error(const file_not_found_error &) = default;
|
||||
~file_not_found_error() noexcept override = default;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -394,182 +494,213 @@ namespace chaiscript
|
||||
/// \brief Struct that doubles as both a parser ast_node and an AST node.
|
||||
struct AST_Node : std::enable_shared_from_this<AST_Node> {
|
||||
public:
|
||||
const AST_Node_Type identifier;
|
||||
const std::string text;
|
||||
const int identifier; //< \todo shouldn't this be a strongly typed enum value?
|
||||
std::shared_ptr<const std::string> filename;
|
||||
File_Position start, end;
|
||||
std::vector<AST_NodePtr> children;
|
||||
AST_NodePtr annotation;
|
||||
Parse_Location location;
|
||||
|
||||
virtual std::string pretty_print() const
|
||||
const std::string &filename() const {
|
||||
return *location.filename;
|
||||
}
|
||||
|
||||
const File_Position &start() const {
|
||||
return location.start;
|
||||
}
|
||||
|
||||
const File_Position &end() const {
|
||||
return location.end;
|
||||
}
|
||||
|
||||
std::string pretty_print() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << text;
|
||||
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->pretty_print();
|
||||
for (auto & elem : this->get_children()) {
|
||||
oss << elem->pretty_print() << ' ';
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the contents of an AST node, including its children, recursively
|
||||
*/
|
||||
std::string to_string(std::string t_prepend = "") {
|
||||
virtual std::vector<AST_NodePtr> get_children() const = 0;
|
||||
virtual Boxed_Value eval(const chaiscript::detail::Dispatch_State &t_e) const = 0;
|
||||
|
||||
|
||||
/// Prints the contents of an AST node, including its children, recursively
|
||||
std::string to_string(const std::string &t_prepend = "") const {
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << t_prepend << "(" << ast_node_type_to_string(this->identifier) << ") "
|
||||
<< this->text << " : " << this->start.line << ", " << this->start.column << std::endl;
|
||||
|
||||
for (unsigned int j = 0; j < this->children.size(); ++j) {
|
||||
oss << this->children[j]->to_string(t_prepend + " ");
|
||||
<< this->text << " : " << this->location.start.line << ", " << this->location.start.column << '\n';
|
||||
|
||||
for (auto & elem : this->get_children()) {
|
||||
oss << elem->to_string(t_prepend + " ");
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string internal_to_string() {
|
||||
return to_string();
|
||||
}
|
||||
|
||||
Boxed_Value eval(chaiscript::detail::Dispatch_Engine &t_e)
|
||||
{
|
||||
static bool get_bool_condition(const Boxed_Value &t_bv, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||
try {
|
||||
return eval_internal(t_e);
|
||||
} catch (exception::eval_error &ee) {
|
||||
ee.call_stack.push_back(shared_from_this());
|
||||
throw ee;
|
||||
return t_ss->boxed_cast<bool>(t_bv);
|
||||
}
|
||||
catch (const exception::bad_boxed_cast &) {
|
||||
throw exception::eval_error("Condition not boolean");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void replace_child(const AST_NodePtr &t_child, const AST_NodePtr &t_new_child)
|
||||
{
|
||||
std::replace(children.begin(), children.end(), t_child, t_new_child);
|
||||
}
|
||||
virtual ~AST_Node() = default;
|
||||
AST_Node(AST_Node &&) = default;
|
||||
AST_Node &operator=(AST_Node &&) = default;
|
||||
AST_Node(const AST_Node &) = delete;
|
||||
AST_Node& operator=(const AST_Node &) = delete;
|
||||
|
||||
|
||||
protected:
|
||||
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
|
||||
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
|
||||
text(t_ast_node_text), identifier(t_id), filename(t_fname),
|
||||
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
|
||||
AST_Node(std::string t_ast_node_text, AST_Node_Type t_id, Parse_Location t_loc)
|
||||
: identifier(t_id), text(std::move(t_ast_node_text)),
|
||||
location(std::move(t_loc))
|
||||
{
|
||||
}
|
||||
|
||||
AST_Node(const std::string &t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
|
||||
text(t_ast_node_text), identifier(t_id), filename(t_fname) {}
|
||||
|
||||
virtual ~AST_Node() {}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &)
|
||||
{
|
||||
throw std::runtime_error("Undispatched ast_node (internal error)");
|
||||
}
|
||||
|
||||
private:
|
||||
// Copy and assignment explicitly unimplemented
|
||||
AST_Node(const AST_Node &);
|
||||
AST_Node& operator=(const AST_Node &);
|
||||
};
|
||||
|
||||
namespace parser {
|
||||
class ChaiScript_Parser_Base
|
||||
{
|
||||
public:
|
||||
virtual AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) = 0;
|
||||
virtual void debug_print(AST_NodePtr t, std::string prepend = "") const = 0;
|
||||
virtual void *get_tracer_ptr() = 0;
|
||||
virtual ~ChaiScript_Parser_Base() = default;
|
||||
ChaiScript_Parser_Base() = default;
|
||||
ChaiScript_Parser_Base(ChaiScript_Parser_Base &&) = default;
|
||||
ChaiScript_Parser_Base &operator=(ChaiScript_Parser_Base &&) = delete;
|
||||
ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete;
|
||||
|
||||
template<typename T>
|
||||
T &get_tracer()
|
||||
{
|
||||
// to do type check this somehow?
|
||||
return *static_cast<T*>(get_tracer_ptr());
|
||||
}
|
||||
|
||||
protected:
|
||||
ChaiScript_Parser_Base(const ChaiScript_Parser_Base &) = default;
|
||||
};
|
||||
}
|
||||
|
||||
namespace eval
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/**
|
||||
* Special type for returned values
|
||||
*/
|
||||
/// Special type for returned values
|
||||
struct Return_Value {
|
||||
Boxed_Value retval;
|
||||
|
||||
Return_Value(const Boxed_Value &t_return_value) : retval(t_return_value) { }
|
||||
explicit Return_Value(Boxed_Value t_return_value) : retval(std::move(t_return_value)) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Special type indicating a call to 'break'
|
||||
*/
|
||||
|
||||
/// Special type indicating a call to 'break'
|
||||
struct Break_Loop {
|
||||
Break_Loop() { }
|
||||
Break_Loop() = default;
|
||||
};
|
||||
|
||||
|
||||
/// Special type indicating a call to 'continue'
|
||||
struct Continue_Loop {
|
||||
Continue_Loop() = default;
|
||||
};
|
||||
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Scope_Push_Pop
|
||||
{
|
||||
Scope_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
Scope_Push_Pop(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop& operator=(Scope_Push_Pop &&) = default;
|
||||
Scope_Push_Pop(const Scope_Push_Pop &) = delete;
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &) = delete;
|
||||
|
||||
explicit Scope_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_scope();
|
||||
m_ds->new_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Scope_Push_Pop()
|
||||
{
|
||||
m_de.pop_scope();
|
||||
m_ds->pop_scope(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// explicitly unimplemented copy and assignment
|
||||
Scope_Push_Pop(const Scope_Push_Pop &);
|
||||
Scope_Push_Pop& operator=(const Scope_Push_Pop &);
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new functon call and pops it on destruction
|
||||
/// Creates a new function call and pops it on destruction
|
||||
struct Function_Push_Pop
|
||||
{
|
||||
Function_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
Function_Push_Pop(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop& operator=(Function_Push_Pop &&) = default;
|
||||
Function_Push_Pop(const Function_Push_Pop &) = delete;
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &) = delete;
|
||||
|
||||
explicit Function_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_function_call();
|
||||
m_ds->new_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
~Function_Push_Pop()
|
||||
{
|
||||
m_de.pop_function_call();
|
||||
m_ds->pop_function_call(m_ds.stack_holder(), m_ds.conversion_saves());
|
||||
}
|
||||
|
||||
void save_params(const std::vector<Boxed_Value> &t_params)
|
||||
{
|
||||
m_de.save_function_params(t_params);
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
void save_params(std::initializer_list<Boxed_Value> t_params)
|
||||
{
|
||||
m_ds->save_function_params(t_params);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// explicitly unimplemented copy and assignment
|
||||
Function_Push_Pop(const Function_Push_Pop &);
|
||||
Function_Push_Pop& operator=(const Function_Push_Pop &);
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
|
||||
/// Creates a new scope then pops it on destruction
|
||||
struct Stack_Push_Pop
|
||||
{
|
||||
Stack_Push_Pop(chaiscript::detail::Dispatch_Engine &t_de)
|
||||
: m_de(t_de)
|
||||
Stack_Push_Pop(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop& operator=(Stack_Push_Pop &&) = default;
|
||||
Stack_Push_Pop(const Stack_Push_Pop &) = delete;
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &) = delete;
|
||||
|
||||
explicit Stack_Push_Pop(const chaiscript::detail::Dispatch_State &t_ds)
|
||||
: m_ds(t_ds)
|
||||
{
|
||||
m_de.new_stack();
|
||||
m_ds->new_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
~Stack_Push_Pop()
|
||||
{
|
||||
m_de.pop_stack();
|
||||
m_ds->pop_stack(m_ds.stack_holder());
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// explicitly unimplemented copy and assignment
|
||||
Stack_Push_Pop(const Stack_Push_Pop &);
|
||||
Stack_Push_Pop& operator=(const Stack_Push_Pop &);
|
||||
|
||||
chaiscript::detail::Dispatch_Engine &m_de;
|
||||
const chaiscript::detail::Dispatch_State &m_ds;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _CHAISCRIPT_COMMON_HPP */
|
||||
#endif /* _CHAISCRIPT_COMMON_HPP */
|
||||
|
||||
|
||||
@@ -1,247 +1,69 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_ENGINE_HPP_
|
||||
#define CHAISCRIPT_ENGINE_HPP_
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "../chaiscript_threading.hpp"
|
||||
#include "../dispatchkit/boxed_cast_helper.hpp"
|
||||
#include "../dispatchkit/boxed_value.hpp"
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
#include "../dispatchkit/type_conversions.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "chaiscript_common.hpp"
|
||||
|
||||
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__)
|
||||
#if defined(__linux__) || defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#if defined(CHAISCRIPT_NO_DYNLOAD)
|
||||
#include "chaiscript_unknown.hpp"
|
||||
#elif defined(CHAISCRIPT_WINDOWS)
|
||||
#include "chaiscript_windows.hpp"
|
||||
#elif _POSIX_VERSION
|
||||
#include "chaiscript_posix.hpp"
|
||||
#else
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include "chaiscript_unknown.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#include "chaiscript_prelude.chai"
|
||||
#include "chaiscript_parser.hpp"
|
||||
#include "../dispatchkit/exception_specification.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
/// \brief Thrown if an error occurs while attempting to load a binary module
|
||||
struct load_module_error : std::runtime_error
|
||||
{
|
||||
load_module_error(const std::string &t_reason) noexcept
|
||||
: std::runtime_error(t_reason)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~load_module_error() noexcept
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#ifdef _POSIX_VERSION
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
|
||||
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
dlclose(m_data);
|
||||
}
|
||||
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p)
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#else
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring towstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string tostring(const T &t_str)
|
||||
{
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#ifdef _UNICODE
|
||||
template<typename T>
|
||||
static std::wstring toproperstring(const T &t_str)
|
||||
{
|
||||
return towstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
static std::string toproperstring(const T &t_str)
|
||||
{
|
||||
return tostring(t_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string GetErrorMessage(DWORD t_err)
|
||||
{
|
||||
#ifdef _UNICODE
|
||||
typedef LPWSTR StringType;
|
||||
std::wstring retval = L"Unknown Error";
|
||||
#else
|
||||
typedef LPSTR StringType;
|
||||
std::string retval = "Unknown Error";
|
||||
#endif
|
||||
StringType lpMsgBuf = 0;
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
t_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(StringType)&lpMsgBuf,
|
||||
0, NULL );
|
||||
|
||||
if (lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
}
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
return tostring(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(toproperstring(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(GetErrorMessage(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(GetErrorMessage(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
|
||||
#else
|
||||
struct Loadable_Module
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||
}
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef std::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
|
||||
}
|
||||
|
||||
|
||||
/// \brief The main object that the ChaiScript user will use.
|
||||
class ChaiScript {
|
||||
class ChaiScript_Basic {
|
||||
|
||||
mutable chaiscript::detail::threading::shared_mutex m_mutex;
|
||||
mutable chaiscript::detail::threading::recursive_mutex m_use_mutex;
|
||||
@@ -250,46 +72,49 @@ namespace chaiscript
|
||||
std::map<std::string, detail::Loadable_Module_Ptr> m_loaded_modules;
|
||||
std::set<std::string> m_active_loaded_modules;
|
||||
|
||||
std::vector<std::string> m_modulepaths;
|
||||
std::vector<std::string> m_usepaths;
|
||||
std::vector<std::string> m_module_paths;
|
||||
std::vector<std::string> m_use_paths;
|
||||
|
||||
std::unique_ptr<parser::ChaiScript_Parser_Base> m_parser;
|
||||
|
||||
chaiscript::detail::Dispatch_Engine m_engine;
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the given string in by parsing it and running the results through the evaluator
|
||||
*/
|
||||
/// Evaluates the given string in by parsing it and running the results through the evaluator
|
||||
Boxed_Value do_eval(const std::string &t_input, const std::string &t_filename = "__EVAL__", bool /* t_internal*/ = false)
|
||||
{
|
||||
try {
|
||||
parser::ChaiScript_Parser parser;
|
||||
if (parser.parse(t_input, t_filename)) {
|
||||
//parser.show_match_stack();
|
||||
return parser.ast()->eval(m_engine);
|
||||
} else {
|
||||
return Boxed_Value();
|
||||
}
|
||||
const auto p = m_parser->parse(t_input, t_filename);
|
||||
return p->eval(chaiscript::detail::Dispatch_State(m_engine));
|
||||
}
|
||||
catch (const chaiscript::eval::detail::Return_Value &rv) {
|
||||
catch (chaiscript::eval::detail::Return_Value &rv) {
|
||||
return rv.retval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const Boxed_Value internal_eval_ast(const AST_NodePtr &t_ast)
|
||||
{
|
||||
try {
|
||||
return t_ast->eval(m_engine);
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
throw Boxed_Value(t_ee);
|
||||
/// Evaluates the given file and looks in the 'use' paths
|
||||
const Boxed_Value internal_eval_file(const std::string &t_filename) {
|
||||
for (const auto &path : m_use_paths)
|
||||
{
|
||||
try {
|
||||
const auto appendedpath = path + t_filename;
|
||||
return do_eval(load_file(appendedpath), appendedpath, true);
|
||||
} catch (const exception::file_not_found_error &) {
|
||||
// failed to load, try the next path
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
throw Boxed_Value(t_ee);
|
||||
}
|
||||
}
|
||||
|
||||
// failed to load by any name
|
||||
throw exception::file_not_found_error(t_filename);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates the given string, used during eval() inside of a script
|
||||
*/
|
||||
|
||||
/// Evaluates the given string, used during eval() inside of a script
|
||||
const Boxed_Value internal_eval(const std::string &t_e) {
|
||||
try {
|
||||
return do_eval(t_e, "__EVAL__", true);
|
||||
@@ -298,73 +123,90 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current evaluation m_engine
|
||||
*/
|
||||
/// Returns the current evaluation m_engine
|
||||
chaiscript::detail::Dispatch_Engine &get_eval_engine() {
|
||||
return m_engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
*/
|
||||
void build_eval_system(const ModulePtr &t_lib) {
|
||||
m_engine.add_reserved_word("def");
|
||||
m_engine.add_reserved_word("fun");
|
||||
m_engine.add_reserved_word("while");
|
||||
m_engine.add_reserved_word("for");
|
||||
m_engine.add_reserved_word("if");
|
||||
m_engine.add_reserved_word("else");
|
||||
m_engine.add_reserved_word("&&");
|
||||
m_engine.add_reserved_word("||");
|
||||
m_engine.add_reserved_word(",");
|
||||
m_engine.add_reserved_word("auto");
|
||||
m_engine.add_reserved_word("return");
|
||||
m_engine.add_reserved_word("break");
|
||||
m_engine.add_reserved_word("true");
|
||||
m_engine.add_reserved_word("false");
|
||||
m_engine.add_reserved_word("_");
|
||||
|
||||
/// Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
void build_eval_system(const ModulePtr &t_lib, const std::vector<Options> &t_opts) {
|
||||
if (t_lib)
|
||||
{
|
||||
add(t_lib);
|
||||
}
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_system, std::ref(m_engine)), "dump_system");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::dump_object, std::ref(m_engine)), "dump_object");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::is_type, std::ref(m_engine)), "is_type");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::type_name, std::ref(m_engine)), "type_name");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::function_exists, std::ref(m_engine)), "function_exists");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_function_objects, std::ref(m_engine)), "get_functions");
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_scripting_objects, std::ref(m_engine)), "get_objects");
|
||||
m_engine.add(fun([this](){ m_engine.dump_system(); }), "dump_system");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ m_engine.dump_object(t_bv); }), "dump_object");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_type){ return m_engine.is_type(t_bv, t_type); }), "is_type");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv){ return m_engine.type_name(t_bv); }), "type_name");
|
||||
m_engine.add(fun([this](const std::string &t_f){ return m_engine.function_exists(t_f); }), "function_exists");
|
||||
m_engine.add(fun([this](){ return m_engine.get_function_objects(); }), "get_functions");
|
||||
m_engine.add(fun([this](){ return m_engine.get_scripting_objects(); }), "get_objects");
|
||||
|
||||
m_engine.add(fun(&chaiscript::detail::Dispatch_Engine::get_type_name, std::ref(m_engine)), "name");
|
||||
m_engine.add(
|
||||
dispatch::make_dynamic_proxy_function(
|
||||
[this](const std::vector<Boxed_Value> &t_params) {
|
||||
return m_engine.call_exists(t_params);
|
||||
})
|
||||
, "call_exists");
|
||||
|
||||
|
||||
typedef void (ChaiScript::*load_mod_1)(const std::string&);
|
||||
typedef void (ChaiScript::*load_mod_2)(const std::string&, const std::string&);
|
||||
m_engine.add(fun(
|
||||
[=](const dispatch::Proxy_Function_Base &t_fun, const std::vector<Boxed_Value> &t_params) -> Boxed_Value {
|
||||
Type_Conversions_State s(this->m_engine.conversions(), this->m_engine.conversions().conversion_saves());
|
||||
return t_fun(t_params, s);
|
||||
}), "call");
|
||||
|
||||
m_engine.add(fun(static_cast<load_mod_1>(&ChaiScript::load_module), this), "load_module");
|
||||
m_engine.add(fun(static_cast<load_mod_2>(&ChaiScript::load_module), this), "load_module");
|
||||
|
||||
m_engine.add(fun(&ChaiScript::use, this), "use");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval, this), "eval");
|
||||
m_engine.add(fun(&ChaiScript::internal_eval_ast, this), "eval");
|
||||
m_engine.add(fun([this](const Type_Info &t_ti){ return m_engine.get_type_name(t_ti); }), "name");
|
||||
|
||||
do_eval(ChaiScript_Prelude::chaiscript_prelude, "standard prelude");
|
||||
m_engine.add(fun([this](const std::string &t_type_name, bool t_throw){ return m_engine.get_type(t_type_name, t_throw); }), "type");
|
||||
m_engine.add(fun([this](const std::string &t_type_name){ return m_engine.get_type(t_type_name, true); }), "type");
|
||||
|
||||
m_engine.add(fun(
|
||||
[=](const Type_Info &t_from, const Type_Info &t_to, const std::function<Boxed_Value (const Boxed_Value &)> &t_func) {
|
||||
m_engine.add(chaiscript::type_conversion(t_from, t_to, t_func));
|
||||
}
|
||||
), "add_type_conversion");
|
||||
|
||||
|
||||
|
||||
if (std::find(t_opts.begin(), t_opts.end(), Options::No_Load_Modules) == t_opts.end()
|
||||
&& std::find(t_opts.begin(), t_opts.end(), Options::Load_Modules) != t_opts.end())
|
||||
{
|
||||
m_engine.add(fun([this](const std::string &t_module, const std::string &t_file){ return load_module(t_module, t_file); }), "load_module");
|
||||
m_engine.add(fun([this](const std::string &t_module){ return load_module(t_module); }), "load_module");
|
||||
}
|
||||
|
||||
if (std::find(t_opts.begin(), t_opts.end(), Options::No_External_Scripts) == t_opts.end()
|
||||
&& std::find(t_opts.begin(), t_opts.end(), Options::External_Scripts) != t_opts.end())
|
||||
{
|
||||
m_engine.add(fun([this](const std::string &t_file){ return use(t_file); }), "use");
|
||||
m_engine.add(fun([this](const std::string &t_file){ return internal_eval_file(t_file); }), "eval_file");
|
||||
}
|
||||
|
||||
m_engine.add(fun([this](const std::string &t_str){ return internal_eval(t_str); }), "eval");
|
||||
m_engine.add(fun([this](const AST_NodePtr &t_ast){ return eval(t_ast); }), "eval");
|
||||
|
||||
m_engine.add(fun([this](const std::string &t_str, const bool t_dump){ return parse(t_str, t_dump); }), "parse");
|
||||
m_engine.add(fun([this](const std::string &t_str){ return parse(t_str); }), "parse");
|
||||
|
||||
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global_const(t_bv, t_name); }), "add_global_const");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ add_global(t_bv, t_name); }), "add_global");
|
||||
m_engine.add(fun([this](const Boxed_Value &t_bv, const std::string &t_name){ set_global(t_bv, t_name); }), "set_global");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for loading a file
|
||||
*/
|
||||
std::string load_file(const std::string &t_filename) {
|
||||
|
||||
/// Helper function for loading a file
|
||||
static std::string load_file(const std::string &t_filename) {
|
||||
std::ifstream infile(t_filename.c_str(), std::ios::in | std::ios::ate | std::ios::binary );
|
||||
|
||||
if (!infile.is_open()) {
|
||||
throw chaiscript::exception::file_not_found_error(t_filename);
|
||||
}
|
||||
|
||||
std::streampos size = infile.tellg();
|
||||
const auto size = infile.tellg();
|
||||
infile.seekg(0, std::ios::beg);
|
||||
|
||||
assert(size >= 0);
|
||||
@@ -373,74 +215,51 @@ namespace chaiscript
|
||||
{
|
||||
return std::string();
|
||||
} else {
|
||||
std::vector<char> v(static_cast<unsigned int>(size));
|
||||
std::vector<char> v(static_cast<size_t>(size));
|
||||
infile.read(&v[0], size);
|
||||
return std::string(v.begin(), v.end());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> ensure_minimum_path_vec(std::vector<std::string> paths)
|
||||
{
|
||||
if (paths.empty()) { return {""}; }
|
||||
else { return paths; }
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor for ChaiScript
|
||||
/// \param[in] t_lib Standard library to apply to this ChaiScript instance
|
||||
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
|
||||
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
|
||||
ChaiScript(const ModulePtr &t_lib,
|
||||
const std::vector<std::string> &t_modulepaths = std::vector<std::string>(),
|
||||
const std::vector<std::string> &t_usepaths = std::vector<std::string>())
|
||||
: m_modulepaths(t_modulepaths), m_usepaths(t_usepaths)
|
||||
ChaiScript_Basic(const ModulePtr &t_lib,
|
||||
std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
: m_module_paths(ensure_minimum_path_vec(std::move(t_module_paths))),
|
||||
m_use_paths(ensure_minimum_path_vec(std::move(t_use_paths))),
|
||||
m_parser(std::move(parser)),
|
||||
m_engine(*m_parser)
|
||||
{
|
||||
if (m_modulepaths.empty())
|
||||
{
|
||||
m_modulepaths.push_back("");
|
||||
}
|
||||
|
||||
if (m_usepaths.empty())
|
||||
{
|
||||
m_usepaths.push_back("");
|
||||
}
|
||||
|
||||
build_eval_system(t_lib);
|
||||
}
|
||||
|
||||
/// \brief Constructor for ChaiScript.
|
||||
///
|
||||
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
|
||||
/// at runtime generates an error if it cannot be found.
|
||||
///
|
||||
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
|
||||
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
|
||||
ChaiScript( const std::vector<std::string> &t_modulepaths = std::vector<std::string>(),
|
||||
const std::vector<std::string> &t_usepaths = std::vector<std::string>())
|
||||
: m_modulepaths(t_modulepaths), m_usepaths(t_usepaths)
|
||||
{
|
||||
if (m_modulepaths.empty())
|
||||
{
|
||||
m_modulepaths.push_back("");
|
||||
}
|
||||
|
||||
if (m_usepaths.empty())
|
||||
{
|
||||
m_usepaths.push_back("");
|
||||
}
|
||||
|
||||
|
||||
#ifdef _POSIX_VERSION
|
||||
#if !defined(CHAISCRIPT_NO_DYNLOAD) && defined(_POSIX_VERSION) && !defined(__CYGWIN__)
|
||||
// If on Unix, add the path of the current executable to the module search path
|
||||
// as windows would do
|
||||
|
||||
union cast_union
|
||||
{
|
||||
void (ChaiScript::*in_ptr)(const std::string&);
|
||||
Boxed_Value (ChaiScript_Basic::*in_ptr)(const std::string&);
|
||||
void *out_ptr;
|
||||
};
|
||||
|
||||
Dl_info rInfo;
|
||||
memset( &rInfo, 0, sizeof(rInfo) );
|
||||
cast_union u;
|
||||
u.in_ptr = &ChaiScript::use;
|
||||
if ( dladdr((void*)(u.out_ptr), &rInfo) && rInfo.dli_fname ) {
|
||||
u.in_ptr = &ChaiScript_Basic::use;
|
||||
if ( (dladdr(static_cast<void*>(u.out_ptr), &rInfo) != 0) && (rInfo.dli_fname != nullptr) ) {
|
||||
std::string dllpath(rInfo.dli_fname);
|
||||
size_t lastslash = dllpath.rfind('/');
|
||||
const size_t lastslash = dllpath.rfind('/');
|
||||
if (lastslash != std::string::npos)
|
||||
{
|
||||
dllpath.erase(lastslash);
|
||||
@@ -448,23 +267,89 @@ namespace chaiscript
|
||||
|
||||
// Let's see if this is a link that we should expand
|
||||
std::vector<char> buf(2048);
|
||||
size_t pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
|
||||
if (pathlen > 0 && pathlen < buf.size())
|
||||
const auto pathlen = readlink(dllpath.c_str(), &buf.front(), buf.size());
|
||||
if (pathlen > 0 && static_cast<size_t>(pathlen) < buf.size())
|
||||
{
|
||||
dllpath = std::string(&buf.front(), pathlen);
|
||||
dllpath = std::string(&buf.front(), static_cast<size_t>(pathlen));
|
||||
}
|
||||
|
||||
m_modulepaths.push_back(dllpath+"/");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// attempt to load the stdlib
|
||||
load_module("chaiscript_stdlib");
|
||||
|
||||
build_eval_system(ModulePtr());
|
||||
m_module_paths.insert(m_module_paths.begin(), dllpath+"/");
|
||||
}
|
||||
#endif
|
||||
build_eval_system(t_lib, t_opts);
|
||||
}
|
||||
|
||||
#ifndef CHAISCRIPT_NO_DYNLOAD
|
||||
/// \brief Constructor for ChaiScript.
|
||||
///
|
||||
/// This version of the ChaiScript constructor attempts to find the stdlib module to load
|
||||
/// at runtime generates an error if it cannot be found.
|
||||
///
|
||||
/// \param[in] t_modulepaths Vector of paths to search when attempting to load a binary module
|
||||
/// \param[in] t_usepaths Vector of paths to search when attempting to "use" an included ChaiScript file
|
||||
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options())
|
||||
: ChaiScript_Basic({}, std::move(parser), t_module_paths, t_use_paths, t_opts)
|
||||
{
|
||||
try {
|
||||
// attempt to load the stdlib
|
||||
load_module("chaiscript_stdlib-" + Build_Info::version());
|
||||
} catch (const exception::load_module_error &t_err) {
|
||||
std::cout << "An error occured while trying to load the chaiscript standard library.\n"
|
||||
<< "\n"
|
||||
<< "You must either provide a standard library, or compile it in.\n"
|
||||
<< "For an example of compiling the standard library in,\n"
|
||||
<< "see: https://gist.github.com/lefticus/9456197\n"
|
||||
<< "Compiling the stdlib in is the recommended and MOST SUPPORTED method.\n"
|
||||
<< "\n"
|
||||
<< "\n"
|
||||
<< t_err.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#else // CHAISCRIPT_NO_DYNLOAD
|
||||
explicit ChaiScript_Basic(std::unique_ptr<parser::ChaiScript_Parser_Base> &&parser,
|
||||
std::vector<std::string> t_module_paths = {},
|
||||
std::vector<std::string> t_use_paths = {},
|
||||
const std::vector<chaiscript::Options> &t_opts = chaiscript::default_options()) = delete;
|
||||
#endif
|
||||
|
||||
parser::ChaiScript_Parser_Base &get_parser()
|
||||
{
|
||||
return *m_parser;
|
||||
}
|
||||
|
||||
const Boxed_Value eval(const AST_NodePtr &t_ast)
|
||||
{
|
||||
try {
|
||||
return t_ast->eval(chaiscript::detail::Dispatch_State(m_engine));
|
||||
} catch (const exception::eval_error &t_ee) {
|
||||
throw Boxed_Value(t_ee);
|
||||
}
|
||||
}
|
||||
|
||||
AST_NodePtr parse(const std::string &t_input, const bool t_debug_print = false)
|
||||
{
|
||||
const auto ast = m_parser->parse(t_input, "PARSE");
|
||||
if (t_debug_print) {
|
||||
m_parser->debug_print(ast);
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
|
||||
std::string get_type_name(const Type_Info &ti) const
|
||||
{
|
||||
return m_engine.get_type_name(ti);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string get_type_name() const
|
||||
{
|
||||
return get_type_name(user_type<T>());
|
||||
}
|
||||
|
||||
|
||||
/// \brief Loads and parses a file. If the file is already, it is not reloaded
|
||||
@@ -472,33 +357,34 @@ namespace chaiscript
|
||||
/// requested file.
|
||||
///
|
||||
/// \param[in] t_filename Filename to load and evaluate
|
||||
void use(const std::string &t_filename)
|
||||
Boxed_Value use(const std::string &t_filename)
|
||||
{
|
||||
for (size_t i = 0; i < m_usepaths.size(); ++i)
|
||||
for (const auto &path : m_use_paths)
|
||||
{
|
||||
try {
|
||||
const std::string appendedpath = m_usepaths[i] + t_filename;
|
||||
const auto appendedpath = path + t_filename;
|
||||
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
|
||||
Boxed_Value retval;
|
||||
|
||||
if (m_used_files.count(appendedpath) == 0)
|
||||
{
|
||||
m_used_files.insert(appendedpath);
|
||||
l2.unlock();
|
||||
eval_file(appendedpath);
|
||||
retval = eval_file(appendedpath);
|
||||
l2.lock();
|
||||
m_used_files.insert(appendedpath);
|
||||
}
|
||||
|
||||
return; // return, we loaded it, or it was already loaded
|
||||
return retval; // return, we loaded it, or it was already loaded
|
||||
} catch (const exception::file_not_found_error &) {
|
||||
if (i == m_usepaths.size() - 1)
|
||||
{
|
||||
throw exception::file_not_found_error(t_filename);
|
||||
}
|
||||
|
||||
// failed to load, try the next path
|
||||
}
|
||||
}
|
||||
|
||||
// failed to load by any name
|
||||
throw exception::file_not_found_error(t_filename);
|
||||
}
|
||||
|
||||
/// \brief Adds a constant object that is available in all contexts and to all threads
|
||||
@@ -506,13 +392,35 @@ namespace chaiscript
|
||||
/// \param[in] t_name Name of the value to add
|
||||
/// \throw chaiscript::exception::global_non_const If t_bv is not a constant object
|
||||
/// \sa Boxed_Value::is_const
|
||||
ChaiScript &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
ChaiScript_Basic &add_global_const(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.add_global_const(t_bv, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Adds a mutable object that is available in all contexts and to all threads
|
||||
/// \param[in] t_bv Boxed_Value to add as a global
|
||||
/// \param[in] t_name Name of the value to add
|
||||
/// \warning The user is responsible for making sure the object is thread-safe if necessary
|
||||
/// ChaiScript is thread-safe but provides no threading locking mechanism to the script
|
||||
ChaiScript_Basic &add_global(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.add_global(t_bv, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChaiScript_Basic &set_global(const Boxed_Value &t_bv, const std::string &t_name)
|
||||
{
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.set_global(t_bv, t_name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Represents the current state of the ChaiScript system. State and be saved and restored
|
||||
/// \warning State object does not contain the user defined type conversions of the engine. They
|
||||
/// are left out due to performance considerations involved in tracking the state
|
||||
/// \sa ChaiScript::get_state
|
||||
/// \sa ChaiScript::set_state
|
||||
struct State
|
||||
@@ -535,7 +443,7 @@ namespace chaiscript
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chaiscript::ChaiScript::State s = chai.get_state(); // represents bootstrapped initial state
|
||||
/// \endcode
|
||||
State get_state()
|
||||
State get_state() const
|
||||
{
|
||||
chaiscript::detail::threading::lock_guard<chaiscript::detail::threading::recursive_mutex> l(m_use_mutex);
|
||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l2(m_mutex);
|
||||
@@ -601,10 +509,11 @@ namespace chaiscript
|
||||
/// chai.add(chaiscript::var(&obj), "obj"); // Add a pointer to a locally defined object
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa \ref addingitems
|
||||
/// \sa \ref adding_items
|
||||
template<typename T>
|
||||
ChaiScript &add(const T &t_t, const std::string &t_name)
|
||||
ChaiScript_Basic &add(const T &t_t, const std::string &t_name)
|
||||
{
|
||||
Name_Validator::validate_object_name(t_name);
|
||||
m_engine.add(t_t, t_name);
|
||||
return *this;
|
||||
}
|
||||
@@ -618,7 +527,7 @@ namespace chaiscript
|
||||
/// chaiscript::ChaiScript chai;
|
||||
/// chai.add(chaiscript::base_class<std::runtime_error, chaiscript::dispatch_error>());
|
||||
/// \endcode
|
||||
ChaiScript &add(const Dynamic_Cast_Conversion &d)
|
||||
ChaiScript_Basic &add(const Type_Conversion &d)
|
||||
{
|
||||
m_engine.add(d);
|
||||
return *this;
|
||||
@@ -627,7 +536,7 @@ namespace chaiscript
|
||||
/// \brief Adds all elements of a module to ChaiScript runtime
|
||||
/// \param[in] t_p The module to add.
|
||||
/// \sa chaiscript::Module
|
||||
ChaiScript &add(const ModulePtr &t_p)
|
||||
ChaiScript_Basic &add(const ModulePtr &t_p)
|
||||
{
|
||||
t_p->apply(*this, this->get_eval_engine());
|
||||
return *this;
|
||||
@@ -638,59 +547,53 @@ namespace chaiscript
|
||||
/// \param[in] t_module_name Name of the module to load
|
||||
///
|
||||
/// The module is searched for in the registered module path folders (chaiscript::ChaiScript::ChaiScript)
|
||||
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|"").
|
||||
/// and with standard prefixes and postfixes: ("lib"|"")\<t_module_name\>(".dll"|".so"|".bundle"|"").
|
||||
///
|
||||
/// Once the file is located, the system looks for the symbol "create_chaiscript_module_\<t_module_name\>".
|
||||
/// If no file can be found matching the search criteria and containing the appropriate entry point
|
||||
/// (the symbol mentioned above), an exception is thrown.
|
||||
///
|
||||
/// \throw chaiscript::exception::load_module_error In the event that no matching module can be found.
|
||||
void load_module(const std::string &t_module_name)
|
||||
std::string load_module(const std::string &t_module_name)
|
||||
{
|
||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||
(void)t_module_name; // -Wunused-parameter
|
||||
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
||||
#else
|
||||
std::vector<exception::load_module_error> errors;
|
||||
|
||||
std::vector<std::string> prefixes;
|
||||
prefixes.push_back("lib");
|
||||
prefixes.push_back("");
|
||||
|
||||
std::vector<std::string> postfixes;
|
||||
postfixes.push_back(".dll");
|
||||
postfixes.push_back(".so");
|
||||
postfixes.push_back("");
|
||||
|
||||
for (size_t i = 0; i < m_modulepaths.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < prefixes.size(); ++j)
|
||||
{
|
||||
for (size_t k = 0; k < postfixes.size(); ++k)
|
||||
{
|
||||
try {
|
||||
std::string name = m_modulepaths[i] + prefixes[j] + t_module_name + postfixes[k];
|
||||
load_module(t_module_name, name);
|
||||
return;
|
||||
} catch (const chaiscript::exception::load_module_error &e) {
|
||||
errors.push_back(e);
|
||||
// Try next set
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string errstring;
|
||||
|
||||
for (std::vector<exception::load_module_error>::const_iterator itr = errors.begin();
|
||||
itr != errors.end();
|
||||
++itr)
|
||||
std::string version_stripped_name = t_module_name;
|
||||
size_t version_pos = version_stripped_name.find("-" + Build_Info::version());
|
||||
if (version_pos != std::string::npos)
|
||||
{
|
||||
if (!errstring.empty())
|
||||
{
|
||||
errstring += "; ";
|
||||
}
|
||||
|
||||
errstring += itr->what();
|
||||
version_stripped_name.erase(version_pos);
|
||||
}
|
||||
|
||||
throw chaiscript::exception::load_module_error("Unable to find module: " + t_module_name + " Errors: " + errstring);
|
||||
std::vector<std::string> prefixes{"lib", "cyg", ""};
|
||||
|
||||
std::vector<std::string> postfixes{".dll", ".so", ".bundle", ""};
|
||||
|
||||
for (auto & elem : m_module_paths)
|
||||
{
|
||||
for (auto & prefix : prefixes)
|
||||
{
|
||||
for (auto & postfix : postfixes)
|
||||
{
|
||||
try {
|
||||
const auto name = elem + prefix + t_module_name + postfix;
|
||||
// std::cerr << "trying location: " << name << '\n';
|
||||
load_module(version_stripped_name, name);
|
||||
return name;
|
||||
} catch (const chaiscript::exception::load_module_error &e) {
|
||||
// std::cerr << "error: " << e.what() << '\n';
|
||||
errors.push_back(e);
|
||||
// Try next set
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw chaiscript::exception::load_module_error(t_module_name, errors);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \brief Load a binary module from a dynamic library. Works on platforms that support
|
||||
@@ -727,14 +630,7 @@ namespace chaiscript
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value operator()(const std::string &t_script, const Exception_Handler &t_handler = Exception_Handler())
|
||||
{
|
||||
try {
|
||||
return do_eval(t_script);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
}
|
||||
throw bv;
|
||||
}
|
||||
return eval(t_script, t_handler);
|
||||
}
|
||||
|
||||
/// \brief Evaluates a string and returns a typesafe result.
|
||||
@@ -753,21 +649,22 @@ namespace chaiscript
|
||||
template<typename T>
|
||||
T eval(const std::string &t_input, const Exception_Handler &t_handler = Exception_Handler(), const std::string &t_filename="__EVAL__")
|
||||
{
|
||||
try {
|
||||
return boxed_cast<T>(do_eval(t_input, t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
}
|
||||
throw bv;
|
||||
}
|
||||
return m_engine.boxed_cast<T>(eval(t_input, t_handler, t_filename));
|
||||
}
|
||||
|
||||
/// \brief casts an object while applying any Dynamic_Conversion available
|
||||
template<typename Type>
|
||||
decltype(auto) boxed_cast(const Boxed_Value &bv) const
|
||||
{
|
||||
return(m_engine.boxed_cast<Type>(bv));
|
||||
}
|
||||
|
||||
|
||||
/// \brief Evaluates a string.
|
||||
///
|
||||
/// \param[in] t_input Script to execute
|
||||
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
|
||||
/// \param[in] t_filename Optional filename to report to the user for where the error occured. Useful
|
||||
/// \param[in] t_filename Optional filename to report to the user for where the error occurred. Useful
|
||||
/// in special cases where you are loading a file internally instead of using eval_file
|
||||
///
|
||||
/// \return result of the script execution
|
||||
@@ -779,9 +676,9 @@ namespace chaiscript
|
||||
return do_eval(t_input, t_filename);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
t_handler->handle(bv, m_engine);
|
||||
}
|
||||
throw bv;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,17 +688,10 @@ namespace chaiscript
|
||||
/// \return result of the script execution
|
||||
/// \throw chaiscript::exception::eval_error In the case that evaluation fails.
|
||||
Boxed_Value eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
try {
|
||||
return do_eval(load_file(t_filename), t_filename);
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
}
|
||||
throw bv;
|
||||
}
|
||||
return eval(load_file(t_filename), t_handler, t_filename);
|
||||
}
|
||||
|
||||
/// \brief Loads the file specified by filename, evaluates it, and returns the typesafe result.
|
||||
/// \brief Loads the file specified by filename, evaluates it, and returns the type safe result.
|
||||
/// \tparam T Type to extract from the result value of the script execution
|
||||
/// \param[in] t_filename File to load and parse.
|
||||
/// \param[in] t_handler Optional Exception_Handler used for automatic unboxing of script thrown exceptions
|
||||
@@ -811,14 +701,7 @@ namespace chaiscript
|
||||
/// to the requested type.
|
||||
template<typename T>
|
||||
T eval_file(const std::string &t_filename, const Exception_Handler &t_handler = Exception_Handler()) {
|
||||
try {
|
||||
return boxed_cast<T>(do_eval(load_file(t_filename), t_filename));
|
||||
} catch (Boxed_Value &bv) {
|
||||
if (t_handler) {
|
||||
t_handler->handle(bv);
|
||||
}
|
||||
throw bv;
|
||||
}
|
||||
return m_engine.boxed_cast<T>(eval_file(t_filename, t_handler));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
427
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
427
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
@@ -0,0 +1,427 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_OPTIMIZER_HPP_
|
||||
#define CHAISCRIPT_OPTIMIZER_HPP_
|
||||
|
||||
#include "chaiscript_eval.hpp"
|
||||
|
||||
|
||||
namespace chaiscript {
|
||||
namespace optimizer {
|
||||
|
||||
template<typename ... T>
|
||||
struct Optimizer : T...
|
||||
{
|
||||
Optimizer() = default;
|
||||
explicit Optimizer(T ... t)
|
||||
: T(std::move(t))...
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Tracer>
|
||||
auto optimize(eval::AST_Node_Impl_Ptr<Tracer> p) {
|
||||
(void)std::initializer_list<int>{ (p = static_cast<T&>(*this).optimize(p), 0)... };
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
auto child_at(const eval::AST_Node_Impl_Ptr<T> &node, const size_t offset) {
|
||||
if (node->children[offset]->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node->children[offset]).m_original_node;
|
||||
} else {
|
||||
return node->children[offset];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (node->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children[offset];
|
||||
} else {
|
||||
return node->children[offset];
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto child_count(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if (node->identifier == AST_Node_Type::Compiled) {
|
||||
return dynamic_cast<const eval::Compiled_AST_Node<T>&>(*node).m_original_node->children.size();
|
||||
} else {
|
||||
return node->children.size();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename Callable>
|
||||
auto make_compiled_node(const eval::AST_Node_Impl_Ptr<T> &original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable)
|
||||
{
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(original_node, std::move(children), std::move(callable));
|
||||
}
|
||||
|
||||
|
||||
struct Return {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &p)
|
||||
{
|
||||
if ( (p->identifier == AST_Node_Type::Def || p->identifier == AST_Node_Type::Lambda)
|
||||
&& !p->children.empty())
|
||||
{
|
||||
auto &last_child = p->children.back();
|
||||
if (last_child->identifier == AST_Node_Type::Block) {
|
||||
auto &block_last_child = last_child->children.back();
|
||||
if (block_last_child->identifier == AST_Node_Type::Return) {
|
||||
if (block_last_child->children.size() == 1) {
|
||||
last_child->children.back() = block_last_child->children[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool contains_var_decl_in_scope(const T &node)
|
||||
{
|
||||
if (node->identifier == AST_Node_Type::Var_Decl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto num = child_count(node);
|
||||
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
const auto &child = child_at(node, i);
|
||||
if (child->identifier != AST_Node_Type::Block
|
||||
&& child->identifier != AST_Node_Type::For
|
||||
&& contains_var_decl_in_scope(child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Block {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if (node->identifier == AST_Node_Type::Block)
|
||||
{
|
||||
if (!contains_var_decl_in_scope(node))
|
||||
{
|
||||
if (node->children.size() == 1) {
|
||||
return node->children[0];
|
||||
} else {
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text, node->location, node->children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct Dead_Code {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if (node->identifier == AST_Node_Type::Block)
|
||||
{
|
||||
std::vector<size_t> keepers;
|
||||
const auto num_children = node->children.size();
|
||||
keepers.reserve(num_children);
|
||||
|
||||
for (size_t i = 0; i < num_children; ++i) {
|
||||
auto child = node->children[i];
|
||||
if ( (child->identifier != AST_Node_Type::Id
|
||||
&& child->identifier != AST_Node_Type::Constant
|
||||
&& child->identifier != AST_Node_Type::Noop)
|
||||
|| i == num_children - 1) {
|
||||
keepers.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (keepers.size() == num_children) {
|
||||
return node;
|
||||
} else {
|
||||
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
||||
for (const auto x : keepers)
|
||||
{
|
||||
new_children.push_back(node->children[x]);
|
||||
}
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Block_AST_Node<T>>(node->text, node->location, new_children);
|
||||
}
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Unused_Return {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if ((node->identifier == AST_Node_Type::Block
|
||||
|| node->identifier == AST_Node_Type::Scopeless_Block)
|
||||
&& !node->children.empty())
|
||||
{
|
||||
for (size_t i = 0; i < node->children.size()-1; ++i) {
|
||||
auto child = node->children[i];
|
||||
if (child->identifier == AST_Node_Type::Fun_Call) {
|
||||
node->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(child->text, child->location, std::move(child->children));
|
||||
}
|
||||
}
|
||||
} else if ((node->identifier == AST_Node_Type::For
|
||||
|| node->identifier == AST_Node_Type::While)
|
||||
&& child_count(node) > 0) {
|
||||
auto child = child_at(node, child_count(node) - 1);
|
||||
if (child->identifier == AST_Node_Type::Block
|
||||
|| child->identifier == AST_Node_Type::Scopeless_Block)
|
||||
{
|
||||
auto num_sub_children = child_count(child);
|
||||
for (size_t i = 0; i < num_sub_children; ++i) {
|
||||
auto sub_child = child_at(child, i);
|
||||
if (sub_child->identifier == AST_Node_Type::Fun_Call) {
|
||||
child->children[i] = chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Unused_Return_Fun_Call_AST_Node<T>>(sub_child->text, sub_child->location, std::move(sub_child->children));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct If {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
if ((node->identifier == AST_Node_Type::If)
|
||||
&& node->children.size() >= 2
|
||||
&& node->children[0]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
const auto condition = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||
if (boxed_cast<bool>(condition)) {
|
||||
return node->children[1];
|
||||
} else if (node->children.size() == 3) {
|
||||
return node->children[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct Partial_Fold {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
|
||||
// Fold right side
|
||||
if (node->identifier == AST_Node_Type::Binary
|
||||
&& node->children.size() == 2
|
||||
&& node->children[0]->identifier != AST_Node_Type::Constant
|
||||
&& node->children[1]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
try {
|
||||
const auto &oper = node->text;
|
||||
const auto parsed = Operators::to_operator(oper);
|
||||
if (parsed != Operators::Opers::invalid) {
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
||||
if (rhs.get_type_info().is_arithmetic()) {
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(node->text, node->location, node->children, rhs);
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//failure to fold, that's OK
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct Constant_Fold {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &node) {
|
||||
|
||||
if (node->identifier == AST_Node_Type::Prefix
|
||||
&& node->children.size() == 1
|
||||
&& node->children[0]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
try {
|
||||
const auto &oper = node->text;
|
||||
const auto parsed = Operators::to_operator(oper, true);
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
const auto match = oper + node->children[0]->text;
|
||||
|
||||
if (parsed != Operators::Opers::invalid && parsed != Operators::Opers::bitwise_and && lhs.get_type_info().is_arithmetic()) {
|
||||
const auto val = Boxed_Number::do_oper(parsed, lhs);
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
||||
} else if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && oper == "!") {
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(!boxed_cast<bool>(lhs)));
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//failure to fold, that's OK
|
||||
}
|
||||
} else if ((node->identifier == AST_Node_Type::Logical_And || node->identifier == AST_Node_Type::Logical_Or)
|
||||
&& node->children.size() == 2
|
||||
&& node->children[0]->identifier == AST_Node_Type::Constant
|
||||
&& node->children[1]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
try {
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
||||
if (lhs.get_type_info().bare_equal_type_info(typeid(bool)) && rhs.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||
const auto match = node->children[0]->text + " " + node->text + " " + node->children[1]->text;
|
||||
const auto val = [lhs_val = boxed_cast<bool>(lhs), rhs_val = boxed_cast<bool>(rhs), id = node->identifier] {
|
||||
if (id == AST_Node_Type::Logical_And) { return Boxed_Value(lhs_val && rhs_val); }
|
||||
else { return Boxed_Value(lhs_val || rhs_val); }
|
||||
}();
|
||||
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//failure to fold, that's OK
|
||||
}
|
||||
} else if (node->identifier == AST_Node_Type::Binary
|
||||
&& node->children.size() == 2
|
||||
&& node->children[0]->identifier == AST_Node_Type::Constant
|
||||
&& node->children[1]->identifier == AST_Node_Type::Constant)
|
||||
{
|
||||
try {
|
||||
const auto &oper = node->text;
|
||||
const auto parsed = Operators::to_operator(oper);
|
||||
if (parsed != Operators::Opers::invalid) {
|
||||
const auto lhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[0])->m_value;
|
||||
const auto rhs = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1])->m_value;
|
||||
if (lhs.get_type_info().is_arithmetic() && rhs.get_type_info().is_arithmetic()) {
|
||||
const auto val = Boxed_Number::do_oper(parsed, lhs, rhs);
|
||||
const auto match = node->children[0]->text + " " + oper + " " + node->children[1]->text;
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, std::move(val));
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
//failure to fold, that's OK
|
||||
}
|
||||
} else if (node->identifier == AST_Node_Type::Fun_Call
|
||||
&& node->children.size() == 2
|
||||
&& node->children[0]->identifier == AST_Node_Type::Id
|
||||
&& node->children[1]->identifier == AST_Node_Type::Arg_List
|
||||
&& node->children[1]->children.size() == 1
|
||||
&& node->children[1]->children[0]->identifier == AST_Node_Type::Constant) {
|
||||
|
||||
const auto arg = std::dynamic_pointer_cast<eval::Constant_AST_Node<T>>(node->children[1]->children[0])->m_value;
|
||||
if (arg.get_type_info().is_arithmetic()) {
|
||||
const auto &fun_name = node->children[0]->text;
|
||||
|
||||
const auto make_constant = [&node, &fun_name](auto val){
|
||||
const auto match = fun_name + "(" + node->children[1]->children[0]->text + ")";
|
||||
return chaiscript::make_shared<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match), node->location, Boxed_Value(val));
|
||||
};
|
||||
|
||||
if (fun_name == "double") {
|
||||
return make_constant(Boxed_Number(arg).get_as<double>());
|
||||
} else if (fun_name == "int") {
|
||||
return make_constant(Boxed_Number(arg).get_as<int>());
|
||||
} else if (fun_name == "float") {
|
||||
return make_constant(Boxed_Number(arg).get_as<float>());
|
||||
} else if (fun_name == "long") {
|
||||
return make_constant(Boxed_Number(arg).get_as<long>());
|
||||
} else if (fun_name == "size_t") {
|
||||
return make_constant(Boxed_Number(arg).get_as<size_t>());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
struct For_Loop {
|
||||
template<typename T>
|
||||
auto optimize(const eval::AST_Node_Impl_Ptr<T> &for_node) {
|
||||
|
||||
if (for_node->identifier != AST_Node_Type::For) {
|
||||
return for_node;
|
||||
}
|
||||
|
||||
const auto eq_node = child_at(for_node, 0);
|
||||
const auto binary_node = child_at(for_node, 1);
|
||||
const auto prefix_node = child_at(for_node, 2);
|
||||
|
||||
if (eq_node->identifier == AST_Node_Type::Equation
|
||||
&& child_count(eq_node) == 2
|
||||
&& child_at(eq_node, 0)->identifier == AST_Node_Type::Var_Decl
|
||||
&& child_at(eq_node, 1)->identifier == AST_Node_Type::Constant
|
||||
&& binary_node->identifier == AST_Node_Type::Binary
|
||||
&& binary_node->text == "<"
|
||||
&& child_count(binary_node) == 2
|
||||
&& child_at(binary_node, 0)->identifier == AST_Node_Type::Id
|
||||
&& child_at(binary_node, 0)->text == child_at(child_at(eq_node,0), 0)->text
|
||||
&& child_at(binary_node, 1)->identifier == AST_Node_Type::Constant
|
||||
&& prefix_node->identifier == AST_Node_Type::Prefix
|
||||
&& prefix_node->text == "++"
|
||||
&& child_count(prefix_node) == 1
|
||||
&& child_at(prefix_node, 0)->identifier == AST_Node_Type::Id
|
||||
&& child_at(prefix_node, 0)->text == child_at(child_at(eq_node,0), 0)->text)
|
||||
{
|
||||
const Boxed_Value &begin = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(eq_node, 1))->m_value;
|
||||
const Boxed_Value &end = std::dynamic_pointer_cast<const eval::Constant_AST_Node<T>>(child_at(binary_node, 1))->m_value;
|
||||
const std::string &id = child_at(prefix_node, 0)->text;
|
||||
|
||||
if (begin.get_type_info().bare_equal(user_type<int>())
|
||||
&& end.get_type_info().bare_equal(user_type<int>())) {
|
||||
|
||||
const auto start_int = boxed_cast<int>(begin);
|
||||
const auto end_int = boxed_cast<int>(end);
|
||||
|
||||
const auto body = child_at(for_node, 3);
|
||||
|
||||
return make_compiled_node(for_node, {body},
|
||||
[id, start_int, end_int](const std::vector<eval::AST_Node_Impl_Ptr<T>> &children, const chaiscript::detail::Dispatch_State &t_ss) {
|
||||
assert(children.size() == 1);
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
int i = start_int;
|
||||
t_ss.add_object(id, var(&i));
|
||||
|
||||
try {
|
||||
for (; i < end_int; ++i) {
|
||||
try {
|
||||
// Body of Loop
|
||||
children[0]->eval(t_ss);
|
||||
} catch (eval::detail::Continue_Loop &) {
|
||||
// we got a continue exception, which means all of the remaining
|
||||
// loop implementation is skipped and we just need to continue to
|
||||
// the next iteration step
|
||||
}
|
||||
}
|
||||
} catch (eval::detail::Break_Loop &) {
|
||||
// loop broken
|
||||
}
|
||||
|
||||
return void_var();
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return for_node;
|
||||
}
|
||||
} else {
|
||||
return for_node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef Optimizer<optimizer::Partial_Fold, optimizer::Unused_Return, optimizer::Constant_Fold,
|
||||
optimizer::If, optimizer::Return, optimizer::Dead_Code, optimizer::Block, optimizer::For_Loop> Optimizer_Default;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
81
include/chaiscript/language/chaiscript_posix.hpp
Normal file
81
include/chaiscript/language/chaiscript_posix.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_POSIX_HPP_
|
||||
#define CHAISCRIPT_POSIX_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
struct DLModule
|
||||
{
|
||||
explicit DLModule(const std::string &t_filename)
|
||||
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
|
||||
{
|
||||
if (m_data == nullptr)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(DLModule &&) = default;
|
||||
DLModule &operator=(DLModule &&) = default;
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
dlclose(m_data);
|
||||
}
|
||||
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(cast_symbol(dlsym(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
static T cast_symbol(void *p)
|
||||
{
|
||||
union cast_union
|
||||
{
|
||||
T func_ptr;
|
||||
void *in_ptr;
|
||||
};
|
||||
|
||||
cast_union c;
|
||||
c.in_ptr = p;
|
||||
return c.func_ptr;
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// and 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace chaiscript {
|
||||
struct ChaiScript_Prelude {
|
||||
constexpr static const char *chaiscript_prelude=R""(
|
||||
static std::string chaiscript_prelude() { return R"chaiscript(
|
||||
|
||||
def lt(l, r) {
|
||||
if (call_exists(`<`, l, r)) {
|
||||
@@ -38,11 +38,28 @@ def eq(l, r) {
|
||||
|
||||
def new(x) {
|
||||
eval(type_name(x))();
|
||||
}
|
||||
}
|
||||
|
||||
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||
{
|
||||
eval(type_name(x))(x);
|
||||
def clone(double x) {
|
||||
double(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
def clone(string x) {
|
||||
string(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
def clone(vector x) {
|
||||
vector(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
|
||||
def clone(int x) {
|
||||
int(x).clone_var_attrs(x)
|
||||
}
|
||||
|
||||
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||
{
|
||||
eval(type_name(x))(x).clone_var_attrs(x);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +73,6 @@ def to_string(x) : call_exists(range, x) && !x.is_type("string"){
|
||||
"[" + x.join(", ") + "]";
|
||||
}
|
||||
|
||||
# Basic to_string function
|
||||
def to_string(x) {
|
||||
internal_to_string(x);
|
||||
}
|
||||
|
||||
# Prints to console with no carriage return
|
||||
def puts(x) {
|
||||
print_string(x.to_string());
|
||||
@@ -115,18 +127,6 @@ def even(x)
|
||||
}
|
||||
|
||||
|
||||
# Pushes the second value onto the container first value while making a clone of the value
|
||||
def push_back(container, x) : call_exists(push_back_ref, container, x)
|
||||
{
|
||||
container.push_back_ref(clone(x))
|
||||
}
|
||||
|
||||
# Pushes the second value onto the front of the container first value while making a clone of the value
|
||||
def push_front(container, x) : call_exists(push_front_ref, container, x)
|
||||
{
|
||||
container.push_front_ref(clone(x))
|
||||
}
|
||||
|
||||
# Inserts the third value at the position of the second value into the container of the first
|
||||
# while making a clone.
|
||||
def insert_at(container, pos, x)
|
||||
@@ -136,8 +136,8 @@ def insert_at(container, pos, x)
|
||||
|
||||
# Returns the reverse of the given container
|
||||
def reverse(container) {
|
||||
auto retval = new(container);
|
||||
auto r = range(container);
|
||||
auto retval := new(container);
|
||||
auto r := range(container);
|
||||
while (!r.empty()) {
|
||||
retval.push_back(r.back());
|
||||
r.pop_back();
|
||||
@@ -145,10 +145,18 @@ def reverse(container) {
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def range(r) : call_exists(range_internal, r)
|
||||
{
|
||||
var ri := range_internal(r);
|
||||
ri.get_var_attr("internal_obj") := r;
|
||||
ri;
|
||||
}
|
||||
|
||||
# Return a range from a range
|
||||
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
||||
{
|
||||
return clone(r);
|
||||
{
|
||||
clone(r);
|
||||
}
|
||||
|
||||
|
||||
@@ -200,19 +208,42 @@ def retro::empty()
|
||||
|
||||
# Performs the second value function over the container first value
|
||||
def for_each(container, func) : call_exists(range, container) {
|
||||
var t_range = range(container);
|
||||
var t_range := range(container);
|
||||
while (!t_range.empty()) {
|
||||
func(t_range.front());
|
||||
t_range.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
def back_inserter(container) {
|
||||
bind(push_back, container, _);
|
||||
def any_of(container, func) : call_exists(range, container) {
|
||||
var t_range := range(container);
|
||||
while (!t_range.empty()) {
|
||||
if (func(t_range.front())) {
|
||||
return true;
|
||||
}
|
||||
t_range.pop_front();
|
||||
}
|
||||
false;
|
||||
}
|
||||
|
||||
def all_of(container, func) : call_exists(range, container) {
|
||||
var t_range := range(container);
|
||||
while (!t_range.empty()) {
|
||||
if (!func(t_range.front())) {
|
||||
return false;
|
||||
}
|
||||
t_range.pop_front();
|
||||
}
|
||||
|
||||
true;
|
||||
}
|
||||
|
||||
def back_inserter(container) {
|
||||
bind(push_back, container, _);
|
||||
}
|
||||
|
||||
def contains(container, item, compare_func) : call_exists(range, container) {
|
||||
auto t_range = range(container);
|
||||
auto t_range := range(container);
|
||||
while (!t_range.empty()) {
|
||||
if ( compare_func(t_range.front(), item) ) {
|
||||
return true;
|
||||
@@ -220,15 +251,15 @@ def contains(container, item, compare_func) : call_exists(range, container) {
|
||||
|
||||
t_range.pop_front();
|
||||
}
|
||||
return false;
|
||||
false;
|
||||
}
|
||||
|
||||
def contains(container, item) {
|
||||
return contains(container, item, eq)
|
||||
contains(container, item, eq)
|
||||
}
|
||||
|
||||
def map(container, func, inserter) : call_exists(range, container) {
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
inserter(func(range.front()));
|
||||
range.pop_front();
|
||||
@@ -237,7 +268,7 @@ def map(container, func, inserter) : call_exists(range, container) {
|
||||
|
||||
# Performs the second value function over the container first value. Creates a new container with the results
|
||||
def map(container, func) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
map(container, func, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -245,7 +276,7 @@ def map(container, func) {
|
||||
# Performs the second value function over the container first value. Starts with initial and continues with each element.
|
||||
def foldl(container, func, initial) : call_exists(range, container){
|
||||
auto retval = initial;
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
retval = (func(range.front(), retval));
|
||||
range.pop_front();
|
||||
@@ -266,8 +297,8 @@ def product(container) {
|
||||
# Returns a new container with the elements of the first value concatenated with the elements of the second value
|
||||
def concat(x, y) : call_exists(clone, x) {
|
||||
auto retval = x;
|
||||
auto inserter = back_inserter(retval);
|
||||
auto range = range(y);
|
||||
auto inserter := back_inserter(retval);
|
||||
auto range := range(y);
|
||||
while (!range.empty()) {
|
||||
inserter(range.front());
|
||||
range.pop_front();
|
||||
@@ -277,7 +308,7 @@ def concat(x, y) : call_exists(clone, x) {
|
||||
|
||||
|
||||
def take(container, num, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
auto i = num;
|
||||
while ((i > 0) && (!r.empty())) {
|
||||
inserter(r.front());
|
||||
@@ -289,14 +320,14 @@ def take(container, num, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given number of elements taken from the container
|
||||
def take(container, num) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
take(container, num, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def take_while(container, f, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
while ((!r.empty()) && f(r.front())) {
|
||||
inserter(r.front());
|
||||
r.pop_front();
|
||||
@@ -306,14 +337,14 @@ def take_while(container, f, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given elements match the second value function
|
||||
def take_while(container, f) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
take_while(container, f, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def drop(container, num, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
auto i = num;
|
||||
while ((i > 0) && (!r.empty())) {
|
||||
r.pop_front();
|
||||
@@ -328,14 +359,14 @@ def drop(container, num, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given number of elements dropped from the given container
|
||||
def drop(container, num) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
drop(container, num, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
|
||||
|
||||
def drop_while(container, f, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
while ((!r.empty())&& f(r.front())) {
|
||||
r.pop_front();
|
||||
}
|
||||
@@ -348,7 +379,7 @@ def drop_while(container, f, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new container with the given elements dropped that match the second value function
|
||||
def drop_while(container, f) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
drop_while(container, f, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -356,7 +387,7 @@ def drop_while(container, f) {
|
||||
|
||||
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.
|
||||
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
auto retval = r.front();
|
||||
r.pop_front();
|
||||
retval = func(retval, r.front());
|
||||
@@ -372,7 +403,7 @@ def reduce(container, func) : container.size() >= 2 && call_exists(range, contai
|
||||
# Returns a string of the elements in container delimited by the second value string
|
||||
def join(container, delim) {
|
||||
auto retval = "";
|
||||
auto range = range(container);
|
||||
auto range := range(container);
|
||||
if (!range.empty()) {
|
||||
retval += to_string(range.front());
|
||||
range.pop_front();
|
||||
@@ -387,7 +418,7 @@ def join(container, delim) {
|
||||
|
||||
|
||||
def filter(container, f, inserter) : call_exists(range, container) {
|
||||
auto r = range(container);
|
||||
auto r := range(container);
|
||||
while (!r.empty()) {
|
||||
if (f(r.front())) {
|
||||
inserter(r.front());
|
||||
@@ -399,7 +430,7 @@ def filter(container, f, inserter) : call_exists(range, container) {
|
||||
|
||||
# Returns a new Vector which match the second value function
|
||||
def filter(container, f) {
|
||||
auto retval = new(container);
|
||||
auto retval := new(container);
|
||||
filter(container, f, back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -416,7 +447,7 @@ def generate_range(x, y, inserter) {
|
||||
|
||||
# Returns a new Vector which represents the range from the first value to the second value
|
||||
def generate_range(x, y) {
|
||||
auto retval = Vector();
|
||||
auto retval := Vector();
|
||||
generate_range(x,y,back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -429,8 +460,8 @@ def collate(x, y) {
|
||||
|
||||
|
||||
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) {
|
||||
auto r_x = range(x);
|
||||
auto r_y = range(y);
|
||||
auto r_x := range(x);
|
||||
auto r_y := range(y);
|
||||
while (!r_x.empty() && !r_y.empty()) {
|
||||
inserter(f(r_x.front(), r_y.front()));
|
||||
r_x.pop_front();
|
||||
@@ -441,7 +472,7 @@ def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y)
|
||||
|
||||
# Returns a new Vector which joins matching elements of the second and third value with the first value function
|
||||
def zip_with(f, x, y) {
|
||||
auto retval = Vector();
|
||||
auto retval := Vector();
|
||||
zip_with(f,x,y,back_inserter(retval));
|
||||
retval;
|
||||
}
|
||||
@@ -454,38 +485,38 @@ def zip(x, y) {
|
||||
|
||||
|
||||
# Returns the position of the second value string in the first value string
|
||||
def string::find(substr) : is_type(substr, "string") {
|
||||
int(find(this, substr, 0));
|
||||
def string::find(string substr) {
|
||||
find(this, substr, size_t(0));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of last match of the second value string in the first value string
|
||||
def string::rfind(substr) : is_type(substr, "string") {
|
||||
int(rfind(this, substr, -1));
|
||||
def string::rfind(string substr) {
|
||||
rfind(this, substr, size_t(-1));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the first match of elements in the second value string in the first value string
|
||||
def string::find_first_of(list) : is_type(list, "string") {
|
||||
int(find_first_of(this, list, 0));
|
||||
def string::find_first_of(string list) {
|
||||
find_first_of(this, list, size_t(0));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the last match of elements in the second value string in the first value string
|
||||
def string::find_last_of(list) : is_type(list, "string") {
|
||||
int(find_last_of(this, list, -1));
|
||||
def string::find_last_of(string list) {
|
||||
find_last_of(this, list, size_t(-1));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the first non-matching element in the second value string in the first value string
|
||||
def string::find_first_not_of(list) : is_type(list, "string") {
|
||||
int(find_first_not_of(this, list, 0));
|
||||
def string::find_first_not_of(string list) {
|
||||
find_first_not_of(this, list, size_t(0));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the last non-matching element in the second value string in the first value string
|
||||
def string::find_last_not_of(list) : is_type(list, "string") {
|
||||
int(find_last_not_of(this, list, -1));
|
||||
def string::find_last_not_of(string list) {
|
||||
find_last_not_of(this, list, size_t(-1));
|
||||
}
|
||||
|
||||
|
||||
@@ -504,8 +535,8 @@ def string::trim() {
|
||||
}
|
||||
|
||||
|
||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
|
||||
auto range = range(container);
|
||||
def find(container, value, Function compare_func) : call_exists(range, container) {
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
if (compare_func(range.front(), value)) {
|
||||
return range;
|
||||
@@ -513,16 +544,17 @@ def find(container, value, compare_func) : call_exists(range, container) && is_t
|
||||
range.pop_front();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
range;
|
||||
}
|
||||
|
||||
|
||||
def find(container, value) {
|
||||
return find(container, value, eq)
|
||||
find(container, value, eq)
|
||||
}
|
||||
|
||||
|
||||
)"";
|
||||
)chaiscript";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace ChaiScript_Language
|
||||
{
|
||||
|
||||
/// \page LangStandardLibraryRef ChaiScript Language Standard Libary Reference
|
||||
/// \page LangStandardLibraryRef ChaiScript Language Standard Library Reference
|
||||
///
|
||||
/// ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly
|
||||
/// as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available
|
||||
@@ -112,7 +112,7 @@ class Map
|
||||
};
|
||||
|
||||
|
||||
/// \brief A concept implemented by string, Vector and Map. It is convertable to Range, default constructable and back_insertable
|
||||
/// \brief A concept implemented by string, Vector and Map. It is convertible to Range, default constructable and back_insertable
|
||||
class Container
|
||||
{
|
||||
public:
|
||||
@@ -153,10 +153,10 @@ void print(Object o);
|
||||
|
||||
/// \brief ChaiScript representation of std::string. It is an std::string but only some member are exposed to ChaiScript.
|
||||
///
|
||||
/// Because the ChaiScript string object is an std::string, it is directly convertable to and from std::string
|
||||
/// Because the ChaiScript string object is an std::string, it is directly convertible to and from std::string
|
||||
/// using the chaiscript::boxed_cast and chaiscript::var functions.
|
||||
///
|
||||
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct passthroughs to the
|
||||
/// With the exception of string::trim, string::rtrim, string::ltrim, all members are direct pass-throughs to the
|
||||
/// std::string of the same name.
|
||||
///
|
||||
/// \note Object and function notations are equivalent in ChaiScript. This means that
|
||||
@@ -309,7 +309,7 @@ class Range
|
||||
|
||||
/// \brief Moves the front pointer forward one
|
||||
///
|
||||
/// \post front() returne the element at front() + 1;
|
||||
/// \post front() returns the element at front() + 1;
|
||||
void pop_front();
|
||||
|
||||
};
|
||||
@@ -340,7 +340,7 @@ class Const_Range
|
||||
|
||||
/// \brief Moves the front pointer forward one
|
||||
///
|
||||
/// \post front() returne the element at front() + 1;
|
||||
/// \post front() returns the element at front() + 1;
|
||||
void pop_front();
|
||||
|
||||
};
|
||||
@@ -505,7 +505,7 @@ class Function
|
||||
/// \endcode
|
||||
Vector get_contained_functions() const;
|
||||
|
||||
/// \brief Returns a vector of the contained functions
|
||||
/// \brief Returns a function guard as function
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
@@ -519,7 +519,7 @@ class Function
|
||||
/// \brief Returns a vector of Type_Info objects that represent the param types for this function.
|
||||
/// The first value in the list is the return type.
|
||||
///
|
||||
/// If this function is a conglomeration of several functions (get_contained_values().size() > 0)
|
||||
/// If this function is a conglomerate of several functions (get_contained_values().size() > 0)
|
||||
/// then the function returns as many Type_Info objects as it can. If the functions contained all have
|
||||
/// the same arity, then it represents the arity. If they have different arities, it returns only
|
||||
/// one value - the return type.
|
||||
@@ -534,7 +534,7 @@ class Function
|
||||
/// \endcode
|
||||
Vector get_param_types() const;
|
||||
|
||||
/// \brief Returns true if the function has a guard to it. Always returns falls for a conglomerate function
|
||||
/// \brief Returns true if the function has a guard to it. Always returns false for a conglomerate function
|
||||
bool has_guard() const;
|
||||
|
||||
/// \brief Calls the function with the given set of parameters and returns the value;
|
||||
@@ -718,14 +718,14 @@ Object drop_while(Range c, Function f);
|
||||
Object reduce(Range c, Function f);
|
||||
|
||||
|
||||
/// \brief Takes elements from Range c that match function f, return them.
|
||||
/// \brief Takes elements from Container c that match function f, return them.
|
||||
///
|
||||
/// Example:
|
||||
/// \code
|
||||
/// eval> filter([1, 2, 3, 4], odd)
|
||||
/// [1, 3]
|
||||
/// \endcode
|
||||
Object filter(Range c, Function f);
|
||||
Object filter(Container c, Function f);
|
||||
|
||||
|
||||
/// \brief Joins the elements of the Range c into a string, delimiting each with the delim string.
|
||||
|
||||
46
include/chaiscript/language/chaiscript_tracer.hpp
Normal file
46
include/chaiscript/language/chaiscript_tracer.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_TRACER_HPP_
|
||||
#define CHAISCRIPT_TRACER_HPP_
|
||||
|
||||
namespace chaiscript {
|
||||
namespace eval {
|
||||
|
||||
|
||||
struct Noop_Tracer_Detail
|
||||
{
|
||||
template<typename T>
|
||||
void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... T>
|
||||
struct Tracer : T...
|
||||
{
|
||||
Tracer() = default;
|
||||
explicit Tracer(T ... t)
|
||||
: T(std::move(t))...
|
||||
{
|
||||
}
|
||||
|
||||
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
|
||||
(void)std::initializer_list<int>{ (static_cast<T&>(*this).trace(ds, node), 0)... };
|
||||
}
|
||||
|
||||
static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
|
||||
ds->get_parser().get_tracer<Tracer<T...>>().do_trace(ds, node);
|
||||
}
|
||||
};
|
||||
|
||||
typedef Tracer<Noop_Tracer_Detail> Noop_Tracer;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
31
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
31
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UNKNOWN_HPP_
|
||||
#define CHAISCRIPT_UNKNOWN_HPP_
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
Loadable_Module(const std::string &, const std::string &)
|
||||
{
|
||||
#ifdef CHAISCRIPT_NO_DYNLOAD
|
||||
throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)");
|
||||
#else
|
||||
throw chaiscript::exception::load_module_error("Loadable module support not available for your platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
133
include/chaiscript/language/chaiscript_windows.hpp
Normal file
133
include/chaiscript/language/chaiscript_windows.hpp
Normal file
@@ -0,0 +1,133 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_WINDOWS_HPP_
|
||||
#define CHAISCRIPT_WINDOWS_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef CHAISCRIPT_WINDOWS
|
||||
#define VC_EXTRA_LEAN
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct Loadable_Module
|
||||
{
|
||||
template<typename T>
|
||||
static std::wstring to_wstring(const T &t_str)
|
||||
{
|
||||
return std::wstring(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static std::string to_string(const T &t_str)
|
||||
{
|
||||
return std::string(t_str.begin(), t_str.end());
|
||||
}
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
template<typename T>
|
||||
static std::wstring to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_wstring(t_str);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
static std::string to_proper_string(const T &t_str)
|
||||
{
|
||||
return to_string(t_str);
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string get_error_message(DWORD t_err)
|
||||
{
|
||||
typedef LPTSTR StringType;
|
||||
|
||||
#if defined(_UNICODE) || defined(UNICODE)
|
||||
std::wstring retval = L"Unknown Error";
|
||||
#else
|
||||
std::string retval = "Unknown Error";
|
||||
#endif
|
||||
StringType lpMsgBuf = nullptr;
|
||||
|
||||
if (FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
t_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
reinterpret_cast<StringType>(&lpMsgBuf),
|
||||
0, nullptr ) != 0 && lpMsgBuf)
|
||||
{
|
||||
retval = lpMsgBuf;
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return to_string(retval);
|
||||
}
|
||||
|
||||
struct DLModule
|
||||
{
|
||||
explicit DLModule(const std::string &t_filename)
|
||||
: m_data(LoadLibrary(to_proper_string(t_filename).c_str()))
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
DLModule(DLModule &&) = default;
|
||||
DLModule &operator=(DLModule &&) = default;
|
||||
DLModule(const DLModule &) = delete;
|
||||
DLModule &operator=(const DLModule &) = delete;
|
||||
|
||||
~DLModule()
|
||||
{
|
||||
FreeLibrary(m_data);
|
||||
}
|
||||
|
||||
HMODULE m_data;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DLSym
|
||||
{
|
||||
DLSym(DLModule &t_mod, const std::string &t_symbol)
|
||||
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
|
||||
{
|
||||
if (!m_symbol)
|
||||
{
|
||||
throw chaiscript::exception::load_module_error(get_error_message(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
T m_symbol;
|
||||
};
|
||||
|
||||
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
|
||||
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name),
|
||||
m_moduleptr(m_func.m_symbol())
|
||||
{
|
||||
}
|
||||
|
||||
DLModule m_dlmodule;
|
||||
DLSym<Create_Module_Func> m_func;
|
||||
ModulePtr m_moduleptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
50
include/chaiscript/utility/fnv1a.hpp
Normal file
50
include/chaiscript/utility/fnv1a.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
|
||||
|
||||
namespace utility
|
||||
{
|
||||
|
||||
|
||||
static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) {
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4307)
|
||||
#endif
|
||||
return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193));
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
674
include/chaiscript/utility/json.hpp
Normal file
674
include/chaiscript/utility/json.hpp
Normal file
@@ -0,0 +1,674 @@
|
||||
// From github.com/nbsdx/SimpleJSON.
|
||||
// Released under the DWTFYW PL
|
||||
//
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef SIMPLEJSON_HPP
|
||||
#define SIMPLEJSON_HPP
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
#include "../chaiscript_defines.hpp"
|
||||
|
||||
namespace json {
|
||||
|
||||
using std::enable_if;
|
||||
using std::initializer_list;
|
||||
using std::is_same;
|
||||
using std::is_convertible;
|
||||
using std::is_integral;
|
||||
using std::is_floating_point;
|
||||
|
||||
|
||||
|
||||
|
||||
class JSON
|
||||
{
|
||||
public:
|
||||
enum class Class {
|
||||
Null,
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Floating,
|
||||
Integral,
|
||||
Boolean
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
struct QuickFlatMap
|
||||
{
|
||||
auto find(const std::string &s) {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||
}
|
||||
|
||||
auto find(const std::string &s) const {
|
||||
return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; });
|
||||
}
|
||||
|
||||
auto size() const {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
auto begin() const {
|
||||
return data.begin();
|
||||
}
|
||||
|
||||
auto end() const {
|
||||
return data.end();
|
||||
}
|
||||
|
||||
|
||||
auto begin() {
|
||||
return data.begin();
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return data.end();
|
||||
}
|
||||
|
||||
|
||||
JSON &operator[](const std::string &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
data.emplace_back(s, JSON());
|
||||
return data.back().second;
|
||||
}
|
||||
}
|
||||
|
||||
JSON &at(const std::string &s) {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::out_of_range("Unknown key: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
const JSON &at(const std::string &s) const {
|
||||
const auto itr = find(s);
|
||||
if (itr != data.end()) {
|
||||
return itr->second;
|
||||
} else {
|
||||
throw std::out_of_range("Unknown key: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
size_t count(const std::string &s) const {
|
||||
return (find(s) != data.end())?1:0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, JSON>> data;
|
||||
|
||||
using iterator = decltype(data)::iterator;
|
||||
using const_iterator = decltype(data)::const_iterator;
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct Internal {
|
||||
template<typename T>
|
||||
auto clone(const std::unique_ptr<T> &ptr) {
|
||||
if (ptr != nullptr) {
|
||||
return std::make_unique<T>(*ptr);
|
||||
} else {
|
||||
return std::unique_ptr<T>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Internal( double d ) : Float( d ), Type(Class::Floating) {}
|
||||
Internal( long l ) : Int( l ), Type(Class::Integral) {}
|
||||
Internal( bool b ) : Bool( b ), Type(Class::Boolean) {}
|
||||
Internal( std::string s ) : String(std::make_unique<std::string>(std::move(s))), Type(Class::String) {}
|
||||
Internal() : Type(Class::Null) {}
|
||||
|
||||
Internal(Class t_type) {
|
||||
set_type(t_type);
|
||||
}
|
||||
|
||||
Internal(const Internal &other)
|
||||
: List(clone(other.List)),
|
||||
Map(clone(other.Map)),
|
||||
String(clone(other.String)),
|
||||
Float(other.Float),
|
||||
Int(other.Int),
|
||||
Bool(other.Bool),
|
||||
Type(other.Type)
|
||||
{
|
||||
}
|
||||
|
||||
Internal &operator=(const Internal &other)
|
||||
{
|
||||
List = clone(other.List);
|
||||
Map = clone(other.Map);
|
||||
String = clone(other.String);
|
||||
Float = other.Float;
|
||||
Int = other.Int;
|
||||
Bool = other.Bool;
|
||||
Type = other.Type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void set_type( Class type ) {
|
||||
if( type == Type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map.reset();
|
||||
List.reset();
|
||||
String.reset();
|
||||
|
||||
switch( type ) {
|
||||
case Class::Object: Map = std::make_unique<QuickFlatMap>(); break;
|
||||
case Class::Array: List = std::make_unique<std::vector<JSON>>(); break;
|
||||
case Class::String: String = std::make_unique<std::string>(); break;
|
||||
case Class::Floating: Float = 0.0; break;
|
||||
case Class::Integral: Int = 0; break;
|
||||
case Class::Boolean: Bool = false; break;
|
||||
case Class::Null: break;
|
||||
}
|
||||
|
||||
Type = type;
|
||||
}
|
||||
|
||||
Internal(Internal &&) = default;
|
||||
Internal &operator=(Internal &&) = default;
|
||||
|
||||
std::unique_ptr<std::vector<JSON>> List;
|
||||
std::unique_ptr<QuickFlatMap> Map;
|
||||
std::unique_ptr<std::string> String;
|
||||
double Float = 0;
|
||||
long Int = 0;
|
||||
bool Bool = false;
|
||||
|
||||
Class Type = Class::Null;
|
||||
};
|
||||
|
||||
Internal internal;
|
||||
|
||||
public:
|
||||
|
||||
template <typename Container>
|
||||
class JSONWrapper {
|
||||
Container *object = nullptr;
|
||||
|
||||
public:
|
||||
JSONWrapper( Container *val ) : object( val ) {}
|
||||
JSONWrapper( std::nullptr_t ) {}
|
||||
|
||||
typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); }
|
||||
typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); }
|
||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); }
|
||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); }
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
class JSONConstWrapper {
|
||||
const Container *object = nullptr;
|
||||
|
||||
public:
|
||||
JSONConstWrapper( const Container *val ) : object( val ) {}
|
||||
JSONConstWrapper( std::nullptr_t ) {}
|
||||
|
||||
typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); }
|
||||
typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); }
|
||||
};
|
||||
|
||||
JSON() = default;
|
||||
JSON( std::nullptr_t ) {}
|
||||
|
||||
explicit JSON(Class type)
|
||||
: internal(type)
|
||||
{
|
||||
}
|
||||
|
||||
JSON( initializer_list<JSON> list )
|
||||
: internal(Class::Object)
|
||||
{
|
||||
for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) {
|
||||
operator[]( i->to_string() ) = *std::next( i );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
explicit JSON( T b, typename enable_if<is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<bool>(b) ) {}
|
||||
|
||||
template <typename T>
|
||||
explicit JSON( T i, typename enable_if<is_integral<T>::value && !is_same<T,bool>::value>::type* = nullptr ) : internal( static_cast<long>(i) ) {}
|
||||
|
||||
template <typename T>
|
||||
explicit JSON( T f, typename enable_if<is_floating_point<T>::value>::type* = nullptr ) : internal( static_cast<double>(f) ) {}
|
||||
|
||||
template <typename T>
|
||||
explicit JSON( T s, typename enable_if<is_convertible<T,std::string>::value>::type* = nullptr ) : internal( static_cast<std::string>(s) ) {}
|
||||
|
||||
|
||||
|
||||
static JSON Load( const std::string & );
|
||||
|
||||
JSON& operator[]( const std::string &key ) {
|
||||
internal.set_type( Class::Object );
|
||||
return internal.Map->operator[]( key );
|
||||
}
|
||||
|
||||
JSON& operator[]( const size_t index ) {
|
||||
internal.set_type( Class::Array );
|
||||
if( index >= internal.List->size() ) {
|
||||
internal.List->resize( index + 1 );
|
||||
}
|
||||
|
||||
return internal.List->operator[]( index );
|
||||
}
|
||||
|
||||
|
||||
JSON &at( const std::string &key ) {
|
||||
return operator[]( key );
|
||||
}
|
||||
|
||||
const JSON &at( const std::string &key ) const {
|
||||
return internal.Map->at( key );
|
||||
}
|
||||
|
||||
JSON &at( size_t index ) {
|
||||
return operator[]( index );
|
||||
}
|
||||
|
||||
const JSON &at( size_t index ) const {
|
||||
return internal.List->at( index );
|
||||
}
|
||||
|
||||
|
||||
long length() const {
|
||||
if( internal.Type == Class::Array ) {
|
||||
return static_cast<long>(internal.List->size());
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool has_key( const std::string &key ) const {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return internal.Map->count(key) != 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return static_cast<int>(internal.Map->size());
|
||||
} else if( internal.Type == Class::Array ) {
|
||||
return static_cast<int>(internal.List->size());
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Class JSONType() const { return internal.Type; }
|
||||
|
||||
/// Functions for getting primitives from the JSON object.
|
||||
bool is_null() const { return internal.Type == Class::Null; }
|
||||
|
||||
std::string to_string() const { bool b; return to_string( b ); }
|
||||
std::string to_string( bool &ok ) const {
|
||||
ok = (internal.Type == Class::String);
|
||||
return ok ? *internal.String : std::string("");
|
||||
}
|
||||
|
||||
double to_float() const { bool b; return to_float( b ); }
|
||||
double to_float( bool &ok ) const {
|
||||
ok = (internal.Type == Class::Floating);
|
||||
return ok ? internal.Float : 0.0;
|
||||
}
|
||||
|
||||
long to_int() const { bool b; return to_int( b ); }
|
||||
long to_int( bool &ok ) const {
|
||||
ok = (internal.Type == Class::Integral);
|
||||
return ok ? internal.Int : 0;
|
||||
}
|
||||
|
||||
bool to_bool() const { bool b; return to_bool( b ); }
|
||||
bool to_bool( bool &ok ) const {
|
||||
ok = (internal.Type == Class::Boolean);
|
||||
return ok ? internal.Bool : false;
|
||||
}
|
||||
|
||||
JSONWrapper<QuickFlatMap> object_range() {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return JSONWrapper<QuickFlatMap>( internal.Map.get() );
|
||||
} else {
|
||||
return JSONWrapper<QuickFlatMap>( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
JSONWrapper<std::vector<JSON>> array_range() {
|
||||
if( internal.Type == Class::Array ) {
|
||||
return JSONWrapper<std::vector<JSON>>( internal.List.get() );
|
||||
} else {
|
||||
return JSONWrapper<std::vector<JSON>>( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
JSONConstWrapper<QuickFlatMap> object_range() const {
|
||||
if( internal.Type == Class::Object ) {
|
||||
return JSONConstWrapper<QuickFlatMap>( internal.Map.get() );
|
||||
} else {
|
||||
return JSONConstWrapper<QuickFlatMap>( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSONConstWrapper<std::vector<JSON>> array_range() const {
|
||||
if( internal.Type == Class::Array ) {
|
||||
return JSONConstWrapper<std::vector<JSON>>( internal.List.get() );
|
||||
} else {
|
||||
return JSONConstWrapper<std::vector<JSON>>( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
std::string dump( long depth = 1, std::string tab = " ") const {
|
||||
switch( internal.Type ) {
|
||||
case Class::Null:
|
||||
return "null";
|
||||
case Class::Object: {
|
||||
std::string pad = "";
|
||||
for( long i = 0; i < depth; ++i, pad += tab ) { }
|
||||
|
||||
std::string s = "{\n";
|
||||
bool skip = true;
|
||||
for( auto &p : *internal.Map ) {
|
||||
if( !skip ) { s += ",\n"; }
|
||||
s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) );
|
||||
skip = false;
|
||||
}
|
||||
s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ;
|
||||
return s;
|
||||
}
|
||||
case Class::Array: {
|
||||
std::string s = "[";
|
||||
bool skip = true;
|
||||
for( auto &p : *internal.List ) {
|
||||
if( !skip ) { s += ", "; }
|
||||
s += p.dump( depth + 1, tab );
|
||||
skip = false;
|
||||
}
|
||||
s += "]";
|
||||
return s;
|
||||
}
|
||||
case Class::String:
|
||||
return "\"" + json_escape( *internal.String ) + "\"";
|
||||
case Class::Floating:
|
||||
return std::to_string( internal.Float );
|
||||
case Class::Integral:
|
||||
return std::to_string( internal.Int );
|
||||
case Class::Boolean:
|
||||
return internal.Bool ? "true" : "false";
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unhandled JSON type");
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static std::string json_escape( const std::string &str ) {
|
||||
std::string output;
|
||||
for(char i : str) {
|
||||
switch( i ) {
|
||||
case '\"': output += "\\\""; break;
|
||||
case '\\': output += "\\\\"; break;
|
||||
case '\b': output += "\\b"; break;
|
||||
case '\f': output += "\\f"; break;
|
||||
case '\n': output += "\\n"; break;
|
||||
case '\r': output += "\\r"; break;
|
||||
case '\t': output += "\\t"; break;
|
||||
default : output += i; break;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
struct JSONParser {
|
||||
static bool isspace(const char c)
|
||||
{
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
// MSVC warns on these line in some circumstances
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 6330)
|
||||
#endif
|
||||
return ::isspace(c) != 0;
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void consume_ws( const std::string &str, size_t &offset ) {
|
||||
while( isspace( str[offset] ) && offset <= str.size() ) { ++offset; }
|
||||
}
|
||||
|
||||
static JSON parse_object( const std::string &str, size_t &offset ) {
|
||||
JSON Object( JSON::Class::Object );
|
||||
|
||||
++offset;
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == '}' ) {
|
||||
++offset; return Object;
|
||||
}
|
||||
|
||||
for (;offset<str.size();) {
|
||||
JSON Key = parse_next( str, offset );
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] != ':' ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str[offset] + "'\n");
|
||||
}
|
||||
consume_ws( str, ++offset );
|
||||
JSON Value = parse_next( str, offset );
|
||||
Object[Key.to_string()] = Value;
|
||||
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == '}' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str[offset] + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
return Object;
|
||||
}
|
||||
|
||||
static JSON parse_array( const std::string &str, size_t &offset ) {
|
||||
JSON Array( JSON::Class::Array );
|
||||
size_t index = 0;
|
||||
|
||||
++offset;
|
||||
consume_ws( str, offset );
|
||||
if( str[offset] == ']' ) {
|
||||
++offset; return Array;
|
||||
}
|
||||
|
||||
for (;offset < str.size();) {
|
||||
Array[index++] = parse_next( str, offset );
|
||||
consume_ws( str, offset );
|
||||
|
||||
if( str[offset] == ',' ) {
|
||||
++offset; continue;
|
||||
}
|
||||
else if( str[offset] == ']' ) {
|
||||
++offset; break;
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str[offset] + "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
return Array;
|
||||
}
|
||||
|
||||
static JSON parse_string( const std::string &str, size_t &offset ) {
|
||||
std::string val;
|
||||
for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) {
|
||||
if( c == '\\' ) {
|
||||
switch( str[ ++offset ] ) {
|
||||
case '\"': val += '\"'; break;
|
||||
case '\\': val += '\\'; break;
|
||||
case '/' : val += '/' ; break;
|
||||
case 'b' : val += '\b'; break;
|
||||
case 'f' : val += '\f'; break;
|
||||
case 'n' : val += '\n'; break;
|
||||
case 'r' : val += '\r'; break;
|
||||
case 't' : val += '\t'; break;
|
||||
case 'u' : {
|
||||
val += "\\u" ;
|
||||
for( size_t i = 1; i <= 4; ++i ) {
|
||||
c = str[offset+i];
|
||||
if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) {
|
||||
val += c;
|
||||
} else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: String: Expected hex character in unicode escape, found '") + c + "'");
|
||||
}
|
||||
}
|
||||
offset += 4;
|
||||
} break;
|
||||
default : val += '\\'; break;
|
||||
}
|
||||
} else {
|
||||
val += c;
|
||||
}
|
||||
}
|
||||
++offset;
|
||||
return JSON(val);
|
||||
}
|
||||
|
||||
static JSON parse_number( const std::string &str, size_t &offset ) {
|
||||
std::string val, exp_str;
|
||||
char c = '\0';
|
||||
bool isDouble = false;
|
||||
bool isNegative = false;
|
||||
long exp = 0;
|
||||
if( offset < str.size() && str[offset] == '-' ) {
|
||||
isNegative = true;
|
||||
++offset;
|
||||
}
|
||||
for (; offset < str.size() ;) {
|
||||
c = str[offset++];
|
||||
if( c >= '0' && c <= '9' ) {
|
||||
val += c;
|
||||
} else if( c == '.' && !isDouble ) {
|
||||
val += c;
|
||||
isDouble = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( offset < str.size() && (c == 'E' || c == 'e' )) {
|
||||
c = str[ offset++ ];
|
||||
if( c == '-' ) {
|
||||
exp_str += '-';
|
||||
} else if( c == '+' ) {
|
||||
// do nothing
|
||||
} else {
|
||||
--offset;
|
||||
}
|
||||
|
||||
for (; offset < str.size() ;) {
|
||||
c = str[ offset++ ];
|
||||
if( c >= '0' && c <= '9' ) {
|
||||
exp_str += c;
|
||||
} else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: Expected a number for exponent, found '") + c + "'");
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
exp = chaiscript::parse_num<long>( exp_str );
|
||||
}
|
||||
else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'");
|
||||
}
|
||||
--offset;
|
||||
|
||||
if( isDouble ) {
|
||||
return JSON((isNegative?-1:1) * chaiscript::parse_num<double>( val ) * std::pow( 10, exp ));
|
||||
} else {
|
||||
if( !exp_str.empty() ) {
|
||||
return JSON((isNegative?-1:1) * static_cast<double>(chaiscript::parse_num<long>( val )) * std::pow( 10, exp ));
|
||||
} else {
|
||||
return JSON((isNegative?-1:1) * chaiscript::parse_num<long>( val ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static JSON parse_bool( const std::string &str, size_t &offset ) {
|
||||
if( str.substr( offset, 4 ) == "true" ) {
|
||||
offset += 4;
|
||||
return JSON(true);
|
||||
} else if( str.substr( offset, 5 ) == "false" ) {
|
||||
offset += 5;
|
||||
return JSON(false);
|
||||
} else {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Bool: Expected 'true' or 'false', found '") + str.substr( offset, 5 ) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
static JSON parse_null( const std::string &str, size_t &offset ) {
|
||||
if( str.substr( offset, 4 ) != "null" ) {
|
||||
throw std::runtime_error(std::string("JSON ERROR: Null: Expected 'null', found '") + str.substr( offset, 4 ) + "'");
|
||||
}
|
||||
offset += 4;
|
||||
return JSON();
|
||||
}
|
||||
|
||||
static JSON parse_next( const std::string &str, size_t &offset ) {
|
||||
char value;
|
||||
consume_ws( str, offset );
|
||||
value = str[offset];
|
||||
switch( value ) {
|
||||
case '[' : return parse_array( str, offset );
|
||||
case '{' : return parse_object( str, offset );
|
||||
case '\"': return parse_string( str, offset );
|
||||
case 't' :
|
||||
case 'f' : return parse_bool( str, offset );
|
||||
case 'n' : return parse_null( str, offset );
|
||||
default : if( ( value <= '9' && value >= '0' ) || value == '-' ) {
|
||||
return parse_number( str, offset );
|
||||
}
|
||||
}
|
||||
throw std::runtime_error(std::string("JSON ERROR: Parse: Unexpected starting character '") + value + "'");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline JSON JSON::Load( const std::string &str ) {
|
||||
size_t offset = 0;
|
||||
return JSONParser::parse_next( str, offset );
|
||||
}
|
||||
|
||||
} // End Namespace json
|
||||
|
||||
|
||||
#endif
|
||||
150
include/chaiscript/utility/json_wrap.hpp
Normal file
150
include/chaiscript/utility/json_wrap.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#ifndef CHAISCRIPT_SIMPLEJSON_WRAP_HPP
|
||||
#define CHAISCRIPT_SIMPLEJSON_WRAP_HPP
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
class json_wrap
|
||||
{
|
||||
public:
|
||||
|
||||
static Module& library(Module& m)
|
||||
{
|
||||
|
||||
m.add(chaiscript::fun([](const std::string &t_str) { return from_json(t_str); }), "from_json");
|
||||
m.add(chaiscript::fun(&json_wrap::to_json), "to_json");
|
||||
|
||||
return m;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static Boxed_Value from_json(const json::JSON &t_json)
|
||||
{
|
||||
switch( t_json.JSONType() ) {
|
||||
case json::JSON::Class::Null:
|
||||
return Boxed_Value();
|
||||
case json::JSON::Class::Object:
|
||||
{
|
||||
std::map<std::string, Boxed_Value> m;
|
||||
|
||||
for (const auto &p : t_json.object_range())
|
||||
{
|
||||
m.insert(std::make_pair(p.first, from_json(p.second)));
|
||||
}
|
||||
|
||||
return Boxed_Value(m);
|
||||
}
|
||||
case json::JSON::Class::Array:
|
||||
{
|
||||
std::vector<Boxed_Value> vec;
|
||||
|
||||
for (const auto &p : t_json.array_range())
|
||||
{
|
||||
vec.emplace_back(from_json(p));
|
||||
}
|
||||
|
||||
return Boxed_Value(vec);
|
||||
}
|
||||
case json::JSON::Class::String:
|
||||
return Boxed_Value(t_json.to_string());
|
||||
case json::JSON::Class::Floating:
|
||||
return Boxed_Value(t_json.to_float());
|
||||
case json::JSON::Class::Integral:
|
||||
return Boxed_Value(t_json.to_int());
|
||||
case json::JSON::Class::Boolean:
|
||||
return Boxed_Value(t_json.to_bool());
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown JSON type");
|
||||
}
|
||||
|
||||
static Boxed_Value from_json(const std::string &t_json)
|
||||
{
|
||||
return from_json( json::JSON::Load(t_json) );
|
||||
}
|
||||
|
||||
static std::string to_json(const Boxed_Value &t_bv)
|
||||
{
|
||||
return to_json_object(t_bv).dump();
|
||||
}
|
||||
|
||||
static json::JSON to_json_object(const Boxed_Value &t_bv)
|
||||
{
|
||||
try {
|
||||
const std::map<std::string, Boxed_Value> m = chaiscript::boxed_cast<const std::map<std::string, Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
for (const auto &o : m)
|
||||
{
|
||||
obj[o.first] = to_json_object(o.second);
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a map
|
||||
}
|
||||
|
||||
try {
|
||||
const std::vector<Boxed_Value> v = chaiscript::boxed_cast<const std::vector<Boxed_Value> &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
{
|
||||
obj[i] = to_json_object(v[i]);
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a vector
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Boxed_Number bn(t_bv);
|
||||
if (Boxed_Number::is_floating_point(t_bv))
|
||||
{
|
||||
return json::JSON(bn.get_as<double>());
|
||||
} else {
|
||||
return json::JSON(bn.get_as<long>());
|
||||
}
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
// not a number
|
||||
}
|
||||
|
||||
try {
|
||||
return json::JSON(boxed_cast<bool>(t_bv));
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a bool
|
||||
}
|
||||
|
||||
try {
|
||||
return json::JSON(boxed_cast<std::string>(t_bv));
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a string
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const chaiscript::dispatch::Dynamic_Object &o = boxed_cast<const dispatch::Dynamic_Object &>(t_bv);
|
||||
|
||||
json::JSON obj;
|
||||
for (const auto &attr : o.get_attrs())
|
||||
{
|
||||
obj[attr.first] = to_json_object(attr.second);
|
||||
}
|
||||
return obj;
|
||||
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||
// not a dynamic object
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unknown object type to convert to JSON");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
37
include/chaiscript/utility/static_string.hpp
Normal file
37
include/chaiscript/utility/static_string.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||
#define CHAISCRIPT_UTILITY_STATIC_STRING_HPP_
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace utility
|
||||
{
|
||||
|
||||
struct Static_String
|
||||
{
|
||||
template<size_t N>
|
||||
constexpr Static_String(const char (&str)[N])
|
||||
: m_size(N-1), data(&str[0])
|
||||
{
|
||||
}
|
||||
|
||||
constexpr size_t size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
constexpr const char *c_str() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
const size_t m_size;
|
||||
const char *data = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,24 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// and Jason Turner (jason@emptycrate.com)
|
||||
// Copyright 2009-2017, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
|
||||
|
||||
#ifndef CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
#define CHAISCRIPT_UTILITY_UTILITY_HPP_
|
||||
|
||||
#include "../chaiscript.hpp"
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../language/chaiscript_common.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
#include "../dispatchkit/operators.hpp"
|
||||
|
||||
|
||||
namespace chaiscript
|
||||
@@ -16,24 +26,95 @@ namespace chaiscript
|
||||
namespace utility
|
||||
{
|
||||
|
||||
/// Single step command for registering a class with ChaiScript
|
||||
///
|
||||
/// \param[in,out] t_module Model to add class to
|
||||
/// \param[in] t_class_name Name of the class being registered
|
||||
/// \param[in] t_constructors Vector of constructors to add
|
||||
/// \param[in] t_funcs Vector of methods to add
|
||||
///
|
||||
/// \example Adding a basic class to ChaiScript in one step
|
||||
///
|
||||
/// \code
|
||||
/// chaiscript::utility::add_class<test>(*m,
|
||||
/// "test",
|
||||
/// { constructor<test ()>(),
|
||||
/// constructor<test (const test &)>() },
|
||||
/// { {fun(&test::function), "function"},
|
||||
/// {fun(&test::function2), "function2"},
|
||||
/// {fun(&test::function3), "function3"},
|
||||
/// {fun(static_cast<std::string(test::*)(double)>(&test::function_overload)), "function_overload" },
|
||||
/// {fun(static_cast<std::string(test::*)(int)>(&test::function_overload)), "function_overload" },
|
||||
/// {fun(static_cast<test & (test::*)(const test &)>(&test::operator=)), "=" }
|
||||
/// }
|
||||
/// );
|
||||
///
|
||||
template<typename Class, typename ModuleType>
|
||||
void add_class(ModuleType &t_module,
|
||||
const std::string &t_classname,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<chaiscript::Proxy_Function> &t_constructors,
|
||||
const std::vector<std::pair<chaiscript::Proxy_Function, std::string>> &t_funcs)
|
||||
{
|
||||
t_module.add(chaiscript::user_type<Class>(), t_classname);
|
||||
t_module.add(chaiscript::user_type<Class>(), t_class_name);
|
||||
|
||||
for(const chaiscript::Proxy_Function &ctor: t_constructors)
|
||||
{
|
||||
t_module.add(ctor, t_classname);
|
||||
t_module.add(ctor, t_class_name);
|
||||
}
|
||||
|
||||
for(auto fun: t_funcs)
|
||||
for(const auto &fun: t_funcs)
|
||||
{
|
||||
t_module.add(fun.first, fun.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Enum, typename ModuleType>
|
||||
typename std::enable_if<std::is_enum<Enum>::value, void>::type
|
||||
add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<std::pair<typename std::underlying_type<Enum>::type, std::string>> &t_constants
|
||||
)
|
||||
{
|
||||
t_module.add(chaiscript::user_type<Enum>(), t_class_name);
|
||||
|
||||
t_module.add(chaiscript::constructor<Enum ()>(), t_class_name);
|
||||
t_module.add(chaiscript::constructor<Enum (const Enum &)>(), t_class_name);
|
||||
|
||||
using namespace chaiscript::bootstrap::operators;
|
||||
equal<Enum>(t_module);
|
||||
not_equal<Enum>(t_module);
|
||||
assign<Enum>(t_module);
|
||||
|
||||
t_module.add(chaiscript::fun([](const Enum &e, const int &i) { return e == i; }), "==");
|
||||
t_module.add(chaiscript::fun([](const int &i, const Enum &e) { return i == e; }), "==");
|
||||
|
||||
for (const auto &constant : t_constants)
|
||||
{
|
||||
t_module.add_global_const(chaiscript::const_var(Enum(constant.first)), constant.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename EnumClass, typename ModuleType>
|
||||
typename std::enable_if<std::is_enum<EnumClass>::value, void>::type
|
||||
add_class(ModuleType &t_module,
|
||||
const std::string &t_class_name,
|
||||
const std::vector<std::pair<EnumClass, std::string>> &t_constants
|
||||
)
|
||||
{
|
||||
t_module.add(chaiscript::user_type<EnumClass>(), t_class_name);
|
||||
|
||||
t_module.add(chaiscript::constructor<EnumClass()>(), t_class_name);
|
||||
t_module.add(chaiscript::constructor<EnumClass(const EnumClass &)>(), t_class_name);
|
||||
|
||||
using namespace chaiscript::bootstrap::operators;
|
||||
equal<EnumClass>(t_module);
|
||||
not_equal<EnumClass>(t_module);
|
||||
assign<EnumClass>(t_module);
|
||||
|
||||
for (const auto &constant : t_constants)
|
||||
{
|
||||
t_module.add_global_const(chaiscript::const_var(EnumClass(constant.first)), constant.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
Copyright 2009-2012 Jason Turner and Jonathan Turner. All Rights Reserved.
|
||||
Copyright 2009-2016 Jason Turner
|
||||
Copyright 2009-2012 Jonathan Turner.
|
||||
|
||||
All Rights Reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
19
performance_tests/heterogenous_array_loop.chai
Normal file
19
performance_tests/heterogenous_array_loop.chai
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
def go()
|
||||
{
|
||||
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
|
||||
|
||||
var q = 0;
|
||||
|
||||
for (var j = 0; j < 10000; ++j)
|
||||
{
|
||||
for (var i = 0; i < 6; ++i)
|
||||
{
|
||||
to_string(my_array[i]);
|
||||
}
|
||||
|
||||
q += j;
|
||||
}
|
||||
}
|
||||
|
||||
go();
|
||||
@@ -1,6 +1,6 @@
|
||||
def isprime(n)
|
||||
{
|
||||
for (auto i = 2; i < n; ++i)
|
||||
for (var i = 2; i < n; ++i)
|
||||
{
|
||||
if (n % i == 0) {return false}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ def isprime(n)
|
||||
|
||||
def primes(n)
|
||||
{
|
||||
auto count = 0
|
||||
for (auto i = 2; i <= n; ++i)
|
||||
var count = 0
|
||||
for (var i = 2; i <= n; ++i)
|
||||
{
|
||||
if (isprime(i)) {++count}
|
||||
}
|
||||
@@ -21,6 +21,6 @@ def primes(n)
|
||||
}
|
||||
|
||||
|
||||
auto N = 5000
|
||||
var N = 5000
|
||||
|
||||
print("primes: " + primes(N).to_string())
|
||||
26
performance_tests/profile_cpp_calls.chai
Normal file
26
performance_tests/profile_cpp_calls.chai
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
var test_str = "bob was a string";
|
||||
|
||||
for( var i = 0; i < 200000; ++i)
|
||||
{
|
||||
test_str.size();
|
||||
// test_str.find("a", i);
|
||||
test_str.c_str();
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
test_str.erase_at(1);
|
||||
|
||||
size(test_str);
|
||||
// test_str.find("a", i);
|
||||
c_str(test_str);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
erase_at(test_str, 1);
|
||||
test_str = "bob was a string";
|
||||
}
|
||||
20
performance_tests/profile_cpp_calls_2.cpp
Normal file
20
performance_tests/profile_cpp_calls_2.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
double f(const std::string &, double, bool) noexcept {
|
||||
return .0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
|
||||
chai.add(chaiscript::fun(&f), "f");
|
||||
|
||||
chai.eval(R"(
|
||||
for (var i = 0; i < 100000; ++i) {
|
||||
f("str", 1.2, false);
|
||||
}
|
||||
)");
|
||||
|
||||
}
|
||||
20
performance_tests/profile_fun_wrappers.cpp
Normal file
20
performance_tests/profile_fun_wrappers.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
double f(const std::string &, double, bool) noexcept {
|
||||
return .0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
|
||||
chai.add(chaiscript::fun(&f), "f");
|
||||
|
||||
const auto f = chai.eval<std::function<void ()>>(R"(fun(){ f("str", 1.2, false); })");
|
||||
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
f();
|
||||
}
|
||||
|
||||
}
|
||||
22
performance_tests/type_conversions.chai
Normal file
22
performance_tests/type_conversions.chai
Normal file
@@ -0,0 +1,22 @@
|
||||
load_module("test_module")
|
||||
|
||||
auto t := TestBaseType();
|
||||
|
||||
// This uses the TestBaseType to Type2 user type
|
||||
// conversion which was added in the module and then calls
|
||||
// "get_val()" which exists on the Type2 type
|
||||
//assert_equal(t.get_val(), 10);
|
||||
//print("Made it past test 1");
|
||||
|
||||
var t2 := Type2(t);
|
||||
|
||||
//dump_system();
|
||||
|
||||
for (var i = 0; i < 50000; ++i) {
|
||||
var str = string(get_str(t2));
|
||||
size(get_str(t2));
|
||||
t2.get_str().size();
|
||||
t.get_str().size();
|
||||
}
|
||||
|
||||
|
||||
80
readme.md
80
readme.md
@@ -1,8 +1,23 @@
|
||||
<a href="https://www.patreon.com/bePatron?u=2977989&redirect_uri=https%3A%2F%2Fwww.patreon.com%2Flefticus">
|
||||
<img height="40" width="204" src="https://s3-us-west-1.amazonaws.com/widget-images/become-patron-widget-medium%402x.png">
|
||||
</a>
|
||||
|
||||
|
||||
Master Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://ci.appveyor.com/project/lefticus/chaiscript) [](http://codecov.io/github/ChaiScript/ChaiScript?branch=master)
|
||||
|
||||
Develop Status: [](https://travis-ci.org/ChaiScript/ChaiScript) [](https://ci.appveyor.com/project/lefticus/chaiscript/branch/develop) [](http://codecov.io/github/ChaiScript/ChaiScript?branch=develop)
|
||||
|
||||
<a href="https://scan.coverity.com/projects/5297">
|
||||
<img alt="Coverity Scan Build Status"
|
||||
src="https://img.shields.io/coverity/scan/5297.svg"/>
|
||||
</a>
|
||||
|
||||
ChaiScript
|
||||
|
||||
http://www.chaiscript.com
|
||||
|
||||
(c) 2009-2012 Jason Turner and Jonathan Turner
|
||||
(c) 2009-2012 Jonathan Turner
|
||||
(c) 2009-2017 Jason Turner
|
||||
|
||||
Release under the BSD license, see "license.txt" for details.
|
||||
|
||||
@@ -10,6 +25,8 @@ Release under the BSD license, see "license.txt" for details.
|
||||
Introduction
|
||||
============
|
||||
|
||||
[](https://gitter.im/ChaiScript/ChaiScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
ChaiScript is one of the only embedded scripting language designed from the
|
||||
ground up to directly target C++ and take advantage of modern C++ development
|
||||
techniques, working with the developer like he expects it to work. Being a
|
||||
@@ -26,10 +43,10 @@ languages:
|
||||
Requirements
|
||||
============
|
||||
|
||||
ChaiScript requires a C++11 compiler to build with support for variadic
|
||||
templates. It has been tested with gcc 4.7 and clang 3.1 (with libcxx). MacOS
|
||||
10.8 (Mountain Lion) is also known to support the C++11 build with Apple's
|
||||
clang 4.0.
|
||||
ChaiScript requires a C++14 compiler to build with support for variadic
|
||||
templates. It has been tested with gcc 4.9 and clang 3.6 (with libcxx).
|
||||
For more information see the build
|
||||
[dashboard](http://chaiscript.com/ChaiScript-BuildResults/index.html).
|
||||
|
||||
Usage
|
||||
=====
|
||||
@@ -62,7 +79,7 @@ directory, and for more in-depth look at the language, the unit tests in the
|
||||
"unittests" directory cover the most ground.
|
||||
|
||||
For examples of how to register parts of your C++ application, see
|
||||
"example.cpp" in the "src" directory. Example.cpp is verbose and shows every
|
||||
"example.cpp" in the "samples" directory. Example.cpp is verbose and shows every
|
||||
possible way of working with the library. For further documentation generate
|
||||
the doxygen documentation in the build folder or see the website
|
||||
http://www.chaiscript.com.
|
||||
@@ -70,44 +87,21 @@ http://www.chaiscript.com.
|
||||
|
||||
The shortest complete example possible follows:
|
||||
|
||||
/// main.cpp
|
||||
```C++
|
||||
/// main.cpp
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
double function(int i, double j)
|
||||
{
|
||||
return i * j;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&function), "function");
|
||||
|
||||
double d = chai.eval<double>("function(3, 4.75);");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Or, if you want to compile the std lib into your code, which reduces
|
||||
runtime requirements.
|
||||
|
||||
/// main.cpp
|
||||
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
#include <chaiscript/chaiscript_stdlib.hpp>
|
||||
|
||||
double function(int i, double j)
|
||||
{
|
||||
return i * j;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library());
|
||||
chai.add(chaiscript::fun(&function), "function");
|
||||
|
||||
double d = chai.eval<double>("function(3, 4.75);");
|
||||
}
|
||||
double function(int i, double j)
|
||||
{
|
||||
return i * j;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
chai.add(chaiscript::fun(&function), "function");
|
||||
|
||||
double d = chai.eval<double>("function(3, 4.75);");
|
||||
}
|
||||
```
|
||||
|
||||
299
releasenotes.md
Normal file
299
releasenotes.md
Normal file
@@ -0,0 +1,299 @@
|
||||
Notes:
|
||||
=======
|
||||
Current Version: 6.0.0
|
||||
|
||||
### Changes since 5.8.6
|
||||
|
||||
*6.0.0 is a massive rework compared to 5.x. It now requires a C++14 enabled compiler*
|
||||
|
||||
#### Compiler Requirements
|
||||
|
||||
* MSVC 2015 or greater
|
||||
* g++ 4.9 or greater
|
||||
* clang 3.6 or greater
|
||||
|
||||
#### Breaking Changes
|
||||
|
||||
* Instantiating a ChaiScript object now, by default, builds the stdlib in
|
||||
* This was done to address the most common support issues of loading stdlib dynamically at runtime
|
||||
* If you want the old behavior, use include/chaiscript/chaiscript_basic.hpp
|
||||
* Headers have been reorganized to fully separate stdlib/parser/engine from each other (some faster builds)
|
||||
* Bootstrap functions no longer return a reference to the module added to (compile time savings)
|
||||
* It's now no longer possible modify AST_Nodes (compile time, runtime efficiency)
|
||||
* Function annotations no longer exist (simplifies code, reduces compile time, compile size)
|
||||
|
||||
#### New Features Added
|
||||
|
||||
* Modular optimization system; this can be accessed via the ChaiScript_Basic interface
|
||||
* Execution tracing capability; also accessed via ChaiScript_Basic interface
|
||||
* range-based for loops `for( id : container ) { }` (much better performance than other loop types)
|
||||
* If-init expressions (ala C++17)
|
||||
* Support for passing r-value references to functions
|
||||
* Support for containing unique_ptr
|
||||
* Add helpers for exposing enum classes to ChaiScript
|
||||
* Allow typed ChaiScript defined functions to perform conversions on call #303
|
||||
|
||||
#### Improvements
|
||||
|
||||
* Compile time improvements
|
||||
* Compile size improvements
|
||||
* Significant runtime improvements (see "Modular optimization system")
|
||||
* Significant parser improvements, both with parse-time and parser initialization time (Thanks @niXman)
|
||||
* Fix type conversion to bool in conditionals
|
||||
|
||||
#### Improvements Still Need To Be Made
|
||||
|
||||
* File location tracking has been rewritten; this currently means error location reporting is not as good as it was
|
||||
* Tracing capability needs to be tested and vetted
|
||||
|
||||
### Changes since 5.8.5
|
||||
* Optimize away `return` statements in lambdas also
|
||||
* Allow conversions to bool in conditionals
|
||||
* Don't allow `class` statements inside of scopes
|
||||
* Properly error when a dynamic object non-function member is called
|
||||
|
||||
### Changes since 5.8.4
|
||||
* Fix order of operations for prefix operators
|
||||
* Make sure atomics are initialized properly
|
||||
* Remove parsing of unused prefix `&` operator
|
||||
|
||||
### Changes since 5.8.3
|
||||
* Fix case with some numeric conversions mixed with numerics that do not need conversion
|
||||
|
||||
### Changes since 5.8.2
|
||||
* Add support for reference of pointer return types
|
||||
|
||||
### Changes since 5.8.1
|
||||
* Allow casting to non-const & std::shared_ptr<T>
|
||||
|
||||
|
||||
### Changes since 5.8.0
|
||||
* Fix parsing of floats to be locale independent #250
|
||||
* Various warning fixes on various platforms
|
||||
|
||||
|
||||
### Changes since 5.7.1
|
||||
* Make all parser iterator operations range checked
|
||||
* Parse in-string eval statements once, not once for each execution
|
||||
* Fix parsing of operators (ie 1<-1 now parses)
|
||||
* Fix variable scoping for functors
|
||||
* Exception reduction
|
||||
* Various object lifetime fixes
|
||||
* Add JSON support for load / save #207
|
||||
* Numeric overload resolution fixes #209
|
||||
* Fix long long #208
|
||||
* Add octal escapes in strings #211
|
||||
* Fixed sizing of binary literals #213
|
||||
* Added support for != with bool values #217
|
||||
* Various value assignment vector fixes
|
||||
* Fixed broken hex escape sequences from @ChristianKaeser
|
||||
* Multiply defined symbols fixes #232 @RaptorFactor
|
||||
* Add add_class<Enum> helper #233 @vrennert
|
||||
* Cheatsheet fixes #235 @mlamby
|
||||
* Fix parsing of strings inside of in-string eval statements
|
||||
* Allow lower-case global keyword
|
||||
* Enable thread-local on MSVC (should be significant performance boost)
|
||||
|
||||
|
||||
### Changes since 5.7.0
|
||||
* Build time reduction
|
||||
* Build size reduction
|
||||
* Performance increases
|
||||
* Fixed ~20 crash-bugs found with fuzzy testing #194
|
||||
* Let unhandled exceptions propogate to user
|
||||
* Report eval_error when break statement is not in loop
|
||||
* Fix handling of 0 length scripts closes #193
|
||||
* Don't crash on arity mismatch - Specifically affects the case where no overloads exist for a given function
|
||||
* Fix error printing for `bind` calls
|
||||
* Handle unexpected continue statement
|
||||
* Check arity during bind
|
||||
* Don't allow arith conversion on variadic function
|
||||
* Correct `bind` parameter match count
|
||||
* Add in expected Boxed_Value exception cases
|
||||
* Check access to AST, don't allow `;` in func def
|
||||
* Don't attempt arithmetic unary & call
|
||||
* Don't crash on 0 param call to `bind`
|
||||
* Catch errors during member function dispatch
|
||||
* Properly handle type of const bool &
|
||||
* Automatic deduction of lambda type signatures
|
||||
* Work with non-polymorphic parent/child conversions
|
||||
* Move to codecov for coverage reporting
|
||||
* Add `.at` method for Map objects
|
||||
* Various corrections for support of move-only objects
|
||||
|
||||
|
||||
### Changes since 5.6.0
|
||||
|
||||
* Significant code cleanups and reduction
|
||||
* Smaller builds
|
||||
* Faster compiles
|
||||
* Less runtime memory usage
|
||||
* ~2x faster runtimes
|
||||
* biicode support
|
||||
* method_missing feature added #164 @arBmind
|
||||
* Generic objects with dynamic properties support
|
||||
* Add ability to call functions contained in properties
|
||||
* Add lambda captures
|
||||
* Create [cheatsheet.md](cheatsheet.md) for all-in-one reference of features
|
||||
* Fix support for libc++
|
||||
* Eliminate clone of return value stored locally
|
||||
* Eliminate 'return' statements when last line of function
|
||||
* Reduce number of runtime exceptions occuring
|
||||
* Reduce copies / moves of return values.
|
||||
* make `use` statement return value of last statement in file
|
||||
* Add ability to access fixed array sizes
|
||||
* Add support for scientific notation floating point literals #174 @totalgee
|
||||
|
||||
|
||||
### Changes since 5.5.1
|
||||
* Throw exception on integer divide by 0
|
||||
* Add optional type specification to function declarations
|
||||
|
||||
```
|
||||
def func(int i, j, double k) {
|
||||
// i must be an int.
|
||||
// j can be anything
|
||||
// k must be a double
|
||||
// normal conversion rules still apply
|
||||
}
|
||||
```
|
||||
* Many minor fixes for compiler warnings
|
||||
* Add support for `std::future` and `std::async`
|
||||
```
|
||||
var f := async(someFunction);
|
||||
var f2 := async(someFunction2);
|
||||
|
||||
// someFunction and someFunction2 are running in parallel now
|
||||
f.get();
|
||||
f2.get();
|
||||
```
|
||||
* Fully support r-value returns, supporting move-only objects and reducing object copies
|
||||
|
||||
|
||||
### Changes since 5.5.0
|
||||
* 30% performance increase
|
||||
* Fix handling of object stack, resulting in greatly reduced memory usage
|
||||
* Code cleanups
|
||||
|
||||
### Changes since 5.4.0
|
||||
* 2x performance increase
|
||||
* Significant code cleanups
|
||||
* Throw exception if user attempts to call function on null object
|
||||
* Allow user defined type conversions
|
||||
* Fix object lifetime for nested function calls made at the global scope
|
||||
* Fix returning of boolean values from function calls
|
||||
|
||||
|
||||
### Changes since 5.3.1
|
||||
* Decreased compile time and build size
|
||||
* Make "reflection" module built in (losing some of the time / build size gains)
|
||||
* Add new "class" syntax for ChaiScript defined methods and attributes see: [unittests/class.chai](unittests/class.chai) for examples
|
||||
* Minor performance enhancements
|
||||
* major to_string performance enhancements
|
||||
* Provide API for retrieving registered type name #124
|
||||
* Added strong reference to container to range object #132
|
||||
|
||||
|
||||
### Changes since 5.3.0
|
||||
* Add automatic conversion of arithmetic return types, following the same
|
||||
rules as conversion of arithmetic types when passing parameters
|
||||
* Add automatic casting up the inheritence hierarchy when possible.
|
||||
* Enable travis.ci testing
|
||||
* Allow users to add globals from within script
|
||||
* Various static analysis fixes
|
||||
* Code modernization to C++11
|
||||
* Unofficial support for Haiku added
|
||||
* Fix #121 - Inability to compile on cygwin
|
||||
* Formatting fixes and spelling corrections
|
||||
* Apply "include what you use" https://code.google.com/p/include-what-you-use/
|
||||
* Apply clang-modernize
|
||||
* Various threading fixes
|
||||
* Performance improvements
|
||||
|
||||
### Changes since 5.2.0
|
||||
* Official support for MSVC with C++11. All major platforms and compilers are now support for C++11 release
|
||||
|
||||
### Changes since 4.2.0
|
||||
* Enhanced unit tests
|
||||
* Add `continue` statement, fix various use cases for `for` loops
|
||||
* Fix use of suffixed numbers in vector initialization
|
||||
* Code cleanups
|
||||
* Eliminate global data, which makes code more portable and thread safe
|
||||
* Fix issue #79
|
||||
* Merge pretty_print fixes from @mgee #82
|
||||
* Compiler warning fixes for latest compiler releases
|
||||
* Fix threading problems
|
||||
* Fix linking error on MacOS Mavericks #88
|
||||
* Allow non-const globals
|
||||
* Make sure user cannot name a variable with `::` in it #91
|
||||
* Fix various string / map / vector `size` and `count` calls for compilers which have weird overloads for them. #90 #93 #95
|
||||
* Make module search path relative to the currently running executable
|
||||
* Build and work with wstring windows builds
|
||||
* fix for some new line cases in the middle of a vector initialization from jespada
|
||||
|
||||
### Changes since 5.1.0
|
||||
* Add support for automatic conversion of arithmetic types when possible
|
||||
and when no ambiguous method dispatch exists.
|
||||
|
||||
### Changes since 5.0.0
|
||||
* Fix sizing of numeric constants to match that of the C++ standard
|
||||
* Add support for u,ll,l,f suffixes for numeric constants
|
||||
* Siginificant improvement in error reporting
|
||||
|
||||
### Changes since 4.0.0
|
||||
* Dropped boost in favor of C++11
|
||||
* Separated out stdlib to make more options for compile time improvements
|
||||
|
||||
### Changes since 3.1.0
|
||||
* svenstaro: Unused variables and CMake consistency fixes
|
||||
* Added support for returning pointers from functions (#13)
|
||||
* Compile with -pedantic (#9)
|
||||
* Fix issues with multiple ChaiScript object types having the same attribute name (#15)
|
||||
* Prevent variable redeclaration in same scope (#22)
|
||||
* mgee: Boxed_Number improvements (#27)
|
||||
* Support switch statements (#34)
|
||||
* Fix uint16 comparions (#26)
|
||||
* Add ability to add const_var globals in Module objects (#14)
|
||||
* Add support for ternary operators ?:
|
||||
* Add headers to CMakeLists so they show up in IDEs
|
||||
* Add ability to get vector of defined objects and vector of defined functions
|
||||
* Fix memory leak in cyclical references
|
||||
* Clean up static analysis issues discovered
|
||||
* Fix vector construction to be consistent with map construction
|
||||
* Increased unit tests to 161
|
||||
* Performance enhancements
|
||||
|
||||
### Changes since 3.0.0
|
||||
* Numeric operations performance increased approximately 10x
|
||||
* Looping operations performance increased up to 2x
|
||||
* Engine start up time decreased
|
||||
* Several parsing bugs related to index operators fixed
|
||||
* Added full support for all C algebraic types: double, long double, float, int, long, char,
|
||||
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
|
||||
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
|
||||
|
||||
### Changes since 2.3.3
|
||||
* Code simplifications
|
||||
* Fully integrate documentation with source code in doxygen style comments
|
||||
* Unit tests increased from 114 to 137
|
||||
* Automatic conversion between boost::function objects and ChaiScript functions
|
||||
* Many bug fixes
|
||||
* Minor performance improvements
|
||||
* Namespace reorganization to make end user code more accessible
|
||||
* clang support
|
||||
* VisualStudio 2010 Support
|
||||
* Support for C++ base classes and automatic upcasting
|
||||
* Remove __ reserved identifiers
|
||||
* Better code organization to reduce #ifdefs
|
||||
* clanmills: command line options for chai eval
|
||||
* clanmills: parser cleanups and code reduction
|
||||
* Function introspection and reflection
|
||||
* Correct function dispatch order to account for base classes and provide a defined order of dispatch
|
||||
* Predictable object lifetime that emulates C++ stack lifetime
|
||||
* emarcotte: pkgconfig support
|
||||
* standardize on method/member naming and indentation
|
||||
* 64bit Visual Studio support
|
||||
* Better support for const objects
|
||||
* Drastic reduction of runtime exceptions - making debug builds orders of magnitude faster
|
||||
* Support for platforms with no loadable module support
|
||||
* Add helper macro for registering class
|
||||
@@ -1,67 +0,0 @@
|
||||
Changes since 5.1.0
|
||||
* Add support for automatic conversion of arithmetic types when possible
|
||||
and when no ambiguous method dispatch exists.
|
||||
|
||||
Changes since 5.0.0
|
||||
* Fix sizing of numeric constants to match that of the C++ standard
|
||||
* Add support for u,ll,l,f suffixes for numeric constants
|
||||
* Siginificant improvement in error reporting
|
||||
|
||||
Changes since 4.0.0
|
||||
* Dropped boost in favor of C++11
|
||||
* Separated out stdlib to make more options for compile time improvements
|
||||
|
||||
Changes since 3.1.0
|
||||
* svenstaro: Unused variables and CMake consistency fixes
|
||||
* Added support for returning pointers from functions (#13)
|
||||
* Compile with -pedantic (#9)
|
||||
* Fix issues with multiple ChaiScript object types having the same attribute name (#15)
|
||||
* Prevent variable redeclaration in same scope (#22)
|
||||
* mgee: Boxed_Number improvements (#27)
|
||||
* Support switch statements (#34)
|
||||
* Fix uint16 comparions (#26)
|
||||
* Add ability to add const_var globals in Module objects (#14)
|
||||
* Add support for ternary operators ?:
|
||||
* Add headers to CMakeLists so they show up in IDEs
|
||||
* Add ability to get vector of defined objects and vector of defined functions
|
||||
* Fix memory leak in cyclical references
|
||||
* Clean up static analysis issues discovered
|
||||
* Fix vector construction to be consistent with map construction
|
||||
* Increased unit tests to 161
|
||||
* Performance enhancements
|
||||
|
||||
Changes since 3.0.0
|
||||
* Numeric operations performance increased approximately 10x
|
||||
* Looping operations performance increased up to 2x
|
||||
* Engine start up time decreased
|
||||
* Several parsing bugs related to index operators fixed
|
||||
* Added full support for all C algebraic types: double, long double, float, int, long, char,
|
||||
uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t
|
||||
* Enhanced support for capturing of exceptions thrown from ChaiScript in C++
|
||||
|
||||
Changes since 2.3.3
|
||||
|
||||
* Code simplifications
|
||||
* Fully integrate documentation with source code in doxygen style comments
|
||||
* Unit tests increased from 114 to 137
|
||||
* Automatic conversion between boost::function objects and ChaiScript functions
|
||||
* Many bug fixes
|
||||
* Minor performance improvements
|
||||
* Namespace reorganization to make end user code more accessible
|
||||
* clang support
|
||||
* VisualStudio 2010 Support
|
||||
* Support for C++ base classes and automatic upcasting
|
||||
* Remove __ reserved identifiers
|
||||
* Better code organization to reduce #ifdefs
|
||||
* clanmills: command line options for chai eval
|
||||
* clanmills: parser cleanups and code reduction
|
||||
* Function introspection and reflection
|
||||
* Correct function dispatch order to account for base classes and provide a defined order of dispatch
|
||||
* Predictable object lifetime that emulates C++ stack lifetime
|
||||
* emarcotte: pkgconfig support
|
||||
* standardize on method/member naming and indentation
|
||||
* 64bit Visual Studio support
|
||||
* Better support for const objects
|
||||
* Drastic reduction of runtime exceptions - making debug builds orders of magnitude faster
|
||||
* Support for platforms with no loadable module support
|
||||
* Add helper macro for registering class
|
||||
@@ -13,12 +13,12 @@
|
||||
|
||||
void log(const std::string &msg)
|
||||
{
|
||||
std::cout << "[" << time(nullptr) << "] " << msg << std::endl;
|
||||
std::cout << "[" << time(nullptr) << "] " << msg << '\n';
|
||||
}
|
||||
|
||||
void log(const std::string &module, const std::string &msg)
|
||||
{
|
||||
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << std::endl;
|
||||
std::cout << "[" << time(nullptr) << "] <" << module << "> " << msg << '\n';
|
||||
}
|
||||
|
||||
void bound_log(const std::string &msg)
|
||||
@@ -28,12 +28,12 @@ void bound_log(const std::string &msg)
|
||||
|
||||
void hello_world(const chaiscript::Boxed_Value & /*o*/)
|
||||
{
|
||||
std::cout << "Hello World" << std::endl;
|
||||
std::cout << "Hello World\n";
|
||||
}
|
||||
|
||||
void hello_constructor(const chaiscript::Boxed_Value & /*o*/)
|
||||
{
|
||||
std::cout << "Hello Constructor" << std::endl;
|
||||
std::cout << "Hello Constructor\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ struct System
|
||||
std::map<std::string, std::function<std::string (const std::string &) > > m_callbacks;
|
||||
|
||||
void add_callback(const std::string &t_name,
|
||||
const chaiscript::Proxy_Function &t_func)
|
||||
const std::function<std::string (const std::string &)> &t_func)
|
||||
{
|
||||
m_callbacks[t_name] = chaiscript::dispatch::functor<std::string (const std::string &)>(t_func);
|
||||
m_callbacks[t_name] = t_func;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,20 +62,21 @@ struct System
|
||||
|
||||
void take_shared_ptr(const std::shared_ptr<const std::string> &p)
|
||||
{
|
||||
std::cout << *p << std::endl;
|
||||
std::cout << *p << '\n';
|
||||
}
|
||||
|
||||
int main(int /*argc*/, char * /*argv*/[]) {
|
||||
using namespace chaiscript;
|
||||
|
||||
ChaiScript chai;
|
||||
|
||||
|
||||
//Create a new system object and share it with the chaiscript engine
|
||||
System system;
|
||||
chai.add(var(&system), "system");
|
||||
chai.add_global(var(&system), "system");
|
||||
|
||||
//Add a bound callback method
|
||||
chai.add(fun(&System::add_callback, system), "add_callback_bound");
|
||||
chai.add(fun(&System::add_callback, std::ref(system)), "add_callback_bound");
|
||||
|
||||
//Register the two methods of the System structure.
|
||||
chai.add(fun(&System::add_callback), "add_callback");
|
||||
@@ -107,9 +108,9 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
// A shortcut to using eval is just to use the chai operator()
|
||||
chai("log(\"Test Module\", \"Test Message\");");
|
||||
|
||||
//Finally, it is possible to register any std::function as a system function, in this
|
||||
//Finally, it is possible to register a lambda as a system function, in this
|
||||
//way, we can, for instance add a bound member function to the system
|
||||
chai.add(fun(&System::do_callbacks, std::ref(system), std::string("Bound Test")), "do_callbacks");
|
||||
chai.add(fun([&system](){ return system.do_callbacks("Bound Test"); }), "do_callbacks");
|
||||
|
||||
//Call bound version of do_callbacks
|
||||
chai("do_callbacks()");
|
||||
@@ -122,7 +123,7 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
//the templated version of eval:
|
||||
int i = chai.eval<int>("5+5");
|
||||
|
||||
std::cout << "5+5: " << i << std::endl;
|
||||
std::cout << "5+5: " << i << '\n';
|
||||
|
||||
//Add a new variable
|
||||
chai("var scripti = 15");
|
||||
@@ -130,14 +131,14 @@ int main(int /*argc*/, char * /*argv*/[]) {
|
||||
//We can even get a handle to the variables in the system
|
||||
int &scripti = chai.eval<int &>("scripti");
|
||||
|
||||
std::cout << "scripti: " << scripti << std::endl;
|
||||
std::cout << "scripti: " << scripti << '\n';
|
||||
scripti *= 2;
|
||||
std::cout << "scripti (updated): " << scripti << std::endl;
|
||||
std::cout << "scripti (updated): " << scripti << '\n';
|
||||
chai("print(\"Scripti from chai: \" + to_string(scripti))");
|
||||
|
||||
//To do: Add examples of handling Boxed_Values directly when needed
|
||||
|
||||
//Creating a functor on the stack and using it immediatly
|
||||
//Creating a functor on the stack and using it immediately
|
||||
int x = chai.eval<std::function<int (int, int)> >("fun (x, y) { return x + y; }")(5, 6);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
102
samples/factory.cpp
Normal file
102
samples/factory.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <chaiscript/chaiscript.hpp>
|
||||
|
||||
class Entity
|
||||
{
|
||||
public:
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
int y;
|
||||
std::string name;
|
||||
|
||||
std::function<void (Entity &)> updater;
|
||||
|
||||
Entity(const int t_width, const int t_height, const int t_x, const int t_y, std::string t_name)
|
||||
: width(t_width), height(t_height), x(t_x), y(t_y), name(std::move(t_name))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Factory
|
||||
{
|
||||
public:
|
||||
// we may as well pass the parameters for the entity to the factory method, this does the initialization
|
||||
// in one step.
|
||||
Entity *make_entity(const int width, const int height, const int x, const int y, const std::string &name)
|
||||
{
|
||||
auto entity = entities.insert({name, Entity{width, height, x, y, name}});
|
||||
return &(entity.first->second);
|
||||
}
|
||||
|
||||
Entity *get_entity(const std::string &name)
|
||||
{
|
||||
return &entities.at(name);
|
||||
}
|
||||
|
||||
|
||||
// loop over all entities and all their updater function (if it exists)
|
||||
void update_entities()
|
||||
{
|
||||
for (auto &entity : entities)
|
||||
{
|
||||
if (entity.second.updater) {
|
||||
entity.second.updater(entity.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// we cannot store the entities in a std::vector if we want to return a pointer to them,
|
||||
// because a vector automatically resizing itself can invalidate the pointer that was returned.
|
||||
// using a map guarantees that the memory assigned to the entity will never change, plus
|
||||
// lets us easily look up an entity by name
|
||||
std::map<std::string, Entity> entities;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
chaiscript::ChaiScript chai;
|
||||
|
||||
chai.add(chaiscript::fun(&Entity::width), "width");
|
||||
chai.add(chaiscript::fun(&Entity::height), "height");
|
||||
chai.add(chaiscript::fun(&Entity::x), "x");
|
||||
chai.add(chaiscript::fun(&Entity::y), "y");
|
||||
chai.add(chaiscript::fun(&Entity::name), "name");
|
||||
chai.add(chaiscript::fun(&Entity::updater), "updater");
|
||||
chai.add(chaiscript::user_type<Entity>(), "Entity"); // this isn't strictly necessary but makes error messages nicer
|
||||
|
||||
chai.add(chaiscript::fun(&Factory::make_entity), "make_entity");
|
||||
chai.add(chaiscript::fun(&Factory::get_entity), "get_entity");
|
||||
chai.add(chaiscript::fun(&Factory::update_entities), "update_entities");
|
||||
chai.add(chaiscript::user_type<Factory>(), "Factory"); // this isn't strictly necessary but makes error messages nicer
|
||||
|
||||
|
||||
Factory f;
|
||||
chai.add(chaiscript::var(&f), "f");
|
||||
|
||||
std::string script = R""(
|
||||
f.make_entity(10,10,1,1,"entity1").updater = fun(e){ e.x += 1; e.y += 1 };
|
||||
f.make_entity(10,10,10,10,"entity2").updater = fun(e){ e.x += 2; e.y += 2 };
|
||||
f.make_entity(10,10,20,20,"entity3");
|
||||
|
||||
print(f.get_entity("entity1").x == 1)
|
||||
print(f.get_entity("entity2").x == 10)
|
||||
print(f.get_entity("entity3").x == 20)
|
||||
|
||||
f.update_entities(); // this runs the function objects we set in the previous lines
|
||||
// we should now see the updated values
|
||||
|
||||
print(f.get_entity("entity1").x == 2)
|
||||
print(f.get_entity("entity2").x == 12)
|
||||
print(f.get_entity("entity3").x == 20) // this one has no updater, so it stays the same
|
||||
)"";
|
||||
|
||||
|
||||
chai.eval(script);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
print(i)
|
||||
print(i)
|
||||
}
|
||||
|
||||
for (var i = 10; i >= 0; i -= 2) {
|
||||
print(i)
|
||||
print(i)
|
||||
}
|
||||
|
||||
var i = 0
|
||||
|
||||
for (; i < 5; ++i) {
|
||||
print(i)
|
||||
print(i)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user