Compare commits
340
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75a21abecd | ||
|
|
763999c376 | ||
|
|
c1b23320c3 | ||
|
|
266bb67c93 | ||
|
|
6276ddfc2c | ||
|
|
b8ead38556 | ||
|
|
1972ae6a82 | ||
|
|
7f3de28e02 | ||
|
|
0322624729 | ||
|
|
68358bb084 | ||
|
|
65ab73d93f | ||
|
|
fff4f68d66 | ||
|
|
65fe06feba | ||
|
|
b980b73f9e | ||
|
|
5d2ab05fc9 | ||
|
|
b82aad097a | ||
|
|
df1bc5c68b | ||
|
|
1033e2fd10 | ||
|
|
f9b5ce71b4 | ||
|
|
951a0898ce | ||
|
|
22b4b25f5a | ||
|
|
a69d51f474 | ||
|
|
9c3069d62e | ||
|
|
c91ca46eb4 | ||
|
|
115bd453b9 | ||
|
|
826282aa72 | ||
|
|
9fa4a548e5 | ||
|
|
18f4ebccd9 | ||
|
|
8dcebe3930 | ||
|
|
3b8b017d4d | ||
|
|
d344ede669 | ||
|
|
85f51df7eb | ||
|
|
5dce82eaf6 | ||
|
|
0b4675b4ad | ||
|
|
e4861a606a | ||
|
|
bbe9fd255d | ||
|
|
6bd3f26746 | ||
|
|
83aa0f3856 | ||
|
|
f97a7b8a55 | ||
|
|
f936877339 | ||
|
|
9fbe8a6316 | ||
|
|
7f087eab03 | ||
|
|
056a2bd791 | ||
|
|
902133a8ba | ||
|
|
1791187808 | ||
|
|
cacb0cdbd6 | ||
|
|
0b1fbf66dc | ||
|
|
2c6f48b1bc | ||
|
|
ed78ed79d9 | ||
|
|
98b97bef66 | ||
|
|
003d22286c | ||
|
|
5232f069fb | ||
|
|
4f13f07071 | ||
|
|
70efab47d1 | ||
|
|
c00c0c3257 | ||
|
|
f8a930cd48 | ||
|
|
1d753731e0 | ||
|
|
b239ad2790 | ||
|
|
97c3f8bb01 | ||
|
|
6b54479211 | ||
|
|
fd88d78544 | ||
|
|
434ded6503 | ||
|
|
a2cdefb369 | ||
|
|
46285a800e | ||
|
|
305ede38cc | ||
|
|
f773589a37 | ||
|
|
b9a0706d6d | ||
|
|
85f3830d71 | ||
|
|
2c6db18d06 | ||
|
|
c165cdfc0a | ||
|
|
b48a3ee9ed | ||
|
|
1af4a64b10 | ||
|
|
64f287fd6d | ||
|
|
c927d324dc | ||
|
|
bcd212a450 | ||
|
|
d05270d413 | ||
|
|
e40d18b8c4 | ||
|
|
0e977b071c | ||
|
|
c79882b75e | ||
|
|
251306a3d3 | ||
|
|
0bd95d402a | ||
|
|
6441acc93d | ||
|
|
04a50580c6 | ||
|
|
a4d2d4c788 | ||
|
|
54ab2fc509 | ||
|
|
c16a5e99d5 | ||
|
|
e28b5a6de5 | ||
|
|
6ac8fc7fe5 | ||
|
|
43bd1001d2 | ||
|
|
8bdc07c91b | ||
|
|
a3a8f602ea | ||
|
|
1a9c0c68ac | ||
|
|
27b26eb2a0 | ||
|
|
1bfe81cfac | ||
|
|
fe673c21b2 | ||
|
|
77420e9873 | ||
|
|
e4789d9c40 | ||
|
|
9f0937b5c3 | ||
|
|
bb46d45d56 | ||
|
|
ad18c12326 | ||
|
|
3a5c4f2164 | ||
|
|
b683c981b0 | ||
|
|
9b614421b6 | ||
|
|
26659db833 | ||
|
|
6b5a47b017 | ||
|
|
3ec4fc9f0b | ||
|
|
5d2a99d40e | ||
|
|
1d06905fc5 | ||
|
|
3f98441918 | ||
|
|
f8e00859cd | ||
|
|
933c9cb5e3 | ||
|
|
11b3a52287 | ||
|
|
07f7a75759 | ||
|
|
644c75094e | ||
|
|
a565cb7b2a | ||
|
|
6db0f7c60b | ||
|
|
bfe0b0e99e | ||
|
|
13bdf30055 | ||
|
|
f18c7a2210 | ||
|
|
123a7de64a | ||
|
|
e0e1436930 | ||
|
|
b96e6c8149 | ||
|
|
f6402ac638 | ||
|
|
1e55d0200b | ||
|
|
1725dfd1ea | ||
|
|
a8cc0ccc86 | ||
|
|
7dd868aac7 | ||
|
|
220e5ce007 | ||
|
|
80f6ea4502 | ||
|
|
eb820aaf6a | ||
|
|
a754c162d9 | ||
|
|
de18ceb887 | ||
|
|
51188173bb | ||
|
|
d0797ad5d8 | ||
|
|
9b37bd532e | ||
|
|
333352edcf | ||
|
|
05783773af | ||
|
|
59ee20ee7a | ||
|
|
87f2c1b062 | ||
|
|
b85cefea56 | ||
|
|
2e28f863f3 | ||
|
|
ddaa4d1741 | ||
|
|
732bd1520a | ||
|
|
1d67946f3f | ||
|
|
fab6d7e662 | ||
|
|
6e20578a81 | ||
|
|
dc5282c32e | ||
|
|
812abae6e5 | ||
|
|
b3b512d027 | ||
|
|
ed296c4c7f | ||
|
|
595bb47249 | ||
|
|
daad1a4fa8 | ||
|
|
daef1ac198 | ||
|
|
3b9d88b252 | ||
|
|
809f8229b4 | ||
|
|
ffb1ee2523 | ||
|
|
0903718314 | ||
|
|
e0cb883ae4 | ||
|
|
17449dd9d5 | ||
|
|
7963631a1d | ||
|
|
77d88f4b34 | ||
|
|
c5e3ab1162 | ||
|
|
75041c1db9 | ||
|
|
558a4c0782 | ||
|
|
995c3b9c8e | ||
|
|
0a64bca9ce | ||
|
|
b7b12b6cbb | ||
|
|
5684ca8671 | ||
|
|
3c81360dc2 | ||
|
|
fc50ebdf90 | ||
|
|
4d6e8db5ff | ||
|
|
938ffac57e | ||
|
|
50aaffb101 | ||
|
|
4f9b449c6e | ||
|
|
c1a36a3f4b | ||
|
|
4ca6e2a680 | ||
|
|
11db805c34 | ||
|
|
f1f700ab69 | ||
|
|
9eeb8ddb80 | ||
|
|
95de26a6d0 | ||
|
|
88c2e28dbc | ||
|
|
30b7a9e4d4 | ||
|
|
37542065d6 | ||
|
|
c9608f7760 | ||
|
|
6ba54b0e77 | ||
|
|
f9bb3105c8 | ||
|
|
4b5baa9b5f | ||
|
|
6dedd87260 | ||
|
|
91317222fb | ||
|
|
494953a8cc | ||
|
|
ae4d8be50c | ||
|
|
d34790e05c | ||
|
|
b77e15c6d6 | ||
|
|
54195d5811 | ||
|
|
9c7907f91a | ||
|
|
0601b8def6 | ||
|
|
841261f199 | ||
|
|
7124b6c4ce | ||
|
|
ad7beec559 | ||
|
|
bd4fc51392 | ||
|
|
54d994a879 | ||
|
|
891a085f2b | ||
|
|
e7ccd2e72d | ||
|
|
459a39e65d | ||
|
|
36eb0fca8b | ||
|
|
53b9e22f26 | ||
|
|
8ff3f5e351 | ||
|
|
e6a2c443cb | ||
|
|
4f25ab162d | ||
|
|
0520d9f187 | ||
|
|
cc3c21b7e3 | ||
|
|
ae9560124e | ||
|
|
085f4ec37e | ||
|
|
476c3a9cc9 | ||
|
|
1bc5ac8768 | ||
|
|
4bdff11b87 | ||
|
|
b32dde3c91 | ||
|
|
b9a566350b | ||
|
|
ce9ce674ea | ||
|
|
b8641779bd | ||
|
|
5e620d784e | ||
|
|
013bcfaffb | ||
|
|
2504c96927 | ||
|
|
e2f4d1481e | ||
|
|
ea3d68573b | ||
|
|
c6cb594ef1 | ||
|
|
948123bc7a | ||
|
|
68f5b26af9 | ||
|
|
5d493630b1 | ||
|
|
f4db6faa80 | ||
|
|
e340f7f5ad | ||
|
|
b4d923b74c | ||
|
|
965f334d59 | ||
|
|
54463b78d2 | ||
|
|
600aec1f50 | ||
|
|
bcfbe81979 | ||
|
|
31e8851bcc | ||
|
|
f464767ee7 | ||
|
|
22eb58b3de | ||
|
|
0daee20545 | ||
|
|
d98073dc33 | ||
|
|
fb199e7dea | ||
|
|
6cea0d97c2 | ||
|
|
058dd2e01e | ||
|
|
975d122491 | ||
|
|
eef4c66374 | ||
|
|
5ce4fbd74d | ||
|
|
f4d8cff26b | ||
|
|
46b6b3c151 | ||
|
|
796b217dec | ||
|
|
1ccc35f464 | ||
|
|
2ed6f15fe1 | ||
|
|
575040be65 | ||
|
|
206959adbd | ||
|
|
dd1c97b6af | ||
|
|
85463dcff0 | ||
|
|
7ff816417e | ||
|
|
3fa2f3898a | ||
|
|
514ce9eec2 | ||
|
|
5bc357b4b3 | ||
|
|
56ddc3c24e | ||
|
|
e407b2a307 | ||
|
|
1ac194ed1d | ||
|
|
62bf5d4cc9 | ||
|
|
27093064a9 | ||
|
|
860a3018a7 | ||
|
|
eb3992dbdb | ||
|
|
8c5f9cc1d3 | ||
|
|
ed78703090 | ||
|
|
29b61bcee9 | ||
|
|
0ff49845a7 | ||
|
|
c17366b2b1 | ||
|
|
5da267fb31 | ||
|
|
dffa3345d0 | ||
|
|
a23c767fb0 | ||
|
|
5d6ec51302 | ||
|
|
585f277bf5 | ||
|
|
aae5f431cb | ||
|
|
4eb84e5c32 | ||
|
|
70b11ec7ad | ||
|
|
f2944e0bae | ||
|
|
fdec33d086 | ||
|
|
0702074469 | ||
|
|
6d5cbf6974 | ||
|
|
5429a3a4d4 | ||
|
|
c124076279 | ||
|
|
0d1d811d2c | ||
|
|
8c04831339 | ||
|
|
4a8b2690aa | ||
|
|
e2bc716ea7 | ||
|
|
6c5987f9af | ||
|
|
1e79880c72 | ||
|
|
f62d891c63 | ||
|
|
930cb8853c | ||
|
|
22104ff64e | ||
|
|
17564441b5 | ||
|
|
a9140a4403 | ||
|
|
ce47ca0a8a | ||
|
|
852fee170e | ||
|
|
8463e99d13 | ||
|
|
3c016b73ee | ||
|
|
8d4173b0be | ||
|
|
502f043804 | ||
|
|
f8571fb175 | ||
|
|
7209aa8880 | ||
|
|
1a4a1217ae | ||
|
|
139c360feb | ||
|
|
be1afbdb5c | ||
|
|
8a7e8c8d7d | ||
|
|
931f79dacb | ||
|
|
261e6ee78e | ||
|
|
9eaddcdafb | ||
|
|
b8ede1a3e7 | ||
|
|
bbaacd5d28 | ||
|
|
60ed5fdfe2 | ||
|
|
512f88c63e | ||
|
|
50c01b2cfb | ||
|
|
27d3f889b5 | ||
|
|
140a9918c0 | ||
|
|
fc6a30b684 | ||
|
|
deb0ae8b8e | ||
|
|
1425479569 | ||
|
|
09923651d8 | ||
|
|
7ca5b85051 | ||
|
|
a34faf8a26 | ||
|
|
7708159e92 | ||
|
|
7851d48e82 | ||
|
|
f320b4fa9b | ||
|
|
b3ea81f4e8 | ||
|
|
ace61e589d | ||
|
|
51506e0400 | ||
|
|
4a1432b01d | ||
|
|
aa16393c1b | ||
|
|
55ed2c0d5c | ||
|
|
6c588733d9 | ||
|
|
d72411632d | ||
|
|
a1af1ec29e | ||
|
|
bdd55483f9 | ||
|
|
01f3030473 | ||
|
|
98c08becd6 |
@@ -1,2 +1,4 @@
|
|||||||
/hscript.swf
|
/hscript.swf
|
||||||
/release.zip
|
/release.zip
|
||||||
|
dump/*
|
||||||
|
tests/bin/*
|
||||||
+25
-29
@@ -4,8 +4,11 @@ os:
|
|||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
|
|
||||||
|
dist: bionic
|
||||||
|
|
||||||
haxe:
|
haxe:
|
||||||
- "3.2.1"
|
- "3.4.7"
|
||||||
|
- "4.0.3"
|
||||||
- development
|
- development
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@@ -17,44 +20,34 @@ addons:
|
|||||||
# Python
|
# Python
|
||||||
- python3
|
- python3
|
||||||
# PHP
|
# PHP
|
||||||
- php5-cli
|
- php-cli
|
||||||
|
- php-mbstring
|
||||||
# C#
|
# C#
|
||||||
- mono-devel
|
- mono-devel
|
||||||
- mono-mcs
|
- mono-mcs
|
||||||
# Flash
|
|
||||||
- libcurl3:i386
|
|
||||||
- libglib2.0-0:i386
|
|
||||||
- libx11-6:i386
|
|
||||||
- libxext6:i386
|
|
||||||
- libxt6:i386
|
|
||||||
- libxcursor1:i386
|
|
||||||
- libnss3:i386
|
|
||||||
- libgtk2.0-0:i386
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# os-specific config
|
# os-specific config
|
||||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||||
export DISPLAY=:99.0;
|
|
||||||
export AUDIODEV=null;
|
|
||||||
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
|
||||||
brew update;
|
brew update;
|
||||||
brew install mono;
|
brew install mono;
|
||||||
brew install python3;
|
brew install php;
|
||||||
fi
|
fi
|
||||||
# Download and setup a standalone flash player debugger
|
|
||||||
- haxe flash/install.hxml
|
|
||||||
# Install haxelibs
|
# Install haxelibs
|
||||||
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then
|
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ]; then
|
||||||
haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git;
|
haxelib git hxcpp https://github.com/HaxeFoundation/hxcpp.git;
|
||||||
|
else
|
||||||
|
haxelib install hxcpp;
|
||||||
|
fi
|
||||||
|
- if [ "${TRAVIS_HAXE_VERSION}" = "development" ] || [ "${TRAVIS_HAXE_VERSION}" = "3.2.1" ]; then
|
||||||
pushd $(haxelib path hxcpp | head -1);
|
pushd $(haxelib path hxcpp | head -1);
|
||||||
pushd tools/hxcpp; haxe compile.hxml; popd;
|
pushd tools/hxcpp; haxe compile.hxml; popd;
|
||||||
pushd project; neko build.n; popd;
|
pushd project; neko build.n; popd;
|
||||||
popd;
|
popd;
|
||||||
else
|
|
||||||
haxelib install hxcpp;
|
|
||||||
fi
|
fi
|
||||||
- haxelib install hxjava
|
- haxelib install hxjava
|
||||||
- haxelib install hxcs
|
- haxelib install hxcs
|
||||||
|
- haxelib install hx3compat
|
||||||
- haxelib dev hscript .
|
- haxelib dev hscript .
|
||||||
- haxelib list
|
- haxelib list
|
||||||
|
|
||||||
@@ -62,12 +55,15 @@ script:
|
|||||||
- pushd script &&
|
- pushd script &&
|
||||||
haxe build.hxml &&
|
haxe build.hxml &&
|
||||||
popd
|
popd
|
||||||
- haxe build-interp.hxml
|
- haxe bin/build-interp.hxml
|
||||||
- haxe build-neko.hxml && neko bin/Test.n
|
- haxe bin/build-interp.hxml -D hscriptPos
|
||||||
- haxe build-js.hxml && node bin/Test.js
|
- haxe bin/build-neko.hxml && neko bin/Test.n
|
||||||
- haxe build-java.hxml && java -jar bin/Test.jar
|
- haxe bin/build-js.hxml && node bin/Test.js
|
||||||
- haxe build-cs.hxml && mono bin/bin/Test.exe
|
- haxe bin/build-java.hxml && java -jar bin/Test.jar
|
||||||
- haxe build-cpp.hxml && ./bin/Test
|
# Only test C# for Haxe 4+
|
||||||
- haxe build-flash.hxml -D fdb && haxe flash/run.hxml bin/Test.swf
|
- if [[ $(haxe -version 2&>1 | head -c 1) > 3 ]]; then
|
||||||
- haxe build-php.hxml && php bin/index.php
|
haxe bin/build-cs.hxml && mono bin/bin/Test.exe;
|
||||||
- haxe build-python.hxml && python3 bin/Test.py
|
fi
|
||||||
|
- haxe bin/build-cpp.hxml && ./bin/Test
|
||||||
|
- haxe bin/build-php.hxml -D php7 && php bin/index.php
|
||||||
|
- haxe bin/build-python.hxml && python3 bin/Test.py
|
||||||
|
|||||||
Vendored
+16
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
|
||||||
|
// Pointez pour afficher la description des attributs existants.
|
||||||
|
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "HashLink (launch)",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "hl",
|
||||||
|
"hxml": "hscript.hxml",
|
||||||
|
"cwd": "${workspaceRoot}",
|
||||||
|
"preLaunchTask": "Build"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+16
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Build",
|
||||||
|
"type": "hxml",
|
||||||
|
"file": "hscript.hxml",
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (C)2008-2017 Haxe Foundation
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
@@ -1,8 +1,30 @@
|
|||||||
hscript
|
hscript-improved
|
||||||
=======
|
=======
|
||||||
|
|
||||||
[](https://travis-ci.org/HaxeFoundation/hscript)
|
- [Features](docs/FEATURES.md)
|
||||||
[](https://ci.appveyor.com/project/HaxeFoundation/hscript)
|
|
||||||
|
How to install
|
||||||
|
```
|
||||||
|
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git
|
||||||
|
```
|
||||||
|
|
||||||
|
To enable custom classes support you have to do this in project.xml
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<define name="CUSTOM_CLASSES" />
|
||||||
|
```
|
||||||
|
|
||||||
|
or set this in build.hxml
|
||||||
|
|
||||||
|
```hxml
|
||||||
|
-D CUSTOM_CLASSES
|
||||||
|
```
|
||||||
|
|
||||||
|
Current Custom Class Limitations :
|
||||||
|
|
||||||
|
- You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
Parse and evalutate Haxe expressions.
|
Parse and evalutate Haxe expressions.
|
||||||
|
|
||||||
@@ -64,26 +86,40 @@ You can use `parser.allowJSON` to allow JSON data.
|
|||||||
|
|
||||||
You can use `parser.allowTypes` to parse types for local vars, exceptions, function args and return types. Types are ignored by the interpreter.
|
You can use `parser.allowTypes` to parse types for local vars, exceptions, function args and return types. Types are ignored by the interpreter.
|
||||||
|
|
||||||
|
You can use `parser.allowMetadata` to parse metadata before expressions on in anonymous types. Metadata are ignored by the interpreter.
|
||||||
|
|
||||||
You can use `new hscript.Macro(pos).convert(ast)` to convert an hscript AST to a Haxe macros one.
|
You can use `new hscript.Macro(pos).convert(ast)` to convert an hscript AST to a Haxe macros one.
|
||||||
|
|
||||||
|
You can use `hscript.Checker` in order to type check and even get completion, using `haxe -xml` output for type information.
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Compared to Haxe, limitations are :
|
Compared to Haxe, limitations are :
|
||||||
|
|
||||||
- no type declarations (classes, enums, typedefs) : only expressions
|
|
||||||
- `switch` construct is supported but not pattern matching (no variable capture, we use strict equality to compare `case` values and `switch` value)
|
- `switch` construct is supported but not pattern matching (no variable capture, we use strict equality to compare `case` values and `switch` value)
|
||||||
- only one variable declaration is allowed in `var`
|
- only one variable declaration is allowed in `var`
|
||||||
- the parser supports optional types for `var` and `function` if `allowTypes` is set, but the interpreter ignores them
|
- the parser supports optional types for `var` and `function` if `allowTypes` is set, but the interpreter ignores them
|
||||||
- you can enable per-expression position tracking by compiling with `-D hscriptPos`
|
- you can enable per-expression position tracking by compiling with `-D hscriptPos`
|
||||||
|
- you can parse some type declarations (import, class, typedef, etc.) with parseModule
|
||||||
|
|
||||||
Install
|
Install
|
||||||
-------
|
-------
|
||||||
|
|
||||||
In order to install Haxe Script, use `haxelib install hscript` and compile your program with `-lib hscript`.
|
In order to install Haxe Script, use `haxelib install hscript` and compile your program with `-lib hscript`.
|
||||||
|
|
||||||
There are only three files in hscript :
|
These are the main required files in hscript :
|
||||||
|
|
||||||
- `hscript.Expr` : contains enums declarations
|
- `hscript.Expr` : contains enums declarations
|
||||||
- `hscript.Parser` : a small parser that turns a string into an expression structure (AST)
|
- `hscript.Parser` : a small parser that turns a string into an expression structure (AST)
|
||||||
- `hscript.Interp` : a small interpreter that execute the AST and returns the latest evaluated value
|
- `hscript.Interp` : a small interpreter that execute the AST and returns the latest evaluated value
|
||||||
|
|
||||||
|
Some other optional files :
|
||||||
|
|
||||||
|
- `hscript.Async` : converts Expr into asynchronous version
|
||||||
|
- `hscript.Bytes` : Expr serializer/unserializer
|
||||||
|
- `hscript.Checker` : type checking and completion for hscript Expr
|
||||||
|
- `hscript.Macro` : convert Haxe macro into hscript Expr
|
||||||
|
- `hscript.Printer` : convert hscript Expr to String
|
||||||
|
- `hscript.Tools` : utility functions (map/iter)
|
||||||
|
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
import hscript.Macro;
|
|
||||||
import haxe.unit.*;
|
|
||||||
|
|
||||||
class Test extends TestCase {
|
|
||||||
function assertScript(x,v:Dynamic,?vars : Dynamic,allowTypes=false) {
|
|
||||||
var p = new hscript.Parser();
|
|
||||||
p.allowTypes = allowTypes;
|
|
||||||
var program = p.parseString(x);
|
|
||||||
var bytes = hscript.Bytes.encode(program);
|
|
||||||
program = hscript.Bytes.decode(bytes);
|
|
||||||
var interp = new hscript.Interp();
|
|
||||||
if( vars != null )
|
|
||||||
for( v in Reflect.fields(vars) )
|
|
||||||
interp.variables.set(v,Reflect.field(vars,v));
|
|
||||||
var ret : Dynamic = interp.execute(program);
|
|
||||||
assertEquals(v, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
function test():Void {
|
|
||||||
assertScript("0",0);
|
|
||||||
assertScript("0xFF", 255);
|
|
||||||
#if !(php || python)
|
|
||||||
#if haxe3
|
|
||||||
assertScript("0xBFFFFFFF", 0xBFFFFFFF);
|
|
||||||
assertScript("0x7FFFFFFF", 0x7FFFFFFF);
|
|
||||||
#elseif !neko
|
|
||||||
assertScript("n(0xBFFFFFFF)", 0xBFFFFFFF, { n : haxe.Int32.toNativeInt });
|
|
||||||
assertScript("n(0x7FFFFFFF)", 0x7FFFFFFF, { n : haxe.Int32.toNativeInt } );
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
assertScript("-123",-123);
|
|
||||||
assertScript("- 123",-123);
|
|
||||||
assertScript("1.546",1.546);
|
|
||||||
assertScript(".545",.545);
|
|
||||||
assertScript("'bla'","bla");
|
|
||||||
assertScript("null",null);
|
|
||||||
assertScript("true",true);
|
|
||||||
assertScript("false",false);
|
|
||||||
assertScript("1 == 2",false);
|
|
||||||
assertScript("1.3 == 1.3",true);
|
|
||||||
assertScript("5 > 3",true);
|
|
||||||
assertScript("0 < 0",false);
|
|
||||||
assertScript("-1 <= -1",true);
|
|
||||||
assertScript("1 + 2",3);
|
|
||||||
assertScript("~545",-546);
|
|
||||||
assertScript("'abc' + 55","abc55");
|
|
||||||
assertScript("'abc' + 'de'","abcde");
|
|
||||||
assertScript("-1 + 2",1);
|
|
||||||
assertScript("1 / 5",0.2);
|
|
||||||
assertScript("3 * 2 + 5",11);
|
|
||||||
assertScript("3 * (2 + 5)",21);
|
|
||||||
assertScript("3 * 2 // + 5 \n + 6",12);
|
|
||||||
assertScript("3 /* 2\n */ + 5",8);
|
|
||||||
assertScript("[55,66,77][1]",66);
|
|
||||||
assertScript("var a = [55]; a[0] *= 2; a[0]",110);
|
|
||||||
assertScript("x",55,{ x : 55 });
|
|
||||||
assertScript("var y = 33; y",33);
|
|
||||||
assertScript("{ 1; 2; 3; }",3);
|
|
||||||
assertScript("{ var x = 0; } x",55,{ x : 55 });
|
|
||||||
assertScript("o.val",55,{ o : { val : 55 } });
|
|
||||||
assertScript("o.val",null,{ o : {} });
|
|
||||||
assertScript("var a = 1; a++",1);
|
|
||||||
assertScript("var a = 1; a++; a",2);
|
|
||||||
assertScript("var a = 1; ++a",2);
|
|
||||||
assertScript("var a = 1; a *= 3",3);
|
|
||||||
assertScript("a = b = 3; a + b",6);
|
|
||||||
assertScript("add(1,2)",3,{ add : function(x,y) return x + y });
|
|
||||||
assertScript("a.push(5); a.pop() + a.pop()",8,{ a : [3] });
|
|
||||||
assertScript("if( true ) 1 else 2",1);
|
|
||||||
assertScript("if( false ) 1 else 2",2);
|
|
||||||
assertScript("var t = 0; for( x in [1,2,3] ) t += x; t",6);
|
|
||||||
assertScript("var a = new Array(); for( x in 0...5 ) a[x] = x; a.join('-')","0-1-2-3-4");
|
|
||||||
assertScript("(function(a,b) return a + b)(4,5)",9);
|
|
||||||
assertScript("var y = 0; var add = function(a) y += a; add(5); add(3); y", 8);
|
|
||||||
assertScript("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10);
|
|
||||||
assertScript("var t = 0; for( x in 1...10 ) t += x; t", 45);
|
|
||||||
#if haxe3
|
|
||||||
assertScript("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45);
|
|
||||||
#else
|
|
||||||
assertScript("var t = 0; for( x in new IntIter(1,10) ) t +=x; t", 45);
|
|
||||||
#end
|
|
||||||
assertScript("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",790);
|
|
||||||
assertScript("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",56);
|
|
||||||
assertScript("var i=2; if( true ) --i; i",1);
|
|
||||||
assertScript("var i=0; if( i++ > 0 ) i=3; i",1);
|
|
||||||
assertScript("var a = 5/2; a",2.5);
|
|
||||||
assertScript("{ x = 3; x; }", 3);
|
|
||||||
assertScript("{ x : 3, y : {} }.x", 3);
|
|
||||||
assertScript("function bug(){ \n }\nbug().x", null);
|
|
||||||
assertScript("1 + 2 == 3", true);
|
|
||||||
assertScript("-2 == 3 - 5", true);
|
|
||||||
assertScript("var x=-3; x", -3);
|
|
||||||
assertScript("var a:Array<Dynamic>=[1,2,4]; a[2]", 4, null, true);
|
|
||||||
assertScript("/**/0", 0);
|
|
||||||
assertScript("x=1;x*=-2", -2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static function main() {
|
|
||||||
var runner = new TestRunner();
|
|
||||||
runner.add(new Test());
|
|
||||||
var succeed = runner.run();
|
|
||||||
#if sys
|
|
||||||
Sys.exit(succeed ? 0 : 1);
|
|
||||||
#elseif flash
|
|
||||||
flash.system.System.exit(succeed ? 0 : 1);
|
|
||||||
#else
|
|
||||||
if (!succeed)
|
|
||||||
throw "failed";
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
import haxe.ds.EnumValueMap;
|
||||||
|
import haxe.ds.Option;
|
||||||
|
import hscript.Macro;
|
||||||
|
import hscript.Tools;
|
||||||
|
import hscript.Async;
|
||||||
|
import hscript.Printer;
|
||||||
|
import hscript.Checker;
|
||||||
|
import haxe.unit.*;
|
||||||
|
|
||||||
|
class TestHScript extends TestCase {
|
||||||
|
function assertScript(x,v:Dynamic,?vars : Dynamic, allowTypes=false, ?pos:haxe.PosInfos) {
|
||||||
|
var p = new hscript.Parser();
|
||||||
|
p.allowTypes = allowTypes;
|
||||||
|
var program = p.parseString(x);
|
||||||
|
var bytes = hscript.Bytes.encode(program);
|
||||||
|
program = hscript.Bytes.decode(bytes);
|
||||||
|
var interp = new hscript.Interp();
|
||||||
|
if( vars != null )
|
||||||
|
for( v in Reflect.fields(vars) )
|
||||||
|
interp.variables.set(v,Reflect.field(vars,v));
|
||||||
|
var ret : Dynamic = interp.execute(program);
|
||||||
|
assertEquals(v, ret, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test():Void {
|
||||||
|
assertScript("0",0);
|
||||||
|
assertScript("0xFF", 255);
|
||||||
|
#if !(php || python)
|
||||||
|
assertScript("0xBFFFFFFF", 0xBFFFFFFF);
|
||||||
|
assertScript("0x7FFFFFFF", 0x7FFFFFFF);
|
||||||
|
#end
|
||||||
|
assertScript("-123",-123);
|
||||||
|
assertScript("- 123",-123);
|
||||||
|
assertScript("1.546",1.546);
|
||||||
|
assertScript(".545",.545);
|
||||||
|
assertScript("'bla'","bla");
|
||||||
|
assertScript("null",null);
|
||||||
|
assertScript("true",true);
|
||||||
|
assertScript("false",false);
|
||||||
|
assertScript("1 == 2",false);
|
||||||
|
assertScript("1.3 == 1.3",true);
|
||||||
|
assertScript("5 > 3",true);
|
||||||
|
assertScript("0 < 0",false);
|
||||||
|
assertScript("-1 <= -1",true);
|
||||||
|
assertScript("1 + 2",3);
|
||||||
|
assertScript("~545",-546);
|
||||||
|
assertScript("'abc' + 55","abc55");
|
||||||
|
assertScript("'abc' + 'de'","abcde");
|
||||||
|
assertScript("-1 + 2",1);
|
||||||
|
assertScript("1 / 5",0.2);
|
||||||
|
assertScript("3 * 2 + 5",11);
|
||||||
|
assertScript("3 * (2 + 5)",21);
|
||||||
|
assertScript("3 * 2 // + 5 \n + 6",12);
|
||||||
|
assertScript("3 /* 2\n */ + 5",8);
|
||||||
|
assertScript("[55,66,77][1]",66);
|
||||||
|
assertScript("var a = [55]; a[0] *= 2; a[0]",110);
|
||||||
|
assertScript("x",55,{ x : 55 });
|
||||||
|
assertScript("var y = 33; y",33);
|
||||||
|
assertScript("{ 1; 2; 3; }",3);
|
||||||
|
assertScript("{ var x = 0; } x",55,{ x : 55 });
|
||||||
|
assertScript("o.val",55,{ o : { val : 55 } });
|
||||||
|
assertScript("o.val",null,{ o : {} });
|
||||||
|
assertScript("var a = 1; a++",1);
|
||||||
|
assertScript("var a = 1; a++; a",2);
|
||||||
|
assertScript("var a = 1; ++a",2);
|
||||||
|
assertScript("var a = 1; a *= 3",3);
|
||||||
|
assertScript("a = b = 3; a + b",6);
|
||||||
|
assertScript("add(1,2)",3,{ add : function(x,y) return x + y });
|
||||||
|
assertScript("a.push(5); a.pop() + a.pop()",8,{ a : [3] });
|
||||||
|
assertScript("if( true ) 1 else 2",1);
|
||||||
|
assertScript("if( false ) 1 else 2",2);
|
||||||
|
assertScript("var t = 0; for( x in [1,2,3] ) t += x; t",6);
|
||||||
|
assertScript("var a = new Array(); for( x in 0...5 ) a[x] = x; a.join('-')","0-1-2-3-4");
|
||||||
|
assertScript("(function(a,b) return a + b)(4,5)",9);
|
||||||
|
assertScript("var y = 0; var add = function(a) y += a; add(5); add(3); y", 8);
|
||||||
|
assertScript("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10);
|
||||||
|
assertScript("var a = false; do { a = true; } while (!a); a;",true);
|
||||||
|
assertScript("var t = 0; for( x in 1...10 ) t += x; t", 45);
|
||||||
|
assertScript("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45);
|
||||||
|
assertScript("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",790);
|
||||||
|
assertScript("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",56);
|
||||||
|
assertScript("var i=2; if( true ) --i; i",1);
|
||||||
|
assertScript("var i=0; if( i++ > 0 ) i=3; i",1);
|
||||||
|
assertScript("var a = 5/2; a",2.5);
|
||||||
|
assertScript("{ x = 3; x; }", 3);
|
||||||
|
assertScript("{ x : 3, y : {} }.x", 3);
|
||||||
|
assertScript("function bug(){ \n }\nbug().x", null);
|
||||||
|
assertScript("1 + 2 == 3", true);
|
||||||
|
assertScript("-2 == 3 - 5", true);
|
||||||
|
assertScript("var x=-3; x", -3);
|
||||||
|
assertScript("var a:Array<Dynamic>=[1,2,4]; a[2]", 4, null, true);
|
||||||
|
assertScript("/**/0", 0);
|
||||||
|
assertScript("x=1;x*=-2", -2);
|
||||||
|
assertScript("var f = x -> x + 1; f(3)", 4);
|
||||||
|
assertScript("var f = () -> 55; f()", 55);
|
||||||
|
assertScript("var f = (x) -> x + 1; f(3)", 4);
|
||||||
|
assertScript("var f = (x:Int) -> x + 1; f(3)", 4);
|
||||||
|
assertScript("var f = (x,y) -> x + y; f(3,1)", 4);
|
||||||
|
assertScript("var f = (x,y:Int) -> x + y; f(3,1)", 4);
|
||||||
|
assertScript("var f = (x:Int,y:Int) -> x + y; f(3,1)", 4);
|
||||||
|
assertScript("var f:Int->Int->Int = (x:Int,y:Int) -> x + y; f(3,1)", 4, null, true);
|
||||||
|
assertScript("var f:(x:Int, y:Int)->Int = (x:Int,y:Int) -> x + y; f(3,1)", 4, null, true);
|
||||||
|
assertScript("var f:(x:Int)->(y:Int, z:Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true);
|
||||||
|
assertScript("var f:(x:Int)->(Int, Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true);
|
||||||
|
assertScript("var a = 10; var b = 5; a - -b", 15);
|
||||||
|
assertScript("var a = 10; var b = 5; a - b / 2", 7.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testMap():Void {
|
||||||
|
var objKey = { ok:true };
|
||||||
|
var vars = {
|
||||||
|
stringMap: ["foo" => "Foo", "bar" => "Bar"],
|
||||||
|
intMap:[100 => "one hundred"],
|
||||||
|
objKey: objKey,
|
||||||
|
objMap:[objKey => "ok"],
|
||||||
|
enumKey:Option.Some("some"),
|
||||||
|
enumMap:new EnumValueMap<Option<String>, String>(),
|
||||||
|
stringIntMap: ["foo" => 100]
|
||||||
|
}
|
||||||
|
vars.enumMap.set(vars.enumKey, "ok");
|
||||||
|
|
||||||
|
assertScript('stringMap["foo"]', "Foo", vars);
|
||||||
|
assertScript('intMap[100]', "one hundred", vars);
|
||||||
|
assertScript('objMap[objKey]', "ok", vars);
|
||||||
|
assertScript('enumMap[enumKey]', "ok", vars);
|
||||||
|
assertScript('stringMap["a"] = "A"; stringMap["a"]', "A", vars);
|
||||||
|
assertScript('intMap[200] = objMap[{foo:false}] = enumMap[enumKey] = "A"', "A", vars);
|
||||||
|
assertEquals('A', vars.intMap[200]);
|
||||||
|
assertEquals('A', vars.enumMap.get(vars.enumKey));
|
||||||
|
for (key in vars.objMap.keys()) {
|
||||||
|
if (key != objKey) {
|
||||||
|
assertEquals(false, (key:Dynamic).foo);
|
||||||
|
assertEquals('A', vars.objMap[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertScript('
|
||||||
|
var keys = [];
|
||||||
|
for (key in stringMap.keys()) keys.push(key);
|
||||||
|
keys.join("_");
|
||||||
|
', {
|
||||||
|
var keys = [];
|
||||||
|
for (key in vars.stringMap.keys()) keys.push(key);
|
||||||
|
keys.join("_");
|
||||||
|
}, vars);
|
||||||
|
assertScript('stringMap.remove("foo"); stringMap.exists("foo");', false, vars);
|
||||||
|
assertScript('stringMap["foo"] = "a"; stringMap["foo"] += "b"', 'ab', vars);
|
||||||
|
assertEquals('ab', vars.stringMap['foo']);
|
||||||
|
assertScript('stringIntMap["foo"]++', 100, vars);
|
||||||
|
assertEquals(101, vars.stringIntMap['foo']);
|
||||||
|
assertScript('++stringIntMap["foo"]', 102, vars);
|
||||||
|
assertScript('var newMap = ["foo"=>"foo"]; newMap["foo"];', 'foo', vars);
|
||||||
|
#if (!php || (haxe_ver >= 3.3))
|
||||||
|
assertScript('var newMap = [enumKey=>"foo"]; newMap[enumKey];', 'foo', vars);
|
||||||
|
#end
|
||||||
|
assertScript('var newMap = [{a:"a"}=>"foo", objKey=>"bar"]; newMap[objKey];', 'bar', vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function main() {
|
||||||
|
#if ((haxe_ver < 4) && php)
|
||||||
|
// uncaught exception: The each() function is deprecated. This message will be suppressed on further calls (errno: 8192)
|
||||||
|
// in file: /Users/travis/build/andyli/hscript/bin/lib/Type.class.php line 178
|
||||||
|
untyped __php__("error_reporting(E_ALL ^ E_DEPRECATED);");
|
||||||
|
#end
|
||||||
|
|
||||||
|
var runner = new TestRunner();
|
||||||
|
runner.add(new TestHScript());
|
||||||
|
var succeed = runner.run();
|
||||||
|
|
||||||
|
#if sys
|
||||||
|
Sys.exit(succeed ? 0 : 1);
|
||||||
|
#elseif flash
|
||||||
|
flash.system.System.exit(succeed ? 0 : 1);
|
||||||
|
#else
|
||||||
|
if (!succeed)
|
||||||
|
throw "failed";
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+14
-17
@@ -5,20 +5,19 @@ environment:
|
|||||||
HAXELIB_ROOT: C:\projects\haxelib
|
HAXELIB_ROOT: C:\projects\haxelib
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
# http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
|
||||||
|
- ps: Set-Service wuauserv -StartupType Manual
|
||||||
# Install the haxe chocolatey package (https://chocolatey.org/packages/haxe)
|
# Install the haxe chocolatey package (https://chocolatey.org/packages/haxe)
|
||||||
- cinst haxe -version 3.2.1 -y
|
- cinst haxe -version 4.0.3 -y
|
||||||
- RefreshEnv
|
- RefreshEnv
|
||||||
# Setup haxelib
|
# Setup haxelib
|
||||||
- mkdir "%HAXELIB_ROOT%"
|
- mkdir "%HAXELIB_ROOT%"
|
||||||
- haxelib setup "%HAXELIB_ROOT%"
|
- haxelib setup "%HAXELIB_ROOT%"
|
||||||
# Install test dependencies
|
|
||||||
- cinst php -y
|
|
||||||
# Download and setup a standalone flash player debugger
|
|
||||||
- haxe flash/install.hxml
|
|
||||||
# Install project dependencies
|
# Install project dependencies
|
||||||
- haxelib install hxcpp > log.txt || type log.txt && cmd /C exit 1
|
- haxelib install hxcpp > log.txt || type log.txt && cmd /C exit 1
|
||||||
- haxelib install hxjava > log.txt || type log.txt && cmd /C exit 1
|
- haxelib install hxjava > log.txt || type log.txt && cmd /C exit 1
|
||||||
- haxelib install hxcs > log.txt || type log.txt && cmd /C exit 1
|
- haxelib install hxcs > log.txt || type log.txt && cmd /C exit 1
|
||||||
|
- haxelib install hx3compat > log.txt || type log.txt && cmd /C exit 1
|
||||||
- haxelib dev hscript .
|
- haxelib dev hscript .
|
||||||
- haxelib list
|
- haxelib list
|
||||||
|
|
||||||
@@ -28,12 +27,10 @@ test_script:
|
|||||||
- pushd script &&
|
- pushd script &&
|
||||||
haxe build.hxml &&
|
haxe build.hxml &&
|
||||||
popd
|
popd
|
||||||
- haxe build-interp.hxml
|
- haxe bin/build-interp.hxml
|
||||||
- haxe build-neko.hxml && neko bin\Test.n
|
- haxe bin/build-neko.hxml && neko bin\Test.n
|
||||||
- haxe build-js.hxml && node bin\Test.js
|
- haxe bin/build-js.hxml && node bin\Test.js
|
||||||
- haxe build-java.hxml && java -jar bin\Test.jar
|
- haxe bin/build-java.hxml && java -jar bin\Test.jar
|
||||||
- haxe build-cs.hxml && bin\bin\Test.exe
|
- haxe bin/build-cs.hxml && bin\bin\Test.exe
|
||||||
- haxe build-cpp.hxml && bin\Test.exe
|
- haxe bin/build-cpp.hxml && bin\Test.exe
|
||||||
- haxe build-flash.hxml -D fdb && haxe flash\run.hxml bin\Test.swf
|
- haxe bin/build-python.hxml && C:\Python34-x64\python.exe bin\Test.py
|
||||||
- haxe build-php.hxml && C:\tools\php\php.exe bin\index.php
|
|
||||||
- haxe build-python.hxml && C:\Python34-x64\python.exe bin\Test.py
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-cpp bin
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-cs bin
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-main TestHScript
|
||||||
|
-dce no
|
||||||
|
-lib hx3compat
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
build-each.hxml
|
bin/build-each.hxml
|
||||||
-swf bin/Test.swf
|
-swf bin/Test.swf
|
||||||
-swf-header 800:600:30:FFFFFF
|
-swf-header 800:600:30:FFFFFF
|
||||||
--flash-strict
|
--flash-strict
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
--interp
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-java bin
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-js bin/Test.js
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-neko bin/Test.n
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-php bin
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
bin/build-each.hxml
|
||||||
|
-python bin/Test.py
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-cpp bin
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-cs bin
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-main Test
|
|
||||||
-dce no
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
--interp
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-java bin
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-js bin/Test.js
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-neko bin/Test.n
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-php bin
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
build-each.hxml
|
|
||||||
-python bin/Test.py
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# FEATURES
|
||||||
|
|
||||||
|
- Custom Classes
|
||||||
|
- Final Classes
|
||||||
|
- Static Classes
|
||||||
|
- Allow for type check (`is`)
|
||||||
|
- Allow extending other custom classes
|
||||||
|
- Enums
|
||||||
|
|
||||||
|
```haxe
|
||||||
|
enum TypeValue {
|
||||||
|
NUMBER(n:Int);
|
||||||
|
DECIMAL(d:Float, ?p:Int);
|
||||||
|
CHARACTER(s:String);
|
||||||
|
BOOLEAN(b:Bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = TypeValue.DECIMAL(10.1234, 2);
|
||||||
|
// You need to type the full enum field for each case
|
||||||
|
// i.e. you can't type the enum field directly (limitation for now)
|
||||||
|
switch(type) {
|
||||||
|
case TypeValue.NUMBER(number):
|
||||||
|
trace("number: " + number);
|
||||||
|
case TypeValue.DECIMAL(decimal, precision):
|
||||||
|
if(precision != null)
|
||||||
|
trace("decimal: " + decimal + " | rounded decimal: " + roundDecimal(decimal, precision));
|
||||||
|
else
|
||||||
|
trace("decimal: " + decimal);
|
||||||
|
case TypeValue.CHARACTER(char):
|
||||||
|
trace("character: " + char);
|
||||||
|
default:
|
||||||
|
trace("unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
function roundDecimal(Value:Float, Precision:Int) {
|
||||||
|
var mult:Float = Math.pow(10, Precision);
|
||||||
|
return Math.fround(Value * mult) / mult;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Enum matching with arguments for switch statements (for real and scripted enums)
|
||||||
|
- Property Fields (`(get, set)` variables)
|
||||||
|
|
||||||
|
```haxe
|
||||||
|
public var myvar(get, set):Int;
|
||||||
|
var _myvar:Int = 10;
|
||||||
|
|
||||||
|
function get_myvar():Int {
|
||||||
|
return _myvar;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_myvar(val:Int):Int {
|
||||||
|
if(val > 10) return _myvar = val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `@:isVar` metadata support
|
||||||
|
|
||||||
|
- Static extension (`using`)
|
||||||
|
|
||||||
|
```haxe
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
class IntExtender {
|
||||||
|
static public function triple(i:Int) {
|
||||||
|
return i * 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// need to create/import the custom class
|
||||||
|
// before setting the extension (limitation for now)
|
||||||
|
using IntExtender;
|
||||||
|
|
||||||
|
var str = " Hello World! ";
|
||||||
|
trace(str.trim()); // "Hello World!"
|
||||||
|
trace(12.triple()); // 36
|
||||||
|
```
|
||||||
|
|
||||||
|
- Support for real and custom classes
|
||||||
|
- Misc.
|
||||||
|
- Allow using type parameters for creating objects (i.e. `var a = new TypedObject<Int>();`)
|
||||||
|
- Allow `package` declaration. Ignored by the interpreter.
|
||||||
+3
-1
@@ -1 +1,3 @@
|
|||||||
--macro keep('IntIterator')
|
--macro keep('IntIterator')
|
||||||
|
--macro hscript.macros.AbstractHandler.init()
|
||||||
|
--macro hscript.macros.ClassExtendMacro.init()
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
*.exe
|
|
||||||
*.app
|
|
||||||
flashplayerdebugger
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import Sys.*;
|
|
||||||
import sys.FileSystem.*;
|
|
||||||
import sys.io.File.*;
|
|
||||||
import haxe.*;
|
|
||||||
import haxe.io.*;
|
|
||||||
|
|
||||||
class Install {
|
|
||||||
// https://www.adobe.com/support/flashplayer/downloads.html
|
|
||||||
static var fpDownload(default, never) = switch (systemName()) {
|
|
||||||
case "Linux":
|
|
||||||
"https://fpdownload.macromedia.com/pub/flashplayer/updaters/11/flashplayer_11_sa_debug.i386.tar.gz";
|
|
||||||
case "Mac":
|
|
||||||
"https://fpdownload.macromedia.com/pub/flashplayer/updaters/19/flashplayer_19_sa_debug.dmg";
|
|
||||||
case "Windows":
|
|
||||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/19/flashplayer_19_sa_debug.exe";
|
|
||||||
case _:
|
|
||||||
throw "unsupported system";
|
|
||||||
}
|
|
||||||
// https://helpx.adobe.com/flash-player/kb/configure-debugger-version-flash-player.html
|
|
||||||
static var mmcfg(default, never) = switch (systemName()) {
|
|
||||||
case "Linux":
|
|
||||||
Path.join([getEnv("HOME"), "mm.cfg"]);
|
|
||||||
case "Mac":
|
|
||||||
"/Library/Application Support/Macromedia/mm.cfg";
|
|
||||||
case "Windows":
|
|
||||||
Path.join([getEnv("HOMEDRIVE") + getEnv("HOMEPATH"), "mm.cfg"]);
|
|
||||||
case _:
|
|
||||||
throw "unsupported system";
|
|
||||||
}
|
|
||||||
// http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7c95.html
|
|
||||||
static var fpTrust(default, never) = switch (systemName()) {
|
|
||||||
case "Linux":
|
|
||||||
Path.join([getEnv("HOME"), ".macromedia/Flash_Player/#Security/FlashPlayerTrust"]);
|
|
||||||
case "Mac":
|
|
||||||
"/Library/Application Support/Macromedia/FlashPlayerTrust";
|
|
||||||
case "Windows":
|
|
||||||
Path.join([getEnv("SYSTEMROOT"), "system32", "Macromed", "Flash", "FlashPlayerTrust"]);
|
|
||||||
case _:
|
|
||||||
throw "unsupported system";
|
|
||||||
}
|
|
||||||
static function main() {
|
|
||||||
switch (systemName()) {
|
|
||||||
case "Linux":
|
|
||||||
// Download and unzip flash player
|
|
||||||
if (command("wget", [fpDownload]) != 0)
|
|
||||||
throw "failed to download flash player";
|
|
||||||
if (command("tar", ["-xf", Path.withoutDirectory(fpDownload), "-C", "flash"]) != 0)
|
|
||||||
throw "failed to extract flash player";
|
|
||||||
case "Mac":
|
|
||||||
if (command("brew", ["install", "caskroom/cask/brew-cask"]) != 0)
|
|
||||||
throw "failed to brew install caskroom/cask/brew-cask";
|
|
||||||
if (command("brew", ["cask", "install", "flash-player-debugger", "--appdir=flash"]) != 0)
|
|
||||||
throw "failed to install flash-player-debugger";
|
|
||||||
case "Windows":
|
|
||||||
// Download flash player
|
|
||||||
download(fpDownload, "flash\\flashplayer.exe");
|
|
||||||
case _:
|
|
||||||
throw "unsupported system";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Create a configuration file so the trace log is enabled
|
|
||||||
createDirectory(Path.directory(mmcfg));
|
|
||||||
saveContent(mmcfg, "ErrorReportingEnable=1\nTraceOutputFileEnable=1");
|
|
||||||
|
|
||||||
// Add the current directory as trusted, so exit() can be used
|
|
||||||
createDirectory(fpTrust);
|
|
||||||
saveContent(Path.join([fpTrust, "test.cfg"]), getCwd());
|
|
||||||
}
|
|
||||||
static function download(url:String, saveAs:String):Void {
|
|
||||||
var http = new Http(url);
|
|
||||||
http.onError = function(e) {
|
|
||||||
throw e;
|
|
||||||
};
|
|
||||||
http.customRequest(false, write(saveAs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import Sys.*;
|
|
||||||
import sys.FileSystem.*;
|
|
||||||
import sys.io.File.*;
|
|
||||||
import haxe.io.*;
|
|
||||||
|
|
||||||
class Run {
|
|
||||||
// https://helpx.adobe.com/flash-player/kb/configure-debugger-version-flash-player.html
|
|
||||||
static var flashlog(default, never) = switch (systemName()) {
|
|
||||||
case "Linux":
|
|
||||||
Path.join([getEnv("HOME"), ".macromedia/Flash_Player/Logs/flashlog.txt"]);
|
|
||||||
case "Mac":
|
|
||||||
Path.join([getEnv("HOME"), "Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt"]);
|
|
||||||
case "Windows":
|
|
||||||
Path.join([getEnv("APPDATA"), "Macromedia", "Flash Player", "Logs", "flashlog.txt"]);
|
|
||||||
case _:
|
|
||||||
throw "unsupported system";
|
|
||||||
}
|
|
||||||
static function main() {
|
|
||||||
var args = args();
|
|
||||||
var swf = args[0];
|
|
||||||
var exitCode = switch (systemName()) {
|
|
||||||
case "Linux":
|
|
||||||
// The flash player has some issues with unexplained crashes,
|
|
||||||
// but if it runs about 8 times, it should succeed one of those...
|
|
||||||
var c = -1;
|
|
||||||
for (i in 0...8) {
|
|
||||||
if ((c = command("xvfb-run", ["flash/flashplayerdebugger", swf])) == 0)
|
|
||||||
break;
|
|
||||||
println('retry... (${i+1})');
|
|
||||||
}
|
|
||||||
c;
|
|
||||||
case "Mac":
|
|
||||||
command("flash/Flash Player Debugger.app/Contents/MacOS/Flash Player Debugger", [fullPath(swf)]);
|
|
||||||
case "Windows":
|
|
||||||
command("flash\\flashplayer.exe", [fullPath(swf)]);
|
|
||||||
case _:
|
|
||||||
throw "unsupported platform";
|
|
||||||
}
|
|
||||||
println(getContent(flashlog));
|
|
||||||
exit(exitCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-cp flash
|
|
||||||
--run Install
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-cp flash
|
|
||||||
--run Run
|
|
||||||
+9
-9
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "hscript",
|
"name": "hscript-improved",
|
||||||
"url": "https://github.com/HaxeFoundation/hscript",
|
"url": "https://github.com/HaxeFoundation/hscript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||||
"version": "2.0.6",
|
"version": "2.4.0",
|
||||||
"releasenote": "fixes for haxe 3.3, use property access by default",
|
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
|
||||||
"contributors": ["ncannasse"]
|
"contributors": ["ncannasse","HaxeFoundation"]
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1 +1,2 @@
|
|||||||
build-flash.hxml
|
bin/build-each.hxml
|
||||||
|
-hl bin/Test.hl
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<project version="2">
|
|
||||||
<!-- Output SWF options -->
|
|
||||||
<output>
|
|
||||||
<movie outputType="Application" />
|
|
||||||
<movie input="" />
|
|
||||||
<movie path="hscript.swf" />
|
|
||||||
<movie fps="30" />
|
|
||||||
<movie width="800" />
|
|
||||||
<movie height="600" />
|
|
||||||
<movie version="9" />
|
|
||||||
<movie minorVersion="0" />
|
|
||||||
<movie platform="Flash Player" />
|
|
||||||
<movie background="#FFFFFF" />
|
|
||||||
</output>
|
|
||||||
<!-- Other classes to be compiled into your SWF -->
|
|
||||||
<classpaths>
|
|
||||||
<!-- example: <class path="..." /> -->
|
|
||||||
</classpaths>
|
|
||||||
<!-- Build options -->
|
|
||||||
<build>
|
|
||||||
<option directives="" />
|
|
||||||
<option flashStrict="True" />
|
|
||||||
<option noInlineOnDebug="False" />
|
|
||||||
<option mainClass="Test" />
|
|
||||||
<option enabledebug="False" />
|
|
||||||
<option additional="-dce no" />
|
|
||||||
</build>
|
|
||||||
<!-- haxelib libraries -->
|
|
||||||
<haxelib>
|
|
||||||
<!-- example: <library name="..." /> -->
|
|
||||||
</haxelib>
|
|
||||||
<!-- Class files to compile (other referenced classes will automatically be included) -->
|
|
||||||
<compileTargets>
|
|
||||||
<!-- example: <compile path="..." /> -->
|
|
||||||
</compileTargets>
|
|
||||||
<!-- Assets to embed into the output SWF -->
|
|
||||||
<library>
|
|
||||||
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
|
|
||||||
</library>
|
|
||||||
<!-- Paths to exclude from the Project Explorer tree -->
|
|
||||||
<hiddenPaths>
|
|
||||||
<hidden path="haxelib.xml" />
|
|
||||||
<hidden path="hscript.hxml" />
|
|
||||||
<hidden path="hscript.js" />
|
|
||||||
<hidden path="hscript.n" />
|
|
||||||
<hidden path="hscript.swf" />
|
|
||||||
<hidden path="hscript9.swf" />
|
|
||||||
<hidden path="release.bat" />
|
|
||||||
<hidden path="release.zip" />
|
|
||||||
<hidden path="obj" />
|
|
||||||
</hiddenPaths>
|
|
||||||
<!-- Executed before build -->
|
|
||||||
<preBuildCommand />
|
|
||||||
<!-- Executed after build -->
|
|
||||||
<postBuildCommand alwaysRun="False" />
|
|
||||||
<!-- Other project options -->
|
|
||||||
<options>
|
|
||||||
<option showHiddenPaths="False" />
|
|
||||||
<option testMovie="Default" />
|
|
||||||
<option testMovieCommand="" />
|
|
||||||
</options>
|
|
||||||
<!-- Plugin storage -->
|
|
||||||
<storage />
|
|
||||||
</project>
|
|
||||||
@@ -0,0 +1,536 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C)2008-2017 Haxe Foundation
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
package hscript;
|
||||||
|
import hscript.Expr;
|
||||||
|
|
||||||
|
|
||||||
|
enum VarMode {
|
||||||
|
Defined;
|
||||||
|
ForceSync;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Async {
|
||||||
|
|
||||||
|
var definedVars : Array<{ n : String, prev : Null<VarMode> }>;
|
||||||
|
var vars : Map<String,VarMode>;
|
||||||
|
var currentFun : String;
|
||||||
|
var currentLoop : Expr;
|
||||||
|
var currentBreak : Expr -> Expr;
|
||||||
|
var uid = 0;
|
||||||
|
public var asyncIdents : Map<String,Bool>;
|
||||||
|
|
||||||
|
static var nullExpr : Expr = #if hscriptPos { e : null, pmin : 0, pmax : 0, origin : "<null>", line : 0 } #else null #end;
|
||||||
|
static var nullId = mk(EIdent("null"), nullExpr);
|
||||||
|
|
||||||
|
inline static function expr( e : Expr ) {
|
||||||
|
return #if hscriptPos e.e #else e #end;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static function mk( e, inf : Expr ) : Expr {
|
||||||
|
return #if hscriptPos { e : e, pmin : inf.pmin, pmax : inf.pmax, origin : inf.origin, line : inf.line } #else e #end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Convert a script into asynchronous one.
|
||||||
|
- calls such as foo(a,b,c) are translated to a_foo(function(r) ...rest, a,b,c) where r is the result value
|
||||||
|
- object access such obj.bar(a,b,c) are translated to obj.a_bar(function(r) ...rest, a, b, c)
|
||||||
|
- @async expr will execute the expression but continue without waiting for it to finish
|
||||||
|
- @split [ e1, e2, e3 ] is transformed to split(function(_) ...rest, [e1, e2, e3]) which
|
||||||
|
should execute asynchronously all expressions - until they return - before continuing the execution
|
||||||
|
- for(i in v) block; loops are translated to the following:
|
||||||
|
var _i = makeIterator(v);
|
||||||
|
function _loop() {
|
||||||
|
if( !_i.hasNext() ) return;
|
||||||
|
var v = _i.next();
|
||||||
|
block(function(_) _loop());
|
||||||
|
}
|
||||||
|
_loop()
|
||||||
|
- while loops are translated similar to for loops
|
||||||
|
- break and continue are correctly handled
|
||||||
|
- you can use @sync <expr> to disable async transformation in some code parts (for performance reason)
|
||||||
|
- a few expressions are still not supported (complex calls, try/catch, and a few others)
|
||||||
|
|
||||||
|
In these examples ...rest represents the continuation of execution of the script after the expression
|
||||||
|
**/
|
||||||
|
public static function toAsync( e : Expr, topLevelSync = false ) {
|
||||||
|
var a = new Async();
|
||||||
|
return a.build(e, topLevelSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic function getTopLevelEnd() {
|
||||||
|
return ignore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function build( e : Expr, topLevelSync = false ) {
|
||||||
|
if( topLevelSync ) {
|
||||||
|
return buildSync(e,null);
|
||||||
|
} else {
|
||||||
|
var end = getTopLevelEnd();
|
||||||
|
return toCps(e, end, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function defineVar( v : String, mode ) {
|
||||||
|
definedVars.push({ n : v, prev : vars.get(v) });
|
||||||
|
vars.set(v, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lookupFunctions( el : Array<Expr> ) {
|
||||||
|
for( e in el )
|
||||||
|
switch( expr(e) ) {
|
||||||
|
case EFunction(_, _, name, _) if( name != null ): defineVar(name, Defined);
|
||||||
|
case EMeta("sync",_,expr(_) => EFunction(_,_,name,_)) if( name != null ): defineVar(name, ForceSync);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSync( e : Expr, exit : Expr ) : Expr {
|
||||||
|
switch( expr(e) ) {
|
||||||
|
case EFunction(_,_,name,_):
|
||||||
|
if( name != null )
|
||||||
|
return toCps(e, null, null);
|
||||||
|
return e;
|
||||||
|
case EBlock(el):
|
||||||
|
var v = saveVars();
|
||||||
|
lookupFunctions(el);
|
||||||
|
var e = block([for(e in el) buildSync(e,exit)], e);
|
||||||
|
restoreVars(v);
|
||||||
|
return e;
|
||||||
|
case EMeta("async", _, e):
|
||||||
|
return toCps(e, ignore(), ignore());
|
||||||
|
case EMeta("sync", args, ef = expr(_) => EFunction(fargs, body, name, ret)):
|
||||||
|
return mk(EMeta("sync",args,mk(EFunction(fargs, buildSync(body,null), name, ret),ef)),e);
|
||||||
|
case EBreak if( currentBreak != null ):
|
||||||
|
return currentBreak(e);
|
||||||
|
case EContinue if( currentLoop != null ):
|
||||||
|
return block([retNull(currentLoop, e), mk(EReturn(),e)],e);
|
||||||
|
case EFor(_), EWhile(_):
|
||||||
|
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||||
|
currentLoop = null;
|
||||||
|
currentBreak = null;
|
||||||
|
e = Tools.map(e, buildSync.bind(_, exit));
|
||||||
|
currentLoop = oldLoop;
|
||||||
|
currentBreak = oldBreak;
|
||||||
|
return e;
|
||||||
|
case EReturn(eret) if( exit != null ):
|
||||||
|
return block([eret == null ? retNull(exit, e) : call(exit,[eret], e), mk(EReturn(),e)], e);
|
||||||
|
default:
|
||||||
|
return Tools.map(e, buildSync.bind(_, exit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function new() {
|
||||||
|
vars = new Map();
|
||||||
|
definedVars = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function ignore(?e) : Expr {
|
||||||
|
var inf = e == null ? nullExpr : e;
|
||||||
|
return fun("_", block(e == null ? [] : [e],inf));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function ident(str, e) {
|
||||||
|
return mk(EIdent(str), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function fun(arg:String, e, ?name) {
|
||||||
|
return mk(EFunction([{ name : arg, t : null, opt: false, value: null }], e, name), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function funs(arg:Array<String>, e, ?name) {
|
||||||
|
return mk(EFunction([for( a in arg ) { name : a, t : null, opt: false, value: null }], e, name), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function block(arr:Array<Expr>, e) {
|
||||||
|
if( arr.length == 1 && expr(arr[0]).match(EBlock(_)) )
|
||||||
|
return arr[0];
|
||||||
|
return mk(EBlock(arr), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function field(e, f, inf) {
|
||||||
|
return mk(EField(e, f), inf);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function binop(op:Binop, e1, e2, inf) {
|
||||||
|
return mk(EBinop(op, e1, e2), inf);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function call(e, args, inf) {
|
||||||
|
return mk(ECall(e, args), inf);
|
||||||
|
}
|
||||||
|
|
||||||
|
function retNull(e:Expr,?pos) : Expr {
|
||||||
|
switch( expr(e) ) {
|
||||||
|
case EFunction([{name:"_"}], e, _, _): return e;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return call(e, [nullId], pos == null ? e : pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeCall( ecall, args : Array<Expr>, rest : Expr, exit, sync = false ) {
|
||||||
|
var names = [for( i in 0...args.length ) "_a"+uid++];
|
||||||
|
var rargs = [for( i in 0...args.length ) ident(names[i],ecall)];
|
||||||
|
if( !sync )
|
||||||
|
rargs.unshift(rest);
|
||||||
|
var rest = mk(sync ? ECall(rest,[call(ecall, rargs,ecall)]) : ECall(ecall, rargs), ecall);
|
||||||
|
var i = args.length - 1;
|
||||||
|
while( i >= 0 ) {
|
||||||
|
rest = toCps(args[i], fun(names[i], rest), exit);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
var syncFlag : Bool;
|
||||||
|
|
||||||
|
function isSync( e : Expr ) {
|
||||||
|
syncFlag = true;
|
||||||
|
checkSync(e);
|
||||||
|
return syncFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function isAsyncIdent( id : String ) {
|
||||||
|
return asyncIdents == null || asyncIdents.exists(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkSync( e : Expr ) {
|
||||||
|
if( !syncFlag )
|
||||||
|
return;
|
||||||
|
switch( expr(e) ) {
|
||||||
|
case ECall(expr(_) => EIdent(i),_) if( isAsyncIdent(i) || vars.get(i) == Defined ):
|
||||||
|
syncFlag = false;
|
||||||
|
case ECall(expr(_) => EField(_,i),_) if( isAsyncIdent(i) ):
|
||||||
|
syncFlag = false;
|
||||||
|
case EFunction(_,_,name,_) if( name != null ):
|
||||||
|
syncFlag = false;
|
||||||
|
case EMeta("sync" | "async", _, _):
|
||||||
|
// isolated from the sync part
|
||||||
|
default:
|
||||||
|
Tools.iter(e, checkSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveVars() {
|
||||||
|
return definedVars.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreVars(k) {
|
||||||
|
while( definedVars.length > k ) {
|
||||||
|
var v = definedVars.pop();
|
||||||
|
if( v.prev == null ) vars.remove(v.n) else vars.set(v.n, v.prev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toCps( e : Expr, rest : Expr, exit : Expr ) : Expr {
|
||||||
|
if( isSync(e) )
|
||||||
|
return call(rest, [buildSync(e, exit)],e);
|
||||||
|
switch( expr(e) ) {
|
||||||
|
case EBlock(el):
|
||||||
|
var el = el.copy();
|
||||||
|
var vold = saveVars();
|
||||||
|
lookupFunctions(el);
|
||||||
|
while( el.length > 0 ) {
|
||||||
|
var e = toCps(el.pop(), rest, exit);
|
||||||
|
rest = ignore(e);
|
||||||
|
}
|
||||||
|
restoreVars(vold);
|
||||||
|
return retNull(rest);
|
||||||
|
case EFunction(args, body, name, t):
|
||||||
|
var vold = saveVars();
|
||||||
|
if( name != null )
|
||||||
|
defineVar(name, Defined);
|
||||||
|
for( a in args )
|
||||||
|
defineVar(a.name, Defined);
|
||||||
|
args.unshift( { name : "_onEnd", t : null, opt: false, value: null } );
|
||||||
|
var frest = ident("_onEnd",e);
|
||||||
|
var oldFun = currentFun;
|
||||||
|
currentFun = name;
|
||||||
|
var body = toCps(body, frest, frest);
|
||||||
|
var f = mk(EFunction(args, body, name, t),e);
|
||||||
|
restoreVars(vold);
|
||||||
|
return rest == null ? f : call(rest, [f],e);
|
||||||
|
case EParent(e):
|
||||||
|
return mk(EParent(toCps(e, rest, exit)),e);
|
||||||
|
case EMeta("sync", _, e):
|
||||||
|
return call(rest,[buildSync(e,exit)],e);
|
||||||
|
case EMeta("async", _, e):
|
||||||
|
var nothing = ignore();
|
||||||
|
return block([toCps(e,nothing,nothing),retNull(rest)],e);
|
||||||
|
case EMeta("split", _, e):
|
||||||
|
var args = switch( expr(e) ) { case EArrayDecl(el): el; default: throw "@split expression should be an array"; };
|
||||||
|
var args = [for( a in args ) fun("_rest", toCps(block([a],a), ident("_rest",a), exit))];
|
||||||
|
return call(ident("split",e), [rest, mk(EArrayDecl(args),e)],e);
|
||||||
|
case ECall(expr(_) => EIdent(i), args):
|
||||||
|
var mode = vars.get(i);
|
||||||
|
return makeCall( ident( mode != null ? i : "a_" + i,e) , args, rest, exit, mode == ForceSync);
|
||||||
|
case ECall(expr(_) => EField(e, f), args):
|
||||||
|
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
||||||
|
case EFor(v, eit, eloop):
|
||||||
|
var id = ++uid;
|
||||||
|
var it = ident("_i" + id,e);
|
||||||
|
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||||
|
var loop = ident("_loop" + id,e);
|
||||||
|
currentLoop = loop;
|
||||||
|
currentBreak = function(inf) return block([retNull(rest, inf), mk(EReturn(),inf)], inf);
|
||||||
|
var efor = block([
|
||||||
|
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
|
||||||
|
fun("_", block([
|
||||||
|
mk(EIf(mk(EUnop(Unop.OpNot, true, call( field(it, "hasNext", it), [], it)),it), currentBreak(it)),it),
|
||||||
|
mk(EVar(v, call(field(it, "next",it), [], it)), it),
|
||||||
|
toCps(eloop, loop, exit),
|
||||||
|
], it),"_loop" + id),
|
||||||
|
retNull(loop, e),
|
||||||
|
], e);
|
||||||
|
currentLoop = oldLoop;
|
||||||
|
currentBreak = oldBreak;
|
||||||
|
return efor;
|
||||||
|
case EUnop(op = Unop.OpNot, prefix, eop):
|
||||||
|
return toCps(eop, fun("_r",call(rest, [mk(EUnop(op, prefix, ident("_r",e)),e)], e)), exit);
|
||||||
|
case EBinop(op, e1, e2):
|
||||||
|
switch( op ) {
|
||||||
|
case OpAssign, OpAddAssign, OpSubAssign, OpDivAssign, OpMultAssign, OpModAssign, OpAndAssign, OpOrAssign, OpXorAssign:
|
||||||
|
switch( expr(e1) ) {
|
||||||
|
case EIdent(_):
|
||||||
|
var id = "_r" + uid++;
|
||||||
|
return toCps(e2, fun(id, call(rest, [binop(op, e1, ident(id,e1),e1)], e1)), exit);
|
||||||
|
case EField(ef1, f):
|
||||||
|
var id1 = "_r" + uid++;
|
||||||
|
var id2 = "_r" + uid++;
|
||||||
|
return toCps(ef1, fun(id1, toCps(e2, fun(id2, call(rest, [binop(op, field(ident(id1, e1), f, ef1), ident(id2, e2), e)], e)), exit)), exit);
|
||||||
|
case EArray(earr, eindex):
|
||||||
|
var idArr = "_r" + uid++;
|
||||||
|
var idIndex = "_r" + uid++;
|
||||||
|
var idVal = "_r" + uid++;
|
||||||
|
return toCps(earr,fun(idArr, toCps(eindex, fun(idIndex, toCps(e2,
|
||||||
|
fun(idVal, call(rest, [binop(op, mk(EArray(ident(idArr,earr), ident(idIndex,eindex)),e1), ident(idVal,e1), e)], e))
|
||||||
|
, exit)), exit)),exit);
|
||||||
|
default:
|
||||||
|
throw "assert " + e1;
|
||||||
|
}
|
||||||
|
case OpBoolOr:
|
||||||
|
var id1 = "_r" + uid++;
|
||||||
|
var id2 = "_r" + uid++;
|
||||||
|
return toCps(e1, fun(id1, mk(EIf(binop(OpEq, ident(id1,e1), ident("true",e1), e1),call(rest,[ident("true",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
||||||
|
case OpBoolAnd:
|
||||||
|
var id1 = "_r" + uid++;
|
||||||
|
var id2 = "_r" + uid++;
|
||||||
|
return toCps(e1, fun(id1, mk(EIf(binop(OpNeq, ident(id1,e1), ident("true",e1), e1),call(rest,[ident("false",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
||||||
|
default:
|
||||||
|
var id1 = "_r" + uid++;
|
||||||
|
var id2 = "_r" + uid++;
|
||||||
|
return toCps(e1, fun(id1, toCps(e2, fun(id2, call(rest, [binop(op, ident(id1,e1), ident(id2,e2), e)], e)), exit)), exit);
|
||||||
|
}
|
||||||
|
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
|
||||||
|
return toCps(cond, fun("_c", mk(EIf(ident("_c",cond), toCps(e1, rest, exit), e2 == null ? retNull(rest) : toCps(e2, rest, exit)),e)), exit);
|
||||||
|
case EWhile(cond, ewh):
|
||||||
|
var id = ++uid;
|
||||||
|
var loop = ident("_loop" + id, cond);
|
||||||
|
var oldLoop = currentLoop, oldBreak = currentBreak;
|
||||||
|
currentLoop = loop;
|
||||||
|
currentBreak = function(e) return block([retNull(rest,e), mk(EReturn(),e)],e);
|
||||||
|
var ewhile = block([
|
||||||
|
fun("_r",
|
||||||
|
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), retNull(rest,cond)),cond)), exit)
|
||||||
|
, "_loop"+id),
|
||||||
|
retNull(loop, cond),
|
||||||
|
],e);
|
||||||
|
currentLoop = oldLoop;
|
||||||
|
currentBreak = oldBreak;
|
||||||
|
return ewhile;
|
||||||
|
case EReturn(eret):
|
||||||
|
return eret == null ? retNull(exit, e) : toCps(eret, exit, exit);
|
||||||
|
case EObject(fields):
|
||||||
|
var id = "_o" + uid++;
|
||||||
|
var rest = call(rest, [ident(id,e)], e);
|
||||||
|
fields.reverse();
|
||||||
|
for( f in fields )
|
||||||
|
rest = toCps(f.e, fun("_r", block([
|
||||||
|
binop(OpAssign, mk(EField(ident(id,f.e), f.name),f.e), ident("_r",f.e), f.e),
|
||||||
|
rest,
|
||||||
|
],f.e)),exit);
|
||||||
|
return block([
|
||||||
|
mk(EVar(id, mk(EObject([]),e)),e),
|
||||||
|
rest,
|
||||||
|
],e);
|
||||||
|
case EArrayDecl(el):
|
||||||
|
var id = "_a" + uid++;
|
||||||
|
var rest = call(rest, [ident(id,e)], e);
|
||||||
|
var i = el.length - 1;
|
||||||
|
while( i >= 0 ) {
|
||||||
|
var e = el[i];
|
||||||
|
rest = toCps(e, fun("_r", block([
|
||||||
|
binop(OpAssign, mk(EArray(ident(id,e), mk(EConst(CInt(i)),e)),e), ident("_r",e), e),
|
||||||
|
rest,
|
||||||
|
],e)), exit);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return block([
|
||||||
|
mk(EVar(id, mk(EArrayDecl([]),e)),e),
|
||||||
|
rest,
|
||||||
|
],e);
|
||||||
|
case EArray(earr, eindex):
|
||||||
|
var id1 = "_r" + uid++;
|
||||||
|
var id2 = "_r" + uid++;
|
||||||
|
return toCps(earr, fun(id1, toCps(eindex, fun(id2, call(rest, [mk(EArray(ident(id1,e), ident(id2,e)),e)], e)), exit)), exit);
|
||||||
|
case EVar(v, t, ev):
|
||||||
|
if( ev == null )
|
||||||
|
return block([e, retNull(rest, e)], e);
|
||||||
|
return block([
|
||||||
|
mk(EVar(v, t),e),
|
||||||
|
toCps(ev, fun("_r", block([binop(OpAssign, ident(v,e), ident("_r",e), e), retNull(rest,e)], e)), exit),
|
||||||
|
],e);
|
||||||
|
case EConst(_), EIdent(_), EUnop(_), EField(_):
|
||||||
|
return call(rest, [e], e);
|
||||||
|
case ENew(cl, args):
|
||||||
|
var names = [for( i in 0...args.length ) "_a"+uid++];
|
||||||
|
var rargs = [for( i in 0...args.length ) ident(names[i], args[i])];
|
||||||
|
var rest = call(rest,[mk(ENew(cl, rargs),e)],e);
|
||||||
|
var i = args.length - 1;
|
||||||
|
while( i >= 0 ) {
|
||||||
|
rest = toCps(args[i], fun(names[i], rest), exit);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return rest;
|
||||||
|
case EBreak:
|
||||||
|
if( currentBreak == null ) throw "Break outside loop";
|
||||||
|
return currentBreak(e);
|
||||||
|
case EContinue:
|
||||||
|
if( currentLoop == null ) throw "Continue outside loop";
|
||||||
|
return block([retNull(currentLoop, e), mk(EReturn(),e)], e);
|
||||||
|
case ESwitch(v, cases, def):
|
||||||
|
var cases:Array<SwitchCase> = [for( c in cases ) { values : c.values, expr : toCps(c.expr, rest, exit) } ];
|
||||||
|
return toCps(v, mk(EFunction([ { name : "_c", t : null, opt: false, value: null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
||||||
|
case EThrow(v):
|
||||||
|
return toCps(v, mk(EFunction([ { name : "_v", t : null, opt: false, value: null } ], mk(EThrow(v),v)), v), exit);
|
||||||
|
case EMeta(name,_,e) if( name.charCodeAt(0) == ":".code ): // ignore custom ":" metadata
|
||||||
|
return toCps(e, rest, exit);
|
||||||
|
//case EDoWhile(_), ETry(_), ECall(_):
|
||||||
|
default:
|
||||||
|
throw "Unsupported async expression " + Printer.toString(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncInterp extends Interp {
|
||||||
|
|
||||||
|
public function setContext( api : Dynamic ) {
|
||||||
|
|
||||||
|
var funs = [];
|
||||||
|
for( v in variables.keys() )
|
||||||
|
if( Reflect.isFunction(variables.get(v)) )
|
||||||
|
funs.push({ v : v, obj : null });
|
||||||
|
|
||||||
|
variables.set("split", split);
|
||||||
|
variables.set("makeIterator", makeIterator);
|
||||||
|
|
||||||
|
var c = Type.getClass(api);
|
||||||
|
for( f in (c == null ? Reflect.fields(api) : Type.getInstanceFields(c)) ) {
|
||||||
|
var fv = Reflect.field(api, f);
|
||||||
|
if( !Reflect.isFunction(fv) ) continue;
|
||||||
|
if( f.charCodeAt(0) == "_".code ) f = f.substr(1);
|
||||||
|
variables.set(f, fv);
|
||||||
|
// create the async wrapper if doesn't exists
|
||||||
|
if( f.substr(0, 2) != "a_" )
|
||||||
|
funs.push({ v : f, obj : api });
|
||||||
|
}
|
||||||
|
|
||||||
|
for( v in funs ) {
|
||||||
|
if( variables.exists("a_" + v.v) ) continue;
|
||||||
|
var fv : Dynamic = variables.get(v.v);
|
||||||
|
var obj = v.obj;
|
||||||
|
variables.set("a_" + v.v, Reflect.makeVarArgs(function(args:Array<Dynamic>) {
|
||||||
|
var onEnd = args.shift();
|
||||||
|
onEnd(Reflect.callMethod(obj, fv, args));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasMethod( name : String ) {
|
||||||
|
var v = variables.get(name);
|
||||||
|
return v != null && Reflect.isFunction(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callValue( value : Dynamic, args : Array<Dynamic>, ?onResult : Dynamic -> Void, ?vthis : {} ) {
|
||||||
|
var oldThis = variables.get("this");
|
||||||
|
if( vthis != null )
|
||||||
|
variables.set("this", vthis);
|
||||||
|
if( onResult == null )
|
||||||
|
onResult = function(_) {};
|
||||||
|
args.unshift(onResult);
|
||||||
|
Reflect.callMethod(null, value, args);
|
||||||
|
variables.set("this", oldThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callAsync( id : String, args, ?onResult, ?vthis : {} ) {
|
||||||
|
var v = variables.get(id);
|
||||||
|
if( v == null )
|
||||||
|
throw "Missing function " + id + "()";
|
||||||
|
callValue(v, args, onResult, vthis);
|
||||||
|
}
|
||||||
|
|
||||||
|
function split( rest : Dynamic -> Void, args : Array<Dynamic> ) {
|
||||||
|
if( args.length == 0 )
|
||||||
|
rest(null);
|
||||||
|
else {
|
||||||
|
var count = args.length;
|
||||||
|
function next(_) {
|
||||||
|
if( --count == 0 ) rest(null);
|
||||||
|
}
|
||||||
|
for( a in args )
|
||||||
|
a(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override function fcall( o : Dynamic, f : String, args : Array<Dynamic> ) : Dynamic {
|
||||||
|
var m = Reflect.field(o, f);
|
||||||
|
if( m == null ) {
|
||||||
|
if( f.substr(0, 2) == "a_" ) {
|
||||||
|
m = Reflect.field(o, f.substr(2));
|
||||||
|
// fallback on sync version
|
||||||
|
if( m != null ) {
|
||||||
|
var onEnd = args.shift();
|
||||||
|
onEnd(call(o, m, args));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// fallback on generic script
|
||||||
|
m = Reflect.field(o, "scriptCall");
|
||||||
|
if( m != null ) {
|
||||||
|
call(o, m, [args.shift(), f.substr(2), args]);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// fallback on generic script
|
||||||
|
m = Reflect.field(o, "scriptCall");
|
||||||
|
if( m != null ) {
|
||||||
|
var result : Dynamic = null;
|
||||||
|
call(o, m, [function(r) result = r, f, args]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error(ECustom(o + " has no method " + f));
|
||||||
|
}
|
||||||
|
return call(o, m, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+92
-57
@@ -1,26 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Nicolas Cannasse
|
* Copyright (C)2008-2017 Haxe Foundation
|
||||||
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
* to deal in the Software without restriction, including without limitation
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
* documentation and/or other materials provided with the distribution.
|
* 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:
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* all copies or substantial portions of the Software.
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
*
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
* DEALINGS IN THE SOFTWARE.
|
||||||
* DAMAGE.
|
|
||||||
*/
|
*/
|
||||||
package hscript;
|
package hscript;
|
||||||
import hscript.Expr;
|
import hscript.Expr;
|
||||||
@@ -30,7 +27,7 @@ class Bytes {
|
|||||||
var bin : haxe.io.Bytes;
|
var bin : haxe.io.Bytes;
|
||||||
var bout : haxe.io.BytesBuffer;
|
var bout : haxe.io.BytesBuffer;
|
||||||
var pin : Int;
|
var pin : Int;
|
||||||
var hstrings : #if haxe3 Map<String,Int> #else Hash<Int> #end;
|
var hstrings : Map<String,Int>;
|
||||||
var strings : Array<String>;
|
var strings : Array<String>;
|
||||||
var nstrings : Int;
|
var nstrings : Int;
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ class Bytes {
|
|||||||
this.bin = bin;
|
this.bin = bin;
|
||||||
pin = 0;
|
pin = 0;
|
||||||
bout = new haxe.io.BytesBuffer();
|
bout = new haxe.io.BytesBuffer();
|
||||||
hstrings = #if haxe3 new Map() #else new Hash() #end;
|
hstrings = new Map();
|
||||||
strings = [null];
|
strings = [null];
|
||||||
nstrings = 1;
|
nstrings = 1;
|
||||||
}
|
}
|
||||||
@@ -47,7 +44,7 @@ class Bytes {
|
|||||||
var vid = hstrings.get(v);
|
var vid = hstrings.get(v);
|
||||||
if( vid == null ) {
|
if( vid == null ) {
|
||||||
if( nstrings == 256 ) {
|
if( nstrings == 256 ) {
|
||||||
hstrings = #if haxe3 new Map() #else new Hash() #end;
|
hstrings = new Map();
|
||||||
nstrings = 1;
|
nstrings = 1;
|
||||||
}
|
}
|
||||||
hstrings.set(v,nstrings);
|
hstrings.set(v,nstrings);
|
||||||
@@ -74,6 +71,10 @@ class Bytes {
|
|||||||
return strings[id];
|
return strings[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doEncodeInt(v: Int) {
|
||||||
|
bout.addInt32(v);
|
||||||
|
}
|
||||||
|
|
||||||
function doEncodeConst( c : Const ) {
|
function doEncodeConst( c : Const ) {
|
||||||
switch( c ) {
|
switch( c ) {
|
||||||
case CInt(v):
|
case CInt(v):
|
||||||
@@ -82,20 +83,8 @@ class Bytes {
|
|||||||
bout.addByte(v);
|
bout.addByte(v);
|
||||||
} else {
|
} else {
|
||||||
bout.addByte(1);
|
bout.addByte(1);
|
||||||
bout.addByte(v & 0xFF);
|
doEncodeInt(v);
|
||||||
bout.addByte((v >> 8) & 0xFF);
|
|
||||||
bout.addByte((v >> 16) & 0xFF);
|
|
||||||
bout.addByte(v >>> 24);
|
|
||||||
}
|
}
|
||||||
#if !haxe3
|
|
||||||
case CInt32(v):
|
|
||||||
bout.addByte(4);
|
|
||||||
var mid = haxe.Int32.toInt(haxe.Int32.and(v,haxe.Int32.ofInt(0xFFFFFF)));
|
|
||||||
bout.addByte(mid & 0xFF);
|
|
||||||
bout.addByte((mid >> 8) & 0xFF);
|
|
||||||
bout.addByte(mid >> 16);
|
|
||||||
bout.addByte(haxe.Int32.toInt(haxe.Int32.ushr(v, 24)));
|
|
||||||
#end
|
|
||||||
case CFloat(f):
|
case CFloat(f):
|
||||||
bout.addByte(2);
|
bout.addByte(2);
|
||||||
doEncodeString(Std.string(f));
|
doEncodeString(Std.string(f));
|
||||||
@@ -105,33 +94,48 @@ class Bytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function doDecodeInt() {
|
||||||
|
var i = bin.getInt32(pin);
|
||||||
|
pin += 4;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
function doDecodeConst() {
|
function doDecodeConst() {
|
||||||
return switch( bin.get(pin++) ) {
|
return switch( bin.get(pin++) ) {
|
||||||
case 0:
|
case 0:
|
||||||
CInt(bin.get(pin++));
|
CInt(bin.get(pin++));
|
||||||
case 1:
|
case 1:
|
||||||
var i = bin.get(pin) | (bin.get(pin+1) << 8) | (bin.get(pin+2) << 16) | (bin.get(pin+3) << 24);
|
var i = doDecodeInt();
|
||||||
pin += 4;
|
|
||||||
CInt(i);
|
CInt(i);
|
||||||
case 2:
|
case 2:
|
||||||
CFloat( Std.parseFloat(doDecodeString()) );
|
CFloat( Std.parseFloat(doDecodeString()) );
|
||||||
case 3:
|
case 3:
|
||||||
CString( doDecodeString() );
|
CString( doDecodeString() );
|
||||||
#if !haxe3
|
|
||||||
case 4:
|
|
||||||
var i = bin.get(pin) | (bin.get(pin+1) << 8) | (bin.get(pin+2) << 16);
|
|
||||||
var j = bin.get(pin+3);
|
|
||||||
pin += 4;
|
|
||||||
CInt32(haxe.Int32.or(haxe.Int32.ofInt(i), haxe.Int32.shl(haxe.Int32.ofInt(j), 24)));
|
|
||||||
#end
|
|
||||||
default:
|
default:
|
||||||
throw "Invalid code "+bin.get(pin-1);
|
throw "Invalid code "+bin.get(pin-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doEncode( e : Expr ) {
|
function doEncode( e : Expr ) {
|
||||||
|
#if hscriptPos
|
||||||
|
doEncodeString(e.origin);
|
||||||
|
doEncodeInt(e.line);
|
||||||
|
var e = e.e;
|
||||||
|
#end
|
||||||
bout.addByte(Type.enumIndex(e));
|
bout.addByte(Type.enumIndex(e));
|
||||||
switch( e ) {
|
switch( e ) {
|
||||||
|
case EPackage(n):
|
||||||
|
// TODO
|
||||||
|
case EImport(c):
|
||||||
|
// TODO
|
||||||
|
case EClass(_, _, _, _):
|
||||||
|
// TODO
|
||||||
|
case EEnum(en):
|
||||||
|
// TODO
|
||||||
|
case ECast(e, _):
|
||||||
|
// TODO
|
||||||
|
case ERegex(e, f):
|
||||||
|
// TODO
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
doEncodeConst(c);
|
doEncodeConst(c);
|
||||||
case EIdent(v):
|
case EIdent(v):
|
||||||
@@ -152,11 +156,11 @@ class Bytes {
|
|||||||
doEncode(e);
|
doEncode(e);
|
||||||
doEncodeString(f);
|
doEncodeString(f);
|
||||||
case EBinop(op,e1,e2):
|
case EBinop(op,e1,e2):
|
||||||
doEncodeString(op);
|
doEncodeString(op.toString());
|
||||||
doEncode(e1);
|
doEncode(e1);
|
||||||
doEncode(e2);
|
doEncode(e2);
|
||||||
case EUnop(op,prefix,e):
|
case EUnop(op,prefix,e):
|
||||||
doEncodeString(op);
|
doEncodeString(op.toString()); // maybe doEncodeInt
|
||||||
bout.addByte(prefix?1:0);
|
bout.addByte(prefix?1:0);
|
||||||
doEncode(e);
|
doEncode(e);
|
||||||
case ECall(e,el):
|
case ECall(e,el):
|
||||||
@@ -174,6 +178,9 @@ class Bytes {
|
|||||||
case EWhile(cond,e):
|
case EWhile(cond,e):
|
||||||
doEncode(cond);
|
doEncode(cond);
|
||||||
doEncode(e);
|
doEncode(e);
|
||||||
|
case EDoWhile(cond,e):
|
||||||
|
doEncode(cond);
|
||||||
|
doEncode(e);
|
||||||
case EFor(v,it,e):
|
case EFor(v,it,e):
|
||||||
doEncodeString(v);
|
doEncodeString(v);
|
||||||
doEncode(it);
|
doEncode(it);
|
||||||
@@ -230,10 +237,28 @@ class Bytes {
|
|||||||
}
|
}
|
||||||
bout.addByte(255);
|
bout.addByte(255);
|
||||||
if( def == null ) bout.addByte(255) else doEncode(def);
|
if( def == null ) bout.addByte(255) else doEncode(def);
|
||||||
|
case EMeta(name,args,e):
|
||||||
|
doEncodeString(name);
|
||||||
|
bout.addByte(args == null ? 0 : args.length + 1);
|
||||||
|
if( args != null ) for( e in args ) doEncode(e);
|
||||||
|
doEncode(e);
|
||||||
|
case ECheckType(e,_):
|
||||||
|
doEncode(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function doDecode() : Expr {
|
function doDecode() : Expr {
|
||||||
|
#if hscriptPos
|
||||||
|
if (bin.get(pin) == 255) {
|
||||||
|
pin++;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var origin = doDecodeString();
|
||||||
|
var line = doDecodeInt();
|
||||||
|
return { e : _doDecode(), pmin : 0, pmax : 0, origin : origin, line : line };
|
||||||
|
}
|
||||||
|
function _doDecode() : ExprDef {
|
||||||
|
#end
|
||||||
return switch( bin.get(pin++) ) {
|
return switch( bin.get(pin++) ) {
|
||||||
case 0:
|
case 0:
|
||||||
EConst( doDecodeConst() );
|
EConst( doDecodeConst() );
|
||||||
@@ -245,7 +270,7 @@ class Bytes {
|
|||||||
case 3:
|
case 3:
|
||||||
EParent(doDecode());
|
EParent(doDecode());
|
||||||
case 4:
|
case 4:
|
||||||
var a = new Array();
|
var a = [];
|
||||||
for( i in 0...bin.get(pin++) )
|
for( i in 0...bin.get(pin++) )
|
||||||
a.push(doDecode());
|
a.push(doDecode());
|
||||||
EBlock(a);
|
EBlock(a);
|
||||||
@@ -253,16 +278,16 @@ class Bytes {
|
|||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
EField(e,doDecodeString());
|
EField(e,doDecodeString());
|
||||||
case 6:
|
case 6:
|
||||||
var op = doDecodeString();
|
var op = Binop.fromString(doDecodeString());
|
||||||
var e1 = doDecode();
|
var e1 = doDecode();
|
||||||
EBinop(op,e1,doDecode());
|
EBinop(op,e1,doDecode());
|
||||||
case 7:
|
case 7:
|
||||||
var op = doDecodeString();
|
var op = Unop.fromString(doDecodeString());
|
||||||
var prefix = bin.get(pin++) != 0;
|
var prefix = bin.get(pin++) != 0;
|
||||||
EUnop(op,prefix,doDecode());
|
EUnop(op,prefix,doDecode());
|
||||||
case 8:
|
case 8:
|
||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
var params = new Array();
|
var params = [];
|
||||||
for( i in 0...bin.get(pin++) )
|
for( i in 0...bin.get(pin++) )
|
||||||
params.push(doDecode());
|
params.push(doDecode());
|
||||||
ECall(e,params);
|
ECall(e,params);
|
||||||
@@ -284,7 +309,7 @@ class Bytes {
|
|||||||
case 14:
|
case 14:
|
||||||
var params = new Array<Argument>();
|
var params = new Array<Argument>();
|
||||||
for( i in 0...bin.get(pin++) )
|
for( i in 0...bin.get(pin++) )
|
||||||
params.push({ name : doDecodeString() });
|
params.push({ name : doDecodeString(), opt: false, value: null, t: null });
|
||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
var name = doDecodeString();
|
var name = doDecodeString();
|
||||||
EFunction(params,e,(name == "") ? null: name);
|
EFunction(params,e,(name == "") ? null: name);
|
||||||
@@ -294,13 +319,13 @@ class Bytes {
|
|||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
EArray(e,doDecode());
|
EArray(e,doDecode());
|
||||||
case 17:
|
case 17:
|
||||||
var el = new Array();
|
var el = [];
|
||||||
for( i in 0...bin.get(pin++) )
|
for( i in 0...bin.get(pin++) )
|
||||||
el.push(doDecode());
|
el.push(doDecode());
|
||||||
EArrayDecl(el);
|
EArrayDecl(el);
|
||||||
case 18:
|
case 18:
|
||||||
var cl = doDecodeString();
|
var cl = doDecodeString();
|
||||||
var el = new Array();
|
var el = [];
|
||||||
for( i in 0...bin.get(pin++) )
|
for( i in 0...bin.get(pin++) )
|
||||||
el.push(doDecode());
|
el.push(doDecode());
|
||||||
ENew(cl,el);
|
ENew(cl,el);
|
||||||
@@ -311,7 +336,7 @@ class Bytes {
|
|||||||
var v = doDecodeString();
|
var v = doDecodeString();
|
||||||
ETry(e,v,null,doDecode());
|
ETry(e,v,null,doDecode());
|
||||||
case 21:
|
case 21:
|
||||||
var fl = new Array();
|
var fl:Array<ObjectField> = [];
|
||||||
for( i in 0...bin.get(pin++) ) {
|
for( i in 0...bin.get(pin++) ) {
|
||||||
var name = doDecodeString();
|
var name = doDecodeString();
|
||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
@@ -325,7 +350,7 @@ class Bytes {
|
|||||||
ETernary(cond, e1, e2);
|
ETernary(cond, e1, e2);
|
||||||
case 23:
|
case 23:
|
||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
var cases = [];
|
var cases:Array<SwitchCase> = [];
|
||||||
while( true ) {
|
while( true ) {
|
||||||
var v = doDecode();
|
var v = doDecode();
|
||||||
if( v == null ) break;
|
if( v == null ) break;
|
||||||
@@ -339,6 +364,16 @@ class Bytes {
|
|||||||
}
|
}
|
||||||
var def = doDecode();
|
var def = doDecode();
|
||||||
ESwitch(e, cases, def);
|
ESwitch(e, cases, def);
|
||||||
|
case 24:
|
||||||
|
var cond = doDecode();
|
||||||
|
EDoWhile(cond,doDecode());
|
||||||
|
case 25:
|
||||||
|
var name = doDecodeString();
|
||||||
|
var count = bin.get(pin++);
|
||||||
|
var args = count == 0 ? null : [for( i in 0...count - 1 ) doDecode()];
|
||||||
|
EMeta(name, args, doDecode());
|
||||||
|
case 26:
|
||||||
|
ECheckType(doDecode(), CTPath(["Void"]));
|
||||||
case 255:
|
case 255:
|
||||||
null;
|
null;
|
||||||
default:
|
default:
|
||||||
@@ -357,4 +392,4 @@ class Bytes {
|
|||||||
return b.doDecode();
|
return b.doDecode();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1259
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
class Config {
|
||||||
|
// Runs support for custom classes in these
|
||||||
|
public static final ALLOWED_CUSTOM_CLASSES = [
|
||||||
|
"flixel",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Runs support for abstract support in these
|
||||||
|
public static final ALLOWED_ABSTRACT_AND_ENUM = [
|
||||||
|
"flixel",
|
||||||
|
"openfl.display.BlendMode",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Incase any of your files fail
|
||||||
|
// These are the module names
|
||||||
|
public static final DISALLOW_CUSTOM_CLASSES = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
public static final DISALLOW_ABSTRACT_AND_ENUM = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
@:unreflective
|
||||||
|
public static final IMPORT_BLACKLIST:Array<String> = [
|
||||||
|
// "flixel.FlxG"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
import hscript.utils.UnsafeReflect;
|
||||||
|
import haxe.Constraints.Function;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Custom Class core.
|
||||||
|
*
|
||||||
|
* Provides handlers for custom classes.
|
||||||
|
*
|
||||||
|
* @author Jamextreme140
|
||||||
|
*/
|
||||||
|
@:access(hscript.CustomClassHandler)
|
||||||
|
class CustomClass implements IHScriptCustomClassBehaviour {
|
||||||
|
public var className(get, never):String;
|
||||||
|
|
||||||
|
private function get_className():String
|
||||||
|
return __class.name;
|
||||||
|
|
||||||
|
public var __interp:Interp;
|
||||||
|
public var __real_fields:Array<String> = []; // UNUSED
|
||||||
|
public var __class__fields:Array<String> = []; // Declared fields
|
||||||
|
|
||||||
|
public var __allowSetGet:Bool = true;
|
||||||
|
|
||||||
|
var __class:CustomClassHandler;
|
||||||
|
var __superClass:IHScriptCustomClassBehaviour;
|
||||||
|
var __upperClass:IHScriptCustomClassBehaviour;
|
||||||
|
var __constructor:Function;
|
||||||
|
|
||||||
|
var __overrideFields:Array<String> = [];
|
||||||
|
var __cachedFieldSet:Map<String, Dynamic> = null;
|
||||||
|
var initializing:Bool = false;
|
||||||
|
|
||||||
|
public function new(__class:CustomClassHandler, ?args:Array<Dynamic>, ?cachedFieldSet:Map<String, Dynamic>) {
|
||||||
|
this.__class = __class;
|
||||||
|
|
||||||
|
__interp = new Interp();
|
||||||
|
__interp.errorHandler = __class.__interp.errorHandler;
|
||||||
|
__interp.importFailedCallback = __class.__interp.importFailedCallback;
|
||||||
|
|
||||||
|
// __interp.variables = __class.staticInterp.variables;
|
||||||
|
@:privateAccess __interp.usingHandler.usingEntries = __class.ogInterp.usingHandler.usingEntries;
|
||||||
|
__interp.publicVariables = __class.ogInterp.publicVariables;
|
||||||
|
__interp.staticVariables = __class.ogInterp.staticVariables;
|
||||||
|
__interp.customClasses = __class.ogInterp.customClasses;
|
||||||
|
|
||||||
|
for(f => v in __class.__interp.variables) {
|
||||||
|
if(f == 'new') continue;
|
||||||
|
if (!__interp.variables.exists(f))
|
||||||
|
__interp.variables.set(f, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (f in __class.fields) {
|
||||||
|
switch (Tools.expr(f)) {
|
||||||
|
case EVar(n): __class__fields.push(n);
|
||||||
|
case EFunction(_, _, n, _, _, _, isOverride):
|
||||||
|
if(isOverride) __overrideFields.push(n);
|
||||||
|
__class__fields.push(n);
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
@:privateAccess __interp.exprReturn(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
__interp.scriptObject = this;
|
||||||
|
|
||||||
|
initializing = true;
|
||||||
|
|
||||||
|
if(cachedFieldSet != null)
|
||||||
|
for(f => v in cachedFieldSet)
|
||||||
|
this.hset(f, v);
|
||||||
|
|
||||||
|
if (hasField('new')) {
|
||||||
|
buildConstructor();
|
||||||
|
call('new', args);
|
||||||
|
|
||||||
|
if(__cachedFieldSet != null) {
|
||||||
|
__cachedFieldSet.clear();
|
||||||
|
__cachedFieldSet = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.__superClass == null && __class.extend != null)
|
||||||
|
__interp.error(ECustom("super() not called"));
|
||||||
|
} else if (__class.extend != null) {
|
||||||
|
buildSuperClass(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cacheFieldSet(name:String, val:Dynamic) {
|
||||||
|
if(!initializing) return;
|
||||||
|
if(__cachedFieldSet == null) __cachedFieldSet = [];
|
||||||
|
__cachedFieldSet.set(name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildConstructor() {
|
||||||
|
__constructor = Reflect.makeVarArgs(buildSuperClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSuperClass(?args:Array<Dynamic>) {
|
||||||
|
if (args == null)
|
||||||
|
args = [];
|
||||||
|
|
||||||
|
if (__class.cl == null) {
|
||||||
|
__interp.error(ECustom('Current class does not have a super'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__class.cl is CustomClassHandler) {
|
||||||
|
var customClass = new CustomClass(__class.cl, args, __cachedFieldSet);
|
||||||
|
if(__overrideFields.length > 0) {
|
||||||
|
for (field in __overrideFields) {
|
||||||
|
var func = __interp.variables.get(field);
|
||||||
|
customClass.overrideField(field, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customClass.__upperClass = this;
|
||||||
|
__superClass = customClass;
|
||||||
|
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(getSuperFields());
|
||||||
|
} else {
|
||||||
|
if(__cachedFieldSet != null)
|
||||||
|
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
|
||||||
|
|
||||||
|
__superClass = Type.createInstance(__class.cl, args);
|
||||||
|
var disallowCopy:Array<String> = {
|
||||||
|
var fieldMap:Map<String, String> = []; // Prevent duplicate values
|
||||||
|
for(f in Reflect.fields(__superClass).concat(Type.getInstanceFields(Type.getClass(__superClass))))
|
||||||
|
fieldMap.set(f, f);
|
||||||
|
|
||||||
|
fieldMap.array();
|
||||||
|
}
|
||||||
|
this.__real_fields = disallowCopy;
|
||||||
|
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(disallowCopy);
|
||||||
|
__superClass.__real_fields = this.__real_fields;
|
||||||
|
__superClass.__class__fields = this.__class__fields;
|
||||||
|
__superClass.__interp = this.__interp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
|
||||||
|
var superFnName:Null<String> = toSuper ? '_HX_SUPER__$name' : null;
|
||||||
|
var fn:Dynamic = {
|
||||||
|
if(toSuper && __interp.variables.exists(superFnName)) {
|
||||||
|
__interp.variables.get(superFnName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
__interp.variables.get(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fn != null && Reflect.isFunction(fn))
|
||||||
|
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
|
||||||
|
|
||||||
|
// If not found in current class, try parent class recursively
|
||||||
|
if (__superClass != null && __superClass is CustomClass)
|
||||||
|
return cast(__superClass, CustomClass).call(name, args, toSuper);
|
||||||
|
|
||||||
|
__interp.error(ECustom('$name doesn\'t exists or is not a function'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasField(name:String) {
|
||||||
|
return __class__fields.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasStaticField(name:String):Bool {
|
||||||
|
return __class.hasField(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getField(name:String, allowProperty:Bool = true):Dynamic {
|
||||||
|
var f = __interp.variables.get(name);
|
||||||
|
if (f != null && allowProperty && f is Property) {
|
||||||
|
var prop:Property = cast f;
|
||||||
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
|
var r = prop.get(!__allowSetGet);
|
||||||
|
//prop.__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setField(name:String, val:Dynamic):Dynamic {
|
||||||
|
var f = getField(name, false);
|
||||||
|
if (f != null && f is Property) {
|
||||||
|
var prop:Property = cast f;
|
||||||
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
|
var r = prop.set(val, !__allowSetGet);
|
||||||
|
//prop.__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides (replaces) the declared function.
|
||||||
|
* @param name
|
||||||
|
* @param func
|
||||||
|
*/
|
||||||
|
function overrideField(name:String, func:Function) {
|
||||||
|
var f = getField(name, false);
|
||||||
|
if(f != null && Reflect.isFunction(f)) {
|
||||||
|
__interp.variables.set(name, func);
|
||||||
|
__interp.variables.set('_HX_SUPER__$name', f);
|
||||||
|
}
|
||||||
|
else if(__superClass != null && __superClass is CustomClass) {
|
||||||
|
cast(__superClass, CustomClass).overrideField(name, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function superHasField(name:String) {
|
||||||
|
if (__superClass == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var realFieldExists = __superClass.__real_fields != null && __superClass.__real_fields.contains(name);
|
||||||
|
var classFieldExists = __superClass.__class__fields != null && __superClass.__class__fields.contains(name);
|
||||||
|
|
||||||
|
if(!realFieldExists && !classFieldExists && __superClass is CustomClass)
|
||||||
|
return cast(__superClass, CustomClass).superHasField(name);
|
||||||
|
|
||||||
|
return realFieldExists || classFieldExists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSuperFields():Array<String> {
|
||||||
|
if(__superClass == null) return [];
|
||||||
|
|
||||||
|
var classFields:Map<String, String> = []; // Prevents duplicated values
|
||||||
|
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
|
||||||
|
|
||||||
|
while (cls != null) {
|
||||||
|
for(fieldSet in [cls.__class__fields, cls.__real_fields])
|
||||||
|
for(f in fieldSet)
|
||||||
|
classFields.set(f, f);
|
||||||
|
var next:IHScriptCustomClassBehaviour = null;
|
||||||
|
if(cls is CustomClass)
|
||||||
|
next = cast(cls, CustomClass).__superClass;
|
||||||
|
if (next == null)
|
||||||
|
break;
|
||||||
|
cls = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [for(f in classFields) f];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
switch (name) {
|
||||||
|
case 'superClass': return __superClass;
|
||||||
|
case 'superConstructor': return __constructor;
|
||||||
|
default:
|
||||||
|
if (hasField(name))
|
||||||
|
return getField(name);
|
||||||
|
|
||||||
|
if (hasStaticField(name)) {
|
||||||
|
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__superClass != null) {
|
||||||
|
if (superHasField(name)) {
|
||||||
|
__superClass.__allowSetGet = this.__allowSetGet;
|
||||||
|
return __superClass.hget(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "field '"
|
||||||
|
+ name
|
||||||
|
+ "' does not exist in custom class '"
|
||||||
|
+ this.className
|
||||||
|
+ "'"
|
||||||
|
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
if (hasField(name))
|
||||||
|
return setField(name, val);
|
||||||
|
|
||||||
|
if (hasStaticField(name)) {
|
||||||
|
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__superClass != null) {
|
||||||
|
if (superHasField(name)) {
|
||||||
|
__superClass.__allowSetGet = this.__allowSetGet;
|
||||||
|
return __superClass.hset(name, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(__class.extend != null && initializing) {
|
||||||
|
cacheFieldSet(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "field '"
|
||||||
|
+ name
|
||||||
|
+ "' does not exist in custom class '"
|
||||||
|
+ this.className
|
||||||
|
+ "'"
|
||||||
|
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNUSED
|
||||||
|
public function __callGetter(name:String):Dynamic {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the real superClass if the Custom Class
|
||||||
|
* extends another Custom Class, and so on until
|
||||||
|
* it reaches a real class, otherwise it will
|
||||||
|
* return the last fetched Custom Class
|
||||||
|
* @return Null<Dynamic>
|
||||||
|
*/
|
||||||
|
public function getSuperclass():IHScriptCustomClassBehaviour {
|
||||||
|
if(__superClass == null) return null;
|
||||||
|
|
||||||
|
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
|
||||||
|
|
||||||
|
// Check if the superClass is another custom class,
|
||||||
|
// so it will find for a real class, otherwise
|
||||||
|
// returns the last super CustomClass parent.
|
||||||
|
while (cls != null && cls is CustomClass) {
|
||||||
|
var next = cast(cls, CustomClass).__superClass;
|
||||||
|
if (next == null)
|
||||||
|
break; // Return the Custom Class itself
|
||||||
|
cls = next;
|
||||||
|
}
|
||||||
|
return cls is CustomClass ? this : cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: scripted safe cast for custom classes
|
||||||
|
public function getUpperclass():IHScriptCustomClassBehaviour {
|
||||||
|
if(__upperClass == null) return this;
|
||||||
|
|
||||||
|
var cls:CustomClass = cast __upperClass;
|
||||||
|
|
||||||
|
while (cls != null) {
|
||||||
|
var prev:CustomClass = cast cls.__upperClass;
|
||||||
|
if(prev == null)
|
||||||
|
break;
|
||||||
|
cls = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: scriptable "toString" function
|
||||||
|
public function toString():String
|
||||||
|
return className;
|
||||||
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides handlers for static custom class fields and instantiation.
|
||||||
|
*/
|
||||||
|
@:access(hscript.Property)
|
||||||
|
class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{
|
||||||
|
public var ogInterp:Interp;
|
||||||
|
public var name:String;
|
||||||
|
public var fields:Array<Expr>;
|
||||||
|
public var extend:Null<String>;
|
||||||
|
public var interfaces:Array<String>;
|
||||||
|
public final isFinal:Bool;
|
||||||
|
|
||||||
|
public var cl:Dynamic;
|
||||||
|
|
||||||
|
private var __interp:Interp;
|
||||||
|
private var __staticFields:Array<String> = [];
|
||||||
|
|
||||||
|
public var __allowSetGet:Bool = true;
|
||||||
|
|
||||||
|
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>, ?isFinal:Bool) {
|
||||||
|
this.ogInterp = ogInterp;
|
||||||
|
this.name = name;
|
||||||
|
this.fields = fields;
|
||||||
|
this.extend = extend;
|
||||||
|
this.interfaces = interfaces;
|
||||||
|
this.isFinal = isFinal != null ? isFinal : false;
|
||||||
|
|
||||||
|
if(extend != null) {
|
||||||
|
if(ogInterp.customClasses.exists(extend)) {
|
||||||
|
var customCls:CustomClassHandler = ogInterp.customClasses.get(extend);
|
||||||
|
if(customCls.isFinal)
|
||||||
|
ogInterp.error(ECustom('Cannot extend a final class'));
|
||||||
|
this.cl = customCls;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.cl = Type.resolveClass('${extend}_HSX');
|
||||||
|
|
||||||
|
if(cl == null)
|
||||||
|
ogInterp.error(EInvalidClass(extend));
|
||||||
|
}
|
||||||
|
|
||||||
|
initStatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
@:access(hscript.Interp)
|
||||||
|
function initStatic() {
|
||||||
|
__interp = new Interp();
|
||||||
|
__interp.errorHandler = ogInterp.errorHandler;
|
||||||
|
__interp.importFailedCallback = ogInterp.importFailedCallback;
|
||||||
|
|
||||||
|
//__interp.variables = ogInterp.variables;
|
||||||
|
__interp.usingHandler.usingEntries = ogInterp.usingHandler.usingEntries;
|
||||||
|
__interp.publicVariables = ogInterp.publicVariables;
|
||||||
|
__interp.staticVariables = ogInterp.staticVariables;
|
||||||
|
__interp.customClasses = ogInterp.customClasses;
|
||||||
|
|
||||||
|
for(f => v in ogInterp.variables)
|
||||||
|
if(!__interp.variables.exists(f))
|
||||||
|
__interp.variables.set(f, v);
|
||||||
|
|
||||||
|
for(i => e in fields.copy()) {
|
||||||
|
var isValid:Bool = false;
|
||||||
|
var staticField:Bool = false;
|
||||||
|
var fieldName:String = null;
|
||||||
|
switch (Tools.expr(e)) {
|
||||||
|
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
|
||||||
|
isValid = true;
|
||||||
|
staticField = isStatic;
|
||||||
|
fieldName = n;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if(staticField && isValid) {
|
||||||
|
__interp.exprReturn(e);
|
||||||
|
__staticFields.push(fieldName);
|
||||||
|
fields.remove(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hnew(args:Array<Dynamic>):Dynamic
|
||||||
|
return new CustomClass(this, args);
|
||||||
|
|
||||||
|
@:allow(hscript.Interp)
|
||||||
|
inline function hasField(name:String) {
|
||||||
|
return __staticFields.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getField(name:String, allowProperty:Bool = true):Dynamic {
|
||||||
|
var f = __interp.variables.get(name);
|
||||||
|
if(f is Property && allowProperty) {
|
||||||
|
var prop:Property = cast f;
|
||||||
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
|
var r = prop.get(!__allowSetGet);
|
||||||
|
//prop.__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setField(name:String, val:Dynamic):Dynamic {
|
||||||
|
var f = getField(name, false);
|
||||||
|
if(f is Property) {
|
||||||
|
var prop:Property = cast f;
|
||||||
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
|
var r = prop.set(val, !__allowSetGet);
|
||||||
|
//prop.__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
if(name == 'new') {
|
||||||
|
return Reflect.makeVarArgs(function(args:Array<Dynamic>):Dynamic {
|
||||||
|
return inline this.hnew(args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hasField(name)) {
|
||||||
|
return getField(name);
|
||||||
|
}
|
||||||
|
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
if(hasField(name))
|
||||||
|
return setField(name, val);
|
||||||
|
|
||||||
|
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNUSED
|
||||||
|
public function __callGetter(name:String):Dynamic {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is for backwards compatibility with old hscript-improved, since some scripts use it
|
||||||
|
**/
|
||||||
|
@:dox(hide)
|
||||||
|
@:keep
|
||||||
|
class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustomAccessBehaviour {
|
||||||
|
public var __interp:Interp;
|
||||||
|
public var __allowSetGet:Bool = true;
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
var variables = __interp.variables;
|
||||||
|
if(__allowSetGet && variables.exists("set_" + name))
|
||||||
|
return __callSetter(name, val);
|
||||||
|
variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
var variables = __interp.variables;
|
||||||
|
if(__allowSetGet && variables.exists("get_" + name))
|
||||||
|
return __callGetter(name);
|
||||||
|
return variables.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callGetter(name:String):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var v = __interp.variables.get("get_" + name)();
|
||||||
|
__allowSetGet = true;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var v = __interp.variables.get("set_" + name)(val);
|
||||||
|
__allowSetGet = true;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
+403
-104
@@ -1,104 +1,403 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, Nicolas Cannasse
|
* Copyright (C)2008-2017 Haxe Foundation
|
||||||
* All rights reserved.
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
*
|
* to deal in the Software without restriction, including without limitation
|
||||||
* - Redistributions of source code must retain the above copyright
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
*
|
||||||
* documentation and/or other materials provided with the distribution.
|
* The above copyright notice and this permission notice shall be included in
|
||||||
*
|
* all copies or substantial portions of the Software.
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
*
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
* DEALINGS IN THE SOFTWARE.
|
||||||
* 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
|
package hscript;
|
||||||
* DAMAGE.
|
|
||||||
*/
|
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||||
package hscript;
|
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||||
|
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||||
enum Const {
|
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||||
CInt( v : Int );
|
|
||||||
CFloat( f : Float );
|
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||||
CString( s : String );
|
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||||
#if !haxe3
|
|
||||||
CInt32( v : haxe.Int32 );
|
enum abstract Binop(Int) from Int to Int {
|
||||||
#end
|
var OpAdd = 0;
|
||||||
}
|
var OpSub = 1;
|
||||||
|
var OpMult = 2;
|
||||||
#if hscriptPos
|
var OpDiv = 3;
|
||||||
typedef Expr = {
|
var OpMod = 4;
|
||||||
var e : ExprDef;
|
var OpAnd = 5;
|
||||||
var pmin : Int;
|
var OpOr = 6;
|
||||||
var pmax : Int;
|
var OpXor = 7;
|
||||||
}
|
var OpShl = 8;
|
||||||
enum ExprDef {
|
var OpShr = 9;
|
||||||
#else
|
var OpUshr = 10;
|
||||||
enum Expr {
|
var OpEq = 11;
|
||||||
#end
|
var OpNeq = 12;
|
||||||
EConst( c : Const );
|
var OpGte = 13;
|
||||||
EIdent( v : String );
|
var OpLte = 14;
|
||||||
EVar( n : String, ?t : CType, ?e : Expr );
|
var OpGt = 15;
|
||||||
EParent( e : Expr );
|
var OpLt = 16;
|
||||||
EBlock( e : Array<Expr> );
|
var OpBoolOr = 17;
|
||||||
EField( e : Expr, f : String );
|
var OpBoolAnd = 18;
|
||||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
var OpIs = 19;
|
||||||
EUnop( op : String, prefix : Bool, e : Expr );
|
var OpAssign = 20;
|
||||||
ECall( e : Expr, params : Array<Expr> );
|
var OpNcoal = 21;
|
||||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
var OpInterval = 22;
|
||||||
EWhile( cond : Expr, e : Expr );
|
var OpArrow = 23;
|
||||||
EFor( v : String, it : Expr, e : Expr );
|
var OpAddAssign = 24;
|
||||||
EBreak;
|
var OpSubAssign = 25;
|
||||||
EContinue;
|
var OpMultAssign = 26;
|
||||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType );
|
var OpDivAssign = 27;
|
||||||
EReturn( ?e : Expr );
|
var OpModAssign = 28;
|
||||||
EArray( e : Expr, index : Expr );
|
var OpAndAssign = 29;
|
||||||
EArrayDecl( e : Array<Expr> );
|
var OpOrAssign = 30;
|
||||||
ENew( cl : String, params : Array<Expr> );
|
var OpXorAssign = 31;
|
||||||
EThrow( e : Expr );
|
var OpShlAssign = 32;
|
||||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
var OpShrAssign = 33;
|
||||||
EObject( fl : Array<{ name : String, e : Expr }> );
|
var OpUshrAssign = 34;
|
||||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
var OpNcoalAssign = 35;
|
||||||
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr);
|
var OpArrowFn = 36;
|
||||||
}
|
|
||||||
|
public static inline function fromString(s:String):Binop {
|
||||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool };
|
return switch(s) {
|
||||||
|
case "+": OpAdd;
|
||||||
enum CType {
|
case "-": OpSub;
|
||||||
CTPath( path : Array<String>, ?params : Array<CType> );
|
case "*": OpMult;
|
||||||
CTFun( args : Array<CType>, ret : CType );
|
case "/": OpDiv;
|
||||||
CTAnon( fields : Array<{ name : String, t : CType }> );
|
case "%": OpMod;
|
||||||
CTParent( t : CType );
|
case "&": OpAnd;
|
||||||
}
|
case "|": OpOr;
|
||||||
|
case "^": OpXor;
|
||||||
#if hscriptPos
|
case "<<": OpShl;
|
||||||
class Error {
|
case ">>": OpShr;
|
||||||
public var e : ErrorDef;
|
case ">>>": OpUshr;
|
||||||
public var pmin : Int;
|
case "==": OpEq;
|
||||||
public var pmax : Int;
|
case "!=": OpNeq;
|
||||||
public function new(e, pmin, pmax) {
|
case ">=": OpGte;
|
||||||
this.e = e;
|
case "<=": OpLte;
|
||||||
this.pmin = pmin;
|
case ">": OpGt;
|
||||||
this.pmax = pmax;
|
case "<": OpLt;
|
||||||
}
|
case "||": OpBoolOr;
|
||||||
}
|
case "&&": OpBoolAnd;
|
||||||
enum ErrorDef {
|
case "is": OpIs;
|
||||||
#else
|
case "=": OpAssign;
|
||||||
enum Error {
|
case "??": OpNcoal;
|
||||||
#end
|
case "...": OpInterval;
|
||||||
EInvalidChar( c : Int );
|
case "->": OpArrow;
|
||||||
EUnexpected( s : String );
|
case "=>": OpArrowFn;
|
||||||
EUnterminatedString;
|
case "+=": OpAddAssign;
|
||||||
EUnterminatedComment;
|
case "-=": OpSubAssign;
|
||||||
EUnknownVariable( v : String );
|
case "*=": OpMultAssign;
|
||||||
EInvalidIterator( v : String );
|
case "/=": OpDivAssign;
|
||||||
EInvalidOp( op : String );
|
case "%=": OpModAssign;
|
||||||
EInvalidAccess( f : String );
|
case "&=": OpAndAssign;
|
||||||
}
|
case "|=": OpOrAssign;
|
||||||
|
case "^=": OpXorAssign;
|
||||||
|
case "<<=": OpShlAssign;
|
||||||
|
case ">>=": OpShrAssign;
|
||||||
|
case ">>>=": OpUshrAssign;
|
||||||
|
case _ if (s == "??" + "="): OpNcoalAssign;
|
||||||
|
default: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function toString():String {
|
||||||
|
return switch(this) {
|
||||||
|
case OpAdd: "+";
|
||||||
|
case OpSub: "-";
|
||||||
|
case OpMult: "*";
|
||||||
|
case OpDiv: "/";
|
||||||
|
case OpMod: "%";
|
||||||
|
case OpAnd: "&";
|
||||||
|
case OpOr: "|";
|
||||||
|
case OpXor: "^";
|
||||||
|
case OpShl: "<<";
|
||||||
|
case OpShr: ">>";
|
||||||
|
case OpUshr: ">>>";
|
||||||
|
case OpEq: "==";
|
||||||
|
case OpNeq: "!=";
|
||||||
|
case OpGte: ">=";
|
||||||
|
case OpLte: "<=";
|
||||||
|
case OpGt: ">";
|
||||||
|
case OpLt: "<";
|
||||||
|
case OpBoolOr: "||";
|
||||||
|
case OpBoolAnd: "&&";
|
||||||
|
case OpIs: "is";
|
||||||
|
case OpAssign: "=";
|
||||||
|
case OpNcoal: "??";
|
||||||
|
case OpInterval: "...";
|
||||||
|
case OpArrow: "->";
|
||||||
|
case OpArrowFn: "=>";
|
||||||
|
case OpAddAssign: "+=";
|
||||||
|
case OpSubAssign: "-=";
|
||||||
|
case OpMultAssign: "*=";
|
||||||
|
case OpDivAssign: "/=";
|
||||||
|
case OpModAssign: "%=";
|
||||||
|
case OpAndAssign: "&=";
|
||||||
|
case OpOrAssign: "|=";
|
||||||
|
case OpXorAssign: "^=";
|
||||||
|
case OpShlAssign: "<<=";
|
||||||
|
case OpShrAssign: ">>=";
|
||||||
|
case OpUshrAssign: ">>>=";
|
||||||
|
case OpNcoalAssign: "??" + "=";
|
||||||
|
default: "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum abstract Unop(Int) from Int to Int {
|
||||||
|
var OpNot = 0;
|
||||||
|
var OpNeg = 1;
|
||||||
|
var OpIncrement = 2;
|
||||||
|
var OpDecrement = 3;
|
||||||
|
var OpNegBits = 4;
|
||||||
|
|
||||||
|
public static inline function fromString(s:String):Unop {
|
||||||
|
return switch(s) {
|
||||||
|
case "!": OpNot;
|
||||||
|
case "-": OpNeg;
|
||||||
|
case "++": OpIncrement;
|
||||||
|
case "--": OpDecrement;
|
||||||
|
case "~": OpNegBits;
|
||||||
|
default: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function toString():String {
|
||||||
|
return switch(this) {
|
||||||
|
case OpNot: "!";
|
||||||
|
case OpNeg: "-";
|
||||||
|
case OpIncrement: "++";
|
||||||
|
case OpDecrement: "--";
|
||||||
|
case OpNegBits: "~";
|
||||||
|
default: "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||||
|
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||||
|
|
||||||
|
enum Const {
|
||||||
|
CInt( v : Int );
|
||||||
|
CFloat( f : Float );
|
||||||
|
CString( s : String, ?i : Bool );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if hscriptPos
|
||||||
|
@:structInit
|
||||||
|
final class Expr {
|
||||||
|
public var e : ExprDef;
|
||||||
|
public var pmin : Int;
|
||||||
|
public var pmax : Int;
|
||||||
|
public var origin : String;
|
||||||
|
public var line : Int;
|
||||||
|
}
|
||||||
|
enum ExprDef {
|
||||||
|
#else
|
||||||
|
typedef ExprDef = Expr;
|
||||||
|
enum Expr {
|
||||||
|
#end
|
||||||
|
EConst( c : Const );
|
||||||
|
EIdent( v : String );
|
||||||
|
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
||||||
|
EParent( e : Expr );
|
||||||
|
EBlock( e : Array<Expr> );
|
||||||
|
EField( e : Expr, f : String , ?safe : Bool );
|
||||||
|
EBinop( op : Binop, e1 : Expr, e2 : Expr );
|
||||||
|
EUnop( op : Unop, prefix : Bool, e : Expr );
|
||||||
|
ECall( e : Expr, params : Array<Expr> );
|
||||||
|
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||||
|
EWhile( cond : Expr, e : Expr );
|
||||||
|
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||||
|
EBreak;
|
||||||
|
EContinue;
|
||||||
|
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||||
|
EReturn( ?e : Expr );
|
||||||
|
EArray( e : Expr, index : Expr );
|
||||||
|
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||||
|
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
||||||
|
EThrow( e : Expr );
|
||||||
|
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||||
|
EObject( fl : Array<ObjectField> );
|
||||||
|
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||||
|
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||||
|
EDoWhile( cond : Expr, e : Expr);
|
||||||
|
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||||
|
ECheckType( e : Expr, t : CType );
|
||||||
|
|
||||||
|
EPackage( ?n:String );
|
||||||
|
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||||
|
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||||
|
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||||
|
ECast(e:Expr, ?t:CType);
|
||||||
|
ERegex(e:String, flags:String);
|
||||||
|
}
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class ObjectField {
|
||||||
|
public var name : String;
|
||||||
|
public var e : Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class SwitchCase {
|
||||||
|
public var values : Array<Expr>;
|
||||||
|
public var expr : Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class Argument {
|
||||||
|
public var name : String;
|
||||||
|
public var t : CType;
|
||||||
|
public var opt : Bool;
|
||||||
|
public var value : Expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class MetadataEntry {
|
||||||
|
public var name : String;
|
||||||
|
public var params : Array<Expr>;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Metadata = Array<MetadataEntry>;
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class EnumDecl {
|
||||||
|
public var name : String;
|
||||||
|
public var fields : Array<EnumField>;
|
||||||
|
public var underlyingType : Null<CType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class EnumField {
|
||||||
|
public var name : String;
|
||||||
|
public var args : Array<Argument>;
|
||||||
|
public var value : Null<Expr>;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CType {
|
||||||
|
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||||
|
CTFun( args : Array<CType>, ret : CType );
|
||||||
|
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||||
|
CTParent( t : CType );
|
||||||
|
CTOpt( t : CType );
|
||||||
|
CTNamed( n : String, t : CType );
|
||||||
|
CTExpr( e : Expr ); // for type parameters only
|
||||||
|
}
|
||||||
|
|
||||||
|
#if hscriptPos
|
||||||
|
class Error {
|
||||||
|
public var e : ErrorDef;
|
||||||
|
public var pmin : Int;
|
||||||
|
public var pmax : Int;
|
||||||
|
public var origin : String;
|
||||||
|
public var line : Int;
|
||||||
|
public function new(e, pmin, pmax, origin, line) {
|
||||||
|
this.e = e;
|
||||||
|
this.pmin = pmin;
|
||||||
|
this.pmax = pmax;
|
||||||
|
this.origin = origin;
|
||||||
|
this.line = line;
|
||||||
|
}
|
||||||
|
public function toString(): String {
|
||||||
|
return Printer.errorToString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enum ErrorDef {
|
||||||
|
#else
|
||||||
|
enum Error {
|
||||||
|
#end
|
||||||
|
EInvalidChar( c : Int );
|
||||||
|
EUnexpected( s : String );
|
||||||
|
EUnterminatedString;
|
||||||
|
EUnterminatedComment;
|
||||||
|
EInvalidPreprocessor( msg : String );
|
||||||
|
EUnknownVariable( v : String );
|
||||||
|
EInvalidIterator( v : String );
|
||||||
|
EInvalidOp( op : String );
|
||||||
|
EInvalidAccess( f : String );
|
||||||
|
ECustom( msg : String );
|
||||||
|
EInvalidClass( className : String);
|
||||||
|
EAlreadyExistingClass( className : String);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum ModuleDecl {
|
||||||
|
DPackage( path : Array<String> );
|
||||||
|
DImport( path : Array<String>, ?everything : Bool );
|
||||||
|
DClass( c : ClassDecl );
|
||||||
|
DTypedef( c : TypeDecl );
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ModuleType = {
|
||||||
|
var name : String;
|
||||||
|
var params : {}; // TODO : not yet parsed
|
||||||
|
var meta : Metadata;
|
||||||
|
var isPrivate : Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ClassDecl = {> ModuleType,
|
||||||
|
var extend : Null<CType>;
|
||||||
|
var implement : Array<CType>;
|
||||||
|
var fields : Array<FieldDecl>;
|
||||||
|
var isExtern : Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef TypeDecl = {> ModuleType,
|
||||||
|
var t : CType;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef FieldDecl = {
|
||||||
|
var name : String;
|
||||||
|
var meta : Metadata;
|
||||||
|
var kind : FieldKind;
|
||||||
|
var access : Array<FieldAccess>;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum abstract FieldAccess(UInt8) {
|
||||||
|
var APublic;
|
||||||
|
var APrivate;
|
||||||
|
var AInline;
|
||||||
|
var AOverride;
|
||||||
|
var AStatic;
|
||||||
|
var AMacro;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum abstract FieldPropertyAccess(UInt8) {
|
||||||
|
var ADefault;
|
||||||
|
var ANull;
|
||||||
|
var AGet;
|
||||||
|
var ASet;
|
||||||
|
var ADynamic;
|
||||||
|
var ANever;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FieldKind {
|
||||||
|
KFunction( f : FunctionDecl );
|
||||||
|
KVar( v : VarDecl );
|
||||||
|
}
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
final class FunctionDecl {
|
||||||
|
public var args : Array<Argument>;
|
||||||
|
public var body : Expr;
|
||||||
|
public var ret : Null<CType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef VarDecl = {
|
||||||
|
var get : Null<String>;
|
||||||
|
var set : Null<String>;
|
||||||
|
var expr : Null<Expr>;
|
||||||
|
var type : Null<CType>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
import hscript.utils.UnsafeReflect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class for enums, both for real and scripted.
|
||||||
|
* Use EnumTools and EnumValueTools for enum operations.
|
||||||
|
*/
|
||||||
|
@:structInit
|
||||||
|
class HEnum implements IHScriptCustomBehaviour {
|
||||||
|
var enumValues(default, null) = {};
|
||||||
|
|
||||||
|
public function setEnum(name:String, enumValue:Dynamic):Void {
|
||||||
|
UnsafeReflect.setField(enumValues, name, enumValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEnum(name:String):Null<Dynamic> {
|
||||||
|
if (UnsafeReflect.hasField(enumValues, name))
|
||||||
|
return UnsafeReflect.field(enumValues, name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEnumValues():Dynamic {
|
||||||
|
return enumValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
return getEnum(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:nullSafety
|
||||||
|
@:structInit
|
||||||
|
class HEnumValue {
|
||||||
|
public var enumName:String;
|
||||||
|
public var fieldName:String;
|
||||||
|
public var index:Int;
|
||||||
|
public var args:Array<Dynamic>;
|
||||||
|
|
||||||
|
public function toString():String {
|
||||||
|
return '$enumName.$fieldName${args.length > 0 ? '(${[for (a in args) a].join(", ")})' : ''}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getEnumName():String
|
||||||
|
return this.enumName;
|
||||||
|
|
||||||
|
public inline function getConstructorArgs():Array<Dynamic>
|
||||||
|
return this.args;
|
||||||
|
|
||||||
|
public function compare(other:HEnumValue):Bool {
|
||||||
|
if (enumName != other.enumName || fieldName != other.fieldName)
|
||||||
|
return false;
|
||||||
|
if (args.length == 0 && other.args.length == 0)
|
||||||
|
return true;
|
||||||
|
if (args.length == 0 || other.args.length == 0)
|
||||||
|
return false;
|
||||||
|
if (args.length != other.args.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i in 0...args.length)
|
||||||
|
if (args[i] != other.args[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:nullSafety
|
||||||
|
class EnumTools {
|
||||||
|
public static function getConstructors(e:Dynamic):Array<String> {
|
||||||
|
if(Std.isOfType(e, HEnum)) {
|
||||||
|
var henum:HEnum = cast e;
|
||||||
|
return UnsafeReflect.fields(henum.getEnumValues());
|
||||||
|
}
|
||||||
|
return Type.getEnumConstructs(cast e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createByName(e:Dynamic, constr:String, ?params:Array<Dynamic>):Dynamic {
|
||||||
|
if(Std.isOfType(e, HEnum)) {
|
||||||
|
var henum:HEnum = cast e;
|
||||||
|
var constructor = henum.getEnum(constr);
|
||||||
|
if(constructor == null)
|
||||||
|
throw 'Constructor $constr not found in enum';
|
||||||
|
if(Std.isOfType(constructor, HEnumValue))
|
||||||
|
return constructor;
|
||||||
|
if(Reflect.isFunction(constructor))
|
||||||
|
return constructor(params == null ? [] : params);
|
||||||
|
throw 'Invalid constructor type';
|
||||||
|
}
|
||||||
|
return Type.createEnum(cast e, constr, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createByIndex(e:Dynamic, index:Int, ?params:Array<Dynamic>):Dynamic {
|
||||||
|
if(Std.isOfType(e, HEnum)) {
|
||||||
|
var constructors = getConstructors(e);
|
||||||
|
if(index < 0 || index >= constructors.length)
|
||||||
|
throw 'Index $index out of bounds for enum';
|
||||||
|
return createByName(e, constructors[index], params);
|
||||||
|
}
|
||||||
|
return Type.createEnumIndex(cast e, index, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@:nullSafety
|
||||||
|
class EnumValueTools {
|
||||||
|
public static function getType(e:Dynamic):Null<String> {
|
||||||
|
if(Std.isOfType(e, HEnumValue)) {
|
||||||
|
var hv:HEnumValue = cast e;
|
||||||
|
return hv.enumName;
|
||||||
|
}
|
||||||
|
var en = Type.getEnum(e);
|
||||||
|
if(en != null)
|
||||||
|
return Type.getEnumName(en);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getName(e:Dynamic):String {
|
||||||
|
if(Std.isOfType(e, HEnumValue)) {
|
||||||
|
var hv:HEnumValue = cast e;
|
||||||
|
return hv.fieldName;
|
||||||
|
}
|
||||||
|
return Type.enumConstructor(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getParameters(e:Dynamic):Array<Dynamic> {
|
||||||
|
if(Std.isOfType(e, HEnumValue)) {
|
||||||
|
var hv:HEnumValue = cast e;
|
||||||
|
return hv.args.copy();
|
||||||
|
}
|
||||||
|
return Type.enumParameters(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getIndex(e:Dynamic):Int {
|
||||||
|
if(Std.isOfType(e, HEnumValue)) {
|
||||||
|
var hv:HEnumValue = cast e;
|
||||||
|
return hv.index;
|
||||||
|
}
|
||||||
|
return Type.enumIndex(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function equals(a:Dynamic, b:Dynamic):Bool {
|
||||||
|
if(Std.isOfType(a, HEnumValue) && Std.isOfType(b, HEnumValue)) {
|
||||||
|
var hva:HEnumValue = cast a;
|
||||||
|
var hvb:HEnumValue = cast b;
|
||||||
|
return hva.compare(hvb);
|
||||||
|
}
|
||||||
|
return Type.enumEq(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function match(e:Dynamic, pattern:Dynamic):Bool {
|
||||||
|
if(Std.isOfType(e, HEnumValue)) {
|
||||||
|
var hv:HEnumValue = cast e;
|
||||||
|
if(Std.isOfType(pattern, HEnumValue)) {
|
||||||
|
var hp:HEnumValue = cast pattern;
|
||||||
|
if(hv.enumName != hp.enumName || hv.fieldName != hp.fieldName)
|
||||||
|
return false;
|
||||||
|
if(hp.args.length == 0)
|
||||||
|
return true;
|
||||||
|
if(hv.args.length != hp.args.length)
|
||||||
|
return false;
|
||||||
|
for(i in 0...hp.args.length) {
|
||||||
|
var pa = hp.args[i];
|
||||||
|
if(pa != null && hv.args[i] != pa)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(Reflect.isObject(pattern)) {
|
||||||
|
var patternName = UnsafeReflect.hasField(pattern, "name") ? UnsafeReflect.field(pattern, "name") : null;
|
||||||
|
if(patternName != null && patternName != hv.fieldName)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Type.enumEq(e, pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
// Soon...
|
||||||
|
interface IHScriptAbstractBehaviour extends IHScriptCustomBehaviour {
|
||||||
|
public var hasOp:Bool;
|
||||||
|
public var hasArr:Bool;
|
||||||
|
// @:op(A * B), @:op(A++), etc...
|
||||||
|
public function hop(kind:String, a:Dynamic, ?b:Dynamic):Dynamic;
|
||||||
|
|
||||||
|
public function harrayget(key:Dynamic):Dynamic;
|
||||||
|
public function harrayset(key:Dynamic, val:Dynamic):Dynamic;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same Interface as IHScriptCustomBehaviour but for Property.
|
||||||
|
*/
|
||||||
|
interface IHScriptCustomAccessBehaviour extends IHScriptCustomBehaviour {
|
||||||
|
var __allowSetGet:Bool;
|
||||||
|
|
||||||
|
public function __callGetter(name:String):Dynamic;
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special Interface for handling field access behaviour.
|
||||||
|
* Basically works like the operator overload `@:op(a.b)`
|
||||||
|
* for an abstract.
|
||||||
|
*/
|
||||||
|
interface IHScriptCustomBehaviour {
|
||||||
|
/**
|
||||||
|
* Field Write Access
|
||||||
|
* @param name - Field Name
|
||||||
|
* @param val - Value to assign
|
||||||
|
* @return Dynamic - The assigned value
|
||||||
|
*/
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field Read Access
|
||||||
|
* @param name - Field Name
|
||||||
|
* @return Dynamic - The returned field
|
||||||
|
*/
|
||||||
|
public function hget(name:String):Dynamic;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special Interface to make a class usable for Custom Classes.
|
||||||
|
*/
|
||||||
|
interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{
|
||||||
|
public var __interp:Interp;
|
||||||
|
public var __real_fields:Array<String>;
|
||||||
|
public var __class__fields:Array<String>;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special Interface for handling new instances of an object.
|
||||||
|
*/
|
||||||
|
interface IHScriptCustomConstructor {
|
||||||
|
public function hnew(args:Array<Dynamic>):Dynamic;
|
||||||
|
}
|
||||||
+1730
-451
File diff suppressed because it is too large
Load Diff
+63
-69
@@ -1,26 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, Nicolas Cannasse
|
* Copyright (C)2008-2017 Haxe Foundation
|
||||||
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* notice, this list of conditions and the following disclaimer.
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
* - Redistributions in binary form must reproduce the above copyright
|
* to deal in the Software without restriction, including without limitation
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
* documentation and/or other materials provided with the distribution.
|
* 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:
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE HAXE PROJECT CONTRIBUTORS "AS IS" AND ANY
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
* all copies or substantial portions of the Software.
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
*
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE HAXE PROJECT CONTRIBUTORS BE LIABLE FOR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
* DEALINGS IN THE SOFTWARE.
|
||||||
* DAMAGE.
|
|
||||||
*/
|
*/
|
||||||
package hscript;
|
package hscript;
|
||||||
import hscript.Expr.Error;
|
import hscript.Expr.Error;
|
||||||
@@ -32,23 +29,13 @@ import haxe.macro.Expr;
|
|||||||
class Macro {
|
class Macro {
|
||||||
|
|
||||||
var p : Position;
|
var p : Position;
|
||||||
#if haxe3
|
|
||||||
var binops : Map<String,Binop>;
|
var binops : Map<String,Binop>;
|
||||||
var unops : Map<String,Unop>;
|
var unops : Map<String,Unop>;
|
||||||
#else
|
|
||||||
var binops : Hash<Binop>;
|
|
||||||
var unops : Hash<Unop>;
|
|
||||||
#end
|
|
||||||
|
|
||||||
public function new(pos) {
|
public function new(pos) {
|
||||||
p = pos;
|
p = pos;
|
||||||
#if haxe3
|
|
||||||
binops = new Map();
|
binops = new Map();
|
||||||
unops = new Map();
|
unops = new Map();
|
||||||
#else
|
|
||||||
binops = new Hash();
|
|
||||||
unops = new Hash();
|
|
||||||
#end
|
|
||||||
for( c in Type.getEnumConstructs(Binop) ) {
|
for( c in Type.getEnumConstructs(Binop) ) {
|
||||||
if( c == "OpAssignOp" ) continue;
|
if( c == "OpAssignOp" ) continue;
|
||||||
var op = Type.createEnum(Binop, c);
|
var op = Type.createEnum(Binop, c);
|
||||||
@@ -76,9 +63,12 @@ class Macro {
|
|||||||
case OpMod: assign = true; "%";
|
case OpMod: assign = true; "%";
|
||||||
case OpAssignOp(_): "";
|
case OpAssignOp(_): "";
|
||||||
case OpInterval: "...";
|
case OpInterval: "...";
|
||||||
#if haxe3
|
|
||||||
case OpArrow: "=>";
|
case OpArrow: "=>";
|
||||||
|
#if (haxe_ver >= 4)
|
||||||
|
case OpIn: "in";
|
||||||
#end
|
#end
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
binops.set(str, op);
|
binops.set(str, op);
|
||||||
if( assign )
|
if( assign )
|
||||||
@@ -92,20 +82,16 @@ class Macro {
|
|||||||
case OpNegBits: "~";
|
case OpNegBits: "~";
|
||||||
case OpIncrement: "++";
|
case OpIncrement: "++";
|
||||||
case OpDecrement: "--";
|
case OpDecrement: "--";
|
||||||
|
#if (haxe_ver >= 4.2)
|
||||||
|
case OpSpread: continue;
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
unops.set(str, op);
|
unops.set(str, op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !haxe3
|
|
||||||
function isType(v:String) {
|
|
||||||
var c0 = v.charCodeAt(0);
|
|
||||||
return c0 >= 'A'.code && c0 <= 'Z'.code;
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
|
|
||||||
function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> {
|
function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> {
|
||||||
var b = new Array();
|
var b = [];
|
||||||
for( x in a )
|
for( x in a )
|
||||||
b.push(f(x));
|
b.push(f(x));
|
||||||
return b;
|
return b;
|
||||||
@@ -113,6 +99,7 @@ class Macro {
|
|||||||
|
|
||||||
function convertType( t : Expr.CType ) : ComplexType {
|
function convertType( t : Expr.CType ) : ComplexType {
|
||||||
return switch( t ) {
|
return switch( t ) {
|
||||||
|
case CTOpt(t): TOptional(convertType(t));
|
||||||
case CTPath(pack, args):
|
case CTPath(pack, args):
|
||||||
var params = [];
|
var params = [];
|
||||||
if( args != null )
|
if( args != null )
|
||||||
@@ -127,11 +114,21 @@ class Macro {
|
|||||||
case CTParent(t): TParent(convertType(t));
|
case CTParent(t): TParent(convertType(t));
|
||||||
case CTFun(args, ret):
|
case CTFun(args, ret):
|
||||||
TFunction(map(args,convertType), convertType(ret));
|
TFunction(map(args,convertType), convertType(ret));
|
||||||
|
case CTNamed(name, convertType(_) => ct):
|
||||||
|
#if (haxe_ver >= 4)
|
||||||
|
TNamed(name, ct);
|
||||||
|
#else
|
||||||
|
ct;
|
||||||
|
#end
|
||||||
case CTAnon(fields):
|
case CTAnon(fields):
|
||||||
var tf = [];
|
var tf = [];
|
||||||
for( f in fields )
|
for( f in fields ) {
|
||||||
tf.push( { name : f.name, meta : [], doc : null, access : [], kind : FVar(convertType(f.t),null), pos : p } );
|
var meta = f.meta == null ? [] : [for( m in f.meta ) { name : m.name, params : m.params == null ? [] : [for( e in m.params ) convert(e)], pos : p }];
|
||||||
|
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
|
||||||
|
}
|
||||||
TAnonymous(tf);
|
TAnonymous(tf);
|
||||||
|
case CTExpr(_):
|
||||||
|
throw "assert";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,17 +139,9 @@ class Macro {
|
|||||||
case CInt(v): CInt(Std.string(v));
|
case CInt(v): CInt(Std.string(v));
|
||||||
case CFloat(f): CFloat(Std.string(f));
|
case CFloat(f): CFloat(Std.string(f));
|
||||||
case CString(s): CString(s);
|
case CString(s): CString(s);
|
||||||
#if !haxe3
|
|
||||||
case CInt32(v): CInt(Std.string(v));
|
|
||||||
#end
|
|
||||||
});
|
});
|
||||||
case EIdent(v):
|
case EIdent(v):
|
||||||
#if !haxe3
|
EConst(CIdent(v));
|
||||||
if( isType(v) )
|
|
||||||
EConst(CType(v));
|
|
||||||
else
|
|
||||||
#end
|
|
||||||
EConst(CIdent(v));
|
|
||||||
case EVar(n, t, e):
|
case EVar(n, t, e):
|
||||||
EVars([ { name : n, expr : if( e == null ) null else convert(e), type : if( t == null ) null else convertType(t) } ]);
|
EVars([ { name : n, expr : if( e == null ) null else convert(e), type : if( t == null ) null else convertType(t) } ]);
|
||||||
case EParent(e):
|
case EParent(e):
|
||||||
@@ -160,19 +149,15 @@ class Macro {
|
|||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
EBlock(map(el,convert));
|
EBlock(map(el,convert));
|
||||||
case EField(e, f):
|
case EField(e, f):
|
||||||
#if !haxe3
|
EField(convert(e), f);
|
||||||
if( isType(f) )
|
|
||||||
EType(convert(e), f);
|
|
||||||
else
|
|
||||||
#end
|
|
||||||
EField(convert(e), f);
|
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
var b = binops.get(op);
|
var b = binops.get(op.toString());
|
||||||
if( b == null ) throw EInvalidOp(op);
|
if( b == null ) throw EInvalidOp(op.toString());
|
||||||
EBinop(b, convert(e1), convert(e2));
|
EBinop(b, convert(e1), convert(e2));
|
||||||
case EUnop(op, prefix, e):
|
case EUnop(op, prefix, e):
|
||||||
var u = unops.get(op);
|
var opStr = op.toString();
|
||||||
if( u == null ) throw EInvalidOp(op);
|
var u = unops.get(opStr);
|
||||||
|
if( u == null ) throw EInvalidOp(opStr);
|
||||||
EUnop(u, !prefix, convert(e));
|
EUnop(u, !prefix, convert(e));
|
||||||
case ECall(e, params):
|
case ECall(e, params):
|
||||||
ECall(convert(e), map(params, convert));
|
ECall(convert(e), map(params, convert));
|
||||||
@@ -180,14 +165,16 @@ class Macro {
|
|||||||
EIf(convert(c), convert(e1), e2 == null ? null : convert(e2));
|
EIf(convert(c), convert(e1), e2 == null ? null : convert(e2));
|
||||||
case EWhile(c, e):
|
case EWhile(c, e):
|
||||||
EWhile(convert(c), convert(e), true);
|
EWhile(convert(c), convert(e), true);
|
||||||
#if (haxe_211 || haxe3)
|
case EDoWhile(c, e):
|
||||||
|
EWhile(convert(c), convert(e), false);
|
||||||
case EFor(v, it, efor):
|
case EFor(v, it, efor):
|
||||||
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
#if (haxe_ver >= 4)
|
||||||
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||||
#else
|
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||||
case EFor(v, it, e):
|
#else
|
||||||
EFor(v, convert(it), convert(e));
|
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||||
#end
|
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
|
||||||
|
#end
|
||||||
case EBreak:
|
case EBreak:
|
||||||
EBreak;
|
EBreak;
|
||||||
case EContinue:
|
case EContinue:
|
||||||
@@ -201,7 +188,7 @@ class Macro {
|
|||||||
opt : false,
|
opt : false,
|
||||||
value : null,
|
value : null,
|
||||||
});
|
});
|
||||||
EFunction(name, {
|
EFunction(#if haxe4 FNamed(name,false) #else name #end, {
|
||||||
params : [],
|
params : [],
|
||||||
args : targs,
|
args : targs,
|
||||||
expr : convert(e),
|
expr : convert(e),
|
||||||
@@ -229,7 +216,14 @@ class Macro {
|
|||||||
ETernary(convert(cond), convert(e1), convert(e2));
|
ETernary(convert(cond), convert(e1), convert(e2));
|
||||||
case ESwitch(e, cases, edef):
|
case ESwitch(e, cases, edef):
|
||||||
ESwitch(convert(e), [for( c in cases ) { values : [for( v in c.values ) convert(v)], expr : convert(c.expr) } ], edef == null ? null : convert(edef));
|
ESwitch(convert(e), [for( c in cases ) { values : [for( v in c.values ) convert(v)], expr : convert(c.expr) } ], edef == null ? null : convert(edef));
|
||||||
|
case EMeta(m, params, esub):
|
||||||
|
var mpos = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||||
|
EMeta({ name : m, params : params == null ? [] : [for( p in params ) convert(p)], pos : mpos }, convert(esub));
|
||||||
|
case ECheckType(e, t):
|
||||||
|
ECheckType(convert(e), convertType(t));
|
||||||
|
default:
|
||||||
|
null;
|
||||||
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
|
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1963
-540
File diff suppressed because it is too large
Load Diff
+494
-262
@@ -1,262 +1,494 @@
|
|||||||
package hscript;
|
/*
|
||||||
import hscript.Expr;
|
* Copyright (C)2008-2017 Haxe Foundation
|
||||||
|
*
|
||||||
class Printer {
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
var buf : StringBuf;
|
* to deal in the Software without restriction, including without limitation
|
||||||
var tabs : String;
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
public function new() {
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
}
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
public function exprToString( e : Expr ) {
|
* all copies or substantial portions of the Software.
|
||||||
buf = new StringBuf();
|
*
|
||||||
tabs = "";
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
expr(e);
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
return buf.toString();
|
* 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
|
||||||
inline function add<T>(s:T) buf.add(s);
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
function type( t : CType ) {
|
*/
|
||||||
switch( t ) {
|
package hscript;
|
||||||
case CTPath(path, params):
|
import hscript.Expr;
|
||||||
add(path.join("."));
|
|
||||||
if( params != null ) {
|
class Printer {
|
||||||
add("<");
|
|
||||||
var first = true;
|
var buf : StringBuf;
|
||||||
for( p in params ) {
|
var tabs : String;
|
||||||
if( first ) first = false else add(", ");
|
|
||||||
type(p);
|
public function new() {
|
||||||
}
|
}
|
||||||
add(">");
|
|
||||||
}
|
public function exprToString( e : Expr ):String {
|
||||||
case CTFun(args, ret):
|
buf = new StringBuf();
|
||||||
if( args.length == 0 )
|
tabs = "";
|
||||||
add("Void -> ");
|
expr(e);
|
||||||
else {
|
return buf.toString();
|
||||||
for( a in args ) {
|
}
|
||||||
type(a);
|
|
||||||
add(" -> ");
|
public function typeToString( t : CType ):String {
|
||||||
}
|
buf = new StringBuf();
|
||||||
}
|
tabs = "";
|
||||||
type(ret);
|
type(t);
|
||||||
case CTAnon(fields):
|
return buf.toString();
|
||||||
add("{");
|
}
|
||||||
var first = true;
|
|
||||||
for( f in fields ) {
|
inline function add<T>(s:T):Void buf.add(s);
|
||||||
if( first ) { first = false; add(" "); } else add(", ");
|
|
||||||
add(f.name + " : ");
|
function type( t : CType ):Void {
|
||||||
type(f.t);
|
switch( t ) {
|
||||||
}
|
case CTOpt(t):
|
||||||
add(first ? "}" : " }");
|
add('?');
|
||||||
case CTParent(t):
|
type(t);
|
||||||
add("(");
|
case CTPath(path, params):
|
||||||
type(t);
|
add(path.join("."));
|
||||||
add(")");
|
if( params != null ) {
|
||||||
}
|
add("<");
|
||||||
}
|
var first = true;
|
||||||
|
for( p in params ) {
|
||||||
function addType( t : CType ) {
|
if( first ) first = false else add(", ");
|
||||||
if( t != null ) {
|
type(p);
|
||||||
add(" : ");
|
}
|
||||||
type(t);
|
add(">");
|
||||||
}
|
}
|
||||||
}
|
case CTNamed(name, t):
|
||||||
|
add(name);
|
||||||
function expr( e : Expr ) {
|
add(':');
|
||||||
if( e == null ) {
|
type(t);
|
||||||
add("??NULL??");
|
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||||
return;
|
add('(');
|
||||||
}
|
for (a in args)
|
||||||
switch( #if hscriptPos e.e #else e #end ) {
|
switch a {
|
||||||
case EConst(c):
|
case CTNamed(_, _): type(a);
|
||||||
switch( c ) {
|
default: type(CTNamed('_', a));
|
||||||
case CInt(i): add(i);
|
}
|
||||||
case CFloat(f): add(f);
|
add(')->');
|
||||||
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
type(ret);
|
||||||
}
|
case CTFun(args, ret):
|
||||||
case EIdent(v):
|
if( args.length == 0 )
|
||||||
add(v);
|
add("Void -> ");
|
||||||
case EVar(n, t, e):
|
else {
|
||||||
add("var " + n);
|
for( a in args ) {
|
||||||
addType(t);
|
type(a);
|
||||||
if( e != null ) {
|
add(" -> ");
|
||||||
add(" = ");
|
}
|
||||||
expr(e);
|
}
|
||||||
}
|
type(ret);
|
||||||
case EParent(e):
|
case CTAnon(fields):
|
||||||
add("("); expr(e); add(")");
|
add("{");
|
||||||
case EBlock(el):
|
var first = true;
|
||||||
if( el.length == 0 ) {
|
for( f in fields ) {
|
||||||
add("{}");
|
if( first ) { first = false; add(" "); } else add(", ");
|
||||||
} else {
|
add(f.name + " : ");
|
||||||
tabs += "\t";
|
type(f.t);
|
||||||
add("{\n");
|
}
|
||||||
for( e in el ) {
|
add(first ? "}" : " }");
|
||||||
add(tabs);
|
case CTParent(t):
|
||||||
expr(e);
|
add("(");
|
||||||
add(";\n");
|
type(t);
|
||||||
}
|
add(")");
|
||||||
tabs = tabs.substr(1);
|
case CTExpr(e):
|
||||||
add("}");
|
expr(e);
|
||||||
}
|
}
|
||||||
case EField(e, f):
|
}
|
||||||
expr(e);
|
|
||||||
add("." + f);
|
function addType( t : CType ):Void {
|
||||||
case EBinop(op, e1, e2):
|
if( t != null ) {
|
||||||
expr(e1);
|
add(" : ");
|
||||||
add(" " + op + " ");
|
type(t);
|
||||||
expr(e2);
|
}
|
||||||
case EUnop(op, pre, e):
|
}
|
||||||
if( pre ) {
|
|
||||||
add(op);
|
function expr( e : Expr ):Void {
|
||||||
expr(e);
|
if( e == null ) {
|
||||||
} else {
|
add("??NULL??");
|
||||||
expr(e);
|
return;
|
||||||
add(op);
|
}
|
||||||
}
|
switch(Tools.expr(e)) {
|
||||||
case ECall(e, args):
|
case EPackage(n):
|
||||||
if( e == null )
|
add('package');
|
||||||
expr(e);
|
if(n != null)
|
||||||
else switch( #if hscriptPos e.e #else e #end ) {
|
add(' $n');
|
||||||
case EField(_), EIdent(_), EConst(_):
|
add(';\n');
|
||||||
expr(e);
|
case EImport(c, n, u):
|
||||||
default:
|
add('${u ? 'using' : 'import'} $c');
|
||||||
add("(");
|
if(n != null)
|
||||||
expr(e);
|
add(' as $n');
|
||||||
add(")");
|
case EClass(name, fields, extend, interfaces, fnal):
|
||||||
}
|
var isFinal = fnal != null && fnal;
|
||||||
add("(");
|
if(isFinal)
|
||||||
var first = true;
|
add('final ');
|
||||||
for( a in args ) {
|
add('class $name');
|
||||||
if( first ) first = false else add(", ");
|
if (extend != null)
|
||||||
expr(a);
|
add(' extends $extend');
|
||||||
}
|
for(_interface in interfaces) {
|
||||||
add(")");
|
add(' implements $_interface');
|
||||||
case EIf(cond,e1,e2):
|
}
|
||||||
add("if( ");
|
tabs += "\t";
|
||||||
expr(cond);
|
add(" {\n");
|
||||||
add(" ) ");
|
for( e in fields ) {
|
||||||
expr(e1);
|
add(tabs);
|
||||||
if( e2 != null ) {
|
expr(e);
|
||||||
add(" else ");
|
//add(";\n");
|
||||||
expr(e2);
|
}
|
||||||
}
|
//for(field in fields) {
|
||||||
case EWhile(cond,e):
|
// expr(field);
|
||||||
add("while( ");
|
//}
|
||||||
expr(cond);
|
|
||||||
add(" ) ");
|
tabs = tabs.substr(1);
|
||||||
expr(e);
|
add("}");
|
||||||
case EFor(v, it, e):
|
case EEnum(en, isAbstract):
|
||||||
add("for( "+v+" in ");
|
if(isAbstract) {
|
||||||
expr(it);
|
add('enum abstract ${en.name}(');
|
||||||
add(" ) ");
|
if(en.underlyingType != null)
|
||||||
expr(e);
|
type(en.underlyingType);
|
||||||
case EBreak:
|
else
|
||||||
add("break");
|
add('Int');
|
||||||
case EContinue:
|
add(')');
|
||||||
add("continue");
|
if(en.fields.length == 0) {
|
||||||
case EFunction(params, e, name, ret):
|
add(' {}');
|
||||||
add("function");
|
return;
|
||||||
if( name != null )
|
}
|
||||||
add(" " + name);
|
tabs += "\t";
|
||||||
add("(");
|
add(" {\n");
|
||||||
var first = true;
|
for(e in en.fields) {
|
||||||
for( a in params ) {
|
add(tabs);
|
||||||
if( first ) first = false else add(", ");
|
add(e.name);
|
||||||
if( a.opt ) add("?");
|
if(e.value != null) {
|
||||||
add(a.name);
|
add(" = ");
|
||||||
addType(a.t);
|
expr(e.value);
|
||||||
}
|
}
|
||||||
add(")");
|
add(";\n");
|
||||||
addType(ret);
|
}
|
||||||
add(" ");
|
tabs = tabs.substr(1);
|
||||||
expr(e);
|
add("}");
|
||||||
case EReturn(e):
|
} else {
|
||||||
add("return");
|
add('enum ${en.name}');
|
||||||
if( e != null ) {
|
if(en.fields.length == 0) {
|
||||||
add(" ");
|
add(' {}');
|
||||||
expr(e);
|
return;
|
||||||
}
|
}
|
||||||
case EArray(e,index):
|
tabs += "\t";
|
||||||
expr(e);
|
add(" {\n");
|
||||||
add("[");
|
for(e in en.fields) {
|
||||||
expr(index);
|
add(tabs);
|
||||||
add("]");
|
add(e.name);
|
||||||
case EArrayDecl(el):
|
if(e.args.length > 0) {
|
||||||
add("[");
|
add("(");
|
||||||
var first = true;
|
var first = true;
|
||||||
for( e in el ) {
|
for( a in e.args ) {
|
||||||
if( first ) first = false else add(", ");
|
if( first ) first = false else add(", ");
|
||||||
expr(e);
|
if( a.opt ) add("?");
|
||||||
}
|
add(a.name);
|
||||||
add("]");
|
addType(a.t);
|
||||||
case ENew(cl, args):
|
}
|
||||||
add("new " + cl + "(");
|
add(')');
|
||||||
var first = true;
|
}
|
||||||
for( e in args ) {
|
add(";\n");
|
||||||
if( first ) first = false else add(", ");
|
}
|
||||||
expr(e);
|
tabs = tabs.substr(1);
|
||||||
}
|
add("}");
|
||||||
add(")");
|
}
|
||||||
case EThrow(e):
|
case ECast(e, t):
|
||||||
add("throw ");
|
var safe = t != null;
|
||||||
expr(e);
|
add("cast ");
|
||||||
case ETry(e, v, t, ecatch):
|
if(safe) add("(");
|
||||||
add("try ");
|
expr(e);
|
||||||
expr(e);
|
if(safe) {
|
||||||
add(" catch( " + v);
|
add(", ");
|
||||||
addType(t);
|
addType(t);
|
||||||
add(") ");
|
add(")");
|
||||||
expr(ecatch);
|
}
|
||||||
case EObject(fl):
|
case ERegex(e, f):
|
||||||
if( fl.length == 0 ) {
|
add('~/$e/$f');
|
||||||
add("{}");
|
add(';\n');
|
||||||
} else {
|
case EConst(c):
|
||||||
tabs += "\t";
|
switch( c ) {
|
||||||
add("{\n");
|
case CInt(i): add(i);
|
||||||
for( f in fl ) {
|
case CFloat(f): add(f);
|
||||||
add(tabs);
|
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
||||||
add(f.name+" : ");
|
}
|
||||||
expr(f.e);
|
case EIdent(v):
|
||||||
add(",\n");
|
add(v);
|
||||||
}
|
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
|
||||||
tabs = tabs.substr(1);
|
if(p) add("public ");
|
||||||
add("}");
|
else if(pr) add("private ");
|
||||||
}
|
if(s) add("static ");
|
||||||
case ETernary(c,e1,e2):
|
if(isInline) add("inline ");
|
||||||
expr(c);
|
if(isFinal) add("final " + n);
|
||||||
add(" ? ");
|
else add("var " + n);
|
||||||
expr(e1);
|
|
||||||
add(" : ");
|
if(get != null || set != null) {
|
||||||
expr(e2);
|
add("(");
|
||||||
case ESwitch(e, cases, def):
|
switch(get) {
|
||||||
add("switch( ");
|
case ADefault: add("default, ");
|
||||||
expr(e);
|
case ANull: add("null, ");
|
||||||
add(") {");
|
case AGet: add("get, ");
|
||||||
for( c in cases ) {
|
case ADynamic: add("dynamic, ");
|
||||||
add("case ");
|
case ANever: add("never, ");
|
||||||
var first = true;
|
default:
|
||||||
for( v in c.values ) {
|
}
|
||||||
if( first ) first = false else add(", ");
|
switch(set) {
|
||||||
expr(v);
|
case ADefault: add("default");
|
||||||
}
|
case ANull: add("null");
|
||||||
add(": ");
|
case ASet: add("set");
|
||||||
expr(c.expr);
|
case ADynamic: add("dynamic");
|
||||||
add(";\n");
|
case ANever: add("never");
|
||||||
}
|
default:
|
||||||
if( def != null ) {
|
}
|
||||||
add("default: ");
|
add(")");
|
||||||
expr(def);
|
}
|
||||||
add(";\n");
|
|
||||||
}
|
addType(t);
|
||||||
add("}");
|
if( e != null ) {
|
||||||
}
|
add(" = ");
|
||||||
}
|
expr(e);
|
||||||
|
}
|
||||||
public static function toString( e : Expr ) {
|
case EParent(e):
|
||||||
return new Printer().exprToString(e);
|
add("("); expr(e); add(")");
|
||||||
}
|
case EBlock(el):
|
||||||
|
if( el.length == 0 ) {
|
||||||
}
|
add("{}");
|
||||||
|
} else {
|
||||||
|
tabs += "\t";
|
||||||
|
add("{\n");
|
||||||
|
for( e in el ) {
|
||||||
|
add(tabs);
|
||||||
|
expr(e);
|
||||||
|
add(";\n");
|
||||||
|
}
|
||||||
|
tabs = tabs.substr(1);
|
||||||
|
add("}");
|
||||||
|
}
|
||||||
|
case EField(e, f, s):
|
||||||
|
expr(e);
|
||||||
|
add((s == true ? "?." : ".") + f);
|
||||||
|
case EBinop(op, e1, e2):
|
||||||
|
expr(e1);
|
||||||
|
add(" " + op.toString() + " ");
|
||||||
|
expr(e2);
|
||||||
|
case EUnop(op, pre, e):
|
||||||
|
if( pre ) {
|
||||||
|
add(op);
|
||||||
|
expr(e);
|
||||||
|
} else {
|
||||||
|
expr(e);
|
||||||
|
add(op);
|
||||||
|
}
|
||||||
|
case ECall(e, args):
|
||||||
|
if( e == null )
|
||||||
|
expr(e);
|
||||||
|
else switch( Tools.expr(e)) {
|
||||||
|
case EField(_), EIdent(_), EConst(_):
|
||||||
|
expr(e);
|
||||||
|
default:
|
||||||
|
add("(");
|
||||||
|
expr(e);
|
||||||
|
add(")");
|
||||||
|
}
|
||||||
|
add("(");
|
||||||
|
var first = true;
|
||||||
|
for( a in args ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
expr(a);
|
||||||
|
}
|
||||||
|
add(")");
|
||||||
|
case EIf(cond,e1,e2):
|
||||||
|
add("if( ");
|
||||||
|
expr(cond);
|
||||||
|
add(" ) ");
|
||||||
|
expr(e1);
|
||||||
|
if( e2 != null ) {
|
||||||
|
add(" else ");
|
||||||
|
expr(e2);
|
||||||
|
}
|
||||||
|
case EWhile(cond,e):
|
||||||
|
add("while( ");
|
||||||
|
expr(cond);
|
||||||
|
add(" ) ");
|
||||||
|
expr(e);
|
||||||
|
case EDoWhile(cond,e):
|
||||||
|
add("do ");
|
||||||
|
expr(e);
|
||||||
|
add(" while ( ");
|
||||||
|
expr(cond);
|
||||||
|
add(" )");
|
||||||
|
case EFor(v, it, e, ithv):
|
||||||
|
if(ithv != null)
|
||||||
|
add("for( "+ithv+" => "+v+" in ");
|
||||||
|
else
|
||||||
|
add("for( "+v+" in ");
|
||||||
|
expr(it);
|
||||||
|
add(" ) ");
|
||||||
|
expr(e);
|
||||||
|
case EBreak:
|
||||||
|
add("break");
|
||||||
|
case EContinue:
|
||||||
|
add("continue");
|
||||||
|
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||||
|
add("function");
|
||||||
|
if( name != null )
|
||||||
|
add(" " + name);
|
||||||
|
add("(");
|
||||||
|
var first = true;
|
||||||
|
for( a in params ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
if( a.opt ) add("?");
|
||||||
|
add(a.name);
|
||||||
|
addType(a.t);
|
||||||
|
}
|
||||||
|
add(")");
|
||||||
|
addType(ret);
|
||||||
|
add(" ");
|
||||||
|
expr(e);
|
||||||
|
case EReturn(e):
|
||||||
|
add("return");
|
||||||
|
if( e != null ) {
|
||||||
|
add(" ");
|
||||||
|
expr(e);
|
||||||
|
}
|
||||||
|
case EArray(e,index):
|
||||||
|
expr(e);
|
||||||
|
add("[");
|
||||||
|
expr(index);
|
||||||
|
add("]");
|
||||||
|
case EArrayDecl(el, _):
|
||||||
|
add("[");
|
||||||
|
var first = true;
|
||||||
|
for( e in el ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
expr(e);
|
||||||
|
}
|
||||||
|
add("]");
|
||||||
|
case ENew(cl, args, params):
|
||||||
|
add("new " + cl);
|
||||||
|
if(params != null) {
|
||||||
|
add("<");
|
||||||
|
var first = true;
|
||||||
|
for( p in params ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
type(p);
|
||||||
|
}
|
||||||
|
add(">");
|
||||||
|
}
|
||||||
|
add("(");
|
||||||
|
var first = true;
|
||||||
|
for( e in args ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
expr(e);
|
||||||
|
}
|
||||||
|
add(")");
|
||||||
|
case EThrow(e):
|
||||||
|
add("throw ");
|
||||||
|
expr(e);
|
||||||
|
case ETry(e, v, t, ecatch):
|
||||||
|
add("try ");
|
||||||
|
expr(e);
|
||||||
|
add(" catch( " + v);
|
||||||
|
addType(t);
|
||||||
|
add(") ");
|
||||||
|
expr(ecatch);
|
||||||
|
case EObject(fl):
|
||||||
|
if( fl.length == 0 ) {
|
||||||
|
add("{}");
|
||||||
|
} else {
|
||||||
|
tabs += "\t";
|
||||||
|
add("{\n");
|
||||||
|
for( f in fl ) {
|
||||||
|
add(tabs);
|
||||||
|
add(f.name+" : ");
|
||||||
|
expr(f.e);
|
||||||
|
add(",\n");
|
||||||
|
}
|
||||||
|
tabs = tabs.substr(1);
|
||||||
|
add("}");
|
||||||
|
}
|
||||||
|
case ETernary(c,e1,e2):
|
||||||
|
expr(c);
|
||||||
|
add(" ? ");
|
||||||
|
expr(e1);
|
||||||
|
add(" : ");
|
||||||
|
expr(e2);
|
||||||
|
case ESwitch(e, cases, def):
|
||||||
|
add("switch( ");
|
||||||
|
expr(e);
|
||||||
|
add(") {");
|
||||||
|
for( c in cases ) {
|
||||||
|
add("case ");
|
||||||
|
var first = true;
|
||||||
|
for( v in c.values ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
expr(v);
|
||||||
|
}
|
||||||
|
add(": ");
|
||||||
|
expr(c.expr);
|
||||||
|
add(";\n");
|
||||||
|
}
|
||||||
|
if( def != null ) {
|
||||||
|
add("default: ");
|
||||||
|
expr(def);
|
||||||
|
add(";\n");
|
||||||
|
}
|
||||||
|
add("}");
|
||||||
|
case EMeta(name, args, e):
|
||||||
|
add("@");
|
||||||
|
add(name);
|
||||||
|
if( args != null && args.length > 0 ) {
|
||||||
|
add("(");
|
||||||
|
var first = true;
|
||||||
|
for( a in args ) {
|
||||||
|
if( first ) first = false else add(", ");
|
||||||
|
expr(e);
|
||||||
|
}
|
||||||
|
add(")");
|
||||||
|
}
|
||||||
|
add(" ");
|
||||||
|
expr(e);
|
||||||
|
case ECheckType(e, t):
|
||||||
|
add("(");
|
||||||
|
expr(e);
|
||||||
|
add(" : ");
|
||||||
|
addType(t);
|
||||||
|
add(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toString( e : Expr ):String {
|
||||||
|
return new Printer().exprToString(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function errorToString( e : Expr.Error ):String {
|
||||||
|
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||||
|
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||||
|
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||||
|
case EUnterminatedString: "Unterminated string";
|
||||||
|
case EUnterminatedComment: "Unterminated comment";
|
||||||
|
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||||
|
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||||
|
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||||
|
case EInvalidOp(op): "Invalid operator: "+op;
|
||||||
|
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||||
|
case ECustom(msg): msg;
|
||||||
|
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||||
|
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||||
|
};
|
||||||
|
#if hscriptPos
|
||||||
|
return e.origin + ":" + e.line + ": " + message;
|
||||||
|
#else
|
||||||
|
return message;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
import hscript.utils.UnsafeReflect;
|
||||||
|
import hscript.Interp;
|
||||||
|
import hscript.Expr.FieldPropertyAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special variable that handles 'getter/setter' function calls
|
||||||
|
* depending of the read/write access combination.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ```haxe
|
||||||
|
* public var myvar(get, set):Int;
|
||||||
|
* var _myvar:Int = 10;
|
||||||
|
*
|
||||||
|
* function get_myvar():Int {
|
||||||
|
* return _myvar;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* function set_myvar(val:Int):Int {
|
||||||
|
* if(val > 10) return _myvar = val;
|
||||||
|
* return val;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @see https://haxe.org/manual/class-field-property.html
|
||||||
|
*/
|
||||||
|
@:access(hscript.Interp)
|
||||||
|
class Property {
|
||||||
|
private static inline var GET = 'get_';
|
||||||
|
private static inline var SET = 'set_';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the attached field.
|
||||||
|
*/
|
||||||
|
public final name:String;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current value. If isn't initialized, it's always `null`.
|
||||||
|
*/
|
||||||
|
public var r:Dynamic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The getter property kind
|
||||||
|
*/
|
||||||
|
public final getter:FieldPropertyAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The setter property kind
|
||||||
|
*/
|
||||||
|
public final setter:FieldPropertyAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the field is declared as static.
|
||||||
|
*/
|
||||||
|
public var isStatic(get, never):Bool;
|
||||||
|
function get_isStatic() {
|
||||||
|
return __isStatic && interp.allowStaticVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isVar:Bool;
|
||||||
|
var interp:Interp;
|
||||||
|
|
||||||
|
@:allow(hscript.Interp)
|
||||||
|
private var getterFunc(get, never):String;
|
||||||
|
private inline function get_getterFunc():String {
|
||||||
|
return '$GET$name';
|
||||||
|
}
|
||||||
|
|
||||||
|
@:allow(hscript.Interp)
|
||||||
|
private var setterFunc(get, never):String;
|
||||||
|
private inline function get_setterFunc():String {
|
||||||
|
return '$SET$name';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function new(name:String, r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic:Bool, interp:Interp) {
|
||||||
|
this.name = name;
|
||||||
|
this.r = r;
|
||||||
|
this.getter = getter;
|
||||||
|
this.setter = setter;
|
||||||
|
this.isVar = isVar;
|
||||||
|
this.__isStatic = isStatic;
|
||||||
|
this.interp = interp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal flags to gain access to the current field value (if isn't a property field)
|
||||||
|
var __allowReadAccess:Bool = false;
|
||||||
|
var __allowWriteAccess:Bool = false;
|
||||||
|
// Internal flag to gain access if the field is accessed with @:bypassAccessor
|
||||||
|
var __allowSetGet:Bool = true;
|
||||||
|
|
||||||
|
final __isStatic:Bool = false;
|
||||||
|
|
||||||
|
public function get(isBypassAccessor:Bool) {
|
||||||
|
if(isBypassAccessor) __allowSetGet = false;
|
||||||
|
var r:Dynamic = callGetter();
|
||||||
|
if(isBypassAccessor) __allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set(value:Dynamic, isBypassAccessor:Bool) {
|
||||||
|
if(isBypassAccessor) __allowSetGet = false;
|
||||||
|
var r:Dynamic = callSetter(value);
|
||||||
|
if(isBypassAccessor) __allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function callGetter():Dynamic {
|
||||||
|
switch (getter) {
|
||||||
|
case AGet | ADynamic:
|
||||||
|
var fName:String = getterFunc;
|
||||||
|
if (!__allowReadAccess && __allowSetGet) {
|
||||||
|
if (varExists(fName)) {
|
||||||
|
return callAccessor(fName);
|
||||||
|
} else
|
||||||
|
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||||
|
} else {
|
||||||
|
if ((setter == ADefault || setter == ANull) || isVar) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||||
|
}
|
||||||
|
case ANever:
|
||||||
|
interp.error(ECustom('This expression cannot be accessed for reading'));
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function callSetter(val:Dynamic):Dynamic {
|
||||||
|
switch (setter) {
|
||||||
|
case ASet | ADynamic:
|
||||||
|
var fName:String = setterFunc;
|
||||||
|
if (!__allowWriteAccess && __allowSetGet) {
|
||||||
|
if (varExists(fName))
|
||||||
|
return callAccessor(fName, true, val);
|
||||||
|
else
|
||||||
|
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||||
|
} else {
|
||||||
|
if ((getter == ADefault || getter == ANull) || isVar) {
|
||||||
|
return r = val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||||
|
}
|
||||||
|
case ANever:
|
||||||
|
interp.error(ECustom('This expression cannot be accessed for writing'));
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
return r = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function callAccessor(f:String, isWrite:Bool = false, ?value:Dynamic):Dynamic {
|
||||||
|
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
|
||||||
|
var rt:Dynamic = null;
|
||||||
|
if (fn != null && Reflect.isFunction(fn)) {
|
||||||
|
if (isWrite) __allowWriteAccess = true;
|
||||||
|
else __allowReadAccess = true;
|
||||||
|
|
||||||
|
rt = UnsafeReflect.callMethodUnsafe(null, fn, isWrite ? [value] : []);
|
||||||
|
|
||||||
|
if (isWrite) __allowWriteAccess = false;
|
||||||
|
else __allowReadAccess = false;
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
} else
|
||||||
|
interp.error(ECustom('Method $f required by property ${f.substr(3)} is missing'));
|
||||||
|
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline function varExists(n:String) {
|
||||||
|
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
+143
-65
@@ -1,66 +1,144 @@
|
|||||||
package hscript;
|
/*
|
||||||
import hscript.Expr;
|
* Copyright (C)2008-2017 Haxe Foundation
|
||||||
|
*
|
||||||
class Tools {
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
* to deal in the Software without restriction, including without limitation
|
||||||
switch( e ) {
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
case EConst(_), EIdent(_):
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
case EVar(_, _, e): if( e != null ) f(e);
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
case EParent(e): f(e);
|
*
|
||||||
case EBlock(el): for( e in el ) f(e);
|
* The above copyright notice and this permission notice shall be included in
|
||||||
case EField(e, _): f(e);
|
* all copies or substantial portions of the Software.
|
||||||
case EBinop(_, e1, e2): f(e1); f(e2);
|
*
|
||||||
case EUnop(_, _, e): f(e);
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
case ECall(e, args): f(e); for( a in args ) f(a);
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
case EWhile(c, e): f(c); f(e);
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
case EFor(_, it, e): f(it); f(e);
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
case EBreak,EContinue:
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
case EFunction(_, e, _, _): f(e);
|
* DEALINGS IN THE SOFTWARE.
|
||||||
case EReturn(e): if( e != null ) f(e);
|
*/
|
||||||
case EArray(e, i): f(e); f(i);
|
package hscript;
|
||||||
case EArrayDecl(el): for( e in el ) f(e);
|
import hscript.Expr;
|
||||||
case ENew(_,el): for( e in el ) f(e);
|
|
||||||
case EThrow(e): f(e);
|
class Tools {
|
||||||
case ETry(e, _, _, c): f(e); f(c);
|
|
||||||
case EObject(fl): for( fi in fl ) f(fi.e);
|
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||||
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
switch( expr(e) ) {
|
||||||
case ESwitch(e, cases, def):
|
case EConst(_), EIdent(_):
|
||||||
f(e);
|
case EImport(c): f(e);
|
||||||
for( c in cases ) {
|
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||||
for( v in c.values ) f(v);
|
case EVar(_, _, e): if( e != null ) f(e);
|
||||||
f(c.expr);
|
case EParent(e): f(e);
|
||||||
}
|
case EBlock(el): for( e in el ) f(e);
|
||||||
if( def != null ) f(def);
|
case EField(e, _): f(e);
|
||||||
}
|
case EBinop(_, e1, e2): f(e1); f(e2);
|
||||||
}
|
case EUnop(_, _, e): f(e);
|
||||||
|
case ECall(e, args): f(e); for( a in args ) f(a);
|
||||||
public static function map( e : Expr, f : Expr -> Expr ) {
|
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
||||||
return switch( e ) {
|
case EWhile(c, e): f(c); f(e);
|
||||||
case EConst(_), EIdent(_): e;
|
case EDoWhile(c, e): f(c); f(e);
|
||||||
case EVar(n, t, e): EVar(n, t, if( e != null ) f(e) else null);
|
case EFor(_, it, e): f(it); f(e);
|
||||||
case EParent(e): EParent(f(e));
|
case EBreak,EContinue:
|
||||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
case EFunction(_, e, _, _): f(e);
|
||||||
case EField(e, fi): EField(f(e),fi);
|
case EReturn(e): if( e != null ) f(e);
|
||||||
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
case EArray(e, i): f(e); f(i);
|
||||||
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
case EArrayDecl(el): for( e in el ) f(e);
|
||||||
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
case ENew(_,el): for( e in el ) f(e);
|
||||||
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
case EThrow(e): f(e);
|
||||||
case EWhile(c, e): EWhile(f(c),f(e));
|
case ETry(e, _, _, c): f(e); f(c);
|
||||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
case EObject(fl): for( fi in fl ) f(fi.e);
|
||||||
case EBreak, EContinue: e;
|
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
||||||
case EFunction(args, e, name, t): EFunction(args, f(e), name, t);
|
case ESwitch(e, cases, def):
|
||||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
f(e);
|
||||||
case EArray(e, i): EArray(f(e),f(i));
|
for( c in cases ) {
|
||||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
for( v in c.values ) f(v);
|
||||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
f(c.expr);
|
||||||
case EThrow(e): EThrow(f(e));
|
}
|
||||||
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
if( def != null ) f(def);
|
||||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
case ECheckType(e,_): f(e);
|
||||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
||||||
|
var edef = switch( expr(e) ) {
|
||||||
|
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||||
|
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
||||||
|
case EParent(e): EParent(f(e));
|
||||||
|
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||||
|
case EField(e, fi): EField(f(e),fi);
|
||||||
|
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
||||||
|
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
||||||
|
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
||||||
|
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
||||||
|
case EWhile(c, e): EWhile(f(c),f(e));
|
||||||
|
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||||
|
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||||
|
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
||||||
|
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||||
|
case EArray(e, i): EArray(f(e),f(i));
|
||||||
|
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||||
|
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||||
|
case EThrow(e): EThrow(f(e));
|
||||||
|
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
||||||
|
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||||
|
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||||
|
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||||
|
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||||
|
case ECheckType(e,t): ECheckType(f(e), t);
|
||||||
|
case EImport(c): EImport(c);
|
||||||
|
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||||
|
default: expr(e);
|
||||||
|
}
|
||||||
|
return mk(edef, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static inline function expr( e : Expr ) : ExprDef {
|
||||||
|
#if hscriptPos
|
||||||
|
return e.e;
|
||||||
|
#else
|
||||||
|
return e;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
||||||
|
#if hscriptPos
|
||||||
|
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||||
|
#else
|
||||||
|
return e;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT USE INLINE ON THIS FUNCTION
|
||||||
|
**/
|
||||||
|
public static function argCount(func: haxe.Constraints.Function): Int {
|
||||||
|
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
|
||||||
|
#if cpp
|
||||||
|
return untyped __cpp__("{0}->__ArgCount()", func);
|
||||||
|
#elseif js
|
||||||
|
return untyped js.Syntax.code("{0}.length", func);
|
||||||
|
#elseif hl
|
||||||
|
var ft = hl.Type.getDynamic(func);
|
||||||
|
if (ft.kind != HFun)
|
||||||
|
return -1;
|
||||||
|
return ft.getArgsCount();
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isUppercase(s:String) {
|
||||||
|
if(s.length == 0) return false;
|
||||||
|
var c:Int = StringTools.fastCodeAt(s, 0);
|
||||||
|
if(StringTools.isEof(c)) return false; // Just in case :3
|
||||||
|
return c >= 65 && c <= 90; // A-Z
|
||||||
|
}
|
||||||
|
|
||||||
|
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
||||||
|
return obj != null && obj is IHScriptAbstractBehaviour;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package hscript.macros;
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
import Type.ValueType;
|
||||||
|
import haxe.macro.ComplexTypeTools;
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
import haxe.macro.Context;
|
||||||
|
import haxe.macro.Printer;
|
||||||
|
import haxe.macro.Compiler;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
class AbstractHandler {
|
||||||
|
public static function init() {
|
||||||
|
#if HSCRIPT_ABSTRACT_SUPPORT
|
||||||
|
#if !display
|
||||||
|
if(Context.defined("display")) return;
|
||||||
|
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||||
|
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function build():Array<Field> {
|
||||||
|
var fields = Context.getBuildFields();
|
||||||
|
var clRef = Context.getLocalClass();
|
||||||
|
if (clRef == null) return fields;
|
||||||
|
var cl = clRef.get();
|
||||||
|
|
||||||
|
if (/* cl.name.startsWith("Flx") && */ cl.name.endsWith("_Impl_") && cl.params.length <= 0 && !cl.meta.has(":multiType") && !cl.name.contains("_HSC")) {
|
||||||
|
var metas = cl.meta.get();
|
||||||
|
|
||||||
|
var trimEnum = cl.name.substr(0, cl.name.length - 6);
|
||||||
|
|
||||||
|
var key = cl.module;
|
||||||
|
var fkey = cl.module + "." + trimEnum;
|
||||||
|
if(key == "lime.system.Locale") return fields; // Error: Unknown identifier : currentLocale, Due to Func
|
||||||
|
if(key == "cpp.Function") return fields; // Error: Unknown identifier : nativeGetProcAddress, Due to Func
|
||||||
|
if(key == "haxe.ds.Vector") return fields; // Error: haxe.ds._Vector.VectorData<blit.T> has no field blit, Due to Func
|
||||||
|
if(key == "haxe.display.Display") return fields; // Error: haxe.display.DisplayItemKind<haxe.display.DisplayLiteral<Dynamic>> has no field Null, Due to Func
|
||||||
|
if(key == "cpp.Callable") return fields; // Error: cpp.Function.fromStaticFunction must be called on static function, Due to Func
|
||||||
|
if(key == "haxe.display.JsonAnonStatusKind") return fields; // Error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *', Due to Func
|
||||||
|
if(key == "cpp.CharStar") return fields; // Error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *', Due to Func
|
||||||
|
if(Config.DISALLOW_ABSTRACT_AND_ENUM.contains(cl.module) || Config.DISALLOW_ABSTRACT_AND_ENUM.contains(fkey)) return fields;
|
||||||
|
if(cl.module.contains("_")) return fields; // Weird issue, sorry
|
||||||
|
|
||||||
|
var shadowClass = macro class {
|
||||||
|
|
||||||
|
};
|
||||||
|
shadowClass.kind = TDClass();
|
||||||
|
shadowClass.params = switch(cl.params.length) {
|
||||||
|
case 0:
|
||||||
|
null;
|
||||||
|
case 1:
|
||||||
|
[{
|
||||||
|
name: "T",
|
||||||
|
}];
|
||||||
|
default:
|
||||||
|
[for(k=>e in cl.params) {
|
||||||
|
name: "T" + Std.int(k+1)
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
shadowClass.name = '${cl.name.substr(0, cl.name.length - 6)}_HSC';
|
||||||
|
|
||||||
|
var imports = Context.getLocalImports().copy();
|
||||||
|
Utils.setupMetas(shadowClass, imports);
|
||||||
|
//trace(cl.module);
|
||||||
|
|
||||||
|
for(f in fields)
|
||||||
|
switch(f.kind) {
|
||||||
|
case FFun(fun):
|
||||||
|
if (f.access.contains(AStatic)) {
|
||||||
|
if (fun.expr != null) {
|
||||||
|
fun.expr = macro @:privateAccess $e{fun.expr};
|
||||||
|
shadowClass.fields.push(f);
|
||||||
|
|
||||||
|
/*var trimEnum = cl.name.substr(0, cl.name.length - 6);
|
||||||
|
|
||||||
|
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
|
||||||
|
|
||||||
|
var name = f.name;
|
||||||
|
|
||||||
|
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
|
||||||
|
|
||||||
|
var expr:Expr = Context.parse('${returns?"return " : ""} $trimEnum.$name(${[for(a in fun.args) a.name].join(", ")})', f.pos);
|
||||||
|
|
||||||
|
var func:Function = {
|
||||||
|
ret: fun.ret,
|
||||||
|
params: fun.params.copy(),
|
||||||
|
expr: expr,
|
||||||
|
args: fun.args.copy()
|
||||||
|
};
|
||||||
|
|
||||||
|
var field:Field = {
|
||||||
|
pos: f.pos,
|
||||||
|
name: f.name,
|
||||||
|
meta: f.meta,
|
||||||
|
kind: FFun(func),
|
||||||
|
doc: null,//f.doc,
|
||||||
|
access: [APublic, AStatic]
|
||||||
|
}
|
||||||
|
shadowClass.fields.push(field);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FProp(get, set, t, e):
|
||||||
|
if (get == "default" && (set == "never" || set == "null")) {
|
||||||
|
shadowClass.fields.push(f);
|
||||||
|
}
|
||||||
|
case FVar(t, e):
|
||||||
|
if (f.access.contains(AStatic) || cl.meta.has(":enum") || f.name.toUpperCase() == f.name) {
|
||||||
|
var name:String = f.name;
|
||||||
|
var enumType:String = cl.name;
|
||||||
|
var pack = cl.module.split(".");
|
||||||
|
|
||||||
|
//trace(pack, cl.name, name, cl.module);
|
||||||
|
|
||||||
|
if(pack[pack.length - 1] == trimEnum)
|
||||||
|
pack.pop();
|
||||||
|
|
||||||
|
var complexType:ComplexType = t;
|
||||||
|
if(complexType == null && e != null) {
|
||||||
|
complexType = switch(e.expr) {
|
||||||
|
case EConst(CRegexp(_)): TPath({ name: "EReg", pack: [] });
|
||||||
|
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(complexType == null) {
|
||||||
|
complexType = TPath({
|
||||||
|
name: trimEnum,
|
||||||
|
pack: [],//pack
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var code = Context.parse('@:privateAccess ($trimEnum.$name)', f.pos); // '${pack.join(".")}.${trimEnum}.$name'
|
||||||
|
|
||||||
|
var field:Field = {
|
||||||
|
pos: f.pos,
|
||||||
|
name: f.name,
|
||||||
|
meta: f.meta,
|
||||||
|
kind: FVar(null, code),
|
||||||
|
doc: f.doc,
|
||||||
|
access: [APublic, AStatic]
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowClass.fields.push(field);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
//var printer = new Printer();
|
||||||
|
//for(field in shadowClass.fields)
|
||||||
|
// trace(printer.printField(field));
|
||||||
|
|
||||||
|
Context.defineModule(cl.module, [shadowClass], imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
@@ -0,0 +1,711 @@
|
|||||||
|
package hscript.macros;
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
import haxe.macro.Type.ClassType;
|
||||||
|
import Type.ValueType;
|
||||||
|
import haxe.macro.Expr.Function;
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
import haxe.macro.Type.MetaAccess;
|
||||||
|
import haxe.macro.Type.FieldKind;
|
||||||
|
import haxe.macro.Type.ClassField;
|
||||||
|
import haxe.macro.Type.VarAccess;
|
||||||
|
import haxe.macro.*;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
// BIG TODO: make typed classes scriptable
|
||||||
|
class ClassExtendMacro {
|
||||||
|
public static inline final FUNC_PREFIX = "_HX_SUPER__";
|
||||||
|
public static inline final CLASS_SUFFIX = "_HSX";
|
||||||
|
|
||||||
|
public static var unallowedMetas:Array<String> = [":bitmap", ":noCustomClass", ":generic"];
|
||||||
|
|
||||||
|
public static var modifiedClasses:Array<String> = [];
|
||||||
|
|
||||||
|
public static function init() {
|
||||||
|
#if !display
|
||||||
|
#if CUSTOM_CLASSES
|
||||||
|
if(Context.defined("display")) return;
|
||||||
|
for(apply in Config.ALLOWED_CUSTOM_CLASSES) {
|
||||||
|
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())");
|
||||||
|
}
|
||||||
|
//Context.onAfterTyping(buildTyped);
|
||||||
|
#end
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function build():Array<Field> {
|
||||||
|
var fields = Context.getBuildFields();
|
||||||
|
var clRef = Context.getLocalClass();
|
||||||
|
if (clRef == null) return fields;
|
||||||
|
var cl = clRef.get();
|
||||||
|
|
||||||
|
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface) return fields;
|
||||||
|
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC")) {
|
||||||
|
var metas = cl.meta.get();
|
||||||
|
|
||||||
|
for(m in metas)
|
||||||
|
if (unallowedMetas.contains(m.name))
|
||||||
|
return fields;
|
||||||
|
|
||||||
|
if(cl.params.length > 0)
|
||||||
|
return fields;
|
||||||
|
|
||||||
|
var key = cl.module;
|
||||||
|
var fkey = cl.module + "." + cl.name;
|
||||||
|
if(key == "sys.thread.FixedThreadPool") return fields; // Error: Type name sys.thread.Worker_HSX is redefined from module sys.thread.FixedThreadPool
|
||||||
|
if(key == "StdTypes") return fields; // Error: Cant extend basic class
|
||||||
|
if(key == "Xml") return fields; // Error: Cant extend basic class
|
||||||
|
if(key == "Date") return fields; // Error: Cant extend basic class
|
||||||
|
if(key == "away3d.tools.commands.Mirror") return fields; // Error: Unknown identifier
|
||||||
|
if(key == "away3d.tools.commands.SphereMaker") return fields; // Error: Unknown identifier
|
||||||
|
if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier
|
||||||
|
if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined
|
||||||
|
if(fkey == "hscript.CustomClassHandler.CustomTemplateClass") return fields; // Error: Redefined
|
||||||
|
if(fkey == "hscript.CustomClass") return fields; // Error: Redefined
|
||||||
|
if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined
|
||||||
|
if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields;
|
||||||
|
if(cl.module.contains("_")) return fields; // Weird issue, sorry
|
||||||
|
|
||||||
|
var superFields = [];
|
||||||
|
if(false && cl.superClass != null) {
|
||||||
|
var _superFields = cl.superClass.t.get().fields.get();
|
||||||
|
_superFields = []; // Comment to enable super support, (broken)
|
||||||
|
|
||||||
|
function convertField(field:ClassField) {
|
||||||
|
try {
|
||||||
|
var nfield = FixedTypeTools.toSimpleField(field);
|
||||||
|
switch ([field.kind, field.type]) {
|
||||||
|
case [FMethod(kind), TFun(args, ret)]:
|
||||||
|
if(kind == MethInline)
|
||||||
|
nfield.access.push(AInline);
|
||||||
|
if(kind == MethDynamic)
|
||||||
|
nfield.access.push(ADynamic);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(nfield.kind) {
|
||||||
|
case FFun(fun):
|
||||||
|
if (fun.params != null && fun.params.length > 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
//sfun.ret = Utils.fixStdTypes(fun.ret);
|
||||||
|
|
||||||
|
var metas = nfield.meta;
|
||||||
|
var defaultValues:Map<String, Dynamic> = [];
|
||||||
|
var defaultEntry = null;
|
||||||
|
var isGeneric = false;
|
||||||
|
for(m in metas) {
|
||||||
|
if(m.name == ":value") {
|
||||||
|
defaultEntry = m;
|
||||||
|
switch(m.params[0].expr) {
|
||||||
|
case EObjectDecl(fields):
|
||||||
|
for(fil in fields)
|
||||||
|
defaultValues[fil.field] = fil.expr;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(m.name == ":generic")
|
||||||
|
isGeneric = true;
|
||||||
|
}
|
||||||
|
if(isGeneric) return null;
|
||||||
|
|
||||||
|
if(defaultEntry != null)
|
||||||
|
metas.remove(defaultEntry);
|
||||||
|
|
||||||
|
for(arg in fun.args) {
|
||||||
|
var opt = false;
|
||||||
|
if(defaultValues.exists(arg.name)) {
|
||||||
|
arg.value = defaultValues[arg.name];
|
||||||
|
arg.opt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg.type = null;//Utils.fixStdTypes(arg.type);
|
||||||
|
|
||||||
|
//if(arg.opt) {
|
||||||
|
// if(arg.type.getParameters()[0].name != "Null")
|
||||||
|
// arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>};
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace(nfield.name);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return nfield;
|
||||||
|
} catch(e) {
|
||||||
|
trace(field.name, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var didPrint = false;
|
||||||
|
|
||||||
|
var fieldNames = [for(f in fields) f.name];
|
||||||
|
|
||||||
|
/*for(field in _superFields) {
|
||||||
|
if(fieldNames.contains(field.name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(field.name.startsWith("get_")) {
|
||||||
|
var access = FixedTypeTools.getAccess(field);
|
||||||
|
if(access.contains(AInline) || access.contains(AFinal) || field.isFinal)
|
||||||
|
continue;
|
||||||
|
var name = field.name;
|
||||||
|
superFields.push({
|
||||||
|
name: field.name,
|
||||||
|
pos: field.pos,
|
||||||
|
kind: FFun({
|
||||||
|
ret: null,
|
||||||
|
params: [],
|
||||||
|
expr: macro {
|
||||||
|
return super.$name();
|
||||||
|
},
|
||||||
|
args: []
|
||||||
|
}),
|
||||||
|
access: access,
|
||||||
|
meta: field.meta.get(),
|
||||||
|
});
|
||||||
|
//var f = convertField(field);
|
||||||
|
//if(f != null)
|
||||||
|
// superFields.push(f);
|
||||||
|
if(field.name == "get_bgColor") {
|
||||||
|
if(!didPrint) {
|
||||||
|
trace(cl.name);
|
||||||
|
didPrint = true;
|
||||||
|
}
|
||||||
|
trace("> " + field.name + " : " + access, field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// want to get this working
|
||||||
|
/*for(field in _superFields) {
|
||||||
|
if(fieldNames.contains(field.name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var f = convertField(field);
|
||||||
|
if(f != null)
|
||||||
|
superFields.push(f);
|
||||||
|
}*/
|
||||||
|
//superFields = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var shadowClass = macro class {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var definedFields:Array<String> = [];
|
||||||
|
|
||||||
|
//trace(getModuleName(cl));
|
||||||
|
|
||||||
|
var hasNew = false;
|
||||||
|
|
||||||
|
for(_field in [fields.copy(), superFields.copy()])
|
||||||
|
for(f in _field) {
|
||||||
|
if (f == null)
|
||||||
|
continue;
|
||||||
|
if (f.name == "new") {
|
||||||
|
hasNew = true;
|
||||||
|
switch (f.kind) {
|
||||||
|
case FFun(fn):
|
||||||
|
var constructor:Field = buildConstructor(fn.args);
|
||||||
|
|
||||||
|
shadowClass.fields.push(constructor);
|
||||||
|
definedFields.push(f.name);
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (f.name.startsWith(FUNC_PREFIX))
|
||||||
|
continue;
|
||||||
|
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline) || f.access.contains(AFinal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(f.name == "hget" || f.name == "hset") continue; // sorry, no overwriting the hget and hset in custom classes, yet
|
||||||
|
if(definedFields.contains(f.name)) continue; // no duplicate fields
|
||||||
|
|
||||||
|
for(m in f.meta)
|
||||||
|
if (unallowedMetas.contains(m.name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch(f.kind) {
|
||||||
|
case FFun(fun):
|
||||||
|
if (fun == null)
|
||||||
|
continue;
|
||||||
|
if (fun.params != null && fun.params.length > 0) // TODO: Support for this maybe?
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(fun.params == null)
|
||||||
|
fun.params = [];
|
||||||
|
|
||||||
|
var overrideExpr:Expr;
|
||||||
|
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
|
||||||
|
|
||||||
|
var name = f.name;
|
||||||
|
|
||||||
|
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
|
||||||
|
|
||||||
|
if (returns) {
|
||||||
|
overrideExpr = macro {
|
||||||
|
var name:String = $v{name};
|
||||||
|
|
||||||
|
if (__interp != null && __class__fields.contains(name)) {
|
||||||
|
var v:Dynamic = null;
|
||||||
|
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||||
|
return v($a{arguments});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.$name($a{arguments});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
overrideExpr = macro {
|
||||||
|
var name:String = $v{name};
|
||||||
|
|
||||||
|
if (__interp != null && __class__fields.contains(name)) {
|
||||||
|
var v:Dynamic = null;
|
||||||
|
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||||
|
v($a{arguments});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.$name($a{arguments});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var superFuncExpr:Expr = returns ? {
|
||||||
|
macro return super.$name($a{arguments});
|
||||||
|
} : {
|
||||||
|
macro super.$name($a{arguments});
|
||||||
|
};
|
||||||
|
|
||||||
|
var func:Function = {
|
||||||
|
ret: fun.ret,
|
||||||
|
params: fun.params.copy(),
|
||||||
|
expr: overrideExpr,
|
||||||
|
args: fun.args.copy()
|
||||||
|
};
|
||||||
|
|
||||||
|
var overrideField:Field = {
|
||||||
|
name: f.name,
|
||||||
|
access: f.access.copy(),
|
||||||
|
kind: FFun(func),
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
doc: f.doc,
|
||||||
|
meta: f.meta.copy()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!overrideField.access.contains(AOverride))
|
||||||
|
overrideField.access.push(AOverride);
|
||||||
|
|
||||||
|
var superField:Field = {
|
||||||
|
name: '$FUNC_PREFIX${f.name}',
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FFun({
|
||||||
|
ret: fun.ret,
|
||||||
|
params: fun.params.copy(),
|
||||||
|
expr: superFuncExpr,
|
||||||
|
args: fun.args.copy()
|
||||||
|
}),
|
||||||
|
access: f.access.copy()
|
||||||
|
};
|
||||||
|
if (superField.access.contains(AOverride))
|
||||||
|
superField.access.remove(AOverride);
|
||||||
|
shadowClass.fields.push(overrideField);
|
||||||
|
shadowClass.fields.push(superField);
|
||||||
|
definedFields.push(f.name);
|
||||||
|
default:
|
||||||
|
// fuck off >:(
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalFields = definedFields.length;
|
||||||
|
|
||||||
|
if(totalFields == 0 && !hasNew) {
|
||||||
|
//Sys.println(cl.pack.join(".") + "." + cl.name + ", " + totalFields);
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowClass.kind = TDClass({
|
||||||
|
pack: cl.pack.copy(),
|
||||||
|
name: cl.name
|
||||||
|
}, [
|
||||||
|
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
|
||||||
|
], false, true, false);
|
||||||
|
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
||||||
|
var imports = Context.getLocalImports().copy();
|
||||||
|
Utils.setupMetas(shadowClass, imports);
|
||||||
|
Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect");
|
||||||
|
|
||||||
|
// Adding hscript getters and setters
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__cachedFieldSet",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: Map<String, Dynamic>),
|
||||||
|
access: [APublic, AStatic]
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__interp",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: hscript.Interp),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__custom__variables",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: Map<String, Dynamic>),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__allowSetGet",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: Bool, macro true),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__real_fields",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: Array<String>),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__class__fields",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: Array<String>),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__callGetter",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FFun({
|
||||||
|
ret: macro: Dynamic,
|
||||||
|
params: [],
|
||||||
|
expr: macro {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: macro: String
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__callSetter",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FFun({
|
||||||
|
ret: macro: Dynamic,
|
||||||
|
params: [],
|
||||||
|
expr: macro {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: macro: String
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "val",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: macro: Dynamic
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Todo: make it possible to override
|
||||||
|
if(cl.name == "FunkinShader" || cl.name == "CustomShader" || cl.name == "MultiThreadedScript") {
|
||||||
|
Context.defineModule(cl.module, [shadowClass], imports);
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasHgetInSuper = false;
|
||||||
|
var hasHsetInSuper = false;
|
||||||
|
|
||||||
|
if(cl.name == "CustomShader") {
|
||||||
|
hasHgetInSuper = hasHsetInSuper = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: somehow check the super super class
|
||||||
|
for(_field in [fields.copy(), superFields.copy()])
|
||||||
|
for(f in _field) {
|
||||||
|
if (f.name == "new")
|
||||||
|
continue;
|
||||||
|
if (f.name.startsWith(FUNC_PREFIX))
|
||||||
|
continue;
|
||||||
|
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch(f.kind) {
|
||||||
|
case FFun(fun):
|
||||||
|
if (fun.params != null && fun.params.length > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!hasHgetInSuper)
|
||||||
|
hasHgetInSuper = f.name == "hget";
|
||||||
|
if(!hasHsetInSuper)
|
||||||
|
hasHsetInSuper = f.name == "hset";
|
||||||
|
|
||||||
|
if(hasHgetInSuper && hasHsetInSuper)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hgetField = if(hasHgetInSuper) {
|
||||||
|
macro {
|
||||||
|
if (__interp != null) {
|
||||||
|
if(__class__fields.contains(name)) {
|
||||||
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
|
if(v != null && v is hscript.Property)
|
||||||
|
return cast(v, hscript.Property).get(ba);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
else @:privateAccess {
|
||||||
|
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||||
|
while(cls != null) {
|
||||||
|
if(cls.hasField(name))
|
||||||
|
return cls.getField(name);
|
||||||
|
|
||||||
|
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||||
|
if(prev == null)
|
||||||
|
break;
|
||||||
|
cls = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.hget(name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
macro {
|
||||||
|
if (__interp != null) {
|
||||||
|
if(__class__fields.contains(name)) {
|
||||||
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
|
if(v != null && v is hscript.Property)
|
||||||
|
return cast(v, hscript.Property).get(ba);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
else @:privateAccess {
|
||||||
|
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||||
|
while(cls != null) {
|
||||||
|
if(cls.hasField(name))
|
||||||
|
return cls.getField(name);
|
||||||
|
|
||||||
|
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||||
|
if(prev == null)
|
||||||
|
break;
|
||||||
|
cls = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnsafeReflect.getProperty(this, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hsetField = if(hasHsetInSuper) {
|
||||||
|
macro {
|
||||||
|
if (__interp != null) {
|
||||||
|
if(__class__fields.contains(name)) {
|
||||||
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
|
if(v != null && v is hscript.Property)
|
||||||
|
return cast(v, hscript.Property).set(val, ba);
|
||||||
|
__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else @:privateAccess {
|
||||||
|
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||||
|
while(cls != null) {
|
||||||
|
if(cls.hasField(name))
|
||||||
|
return cls.setField(name, val);
|
||||||
|
|
||||||
|
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||||
|
if(prev == null)
|
||||||
|
break;
|
||||||
|
cls = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(__real_fields.contains(name)) {
|
||||||
|
UnsafeReflect.setProperty(this, name, val);
|
||||||
|
return UnsafeReflect.field(this, name);
|
||||||
|
}
|
||||||
|
return super.hset(name, val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
macro {
|
||||||
|
if (__interp != null) {
|
||||||
|
if(__class__fields.contains(name)) {
|
||||||
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
|
if(v != null && v is hscript.Property)
|
||||||
|
return cast(v, hscript.Property).set(val, ba);
|
||||||
|
__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else @:privateAccess {
|
||||||
|
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||||
|
while(cls != null) {
|
||||||
|
if(cls.hasField(name))
|
||||||
|
return cls.setField(name, val);
|
||||||
|
|
||||||
|
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||||
|
if(prev == null)
|
||||||
|
break;
|
||||||
|
cls = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(__real_fields.contains(name)) {
|
||||||
|
UnsafeReflect.setProperty(this, name, val);
|
||||||
|
return UnsafeReflect.field(this, name);
|
||||||
|
}
|
||||||
|
//__custom__variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(hasHsetInSuper || hasHgetInSuper) return fields;
|
||||||
|
|
||||||
|
//trace(cl.name);
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "hset",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
access: hasHsetInSuper ? [AOverride, APublic] : [APublic],
|
||||||
|
kind: FFun({
|
||||||
|
ret: macro: Dynamic,
|
||||||
|
params: [],
|
||||||
|
expr: hsetField,
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: macro: String
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "val",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: macro: Dynamic
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "hget",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
access: hasHgetInSuper ? [AOverride, APublic] : [APublic],
|
||||||
|
kind: FFun({
|
||||||
|
ret: macro: Dynamic,
|
||||||
|
params: [],
|
||||||
|
expr: hgetField,
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: macro: String
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/*var p = new Printer();
|
||||||
|
var aa = p.printTypeDefinition(shadowClass);
|
||||||
|
if(aa.length < 5024)
|
||||||
|
trace(aa);
|
||||||
|
if(aa.indexOf("pack") >= 0)
|
||||||
|
if(cl.name == "FunkinShader")*/
|
||||||
|
|
||||||
|
Context.defineModule(cl.module, [shadowClass], imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function buildConstructor(constArgs:Array<FunctionArg>):Field {
|
||||||
|
var superCallArgs:Array<Expr> = [for (arg in constArgs) macro $i{arg.name}];
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'new',
|
||||||
|
access: [APublic],
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FFun({
|
||||||
|
args: constArgs,
|
||||||
|
expr: macro {
|
||||||
|
// Call the super constructor with appropriate args
|
||||||
|
super($a{superCallArgs});
|
||||||
|
|
||||||
|
if(__cachedFieldSet != null) {
|
||||||
|
for(k => v in __cachedFieldSet) {
|
||||||
|
Reflect.setProperty(this, k, v);
|
||||||
|
}
|
||||||
|
__cachedFieldSet.clear();
|
||||||
|
__cachedFieldSet = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static function buildTyped(modules:Array<haxe.macro.Type.ModuleType>) {
|
||||||
|
for(m in modules) {
|
||||||
|
switch(m) {
|
||||||
|
case TClassDecl(c):
|
||||||
|
var cl = c.get();
|
||||||
|
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface)
|
||||||
|
continue;
|
||||||
|
if (cl.params.length == 0)
|
||||||
|
continue;
|
||||||
|
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC"))
|
||||||
|
buildTypedClass(cl);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function buildTypedClass(cl:ClassType) {}
|
||||||
|
|
||||||
|
static function buildShadowClass(cl:ClassType) {}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
class ClassExtendMacro {
|
||||||
|
public var usedClass:Class<Dynamic>;
|
||||||
|
public var className:String;
|
||||||
|
}
|
||||||
|
#end
|
||||||
@@ -0,0 +1,529 @@
|
|||||||
|
package hscript.macros;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C)2005-2019 Haxe Foundation
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import haxe.macro.Context;
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
import haxe.macro.Type;
|
||||||
|
import Type as StdType;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
|
||||||
|
/**
|
||||||
|
This class provides some utility methods to work with types. It is
|
||||||
|
best used through 'using haxe.macro.TypeTools' syntax and then provides
|
||||||
|
additional methods on haxe.macro.Type instances.
|
||||||
|
**/
|
||||||
|
#if hl
|
||||||
|
@:hlNative("macro")
|
||||||
|
#end
|
||||||
|
class FixedTypeTools {
|
||||||
|
static function nullable(complexType:ComplexType):ComplexType
|
||||||
|
return macro:Null<$complexType>;
|
||||||
|
|
||||||
|
public static function toField(cf:ClassField):Field {
|
||||||
|
function varAccessToString(va:VarAccess, getOrSet:String):String {
|
||||||
|
return {
|
||||||
|
switch (va) {
|
||||||
|
case AccNormal | AccCtor: "default";
|
||||||
|
case AccNo: "null";
|
||||||
|
case AccNever: "never";
|
||||||
|
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
|
||||||
|
case AccCall: getOrSet;
|
||||||
|
case AccInline: "default";
|
||||||
|
case AccRequire(_, _): "default";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var access = cf.isPublic ? [APublic] : [APrivate];
|
||||||
|
if (cf.meta.has(":final")) {
|
||||||
|
access.push(AFinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cf.params.length != 0)
|
||||||
|
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: cf.name,
|
||||||
|
doc: cf.doc,
|
||||||
|
access: access,
|
||||||
|
kind: switch ([cf.kind, cf.type]) {
|
||||||
|
case [FVar(read, write), ret]:
|
||||||
|
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
|
||||||
|
case [FMethod(_), TFun(args, ret)]:
|
||||||
|
Sys.println("Converting " + cf.name);
|
||||||
|
FFun({
|
||||||
|
args: [
|
||||||
|
for (a in args)
|
||||||
|
{
|
||||||
|
name: a.name,
|
||||||
|
opt: a.opt,
|
||||||
|
type: toComplexType(a.t),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
ret: toComplexType(ret),
|
||||||
|
expr: null,
|
||||||
|
});
|
||||||
|
case [FMethod(_), TLazy(f)]:
|
||||||
|
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
|
||||||
|
switch(f()) {
|
||||||
|
case TFun(args, ret):
|
||||||
|
FFun({
|
||||||
|
args: [
|
||||||
|
for (a in args)
|
||||||
|
{
|
||||||
|
name: a.name,
|
||||||
|
opt: a.opt,
|
||||||
|
type: toComplexType(a.t),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
ret: toComplexType(ret),
|
||||||
|
expr: null,
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||||
|
},
|
||||||
|
pos: cf.pos,
|
||||||
|
meta: cf.meta.get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAccess(cf:ClassField):Array<Access> {
|
||||||
|
var access = cf.isPublic ? [APublic] : [APrivate];
|
||||||
|
if (cf.meta.has(":final") || cf.isFinal) {
|
||||||
|
access.push(AFinal);
|
||||||
|
}
|
||||||
|
switch ([cf.kind, cf.type]) {
|
||||||
|
case [FMethod(kind), TFun(_, _)] | [FMethod(kind), TLazy(_)]:
|
||||||
|
if(kind == MethInline)
|
||||||
|
access.push(AInline);
|
||||||
|
if(kind == MethDynamic)
|
||||||
|
access.push(ADynamic);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toSimpleField(cf:ClassField):Field {
|
||||||
|
function varAccessToString(va:VarAccess, getOrSet:String):String {
|
||||||
|
return {
|
||||||
|
switch (va) {
|
||||||
|
case AccNormal | AccCtor: "default";
|
||||||
|
case AccNo: "null";
|
||||||
|
case AccNever: "never";
|
||||||
|
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
|
||||||
|
case AccCall: getOrSet;
|
||||||
|
case AccInline: "default";
|
||||||
|
case AccRequire(_, _): "default";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var access = cf.isPublic ? [APublic] : [APrivate];
|
||||||
|
if (cf.meta.has(":final")) {
|
||||||
|
access.push(AFinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cf.params.length != 0)
|
||||||
|
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: cf.name,
|
||||||
|
doc: cf.doc,
|
||||||
|
access: access,
|
||||||
|
kind: switch ([cf.kind, cf.type]) {
|
||||||
|
case [FVar(read, write), ret]:
|
||||||
|
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
|
||||||
|
case [FMethod(_), TFun(args, ret)]:
|
||||||
|
Sys.println("Converting " + cf.name);
|
||||||
|
FFun({
|
||||||
|
args: [
|
||||||
|
for (a in args)
|
||||||
|
{
|
||||||
|
name: a.name,
|
||||||
|
opt: a.opt,
|
||||||
|
type: null,//toComplexType(a.t),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
ret: null,//toComplexType(ret),
|
||||||
|
expr: null,
|
||||||
|
});
|
||||||
|
case [FMethod(_), TLazy(f)]:
|
||||||
|
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
|
||||||
|
switch(f()) {
|
||||||
|
case TFun(args, ret):
|
||||||
|
FFun({
|
||||||
|
args: [
|
||||||
|
for (a in args)
|
||||||
|
{
|
||||||
|
name: a.name,
|
||||||
|
opt: a.opt,
|
||||||
|
type: null,//toComplexType(a.t),
|
||||||
|
}
|
||||||
|
],
|
||||||
|
ret: null,//toComplexType(ret),
|
||||||
|
expr: null,
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
|
||||||
|
},
|
||||||
|
pos: cf.pos,
|
||||||
|
meta: cf.meta.get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a syntax-level type corresponding to Type `t`.
|
||||||
|
|
||||||
|
This function is mostly inverse to `ComplexTypeTools.toType`, but may
|
||||||
|
lose some information on types that do not have a corresponding syntax
|
||||||
|
version, such as monomorphs. In these cases, the result is null.
|
||||||
|
|
||||||
|
If `t` is null, an internal exception is thrown.
|
||||||
|
**/
|
||||||
|
public static function toComplexType(type:Null<Type>):Null<ComplexType>
|
||||||
|
return {
|
||||||
|
#if macro
|
||||||
|
Context.toComplexType(type);
|
||||||
|
#else
|
||||||
|
switch (type) {
|
||||||
|
case null:
|
||||||
|
null;
|
||||||
|
case TMono(_.get() => t):
|
||||||
|
t == null ? null : toComplexType(t);
|
||||||
|
case TEnum(_.get() => baseType, params):
|
||||||
|
TPath(toTypePath(baseType, params));
|
||||||
|
case TInst(_.get() => classType, params):
|
||||||
|
switch (classType.kind) {
|
||||||
|
case KTypeParameter(_):
|
||||||
|
TPath({
|
||||||
|
name: classType.name,
|
||||||
|
pack: [],
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
TPath(toTypePath(classType, params));
|
||||||
|
}
|
||||||
|
case TType(_.get() => baseType, params):
|
||||||
|
TPath(toTypePath(baseType, params));
|
||||||
|
case TFun(args, ret):
|
||||||
|
TFunction([for (a in args) a.opt ? nullable(toComplexType(a.t)) : toComplexType(a.t)], toComplexType(ret));
|
||||||
|
case TAnonymous(_.get() => {fields: fields}):
|
||||||
|
TAnonymous([for (cf in fields) toField(cf)]);
|
||||||
|
case TDynamic(t):
|
||||||
|
if (t == null) {
|
||||||
|
macro:Dynamic;
|
||||||
|
} else {
|
||||||
|
var ct = toComplexType(t);
|
||||||
|
macro:Dynamic<$ct>;
|
||||||
|
}
|
||||||
|
case TLazy(f):
|
||||||
|
toComplexType(f());
|
||||||
|
case TAbstract(_.get() => baseType, params):
|
||||||
|
TPath(toTypePath(baseType, params));
|
||||||
|
default:
|
||||||
|
throw "Invalid type";
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
static function toTypeParam(type:Type):TypeParam
|
||||||
|
return {
|
||||||
|
switch (type) {
|
||||||
|
case TInst(_.get() => {kind: KExpr(e)}, _): TPExpr(e);
|
||||||
|
case _: TPType(toComplexType(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function toTypePath(baseType:BaseType, params:Array<Type>):TypePath
|
||||||
|
return {
|
||||||
|
var module = baseType.module;
|
||||||
|
{
|
||||||
|
pack: baseType.pack,
|
||||||
|
name: module.substring(module.lastIndexOf(".") + 1),
|
||||||
|
sub: baseType.name,
|
||||||
|
params: [for (t in params) toTypeParam(t)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
/**
|
||||||
|
Follows all typedefs of `t` to reach the actual type.
|
||||||
|
|
||||||
|
If `once` is true, this function does not call itself recursively,
|
||||||
|
otherwise it does. This can be useful in cases where intermediate
|
||||||
|
typedefs might be of interest.
|
||||||
|
|
||||||
|
Affected types are monomorphs `TMono` and typedefs `TType(t,pl)`.
|
||||||
|
|
||||||
|
If `t` is null, an internal exception is thrown.
|
||||||
|
|
||||||
|
Usage example with monomorphs:
|
||||||
|
var t = Context.typeof(macro null); // TMono(<mono>)
|
||||||
|
var ts = Context.typeof(macro "foo"); //TInst(String,[])
|
||||||
|
Context.unify(t, ts);
|
||||||
|
trace(t); // TMono(<mono>)
|
||||||
|
trace(t.follow()); //TInst(String,[])
|
||||||
|
|
||||||
|
Usage example with typedefs:
|
||||||
|
var t = Context.typeof(macro ("foo" :MyString)); // typedef MyString = String
|
||||||
|
trace(t); // TType(MyString,[])
|
||||||
|
trace(t.follow()); //TInst(String,[])
|
||||||
|
**/
|
||||||
|
static public inline function follow(t:Type, ?once:Bool):Type
|
||||||
|
return Context.follow(t, once);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Like `follow`, follows all typedefs of `t` to reach the actual type.
|
||||||
|
|
||||||
|
Will however follow also abstracts to their underlying implementation,
|
||||||
|
if they are not a @:coreType abstract
|
||||||
|
|
||||||
|
If `t` is null, an internal exception is thrown.
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
var t = Context.typeof(macro new Map<String, String>());
|
||||||
|
trace(t); // TAbstract(Map,[TInst(String,[]),TInst(String,[])])
|
||||||
|
trace(t.followWithAbstracts()); // TInst(haxe.ds.StringMap, [TInst(String,[])])
|
||||||
|
**/
|
||||||
|
static public inline function followWithAbstracts(t:Type, once:Bool = false):Type
|
||||||
|
return Context.followWithAbstracts(t, once);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true if `t1` and `t2` unify, false otherwise.
|
||||||
|
**/
|
||||||
|
static public inline function unify(t1:Type, t2:Type):Bool
|
||||||
|
return Context.unify(t1, t2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Tries to extract the class instance stored inside `t`.
|
||||||
|
|
||||||
|
If `t` is a class instance `TInst(c,pl)`, c is returned.
|
||||||
|
|
||||||
|
If `t` is of a different type, an exception of type String is thrown.
|
||||||
|
|
||||||
|
If `t` is null, the result is null.
|
||||||
|
**/
|
||||||
|
static public function getClass(t:Type)
|
||||||
|
return t == null ? null : switch (follow(t)) {
|
||||||
|
case TInst(c, _): c.get();
|
||||||
|
case _: throw "Class instance expected";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Tries to extract the enum instance stored inside `t`.
|
||||||
|
|
||||||
|
If `t` is an enum instance `TEnum(e,pl)`, e is returned.
|
||||||
|
|
||||||
|
If `t` is of a different type, an exception of type String is thrown.
|
||||||
|
|
||||||
|
If `t` is null, the result is null.
|
||||||
|
**/
|
||||||
|
static public function getEnum(t:Type)
|
||||||
|
return t == null ? null : switch (follow(t)) {
|
||||||
|
case TEnum(e, _): e.get();
|
||||||
|
case _: throw "Enum instance expected";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Applies the type parameters `typeParameters` to type `t` with the given
|
||||||
|
types `concreteTypes`.
|
||||||
|
|
||||||
|
This function replaces occurrences of type parameters in `t` if they are
|
||||||
|
part of `typeParameters`. The array index of such a type parameter is
|
||||||
|
then used to lookup the concrete type in `concreteTypes`.
|
||||||
|
|
||||||
|
If `typeParameters.length` is not equal to `concreteTypes.length`, an
|
||||||
|
exception of type `String` is thrown.
|
||||||
|
|
||||||
|
If `typeParameters.length` is 0, `t` is returned unchanged.
|
||||||
|
|
||||||
|
If either argument is `null`, the result is unspecified.
|
||||||
|
**/
|
||||||
|
static public function applyTypeParameters(t:Type, typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>):Type {
|
||||||
|
if (typeParameters.length != concreteTypes.length)
|
||||||
|
throw 'Incompatible arguments: ${typeParameters.length} type parameters and ${concreteTypes.length} concrete types';
|
||||||
|
else if (typeParameters.length == 0)
|
||||||
|
return t;
|
||||||
|
#if (neko || eval)
|
||||||
|
return @:privateAccess Context.load("apply_params", 3)(typeParameters, concreteTypes, t);
|
||||||
|
#else
|
||||||
|
return applyParams(typeParameters, concreteTypes, t);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !neko
|
||||||
|
private static function applyParams(typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>, t:Type):Type {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
/**
|
||||||
|
Transforms `t` by calling `f` on each of its subtypes.
|
||||||
|
|
||||||
|
If `t` is a compound type, `f` is called on each of its components.
|
||||||
|
|
||||||
|
Otherwise `t` is returned unchanged.
|
||||||
|
|
||||||
|
The following types are considered compound:
|
||||||
|
- TInst, TEnum, TType and TAbstract with type parameters
|
||||||
|
- TFun
|
||||||
|
- TAnonymous
|
||||||
|
|
||||||
|
If `t` or `f` are null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
static public function map(t:Type, f:Type->Type):Type {
|
||||||
|
return switch (t) {
|
||||||
|
case TMono(tm):
|
||||||
|
switch (tm.get()) {
|
||||||
|
case null: t;
|
||||||
|
case var t: f(t);
|
||||||
|
}
|
||||||
|
case TEnum(_, []) | TInst(_, []) | TType(_, []):
|
||||||
|
t;
|
||||||
|
case TEnum(en, tl):
|
||||||
|
TEnum(en, tl.map(f));
|
||||||
|
case TInst(cl, tl):
|
||||||
|
TInst(cl, tl.map(f));
|
||||||
|
case TType(t2, tl):
|
||||||
|
TType(t2, tl.map(f));
|
||||||
|
case TAbstract(a, tl):
|
||||||
|
TAbstract(a, tl.map(f));
|
||||||
|
case TFun(args, ret):
|
||||||
|
TFun(args.map(function(arg) return {
|
||||||
|
name: arg.name,
|
||||||
|
opt: arg.opt,
|
||||||
|
t: f(arg.t)
|
||||||
|
}), f(ret));
|
||||||
|
case TAnonymous(an):
|
||||||
|
TAnonymous(@:privateAccess Context.load("map_anon_ref", 2)(an, f));
|
||||||
|
case TDynamic(t2):
|
||||||
|
t == t2 ? t : TDynamic(f(t2));
|
||||||
|
case TLazy(ft):
|
||||||
|
var ft = ft();
|
||||||
|
var ft2 = f(ft);
|
||||||
|
ft == ft2 ? t : ft2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Calls function `f` on each component of type `t`.
|
||||||
|
|
||||||
|
If `t` is not a compound type, this operation has no effect.
|
||||||
|
|
||||||
|
The following types are considered compound:
|
||||||
|
- TInst, TEnum, TType and TAbstract with type parameters
|
||||||
|
- TFun
|
||||||
|
- TAnonymous
|
||||||
|
|
||||||
|
If `t` or `f` are null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
static public function iter(t:Type, f:Type->Void):Void {
|
||||||
|
switch (t) {
|
||||||
|
case TMono(tm):
|
||||||
|
var t = tm.get();
|
||||||
|
if (t != null)
|
||||||
|
f(t);
|
||||||
|
case TEnum(_, tl) | TInst(_, tl) | TType(_, tl) | TAbstract(_, tl):
|
||||||
|
for (t in tl)
|
||||||
|
f(t);
|
||||||
|
case TDynamic(t2):
|
||||||
|
if (t != t2)
|
||||||
|
f(t2);
|
||||||
|
case TLazy(ft):
|
||||||
|
f(ft());
|
||||||
|
case TAnonymous(an):
|
||||||
|
for (field in an.get().fields)
|
||||||
|
f(field.type);
|
||||||
|
case TFun(args, ret):
|
||||||
|
for (arg in args)
|
||||||
|
f(arg.t);
|
||||||
|
f(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Converts type `t` to a human-readable String representation.
|
||||||
|
**/
|
||||||
|
static public function toString(t:Type):String {
|
||||||
|
#if (neko || eval)
|
||||||
|
return @:privateAccess Context.load("s_type", 1)(t);
|
||||||
|
#else
|
||||||
|
return null;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Changes the name of the variable in the typed expression.
|
||||||
|
**/
|
||||||
|
static public function setVarName(t:TVar, name:String) {
|
||||||
|
@:privateAccess Context.load("set_var_name", 2)(t, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Converts type `t` to `ModuleType`.
|
||||||
|
**/
|
||||||
|
static public function toModuleType(t:Type):ModuleType {
|
||||||
|
#if (neko || eval)
|
||||||
|
return @:privateAccess Context.load("type_to_module_type", 1)(t);
|
||||||
|
#else
|
||||||
|
return null;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates a type from the `ModuleType` argument.
|
||||||
|
**/
|
||||||
|
static public function fromModuleType(mt:ModuleType):Type {
|
||||||
|
#if (neko || eval)
|
||||||
|
return @:privateAccess Context.load("module_type_to_type", 1)(mt);
|
||||||
|
#else
|
||||||
|
return null;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
/**
|
||||||
|
Resolves the field named `name` on class `c`.
|
||||||
|
|
||||||
|
If `isStatic` is true, the classes' static fields are checked. Otherwise
|
||||||
|
the classes' member fields are checked.
|
||||||
|
|
||||||
|
If the field is found, it is returned. Otherwise if `c` has a super
|
||||||
|
class, `findField` recursively checks that super class. Otherwise null
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
If any argument is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
static public function findField(c:ClassType, name:String, isStatic:Bool = false):Null<ClassField> {
|
||||||
|
var field = (isStatic ? c.statics : c.fields).get().find(function(field) return field.name == name);
|
||||||
|
return if (field != null) field; else if (c.superClass != null) findField(c.superClass.t.get(), name, isStatic); else null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
package hscript.macros;
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
import haxe.macro.Type.ClassType;
|
||||||
|
import Type.ValueType;
|
||||||
|
import haxe.macro.Expr.Function;
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
import haxe.macro.Type.MetaAccess;
|
||||||
|
import haxe.macro.Type.FieldKind;
|
||||||
|
import haxe.macro.Type.ClassField;
|
||||||
|
import haxe.macro.Type.VarAccess;
|
||||||
|
import haxe.macro.*;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
class Utils {
|
||||||
|
public static function fixStdTypes(type:ComplexType) {
|
||||||
|
switch(type) {
|
||||||
|
case TPath({name: "StdTypes"}):
|
||||||
|
var a:TypePath = type.getParameters()[0];
|
||||||
|
a.name = a.sub;
|
||||||
|
a.sub = null;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setupMetas(shadowClass:TypeDefinition, imports) {
|
||||||
|
shadowClass.meta = [];
|
||||||
|
shadowClass.meta.push({name: ":dox", params: [macro hide], pos: Context.currentPos()});
|
||||||
|
shadowClass.meta.push({name: ":noCompletion", params: [], pos: Context.currentPos()});
|
||||||
|
var module = Context.getModule(Context.getLocalModule());
|
||||||
|
for(t in module) {
|
||||||
|
switch(t) {
|
||||||
|
case TInst(t, params):
|
||||||
|
if (t != null) {
|
||||||
|
var e = t.get();
|
||||||
|
processModule(shadowClass, e.module, e.name);
|
||||||
|
processImport(imports, e.module, e.name);
|
||||||
|
}
|
||||||
|
case TEnum(t, params):
|
||||||
|
if (t != null) {
|
||||||
|
var e = t.get();
|
||||||
|
processModule(shadowClass, e.module, e.name);
|
||||||
|
processImport(imports, e.module, e.name);
|
||||||
|
}
|
||||||
|
case TType(t, params):
|
||||||
|
if (t != null) {
|
||||||
|
var e = t.get();
|
||||||
|
processModule(shadowClass, e.module, e.name);
|
||||||
|
processImport(imports, e.module, e.name);
|
||||||
|
}
|
||||||
|
case TAbstract(t, params):
|
||||||
|
if (t != null) {
|
||||||
|
var e = t.get();
|
||||||
|
processModule(shadowClass, e.module, e.name);
|
||||||
|
processImport(imports, e.module, e.name);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// not needed?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processModule(shadowClass:TypeDefinition, module:String, n:String) {
|
||||||
|
if (n.endsWith("_Impl_"))
|
||||||
|
n = n.substr(0, n.length - 6);
|
||||||
|
if (module.endsWith("_Impl_"))
|
||||||
|
module = module.substr(0, module.length - 6);
|
||||||
|
|
||||||
|
shadowClass.meta.push(
|
||||||
|
{
|
||||||
|
name: ':access',
|
||||||
|
params: [
|
||||||
|
Context.parse(fixModuleName(module.endsWith('.${n}') ? module : '${module}.${n}'), Context.currentPos())
|
||||||
|
],
|
||||||
|
pos: Context.currentPos()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*public static function getModuleName(path:Type) {
|
||||||
|
switch(path) {
|
||||||
|
case TPath(name, pack):// | TDClass(name, pack):
|
||||||
|
var str = "";
|
||||||
|
for(p in pack) {
|
||||||
|
str += p + ".";
|
||||||
|
}
|
||||||
|
str += name;
|
||||||
|
return str;
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return "INVALID";
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public static function fixModuleName(name:String) {
|
||||||
|
return [for(s in name.split(".")) if (s.charAt(0) == "_") s.substr(1) else s].join(".");
|
||||||
|
}
|
||||||
|
public static function processImport(imports:Array<ImportExpr>, module:String, n:String) {
|
||||||
|
if (n.endsWith("_Impl_"))
|
||||||
|
n = n.substr(0, n.length - 6);
|
||||||
|
module = fixModuleName(module);
|
||||||
|
if (module.endsWith("_Impl_"))
|
||||||
|
module = module.substr(0, module.length - 6);
|
||||||
|
|
||||||
|
imports.push({
|
||||||
|
path: [for(m in module.split(".")) {
|
||||||
|
name: m,
|
||||||
|
pos: Context.currentPos()
|
||||||
|
}],
|
||||||
|
mode: INormal
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cleanExpr(expr:Expr, oldFunc:String, newFunc:String) {
|
||||||
|
if (expr == null) return;
|
||||||
|
if (expr.expr == null) return;
|
||||||
|
switch(expr.expr) {
|
||||||
|
case EConst(c):
|
||||||
|
switch(c) {
|
||||||
|
case CIdent(s):
|
||||||
|
if (s == oldFunc)
|
||||||
|
expr.expr = EConst(CIdent(newFunc));
|
||||||
|
case CString(s, b):
|
||||||
|
if (s == oldFunc)
|
||||||
|
expr.expr = EConst(CString(s, b));
|
||||||
|
default:
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
case EField(e, field):
|
||||||
|
if (field == oldFunc && e != null) {
|
||||||
|
switch(e.expr) {
|
||||||
|
case EConst(c):
|
||||||
|
switch(c) {
|
||||||
|
case CIdent(s):
|
||||||
|
if (s == "super")
|
||||||
|
expr.expr = EField(e, newFunc);
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case EParenthesis(e):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case EObjectDecl(fields):
|
||||||
|
for(f in fields) {
|
||||||
|
cleanExpr(f.expr, oldFunc, newFunc);
|
||||||
|
}
|
||||||
|
case EArrayDecl(values):
|
||||||
|
for(a in values) {
|
||||||
|
cleanExpr(a, oldFunc, newFunc);
|
||||||
|
}
|
||||||
|
case ECall(e, params):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case EBlock(exprs):
|
||||||
|
for(e in exprs)
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case EFor(it, expr):
|
||||||
|
cleanExpr(it, oldFunc, newFunc);
|
||||||
|
cleanExpr(expr, oldFunc, newFunc);
|
||||||
|
case EIf(econd, eif, eelse):
|
||||||
|
cleanExpr(econd, oldFunc, newFunc);
|
||||||
|
cleanExpr(eif, oldFunc, newFunc);
|
||||||
|
cleanExpr(eelse, oldFunc, newFunc);
|
||||||
|
case EWhile(econd, e, normalWhile):
|
||||||
|
cleanExpr(econd, oldFunc, newFunc);
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case ECast(e, t):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case ECheckType(e, t):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case ETry(e, catches):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
for(c in catches) {
|
||||||
|
cleanExpr(c.expr, oldFunc, newFunc);
|
||||||
|
}
|
||||||
|
case EThrow(e):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case ETernary(econd, eif, eelse):
|
||||||
|
cleanExpr(econd, oldFunc, newFunc);
|
||||||
|
cleanExpr(eif, oldFunc, newFunc);
|
||||||
|
cleanExpr(eelse, oldFunc, newFunc);
|
||||||
|
case ESwitch(e, cases, edef):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
for(c in cases) {
|
||||||
|
cleanExpr(c.expr, oldFunc, newFunc);
|
||||||
|
}
|
||||||
|
cleanExpr(edef, oldFunc, newFunc);
|
||||||
|
case EReturn(e):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case EIs(e, t):
|
||||||
|
cleanExpr(e, oldFunc, newFunc);
|
||||||
|
case EVars(vars):
|
||||||
|
for(v in vars) {
|
||||||
|
cleanExpr(v.expr, oldFunc, newFunc);
|
||||||
|
}
|
||||||
|
case ENew(t, params):
|
||||||
|
for(p in params) {
|
||||||
|
cleanExpr(p, oldFunc, newFunc);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
package hscript.utils;
|
||||||
|
|
||||||
|
#if cpp
|
||||||
|
import cpp.ObjectType;
|
||||||
|
#end
|
||||||
|
|
||||||
|
@:analyzer(ignore)
|
||||||
|
class UnsafeReflect {
|
||||||
|
public #if !cpp inline #end static function hasField(o:Dynamic, field:String):Bool {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
return o.__HasField(field);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.hasField(o, field);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function field(o:Dynamic, field:String):Dynamic {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
return o.__Field(field, untyped __cpp__("::hx::paccNever"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.field(o, field);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function setField(o:Dynamic, field:String, value:Dynamic):Void {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
o.__SetField(field, value, untyped __cpp__("::hx::paccNever"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.setField(o, field, value);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function getProperty(o:Dynamic, field:String):Dynamic {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
return o.__Field(field, untyped __cpp__("::hx::paccAlways"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.getProperty(o, field);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function setProperty(o:Dynamic, field:String, value:Dynamic):Void {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
o.__SetField(field, value, untyped __cpp__("::hx::paccAlways"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Reflect.setProperty(o, field, value);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function callFieldUnsafe(o:Dynamic, field:String, args:Array<Dynamic>):Dynamic {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
var func:Dynamic = o.__Field(field, untyped __cpp__("::hx::paccDynamic"));
|
||||||
|
untyped func.__SetThis(o);
|
||||||
|
return untyped func.__Run(args);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.callMethod(o, Reflect.field(o, field), args);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
|
||||||
|
return Reflect.callMethod(o, func, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function callMethodSafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
if (func == null)
|
||||||
|
throw cpp.ErrorConstants.nullFunctionPointer;
|
||||||
|
untyped func.__SetThis(o);
|
||||||
|
return untyped func.__Run(args);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.callMethod(o, func, args);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function callMethodUnsafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
untyped func.__SetThis(o);
|
||||||
|
return untyped func.__Run(args);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.callMethod(o, func, args);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline static function fields(o:Dynamic):Array<String>
|
||||||
|
return Reflect.fields(o);
|
||||||
|
/*untyped {
|
||||||
|
if (o == null)
|
||||||
|
return new Array();
|
||||||
|
var a:Array<String> = [];
|
||||||
|
o.__GetFields(a);
|
||||||
|
return a;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function isFunction(f:Dynamic):Bool
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
return f.__GetType() == ObjectType.vtFunction;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.isFunction(f);
|
||||||
|
#end
|
||||||
|
|
||||||
|
public inline static function compare<T>(a:T, b:T):Int {
|
||||||
|
return Reflect.compare(a, b);
|
||||||
|
//return (a == b) ? 0 : (((a : Dynamic) > (b : Dynamic)) ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
|
||||||
|
return Reflect.compareMethods(f1, f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function isObject(v:Dynamic):Bool {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
var t:Int = v.__GetType();
|
||||||
|
return t == ObjectType.vtObject || t == ObjectType.vtClass || t == ObjectType.vtString || t == ObjectType.vtArray;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.isObject(v);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function isEnumValue(v:Dynamic):Bool {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
return v.__GetType() == ObjectType.vtEnum;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.isEnumValue(v);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function deleteField(o:Dynamic, field:String):Bool {
|
||||||
|
#if cpp
|
||||||
|
untyped {
|
||||||
|
return untyped __global__.__hxcpp_anon_remove(o, field);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return Reflect.deleteField(o, field);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public #if !cpp inline #end static function copy<T>(o:Null<T>):Null<T> {
|
||||||
|
#if cpp
|
||||||
|
if (o == null)
|
||||||
|
return null;
|
||||||
|
var t:Int = untyped o.__GetType();
|
||||||
|
if (t == ObjectType.vtString)
|
||||||
|
return o;
|
||||||
|
if (t == ObjectType.vtArray)
|
||||||
|
return untyped o.__Field("copy", untyped __cpp__("::hx::paccDynamic"))();
|
||||||
|
var o2:Dynamic = {};
|
||||||
|
for (f in UnsafeReflect.fields(o))
|
||||||
|
UnsafeReflect.setField(o2, f, UnsafeReflect.field(o, f));
|
||||||
|
return o2;
|
||||||
|
#else
|
||||||
|
return Reflect.copy(o);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
@:overload(function(f:Array<Dynamic>->Void):Dynamic {})
|
||||||
|
public static function makeVarArgs(f:Array<Dynamic>->Dynamic):Dynamic {
|
||||||
|
#if cpp
|
||||||
|
return untyped __global__.__hxcpp_create_var_args(f);
|
||||||
|
#else
|
||||||
|
return inline Reflect.makeVarArgs(f);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package hscript.utils;
|
||||||
|
|
||||||
|
@:structInit
|
||||||
|
class UsingEntry {
|
||||||
|
public var call:Dynamic->String->Array<Dynamic>->Dynamic;
|
||||||
|
public var fields:Array<String>;
|
||||||
|
|
||||||
|
public function hasField(name:String) {
|
||||||
|
return fields.contains(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special class that handles static extension function calls.
|
||||||
|
*
|
||||||
|
* A static extension allows pseudo-extending
|
||||||
|
* existing types without modifying their source.
|
||||||
|
* In Haxe this is achieved by declaring a static method with a first argument
|
||||||
|
* of the extending type and then bringing the defining class into context through `using`.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* ```haxe
|
||||||
|
* class IntExtender {
|
||||||
|
* static public function triple(i:Int) {
|
||||||
|
* return i * 3;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* using IntExtender;
|
||||||
|
*
|
||||||
|
* trace(12.triple()); // 36
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @see https://haxe.org/manual/lf-static-extension.html
|
||||||
|
*/
|
||||||
|
class UsingHandler {
|
||||||
|
// Predefined static extension classes
|
||||||
|
public static final defaultExtension:Map<String, UsingEntry> = [
|
||||||
|
"StringTools" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L45
|
||||||
|
fields: Type.getClassFields(StringTools),
|
||||||
|
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||||
|
if (f == "isEof") // has @:noUsing
|
||||||
|
return null;
|
||||||
|
return switch (Type.typeof(o)) {
|
||||||
|
case TInt if (f == 'hex'):
|
||||||
|
StringTools.hex(o, args[0]);
|
||||||
|
case TClass(String):
|
||||||
|
var field = UnsafeReflect.field(StringTools, f);
|
||||||
|
if (UnsafeReflect.isFunction(field)) UnsafeReflect.callMethodUnsafe(StringTools, field, [o].concat(args)); else null;
|
||||||
|
default:
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Lambda" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L62
|
||||||
|
fields: Type.getClassFields(Lambda),
|
||||||
|
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||||
|
if (o != null && o.iterator != null) {
|
||||||
|
var field = UnsafeReflect.field(Lambda, f);
|
||||||
|
if (UnsafeReflect.isFunction(field)) {
|
||||||
|
return UnsafeReflect.callMethodUnsafe(Lambda, field, [o].concat(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@:allow(hscript.CustomClass)
|
||||||
|
@:allow(hscript.CustomClassHandler)
|
||||||
|
public var usingEntries(default, null):Map<String, UsingEntry> = [];
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function registerEntry(name:String, entry:Dynamic->String->Array<Dynamic>->Dynamic, fields:Array<String>) {
|
||||||
|
usingEntries.set(name, {call: entry, fields: fields});
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function entryExists(name:String):Bool {
|
||||||
|
return usingEntries.exists(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
set PATH="C:\Program Files\7-Zip";%PATH%
|
||||||
rm -rf release
|
rm -rf release
|
||||||
mkdir release
|
mkdir release
|
||||||
cp haxelib.json README.md extraParams.hxml release
|
cp haxelib.json README.md extraParams.hxml release
|
||||||
@@ -15,4 +16,5 @@ haxe -xml release/haxedoc.xml hscript.Interp hscript.Parser hscript.Bytes hscrip
|
|||||||
7z a -tzip release.zip release
|
7z a -tzip release.zip release
|
||||||
rm -rf release
|
rm -rf release
|
||||||
haxelib submit release.zip
|
haxelib submit release.zip
|
||||||
|
echo Remember to "git tag vX.Y.Z && git push --tags"
|
||||||
pause
|
pause
|
||||||
Reference in New Issue
Block a user