Compare commits

...
101 Commits
Author SHA1 Message Date
Ne_Eo 49c90e6434 Fix typo 2025-01-19 20:09:38 +01:00
Ne_Eo bb46d45d56 Import Redirects 2024-11-15 15:25:04 +01:00
Redar13andGitHub 3a5c4f2164 Fix ending in with #end in the file (#5)
* Update Parser.hx

* Update Parser.hx
2024-11-06 16:39:09 +01:00
Ne_Eo f18c7a2210 Small optimization 2024-08-02 23:50:16 +02:00
Ne_Eo 123a7de64a Fix Trigraph bug 2024-07-26 04:24:37 +02:00
Ne_Eo e0e1436930 Fix bug oops :3 2024-06-03 19:00:40 +02:00
b96e6c8149 Fix import extend class (#4)
* Fix import extend class

yea

* Update Interp.hx

* Fix issues with compiling

* Improved extend Errors

---------

Co-authored-by: NeeEoo <NeeEoo@users.noreply.github.com>
2024-04-23 00:01:43 +02:00
NeeEoo f6402ac638 Improve Auto Complete Performance 2024-04-13 18:32:13 +02:00
Ne_EoandGitHub 1e55d0200b Update README.md 2024-02-15 19:43:11 +01:00
NeeEoo 1725dfd1ea Merge branch 'master' into custom-classes 2024-02-15 19:35:31 +01:00
NeeEoo a8cc0ccc86 Restructuring + KeyValueItherators + is + fixes 2023-09-23 21:23:31 +02:00
LeerandGitHub 7dd868aac7 fix compilation errors and make setVar public (#1)
* fix 1

* fix 2

* make setVar public
2023-09-23 20:32:31 +02:00
NeeEoo 220e5ce007 Merge branch 'custom-classes' 2023-08-17 09:55:12 +02:00
NeeEoo 80f6ea4502 Oops 2023-08-17 09:54:56 +02:00
NeeEoo eb820aaf6a Improved ?. 2023-08-17 09:51:43 +02:00
NeeEoo a754c162d9 Fix private class bug 2023-08-13 19:29:08 +02:00
NeeEoo de18ceb887 Fixed Type not found error 2023-08-13 19:24:08 +02:00
NeeEoo 51188173bb Merge To Main 2023-08-13 11:59:13 +02:00
NeeEoo d0797ad5d8 Fixed bug with redirects 2023-08-07 13:54:19 +02:00
NeeEoo 9b37bd532e Oops forgot this 2023-07-06 11:59:12 +02:00
NeeEoo 333352edcf Fix bug + bypassAccessor on assign on scriptObject 2023-07-06 00:40:21 +02:00
NeeEoo 05783773af Added support for sub class imports 2023-06-15 14:36:28 +02:00
NeeEoo 59ee20ee7a WIP Super Class Support 2023-06-15 14:21:18 +02:00
NeeEoo 87f2c1b062 Added import as and switch or and def null 2023-06-15 11:08:08 +02:00
NeeEoo b85cefea56 Cleanup 2023-04-19 13:37:08 +02:00
Yoshman29 2e28f863f3 some fixes & stuff 2023-04-19 01:46:48 +02:00
NeeEoo ddaa4d1741 Added support for dots in preprocessors 2023-04-10 15:08:16 +02:00
NeeEoo 732bd1520a Improved Custom Classes (getting fields outside of the class) 2023-04-10 14:14:16 +02:00
NeeEoo 1d67946f3f Outside variables now in classes (no more import in class) 2023-04-10 03:36:50 +02:00
Yoshman29 fab6d7e662 Merge branch 'custom-classes' of https://github.com/YoshiCrafter29/hscript-improved into custom-classes 2023-04-10 02:56:20 +02:00
NeeEoo 6e20578a81 Improved static variables 2023-04-10 02:37:41 +02:00
NeeEoo dc5282c32e Added finals 2023-04-10 02:10:46 +02:00
lunarcleint 812abae6e5 ??= op 2023-04-09 16:51:04 -07:00
NeeEoo b3b512d027 Added support for ?. 2023-04-10 00:09:50 +02:00
NeeEoo ed296c4c7f Merge branch 'master' into custom-classes 2023-04-09 23:28:45 +02:00
lunarcleint 595bb47249 ?? and .? syntax (only ?? is functional) 2023-04-09 14:09:58 -07:00
NeeEoo daad1a4fa8 Added underscore support to numbers + binary 2023-04-08 00:08:49 +02:00
Yoshman29 daef1ac198 Merge branch 'custom-classes' of https://github.com/YoshiCrafter29/hscript-improved into custom-classes 2023-04-07 16:40:23 +02:00
Yoshman29 3b9d88b252 Update Interp.hx 2023-04-07 16:40:22 +02:00
NeeEoo 809f8229b4 Implemented Super 2023-04-02 18:22:02 +02:00
Yoshman29 ffb1ee2523 Update CustomClassHandler.hx 2023-04-02 03:39:21 +02:00
Yoshman29 0903718314 removed all unnecessary traces 2023-04-01 22:46:02 +02:00
Yoshman29 e0cb883ae4 Update ClassExtendMacro.hx 2023-04-01 18:31:39 +02:00
Yoshman29 17449dd9d5 oopsie 2023-04-01 17:15:01 +02:00
Yoshman29 7963631a1d Update ClassExtendMacro.hx 2023-04-01 15:30:46 +02:00
Yoshman29 77d88f4b34 Update ClassExtendMacro.hx 2023-04-01 15:12:36 +02:00
Yoshman29 c5e3ab1162 custom classes 2023-04-01 15:02:36 +02:00
Yoshman29 75041c1db9 possible working code????? huh??? 2023-04-01 14:38:13 +02:00
Yoshman29 558a4c0782 Tried some fuckery 2023-04-01 02:23:07 +02:00
NeeEoo 995c3b9c8e ‍ 2023-03-31 22:11:48 +02:00
Yoshman29 0a64bca9ce custom class progress 2023-03-31 21:41:34 +02:00
NeeEoo b7b12b6cbb WIP Classes 2023-03-31 20:16:30 +02:00
NeeEoo 5684ca8671 WIP Class Parsing 2023-03-31 18:12:50 +02:00
NeeEoo 3c81360dc2 Merge branch 'master' into custom-classes 2023-03-31 17:03:00 +02:00
NeeEoo fc50ebdf90 Small Fix 2023-03-31 00:12:54 +02:00
Yoshman29 4d6e8db5ff helpers 2023-03-30 17:34:50 +02:00
NeeEoo 938ffac57e Custom classes, 2/? finished the macro 2023-03-19 17:57:37 +01:00
NeeEoo 50aaffb101 Custom classes, 1/? started with macros 2023-03-19 05:30:06 +01:00
NeeEoo 4f9b449c6e Added inferred map types and bypassAccessor 2023-03-19 05:26:27 +01:00
Yoshman29 c1a36a3f4b improve deez nuts 2023-01-07 22:22:05 +01:00
Yoshman29 4ca6e2a680 Fixed weird erroring with an error handling 2022-12-26 22:17:08 +01:00
Yoshman29 11db805c34 improve deez nuts 2022-12-24 13:07:02 +01:00
Yoshman29 f1f700ab69 Update UsingHandler.hx 2022-12-22 21:17:47 +01:00
Yoshman29 9eeb8ddb80 that macro took me 3 hours 2022-12-22 21:09:11 +01:00
Yoshman29 95de26a6d0 fuck 2022-12-09 23:09:28 +01:00
Yoshman29 88c2e28dbc crap 2022-12-07 23:51:03 +01:00
Yoshman29 30b7a9e4d4 Update Checker.hx 2022-12-07 23:47:37 +01:00
Yoshman29 37542065d6 bug fix (now it works as intended) 2022-11-04 20:10:35 +01:00
Yoshman29 c9608f7760 Update Interp.hx 2022-11-04 19:54:57 +01:00
Yoshman29 6ba54b0e77 static and public 2022-11-04 19:33:04 +01:00
Yoshman29 f9bb3105c8 new interface 2022-11-02 14:36:36 +01:00
Yoshman29 4b5baa9b5f Revert "thing that needs to be reverted"
This reverts commit 6dedd87260.
2022-10-13 23:18:54 +02:00
Yoshman29 6dedd87260 thing that needs to be reverted 2022-10-13 23:18:47 +02:00
Yoshman29 91317222fb Update Interp.hx 2022-08-13 03:00:11 +02:00
Yoshman29 494953a8cc Added interp.importEnabled 2022-08-12 23:40:55 +02:00
Yoshman29 ae4d8be50c more error handling + variables fix 2022-08-10 17:21:15 +02:00
Yoshman29 d34790e05c fix 2022-07-19 02:44:22 +02:00
Yoshman29 b77e15c6d6 forgot to push smh 2022-07-11 11:32:45 +02:00
Yoshman29 54195d5811 hscript updates 2022-07-02 18:21:43 +02:00
Yoshman29 9c7907f91a fixes 2022-06-30 02:03:07 +02:00
Yoshman29 0601b8def6 natural import & static access from vars for YCE 2022-06-29 00:53:51 +02:00
YoshiCrafter29 841261f199 Added import support 2022-06-08 20:10:40 +02:00
Nicolas Cannasse 7124b6c4ce fix for latest haxe 2022-04-11 17:14:38 +02:00
Nicolas Cannasse ad7beec559 fix for async idents and local functions 2022-04-01 14:43:03 +02:00
Nicolas Cannasse bd4fc51392 renamed test script 2022-04-01 10:27:20 +02:00
Nicolas Cannasse 54d994a879 added asyncIdents support 2022-03-24 15:26:50 +01:00
Nicolas Cannasse 891a085f2b fixed declared vars leak when return (close #111) 2022-01-30 11:26:32 +01:00
Nicolas Cannasse e7ccd2e72d another {} unify fix 2021-05-14 18:22:16 +02:00
Nicolas Cannasse 459a39e65d fix unification with {} 2021-05-14 18:18:55 +02:00
Jens FischerandGitHub 36eb0fca8b Fix Std.is() deprecation warnings with Haxe 4.2 (#101) 2021-03-15 19:49:07 +01:00
Nicolas Cannasse 53b9e22f26 fix for haxe 4.2 2021-02-11 12:07:30 +01:00
Nicolas Cannasse 8ff3f5e351 fixed getFields (apply params, handle interfaces) and getField (handle interface inheritance) 2020-12-18 15:58:21 +01:00
Nicolas Cannasse e6a2c443cb added support for interfaces type checking 2020-12-04 17:08:41 +01:00
Nicolas Cannasse 4f25ab162d added inheritance on setGlobals 2020-08-26 15:51:27 +02:00
Nicolas Cannasse 0520d9f187 added setVar (allow to define globals set behavior) 2020-07-30 10:22:48 +02:00
Nicolas Cannasse cc3c21b7e3 fixed unop priority overriding binop one (close #94) 2020-07-14 12:49:24 +02:00
Nicolas Cannasse ae9560124e fixed () -> e short lambda parsing (close #93) 2020-05-07 10:24:04 +02:00
Nicolas Cannasse 085f4ec37e fixed comments parsing was broken by previous fix 2020-04-27 11:19:46 +02:00
Nicolas Cannasse 476c3a9cc9 fixed parser with concat binop/unop such as a<-b or a<++b (close #92) 2020-04-26 15:10:00 +02:00
Mark KnolandGitHub 1bc5ac8768 Update haxelib.json (#83) 2020-04-12 21:32:39 +02:00
Nicolas Cannasse 4bdff11b87 removed 2020-04-10 12:21:54 +02:00
23 changed files with 2844 additions and 1062 deletions
+2
View File
@@ -1,2 +1,4 @@
/hscript.swf /hscript.swf
/release.zip /release.zip
tests/bin/*
+13 -3
View File
@@ -1,8 +1,18 @@
hscript hscript-improved
======= =======
[![TravisCI Build Status](https://travis-ci.org/HaxeFoundation/hscript.svg?branch=master)](https://travis-ci.org/HaxeFoundation/hscript) How to install
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/HaxeFoundation/hscript?branch=master&svg=true)](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.
+5 -2
View File
@@ -7,7 +7,7 @@ import hscript.Printer;
import hscript.Checker; 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;
@@ -101,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);
@@ -110,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 {
@@ -170,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 -1
View File
@@ -1,3 +1,3 @@
-main Test -main TestHScript
-dce no -dce no
-lib hx3compat -lib hx3compat
+2
View File
@@ -1 +1,3 @@
--macro keep('IntIterator') --macro keep('IntIterator')
--macro hscript.macros.UsingHandler.init()
--macro hscript.macros.ClassExtendMacro.init()
+1 -1
View File
@@ -5,5 +5,5 @@
"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.4.0", "version": "2.4.0",
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)", "releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
"contributors": ["ncannasse"] "contributors": ["ncannasse","HaxeFoundation"]
} }
-65
View File
@@ -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>
+8 -1
View File
@@ -36,6 +36,7 @@ class Async {
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);
@@ -207,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;
+4
View File
@@ -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):
+68 -10
View File
@@ -48,6 +48,8 @@ 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>;
} }
@@ -121,12 +123,19 @@ 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;
@@ -295,9 +304,17 @@ class Checker {
} }
public function setGlobals( cl : CClass ) { public function setGlobals( cl : CClass ) {
while( true ) {
for( f in cl.fields ) for( f in cl.fields )
if( f.isPublic ) 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()]))); 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 ) { public function removeGlobal( name : String ) {
@@ -580,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);
@@ -595,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):
@@ -693,24 +724,43 @@ class Checker {
} }
} }
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;
} }
@@ -726,6 +776,13 @@ class Checker {
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, forWrite); var ft = getField(c.superClass, f, e, forWrite);
@@ -917,7 +974,7 @@ 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);
@@ -930,7 +987,7 @@ class Checker {
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));
@@ -1176,6 +1233,7 @@ class Checker {
mergeType( typeExpr(defaultExpr, withType), defaultExpr); mergeType( typeExpr(defaultExpr, withType), defaultExpr);
return withType == NoValue ? TVoid : tmin == null ? makeMono() : tmin; return withType == NoValue ? TVoid : tmin == null ? makeMono() : tmin;
case ENew(cl, params): case ENew(cl, params):
default:
} }
error("Don't know how to type "+edef(expr).getName(), expr); error("Don't know how to type "+edef(expr).getName(), expr);
return TDynamic; return TDynamic;
+24
View File
@@ -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 = [
];
}
+104
View File
@@ -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
View File
@@ -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);
} }
+6
View File
@@ -0,0 +1,6 @@
package hscript;
interface IHScriptCustomBehaviour {
public function hset(name:String, val:Dynamic):Dynamic;
public function hget(name:String):Dynamic;
}
+5
View File
@@ -0,0 +1,5 @@
package hscript;
interface IHScriptCustomConstructor {
public function hnew(args:Array<Dynamic>):Dynamic;
}
+492 -101
View File
@@ -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,22 +44,48 @@ 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
@@ -63,9 +103,15 @@ class Interp {
private function resetVariables() { private function resetVariables() {
#if haxe3 #if haxe3
customClasses = new Map<String, Dynamic>();
variables = new Map<String, Dynamic>(); variables = new Map<String, Dynamic>();
publicVariables = new Map<String, Dynamic>();
staticVariables = new Map<String, Dynamic>();
#else #else
customClasses = new Hash();
variables = new Hash(); variables = new Hash();
publicVariables = new Hash();
staticVariables = new Hash();
#end #end
variables.set("null", null); variables.set("null", null);
@@ -74,7 +120,8 @@ class Interp {
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);
})); }));
} }
@@ -113,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);
@@ -126,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 {
@@ -133,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;
} }
@@ -166,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):
@@ -180,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;
} }
@@ -199,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;
@@ -223,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;
@@ -255,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
@@ -288,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;
} }
@@ -302,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;
@@ -329,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);
@@ -342,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) {
@@ -373,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);
@@ -388,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;
@@ -398,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)
@@ -408,10 +688,13 @@ class Interp {
else else
minParams++; minParams++;
var f = function(args:Array<Dynamic>) { var f = function(args:Array<Dynamic>) {
if (me.locals == null || me.variables == null) return null;
if (((args == null) ? 0 : args.length) != params.length) { 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)
str += " for function '" + name + "'";
error(ECustom(str)); error(ECustom(str));
} }
// make sure mandatory args are forced // make sure mandatory args are forced
@@ -433,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);
@@ -449,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;
@@ -457,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;
@@ -480,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);
@@ -490,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));
@@ -514,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):
@@ -542,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;
@@ -572,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);
} }
@@ -588,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);
} }
@@ -605,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;
} }
} }
} }
@@ -643,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 {
@@ -654,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);
} }
} }
+7
View File
@@ -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);
} }
@@ -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 }
} }
+422 -38
View File
@@ -32,6 +32,7 @@ enum Token {
TBrOpen; TBrOpen;
TBrClose; TBrClose;
TDot; TDot;
TQuestionDot;
TComma; TComma;
TSemicolon; TSemicolon;
TBkOpen; TBkOpen;
@@ -51,20 +52,18 @@ class Parser {
#if haxe3 #if haxe3
public var opPriority : Map<String,Int>; public var opPriority : Map<String,Int>;
public var opRightAssoc : Map<String,Bool>; public var opRightAssoc : Map<String,Bool>;
public var unops : Map<String,Bool>; // true if allow postfix
#else #else
public var opPriority : Hash<Int>; public var opPriority : Hash<Int>;
public var opRightAssoc : Hash<Bool>; public var opRightAssoc : Hash<Bool>;
public var unops : Hash<Bool>; // true if allow postfix
#end #end
/** /**
allows to check for #if / #else in code allows to check for #if / #else in code
**/ **/
public var preprocesorValues : Map<String,Dynamic> = new Map(); public var preprocessorValues : Map<String,Dynamic> = new Map();
/** /**
activate JSON compatiblity activate JSON compatibility
**/ **/
public var allowJSON : Bool; public var allowJSON : Bool;
@@ -92,6 +91,8 @@ class Parser {
var idents : Array<Bool>; var idents : Array<Bool>;
var uid : Int = 0; var uid : Int = 0;
var disableOrOp : Bool = false;
#if hscriptPos #if hscriptPos
var origin : String; var origin : String;
var tokenMin : Int; var tokenMin : Int;
@@ -111,7 +112,6 @@ class Parser {
#end #end
public function new() { public function new() {
line = 1; line = 1;
opChars = "+*/-=!><&|^%~"; opChars = "+*/-=!><&|^%~";
@@ -126,24 +126,24 @@ class Parser {
["..."], ["..."],
["&&"], ["&&"],
["||"], ["||"],
["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>"], ["=","+=","-=","*=","/=","%=","<<=",">>=",">>>=","|=","&=","^=","=>","??" + "="],
["->", "??"],
["is"]
]; ];
#if haxe3 #if haxe3
opPriority = new Map(); opPriority = new Map();
opRightAssoc = new Map(); opRightAssoc = new Map();
unops = new Map();
#else #else
opPriority = new Hash(); opPriority = new Hash();
opRightAssoc = new Hash(); opRightAssoc = new Hash();
unops = new Hash();
#end #end
for( i in 0...priorities.length ) for( i in 0...priorities.length )
for( x in priorities[i] ) { for( x in priorities[i] ) {
opPriority.set(x, i); opPriority.set(x, i);
if( i == 9 ) opRightAssoc.set(x, true); if( i == 9 ) opRightAssoc.set(x, true);
} }
for( x in ["!", "++", "--", "-", "~"] ) for( x in ["!", "++", "--", "~"] ) // unary "-" handled in parser directly!
unops.set(x, x == "++" || x == "--"); opPriority.set(x, x == "++" || x == "--" ? -1 : -2);
} }
public inline function error( err, pmin, pmax ) { public inline function error( err, pmin, pmax ) {
@@ -185,6 +185,7 @@ class Parser {
public function parseString( s : String, ?origin : String = "hscript" ) { public function parseString( s : String, ?origin : String = "hscript" ) {
initParser(origin); initParser(origin);
if(s == "") s = "0;"; // fixing crash with empty file
input = s; input = s;
readPos = 0; readPos = 0;
var a = new Array(); var a = new Array();
@@ -279,8 +280,9 @@ class Parser {
if( e == null ) return false; if( e == null ) return false;
return switch( expr(e) ) { return switch( expr(e) ) {
case EBlock(_), EObject(_), ESwitch(_): true; case EBlock(_), EObject(_), ESwitch(_): true;
case EFunction(_,e,_,_): isBlock(e); case EFunction(_,e,_,_,_,_): isBlock(e);
case EVar(_, t, e): e != null ? isBlock(e) : t != null ? t.match(CTAnon(_)) : false; case EClass(_,e,_,_): true;
case EVar(_, t, e, _,_): e != null ? isBlock(e) : t != null ? t.match(CTAnon(_)) : false;
case EIf(_,e1,e2): if( e2 != null ) isBlock(e2) else isBlock(e1); case EIf(_,e1,e2): if( e2 != null ) isBlock(e2) else isBlock(e1);
case EBinop(_,_,e): isBlock(e); case EBinop(_,_,e): isBlock(e);
case EUnop(_,prefix,e): !prefix && isBlock(e); case EUnop(_,prefix,e): !prefix && isBlock(e);
@@ -350,20 +352,32 @@ class Parser {
} }
function parseExpr() { function parseExpr() {
var oldPos = readPos;
var tk = token(); var tk = token();
#if hscriptPos #if hscriptPos
var p1 = tokenMin; var p1 = tokenMin;
#end #end
switch( tk ) { switch( tk ) {
case TId(id): case TId(id):
var e = parseStructure(id); var e = parseStructure(id, oldPos);
if( e == null ) if( e == null )
e = mk(EIdent(id)); e = mk(EIdent(id));
return parseExprNext(e); return parseExprNext(e);
case TConst(c): case TConst(c):
return parseExprNext(mk(EConst(c))); return parseExprNext(mk(EConst(c)));
case TPOpen: case TPOpen:
tk = token();
if( tk == TPClose ) {
ensureToken(TOp("->"));
var eret = parseExpr();
return mk(EFunction([], mk(EReturn(eret),p1)), p1);
}
push(tk);
var oldoo = disableOrOp;
disableOrOp = false;
var e = parseExpr(); var e = parseExpr();
disableOrOp = oldoo;
tk = token(); tk = token();
switch( tk ) { switch( tk ) {
case TPClose: case TPClose:
@@ -433,31 +447,40 @@ class Parser {
} }
return mk(EBlock(a),p1); return mk(EBlock(a),p1);
case TOp(op): case TOp(op):
if( unops.exists(op) ) { if( op == "-" ) {
var start = tokenMin; var start = tokenMin;
var oldoo = disableOrOp;
disableOrOp = false;
var e = parseExpr(); var e = parseExpr();
if( op == "-" && e != null ) disableOrOp = oldoo;
if( e == null )
return makeUnop(op,e);
switch( expr(e) ) { switch( expr(e) ) {
case EConst(CInt(i)): case EConst(CInt(i)):
return mk(EConst(CInt(-i)), start, pmax(e)); return mk(EConst(CInt(-i)), start, pmax(e));
case EConst(CFloat(f)): case EConst(CFloat(f)):
return mk(EConst(CFloat(-f)), start, pmax(e)); return mk(EConst(CFloat(-f)), start, pmax(e));
default: default:
}
return makeUnop(op,e); return makeUnop(op,e);
} }
}
if( opPriority.get(op) < 0 )
return makeUnop(op,parseExpr());
return unexpected(tk); return unexpected(tk);
case TBkOpen: case TBkOpen:
var a = new Array(); var a = new Array();
tk = token(); tk = token();
while( tk != TBkClose && (!resumeErrors || tk != TEof) ) { while( tk != TBkClose && (!resumeErrors || tk != TEof) ) {
push(tk); push(tk);
var oldoo = disableOrOp;
disableOrOp = false;
a.push(parseExpr()); a.push(parseExpr());
disableOrOp = oldoo;
tk = token(); tk = token();
if( tk == TComma ) if( tk == TComma )
tk = token(); tk = token();
} }
if( a.length == 1 && a[0] != null ) if( a.length == 1 && a[0] != null ) // What is this for???
switch( expr(a[0]) ) { switch( expr(a[0]) ) {
case EFor(_), EWhile(_), EDoWhile(_): case EFor(_), EWhile(_), EDoWhile(_):
var tmp = "__a_" + (uid++); var tmp = "__a_" + (uid++);
@@ -469,7 +492,7 @@ class Parser {
return parseExprNext(e); return parseExprNext(e);
default: default:
} }
return parseExprNext(mk(EArrayDecl(a), p1)); return parseExprNext(mk(EArrayDecl(a, nextType), p1));
case TMeta(id) if( allowMetadata ): case TMeta(id) if( allowMetadata ):
var args = parseMetaArgs(); var args = parseMetaArgs();
return mk(EMeta(id, args, parseExpr()),p1); return mk(EMeta(id, args, parseExpr()),p1);
@@ -525,8 +548,8 @@ class Parser {
function mapCompr( tmp : String, e : Expr ) { function mapCompr( tmp : String, e : Expr ) {
if( e == null ) return null; if( e == null ) return null;
var edef = switch( expr(e) ) { var edef = switch( expr(e) ) {
case EFor(v, it, e2): case EFor(v, it, e2, ithv):
EFor(v, it, mapCompr(tmp, e2)); EFor(v, it, mapCompr(tmp, e2), ithv);
case EWhile(cond, e2): case EWhile(cond, e2):
EWhile(cond, mapCompr(tmp, e2)); EWhile(cond, mapCompr(tmp, e2));
case EDoWhile(cond, e2): case EDoWhile(cond, e2):
@@ -572,7 +595,11 @@ class Parser {
} }
} }
function parseStructure(id) { var nextIsOverride:Bool = false;
var nextIsStatic:Bool = false;
var nextIsPublic:Bool = false;
var nextType:CType = null;
function parseStructure(id, ?oldPos:Int) {
#if hscriptPos #if hscriptPos
var p1 = tokenMin; var p1 = tokenMin;
#end #end
@@ -596,20 +623,111 @@ class Parser {
if( semic ) push(TSemicolon); if( semic ) push(TSemicolon);
} }
mk(EIf(cond,e1,e2),p1,(e2 == null) ? tokenMax : pmax(e2)); mk(EIf(cond,e1,e2),p1,(e2 == null) ? tokenMax : pmax(e2));
case "var": case "override":
nextIsOverride = true;
var nextToken = token();
switch(nextToken) {
case TId("public"):
var str = parseStructure("public"); // override public
nextIsOverride = false;
str;
case TId("function"):
var str = parseStructure("function"); // override function
nextIsOverride = false;
str;
case TId("static"):
var str = parseStructure("static"); // override static
nextIsOverride = false;
str;
case TId("var"):
var str = parseStructure("var"); // override var
nextIsOverride = false;
str;
case TId("final"):
var str = parseStructure("final"); // override final
nextIsOverride = false;
str;
default:
unexpected(nextToken);
nextIsOverride = false;
null;
}
case "static":
nextIsStatic = true;
var nextToken = token();
switch(nextToken) {
case TId("public"):
var str = parseStructure("public"); // static public
nextIsStatic = false;
str;
case TId("function"):
var str = parseStructure("function"); // static function
nextIsStatic = false;
str;
case TId("override"):
var str = parseStructure("override"); // static override
nextIsStatic = false;
str;
case TId("var"):
var str = parseStructure("var"); // static var
nextIsStatic = false;
str;
case TId("final"):
var str = parseStructure("final"); // static final
nextIsStatic = false;
str;
default:
unexpected(nextToken);
nextIsStatic = false;
null;
}
case "public":
nextIsPublic = true;
var nextToken = token();
switch(nextToken) {
case TId("static"):
var str = parseStructure("static"); // public static
nextIsPublic = false;
str;
case TId("function"):
var str = parseStructure("function"); // public function
nextIsPublic = false;
str;
case TId("override"):
var str = parseStructure("override"); // public override
nextIsPublic = false;
str;
case TId("var"):
var str = parseStructure("var"); // public var
nextIsPublic = false;
str;
case TId("final"):
var str = parseStructure("final"); // public final
nextIsPublic = false;
str;
default:
unexpected(nextToken);
nextIsPublic = false;
null;
}
case "var" | "final":
var ident = getIdent(); var ident = getIdent();
var tk = token(); var tk = token();
var t = null; var t = null;
nextType = null;
if( tk == TDoubleDot && allowTypes ) { if( tk == TDoubleDot && allowTypes ) {
t = parseType(); t = parseType();
tk = token(); tk = token();
nextType = t;
} }
var e = null; var e = null;
if( Type.enumEq(tk,TOp("=")) ) if( Type.enumEq(tk,TOp("=")) )
e = parseExpr(); e = parseExpr();
else else
push(tk); push(tk);
mk(EVar(ident,t,e),p1,(e == null) ? tokenMax : pmax(e)); nextType = null;
mk(EVar(ident, t, e, nextIsPublic, nextIsStatic), p1, (e == null) ? tokenMax : pmax(e));
case "while": case "while":
var econd = parseExpr(); var econd = parseExpr();
var e = parseExpr(); var e = parseExpr();
@@ -626,12 +744,21 @@ class Parser {
mk(EDoWhile(econd,e),p1,pmax(econd)); mk(EDoWhile(econd,e),p1,pmax(econd));
case "for": case "for":
ensure(TPOpen); ensure(TPOpen);
var ithv:String = null;
var vname = getIdent(); var vname = getIdent();
var tk = token();
if( Type.enumEq(tk,TOp("=>")) ) {
var old = vname;
vname = getIdent();
ithv = old;
} else {
push(tk);
}
ensureToken(TId("in")); ensureToken(TId("in"));
var eiter = parseExpr(); var eiter = parseExpr();
ensure(TPClose); ensure(TPClose);
var e = parseExpr(); var e = parseExpr();
mk(EFor(vname,eiter,e),p1,pmax(e)); mk(EFor(vname,eiter,e,ithv),p1,pmax(e));
case "break": mk(EBreak); case "break": mk(EBreak);
case "continue": mk(EContinue); case "continue": mk(EContinue);
case "else": unexpected(TId(id)); case "else": unexpected(TId(id));
@@ -646,7 +773,150 @@ class Parser {
default: push(tk); default: push(tk);
} }
var inf = parseFunctionDecl(); var inf = parseFunctionDecl();
mk(EFunction(inf.args, inf.body, name, inf.ret),p1,pmax(inf.body));
var tk = token();
push(tk);
mk(EFunction(inf.args, inf.body, name, inf.ret, nextIsPublic, nextIsStatic, nextIsOverride),p1,pmax(inf.body));
case "import":
var oldReadPos = readPos;
var tk = token();
switch( tk ) {
case TPOpen:
var tok = token();
switch(tok) {
case TConst(c):
switch(c) {
case CString(s):
token();
ensure(TSemicolon);
push(TSemicolon);
mk(EImport(s), p1);
default:
unexpected(tok);
null;
}
default:
unexpected(tok);
null;
}
case TId(id):
var path = [id];
var asname:String = null;
var t = null;
while( true ) {
t = token();
if( t != TDot ) {
if(t.match(TId("as"))) {
t = token();
switch( t ) {
case TId(id):
asname = id;
default:
unexpected(t);
}
break;
}
push(t);
break;
}
t = token();
switch( t ) {
case TId(id):
path.push(id);
default:
unexpected(t);
}
}
ensure(TSemicolon);
push(TSemicolon);
var p = path.join(".");
mk(EImport(p, asname),p1);
default:
unexpected(tk);
null;
}
case "class":
// example: class ClassName
var tk = token();
var name = null;
switch (tk) {
case TId(id): name = id;
default: push(tk);
}
var extend:String = null;
var interfaces:Array<String> = [];
// optional - example: extends BaseClass
while( true ) {
var t = token();
switch( t ) {
case TId("extends"):
var e = parseType();
switch(e) {
case CTPath(path, params):
if(extend != null) {
error(ECustom('Cannot extend a class twice.'), 0, 0);
}
extend = path.join(".");
default:
error(ECustom('${Std.string(e)} is not a valid path.'), 0, 0);
}
default:
push(t);
break;
}
}
/*while(true) {
tk = token();
trace(tk);
switch (tk) {
case TId(id):
if (id == "extends") {
tk = token();
if(extend != null) {
unexpected(tk);
} else {
switch (tk) {
case TId(id): extend = id;
default: unexpected(tk);
}
}
} else if (id == "implements") {
tk = token();
switch (tk) {
case TId(id): interfaces.push(id);
default: unexpected(tk);
}
} else {
//push(tk);
}
case TBrOpen:
push(tk);
break;
default:
//push(tk);
}
}*/
var fields = [];
ensure(TBrOpen);
while( !maybe(TBrClose) ) {
if(token() == TSemicolon) continue;
var a = parseExpr();
fields.push(a);
}
var tk = token();
push(tk);
mk(EClass(name, fields, extend, interfaces), p1);
case "return": case "return":
var tk = token(); var tk = token();
push(tk); push(tk);
@@ -696,12 +966,13 @@ class Parser {
case TId("case"): case TId("case"):
var c = { values : [], expr : null }; var c = { values : [], expr : null };
cases.push(c); cases.push(c);
disableOrOp = true;
while( true ) { while( true ) {
var e = parseExpr(); var e = parseExpr();
c.values.push(e); c.values.push(e);
tk = token(); tk = token();
switch( tk ) { switch( tk ) {
case TComma: case TComma | TOp("|"):
// next expr // next expr
case TDoubleDot: case TDoubleDot:
break; break;
@@ -710,6 +981,7 @@ class Parser {
break; break;
} }
} }
disableOrOp = false;
var exprs = []; var exprs = [];
while( true ) { while( true ) {
tk = token(); tk = token();
@@ -783,7 +1055,12 @@ class Parser {
unexpected(tk); unexpected(tk);
} }
if( unops.get(op) ) { if(disableOrOp && op == "|") {
push(tk);
return e1;
}
if( opPriority.get(op) == -1 ) {
if( isBlock(e1) || switch(expr(e1)) { case EParent(_): true; default: false; } ) { if( isBlock(e1) || switch(expr(e1)) { case EParent(_): true; default: false; } ) {
push(tk); push(tk);
return e1; return e1;
@@ -791,9 +1068,9 @@ class Parser {
return parseExprNext(mk(EUnop(op,false,e1),pmin(e1))); return parseExprNext(mk(EUnop(op,false,e1),pmin(e1)));
} }
return makeBinop(op,e1,parseExpr()); return makeBinop(op,e1,parseExpr());
case TDot: case TDot | TQuestionDot:
var field = getIdent(); var field = getIdent();
return parseExprNext(mk(EField(e1,field),pmin(e1))); return parseExprNext(mk(EField(e1, field, tk == TQuestionDot), pmin(e1)));
case TPOpen: case TPOpen:
return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1))); return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)));
case TBkOpen: case TBkOpen:
@@ -836,8 +1113,10 @@ class Parser {
if( allowTypes ) { if( allowTypes ) {
if( maybe(TDoubleDot) ) if( maybe(TDoubleDot) )
arg.t = parseType(); arg.t = parseType();
if( maybe(TOp("=")) ) if( maybe(TOp("="))) {
arg.value = parseExpr(); arg.value = parseExpr();
arg.opt = true;
}
} }
tk = token(); tk = token();
switch( tk ) { switch( tk ) {
@@ -979,6 +1258,14 @@ class Parser {
fields.push( { name : name, t : parseType(), meta : meta } ); fields.push( { name : name, t : parseType(), meta : meta } );
meta = null; meta = null;
ensure(TSemicolon); ensure(TSemicolon);
case TId("final"):
var name = getIdent();
ensure(TDoubleDot);
if( meta == null ) meta = [];
meta.push({ name : ":final", params : [] });
fields.push( { name : name, t : parseType(), meta : meta } );
meta = null;
ensure(TSemicolon);
case TId(name): case TId(name):
ensure(TDoubleDot); ensure(TDoubleDot);
fields.push( { name : name, t : parseType(), meta : meta } ); fields.push( { name : name, t : parseType(), meta : meta } );
@@ -1314,18 +1601,25 @@ class Parser {
return b.toString(); return b.toString();
} }
function token() { function token(?infos : Null<haxe.PosInfos>) {
//function ttrace(v:Dynamic, ?infos : Null<haxe.PosInfos>) {
// Sys.print(infos.fileName+":"+infos.lineNumber+": " + Std.string(v));
// Sys.print("\r\n");
//}
#if hscriptPos #if hscriptPos
var t = tokens.pop(); var t = tokens.pop();
if( t != null ) { if( t != null ) {
tokenMin = t.min; tokenMin = t.min;
tokenMax = t.max; tokenMax = t.max;
//ttrace(t.t, infos);
return t.t; return t.t;
} }
oldTokenMin = tokenMin; oldTokenMin = tokenMin;
oldTokenMax = tokenMax; oldTokenMax = tokenMax;
tokenMin = (this.char < 0) ? readPos : readPos - 1; tokenMin = (this.char < 0) ? readPos : readPos - 1;
var t = _token(); var t = _token();
//ttrace(t, infos);
tokenMax = (this.char < 0) ? readPos - 1 : readPos - 2; tokenMax = (this.char < 0) ? readPos - 1 : readPos - 2;
return t; return t;
} }
@@ -1367,6 +1661,7 @@ class Parser {
switch( char ) { switch( char ) {
case 48,49,50,51,52,53,54,55,56,57: case 48,49,50,51,52,53,54,55,56,57:
n = n * 10 + (char - 48); n = n * 10 + (char - 48);
case '_'.code:
case "e".code, "E".code: case "e".code, "E".code:
var tk = token(); var tk = token();
var pow : Null<Int> = null; var pow : Null<Int> = null;
@@ -1410,6 +1705,7 @@ class Parser {
n = (n << 4) + (char - 55); n = (n << 4) + (char - 55);
case 97,98,99,100,101,102: // a-f case 97,98,99,100,101,102: // a-f
n = (n << 4) + (char - 87); n = (n << 4) + (char - 87);
case '_'.code:
default: default:
this.char = char; this.char = char;
return TConst(CInt(n)); return TConst(CInt(n));
@@ -1426,6 +1722,7 @@ class Parser {
n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 55)); n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 55));
case 97,98,99,100,101,102: // a-f case 97,98,99,100,101,102: // a-f
n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 87)); n = haxe.Int32.add(haxe.Int32.shl(n,4), cast (char - 87));
case '_'.code:
default: default:
this.char = char; this.char = char;
// we allow to parse hexadecimal Int32 in Neko, but when the value will be // we allow to parse hexadecimal Int32 in Neko, but when the value will be
@@ -1436,6 +1733,41 @@ class Parser {
} }
} }
#end #end
case "b".code: // Custom thing, not supported in haxe
if( n > 0 || exp > 0 )
invalidChar(char);
// read binary
#if haxe3
var n = 0;
while( true ) {
char = readChar();
switch( char ) {
case 48,49: // 0-1
n = (n << 1) + char - 48;
case '_'.code:
default:
this.char = char;
return TConst(CInt(n));
}
}
#else
var n = haxe.Int32.ofInt(0);
while( true ) {
char = readChar();
switch( char ) {
case 48,49: // 0-1
n = haxe.Int32.add(haxe.Int32.shl(n,1), cast (char - 48));
case '_'.code:
default:
this.char = char;
// we allow to parse binary Int32 in Neko, but when the value will be
// evaluated by Interpreter, a failure will occur if no Int32 operation is
// performed
var v = try CInt(haxe.Int32.toInt(n)) catch( e : Dynamic ) CInt32(n);
return TConst(v);
}
}
#end
default: default:
this.char = char; this.char = char;
var i = Std.int(n); var i = Std.int(n);
@@ -1477,7 +1809,22 @@ class Parser {
case "[".code: return TBkOpen; case "[".code: return TBkOpen;
case "]".code: return TBkClose; case "]".code: return TBkClose;
case "'".code, '"'.code: return TConst( CString(readString(char)) ); case "'".code, '"'.code: return TConst( CString(readString(char)) );
case "?".code: return TQuestion; case "?".code:
char = readChar();
switch (char) {
case '?'.code:
var orp = readPos;
if (readChar() == '='.code)
return TOp("??" + "=");
this.readPos = orp;
return TOp("??");
case '.'.code:
return TQuestionDot;
}
this.char = char;
return TQuestion;
case ":".code: return TDoubleDot; case ":".code: return TDoubleDot;
case '='.code: case '='.code:
char = readChar(); char = readChar();
@@ -1518,18 +1865,21 @@ class Parser {
default: default:
if( ops[char] ) { if( ops[char] ) {
var op = String.fromCharCode(char); var op = String.fromCharCode(char);
var prev = -1;
while( true ) { while( true ) {
char = readChar(); char = readChar();
if( StringTools.isEof(char) ) char = 0; if( StringTools.isEof(char) ) char = 0;
if( !ops[char] || prev == '='.code ) { if( !ops[char] ) {
if( op.charCodeAt(0) == '/'.code )
return tokenComment(op,char);
this.char = char; this.char = char;
return TOp(op); return TOp(op);
} }
prev = char; var pop = op;
op += String.fromCharCode(char); op += String.fromCharCode(char);
if( !opPriority.exists(op) && opPriority.exists(pop) ) {
if( op == "//" || op == "/*" )
return tokenComment(op,char);
this.char = char;
return TOp(pop);
}
} }
} }
if( idents[char] ) { if( idents[char] ) {
@@ -1539,6 +1889,7 @@ class Parser {
if( StringTools.isEof(char) ) char = 0; if( StringTools.isEof(char) ) char = 0;
if( !idents[char] ) { if( !idents[char] ) {
this.char = char; this.char = char;
if(id == "is") return TOp("is");
return TId(id); return TId(id);
} }
id += String.fromCharCode(char); id += String.fromCharCode(char);
@@ -1564,6 +1915,21 @@ class Parser {
push(TPOpen); push(TPOpen);
parseExpr(); parseExpr();
case TId(id): case TId(id):
while(true) {
var tk = token();
if(tk == TDot) {
id += ".";
tk = token();
switch(tk) {
case TId(id2):
id += id2;
default: unexpected(tk);
}
} else {
push(tk);
break;
}
}
mk(EIdent(id), tokenMin, tokenMax); mk(EIdent(id), tokenMin, tokenMax);
case TOp("!"): case TOp("!"):
mk(EUnop("!", true, parsePreproCond()), tokenMin, tokenMax); mk(EUnop("!", true, parsePreproCond()), tokenMin, tokenMax);
@@ -1576,6 +1942,14 @@ class Parser {
switch( expr(e) ) { switch( expr(e) ) {
case EIdent(id): case EIdent(id):
return preprocValue(id) != null; return preprocValue(id) != null;
case EField(e2, f):
switch(expr(e2)) {
case EIdent(id):
return preprocValue(id + "." + f) != null;
default:
error(EInvalidPreprocessor("Can't eval " + expr(e).getName() + " with " + expr(e2).getName()), readPos, readPos);
return false;
}
case EUnop("!", _, e): case EUnop("!", _, e):
return !evalPreproCond(e); return !evalPreproCond(e);
case EParent(e): case EParent(e):
@@ -1629,8 +2003,14 @@ class Parser {
var pos = readPos; var pos = readPos;
while( true ) { while( true ) {
var tk = token(); var tk = token();
if( tk == TEof )
if( tk == TEof ) {
if (preprocStack.length != 0) {
error(EInvalidPreprocessor("Unclosed"), pos, pos); error(EInvalidPreprocessor("Unclosed"), pos, pos);
} else {
break;
}
}
if( preprocStack[spos] != obj ) { if( preprocStack[spos] != obj ) {
push(tk); push(tk);
break; break;
@@ -1702,6 +2082,7 @@ class Parser {
case TBrOpen: "{"; case TBrOpen: "{";
case TBrClose: "}"; case TBrClose: "}";
case TDot: "."; case TDot: ".";
case TQuestionDot: "?.";
case TComma: ","; case TComma: ",";
case TSemicolon: ";"; case TSemicolon: ";";
case TBkOpen: "["; case TBkOpen: "[";
@@ -1713,4 +2094,7 @@ class Parser {
} }
} }
@:noCompletion public var preprocesorValues(get,set) : Map<String,Dynamic>;
inline function get_preprocesorValues() return this.preprocessorValues;
inline function set_preprocesorValues(v) return this.preprocessorValues = v;
} }
+31 -7
View File
@@ -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: '"+(StringTools.isEof(c) ? "EOF" : 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;
+5
View File
@@ -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);
} }
+437
View File
@@ -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
+160
View File
@@ -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
+209
View File
@@ -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