Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48ec0f4b01 | ||
|
|
49c90e6434 | ||
|
|
bb46d45d56 | ||
|
|
3a5c4f2164 | ||
|
|
f18c7a2210 | ||
|
|
123a7de64a | ||
|
|
e0e1436930 | ||
|
|
b96e6c8149 | ||
|
|
f6402ac638 | ||
|
|
1e55d0200b | ||
|
|
1725dfd1ea | ||
|
|
a8cc0ccc86 | ||
|
|
7dd868aac7 | ||
|
|
220e5ce007 | ||
|
|
80f6ea4502 | ||
|
|
eb820aaf6a | ||
|
|
a754c162d9 | ||
|
|
de18ceb887 | ||
|
|
51188173bb | ||
|
|
d0797ad5d8 | ||
|
|
9b37bd532e | ||
|
|
333352edcf | ||
|
|
05783773af | ||
|
|
59ee20ee7a | ||
|
|
87f2c1b062 | ||
|
|
b85cefea56 | ||
|
|
2e28f863f3 | ||
|
|
ddaa4d1741 | ||
|
|
732bd1520a | ||
|
|
1d67946f3f | ||
|
|
fab6d7e662 | ||
|
|
6e20578a81 | ||
|
|
dc5282c32e | ||
|
|
812abae6e5 | ||
|
|
b3b512d027 | ||
|
|
ed296c4c7f | ||
|
|
595bb47249 | ||
|
|
daad1a4fa8 | ||
|
|
daef1ac198 | ||
|
|
3b9d88b252 | ||
|
|
809f8229b4 | ||
|
|
ffb1ee2523 | ||
|
|
0903718314 | ||
|
|
e0cb883ae4 | ||
|
|
17449dd9d5 | ||
|
|
7963631a1d | ||
|
|
77d88f4b34 | ||
|
|
c5e3ab1162 | ||
|
|
75041c1db9 | ||
|
|
558a4c0782 | ||
|
|
995c3b9c8e | ||
|
|
0a64bca9ce | ||
|
|
b7b12b6cbb | ||
|
|
5684ca8671 | ||
|
|
3c81360dc2 | ||
|
|
fc50ebdf90 | ||
|
|
4d6e8db5ff | ||
|
|
938ffac57e | ||
|
|
50aaffb101 | ||
|
|
4f9b449c6e | ||
|
|
c1a36a3f4b | ||
|
|
4ca6e2a680 | ||
|
|
11db805c34 | ||
|
|
f1f700ab69 | ||
|
|
9eeb8ddb80 | ||
|
|
95de26a6d0 | ||
|
|
88c2e28dbc | ||
|
|
30b7a9e4d4 | ||
|
|
37542065d6 | ||
|
|
c9608f7760 | ||
|
|
6ba54b0e77 | ||
|
|
f9bb3105c8 | ||
|
|
4b5baa9b5f | ||
|
|
6dedd87260 | ||
|
|
91317222fb | ||
|
|
494953a8cc | ||
|
|
ae4d8be50c | ||
|
|
d34790e05c | ||
|
|
b77e15c6d6 | ||
|
|
54195d5811 | ||
|
|
9c7907f91a | ||
|
|
0601b8def6 | ||
|
|
841261f199 | ||
|
|
7124b6c4ce | ||
|
|
ad7beec559 | ||
|
|
bd4fc51392 | ||
|
|
54d994a879 | ||
|
|
891a085f2b | ||
|
|
e7ccd2e72d | ||
|
|
459a39e65d | ||
|
|
36eb0fca8b | ||
|
|
53b9e22f26 | ||
|
|
8ff3f5e351 | ||
|
|
e6a2c443cb | ||
|
|
4f25ab162d | ||
|
|
0520d9f187 | ||
|
|
cc3c21b7e3 | ||
|
|
ae9560124e | ||
|
|
085f4ec37e | ||
|
|
476c3a9cc9 | ||
|
|
1bc5ac8768 | ||
|
|
4bdff11b87 |
@@ -1,2 +1,4 @@
|
||||
/hscript.swf
|
||||
/release.zip
|
||||
|
||||
tests/bin/*
|
||||
@@ -1,8 +1,18 @@
|
||||
hscript
|
||||
hscript-improved
|
||||
=======
|
||||
|
||||
[](https://travis-ci.org/HaxeFoundation/hscript)
|
||||
[](https://ci.appveyor.com/project/HaxeFoundation/hscript)
|
||||
How to install
|
||||
```
|
||||
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.
|
||||
|
||||
@@ -100,4 +110,4 @@ Some other optional files :
|
||||
- `hscript.Macro` : convert Haxe macro into hscript Expr
|
||||
- `hscript.Printer` : convert hscript Expr to String
|
||||
- `hscript.Tools` : utility functions (map/iter)
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import hscript.Printer;
|
||||
import hscript.Checker;
|
||||
import haxe.unit.*;
|
||||
|
||||
class Test extends TestCase {
|
||||
class TestHScript extends TestCase {
|
||||
function assertScript(x,v:Dynamic,?vars : Dynamic, allowTypes=false, ?pos:haxe.PosInfos) {
|
||||
var p = new hscript.Parser();
|
||||
p.allowTypes = allowTypes;
|
||||
@@ -101,6 +101,7 @@ class Test extends TestCase {
|
||||
assertScript("/**/0", 0);
|
||||
assertScript("x=1;x*=-2", -2);
|
||||
assertScript("var f = x -> x + 1; f(3)", 4);
|
||||
assertScript("var f = () -> 55; f()", 55);
|
||||
assertScript("var f = (x) -> x + 1; f(3)", 4);
|
||||
assertScript("var f = (x:Int) -> x + 1; f(3)", 4);
|
||||
assertScript("var f = (x,y) -> x + y; f(3,1)", 4);
|
||||
@@ -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, z:Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true);
|
||||
assertScript("var f:(x:Int)->(Int, Int)->Int = (x:Int) -> (y:Int, z:Int) -> x + y + z; f(3)(1, 2)", 6, null, true);
|
||||
assertScript("var a = 10; var b = 5; a - -b", 15);
|
||||
assertScript("var a = 10; var b = 5; a - b / 2", 7.5);
|
||||
}
|
||||
|
||||
function testMap():Void {
|
||||
@@ -170,7 +173,7 @@ class Test extends TestCase {
|
||||
#end
|
||||
|
||||
var runner = new TestRunner();
|
||||
runner.add(new Test());
|
||||
runner.add(new TestHScript());
|
||||
var succeed = runner.run();
|
||||
|
||||
#if sys
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
-main Test
|
||||
-main TestHScript
|
||||
-dce no
|
||||
-lib hx3compat
|
||||
+3
-1
@@ -1 +1,3 @@
|
||||
--macro keep('IntIterator')
|
||||
--macro keep('IntIterator')
|
||||
--macro hscript.macros.UsingHandler.init()
|
||||
--macro hscript.macros.ClassExtendMacro.init()
|
||||
|
||||
+9
-9
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "hscript",
|
||||
"url": "https://github.com/HaxeFoundation/hscript",
|
||||
"license": "MIT",
|
||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||
"version": "2.4.0",
|
||||
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
|
||||
"contributors": ["ncannasse"]
|
||||
}
|
||||
{
|
||||
"name": "hscript-improved",
|
||||
"url": "https://github.com/HaxeFoundation/hscript",
|
||||
"license": "MIT",
|
||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||
"version": "2.4.0",
|
||||
"releasenote": "Haxe 4.0 final + type checking/completion (hscript.Checker)",
|
||||
"contributors": ["ncannasse","HaxeFoundation"]
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project version="2">
|
||||
<!-- Output SWF options -->
|
||||
<output>
|
||||
<movie outputType="Application" />
|
||||
<movie input="" />
|
||||
<movie path="hscript.swf" />
|
||||
<movie fps="30" />
|
||||
<movie width="800" />
|
||||
<movie height="600" />
|
||||
<movie version="9" />
|
||||
<movie minorVersion="0" />
|
||||
<movie platform="Flash Player" />
|
||||
<movie background="#FFFFFF" />
|
||||
</output>
|
||||
<!-- Other classes to be compiled into your SWF -->
|
||||
<classpaths>
|
||||
<!-- example: <class path="..." /> -->
|
||||
</classpaths>
|
||||
<!-- Build options -->
|
||||
<build>
|
||||
<option directives="" />
|
||||
<option flashStrict="True" />
|
||||
<option noInlineOnDebug="False" />
|
||||
<option mainClass="Test" />
|
||||
<option enabledebug="False" />
|
||||
<option additional="-dce no" />
|
||||
</build>
|
||||
<!-- haxelib libraries -->
|
||||
<haxelib>
|
||||
<!-- example: <library name="..." /> -->
|
||||
</haxelib>
|
||||
<!-- Class files to compile (other referenced classes will automatically be included) -->
|
||||
<compileTargets>
|
||||
<!-- example: <compile path="..." /> -->
|
||||
</compileTargets>
|
||||
<!-- Assets to embed into the output SWF -->
|
||||
<library>
|
||||
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
|
||||
</library>
|
||||
<!-- Paths to exclude from the Project Explorer tree -->
|
||||
<hiddenPaths>
|
||||
<hidden path="haxelib.xml" />
|
||||
<hidden path="hscript.hxml" />
|
||||
<hidden path="hscript.js" />
|
||||
<hidden path="hscript.n" />
|
||||
<hidden path="hscript.swf" />
|
||||
<hidden path="hscript9.swf" />
|
||||
<hidden path="release.bat" />
|
||||
<hidden path="release.zip" />
|
||||
<hidden path="obj" />
|
||||
</hiddenPaths>
|
||||
<!-- Executed before build -->
|
||||
<preBuildCommand />
|
||||
<!-- Executed after build -->
|
||||
<postBuildCommand alwaysRun="False" />
|
||||
<!-- Other project options -->
|
||||
<options>
|
||||
<option showHiddenPaths="False" />
|
||||
<option testMovie="Default" />
|
||||
<option testMovieCommand="" />
|
||||
</options>
|
||||
<!-- Plugin storage -->
|
||||
<storage />
|
||||
</project>
|
||||
+8
-1
@@ -36,6 +36,7 @@ class Async {
|
||||
var currentLoop : Expr;
|
||||
var currentBreak : Expr -> Expr;
|
||||
var uid = 0;
|
||||
public var asyncIdents : Map<String,Bool>;
|
||||
|
||||
static var nullExpr : Expr = #if hscriptPos { e : null, pmin : 0, pmax : 0, origin : "<null>", line : 0 } #else null #end;
|
||||
static var nullId = mk(EIdent("null"), nullExpr);
|
||||
@@ -207,11 +208,17 @@ class Async {
|
||||
return syncFlag;
|
||||
}
|
||||
|
||||
inline function isAsyncIdent( id : String ) {
|
||||
return asyncIdents == null || asyncIdents.exists(id);
|
||||
}
|
||||
|
||||
function checkSync( e : Expr ) {
|
||||
if( !syncFlag )
|
||||
return;
|
||||
switch( expr(e) ) {
|
||||
case ECall(_):
|
||||
case ECall(expr(_) => EIdent(i),_) if( isAsyncIdent(i) || vars.get(i) == Defined ):
|
||||
syncFlag = false;
|
||||
case ECall(expr(_) => EField(_,i),_) if( isAsyncIdent(i) ):
|
||||
syncFlag = false;
|
||||
case EFunction(_,_,name,_) if( name != null ):
|
||||
syncFlag = false;
|
||||
|
||||
@@ -140,6 +140,10 @@ class Bytes {
|
||||
#end
|
||||
bout.addByte(Type.enumIndex(e));
|
||||
switch( e ) {
|
||||
case EImport(c):
|
||||
// TODO
|
||||
case EClass(_, _, _, _):
|
||||
// TODO
|
||||
case EConst(c):
|
||||
doEncodeConst(c);
|
||||
case EIdent(v):
|
||||
|
||||
+76
-18
@@ -48,6 +48,8 @@ typedef CNamedType = {
|
||||
typedef CClass = {> CNamedType,
|
||||
@:optional var superClass : TType;
|
||||
@:optional var constructor : CField;
|
||||
@:optional var interfaces : Array<TType>;
|
||||
@:optional var isInterface : Bool;
|
||||
var fields : Map<String,CField>;
|
||||
var statics : Map<String,CField>;
|
||||
}
|
||||
@@ -121,12 +123,19 @@ class CheckerTypes {
|
||||
fields : new Map(),
|
||||
statics : new Map(),
|
||||
};
|
||||
if( c.isInterface )
|
||||
cl.isInterface = true;
|
||||
for( p in c.params )
|
||||
cl.params.push(TParam(p));
|
||||
todo.push(function() {
|
||||
localParams = [for( t in cl.params ) c.path+"."+Checker.typeStr(t) => t];
|
||||
if( c.superClass != null )
|
||||
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 = [];
|
||||
for( f in c.fields ) {
|
||||
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 ) {
|
||||
for( f in cl.fields )
|
||||
if( f.isPublic )
|
||||
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(function() return apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()])));
|
||||
while( true ) {
|
||||
for( f in cl.fields )
|
||||
if( f.isPublic )
|
||||
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(function() return apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()])));
|
||||
if( cl.superClass == null )
|
||||
break;
|
||||
cl = switch( cl.superClass ) {
|
||||
case TInst(c,_): c;
|
||||
default: throw "assert";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeGlobal( name : String ) {
|
||||
@@ -580,6 +597,8 @@ class Checker {
|
||||
case [TDynamic, _]:
|
||||
return true;
|
||||
case [TAnon(a1),TAnon(a2)]:
|
||||
if( a2.length == 0 ) // always unify with {}
|
||||
return true;
|
||||
var m = new Map();
|
||||
for( f in a1 )
|
||||
m.set(f.name, f);
|
||||
@@ -595,6 +614,18 @@ class Checker {
|
||||
return true;
|
||||
case [TInst(cl1,pl1), TInst(cl2,pl2)]:
|
||||
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 ) {
|
||||
case null: return false;
|
||||
case TInst(c, args):
|
||||
@@ -693,23 +724,42 @@ class Checker {
|
||||
}
|
||||
}
|
||||
|
||||
public function getFields( t : TType ) {
|
||||
public function getFields( t : TType ) : Array<{ name : String, t : TType }> {
|
||||
var fields = [];
|
||||
while( t != null ) {
|
||||
t = follow(t);
|
||||
switch( t ) {
|
||||
case TInst(c, args):
|
||||
switch( follow(t) ) {
|
||||
case TInst(c, args):
|
||||
var map = (t) -> apply(t,c.params,args);
|
||||
while( c != null ) {
|
||||
for( fname in c.fields.keys() ) {
|
||||
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):
|
||||
for( f in fl )
|
||||
fields.push({ name : f.name, t : f.t });
|
||||
break;
|
||||
default:
|
||||
}
|
||||
case TAnon(fl):
|
||||
for( f in fl )
|
||||
fields.push({ name : f.name, t : f.t });
|
||||
default:
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
@@ -726,6 +776,13 @@ class Checker {
|
||||
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( c.superClass == null ) return null;
|
||||
var ft = getField(c.superClass, f, e, forWrite);
|
||||
@@ -917,7 +974,7 @@ class Checker {
|
||||
return TVoid;
|
||||
case EObject(fl):
|
||||
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];
|
||||
return TAnon([for( f in fl ) {
|
||||
var ft = map.get(f.name);
|
||||
@@ -930,7 +987,7 @@ class Checker {
|
||||
default:
|
||||
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;
|
||||
case EReturn(v):
|
||||
var et = v == null ? TVoid : typeExpr(v, allowReturn == null ? Value : WithType(allowReturn));
|
||||
@@ -1176,9 +1233,10 @@ class Checker {
|
||||
mergeType( typeExpr(defaultExpr, withType), defaultExpr);
|
||||
return withType == NoValue ? TVoid : tmin == null ? makeMono() : tmin;
|
||||
case ENew(cl, params):
|
||||
default:
|
||||
}
|
||||
error("Don't know how to type "+edef(expr).getName(), expr);
|
||||
return TDynamic;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package hscript;
|
||||
|
||||
class Config {
|
||||
// Runs support for custom classes in these
|
||||
public static final ALLOWED_CUSTOM_CLASSES = [
|
||||
"flixel",
|
||||
];
|
||||
|
||||
// Runs support for abstract support in these
|
||||
public static final ALLOWED_ABSTRACT_AND_ENUM = [
|
||||
"flixel",
|
||||
"openfl.display.BlendMode",
|
||||
];
|
||||
|
||||
// Incase any of your files fail
|
||||
// These are the module names
|
||||
public static final DISALLOW_CUSTOM_CLASSES = [
|
||||
|
||||
];
|
||||
|
||||
public static final DISALLOW_ABSTRACT_AND_ENUM = [
|
||||
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package hscript;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class CustomClassHandler implements IHScriptCustomConstructor {
|
||||
public static var staticHandler = new StaticHandler();
|
||||
|
||||
public var ogInterp:Interp;
|
||||
public var name:String;
|
||||
public var fields:Array<Expr>;
|
||||
public var extend:String;
|
||||
public var interfaces:Array<String>;
|
||||
|
||||
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
|
||||
this.ogInterp = ogInterp;
|
||||
this.name = name;
|
||||
this.fields = fields;
|
||||
this.extend = extend;
|
||||
this.interfaces = interfaces;
|
||||
}
|
||||
|
||||
public function hnew(args:Array<Dynamic>):Dynamic {
|
||||
var interp = new Interp();
|
||||
|
||||
interp.errorHandler = ogInterp.errorHandler;
|
||||
|
||||
var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
|
||||
if(cl == null)
|
||||
ogInterp.error(EInvalidClass(extend));
|
||||
|
||||
var _class = Type.createInstance(cl, args);
|
||||
|
||||
var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
|
||||
var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
|
||||
for(k=>e in __capturedLocals)
|
||||
if (e != null && e.depth <= 0)
|
||||
capturedLocals.set(k, e);
|
||||
|
||||
var disallowCopy = Type.getInstanceFields(cl);
|
||||
|
||||
for (key => value in capturedLocals) {
|
||||
if(!disallowCopy.contains(key)) {
|
||||
interp.locals.set(key, {r: value, depth: -1});
|
||||
}
|
||||
}
|
||||
for (key => value in ogInterp.variables) {
|
||||
if(!disallowCopy.contains(key)) {
|
||||
interp.variables.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
for(expr in fields) {
|
||||
@:privateAccess
|
||||
interp.exprReturn(expr);
|
||||
}
|
||||
|
||||
interp.variables.set("super", staticHandler);
|
||||
|
||||
_class.__interp = interp;
|
||||
interp.scriptObject = _class;
|
||||
|
||||
var newFunc = interp.variables.get("new");
|
||||
if(newFunc != null) {
|
||||
Reflect.callMethod(null, newFunc, args);
|
||||
}
|
||||
|
||||
for(variable => value in interp.variables) {
|
||||
if(variable == "this") continue;
|
||||
}
|
||||
|
||||
return _class;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
class TemplateClass implements IHScriptCustomBehaviour {
|
||||
public var __interp:Interp;
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if(this.__interp.variables.exists("set_" + name)) {
|
||||
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
|
||||
}
|
||||
if (this.__interp.variables.exists(name)) {
|
||||
this.__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
Reflect.setProperty(this, name, val);
|
||||
return Reflect.field(this, name);
|
||||
}
|
||||
public function hget(name:String):Dynamic {
|
||||
if(this.__interp.variables.exists("get_" + name))
|
||||
return this.__interp.variables.get("get_" + name)();
|
||||
if (this.__interp.variables.exists(name))
|
||||
return this.__interp.variables.get(name);
|
||||
return Reflect.getProperty(this, name);
|
||||
}
|
||||
}
|
||||
|
||||
class StaticHandler {
|
||||
public function new() {}
|
||||
}
|
||||
+11
-6
@@ -45,31 +45,34 @@ enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : String, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
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 );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr> );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<{ name : String, e : Expr }> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr);
|
||||
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
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 };
|
||||
@@ -117,6 +120,8 @@ enum Error {
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String );
|
||||
ECustom( msg : String );
|
||||
EInvalidClass( className : String);
|
||||
EAlreadyExistingClass( className : String);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package hscript;
|
||||
|
||||
interface IHScriptCustomBehaviour {
|
||||
public function hset(name:String, val:Dynamic):Dynamic;
|
||||
public function hget(name:String):Dynamic;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package hscript;
|
||||
|
||||
interface IHScriptCustomConstructor {
|
||||
public function hnew(args:Array<Dynamic>):Dynamic;
|
||||
}
|
||||
+854
-463
File diff suppressed because it is too large
Load Diff
@@ -79,6 +79,8 @@ class Macro {
|
||||
#if (haxe_ver >= 4)
|
||||
case OpIn: "in";
|
||||
#end
|
||||
default:
|
||||
continue;
|
||||
};
|
||||
binops.set(str, op);
|
||||
if( assign )
|
||||
@@ -92,6 +94,9 @@ class Macro {
|
||||
case OpNegBits: "~";
|
||||
case OpIncrement: "++";
|
||||
case OpDecrement: "--";
|
||||
#if (haxe_ver >= 4.2)
|
||||
case OpSpread: continue;
|
||||
#end
|
||||
}
|
||||
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));
|
||||
case ECheckType(e, t):
|
||||
ECheckType(convert(e), convertType(t));
|
||||
default:
|
||||
null;
|
||||
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
|
||||
}
|
||||
|
||||
|
||||
+868
-484
File diff suppressed because it is too large
Load Diff
+32
-8
@@ -114,6 +114,25 @@ class Printer {
|
||||
return;
|
||||
}
|
||||
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):
|
||||
switch( c ) {
|
||||
case CInt(i): add(i);
|
||||
@@ -122,7 +141,7 @@ class Printer {
|
||||
}
|
||||
case EIdent(v):
|
||||
add(v);
|
||||
case EVar(n, t, e):
|
||||
case EVar(n, t, e): // TODO: static, public, override
|
||||
add("var " + n);
|
||||
addType(t);
|
||||
if( e != null ) {
|
||||
@@ -145,9 +164,9 @@ class Printer {
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case EField(e, f):
|
||||
case EField(e, f, s):
|
||||
expr(e);
|
||||
add("." + f);
|
||||
add((s == true ? "?." : ".") + f);
|
||||
case EBinop(op, e1, e2):
|
||||
expr(e1);
|
||||
add(" " + op + " ");
|
||||
@@ -198,8 +217,11 @@ class Printer {
|
||||
add(" while ( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
case EFor(v, it, e):
|
||||
add("for( "+v+" in ");
|
||||
case EFor(v, it, e, ithv):
|
||||
if(ithv != null)
|
||||
add("for( "+ithv+" => "+v+" in ");
|
||||
else
|
||||
add("for( "+v+" in ");
|
||||
expr(it);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
@@ -207,7 +229,7 @@ class Printer {
|
||||
add("break");
|
||||
case EContinue:
|
||||
add("continue");
|
||||
case EFunction(params, e, name, ret):
|
||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||
add("function");
|
||||
if( name != null )
|
||||
add(" " + name);
|
||||
@@ -234,7 +256,7 @@ class Printer {
|
||||
add("[");
|
||||
expr(index);
|
||||
add("]");
|
||||
case EArrayDecl(el):
|
||||
case EArrayDecl(el, _):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
@@ -331,7 +353,7 @@ class Printer {
|
||||
|
||||
public static function errorToString( e : Expr.Error ) {
|
||||
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 EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
@@ -341,6 +363,8 @@ class Printer {
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
|
||||
@@ -27,6 +27,8 @@ class Tools {
|
||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
||||
switch( expr(e) ) {
|
||||
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 EParent(e): f(e);
|
||||
case EBlock(el): for( e in el ) f(e);
|
||||
@@ -57,6 +59,7 @@ class Tools {
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); 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 EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||
case ECheckType(e,t): ECheckType(f(e), t);
|
||||
case EImport(c): EImport(c);
|
||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||
}
|
||||
return mk(edef, e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
package hscript.macros;
|
||||
|
||||
#if macro
|
||||
import haxe.macro.Type.ClassType;
|
||||
import Type.ValueType;
|
||||
import haxe.macro.Expr.Function;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type.MetaAccess;
|
||||
import haxe.macro.Type.FieldKind;
|
||||
import haxe.macro.Type.ClassField;
|
||||
import haxe.macro.Type.VarAccess;
|
||||
import haxe.macro.*;
|
||||
import Sys;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class ClassExtendMacro {
|
||||
public static inline final FUNC_PREFIX = "_HX_SUPER__";
|
||||
public static inline final CLASS_SUFFIX = "_HSX";
|
||||
|
||||
public static var unallowedMetas:Array<String> = [":bitmap", ":noCustomClass", ":generic"];
|
||||
|
||||
public static var modifiedClasses:Array<String> = [];
|
||||
|
||||
public static function init() {
|
||||
#if !display
|
||||
#if CUSTOM_CLASSES
|
||||
if(Context.defined("display")) return;
|
||||
for(apply in Config.ALLOWED_CUSTOM_CLASSES) {
|
||||
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())");
|
||||
}
|
||||
#end
|
||||
#end
|
||||
}
|
||||
|
||||
public static function build():Array<Field> {
|
||||
var fields = Context.getBuildFields();
|
||||
var clRef = Context.getLocalClass();
|
||||
if (clRef == null) return fields;
|
||||
var cl = clRef.get();
|
||||
|
||||
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface) return fields;
|
||||
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC")) {
|
||||
var metas = cl.meta.get();
|
||||
|
||||
for(m in metas)
|
||||
if (unallowedMetas.contains(m.name))
|
||||
return fields;
|
||||
|
||||
if(cl.params.length > 0)
|
||||
return fields;
|
||||
|
||||
var key = cl.module;
|
||||
var fkey = cl.module + "." + cl.name;
|
||||
if(key == "sys.thread.FixedThreadPool") return fields; // Error: Type name sys.thread.Worker_HSX is redefined from module sys.thread.FixedThreadPool
|
||||
if(key == "StdTypes") return fields; // Error: Cant extend basic class
|
||||
if(key == "Xml") return fields; // Error: Cant extend basic class
|
||||
if(key == "Date") return fields; // Error: Cant extend basic class
|
||||
if(key == "away3d.tools.commands.Mirror") return fields; // Error: Unknown identifier
|
||||
if(key == "away3d.tools.commands.SphereMaker") return fields; // Error: Unknown identifier
|
||||
if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier
|
||||
if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined
|
||||
if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined
|
||||
if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields;
|
||||
if(cl.module.contains("_")) return fields; // Weird issue, sorry
|
||||
|
||||
var superFields = [];
|
||||
if(cl.superClass != null) {
|
||||
var _superFields = cl.superClass.t.get().fields.get();
|
||||
_superFields = []; // Comment to enable super support, (broken)
|
||||
for(field in _superFields) {
|
||||
if(!field.kind.match(FMethod(_))) // only catch methods
|
||||
continue;
|
||||
|
||||
try {
|
||||
var nfield = @:privateAccess TypeTools.toField(field);
|
||||
switch ([field.kind, field.type]) {
|
||||
case [FMethod(kind), TFun(args, ret)]:
|
||||
if(kind == MethInline)
|
||||
nfield.access.push(AInline);
|
||||
if(kind == MethDynamic)
|
||||
nfield.access.push(ADynamic);
|
||||
default:
|
||||
}
|
||||
|
||||
switch(nfield.kind) {
|
||||
case FFun(fun):
|
||||
if (fun.params != null && fun.params.length > 0)
|
||||
continue;
|
||||
|
||||
fun.ret = Utils.fixStdTypes(fun.ret);
|
||||
|
||||
var metas = nfield.meta;
|
||||
var defaultValues:Map<String, Dynamic> = [];
|
||||
var defaultEntry = null;
|
||||
var isGeneric = false;
|
||||
for(m in metas) {
|
||||
if(m.name == ":value") {
|
||||
defaultEntry = m;
|
||||
switch(m.params[0].expr) {
|
||||
case EObjectDecl(fields):
|
||||
for(fil in fields)
|
||||
defaultValues[fil.field] = fil.expr;
|
||||
default:
|
||||
}
|
||||
}
|
||||
if(m.name == ":generic")
|
||||
isGeneric = true;
|
||||
}
|
||||
if(isGeneric) continue;
|
||||
|
||||
if(defaultEntry != null)
|
||||
metas.remove(defaultEntry);
|
||||
|
||||
for(arg in fun.args) {
|
||||
var opt = false;
|
||||
if(defaultValues.exists(arg.name)) {
|
||||
arg.value = defaultValues[arg.name];
|
||||
arg.opt = false;
|
||||
}
|
||||
|
||||
arg.type = Utils.fixStdTypes(arg.type);
|
||||
|
||||
if(arg.opt) {
|
||||
if(arg.type.getParameters()[0].name != "Null")
|
||||
arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>};
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
superFields.push(nfield);
|
||||
} catch(e) {
|
||||
|
||||
}
|
||||
}
|
||||
//superFields = [];
|
||||
}
|
||||
|
||||
var shadowClass = macro class {
|
||||
|
||||
};
|
||||
|
||||
var definedFields:Array<String> = [];
|
||||
|
||||
//trace(getModuleName(cl));
|
||||
|
||||
var hasNew = false;
|
||||
|
||||
for(_field in [fields.copy(), superFields.copy()])
|
||||
for(f in _field) {
|
||||
if (f == null)
|
||||
continue;
|
||||
if (f.name == "new") {
|
||||
hasNew = true;
|
||||
continue;
|
||||
}
|
||||
if (f.name.startsWith(FUNC_PREFIX))
|
||||
continue;
|
||||
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline))
|
||||
continue;
|
||||
|
||||
if(f.name == "hget" || f.name == "hset") continue; // sorry, no overwriting the hget and hset in custom classes, yet
|
||||
if(definedFields.contains(f.name)) continue; // no duplicate fields
|
||||
|
||||
for(m in f.meta)
|
||||
if (unallowedMetas.contains(m.name))
|
||||
continue;
|
||||
|
||||
switch(f.kind) {
|
||||
case FFun(fun):
|
||||
if (fun == null)
|
||||
continue;
|
||||
if (fun.params != null && fun.params.length > 0) // TODO: Support for this maybe?
|
||||
continue;
|
||||
|
||||
if(fun.params == null)
|
||||
fun.params = [];
|
||||
|
||||
var overrideExpr:Expr;
|
||||
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
|
||||
|
||||
var name = f.name;
|
||||
|
||||
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
|
||||
|
||||
if (returns) {
|
||||
overrideExpr = macro {
|
||||
var name:String = $v{name};
|
||||
|
||||
if (__interp != null) {
|
||||
var v:Dynamic = null;
|
||||
if (__interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||
return v($a{arguments});
|
||||
}
|
||||
}
|
||||
return super.$name($a{arguments});
|
||||
};
|
||||
} else {
|
||||
overrideExpr = macro {
|
||||
var name:String = $v{name};
|
||||
|
||||
if (__interp != null) {
|
||||
var v:Dynamic = null;
|
||||
if (__interp != null && __interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||
v($a{arguments});
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.$name($a{arguments});
|
||||
};
|
||||
}
|
||||
|
||||
var superFuncExpr:Expr = returns ? {
|
||||
macro return super.$name($a{arguments});
|
||||
} : {
|
||||
macro super.$name($a{arguments});
|
||||
};
|
||||
|
||||
var func:Function = {
|
||||
ret: fun.ret,
|
||||
params: fun.params.copy(),
|
||||
expr: overrideExpr,
|
||||
args: fun.args.copy()
|
||||
};
|
||||
|
||||
var overrideField:Field = {
|
||||
name: f.name,
|
||||
access: f.access.copy(),
|
||||
kind: FFun(func),
|
||||
pos: Context.currentPos(),
|
||||
doc: f.doc,
|
||||
meta: f.meta.copy()
|
||||
};
|
||||
|
||||
if (!overrideField.access.contains(AOverride))
|
||||
overrideField.access.push(AOverride);
|
||||
|
||||
var superField:Field = {
|
||||
name: '$FUNC_PREFIX${f.name}',
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
ret: fun.ret,
|
||||
params: fun.params.copy(),
|
||||
expr: superFuncExpr,
|
||||
args: fun.args.copy()
|
||||
}),
|
||||
access: f.access.copy()
|
||||
};
|
||||
if (superField.access.contains(AOverride))
|
||||
superField.access.remove(AOverride);
|
||||
shadowClass.fields.push(overrideField);
|
||||
shadowClass.fields.push(superField);
|
||||
definedFields.push(f.name);
|
||||
default:
|
||||
// fuck off >:(
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var totalFields = definedFields.length;
|
||||
|
||||
if(totalFields == 0 && !hasNew) {
|
||||
//Sys.println(cl.pack.join(".") + "." + cl.name + ", " + totalFields);
|
||||
return fields;
|
||||
}
|
||||
|
||||
shadowClass.kind = TDClass({
|
||||
pack: cl.pack.copy(),
|
||||
name: cl.name
|
||||
}, [
|
||||
{name: "IHScriptCustomBehaviour", pack: ["hscript"]}
|
||||
], false, true, false);
|
||||
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
||||
var imports = Context.getLocalImports().copy();
|
||||
Utils.setupMetas(shadowClass, imports);
|
||||
|
||||
// Adding hscript getters and setters
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "__interp",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(TPath({
|
||||
pack: ['hscript'],
|
||||
name: 'Interp'
|
||||
}))
|
||||
});
|
||||
|
||||
// Todo: make it possible to override
|
||||
if(cl.name == "FunkinShader" || cl.name == "CustomShader" || cl.name == "MultiThreadedScript") {
|
||||
Context.defineModule(cl.module, [shadowClass], imports);
|
||||
return fields;
|
||||
}
|
||||
|
||||
var hasHgetInSuper = false;
|
||||
var hasHsetInSuper = false;
|
||||
|
||||
if(cl.name == "CustomShader") {
|
||||
hasHgetInSuper = hasHsetInSuper = true;
|
||||
}
|
||||
|
||||
// TODO: somehow check the super super class
|
||||
for(_field in [fields.copy(), superFields.copy()])
|
||||
for(f in _field) {
|
||||
if (f.name == "new")
|
||||
continue;
|
||||
if (f.name.startsWith(FUNC_PREFIX))
|
||||
continue;
|
||||
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern))
|
||||
continue;
|
||||
|
||||
switch(f.kind) {
|
||||
case FFun(fun):
|
||||
if (fun.params != null && fun.params.length > 0)
|
||||
continue;
|
||||
|
||||
if(!hasHgetInSuper)
|
||||
hasHgetInSuper = f.name == "hget";
|
||||
if(!hasHsetInSuper)
|
||||
hasHsetInSuper = f.name == "hset";
|
||||
|
||||
if(hasHgetInSuper && hasHsetInSuper)
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var hgetField = if(hasHgetInSuper) {
|
||||
macro {
|
||||
if(this.__interp.variables.exists("get_" + name))
|
||||
return this.__interp.variables.get("get_" + name)();
|
||||
if (this.__interp.variables.exists(name))
|
||||
return this.__interp.variables.get(name);
|
||||
return super.hget(name);
|
||||
}
|
||||
} else {
|
||||
macro {
|
||||
if(this.__interp.variables.exists("get_" + name))
|
||||
return this.__interp.variables.get("get_" + name)();
|
||||
if (this.__interp.variables.exists(name))
|
||||
return this.__interp.variables.get(name);
|
||||
return Reflect.getProperty(this, name);
|
||||
}
|
||||
}
|
||||
|
||||
var hsetField = if(hasHsetInSuper) {
|
||||
macro {
|
||||
if(this.__interp.variables.exists("set_" + name)) {
|
||||
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
|
||||
}
|
||||
if (this.__interp.variables.exists(name)) {
|
||||
this.__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
return super.hset(name, val);
|
||||
}
|
||||
} else {
|
||||
macro {
|
||||
if(this.__interp.variables.exists("set_" + name)) {
|
||||
return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
|
||||
}
|
||||
if (this.__interp.variables.exists(name)) {
|
||||
this.__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
Reflect.setProperty(this, name, val);
|
||||
return Reflect.field(this, name);
|
||||
}
|
||||
}
|
||||
|
||||
//if(hasHsetInSuper || hasHgetInSuper) return fields;
|
||||
|
||||
//trace(cl.name);
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "hset",
|
||||
pos: Context.currentPos(),
|
||||
access: hasHsetInSuper ? [AOverride, APublic] : [APublic],
|
||||
kind: FFun({
|
||||
ret: TPath({name: 'Dynamic', pack: []}),
|
||||
params: [],
|
||||
expr: hsetField,
|
||||
args: [
|
||||
{
|
||||
name: "name",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "String", pack: []})
|
||||
},
|
||||
{
|
||||
name: "val",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "Dynamic", pack: []})
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "hget",
|
||||
pos: Context.currentPos(),
|
||||
access: hasHgetInSuper ? [AOverride, APublic] : [APublic],
|
||||
kind: FFun({
|
||||
ret: TPath({name: 'Dynamic', pack: []}),
|
||||
params: [],
|
||||
expr: hgetField,
|
||||
args: [
|
||||
{
|
||||
name: "name",
|
||||
opt: false,
|
||||
meta: [],
|
||||
type: TPath({name: "String", pack: []})
|
||||
}
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
/*var p = new Printer();
|
||||
var aa = p.printTypeDefinition(shadowClass);
|
||||
if(aa.length < 5024)
|
||||
trace(aa);
|
||||
if(aa.indexOf("pack") >= 0)
|
||||
if(cl.name == "FunkinShader")*/
|
||||
|
||||
Context.defineModule(cl.module, [shadowClass], imports);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
#else
|
||||
class ClassExtendMacro {
|
||||
public var usedClass:Class<Dynamic>;
|
||||
public var className:String;
|
||||
}
|
||||
#end
|
||||
@@ -0,0 +1,160 @@
|
||||
package hscript.macros;
|
||||
|
||||
#if macro
|
||||
import Type.ValueType;
|
||||
import haxe.macro.ComplexTypeTools;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Context;
|
||||
import haxe.macro.Printer;
|
||||
import haxe.macro.Compiler;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class UsingHandler {
|
||||
public static function init() {
|
||||
#if !display
|
||||
if(Context.defined("display")) return;
|
||||
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.UsingHandler.build())');
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function build():Array<Field> {
|
||||
var fields = Context.getBuildFields();
|
||||
var clRef = Context.getLocalClass();
|
||||
if (clRef == null) return fields;
|
||||
var cl = clRef.get();
|
||||
|
||||
if (/* cl.name.startsWith("Flx") && */ cl.name.endsWith("_Impl_") && cl.params.length <= 0 && !cl.meta.has(":multiType") && !cl.name.contains("_HSC")) {
|
||||
var metas = cl.meta.get();
|
||||
|
||||
var trimEnum = cl.name.substr(0, cl.name.length - 6);
|
||||
|
||||
var key = cl.module;
|
||||
var fkey = cl.module + "." + trimEnum;
|
||||
if(key == "lime.system.Locale") return fields; // Error: Unknown identifier : currentLocale, Due to Func
|
||||
if(key == "cpp.Function") return fields; // Error: Unknown identifier : nativeGetProcAddress, Due to Func
|
||||
if(key == "haxe.ds.Vector") return fields; // Error: haxe.ds._Vector.VectorData<blit.T> has no field blit, Due to Func
|
||||
if(key == "haxe.display.Display") return fields; // Error: haxe.display.DisplayItemKind<haxe.display.DisplayLiteral<Dynamic>> has no field Null, Due to Func
|
||||
if(key == "cpp.Callable") return fields; // Error: cpp.Function.fromStaticFunction must be called on static function, Due to Func
|
||||
if(key == "haxe.display.JsonAnonStatusKind") return fields; // Error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *', Due to Func
|
||||
if(key == "cpp.CharStar") return fields; // Error: cannot initialize a variable of type 'char *' with an rvalue of type 'const char *', Due to Func
|
||||
if(Config.DISALLOW_ABSTRACT_AND_ENUM.contains(cl.module) || Config.DISALLOW_ABSTRACT_AND_ENUM.contains(fkey)) return fields;
|
||||
if(cl.module.contains("_")) return fields; // Weird issue, sorry
|
||||
|
||||
var shadowClass = macro class {
|
||||
|
||||
};
|
||||
shadowClass.kind = TDClass();
|
||||
shadowClass.params = switch(cl.params.length) {
|
||||
case 0:
|
||||
null;
|
||||
case 1:
|
||||
[{
|
||||
name: "T",
|
||||
}];
|
||||
default:
|
||||
[for(k=>e in cl.params) {
|
||||
name: "T" + Std.int(k+1)
|
||||
}];
|
||||
};
|
||||
shadowClass.name = '${cl.name.substr(0, cl.name.length - 6)}_HSC';
|
||||
|
||||
var imports = Context.getLocalImports().copy();
|
||||
Utils.setupMetas(shadowClass, imports);
|
||||
//trace(cl.module);
|
||||
|
||||
for(f in fields)
|
||||
switch(f.kind) {
|
||||
case FFun(fun):
|
||||
if (f.access.contains(AStatic)) {
|
||||
if (fun.expr != null) {
|
||||
fun.expr = macro @:privateAccess $e{fun.expr};
|
||||
shadowClass.fields.push(f);
|
||||
|
||||
/*var trimEnum = cl.name.substr(0, cl.name.length - 6);
|
||||
|
||||
var returns:Bool = !fun.ret.match(TPath({name: "Void"}));
|
||||
|
||||
var name = f.name;
|
||||
|
||||
var arguments = fun.args == null ? [] : [for(a in fun.args) macro $i{a.name}];
|
||||
|
||||
var expr:Expr = Context.parse('${returns?"return " : ""} $trimEnum.$name(${[for(a in fun.args) a.name].join(", ")})', f.pos);
|
||||
|
||||
var func:Function = {
|
||||
ret: fun.ret,
|
||||
params: fun.params.copy(),
|
||||
expr: expr,
|
||||
args: fun.args.copy()
|
||||
};
|
||||
|
||||
var field:Field = {
|
||||
pos: f.pos,
|
||||
name: f.name,
|
||||
meta: f.meta,
|
||||
kind: FFun(func),
|
||||
doc: null,//f.doc,
|
||||
access: [APublic, AStatic]
|
||||
}
|
||||
shadowClass.fields.push(field);*/
|
||||
}
|
||||
}
|
||||
case FProp(get, set, t, e):
|
||||
if (get == "default" && (set == "never" || set == "null")) {
|
||||
shadowClass.fields.push(f);
|
||||
}
|
||||
case FVar(t, e):
|
||||
if (f.access.contains(AStatic) || cl.meta.has(":enum") || f.name.toUpperCase() == f.name) {
|
||||
var name:String = f.name;
|
||||
var enumType:String = cl.name;
|
||||
var pack = cl.module.split(".");
|
||||
|
||||
//trace(pack, cl.name, name, cl.module);
|
||||
|
||||
if(pack[pack.length - 1] == trimEnum)
|
||||
pack.pop();
|
||||
|
||||
var complexType:ComplexType = t;
|
||||
if(complexType == null && e != null) {
|
||||
complexType = switch(e.expr) {
|
||||
case EConst(CRegexp(_)): TPath({ name: "EReg", pack: [] });
|
||||
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
if(complexType == null) {
|
||||
complexType = TPath({
|
||||
name: trimEnum,
|
||||
pack: [],//pack
|
||||
});
|
||||
}
|
||||
|
||||
var code = Context.parse('@:privateAccess ($trimEnum.$name)', f.pos); // '${pack.join(".")}.${trimEnum}.$name'
|
||||
|
||||
var field:Field = {
|
||||
pos: f.pos,
|
||||
name: f.name,
|
||||
meta: f.meta,
|
||||
kind: FVar(null, code),
|
||||
doc: f.doc,
|
||||
access: [APublic, AStatic]
|
||||
}
|
||||
|
||||
shadowClass.fields.push(field);
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
//var printer = new Printer();
|
||||
//for(field in shadowClass.fields)
|
||||
// trace(printer.printField(field));
|
||||
|
||||
Context.defineModule(cl.module, [shadowClass], imports);
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
#end
|
||||
@@ -0,0 +1,209 @@
|
||||
package hscript.macros;
|
||||
|
||||
#if macro
|
||||
import haxe.macro.Type.ClassType;
|
||||
import Type.ValueType;
|
||||
import haxe.macro.Expr.Function;
|
||||
import haxe.macro.Expr;
|
||||
import haxe.macro.Type.MetaAccess;
|
||||
import haxe.macro.Type.FieldKind;
|
||||
import haxe.macro.Type.ClassField;
|
||||
import haxe.macro.Type.VarAccess;
|
||||
import haxe.macro.*;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class Utils {
|
||||
public static function fixStdTypes(type:ComplexType) {
|
||||
switch(type) {
|
||||
case TPath({name: "StdTypes"}):
|
||||
var a:TypePath = type.getParameters()[0];
|
||||
a.name = a.sub;
|
||||
a.sub = null;
|
||||
default:
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
public static function setupMetas(shadowClass:TypeDefinition, imports) {
|
||||
shadowClass.meta = [];
|
||||
shadowClass.meta.push({name: ":dox", params: [macro hide], pos: Context.currentPos()});
|
||||
shadowClass.meta.push({name: ":noCompletion", params: [], pos: Context.currentPos()});
|
||||
var module = Context.getModule(Context.getLocalModule());
|
||||
for(t in module) {
|
||||
switch(t) {
|
||||
case TInst(t, params):
|
||||
if (t != null) {
|
||||
var e = t.get();
|
||||
processModule(shadowClass, e.module, e.name);
|
||||
processImport(imports, e.module, e.name);
|
||||
}
|
||||
case TEnum(t, params):
|
||||
if (t != null) {
|
||||
var e = t.get();
|
||||
processModule(shadowClass, e.module, e.name);
|
||||
processImport(imports, e.module, e.name);
|
||||
}
|
||||
case TType(t, params):
|
||||
if (t != null) {
|
||||
var e = t.get();
|
||||
processModule(shadowClass, e.module, e.name);
|
||||
processImport(imports, e.module, e.name);
|
||||
}
|
||||
case TAbstract(t, params):
|
||||
if (t != null) {
|
||||
var e = t.get();
|
||||
processModule(shadowClass, e.module, e.name);
|
||||
processImport(imports, e.module, e.name);
|
||||
}
|
||||
default:
|
||||
// not needed?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function processModule(shadowClass:TypeDefinition, module:String, n:String) {
|
||||
if (n.endsWith("_Impl_"))
|
||||
n = n.substr(0, n.length - 6);
|
||||
if (module.endsWith("_Impl_"))
|
||||
module = module.substr(0, module.length - 6);
|
||||
|
||||
shadowClass.meta.push(
|
||||
{
|
||||
name: ':access',
|
||||
params: [
|
||||
Context.parse(fixModuleName(module.endsWith('.${n}') ? module : '${module}.${n}'), Context.currentPos())
|
||||
],
|
||||
pos: Context.currentPos()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*public static function getModuleName(path:Type) {
|
||||
switch(path) {
|
||||
case TPath(name, pack):// | TDClass(name, pack):
|
||||
var str = "";
|
||||
for(p in pack) {
|
||||
str += p + ".";
|
||||
}
|
||||
str += name;
|
||||
return str;
|
||||
|
||||
default:
|
||||
}
|
||||
return "INVALID";
|
||||
}*/
|
||||
|
||||
public static function fixModuleName(name:String) {
|
||||
return [for(s in name.split(".")) if (s.charAt(0) == "_") s.substr(1) else s].join(".");
|
||||
}
|
||||
public static function processImport(imports:Array<ImportExpr>, module:String, n:String) {
|
||||
if (n.endsWith("_Impl_"))
|
||||
n = n.substr(0, n.length - 6);
|
||||
module = fixModuleName(module);
|
||||
if (module.endsWith("_Impl_"))
|
||||
module = module.substr(0, module.length - 6);
|
||||
|
||||
imports.push({
|
||||
path: [for(m in module.split(".")) {
|
||||
name: m,
|
||||
pos: Context.currentPos()
|
||||
}],
|
||||
mode: INormal
|
||||
});
|
||||
}
|
||||
|
||||
public static function cleanExpr(expr:Expr, oldFunc:String, newFunc:String) {
|
||||
if (expr == null) return;
|
||||
if (expr.expr == null) return;
|
||||
switch(expr.expr) {
|
||||
case EConst(c):
|
||||
switch(c) {
|
||||
case CIdent(s):
|
||||
if (s == oldFunc)
|
||||
expr.expr = EConst(CIdent(newFunc));
|
||||
case CString(s, b):
|
||||
if (s == oldFunc)
|
||||
expr.expr = EConst(CString(s, b));
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
case EField(e, field):
|
||||
if (field == oldFunc && e != null) {
|
||||
switch(e.expr) {
|
||||
case EConst(c):
|
||||
switch(c) {
|
||||
case CIdent(s):
|
||||
if (s == "super")
|
||||
expr.expr = EField(e, newFunc);
|
||||
default:
|
||||
|
||||
}
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
case EParenthesis(e):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case EObjectDecl(fields):
|
||||
for(f in fields) {
|
||||
cleanExpr(f.expr, oldFunc, newFunc);
|
||||
}
|
||||
case EArrayDecl(values):
|
||||
for(a in values) {
|
||||
cleanExpr(a, oldFunc, newFunc);
|
||||
}
|
||||
case ECall(e, params):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case EBlock(exprs):
|
||||
for(e in exprs)
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case EFor(it, expr):
|
||||
cleanExpr(it, oldFunc, newFunc);
|
||||
cleanExpr(expr, oldFunc, newFunc);
|
||||
case EIf(econd, eif, eelse):
|
||||
cleanExpr(econd, oldFunc, newFunc);
|
||||
cleanExpr(eif, oldFunc, newFunc);
|
||||
cleanExpr(eelse, oldFunc, newFunc);
|
||||
case EWhile(econd, e, normalWhile):
|
||||
cleanExpr(econd, oldFunc, newFunc);
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case ECast(e, t):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case ECheckType(e, t):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case ETry(e, catches):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
for(c in catches) {
|
||||
cleanExpr(c.expr, oldFunc, newFunc);
|
||||
}
|
||||
case EThrow(e):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case ETernary(econd, eif, eelse):
|
||||
cleanExpr(econd, oldFunc, newFunc);
|
||||
cleanExpr(eif, oldFunc, newFunc);
|
||||
cleanExpr(eelse, oldFunc, newFunc);
|
||||
case ESwitch(e, cases, edef):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
for(c in cases) {
|
||||
cleanExpr(c.expr, oldFunc, newFunc);
|
||||
}
|
||||
cleanExpr(edef, oldFunc, newFunc);
|
||||
case EReturn(e):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case EIs(e, t):
|
||||
cleanExpr(e, oldFunc, newFunc);
|
||||
case EVars(vars):
|
||||
for(v in vars) {
|
||||
cleanExpr(v.expr, oldFunc, newFunc);
|
||||
}
|
||||
case ENew(t, params):
|
||||
for(p in params) {
|
||||
cleanExpr(p, oldFunc, newFunc);
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
Reference in New Issue
Block a user