Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f2dec1634 | ||
|
|
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 |
@@ -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
@@ -1,3 +1,3 @@
|
|||||||
-main Test
|
-main TestHScript
|
||||||
-dce no
|
-dce no
|
||||||
-lib hx3compat
|
-lib hx3compat
|
||||||
+1
-1
@@ -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"]
|
||||||
}
|
}
|
||||||
@@ -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 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;
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
+67
-10
@@ -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));
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
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');
|
||||||
|
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);
|
||||||
|
|
||||||
|
//trace("Locals");
|
||||||
|
for (key => value in capturedLocals) {
|
||||||
|
if(!disallowCopy.contains(key)) {
|
||||||
|
interp.locals.set(key, {r: value, depth: -1});
|
||||||
|
//trace(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//trace("Variables");
|
||||||
|
for (key => value in ogInterp.variables) {
|
||||||
|
if(!disallowCopy.contains(key)) {
|
||||||
|
interp.variables.set(key, value);
|
||||||
|
//trace(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() {}
|
||||||
|
}
|
||||||
+9
-4
@@ -45,10 +45,10 @@ 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> );
|
||||||
@@ -57,10 +57,10 @@ enum Expr {
|
|||||||
EFor( v : String, it : Expr, e : Expr );
|
EFor( v : String, it : Expr, e : Expr );
|
||||||
EBreak;
|
EBreak;
|
||||||
EContinue;
|
EContinue;
|
||||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType );
|
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool );
|
||||||
EReturn( ?e : Expr );
|
EReturn( ?e : Expr );
|
||||||
EArray( e : Expr, index : Expr );
|
EArray( e : Expr, index : Expr );
|
||||||
EArrayDecl( e : Array<Expr> );
|
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||||
ENew( cl : String, params : Array<Expr> );
|
ENew( cl : String, params : Array<Expr> );
|
||||||
EThrow( e : Expr );
|
EThrow( e : Expr );
|
||||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||||
@@ -70,6 +70,9 @@ enum Expr {
|
|||||||
EDoWhile( cond : Expr, e : Expr);
|
EDoWhile( cond : Expr, e : Expr);
|
||||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||||
ECheckType( e : Expr, t : CType );
|
ECheckType( e : Expr, t : CType );
|
||||||
|
|
||||||
|
EImport( c : String, ?asname:String );
|
||||||
|
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
|
||||||
@@ -117,6 +120,8 @@ enum Error {
|
|||||||
EInvalidOp( op : String );
|
EInvalidOp( op : String );
|
||||||
EInvalidAccess( f : String );
|
EInvalidAccess( f : String );
|
||||||
ECustom( msg : String );
|
ECustom( msg : String );
|
||||||
|
EInvalidClass( className : String);
|
||||||
|
EAlreadyExistingClass( className : String);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
interface IHScriptCustomBehaviour {
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic;
|
||||||
|
public function hget(name:String):Dynamic;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
interface IHScriptCustomConstructor {
|
||||||
|
public function hnew(args:Array<Dynamic>):Dynamic;
|
||||||
|
}
|
||||||
+421
-91
@@ -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);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -114,7 +161,16 @@ class Interp {
|
|||||||
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("=", 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 +182,17 @@ 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("is", function(v1, v2) return Std.isOfType(v1, v2));
|
||||||
|
assignOp("??=", function(v1, v2) return v1 == null ? v2 : v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,10 +200,35 @@ 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;
|
||||||
|
if (l.depth == 0) {
|
||||||
|
setVar(id, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
case EField(e, f):
|
case EField(e, f):
|
||||||
v = set(expr(e), f, v);
|
v = set(expr(e), f, v);
|
||||||
case EArray(e, index):
|
case EArray(e, index):
|
||||||
@@ -144,8 +236,7 @@ class Interp {
|
|||||||
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,8 +257,15 @@ 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):
|
||||||
@@ -180,8 +278,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,12 +296,17 @@ 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):
|
||||||
var obj = expr(e);
|
var obj = expr(e);
|
||||||
@@ -223,13 +325,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 +355,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
|
||||||
@@ -290,7 +405,12 @@ class Interp {
|
|||||||
|
|
||||||
inline function error(e:#if hscriptPos ErrorDef #else Error #end, rethrow = false):Dynamic {
|
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,12 +422,32 @@ class Interp {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolve( id : String ) : Dynamic {
|
public function resolve(id:String, doException:Bool = true):Dynamic {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
@@ -318,6 +458,78 @@ class Interp {
|
|||||||
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));
|
||||||
|
customClasses.set(name, new CustomClassHandler(this, name, fields, extend, interfaces));
|
||||||
|
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;
|
||||||
|
|
||||||
|
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(".");
|
||||||
|
|
||||||
|
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 +541,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 +563,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 +598,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);
|
||||||
@@ -398,8 +626,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 +641,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 +669,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 +686,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 +695,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 +726,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 +736,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 +780,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 +807,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 +837,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 +860,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,8 +878,10 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,27 +890,33 @@ class Interp {
|
|||||||
|
|
||||||
function makeIterator(v:Dynamic):Iterator<Dynamic> {
|
function makeIterator(v:Dynamic):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 ) {};
|
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) {
|
||||||
var old = declared.length;
|
var old = declared.length;
|
||||||
declared.push({ n : n, old : locals.get(n) });
|
declared.push({n: n, old: locals.get(n), depth: depth});
|
||||||
var it = makeIterator(expr(it));
|
var it = makeIterator(expr(it));
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
locals.set(n,{ r : it.next() });
|
locals.set(n, {r: it.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 +924,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 +935,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
+397
-32
@@ -32,6 +32,7 @@ enum Token {
|
|||||||
TBrOpen;
|
TBrOpen;
|
||||||
TBrClose;
|
TBrClose;
|
||||||
TDot;
|
TDot;
|
||||||
|
TQuestionDot;
|
||||||
TComma;
|
TComma;
|
||||||
TSemicolon;
|
TSemicolon;
|
||||||
TBkOpen;
|
TBkOpen;
|
||||||
@@ -51,11 +52,9 @@ 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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -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 ) {
|
||||||
@@ -279,8 +279,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 +351,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 +446,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 +491,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);
|
||||||
@@ -572,7 +594,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 +622,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();
|
||||||
@@ -646,7 +763,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 +956,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 +971,7 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
disableOrOp = false;
|
||||||
var exprs = [];
|
var exprs = [];
|
||||||
while( true ) {
|
while( true ) {
|
||||||
tk = token();
|
tk = token();
|
||||||
@@ -783,7 +1045,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 +1058,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 +1103,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 +1248,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 +1591,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 +1651,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 +1695,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 +1712,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 +1723,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 +1799,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 +1855,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] ) {
|
||||||
@@ -1564,6 +1904,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 +1931,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,6 +1992,7 @@ class Parser {
|
|||||||
var pos = readPos;
|
var pos = readPos;
|
||||||
while( true ) {
|
while( true ) {
|
||||||
var tk = token();
|
var tk = token();
|
||||||
|
// TODO: Fix ending in with #end in the file
|
||||||
if( tk == TEof )
|
if( tk == TEof )
|
||||||
error(EInvalidPreprocessor("Unclosed"), pos, pos);
|
error(EInvalidPreprocessor("Unclosed"), pos, pos);
|
||||||
if( preprocStack[spos] != obj ) {
|
if( preprocStack[spos] != obj ) {
|
||||||
@@ -1702,6 +2066,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: "[";
|
||||||
|
|||||||
+27
-6
@@ -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 + " ");
|
||||||
@@ -207,7 +226,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 +253,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 +350,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 +360,8 @@ class Printer {
|
|||||||
case EInvalidOp(op): "Invalid operator: "+op;
|
case EInvalidOp(op): "Invalid operator: "+op;
|
||||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||||
case ECustom(msg): msg;
|
case ECustom(msg): msg;
|
||||||
|
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||||
|
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||||
};
|
};
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e.origin + ":" + e.line + ": " + message;
|
return e.origin + ":" + e.line + ": " + message;
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ class Tools {
|
|||||||
public static function iter( e : Expr, f : Expr -> Void ) {
|
public static function iter( e : Expr, f : Expr -> Void ) {
|
||||||
switch( expr(e) ) {
|
switch( expr(e) ) {
|
||||||
case EConst(_), EIdent(_):
|
case EConst(_), EIdent(_):
|
||||||
|
case EImport(c): f(e);
|
||||||
|
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||||
case EVar(_, _, e): if( e != null ) f(e);
|
case EVar(_, _, e): if( e != null ) f(e);
|
||||||
case EParent(e): f(e);
|
case EParent(e): f(e);
|
||||||
case EBlock(el): for( e in el ) f(e);
|
case EBlock(el): for( e in el ) f(e);
|
||||||
@@ -57,6 +59,7 @@ class Tools {
|
|||||||
if( def != null ) f(def);
|
if( def != null ) f(def);
|
||||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||||
case ECheckType(e,_): f(e);
|
case ECheckType(e,_): f(e);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +89,8 @@ class Tools {
|
|||||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||||
case ECheckType(e,t): ECheckType(f(e), t);
|
case ECheckType(e,t): ECheckType(f(e), t);
|
||||||
|
case EImport(c): EImport(c);
|
||||||
|
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||||
}
|
}
|
||||||
return mk(edef, e);
|
return mk(edef, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,308 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
import Type.ValueType;
|
||||||
|
import haxe.macro.ComplexTypeTools;
|
||||||
|
#if macro
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
import haxe.macro.Context;
|
||||||
|
import haxe.macro.Printer;
|
||||||
|
import haxe.macro.Compiler;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
class UsingHandler {
|
||||||
|
public var usedClass:Class<Dynamic>;
|
||||||
|
public var className:String;
|
||||||
|
|
||||||
|
public function new(className:String, usedClass:Class<Dynamic>) {
|
||||||
|
this.className = className;
|
||||||
|
this.usedClass = usedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function init() {
|
||||||
|
Compiler.addGlobalMetadata('flixel', '@:build(hscript.UsingHandler.build())');
|
||||||
|
Compiler.addGlobalMetadata('openfl.display.BlendMode', '@:build(hscript.UsingHandler.build())');
|
||||||
|
}
|
||||||
|
|
||||||
|
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")) {
|
||||||
|
var metas = cl.meta.get();
|
||||||
|
|
||||||
|
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();
|
||||||
|
setupMetas(shadowClass, imports);
|
||||||
|
|
||||||
|
for(f in fields)
|
||||||
|
switch(f.kind) {
|
||||||
|
case FFun(fun):
|
||||||
|
if (f.access.contains(AStatic)) {
|
||||||
|
if (fun.expr != null)
|
||||||
|
shadowClass.fields.push(f);
|
||||||
|
}
|
||||||
|
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(".");
|
||||||
|
pack.pop();
|
||||||
|
var complexType:ComplexType = t != null ? t : (name.contains("REGEX") ? TPath({
|
||||||
|
name: "EReg",
|
||||||
|
pack: []
|
||||||
|
}) : TPath({
|
||||||
|
name: cl.name.substr(0, cl.name.length - 6),
|
||||||
|
pack: pack}));
|
||||||
|
var field:Field = {
|
||||||
|
pos: f.pos,
|
||||||
|
name: f.name,
|
||||||
|
meta: f.meta,
|
||||||
|
kind: FVar(complexType, {
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
expr: ECast(e, complexType)
|
||||||
|
}),
|
||||||
|
doc: f.doc,
|
||||||
|
access: [APublic, AStatic]
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowClass.fields.push(field);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.defineModule(cl.module + "_HSC", [shadowClass], imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = [{
|
||||||
|
name: ':dox',
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
expr: EConst(CIdent("hide")),
|
||||||
|
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:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
class UsingHandler {
|
||||||
|
public var usedClass:Class<Dynamic>;
|
||||||
|
public var className:String;
|
||||||
|
}
|
||||||
|
#end
|
||||||
Reference in New Issue
Block a user