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() {}
|
||||||
|
}
|
||||||
+10
-5
@@ -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,19 +57,22 @@ 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 );
|
||||||
EObject( fl : Array<{ name : String, e : Expr }> );
|
EObject( fl : Array<{ name : String, e : Expr }> );
|
||||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||||
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr);
|
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr );
|
||||||
EDoWhile( cond : Expr, e : Expr);
|
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;
|
||||||
|
}
|
||||||
+578
-248
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
+398
-33
@@ -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);
|
||||||
@@ -668,7 +928,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var args = parseExprList(TPClose);
|
var args = parseExprList(TPClose);
|
||||||
mk(ENew(a.join("."),args),p1);
|
mk(ENew(a.join("."), args), p1);
|
||||||
case "throw":
|
case "throw":
|
||||||
var e = parseExpr();
|
var e = parseExpr();
|
||||||
mk(EThrow(e),p1,pmax(e));
|
mk(EThrow(e),p1,pmax(e));
|
||||||
@@ -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