mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2025-12-06 16:57:04 +08:00
Compare commits
1381 Commits
Release-5.
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2eb3279c39 | ||
|
|
2951ce4a7a | ||
|
|
f904cd5447 | ||
|
|
b44b987d4b | ||
|
|
43dc35c3df | ||
|
|
681104b68f | ||
|
|
406a7ba1ef | ||
|
|
8d82f237bf | ||
|
|
dbd2050eb2 | ||
|
|
866ef314a8 | ||
|
|
bf9f5ae2e1 | ||
|
|
0870cb5a3a | ||
|
|
3e548184c0 | ||
|
|
41da3db06a | ||
|
|
2898ae679f | ||
|
|
6ccab2af6a | ||
|
|
7cd229cf26 | ||
|
|
6411aa7498 | ||
|
|
5722a5177d | ||
|
|
3703a78813 | ||
|
|
53fe932be4 | ||
|
|
651abc2f5b | ||
|
|
b3ed4466f3 | ||
|
|
855c3ced88 | ||
|
|
323cd7a8d4 | ||
|
|
535d80e8d2 | ||
|
|
efeb244cd9 | ||
|
|
a1a78e9cf1 | ||
|
|
0f37802aba | ||
|
|
c258670350 | ||
|
|
69123db3dc | ||
|
|
439c1a96d3 | ||
|
|
3aa1fa8278 | ||
|
|
ef5a22b2b5 | ||
|
|
6030ea63bd | ||
|
|
9c118c2b1e | ||
|
|
cff6a0aced | ||
|
|
6491b80496 | ||
|
|
a4fd5371bd | ||
|
|
55ec76fd39 | ||
|
|
82ef037912 | ||
|
|
4ec767bdc9 | ||
|
|
7aea27412d | ||
|
|
8ee033cf89 | ||
|
|
59f64d8d82 | ||
|
|
39f7aa0900 | ||
|
|
32723fcbc0 | ||
|
|
14e9ec6e97 | ||
|
|
532f044bd3 | ||
|
|
b5d81613cf | ||
|
|
2c92e83afa | ||
|
|
c580726020 | ||
|
|
816cb5e8e2 | ||
|
|
b3ee667ca5 | ||
|
|
1302e28e32 | ||
|
|
cf7821cb1e | ||
|
|
5ff3679811 | ||
|
|
e8e47173fb | ||
|
|
19929be684 | ||
|
|
c4e1e1965e | ||
|
|
1e6263976f | ||
|
|
2b3bddb02d | ||
|
|
684522a8b7 | ||
|
|
c26fd14953 | ||
|
|
bd933592a9 | ||
|
|
e62f0d3296 | ||
|
|
1235fdad7c | ||
|
|
c47b9e3b0d | ||
|
|
180a6d4a1c | ||
|
|
52a9fa47c1 | ||
|
|
964a36bdcd | ||
|
|
0a3bc48788 | ||
|
|
301f2e7061 | ||
|
|
940afb399c | ||
|
|
586779ccca | ||
|
|
ab691f687d | ||
|
|
cb55083603 | ||
|
|
c7fcc9f7d9 | ||
|
|
d7832661e7 | ||
|
|
c8c9f805f6 | ||
|
|
259f130a60 | ||
|
|
12f034b424 | ||
|
|
7178460415 | ||
|
|
009b2963a8 | ||
|
|
f355d27aea | ||
|
|
350acbf254 | ||
|
|
4993e4773b | ||
|
|
cb9a8587b6 | ||
|
|
dd69230f19 | ||
|
|
6abbd9dd1b | ||
|
|
aa3c4ae797 | ||
|
|
50ca037da9 | ||
|
|
85e4598986 | ||
|
|
0e243b006a | ||
|
|
a3c033d1db | ||
|
|
a7dae37a23 | ||
|
|
0ec4a928a6 | ||
|
|
d355787820 | ||
|
|
cb1867dfd1 | ||
|
|
0aa186abbe | ||
|
|
63951d06f2 | ||
|
|
741893204a | ||
|
|
3e62181414 | ||
|
|
21695875f8 | ||
|
|
2de0844616 | ||
|
|
02490c26a6 | ||
|
|
eeda632846 | ||
|
|
af7a5d7c49 | ||
|
|
58f2e5be8b | ||
|
|
8e5d4a712c | ||
|
|
f235bd558a | ||
|
|
273bc4a94a | ||
|
|
6ce716f5f2 | ||
|
|
2890f95597 | ||
|
|
57ebd9d403 | ||
|
|
a5a756a20e | ||
|
|
27072a77e6 | ||
|
|
b7e26b9076 | ||
|
|
62ccd6d2ff | ||
|
|
b0c1483f70 | ||
|
|
c0f217abab | ||
|
|
cba13f94d6 | ||
|
|
8c7ea9bd32 | ||
|
|
7a67963ca7 | ||
|
|
8d0fc74341 | ||
|
|
7931405b83 | ||
|
|
e729e4e86c | ||
|
|
c737f2419b | ||
|
|
5db87a9175 | ||
|
|
3af55d60f2 | ||
|
|
44dab4d45c | ||
|
|
4be5e876b8 | ||
|
|
9f9436e741 | ||
|
|
b9741d9433 | ||
|
|
a254e11286 | ||
|
|
eb3ee28cee | ||
|
|
80f11de41e | ||
|
|
27bee4a266 | ||
|
|
ecd6000d54 | ||
|
|
2dfd444178 | ||
|
|
07fdb3bf6e | ||
|
|
d0d08d2ed9 | ||
|
|
aa61df941b | ||
|
|
63d1b16a7e | ||
|
|
a880319db8 | ||
|
|
c19705da5d | ||
|
|
2d762c8be3 | ||
|
|
5b66481996 | ||
|
|
2e77b9d0bf | ||
|
|
8a74bdbfe5 | ||
|
|
ac0d7ce949 | ||
|
|
d5d5561d74 | ||
|
|
98c362d038 | ||
|
|
145acd378b | ||
|
|
f09b2d8731 | ||
|
|
61dfb22af8 | ||
|
|
7d5dda244e | ||
|
|
15e3dea53b | ||
|
|
73f177c73e | ||
|
|
98b10c6435 | ||
|
|
52a26bea5f | ||
|
|
f8bb8dc53e | ||
|
|
9c26289254 | ||
|
|
8bc7b9bfa1 | ||
|
|
dae0f3dd62 | ||
|
|
9c28f2f180 | ||
|
|
805e7c0917 | ||
|
|
e0f29e0f7c | ||
|
|
b3f77f0c82 | ||
|
|
0f67b2f430 | ||
|
|
fb635033a9 | ||
|
|
393f8d31ab | ||
|
|
1711d50eff | ||
|
|
42c355a8d0 | ||
|
|
0e964da426 | ||
|
|
51693aa0bd | ||
|
|
51bb793664 | ||
|
|
edadb7aa98 | ||
|
|
ac10575b5f | ||
|
|
d24743370a | ||
|
|
4ada12a34c | ||
|
|
67dcd3e8d8 | ||
|
|
df6bc8f9b5 | ||
|
|
f9615efea5 | ||
|
|
d880d46214 | ||
|
|
be29b0a193 | ||
|
|
b70a9e7a61 | ||
|
|
60c0a0bf15 | ||
|
|
062f821b46 | ||
|
|
0520bb178c | ||
|
|
0d44b0b456 | ||
|
|
322568ba39 | ||
|
|
c09af92963 | ||
|
|
a024db040d | ||
|
|
efbebee9da | ||
|
|
b9a5607a56 | ||
|
|
1e8f7f9fa5 | ||
|
|
1d782338c9 | ||
|
|
f37d0e13d3 | ||
|
|
5c2fd20a9e | ||
|
|
c14d9dfb6e | ||
|
|
f695a24e1b | ||
|
|
06191646d2 | ||
|
|
9a670d79fc | ||
|
|
a48f358555 | ||
|
|
3bf72420c2 | ||
|
|
c2a3518eb0 | ||
|
|
4139eb1efc | ||
|
|
3dec2af071 | ||
|
|
be5709ab5c | ||
|
|
258cb23dda | ||
|
|
476a752a08 | ||
|
|
2818ec67df | ||
|
|
2e9512c6b8 | ||
|
|
12797c0a03 | ||
|
|
1a9165f7fc | ||
|
|
1b9027a24f | ||
|
|
81ebe1a7be | ||
|
|
1311c97c49 | ||
|
|
1acfb4f7b8 | ||
|
|
d5faaeca1a | ||
|
|
ef47b4582e | ||
|
|
6a8541971e | ||
|
|
9c5514f1b6 | ||
|
|
33451163c4 | ||
|
|
e23c2bb04f | ||
|
|
906e5e2b6f | ||
|
|
c902771f16 | ||
|
|
21b397c2cb | ||
|
|
3e1916a8d5 | ||
|
|
0ad4f83366 | ||
|
|
2dbfdfe111 | ||
|
|
88042c7958 | ||
|
|
0391a9c715 | ||
|
|
5cd9e94d4a | ||
|
|
55b16a8204 | ||
|
|
1c5c34561b | ||
|
|
bbaa6ed76f | ||
|
|
e154e1e380 | ||
|
|
35af4edb30 | ||
|
|
9be8f36824 | ||
|
|
6c41ac90d8 | ||
|
|
de4b497de1 | ||
|
|
0c32c5054c | ||
|
|
cb30a97832 | ||
|
|
695fa0b371 | ||
|
|
ad606c7cfa | ||
|
|
eb93760f1b | ||
|
|
be8726b41a | ||
|
|
3d97c93e49 | ||
|
|
783b8b7361 | ||
|
|
f8c8bad468 | ||
|
|
6bfc130b73 | ||
|
|
cd05b1f750 | ||
|
|
6c18c64270 | ||
|
|
4a61d1e511 | ||
|
|
e78f8a73f9 | ||
|
|
f6ffcd9481 | ||
|
|
136539867c | ||
|
|
e884f0816d | ||
|
|
56140608ef | ||
|
|
dee2ce5c56 | ||
|
|
ed9c0747fb | ||
|
|
3a019b06c3 | ||
|
|
035319bbd0 | ||
|
|
db72ab626f | ||
|
|
af76d1bb42 | ||
|
|
48e5a46cbd | ||
|
|
bcd01f3b03 | ||
|
|
2c30268bf2 | ||
|
|
b47fec2f71 | ||
|
|
6ae3f2d187 | ||
|
|
903454bf05 | ||
|
|
f462796ee5 | ||
|
|
fe405a781c | ||
|
|
8b523c73b8 | ||
|
|
f37bb847c7 | ||
|
|
9f2ed24dd0 | ||
|
|
fdddba1e00 | ||
|
|
e2aec593c1 | ||
|
|
bd6c83f3b1 | ||
|
|
680f9b9242 | ||
|
|
e97d3723df | ||
|
|
8307663938 | ||
|
|
50a2773081 | ||
|
|
784c3a9720 | ||
|
|
61bce30901 | ||
|
|
7f822be5db | ||
|
|
a1772a055b | ||
|
|
c6021f3e61 | ||
|
|
92ae85c3e8 | ||
|
|
d59350d356 | ||
|
|
a6d30baa27 | ||
|
|
b03b90dee6 | ||
|
|
28a59d2a6e | ||
|
|
425c679c6c | ||
|
|
5d5a126bb1 | ||
|
|
dd912822a7 | ||
|
|
8895ee8fc5 | ||
|
|
91bcf1187e | ||
|
|
df21840feb | ||
|
|
df629c62f5 | ||
|
|
79d985d6ff | ||
|
|
2b735d1b3a | ||
|
|
f42bdb7541 | ||
|
|
1541cce1d9 | ||
|
|
be225a9209 | ||
|
|
15196af5d6 | ||
|
|
f54aa90736 | ||
|
|
c6237cc528 | ||
|
|
8e590387f1 | ||
|
|
6cae70c208 | ||
|
|
c5a9cab3dd | ||
|
|
7142d0ea39 | ||
|
|
3e521d2952 | ||
|
|
0fa0def112 | ||
|
|
ee3f828b8c | ||
|
|
ee0d6e676c | ||
|
|
a87147a12d | ||
|
|
e38b05ff9a | ||
|
|
037faddab4 | ||
|
|
ff78d31583 | ||
|
|
a9fc1d492e | ||
|
|
3f299333cc | ||
|
|
f338586d37 | ||
|
|
bfe7799d13 | ||
|
|
1738476321 | ||
|
|
4213f24761 | ||
|
|
ac78e978fe | ||
|
|
e6a6a20eb6 | ||
|
|
f9a1784b9b | ||
|
|
4275ec6878 | ||
|
|
dce9e17c34 | ||
|
|
04902f8209 | ||
|
|
e49df4c54d | ||
|
|
ff70341af2 | ||
|
|
d115dbfd79 | ||
|
|
9596e15049 | ||
|
|
9bbe723827 | ||
|
|
7722841294 | ||
|
|
dd918c524d | ||
|
|
8568b61014 | ||
|
|
b8b548bab3 | ||
|
|
0d76241f77 | ||
|
|
3feb084438 | ||
|
|
d56c5b489b | ||
|
|
21500a1dcc | ||
|
|
ac7af60d76 | ||
|
|
b810e4f7d9 | ||
|
|
ac8f876347 | ||
|
|
b51b52dea9 | ||
|
|
535c0344b7 | ||
|
|
ddb2f352cd | ||
|
|
58f740844d | ||
|
|
0fc420f69d | ||
|
|
1ca857b890 | ||
|
|
710b3c4003 | ||
|
|
ca8f78ff89 | ||
|
|
73d543eef0 | ||
|
|
5ba155e058 | ||
|
|
5d56051532 | ||
|
|
e1cf8b9eb1 | ||
|
|
7986ea08b6 | ||
|
|
34534c1386 | ||
|
|
171765cfdb | ||
|
|
7f6f1d8a59 | ||
|
|
2662395cac | ||
|
|
3f8b697e9e | ||
|
|
e07cd88659 | ||
|
|
f20cdc7c8f | ||
|
|
755f650a8d | ||
|
|
cdf152b013 | ||
|
|
f640784d56 | ||
|
|
ef333e491a | ||
|
|
f753961ab7 | ||
|
|
0f74597139 | ||
|
|
f465d2ceca | ||
|
|
14eaefdceb | ||
|
|
f03659c865 | ||
|
|
b42316a275 | ||
|
|
d8da295e40 | ||
|
|
cfb2e663d3 | ||
|
|
ea03a5462f | ||
|
|
0c31d81711 | ||
|
|
77315ae4b9 | ||
|
|
5a5600914c | ||
|
|
700a620552 | ||
|
|
36e61dec0a | ||
|
|
76c7712507 | ||
|
|
d720d069ca | ||
|
|
94f7bfec2b | ||
|
|
562ca5aee6 | ||
|
|
ab90c61710 | ||
|
|
bdd0a12bb7 | ||
|
|
3b48983bc2 | ||
|
|
bd736eddec | ||
|
|
3b1e9011e7 | ||
|
|
9f8b57c145 | ||
|
|
a999ea3692 | ||
|
|
5c9b16bdce | ||
|
|
252ea8072d | ||
|
|
0f9d9cae4a | ||
|
|
468d65a661 | ||
|
|
9847618cf3 | ||
|
|
a281d9571e | ||
|
|
204faa82c1 | ||
|
|
be2fec02d9 | ||
|
|
491b95099d | ||
|
|
561c5bc981 | ||
|
|
12829ee5d2 | ||
|
|
f53a1ed951 | ||
|
|
12100cce99 | ||
|
|
bd4a458c31 | ||
|
|
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 | ||
|
|
93bc6109e7 | ||
|
|
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 | ||
|
|
4119e6e7d8 | ||
|
|
eefd50a6bc | ||
|
|
0d4a99af82 | ||
|
|
9f30d84f39 | ||
|
|
8b18e301d2 | ||
|
|
508729ec77 | ||
|
|
0fe78f7ba5 | ||
|
|
6202149b4f | ||
|
|
4ad661475b | ||
|
|
08abf41dfb | ||
|
|
9f1ba21c5e | ||
|
|
96d2eddce1 | ||
|
|
c45be80bf5 | ||
|
|
d61e322c1d | ||
|
|
6d309b7516 | ||
|
|
7d9e1b3af7 | ||
|
|
d2c2962eb7 | ||
|
|
b99ccafa07 | ||
|
|
c97a69537d | ||
|
|
a01687d7ad | ||
|
|
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 | ||
|
|
7d11b7c5f1 | ||
|
|
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 | ||
|
|
82a69ca043 | ||
|
|
c57ea79d0d | ||
|
|
b424d1f9cb | ||
|
|
7dcd6b8447 | ||
|
|
de63529887 | ||
|
|
d95f59fa97 | ||
|
|
d5ae30191d | ||
|
|
16ffbca6d6 | ||
|
|
afa3f2249c | ||
|
|
c5f4a4dfd8 | ||
|
|
34a2001a7b | ||
|
|
16c4a11990 | ||
|
|
6f01568a9a | ||
|
|
dfb2394b0b | ||
|
|
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 | ||
|
|
c07f413694 | ||
|
|
b5b6e5a5a3 | ||
|
|
a0f3eafe30 | ||
|
|
8feff5bc76 | ||
|
|
463f688978 | ||
|
|
70c6ed713b | ||
|
|
a6dcbb1f1c | ||
|
|
d4f02b5e67 | ||
|
|
645377e191 | ||
|
|
5a03c88ee3 | ||
|
|
abc30ba573 | ||
|
|
f36b1fc5eb | ||
|
|
feb7775d21 | ||
|
|
8d50160cd9 | ||
|
|
871ad10e0e | ||
|
|
649edf1dd1 | ||
|
|
172ab7b8e4 | ||
|
|
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 | ||
|
|
fe8ddd1869 | ||
|
|
7ed5c18a86 | ||
|
|
5cb6f6a1a2 | ||
|
|
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 | ||
|
|
95256417ac | ||
|
|
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 | ||
|
|
2d2251c1da | ||
|
|
0adacc0b5e | ||
|
|
818fd0b823 | ||
|
|
c9625b09b0 | ||
|
|
800c7fb37b | ||
|
|
179eaefafe | ||
|
|
28f5a74e98 | ||
|
|
781d62d3a5 | ||
|
|
bd9af5eff4 | ||
|
|
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 |
33
.clang-format
Normal file
33
.clang-format
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# clang-format: 11
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveBitFields: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BasedOnStyle: WebKit
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
ColumnLimit: 0
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
FixNamespaceComments: true
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 2
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
NamespaceIndentation: All
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 200
|
||||||
|
PenaltyBreakComment: 5
|
||||||
|
PenaltyBreakFirstLessLess: 50
|
||||||
|
PenaltyExcessCharacter: 4
|
||||||
|
PointerAlignment: Right
|
||||||
|
SortIncludes: true
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
Standard: Latest
|
||||||
|
TabWidth: 2
|
||||||
|
UseTab: Never
|
||||||
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
|
||||||
|
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
|
||||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/buck-out/
|
||||||
|
/.buckd/
|
||||||
|
/buckaroo/
|
||||||
|
.buckconfig.local
|
||||||
|
BUCKAROO_DEPS
|
||||||
|
/build
|
||||||
85
.travis.yml
85
.travis.yml
@ -1,17 +1,82 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
compiler:
|
|
||||||
- gcc
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
- llvm-toolchain-trusty-5.0
|
||||||
|
- sourceline: 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main'
|
||||||
|
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||||
|
packages:
|
||||||
|
- g++-7
|
||||||
|
- g++-8
|
||||||
|
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="7"
|
||||||
|
compiler: gcc
|
||||||
|
# - os: linux
|
||||||
|
#sudo: false
|
||||||
|
#env: GCC_VER="6" 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="7" CPPCHECK=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||||
|
compiler: gcc
|
||||||
|
- os: linux
|
||||||
|
sudo: false
|
||||||
|
env: GCC_VER="8" CPPCHECK=1 COVERAGE=1 CMAKE_OPTIONS="-D RUN_FUZZY_TESTS:BOOL=TRUE"
|
||||||
|
compiler: gcc
|
||||||
|
#- os: osx
|
||||||
|
# compiler: clang
|
||||||
|
# osx_image: xcode10
|
||||||
|
# env: CLANG_VER="5.0"
|
||||||
|
#- os: osx
|
||||||
|
# compiler: clang
|
||||||
|
# osx_image: xcode10
|
||||||
|
# env: CLANG_VER="5.0" 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:
|
before_install:
|
||||||
- sudo pip install cpp-coveralls --use-mirrors
|
- if [ "${GCC_VER}" != "" ]; then export CXX="g++-$GCC_VER" CC="gcc-$GCC_VER" GCOV="gcov-$GCC_VER" ; fi
|
||||||
|
#- if [ "${CLANG_VER}" != "" ]; then export CXX="clang++-$CLANG_VER"; fi
|
||||||
|
- pip install --user cpp-coveralls
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug -D USE_LIBCXX:BOOL=FALSE .
|
- cmake -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE:STRING=Debug $CMAKE_OPTIONS .
|
||||||
- make
|
- cmake --build . -- -j2
|
||||||
- make test
|
- if [ "${BUILD_ONLY}" != "1" ]; then ctest; fi
|
||||||
- coveralls -x hpp
|
- 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:
|
notifications:
|
||||||
recipients:
|
|
||||||
- jason@emptycrate.com
|
|
||||||
email:
|
email:
|
||||||
|
recipients:
|
||||||
|
- jason@emptycrate.com
|
||||||
on_success: always
|
on_success: always
|
||||||
on_failure: 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
|
||||||
|
|||||||
11
BUCK
Normal file
11
BUCK
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
prebuilt_cxx_library(
|
||||||
|
name = 'chaiscript',
|
||||||
|
header_only = True,
|
||||||
|
header_namespace = 'chaiscript',
|
||||||
|
exported_headers = subdir_glob([
|
||||||
|
('include/chaiscript', '**/*.hpp'),
|
||||||
|
]),
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
],
|
||||||
|
)
|
||||||
485
CMakeLists.txt
485
CMakeLists.txt
@ -1,22 +1,93 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 3.12)
|
||||||
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# required since cmake 3.4 at least for libc++
|
||||||
|
set(CMAKE_ENABLE_EXPORTS ON)
|
||||||
|
|
||||||
project(chaiscript)
|
project(chaiscript)
|
||||||
|
|
||||||
# MINGW does not yet support C++11's concurrency features
|
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
||||||
if (MINGW)
|
option(DYNLOAD_ENABLED "Dynamic Loading Support Enabled" TRUE)
|
||||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" FALSE)
|
|
||||||
else()
|
|
||||||
option(MULTITHREAD_SUPPORT_ENABLED "Multithreaded Support Enabled" TRUE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
|
||||||
option(ENABLE_COVERAGE "Enable Coverage Reporting in GCC" FALSE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
|
option(BUILD_MODULES "Build Extra Modules (stl)" TRUE)
|
||||||
option(BUILD_MODULES "Build Extra Modules (stl, reflection)" TRUE)
|
|
||||||
option(BUILD_SAMPLES "Build Samples Folder" FALSE)
|
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()
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
option(BUILD_LIBFUZZ_TESTER "Build libfuzzer tool" FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE)
|
||||||
|
if(ENABLE_MEMORY_SANITIZER)
|
||||||
|
add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g)
|
||||||
|
set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ")
|
||||||
|
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)
|
||||||
|
check_ipo_supported()
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
|
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 "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
|
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\\\.svn")
|
||||||
@ -28,8 +99,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_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||||
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
set(CPACK_PACKAGE_VERSION_MAJOR 7)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR 3)
|
set(CPACK_PACKAGE_VERSION_MINOR 0)
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||||
@ -49,58 +120,42 @@ configure_file(Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile)
|
|||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
include(cmake/Catch.cmake)
|
||||||
include(cmake/CheckCXX11Features.cmake)
|
|
||||||
|
|
||||||
if(NOT MINGW)
|
if(NOT MINGW)
|
||||||
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
find_library(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(HAS_CXX11_VARIADIC_TEMPLATES)
|
if(UNIX AND NOT APPLE)
|
||||||
message(STATUS "Variadic Template support detected")
|
find_program(VALGRIND NAMES valgrind PATH /usr/bin /usr/local/bin)
|
||||||
else()
|
|
||||||
message(SEND_ERROR "The selected compiler does not support the C++11 feature Variadic Templates.")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
|
|
||||||
message(STATUS "Detecting readline support")
|
message(STATUS "Detecting readline support")
|
||||||
if (READLINE_LIBRARY)
|
if(READLINE_LIBRARY)
|
||||||
message(STATUS "Found: ${READLINE_LIBRARY}")
|
message(STATUS "Found: ${READLINE_LIBRARY}")
|
||||||
set (READLINE_LIB readline)
|
set(READLINE_LIB readline)
|
||||||
add_definitions(/DREADLINE_AVAILABLE)
|
add_definitions(/DREADLINE_AVAILABLE)
|
||||||
else(READLINE_LIBRARY)
|
|
||||||
message(STATUS "Not Found")
|
|
||||||
set (READLINE_LIB )
|
|
||||||
set (READLINE_FLAG )
|
|
||||||
endif(READLINE_LIBRARY)
|
|
||||||
|
|
||||||
SET(EXTRA_LINKER_FLAGS "")
|
|
||||||
|
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
|
||||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
|
||||||
|
|
||||||
if (GCC_VERSION VERSION_LESS 4.8)
|
|
||||||
SET(CPP11_FLAG "-std=c++0x")
|
|
||||||
else()
|
|
||||||
SET(CPP11_FLAG "-std=c++11")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ENABLE_COVERAGE)
|
|
||||||
add_definitions(-fprofile-arcs -ftest-coverage)
|
|
||||||
SET(EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} "-fprofile-arcs -ftest-coverage")
|
|
||||||
# SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "-fprofile-arcs -ftest-coverage")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
else()
|
else()
|
||||||
SET(CPP11_FLAG "-std=c++11")
|
message(STATUS "Not Found")
|
||||||
|
set(READLINE_LIB)
|
||||||
|
set(READLINE_FLAG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
add_definitions(/W4)
|
add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928)
|
||||||
add_definitions(/bigobj)
|
|
||||||
|
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 /permissive- /utf-8)
|
||||||
# Note on MSVC compiler flags.
|
# Note on MSVC compiler flags.
|
||||||
# The code base selective disables warnings as necessary when the compiler is complaining too much
|
# 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
|
# about something that is perfectly valid, or there is simply no technical way around it
|
||||||
@ -108,233 +163,289 @@ if(MSVC)
|
|||||||
# The error did not come up until the move to C++11, but the compiler doesn't give enough information
|
# 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
|
# 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.
|
# how to workaround or fix the error. So I'm disabling it globally.
|
||||||
ADD_DEFINITIONS(/wd4503)
|
add_definitions(/wd4503)
|
||||||
else()
|
else()
|
||||||
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic ${CPP11_FLAG})
|
add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic -Werror=return-type)
|
||||||
|
|
||||||
if (APPLE)
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
|
||||||
|
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 -Wno-unused-template -Wno-undef -Wno-double-promotion)
|
||||||
|
else()
|
||||||
|
add_definitions(-Wnoexcept)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
add_definitions(-Wno-sign-compare)
|
add_definitions(-Wno-sign-compare)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||||
option(USE_LIBCXX "Use clang's libcxx" TRUE)
|
option(USE_LIBCXX "Use clang's libcxx" FALSE)
|
||||||
|
|
||||||
if (USE_LIBCXX)
|
if(USE_LIBCXX)
|
||||||
add_definitions(-stdlib=libc++)
|
add_definitions(-stdlib=libc++)
|
||||||
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} ${CPP11_FLAG} -stdlib=libc++)
|
set(LINKER_FLAGS "${LINKER_FLAGS} -stdlib=libc++")
|
||||||
else ()
|
|
||||||
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} ${CPP11_FLAG})
|
|
||||||
endif()
|
endif()
|
||||||
elseif(CMAKE_COMPILER_IS_GNUCC)
|
|
||||||
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} ${CPP11_FLAG})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# limitations in MinGW require us to make an optimized build
|
# limitations in MinGW require us to make an optimized build
|
||||||
# for the sake of object sizes or something
|
# for the sake of object sizes or something
|
||||||
if (MINGW)
|
if(MINGW OR CYGWIN)
|
||||||
add_definitions(-O3)
|
add_definitions(-O3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(include)
|
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)
|
set_source_files_properties(${Chai_INCLUDES} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||||
|
|
||||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
if(NOT MULTITHREAD_SUPPORT_ENABLED)
|
||||||
else()
|
|
||||||
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
add_definitions(-DCHAISCRIPT_NO_THREADS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_HOST_UNIX)
|
if(NOT DYNLOAD_ENABLED)
|
||||||
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
add_definitions(-DCHAISCRIPT_NO_DYNLOAD)
|
||||||
list(APPEND LIBS "dl")
|
endif()
|
||||||
endif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
|
||||||
|
|
||||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
if(CMAKE_HOST_UNIX)
|
||||||
if (CMAKE_COMPILER_IS_GNUCC)
|
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)
|
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE GCC_FULL_VERSION)
|
||||||
if (GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu")
|
if(GCC_FULL_VERSION MATCHES "4.8.1.*ubuntu")
|
||||||
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} -Wl,--no-as-needed -pthread )
|
set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,--no-as-needed -pthread")
|
||||||
else()
|
else()
|
||||||
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} -pthread )
|
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set (EXTRA_LINKER_FLAGS ${EXTRA_LINKER_FLAGS} -pthread )
|
set(LINKER_FLAGS "${LINKER_FLAGS} -pthread")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-pthread)
|
add_definitions(-pthread)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif(CMAKE_HOST_UNIX)
|
endif()
|
||||||
|
|
||||||
list(APPEND LIBS ${READLINE_LIB})
|
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}")
|
||||||
|
|
||||||
|
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)
|
add_library(chaiscript_stdlib-${CHAI_VERSION} MODULE src/chaiscript_stdlib_module.cpp)
|
||||||
target_link_libraries(chaiscript_stdlib ${LIBS} ${EXTRA_LINKER_FLAGS} ${CMAKE_THREAD_LIBS_INIT})
|
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})
|
add_executable(chai src/main.cpp ${Chai_INCLUDES})
|
||||||
target_link_libraries(chai ${LIBS} ${EXTRA_LINKER_FLAGS})
|
target_link_libraries(chai ${LIBS} ${CHAISCRIPT_LIBS})
|
||||||
add_dependencies(chai chaiscript_stdlib)
|
|
||||||
|
|
||||||
if (BUILD_SAMPLES)
|
add_library(chaiscript INTERFACE)
|
||||||
add_executable(example samples/example.cpp)
|
target_include_directories(chaiscript INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
target_link_libraries(example ${LIBS} ${EXTRA_LINKER_FLAGS})
|
|
||||||
|
if(BUILD_SAMPLES)
|
||||||
|
add_executable(sanity_checks src/sanity_checks.cpp)
|
||||||
|
target_link_libraries(sanity_checks ${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)
|
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()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if (BUILD_MODULES)
|
if(BUILD_MODULES)
|
||||||
|
add_library(test_module MODULE src/test_module.cpp)
|
||||||
|
target_link_libraries(test_module ${LIBS})
|
||||||
|
|
||||||
add_library(stl_extra MODULE src/stl_extra.cpp)
|
add_library(stl_extra MODULE src/stl_extra.cpp)
|
||||||
target_link_libraries(stl_extra ${LIBS} ${EXTRA_LINKER_FLAGS})
|
target_link_libraries(stl_extra ${LIBS})
|
||||||
|
|
||||||
add_library(reflection MODULE src/reflection.cpp)
|
set(MODULES stl_extra)
|
||||||
target_link_libraries(reflection ${LIBS} ${EXTRA_LINKER_FLAGS})
|
|
||||||
set(MODULES stl_extra reflection)
|
|
||||||
endif()
|
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)
|
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)
|
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-2017-07-20.tar.bz2
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/unittests
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
file(GLOB FUZZY_TESTS RELATIVE ${CMAKE_BINARY_DIR}/unittests/ ${CMAKE_BINARY_DIR}/unittests/MINIMIZED/*)
|
||||||
|
list(SORT FUZZY_TESTS)
|
||||||
|
|
||||||
|
foreach(filename ${FUZZY_TESTS})
|
||||||
|
message(STATUS "Adding test ${filename}")
|
||||||
|
add_test(fuzz.${filename} chai "-e" "--exception" "--any-exception" ${CMAKE_CURRENT_SOURCE_DIR}/unittests/fuzz_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)
|
if(BUILD_TESTING)
|
||||||
|
|
||||||
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
option(UNIT_TEST_LIGHT "Unit tests light (expect module loading failures)" FALSE)
|
||||||
|
|
||||||
foreach(filename ${UNIT_TESTS})
|
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) }")
|
||||||
message(STATUS "Adding test ${filename}")
|
set_property(TEST version_check
|
||||||
add_test(${filename} chai ${CMAKE_CURRENT_SOURCE_DIR}/unittests/unit_test.inc ${CMAKE_CURRENT_SOURCE_DIR}/unittests/${filename})
|
PROPERTY ENVIRONMENT
|
||||||
endforeach(filename)
|
|
||||||
|
|
||||||
set_property(TEST ${UNIT_TESTS}
|
|
||||||
PROPERTY ENVIRONMENT
|
|
||||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (NOT UNIT_TEST_LIGHT)
|
add_test(version_check_2 chai --version )
|
||||||
# commented out because uniform initializer syntax is not working properly in MSVC 2013
|
set_property(TEST version_check_2
|
||||||
add_executable(utility_test unittests/utility_test.cpp)
|
PROPERTY ENVIRONMENT
|
||||||
target_link_libraries(utility_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||||
add_test(NAME Utility_Test COMMAND utility_test)
|
PROPERTY PASS_REGULAR_EXPRESSION "${CHAI_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(dynamic_object_test unittests/dynamic_object_test.cpp)
|
add_test(help chai --help )
|
||||||
target_link_libraries(dynamic_object_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
set_property(TEST help
|
||||||
add_test(NAME Dynamic_Object_Test COMMAND dynamic_object_test)
|
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)
|
set(TESTS "")
|
||||||
target_link_libraries(functor_cast_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
|
||||||
add_test(NAME Functor_Cast_Test COMMAND functor_cast_test)
|
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})
|
||||||
|
catch_discover_tests(compiled_tests TEST_PREFIX "compiled.")
|
||||||
|
|
||||||
|
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)
|
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_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)
|
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_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} ${EXTRA_LINKER_FLAGS})
|
|
||||||
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} ${EXTRA_LINKER_FLAGS})
|
|
||||||
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} ${EXTRA_LINKER_FLAGS})
|
|
||||||
add_test(NAME Simultaneous_Chaiscript_Test COMMAND simultaneous_chaiscript_test)
|
|
||||||
|
|
||||||
add_executable(heap_allocated_chaiscript_test unittests/heap_allocated_chaiscript_test.cpp)
|
|
||||||
target_link_libraries(heap_allocated_chaiscript_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
|
||||||
add_test(NAME Heap_Allocated_Chaiscript_Test COMMAND heap_allocated_chaiscript_test)
|
|
||||||
|
|
||||||
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
add_executable(c_linkage_test unittests/c_linkage_test.cpp)
|
||||||
target_link_libraries(c_linkage_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
target_link_libraries(c_linkage_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||||
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
|
add_test(NAME C_Linkage_Test COMMAND c_linkage_test)
|
||||||
|
|
||||||
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
|
add_executable(integer_literal_test unittests/integer_literal_test.cpp)
|
||||||
target_link_libraries(integer_literal_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
target_link_libraries(integer_literal_test ${LIBS} ${CHAISCRIPT_LIBS})
|
||||||
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
|
add_test(NAME Integer_Literal_Test COMMAND integer_literal_test)
|
||||||
|
|
||||||
add_executable(arithmetic_conversions_test unittests/arithmetic_conversions_test.cpp)
|
if(MULTITHREAD_SUPPORT_ENABLED)
|
||||||
target_link_libraries(arithmetic_conversions_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
|
||||||
add_test(NAME Arithmetic_Conversions_Test COMMAND arithmetic_conversions_test)
|
|
||||||
|
|
||||||
if (MULTITHREAD_SUPPORT_ENABLED)
|
|
||||||
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
|
add_executable(multithreaded_test unittests/multithreaded_test.cpp)
|
||||||
target_link_libraries(multithreaded_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
target_link_libraries(multithreaded_test ${LIBS})
|
||||||
add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
|
add_test(NAME Multithreaded_Test COMMAND multithreaded_test)
|
||||||
set_property(TEST Multithreaded_Test
|
set_property(TEST Multithreaded_Test
|
||||||
PROPERTY ENVIRONMENT
|
PROPERTY ENVIRONMENT
|
||||||
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
"CHAI_USE_PATH=${CMAKE_CURRENT_SOURCE_DIR}/unittests/"
|
||||||
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
"CHAI_MODULE_PATH=${CMAKE_CURRENT_BINARY_DIR}/"
|
||||||
)
|
)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_executable(multifile_test
|
||||||
add_executable(multifile_test unittests/multifile_test_main.cpp unittests/multifile_test_chai.cpp
|
unittests/multifile_test_main.cpp
|
||||||
unittests/multifile_test_module.cpp)
|
unittests/multifile_test_chai.cpp
|
||||||
target_link_libraries(multifile_test ${LIBS} ${EXTRA_LINKER_FLAGS})
|
unittests/multifile_test_module.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(multifile_test ${LIBS})
|
||||||
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
add_test(NAME MultiFile_Test COMMAND multifile_test)
|
||||||
|
|
||||||
add_library(test_module MODULE src/test_module.cpp)
|
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
|
||||||
target_link_libraries(test_module ${LIBS} ${EXTRA_LINKER_FLAGS})
|
|
||||||
|
|
||||||
install(TARGETS test_module RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript)
|
|
||||||
endif()
|
endif()
|
||||||
endif(BUILD_TESTING)
|
endif()
|
||||||
|
|
||||||
install(TARGETS chai chaiscript_stdlib ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION lib/chaiscript )
|
|
||||||
|
if(BUILD_LIBFUZZ_TESTER)
|
||||||
|
add_executable(fuzzer src/libfuzzer_client.cpp src/sha3.cpp)
|
||||||
|
target_compile_options(fuzzer PRIVATE "-fsanitize=fuzzer,address")
|
||||||
|
target_link_libraries(fuzzer PRIVATE ${LIBS} "-fsanitize=fuzzer,address")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
install(TARGETS chai chaiscript_stdlib-${CHAI_VERSION} ${MODULES} RUNTIME DESTINATION bin LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/chaiscript")
|
||||||
|
|
||||||
install(DIRECTORY include/chaiscript DESTINATION include
|
install(DIRECTORY include/chaiscript DESTINATION include
|
||||||
PATTERN "*.hpp"
|
PATTERN "*.hpp"
|
||||||
PATTERN "*/.svn*" EXCLUDE
|
PATTERN "*/.svn*" EXCLUDE
|
||||||
PATTERN "*/.git*" EXCLUDE
|
PATTERN "*/.git*" EXCLUDE
|
||||||
PATTERN "*~" EXCLUDE)
|
PATTERN "*~" EXCLUDE)
|
||||||
install(DIRECTORY unittests DESTINATION share/chaiscript
|
install(DIRECTORY unittests DESTINATION share/chaiscript
|
||||||
PATTERN "*.chai"
|
PATTERN "*.chai"
|
||||||
PATTERN "*.inc"
|
PATTERN "*.inc"
|
||||||
PATTERN "*/.svn*" EXCLUDE
|
PATTERN "*/.svn*" EXCLUDE
|
||||||
PATTERN "*/.git*" EXCLUDE
|
PATTERN "*/.git*" EXCLUDE
|
||||||
PATTERN "*~" EXCLUDE)
|
PATTERN "*~" EXCLUDE)
|
||||||
install(DIRECTORY samples DESTINATION share/chaiscript
|
install(DIRECTORY samples DESTINATION share/chaiscript
|
||||||
PATTERN "*.chai"
|
PATTERN "*.chai"
|
||||||
PATTERN "*/.svn*" EXCLUDE
|
PATTERN "*/.svn*" EXCLUDE
|
||||||
PATTERN "*/.git*" EXCLUDE
|
PATTERN "*/.git*" EXCLUDE
|
||||||
PATTERN "*~" EXCLUDE)
|
PATTERN "*~" EXCLUDE)
|
||||||
|
|
||||||
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
|
configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @ONLY)
|
||||||
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
||||||
DESTINATION lib/pkgconfig)
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
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
31
LICENSE
Normal file
31
LICENSE
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
BSD-3-Clause License
|
||||||
|
|
||||||
|
Copyright 2009-2018 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.
|
||||||
23
appveyor.yml
Normal file
23
appveyor.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
version: 6.1.x.{build}
|
||||||
|
image:
|
||||||
|
- Visual Studio 2019
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- VS_VERSION: "Visual Studio 16"
|
||||||
|
build_script:
|
||||||
|
- cmd: >-
|
||||||
|
mkdir build
|
||||||
|
|
||||||
|
cd build
|
||||||
|
|
||||||
|
cmake c:\Projects\chaiscript -G "%VS_VERSION%" -DBUILD_TESTING:BOOL=ON -DBUILD_MODULES:BOOL=ON
|
||||||
|
|
||||||
|
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
|
||||||
3
buckaroo.json
Normal file
3
buckaroo.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"name": "ChaiScript"
|
||||||
|
}
|
||||||
602
cheatsheet.md
Normal file
602
cheatsheet.md
Normal file
@ -0,0 +1,602 @@
|
|||||||
|
# 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; // initializes ChaiScript, adding the standard ChaiScript types (map, string, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that ChaiScript cannot be used as a global / static object unless it is being compiled with `CHAISCRIPT_NO_THREADS`.
|
||||||
|
|
||||||
|
# Adding Things To The Engine
|
||||||
|
|
||||||
|
## Adding a Function / Method / Member
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Alternative
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
chai.add(chaiscript::fun(static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
|
||||||
|
```
|
||||||
|
This overload technique is also used when exposing base members using derived type
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Base
|
||||||
|
{
|
||||||
|
int data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Derived : public Base
|
||||||
|
{};
|
||||||
|
|
||||||
|
chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lambda
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
chai.add(
|
||||||
|
chaiscript::fun<std::function<std::string (bool)>>(
|
||||||
|
[](bool type) {
|
||||||
|
if (type) { return "x"; }
|
||||||
|
else { return "y"; }
|
||||||
|
}), "function_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constructors
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
chai.add(chaiscript::type_conversion<T, bool>());
|
||||||
|
```
|
||||||
|
|
||||||
|
Calling a user-defined type conversion that takes a lambda
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 ChaiScript about the relationship.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding Namespaces
|
||||||
|
|
||||||
|
Namespaces will not be populated until `import` is called.
|
||||||
|
This saves memory and computing costs if a namespace is not imported into every ChaiScript instance.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
chai.register_namespace([](chaiscript::Namespace& math) {
|
||||||
|
math["pi"] = chaiscript::const_var(3.14159);
|
||||||
|
math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); },
|
||||||
|
"math");
|
||||||
|
```
|
||||||
|
|
||||||
|
Import namespace in ChaiScript
|
||||||
|
```
|
||||||
|
import("math")
|
||||||
|
print(math.pi) // prints 3.14159
|
||||||
|
```
|
||||||
|
|
||||||
|
# Using STL
|
||||||
|
ChaiScript recognizes many types from STL, but you have to add specific instantiation yourself.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternative
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 that will be called in the specific throw() above
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sharing Functions
|
||||||
|
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto p = chai.eval<std::function<int (int, int)>>("`+`");
|
||||||
|
p(5, 6); // calls chaiscript's '+' function, returning 11
|
||||||
|
```
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
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 (i : [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) { }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Switch Statements
|
||||||
|
|
||||||
|
``` chaiscript
|
||||||
|
var myvalue = 2
|
||||||
|
switch (myvalue) {
|
||||||
|
case (1) {
|
||||||
|
print("My Value is 1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
print("My Value is 2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
print("My Value is something else.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Built-in Types
|
||||||
|
|
||||||
|
There are a number of built-in types that are part of ChaiScript.
|
||||||
|
|
||||||
|
### Vectors and Maps
|
||||||
|
|
||||||
|
```
|
||||||
|
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
|
||||||
|
var m = ["a":1, "b":2]; // map of string:value pairs
|
||||||
|
|
||||||
|
// Add a value to the vector by value.
|
||||||
|
v.push_back(123);
|
||||||
|
|
||||||
|
// Add an object to the vector by reference.
|
||||||
|
v.push_back_ref(m);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Numbers
|
||||||
|
|
||||||
|
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 a `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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Namespaces
|
||||||
|
|
||||||
|
Namespaces in ChaiScript are Dynamic Objects with global scope
|
||||||
|
|
||||||
|
```
|
||||||
|
namespace("math") // create a new namespace
|
||||||
|
|
||||||
|
math.square = fun(x) { x * x } // add a function to the "math" namespace
|
||||||
|
math.sum_squares = fun(x, y) { math.square(x) + math.square(y) }
|
||||||
|
|
||||||
|
print(math.square(4)) // prints 16
|
||||||
|
print(math.sum_squares(2, 5)) // prints 29
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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__` Name of current function
|
||||||
|
|
||||||
|
|
||||||
|
# Built-in Functions
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
## Extras
|
||||||
|
ChaiScript itself does not provide a link to the math functions defined in `<cmath>`. You can either add them yourself, or use the [ChaiScript_Extras](https://github.com/ChaiScript/ChaiScript_Extras) helper library. (Which also provides some additional string functions.)
|
||||||
175
cmake/Catch.cmake
Normal file
175
cmake/Catch.cmake
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
#[=======================================================================[.rst:
|
||||||
|
Catch
|
||||||
|
-----
|
||||||
|
|
||||||
|
This module defines a function to help use the Catch test framework.
|
||||||
|
|
||||||
|
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||||
|
executable to enumerate its tests. This does not require CMake to be re-run
|
||||||
|
when tests change. However, it may not work in a cross-compiling environment,
|
||||||
|
and setting test properties is less convenient.
|
||||||
|
|
||||||
|
This command is intended to replace use of :command:`add_test` to register
|
||||||
|
tests, and will create a separate CTest test for each Catch test case. Note
|
||||||
|
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||||
|
cannot be shared by multiple test cases executing in the same instance.
|
||||||
|
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||||
|
usually considered as more beneficial. By default, the CTest test name is the
|
||||||
|
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||||
|
|
||||||
|
.. command:: catch_discover_tests
|
||||||
|
|
||||||
|
Automatically add tests with CTest by querying the compiled test executable
|
||||||
|
for available tests::
|
||||||
|
|
||||||
|
catch_discover_tests(target
|
||||||
|
[TEST_SPEC arg1...]
|
||||||
|
[EXTRA_ARGS arg1...]
|
||||||
|
[WORKING_DIRECTORY dir]
|
||||||
|
[TEST_PREFIX prefix]
|
||||||
|
[TEST_SUFFIX suffix]
|
||||||
|
[PROPERTIES name1 value1...]
|
||||||
|
[TEST_LIST var]
|
||||||
|
)
|
||||||
|
|
||||||
|
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||||
|
that generates the list of tests by parsing the output from running the test
|
||||||
|
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||||
|
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||||
|
not necessary to re-run CMake when the list of tests changes.
|
||||||
|
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||||
|
in order to function in a cross-compiling environment.
|
||||||
|
|
||||||
|
Additionally, setting properties on tests is somewhat less convenient, since
|
||||||
|
the tests are not available at CMake time. Additional test properties may be
|
||||||
|
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||||
|
more fine-grained test control is needed, custom content may be provided
|
||||||
|
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||||
|
directory property. The set of discovered tests is made accessible to such a
|
||||||
|
script via the ``<target>_TESTS`` variable.
|
||||||
|
|
||||||
|
The options are:
|
||||||
|
|
||||||
|
``target``
|
||||||
|
Specifies the Catch executable, which must be a known CMake executable
|
||||||
|
target. CMake will substitute the location of the built executable when
|
||||||
|
running the test.
|
||||||
|
|
||||||
|
``TEST_SPEC arg1...``
|
||||||
|
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||||
|
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||||
|
|
||||||
|
``EXTRA_ARGS arg1...``
|
||||||
|
Any extra arguments to pass on the command line to each test case.
|
||||||
|
|
||||||
|
``WORKING_DIRECTORY dir``
|
||||||
|
Specifies the directory in which to run the discovered test cases. If this
|
||||||
|
option is not provided, the current binary directory is used.
|
||||||
|
|
||||||
|
``TEST_PREFIX prefix``
|
||||||
|
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||||
|
case. This can be useful when the same test executable is being used in
|
||||||
|
multiple calls to ``catch_discover_tests()`` but with different
|
||||||
|
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||||
|
|
||||||
|
``TEST_SUFFIX suffix``
|
||||||
|
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||||
|
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||||
|
be specified.
|
||||||
|
|
||||||
|
``PROPERTIES name1 value1...``
|
||||||
|
Specifies additional properties to be set on all tests discovered by this
|
||||||
|
invocation of ``catch_discover_tests``.
|
||||||
|
|
||||||
|
``TEST_LIST var``
|
||||||
|
Make the list of tests available in the variable ``var``, rather than the
|
||||||
|
default ``<target>_TESTS``. This can be useful when the same test
|
||||||
|
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||||
|
Note that this variable is only available in CTest.
|
||||||
|
|
||||||
|
#]=======================================================================]
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
function(catch_discover_tests TARGET)
|
||||||
|
cmake_parse_arguments(
|
||||||
|
""
|
||||||
|
""
|
||||||
|
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||||
|
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||||
|
${ARGN}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT _WORKING_DIRECTORY)
|
||||||
|
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
|
endif()
|
||||||
|
if(NOT _TEST_LIST)
|
||||||
|
set(_TEST_LIST ${TARGET}_TESTS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
## Generate a unique name based on the extra arguments
|
||||||
|
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||||
|
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||||
|
|
||||||
|
# Define rule to generate test list for aforementioned test executable
|
||||||
|
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||||
|
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||||
|
get_property(crosscompiling_emulator
|
||||||
|
TARGET ${TARGET}
|
||||||
|
PROPERTY CROSSCOMPILING_EMULATOR
|
||||||
|
)
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${TARGET} POST_BUILD
|
||||||
|
BYPRODUCTS "${ctest_tests_file}"
|
||||||
|
COMMAND "${CMAKE_COMMAND}"
|
||||||
|
-D "TEST_TARGET=${TARGET}"
|
||||||
|
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||||
|
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||||
|
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||||
|
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||||
|
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||||
|
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||||
|
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||||
|
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||||
|
-D "TEST_LIST=${_TEST_LIST}"
|
||||||
|
-D "CTEST_FILE=${ctest_tests_file}"
|
||||||
|
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
file(WRITE "${ctest_include_file}"
|
||||||
|
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||||
|
" include(\"${ctest_tests_file}\")\n"
|
||||||
|
"else()\n"
|
||||||
|
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||||
|
"endif()\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||||
|
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||||
|
set_property(DIRECTORY
|
||||||
|
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||||
|
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||||
|
if (NOT ${test_include_file_set})
|
||||||
|
set_property(DIRECTORY
|
||||||
|
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||||
|
)
|
||||||
76
cmake/CatchAddTests.cmake
Normal file
76
cmake/CatchAddTests.cmake
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||||
|
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||||
|
|
||||||
|
set(prefix "${TEST_PREFIX}")
|
||||||
|
set(suffix "${TEST_SUFFIX}")
|
||||||
|
set(spec ${TEST_SPEC})
|
||||||
|
set(extra_args ${TEST_EXTRA_ARGS})
|
||||||
|
set(properties ${TEST_PROPERTIES})
|
||||||
|
set(script)
|
||||||
|
set(suite)
|
||||||
|
set(tests)
|
||||||
|
|
||||||
|
function(add_command NAME)
|
||||||
|
set(_args "")
|
||||||
|
foreach(_arg ${ARGN})
|
||||||
|
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||||
|
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||||
|
else()
|
||||||
|
set(_args "${_args} ${_arg}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Run test executable to get list of available tests
|
||||||
|
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
|
||||||
|
OUTPUT_VARIABLE output
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||||
|
if(${result} EQUAL 0)
|
||||||
|
message(WARNING
|
||||||
|
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||||
|
)
|
||||||
|
elseif(${result} LESS 0)
|
||||||
|
message(FATAL_ERROR
|
||||||
|
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||||
|
" Result: ${result}\n"
|
||||||
|
" Output: ${output}\n"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REPLACE "\n" ";" output "${output}")
|
||||||
|
|
||||||
|
# Parse output
|
||||||
|
foreach(line ${output})
|
||||||
|
set(test ${line})
|
||||||
|
# ...and add to script
|
||||||
|
add_command(add_test
|
||||||
|
"${prefix}${test}${suffix}"
|
||||||
|
${TEST_EXECUTOR}
|
||||||
|
"${TEST_EXECUTABLE}"
|
||||||
|
${test}
|
||||||
|
${extra_args}
|
||||||
|
)
|
||||||
|
add_command(set_tests_properties
|
||||||
|
"${prefix}${test}${suffix}"
|
||||||
|
PROPERTIES
|
||||||
|
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||||
|
${properties}
|
||||||
|
)
|
||||||
|
list(APPEND tests "${prefix}${test}${suffix}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Create a list of all discovered tests, which users may use to e.g. set
|
||||||
|
# properties on the tests
|
||||||
|
add_command(set ${TEST_LIST} ${tests})
|
||||||
|
|
||||||
|
# Write CTest script
|
||||||
|
file(WRITE "${CTEST_FILE}" "${script}")
|
||||||
@ -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)
|
|
||||||
|
|
||||||
185
cmake/ParseAndAddCatchTests.cmake
Normal file
185
cmake/ParseAndAddCatchTests.cmake
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#==================================================================================================#
|
||||||
|
# supported macros #
|
||||||
|
# - TEST_CASE, #
|
||||||
|
# - SCENARIO, #
|
||||||
|
# - TEST_CASE_METHOD, #
|
||||||
|
# - CATCH_TEST_CASE, #
|
||||||
|
# - CATCH_SCENARIO, #
|
||||||
|
# - CATCH_TEST_CASE_METHOD. #
|
||||||
|
# #
|
||||||
|
# Usage #
|
||||||
|
# 1. make sure this module is in the path or add this otherwise: #
|
||||||
|
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||||
|
# 2. make sure that you've enabled testing option for the project by the call: #
|
||||||
|
# enable_testing() #
|
||||||
|
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
|
||||||
|
# project(testing_target) #
|
||||||
|
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
|
||||||
|
# enable_testing() #
|
||||||
|
# #
|
||||||
|
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
|
||||||
|
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
|
||||||
|
# #
|
||||||
|
# file(GLOB SOURCE_FILES "*.cpp") #
|
||||||
|
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
|
||||||
|
# #
|
||||||
|
# include(ParseAndAddCatchTests) #
|
||||||
|
# ParseAndAddCatchTests(${PROJECT_NAME}) #
|
||||||
|
# #
|
||||||
|
# The following variables affect the behavior of the script: #
|
||||||
|
# #
|
||||||
|
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
|
||||||
|
# -- enables debug messages #
|
||||||
|
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
|
||||||
|
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
|
||||||
|
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
|
||||||
|
# -- adds fixture class name to the test name #
|
||||||
|
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
|
||||||
|
# -- adds cmake target name to the test name #
|
||||||
|
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
|
||||||
|
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
|
||||||
|
# #
|
||||||
|
#==================================================================================================#
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.8)
|
||||||
|
|
||||||
|
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
|
||||||
|
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
|
||||||
|
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
|
||||||
|
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
|
||||||
|
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
|
||||||
|
|
||||||
|
function(PrintDebugMessage)
|
||||||
|
if(PARSE_CATCH_TESTS_VERBOSE)
|
||||||
|
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# This removes the contents between
|
||||||
|
# - block comments (i.e. /* ... */)
|
||||||
|
# - full line comments (i.e. // ... )
|
||||||
|
# contents have been read into '${CppCode}'.
|
||||||
|
# !keep partial line comments
|
||||||
|
function(RemoveComments CppCode)
|
||||||
|
string(ASCII 2 CMakeBeginBlockComment)
|
||||||
|
string(ASCII 3 CMakeEndBlockComment)
|
||||||
|
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
|
||||||
|
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
|
||||||
|
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
|
||||||
|
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
|
||||||
|
|
||||||
|
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Worker function
|
||||||
|
function(ParseFile SourceFile TestTarget)
|
||||||
|
# According to CMake docs EXISTS behavior is well-defined only for full paths.
|
||||||
|
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
|
||||||
|
if(NOT EXISTS ${SourceFile})
|
||||||
|
message(WARNING "Cannot find source file: ${SourceFile}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
PrintDebugMessage("parsing ${SourceFile}")
|
||||||
|
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
|
||||||
|
|
||||||
|
# Remove block and fullline comments
|
||||||
|
RemoveComments(Contents)
|
||||||
|
|
||||||
|
# Find definition of test names
|
||||||
|
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^\)]+\\)+[ \t\n]*{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
|
||||||
|
|
||||||
|
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
|
||||||
|
PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
|
||||||
|
set_property(
|
||||||
|
DIRECTORY
|
||||||
|
APPEND
|
||||||
|
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(TestName ${Tests})
|
||||||
|
# Strip newlines
|
||||||
|
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
|
||||||
|
|
||||||
|
# Get test type and fixture if applicable
|
||||||
|
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
|
||||||
|
string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
|
||||||
|
string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
|
||||||
|
|
||||||
|
# Get string parts of test definition
|
||||||
|
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
|
||||||
|
|
||||||
|
# Strip wrapping quotation marks
|
||||||
|
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
|
||||||
|
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
|
||||||
|
|
||||||
|
# Validate that a test name and tags have been provided
|
||||||
|
list(LENGTH TestStrings TestStringsLength)
|
||||||
|
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
|
||||||
|
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Assign name and tags
|
||||||
|
list(GET TestStrings 0 Name)
|
||||||
|
if("${TestType}" STREQUAL "SCENARIO")
|
||||||
|
set(Name "Scenario: ${Name}")
|
||||||
|
endif()
|
||||||
|
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND TestFixture)
|
||||||
|
set(CTestName "${TestFixture}:${Name}")
|
||||||
|
else()
|
||||||
|
set(CTestName "${Name}")
|
||||||
|
endif()
|
||||||
|
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
|
||||||
|
set(CTestName "${TestTarget}:${CTestName}")
|
||||||
|
endif()
|
||||||
|
# add target to labels to enable running all tests added from this target
|
||||||
|
set(Labels ${TestTarget})
|
||||||
|
if(TestStringsLength EQUAL 2)
|
||||||
|
list(GET TestStrings 1 Tags)
|
||||||
|
string(TOLOWER "${Tags}" Tags)
|
||||||
|
# remove target from labels if the test is hidden
|
||||||
|
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
|
||||||
|
list(REMOVE_ITEM Labels ${TestTarget})
|
||||||
|
endif()
|
||||||
|
string(REPLACE "]" ";" Tags "${Tags}")
|
||||||
|
string(REPLACE "[" "" Tags "${Tags}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND Labels ${Tags})
|
||||||
|
|
||||||
|
list(FIND Labels "!hide" IndexOfHideLabel)
|
||||||
|
set(HiddenTagFound OFF)
|
||||||
|
foreach(label ${Labels})
|
||||||
|
string(REGEX MATCH "^!hide|^\\." result ${label})
|
||||||
|
if(result)
|
||||||
|
set(HiddenTagFound ON)
|
||||||
|
break()
|
||||||
|
endif(result)
|
||||||
|
endforeach(label)
|
||||||
|
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
|
||||||
|
PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
|
||||||
|
else()
|
||||||
|
PrintDebugMessage("Adding test \"${CTestName}\"")
|
||||||
|
if(Labels)
|
||||||
|
PrintDebugMessage("Setting labels to ${Labels}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add the test and set its properties
|
||||||
|
add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
|
||||||
|
set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
|
||||||
|
LABELS "${Labels}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# entry point
|
||||||
|
function(ParseAndAddCatchTests TestTarget)
|
||||||
|
PrintDebugMessage("Started parsing ${TestTarget}")
|
||||||
|
get_target_property(SourceFiles ${TestTarget} SOURCES)
|
||||||
|
PrintDebugMessage("Found the following sources: ${SourceFiles}")
|
||||||
|
foreach(SourceFile ${SourceFiles})
|
||||||
|
ParseFile(${SourceFile} ${TestTarget})
|
||||||
|
endforeach()
|
||||||
|
PrintDebugMessage("Finished parsing ${TestTarget}")
|
||||||
|
endfunction()
|
||||||
@ -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" }
|
||||||
@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
var my_array=["1", 4, 6.6l, 10ul, "1000", 100, 10.9f ];
|
|
||||||
|
|
||||||
for (var j = 0; j < 10000; ++j)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < 6; ++i)
|
|
||||||
{
|
|
||||||
to_string(my_array[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 (
|
$language_data = array (
|
||||||
'LANG_NAME' => 'Chaiscript',
|
'LANG_NAME' => 'ChaiScript',
|
||||||
'COMMENT_SINGLE' => array(1 => '//'),
|
'COMMENT_SINGLE' => array(1 => '//'),
|
||||||
'COMMENT_MULTI' => array('/*' => '*/'),
|
'COMMENT_MULTI' => array('/*' => '*/'),
|
||||||
//Regular Expressions
|
//Regular Expressions
|
||||||
|
|||||||
1
contrib/vim
Normal file
1
contrib/vim
Normal file
@ -0,0 +1 @@
|
|||||||
|
vim support can be found at https://github.com/ChaiScript/vim-chaiscript
|
||||||
@ -1,7 +0,0 @@
|
|||||||
Install ftdetect, indent and syntax subdirectories to:
|
|
||||||
|
|
||||||
~/.vim/
|
|
||||||
|
|
||||||
See the vim documentation on this:
|
|
||||||
|
|
||||||
http://vimdoc.sourceforge.net/htmldoc/syntax.html#mysyntaxfile
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
au BufRead,BufNewFile *.chai set filetype=chaiscript
|
|
||||||
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
" Vim indent file
|
|
||||||
" Language: ChaiScript
|
|
||||||
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
|
||||||
|
|
||||||
" Only load this indent file when no other was loaded.
|
|
||||||
if exists("b:did_indent")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let b:did_indent = 1
|
|
||||||
|
|
||||||
setlocal indentexpr=GetChaiScriptIndent()
|
|
||||||
setlocal autoindent
|
|
||||||
|
|
||||||
" Only define the function once.
|
|
||||||
if exists("*GetChaiScriptIndent")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! GetChaiScriptIndent()
|
|
||||||
" Find a non-blank line above the current line.
|
|
||||||
let lnum = prevnonblank(v:lnum - 1)
|
|
||||||
|
|
||||||
" Hit the start of the file, use zero indent.
|
|
||||||
if lnum == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Add a 'shiftwidth' after lines that start a block:
|
|
||||||
" lines containing a {
|
|
||||||
let ind = indent(lnum)
|
|
||||||
let flag = 0
|
|
||||||
let prevline = getline(lnum)
|
|
||||||
if prevline =~ '^.*{.*'
|
|
||||||
let ind = ind + &shiftwidth
|
|
||||||
let flag = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Subtract a 'shiftwidth' after lines containing a { followed by a }
|
|
||||||
" to keep it balanced
|
|
||||||
if flag == 1 && prevline =~ '.*{.*}.*'
|
|
||||||
let ind = ind - &shiftwidth
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Subtract a 'shiftwidth' on lines ending with }
|
|
||||||
if getline(v:lnum) =~ '^\s*\%(}\)'
|
|
||||||
let ind = ind - &shiftwidth
|
|
||||||
endif
|
|
||||||
|
|
||||||
return ind
|
|
||||||
endfunction
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
" Vim syntax file
|
|
||||||
" Language: ChaiScript
|
|
||||||
" Maintainer: Jason Turner <lefticus 'at' gmail com>
|
|
||||||
|
|
||||||
" Quit when a (custom) syntax file was already loaded
|
|
||||||
if exists("b:current_syntax")
|
|
||||||
finish
|
|
||||||
end
|
|
||||||
|
|
||||||
let s:cpo_save = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
syn case match
|
|
||||||
|
|
||||||
" syncing method
|
|
||||||
syn sync fromstart
|
|
||||||
|
|
||||||
" Strings
|
|
||||||
syn region chaiscriptString start=+"+ end=+"+ skip=+\\\\\|\\"+ contains=chaiscriptSpecial,chaiscriptEval,@Spell
|
|
||||||
|
|
||||||
" Escape characters
|
|
||||||
syn match chaiscriptSpecial contained "\\[\\abfnrtv\'\"]\|\\\d\{,3}"
|
|
||||||
|
|
||||||
" String evals
|
|
||||||
syn region chaiscriptEval contained start="${" end="}"
|
|
||||||
|
|
||||||
" integer number
|
|
||||||
syn match chaiscriptNumber "\<\d\+\>"
|
|
||||||
|
|
||||||
" floating point number, with dot, optional exponent
|
|
||||||
syn match chaiscriptFloat "\<\d\+\.\d*\%(e[-+]\=\d\+\)\=\>"
|
|
||||||
|
|
||||||
" floating point number, starting with a dot, optional exponent
|
|
||||||
syn match chaiscriptFloat "\.\d\+\%(e[-+]\=\d\+\)\=\>"
|
|
||||||
|
|
||||||
" floating point number, without dot, with exponent
|
|
||||||
syn match chaiscriptFloat "\<\d\+e[-+]\=\d\+\>"
|
|
||||||
|
|
||||||
" Hex strings
|
|
||||||
syn match chaiscriptNumber "\<0x\x\+\>"
|
|
||||||
|
|
||||||
" Binary strings
|
|
||||||
syn match chaiscriptNumber "\<0b[01]\+\>"
|
|
||||||
|
|
||||||
" Various language features
|
|
||||||
syn keyword chaiscriptCond if else
|
|
||||||
syn keyword chaiscriptRepeat while for do
|
|
||||||
syn keyword chaiscriptStatement break continue return switch case default
|
|
||||||
syn keyword chaiscriptExceptions try catch throw
|
|
||||||
|
|
||||||
"Keyword
|
|
||||||
syn keyword chaiscriptKeyword def true false attr
|
|
||||||
|
|
||||||
"Built in types
|
|
||||||
syn keyword chaiscriptType fun var auto
|
|
||||||
|
|
||||||
"Built in funcs, keep it simple
|
|
||||||
syn keyword chaiscriptFunc eval throw
|
|
||||||
|
|
||||||
"Let's treat all backtick operator function lookups as built in too
|
|
||||||
syn region chaiscriptFunc matchgroup=chaiscriptFunc start="`" end="`"
|
|
||||||
|
|
||||||
" Account for the "[1..10]" syntax, treating it as an operator
|
|
||||||
" Intentionally leaving out all of the normal, well known operators
|
|
||||||
syn match chaiscriptOperator "\.\."
|
|
||||||
|
|
||||||
" Guard seperator as an operator
|
|
||||||
syn match chaiscriptOperator ":"
|
|
||||||
|
|
||||||
" Comments
|
|
||||||
syn match chaiscriptComment "//.*$" contains=@Spell
|
|
||||||
syn region chaiscriptComment matchgroup=chaiscriptComment start="/\*" end="\*/" contains=@Spell
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hi def link chaiscriptExceptions Exception
|
|
||||||
hi def link chaiscriptKeyword Keyword
|
|
||||||
hi def link chaiscriptStatement Statement
|
|
||||||
hi def link chaiscriptRepeat Repeat
|
|
||||||
hi def link chaiscriptString String
|
|
||||||
hi def link chaiscriptNumber Number
|
|
||||||
hi def link chaiscriptFloat Float
|
|
||||||
hi def link chaiscriptOperator Operator
|
|
||||||
hi def link chaiscriptConstant Constant
|
|
||||||
hi def link chaiscriptCond Conditional
|
|
||||||
hi def link chaiscriptFunction Function
|
|
||||||
hi def link chaiscriptComment Comment
|
|
||||||
hi def link chaiscriptTodo Todo
|
|
||||||
hi def link chaiscriptError Error
|
|
||||||
hi def link chaiscriptSpecial SpecialChar
|
|
||||||
hi def link chaiscriptFunc Identifier
|
|
||||||
hi def link chaiscriptType Type
|
|
||||||
hi def link chaiscriptEval Special
|
|
||||||
|
|
||||||
let b:current_syntax = "chaiscript"
|
|
||||||
|
|
||||||
let &cpo = s:cpo_save
|
|
||||||
unlet s:cpo_save
|
|
||||||
" vim: nowrap sw=2 sts=2 ts=8 noet
|
|
||||||
File diff suppressed because it is too large
Load Diff
37
include/chaiscript/chaiscript_basic.hpp
Normal file
37
include/chaiscript/chaiscript_basic.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-2018, Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_BASIC_HPP_
|
||||||
|
#define CHAISCRIPT_BASIC_HPP_
|
||||||
|
|
||||||
|
#include "chaiscript_defines.hpp"
|
||||||
|
|
||||||
|
#include "dispatchkit/boxed_number.hpp"
|
||||||
|
#include "dispatchkit/dispatchkit.hpp"
|
||||||
|
#include "dispatchkit/dynamic_object.hpp"
|
||||||
|
#include "dispatchkit/function_call.hpp"
|
||||||
|
|
||||||
|
#include "language/chaiscript_engine.hpp"
|
||||||
|
#include "language/chaiscript_eval.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,37 +1,244 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// and Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_DEFINES_HPP_
|
#ifndef CHAISCRIPT_DEFINES_HPP_
|
||||||
#define CHAISCRIPT_DEFINES_HPP_
|
#define CHAISCRIPT_DEFINES_HPP_
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#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_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
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#if defined(_LIBCPP_VERSION)
|
||||||
|
#define CHAISCRIPT_LIBCPP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
#define CHAISCRIPT_WINDOWS
|
#define CHAISCRIPT_WINDOWS
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
#if defined(__llvm__)
|
||||||
|
#define CHAISCRIPT_CLANG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_HAS_DECLSPEC
|
||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CHAISCRIPT_MSVC
|
#if defined(CHAISCRIPT_MSVC) || (defined(__GNUC__) && __GNUC__ >= 5) || defined(CHAISCRIPT_CLANG)
|
||||||
#define CHAISCRIPT_NOEXCEPT throw()
|
#define CHAISCRIPT_UTF16_UTF32
|
||||||
#define CHAISCRIPT_CONSTEXPR
|
#endif
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define CHAISCRIPT_DEBUG true
|
||||||
#else
|
#else
|
||||||
#define CHAISCRIPT_NOEXCEPT noexcept
|
#define CHAISCRIPT_DEBUG false
|
||||||
#define CHAISCRIPT_CONSTEXPR constexpr
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
constexpr static const int version_major = 7;
|
||||||
|
constexpr static const int version_minor = 0;
|
||||||
|
constexpr static const int version_patch = 0;
|
||||||
|
|
||||||
|
constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION;
|
||||||
|
constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME;
|
||||||
|
constexpr 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
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename B, typename D, typename... Arg>
|
||||||
|
inline std::unique_ptr<B> make_unique(Arg &&...arg) {
|
||||||
|
#ifdef CHAISCRIPT_USE_STD_MAKE_SHARED
|
||||||
|
return std::make_unique<D>(std::forward<Arg>(arg)...);
|
||||||
|
#else
|
||||||
|
return std::unique_ptr<B>(static_cast<B *>(new D(std::forward<Arg>(arg)...)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Build_Info {
|
||||||
|
[[nodiscard]] constexpr static int version_major() noexcept { return chaiscript::version_major; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr static int version_minor() noexcept { return chaiscript::version_minor; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr static int version_patch() noexcept { return chaiscript::version_patch; }
|
||||||
|
|
||||||
|
[[nodiscard]] static std::string version() {
|
||||||
|
return std::to_string(version_major()) + '.' + std::to_string(version_minor()) + '.' + std::to_string(version_patch());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static std::string compiler_id() { return compiler_name() + '-' + compiler_version(); }
|
||||||
|
|
||||||
|
[[nodiscard]] static std::string build_id() { return compiler_id() + (debug_build() ? "-Debug" : "-Release"); }
|
||||||
|
|
||||||
|
[[nodiscard]] static std::string compiler_version() { return chaiscript::compiler_version; }
|
||||||
|
|
||||||
|
[[nodiscard]] static std::string compiler_name() { return chaiscript::compiler_name; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr static bool debug_build() noexcept { return chaiscript::debug_build; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if<std::is_integral<T>::value, T>::type {
|
||||||
|
T t = 0;
|
||||||
|
for (const auto c : t_str) {
|
||||||
|
if (c < '0' || c > '9') {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
t *= 10;
|
||||||
|
t += c - '0';
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] auto parse_num(const std::string_view t_str) -> typename std::enable_if<!std::is_integral<T>::value, T>::type {
|
||||||
|
T t = 0;
|
||||||
|
T base{};
|
||||||
|
T decimal_place = 0;
|
||||||
|
int exponent = 0;
|
||||||
|
|
||||||
|
for (const auto c : t_str) {
|
||||||
|
switch (c) {
|
||||||
|
case '.':
|
||||||
|
decimal_place = 10;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
exponent = 1;
|
||||||
|
decimal_place = 0;
|
||||||
|
base = t;
|
||||||
|
t = 0;
|
||||||
|
break;
|
||||||
|
case '-':
|
||||||
|
exponent = -1;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
if (decimal_place < 10) {
|
||||||
|
t *= 10;
|
||||||
|
t += static_cast<T>(c - '0');
|
||||||
|
} else {
|
||||||
|
t += static_cast<T>(c - '0') / decimal_place;
|
||||||
|
decimal_place *= 10;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exponent ? base * std::pow(T(10), t * static_cast<T>(exponent)) : t;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct str_equal {
|
||||||
|
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs == t_rhs; }
|
||||||
|
template<typename LHS, typename RHS>
|
||||||
|
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
||||||
|
return std::equal(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
|
||||||
|
}
|
||||||
|
struct is_transparent {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct str_less {
|
||||||
|
[[nodiscard]] bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { return t_lhs < t_rhs; }
|
||||||
|
template<typename LHS, typename RHS>
|
||||||
|
[[nodiscard]] constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept {
|
||||||
|
return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end());
|
||||||
|
}
|
||||||
|
struct is_transparent {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Options {
|
||||||
|
No_Load_Modules,
|
||||||
|
Load_Modules,
|
||||||
|
No_External_Scripts,
|
||||||
|
External_Scripts
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename From, typename To>
|
||||||
|
struct is_nothrow_forward_constructible : std::bool_constant<noexcept(To{std::declval<From>()})> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class From, class To>
|
||||||
|
static inline constexpr bool is_nothrow_forward_constructible_v = is_nothrow_forward_constructible<From, To>::value;
|
||||||
|
|
||||||
|
template<typename Container, typename... T>
|
||||||
|
[[nodiscard]] constexpr auto make_container(T &&...t) {
|
||||||
|
Container c;
|
||||||
|
c.reserve(sizeof...(t));
|
||||||
|
(c.push_back(std::forward<T>(t)), ...);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
[[nodiscard]] auto make_vector(T &&...t) -> std::vector<std::common_type_t<std::decay_t<T>...>> {
|
||||||
|
using container_type = std::vector<std::common_type_t<std::decay_t<T>...>>;
|
||||||
|
|
||||||
|
return make_container<container_type>(std::forward<T>(t)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] 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
|
||||||
|
}
|
||||||
|
} // namespace chaiscript
|
||||||
|
#endif
|
||||||
|
|||||||
@ -7,36 +7,60 @@
|
|||||||
#ifndef CHAISCRIPT_STDLIB_HPP_
|
#ifndef CHAISCRIPT_STDLIB_HPP_
|
||||||
#define CHAISCRIPT_STDLIB_HPP_
|
#define CHAISCRIPT_STDLIB_HPP_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "chaiscript_defines.hpp"
|
#include "chaiscript_defines.hpp"
|
||||||
|
#include "language/chaiscript_common.hpp"
|
||||||
|
|
||||||
|
#include "dispatchkit/function_call.hpp"
|
||||||
|
|
||||||
|
//#include "dispatchkit/dispatchkit.hpp"
|
||||||
#include "dispatchkit/bootstrap.hpp"
|
#include "dispatchkit/bootstrap.hpp"
|
||||||
#include "dispatchkit/bootstrap_stl.hpp"
|
#include "dispatchkit/bootstrap_stl.hpp"
|
||||||
|
#include "dispatchkit/operators.hpp"
|
||||||
|
//#include "dispatchkit/boxed_value.hpp"
|
||||||
|
#include "dispatchkit/register_function.hpp"
|
||||||
|
#include "language/chaiscript_prelude.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.
|
/// This file generates the standard library that normal ChaiScript usage requires.
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
class Std_Lib {
|
||||||
class Std_Lib
|
public:
|
||||||
{
|
[[nodiscard]] static ModulePtr library() {
|
||||||
public:
|
auto lib = std::make_shared<Module>();
|
||||||
|
bootstrap::Bootstrap::bootstrap(*lib);
|
||||||
|
|
||||||
static ModulePtr library()
|
bootstrap::standard_library::vector_type<std::vector<Boxed_Value>>("Vector", *lib);
|
||||||
{
|
bootstrap::standard_library::string_type<std::string>("string", *lib);
|
||||||
using namespace bootstrap;
|
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);
|
||||||
ModulePtr lib = Bootstrap::bootstrap();
|
|
||||||
|
|
||||||
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"));
|
|
||||||
|
|
||||||
return lib;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#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
|
#endif
|
||||||
|
|
||||||
|
json_wrap::library(*lib);
|
||||||
|
|
||||||
|
lib->eval(ChaiScript_Prelude::chaiscript_prelude() /*, "standard prelude"*/);
|
||||||
|
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,20 +1,28 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_THREADING_HPP_
|
||||||
#define CHAISCRIPT_THREADING_HPP_
|
#define CHAISCRIPT_THREADING_HPP_
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
#include <thread>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <thread>
|
||||||
#else
|
#else
|
||||||
#pragma message ("ChaiScript is compiling without thread safety.")
|
#ifndef CHAISCRIPT_NO_THREADS_WARNING
|
||||||
|
#pragma message("ChaiScript is compiling without thread safety.")
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "chaiscript_defines.hpp"
|
||||||
|
|
||||||
/// \file
|
/// \file
|
||||||
///
|
///
|
||||||
@ -24,153 +32,102 @@
|
|||||||
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
|
/// It also has the side effect that the chaiscript::ChaiScript object may not be accessed from more than
|
||||||
/// one thread simultaneously.
|
/// one thread simultaneously.
|
||||||
|
|
||||||
namespace chaiscript
|
/// If threading is enabled, then this namespace contains std thread classes.
|
||||||
{
|
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
|
||||||
namespace detail
|
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
|
||||||
{
|
namespace chaiscript::detail::threading {
|
||||||
/// If threading is enabled, then this namespace contains std thread classes.
|
|
||||||
/// If threading is not enabled, then stubbed in wrappers that do nothing are provided.
|
|
||||||
/// This allows us to avoid \#ifdef code in the sections that need thread safety.
|
|
||||||
namespace threading
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_NO_THREADS
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class unique_lock : public std::unique_lock<T>
|
using unique_lock = std::unique_lock<T>;
|
||||||
{
|
|
||||||
public:
|
|
||||||
unique_lock(T &t) : std::unique_lock<T>(t) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class shared_lock : public std::unique_lock<T>
|
using shared_lock = std::shared_lock<T>;
|
||||||
{
|
|
||||||
public:
|
|
||||||
shared_lock(T &t) : std::unique_lock<T>(t) {}
|
|
||||||
void unlock() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class lock_guard : public std::lock_guard<T>
|
using lock_guard = std::lock_guard<T>;
|
||||||
{
|
|
||||||
public:
|
|
||||||
lock_guard(T &t) : std::lock_guard<T>(t) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class shared_mutex : public std::mutex { };
|
using std::shared_mutex;
|
||||||
|
|
||||||
using std::mutex;
|
using std::mutex;
|
||||||
|
|
||||||
using std::recursive_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.
|
||||||
|
template<typename T>
|
||||||
|
class Thread_Storage {
|
||||||
|
public:
|
||||||
|
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() { t().erase(this); }
|
||||||
|
|
||||||
/// Typesafe thread specific storage. If threading is enabled, this class uses a mutex protected map. If
|
inline const T *operator->() const noexcept { return &(t()[this]); }
|
||||||
/// 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
|
|
||||||
{
|
|
||||||
return get_tls().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T &operator*() const
|
inline const T &operator*() const noexcept { return t()[this]; }
|
||||||
{
|
|
||||||
return *get_tls();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
inline T *operator->() noexcept { return &(t()[this]); }
|
||||||
|
|
||||||
private:
|
inline T &operator*() noexcept { return t()[this]; }
|
||||||
std::shared_ptr<T> get_tls() const
|
|
||||||
{
|
|
||||||
|
|
||||||
unique_lock<mutex> lock(m_mutex);
|
|
||||||
|
|
||||||
auto itr = m_instances.find(std::this_thread::get_id());
|
|
||||||
|
|
||||||
if (itr != m_instances.end()) { return itr->second; }
|
void *m_key;
|
||||||
|
|
||||||
std::shared_ptr<T> new_instance(new T());
|
|
||||||
|
|
||||||
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
private:
|
||||||
|
/// todo: is it valid to make this noexcept? The allocation could fail, but if it
|
||||||
return new_instance;
|
/// does there is no possible way to recover
|
||||||
|
static std::unordered_map<const void *, T> &t() noexcept {
|
||||||
|
static thread_local std::unordered_map<const void *, T> my_t;
|
||||||
/*
|
return my_t;
|
||||||
static __thread std::shared_ptr<T> *m_data = 0;
|
|
||||||
|
|
||||||
if (!m_data) { m_data = new std::shared_ptr<T>(new T()); }
|
|
||||||
|
|
||||||
return *m_data;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
mutable mutex m_mutex;
|
|
||||||
mutable std::unordered_map<std::thread::id, std::shared_ptr<T> > m_instances;
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
template<typename T>
|
|
||||||
class unique_lock
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
unique_lock(T &) {}
|
|
||||||
void lock() {}
|
|
||||||
void unlock() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class shared_lock
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
shared_lock(T &) {}
|
|
||||||
void lock() {}
|
|
||||||
void unlock() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class lock_guard
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
lock_guard(T &) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class shared_mutex { };
|
|
||||||
|
|
||||||
class recursive_mutex {};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class Thread_Storage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
inline T *operator->() const
|
|
||||||
{
|
|
||||||
return &obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline T &operator*() const
|
|
||||||
{
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable T obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
#else // threading disabled
|
||||||
|
template<typename T>
|
||||||
|
class unique_lock {
|
||||||
|
public:
|
||||||
|
constexpr explicit unique_lock(T &) noexcept {}
|
||||||
|
constexpr void lock() noexcept {}
|
||||||
|
constexpr void unlock() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class shared_lock {
|
||||||
|
public:
|
||||||
|
constexpr explicit shared_lock(T &) noexcept {}
|
||||||
|
constexpr void lock() noexcept {}
|
||||||
|
constexpr void unlock() noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class lock_guard {
|
||||||
|
public:
|
||||||
|
constexpr explicit lock_guard(T &) noexcept {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class shared_mutex {
|
||||||
|
};
|
||||||
|
|
||||||
|
class recursive_mutex {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Thread_Storage {
|
||||||
|
public:
|
||||||
|
constexpr explicit Thread_Storage() noexcept {}
|
||||||
|
|
||||||
|
constexpr inline T *operator->() const noexcept { return &obj; }
|
||||||
|
|
||||||
|
constexpr inline T &operator*() const noexcept { return obj; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable T obj;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
} // namespace chaiscript::detail::threading
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -7,161 +7,109 @@
|
|||||||
#ifndef CHAISCRIPT_ANY_HPP_
|
#ifndef CHAISCRIPT_ANY_HPP_
|
||||||
#define CHAISCRIPT_ANY_HPP_
|
#define CHAISCRIPT_ANY_HPP_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
namespace exception
|
namespace exception {
|
||||||
{
|
|
||||||
/// \brief Thrown in the event that an Any cannot be cast to the desired type
|
/// \brief Thrown in the event that an Any cannot be cast to the desired type
|
||||||
///
|
///
|
||||||
/// It is used internally during function dispatch.
|
/// It is used internally during function dispatch.
|
||||||
///
|
///
|
||||||
/// \sa chaiscript::detail::Any
|
/// \sa chaiscript::detail::Any
|
||||||
class bad_any_cast : public std::bad_cast
|
class bad_any_cast : public std::bad_cast {
|
||||||
{
|
public:
|
||||||
public:
|
/// \brief Description of what error occurred
|
||||||
bad_any_cast() CHAISCRIPT_NOEXCEPT
|
const char *what() const noexcept override { return "bad any cast"; }
|
||||||
: m_what("bad any cast")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~bad_any_cast() CHAISCRIPT_NOEXCEPT {}
|
|
||||||
|
|
||||||
/// \brief Description of what error occured
|
|
||||||
virtual const char * what() const CHAISCRIPT_NOEXCEPT
|
|
||||||
{
|
|
||||||
return m_what.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_what;
|
|
||||||
};
|
};
|
||||||
}
|
} // namespace exception
|
||||||
|
|
||||||
|
|
||||||
class Any {
|
class Any {
|
||||||
private:
|
private:
|
||||||
struct Data
|
struct Data {
|
||||||
{
|
constexpr explicit Data(const std::type_info &t_type) noexcept
|
||||||
virtual ~Data() {}
|
: m_type(t_type) {
|
||||||
virtual void *data() = 0;
|
|
||||||
virtual const std::type_info &type() const = 0;
|
|
||||||
virtual std::shared_ptr<Data> clone() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Data_Impl : Data
|
|
||||||
{
|
|
||||||
Data_Impl(const T &t_type)
|
|
||||||
: m_type(typeid(T)),
|
|
||||||
m_data(t_type)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Data_Impl() {}
|
|
||||||
|
|
||||||
virtual void *data()
|
|
||||||
{
|
|
||||||
return &m_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::type_info &type() const
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// construct/copy/destruct
|
|
||||||
Any() = default;
|
|
||||||
|
|
||||||
Any(const Any &t_any)
|
|
||||||
{
|
|
||||||
if (!t_any.empty())
|
|
||||||
{
|
|
||||||
m_data = t_any.m_data->clone();
|
|
||||||
} else {
|
|
||||||
m_data.reset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ValueType>
|
Data &operator=(const Data &) = delete;
|
||||||
Any(const ValueType &t_value)
|
|
||||||
: m_data(std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value)))
|
virtual ~Data() noexcept = default;
|
||||||
{
|
|
||||||
|
virtual void *data() noexcept = 0;
|
||||||
|
|
||||||
|
const std::type_info &type() const noexcept { return m_type; }
|
||||||
|
|
||||||
|
virtual std::unique_ptr<Data> clone() const = 0;
|
||||||
|
const std::type_info &m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Data_Impl : Data {
|
||||||
|
explicit Data_Impl(T t_type)
|
||||||
|
: Data(typeid(T))
|
||||||
|
, m_data(std::move(t_type)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Any & operator=(const Any &t_any)
|
void *data() noexcept override { return &m_data; }
|
||||||
{
|
|
||||||
Any copy(t_any);
|
std::unique_ptr<Data> clone() const override { return std::make_unique<Data_Impl<T>>(m_data); }
|
||||||
swap(copy);
|
|
||||||
return *this;
|
Data_Impl &operator=(const Data_Impl &) = delete;
|
||||||
|
|
||||||
|
T m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Data> m_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// construct/copy/destruct
|
||||||
|
constexpr Any() noexcept = default;
|
||||||
|
Any(Any &&) noexcept = default;
|
||||||
|
Any &operator=(Any &&t_any) = default;
|
||||||
|
|
||||||
|
Any(const Any &t_any)
|
||||||
|
: m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType, typename = std::enable_if_t<!std::is_same_v<Any, std::decay_t<ValueType>>>>
|
||||||
|
explicit Any(ValueType &&t_value)
|
||||||
|
: m_data(std::make_unique<Data_Impl<std::decay_t<ValueType>>>(std::forward<ValueType>(t_value))) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Any &operator=(const Any &t_any) {
|
||||||
|
Any copy(t_any);
|
||||||
|
swap(copy);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ToType>
|
||||||
|
ToType &cast() const {
|
||||||
|
if (m_data && typeid(ToType) == m_data->type()) {
|
||||||
|
return *static_cast<ToType *>(m_data->data());
|
||||||
|
} else {
|
||||||
|
throw chaiscript::detail::exception::bad_any_cast();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ValueType>
|
// modifiers
|
||||||
Any & operator=(const ValueType &t_value)
|
Any &swap(Any &t_other) {
|
||||||
{
|
std::swap(t_other.m_data, m_data);
|
||||||
m_data = std::shared_ptr<Data>(new Data_Impl<ValueType>(t_value));
|
return *this;
|
||||||
return *this;
|
}
|
||||||
}
|
|
||||||
|
// queries
|
||||||
template<typename ToType>
|
bool empty() const noexcept { return !static_cast<bool>(m_data); }
|
||||||
ToType &cast() const
|
|
||||||
{
|
const std::type_info &type() const noexcept {
|
||||||
if (m_data && typeid(ToType) == m_data->type())
|
if (m_data) {
|
||||||
{
|
return m_data->type();
|
||||||
return *static_cast<ToType *>(m_data->data());
|
} else {
|
||||||
} else {
|
return typeid(void);
|
||||||
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;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// queries
|
|
||||||
bool empty() const
|
|
||||||
{
|
|
||||||
return !bool(m_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::type_info & type() const
|
|
||||||
{
|
|
||||||
if (m_data)
|
|
||||||
{
|
|
||||||
return m_data->type();
|
|
||||||
} else {
|
|
||||||
return typeid(void);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace detail
|
||||||
}
|
} // namespace chaiscript
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,60 +1,64 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||||
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
#define CHAISCRIPT_BAD_BOXED_CAST_HPP_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
#include "../chaiscript_defines.hpp"
|
||||||
|
#include "../utility/static_string.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
class Type_Info;
|
||||||
namespace exception
|
} // namespace chaiscript
|
||||||
{
|
|
||||||
|
namespace chaiscript {
|
||||||
|
namespace exception {
|
||||||
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
|
/// \brief Thrown in the event that a Boxed_Value cannot be cast to the desired type
|
||||||
///
|
///
|
||||||
/// It is used internally during function dispatch and may be used by the end user.
|
/// It is used internally during function dispatch and may be used by the end user.
|
||||||
///
|
///
|
||||||
/// \sa chaiscript::boxed_cast
|
/// \sa chaiscript::boxed_cast
|
||||||
class bad_boxed_cast : public std::bad_cast
|
class bad_boxed_cast : public std::bad_cast {
|
||||||
{
|
public:
|
||||||
public:
|
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, utility::Static_String t_what) noexcept
|
||||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to,
|
: from(t_from)
|
||||||
const std::string &t_what) CHAISCRIPT_NOEXCEPT
|
, to(&t_to)
|
||||||
: from(t_from), to(&t_to), m_what(t_what)
|
, m_what(std::move(t_what)) {
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) CHAISCRIPT_NOEXCEPT
|
bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept
|
||||||
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
|
: from(t_from)
|
||||||
{
|
, to(&t_to)
|
||||||
}
|
, m_what("Cannot perform boxed_cast") {
|
||||||
|
}
|
||||||
|
|
||||||
bad_boxed_cast(const std::string &t_what) CHAISCRIPT_NOEXCEPT
|
explicit bad_boxed_cast(utility::Static_String t_what) noexcept
|
||||||
: to(0), m_what(t_what)
|
: m_what(std::move(t_what)) {
|
||||||
{
|
}
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~bad_boxed_cast() CHAISCRIPT_NOEXCEPT {}
|
bad_boxed_cast(const bad_boxed_cast &) noexcept = default;
|
||||||
|
~bad_boxed_cast() noexcept override = default;
|
||||||
|
|
||||||
/// \brief Description of what error occured
|
/// \brief Description of what error occurred
|
||||||
virtual const char * what() const CHAISCRIPT_NOEXCEPT
|
const char *what() const noexcept override { return m_what.c_str(); }
|
||||||
{
|
|
||||||
return m_what.c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
Type_Info from; ///< Type_Info contained in the Boxed_Value
|
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:
|
private:
|
||||||
std::string m_what;
|
utility::Static_String m_what;
|
||||||
};
|
};
|
||||||
}
|
} // namespace exception
|
||||||
}
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,133 +1,60 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_BIND_FIRST_HPP_
|
||||||
#define CHAISCRIPT_BIND_FIRST_HPP_
|
#define CHAISCRIPT_BIND_FIRST_HPP_
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
namespace detail {
|
||||||
namespace detail
|
template<typename T>
|
||||||
{
|
constexpr T *get_pointer(T *t) noexcept {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
template<int>
|
template<typename T>
|
||||||
struct Placeholder
|
T *get_pointer(const std::reference_wrapper<T> &t) noexcept {
|
||||||
{
|
return &t.get();
|
||||||
};
|
}
|
||||||
|
|
||||||
template<>
|
template<typename O, typename Ret, typename P1, typename... Param>
|
||||||
struct Placeholder<1>
|
constexpr auto bind_first(Ret (*f)(P1, Param...), O &&o) {
|
||||||
{
|
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
|
||||||
static decltype(std::placeholders::_1) value() { return std::placeholders::_1; }
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<typename O, typename Ret, typename Class, typename... Param>
|
||||||
struct Placeholder<2>
|
constexpr auto bind_first(Ret (Class::*f)(Param...), O &&o) {
|
||||||
{
|
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
|
||||||
static decltype(std::placeholders::_2) value() { return std::placeholders::_2; }
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<typename O, typename Ret, typename Class, typename... Param>
|
||||||
struct Placeholder<3>
|
constexpr auto bind_first(Ret (Class::*f)(Param...) const, O &&o) {
|
||||||
{
|
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return (get_pointer(o)->*f)(std::forward<Param>(param)...); };
|
||||||
static decltype(std::placeholders::_3) value() { return std::placeholders::_3; }
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<typename O, typename Ret, typename P1, typename... Param>
|
||||||
struct Placeholder<4>
|
auto bind_first(const std::function<Ret(P1, Param...)> &f, O &&o) {
|
||||||
{
|
return [f, o = std::forward<O>(o)](Param... param) -> Ret { return f(o, std::forward<Param>(param)...); };
|
||||||
static decltype(std::placeholders::_4) value() { return std::placeholders::_4; }
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<typename F, typename O, typename Ret, typename Class, typename P1, typename... Param>
|
||||||
struct Placeholder<5>
|
constexpr auto bind_first(const F &fo, O &&o, Ret (Class::*f)(P1, Param...) const) {
|
||||||
{
|
return [fo, o = std::forward<O>(o), f](Param... param) -> Ret { return (fo.*f)(o, std::forward<Param>(param)...); };
|
||||||
static decltype(std::placeholders::_5) value() { return std::placeholders::_5; }
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<typename F, typename O>
|
||||||
struct Placeholder<6>
|
constexpr auto bind_first(const F &f, O &&o) {
|
||||||
{
|
return bind_first(f, std::forward<O>(o), &F::operator());
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename O, typename Ret, typename Class, typename ... Param>
|
|
||||||
std::function<Ret (Param...)> bind_first(Ret (Class::*f)(Param...), O o)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename O, typename Ret, typename P1, typename ... Param>
|
|
||||||
std::function<Ret (Param...)> bind_first(const std::function<Ret (P1, Param...)> &f, O o)
|
|
||||||
{
|
|
||||||
return Bind_First<sizeof...(Param), sizeof...(Param), Ret (Param...)>::bind(f, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,472 +1,511 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_BOOTSTRAP_HPP_
|
||||||
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
#define CHAISCRIPT_BOOTSTRAP_HPP_
|
||||||
|
|
||||||
#include "dispatchkit.hpp"
|
#include "../utility/utility.hpp"
|
||||||
#include "dynamic_object.hpp"
|
|
||||||
#include "register_function.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 chaiscript::bootstrap {
|
||||||
/// \brief Classes and functions useful for bootstrapping of ChaiScript and adding of new types
|
template<typename T, typename = typename std::enable_if<std::is_array<T>::value>::type>
|
||||||
namespace bootstrap
|
void array(const std::string &type, Module &m) {
|
||||||
{
|
using ReturnType = typename std::remove_extent<T>::type;
|
||||||
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)
|
|
||||||
{
|
|
||||||
std::shared_ptr<P1> p(new P1());
|
|
||||||
Boxed_Value bv(p);
|
|
||||||
Boxed_Number nb(bv);
|
|
||||||
nb = v;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Adds a copy constructor for the given type to the given Model
|
m.add(user_type<T>(), type);
|
||||||
/// \param[in] type The name of the type. The copy constructor will be named "type".
|
m.add(fun([](T &t, size_t index) -> ReturnType & {
|
||||||
/// \param[in,out] m The Module to add the copy constructor to
|
constexpr const auto extent = std::extent<T>::value;
|
||||||
/// \tparam T The type to add a copy constructor for
|
if (extent > 0 && index >= extent) {
|
||||||
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
||||||
template<typename T>
|
+ std::to_string(extent));
|
||||||
ModulePtr copy_constructor(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
} else {
|
||||||
{
|
return t[index];
|
||||||
m->add(constructor<T (const T &)>(), type);
|
}
|
||||||
return m;
|
}),
|
||||||
}
|
"[]");
|
||||||
|
|
||||||
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
m.add(fun([](const T &t, size_t index) -> const ReturnType & {
|
||||||
/// \tparam T Type to create comparison operators for
|
constexpr const auto extent = std::extent<T>::value;
|
||||||
/// \param[in,out] m module to add comparison operators to
|
if (extent > 0 && index >= extent) {
|
||||||
/// \returns the passed in ModulePtr or the newly constructed one if the default params are used.
|
throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < "
|
||||||
template<typename T>
|
+ std::to_string(extent));
|
||||||
ModulePtr opers_comparison(ModulePtr m = ModulePtr(new Module()))
|
} else {
|
||||||
{
|
return t[index];
|
||||||
operators::equal<T>(m);
|
}
|
||||||
operators::greater_than<T>(m);
|
}),
|
||||||
operators::greater_than_equal<T>(m);
|
"[]");
|
||||||
operators::less_than<T>(m);
|
|
||||||
operators::less_than_equal<T>(m);
|
|
||||||
operators::not_equal<T>(m);
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
m.add(fun([](const T &) { return std::extent<T>::value; }), "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 Module
|
||||||
|
template<typename T>
|
||||||
|
void copy_constructor(const std::string &type, Module &m) {
|
||||||
|
m.add(constructor<T(const T &)>(), type);
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Adds default and copy constructors for the given type
|
/// \brief Add all comparison operators for the templated type. Used during bootstrap, also available to users.
|
||||||
/// \param[in] type The name of the type to add the constructors for.
|
/// \tparam T Type to create comparison operators for
|
||||||
/// \param[in,out] m The Module to add the basic constructors to
|
/// \param[in,out] m module to add comparison operators to
|
||||||
/// \tparam T Type to generate basic constructors for
|
/// \returns the passed in Module.
|
||||||
/// \returns The passed in ModulePtr, or the newly constructed one if the default param is used
|
template<typename T>
|
||||||
/// \sa copy_constructor
|
void opers_comparison(Module &m) {
|
||||||
/// \sa constructor
|
operators::equal<T>(m);
|
||||||
template<typename T>
|
operators::greater_than<T>(m);
|
||||||
ModulePtr basic_constructors(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
operators::greater_than_equal<T>(m);
|
||||||
{
|
operators::less_than<T>(m);
|
||||||
m->add(constructor<T ()>(), type);
|
operators::less_than_equal<T>(m);
|
||||||
copy_constructor<T>(type, m);
|
operators::not_equal<T>(m);
|
||||||
return m;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Adds a constructor for a POD type
|
/// \brief Adds default and copy constructors for the given type
|
||||||
/// \tparam T The type to add the constructor for
|
/// \param[in] type The name of the type to add the constructors for.
|
||||||
/// \param[in] type The name of the type
|
/// \param[in,out] m The Module to add the basic constructors to
|
||||||
/// \param[in,out] m The Module to add the constructor to
|
/// \tparam T Type to generate basic constructors for
|
||||||
template<typename T>
|
/// \returns The passed in Module
|
||||||
ModulePtr construct_pod(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
/// \sa copy_constructor
|
||||||
{
|
/// \sa constructor
|
||||||
m->add(fun(&detail::construct_pod<T>), type);
|
template<typename T>
|
||||||
return m;
|
void basic_constructors(const std::string &type, Module &m) {
|
||||||
}
|
m.add(constructor<T()>(), type);
|
||||||
|
copy_constructor<T>(type, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Adds a constructor for a POD type
|
||||||
|
/// \tparam T The type to add the constructor for
|
||||||
|
/// \param[in] type The name of the type
|
||||||
|
/// \param[in,out] m The Module to add the constructor to
|
||||||
|
template<typename T>
|
||||||
|
void construct_pod(const std::string &type, Module &m) {
|
||||||
|
m.add(fun([](const Boxed_Number &bn) { return bn.get_as<T>(); }), type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/// Internal function for converting from a string to a value
|
||||||
* to_string function for internal use. Uses ostream operator<<
|
/// uses ostream operator >> to perform the conversion
|
||||||
*/
|
template<typename Input>
|
||||||
template<typename Input>
|
Input parse_string(const std::string &i) {
|
||||||
std::string to_string(Input i)
|
if constexpr (!std::is_same<Input, wchar_t>::value && !std::is_same<Input, char16_t>::value && !std::is_same<Input, char32_t>::value) {
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
std::stringstream ss(i);
|
std::stringstream ss(i);
|
||||||
Input t;
|
Input t;
|
||||||
ss >> t;
|
ss >> t;
|
||||||
return t;
|
return t;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Parsing of wide characters is not yet supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "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)
|
|
||||||
{
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
template<typename Type>
|
|
||||||
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs)
|
|
||||||
{
|
|
||||||
if (lhs.is_undef()
|
|
||||||
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
|
|
||||||
{
|
|
||||||
lhs.assign(Boxed_Value(rhs));
|
|
||||||
return lhs;
|
|
||||||
} else {
|
|
||||||
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs)
|
|
||||||
{
|
|
||||||
if (lhs.is_undef())
|
|
||||||
{
|
|
||||||
return (lhs.assign(rhs));
|
|
||||||
} else {
|
|
||||||
throw exception::bad_boxed_cast("boxed_value has a set type already");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print(const std::string &s)
|
|
||||||
{
|
|
||||||
std::cout << s;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void println(const std::string &s)
|
|
||||||
{
|
|
||||||
std::cout << s << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add all arithmetic operators for PODs
|
|
||||||
*/
|
|
||||||
static void opers_arithmetic_pod(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
|
||||||
|
|
||||||
return Boxed_Value(Const_Proxy_Function(new dispatch::Bound_Function(f,
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (pf->get_guard()) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (pf->get_guard())
|
|
||||||
{
|
|
||||||
return pf->get_guard();
|
|
||||||
} else {
|
|
||||||
throw std::runtime_error("Function does not have a 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)
|
|
||||||
{
|
|
||||||
auto v = (b->*f)();
|
|
||||||
|
|
||||||
std::vector<Boxed_Value> vbv;
|
|
||||||
|
|
||||||
for (const auto &o: v)
|
|
||||||
{
|
|
||||||
vbv.push_back(const_var(o));
|
|
||||||
}
|
|
||||||
|
|
||||||
return vbv;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Function>
|
|
||||||
static std::function<std::vector<Boxed_Value> (const dispatch::Proxy_Function_Base*)> return_boxed_value_vector(const Function &f)
|
|
||||||
{
|
|
||||||
return std::bind(&do_return_boxed_value_vector<Function>, f, std::placeholders::_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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()))
|
|
||||||
{
|
|
||||||
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(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==), "==");
|
|
||||||
|
|
||||||
|
|
||||||
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(user_type<std::runtime_error>(), "runtime_error");
|
|
||||||
m->add(chaiscript::base_class<std::exception, std::runtime_error>());
|
|
||||||
|
|
||||||
|
|
||||||
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(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->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(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_type), "is_type");
|
|
||||||
|
|
||||||
m->add(fun(&Boxed_Value::get_type_info), "get_type_info");
|
|
||||||
m->add(user_type<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");
|
|
||||||
|
|
||||||
|
|
||||||
basic_constructors<bool>("bool", m);
|
|
||||||
operators::assign<bool>(m);
|
|
||||||
operators::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");
|
|
||||||
|
|
||||||
bootstrap_pod_type<double>("double", m);
|
|
||||||
bootstrap_pod_type<long double>("long_double", m);
|
|
||||||
bootstrap_pod_type<float>("float", m);
|
|
||||||
bootstrap_pod_type<int>("int", m);
|
|
||||||
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<size_t>("size_t", m);
|
|
||||||
bootstrap_pod_type<char>("char", 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);
|
|
||||||
bootstrap_pod_type<std::int64_t>("int64_t", m);
|
|
||||||
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
|
|
||||||
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
|
|
||||||
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(&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(&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(fun(&Boxed_Value::type_match), "type_match");
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// 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);
|
||||||
|
m.add(fun([](const T t) { return 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>
|
||||||
|
auto shared_ptr_clone(const std::shared_ptr<Type> &p) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specific version of shared_ptr_clone just for Proxy_Functions
|
||||||
|
template<typename Type>
|
||||||
|
std::shared_ptr<std::remove_const_t<Type>> shared_ptr_unconst_clone(const std::shared_ptr<std::add_const_t<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.
|
||||||
|
template<typename Type>
|
||||||
|
Boxed_Value ptr_assign(Boxed_Value lhs, const std::shared_ptr<Type> &rhs) {
|
||||||
|
if (lhs.is_undef() || (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get()))) {
|
||||||
|
lhs.assign(Boxed_Value(rhs));
|
||||||
|
return lhs;
|
||||||
|
} else {
|
||||||
|
throw exception::bad_boxed_cast("type mismatch in pointer assignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
static Boxed_Value unknown_assign(Boxed_Value lhs, Boxed_Value rhs) {
|
||||||
|
if (lhs.is_undef()) {
|
||||||
|
return (lhs.assign(rhs));
|
||||||
|
} else {
|
||||||
|
throw exception::bad_boxed_cast("boxed_value has a set type already");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); }
|
||||||
|
|
||||||
|
static void println(const std::string &s) noexcept { puts(s.c_str()); }
|
||||||
|
|
||||||
|
/// 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), ">>");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 Function_Params ¶ms) {
|
||||||
|
if (params.empty()) {
|
||||||
|
throw exception::arity_error(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
|
||||||
|
|
||||||
|
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()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool has_guard(const Const_Proxy_Function &t_pf) noexcept {
|
||||||
|
auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
|
return pf && pf->has_guard();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) {
|
||||||
|
const auto pf = std::dynamic_pointer_cast<const dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
|
if (pf && pf->get_guard()) {
|
||||||
|
return pf->get_guard();
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Function does not have a guard");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FunctionType>
|
||||||
|
static std::vector<Boxed_Value> do_return_boxed_value_vector(FunctionType f, const dispatch::Proxy_Function_Base *b) {
|
||||||
|
auto v = (b->*f)();
|
||||||
|
|
||||||
|
std::vector<Boxed_Value> vbv;
|
||||||
|
|
||||||
|
for (const auto &o : v) {
|
||||||
|
vbv.push_back(const_var(o));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vbv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept {
|
||||||
|
const auto pf = std::dynamic_pointer_cast<const chaiscript::dispatch::Dynamic_Proxy_Function>(t_pf);
|
||||||
|
return bool(pf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const chaiscript::AST_Node &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) {
|
||||||
|
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 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<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::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([](const std::exception &e) { return std::string(e.what()); }), "what");
|
||||||
|
|
||||||
|
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.add(user_type<std::runtime_error>(), "runtime_error");
|
||||||
|
m.add(chaiscript::base_class<std::exception, std::runtime_error>());
|
||||||
|
|
||||||
|
m.add(constructor<std::runtime_error(const std::string &)>(), "runtime_error");
|
||||||
|
|
||||||
|
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(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");
|
||||||
|
|
||||||
|
basic_constructors<bool>("bool", m);
|
||||||
|
operators::assign<bool>(m);
|
||||||
|
operators::equal<bool>(m);
|
||||||
|
operators::not_equal<bool>(m);
|
||||||
|
|
||||||
|
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);
|
||||||
|
bootstrap_pod_type<int>("int", m);
|
||||||
|
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);
|
||||||
|
bootstrap_pod_type<std::int64_t>("int64_t", m);
|
||||||
|
bootstrap_pod_type<std::uint8_t>("uint8_t", m);
|
||||||
|
bootstrap_pod_type<std::uint16_t>("uint16_t", m);
|
||||||
|
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(dispatch::make_dynamic_proxy_function(&bind_function), "bind");
|
||||||
|
|
||||||
|
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(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 chaiscript::AST_Node_Trace &>);
|
||||||
|
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::reference_wrapper<chaiscript::AST_Node> &>);
|
||||||
|
return retval;
|
||||||
|
}),
|
||||||
|
"children"}});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace chaiscript::bootstrap
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,30 +1,36 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_BOXED_CAST_HPP_
|
||||||
#define CHAISCRIPT_BOXED_CAST_HPP_
|
#define CHAISCRIPT_BOXED_CAST_HPP_
|
||||||
|
|
||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
|
#include "bad_boxed_cast.hpp"
|
||||||
#include "type_info.hpp"
|
|
||||||
#include "boxed_value.hpp"
|
|
||||||
#include "boxed_cast_helper.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 chaiscript::detail::exception {
|
||||||
|
class bad_any_cast;
|
||||||
|
} // namespace chaiscript::detail::exception
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
|
||||||
|
|
||||||
/// \brief Function for extracting a value stored in a Boxed_Value object
|
/// \brief Function for extracting a value stored in a Boxed_Value object
|
||||||
/// \tparam Type The type to extract from the Boxed_Value
|
/// \tparam Type The type to extract from the Boxed_Value
|
||||||
/// \param[in] bv The Boxed_Value to extract a typed value from
|
/// \param[in] bv The Boxed_Value to extract a typed value from
|
||||||
/// \returns Type equivalent to the requested type
|
/// \returns Type equivalent to the requested type
|
||||||
/// \throws exception::bad_boxed_cast If the requested conversion is not possible
|
/// \throws exception::bad_boxed_cast If the requested conversion is not possible
|
||||||
///
|
///
|
||||||
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
|
/// boxed_cast will attempt to make conversions between value, &, *, std::shared_ptr, std::reference_wrapper,
|
||||||
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function
|
/// and std::function (const and non-const) where possible. boxed_cast is used internally during function
|
||||||
/// dispatch. This means that all of these conversions will be attempted automatically for you during
|
/// dispatch. This means that all of these conversions will be attempted automatically for you during
|
||||||
@ -56,52 +62,41 @@ namespace chaiscript
|
|||||||
/// std::function conversion example
|
/// std::function conversion example
|
||||||
/// \code
|
/// \code
|
||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
|
/// Boxed_Value bv = chai.eval("`+`"); // Get the functor for the + operator which is built in
|
||||||
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
|
/// std::function<int (int, int)> f = chaiscript::boxed_cast<std::function<int (int, int)> >(bv);
|
||||||
/// int i = f(2,3);
|
/// int i = f(2,3);
|
||||||
/// assert(i == 5);
|
/// assert(i == 5);
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions = nullptr)
|
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions = nullptr) {
|
||||||
{
|
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !(*t_conversions)->convertable_type<Type>())) {
|
||||||
try {
|
try {
|
||||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_conversions && (*t_conversions)->convertable_type<Type>()) {
|
||||||
#ifdef CHAISCRIPT_MSVC
|
try {
|
||||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||||
// statment in THIS VERSION of the template instantiation
|
// either way, we are not responsible if it doesn't work
|
||||||
#pragma warning(push)
|
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
|
||||||
#pragma warning(disable : 4127)
|
} catch (...) {
|
||||||
#endif
|
|
||||||
|
|
||||||
if (std::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions)
|
|
||||||
{
|
|
||||||
try {
|
try {
|
||||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
// try going the other way
|
||||||
// either way, we are not responsible if it doesn't work
|
return (detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv),
|
||||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
|
t_conversions));
|
||||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
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 {
|
||||||
#ifdef CHAISCRIPT_MSVC
|
// If it's not convertable, just throw the error, don't waste the time on the
|
||||||
#pragma warning(pop)
|
// attempted dynamic_cast
|
||||||
#endif
|
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,272 +1,260 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_BOXED_CAST_HELPER_HPP_
|
||||||
#define 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 "boxed_value.hpp"
|
||||||
|
#include "type_info.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
class Type_Conversions_State;
|
||||||
|
|
||||||
namespace chaiscript
|
namespace detail {
|
||||||
{
|
|
||||||
class Dynamic_Cast_Conversions;
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
// Cast_Helper_Inner helper classes
|
// Cast_Helper_Inner helper classes
|
||||||
|
|
||||||
/**
|
|
||||||
* 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, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
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> >()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
if (ob.is_ref())
|
|
||||||
{
|
|
||||||
return &(ob.get().cast<std::reference_wrapper<Result> >()).get();
|
|
||||||
} else {
|
|
||||||
return (ob.get().cast<std::shared_ptr<Result> >()).get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
if (ob.is_ref())
|
|
||||||
{
|
|
||||||
return ob.get().cast<std::reference_wrapper<Result> >();
|
|
||||||
} else {
|
|
||||||
Result &r = *(ob.get().cast<std::shared_ptr<Result> >());
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cast_Helper_Inner for casting to a std::shared_ptr<> type
|
|
||||||
*/
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<typename std::shared_ptr<Result> >
|
|
||||||
{
|
|
||||||
typedef typename std::shared_ptr<Result> Result_Type;
|
|
||||||
|
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
return ob.get().cast<std::shared_ptr<Result> >();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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> >
|
|
||||||
{
|
|
||||||
typedef typename std::shared_ptr<const Result> Result_Type;
|
|
||||||
|
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
if (!ob.get_type_info().is_const())
|
|
||||||
{
|
|
||||||
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result> >());
|
|
||||||
} else {
|
|
||||||
return ob.get().cast<std::shared_ptr<const Result> >();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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> >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result> >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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> >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result> >
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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, const Dynamic_Cast_Conversions *)
|
|
||||||
{
|
|
||||||
return 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>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 &>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<Result> > : Cast_Helper_Inner<Result &>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> > : Cast_Helper_Inner<const Result &>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result>
|
|
||||||
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> & > : Cast_Helper_Inner<const Result &>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
|
||||||
*/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Cast_Helper
|
constexpr T *throw_if_null(T *t) {
|
||||||
{
|
if (t) {
|
||||||
typedef typename Cast_Helper_Inner<T>::Result_Type Result_Type;
|
return t;
|
||||||
|
}
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
|
throw std::runtime_error("Attempted to dereference null Boxed_Value");
|
||||||
{
|
}
|
||||||
return Cast_Helper_Inner<T>::cast(ob, t_conversions);
|
|
||||||
|
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 {
|
||||||
|
static Result cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||||
|
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 *> {
|
||||||
|
static const Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||||
|
return static_cast<const Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_const_ptr()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Cast_Helper_Inner for casting to a * type
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<Result *> {
|
||||||
|
static Result *cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||||
|
return static_cast<Result *>(verify_type_no_throw(ob, typeid(Result), ob.get_ptr()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 &> {
|
||||||
|
static Result &cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||||
|
return *static_cast<Result *>(verify_type(ob, typeid(Result), ob.get_ptr()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Cast_Helper_Inner for casting to a && type
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<Result &&> {
|
||||||
|
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())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
||||||
|
static auto cast(const Boxed_Value &ob, const Type_Conversions_State *) {
|
||||||
|
if (!ob.get_type_info().is_const()) {
|
||||||
|
return std::const_pointer_cast<const Result>(ob.get().cast<std::shared_ptr<Result>>());
|
||||||
|
} else {
|
||||||
|
return ob.get().cast<std::shared_ptr<const Result>>();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
}
|
/// 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>> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::shared_ptr<Result> &> : Cast_Helper_Inner<std::shared_ptr<Result>> {
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::shared_ptr<const Result>> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::shared_ptr<const Result> &> : Cast_Helper_Inner<std::shared_ptr<const Result>> {
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Cast_Helper_Inner for casting to a Boxed_Value type
|
||||||
|
template<>
|
||||||
|
struct Cast_Helper_Inner<Boxed_Value> {
|
||||||
|
static Boxed_Value cast(const Boxed_Value &ob, const Type_Conversions_State *) { return ob; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Cast_Helper_Inner<const Boxed_Value &> : Cast_Helper_Inner<Boxed_Value> {
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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 &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::reference_wrapper<Result>> : Cast_Helper_Inner<Result &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::reference_wrapper<Result> &> : Cast_Helper_Inner<Result &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::reference_wrapper<const Result>> : Cast_Helper_Inner<const Result &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
struct Cast_Helper_Inner<const std::reference_wrapper<const Result> &> : Cast_Helper_Inner<const Result &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner
|
||||||
|
template<typename T>
|
||||||
|
struct Cast_Helper {
|
||||||
|
static decltype(auto) cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
||||||
|
return (Cast_Helper_Inner<T>::cast(ob, t_conversions));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,288 +1,282 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_BOXED_VALUE_HPP_
|
||||||
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
#define CHAISCRIPT_BOXED_VALUE_HPP_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "../chaiscript_defines.hpp"
|
||||||
|
#include "any.hpp"
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
|
||||||
#include "../chaiscript_threading.hpp"
|
namespace chaiscript {
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include "any.hpp"
|
|
||||||
|
|
||||||
namespace chaiscript
|
|
||||||
{
|
|
||||||
|
|
||||||
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
|
/// \brief A wrapper for holding any valid C++ type. All types in ChaiScript are Boxed_Value objects
|
||||||
/// \sa chaiscript::boxed_cast
|
/// \sa chaiscript::boxed_cast
|
||||||
class Boxed_Value
|
class Boxed_Value {
|
||||||
{
|
public:
|
||||||
public:
|
/// used for explicitly creating a "void" object
|
||||||
/**
|
struct Void_Type {
|
||||||
* used for explicitly creating a "void" object
|
};
|
||||||
*/
|
|
||||||
struct Void_Type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
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 {
|
||||||
struct Data
|
Data(const Type_Info &ti, chaiscript::detail::Any to, bool is_ref, const void *t_void_ptr, bool t_return_value) noexcept
|
||||||
{
|
: m_type_info(ti)
|
||||||
Data(const Type_Info &ti,
|
, m_obj(std::move(to))
|
||||||
const chaiscript::detail::Any &to,
|
, m_data_ptr(ti.is_const() ? nullptr : const_cast<void *>(t_void_ptr))
|
||||||
bool tr,
|
, m_const_data_ptr(t_void_ptr)
|
||||||
const void *t_void_ptr)
|
, m_is_ref(is_ref)
|
||||||
: 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_return_value(t_return_value) {
|
||||||
m_is_ref(tr)
|
}
|
||||||
{
|
|
||||||
|
Data &operator=(const Data &rhs) {
|
||||||
|
m_type_info = rhs.m_type_info;
|
||||||
|
m_obj = rhs.m_obj;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Data &operator=(const Data &rhs)
|
return *this;
|
||||||
{
|
}
|
||||||
m_type_info = rhs.m_type_info;
|
|
||||||
m_obj = rhs.m_obj;
|
|
||||||
m_is_ref = rhs.m_is_ref;
|
|
||||||
m_data_ptr = rhs.m_data_ptr;
|
|
||||||
m_const_data_ptr = rhs.m_const_data_ptr;
|
|
||||||
|
|
||||||
return *this;
|
Data(const Data &) = delete;
|
||||||
}
|
|
||||||
|
|
||||||
~Data()
|
Data(Data &&) = default;
|
||||||
{
|
Data &operator=(Data &&rhs) = default;
|
||||||
}
|
|
||||||
|
|
||||||
Type_Info m_type_info;
|
Type_Info m_type_info;
|
||||||
chaiscript::detail::Any m_obj;
|
chaiscript::detail::Any m_obj;
|
||||||
void *m_data_ptr;
|
void *m_data_ptr;
|
||||||
const void *m_const_data_ptr;
|
const void *m_const_data_ptr;
|
||||||
bool m_is_ref;
|
std::unique_ptr<std::map<std::string, std::shared_ptr<Data>>> m_attrs;
|
||||||
};
|
bool m_is_ref;
|
||||||
|
bool m_return_value;
|
||||||
|
};
|
||||||
|
|
||||||
struct Object_Data
|
struct Object_Data {
|
||||||
{
|
static auto get(Boxed_Value::Void_Type, bool t_return_value) {
|
||||||
static std::shared_ptr<Data> get(Boxed_Value::Void_Type)
|
return std::make_shared<Data>(detail::Get_Type_Info<void>::get(), chaiscript::detail::Any(), false, nullptr, t_return_value);
|
||||||
{
|
}
|
||||||
return std::make_shared<Data>(
|
|
||||||
detail::Get_Type_Info<void>::get(),
|
|
||||||
chaiscript::detail::Any(),
|
|
||||||
false,
|
|
||||||
nullptr)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> *obj)
|
|
||||||
{
|
|
||||||
return get(*obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static std::shared_ptr<Data> get(const std::shared_ptr<T> &obj)
|
|
||||||
{
|
|
||||||
return std::make_shared<Data>(
|
|
||||||
detail::Get_Type_Info<T>::get(),
|
|
||||||
chaiscript::detail::Any(obj),
|
|
||||||
false,
|
|
||||||
obj.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static std::shared_ptr<Data> get(T *t)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
return std::make_shared<Data>(
|
|
||||||
detail::Get_Type_Info<T>::get(),
|
|
||||||
chaiscript::detail::Any(p),
|
|
||||||
false,
|
|
||||||
p.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::shared_ptr<Data> get()
|
|
||||||
{
|
|
||||||
return std::make_shared<Data>(
|
|
||||||
Type_Info(),
|
|
||||||
chaiscript::detail::Any(),
|
|
||||||
false,
|
|
||||||
nullptr
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Basic Boxed_Value constructor
|
|
||||||
*/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
explicit Boxed_Value(T t)
|
static auto get(const std::shared_ptr<T> *obj, bool t_return_value) {
|
||||||
: m_data(Object_Data::get(t))
|
return get(*obj, t_return_value);
|
||||||
{
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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(), t_return_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static auto get(std::shared_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::move(obj)), false, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<Data> get() { return std::make_shared<Data>(Type_Info(), chaiscript::detail::Any(), false, nullptr, false); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Basic Boxed_Value constructor
|
||||||
|
template<typename T, typename = std::enable_if_t<!std::is_same_v<Boxed_Value, std::decay_t<T>>>>
|
||||||
|
explicit Boxed_Value(T &&t, bool t_return_value = false)
|
||||||
|
: m_data(Object_Data::get(std::forward<T>(t), t_return_value)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unknown-type constructor
|
||||||
|
Boxed_Value() = default;
|
||||||
|
|
||||||
|
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) noexcept { 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
|
||||||
|
Boxed_Value assign(const Boxed_Value &rhs) noexcept {
|
||||||
|
(*m_data) = (*rhs.m_data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 noexcept { return m_data->m_type_info.is_undef(); }
|
||||||
|
|
||||||
|
bool is_const() const noexcept { return m_data->m_type_info.is_const(); }
|
||||||
|
|
||||||
|
bool is_type(const Type_Info &ti) const noexcept { return m_data->m_type_info.bare_equal(ti); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto pointer_sentinel(std::shared_ptr<T> &ptr) const noexcept {
|
||||||
|
struct Sentinel {
|
||||||
|
Sentinel(std::shared_ptr<T> &t_ptr, Data &data)
|
||||||
|
: m_ptr(t_ptr)
|
||||||
|
, m_data(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
~Sentinel() {
|
||||||
* Copy constructor - each copy shares the same data pointer
|
// save new pointer data
|
||||||
*/
|
const auto ptr_ = m_ptr.get().get();
|
||||||
Boxed_Value(const Boxed_Value &t_so)
|
m_data.get().m_data_ptr = ptr_;
|
||||||
: m_data(t_so.m_data)
|
m_data.get().m_const_data_ptr = ptr_;
|
||||||
{
|
}
|
||||||
|
|
||||||
|
Sentinel &operator=(Sentinel &&s) = default;
|
||||||
|
Sentinel(Sentinel &&s) = default;
|
||||||
|
|
||||||
|
operator std::shared_ptr<T> &() const noexcept { 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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 noexcept { return m_data->m_is_ref; }
|
||||||
|
|
||||||
|
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 noexcept { return m_data->m_data_ptr; }
|
||||||
|
|
||||||
|
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];
|
||||||
* Unknown-type constructor
|
if (attr) {
|
||||||
*/
|
return Boxed_Value(attr, Internal_Construction());
|
||||||
Boxed_Value()
|
} else {
|
||||||
: m_data(Object_Data::get())
|
Boxed_Value bv; // default construct a new one
|
||||||
{
|
attr = bv.m_data;
|
||||||
|
return bv;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~Boxed_Value()
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void swap(Boxed_Value &rhs)
|
Boxed_Value &clone_attrs(const Boxed_Value &t_obj) {
|
||||||
{
|
copy_attrs(t_obj);
|
||||||
std::swap(m_data, rhs.m_data);
|
reset_return_value();
|
||||||
}
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/// \returns true if the two Boxed_Values share the same internal type
|
||||||
* copy the values stored in rhs.m_data to m_data
|
static bool type_match(const Boxed_Value &l, const Boxed_Value &r) noexcept { return l.get_type_info() == r.get_type_info(); }
|
||||||
* m_data pointers are not shared in this case
|
|
||||||
*/
|
|
||||||
Boxed_Value assign(const Boxed_Value &rhs)
|
|
||||||
{
|
|
||||||
(*m_data) = (*rhs.m_data);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private:
|
||||||
* shared data assignment, same as copy construction
|
// necessary to avoid hitting the templated && constructor of Boxed_Value
|
||||||
*/
|
struct Internal_Construction {
|
||||||
Boxed_Value &operator=(const Boxed_Value &rhs)
|
};
|
||||||
{
|
|
||||||
Boxed_Value temp(rhs);
|
|
||||||
swap(temp);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type_Info &get_type_info() const
|
Boxed_Value(std::shared_ptr<Data> t_data, Internal_Construction)
|
||||||
{
|
: m_data(std::move(t_data)) {
|
||||||
return m_data->m_type_info;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
std::shared_ptr<Data> m_data = Object_Data::get();
|
||||||
* return true if the object is uninitialized
|
|
||||||
*/
|
|
||||||
bool is_undef() const
|
|
||||||
{
|
|
||||||
return m_data->m_type_info.is_undef();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_const() const
|
|
||||||
{
|
|
||||||
return m_data->m_type_info.is_const();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_type(const Type_Info &ti) const
|
|
||||||
{
|
|
||||||
return m_data->m_type_info.bare_equal(ti);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_null() const
|
|
||||||
{
|
|
||||||
return (m_data->m_data_ptr == 0 && m_data->m_const_data_ptr == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const chaiscript::detail::Any & get() const
|
|
||||||
{
|
|
||||||
return m_data->m_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_ref() const
|
|
||||||
{
|
|
||||||
return m_data->m_is_ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_pointer() const
|
|
||||||
{
|
|
||||||
return !is_ref();
|
|
||||||
}
|
|
||||||
|
|
||||||
void *get_ptr() const
|
|
||||||
{
|
|
||||||
return m_data->m_data_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const void *get_const_ptr() const
|
|
||||||
{
|
|
||||||
return m_data->m_const_data_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \returns true if the two Boxed_Values share the same internal type
|
|
||||||
static bool type_match(Boxed_Value l, Boxed_Value r)
|
|
||||||
{
|
|
||||||
return l.get_type_info() == r.get_type_info();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<Data> m_data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \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.
|
/// a copy is not made.
|
||||||
/// \param t The value to box
|
/// @param t The value to box
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// \code
|
///
|
||||||
|
/// ~~~{.cpp}
|
||||||
/// int i;
|
/// int i;
|
||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
/// chai.add(chaiscript::var(i), "i");
|
/// chai.add(chaiscript::var(i), "i");
|
||||||
/// chai.add(chaiscript::var(&i), "ip");
|
/// chai.add(chaiscript::var(&i), "ip");
|
||||||
/// \endcode
|
/// ~~~
|
||||||
///
|
///
|
||||||
/// \sa \ref addingobjects
|
/// @sa @ref adding_objects
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value var(T t)
|
Boxed_Value var(T &&t) {
|
||||||
{
|
return Boxed_Value(std::forward<T>(t));
|
||||||
return Boxed_Value(t);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
/// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
|
/// \brief Takes a value, copies it and returns a Boxed_Value object that is immutable
|
||||||
/// \param[in] t Value to copy and make const
|
/// \param[in] t Value to copy and make const
|
||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(const T &t)
|
Boxed_Value const_var_impl(const T &t) {
|
||||||
{
|
return Boxed_Value(std::make_shared<typename std::add_const<T>::type>(t));
|
||||||
return Boxed_Value(std::shared_ptr<typename std::add_const<T>::type >(new T(t)));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
/// \brief Takes a pointer to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||||
/// Does not copy the pointed to value.
|
/// Does not copy the pointed to value.
|
||||||
@ -290,10 +284,9 @@ namespace chaiscript
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(T *t)
|
Boxed_Value const_var_impl(T *t) {
|
||||||
{
|
return Boxed_Value(const_cast<typename std::add_const<T>::type *>(t));
|
||||||
return Boxed_Value( const_cast<typename std::add_const<T>::type *>(t) );
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
/// \brief Takes a std::shared_ptr to a value, adds const to the pointed to type and returns an immutable Boxed_Value.
|
||||||
/// Does not copy the pointed to value.
|
/// Does not copy the pointed to value.
|
||||||
@ -301,10 +294,9 @@ namespace chaiscript
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(const std::shared_ptr<T> &t)
|
Boxed_Value const_var_impl(const std::shared_ptr<T> &t) {
|
||||||
{
|
return Boxed_Value(std::const_pointer_cast<typename std::add_const<T>::type>(t));
|
||||||
return Boxed_Value( std::const_pointer_cast<typename std::add_const<T>::type>(t) );
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
|
/// \brief Takes a std::reference_wrapper value, adds const to the referenced type and returns an immutable Boxed_Value.
|
||||||
/// Does not copy the referenced value.
|
/// Does not copy the referenced value.
|
||||||
@ -312,11 +304,10 @@ namespace chaiscript
|
|||||||
/// \returns Immutable Boxed_Value
|
/// \returns Immutable Boxed_Value
|
||||||
/// \sa Boxed_Value::is_const
|
/// \sa Boxed_Value::is_const
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t)
|
Boxed_Value const_var_impl(const std::reference_wrapper<T> &t) {
|
||||||
{
|
return Boxed_Value(std::cref(t.get()));
|
||||||
return Boxed_Value( std::cref(t.get()) );
|
}
|
||||||
}
|
} // namespace detail
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
|
/// \brief Takes an object and returns an immutable Boxed_Value. If the object is a std::reference or pointer type
|
||||||
/// the value is not copied. If it is an object type, it is copied.
|
/// the value is not copied. If it is an object type, it is copied.
|
||||||
@ -338,17 +329,30 @@ namespace chaiscript
|
|||||||
/// chai.add(chaiscript::const_var(Red), "Red");
|
/// chai.add(chaiscript::const_var(Red), "Red");
|
||||||
/// chai.add(chaiscript::const_var(Green), "Green");
|
/// chai.add(chaiscript::const_var(Green), "Green");
|
||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
///
|
||||||
/// \sa \ref addingobjects
|
/// \todo support C++11 strongly typed enums
|
||||||
|
/// \sa \ref adding_objects
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Boxed_Value const_var(const T &t)
|
Boxed_Value const_var(const T &t) {
|
||||||
{
|
return detail::const_var_impl(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;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
99
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
99
include/chaiscript/dispatchkit/callable_traits.hpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, 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...)> {
|
||||||
|
using Return_Type = Ret;
|
||||||
|
using Signature = Ret()(Params...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename T, typename... Params>
|
||||||
|
struct Function_Signature<Ret (T::*)(Params...) const> {
|
||||||
|
using Return_Type = Ret;
|
||||||
|
using Signature = Ret()(Params...);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Callable_Traits {
|
||||||
|
using Signature = typename Function_Signature<decltype(&T::operator())>::Signature;
|
||||||
|
using Return_Type = typename Function_Signature<decltype(&T::operator())>::Return_Type;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace dispatch
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,262 +0,0 @@
|
|||||||
// This file is distributed under the BSD License.
|
|
||||||
// See "license.txt" for details.
|
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
|
||||||
// http://www.chaiscript.com
|
|
||||||
|
|
||||||
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
|
||||||
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#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) CHAISCRIPT_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) CHAISCRIPT_NOEXCEPT
|
|
||||||
: bad_boxed_cast(t_from, t_to)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_boxed_dynamic_cast(const std::string &w) CHAISCRIPT_NOEXCEPT
|
|
||||||
: bad_boxed_cast(w)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~bad_boxed_dynamic_cast() CHAISCRIPT_NOEXCEPT {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
class Dynamic_Conversion
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual Boxed_Value convert(const Boxed_Value &derived) const = 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) const
|
|
||||||
{
|
|
||||||
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, nullptr));
|
|
||||||
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, nullptr));
|
|
||||||
|
|
||||||
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, 0);
|
|
||||||
const Base &data = dynamic_cast<const Base &>(d);
|
|
||||||
return Boxed_Value(std::cref(data));
|
|
||||||
} else {
|
|
||||||
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived, 0);
|
|
||||||
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_Cast_Conversions
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Dynamic_Cast_Conversions()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Dynamic_Cast_Conversions(const Dynamic_Cast_Conversions &t_other)
|
|
||||||
: m_conversions(t_other.get_conversions())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_conversion(const std::shared_ptr<detail::Dynamic_Conversion> &conversion)
|
|
||||||
{
|
|
||||||
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
|
||||||
m_conversions.insert(conversion);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Base, typename Derived>
|
|
||||||
bool dynamic_cast_converts() const
|
|
||||||
{
|
|
||||||
return dynamic_cast_converts(user_type<Base>(), user_type<Derived>());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
|
|
||||||
{
|
|
||||||
return has_conversion(base, derived);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Base>
|
|
||||||
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) const
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
|
|
||||||
} catch (const std::out_of_range &) {
|
|
||||||
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
|
|
||||||
} catch (const std::bad_cast &) {
|
|
||||||
throw exception::bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<detail::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<std::shared_ptr<detail::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:
|
|
||||||
std::set<std::shared_ptr<detail::Dynamic_Conversion> >::const_iterator find(
|
|
||||||
const Type_Info &base, const Type_Info &derived) const
|
|
||||||
{
|
|
||||||
for (std::set<std::shared_ptr<detail::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();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::set<std::shared_ptr<detail::Dynamic_Conversion> > 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::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 std::shared_ptr<detail::Dynamic_Conversion>(new detail::Dynamic_Conversion_Impl<Base, Derived>());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,272 +1,98 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||||
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
#define CHAISCRIPT_DYNAMIC_OBJECT_HPP_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace chaiscript
|
#include "boxed_value.hpp"
|
||||||
{
|
|
||||||
namespace dispatch
|
|
||||||
{
|
|
||||||
class Dynamic_Object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Dynamic_Object(const std::string &t_type_name)
|
|
||||||
: m_type_name(t_type_name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_type_name() const
|
namespace chaiscript {
|
||||||
{
|
class Type_Conversions;
|
||||||
return m_type_name;
|
namespace dispatch {
|
||||||
}
|
class Proxy_Function_Base;
|
||||||
|
} // namespace dispatch
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
Boxed_Value get_attr(const std::string &t_attr_name)
|
namespace chaiscript {
|
||||||
{
|
namespace dispatch {
|
||||||
return m_attrs[t_attr_name];
|
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") {
|
||||||
|
}
|
||||||
|
|
||||||
std::map<std::string, Boxed_Value> get_attrs()
|
option_explicit_set(const option_explicit_set &) = default;
|
||||||
{
|
|
||||||
return m_attrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
~option_explicit_set() noexcept override = default;
|
||||||
std::string m_type_name;
|
|
||||||
|
|
||||||
std::map<std::string, Boxed_Value> m_attrs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
class Dynamic_Object {
|
||||||
{
|
public:
|
||||||
/**
|
explicit Dynamic_Object(std::string t_type_name)
|
||||||
* A Proxy_Function implementation designed for calling a function
|
: m_type_name(std::move(t_type_name))
|
||||||
* that is automatically guarded based on the first param based on the
|
, m_option_explicit(false) {
|
||||||
* 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(
|
Dynamic_Object() = default;
|
||||||
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() {}
|
bool is_explicit() const noexcept { return m_option_explicit; }
|
||||||
|
|
||||||
virtual bool operator==(const Proxy_Function_Base &f) const
|
void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; }
|
||||||
{
|
|
||||||
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 Dynamic_Cast_Conversions &t_conversions) const
|
const std::string &get_type_name() const noexcept { return m_type_name; }
|
||||||
{
|
|
||||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
|
||||||
{
|
|
||||||
return m_func->call_match(vals, t_conversions);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const
|
const Boxed_Value &operator[](const std::string &t_attr_name) const { return get_attr(t_attr_name); }
|
||||||
{
|
|
||||||
return {m_func};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Boxed_Value &operator[](const std::string &t_attr_name) { return get_attr(t_attr_name); }
|
||||||
|
|
||||||
virtual int get_arity() const
|
const Boxed_Value &get_attr(const std::string &t_attr_name) const {
|
||||||
{
|
auto a = m_attrs.find(t_attr_name);
|
||||||
return m_func->get_arity();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string annotation() const
|
if (a != m_attrs.end()) {
|
||||||
{
|
return a->second;
|
||||||
return m_func->annotation();
|
} 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(); }
|
||||||
|
|
||||||
protected:
|
Boxed_Value &get_attr(const std::string &t_attr_name) { return m_attrs[t_attr_name]; }
|
||||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions) const
|
|
||||||
{
|
|
||||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
|
||||||
{
|
|
||||||
return (*m_func)(params, t_conversions);
|
|
||||||
} else {
|
|
||||||
throw exception::guard_error();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool compare_first_type(const Boxed_Value &bv, const Dynamic_Cast_Conversions &t_conversions) const
|
Boxed_Value &method_missing(const std::string &t_method_name) {
|
||||||
{
|
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||||
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
throw option_explicit_set(t_method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
return get_attr(t_method_name);
|
||||||
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);
|
const Boxed_Value &method_missing(const std::string &t_method_name) const {
|
||||||
assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
if (m_option_explicit && m_attrs.find(t_method_name) == m_attrs.end()) {
|
||||||
types[1] = t_objectti;
|
throw option_explicit_set(t_method_name);
|
||||||
return types;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
return get_attr(t_method_name);
|
||||||
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions)
|
}
|
||||||
{
|
|
||||||
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, &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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
std::map<std::string, Boxed_Value> get_attrs() const { return m_attrs; }
|
||||||
|
|
||||||
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
private:
|
||||||
const std::shared_ptr<Type_Info> &ti, const Dynamic_Cast_Conversions &t_conversions)
|
const std::string m_type_name = "";
|
||||||
{
|
bool m_option_explicit = false;
|
||||||
if (bvs.size() > 0)
|
|
||||||
{
|
|
||||||
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string m_type_name;
|
std::map<std::string, Boxed_Value> m_attrs;
|
||||||
Proxy_Function m_func;
|
};
|
||||||
std::shared_ptr<Type_Info> m_ti;
|
|
||||||
|
|
||||||
};
|
} // namespace dispatch
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 Dynamic_Cast_Conversions &t_conversions) 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, t_conversions);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 Dynamic_Cast_Conversions &t_conversions) 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, t_conversions);
|
|
||||||
|
|
||||||
return bv;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_type_name;
|
|
||||||
Proxy_Function m_func;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
203
include/chaiscript/dispatchkit/dynamic_object_detail.hpp
Normal file
203
include/chaiscript/dispatchkit/dynamic_object_detail.hpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, 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 "dynamic_object.hpp"
|
||||||
|
#include "proxy_functions.hpp"
|
||||||
|
#include "type_info.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 noexcept 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 noexcept override { return m_is_attribute; }
|
||||||
|
|
||||||
|
bool call_match(const chaiscript::Function_Params &vals, const Type_Conversions_State &t_conversions) const noexcept 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 chaiscript::Function_Params ¶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 noexcept 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 noexcept {
|
||||||
|
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 chaiscript::Function_Params &bvs,
|
||||||
|
const std::string &name,
|
||||||
|
const std::unique_ptr<Type_Info> &ti,
|
||||||
|
const Type_Conversions_State &t_conversions) const noexcept {
|
||||||
|
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 noexcept 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 chaiscript::Function_Params &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(chaiscript::Function_Params{new_vals}, t_conversions);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Boxed_Value do_call(const chaiscript::Function_Params ¶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)(chaiscript::Function_Params{new_params}, t_conversions);
|
||||||
|
|
||||||
|
return bv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string m_type_name;
|
||||||
|
const Proxy_Function m_func;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace dispatch
|
||||||
|
} // namespace chaiscript
|
||||||
|
#endif
|
||||||
@ -1,94 +1,43 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||||
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
#define CHAISCRIPT_EXCEPTION_SPECIFICATION_HPP_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "../chaiscript_defines.hpp"
|
||||||
#include "boxed_cast.hpp"
|
#include "boxed_cast.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
namespace detail {
|
||||||
namespace detail
|
struct Exception_Handler_Base {
|
||||||
{
|
|
||||||
struct Exception_Handler_Base
|
|
||||||
{
|
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
|
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) = 0;
|
||||||
|
|
||||||
virtual ~Exception_Handler_Base() {}
|
virtual ~Exception_Handler_Base() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
static void throw_type(const Boxed_Value &bv, const Dispatch_Engine &t_engine) {
|
||||||
{
|
try {
|
||||||
try { T t = t_engine.boxed_cast<T>(bv); throw t; } catch (const chaiscript::exception::bad_boxed_cast &) {}
|
T t = t_engine.boxed_cast<T>(bv);
|
||||||
|
throw t;
|
||||||
|
} catch (const chaiscript::exception::bad_boxed_cast &) {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T1>
|
template<typename... T>
|
||||||
struct Exception_Handler_Impl1 : Exception_Handler_Base
|
struct Exception_Handler_Impl : Exception_Handler_Base {
|
||||||
{
|
void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { (throw_type<T>(bv, t_engine), ...); }
|
||||||
virtual ~Exception_Handler_Impl1() {}
|
};
|
||||||
|
} // namespace detail
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
|
||||||
{
|
|
||||||
throw_type<T1>(bv, t_engine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2>
|
|
||||||
struct Exception_Handler_Impl2 : Exception_Handler_Base
|
|
||||||
{
|
|
||||||
virtual ~Exception_Handler_Impl2() {}
|
|
||||||
|
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
|
||||||
{
|
|
||||||
throw_type<T1>(bv, t_engine);
|
|
||||||
throw_type<T2>(bv, t_engine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T1, typename T2, typename T3>
|
|
||||||
struct Exception_Handler_Impl3 : Exception_Handler_Base
|
|
||||||
{
|
|
||||||
virtual ~Exception_Handler_Impl3() {}
|
|
||||||
|
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
|
||||||
{
|
|
||||||
throw_type<T1>(bv, t_engine);
|
|
||||||
throw_type<T2>(bv, t_engine);
|
|
||||||
throw_type<T3>(bv, t_engine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2, typename T3, typename T4>
|
|
||||||
struct Exception_Handler_Impl4 : Exception_Handler_Base
|
|
||||||
{
|
|
||||||
virtual ~Exception_Handler_Impl4() {}
|
|
||||||
|
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
|
||||||
{
|
|
||||||
throw_type<T1>(bv, t_engine);
|
|
||||||
throw_type<T2>(bv, t_engine);
|
|
||||||
throw_type<T3>(bv, t_engine);
|
|
||||||
throw_type<T4>(bv, t_engine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T1, typename T2, typename T3, typename T4, typename T5>
|
|
||||||
struct Exception_Handler_Impl5 : Exception_Handler_Base
|
|
||||||
{
|
|
||||||
virtual ~Exception_Handler_Impl5() {}
|
|
||||||
|
|
||||||
virtual void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine)
|
|
||||||
{
|
|
||||||
throw_type<T1>(bv, t_engine);
|
|
||||||
throw_type<T2>(bv, t_engine);
|
|
||||||
throw_type<T3>(bv, t_engine);
|
|
||||||
throw_type<T4>(bv, t_engine);
|
|
||||||
throw_type<T5>(bv, t_engine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
|
/// \brief Used in the automatic unboxing of exceptions thrown during script evaluation
|
||||||
///
|
///
|
||||||
@ -100,7 +49,8 @@ namespace chaiscript
|
|||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
///
|
///
|
||||||
/// try {
|
/// 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 (const double e) {
|
||||||
/// } catch (int) {
|
/// } catch (int) {
|
||||||
/// } catch (float) {
|
/// } catch (float) {
|
||||||
@ -125,7 +75,7 @@ namespace chaiscript
|
|||||||
///
|
///
|
||||||
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
|
/// Similarly, if you are using the ChaiScript::eval form that unboxes the return value, then chaiscript::exception::bad_boxed_cast
|
||||||
/// should be handled as well.
|
/// should be handled as well.
|
||||||
///
|
///
|
||||||
/// \code
|
/// \code
|
||||||
/// try {
|
/// try {
|
||||||
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
|
/// chai.eval<int>("1.0", chaiscript::exception_specification<const std::exception &>());
|
||||||
@ -140,49 +90,14 @@ namespace chaiscript
|
|||||||
///
|
///
|
||||||
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
|
/// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects
|
||||||
/// \sa \ref exceptions
|
/// \sa \ref exceptions
|
||||||
typedef std::shared_ptr<detail::Exception_Handler_Base> Exception_Handler;
|
using Exception_Handler = std::shared_ptr<detail::Exception_Handler_Base>;
|
||||||
|
|
||||||
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
/// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing
|
||||||
/// \sa \ref exceptions
|
/// \sa \ref exceptions
|
||||||
template<typename T1>
|
template<typename... T>
|
||||||
Exception_Handler exception_specification()
|
Exception_Handler exception_specification() {
|
||||||
{
|
return std::make_shared<detail::Exception_Handler_Impl<T...>>();
|
||||||
return Exception_Handler(new detail::Exception_Handler_Impl1<T1>());
|
|
||||||
}
|
}
|
||||||
|
} // namespace chaiscript
|
||||||
/// \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>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,133 +1,122 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||||
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
#define CHAISCRIPT_FUNCTION_CALL_HPP_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "proxy_functions.hpp"
|
|
||||||
|
#include "boxed_cast.hpp"
|
||||||
#include "function_call_detail.hpp"
|
#include "function_call_detail.hpp"
|
||||||
|
#include "proxy_functions.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
class Boxed_Value;
|
||||||
|
class Type_Conversions_State;
|
||||||
|
namespace detail {
|
||||||
|
template<typename T>
|
||||||
|
struct Cast_Helper;
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
#include <iostream>
|
namespace chaiscript {
|
||||||
|
namespace dispatch {
|
||||||
|
namespace detail {
|
||||||
|
template<typename Ret, typename... Param>
|
||||||
|
constexpr auto arity(Ret (*)(Param...)) noexcept {
|
||||||
|
return sizeof...(Param);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
namespace chaiscript
|
/// Build a function caller that knows how to dispatch on a set of functions
|
||||||
{
|
/// example:
|
||||||
namespace dispatch
|
/// std::function<void (int)> f =
|
||||||
{
|
/// build_function_caller(dispatchkit.get_function("print"));
|
||||||
/**
|
/// \returns A std::function object for dispatching
|
||||||
* Build a function caller that knows how to dispatch on a set of functions
|
/// \param[in] funcs the set of functions to dispatch on.
|
||||||
* 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>
|
template<typename FunctionType>
|
||||||
std::function<FunctionType>
|
std::function<FunctionType> functor(const std::vector<Const_Proxy_Function> &funcs, const Type_Conversions_State *t_conversions) {
|
||||||
functor(const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
|
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()) == detail::arity(static_cast<FunctionType *>(nullptr));
|
||||||
FunctionType *p=0;
|
});
|
||||||
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
|
||||||
|
if (!has_arity_match) {
|
||||||
|
throw exception::bad_boxed_cast(user_type<Const_Proxy_Function>(), typeid(std::function<FunctionType>));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
FunctionType *p = nullptr;
|
||||||
* Build a function caller for a particular Proxy_Function object
|
return detail::build_function_caller_helper(p, funcs, t_conversions);
|
||||||
* useful in the case that a function is being pass out from scripting back
|
}
|
||||||
* into code
|
|
||||||
* example:
|
/// Build a function caller for a particular Proxy_Function object
|
||||||
* void my_function(Proxy_Function f)
|
/// useful in the case that a function is being pass out from scripting back
|
||||||
* {
|
/// into code
|
||||||
* std::function<void (int)> local_f =
|
/// example:
|
||||||
* build_function_caller(f);
|
/// void my_function(Proxy_Function f)
|
||||||
* }
|
/// {
|
||||||
* \returns A std::function object for dispatching
|
/// std::function<void (int)> local_f =
|
||||||
* \param[in] func A function to execute.
|
/// build_function_caller(f);
|
||||||
*/
|
/// }
|
||||||
|
/// \returns A std::function object for dispatching
|
||||||
|
/// \param[in] func A function to execute.
|
||||||
template<typename FunctionType>
|
template<typename FunctionType>
|
||||||
std::function<FunctionType>
|
std::function<FunctionType> functor(Const_Proxy_Function func, const Type_Conversions_State *t_conversions) {
|
||||||
functor(Const_Proxy_Function func, const Dynamic_Cast_Conversions *t_conversions)
|
return functor<FunctionType>(std::vector<Const_Proxy_Function>({std::move(func)}), t_conversions);
|
||||||
{
|
}
|
||||||
std::vector<Const_Proxy_Function> funcs;
|
|
||||||
funcs.push_back(func);
|
|
||||||
return functor<FunctionType>(funcs, t_conversions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/// Helper for automatically unboxing a Boxed_Value that contains a function object
|
||||||
* Helper for automatically unboxing a Boxed_Value that contains a function object
|
/// and creating a typesafe C++ function caller from it.
|
||||||
* and creating a typesafe C++ function caller from it.
|
|
||||||
*/
|
|
||||||
template<typename FunctionType>
|
template<typename FunctionType>
|
||||||
std::function<FunctionType>
|
std::function<FunctionType> functor(const Boxed_Value &bv, const Type_Conversions_State *t_conversions) {
|
||||||
functor(const Boxed_Value &bv, const Dynamic_Cast_Conversions *t_conversions)
|
return functor<FunctionType>(boxed_cast<Const_Proxy_Function>(bv, t_conversions), t_conversions);
|
||||||
{
|
}
|
||||||
return functor<FunctionType>(boxed_cast<Const_Proxy_Function >(bv, t_conversions), t_conversions);
|
} // namespace dispatch
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
/// Cast helper to handle automatic casting to const std::function &
|
||||||
|
template<typename Signature>
|
||||||
|
struct Cast_Helper<const std::function<Signature> &> {
|
||||||
|
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, t_conversions);
|
||||||
|
} else {
|
||||||
|
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
namespace detail{
|
/// Cast helper to handle automatic casting to std::function
|
||||||
/**
|
|
||||||
* Cast helper to handle automatic casting to const std::function &
|
|
||||||
*/
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct Cast_Helper<const std::function<Signature> &>
|
struct Cast_Helper<std::function<Signature>> {
|
||||||
{
|
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
||||||
typedef std::function<Signature> Result_Type;
|
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
|
||||||
|
return dispatch::functor<Signature>(ob, t_conversions);
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
|
} else {
|
||||||
{
|
return Cast_Helper_Inner<std::function<Signature>>::cast(ob, t_conversions);
|
||||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
|
||||||
{
|
|
||||||
return dispatch::functor<Signature>(ob, t_conversions);
|
|
||||||
} else {
|
|
||||||
return Cast_Helper_Inner<const std::function<Signature> &>::cast(ob, t_conversions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/// Cast helper to handle automatic casting to const std::function
|
||||||
* Cast helper to handle automatic casting to std::function
|
|
||||||
*/
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct Cast_Helper<std::function<Signature> >
|
struct Cast_Helper<const std::function<Signature>> {
|
||||||
{
|
static std::function<Signature> cast(const Boxed_Value &ob, const Type_Conversions_State *t_conversions) {
|
||||||
typedef std::function<Signature> Result_Type;
|
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>())) {
|
||||||
|
return dispatch::functor<Signature>(ob, t_conversions);
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
|
} else {
|
||||||
{
|
return Cast_Helper_Inner<const std::function<Signature>>::cast(ob, t_conversions);
|
||||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
|
||||||
{
|
|
||||||
return dispatch::functor<Signature>(ob, t_conversions);
|
|
||||||
} else {
|
|
||||||
return Cast_Helper_Inner<std::function<Signature> >::cast(ob, t_conversions);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
/**
|
} // namespace detail
|
||||||
* Cast helper to handle automatic casting to const std::function
|
} // namespace chaiscript
|
||||||
*/
|
|
||||||
template<typename Signature>
|
|
||||||
struct Cast_Helper<const std::function<Signature> >
|
|
||||||
{
|
|
||||||
typedef std::function<Signature> Result_Type;
|
|
||||||
|
|
||||||
static Result_Type cast(const Boxed_Value &ob, const Dynamic_Cast_Conversions *t_conversions)
|
|
||||||
{
|
|
||||||
if (ob.get_type_info().bare_equal(user_type<Const_Proxy_Function>()))
|
|
||||||
{
|
|
||||||
return dispatch::functor<Signature>(ob, t_conversions);
|
|
||||||
} else {
|
|
||||||
return Cast_Helper_Inner<const std::function<Signature> >::cast(ob, t_conversions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,100 +1,97 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||||
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
#define CHAISCRIPT_FUNCTION_CALL_DETAIL_HPP_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "boxed_cast.hpp"
|
||||||
|
#include "boxed_number.hpp"
|
||||||
|
#include "boxed_value.hpp"
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
|
#include "type_conversions.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript::dispatch::detail {
|
||||||
{
|
/// used internally for unwrapping a function call's types
|
||||||
namespace dispatch
|
template<typename Ret, typename... Param>
|
||||||
{
|
struct Build_Function_Caller_Helper {
|
||||||
namespace detail
|
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) {
|
||||||
/**
|
|
||||||
* Internal helper class for handling the return
|
|
||||||
* value of a build_function_caller
|
|
||||||
*/
|
|
||||||
template<typename Ret>
|
|
||||||
struct Function_Caller_Ret
|
|
||||||
{
|
|
||||||
static Ret call(const std::vector<Const_Proxy_Function> &t_funcs,
|
|
||||||
const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
return boxed_cast<Ret>(dispatch::dispatch(t_funcs, params, t_conversions));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specialization for void return types
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
struct Function_Caller_Ret<void>
|
|
||||||
{
|
|
||||||
static void call(const std::vector<Const_Proxy_Function> &t_funcs,
|
|
||||||
const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
dispatch::dispatch(t_funcs, params, t_conversions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* used internally for unwrapping a function call's types
|
|
||||||
*/
|
|
||||||
template<typename Ret, typename ... Param>
|
|
||||||
struct Build_Function_Caller_Helper
|
|
||||||
{
|
|
||||||
Build_Function_Caller_Helper(const std::vector<Const_Proxy_Function> &t_funcs, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
: m_funcs(t_funcs),
|
|
||||||
m_conversions(t_conversions)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Ret operator()(Param...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)...
|
|
||||||
}, m_conversions
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Const_Proxy_Function> m_funcs;
|
|
||||||
Dynamic_Cast_Conversions m_conversions;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Ret, typename ... Params>
|
|
||||||
std::function<Ret (Params...)> build_function_caller_helper(Ret (Params...), const std::vector<Const_Proxy_Function> &funcs, const Dynamic_Cast_Conversions *t_conversions)
|
|
||||||
{
|
|
||||||
if (funcs.size() == 1)
|
|
||||||
{
|
|
||||||
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
|
|
||||||
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
|
|
||||||
(funcs[0]);
|
|
||||||
|
|
||||||
if (pfi)
|
|
||||||
{
|
|
||||||
return pfi->internal_function();
|
|
||||||
}
|
|
||||||
// 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, t_conversions?*t_conversions:Dynamic_Cast_Conversions()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ret call(const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_state) {
|
||||||
|
if constexpr (std::is_arithmetic_v<Ret> && !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ret>>, bool>) {
|
||||||
|
return Boxed_Number(dispatch::dispatch(m_funcs, params, t_state)).get_as<Ret>();
|
||||||
|
} else if constexpr (std::is_same_v<void, Ret>) {
|
||||||
|
dispatch::dispatch(m_funcs, params, t_state);
|
||||||
|
} else {
|
||||||
|
return boxed_cast<Ret>(dispatch::dispatch(m_funcs, params, t_state), &t_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... P>
|
||||||
|
Ret operator()(P &&...param) {
|
||||||
|
std::array<Boxed_Value, sizeof...(P)> params{box<P>(std::forward<P>(param))...};
|
||||||
|
|
||||||
|
if (m_conversions) {
|
||||||
|
Type_Conversions_State state(*m_conversions, m_conversions->conversion_saves());
|
||||||
|
return call(chaiscript::Function_Params{params}, state);
|
||||||
|
} else {
|
||||||
|
Type_Conversions conv;
|
||||||
|
Type_Conversions_State state(conv, conv.conversion_saves());
|
||||||
|
return call(chaiscript::Function_Params{params}, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename P, typename Q>
|
||||||
|
static Boxed_Value box(Q &&q) {
|
||||||
|
if constexpr (std::is_same_v<chaiscript::Boxed_Value, std::decay_t<Q>>) {
|
||||||
|
return std::forward<Q>(q);
|
||||||
|
} else if constexpr (std::is_reference_v<P>) {
|
||||||
|
return Boxed_Value(std::ref(std::forward<Q>(q)));
|
||||||
|
} else {
|
||||||
|
return Boxed_Value(std::forward<Q>(q));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, const Type_Conversions_State *t_conversions) {
|
||||||
|
/*
|
||||||
|
if (funcs.size() == 1)
|
||||||
|
{
|
||||||
|
std::shared_ptr<const Proxy_Function_Impl<Ret (Params...)>> pfi =
|
||||||
|
std::dynamic_pointer_cast<const Proxy_Function_Impl<Ret (Params...)> >
|
||||||
|
(funcs[0]);
|
||||||
|
|
||||||
|
if (pfi)
|
||||||
|
{
|
||||||
|
return pfi->internal_function();
|
||||||
|
}
|
||||||
|
// 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, t_conversions ? t_conversions->get() : nullptr));
|
||||||
}
|
}
|
||||||
}
|
} // namespace chaiscript::dispatch::detail
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
67
include/chaiscript/dispatchkit/function_params.hpp
Normal file
67
include/chaiscript/dispatchkit/function_params.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// 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_FUNCTION_PARAMS_HPP
|
||||||
|
#define CHAISCRIPT_FUNCTION_PARAMS_HPP
|
||||||
|
|
||||||
|
#include "boxed_value.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
class Function_Params {
|
||||||
|
public:
|
||||||
|
constexpr Function_Params(const Boxed_Value *const t_begin, const Boxed_Value *const t_end)
|
||||||
|
: m_begin(t_begin)
|
||||||
|
, m_end(t_end) {
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit Function_Params(const Boxed_Value &bv)
|
||||||
|
: m_begin(&bv)
|
||||||
|
, m_end(m_begin + 1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit Function_Params(const std::vector<Boxed_Value> &vec)
|
||||||
|
: m_begin(vec.empty() ? nullptr : &vec.front())
|
||||||
|
, m_end(vec.empty() ? nullptr : &vec.front() + vec.size()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t Size>
|
||||||
|
constexpr explicit Function_Params(const std::array<Boxed_Value, Size> &a)
|
||||||
|
: m_begin(&a.front())
|
||||||
|
, m_end(&a.front() + Size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const Boxed_Value &operator[](const std::size_t t_i) const noexcept { return m_begin[t_i]; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const Boxed_Value *begin() const noexcept { return m_begin; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const Boxed_Value &front() const noexcept { return *m_begin; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const Boxed_Value *end() const noexcept { return m_end; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr std::size_t size() const noexcept { return std::size_t(m_end - m_begin); }
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<Boxed_Value> to_vector() const { return std::vector<Boxed_Value>{m_begin, m_end}; }
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool empty() const noexcept { return m_begin == m_end; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Boxed_Value *m_begin = nullptr;
|
||||||
|
const Boxed_Value *m_end = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructor specialization for array of size 0
|
||||||
|
template<>
|
||||||
|
constexpr Function_Params::Function_Params(const std::array<Boxed_Value, size_t{0}> & /* a */)
|
||||||
|
: m_begin(nullptr)
|
||||||
|
, m_end(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
149
include/chaiscript/dispatchkit/function_signature.hpp
Normal file
149
include/chaiscript/dispatchkit/function_signature.hpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#ifndef CHAISCRIPT_FUNCTION_SIGNATURE_HPP
|
||||||
|
#define CHAISCRIPT_FUNCTION_SIGNATURE_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace chaiscript::dispatch::detail {
|
||||||
|
template<typename... Param>
|
||||||
|
struct Function_Params {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, typename Params, bool IsNoExcept = false, bool IsMember = false, bool IsMemberObject = false, bool IsObject = false>
|
||||||
|
struct Function_Signature {
|
||||||
|
using Param_Types = Params;
|
||||||
|
using Return_Type = Ret;
|
||||||
|
constexpr static const bool is_object = IsObject;
|
||||||
|
constexpr static const bool is_member_object = IsMemberObject;
|
||||||
|
constexpr static const bool is_noexcept = IsNoExcept;
|
||||||
|
template<typename T>
|
||||||
|
constexpr Function_Signature(T &&) noexcept {
|
||||||
|
}
|
||||||
|
constexpr Function_Signature() noexcept = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Free functions
|
||||||
|
|
||||||
|
template<typename Ret, typename... Param>
|
||||||
|
Function_Signature(Ret (*f)(Param...)) -> Function_Signature<Ret, Function_Params<Param...>>;
|
||||||
|
|
||||||
|
template<typename Ret, typename... Param>
|
||||||
|
Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Param...>, true>;
|
||||||
|
|
||||||
|
// no reference specifier
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile const)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile const noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...)) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) const) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) const noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
// & reference specifier
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile &) -> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile &noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile const &)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile const &noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile const Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) &) -> Function_Signature<Ret, Function_Params<Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) &noexcept) -> Function_Signature<Ret, Function_Params<Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) const &) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) const &noexcept) -> Function_Signature<Ret, Function_Params<const Class &, Param...>, true, true>;
|
||||||
|
|
||||||
|
// && reference specifier
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile &&) -> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile &&noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile Class &&, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile const &&)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) volatile const &&noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<volatile const Class &&, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) &&) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) &&noexcept) -> Function_Signature<Ret, Function_Params<Class &&, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) const &&) -> Function_Signature<Ret, Function_Params<const Class &&, Param...>, false, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class, typename... Param>
|
||||||
|
Function_Signature(Ret (Class::*f)(Param...) const &&noexcept)
|
||||||
|
-> Function_Signature<Ret, Function_Params<const Class &&, Param...>, true, true>;
|
||||||
|
|
||||||
|
template<typename Ret, typename Class>
|
||||||
|
Function_Signature(Ret Class::*f) -> Function_Signature<Ret, Function_Params<Class &>, true, true, true>;
|
||||||
|
|
||||||
|
// primary template handles types that have no nested ::type member:
|
||||||
|
template<class, class = std::void_t<>>
|
||||||
|
struct has_call_operator : std::false_type {
|
||||||
|
};
|
||||||
|
|
||||||
|
// specialization recognizes types that do have a nested ::type member:
|
||||||
|
template<class T>
|
||||||
|
struct has_call_operator<T, std::void_t<decltype(&T::operator())>> : std::true_type {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Func>
|
||||||
|
auto function_signature(const Func &f) {
|
||||||
|
if constexpr (has_call_operator<Func>::value) {
|
||||||
|
return Function_Signature<typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Return_Type,
|
||||||
|
typename decltype(Function_Signature{&std::decay_t<Func>::operator()})::Param_Types,
|
||||||
|
decltype(Function_Signature{&std::decay_t<Func>::operator()})::is_noexcept,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true>{};
|
||||||
|
} else {
|
||||||
|
return Function_Signature{f};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chaiscript::dispatch::detail
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,187 +1,195 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||||
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
#define CHAISCRIPT_HANDLE_RETURN_HPP_
|
||||||
|
|
||||||
#include "boxed_value.hpp"
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "boxed_number.hpp"
|
#include "boxed_number.hpp"
|
||||||
#include "type_info.hpp"
|
#include "boxed_value.hpp"
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
namespace chaiscript {
|
||||||
#include <vector>
|
class Boxed_Number;
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
namespace dispatch {
|
||||||
namespace dispatch
|
template<class T, class U>
|
||||||
{
|
class Proxy_Function_Callable_Impl;
|
||||||
namespace detail
|
template<class T>
|
||||||
{
|
class Assignable_Proxy_Function_Impl;
|
||||||
/**
|
|
||||||
* Used internally for handling a return value from a Proxy_Function call
|
namespace detail {
|
||||||
*/
|
/// Used internally for handling a return value from a Proxy_Function call
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return
|
struct Handle_Return {
|
||||||
{
|
template<typename T, typename = typename std::enable_if_t<std::is_trivial_v<typename std::decay_t<T>>>>
|
||||||
static Boxed_Value handle(const Ret &r)
|
static Boxed_Value handle(T r) {
|
||||||
{
|
return Boxed_Value(std::move(r), true);
|
||||||
return const_var(r);
|
}
|
||||||
}
|
|
||||||
};
|
template<typename T, typename = typename std::enable_if_t<!(std::is_trivial_v<typename std::decay_t<T>>)>>
|
||||||
|
static Boxed_Value handle(T &&r) {
|
||||||
|
return Boxed_Value(std::make_shared<T>(std::forward<T>(r)), true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<Ret *>
|
struct Handle_Return<const std::function<Ret> &> {
|
||||||
{
|
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||||
static Boxed_Value handle(Ret *p)
|
return Boxed_Value(
|
||||||
{
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret, std::function<Ret>>>(f));
|
||||||
return Boxed_Value(p);
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<std::shared_ptr<Ret> &>
|
struct Handle_Return<std::function<Ret>> : Handle_Return<const std::function<Ret> &> {
|
||||||
{
|
};
|
||||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
|
||||||
{
|
|
||||||
return Boxed_Value(r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<std::shared_ptr<Ret> >
|
struct Handle_Return<const std::shared_ptr<std::function<Ret>>> {
|
||||||
{
|
static Boxed_Value handle(const std::shared_ptr<std::function<Ret>> &f) {
|
||||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
return Boxed_Value(
|
||||||
{
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Assignable_Proxy_Function_Impl<Ret>>(std::ref(*f), f));
|
||||||
return Boxed_Value(r);
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const std::shared_ptr<Ret> &>
|
struct Handle_Return<const std::shared_ptr<std::function<Ret>> &> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
|
||||||
{
|
};
|
||||||
static Boxed_Value handle(const std::shared_ptr<Ret> &r)
|
|
||||||
{
|
|
||||||
return Boxed_Value(r);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<const Ret &>
|
struct Handle_Return<std::shared_ptr<std::function<Ret>>> : Handle_Return<const std::shared_ptr<std::function<Ret>>> {
|
||||||
{
|
};
|
||||||
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<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return<Ret &>
|
struct Handle_Return<std::function<Ret> &> {
|
||||||
{
|
static Boxed_Value handle(std::function<Ret> &f) {
|
||||||
static Boxed_Value handle(Ret &r)
|
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>>()));
|
||||||
return Boxed_Value(std::ref(r));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static Boxed_Value handle(const Ret &r)
|
static Boxed_Value handle(const std::function<Ret> &f) {
|
||||||
{
|
return Boxed_Value(
|
||||||
return Boxed_Value(std::cref(r));
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<std::shared_ptr<Ret> &> {
|
||||||
|
static Boxed_Value handle(const std::shared_ptr<Ret> &r) { return Boxed_Value(r, true); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<std::shared_ptr<Ret>> : Handle_Return<std::shared_ptr<Ret> &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<const std::shared_ptr<Ret> &> : Handle_Return<std::shared_ptr<Ret> &> {
|
||||||
|
};
|
||||||
|
|
||||||
|
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(std::move(r), true); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret, bool Ptr>
|
||||||
|
struct Handle_Return_Ref {
|
||||||
|
template<typename T>
|
||||||
|
static Boxed_Value handle(T &&r) {
|
||||||
|
return Boxed_Value(std::cref(r), true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return_Ref<Ret, true> {
|
||||||
|
template<typename T>
|
||||||
|
static Boxed_Value handle(T &&r) {
|
||||||
|
return Boxed_Value(typename std::remove_reference<decltype(r)>::type{r}, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<const Ret &> : Handle_Return_Ref<const Ret &, std::is_pointer<typename std::remove_reference<const Ret &>::type>::value> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<const Ret> {
|
||||||
|
static Boxed_Value handle(Ret r) { return Boxed_Value(std::move(r)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ret>
|
||||||
|
struct Handle_Return<Ret &> {
|
||||||
|
static Boxed_Value handle(Ret &r) { return Boxed_Value(std::ref(r)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<Boxed_Value> {
|
||||||
|
static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<const Boxed_Value> : Handle_Return<Boxed_Value> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<Boxed_Value &> : Handle_Return<Boxed_Value> {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Handle_Return<const Boxed_Value &> : Handle_Return<Boxed_Value> {
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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<>
|
template<>
|
||||||
struct Handle_Return<Boxed_Value>
|
struct Handle_Return<Boxed_Number> {
|
||||||
{
|
static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; }
|
||||||
static Boxed_Value handle(const Boxed_Value &r)
|
};
|
||||||
{
|
|
||||||
return r;
|
template<>
|
||||||
}
|
struct Handle_Return<const Boxed_Number> : Handle_Return<Boxed_Number> {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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<>
|
template<>
|
||||||
struct Handle_Return<const Boxed_Value>
|
struct Handle_Return<void> {
|
||||||
{
|
static Boxed_Value handle() { return void_var(); }
|
||||||
static Boxed_Value handle(const Boxed_Value &r)
|
};
|
||||||
{
|
} // namespace detail
|
||||||
return r;
|
} // namespace dispatch
|
||||||
}
|
} // namespace chaiscript
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally for handling a return value from a Proxy_Function call
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
struct 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 &>
|
|
||||||
{
|
|
||||||
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_Number>
|
|
||||||
{
|
|
||||||
static Boxed_Value handle(const Boxed_Number &r)
|
|
||||||
{
|
|
||||||
return r.bv;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally for handling a return value from a Proxy_Function call
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
struct Handle_Return<const Boxed_Number>
|
|
||||||
{
|
|
||||||
static Boxed_Value handle(const Boxed_Number &r)
|
|
||||||
{
|
|
||||||
return r.bv;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used internally for handling a return value from a Proxy_Function call
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
struct Handle_Return<void>
|
|
||||||
{
|
|
||||||
static Boxed_Value handle()
|
|
||||||
{
|
|
||||||
return Boxed_Value(Boxed_Value::Void_Type());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,460 +1,184 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_OPERATORS_HPP_
|
||||||
#define CHAISCRIPT_OPERATORS_HPP_
|
#define CHAISCRIPT_OPERATORS_HPP_
|
||||||
|
|
||||||
#include "../chaiscript_defines.hpp"
|
#include "../chaiscript_defines.hpp"
|
||||||
|
#include "../dispatchkit/dispatchkit.hpp"
|
||||||
|
#include "register_function.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript::bootstrap::operators {
|
||||||
{
|
template<typename T>
|
||||||
namespace bootstrap
|
void assign(Module &m) {
|
||||||
{
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs = rhs; }), "=");
|
||||||
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()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign<T &, T &, const T&>), "=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_bitwise_and(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_bitwise_and<T &, T &, const T&>), "&=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_xor(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_xor<T &, T &, const T&>), "^=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_bitwise_or(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_bitwise_or<T &, T &, const T&>), "|=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_difference(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_difference<T &, T &, const T&>), "-=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_left_shift(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_left_shift<T &, T &, const T&>), "<<=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_product(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_product<T &, T &, const T&>), "*=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_quotient(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_quotient<T &, T &, const T&>), "/=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_remainder(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_remainder<T &, T &, const T&>), "%=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_right_shift(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_right_shift<T &, T &, const T&>), ">>=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr assign_sum(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&assign_sum<T &, T &, const T&>), "+=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr prefix_decrement(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&prefix_decrement<T &, T &>), "--");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr prefix_increment(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&prefix_increment<T &, T &>), "++");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr equal(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&equal<bool, const T&, const T&>), "==");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr greater_than(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&greater_than<bool, const T&, const T&>), ">");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr greater_than_equal(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&greater_than_equal<bool, const T&, const T&>), ">=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr less_than(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&less_than<bool, const T&, const T&>), "<");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr less_than_equal(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&less_than_equal<bool, const T&, const T&>), "<=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr logical_compliment(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&logical_compliment<bool, const T &>), "!");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr not_equal(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(¬_equal<bool, const T &, const T &>), "!=");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr addition(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&addition<T, const T &, const T &>), "+");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr unary_plus(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&unary_plus<T, const T &>), "+");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr subtraction(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&subtraction<T, const T &, const T &>), "-");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr unary_minus(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&unary_minus<T, const T &>), "-");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr bitwise_and(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&bitwise_and<T, const T &, const T &>), "&");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr bitwise_compliment(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&bitwise_compliment<T, const T &>), "~");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr bitwise_xor(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&bitwise_xor<T, const T &, const T &>), "^");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr bitwise_or(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&bitwise_or<T, const T &, const T &>), "|");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr division(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&division<T, const T &, const T &>), "/");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr left_shift(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&left_shift<T, const T &, const T &>), "<<");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr multiplication(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&multiplication<T, const T &, const T &>), "*");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr remainder(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&remainder<T, const T &, const T &>), "%");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
ModulePtr right_shift(ModulePtr m = ModulePtr(new Module()))
|
|
||||||
{
|
|
||||||
m->add(fun(&right_shift<T, const T &, const T &>), ">>");
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_bitwise_and(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs &= rhs; }), "&=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_xor(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs ^= rhs; }), "^=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_bitwise_or(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs |= rhs; }), "|=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_difference(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs -= rhs; }), "-=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_left_shift(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "<<=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_product(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs <<= rhs; }), "*=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_quotient(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs /= rhs; }), "/=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_remainder(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs %= rhs; }), "%=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_right_shift(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs >>= rhs; }), ">>=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void assign_sum(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs, const T &rhs) -> T & { return lhs += rhs; }), "+=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void prefix_decrement(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs) -> T & { return --lhs; }), "--");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void prefix_increment(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](T &lhs) -> T & { return ++lhs; }), "++");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void equal(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs == rhs; }), "==");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void greater_than(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs > rhs; }), ">");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void greater_than_equal(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >= rhs; }), ">=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void less_than(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs < rhs; }), "<");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void less_than_equal(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs <= rhs; }), "<=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void logical_compliment(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs) { return !lhs; }), "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void not_equal(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs != rhs; }), "!=");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void addition(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs + rhs; }), "+");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void unary_plus(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs) { return +lhs; }), "+");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void subtraction(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs - rhs; }), "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void unary_minus(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs) { return -lhs; }), "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void bitwise_and(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs & rhs; }), "&");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void bitwise_compliment(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs) { return ~lhs; }), "~");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void bitwise_xor(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs ^ rhs; }), "^");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void bitwise_or(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs | rhs; }), "|");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void division(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs / rhs; }), "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void left_shift(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs << rhs; }), "<<");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void multiplication(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs * rhs; }), "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void remainder(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs % rhs; }), "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void right_shift(Module &m) {
|
||||||
|
m.add(chaiscript::fun([](const T &lhs, const T &rhs) { return lhs >> rhs; }), ">>");
|
||||||
|
}
|
||||||
|
} // namespace chaiscript::bootstrap::operators
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,43 +1,41 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||||
|
|
||||||
namespace chaiscript
|
#include "proxy_functions.hpp"
|
||||||
{
|
|
||||||
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 >
|
namespace chaiscript::dispatch::detail {
|
||||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
template<typename Class, typename... Params>
|
||||||
{
|
Proxy_Function build_constructor_(Class (*)(Params...)) {
|
||||||
typedef std::shared_ptr<Class> (sig)(Params...);
|
if constexpr (!std::is_copy_constructible_v<Class>) {
|
||||||
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
|
auto call = [](auto &&...param) { return std::make_shared<Class>(std::forward<decltype(param)>(param)...); };
|
||||||
}
|
|
||||||
|
return Proxy_Function(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base,
|
||||||
|
dispatch::Proxy_Function_Callable_Impl<std::shared_ptr<Class>(Params...), decltype(call)>>(call));
|
||||||
|
} else if constexpr (true) {
|
||||||
|
auto call = [](auto &&...param) { return Class(std::forward<decltype(param)>(param)...); };
|
||||||
|
|
||||||
|
return Proxy_Function(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Class(Params...), decltype(call)>>(
|
||||||
|
call));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace chaiscript::dispatch::detail
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
/// \brief Generates a constructor function for use with ChaiScript
|
/// \brief Generates a constructor function for use with ChaiScript
|
||||||
///
|
///
|
||||||
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
|
/// \tparam T The signature of the constructor to generate. In the form of: ClassType (ParamType1, ParamType2, ...)
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// \code
|
/// \code
|
||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
@ -46,13 +44,10 @@ namespace chaiscript
|
|||||||
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
|
/// chai.add(constructor<MyClass (int, float)>(), "MyClass");
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Proxy_Function constructor()
|
Proxy_Function constructor() {
|
||||||
{
|
T *f = nullptr;
|
||||||
T *f = 0;
|
return (dispatch::detail::build_constructor_(f));
|
||||||
return (dispatch::detail::build_constructor_(f));
|
}
|
||||||
}
|
} // namespace chaiscript
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,211 +1,111 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||||
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
#define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_
|
||||||
|
|
||||||
#include "boxed_value.hpp"
|
#include <array>
|
||||||
#include "boxed_cast.hpp"
|
#include <functional>
|
||||||
#include "type_info.hpp"
|
|
||||||
#include "handle_return.hpp"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace chaiscript
|
#include "../chaiscript_defines.hpp"
|
||||||
{
|
#include "boxed_cast.hpp"
|
||||||
namespace exception
|
#include "boxed_value.hpp"
|
||||||
{
|
#include "function_params.hpp"
|
||||||
|
#include "handle_return.hpp"
|
||||||
|
#include "type_info.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
class Type_Conversions_State;
|
||||||
|
namespace exception {
|
||||||
|
class bad_boxed_cast;
|
||||||
|
} // namespace exception
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
namespace exception {
|
||||||
/**
|
/**
|
||||||
* Exception thrown when there is a mismatch in number of
|
* Exception thrown when there is a mismatch in number of
|
||||||
* parameters during Proxy_Function execution
|
* parameters during Proxy_Function execution
|
||||||
*/
|
*/
|
||||||
struct arity_error : std::range_error
|
struct arity_error : std::range_error {
|
||||||
{
|
|
||||||
arity_error(int t_got, int t_expected)
|
arity_error(int t_got, int t_expected)
|
||||||
: std::range_error("Function dispatch arity mismatch"),
|
: std::range_error("Function dispatch arity mismatch")
|
||||||
got(t_got), expected(t_expected)
|
, got(t_got)
|
||||||
{
|
, expected(t_expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~arity_error() CHAISCRIPT_NOEXCEPT {}
|
arity_error(const arity_error &) = default;
|
||||||
|
|
||||||
|
~arity_error() noexcept override = default;
|
||||||
|
|
||||||
int got;
|
int got;
|
||||||
int expected;
|
int expected;
|
||||||
};
|
};
|
||||||
}
|
} // namespace exception
|
||||||
|
|
||||||
namespace dispatch
|
|
||||||
{
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template<typename ... Rest>
|
|
||||||
struct Build_Param_Type_List;
|
|
||||||
|
|
||||||
template<typename Param, typename ... Rest>
|
|
||||||
struct Build_Param_Type_List<Param, Rest...>
|
|
||||||
{
|
|
||||||
static void build(std::vector<Type_Info> &t_params)
|
|
||||||
{
|
|
||||||
t_params.push_back(chaiscript::detail::Get_Type_Info<Param>::get());
|
|
||||||
Build_Param_Type_List<Rest...>::build(t_params);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 0th case
|
|
||||||
template<>
|
|
||||||
struct Build_Param_Type_List<>
|
|
||||||
{
|
|
||||||
static void build(std::vector<Type_Info> &)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
namespace dispatch {
|
||||||
|
namespace detail {
|
||||||
|
/**
|
||||||
|
* Used by Proxy_Function_Impl to return a list of all param types
|
||||||
|
* it contains.
|
||||||
|
*/
|
||||||
|
template<typename Ret, typename... Params>
|
||||||
|
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...)) {
|
||||||
|
/// \note somehow this is responsible for a large part of the code generation
|
||||||
|
return {user_type<Ret>(), user_type<Params>()...};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by Proxy_Function_Impl to return a list of all param types
|
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
||||||
* it contains.
|
* 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>
|
*/
|
||||||
std::vector<Type_Info> build_param_type_list(Ret (*)(Params...))
|
template<typename Ret, typename... Params>
|
||||||
{
|
bool compare_types_cast(Ret (*)(Params...), const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) noexcept {
|
||||||
/// \todo this code was previously using { chaiscript::detail::Get_Type_Info<Ret>::get()... }
|
try {
|
||||||
/// but this seems to indicate another bug with MSVC's uniform initializer lists
|
std::vector<Boxed_Value>::size_type i = 0;
|
||||||
std::vector<Type_Info> params;
|
(boxed_cast<Params>(params[i++], &t_conversions), ...);
|
||||||
params.push_back(chaiscript::detail::Get_Type_Info<Ret>::get());
|
|
||||||
Build_Param_Type_List<Params...>::build(params);
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Forward declaration
|
|
||||||
template<typename ... Rest>
|
|
||||||
struct Try_Cast;
|
|
||||||
|
|
||||||
template<typename Param, typename ... Rest>
|
|
||||||
struct Try_Cast<Param, Rest...>
|
|
||||||
{
|
|
||||||
static void do_try(const std::vector<Boxed_Value> ¶ms, int generation, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
boxed_cast<Param>(params[generation], &t_conversions);
|
|
||||||
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 0th case
|
|
||||||
template<>
|
|
||||||
struct Try_Cast<>
|
|
||||||
{
|
|
||||||
static void do_try(const std::vector<Boxed_Value> &, int, const Dynamic_Cast_Conversions &)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by Proxy_Function_Impl to determine if it is equivalent to another
|
|
||||||
* Proxy_Function_Impl object. This function is primarly 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 Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
Try_Cast<Params...>::do_try(params, 0, t_conversions);
|
|
||||||
} catch (const exception::bad_boxed_cast &) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Ret, int count, typename ... Params>
|
template<typename Callable, typename Ret, typename... Params, size_t... I>
|
||||||
struct Call_Func
|
Ret call_func(Ret (*)(Params...),
|
||||||
{
|
std::index_sequence<I...>,
|
||||||
|
const Callable &f,
|
||||||
|
[[maybe_unused]] const chaiscript::Function_Params ¶ms,
|
||||||
|
[[maybe_unused]] const Type_Conversions_State &t_conversions) {
|
||||||
|
return f(boxed_cast<Params>(params[I], &t_conversions)...);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ... InnerParams>
|
/// Used by Proxy_Function_Impl to perform typesafe execution of a function.
|
||||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
/// The function attempts to unbox each parameter to the expected type.
|
||||||
const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
|
/// if any unboxing fails the execution of the function fails and
|
||||||
{
|
/// the bad_boxed_cast is passed up to the caller.
|
||||||
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
|
template<typename Callable, typename Ret, typename... Params>
|
||||||
}
|
Boxed_Value
|
||||||
};
|
call_func(Ret (*sig)(Params...), const Callable &f, const chaiscript::Function_Params ¶ms, const Type_Conversions_State &t_conversions) {
|
||||||
|
if constexpr (std::is_same_v<Ret, void>) {
|
||||||
template<typename Ret, typename ... Params>
|
call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions);
|
||||||
struct Call_Func<Ret, 0, Params...>
|
return Handle_Return<void>::handle();
|
||||||
{
|
} else {
|
||||||
#ifdef CHAISCRIPT_MSVC
|
return Handle_Return<Ret>::handle(call_func(sig, std::index_sequence_for<Params...>{}, f, params, t_conversions));
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
|
|
||||||
#endif
|
|
||||||
template<typename ... InnerParams>
|
|
||||||
static Ret do_call(const std::function<Ret (Params...)> &f,
|
|
||||||
const std::vector<Boxed_Value> &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams)
|
|
||||||
{
|
|
||||||
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
|
|
||||||
}
|
|
||||||
#ifdef CHAISCRIPT_MSVC
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
if (params.size() == sizeof...(Params))
|
|
||||||
{
|
|
||||||
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
} // namespace detail
|
||||||
|
} // namespace dispatch
|
||||||
|
|
||||||
|
} // namespace chaiscript
|
||||||
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, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
return Handle_Return<Ret>::handle(call_func(fun, params, t_conversions));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Do_Call<void>
|
|
||||||
{
|
|
||||||
template<typename Fun>
|
|
||||||
static Boxed_Value go(const std::function<Fun> &fun, const std::vector<Boxed_Value> ¶ms, const Dynamic_Cast_Conversions &t_conversions)
|
|
||||||
{
|
|
||||||
call_func(fun, params, t_conversions);
|
|
||||||
return Handle_Return<void>::handle();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,77 +1,61 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||||
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
#define CHAISCRIPT_REGISTER_FUNCTION_HPP_
|
||||||
|
|
||||||
#include "dispatchkit.hpp"
|
#include <type_traits>
|
||||||
|
|
||||||
#include "bind_first.hpp"
|
#include "bind_first.hpp"
|
||||||
|
#include "function_signature.hpp"
|
||||||
|
#include "proxy_functions.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
namespace dispatch::detail {
|
||||||
namespace dispatch
|
template<typename Obj, typename Param1, typename... Rest>
|
||||||
{
|
Param1 get_first_param(Function_Params<Param1, Rest...>, Obj &&obj) {
|
||||||
namespace detail
|
return static_cast<Param1>(std::forward<Obj>(obj));
|
||||||
{
|
|
||||||
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...))
|
|
||||||
{
|
|
||||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
|
||||||
/// std::function for member function pointers seems to be broken in MSVC
|
|
||||||
return std::function<Ret(Class &, Args...)>(std::mem_fn(func));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename ... Args>
|
|
||||||
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
|
||||||
{
|
|
||||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
|
||||||
/// std::function for member function pointers seems to be broken in MSVC
|
|
||||||
return std::function<Ret (const Class &, Args...)>(std::mem_fn(func));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool Object>
|
|
||||||
struct Fun_Helper
|
|
||||||
{
|
|
||||||
template<typename T>
|
|
||||||
static Proxy_Function go(T t)
|
|
||||||
{
|
|
||||||
/// \todo is it possible to reduce the number of templates generated here?
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
template<typename Func, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject, bool Is_Object, typename Ret, typename... Param>
|
||||||
|
auto make_callable_impl(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) {
|
||||||
|
if constexpr (Is_MemberObject) {
|
||||||
|
// we now that the Param pack will have only one element, so we are safe expanding it here
|
||||||
|
return Proxy_Function(chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Attribute_Access<Ret, std::decay_t<Param>...>>(
|
||||||
|
std::forward<Func>(func)));
|
||||||
|
} else if constexpr (Is_Member) {
|
||||||
|
// TODO some kind of bug is preventing forwarding of this noexcept for the lambda
|
||||||
|
auto call = [func = std::forward<Func>(func)](auto &&obj, auto &&...param) /* noexcept(Is_Noexcept) */ -> decltype(auto) {
|
||||||
|
return ((get_first_param(Function_Params<Param...>{}, obj).*func)(std::forward<decltype(param)>(param)...));
|
||||||
|
};
|
||||||
|
return Proxy_Function(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), decltype(call)>>(
|
||||||
|
std::move(call)));
|
||||||
|
} else {
|
||||||
|
return Proxy_Function(
|
||||||
|
chaiscript::make_shared<dispatch::Proxy_Function_Base, dispatch::Proxy_Function_Callable_Impl<Ret(Param...), std::decay_t<Func>>>(
|
||||||
|
std::forward<Func>(func)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this version peels off the function object itself from the function signature, when used
|
||||||
|
// on a callable object
|
||||||
|
template<typename Func, typename Ret, typename Object, typename... Param, bool Is_Noexcept>
|
||||||
|
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Object, Param...>, Is_Noexcept, false, false, true>) {
|
||||||
|
return make_callable_impl(std::forward<Func>(func), Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, false, false, true>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func, typename Ret, typename... Param, bool Is_Noexcept, bool Is_Member, bool Is_MemberObject>
|
||||||
|
auto make_callable(Func &&func, Function_Signature<Ret, Function_Params<Param...>, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) {
|
||||||
|
return make_callable_impl(std::forward<Func>(func), fs);
|
||||||
|
}
|
||||||
|
} // namespace dispatch::detail
|
||||||
|
|
||||||
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
/// \brief Creates a new Proxy_Function object from a free function, member function or data member
|
||||||
/// \param[in] t Function / member to expose
|
/// \param[in] t Function / member to expose
|
||||||
@ -85,39 +69,19 @@ namespace chaiscript
|
|||||||
/// void memberfunction();
|
/// void memberfunction();
|
||||||
/// int memberdata;
|
/// int memberdata;
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
/// chai.add(fun(&myfunction), "myfunction");
|
/// chai.add(fun(&myfunction), "myfunction");
|
||||||
/// chai.add(fun(&MyClass::memberfunction), "memberfunction");
|
/// chai.add(fun(&MyClass::memberfunction), "memberfunction");
|
||||||
/// chai.add(fun(&MyClass::memberdata), "memberdata");
|
/// chai.add(fun(&MyClass::memberdata), "memberdata");
|
||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
|
||||||
/// \sa \ref addingfunctions
|
|
||||||
template<typename T>
|
|
||||||
Proxy_Function fun(T t)
|
|
||||||
{
|
|
||||||
return dispatch::detail::Fun_Helper<std::is_member_object_pointer<T>::value>::go(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// \brief Creates a new Proxy_Function object from a std::function object
|
|
||||||
/// \param[in] f std::function to expose to ChaiScript
|
|
||||||
///
|
///
|
||||||
/// \b Example:
|
/// \sa \ref adding_functions
|
||||||
/// \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>
|
template<typename T>
|
||||||
Proxy_Function fun(const std::function<T> &f)
|
Proxy_Function fun(T &&t) {
|
||||||
{
|
return dispatch::detail::make_callable(std::forward<T>(t), dispatch::detail::function_signature(t));
|
||||||
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 and binds the first parameter of it
|
/// \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] t Function / member to expose
|
||||||
/// \param[in] q Value to bind to first parameter
|
/// \param[in] q Value to bind to first parameter
|
||||||
@ -128,48 +92,19 @@ namespace chaiscript
|
|||||||
/// {
|
/// {
|
||||||
/// void memberfunction(int);
|
/// void memberfunction(int);
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// MyClass obj;
|
/// MyClass obj;
|
||||||
/// chaiscript::ChaiScript chai;
|
/// chaiscript::ChaiScript chai;
|
||||||
/// // Add function taking only one argument, an int, and permanently bound to "obj"
|
/// // Add function taking only one argument, an int, and permanently bound to "obj"
|
||||||
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
|
/// chai.add(fun(&MyClass::memberfunction, std::ref(obj)), "memberfunction");
|
||||||
/// \endcode
|
/// \endcode
|
||||||
///
|
|
||||||
/// \sa \ref addingfunctions
|
|
||||||
template<typename T, typename Q>
|
|
||||||
Proxy_Function fun(T t, const Q &q)
|
|
||||||
{
|
|
||||||
return fun(detail::bind_first(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:
|
/// \sa \ref adding_functions
|
||||||
/// \code
|
template<typename T, typename Q>
|
||||||
/// struct MyClass
|
Proxy_Function fun(T &&t, const Q &q) {
|
||||||
/// {
|
return fun(detail::bind_first(std::forward<T>(t), q));
|
||||||
/// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
137
include/chaiscript/dispatchkit/short_alloc.hpp
Normal file
137
include/chaiscript/dispatchkit/short_alloc.hpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#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 <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
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
|
||||||
539
include/chaiscript/dispatchkit/type_conversions.hpp
Normal file
539
include/chaiscript/dispatchkit/type_conversions.hpp
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, 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 <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
#include "../chaiscript_threading.hpp"
|
||||||
|
#include "../utility/static_string.hpp"
|
||||||
|
#include "bad_boxed_cast.hpp"
|
||||||
|
#include "boxed_cast_helper.hpp"
|
||||||
|
#include "boxed_value.hpp"
|
||||||
|
#include "type_info.hpp"
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
namespace exception {
|
||||||
|
/// \brief Error thrown when there's a problem with type conversion
|
||||||
|
class conversion_error : public bad_boxed_cast {
|
||||||
|
public:
|
||||||
|
conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept
|
||||||
|
: bad_boxed_cast(t_from, (*t_to.bare_type_info()), what)
|
||||||
|
, type_to(t_to) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Type_Info type_to;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 utility::Static_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 utility::Static_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 utility::Static_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 utility::Static_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 exception
|
||||||
|
|
||||||
|
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 noexcept { return m_to; }
|
||||||
|
const Type_Info &from() const noexcept { return m_from; }
|
||||||
|
|
||||||
|
virtual bool bidir() const noexcept { 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 noexcept 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 noexcept override { return false; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Callable m_func;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
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 noexcept {
|
||||||
|
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 &&) = delete;
|
||||||
|
|
||||||
|
Type_Conversions &operator=(const Type_Conversions &) = delete;
|
||||||
|
Type_Conversions &operator=(Type_Conversions &&) = delete;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
|
||||||
|
throw exception::conversion_error(conversion->to(), conversion->from(), "Trying to re-insert an existing conversion!");
|
||||||
|
}
|
||||||
|
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 noexcept {
|
||||||
|
const auto type = user_type<T>().bare_type_info();
|
||||||
|
return thread_cache().count(type) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename To, typename From>
|
||||||
|
bool converts() const noexcept {
|
||||||
|
return converts(user_type<To>(), user_type<From>());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool converts(const Type_Info &to, const Type_Info &from) const noexcept {
|
||||||
|
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(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Conversion_Saves &conversion_saves() const noexcept { 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 noexcept { return &m_conversions.get(); }
|
||||||
|
|
||||||
|
const Type_Conversions *get() const noexcept { return &m_conversions.get(); }
|
||||||
|
|
||||||
|
Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::reference_wrapper<const Type_Conversions> m_conversions;
|
||||||
|
std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
|
||||||
|
|
||||||
|
/// \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() {
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
if constexpr (std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
|
||||||
|
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
|
||||||
|
} else {
|
||||||
|
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<const 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);
|
||||||
|
}
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,257 +1,210 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_
|
#ifndef CHAISCRIPT_TYPE_INFO_HPP_
|
||||||
#define CHAISCRIPT_TYPE_INFO_HPP_
|
#define CHAISCRIPT_TYPE_INFO_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript {
|
||||||
{
|
namespace detail {
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Bare_Type
|
struct Bare_Type {
|
||||||
{
|
using type = typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type;
|
||||||
typedef typename std::remove_cv<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::type type;
|
};
|
||||||
};
|
} // namespace detail
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Compile time deduced information about a type
|
/// \brief Compile time deduced information about a type
|
||||||
class Type_Info
|
class Type_Info {
|
||||||
{
|
public:
|
||||||
public:
|
constexpr Type_Info(const bool t_is_const,
|
||||||
CHAISCRIPT_CONSTEXPR Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
const bool t_is_reference,
|
||||||
bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bareti)
|
const bool t_is_pointer,
|
||||||
: m_type_info(t_ti), m_bare_type_info(t_bareti),
|
const bool t_is_void,
|
||||||
m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
const bool t_is_arithmetic,
|
||||||
m_is_void(t_is_void), m_is_arithmetic(t_is_arithmetic),
|
const std::type_info *t_ti,
|
||||||
m_is_undef(false)
|
const std::type_info *t_bare_ti) noexcept
|
||||||
{
|
: 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)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Type_Info() noexcept = default;
|
||||||
|
|
||||||
|
bool operator<(const Type_Info &ti) const noexcept { return m_type_info->before(*ti.m_type_info); }
|
||||||
|
|
||||||
|
constexpr bool operator!=(const Type_Info &ti) const noexcept { return !(operator==(ti)); }
|
||||||
|
|
||||||
|
constexpr bool operator!=(const std::type_info &ti) const noexcept { return !(operator==(ti)); }
|
||||||
|
|
||||||
|
constexpr bool operator==(const Type_Info &ti) const noexcept {
|
||||||
|
return ti.m_type_info == m_type_info || *ti.m_type_info == *m_type_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator==(const std::type_info &ti) const noexcept { return !is_undef() && (*m_type_info) == ti; }
|
||||||
|
|
||||||
|
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; }
|
||||||
|
|
||||||
|
const char *name() const noexcept {
|
||||||
|
if (!is_undef()) {
|
||||||
|
return m_type_info->name();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type_Info()
|
const char *bare_name() const noexcept {
|
||||||
: m_type_info(0), m_bare_type_info(0),
|
if (!is_undef()) {
|
||||||
m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
return m_bare_type_info->name();
|
||||||
m_is_void(false), m_is_arithmetic(false),
|
} else {
|
||||||
m_is_undef(true)
|
return "";
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Type_Info(const Type_Info &ti)
|
constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; }
|
||||||
: 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)
|
private:
|
||||||
{
|
struct Unknown_Type {
|
||||||
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
|
const std::type_info *m_type_info = &typeid(Unknown_Type);
|
||||||
{
|
const std::type_info *m_bare_type_info = &typeid(Unknown_Type);
|
||||||
return m_type_info < ti.m_type_info;
|
static const int is_const_flag = 0;
|
||||||
}
|
static const int is_reference_flag = 1;
|
||||||
|
static const int is_pointer_flag = 2;
|
||||||
bool operator==(const Type_Info &ti) const
|
static const int is_void_flag = 3;
|
||||||
{
|
static const int is_arithmetic_flag = 4;
|
||||||
return ti.m_type_info == m_type_info
|
static const int is_undef_flag = 5;
|
||||||
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
|
unsigned int m_flags = (1 << is_undef_flag);
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const std::type_info &ti) const
|
|
||||||
{
|
|
||||||
return m_type_info != 0 && (*m_type_info) == ti;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bare_equal(const Type_Info &ti) const
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bare_equal_type_info(const std::type_info &ti) const
|
|
||||||
{
|
|
||||||
return m_bare_type_info != 0
|
|
||||||
&& (*m_bare_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; }
|
|
||||||
|
|
||||||
std::string name() const
|
|
||||||
{
|
|
||||||
if (m_type_info)
|
|
||||||
{
|
|
||||||
return m_type_info->name();
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string bare_name() const
|
|
||||||
{
|
|
||||||
if (m_bare_type_info)
|
|
||||||
{
|
|
||||||
return m_bare_type_info->name();
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail {
|
||||||
{
|
/// Helper used to create a Type_Info object
|
||||||
/**
|
|
||||||
* Helper used to create a Type_Info object
|
|
||||||
*/
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info
|
struct Get_Type_Info {
|
||||||
{
|
constexpr static Type_Info get() noexcept {
|
||||||
typedef T type;
|
return Type_Info(std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
|
||||||
|
std::is_reference<T>::value,
|
||||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
std::is_pointer<T>::value,
|
||||||
{
|
std::is_void<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_arithmetic<T>::value || std::is_arithmetic<typename std::remove_reference<T>::type>::value)
|
||||||
std::is_void<T>::value,
|
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
&typeid(T),
|
||||||
&typeid(T),
|
&typeid(typename Bare_Type<T>::type));
|
||||||
&typeid(typename Bare_Type<T>::type));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<std::shared_ptr<T> >
|
struct Get_Type_Info<std::shared_ptr<T>> {
|
||||||
{
|
constexpr static Type_Info get() noexcept {
|
||||||
typedef T type;
|
return Type_Info(std::is_const<T>::value,
|
||||||
|
std::is_reference<T>::value,
|
||||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
std::is_pointer<T>::value,
|
||||||
{
|
std::is_void<T>::value,
|
||||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
std::is_arithmetic<T>::value
|
||||||
std::is_void<T>::value,
|
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
&typeid(std::shared_ptr<T>),
|
||||||
&typeid(std::shared_ptr<T> ),
|
&typeid(typename Bare_Type<T>::type));
|
||||||
&typeid(typename Bare_Type<T>::type));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<const std::shared_ptr<T> &>
|
struct Get_Type_Info<std::shared_ptr<T> &> : Get_Type_Info<std::shared_ptr<T>> {
|
||||||
{
|
};
|
||||||
typedef T type;
|
|
||||||
|
|
||||||
CHAISCRIPT_CONSTEXPR static 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,
|
|
||||||
&typeid(const std::shared_ptr<T> &),
|
|
||||||
&typeid(typename Bare_Type<T>::type));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<std::reference_wrapper<T> >
|
struct Get_Type_Info<const std::shared_ptr<T> &> {
|
||||||
{
|
constexpr static Type_Info get() noexcept {
|
||||||
typedef T type;
|
return Type_Info(std::is_const<T>::value,
|
||||||
|
std::is_reference<T>::value,
|
||||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
std::is_pointer<T>::value,
|
||||||
{
|
std::is_void<T>::value,
|
||||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
std::is_arithmetic<T>::value
|
||||||
std::is_void<T>::value,
|
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
&typeid(const std::shared_ptr<T> &),
|
||||||
&typeid(std::reference_wrapper<T> ),
|
&typeid(typename Bare_Type<T>::type));
|
||||||
&typeid(typename Bare_Type<T>::type));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Get_Type_Info<const std::reference_wrapper<T> &>
|
struct Get_Type_Info<std::reference_wrapper<T>> {
|
||||||
{
|
constexpr static Type_Info get() noexcept {
|
||||||
typedef T type;
|
return Type_Info(std::is_const<T>::value,
|
||||||
|
std::is_reference<T>::value,
|
||||||
CHAISCRIPT_CONSTEXPR static Type_Info get()
|
std::is_pointer<T>::value,
|
||||||
{
|
std::is_void<T>::value,
|
||||||
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
|
std::is_arithmetic<T>::value
|
||||||
std::is_void<T>::value,
|
&& !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<T>::type, bool>::value,
|
&typeid(std::reference_wrapper<T>),
|
||||||
&typeid(const std::reference_wrapper<T> &),
|
&typeid(typename Bare_Type<T>::type));
|
||||||
&typeid(typename Bare_Type<T>::type));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Stripped_Type
|
struct Get_Type_Info<const std::reference_wrapper<T> &> {
|
||||||
{
|
constexpr static Type_Info get() noexcept {
|
||||||
typedef typename Bare_Type<typename detail::Get_Type_Info<T>::type>::type type;
|
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<typename std::remove_reference<T>::type>::type, bool>::value,
|
||||||
|
&typeid(const std::reference_wrapper<T> &),
|
||||||
|
&typeid(typename Bare_Type<T>::type));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
/// \brief Creates a Type_Info object representing the type passed in
|
/// \brief Creates a Type_Info object representing the type passed in
|
||||||
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
|
/// \tparam T Type of object to get a Type_Info for, derived from the passed in parameter
|
||||||
/// \return Type_Info for T
|
/// \return Type_Info for T
|
||||||
///
|
///
|
||||||
/// \b Example:
|
/// \b Example:
|
||||||
/// \code
|
/// \code
|
||||||
/// int i;
|
/// int i;
|
||||||
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
/// chaiscript::Type_Info ti = chaiscript::user_type(i);
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename T>
|
template<typename T>
|
||||||
CHAISCRIPT_CONSTEXPR Type_Info user_type(const T &/*t*/)
|
constexpr Type_Info user_type(const T & /*t*/) noexcept {
|
||||||
{
|
|
||||||
return detail::Get_Type_Info<T>::get();
|
return detail::Get_Type_Info<T>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// \brief Creates a Type_Info object representing the templated type
|
/// \brief Creates a Type_Info object representing the templated type
|
||||||
/// \tparam T Type of object to get a Type_Info for
|
/// \tparam T Type of object to get a Type_Info for
|
||||||
/// \return Type_Info for T
|
/// \return Type_Info for T
|
||||||
///
|
///
|
||||||
/// \b Example:
|
/// \b Example:
|
||||||
/// \code
|
/// \code
|
||||||
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
/// chaiscript::Type_Info ti = chaiscript::user_type<int>();
|
||||||
/// \endcode
|
/// \endcode
|
||||||
template<typename T>
|
template<typename T>
|
||||||
CHAISCRIPT_CONSTEXPR Type_Info user_type()
|
constexpr Type_Info user_type() noexcept {
|
||||||
{
|
|
||||||
return detail::Get_Type_Info<T>::get();
|
return detail::Get_Type_Info<T>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace chaiscript
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -1,130 +1,167 @@
|
|||||||
// This file is distributed under the BSD License.
|
// This file is distributed under the BSD License.
|
||||||
// See "license.txt" for details.
|
// See "license.txt" for details.
|
||||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
// http://www.chaiscript.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_ALGEBRAIC_HPP_
|
#ifndef CHAISCRIPT_ALGEBRAIC_HPP_
|
||||||
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
#define CHAISCRIPT_ALGEBRAIC_HPP_
|
||||||
|
|
||||||
#include "../dispatchkit/dispatchkit.hpp"
|
#include "../utility/hash.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
#include <string>
|
||||||
{
|
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
struct Operators {
|
struct Operators {
|
||||||
enum Opers
|
enum class Opers {
|
||||||
{
|
equals,
|
||||||
boolean_flag,
|
less_than,
|
||||||
equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal,
|
greater_than,
|
||||||
non_const_flag,
|
less_than_equal,
|
||||||
assign, pre_increment, pre_decrement, assign_product, assign_sum,
|
greater_than_equal,
|
||||||
assign_quotient, assign_difference,
|
not_equal,
|
||||||
non_const_int_flag,
|
assign,
|
||||||
assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right,
|
pre_increment,
|
||||||
assign_remainder, assign_bitwise_xor,
|
pre_decrement,
|
||||||
const_int_flag,
|
assign_product,
|
||||||
shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement,
|
assign_sum,
|
||||||
const_flag,
|
assign_quotient,
|
||||||
sum, quotient, product, difference, unary_plus, unary_minus,
|
assign_difference,
|
||||||
|
assign_bitwise_and,
|
||||||
|
assign_bitwise_or,
|
||||||
|
assign_shift_left,
|
||||||
|
assign_shift_right,
|
||||||
|
assign_remainder,
|
||||||
|
assign_bitwise_xor,
|
||||||
|
shift_left,
|
||||||
|
shift_right,
|
||||||
|
remainder,
|
||||||
|
bitwise_and,
|
||||||
|
bitwise_or,
|
||||||
|
bitwise_xor,
|
||||||
|
bitwise_complement,
|
||||||
|
sum,
|
||||||
|
quotient,
|
||||||
|
product,
|
||||||
|
difference,
|
||||||
|
unary_plus,
|
||||||
|
unary_minus,
|
||||||
invalid
|
invalid
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *to_string(Opers t_oper) {
|
constexpr static const char *to_string(Opers t_oper) noexcept {
|
||||||
const char *opers[] = {
|
constexpr const char *opers[]
|
||||||
"",
|
= {"", "==", "<", ">", "<=", ">=", "!=", "", "=", "++", "--", "*=", "+=", "/=", "-=", "", "&=", "|=", "<<=", ">>=", "%=", "^=", "", "<<", ">>", "%", "&", "|", "^", "~", "", "+", "/", "*", "-", "+", "-", ""};
|
||||||
"==", "<", ">", "<=", ">=", "!=",
|
return opers[static_cast<int>(t_oper)];
|
||||||
"",
|
|
||||||
"=", "++", "--", "*=", "+=",
|
|
||||||
"/=", "-=",
|
|
||||||
"",
|
|
||||||
"&=", "|=", "<<=", ">>=",
|
|
||||||
"%=", "^=",
|
|
||||||
"",
|
|
||||||
"<<", ">>", "%", "&", "|", "^", "~",
|
|
||||||
"",
|
|
||||||
"+", "/", "*", "-", "+", "-",
|
|
||||||
""
|
|
||||||
};
|
|
||||||
return opers[t_oper];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Opers to_operator(const std::string &t_str, bool t_is_unary = false)
|
constexpr static Opers to_operator(std::string_view t_str, bool t_is_unary = false) noexcept {
|
||||||
{
|
#ifdef CHAISCRIPT_MSVC
|
||||||
if (t_str == "==")
|
#pragma warning(push)
|
||||||
{
|
#pragma warning(disable : 4307)
|
||||||
return equals;
|
#endif
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const auto op_hash = utility::hash(t_str);
|
||||||
|
switch (op_hash) {
|
||||||
|
case utility::hash("=="): {
|
||||||
|
return Opers::equals;
|
||||||
|
}
|
||||||
|
case utility::hash("<"): {
|
||||||
|
return Opers::less_than;
|
||||||
|
}
|
||||||
|
case utility::hash(">"): {
|
||||||
|
return Opers::greater_than;
|
||||||
|
}
|
||||||
|
case utility::hash("<="): {
|
||||||
|
return Opers::less_than_equal;
|
||||||
|
}
|
||||||
|
case utility::hash(">="): {
|
||||||
|
return Opers::greater_than_equal;
|
||||||
|
}
|
||||||
|
case utility::hash("!="): {
|
||||||
|
return Opers::not_equal;
|
||||||
|
}
|
||||||
|
case utility::hash("="): {
|
||||||
|
return Opers::assign;
|
||||||
|
}
|
||||||
|
case utility::hash("++"): {
|
||||||
|
return Opers::pre_increment;
|
||||||
|
}
|
||||||
|
case utility::hash("--"): {
|
||||||
|
return Opers::pre_decrement;
|
||||||
|
}
|
||||||
|
case utility::hash("*="): {
|
||||||
|
return Opers::assign_product;
|
||||||
|
}
|
||||||
|
case utility::hash("+="): {
|
||||||
|
return Opers::assign_sum;
|
||||||
|
}
|
||||||
|
case utility::hash("-="): {
|
||||||
|
return Opers::assign_difference;
|
||||||
|
}
|
||||||
|
case utility::hash("&="): {
|
||||||
|
return Opers::assign_bitwise_and;
|
||||||
|
}
|
||||||
|
case utility::hash("|="): {
|
||||||
|
return Opers::assign_bitwise_or;
|
||||||
|
}
|
||||||
|
case utility::hash("<<="): {
|
||||||
|
return Opers::assign_shift_left;
|
||||||
|
}
|
||||||
|
case utility::hash(">>="): {
|
||||||
|
return Opers::assign_shift_right;
|
||||||
|
}
|
||||||
|
case utility::hash("%="): {
|
||||||
|
return Opers::assign_remainder;
|
||||||
|
}
|
||||||
|
case utility::hash("^="): {
|
||||||
|
return Opers::assign_bitwise_xor;
|
||||||
|
}
|
||||||
|
case utility::hash("<<"): {
|
||||||
|
return Opers::shift_left;
|
||||||
|
}
|
||||||
|
case utility::hash(">>"): {
|
||||||
|
return Opers::shift_right;
|
||||||
|
}
|
||||||
|
case utility::hash("%"): {
|
||||||
|
return Opers::remainder;
|
||||||
|
}
|
||||||
|
case utility::hash("&"): {
|
||||||
|
return Opers::bitwise_and;
|
||||||
|
}
|
||||||
|
case utility::hash("|"): {
|
||||||
|
return Opers::bitwise_or;
|
||||||
|
}
|
||||||
|
case utility::hash("^"): {
|
||||||
|
return Opers::bitwise_xor;
|
||||||
|
}
|
||||||
|
case utility::hash("~"): {
|
||||||
|
return Opers::bitwise_complement;
|
||||||
|
}
|
||||||
|
case utility::hash("+"): {
|
||||||
|
return t_is_unary ? Opers::unary_plus : Opers::sum;
|
||||||
|
}
|
||||||
|
case utility::hash("-"): {
|
||||||
|
return t_is_unary ? Opers::unary_minus : Opers::difference;
|
||||||
|
}
|
||||||
|
case utility::hash("/"): {
|
||||||
|
return Opers::quotient;
|
||||||
|
}
|
||||||
|
case utility::hash("*"): {
|
||||||
|
return Opers::product;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return Opers::invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace chaiscript
|
||||||
|
|
||||||
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
|
||||||
|
|
||||||
|
#endif /* _CHAISCRIPT_ALGEBRAIC_HPP */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
433
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
433
include/chaiscript/language/chaiscript_optimizer.hpp
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, 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) {
|
||||||
|
((p = static_cast<T &>(*this).optimize(std::move(p))), ...);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
eval::AST_Node_Impl<T> &child_at(eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
|
||||||
|
if (node.children[offset]->identifier == AST_Node_Type::Compiled) {
|
||||||
|
return *(dynamic_cast<eval::Compiled_AST_Node<T> &>(*node.children[offset]).m_original_node);
|
||||||
|
} else {
|
||||||
|
return *node.children[offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const eval::AST_Node_Impl<T> &child_at(const eval::AST_Node_Impl<T> &node, const size_t offset) noexcept {
|
||||||
|
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<T> &node) noexcept {
|
||||||
|
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(eval::AST_Node_Impl_Ptr<T> original_node, std::vector<eval::AST_Node_Impl_Ptr<T>> children, Callable callable) {
|
||||||
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Compiled_AST_Node<T>>(std::move(original_node),
|
||||||
|
std::move(children),
|
||||||
|
std::move(callable));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Return {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(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() = std::move(block_last_child->children[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool contains_var_decl_in_scope(const eval::AST_Node_Impl<T> &node) noexcept {
|
||||||
|
if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl
|
||||||
|
|| node.identifier == AST_Node_Type::Reference) {
|
||||||
|
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
|
||||||
|
&& child.identifier != AST_Node_Type::Ranged_For && contains_var_decl_in_scope(child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(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 std::move(node->children[0]);
|
||||||
|
} else {
|
||||||
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Scopeless_Block_AST_Node<T>>(node->text,
|
||||||
|
node->location,
|
||||||
|
std::move(node->children));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Dead_Code {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(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) {
|
||||||
|
const 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 {
|
||||||
|
const auto new_children = [&]() {
|
||||||
|
std::vector<eval::AST_Node_Impl_Ptr<T>> retval;
|
||||||
|
for (const auto x : keepers) {
|
||||||
|
retval.push_back(std::move(node->children[x]));
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
};
|
||||||
|
|
||||||
|
return chaiscript::make_unique<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(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].get();
|
||||||
|
if (child->identifier == AST_Node_Type::Fun_Call) {
|
||||||
|
node->children[i]
|
||||||
|
= chaiscript::make_unique<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_unique<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 Assign_Decl {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(eval::AST_Node_Impl_Ptr<T> node) {
|
||||||
|
if ((node->identifier == AST_Node_Type::Equation) && node->text == "=" && node->children.size() == 2
|
||||||
|
&& node->children[0]->identifier == AST_Node_Type::Var_Decl) {
|
||||||
|
std::vector<eval::AST_Node_Impl_Ptr<T>> new_children;
|
||||||
|
new_children.push_back(std::move(node->children[0]->children[0]));
|
||||||
|
new_children.push_back(std::move(node->children[1]));
|
||||||
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Assign_Decl_AST_Node<T>>(node->text,
|
||||||
|
node->location,
|
||||||
|
std::move(new_children));
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct If {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(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 = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[0].get())->m_value;
|
||||||
|
if (condition.get_type_info().bare_equal_type_info(typeid(bool))) {
|
||||||
|
if (boxed_cast<bool>(condition)) {
|
||||||
|
return std::move(node->children[1]);
|
||||||
|
} else if (node->children.size() == 3) {
|
||||||
|
return std::move(node->children[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Partial_Fold {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(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 = dynamic_cast<eval::Constant_AST_Node<T> *>(node->children[1].get())->m_value;
|
||||||
|
if (rhs.get_type_info().is_arithmetic()) {
|
||||||
|
return chaiscript::make_unique<eval::AST_Node_Impl<T>, eval::Fold_Right_Binary_Operator_AST_Node<T>>(
|
||||||
|
node->text, node->location, std::move(node->children), rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception &) {
|
||||||
|
// failure to fold, that's OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Constant_Fold {
|
||||||
|
template<typename T>
|
||||||
|
auto optimize(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 = dynamic_cast<const eval::Constant_AST_Node<T> *>(node->children[0].get())->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_unique<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_unique<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 = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
|
||||||
|
const auto rhs = dynamic_cast<const 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_unique<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 = dynamic_cast<const eval::Constant_AST_Node<T> &>(*node->children[0]).m_value;
|
||||||
|
const auto rhs = dynamic_cast<const 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_unique<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 = dynamic_cast<const 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_unique<eval::AST_Node_Impl<T>, eval::Constant_AST_Node<T>>(std::move(match),
|
||||||
|
node->location,
|
||||||
|
const_var(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(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 (child_count(*for_node) == 4 && eq_node.identifier == AST_Node_Type::Assign_Decl && child_count(eq_node) == 2
|
||||||
|
&& child_at(eq_node, 0).identifier == AST_Node_Type::Id && 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(eq_node, 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(eq_node, 0).text) {
|
||||||
|
const Boxed_Value &begin = dynamic_cast<const eval::Constant_AST_Node<T> &>(child_at(eq_node, 1)).m_value;
|
||||||
|
const Boxed_Value &end = dynamic_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);
|
||||||
|
|
||||||
|
// note that we are moving the last element out, then popping the empty shared_ptr
|
||||||
|
// from the vector
|
||||||
|
std::vector<eval::AST_Node_Impl_Ptr<T>> body_vector;
|
||||||
|
auto body_child = std::move(for_node->children[3]);
|
||||||
|
for_node->children.pop_back();
|
||||||
|
body_vector.emplace_back(std::move(body_child));
|
||||||
|
|
||||||
|
return make_compiled_node(std::move(for_node),
|
||||||
|
std::move(body_vector),
|
||||||
|
[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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Optimizer_Default = Optimizer<optimizer::Partial_Fold,
|
||||||
|
optimizer::Unused_Return,
|
||||||
|
optimizer::Constant_Fold,
|
||||||
|
optimizer::If,
|
||||||
|
optimizer::Return,
|
||||||
|
optimizer::Dead_Code,
|
||||||
|
optimizer::Block,
|
||||||
|
optimizer::For_Loop,
|
||||||
|
optimizer::Assign_Decl>;
|
||||||
|
|
||||||
|
} // namespace optimizer
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
53
include/chaiscript/language/chaiscript_posix.hpp
Normal file
53
include/chaiscript/language/chaiscript_posix.hpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_POSIX_HPP_
|
||||||
|
#define CHAISCRIPT_POSIX_HPP_
|
||||||
|
|
||||||
|
namespace chaiscript::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(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str()))) {
|
||||||
|
if (!m_symbol) {
|
||||||
|
throw chaiscript::exception::load_module_error(dlerror());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
} // namespace chaiscript::detail
|
||||||
|
#endif
|
||||||
@ -1,531 +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_PRELUDE_HPP_
|
|
||||||
#define CHAISCRIPT_PRELUDE_HPP_
|
|
||||||
|
|
||||||
namespace chaiscript {
|
|
||||||
struct ChaiScript_Prelude {
|
|
||||||
static std::string chaiscript_prelude() { return R""(
|
|
||||||
|
|
||||||
def lt(l, r) {
|
|
||||||
if (call_exists(`<`, l, r)) {
|
|
||||||
l < r
|
|
||||||
} else {
|
|
||||||
type_name(l) < type_name(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def gt(l, r) {
|
|
||||||
if (call_exists(`>`, l, r)) {
|
|
||||||
l > r
|
|
||||||
} else {
|
|
||||||
type_name(l) > type_name(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def eq(l, r) {
|
|
||||||
if (call_exists(`==`, l, r)) {
|
|
||||||
l == r
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# to_string for Pair()
|
|
||||||
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
|
|
||||||
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
# to_string for containers
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
# Prints to console with carriage return
|
|
||||||
def print(x) {
|
|
||||||
println_string(x.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the maximum value of two numbers
|
|
||||||
def max(a, b) {
|
|
||||||
if (a>b) {
|
|
||||||
a
|
|
||||||
} else {
|
|
||||||
b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the minimum value of two numbers
|
|
||||||
def min(a, b)
|
|
||||||
{
|
|
||||||
if (a<b)
|
|
||||||
{
|
|
||||||
a
|
|
||||||
} else {
|
|
||||||
b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns true if the value is odd
|
|
||||||
def odd(x) {
|
|
||||||
if (x % 2 == 1)
|
|
||||||
{
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns true if the value is even
|
|
||||||
def even(x)
|
|
||||||
{
|
|
||||||
if (x % 2 == 0)
|
|
||||||
{
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
{
|
|
||||||
container.insert_ref_at(pos, clone(x));
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the reverse of the given container
|
|
||||||
def reverse(container) {
|
|
||||||
auto retval = new(container);
|
|
||||||
auto r = range(container);
|
|
||||||
while (!r.empty()) {
|
|
||||||
retval.push_back(r.back());
|
|
||||||
r.pop_back();
|
|
||||||
}
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# The retro attribute that contains the underlying range
|
|
||||||
attr retro::m_range;
|
|
||||||
|
|
||||||
# Creates a retro from a retro by returning the original range
|
|
||||||
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
|
|
||||||
{
|
|
||||||
clone(r.m_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Creates a retro range from a range
|
|
||||||
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
|
||||||
{
|
|
||||||
this.m_range = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the first value of a retro
|
|
||||||
def retro::front()
|
|
||||||
{
|
|
||||||
back(this.m_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the last value of a retro
|
|
||||||
def retro::back()
|
|
||||||
{
|
|
||||||
front(this.m_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Moves the back iterator of a retro towards the front by one
|
|
||||||
def retro::pop_back()
|
|
||||||
{
|
|
||||||
pop_front(this.m_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Moves the front iterator of a retro towards the back by one
|
|
||||||
def retro::pop_front()
|
|
||||||
{
|
|
||||||
pop_back(this.m_range)
|
|
||||||
}
|
|
||||||
|
|
||||||
# returns true if the retro is out of elements
|
|
||||||
def retro::empty()
|
|
||||||
{
|
|
||||||
empty(this.m_range);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Performs the second value function over the container first value
|
|
||||||
def for_each(container, func) : call_exists(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 contains(container, item, compare_func) : call_exists(range, container) {
|
|
||||||
auto t_range = range(container);
|
|
||||||
while (!t_range.empty()) {
|
|
||||||
if ( compare_func(t_range.front(), item) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
t_range.pop_front();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
def contains(container, item) {
|
|
||||||
return contains(container, item, eq)
|
|
||||||
}
|
|
||||||
|
|
||||||
def map(container, func, inserter) : call_exists(range, container) {
|
|
||||||
auto range = range(container);
|
|
||||||
while (!range.empty()) {
|
|
||||||
inserter(func(range.front()));
|
|
||||||
range.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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);
|
|
||||||
map(container, func, back_inserter(retval));
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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);
|
|
||||||
while (!range.empty()) {
|
|
||||||
retval = (func(range.front(), retval));
|
|
||||||
range.pop_front();
|
|
||||||
}
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the sum of the elements of the given value
|
|
||||||
def sum(container) {
|
|
||||||
foldl(container, `+`, 0.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the product of the elements of the given value
|
|
||||||
def product(container) {
|
|
||||||
foldl(container, `*`, 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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);
|
|
||||||
while (!range.empty()) {
|
|
||||||
inserter(range.front());
|
|
||||||
range.pop_front();
|
|
||||||
}
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def take(container, num, inserter) : call_exists(range, container) {
|
|
||||||
auto r = range(container);
|
|
||||||
auto i = num;
|
|
||||||
while ((i > 0) && (!r.empty())) {
|
|
||||||
inserter(r.front());
|
|
||||||
r.pop_front();
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new container with the given number of elements taken from the container
|
|
||||||
def take(container, num) {
|
|
||||||
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);
|
|
||||||
while ((!r.empty()) && f(r.front())) {
|
|
||||||
inserter(r.front());
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new container with the given elements match the second value function
|
|
||||||
def take_while(container, f) {
|
|
||||||
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 i = num;
|
|
||||||
while ((i > 0) && (!r.empty())) {
|
|
||||||
r.pop_front();
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
while (!r.empty()) {
|
|
||||||
inserter(r.front());
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new container with the given number of elements dropped from the given container
|
|
||||||
def drop(container, num) {
|
|
||||||
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);
|
|
||||||
while ((!r.empty())&& f(r.front())) {
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
while (!r.empty()) {
|
|
||||||
inserter(r.front());
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new container with the given elements dropped that match the second value function
|
|
||||||
def drop_while(container, f) {
|
|
||||||
auto retval = new(container);
|
|
||||||
drop_while(container, f, back_inserter(retval));
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# 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 retval = r.front();
|
|
||||||
r.pop_front();
|
|
||||||
retval = func(retval, r.front());
|
|
||||||
r.pop_front();
|
|
||||||
while (!r.empty()) {
|
|
||||||
retval = func(retval, r.front());
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a string of the elements in container delimited by the second value string
|
|
||||||
def join(container, delim) {
|
|
||||||
auto retval = "";
|
|
||||||
auto range = range(container);
|
|
||||||
if (!range.empty()) {
|
|
||||||
retval += to_string(range.front());
|
|
||||||
range.pop_front();
|
|
||||||
while (!range.empty()) {
|
|
||||||
retval += delim;
|
|
||||||
retval += to_string(range.front());
|
|
||||||
range.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def filter(container, f, inserter) : call_exists(range, container) {
|
|
||||||
auto r = range(container);
|
|
||||||
while (!r.empty()) {
|
|
||||||
if (f(r.front())) {
|
|
||||||
inserter(r.front());
|
|
||||||
}
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new Vector which match the second value function
|
|
||||||
def filter(container, f) {
|
|
||||||
auto retval = new(container);
|
|
||||||
filter(container, f, back_inserter(retval));
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def generate_range(x, y, inserter) {
|
|
||||||
auto i = x;
|
|
||||||
while (i <= y) {
|
|
||||||
inserter(i);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new Vector which represents the range from the first value to the second value
|
|
||||||
def generate_range(x, y) {
|
|
||||||
auto retval = Vector();
|
|
||||||
generate_range(x,y,back_inserter(retval));
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new Vector with the first value to the second value as its elements
|
|
||||||
def collate(x, y) {
|
|
||||||
return [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);
|
|
||||||
while (!r_x.empty() && !r_y.empty()) {
|
|
||||||
inserter(f(r_x.front(), r_y.front()));
|
|
||||||
r_x.pop_front();
|
|
||||||
r_y.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# 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();
|
|
||||||
zip_with(f,x,y,back_inserter(retval));
|
|
||||||
retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns a new Vector which joins matching elements of the first and second
|
|
||||||
def zip(x, y) {
|
|
||||||
zip_with(collate, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Returns the position of the second value string in the first value string
|
|
||||||
def string::find(substr) : is_type(substr, "string") {
|
|
||||||
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") {
|
|
||||||
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") {
|
|
||||||
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") {
|
|
||||||
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") {
|
|
||||||
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") {
|
|
||||||
find_last_not_of(this, list, size_t(-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def string::ltrim() {
|
|
||||||
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def string::rtrim() {
|
|
||||||
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def string::trim() {
|
|
||||||
ltrim(rtrim(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
|
|
||||||
auto range = range(container);
|
|
||||||
while (!range.empty()) {
|
|
||||||
if (compare_func(range.front(), value)) {
|
|
||||||
return range;
|
|
||||||
} else {
|
|
||||||
range.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return range;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def find(container, value) {
|
|
||||||
return find(container, value, eq)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
)"";
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CHAISCRIPT_PRELUDE_HPP_ */
|
|
||||||
562
include/chaiscript/language/chaiscript_prelude.hpp
Normal file
562
include/chaiscript/language/chaiscript_prelude.hpp
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// and 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||||
|
#define CHAISCRIPT_PRELUDE_HPP_
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
struct ChaiScript_Prelude {
|
||||||
|
static std::string chaiscript_prelude() {
|
||||||
|
return R"chaiscript(
|
||||||
|
|
||||||
|
def lt(l, r) {
|
||||||
|
if (call_exists(`<`, l, r)) {
|
||||||
|
l < r
|
||||||
|
} else {
|
||||||
|
type_name(l) < type_name(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def gt(l, r) {
|
||||||
|
if (call_exists(`>`, l, r)) {
|
||||||
|
l > r
|
||||||
|
} else {
|
||||||
|
type_name(l) > type_name(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def eq(l, r) {
|
||||||
|
if (call_exists(`==`, l, r)) {
|
||||||
|
l == r
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def new(x) {
|
||||||
|
eval(type_name(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# to_string for Pair()
|
||||||
|
def to_string(x) : call_exists(first, x) && call_exists(second, x) {
|
||||||
|
"<" + x.first.to_string() + ", " + x.second.to_string() + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
# to_string for containers
|
||||||
|
def to_string(x) : call_exists(range, x) && !x.is_type("string"){
|
||||||
|
"[" + x.join(", ") + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prints to console with no carriage return
|
||||||
|
def puts(x) {
|
||||||
|
print_string(x.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prints to console with carriage return
|
||||||
|
def print(x) {
|
||||||
|
println_string(x.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the maximum value of two numbers
|
||||||
|
def max(a, b) {
|
||||||
|
if (a>b) {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the minimum value of two numbers
|
||||||
|
def min(a, b)
|
||||||
|
{
|
||||||
|
if (a<b)
|
||||||
|
{
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns true if the value is odd
|
||||||
|
def odd(x) {
|
||||||
|
if (x % 2 == 1)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns true if the value is even
|
||||||
|
def even(x)
|
||||||
|
{
|
||||||
|
if (x % 2 == 0)
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
{
|
||||||
|
container.insert_ref_at(pos, clone(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the reverse of the given container
|
||||||
|
def reverse(container) {
|
||||||
|
auto retval := new(container);
|
||||||
|
auto r := range(container);
|
||||||
|
while (!r.empty()) {
|
||||||
|
retval.push_back(r.back());
|
||||||
|
r.pop_back();
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
clone(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# The retro attribute that contains the underlying range
|
||||||
|
attr retro::m_range;
|
||||||
|
|
||||||
|
# Creates a retro from a retro by returning the original range
|
||||||
|
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro"
|
||||||
|
{
|
||||||
|
clone(r.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Creates a retro range from a range
|
||||||
|
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r)
|
||||||
|
{
|
||||||
|
this.m_range = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the first value of a retro
|
||||||
|
def retro::front()
|
||||||
|
{
|
||||||
|
back(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the last value of a retro
|
||||||
|
def retro::back()
|
||||||
|
{
|
||||||
|
front(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Moves the back iterator of a retro towards the front by one
|
||||||
|
def retro::pop_back()
|
||||||
|
{
|
||||||
|
pop_front(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Moves the front iterator of a retro towards the back by one
|
||||||
|
def retro::pop_front()
|
||||||
|
{
|
||||||
|
pop_back(this.m_range)
|
||||||
|
}
|
||||||
|
|
||||||
|
# returns true if the retro is out of elements
|
||||||
|
def retro::empty()
|
||||||
|
{
|
||||||
|
empty(this.m_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Performs the second value function over the container first value
|
||||||
|
def for_each(container, func) : call_exists(range, container) {
|
||||||
|
var t_range := range(container);
|
||||||
|
while (!t_range.empty()) {
|
||||||
|
func(t_range.front());
|
||||||
|
t_range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
while (!t_range.empty()) {
|
||||||
|
if ( compare_func(t_range.front(), item) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_range.pop_front();
|
||||||
|
}
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
def contains(container, item) {
|
||||||
|
contains(container, item, eq)
|
||||||
|
}
|
||||||
|
|
||||||
|
def map(container, func, inserter) : call_exists(range, container) {
|
||||||
|
auto range := range(container);
|
||||||
|
while (!range.empty()) {
|
||||||
|
inserter(func(range.front()));
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
map(container, func, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
while (!range.empty()) {
|
||||||
|
retval = (func(range.front(), retval));
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the sum of the elements of the given value
|
||||||
|
def sum(container) {
|
||||||
|
foldl(container, `+`, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Returns the product of the elements of the given value
|
||||||
|
def product(container) {
|
||||||
|
foldl(container, `*`, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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);
|
||||||
|
while (!range.empty()) {
|
||||||
|
inserter(range.front());
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def take(container, num, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
auto i = num;
|
||||||
|
while ((i > 0) && (!r.empty())) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given number of elements taken from the container
|
||||||
|
def take(container, num) {
|
||||||
|
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);
|
||||||
|
while ((!r.empty()) && f(r.front())) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given elements match the second value function
|
||||||
|
def take_while(container, f) {
|
||||||
|
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 i = num;
|
||||||
|
while ((i > 0) && (!r.empty())) {
|
||||||
|
r.pop_front();
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
while (!r.empty()) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given number of elements dropped from the given container
|
||||||
|
def drop(container, num) {
|
||||||
|
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);
|
||||||
|
while ((!r.empty())&& f(r.front())) {
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
while (!r.empty()) {
|
||||||
|
inserter(r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new container with the given elements dropped that match the second value function
|
||||||
|
def drop_while(container, f) {
|
||||||
|
auto retval := new(container);
|
||||||
|
drop_while(container, f, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 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 retval = r.front();
|
||||||
|
r.pop_front();
|
||||||
|
retval = func(retval, r.front());
|
||||||
|
r.pop_front();
|
||||||
|
while (!r.empty()) {
|
||||||
|
retval = func(retval, r.front());
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a string of the elements in container delimited by the second value string
|
||||||
|
def join(container, delim) {
|
||||||
|
auto retval = "";
|
||||||
|
auto range := range(container);
|
||||||
|
if (!range.empty()) {
|
||||||
|
retval += to_string(range.front());
|
||||||
|
range.pop_front();
|
||||||
|
while (!range.empty()) {
|
||||||
|
retval += delim;
|
||||||
|
retval += to_string(range.front());
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def filter(container, f, inserter) : call_exists(range, container) {
|
||||||
|
auto r := range(container);
|
||||||
|
while (!r.empty()) {
|
||||||
|
if (f(r.front())) {
|
||||||
|
inserter(r.front());
|
||||||
|
}
|
||||||
|
r.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which match the second value function
|
||||||
|
def filter(container, f) {
|
||||||
|
auto retval := new(container);
|
||||||
|
filter(container, f, back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_range(x, y, inserter) {
|
||||||
|
auto i = x;
|
||||||
|
while (i <= y) {
|
||||||
|
inserter(i);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which represents the range from the first value to the second value
|
||||||
|
def generate_range(x, y) {
|
||||||
|
auto retval := Vector();
|
||||||
|
generate_range(x,y,back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector with the first value to the second value as its elements
|
||||||
|
def collate(x, y) {
|
||||||
|
return [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);
|
||||||
|
while (!r_x.empty() && !r_y.empty()) {
|
||||||
|
inserter(f(r_x.front(), r_y.front()));
|
||||||
|
r_x.pop_front();
|
||||||
|
r_y.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# 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();
|
||||||
|
zip_with(f,x,y,back_inserter(retval));
|
||||||
|
retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns a new Vector which joins matching elements of the first and second
|
||||||
|
def zip(x, y) {
|
||||||
|
zip_with(collate, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Returns the position of the second value string in the first value string
|
||||||
|
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(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(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(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(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(string list) {
|
||||||
|
find_last_not_of(this, list, size_t(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def string::ltrim() {
|
||||||
|
drop_while(this, fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def string::rtrim() {
|
||||||
|
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' || x == '\r' || x == '\n'}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def string::trim() {
|
||||||
|
ltrim(rtrim(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
range.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
range;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def find(container, value) {
|
||||||
|
find(container, value, eq)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
)chaiscript";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif /* CHAISCRIPT_PRELUDE_HPP_ */
|
||||||
File diff suppressed because it is too large
Load Diff
37
include/chaiscript/language/chaiscript_tracer.hpp
Normal file
37
include/chaiscript/language/chaiscript_tracer.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-2018, Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_TRACER_HPP_
|
||||||
|
#define CHAISCRIPT_TRACER_HPP_
|
||||||
|
|
||||||
|
namespace chaiscript::eval {
|
||||||
|
struct Noop_Tracer_Detail {
|
||||||
|
template<typename T>
|
||||||
|
constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl<T> *) noexcept {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
struct Tracer : T... {
|
||||||
|
Tracer() = default;
|
||||||
|
constexpr explicit Tracer(T... t)
|
||||||
|
: T(std::move(t))... {
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl<Tracer<T...>> *node) {
|
||||||
|
(static_cast<T &>(*this).trace(ds, node), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Noop_Tracer = Tracer<Noop_Tracer_Detail>;
|
||||||
|
|
||||||
|
} // namespace chaiscript::eval
|
||||||
|
|
||||||
|
#endif
|
||||||
25
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
25
include/chaiscript/language/chaiscript_unknown.hpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, 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;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace chaiscript
|
||||||
|
#endif
|
||||||
113
include/chaiscript/language/chaiscript_windows.hpp
Normal file
113
include/chaiscript/language/chaiscript_windows.hpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, 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) {
|
||||||
|
using StringType = LPTSTR;
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace chaiscript
|
||||||
|
#endif
|
||||||
38
include/chaiscript/utility/fnv1a.hpp
Normal file
38
include/chaiscript/utility/fnv1a.hpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// This file is distributed under the BSD License.
|
||||||
|
// See "license.txt" for details.
|
||||||
|
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||||
|
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
|
||||||
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
|
#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||||
|
#define CHAISCRIPT_UTILITY_FNV1A_HPP_
|
||||||
|
|
||||||
|
#include "../chaiscript_defines.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utility
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
94
include/chaiscript/utility/hash.hpp
Normal file
94
include/chaiscript/utility/hash.hpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// 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 "../chaiscript_defines.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace chaiscript {
|
||||||
|
namespace utility {
|
||||||
|
namespace fnv1a {
|
||||||
|
template<typename Itr>
|
||||||
|
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4307)
|
||||||
|
#endif
|
||||||
|
std::uint32_t h = 0x811c9dc5;
|
||||||
|
|
||||||
|
while (begin != end) {
|
||||||
|
h = (h ^ (*begin)) * 0x01000193;
|
||||||
|
++begin;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
|
||||||
|
return hash(std::begin(str), std::end(str) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
|
||||||
|
return hash(sv.begin(), sv.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::uint32_t hash(const std::string &s) noexcept {
|
||||||
|
return hash(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
} // namespace fnv1a
|
||||||
|
|
||||||
|
namespace jenkins_one_at_a_time {
|
||||||
|
template<typename Itr>
|
||||||
|
static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept {
|
||||||
|
std::uint32_t hash = 0;
|
||||||
|
|
||||||
|
while (begin != end) {
|
||||||
|
hash += std::uint32_t(*begin);
|
||||||
|
hash += hash << 10;
|
||||||
|
hash ^= hash >> 6;
|
||||||
|
++begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash += hash << 3;
|
||||||
|
hash ^= hash >> 11;
|
||||||
|
hash += hash << 15;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
static constexpr std::uint32_t hash(const char (&str)[N]) noexcept {
|
||||||
|
return hash(std::begin(str), std::end(str) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr std::uint32_t hash(std::string_view sv) noexcept {
|
||||||
|
return hash(sv.begin(), sv.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::uint32_t hash(const std::string &s) noexcept {
|
||||||
|
return hash(s.begin(), s.end());
|
||||||
|
}
|
||||||
|
} // namespace jenkins_one_at_a_time
|
||||||
|
|
||||||
|
using fnv1a::hash;
|
||||||
|
} // namespace utility
|
||||||
|
} // namespace chaiscript
|
||||||
|
|
||||||
|
#endif
|
||||||
598
include/chaiscript/utility/json.hpp
Normal file
598
include/chaiscript/utility/json.hpp
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
// From github.com/nbsdx/SimpleJSON.
|
||||||
|
// Released under the DWTFYW PL
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SIMPLEJSON_HPP
|
||||||
|
#define SIMPLEJSON_HPP
|
||||||
|
|
||||||
|
#include "../chaiscript_defines.hpp"
|
||||||
|
#include "quick_flat_map.hpp"
|
||||||
|
#include <cctype>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace chaiscript::json {
|
||||||
|
using std::enable_if;
|
||||||
|
using std::initializer_list;
|
||||||
|
using std::is_convertible;
|
||||||
|
using std::is_floating_point;
|
||||||
|
using std::is_integral;
|
||||||
|
using std::is_same;
|
||||||
|
|
||||||
|
class JSON {
|
||||||
|
public:
|
||||||
|
enum class Class {
|
||||||
|
Null = 0,
|
||||||
|
Object,
|
||||||
|
Array,
|
||||||
|
String,
|
||||||
|
Floating,
|
||||||
|
Integral,
|
||||||
|
Boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Data
|
||||||
|
= std::variant<std::nullptr_t, chaiscript::utility::QuickFlatMap<std::string, JSON>, std::vector<JSON>, std::string, double, std::int64_t, bool>;
|
||||||
|
|
||||||
|
struct Internal {
|
||||||
|
Internal(std::nullptr_t)
|
||||||
|
: d(nullptr) {
|
||||||
|
}
|
||||||
|
Internal()
|
||||||
|
: d(nullptr) {
|
||||||
|
}
|
||||||
|
Internal(Class c)
|
||||||
|
: d(make_type(c)) {
|
||||||
|
}
|
||||||
|
template<typename T>
|
||||||
|
Internal(T t)
|
||||||
|
: d(std::move(t)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static Data make_type(Class c) {
|
||||||
|
switch (c) {
|
||||||
|
case Class::Null:
|
||||||
|
return nullptr;
|
||||||
|
case Class::Object:
|
||||||
|
return chaiscript::utility::QuickFlatMap<std::string, JSON>{};
|
||||||
|
case Class::Array:
|
||||||
|
return std::vector<JSON>{};
|
||||||
|
case Class::String:
|
||||||
|
return std::string{};
|
||||||
|
case Class::Floating:
|
||||||
|
return double{};
|
||||||
|
case Class::Integral:
|
||||||
|
return std::int64_t{};
|
||||||
|
case Class::Boolean:
|
||||||
|
return bool{};
|
||||||
|
}
|
||||||
|
throw std::runtime_error("unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_type(Class c) {
|
||||||
|
if (type() != c) {
|
||||||
|
d = make_type(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Class type() const noexcept { return Class(d.index()); }
|
||||||
|
|
||||||
|
template<auto ClassValue, typename Visitor, typename Or>
|
||||||
|
decltype(auto) visit_or(Visitor &&visitor, Or &&other) const {
|
||||||
|
if (type() == Class(ClassValue)) {
|
||||||
|
return visitor(std::get<static_cast<std::size_t>(ClassValue)>(d));
|
||||||
|
} else {
|
||||||
|
return other();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<auto ClassValue>
|
||||||
|
auto &get_set_type() {
|
||||||
|
set_type(ClassValue);
|
||||||
|
return (std::get<static_cast<std::size_t>(ClassValue)>(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &Map() { return get_set_type<Class::Object>(); }
|
||||||
|
auto &Vector() { return get_set_type<Class::Array>(); }
|
||||||
|
auto &String() { return get_set_type<Class::String>(); }
|
||||||
|
auto &Int() { return get_set_type<Class::Integral>(); }
|
||||||
|
auto &Float() { return get_set_type<Class::Floating>(); }
|
||||||
|
auto &Bool() { return get_set_type<Class::Boolean>(); }
|
||||||
|
|
||||||
|
auto Map() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Object)>(&d); }
|
||||||
|
auto Vector() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Array)>(&d); }
|
||||||
|
auto String() const noexcept { return std::get_if<static_cast<std::size_t>(Class::String)>(&d); }
|
||||||
|
auto Int() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Integral)>(&d); }
|
||||||
|
auto Float() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Floating)>(&d); }
|
||||||
|
auto Bool() const noexcept { return std::get_if<static_cast<std::size_t>(Class::Boolean)>(&d); }
|
||||||
|
|
||||||
|
Data d;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 noexcept {
|
||||||
|
return object ? object->begin() : typename Container::const_iterator();
|
||||||
|
}
|
||||||
|
typename Container::const_iterator end() const noexcept { 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) noexcept
|
||||||
|
: 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) noexcept
|
||||||
|
: internal(static_cast<std::int64_t>(i)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
explicit JSON(T f, typename enable_if<is_floating_point<T>::value>::type * = nullptr) noexcept
|
||||||
|
: 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) { return internal.Map().operator[](key); }
|
||||||
|
|
||||||
|
JSON &operator[](const size_t index) {
|
||||||
|
auto &vec = internal.Vector();
|
||||||
|
if (index >= vec.size()) {
|
||||||
|
vec.resize(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec.operator[](index);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON &at(const std::string &key) { return operator[](key); }
|
||||||
|
|
||||||
|
const JSON &at(const std::string &key) const {
|
||||||
|
return internal.visit_or<Class::Object>([&](const auto &m) -> const JSON & { return m.at(key); },
|
||||||
|
[]() -> const JSON & { throw std::range_error("Not an object, no keys"); });
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON &at(size_t index) { return operator[](index); }
|
||||||
|
|
||||||
|
const JSON &at(size_t index) const {
|
||||||
|
return internal.visit_or<Class::Array>([&](const auto &m) -> const JSON & { return m.at(index); },
|
||||||
|
[]() -> const JSON & { throw std::range_error("Not an array, no indexes"); });
|
||||||
|
}
|
||||||
|
|
||||||
|
auto length() const noexcept {
|
||||||
|
return internal.visit_or<Class::Array>([&](const auto &m) { return static_cast<int>(m.size()); }, []() { return -1; });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_key(const std::string &key) const noexcept {
|
||||||
|
return internal.visit_or<Class::Object>([&](const auto &m) { return m.count(key) != 0; }, []() { return false; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int size() const noexcept {
|
||||||
|
if (auto m = internal.Map(); m != nullptr) {
|
||||||
|
return static_cast<int>(m->size());
|
||||||
|
}
|
||||||
|
if (auto v = internal.Vector(); v != nullptr) {
|
||||||
|
return static_cast<int>(v->size());
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Class JSONType() const noexcept { return internal.type(); }
|
||||||
|
|
||||||
|
/// Functions for getting primitives from the JSON object.
|
||||||
|
bool is_null() const noexcept { return internal.type() == Class::Null; }
|
||||||
|
|
||||||
|
std::string to_string() const noexcept {
|
||||||
|
return internal.visit_or<Class::String>([](const auto &o) { return o; }, []() { return std::string{}; });
|
||||||
|
}
|
||||||
|
double to_float() const noexcept {
|
||||||
|
return internal.visit_or<Class::Floating>([](const auto &o) { return o; }, []() { return double{}; });
|
||||||
|
}
|
||||||
|
std::int64_t to_int() const noexcept {
|
||||||
|
return internal.visit_or<Class::Integral>([](const auto &o) { return o; }, []() { return std::int64_t{}; });
|
||||||
|
}
|
||||||
|
bool to_bool() const noexcept {
|
||||||
|
return internal.visit_or<Class::Boolean>([](const auto &o) { return o; }, []() { return false; });
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() {
|
||||||
|
return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWrapper<std::vector<JSON>> array_range() { return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d); }
|
||||||
|
|
||||||
|
JSONConstWrapper<chaiscript::utility::QuickFlatMap<std::string, JSON>> object_range() const {
|
||||||
|
return std::get_if<static_cast<std::size_t>(Class::Object)>(&internal.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONConstWrapper<std::vector<JSON>> array_range() const { return std::get_if<static_cast<std::size_t>(Class::Array)>(&internal.d); }
|
||||||
|
|
||||||
|
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 + "\"" + json_escape(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.Vector()) {
|
||||||
|
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) noexcept {
|
||||||
|
#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.at(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.at(offset) == '}') {
|
||||||
|
++offset;
|
||||||
|
return Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; offset < str.size();) {
|
||||||
|
JSON Key = parse_next(str, offset);
|
||||||
|
consume_ws(str, offset);
|
||||||
|
if (str.at(offset) != ':') {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Object: Expected colon, found '") + str.at(offset) + "'\n");
|
||||||
|
}
|
||||||
|
consume_ws(str, ++offset);
|
||||||
|
JSON Value = parse_next(str, offset);
|
||||||
|
Object[Key.to_string()] = Value;
|
||||||
|
|
||||||
|
consume_ws(str, offset);
|
||||||
|
if (str.at(offset) == ',') {
|
||||||
|
++offset;
|
||||||
|
continue;
|
||||||
|
} else if (str.at(offset) == '}') {
|
||||||
|
++offset;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Object: Expected comma, found '") + str.at(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.at(offset) == ']') {
|
||||||
|
++offset;
|
||||||
|
return Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; offset < str.size();) {
|
||||||
|
Array[index++] = parse_next(str, offset);
|
||||||
|
consume_ws(str, offset);
|
||||||
|
|
||||||
|
if (str.at(offset) == ',') {
|
||||||
|
++offset;
|
||||||
|
continue;
|
||||||
|
} else if (str.at(offset) == ']') {
|
||||||
|
++offset;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error(std::string("JSON ERROR: Array: Expected ',' or ']', found '") + str.at(offset) + "'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSON parse_string(const std::string &str, size_t &offset) {
|
||||||
|
std::string val;
|
||||||
|
for (char c = str.at(++offset); c != '\"'; c = str.at(++offset)) {
|
||||||
|
if (c == '\\') {
|
||||||
|
switch (str.at(++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.at(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;
|
||||||
|
std::int64_t exp = 0;
|
||||||
|
bool isExpNegative = false;
|
||||||
|
if (offset < str.size() && str.at(offset) == '-') {
|
||||||
|
isNegative = true;
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
for (; offset < str.size();) {
|
||||||
|
c = str.at(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.at(offset++);
|
||||||
|
if (c == '-') {
|
||||||
|
isExpNegative = true;
|
||||||
|
} else if (c == '+') {
|
||||||
|
// do nothing
|
||||||
|
} else {
|
||||||
|
--offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; offset < str.size();) {
|
||||||
|
c = str.at(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<std::int64_t>(exp_str) * (isExpNegative ? -1 : 1);
|
||||||
|
} 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<std::int64_t>(val)) * std::pow(10, exp));
|
||||||
|
} else {
|
||||||
|
return JSON((isNegative ? -1 : 1) * chaiscript::parse_num<std::int64_t>(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.at(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace chaiscript::json
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user