Compare commits
136
Commits
2.3.0
...
custom-classes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49c90e6434 | ||
|
|
bb46d45d56 | ||
|
|
3a5c4f2164 | ||
|
|
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 |
@@ -1,2 +1,4 @@
|
|||||||
/hscript.swf
|
/hscript.swf
|
||||||
/release.zip
|
/release.zip
|
||||||
|
|
||||||
|
tests/bin/*
|
||||||
+11
-16
@@ -4,11 +4,11 @@ os:
|
|||||||
- linux
|
- linux
|
||||||
- osx
|
- osx
|
||||||
|
|
||||||
sudo: false
|
dist: bionic
|
||||||
dist: trusty
|
|
||||||
|
|
||||||
haxe:
|
haxe:
|
||||||
- "3.4.7"
|
- "3.4.7"
|
||||||
|
- "4.0.3"
|
||||||
- development
|
- development
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@@ -19,27 +19,20 @@ addons:
|
|||||||
- g++-multilib
|
- g++-multilib
|
||||||
# Python
|
# Python
|
||||||
- python3
|
- python3
|
||||||
|
# PHP
|
||||||
|
- php-cli
|
||||||
|
- php-mbstring
|
||||||
# C#
|
# C#
|
||||||
- mono-devel
|
- mono-devel
|
||||||
- mono-mcs
|
- mono-mcs
|
||||||
# Flash
|
|
||||||
- libglib2.0
|
|
||||||
- libfreetype6
|
|
||||||
|
|
||||||
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;
|
|
||||||
phpenv global 7.0;
|
|
||||||
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
|
||||||
brew update;
|
brew update;
|
||||||
brew install mono;
|
brew install mono;
|
||||||
brew upgrade python;
|
|
||||||
brew install php;
|
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;
|
||||||
@@ -67,8 +60,10 @@ script:
|
|||||||
- haxe bin/build-neko.hxml && neko bin/Test.n
|
- haxe bin/build-neko.hxml && neko bin/Test.n
|
||||||
- haxe bin/build-js.hxml && node bin/Test.js
|
- haxe bin/build-js.hxml && node bin/Test.js
|
||||||
- haxe bin/build-java.hxml && java -jar bin/Test.jar
|
- haxe bin/build-java.hxml && java -jar bin/Test.jar
|
||||||
- haxe bin/build-cs.hxml && mono bin/bin/Test.exe
|
# Only test C# for Haxe 4+
|
||||||
|
- if [[ $(haxe -version 2&>1 | head -c 1) > 3 ]]; then
|
||||||
|
haxe bin/build-cs.hxml && mono bin/bin/Test.exe;
|
||||||
|
fi
|
||||||
- haxe bin/build-cpp.hxml && ./bin/Test
|
- haxe bin/build-cpp.hxml && ./bin/Test
|
||||||
- haxe bin/build-flash.hxml -D fdb && haxe flash/run.hxml bin/Test.swf
|
- haxe bin/build-php.hxml -D php7 && php bin/index.php
|
||||||
- haxe bin/build-php.hxml && php bin/index.php
|
|
||||||
- haxe bin/build-python.hxml && python3 bin/Test.py
|
- haxe bin/build-python.hxml && python3 bin/Test.py
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
hscript
|
hscript-improved
|
||||||
=======
|
=======
|
||||||
|
|
||||||
[](https://travis-ci.org/HaxeFoundation/hscript)
|
How to install
|
||||||
[](https://ci.appveyor.com/project/HaxeFoundation/hscript)
|
```
|
||||||
|
haxelib git hscript-improved https://github.com/FNF-CNE-Devs/hscript-improved.git
|
||||||
|
```
|
||||||
|
|
||||||
|
To enable custom classes support you have to do this in project.xml
|
||||||
|
```xml
|
||||||
|
<define name="CUSTOM_CLASSES" />
|
||||||
|
```
|
||||||
|
Warning: custom classes are sometimes broken, would like help to fix them. You can only override functions from the current class, not from the extended part, like you cant override update in FlxText because FlxText doesnt have a update function overriden
|
||||||
|
|
||||||
|
-----------
|
||||||
|
|
||||||
Parse and evalutate Haxe expressions.
|
Parse and evalutate Haxe expressions.
|
||||||
|
|
||||||
@@ -68,24 +78,36 @@ You can use `parser.allowMetadata` to parse metadata before expressions on in an
|
|||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import hscript.Macro;
|
|||||||
import hscript.Tools;
|
import hscript.Tools;
|
||||||
import hscript.Async;
|
import hscript.Async;
|
||||||
import hscript.Printer;
|
import hscript.Printer;
|
||||||
|
import hscript.Checker;
|
||||||
import haxe.unit.*;
|
import haxe.unit.*;
|
||||||
|
|
||||||
class Test extends TestCase {
|
class TestHScript extends TestCase {
|
||||||
function assertScript(x,v:Dynamic,?vars : Dynamic, allowTypes=false, ?pos:haxe.PosInfos) {
|
function assertScript(x,v:Dynamic,?vars : Dynamic, allowTypes=false, ?pos:haxe.PosInfos) {
|
||||||
var p = new hscript.Parser();
|
var p = new hscript.Parser();
|
||||||
p.allowTypes = allowTypes;
|
p.allowTypes = allowTypes;
|
||||||
@@ -100,6 +101,7 @@ class Test extends TestCase {
|
|||||||
assertScript("/**/0", 0);
|
assertScript("/**/0", 0);
|
||||||
assertScript("x=1;x*=-2", -2);
|
assertScript("x=1;x*=-2", -2);
|
||||||
assertScript("var f = x -> x + 1; f(3)", 4);
|
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) -> x + 1; f(3)", 4);
|
||||||
assertScript("var f = (x:Int) -> 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) -> x + y; f(3,1)", 4);
|
||||||
@@ -109,6 +111,8 @@ class Test extends TestCase {
|
|||||||
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)->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)->(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 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 {
|
function testMap():Void {
|
||||||
@@ -169,7 +173,7 @@ class Test extends TestCase {
|
|||||||
#end
|
#end
|
||||||
|
|
||||||
var runner = new TestRunner();
|
var runner = new TestRunner();
|
||||||
runner.add(new Test());
|
runner.add(new TestHScript());
|
||||||
var succeed = runner.run();
|
var succeed = runner.run();
|
||||||
|
|
||||||
#if sys
|
#if sys
|
||||||
+1
-9
@@ -8,17 +8,11 @@ install:
|
|||||||
# http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
|
# http://help.appveyor.com/discussions/problems/5616-not-able-to-build-due-to-problem-in-chocolateyinstallps1
|
||||||
- ps: Set-Service wuauserv -StartupType Manual
|
- 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.4.7 -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
|
|
||||||
- ps: Set-Service wuauserv -StartupType Manual
|
|
||||||
- cinst php -y
|
|
||||||
- RefreshEnv
|
|
||||||
# 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
|
||||||
@@ -39,6 +33,4 @@ test_script:
|
|||||||
- haxe bin/build-java.hxml && java -jar bin\Test.jar
|
- haxe bin/build-java.hxml && java -jar bin\Test.jar
|
||||||
- haxe bin/build-cs.hxml && bin\bin\Test.exe
|
- haxe bin/build-cs.hxml && bin\bin\Test.exe
|
||||||
- haxe bin/build-cpp.hxml && bin\Test.exe
|
- haxe bin/build-cpp.hxml && bin\Test.exe
|
||||||
- haxe bin/build-flash.hxml -D fdb && haxe flash\run.hxml bin\Test.swf
|
|
||||||
- haxe bin/build-php.hxml && php bin\index.php
|
|
||||||
- haxe bin/build-python.hxml && C:\Python34-x64\python.exe bin\Test.py
|
- haxe bin/build-python.hxml && C:\Python34-x64\python.exe bin\Test.py
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
-main Test
|
-main TestHScript
|
||||||
-dce no
|
-dce no
|
||||||
-lib hx3compat
|
-lib hx3compat
|
||||||
@@ -1 +1,3 @@
|
|||||||
--macro keep('IntIterator')
|
--macro keep('IntIterator')
|
||||||
|
--macro hscript.macros.UsingHandler.init()
|
||||||
|
--macro hscript.macros.ClassExtendMacro.init()
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
*.exe
|
|
||||||
*.app
|
|
||||||
flashplayerdebugger
|
|
||||||
LGPL/
|
|
||||||
license.pdf
|
|
||||||
@@ -1,91 +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":
|
|
||||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/26/flash_player_sa_linux_debug.x86_64.tar.gz";
|
|
||||||
case "Mac":
|
|
||||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/26/flashplayer_26_sa_debug.dmg";
|
|
||||||
case "Windows":
|
|
||||||
"http://fpdownload.macromedia.com/pub/flashplayer/updaters/26/flashplayer_26_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("APPDATA"), "Macromedia", "Flash Player", "#Security", "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";
|
|
||||||
deleteFile(Path.withoutDirectory(fpDownload));
|
|
||||||
case "Mac":
|
|
||||||
if (command("brew", ["cask", "install", "flash-player-debugger"]) != 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));
|
|
||||||
}
|
|
||||||
static function createDirectory(dir:String):Void {
|
|
||||||
try {
|
|
||||||
sys.FileSystem.createDirectory(dir);
|
|
||||||
} catch(e:Dynamic) {
|
|
||||||
switch (systemName()) {
|
|
||||||
case "Mac", "Linux":
|
|
||||||
if (command("sudo", ["mkdir", "-p", dir]) != 0)
|
|
||||||
throw 'cannot create $dir';
|
|
||||||
if (command("sudo", ["chmod", "a+rw", dir]) != 0)
|
|
||||||
throw 'cannot set permission of $dir';
|
|
||||||
case _:
|
|
||||||
throw 'cannot create $dir: $e';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +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 16 times, it should succeed one of those...
|
|
||||||
var c = -1;
|
|
||||||
for (i in 0...16) {
|
|
||||||
if ((c = command("xvfb-run", ["-a", "flash/flashplayerdebugger", swf])) == 0)
|
|
||||||
break;
|
|
||||||
println('retry... (${i+1})');
|
|
||||||
sleep(1.5);
|
|
||||||
}
|
|
||||||
c;
|
|
||||||
case "Mac":
|
|
||||||
command("/Applications/Flash Player Debugger.app/Contents/MacOS/Flash Player Debugger", [fullPath(swf)]);
|
|
||||||
case "Windows":
|
|
||||||
command("flash\\flashplayer.exe", [fullPath(swf)]);
|
|
||||||
case _:
|
|
||||||
throw "unsupported platform";
|
|
||||||
}
|
|
||||||
if (exists(flashlog))
|
|
||||||
println(getContent(flashlog));
|
|
||||||
else {
|
|
||||||
println('does not exist: $flashlog');
|
|
||||||
var parts = Path.normalize(flashlog).split("/");
|
|
||||||
println(parts);
|
|
||||||
for (i in 0...parts.length-1) {
|
|
||||||
var path = parts.splice(0, i+1).join("/");
|
|
||||||
println('ls $path');
|
|
||||||
command("ls", [path]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit(exitCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-cp flash
|
|
||||||
--run Install
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-cp flash
|
|
||||||
--run Run
|
|
||||||
+3
-3
@@ -3,7 +3,7 @@
|
|||||||
"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.3.0",
|
"version": "2.4.0",
|
||||||
"releasenote": "",
|
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
|
||||||
"contributors": ["ncannasse"]
|
"contributors": ["ncannasse","HaxeFoundation"]
|
||||||
}
|
}
|
||||||
@@ -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>
|
|
||||||
+53
-21
@@ -22,13 +22,21 @@
|
|||||||
package hscript;
|
package hscript;
|
||||||
import hscript.Expr;
|
import hscript.Expr;
|
||||||
|
|
||||||
|
|
||||||
|
enum VarMode {
|
||||||
|
Defined;
|
||||||
|
ForceSync;
|
||||||
|
}
|
||||||
|
|
||||||
class Async {
|
class Async {
|
||||||
|
|
||||||
var varNames : Array<String>;
|
var definedVars : Array<{ n : String, prev : Null<VarMode> }>;
|
||||||
|
var vars : Map<String,VarMode>;
|
||||||
var currentFun : String;
|
var currentFun : String;
|
||||||
var currentLoop : Expr;
|
var currentLoop : Expr;
|
||||||
var currentBreak : Expr -> Expr;
|
var currentBreak : Expr -> Expr;
|
||||||
var uid = 0;
|
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 nullExpr : Expr = #if hscriptPos { e : null, pmin : 0, pmax : 0, origin : "<null>", line : 0 } #else null #end;
|
||||||
static var nullId = mk(EIdent("null"), nullExpr);
|
static var nullId = mk(EIdent("null"), nullExpr);
|
||||||
@@ -68,12 +76,30 @@ class Async {
|
|||||||
return a.build(e, topLevelSync);
|
return a.build(e, topLevelSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public dynamic function getTopLevelEnd() {
|
||||||
|
return ignore();
|
||||||
|
}
|
||||||
|
|
||||||
public function build( e : Expr, topLevelSync = false ) {
|
public function build( e : Expr, topLevelSync = false ) {
|
||||||
if( topLevelSync ) {
|
if( topLevelSync ) {
|
||||||
return buildSync(e,null);
|
return buildSync(e,null);
|
||||||
} else {
|
} else {
|
||||||
var nothing = ignore();
|
var end = getTopLevelEnd();
|
||||||
return new Async().toCps(e, nothing, nothing);
|
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:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,16 +111,14 @@ class Async {
|
|||||||
return e;
|
return e;
|
||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
var v = saveVars();
|
var v = saveVars();
|
||||||
for( e in el )
|
lookupFunctions(el);
|
||||||
switch( expr(e) ) {
|
|
||||||
case EFunction(_, _, name, _) if( name != null ): varNames.push(name);
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
var e = block([for(e in el) buildSync(e,exit)], e);
|
var e = block([for(e in el) buildSync(e,exit)], e);
|
||||||
restoreVars(v);
|
restoreVars(v);
|
||||||
return e;
|
return e;
|
||||||
case EMeta("async", _, e):
|
case EMeta("async", _, e):
|
||||||
return toCps(e, ignore(), ignore());
|
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 ):
|
case EBreak if( currentBreak != null ):
|
||||||
return currentBreak(e);
|
return currentBreak(e);
|
||||||
case EContinue if( currentLoop != null ):
|
case EContinue if( currentLoop != null ):
|
||||||
@@ -115,7 +139,8 @@ class Async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
varNames = [];
|
vars = new Map();
|
||||||
|
definedVars = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function ignore(?e) : Expr {
|
function ignore(?e) : Expr {
|
||||||
@@ -183,11 +208,17 @@ class Async {
|
|||||||
return syncFlag;
|
return syncFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline function isAsyncIdent( id : String ) {
|
||||||
|
return asyncIdents == null || asyncIdents.exists(id);
|
||||||
|
}
|
||||||
|
|
||||||
function checkSync( e : Expr ) {
|
function checkSync( e : Expr ) {
|
||||||
if( !syncFlag )
|
if( !syncFlag )
|
||||||
return;
|
return;
|
||||||
switch( expr(e) ) {
|
switch( expr(e) ) {
|
||||||
case ECall(_):
|
case ECall(expr(_) => EIdent(i),_) if( isAsyncIdent(i) || vars.get(i) == Defined ):
|
||||||
|
syncFlag = false;
|
||||||
|
case ECall(expr(_) => EField(_,i),_) if( isAsyncIdent(i) ):
|
||||||
syncFlag = false;
|
syncFlag = false;
|
||||||
case EFunction(_,_,name,_) if( name != null ):
|
case EFunction(_,_,name,_) if( name != null ):
|
||||||
syncFlag = false;
|
syncFlag = false;
|
||||||
@@ -199,11 +230,14 @@ class Async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveVars() {
|
function saveVars() {
|
||||||
return varNames.length;
|
return definedVars.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreVars(k) {
|
function restoreVars(k) {
|
||||||
while( varNames.length > k ) varNames.pop();
|
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 {
|
public function toCps( e : Expr, rest : Expr, exit : Expr ) : Expr {
|
||||||
@@ -213,12 +247,7 @@ class Async {
|
|||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
var el = el.copy();
|
var el = el.copy();
|
||||||
var vold = saveVars();
|
var vold = saveVars();
|
||||||
// local recursion
|
lookupFunctions(el);
|
||||||
for( e in el )
|
|
||||||
switch( expr(e) ) {
|
|
||||||
case EFunction(_, _, name, null): if( name != null ) varNames.push(name);
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
while( el.length > 0 ) {
|
while( el.length > 0 ) {
|
||||||
var e = toCps(el.pop(), rest, exit);
|
var e = toCps(el.pop(), rest, exit);
|
||||||
rest = ignore(e);
|
rest = ignore(e);
|
||||||
@@ -228,9 +257,9 @@ class Async {
|
|||||||
case EFunction(args, body, name, t):
|
case EFunction(args, body, name, t):
|
||||||
var vold = saveVars();
|
var vold = saveVars();
|
||||||
if( name != null )
|
if( name != null )
|
||||||
varNames.push(name);
|
defineVar(name, Defined);
|
||||||
for( a in args )
|
for( a in args )
|
||||||
varNames.push(a.name);
|
defineVar(a.name, Defined);
|
||||||
args.unshift( { name : "_onEnd", t : null } );
|
args.unshift( { name : "_onEnd", t : null } );
|
||||||
var frest = ident("_onEnd",e);
|
var frest = ident("_onEnd",e);
|
||||||
var oldFun = currentFun;
|
var oldFun = currentFun;
|
||||||
@@ -251,7 +280,8 @@ class Async {
|
|||||||
var args = [for( a in args ) fun("_rest", toCps(block([a],a), ident("_rest",a), exit))];
|
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);
|
return call(ident("split",e), [rest, mk(EArrayDecl(args),e)],e);
|
||||||
case ECall(expr(_) => EIdent(i), args):
|
case ECall(expr(_) => EIdent(i), args):
|
||||||
return makeCall( ident( varNames.indexOf(i) < 0 ? "a_" + i : i,e) , args, rest, exit);
|
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):
|
case ECall(expr(_) => EField(e, f), args):
|
||||||
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
return makeCall(field(e,"a_"+f,e), args, rest, exit);
|
||||||
case EFor(v, eit, eloop):
|
case EFor(v, eit, eloop):
|
||||||
@@ -391,6 +421,8 @@ class Async {
|
|||||||
return toCps(v, mk(EFunction([ { name : "_c", t : null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
return toCps(v, mk(EFunction([ { name : "_c", t : null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );
|
||||||
case EThrow(v):
|
case EThrow(v):
|
||||||
return toCps(v, mk(EFunction([ { name : "_v", t : null } ], mk(EThrow(v),v)), v), exit);
|
return toCps(v, mk(EFunction([ { name : "_v", t : 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(_):
|
//case EDoWhile(_), ETry(_), ECall(_):
|
||||||
default:
|
default:
|
||||||
throw "Unsupported async expression " + Printer.toString(e);
|
throw "Unsupported async expression " + Printer.toString(e);
|
||||||
|
|||||||
@@ -140,6 +140,10 @@ class Bytes {
|
|||||||
#end
|
#end
|
||||||
bout.addByte(Type.enumIndex(e));
|
bout.addByte(Type.enumIndex(e));
|
||||||
switch( e ) {
|
switch( e ) {
|
||||||
|
case EImport(c):
|
||||||
|
// TODO
|
||||||
|
case EClass(_, _, _, _):
|
||||||
|
// TODO
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
doEncodeConst(c);
|
doEncodeConst(c);
|
||||||
case EIdent(v):
|
case EIdent(v):
|
||||||
|
|||||||
+363
-61
@@ -23,6 +23,7 @@ enum TType {
|
|||||||
TAbstract( a : CAbstract, args : Array<TType> );
|
TAbstract( a : CAbstract, args : Array<TType> );
|
||||||
TFun( args : Array<{ name : String, opt : Bool, t : TType }>, ret : TType );
|
TFun( args : Array<{ name : String, opt : Bool, t : TType }>, ret : TType );
|
||||||
TAnon( fields : Array<{ name : String, opt : Bool, t : TType }> );
|
TAnon( fields : Array<{ name : String, opt : Bool, t : TType }> );
|
||||||
|
TLazy( f : Void -> TType );
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum WithType {
|
private enum WithType {
|
||||||
@@ -47,19 +48,23 @@ typedef CNamedType = {
|
|||||||
typedef CClass = {> CNamedType,
|
typedef CClass = {> CNamedType,
|
||||||
@:optional var superClass : TType;
|
@:optional var superClass : TType;
|
||||||
@:optional var constructor : CField;
|
@:optional var constructor : CField;
|
||||||
|
@:optional var interfaces : Array<TType>;
|
||||||
|
@:optional var isInterface : Bool;
|
||||||
var fields : Map<String,CField>;
|
var fields : Map<String,CField>;
|
||||||
var statics : Map<String,CField>;
|
var statics : Map<String,CField>;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef CField = {
|
typedef CField = {
|
||||||
var isPublic : Bool;
|
var isPublic : Bool;
|
||||||
|
var canWrite : Bool;
|
||||||
|
var complete : Bool;
|
||||||
var params : Array<TType>;
|
var params : Array<TType>;
|
||||||
var name : String;
|
var name : String;
|
||||||
var t : TType;
|
var t : TType;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef CEnum = {> CNamedType,
|
typedef CEnum = {> CNamedType,
|
||||||
var constructors : Map<String,TType>;
|
var constructors : Array<{ name : String, ?args : Array<{ name : String, opt : Bool, t : TType }> }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef CTypedef = {> CNamedType,
|
typedef CTypedef = {> CNamedType,
|
||||||
@@ -67,6 +72,16 @@ typedef CTypedef = {> CNamedType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef CAbstract = {> CNamedType,
|
typedef CAbstract = {> CNamedType,
|
||||||
|
var t : TType;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Completion {
|
||||||
|
public var expr : Expr;
|
||||||
|
public var t : TType;
|
||||||
|
public function new(expr,t) {
|
||||||
|
this.expr = expr;
|
||||||
|
this.t = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:allow(hscript.Checker)
|
@:allow(hscript.Checker)
|
||||||
@@ -108,23 +123,34 @@ class CheckerTypes {
|
|||||||
fields : new Map(),
|
fields : new Map(),
|
||||||
statics : new Map(),
|
statics : new Map(),
|
||||||
};
|
};
|
||||||
|
if( c.isInterface )
|
||||||
|
cl.isInterface = true;
|
||||||
for( p in c.params )
|
for( p in c.params )
|
||||||
cl.params.push(TParam(p));
|
cl.params.push(TParam(p));
|
||||||
todo.push(function() {
|
todo.push(function() {
|
||||||
localParams = [for( t in cl.params ) c.path+"."+Checker.typeStr(t) => t];
|
localParams = [for( t in cl.params ) c.path+"."+Checker.typeStr(t) => t];
|
||||||
if( c.superClass != null )
|
if( c.superClass != null )
|
||||||
cl.superClass = getType(c.superClass.path, [for( t in c.superClass.params ) makeXmlType(t)]);
|
cl.superClass = getType(c.superClass.path, [for( t in c.superClass.params ) makeXmlType(t)]);
|
||||||
|
if( c.interfaces != null ) {
|
||||||
|
cl.interfaces = [];
|
||||||
|
for( i in c.interfaces )
|
||||||
|
cl.interfaces.push(getType(i.path, [for( t in i.params ) makeXmlType(t)]));
|
||||||
|
}
|
||||||
var pkeys = [];
|
var pkeys = [];
|
||||||
for( f in c.fields ) {
|
for( f in c.fields ) {
|
||||||
if( f.isOverride || f.name.substr(0,4) == "get_" || f.name.substr(0,4) == "set_" ) continue;
|
if( f.isOverride || f.name.substr(0,4) == "get_" || f.name.substr(0,4) == "set_" ) continue;
|
||||||
var skip = false;
|
var skip = false;
|
||||||
for( m in f.meta )
|
var complete = !StringTools.startsWith(f.name,"__"); // __uid, etc. (no metadata in such fields)
|
||||||
|
for( m in f.meta ) {
|
||||||
if( m.name == ":noScript" ) {
|
if( m.name == ":noScript" ) {
|
||||||
skip = true;
|
skip = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if( m.name == ":noCompletion" )
|
||||||
|
complete = false;
|
||||||
|
}
|
||||||
if( skip ) continue;
|
if( skip ) continue;
|
||||||
var fl : CField = { isPublic : f.isPublic, params : [], name : f.name, t : null };
|
var fl : CField = { isPublic : f.isPublic, canWrite : f.set.match(RNormal | RCall(_) | RDynamic), complete : complete, params : [], name : f.name, t : null };
|
||||||
for( p in f.params ) {
|
for( p in f.params ) {
|
||||||
var pt = TParam(p);
|
var pt = TParam(p);
|
||||||
var key = f.name+"."+p;
|
var key = f.name+"."+p;
|
||||||
@@ -148,12 +174,14 @@ class CheckerTypes {
|
|||||||
var en : CEnum = {
|
var en : CEnum = {
|
||||||
name : e.path,
|
name : e.path,
|
||||||
params : [],
|
params : [],
|
||||||
constructors: new Map(),
|
constructors: [],
|
||||||
};
|
};
|
||||||
for( p in e.params )
|
for( p in e.params )
|
||||||
en.params.push(TParam(p));
|
en.params.push(TParam(p));
|
||||||
todo.push(function() {
|
todo.push(function() {
|
||||||
localParams = [for( t in en.params ) e.path+"."+Checker.typeStr(t) => t];
|
localParams = [for( t in en.params ) e.path+"."+Checker.typeStr(t) => t];
|
||||||
|
for( c in e.constructors )
|
||||||
|
en.constructors.push({ name : c.name, args : c.args == null ? null : [for( a in c.args ) { name : a.name, opt : a.opt, t : makeXmlType(a.t) }] });
|
||||||
localParams = null;
|
localParams = null;
|
||||||
});
|
});
|
||||||
types.set(en.name, CTEnum(en));
|
types.set(en.name, CTEnum(en));
|
||||||
@@ -179,11 +207,13 @@ class CheckerTypes {
|
|||||||
var ta : CAbstract = {
|
var ta : CAbstract = {
|
||||||
name : a.path,
|
name : a.path,
|
||||||
params : [],
|
params : [],
|
||||||
|
t : null,
|
||||||
};
|
};
|
||||||
for( p in a.params )
|
for( p in a.params )
|
||||||
ta.params.push(TParam(p));
|
ta.params.push(TParam(p));
|
||||||
todo.push(function() {
|
todo.push(function() {
|
||||||
localParams = [for( t in ta.params ) a.path+"."+Checker.typeStr(t) => t];
|
localParams = [for( t in ta.params ) a.path+"."+Checker.typeStr(t) => t];
|
||||||
|
ta.t = makeXmlType(a.athis);
|
||||||
localParams = null;
|
localParams = null;
|
||||||
});
|
});
|
||||||
types.set(a.path, CTAbstract(ta));
|
types.set(a.path, CTAbstract(ta));
|
||||||
@@ -220,8 +250,18 @@ class CheckerTypes {
|
|||||||
if( t != null ) return t;
|
if( t != null ) return t;
|
||||||
}
|
}
|
||||||
var t = resolve(name,args);
|
var t = resolve(name,args);
|
||||||
if( t == null )
|
if( t == null ) {
|
||||||
|
var pack = name.split(".");
|
||||||
|
if( pack.length > 1 ) {
|
||||||
|
// bugfix for some args reported as pack._Name.Name while they are not private
|
||||||
|
var priv = pack[pack.length-2];
|
||||||
|
if( priv.charCodeAt(0) == "_".code ) {
|
||||||
|
pack.remove(priv);
|
||||||
|
return getType(pack.join("."), args);
|
||||||
|
}
|
||||||
|
}
|
||||||
return TUnresolved(name); // most likely private class
|
return TUnresolved(name); // most likely private class
|
||||||
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,14 +290,37 @@ class Checker {
|
|||||||
var locals : Map<String,TType>;
|
var locals : Map<String,TType>;
|
||||||
var globals : Map<String,TType> = new Map();
|
var globals : Map<String,TType> = new Map();
|
||||||
var events : Map<String,TType> = new Map();
|
var events : Map<String,TType> = new Map();
|
||||||
|
var currentFunType : TType;
|
||||||
|
var isCompletion : Bool;
|
||||||
|
var allowDefine : Bool;
|
||||||
public var allowAsync : Bool;
|
public var allowAsync : Bool;
|
||||||
public var allowReturn : Null<TType>;
|
public var allowReturn : Null<TType>;
|
||||||
|
public var allowGlobalsDefine : Bool;
|
||||||
|
public var allowUntypedMeta : Bool;
|
||||||
|
|
||||||
public function new( ?types ) {
|
public function new( ?types ) {
|
||||||
if( types == null ) types = new CheckerTypes();
|
if( types == null ) types = new CheckerTypes();
|
||||||
this.types = types;
|
this.types = types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setGlobals( cl : CClass ) {
|
||||||
|
while( true ) {
|
||||||
|
for( f in cl.fields )
|
||||||
|
if( f.isPublic )
|
||||||
|
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(function() return apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()])));
|
||||||
|
if( cl.superClass == null )
|
||||||
|
break;
|
||||||
|
cl = switch( cl.superClass ) {
|
||||||
|
case TInst(c,_): c;
|
||||||
|
default: throw "assert";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeGlobal( name : String ) {
|
||||||
|
globals.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
public function setGlobal( name : String, type : TType ) {
|
public function setGlobal( name : String, type : TType ) {
|
||||||
globals.set(name, type);
|
globals.set(name, type);
|
||||||
}
|
}
|
||||||
@@ -270,9 +333,54 @@ class Checker {
|
|||||||
return globals;
|
return globals;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function check( expr : Expr, ?withType : WithType ) {
|
function typeArgs( args : Array<Argument>, pos : Expr ) {
|
||||||
|
return [for( i in 0...args.length ) {
|
||||||
|
var a = args[i];
|
||||||
|
var at = a.t == null ? makeMono() : makeType(a.t, pos);
|
||||||
|
{ name : a.name, opt : a.opt, t : at };
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function check( expr : Expr, ?withType : WithType, ?isCompletion = false ) {
|
||||||
if( withType == null ) withType = NoValue;
|
if( withType == null ) withType = NoValue;
|
||||||
locals = new Map();
|
locals = new Map();
|
||||||
|
allowDefine = allowGlobalsDefine;
|
||||||
|
this.isCompletion = isCompletion;
|
||||||
|
switch( edef(expr) ) {
|
||||||
|
case EBlock(el):
|
||||||
|
var delayed = [];
|
||||||
|
var last = TVoid;
|
||||||
|
for( e in el ) {
|
||||||
|
while( true ) {
|
||||||
|
switch( edef(e) ) {
|
||||||
|
case EMeta(_,_,e2): e = e2;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch( edef(e) ) {
|
||||||
|
case EFunction(args,_,name,ret) if( name != null ):
|
||||||
|
var tret = ret == null ? makeMono() : makeType(ret, e);
|
||||||
|
var ft = TFun(typeArgs(args,e),tret);
|
||||||
|
locals.set(name, ft);
|
||||||
|
delayed.push(function() {
|
||||||
|
currentFunType = ft;
|
||||||
|
typeExpr(e, NoValue);
|
||||||
|
return ft;
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
for( f in delayed ) f();
|
||||||
|
delayed = [];
|
||||||
|
if( el[el.length-1] == e )
|
||||||
|
last = typeExpr(e, withType);
|
||||||
|
else
|
||||||
|
typeExpr(e, NoValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( f in delayed )
|
||||||
|
last = f();
|
||||||
|
return last;
|
||||||
|
default:
|
||||||
|
}
|
||||||
return typeExpr(expr,withType);
|
return typeExpr(expr,withType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +395,7 @@ class Checker {
|
|||||||
inline function error( msg : String, curExpr : Expr ) {
|
inline function error( msg : String, curExpr : Expr ) {
|
||||||
var e = ECustom(msg);
|
var e = ECustom(msg);
|
||||||
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
||||||
throw e;
|
if( !isCompletion ) throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveLocals() {
|
function saveLocals() {
|
||||||
@@ -297,8 +405,11 @@ class Checker {
|
|||||||
function makeType( t : CType, e : Expr ) : TType {
|
function makeType( t : CType, e : Expr ) : TType {
|
||||||
return switch (t) {
|
return switch (t) {
|
||||||
case CTPath(path, params):
|
case CTPath(path, params):
|
||||||
var ct = types.resolve(path.join("."),params == null ? [] : [for( p in params ) makeType(t,e)]);
|
var ct = types.resolve(path.join("."),params == null ? [] : [for( p in params ) makeType(p,e)]);
|
||||||
if( ct == null ) error("Unknown type "+path, e);
|
if( ct == null ) {
|
||||||
|
error("Unknown type "+path, e);
|
||||||
|
ct = TDynamic;
|
||||||
|
}
|
||||||
return ct;
|
return ct;
|
||||||
case CTFun(args, ret):
|
case CTFun(args, ret):
|
||||||
var i = 0;
|
var i = 0;
|
||||||
@@ -307,6 +418,10 @@ class Checker {
|
|||||||
return TAnon([for( f in fields ) { name : f.name, opt : false, t : makeType(f.t,e) }]);
|
return TAnon([for( f in fields ) { name : f.name, opt : false, t : makeType(f.t,e) }]);
|
||||||
case CTParent(t):
|
case CTParent(t):
|
||||||
return makeType(t,e);
|
return makeType(t,e);
|
||||||
|
case CTNamed(n, t):
|
||||||
|
return makeType(t,e);
|
||||||
|
case CTOpt(t):
|
||||||
|
return makeType(t,e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +431,11 @@ class Checker {
|
|||||||
case TMono(r): r.r == null ? "Unknown" : typeStr(r.r);
|
case TMono(r): r.r == null ? "Unknown" : typeStr(r.r);
|
||||||
case TInst(c, args): c.name + makeArgs(args);
|
case TInst(c, args): c.name + makeArgs(args);
|
||||||
case TEnum(e, args): e.name + makeArgs(args);
|
case TEnum(e, args): e.name + makeArgs(args);
|
||||||
case TType(t, args): t.name + makeArgs(args);
|
case TType(t, args):
|
||||||
|
if( t.name == "hscript.TypeCheck" )
|
||||||
|
typeStr(args[1]);
|
||||||
|
else
|
||||||
|
t.name + makeArgs(args);
|
||||||
case TAbstract(a, args): a.name + makeArgs(args);
|
case TAbstract(a, args): a.name + makeArgs(args);
|
||||||
case TFun(args, ret): "(" + [for( a in args ) (a.opt?"?":"")+(a.name == "" ? "" : a.name+":")+typeStr(a.t)].join(", ")+") -> "+typeStr(ret);
|
case TFun(args, ret): "(" + [for( a in args ) (a.opt?"?":"")+(a.name == "" ? "" : a.name+":")+typeStr(a.t)].join(", ")+") -> "+typeStr(ret);
|
||||||
case TAnon(fields): "{" + [for( f in fields ) (f.opt?"?":"")+f.name+":"+typeStr(f.t)].join(", ")+"}";
|
case TAnon(fields): "{" + [for( f in fields ) (f.opt?"?":"")+f.name+":"+typeStr(f.t)].join(", ")+"}";
|
||||||
@@ -478,6 +597,8 @@ class Checker {
|
|||||||
case [TDynamic, _]:
|
case [TDynamic, _]:
|
||||||
return true;
|
return true;
|
||||||
case [TAnon(a1),TAnon(a2)]:
|
case [TAnon(a1),TAnon(a2)]:
|
||||||
|
if( a2.length == 0 ) // always unify with {}
|
||||||
|
return true;
|
||||||
var m = new Map();
|
var m = new Map();
|
||||||
for( f in a1 )
|
for( f in a1 )
|
||||||
m.set(f.name, f);
|
m.set(f.name, f);
|
||||||
@@ -493,6 +614,18 @@ class Checker {
|
|||||||
return true;
|
return true;
|
||||||
case [TInst(cl1,pl1), TInst(cl2,pl2)]:
|
case [TInst(cl1,pl1), TInst(cl2,pl2)]:
|
||||||
while( cl1 != cl2 ) {
|
while( cl1 != cl2 ) {
|
||||||
|
if( cl1.interfaces != null ) {
|
||||||
|
for( i in cl1.interfaces ) {
|
||||||
|
switch( i ) {
|
||||||
|
case TInst(cli, args):
|
||||||
|
var i = TInst(cli, [for( a in args ) apply(a, cl1.params, pl1)]);
|
||||||
|
if( tryUnify(i, t2) )
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
throw "assert";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
switch( cl1.superClass ) {
|
switch( cl1.superClass ) {
|
||||||
case null: return false;
|
case null: return false;
|
||||||
case TInst(c, args):
|
case TInst(c, args):
|
||||||
@@ -505,6 +638,25 @@ class Checker {
|
|||||||
if( !typeEq(pl1[i],pl2[i]) )
|
if( !typeEq(pl1[i],pl2[i]) )
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
case [TInst(cl1,pl1),TAnon(fl)]:
|
||||||
|
for( i in 0...fl.length ) {
|
||||||
|
var f2 = fl[i];
|
||||||
|
var f1 = null;
|
||||||
|
var cl = cl1;
|
||||||
|
while( true ) {
|
||||||
|
f1 = cl.fields.get(f2.name);
|
||||||
|
if( f1 != null ) break;
|
||||||
|
if( cl.superClass == null )
|
||||||
|
return false;
|
||||||
|
cl = switch( cl.superClass ) {
|
||||||
|
case TInst(c,_): c;
|
||||||
|
default: throw "assert";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !typeEq(f1.t,f2.t) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
case [TInt, TFloat]:
|
case [TInt, TFloat]:
|
||||||
return true;
|
return true;
|
||||||
case [TFun(_), TAbstract({ name : "haxe.Function" },_)]:
|
case [TFun(_), TAbstract({ name : "haxe.Function" },_)]:
|
||||||
@@ -514,12 +666,12 @@ class Checker {
|
|||||||
return typeEq(t1,t2);
|
return typeEq(t1,t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unify( t1 : TType, t2 : TType, e : Expr ) {
|
public function unify( t1 : TType, t2 : TType, e : Expr ) {
|
||||||
if( !tryUnify(t1,t2) )
|
if( !tryUnify(t1,t2) )
|
||||||
error(typeStr(t1)+" should be "+typeStr(t2),e);
|
error(typeStr(t1)+" should be "+typeStr(t2),e);
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply( t : TType, params : Array<TType>, args : Array<TType> ) {
|
public function apply( t : TType, params : Array<TType>, args : Array<TType> ) {
|
||||||
if( args.length != params.length ) throw "Invalid number of type parameters";
|
if( args.length != params.length ) throw "Invalid number of type parameters";
|
||||||
if( args.length == 0 )
|
if( args.length == 0 )
|
||||||
return t;
|
return t;
|
||||||
@@ -557,40 +709,62 @@ class Checker {
|
|||||||
return TFun([for( a in args ) { name : a.name, opt : a.opt, t : f(a.t) }], f(ret));
|
return TFun([for( a in args ) { name : a.name, opt : a.opt, t : f(a.t) }], f(ret));
|
||||||
case TAnon(fields):
|
case TAnon(fields):
|
||||||
return TAnon([for( af in fields ) { name : af.name, opt : af.opt, t : f(af.t) }]);
|
return TAnon([for( af in fields ) { name : af.name, opt : af.opt, t : f(af.t) }]);
|
||||||
|
case TLazy(l):
|
||||||
|
return f(l());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function follow( t : TType ) {
|
public function follow( t : TType ) {
|
||||||
return switch( t ) {
|
return switch( t ) {
|
||||||
case TMono(r): if( r.r != null ) follow(r.r) else t;
|
case TMono(r): if( r.r != null ) follow(r.r) else t;
|
||||||
case TType(t,args): apply(t.t, t.params, args);
|
case TType(t,args): follow(apply(t.t, t.params, args));
|
||||||
case TNull(t): follow(t);
|
case TNull(t): follow(t);
|
||||||
|
case TLazy(f): follow(f());
|
||||||
default: t;
|
default: t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFields( t : TType ) {
|
public function getFields( t : TType ) : Array<{ name : String, t : TType }> {
|
||||||
var fields = [];
|
var fields = [];
|
||||||
while( t != null ) {
|
switch( follow(t) ) {
|
||||||
t = follow(t);
|
|
||||||
switch( t ) {
|
|
||||||
case TInst(c, args):
|
case TInst(c, args):
|
||||||
|
var map = (t) -> apply(t,c.params,args);
|
||||||
|
while( c != null ) {
|
||||||
for( fname in c.fields.keys() ) {
|
for( fname in c.fields.keys() ) {
|
||||||
var f = c.fields.get(fname);
|
var f = c.fields.get(fname);
|
||||||
fields.push({ name : f.name, t : f.t });
|
if( !f.isPublic || !f.complete ) continue;
|
||||||
|
var name = f.name, t = map(f.t);
|
||||||
|
if( allowAsync && StringTools.startsWith(name,"a_") ) {
|
||||||
|
t = unasync(t);
|
||||||
|
name = name.substr(2);
|
||||||
|
}
|
||||||
|
fields.push({ name : name, t : t });
|
||||||
|
}
|
||||||
|
if( c.isInterface && c.interfaces != null ) {
|
||||||
|
for( i in c.interfaces ) {
|
||||||
|
for( f in getFields(i) )
|
||||||
|
fields.push({ name : f.name, t : map(f.t) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( c.superClass == null ) break;
|
||||||
|
switch( c.superClass ) {
|
||||||
|
case TInst(csup,args):
|
||||||
|
var curMap = map;
|
||||||
|
map = (t) -> curMap(apply(t,csup.params,args));
|
||||||
|
c = csup;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t = c.superClass;
|
|
||||||
case TAnon(fl):
|
case TAnon(fl):
|
||||||
for( f in fl )
|
for( f in fl )
|
||||||
fields.push({ name : f.name, t : f.t });
|
fields.push({ name : f.name, t : f.t });
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getField( t : TType, f : String, e : Expr ) {
|
function getField( t : TType, f : String, e : Expr, forWrite = false ) {
|
||||||
switch( follow(t) ) {
|
switch( follow(t) ) {
|
||||||
case TInst(c, args):
|
case TInst(c, args):
|
||||||
var cf = c.fields.get(f);
|
var cf = c.fields.get(f);
|
||||||
@@ -598,19 +772,30 @@ class Checker {
|
|||||||
cf = c.fields.get("a_"+f);
|
cf = c.fields.get("a_"+f);
|
||||||
if( cf != null ) {
|
if( cf != null ) {
|
||||||
var isPublic = true; // consider a_ prefixed as script specific
|
var isPublic = true; // consider a_ prefixed as script specific
|
||||||
cf = { isPublic : isPublic, params : cf.params, name : cf.name, t : unasync(cf.t) };
|
cf = { isPublic : isPublic, canWrite : false, params : cf.params, name : cf.name, t : unasync(cf.t), complete : cf.complete };
|
||||||
if( cf.t == null ) cf = null;
|
if( cf.t == null ) cf = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( cf == null && c.isInterface && c.interfaces != null ) {
|
||||||
|
for( i in c.interfaces ) {
|
||||||
|
var ft = getField(i, f, e, forWrite);
|
||||||
|
if( ft != null )
|
||||||
|
return apply(ft, c.params, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
if( cf == null ) {
|
if( cf == null ) {
|
||||||
if( c.superClass == null ) return null;
|
if( c.superClass == null ) return null;
|
||||||
var ft = getField(c.superClass, f, e);
|
var ft = getField(c.superClass, f, e, forWrite);
|
||||||
if( ft != null ) ft = apply(ft, c.params, args);
|
if( ft != null ) ft = apply(ft, c.params, args);
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
if( !cf.isPublic )
|
if( !cf.isPublic )
|
||||||
error("Can't access private field "+f+" on "+c.name, e);
|
error("Can't access private field "+f+" on "+c.name, e);
|
||||||
return apply(cf.t, c.params, args);
|
if( forWrite && !cf.canWrite )
|
||||||
|
error("Can't write readonly field "+f+" on "+c.name, e);
|
||||||
|
var t = cf.t;
|
||||||
|
if( cf.params != null ) t = apply(t, cf.params, [for( i in 0...cf.params.length ) makeMono()]);
|
||||||
|
return apply(t, c.params, args);
|
||||||
case TDynamic:
|
case TDynamic:
|
||||||
return makeMono();
|
return makeMono();
|
||||||
case TAnon(fields):
|
case TAnon(fields):
|
||||||
@@ -663,7 +848,28 @@ class Checker {
|
|||||||
return t.match(TInst({name:"String"},_));
|
return t.match(TInst({name:"String"},_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCompletion( expr : Expr, t : TType ) {
|
||||||
|
if( isCompletion ) throw new Completion(expr, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
function typeField( o : Expr, f : String, expr : Expr, forWrite : Bool ) {
|
||||||
|
var ot = typeExpr(o, Value);
|
||||||
|
if( f == null )
|
||||||
|
onCompletion(expr, ot);
|
||||||
|
var ft = getField(ot, f, expr, forWrite);
|
||||||
|
if( ft == null ) {
|
||||||
|
error(typeStr(ot)+" has no field "+f, expr);
|
||||||
|
ft = TDynamic;
|
||||||
|
}
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
|
||||||
function typeExpr( expr : Expr, withType : WithType ) : TType {
|
function typeExpr( expr : Expr, withType : WithType ) : TType {
|
||||||
|
if( expr == null && isCompletion )
|
||||||
|
return switch( withType ) {
|
||||||
|
case WithType(t): t;
|
||||||
|
default: TDynamic;
|
||||||
|
}
|
||||||
switch( edef(expr) ) {
|
switch( edef(expr) ) {
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
return switch (c) {
|
return switch (c) {
|
||||||
@@ -675,7 +881,12 @@ class Checker {
|
|||||||
var l = locals.get(v);
|
var l = locals.get(v);
|
||||||
if( l != null ) return l;
|
if( l != null ) return l;
|
||||||
var g = globals.get(v);
|
var g = globals.get(v);
|
||||||
if( g != null ) return g;
|
if( g != null ) {
|
||||||
|
return switch( g ) {
|
||||||
|
case TLazy(f): f();
|
||||||
|
default: g;
|
||||||
|
}
|
||||||
|
}
|
||||||
if( allowAsync ) {
|
if( allowAsync ) {
|
||||||
g = globals.get("a_"+v);
|
g = globals.get("a_"+v);
|
||||||
if( g != null ) g = unasync(g);
|
if( g != null ) g = unasync(g);
|
||||||
@@ -689,6 +900,7 @@ class Checker {
|
|||||||
case "trace":
|
case "trace":
|
||||||
return TDynamic;
|
return TDynamic;
|
||||||
default:
|
default:
|
||||||
|
if( isCompletion) return TDynamic;
|
||||||
error("Unknown identifier "+v, expr);
|
error("Unknown identifier "+v, expr);
|
||||||
}
|
}
|
||||||
case EBlock(el):
|
case EBlock(el):
|
||||||
@@ -714,32 +926,34 @@ class Checker {
|
|||||||
case TFun(args, ret):
|
case TFun(args, ret):
|
||||||
for( i in 0...params.length ) {
|
for( i in 0...params.length ) {
|
||||||
var a = args[i];
|
var a = args[i];
|
||||||
if( a == null ) error("Too many arguments", params[i]);
|
if( a == null ) {
|
||||||
var t = typeExpr(params[i], WithType(a.t));
|
error("Too many arguments", params[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var t = typeExpr(params[i], a == null ? Value : WithType(a.t));
|
||||||
unify(t, a.t, params[i]);
|
unify(t, a.t, params[i]);
|
||||||
}
|
}
|
||||||
for( i in params.length...args.length )
|
for( i in params.length...args.length )
|
||||||
if( !args[i].opt )
|
if( !args[i].opt )
|
||||||
error("Missing argument '"+args[i].name+"'", expr);
|
error("Missing argument "+args[i].name+":"+typeStr(args[i].t), expr);
|
||||||
return ret;
|
return ret;
|
||||||
case TDynamic:
|
case TDynamic:
|
||||||
for( p in params ) typeExpr(p,Value);
|
for( p in params ) typeExpr(p,Value);
|
||||||
return TDynamic;
|
return makeMono();
|
||||||
default:
|
default:
|
||||||
error(typeStr(ft)+" cannot be called", e);
|
error(typeStr(ft)+" cannot be called", e);
|
||||||
|
return makeMono();
|
||||||
}
|
}
|
||||||
case EField(o, f):
|
case EField(o, f):
|
||||||
var ot = typeExpr(o, Value);
|
return typeField(o,f,expr,false);
|
||||||
var ft = getField(ot, f, expr);
|
|
||||||
if( ft == null )
|
|
||||||
error(typeStr(ot)+" has no field "+f, expr);
|
|
||||||
return ft;
|
|
||||||
case ECheckType(v, t):
|
case ECheckType(v, t):
|
||||||
var ct = makeType(t, expr);
|
var ct = makeType(t, expr);
|
||||||
var vt = typeExpr(v, WithType(ct));
|
var vt = typeExpr(v, WithType(ct));
|
||||||
unify(vt, ct, v);
|
unify(vt, ct, v);
|
||||||
return ct;
|
return ct;
|
||||||
case EMeta(_, _, e):
|
case EMeta(m, _, e):
|
||||||
|
if( m == ":untyped" && allowUntypedMeta )
|
||||||
|
return makeMono();
|
||||||
return typeExpr(e, withType);
|
return typeExpr(e, withType);
|
||||||
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
|
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
|
||||||
typeExprWith(cond, TBool);
|
typeExprWith(cond, TBool);
|
||||||
@@ -760,17 +974,20 @@ class Checker {
|
|||||||
return TVoid;
|
return TVoid;
|
||||||
case EObject(fl):
|
case EObject(fl):
|
||||||
switch( withType ) {
|
switch( withType ) {
|
||||||
case WithType(follow(_) => TAnon(tfields)):
|
case WithType(follow(_) => TAnon(tfields)) if( tfields.length > 0 ):
|
||||||
var map = [for( f in tfields ) f.name => f];
|
var map = [for( f in tfields ) f.name => f];
|
||||||
return TAnon([for( f in fl ) {
|
return TAnon([for( f in fl ) {
|
||||||
var ft = map.get(f.name);
|
var ft = map.get(f.name);
|
||||||
if( ft == null ) error("Extra field "+f.name, f.e);
|
var ft = if( ft == null ) {
|
||||||
{ t : typeExprWith(f.e, ft.t), opt : false, name : f.name }
|
error("Extra field "+f.name, f.e);
|
||||||
|
TDynamic;
|
||||||
|
} else ft.t;
|
||||||
|
{ t : typeExprWith(f.e, ft), opt : false, name : f.name }
|
||||||
}]);
|
}]);
|
||||||
default:
|
default:
|
||||||
return TAnon([for( f in fl ) { t : typeExpr(f.e, Value), opt : false, name : f.name }]);
|
return TAnon([for( f in fl ) { t : typeExpr(f.e, Value), opt : false, name : f.name }]);
|
||||||
}
|
}
|
||||||
case EBreak, EContinue:
|
case EBreak, EContinue, EImport(_):
|
||||||
return TVoid;
|
return TVoid;
|
||||||
case EReturn(v):
|
case EReturn(v):
|
||||||
var et = v == null ? TVoid : typeExpr(v, allowReturn == null ? Value : WithType(allowReturn));
|
var et = v == null ? TVoid : typeExpr(v, allowReturn == null ? Value : WithType(allowReturn));
|
||||||
@@ -778,7 +995,7 @@ class Checker {
|
|||||||
error("Return not allowed here", expr);
|
error("Return not allowed here", expr);
|
||||||
else
|
else
|
||||||
unify(et, allowReturn, v == null ? expr : v);
|
unify(et, allowReturn, v == null ? expr : v);
|
||||||
return TDynamic;
|
return makeMono();
|
||||||
case EArrayDecl(el):
|
case EArrayDecl(el):
|
||||||
var et = null;
|
var et = null;
|
||||||
for( v in el ) {
|
for( v in el ) {
|
||||||
@@ -787,7 +1004,7 @@ class Checker {
|
|||||||
if( tryUnify(et,t) ) et = t else unify(t,et,v);
|
if( tryUnify(et,t) ) et = t else unify(t,et,v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( et == null ) et = TDynamic;
|
if( et == null ) et = makeMono();
|
||||||
return types.getType("Array",[et]);
|
return types.getType("Array",[et]);
|
||||||
case EArray(a, index):
|
case EArray(a, index):
|
||||||
typeExprWith(index, TInt);
|
typeExprWith(index, TInt);
|
||||||
@@ -798,12 +1015,26 @@ class Checker {
|
|||||||
}
|
}
|
||||||
case EThrow(e):
|
case EThrow(e):
|
||||||
typeExpr(e, Value);
|
typeExpr(e, Value);
|
||||||
return TDynamic;
|
return makeMono();
|
||||||
case EFunction(args, body, name, ret):
|
case EFunction(args, body, name, ret):
|
||||||
var tret = ret == null ? makeMono() : makeType(ret, expr);
|
var ft = null, tret = null, targs = null;
|
||||||
|
if( currentFunType != null ) {
|
||||||
|
switch( currentFunType ) {
|
||||||
|
case TFun(args,ret):
|
||||||
|
ft = currentFunType;
|
||||||
|
tret = ret; targs = args;
|
||||||
|
default:
|
||||||
|
throw "assert";
|
||||||
|
}
|
||||||
|
currentFunType = null;
|
||||||
|
} else {
|
||||||
|
tret = ret == null ? makeMono() : makeType(ret, expr);
|
||||||
|
}
|
||||||
var locals = saveLocals();
|
var locals = saveLocals();
|
||||||
var oldRet = allowReturn;
|
var oldRet = allowReturn;
|
||||||
|
var oldGDef = allowDefine;
|
||||||
allowReturn = tret;
|
allowReturn = tret;
|
||||||
|
allowDefine = false;
|
||||||
var withArgs = null;
|
var withArgs = null;
|
||||||
if( name != null && !withType.match(WithType(follow(_) => TFun(_))) ) {
|
if( name != null && !withType.match(WithType(follow(_) => TFun(_))) ) {
|
||||||
var ev = events.get(name);
|
var ev = events.get(name);
|
||||||
@@ -813,26 +1044,33 @@ class Checker {
|
|||||||
case WithType(follow(_) => TFun(args,ret)): withArgs = args; unify(tret,ret,expr);
|
case WithType(follow(_) => TFun(args,ret)): withArgs = args; unify(tret,ret,expr);
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
var targs = [for( i in 0...args.length ) {
|
if( targs == null )
|
||||||
var a = args[i];
|
targs = typeArgs(args,expr);
|
||||||
var at = a.t == null ? makeMono() : makeType(a.t, expr);
|
for( i in 0...targs.length ) {
|
||||||
if( withArgs != null && withArgs.length > i )
|
var a = targs[i];
|
||||||
unify(withArgs[i].t, at, expr);
|
if( withArgs != null ) {
|
||||||
this.locals.set(a.name, at);
|
if( i < withArgs.length )
|
||||||
{ name : a.name, opt : a.opt, t : at };
|
unify(withArgs[i].t, a.t, expr);
|
||||||
}];
|
else
|
||||||
|
error("Extra argument "+a.name, expr);
|
||||||
|
}
|
||||||
|
this.locals.set(a.name, a.t);
|
||||||
|
}
|
||||||
|
if( withArgs != null && targs.length < withArgs.length )
|
||||||
|
error("Missing "+(withArgs.length - targs.length)+" arguments ("+[for( i in targs.length...withArgs.length ) typeStr(withArgs[i].t)].join(",")+")", expr);
|
||||||
typeExpr(body,NoValue);
|
typeExpr(body,NoValue);
|
||||||
|
allowDefine = oldGDef;
|
||||||
allowReturn = oldRet;
|
allowReturn = oldRet;
|
||||||
this.locals = locals;
|
this.locals = locals;
|
||||||
var ft = TFun(targs,tret);
|
if( ft == null ) {
|
||||||
if( name != null )
|
ft = TFun(targs, tret);
|
||||||
locals.set(name, ft);
|
locals.set(name, ft);
|
||||||
|
}
|
||||||
return ft;
|
return ft;
|
||||||
case EUnop(op, _, e):
|
case EUnop(op, _, e):
|
||||||
var et = typeExpr(e, Value);
|
var et = typeExpr(e, Value);
|
||||||
switch( op ) {
|
switch( op ) {
|
||||||
case "++", "--":
|
case "++", "--", "-":
|
||||||
unify(et,TInt,e);
|
unify(et,TInt,e);
|
||||||
return et;
|
return et;
|
||||||
case "!":
|
case "!":
|
||||||
@@ -847,13 +1085,27 @@ class Checker {
|
|||||||
case TInst({name:"Array"},[t]):
|
case TInst({name:"Array"},[t]):
|
||||||
t;
|
t;
|
||||||
default:
|
default:
|
||||||
|
var ft = getField(itt,"iterator", it);
|
||||||
|
if( ft == null )
|
||||||
|
switch( itt ) {
|
||||||
|
case TAbstract(a, args):
|
||||||
|
// special case : we allow unconditional access
|
||||||
|
// to an abstract iterator() underlying value (eg: ArrayProxy)
|
||||||
|
ft = getField(apply(a.t,a.params,args),"iterator",it);
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if( ft != null )
|
||||||
|
switch( ft ) {
|
||||||
|
case TFun([],ret): ft = ret;
|
||||||
|
default: ft = null;
|
||||||
|
}
|
||||||
var t = makeMono();
|
var t = makeMono();
|
||||||
var iter = makeIterator(t);
|
var iter = makeIterator(t);
|
||||||
unify(itt,iter,it);
|
unify(ft != null ? ft : itt,iter,it);
|
||||||
t;
|
t;
|
||||||
}
|
}
|
||||||
this.locals.set(v, vt);
|
this.locals.set(v, vt);
|
||||||
typeExpr(e, Value);
|
typeExpr(e, NoValue);
|
||||||
this.locals = locals;
|
this.locals = locals;
|
||||||
return TVoid;
|
return TVoid;
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
@@ -863,7 +1115,19 @@ class Checker {
|
|||||||
typeExprWith(e2,TInt);
|
typeExprWith(e2,TInt);
|
||||||
return TInt;
|
return TInt;
|
||||||
case "=":
|
case "=":
|
||||||
var vt = typeExpr(e1, Value);
|
if( allowDefine ) {
|
||||||
|
switch( edef(e1) ) {
|
||||||
|
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
|
||||||
|
var vt = typeExpr(e2,Value);
|
||||||
|
locals.set(i, vt);
|
||||||
|
return vt;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var vt = switch( edef(e1) ) {
|
||||||
|
case EField(o,f): typeField(o, f, e1, true);
|
||||||
|
default: typeExpr(e1,Value);
|
||||||
|
}
|
||||||
typeExprWith(e2,vt);
|
typeExprWith(e2,vt);
|
||||||
return vt;
|
return vt;
|
||||||
case "+":
|
case "+":
|
||||||
@@ -930,11 +1194,49 @@ class Checker {
|
|||||||
}
|
}
|
||||||
error("Unsupported operation "+op, expr);
|
error("Unsupported operation "+op, expr);
|
||||||
}
|
}
|
||||||
|
case ETry(etry, v, et, ecatch):
|
||||||
|
var vt = typeExpr(etry, withType);
|
||||||
|
|
||||||
|
var old = locals.get(v);
|
||||||
|
locals.set(v, makeType(et, ecatch));
|
||||||
|
var ct = typeExpr(ecatch, withType);
|
||||||
|
if( old != null ) locals.set(v,old) else locals.remove(v);
|
||||||
|
|
||||||
|
if( withType == NoValue )
|
||||||
|
return TVoid;
|
||||||
|
if( tryUnify(vt,ct) )
|
||||||
|
return ct;
|
||||||
|
unify(ct,vt,ecatch);
|
||||||
|
return vt;
|
||||||
|
case ESwitch(value, cases, defaultExpr):
|
||||||
|
var tmin = null;
|
||||||
|
var vt = typeExpr(value, Value);
|
||||||
|
inline function mergeType(t,p) {
|
||||||
|
if( withType != NoValue ) {
|
||||||
|
if( tmin == null )
|
||||||
|
tmin = t;
|
||||||
|
else if( !tryUnify(t,tmin) ) {
|
||||||
|
unify(tmin,t, p);
|
||||||
|
tmin = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( c in cases ) {
|
||||||
|
for( v in c.values ) {
|
||||||
|
var ct = typeExpr(v, WithType(vt));
|
||||||
|
unify(ct, vt, v);
|
||||||
|
}
|
||||||
|
var et = typeExpr(c.expr, withType);
|
||||||
|
mergeType(et, c.expr);
|
||||||
|
}
|
||||||
|
if( defaultExpr != null )
|
||||||
|
mergeType( typeExpr(defaultExpr, withType), defaultExpr);
|
||||||
|
return withType == NoValue ? TVoid : tmin == null ? makeMono() : tmin;
|
||||||
case ENew(cl, params):
|
case ENew(cl, params):
|
||||||
case ETry(e, v, t, ecatch):
|
default:
|
||||||
case ESwitch(e, cases, defaultExpr):
|
|
||||||
}
|
}
|
||||||
error("Don't know how to type "+edef(expr).getName(), expr);
|
error("Don't know how to type "+edef(expr).getName(), expr);
|
||||||
|
return TDynamic;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
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 = [
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
class CustomClassHandler implements IHScriptCustomConstructor {
|
||||||
|
public static var staticHandler = new StaticHandler();
|
||||||
|
|
||||||
|
public var ogInterp:Interp;
|
||||||
|
public var name:String;
|
||||||
|
public var fields:Array<Expr>;
|
||||||
|
public var extend:String;
|
||||||
|
public var interfaces:Array<String>;
|
||||||
|
|
||||||
|
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
|
||||||
|
this.ogInterp = ogInterp;
|
||||||
|
this.name = name;
|
||||||
|
this.fields = fields;
|
||||||
|
this.extend = extend;
|
||||||
|
this.interfaces = interfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hnew(args:Array<Dynamic>):Dynamic {
|
||||||
|
var interp = new Interp();
|
||||||
|
|
||||||
|
interp.errorHandler = ogInterp.errorHandler;
|
||||||
|
|
||||||
|
var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
|
||||||
|
if(cl == null)
|
||||||
|
ogInterp.error(EInvalidClass(extend));
|
||||||
|
|
||||||
|
var _class = Type.createInstance(cl, args);
|
||||||
|
|
||||||
|
var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
|
||||||
|
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
|
||||||
|
for(k=>e in __capturedLocals)
|
||||||
|
if (e != null && e.depth <= 0)
|
||||||
|
capturedLocals.set(k, e);
|
||||||
|
|
||||||
|
var disallowCopy = Type.getInstanceFields(cl);
|
||||||
|
|
||||||
|
for (key => value in capturedLocals) {
|
||||||
|
if(!disallowCopy.contains(key)) {
|
||||||
|
interp.locals.set(key, {r: value, depth: -1});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (key => value in ogInterp.variables) {
|
||||||
|
if(!disallowCopy.contains(key)) {
|
||||||
|
interp.variables.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(expr in fields) {
|
||||||
|
@:privateAccess
|
||||||
|
interp.exprReturn(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
interp.variables.set("super", staticHandler);
|
||||||
|
|
||||||
|
_class.__interp = interp;
|
||||||
|
interp.scriptObject = _class;
|
||||||
|
|
||||||
|
var newFunc = interp.variables.get("new");
|
||||||
|
if(newFunc != null) {
|
||||||
|
Reflect.callMethod(null, newFunc, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(variable => value in interp.variables) {
|
||||||
|
if(variable == "this") continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TemplateClass implements IHScriptCustomBehaviour {
|
||||||
|
public var __interp:Interp;
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
if(this.__interp.variables.exists("set_" + name)) {
|
||||||
|
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
|
||||||
|
}
|
||||||
|
if (this.__interp.variables.exists(name)) {
|
||||||
|
this.__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
Reflect.setProperty(this, name, val);
|
||||||
|
return Reflect.field(this, name);
|
||||||
|
}
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
if(this.__interp.variables.exists("get_" + name))
|
||||||
|
return this.__interp.variables.get("get_" + name)();
|
||||||
|
if (this.__interp.variables.exists(name))
|
||||||
|
return this.__interp.variables.get(name);
|
||||||
|
return Reflect.getProperty(this, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StaticHandler {
|
||||||
|
public function new() {}
|
||||||
|
}
|
||||||
+10
-5
@@ -45,22 +45,22 @@ enum Expr {
|
|||||||
#end
|
#end
|
||||||
EConst( c : Const );
|
EConst( c : Const );
|
||||||
EIdent( v : String );
|
EIdent( v : String );
|
||||||
EVar( n : String, ?t : CType, ?e : Expr );
|
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool );
|
||||||
EParent( e : Expr );
|
EParent( e : Expr );
|
||||||
EBlock( e : Array<Expr> );
|
EBlock( e : Array<Expr> );
|
||||||
EField( e : Expr, f : String );
|
EField( e : Expr, f : String , ?safe : Bool );
|
||||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||||
EUnop( op : String, prefix : Bool, e : Expr );
|
EUnop( op : String, prefix : Bool, e : Expr );
|
||||||
ECall( e : Expr, params : Array<Expr> );
|
ECall( e : Expr, params : Array<Expr> );
|
||||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||||
EWhile( cond : Expr, e : Expr );
|
EWhile( cond : Expr, e : Expr );
|
||||||
EFor( v : String, it : Expr, e : Expr );
|
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||||
EBreak;
|
EBreak;
|
||||||
EContinue;
|
EContinue;
|
||||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType );
|
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool );
|
||||||
EReturn( ?e : Expr );
|
EReturn( ?e : Expr );
|
||||||
EArray( e : Expr, index : Expr );
|
EArray( e : Expr, index : Expr );
|
||||||
EArrayDecl( e : Array<Expr> );
|
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||||
ENew( cl : String, params : Array<Expr> );
|
ENew( cl : String, params : Array<Expr> );
|
||||||
EThrow( e : Expr );
|
EThrow( e : Expr );
|
||||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||||
@@ -70,6 +70,9 @@ enum Expr {
|
|||||||
EDoWhile( cond : Expr, e : Expr);
|
EDoWhile( cond : Expr, e : Expr);
|
||||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||||
ECheckType( e : Expr, t : CType );
|
ECheckType( e : Expr, t : CType );
|
||||||
|
|
||||||
|
EImport( c : String, ?asname:String );
|
||||||
|
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||||
@@ -117,6 +120,8 @@ enum Error {
|
|||||||
EInvalidOp( op : String );
|
EInvalidOp( op : String );
|
||||||
EInvalidAccess( f : String );
|
EInvalidAccess( f : String );
|
||||||
ECustom( msg : String );
|
ECustom( msg : String );
|
||||||
|
EInvalidClass( className : String);
|
||||||
|
EAlreadyExistingClass( className : String);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
interface IHScriptCustomBehaviour {
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic;
|
||||||
|
public function hget(name:String):Dynamic;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
interface IHScriptCustomConstructor {
|
||||||
|
public function hnew(args:Array<Dynamic>):Dynamic;
|
||||||
|
}
|
||||||
+505
-106
@@ -19,9 +19,23 @@
|
|||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
* DEALINGS IN THE SOFTWARE.
|
* DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* YoshiCrafter Engine fixes:
|
||||||
|
* - Added Error handler
|
||||||
|
* - Added Imports
|
||||||
|
* - Added @:bypassAccessor
|
||||||
|
*/
|
||||||
package hscript;
|
package hscript;
|
||||||
|
|
||||||
|
import haxe.iterators.StringKeyValueIteratorUnicode;
|
||||||
|
import haxe.EnumTools;
|
||||||
|
import haxe.display.Protocol.InitializeResult;
|
||||||
import haxe.PosInfos;
|
import haxe.PosInfos;
|
||||||
import hscript.Expr;
|
import hscript.Expr;
|
||||||
|
import haxe.Constraints.IMap;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
private enum Stop {
|
private enum Stop {
|
||||||
SBreak;
|
SBreak;
|
||||||
@@ -30,45 +44,86 @@ private enum Stop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Interp {
|
class Interp {
|
||||||
|
public var scriptObject(default, set):Dynamic;
|
||||||
|
public function set_scriptObject(v:Dynamic) {
|
||||||
|
__instanceFields = (v == null) ? [] : Type.getInstanceFields(Type.getClass(v));
|
||||||
|
return scriptObject = v;
|
||||||
|
}
|
||||||
|
public var errorHandler:Error->Void;
|
||||||
|
public var importFailedCallback:Array<String>->Bool;
|
||||||
#if haxe3
|
#if haxe3
|
||||||
|
public var customClasses:Map<String, Dynamic>;
|
||||||
public var variables:Map<String, Dynamic>;
|
public var variables:Map<String, Dynamic>;
|
||||||
var locals : Map<String,{ r : Dynamic }>;
|
public var publicVariables:Map<String, Dynamic>;
|
||||||
|
public var staticVariables:Map<String, Dynamic>;
|
||||||
|
|
||||||
|
public var locals:Map<String, {r:Dynamic, depth:Int}>;
|
||||||
var binops:Map<String, Expr->Expr->Dynamic>;
|
var binops:Map<String, Expr->Expr->Dynamic>;
|
||||||
#else
|
#else
|
||||||
|
public var customClasses:Hash<Dynamic>;
|
||||||
public var variables:Hash<Dynamic>;
|
public var variables:Hash<Dynamic>;
|
||||||
var locals : Hash<{ r : Dynamic }>;
|
public var publicVariables:Hash<Dynamic>;
|
||||||
|
public var staticVariables:Hash<Dynamic>;
|
||||||
|
|
||||||
|
public var locals:Hash<{r:Dynamic, depth:Int}>;
|
||||||
var binops:Hash<Expr->Expr->Dynamic>;
|
var binops:Hash<Expr->Expr->Dynamic>;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
var depth : Int;
|
var depth:Int = 0;
|
||||||
var inTry:Bool;
|
var inTry:Bool;
|
||||||
var declared : Array<{ n : String, old : { r : Dynamic } }>;
|
var declared:Array<{n:String, old:{r:Dynamic, depth:Int}, depth:Int}>;
|
||||||
var returnValue:Dynamic;
|
var returnValue:Dynamic;
|
||||||
|
|
||||||
|
var isBypassAccessor:Bool = false;
|
||||||
|
|
||||||
|
public var importEnabled:Bool = true;
|
||||||
|
|
||||||
|
public var allowStaticVariables:Bool = false;
|
||||||
|
public var allowPublicVariables:Bool = false;
|
||||||
|
|
||||||
|
public var importBlocklist:Array<String> = [
|
||||||
|
// "flixel.FlxG"
|
||||||
|
];
|
||||||
|
|
||||||
|
var __instanceFields:Array<String> = [];
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
var curExpr:Expr;
|
var curExpr:Expr;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
#if haxe3
|
#if haxe3
|
||||||
variables = new Map<String,Dynamic>();
|
|
||||||
locals = new Map();
|
locals = new Map();
|
||||||
#else
|
#else
|
||||||
variables = new Hash();
|
|
||||||
locals = new Hash();
|
locals = new Hash();
|
||||||
#end
|
#end
|
||||||
declared = new Array();
|
declared = new Array();
|
||||||
|
resetVariables();
|
||||||
|
initOps();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resetVariables() {
|
||||||
|
#if haxe3
|
||||||
|
customClasses = new Map<String, Dynamic>();
|
||||||
|
variables = new Map<String, Dynamic>();
|
||||||
|
publicVariables = new Map<String, Dynamic>();
|
||||||
|
staticVariables = new Map<String, Dynamic>();
|
||||||
|
#else
|
||||||
|
customClasses = new Hash();
|
||||||
|
variables = new Hash();
|
||||||
|
publicVariables = new Hash();
|
||||||
|
staticVariables = new Hash();
|
||||||
|
#end
|
||||||
|
|
||||||
variables.set("null", null);
|
variables.set("null", null);
|
||||||
variables.set("true", true);
|
variables.set("true", true);
|
||||||
variables.set("false", false);
|
variables.set("false", false);
|
||||||
variables.set("trace", Reflect.makeVarArgs(function(el) {
|
variables.set("trace", Reflect.makeVarArgs(function(el) {
|
||||||
var inf = posInfos();
|
var inf = posInfos();
|
||||||
var v = el.shift();
|
var v = el.shift();
|
||||||
if( el.length > 0 ) inf.customParams = el;
|
if (el.length > 0)
|
||||||
|
inf.customParams = el;
|
||||||
haxe.Log.trace(Std.string(v), inf);
|
haxe.Log.trace(Std.string(v), inf);
|
||||||
}));
|
}));
|
||||||
initOps();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function posInfos():PosInfos {
|
public function posInfos():PosInfos {
|
||||||
@@ -105,8 +160,18 @@ class Interp {
|
|||||||
binops.set("<", function(e1, e2) return me.expr(e1) < me.expr(e2));
|
binops.set("<", function(e1, e2) return me.expr(e1) < me.expr(e2));
|
||||||
binops.set("||", function(e1, e2) return me.expr(e1) == true || me.expr(e2) == true);
|
binops.set("||", function(e1, e2) return me.expr(e1) == true || me.expr(e2) == true);
|
||||||
binops.set("&&", function(e1, e2) return me.expr(e1) == true && me.expr(e2) == true);
|
binops.set("&&", function(e1, e2) return me.expr(e1) == true && me.expr(e2) == true);
|
||||||
|
binops.set("is", checkIsType);
|
||||||
binops.set("=", assign);
|
binops.set("=", assign);
|
||||||
binops.set("...",function(e1,e2) return new #if (haxe_211 || haxe3) IntIterator #else IntIter #end(me.expr(e1),me.expr(e2)));
|
binops.set("??", function(e1, e2) {
|
||||||
|
var expr1:Dynamic = me.expr(e1);
|
||||||
|
return expr1 == null ? me.expr(e2) : expr1;
|
||||||
|
});
|
||||||
|
binops.set("...", function(e1, e2) return new
|
||||||
|
#if (haxe_211 || haxe3)
|
||||||
|
IntIterator
|
||||||
|
#else
|
||||||
|
IntIter
|
||||||
|
#end(me.expr(e1), me.expr(e2)));
|
||||||
assignOp("+=", function(v1:Dynamic, v2:Dynamic) return v1 + v2);
|
assignOp("+=", function(v1:Dynamic, v2:Dynamic) return v1 + v2);
|
||||||
assignOp("-=", function(v1:Float, v2:Float) return v1 - v2);
|
assignOp("-=", function(v1:Float, v2:Float) return v1 - v2);
|
||||||
assignOp("*=", function(v1:Float, v2:Float) return v1 * v2);
|
assignOp("*=", function(v1:Float, v2:Float) return v1 * v2);
|
||||||
@@ -118,6 +183,31 @@ class Interp {
|
|||||||
assignOp("<<=", function(v1, v2) return v1 << v2);
|
assignOp("<<=", function(v1, v2) return v1 << v2);
|
||||||
assignOp(">>=", function(v1, v2) return v1 >> v2);
|
assignOp(">>=", function(v1, v2) return v1 >> v2);
|
||||||
assignOp(">>>=", function(v1, v2) return v1 >>> v2);
|
assignOp(">>>=", function(v1, v2) return v1 >>> v2);
|
||||||
|
assignOp("??" + "=", function(v1, v2) return v1 == null ? v2 : v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkIsType(e1,e2): Bool {
|
||||||
|
var expr1:Dynamic = expr(e1);
|
||||||
|
|
||||||
|
return switch(Tools.expr(e2))
|
||||||
|
{
|
||||||
|
case EIdent("Class"):
|
||||||
|
Std.isOfType(expr1, Class);
|
||||||
|
case EIdent("Map") | EIdent("IMap"):
|
||||||
|
Std.isOfType(expr1, IMap);
|
||||||
|
default:
|
||||||
|
var expr2:Dynamic = expr(e2);
|
||||||
|
expr2 != null ? Std.isOfType(expr1, expr2) : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setVar(name:String, v:Dynamic) {
|
||||||
|
if (allowStaticVariables && staticVariables.exists(name))
|
||||||
|
staticVariables.set(name, v);
|
||||||
|
else if (allowPublicVariables && publicVariables.exists(name))
|
||||||
|
publicVariables.set(name, v);
|
||||||
|
else
|
||||||
|
variables.set(name, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assign(e1:Expr, e2:Expr):Dynamic {
|
function assign(e1:Expr, e2:Expr):Dynamic {
|
||||||
@@ -125,19 +215,45 @@ class Interp {
|
|||||||
switch (Tools.expr(e1)) {
|
switch (Tools.expr(e1)) {
|
||||||
case EIdent(id):
|
case EIdent(id):
|
||||||
var l = locals.get(id);
|
var l = locals.get(id);
|
||||||
if( l == null )
|
if (l == null) {
|
||||||
variables.set(id,v)
|
if (!variables.exists(id) && !staticVariables.exists(id) && !publicVariables.exists(id) && scriptObject != null) {
|
||||||
else
|
if (Type.typeof(scriptObject) == TObject) {
|
||||||
|
Reflect.setField(scriptObject, id, v);
|
||||||
|
} else {
|
||||||
|
if (isBypassAccessor) {
|
||||||
|
if (__instanceFields.contains(id)) {
|
||||||
|
Reflect.setField(scriptObject, id, v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (__instanceFields.contains(id)) {
|
||||||
|
Reflect.setProperty(scriptObject, id, v);
|
||||||
|
} else if (__instanceFields.contains('set_$id')) { // setter
|
||||||
|
Reflect.getProperty(scriptObject, 'set_$id')(v);
|
||||||
|
} else {
|
||||||
|
setVar(id, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setVar(id, v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
l.r = v;
|
l.r = v;
|
||||||
case EField(e,f):
|
if (l.depth == 0) {
|
||||||
v = set(expr(e),f,v);
|
setVar(id, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
case EField(e, f, s):
|
||||||
|
var obj = expr(e);
|
||||||
|
if(s && obj == null) return null;
|
||||||
|
v = set(obj, f, v);
|
||||||
case EArray(e, index):
|
case EArray(e, index):
|
||||||
var arr:Dynamic = expr(e);
|
var arr:Dynamic = expr(e);
|
||||||
var index:Dynamic = expr(index);
|
var index:Dynamic = expr(index);
|
||||||
if (isMap(arr)) {
|
if (isMap(arr)) {
|
||||||
setMapValue(arr, index, v);
|
setMapValue(arr, index, v);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
arr[index] = v;
|
arr[index] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,12 +274,20 @@ class Interp {
|
|||||||
case EIdent(id):
|
case EIdent(id):
|
||||||
var l = locals.get(id);
|
var l = locals.get(id);
|
||||||
v = fop(expr(e1), expr(e2));
|
v = fop(expr(e1), expr(e2));
|
||||||
if( l == null )
|
if (l == null) {
|
||||||
variables.set(id,v)
|
if (__instanceFields.contains(id)) {
|
||||||
|
Reflect.setProperty(scriptObject, id, v);
|
||||||
|
} else if (__instanceFields.contains('set_$id')) { // setter
|
||||||
|
Reflect.getProperty(scriptObject, 'set_$id')(v);
|
||||||
|
} else {
|
||||||
|
setVar(id, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
l.r = v;
|
l.r = v;
|
||||||
case EField(e,f):
|
case EField(e, f, s):
|
||||||
var obj = expr(e);
|
var obj = expr(e);
|
||||||
|
if(s && obj == null) return null;
|
||||||
v = fop(get(obj, f), expr(e2));
|
v = fop(get(obj, f), expr(e2));
|
||||||
v = set(obj, f, v);
|
v = set(obj, f, v);
|
||||||
case EArray(e, index):
|
case EArray(e, index):
|
||||||
@@ -172,8 +296,7 @@ class Interp {
|
|||||||
if (isMap(arr)) {
|
if (isMap(arr)) {
|
||||||
v = fop(getMapValue(arr, index), expr(e2));
|
v = fop(getMapValue(arr, index), expr(e2));
|
||||||
setMapValue(arr, index, v);
|
setMapValue(arr, index, v);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
v = fop(arr[index], expr(e2));
|
v = fop(arr[index], expr(e2));
|
||||||
arr[index] = v;
|
arr[index] = v;
|
||||||
}
|
}
|
||||||
@@ -191,15 +314,21 @@ class Interp {
|
|||||||
switch (e) {
|
switch (e) {
|
||||||
case EIdent(id):
|
case EIdent(id):
|
||||||
var l = locals.get(id);
|
var l = locals.get(id);
|
||||||
var v : Dynamic = (l == null) ? variables.get(id) : l.r;
|
var v:Dynamic = (l == null) ? resolve(id) : l.r;
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
v += delta;
|
v += delta;
|
||||||
if( l == null ) variables.set(id,v) else l.r = v;
|
if (l == null)
|
||||||
} else
|
setVar(id, v)
|
||||||
if( l == null ) variables.set(id,v + delta) else l.r = v + delta;
|
else
|
||||||
|
l.r = v;
|
||||||
|
} else if (l == null)
|
||||||
|
setVar(id, v + delta)
|
||||||
|
else
|
||||||
|
l.r = v + delta;
|
||||||
return v;
|
return v;
|
||||||
case EField(e,f):
|
case EField(e, f, s):
|
||||||
var obj = expr(e);
|
var obj = expr(e);
|
||||||
|
if(s && obj == null) return null;
|
||||||
var v:Dynamic = get(obj, f);
|
var v:Dynamic = get(obj, f);
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
v += delta;
|
v += delta;
|
||||||
@@ -215,13 +344,11 @@ class Interp {
|
|||||||
if (prefix) {
|
if (prefix) {
|
||||||
v += delta;
|
v += delta;
|
||||||
setMapValue(arr, index, v);
|
setMapValue(arr, index, v);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
setMapValue(arr, index, v + delta);
|
setMapValue(arr, index, v + delta);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var v = arr[index];
|
var v = arr[index];
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
v += delta;
|
v += delta;
|
||||||
@@ -247,22 +374,37 @@ class Interp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function exprReturn(e):Dynamic {
|
function exprReturn(e):Dynamic {
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
return expr(e);
|
return expr(e);
|
||||||
} catch (e:Stop) {
|
} catch (e:Stop) {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case SBreak: throw "Invalid break";
|
case SBreak:
|
||||||
case SContinue: throw "Invalid continue";
|
throw "Invalid break";
|
||||||
|
case SContinue:
|
||||||
|
throw "Invalid continue";
|
||||||
case SReturn:
|
case SReturn:
|
||||||
var v = returnValue;
|
var v = returnValue;
|
||||||
returnValue = null;
|
returnValue = null;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
} catch(e) {
|
||||||
|
error(ECustom('${e.toString()}'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch(e:Error) {
|
||||||
|
if (errorHandler != null)
|
||||||
|
errorHandler(e);
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
return null;
|
||||||
|
} catch(e) {
|
||||||
|
trace(e);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function duplicate<T>( h : #if haxe3 Map < String, T > #else Hash<T> #end ) {
|
public function duplicate<T>(h:#if haxe3 Map<String, T> #else Hash<T> #end) {
|
||||||
#if haxe3
|
#if haxe3
|
||||||
var h2 = new Map();
|
var h2 = new Map();
|
||||||
#else
|
#else
|
||||||
@@ -280,9 +422,14 @@ class Interp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function error(e : #if hscriptPos ErrorDef #else Error #end, rethrow=false ) : Dynamic {
|
public inline function error(e:#if hscriptPos ErrorDef #else Error #end, rethrow = false):Dynamic {
|
||||||
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
#if hscriptPos var e = new Error(e, curExpr.pmin, curExpr.pmax, curExpr.origin, curExpr.line); #end
|
||||||
if( rethrow ) this.rethrow(e) else throw e;
|
|
||||||
|
if (rethrow) {
|
||||||
|
this.rethrow(e);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,22 +441,142 @@ class Interp {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolve( id : String ) : Dynamic {
|
public function resolve(id:String, doException:Bool = true):Dynamic {
|
||||||
|
if (id == null)
|
||||||
|
return null;
|
||||||
|
id = StringTools.trim(id);
|
||||||
var l = locals.get(id);
|
var l = locals.get(id);
|
||||||
if (l != null)
|
if (l != null)
|
||||||
return l.r;
|
return l.r;
|
||||||
|
|
||||||
var v = variables.get(id);
|
var v = variables.get(id);
|
||||||
if( v == null && !variables.exists(id) )
|
for(map in [variables, publicVariables, staticVariables, customClasses])
|
||||||
|
if (map.exists(id))
|
||||||
|
return map[id];
|
||||||
|
|
||||||
|
if (scriptObject != null) {
|
||||||
|
// search in object
|
||||||
|
if (id == "this") {
|
||||||
|
return scriptObject;
|
||||||
|
} else if ((Type.typeof(scriptObject) == TObject) && Reflect.hasField(scriptObject, id)) {
|
||||||
|
return Reflect.field(scriptObject, id);
|
||||||
|
} else {
|
||||||
|
if (__instanceFields.contains(id)) {
|
||||||
|
return Reflect.getProperty(scriptObject, id);
|
||||||
|
} else if (__instanceFields.contains('get_$id')) { // getter
|
||||||
|
return Reflect.getProperty(scriptObject, 'get_$id')();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (doException)
|
||||||
error(EUnknownVariable(id));
|
error(EUnknownVariable(id));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static var importRedirects:Map<String, String> = new Map();
|
||||||
|
public static function getImportRedirect(className:String):String {
|
||||||
|
return importRedirects.exists(className) ? importRedirects.get(className) : className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var localImportRedirects:Map<String, String> = new Map();
|
||||||
|
public function getLocalImportRedirect(className:String):String {
|
||||||
|
var className = className;
|
||||||
|
if (importRedirects.exists(className))
|
||||||
|
className = importRedirects.get(className);
|
||||||
|
if (localImportRedirects.exists(className))
|
||||||
|
className = localImportRedirects.get(className);
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
public function expr(e:Expr):Dynamic {
|
public function expr(e:Expr):Dynamic {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
curExpr = e;
|
curExpr = e;
|
||||||
var e = e.e;
|
var e = e.e;
|
||||||
#end
|
#end
|
||||||
switch (e) {
|
switch (e) {
|
||||||
|
case EClass(name, fields, extend, interfaces):
|
||||||
|
if (customClasses.exists(name))
|
||||||
|
error(EAlreadyExistingClass(name));
|
||||||
|
|
||||||
|
inline function importVar(thing:String):String {
|
||||||
|
if (thing == null)
|
||||||
|
return null;
|
||||||
|
final variable:Class<Any> = variables.exists(thing) ? cast variables.get(thing) : null;
|
||||||
|
return variable == null ? thing : Type.getClassName(variable);
|
||||||
|
}
|
||||||
|
customClasses.set(name, new CustomClassHandler(this, name, fields, importVar(extend), [for (i in interfaces) importVar(i)]));
|
||||||
|
case EImport(c, n):
|
||||||
|
if (!importEnabled)
|
||||||
|
return null;
|
||||||
|
var splitClassName = [for (e in c.split(".")) e.trim()];
|
||||||
|
var realClassName = splitClassName.join(".");
|
||||||
|
var claVarName = splitClassName[splitClassName.length - 1];
|
||||||
|
var toSetName = n != null ? n : claVarName;
|
||||||
|
var oldClassName = realClassName;
|
||||||
|
var oldSplitName = splitClassName.copy();
|
||||||
|
|
||||||
|
if (variables.exists(toSetName)) // class is already imported
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var realClassName = getLocalImportRedirect(realClassName);
|
||||||
|
|
||||||
|
if (importBlocklist.contains(realClassName))
|
||||||
|
return null;
|
||||||
|
var cl = Type.resolveClass(realClassName);
|
||||||
|
if (cl == null)
|
||||||
|
cl = Type.resolveClass('${realClassName}_HSC');
|
||||||
|
|
||||||
|
var en = Type.resolveEnum(realClassName);
|
||||||
|
|
||||||
|
//trace(realClassName, cl, en, splitClassName);
|
||||||
|
|
||||||
|
// Allow for flixel.ui.FlxBar.FlxBarFillDirection;
|
||||||
|
if (cl == null && en == null) {
|
||||||
|
if(splitClassName.length > 1) {
|
||||||
|
splitClassName.splice(-2, 1); // Remove the last last item
|
||||||
|
realClassName = splitClassName.join(".");
|
||||||
|
|
||||||
|
var realClassName = getLocalImportRedirect(realClassName);
|
||||||
|
|
||||||
|
if (importBlocklist.contains(realClassName))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
cl = Type.resolveClass(realClassName);
|
||||||
|
if (cl == null)
|
||||||
|
cl = Type.resolveClass('${realClassName}_HSC');
|
||||||
|
|
||||||
|
en = Type.resolveEnum(realClassName);
|
||||||
|
|
||||||
|
//trace(realClassName, cl, en, splitClassName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cl == null && en == null) {
|
||||||
|
if (importFailedCallback == null || !importFailedCallback(oldSplitName))
|
||||||
|
error(EInvalidClass(oldClassName));
|
||||||
|
} else {
|
||||||
|
if (en != null) {
|
||||||
|
// ENUM!!!!
|
||||||
|
var enumThingy = {};
|
||||||
|
for (c in en.getConstructors()) {
|
||||||
|
try {
|
||||||
|
Reflect.setField(enumThingy, c, en.createByName(c));
|
||||||
|
} catch(e) {
|
||||||
|
try {
|
||||||
|
Reflect.setField(enumThingy, c, Reflect.field(en, c));
|
||||||
|
} catch(ex) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
variables.set(toSetName, enumThingy);
|
||||||
|
} else {
|
||||||
|
variables.set(toSetName, cl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case CInt(v): return v;
|
case CInt(v): return v;
|
||||||
@@ -321,9 +588,18 @@ class Interp {
|
|||||||
}
|
}
|
||||||
case EIdent(id):
|
case EIdent(id):
|
||||||
return resolve(id);
|
return resolve(id);
|
||||||
case EVar(n,_,e):
|
case EVar(n, _, e, isPublic, isStatic):
|
||||||
declared.push({ n : n, old : locals.get(n) });
|
declared.push({n: n, old: locals.get(n), depth: depth});
|
||||||
locals.set(n,{ r : (e == null)?null:expr(e) });
|
locals.set(n, {r: (e == null) ? null : expr(e), depth: depth});
|
||||||
|
if (depth == 0) {
|
||||||
|
if(isStatic == true) {
|
||||||
|
if(!staticVariables.exists(n)) {
|
||||||
|
staticVariables.set(n, locals[n].r);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
(isPublic ? publicVariables : variables).set(n, locals[n].r);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
case EParent(e):
|
case EParent(e):
|
||||||
return expr(e);
|
return expr(e);
|
||||||
@@ -334,11 +610,15 @@ class Interp {
|
|||||||
v = expr(e);
|
v = expr(e);
|
||||||
restore(old);
|
restore(old);
|
||||||
return v;
|
return v;
|
||||||
case EField(e,f):
|
case EField(e, f, s):
|
||||||
return get(expr(e),f);
|
var field = expr(e);
|
||||||
|
if(s && field == null)
|
||||||
|
return null;
|
||||||
|
return get(field, f);
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
var fop = binops.get(op);
|
var fop = binops.get(op);
|
||||||
if( fop == null ) error(EInvalidOp(op));
|
if (fop == null)
|
||||||
|
error(EInvalidOp(op));
|
||||||
return fop(e1, e2);
|
return fop(e1, e2);
|
||||||
case EUnop(op, prefix, e):
|
case EUnop(op, prefix, e):
|
||||||
switch (op) {
|
switch (op) {
|
||||||
@@ -365,9 +645,12 @@ class Interp {
|
|||||||
args.push(expr(p));
|
args.push(expr(p));
|
||||||
|
|
||||||
switch (Tools.expr(e)) {
|
switch (Tools.expr(e)) {
|
||||||
case EField(e,f):
|
case EField(e, f, s):
|
||||||
var obj = expr(e);
|
var obj = expr(e);
|
||||||
if( obj == null ) error(EInvalidAccess(f));
|
if (obj == null) {
|
||||||
|
if(s) return null;
|
||||||
|
error(EInvalidAccess(f));
|
||||||
|
}
|
||||||
return fcall(obj, f, args);
|
return fcall(obj, f, args);
|
||||||
default:
|
default:
|
||||||
return call(null, expr(e), args);
|
return call(null, expr(e), args);
|
||||||
@@ -380,8 +663,8 @@ class Interp {
|
|||||||
case EDoWhile(econd, e):
|
case EDoWhile(econd, e):
|
||||||
doWhileLoop(econd, e);
|
doWhileLoop(econd, e);
|
||||||
return null;
|
return null;
|
||||||
case EFor(v,it,e):
|
case EFor(v, it, e, ithv):
|
||||||
forLoop(v,it,e);
|
forLoop(v, it, e, ithv);
|
||||||
return null;
|
return null;
|
||||||
case EBreak:
|
case EBreak:
|
||||||
throw SBreak;
|
throw SBreak;
|
||||||
@@ -390,8 +673,13 @@ class Interp {
|
|||||||
case EReturn(e):
|
case EReturn(e):
|
||||||
returnValue = e == null ? null : expr(e);
|
returnValue = e == null ? null : expr(e);
|
||||||
throw SReturn;
|
throw SReturn;
|
||||||
case EFunction(params,fexpr,name,_):
|
case EFunction(params, fexpr, name, _, isPublic, isStatic, isOverride):
|
||||||
var capturedLocals = duplicate(locals);
|
var __capturedLocals = duplicate(locals);
|
||||||
|
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
|
||||||
|
for(k=>e in __capturedLocals)
|
||||||
|
if (e != null && e.depth > 0)
|
||||||
|
capturedLocals.set(k, e);
|
||||||
|
|
||||||
var me = this;
|
var me = this;
|
||||||
var hasOpt = false, minParams = 0;
|
var hasOpt = false, minParams = 0;
|
||||||
for (p in params)
|
for (p in params)
|
||||||
@@ -400,11 +688,14 @@ class Interp {
|
|||||||
else
|
else
|
||||||
minParams++;
|
minParams++;
|
||||||
var f = function(args:Array<Dynamic>) {
|
var f = function(args:Array<Dynamic>) {
|
||||||
if( args.length != params.length ) {
|
if (me.locals == null || me.variables == null) return null;
|
||||||
|
|
||||||
|
if (((args == null) ? 0 : args.length) != params.length) {
|
||||||
if (args.length < minParams) {
|
if (args.length < minParams) {
|
||||||
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
||||||
if( name != null ) str += " for function '" + name+"'";
|
if (name != null)
|
||||||
throw str;
|
str += " for function '" + name + "'";
|
||||||
|
error(ECustom(str));
|
||||||
}
|
}
|
||||||
// make sure mandatory args are forced
|
// make sure mandatory args are forced
|
||||||
var args2 = [];
|
var args2 = [];
|
||||||
@@ -425,8 +716,9 @@ class Interp {
|
|||||||
me.depth++;
|
me.depth++;
|
||||||
me.locals = me.duplicate(capturedLocals);
|
me.locals = me.duplicate(capturedLocals);
|
||||||
for (i in 0...params.length)
|
for (i in 0...params.length)
|
||||||
me.locals.set(params[i].name,{ r : args[i] });
|
me.locals.set(params[i].name, {r: args[i], depth: depth});
|
||||||
var r = null;
|
var r = null;
|
||||||
|
var oldDecl = declared.length;
|
||||||
if (inTry)
|
if (inTry)
|
||||||
try {
|
try {
|
||||||
r = me.exprReturn(fexpr);
|
r = me.exprReturn(fexpr);
|
||||||
@@ -441,6 +733,7 @@ class Interp {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
r = me.exprReturn(fexpr);
|
r = me.exprReturn(fexpr);
|
||||||
|
restore(oldDecl);
|
||||||
me.locals = old;
|
me.locals = old;
|
||||||
me.depth = depth;
|
me.depth = depth;
|
||||||
return r;
|
return r;
|
||||||
@@ -449,18 +742,26 @@ class Interp {
|
|||||||
if (name != null) {
|
if (name != null) {
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
// global function
|
// global function
|
||||||
variables.set(name, f);
|
((isStatic && allowStaticVariables) ? staticVariables : ((isPublic && allowPublicVariables) ? publicVariables : variables)).set(name, f);
|
||||||
} else {
|
} else {
|
||||||
// function-in-function is a local function
|
// function-in-function is a local function
|
||||||
declared.push( { n : name, old : locals.get(name) } );
|
declared.push({n: name, old: locals.get(name), depth: depth});
|
||||||
var ref = { r : f };
|
var ref = {r: f, depth: depth};
|
||||||
locals.set(name, ref);
|
locals.set(name, ref);
|
||||||
capturedLocals.set(name, ref); // allow self-recursion
|
capturedLocals.set(name, ref); // allow self-recursion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
case EArrayDecl(arr):
|
case EArrayDecl(arr, wantedType):
|
||||||
if (arr.length > 0 && Tools.expr(arr[0]).match(EBinop("=>", _))) {
|
var isMap = false;
|
||||||
|
var isTypeMap = false;
|
||||||
|
if(!isMap && wantedType != null) {
|
||||||
|
isMap = wantedType.match(CTPath(["Map"], [_, _]));
|
||||||
|
isTypeMap = true;
|
||||||
|
} else {
|
||||||
|
isMap = arr.length > 0 && Tools.expr(arr[0]).match(EBinop("=>", _));
|
||||||
|
}
|
||||||
|
if (isMap) {
|
||||||
var isAllString:Bool = true;
|
var isAllString:Bool = true;
|
||||||
var isAllInt:Bool = true;
|
var isAllInt:Bool = true;
|
||||||
var isAllObject:Bool = true;
|
var isAllObject:Bool = true;
|
||||||
@@ -472,8 +773,8 @@ class Interp {
|
|||||||
case EBinop("=>", eKey, eValue): {
|
case EBinop("=>", eKey, eValue): {
|
||||||
var key:Dynamic = expr(eKey);
|
var key:Dynamic = expr(eKey);
|
||||||
var value:Dynamic = expr(eValue);
|
var value:Dynamic = expr(eValue);
|
||||||
isAllString = isAllString && Std.is(key, String);
|
isAllString = isAllString && (key is String);
|
||||||
isAllInt = isAllInt && Std.is(key, Int);
|
isAllInt = isAllInt && (key is Int);
|
||||||
isAllObject = isAllObject && Reflect.isObject(key);
|
isAllObject = isAllObject && Reflect.isObject(key);
|
||||||
isAllEnum = isAllEnum && Reflect.isEnumValue(key);
|
isAllEnum = isAllEnum && Reflect.isEnumValue(key);
|
||||||
keys.push(key);
|
keys.push(key);
|
||||||
@@ -482,19 +783,39 @@ class Interp {
|
|||||||
default: throw("=> expected");
|
default: throw("=> expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isTypeMap) {
|
||||||
|
if(wantedType != null) {
|
||||||
|
isAllString = wantedType.match(CTPath(["Map"], [CTPath(["String"], _), _]));
|
||||||
|
isAllInt = wantedType.match(CTPath(["Map"], [CTPath(["Int"], _), _]));
|
||||||
|
if(isAllString || isAllInt) {
|
||||||
|
isAllObject = false;
|
||||||
|
isAllEnum = false;
|
||||||
|
} else {
|
||||||
|
if(!isAllObject && !isAllEnum) {
|
||||||
|
throw("Unknown Type Key");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var map:Dynamic = {
|
var map:Dynamic = {
|
||||||
if (isAllInt) new haxe.ds.IntMap<Dynamic>();
|
if (isAllInt)
|
||||||
else if (isAllString) new haxe.ds.StringMap<Dynamic>();
|
new haxe.ds.IntMap<Dynamic>();
|
||||||
else if (isAllEnum) new haxe.ds.EnumValueMap<Dynamic, Dynamic>();
|
else if (isAllString)
|
||||||
else if (isAllObject) new haxe.ds.ObjectMap<Dynamic, Dynamic>();
|
new haxe.ds.StringMap<Dynamic>();
|
||||||
else throw 'Inconsistent key types';
|
else if (isAllEnum)
|
||||||
|
new haxe.ds.EnumValueMap<Dynamic, Dynamic>();
|
||||||
|
else if (isAllObject)
|
||||||
|
new haxe.ds.ObjectMap<Dynamic, Dynamic>();
|
||||||
|
else
|
||||||
|
throw 'Inconsistent key types';
|
||||||
}
|
}
|
||||||
for (n in 0...keys.length) {
|
for (n in 0...keys.length) {
|
||||||
setMapValue(map, keys[n], values[n]);
|
setMapValue(map, keys[n], values[n]);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var a = new Array();
|
var a = new Array();
|
||||||
for (e in arr) {
|
for (e in arr) {
|
||||||
a.push(expr(e));
|
a.push(expr(e));
|
||||||
@@ -506,8 +827,7 @@ class Interp {
|
|||||||
var index:Dynamic = expr(index);
|
var index:Dynamic = expr(index);
|
||||||
if (isMap(arr)) {
|
if (isMap(arr)) {
|
||||||
return getMapValue(arr, index);
|
return getMapValue(arr, index);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return arr[index];
|
return arr[index];
|
||||||
}
|
}
|
||||||
case ENew(cl, params):
|
case ENew(cl, params):
|
||||||
@@ -534,8 +854,8 @@ class Interp {
|
|||||||
restore(old);
|
restore(old);
|
||||||
inTry = oldTry;
|
inTry = oldTry;
|
||||||
// declare 'v'
|
// declare 'v'
|
||||||
declared.push({ n : n, old : locals.get(n) });
|
declared.push({n: n, old: locals.get(n), depth: depth});
|
||||||
locals.set(n,{ r : err });
|
locals.set(n, {r: err, depth: depth});
|
||||||
var v:Dynamic = expr(ecatch);
|
var v:Dynamic = expr(ecatch);
|
||||||
restore(old);
|
restore(old);
|
||||||
return v;
|
return v;
|
||||||
@@ -564,8 +884,15 @@ class Interp {
|
|||||||
if (!match)
|
if (!match)
|
||||||
val = def == null ? null : expr(def);
|
val = def == null ? null : expr(def);
|
||||||
return val;
|
return val;
|
||||||
case EMeta(_, _, e):
|
case EMeta(a, b, e):
|
||||||
return expr(e);
|
var oldAccessor = isBypassAccessor;
|
||||||
|
if(a == ":bypassAccessor") {
|
||||||
|
isBypassAccessor = true;
|
||||||
|
}
|
||||||
|
var val = expr(e);
|
||||||
|
|
||||||
|
isBypassAccessor = oldAccessor;
|
||||||
|
return val;
|
||||||
case ECheckType(e, _):
|
case ECheckType(e, _):
|
||||||
return expr(e);
|
return expr(e);
|
||||||
}
|
}
|
||||||
@@ -580,12 +907,13 @@ class Interp {
|
|||||||
} catch (err:Stop) {
|
} catch (err:Stop) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case SContinue:
|
case SContinue:
|
||||||
case SBreak: break;
|
case SBreak:
|
||||||
case SReturn: throw err;
|
break;
|
||||||
|
case SReturn:
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while (expr(econd) == true);
|
||||||
while( expr(econd) == true );
|
|
||||||
restore(old);
|
restore(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -597,37 +925,59 @@ class Interp {
|
|||||||
} catch (err:Stop) {
|
} catch (err:Stop) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case SContinue:
|
case SContinue:
|
||||||
case SBreak: break;
|
case SBreak:
|
||||||
case SReturn: throw err;
|
break;
|
||||||
|
case SReturn:
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restore(old);
|
restore(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeIterator( v : Dynamic ) : Iterator<Dynamic> {
|
function makeIterator(v:Dynamic, ?allowKeyValue = false):Iterator<Dynamic> {
|
||||||
#if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0'))
|
#if ((flash && !flash9) || (php && !php7 && haxe_ver < '4.0.0'))
|
||||||
if ( v.iterator != null ) v = v.iterator();
|
if (v.iterator != null)
|
||||||
|
v = v.iterator();
|
||||||
#else
|
#else
|
||||||
try v = v.iterator() catch( e : Dynamic ) {};
|
if(allowKeyValue) {
|
||||||
|
try
|
||||||
|
v = v.keyValueIterator()
|
||||||
|
catch (e:Dynamic) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(v.hasNext == null || v.next == null) {
|
||||||
|
try
|
||||||
|
v = v.iterator()
|
||||||
|
catch (e:Dynamic) {};
|
||||||
|
}
|
||||||
#end
|
#end
|
||||||
if( v.hasNext == null || v.next == null ) error(EInvalidIterator(v));
|
if (v.hasNext == null || v.next == null)
|
||||||
|
error(EInvalidIterator(v));
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
function forLoop(n,it,e) {
|
function forLoop(n, it, e, ?ithv) {
|
||||||
|
var isKeyValue = ithv != null;
|
||||||
var old = declared.length;
|
var old = declared.length;
|
||||||
declared.push({ n : n, old : locals.get(n) });
|
if(isKeyValue)
|
||||||
var it = makeIterator(expr(it));
|
declared.push({n: ithv, old: locals.get(ithv), depth: depth});
|
||||||
|
declared.push({n: n, old: locals.get(n), depth: depth});
|
||||||
|
var it = makeIterator(expr(it), isKeyValue);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
locals.set(n,{ r : it.next() });
|
var next = it.next();
|
||||||
|
if(isKeyValue)
|
||||||
|
locals.set(ithv, {r: next.key, depth: depth});
|
||||||
|
locals.set(n, {r: isKeyValue ? next.value : next, depth: depth});
|
||||||
try {
|
try {
|
||||||
expr(e);
|
expr(e);
|
||||||
} catch (err:Stop) {
|
} catch (err:Stop) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case SContinue:
|
case SContinue:
|
||||||
case SBreak: break;
|
case SBreak:
|
||||||
case SReturn: throw err;
|
break;
|
||||||
|
case SReturn:
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -635,7 +985,7 @@ class Interp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline function isMap(o:Dynamic):Bool {
|
inline function isMap(o:Dynamic):Bool {
|
||||||
return Std.is(o, haxe.Constraints.IMap);
|
return (o is IMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
|
inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
|
||||||
@@ -646,40 +996,89 @@ class Interp {
|
|||||||
cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).set(key, value);
|
cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).set(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static var getRedirects:Map<String, Dynamic->String->Dynamic> = [];
|
||||||
|
public static var setRedirects:Map<String, Dynamic->String->Dynamic->Dynamic> = [];
|
||||||
|
|
||||||
function get(o:Dynamic, f:String):Dynamic {
|
function get(o:Dynamic, f:String):Dynamic {
|
||||||
if ( o == null ) error(EInvalidAccess(f));
|
if (o == null)
|
||||||
|
error(EInvalidAccess(f));
|
||||||
return {
|
return {
|
||||||
#if php
|
var redirect:Dynamic->String->Dynamic = null;
|
||||||
// https://github.com/HaxeFoundation/haxe/issues/4915
|
var cls = Type.getClass(o);
|
||||||
try {
|
var cl:Null<String> = switch (Type.typeof(o)) {
|
||||||
Reflect.getProperty(o, f);
|
case TNull: "Null";
|
||||||
} catch (e:Dynamic) {
|
case TInt: "Int";
|
||||||
Reflect.field(o, f);
|
case TFloat: "Float";
|
||||||
|
case TBool: "Bool";
|
||||||
|
case _: cls != null ? Type.getClassName(cls) : null;
|
||||||
|
};
|
||||||
|
if (cl != null && getRedirects.exists(cl) && (redirect = getRedirects[cl]) != null) {
|
||||||
|
return redirect(o, f);
|
||||||
|
} else if (o is IHScriptCustomBehaviour) {
|
||||||
|
var obj = cast(o, IHScriptCustomBehaviour);
|
||||||
|
return obj.hget(f);
|
||||||
|
} else {
|
||||||
|
var v = null;
|
||||||
|
if(isBypassAccessor) {
|
||||||
|
if ((v = Reflect.field(o, f)) == null)
|
||||||
|
v = Reflect.field(cls, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(v == null) {
|
||||||
|
if ((v = Reflect.getProperty(o, f)) == null)
|
||||||
|
v = Reflect.getProperty(cls, f);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
Reflect.getProperty(o, f);
|
|
||||||
#end
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function set(o:Dynamic, f:String, v:Dynamic):Dynamic {
|
function set(o:Dynamic, f:String, v:Dynamic):Dynamic {
|
||||||
if( o == null ) error(EInvalidAccess(f));
|
if (o == null)
|
||||||
|
error(EInvalidAccess(f));
|
||||||
|
|
||||||
|
var redirect:Dynamic->String->Dynamic->Dynamic = null;
|
||||||
|
var cls = Type.getClass(o);
|
||||||
|
var cl:Null<String> = switch (Type.typeof(o)) {
|
||||||
|
case TNull: "Null";
|
||||||
|
case TInt: "Int";
|
||||||
|
case TFloat: "Float";
|
||||||
|
case TBool: "Bool";
|
||||||
|
case _: cls != null ? Type.getClassName(cls) : null;
|
||||||
|
};
|
||||||
|
if (cl != null && setRedirects.exists(cl) && (redirect = setRedirects[cl]) != null)
|
||||||
|
return redirect(o, f, v);
|
||||||
|
else if (o is IHScriptCustomBehaviour) {
|
||||||
|
var obj = cast(o, IHScriptCustomBehaviour);
|
||||||
|
return obj.hset(f, v);
|
||||||
|
}
|
||||||
|
if(isBypassAccessor) {
|
||||||
|
Reflect.setField(o, f, v);
|
||||||
|
} else {
|
||||||
Reflect.setProperty(o, f, v);
|
Reflect.setProperty(o, f, v);
|
||||||
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||||
|
if(o == CustomClassHandler.staticHandler && scriptObject != null) {
|
||||||
|
return Reflect.callMethod(scriptObject, Reflect.field(scriptObject, "_HX_SUPER__" + f), args);
|
||||||
|
}
|
||||||
return call(o, get(o, f), args);
|
return call(o, get(o, f), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function call(o:Dynamic, f:Dynamic, args:Array<Dynamic>):Dynamic {
|
function call(o:Dynamic, f:Dynamic, args:Array<Dynamic>):Dynamic {
|
||||||
|
if(f == CustomClassHandler.staticHandler) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return Reflect.callMethod(o, f, args);
|
return Reflect.callMethod(o, f, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cnew(cl:String, args:Array<Dynamic>):Dynamic {
|
function cnew(cl:String, args:Array<Dynamic>):Dynamic {
|
||||||
var c = Type.resolveClass(cl);
|
var cl:String = cast cl;
|
||||||
if( c == null ) c = resolve(cl);
|
var c:Dynamic = resolve(cl);
|
||||||
return Type.createInstance(c,args);
|
if (c == null)
|
||||||
|
c = Type.resolveClass(cl);
|
||||||
|
return (c is IHScriptCustomConstructor) ? cast(c, IHScriptCustomConstructor).hnew(args) : Type.createInstance(c, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -79,6 +79,8 @@ class Macro {
|
|||||||
#if (haxe_ver >= 4)
|
#if (haxe_ver >= 4)
|
||||||
case OpIn: "in";
|
case OpIn: "in";
|
||||||
#end
|
#end
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
binops.set(str, op);
|
binops.set(str, op);
|
||||||
if( assign )
|
if( assign )
|
||||||
@@ -92,6 +94,9 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -214,7 +219,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),
|
||||||
@@ -247,6 +252,8 @@ class Macro {
|
|||||||
EMeta({ name : m, params : params == null ? [] : [for( p in params ) convert(p)], pos : mpos }, convert(esub));
|
EMeta({ name : m, params : params == null ? [] : [for( p in params ) convert(p)], pos : mpos }, convert(esub));
|
||||||
case ECheckType(e, t):
|
case ECheckType(e, t):
|
||||||
ECheckType(convert(e), convertType(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 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+505
-115
File diff suppressed because it is too large
Load Diff
+31
-7
@@ -114,6 +114,25 @@ class Printer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch( #if hscriptPos e.e #else e #end ) {
|
switch( #if hscriptPos e.e #else e #end ) {
|
||||||
|
case EImport(c, n):
|
||||||
|
add("import " + c);
|
||||||
|
if(n != null)
|
||||||
|
add(' as $n');
|
||||||
|
case EClass(name, fields, extend, interfaces):
|
||||||
|
add('class $name');
|
||||||
|
if (extend != null)
|
||||||
|
add(' extends $extend');
|
||||||
|
for(_interface in interfaces) {
|
||||||
|
add(' implements $_interface');
|
||||||
|
}
|
||||||
|
add(' {\n');
|
||||||
|
tabs += "\t";
|
||||||
|
//for(field in fields) {
|
||||||
|
// expr(field);
|
||||||
|
//}
|
||||||
|
|
||||||
|
tabs = tabs.substr(1);
|
||||||
|
add("}");
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
switch( c ) {
|
switch( c ) {
|
||||||
case CInt(i): add(i);
|
case CInt(i): add(i);
|
||||||
@@ -122,7 +141,7 @@ class Printer {
|
|||||||
}
|
}
|
||||||
case EIdent(v):
|
case EIdent(v):
|
||||||
add(v);
|
add(v);
|
||||||
case EVar(n, t, e):
|
case EVar(n, t, e): // TODO: static, public, override
|
||||||
add("var " + n);
|
add("var " + n);
|
||||||
addType(t);
|
addType(t);
|
||||||
if( e != null ) {
|
if( e != null ) {
|
||||||
@@ -145,9 +164,9 @@ class Printer {
|
|||||||
tabs = tabs.substr(1);
|
tabs = tabs.substr(1);
|
||||||
add("}");
|
add("}");
|
||||||
}
|
}
|
||||||
case EField(e, f):
|
case EField(e, f, s):
|
||||||
expr(e);
|
expr(e);
|
||||||
add("." + f);
|
add((s == true ? "?." : ".") + f);
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
expr(e1);
|
expr(e1);
|
||||||
add(" " + op + " ");
|
add(" " + op + " ");
|
||||||
@@ -198,7 +217,10 @@ class Printer {
|
|||||||
add(" while ( ");
|
add(" while ( ");
|
||||||
expr(cond);
|
expr(cond);
|
||||||
add(" )");
|
add(" )");
|
||||||
case EFor(v, it, e):
|
case EFor(v, it, e, ithv):
|
||||||
|
if(ithv != null)
|
||||||
|
add("for( "+ithv+" => "+v+" in ");
|
||||||
|
else
|
||||||
add("for( "+v+" in ");
|
add("for( "+v+" in ");
|
||||||
expr(it);
|
expr(it);
|
||||||
add(" ) ");
|
add(" ) ");
|
||||||
@@ -207,7 +229,7 @@ class Printer {
|
|||||||
add("break");
|
add("break");
|
||||||
case EContinue:
|
case EContinue:
|
||||||
add("continue");
|
add("continue");
|
||||||
case EFunction(params, e, name, ret):
|
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||||
add("function");
|
add("function");
|
||||||
if( name != null )
|
if( name != null )
|
||||||
add(" " + name);
|
add(" " + name);
|
||||||
@@ -234,7 +256,7 @@ class Printer {
|
|||||||
add("[");
|
add("[");
|
||||||
expr(index);
|
expr(index);
|
||||||
add("]");
|
add("]");
|
||||||
case EArrayDecl(el):
|
case EArrayDecl(el, _):
|
||||||
add("[");
|
add("[");
|
||||||
var first = true;
|
var first = true;
|
||||||
for( e in el ) {
|
for( e in el ) {
|
||||||
@@ -331,7 +353,7 @@ class Printer {
|
|||||||
|
|
||||||
public static function errorToString( e : Expr.Error ) {
|
public static function errorToString( e : Expr.Error ) {
|
||||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||||
case EInvalidChar(c): "Invalid character: '"+String.fromCharCode(c)+"' ("+c+")";
|
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||||
case EUnterminatedString: "Unterminated string";
|
case EUnterminatedString: "Unterminated string";
|
||||||
case EUnterminatedComment: "Unterminated comment";
|
case EUnterminatedComment: "Unterminated comment";
|
||||||
@@ -341,6 +363,8 @@ class Printer {
|
|||||||
case EInvalidOp(op): "Invalid operator: "+op;
|
case EInvalidOp(op): "Invalid operator: "+op;
|
||||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||||
case ECustom(msg): msg;
|
case ECustom(msg): msg;
|
||||||
|
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||||
|
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||||
};
|
};
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e.origin + ":" + e.line + ": " + message;
|
return e.origin + ":" + e.line + ": " + message;
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class Tools {
|
|||||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
public static function iter( e : Expr, f : Expr -> Void ) {
|
||||||
switch( expr(e) ) {
|
switch( expr(e) ) {
|
||||||
case EConst(_), EIdent(_):
|
case EConst(_), EIdent(_):
|
||||||
|
case EImport(c): f(e);
|
||||||
|
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||||
case EVar(_, _, e): if( e != null ) f(e);
|
case EVar(_, _, e): if( e != null ) f(e);
|
||||||
case EParent(e): f(e);
|
case EParent(e): f(e);
|
||||||
case EBlock(el): for( e in el ) f(e);
|
case EBlock(el): for( e in el ) f(e);
|
||||||
@@ -57,6 +59,7 @@ class Tools {
|
|||||||
if( def != null ) f(def);
|
if( def != null ) f(def);
|
||||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||||
case ECheckType(e,_): f(e);
|
case ECheckType(e,_): f(e);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +89,8 @@ class Tools {
|
|||||||
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 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 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 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);
|
||||||
}
|
}
|
||||||
return mk(edef, e);
|
return mk(edef, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,437 @@
|
|||||||
|
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.*;
|
||||||
|
import Sys;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
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())");
|
||||||
|
}
|
||||||
|
#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(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(cl.superClass != null) {
|
||||||
|
var _superFields = cl.superClass.t.get().fields.get();
|
||||||
|
_superFields = []; // Comment to enable super support, (broken)
|
||||||
|
for(field in _superFields) {
|
||||||
|
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var nfield = @:privateAccess TypeTools.toField(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)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fun.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) continue;
|
||||||
|
|
||||||
|
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 = 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>};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
superFields.push(nfield);
|
||||||
|
} catch(e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//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;
|
||||||
|
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))
|
||||||
|
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) {
|
||||||
|
var v:Dynamic = null;
|
||||||
|
if (__interp.variables.exists(name) && 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) {
|
||||||
|
var v:Dynamic = null;
|
||||||
|
if (__interp != null && __interp.variables.exists(name) && 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: "IHScriptCustomBehaviour", pack: ["hscript"]}
|
||||||
|
], false, true, false);
|
||||||
|
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
||||||
|
var imports = Context.getLocalImports().copy();
|
||||||
|
Utils.setupMetas(shadowClass, imports);
|
||||||
|
|
||||||
|
// Adding hscript getters and setters
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__interp",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(TPath({
|
||||||
|
pack: ['hscript'],
|
||||||
|
name: 'Interp'
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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(this.__interp.variables.exists("get_" + name))
|
||||||
|
return this.__interp.variables.get("get_" + name)();
|
||||||
|
if (this.__interp.variables.exists(name))
|
||||||
|
return this.__interp.variables.get(name);
|
||||||
|
return super.hget(name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
macro {
|
||||||
|
if(this.__interp.variables.exists("get_" + name))
|
||||||
|
return this.__interp.variables.get("get_" + name)();
|
||||||
|
if (this.__interp.variables.exists(name))
|
||||||
|
return this.__interp.variables.get(name);
|
||||||
|
return Reflect.getProperty(this, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hsetField = if(hasHsetInSuper) {
|
||||||
|
macro {
|
||||||
|
if(this.__interp.variables.exists("set_" + name)) {
|
||||||
|
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
|
||||||
|
}
|
||||||
|
if (this.__interp.variables.exists(name)) {
|
||||||
|
this.__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return super.hset(name, val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
macro {
|
||||||
|
if(this.__interp.variables.exists("set_" + name)) {
|
||||||
|
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
|
||||||
|
}
|
||||||
|
if (this.__interp.variables.exists(name)) {
|
||||||
|
this.__interp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
Reflect.setProperty(this, name, val);
|
||||||
|
return Reflect.field(this, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(hasHsetInSuper || hasHgetInSuper) return fields;
|
||||||
|
|
||||||
|
//trace(cl.name);
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "hset",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
access: hasHsetInSuper ? [AOverride, APublic] : [APublic],
|
||||||
|
kind: FFun({
|
||||||
|
ret: TPath({name: 'Dynamic', pack: []}),
|
||||||
|
params: [],
|
||||||
|
expr: hsetField,
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: TPath({name: "String", pack: []})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "val",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: TPath({name: "Dynamic", pack: []})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "hget",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
access: hasHgetInSuper ? [AOverride, APublic] : [APublic],
|
||||||
|
kind: FFun({
|
||||||
|
ret: TPath({name: 'Dynamic', pack: []}),
|
||||||
|
params: [],
|
||||||
|
expr: hgetField,
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: "name",
|
||||||
|
opt: false,
|
||||||
|
meta: [],
|
||||||
|
type: TPath({name: "String", pack: []})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/*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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
class ClassExtendMacro {
|
||||||
|
public var usedClass:Class<Dynamic>;
|
||||||
|
public var className:String;
|
||||||
|
}
|
||||||
|
#end
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
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 UsingHandler {
|
||||||
|
public static function init() {
|
||||||
|
#if !display
|
||||||
|
if(Context.defined("display")) return;
|
||||||
|
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||||
|
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.UsingHandler.build())');
|
||||||
|
}
|
||||||
|
#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,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
|
||||||
Reference in New Issue
Block a user