Compare commits

..
Author SHA1 Message Date
Ne_Eo 49c90e6434 Fix typo 2025-01-19 20:09:38 +01:00
30 changed files with 2163 additions and 5777 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
/hscript.swf /hscript.swf
/release.zip /release.zip
dump/*
tests/bin/* tests/bin/*
+2 -14
View File
@@ -1,28 +1,16 @@
hscript-improved hscript-improved
======= =======
- [Features](docs/FEATURES.md)
How to install How to install
``` ```
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git haxelib git hscript-improved https://github.com/FNF-CNE-Devs/hscript-improved.git
``` ```
To enable custom classes support you have to do this in project.xml To enable custom classes support you have to do this in project.xml
```xml ```xml
<define name="CUSTOM_CLASSES" /> <define name="CUSTOM_CLASSES" />
``` ```
Warning: custom classes are sometimes broken, would like help to fix them. You can only override functions from the current class, not from the extended part, like you cant override update in FlxText because FlxText doesnt have a update function overriden
or set this in build.hxml
```hxml
-D CUSTOM_CLASSES
```
Current Custom Class Limitations :
- You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
----------- -----------
+9
View File
@@ -26,8 +26,13 @@ class TestHScript extends TestCase {
assertScript("0",0); assertScript("0",0);
assertScript("0xFF", 255); assertScript("0xFF", 255);
#if !(php || python) #if !(php || python)
#if haxe3
assertScript("0xBFFFFFFF", 0xBFFFFFFF); assertScript("0xBFFFFFFF", 0xBFFFFFFF);
assertScript("0x7FFFFFFF", 0x7FFFFFFF); assertScript("0x7FFFFFFF", 0x7FFFFFFF);
#elseif !neko
assertScript("n(0xBFFFFFFF)", 0xBFFFFFFF, { n : haxe.Int32.toNativeInt });
assertScript("n(0x7FFFFFFF)", 0x7FFFFFFF, { n : haxe.Int32.toNativeInt } );
#end
#end #end
assertScript("-123",-123); assertScript("-123",-123);
assertScript("- 123",-123); assertScript("- 123",-123);
@@ -76,7 +81,11 @@ class TestHScript extends TestCase {
assertScript("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10); assertScript("var a = [1,[2,[3,[4,null]]]]; var t = 0; while( a != null ) { t += a[0]; a = a[1]; }; t",10);
assertScript("var a = false; do { a = true; } while (!a); a;",true); assertScript("var a = false; do { a = true; } while (!a); a;",true);
assertScript("var t = 0; for( x in 1...10 ) t += x; t", 45); assertScript("var t = 0; for( x in 1...10 ) t += x; t", 45);
#if haxe3
assertScript("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45); assertScript("var t = 0; for( x in new IntIterator(1,10) ) t +=x; t", 45);
#else
assertScript("var t = 0; for( x in new IntIter(1,10) ) t +=x; t", 45);
#end
assertScript("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",790); assertScript("var x = 1; try { var x = 66; throw 789; } catch( e : Dynamic ) e + x",790);
assertScript("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",56); assertScript("var x = 1; var f = function(x) throw x; try f(55) catch( e : Dynamic ) e + x",56);
assertScript("var i=2; if( true ) --i; i",1); assertScript("var i=2; if( true ) --i; i",1);
-83
View File
@@ -1,83 +0,0 @@
# FEATURES
- Custom Classes
- Final Classes
- Static Classes
- Allow for type check (`is`)
- Allow extending other custom classes
- Enums
```haxe
enum TypeValue {
NUMBER(n:Int);
DECIMAL(d:Float, ?p:Int);
CHARACTER(s:String);
BOOLEAN(b:Bool);
}
var type = TypeValue.DECIMAL(10.1234, 2);
// You need to type the full enum field for each case
// i.e. you can't type the enum field directly (limitation for now)
switch(type) {
case TypeValue.NUMBER(number):
trace("number: " + number);
case TypeValue.DECIMAL(decimal, precision):
if(precision != null)
trace("decimal: " + decimal + " | rounded decimal: " + roundDecimal(decimal, precision));
else
trace("decimal: " + decimal);
case TypeValue.CHARACTER(char):
trace("character: " + char);
default:
trace("unknown type");
}
function roundDecimal(Value:Float, Precision:Int) {
var mult:Float = Math.pow(10, Precision);
return Math.fround(Value * mult) / mult;
}
```
- Enum matching with arguments for switch statements (for real and scripted enums)
- Property Fields (`(get, set)` variables)
```haxe
public var myvar(get, set):Int;
var _myvar:Int = 10;
function get_myvar():Int {
return _myvar;
}
function set_myvar(val:Int):Int {
if(val > 10) return _myvar = val;
return val;
}
```
- `@:isVar` metadata support
- Static extension (`using`)
```haxe
using StringTools;
class IntExtender {
static public function triple(i:Int) {
return i * 3;
}
}
// need to create/import the custom class
// before setting the extension (limitation for now)
using IntExtender;
var str = " Hello World! ";
trace(str.trim()); // "Hello World!"
trace(12.triple()); // 36
```
- Support for real and custom classes
- Misc.
- Allow using type parameters for creating objects (i.e. `var a = new TypedObject<Int>();`)
- Allow `package` declaration. Ignored by the interpreter.
+1 -1
View File
@@ -1,3 +1,3 @@
--macro keep('IntIterator') --macro keep('IntIterator')
--macro hscript.macros.AbstractHandler.init() --macro hscript.macros.UsingHandler.init()
--macro hscript.macros.ClassExtendMacro.init() --macro hscript.macros.ClassExtendMacro.init()
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "hscript-improved", "name": "hscript",
"url": "https://github.com/HaxeFoundation/hscript", "url": "https://github.com/HaxeFoundation/hscript",
"license": "MIT", "license": "MIT",
"description": "Haxe Script is a scripting engine for a subset of the Haxe language", "description": "Haxe Script is a scripting engine for a subset of the Haxe language",
+536 -536
View File
File diff suppressed because it is too large Load Diff
+30 -22
View File
@@ -27,7 +27,7 @@ class Bytes {
var bin : haxe.io.Bytes; var bin : haxe.io.Bytes;
var bout : haxe.io.BytesBuffer; var bout : haxe.io.BytesBuffer;
var pin : Int; var pin : Int;
var hstrings : Map<String,Int>; var hstrings : #if haxe3 Map<String,Int> #else Hash<Int> #end;
var strings : Array<String>; var strings : Array<String>;
var nstrings : Int; var nstrings : Int;
@@ -35,7 +35,7 @@ class Bytes {
this.bin = bin; this.bin = bin;
pin = 0; pin = 0;
bout = new haxe.io.BytesBuffer(); bout = new haxe.io.BytesBuffer();
hstrings = new Map(); hstrings = #if haxe3 new Map() #else new Hash() #end;
strings = [null]; strings = [null];
nstrings = 1; nstrings = 1;
} }
@@ -44,7 +44,7 @@ class Bytes {
var vid = hstrings.get(v); var vid = hstrings.get(v);
if( vid == null ) { if( vid == null ) {
if( nstrings == 256 ) { if( nstrings == 256 ) {
hstrings = new Map(); hstrings = #if haxe3 new Map() #else new Hash() #end;
nstrings = 1; nstrings = 1;
} }
hstrings.set(v,nstrings); hstrings.set(v,nstrings);
@@ -85,6 +85,15 @@ class Bytes {
bout.addByte(1); bout.addByte(1);
doEncodeInt(v); doEncodeInt(v);
} }
#if !haxe3
case CInt32(v):
bout.addByte(4);
var mid = haxe.Int32.toInt(haxe.Int32.and(v,haxe.Int32.ofInt(0xFFFFFF)));
bout.addByte(mid & 0xFF);
bout.addByte((mid >> 8) & 0xFF);
bout.addByte(mid >> 16);
bout.addByte(haxe.Int32.toInt(haxe.Int32.ushr(v, 24)));
#end
case CFloat(f): case CFloat(f):
bout.addByte(2); bout.addByte(2);
doEncodeString(Std.string(f)); doEncodeString(Std.string(f));
@@ -111,6 +120,13 @@ class Bytes {
CFloat( Std.parseFloat(doDecodeString()) ); CFloat( Std.parseFloat(doDecodeString()) );
case 3: case 3:
CString( doDecodeString() ); CString( doDecodeString() );
#if !haxe3
case 4:
var i = bin.get(pin) | (bin.get(pin+1) << 8) | (bin.get(pin+2) << 16);
var j = bin.get(pin+3);
pin += 4;
CInt32(haxe.Int32.or(haxe.Int32.ofInt(i), haxe.Int32.shl(haxe.Int32.ofInt(j), 24)));
#end
default: default:
throw "Invalid code "+bin.get(pin-1); throw "Invalid code "+bin.get(pin-1);
} }
@@ -124,18 +140,10 @@ class Bytes {
#end #end
bout.addByte(Type.enumIndex(e)); bout.addByte(Type.enumIndex(e));
switch( e ) { switch( e ) {
case EPackage(n):
// TODO
case EImport(c): case EImport(c):
// TODO // TODO
case EClass(_, _, _, _): case EClass(_, _, _, _):
// TODO // TODO
case EEnum(en):
// TODO
case ECast(e, _):
// TODO
case ERegex(e, f):
// TODO
case EConst(c): case EConst(c):
doEncodeConst(c); doEncodeConst(c);
case EIdent(v): case EIdent(v):
@@ -156,11 +164,11 @@ class Bytes {
doEncode(e); doEncode(e);
doEncodeString(f); doEncodeString(f);
case EBinop(op,e1,e2): case EBinop(op,e1,e2):
doEncodeString(op.toString()); doEncodeString(op);
doEncode(e1); doEncode(e1);
doEncode(e2); doEncode(e2);
case EUnop(op,prefix,e): case EUnop(op,prefix,e):
doEncodeString(op.toString()); // maybe doEncodeInt doEncodeString(op);
bout.addByte(prefix?1:0); bout.addByte(prefix?1:0);
doEncode(e); doEncode(e);
case ECall(e,el): case ECall(e,el):
@@ -270,7 +278,7 @@ class Bytes {
case 3: case 3:
EParent(doDecode()); EParent(doDecode());
case 4: case 4:
var a = []; var a = new Array();
for( i in 0...bin.get(pin++) ) for( i in 0...bin.get(pin++) )
a.push(doDecode()); a.push(doDecode());
EBlock(a); EBlock(a);
@@ -278,16 +286,16 @@ class Bytes {
var e = doDecode(); var e = doDecode();
EField(e,doDecodeString()); EField(e,doDecodeString());
case 6: case 6:
var op = Binop.fromString(doDecodeString()); var op = doDecodeString();
var e1 = doDecode(); var e1 = doDecode();
EBinop(op,e1,doDecode()); EBinop(op,e1,doDecode());
case 7: case 7:
var op = Unop.fromString(doDecodeString()); var op = doDecodeString();
var prefix = bin.get(pin++) != 0; var prefix = bin.get(pin++) != 0;
EUnop(op,prefix,doDecode()); EUnop(op,prefix,doDecode());
case 8: case 8:
var e = doDecode(); var e = doDecode();
var params = []; var params = new Array();
for( i in 0...bin.get(pin++) ) for( i in 0...bin.get(pin++) )
params.push(doDecode()); params.push(doDecode());
ECall(e,params); ECall(e,params);
@@ -309,7 +317,7 @@ class Bytes {
case 14: case 14:
var params = new Array<Argument>(); var params = new Array<Argument>();
for( i in 0...bin.get(pin++) ) for( i in 0...bin.get(pin++) )
params.push({ name : doDecodeString(), opt: false, value: null, t: null }); params.push({ name : doDecodeString() });
var e = doDecode(); var e = doDecode();
var name = doDecodeString(); var name = doDecodeString();
EFunction(params,e,(name == "") ? null: name); EFunction(params,e,(name == "") ? null: name);
@@ -319,13 +327,13 @@ class Bytes {
var e = doDecode(); var e = doDecode();
EArray(e,doDecode()); EArray(e,doDecode());
case 17: case 17:
var el = []; var el = new Array();
for( i in 0...bin.get(pin++) ) for( i in 0...bin.get(pin++) )
el.push(doDecode()); el.push(doDecode());
EArrayDecl(el); EArrayDecl(el);
case 18: case 18:
var cl = doDecodeString(); var cl = doDecodeString();
var el = []; var el = new Array();
for( i in 0...bin.get(pin++) ) for( i in 0...bin.get(pin++) )
el.push(doDecode()); el.push(doDecode());
ENew(cl,el); ENew(cl,el);
@@ -336,7 +344,7 @@ class Bytes {
var v = doDecodeString(); var v = doDecodeString();
ETry(e,v,null,doDecode()); ETry(e,v,null,doDecode());
case 21: case 21:
var fl:Array<ObjectField> = []; var fl = new Array();
for( i in 0...bin.get(pin++) ) { for( i in 0...bin.get(pin++) ) {
var name = doDecodeString(); var name = doDecodeString();
var e = doDecode(); var e = doDecode();
@@ -350,7 +358,7 @@ class Bytes {
ETernary(cond, e1, e2); ETernary(cond, e1, e2);
case 23: case 23:
var e = doDecode(); var e = doDecode();
var cases:Array<SwitchCase> = []; var cases = [];
while( true ) { while( true ) {
var v = doDecode(); var v = doDecode();
if( v == null ) break; if( v == null ) break;
+16 -33
View File
@@ -422,9 +422,6 @@ class Checker {
return makeType(t,e); return makeType(t,e);
case CTOpt(t): case CTOpt(t):
return makeType(t,e); return makeType(t,e);
case CTExpr(_):
error("Unsupported expr type parameter", e);
return null;
} }
} }
@@ -1073,10 +1070,10 @@ class Checker {
case EUnop(op, _, e): case EUnop(op, _, e):
var et = typeExpr(e, Value); var et = typeExpr(e, Value);
switch( op ) { switch( op ) {
case OpIncrement | OpDecrement | OpNeg: case "++", "--", "-":
unify(et,TInt,e); unify(et,TInt,e);
return et; return et;
case OpNot: case "!":
unify(et,TBool,e); unify(et,TBool,e);
return et; return et;
default: default:
@@ -1113,11 +1110,11 @@ class Checker {
return TVoid; return TVoid;
case EBinop(op, e1, e2): case EBinop(op, e1, e2):
switch( op ) { switch( op ) {
case OpAnd, OpOr, OpXor, OpShr, OpUshr, OpShl: case "&", "|", "^", ">>", ">>>", "<<":
typeExprWith(e1,TInt); typeExprWith(e1,TInt);
typeExprWith(e2,TInt); typeExprWith(e2,TInt);
return TInt; return TInt;
case OpAssign: case "=":
if( allowDefine ) { if( allowDefine ) {
switch( edef(e1) ) { switch( edef(e1) ) {
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ): case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
@@ -1133,7 +1130,7 @@ class Checker {
} }
typeExprWith(e2,vt); typeExprWith(e2,vt);
return vt; return vt;
case OpAdd: case "+":
var t1 = typeExpr(e1,WithType(TInt)); var t1 = typeExpr(e1,WithType(TInt));
var t2 = typeExpr(e2,WithType(t1)); var t2 = typeExpr(e2,WithType(t1));
tryUnify(t1,t2); tryUnify(t1,t2);
@@ -1150,14 +1147,14 @@ class Checker {
unify(t1, TFloat, e1); unify(t1, TFloat, e1);
unify(t2, TFloat, e2); unify(t2, TFloat, e2);
} }
case OpSub, OpMult, OpDiv, OpMod: case "-", "*", "/", "%":
var t1 = typeExpr(e1,WithType(TInt)); var t1 = typeExpr(e1,WithType(TInt));
var t2 = typeExpr(e2,WithType(t1)); var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) ) if( !tryUnify(t1,t2) )
unify(t2,t1,e2); unify(t2,t1,e2);
switch( [follow(t1), follow(t2)]) { switch( [follow(t1), follow(t2)]) {
case [TInt, TInt]: case [TInt, TInt]:
if( op == OpDiv ) return TFloat; if( op == "/" ) return TFloat;
return TInt; return TInt;
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]: case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
return TFloat; return TFloat;
@@ -1165,21 +1162,21 @@ class Checker {
unify(t1, TFloat, e1); unify(t1, TFloat, e1);
unify(t2, TFloat, e2); unify(t2, TFloat, e2);
} }
case OpBoolAnd, OpBoolOr: case "&&", "||":
typeExprWith(e1,TBool); typeExprWith(e1,TBool);
typeExprWith(e2,TBool); typeExprWith(e2,TBool);
return TBool; return TBool;
case OpInterval: case "...":
typeExprWith(e1,TInt); typeExprWith(e1,TInt);
typeExprWith(e2,TInt); typeExprWith(e2,TInt);
return makeIterator(TInt); return makeIterator(TInt);
case OpEq, OpNeq: case "==", "!=":
var t1 = typeExpr(e1,Value); var t1 = typeExpr(e1,Value);
var t2 = typeExpr(e2,WithType(t1)); var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) ) if( !tryUnify(t1,t2) )
unify(t2,t1,e2); unify(t2,t1,e2);
return TBool; return TBool;
case OpGt, OpLt, OpGte, OpLte: case ">", "<", ">=", "<=":
var t1 = typeExpr(e1,Value); var t1 = typeExpr(e1,Value);
var t2 = typeExpr(e2,WithType(t1)); var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) ) if( !tryUnify(t1,t2) )
@@ -1190,26 +1187,12 @@ class Checker {
error("Cannot compare "+typeStr(t1), expr); error("Cannot compare "+typeStr(t1), expr);
} }
return TBool; return TBool;
case OpAddAssign, OpSubAssign, OpMultAssign, OpDivAssign, OpModAssign, OpAndAssign, OpOrAssign, OpXorAssign, OpShlAssign, OpShrAssign, OpUshrAssign, OpNcoalAssign:
var baseOp = switch(op) {
case OpAddAssign: OpAdd;
case OpSubAssign: OpSub;
case OpMultAssign: OpMult;
case OpDivAssign: OpDiv;
case OpModAssign: OpMod;
case OpAndAssign: OpAnd;
case OpOrAssign: OpOr;
case OpXorAssign: OpXor;
case OpShlAssign: OpShl;
case OpShrAssign: OpShr;
case OpUshrAssign: OpUshr;
case OpNcoalAssign: OpNcoal;
default: op;
};
var t = typeExpr(mk(EBinop(baseOp,e1,e2),expr),withType);
return typeExpr(mk(EBinop(OpAssign,e1,e2),expr), withType);
default: default:
error("Unsupported operation "+op.toString(), expr); if( op.charCodeAt(op.length-1) == "=".code ) {
var t = typeExpr(mk(EBinop(op.substr(0,op.length-1),e1,e2),expr),withType);
return typeExpr(mk(EBinop("=",e1,e2),expr), withType);
}
error("Unsupported operation "+op, expr);
} }
case ETry(etry, v, et, ecatch): case ETry(etry, v, et, ecatch):
var vt = typeExpr(etry, withType); var vt = typeExpr(etry, withType);
-5
View File
@@ -21,9 +21,4 @@ class Config {
public static final DISALLOW_ABSTRACT_AND_ENUM = [ public static final DISALLOW_ABSTRACT_AND_ENUM = [
]; ];
@:unreflective
public static final IMPORT_BLACKLIST:Array<String> = [
// "flixel.FlxG"
];
} }
-359
View File
@@ -1,359 +0,0 @@
package hscript;
import hscript.utils.UnsafeReflect;
import haxe.Constraints.Function;
using Lambda;
/**
* The Custom Class core.
*
* Provides handlers for custom classes.
*
* @author Jamextreme140
*/
@:access(hscript.CustomClassHandler)
class CustomClass implements IHScriptCustomClassBehaviour {
public var className(get, never):String;
private function get_className():String
return __class.name;
public var __interp:Interp;
public var __real_fields:Array<String> = []; // UNUSED
public var __class__fields:Array<String> = []; // Declared fields
public var __allowSetGet:Bool = true;
var __class:CustomClassHandler;
var __superClass:IHScriptCustomClassBehaviour;
var __upperClass:IHScriptCustomClassBehaviour;
var __constructor:Function;
var __overrideFields:Array<String> = [];
var __cachedFieldSet:Map<String, Dynamic> = null;
var initializing:Bool = false;
public function new(__class:CustomClassHandler, ?args:Array<Dynamic>, ?cachedFieldSet:Map<String, Dynamic>) {
this.__class = __class;
__interp = new Interp();
__interp.errorHandler = __class.__interp.errorHandler;
__interp.importFailedCallback = __class.__interp.importFailedCallback;
// __interp.variables = __class.staticInterp.variables;
@:privateAccess __interp.usingHandler.usingEntries = __class.ogInterp.usingHandler.usingEntries;
__interp.publicVariables = __class.ogInterp.publicVariables;
__interp.staticVariables = __class.ogInterp.staticVariables;
__interp.customClasses = __class.ogInterp.customClasses;
for(f => v in __class.__interp.variables) {
if(f == 'new') continue;
if (!__interp.variables.exists(f))
__interp.variables.set(f, v);
}
for (f in __class.fields) {
switch (Tools.expr(f)) {
case EVar(n): __class__fields.push(n);
case EFunction(_, _, n, _, _, _, isOverride):
if(isOverride) __overrideFields.push(n);
__class__fields.push(n);
default: continue;
}
@:privateAccess __interp.exprReturn(f);
}
__interp.scriptObject = this;
initializing = true;
if(cachedFieldSet != null)
for(f => v in cachedFieldSet)
this.hset(f, v);
if (hasField('new')) {
buildConstructor();
call('new', args);
if(__cachedFieldSet != null) {
__cachedFieldSet.clear();
__cachedFieldSet = null;
}
if (this.__superClass == null && __class.extend != null)
__interp.error(ECustom("super() not called"));
} else if (__class.extend != null) {
buildSuperClass(args);
}
initializing = false;
}
function cacheFieldSet(name:String, val:Dynamic) {
if(!initializing) return;
if(__cachedFieldSet == null) __cachedFieldSet = [];
__cachedFieldSet.set(name, val);
}
function buildConstructor() {
__constructor = Reflect.makeVarArgs(buildSuperClass);
}
function buildSuperClass(?args:Array<Dynamic>) {
if (args == null)
args = [];
if (__class.cl == null) {
__interp.error(ECustom('Current class does not have a super'));
return;
}
if (__class.cl is CustomClassHandler) {
var customClass = new CustomClass(__class.cl, args, __cachedFieldSet);
if(__overrideFields.length > 0) {
for (field in __overrideFields) {
var func = __interp.variables.get(field);
customClass.overrideField(field, func);
}
}
customClass.__upperClass = this;
__superClass = customClass;
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(getSuperFields());
} else {
if(__cachedFieldSet != null)
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
__superClass = Type.createInstance(__class.cl, args);
var disallowCopy:Array<String> = {
var fieldMap:Map<String, String> = []; // Prevent duplicate values
for(f in Reflect.fields(__superClass).concat(Type.getInstanceFields(Type.getClass(__superClass))))
fieldMap.set(f, f);
fieldMap.array();
}
this.__real_fields = disallowCopy;
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(disallowCopy);
__superClass.__real_fields = this.__real_fields;
__superClass.__class__fields = this.__class__fields;
__superClass.__interp = this.__interp;
}
}
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
var superFnName:Null<String> = toSuper ? '_HX_SUPER__$name' : null;
var fn:Dynamic = {
if(toSuper && __interp.variables.exists(superFnName)) {
__interp.variables.get(superFnName);
}
else
__interp.variables.get(name);
};
if (fn != null && Reflect.isFunction(fn))
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
// If not found in current class, try parent class recursively
if (__superClass != null && __superClass is CustomClass)
return cast(__superClass, CustomClass).call(name, args, toSuper);
__interp.error(ECustom('$name doesn\'t exists or is not a function'));
return null;
}
function hasField(name:String) {
return __class__fields.contains(name);
}
function hasStaticField(name:String):Bool {
return __class.hasField(name);
}
function getField(name:String, allowProperty:Bool = true):Dynamic {
var f = __interp.variables.get(name);
if (f != null && allowProperty && f is Property) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.get(!__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
return f;
}
function setField(name:String, val:Dynamic):Dynamic {
var f = getField(name, false);
if (f != null && f is Property) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.set(val, !__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
__interp.variables.set(name, val);
return val;
}
/**
* Overrides (replaces) the declared function.
* @param name
* @param func
*/
function overrideField(name:String, func:Function) {
var f = getField(name, false);
if(f != null && Reflect.isFunction(f)) {
__interp.variables.set(name, func);
__interp.variables.set('_HX_SUPER__$name', f);
}
else if(__superClass != null && __superClass is CustomClass) {
cast(__superClass, CustomClass).overrideField(name, func);
}
}
function superHasField(name:String) {
if (__superClass == null)
return false;
var realFieldExists = __superClass.__real_fields != null && __superClass.__real_fields.contains(name);
var classFieldExists = __superClass.__class__fields != null && __superClass.__class__fields.contains(name);
if(!realFieldExists && !classFieldExists && __superClass is CustomClass)
return cast(__superClass, CustomClass).superHasField(name);
return realFieldExists || classFieldExists;
}
function getSuperFields():Array<String> {
if(__superClass == null) return [];
var classFields:Map<String, String> = []; // Prevents duplicated values
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
while (cls != null) {
for(fieldSet in [cls.__class__fields, cls.__real_fields])
for(f in fieldSet)
classFields.set(f, f);
var next:IHScriptCustomClassBehaviour = null;
if(cls is CustomClass)
next = cast(cls, CustomClass).__superClass;
if (next == null)
break;
cls = next;
}
return [for(f in classFields) f];
}
public function hget(name:String):Dynamic {
switch (name) {
case 'superClass': return __superClass;
case 'superConstructor': return __constructor;
default:
if (hasField(name))
return getField(name);
if (hasStaticField(name)) {
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
return null;
}
if (__superClass != null) {
if (superHasField(name)) {
__superClass.__allowSetGet = this.__allowSetGet;
return __superClass.hget(name);
}
}
throw "field '"
+ name
+ "' does not exist in custom class '"
+ this.className
+ "'"
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
}
return null;
}
public function hset(name:String, val:Dynamic):Dynamic {
if (hasField(name))
return setField(name, val);
if (hasStaticField(name)) {
__interp.error(ECustom('The field ${name} should be accessed in a static way.'));
return null;
}
if (__superClass != null) {
if (superHasField(name)) {
__superClass.__allowSetGet = this.__allowSetGet;
return __superClass.hset(name, val);
}
}
else if(__class.extend != null && initializing) {
cacheFieldSet(name, val);
return val;
}
throw "field '"
+ name
+ "' does not exist in custom class '"
+ this.className
+ "'"
+ (__superClass != null ? "' or super class '" + Type.getClassName(Type.getClass(this.__superClass)) + "'" : "");
return null;
}
// UNUSED
public function __callGetter(name:String):Dynamic {
return null;
}
public function __callSetter(name:String, val:Dynamic):Dynamic {
return null;
}
/**
* Returns the real superClass if the Custom Class
* extends another Custom Class, and so on until
* it reaches a real class, otherwise it will
* return the last fetched Custom Class
* @return Null<Dynamic>
*/
public function getSuperclass():IHScriptCustomClassBehaviour {
if(__superClass == null) return null;
var cls:Null<IHScriptCustomClassBehaviour> = __superClass;
// Check if the superClass is another custom class,
// so it will find for a real class, otherwise
// returns the last super CustomClass parent.
while (cls != null && cls is CustomClass) {
var next = cast(cls, CustomClass).__superClass;
if (next == null)
break; // Return the Custom Class itself
cls = next;
}
return cls is CustomClass ? this : cls;
}
// TODO: scripted safe cast for custom classes
public function getUpperclass():IHScriptCustomClassBehaviour {
if(__upperClass == null) return this;
var cls:CustomClass = cast __upperClass;
while (cls != null) {
var prev:CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
return cls;
}
// TODO: scriptable "toString" function
public function toString():String
return className;
}
+65 -150
View File
@@ -1,147 +1,74 @@
package hscript; package hscript;
/** using StringTools;
* Provides handlers for static custom class fields and instantiation.
*/ class CustomClassHandler implements IHScriptCustomConstructor {
@:access(hscript.Property) public static var staticHandler = new StaticHandler();
class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{
public var ogInterp:Interp; public var ogInterp:Interp;
public var name:String; public var name:String;
public var fields:Array<Expr>; public var fields:Array<Expr>;
public var extend:Null<String>; public var extend:String;
public var interfaces:Array<String>; public var interfaces:Array<String>;
public final isFinal:Bool;
public var cl:Dynamic; public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
private var __interp:Interp;
private var __staticFields:Array<String> = [];
public var __allowSetGet:Bool = true;
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>, ?isFinal:Bool) {
this.ogInterp = ogInterp; this.ogInterp = ogInterp;
this.name = name; this.name = name;
this.fields = fields; this.fields = fields;
this.extend = extend; this.extend = extend;
this.interfaces = interfaces; this.interfaces = interfaces;
this.isFinal = isFinal != null ? isFinal : false;
if(extend != null) {
if(ogInterp.customClasses.exists(extend)) {
var customCls:CustomClassHandler = ogInterp.customClasses.get(extend);
if(customCls.isFinal)
ogInterp.error(ECustom('Cannot extend a final class'));
this.cl = customCls;
}
else
this.cl = Type.resolveClass('${extend}_HSX');
if(cl == null)
ogInterp.error(EInvalidClass(extend));
}
initStatic();
} }
@:access(hscript.Interp) public function hnew(args:Array<Dynamic>):Dynamic {
function initStatic() { var interp = new Interp();
__interp = new Interp();
__interp.errorHandler = ogInterp.errorHandler;
__interp.importFailedCallback = ogInterp.importFailedCallback;
//__interp.variables = ogInterp.variables; interp.errorHandler = ogInterp.errorHandler;
__interp.usingHandler.usingEntries = ogInterp.usingHandler.usingEntries;
__interp.publicVariables = ogInterp.publicVariables;
__interp.staticVariables = ogInterp.staticVariables;
__interp.customClasses = ogInterp.customClasses;
for(f => v in ogInterp.variables) var cl = extend == null ? TemplateClass : Type.resolveClass('${extend}_HSX');
if(!__interp.variables.exists(f)) if(cl == null)
__interp.variables.set(f, v); ogInterp.error(EInvalidClass(extend));
for(i => e in fields.copy()) { var _class = Type.createInstance(cl, args);
var isValid:Bool = false;
var staticField:Bool = false;
var fieldName:String = null;
switch (Tools.expr(e)) {
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
isValid = true;
staticField = isStatic;
fieldName = n;
default:
}
if(staticField && isValid) { var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
__interp.exprReturn(e); var capturedLocals:Map<String, {r:Dynamic, depth:Int}> = [];
__staticFields.push(fieldName); for(k=>e in __capturedLocals)
fields.remove(e); if (e != null && e.depth <= 0)
capturedLocals.set(k, e);
var disallowCopy = Type.getInstanceFields(cl);
for (key => value in capturedLocals) {
if(!disallowCopy.contains(key)) {
interp.locals.set(key, {r: value, depth: -1});
} }
} }
} for (key => value in ogInterp.variables) {
if(!disallowCopy.contains(key)) {
public function hnew(args:Array<Dynamic>):Dynamic interp.variables.set(key, value);
return new CustomClass(this, args); }
@:allow(hscript.Interp)
inline function hasField(name:String) {
return __staticFields.contains(name);
}
function getField(name:String, allowProperty:Bool = true):Dynamic {
var f = __interp.variables.get(name);
if(f is Property && allowProperty) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.get(!__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
return f;
}
function setField(name:String, val:Dynamic):Dynamic {
var f = getField(name, false);
if(f is Property) {
var prop:Property = cast f;
//prop.__allowSetGet = this.__allowSetGet;
var r = prop.set(val, !__allowSetGet);
//prop.__allowSetGet = true;
return r;
}
__interp.variables.set(name, val);
return val;
}
public function hget(name:String):Dynamic {
if(name == 'new') {
return Reflect.makeVarArgs(function(args:Array<Dynamic>):Dynamic {
return inline this.hnew(args);
});
} }
if(hasField(name)) {
return getField(name);
}
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
return null;
}
public function hset(name:String, val:Dynamic):Dynamic { for(expr in fields) {
if(hasField(name)) @:privateAccess
return setField(name, val); interp.exprReturn(expr);
}
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'"; interp.variables.set("super", staticHandler);
return null;
}
// UNUSED _class.__interp = interp;
public function __callGetter(name:String):Dynamic { interp.scriptObject = _class;
return null;
}
public function __callSetter(name:String, val:Dynamic):Dynamic { var newFunc = interp.variables.get("new");
return null; if(newFunc != null) {
Reflect.callMethod(null, newFunc, args);
}
for(variable => value in interp.variables) {
if(variable == "this") continue;
}
return _class;
} }
public function toString():String { public function toString():String {
@@ -149,41 +76,29 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
} }
} }
class TemplateClass implements IHScriptCustomBehaviour {
/**
* This is for backwards compatibility with old hscript-improved, since some scripts use it
**/
@:dox(hide)
@:keep
class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustomAccessBehaviour {
public var __interp:Interp; public var __interp:Interp;
public var __allowSetGet:Bool = true;
public function hset(name:String, val:Dynamic):Dynamic { public function hset(name:String, val:Dynamic):Dynamic {
var variables = __interp.variables; if(this.__interp.variables.exists("set_" + name)) {
if(__allowSetGet && variables.exists("set_" + name)) return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
return __callSetter(name, val); }
variables.set(name, val); if (this.__interp.variables.exists(name)) {
return val; this.__interp.variables.set(name, val);
return val;
}
Reflect.setProperty(this, name, val);
return Reflect.field(this, name);
} }
public function hget(name:String):Dynamic { public function hget(name:String):Dynamic {
var variables = __interp.variables; if(this.__interp.variables.exists("get_" + name))
if(__allowSetGet && variables.exists("get_" + name)) return this.__interp.variables.get("get_" + name)();
return __callGetter(name); if (this.__interp.variables.exists(name))
return variables.get(name); return this.__interp.variables.get(name);
} return Reflect.getProperty(this, name);
public function __callGetter(name:String):Dynamic {
__allowSetGet = false;
var v = __interp.variables.get("get_" + name)();
__allowSetGet = true;
return v;
}
public function __callSetter(name:String, val:Dynamic):Dynamic {
__allowSetGet = false;
var v = __interp.variables.get("set_" + name)(val);
__allowSetGet = true;
return v;
} }
} }
class StaticHandler {
public function new() {}
}
+185 -403
View File
@@ -1,403 +1,185 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * Copyright (C)2008-2017 Haxe Foundation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the * and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions: * Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* 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.
*/ */
package hscript; package hscript;
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end; enum Const {
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end; CInt( v : Int );
typedef Int32 = #if cpp cpp.Int32 #else Int #end; CFloat( f : Float );
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end; CString( s : String );
#if !haxe3
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end; CInt32( v : haxe.Int32 );
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end; #end
}
enum abstract Binop(Int) from Int to Int {
var OpAdd = 0; #if hscriptPos
var OpSub = 1; typedef Expr = {
var OpMult = 2; var e : ExprDef;
var OpDiv = 3; var pmin : Int;
var OpMod = 4; var pmax : Int;
var OpAnd = 5; var origin : String;
var OpOr = 6; var line : Int;
var OpXor = 7; }
var OpShl = 8; enum ExprDef {
var OpShr = 9; #else
var OpUshr = 10; typedef ExprDef = Expr;
var OpEq = 11; enum Expr {
var OpNeq = 12; #end
var OpGte = 13; EConst( c : Const );
var OpLte = 14; EIdent( v : String );
var OpGt = 15; EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool );
var OpLt = 16; EParent( e : Expr );
var OpBoolOr = 17; EBlock( e : Array<Expr> );
var OpBoolAnd = 18; EField( e : Expr, f : String , ?safe : Bool );
var OpIs = 19; EBinop( op : String, e1 : Expr, e2 : Expr );
var OpAssign = 20; EUnop( op : String, prefix : Bool, e : Expr );
var OpNcoal = 21; ECall( e : Expr, params : Array<Expr> );
var OpInterval = 22; EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
var OpArrow = 23; EWhile( cond : Expr, e : Expr );
var OpAddAssign = 24; EFor( v : String, it : Expr, e : Expr, ?ithv: String);
var OpSubAssign = 25; EBreak;
var OpMultAssign = 26; EContinue;
var OpDivAssign = 27; EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool );
var OpModAssign = 28; EReturn( ?e : Expr );
var OpAndAssign = 29; EArray( e : Expr, index : Expr );
var OpOrAssign = 30; EArrayDecl( e : Array<Expr>, ?wantedType: CType );
var OpXorAssign = 31; ENew( cl : String, params : Array<Expr> );
var OpShlAssign = 32; EThrow( e : Expr );
var OpShrAssign = 33; ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
var OpUshrAssign = 34; EObject( fl : Array<{ name : String, e : Expr }> );
var OpNcoalAssign = 35; ETernary( cond : Expr, e1 : Expr, e2 : Expr );
var OpArrowFn = 36; ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr );
EDoWhile( cond : Expr, e : Expr);
public static inline function fromString(s:String):Binop { EMeta( name : String, args : Array<Expr>, e : Expr );
return switch(s) { ECheckType( e : Expr, t : CType );
case "+": OpAdd;
case "-": OpSub; EImport( c : String, ?asname:String );
case "*": OpMult; EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String> );
case "/": OpDiv; }
case "%": OpMod;
case "&": OpAnd; typedef Argument = { name : String, ?t : CType, ?opt : Bool, ?value : Expr };
case "|": OpOr;
case "^": OpXor; typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
case "<<": OpShl;
case ">>": OpShr; enum CType {
case ">>>": OpUshr; CTPath( path : Array<String>, ?params : Array<CType> );
case "==": OpEq; CTFun( args : Array<CType>, ret : CType );
case "!=": OpNeq; CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
case ">=": OpGte; CTParent( t : CType );
case "<=": OpLte; CTOpt( t : CType );
case ">": OpGt; CTNamed( n : String, t : CType );
case "<": OpLt; }
case "||": OpBoolOr;
case "&&": OpBoolAnd; #if hscriptPos
case "is": OpIs; class Error {
case "=": OpAssign; public var e : ErrorDef;
case "??": OpNcoal; public var pmin : Int;
case "...": OpInterval; public var pmax : Int;
case "->": OpArrow; public var origin : String;
case "=>": OpArrowFn; public var line : Int;
case "+=": OpAddAssign; public function new(e, pmin, pmax, origin, line) {
case "-=": OpSubAssign; this.e = e;
case "*=": OpMultAssign; this.pmin = pmin;
case "/=": OpDivAssign; this.pmax = pmax;
case "%=": OpModAssign; this.origin = origin;
case "&=": OpAndAssign; this.line = line;
case "|=": OpOrAssign; }
case "^=": OpXorAssign; public function toString(): String {
case "<<=": OpShlAssign; return Printer.errorToString(this);
case ">>=": OpShrAssign; }
case ">>>=": OpUshrAssign; }
case _ if (s == "??" + "="): OpNcoalAssign; enum ErrorDef {
default: -1; #else
} enum Error {
} #end
EInvalidChar( c : Int );
public inline function toString():String { EUnexpected( s : String );
return switch(this) { EUnterminatedString;
case OpAdd: "+"; EUnterminatedComment;
case OpSub: "-"; EInvalidPreprocessor( msg : String );
case OpMult: "*"; EUnknownVariable( v : String );
case OpDiv: "/"; EInvalidIterator( v : String );
case OpMod: "%"; EInvalidOp( op : String );
case OpAnd: "&"; EInvalidAccess( f : String );
case OpOr: "|"; ECustom( msg : String );
case OpXor: "^"; EInvalidClass( className : String);
case OpShl: "<<"; EAlreadyExistingClass( className : String);
case OpShr: ">>"; }
case OpUshr: ">>>";
case OpEq: "==";
case OpNeq: "!="; enum ModuleDecl {
case OpGte: ">="; DPackage( path : Array<String> );
case OpLte: "<="; DImport( path : Array<String>, ?everything : Bool );
case OpGt: ">"; DClass( c : ClassDecl );
case OpLt: "<"; DTypedef( c : TypeDecl );
case OpBoolOr: "||"; }
case OpBoolAnd: "&&";
case OpIs: "is"; typedef ModuleType = {
case OpAssign: "="; var name : String;
case OpNcoal: "??"; var params : {}; // TODO : not yet parsed
case OpInterval: "..."; var meta : Metadata;
case OpArrow: "->"; var isPrivate : Bool;
case OpArrowFn: "=>"; }
case OpAddAssign: "+=";
case OpSubAssign: "-="; typedef ClassDecl = {> ModuleType,
case OpMultAssign: "*="; var extend : Null<CType>;
case OpDivAssign: "/="; var implement : Array<CType>;
case OpModAssign: "%="; var fields : Array<FieldDecl>;
case OpAndAssign: "&="; var isExtern : Bool;
case OpOrAssign: "|="; }
case OpXorAssign: "^=";
case OpShlAssign: "<<="; typedef TypeDecl = {> ModuleType,
case OpShrAssign: ">>="; var t : CType;
case OpUshrAssign: ">>>="; }
case OpNcoalAssign: "??" + "=";
default: "?"; typedef FieldDecl = {
} var name : String;
} var meta : Metadata;
} var kind : FieldKind;
var access : Array<FieldAccess>;
enum abstract Unop(Int) from Int to Int { }
var OpNot = 0;
var OpNeg = 1; enum FieldAccess {
var OpIncrement = 2; APublic;
var OpDecrement = 3; APrivate;
var OpNegBits = 4; AInline;
AOverride;
public static inline function fromString(s:String):Unop { AStatic;
return switch(s) { AMacro;
case "!": OpNot; }
case "-": OpNeg;
case "++": OpIncrement; enum FieldKind {
case "--": OpDecrement; KFunction( f : FunctionDecl );
case "~": OpNegBits; KVar( v : VarDecl );
default: -1; }
}
} typedef FunctionDecl = {
var args : Array<Argument>;
public inline function toString():String { var expr : Expr;
return switch(this) { var ret : Null<CType>;
case OpNot: "!"; }
case OpNeg: "-";
case OpIncrement: "++"; typedef VarDecl = {
case OpDecrement: "--"; var get : Null<String>;
case OpNegBits: "~"; var set : Null<String>;
default: "?"; var expr : Null<Expr>;
} var type : Null<CType>;
} }
}
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
enum Const {
CInt( v : Int );
CFloat( f : Float );
CString( s : String, ?i : Bool );
}
#if hscriptPos
@:structInit
final class Expr {
public var e : ExprDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
}
enum ExprDef {
#else
typedef ExprDef = Expr;
enum Expr {
#end
EConst( c : Const );
EIdent( v : String );
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
EParent( e : Expr );
EBlock( e : Array<Expr> );
EField( e : Expr, f : String , ?safe : Bool );
EBinop( op : Binop, e1 : Expr, e2 : Expr );
EUnop( op : Unop, prefix : Bool, e : Expr );
ECall( e : Expr, params : Array<Expr> );
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
EWhile( cond : Expr, e : Expr );
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
EBreak;
EContinue;
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
EReturn( ?e : Expr );
EArray( e : Expr, index : Expr );
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
EThrow( e : Expr );
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
EObject( fl : Array<ObjectField> );
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
EDoWhile( cond : Expr, e : Expr);
EMeta( name : String, args : Array<Expr>, e : Expr );
ECheckType( e : Expr, t : CType );
EPackage( ?n:String );
EImport( c : String, ?asname:String, ?isUsing:Bool );
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
EEnum( en:EnumDecl, ?isAbstract:Bool );
ECast(e:Expr, ?t:CType);
ERegex(e:String, flags:String);
}
@:structInit
final class ObjectField {
public var name : String;
public var e : Expr;
}
@:structInit
final class SwitchCase {
public var values : Array<Expr>;
public var expr : Expr;
}
@:structInit
final class Argument {
public var name : String;
public var t : CType;
public var opt : Bool;
public var value : Expr;
}
@:structInit
final class MetadataEntry {
public var name : String;
public var params : Array<Expr>;
}
typedef Metadata = Array<MetadataEntry>;
@:structInit
final class EnumDecl {
public var name : String;
public var fields : Array<EnumField>;
public var underlyingType : Null<CType>;
}
@:structInit
final class EnumField {
public var name : String;
public var args : Array<Argument>;
public var value : Null<Expr>;
}
enum CType {
CTPath( path : Array<String>, ?params : Array<CType> );
CTFun( args : Array<CType>, ret : CType );
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
CTParent( t : CType );
CTOpt( t : CType );
CTNamed( n : String, t : CType );
CTExpr( e : Expr ); // for type parameters only
}
#if hscriptPos
class Error {
public var e : ErrorDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
public function new(e, pmin, pmax, origin, line) {
this.e = e;
this.pmin = pmin;
this.pmax = pmax;
this.origin = origin;
this.line = line;
}
public function toString(): String {
return Printer.errorToString(this);
}
}
enum ErrorDef {
#else
enum Error {
#end
EInvalidChar( c : Int );
EUnexpected( s : String );
EUnterminatedString;
EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String );
EInvalidIterator( v : String );
EInvalidOp( op : String );
EInvalidAccess( f : String );
ECustom( msg : String );
EInvalidClass( className : String);
EAlreadyExistingClass( className : String);
}
enum ModuleDecl {
DPackage( path : Array<String> );
DImport( path : Array<String>, ?everything : Bool );
DClass( c : ClassDecl );
DTypedef( c : TypeDecl );
}
typedef ModuleType = {
var name : String;
var params : {}; // TODO : not yet parsed
var meta : Metadata;
var isPrivate : Bool;
}
typedef ClassDecl = {> ModuleType,
var extend : Null<CType>;
var implement : Array<CType>;
var fields : Array<FieldDecl>;
var isExtern : Bool;
}
typedef TypeDecl = {> ModuleType,
var t : CType;
}
typedef FieldDecl = {
var name : String;
var meta : Metadata;
var kind : FieldKind;
var access : Array<FieldAccess>;
}
enum abstract FieldAccess(UInt8) {
var APublic;
var APrivate;
var AInline;
var AOverride;
var AStatic;
var AMacro;
}
enum abstract FieldPropertyAccess(UInt8) {
var ADefault;
var ANull;
var AGet;
var ASet;
var ADynamic;
var ANever;
}
enum FieldKind {
KFunction( f : FunctionDecl );
KVar( v : VarDecl );
}
@:structInit
final class FunctionDecl {
public var args : Array<Argument>;
public var body : Expr;
public var ret : Null<CType>;
}
typedef VarDecl = {
var get : Null<String>;
var set : Null<String>;
var expr : Null<Expr>;
var type : Null<CType>;
}
-182
View File
@@ -1,182 +0,0 @@
package hscript;
import hscript.utils.UnsafeReflect;
/**
* Wrapper class for enums, both for real and scripted.
* Use EnumTools and EnumValueTools for enum operations.
*/
@:structInit
class HEnum implements IHScriptCustomBehaviour {
var enumValues(default, null) = {};
public function setEnum(name:String, enumValue:Dynamic):Void {
UnsafeReflect.setField(enumValues, name, enumValue);
}
public function getEnum(name:String):Null<Dynamic> {
if (UnsafeReflect.hasField(enumValues, name))
return UnsafeReflect.field(enumValues, name);
return null;
}
public function getEnumValues():Dynamic {
return enumValues;
}
public function hget(name:String):Dynamic {
return getEnum(name);
}
public function hset(name:String, val:Dynamic):Dynamic {
return null;
}
}
@:nullSafety
@:structInit
class HEnumValue {
public var enumName:String;
public var fieldName:String;
public var index:Int;
public var args:Array<Dynamic>;
public function toString():String {
return '$enumName.$fieldName${args.length > 0 ? '(${[for (a in args) a].join(", ")})' : ''}';
}
public inline function getEnumName():String
return this.enumName;
public inline function getConstructorArgs():Array<Dynamic>
return this.args;
public function compare(other:HEnumValue):Bool {
if (enumName != other.enumName || fieldName != other.fieldName)
return false;
if (args.length == 0 && other.args.length == 0)
return true;
if (args.length == 0 || other.args.length == 0)
return false;
if (args.length != other.args.length)
return false;
for (i in 0...args.length)
if (args[i] != other.args[i])
return false;
return true;
}
}
@:nullSafety
class EnumTools {
public static function getConstructors(e:Dynamic):Array<String> {
if(Std.isOfType(e, HEnum)) {
var henum:HEnum = cast e;
return UnsafeReflect.fields(henum.getEnumValues());
}
return Type.getEnumConstructs(cast e);
}
public static function createByName(e:Dynamic, constr:String, ?params:Array<Dynamic>):Dynamic {
if(Std.isOfType(e, HEnum)) {
var henum:HEnum = cast e;
var constructor = henum.getEnum(constr);
if(constructor == null)
throw 'Constructor $constr not found in enum';
if(Std.isOfType(constructor, HEnumValue))
return constructor;
if(Reflect.isFunction(constructor))
return constructor(params == null ? [] : params);
throw 'Invalid constructor type';
}
return Type.createEnum(cast e, constr, params);
}
public static function createByIndex(e:Dynamic, index:Int, ?params:Array<Dynamic>):Dynamic {
if(Std.isOfType(e, HEnum)) {
var constructors = getConstructors(e);
if(index < 0 || index >= constructors.length)
throw 'Index $index out of bounds for enum';
return createByName(e, constructors[index], params);
}
return Type.createEnumIndex(cast e, index, params);
}
}
@:nullSafety
class EnumValueTools {
public static function getType(e:Dynamic):Null<String> {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.enumName;
}
var en = Type.getEnum(e);
if(en != null)
return Type.getEnumName(en);
return null;
}
public static function getName(e:Dynamic):String {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.fieldName;
}
return Type.enumConstructor(e);
}
public static function getParameters(e:Dynamic):Array<Dynamic> {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.args.copy();
}
return Type.enumParameters(e);
}
public static function getIndex(e:Dynamic):Int {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
return hv.index;
}
return Type.enumIndex(e);
}
public static function equals(a:Dynamic, b:Dynamic):Bool {
if(Std.isOfType(a, HEnumValue) && Std.isOfType(b, HEnumValue)) {
var hva:HEnumValue = cast a;
var hvb:HEnumValue = cast b;
return hva.compare(hvb);
}
return Type.enumEq(a, b);
}
public static function match(e:Dynamic, pattern:Dynamic):Bool {
if(Std.isOfType(e, HEnumValue)) {
var hv:HEnumValue = cast e;
if(Std.isOfType(pattern, HEnumValue)) {
var hp:HEnumValue = cast pattern;
if(hv.enumName != hp.enumName || hv.fieldName != hp.fieldName)
return false;
if(hp.args.length == 0)
return true;
if(hv.args.length != hp.args.length)
return false;
for(i in 0...hp.args.length) {
var pa = hp.args[i];
if(pa != null && hv.args[i] != pa)
return false;
}
return true;
}
if(Reflect.isObject(pattern)) {
var patternName = UnsafeReflect.hasField(pattern, "name") ? UnsafeReflect.field(pattern, "name") : null;
if(patternName != null && patternName != hv.fieldName)
return false;
return true;
}
return false;
}
return Type.enumEq(e, pattern);
}
}
-12
View File
@@ -1,12 +0,0 @@
package hscript;
// Soon...
interface IHScriptAbstractBehaviour extends IHScriptCustomBehaviour {
public var hasOp:Bool;
public var hasArr:Bool;
// @:op(A * B), @:op(A++), etc...
public function hop(kind:String, a:Dynamic, ?b:Dynamic):Dynamic;
public function harrayget(key:Dynamic):Dynamic;
public function harrayset(key:Dynamic, val:Dynamic):Dynamic;
}
-11
View File
@@ -1,11 +0,0 @@
package hscript;
/**
* Same Interface as IHScriptCustomBehaviour but for Property.
*/
interface IHScriptCustomAccessBehaviour extends IHScriptCustomBehaviour {
var __allowSetGet:Bool;
public function __callGetter(name:String):Dynamic;
public function __callSetter(name:String, val:Dynamic):Dynamic;
}
-17
View File
@@ -1,23 +1,6 @@
package hscript; package hscript;
/**
* Special Interface for handling field access behaviour.
* Basically works like the operator overload `@:op(a.b)`
* for an abstract.
*/
interface IHScriptCustomBehaviour { interface IHScriptCustomBehaviour {
/**
* Field Write Access
* @param name - Field Name
* @param val - Value to assign
* @return Dynamic - The assigned value
*/
public function hset(name:String, val:Dynamic):Dynamic; public function hset(name:String, val:Dynamic):Dynamic;
/**
* Field Read Access
* @param name - Field Name
* @return Dynamic - The returned field
*/
public function hget(name:String):Dynamic; public function hget(name:String):Dynamic;
} }
-11
View File
@@ -1,11 +0,0 @@
package hscript;
/**
* Special Interface to make a class usable for Custom Classes.
*/
interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{
public var __interp:Interp;
public var __real_fields:Array<String>;
public var __class__fields:Array<String>;
}
-3
View File
@@ -1,8 +1,5 @@
package hscript; package hscript;
/**
* Special Interface for handling new instances of an object.
*/
interface IHScriptCustomConstructor { interface IHScriptCustomConstructor {
public function hnew(args:Array<Dynamic>):Dynamic; public function hnew(args:Array<Dynamic>):Dynamic;
} }
+429 -1187
View File
File diff suppressed because it is too large Load Diff
+42 -11
View File
@@ -29,13 +29,23 @@ import haxe.macro.Expr;
class Macro { class Macro {
var p : Position; var p : Position;
#if haxe3
var binops : Map<String,Binop>; var binops : Map<String,Binop>;
var unops : Map<String,Unop>; var unops : Map<String,Unop>;
#else
var binops : Hash<Binop>;
var unops : Hash<Unop>;
#end
public function new(pos) { public function new(pos) {
p = pos; p = pos;
#if haxe3
binops = new Map(); binops = new Map();
unops = new Map(); unops = new Map();
#else
binops = new Hash();
unops = new Hash();
#end
for( c in Type.getEnumConstructs(Binop) ) { for( c in Type.getEnumConstructs(Binop) ) {
if( c == "OpAssignOp" ) continue; if( c == "OpAssignOp" ) continue;
var op = Type.createEnum(Binop, c); var op = Type.createEnum(Binop, c);
@@ -63,7 +73,9 @@ class Macro {
case OpMod: assign = true; "%"; case OpMod: assign = true; "%";
case OpAssignOp(_): ""; case OpAssignOp(_): "";
case OpInterval: "..."; case OpInterval: "...";
#if haxe3
case OpArrow: "=>"; case OpArrow: "=>";
#end
#if (haxe_ver >= 4) #if (haxe_ver >= 4)
case OpIn: "in"; case OpIn: "in";
#end #end
@@ -90,8 +102,15 @@ class Macro {
} }
} }
#if !haxe3
function isType(v:String) {
var c0 = v.charCodeAt(0);
return c0 >= 'A'.code && c0 <= 'Z'.code;
}
#end
function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> { function map < T, R > ( a : Array<T>, f : T -> R ) : Array<R> {
var b = []; var b = new Array();
for( x in a ) for( x in a )
b.push(f(x)); b.push(f(x));
return b; return b;
@@ -127,8 +146,6 @@ class Macro {
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } ); tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
} }
TAnonymous(tf); TAnonymous(tf);
case CTExpr(_):
throw "assert";
}; };
} }
@@ -139,9 +156,17 @@ class Macro {
case CInt(v): CInt(Std.string(v)); case CInt(v): CInt(Std.string(v));
case CFloat(f): CFloat(Std.string(f)); case CFloat(f): CFloat(Std.string(f));
case CString(s): CString(s); case CString(s): CString(s);
#if !haxe3
case CInt32(v): CInt(Std.string(v));
#end
}); });
case EIdent(v): case EIdent(v):
EConst(CIdent(v)); #if !haxe3
if( isType(v) )
EConst(CType(v));
else
#end
EConst(CIdent(v));
case EVar(n, t, e): case EVar(n, t, e):
EVars([ { name : n, expr : if( e == null ) null else convert(e), type : if( t == null ) null else convertType(t) } ]); EVars([ { name : n, expr : if( e == null ) null else convert(e), type : if( t == null ) null else convertType(t) } ]);
case EParent(e): case EParent(e):
@@ -149,15 +174,19 @@ class Macro {
case EBlock(el): case EBlock(el):
EBlock(map(el,convert)); EBlock(map(el,convert));
case EField(e, f): case EField(e, f):
EField(convert(e), f); #if !haxe3
if( isType(f) )
EType(convert(e), f);
else
#end
EField(convert(e), f);
case EBinop(op, e1, e2): case EBinop(op, e1, e2):
var b = binops.get(op.toString()); var b = binops.get(op);
if( b == null ) throw EInvalidOp(op.toString()); if( b == null ) throw EInvalidOp(op);
EBinop(b, convert(e1), convert(e2)); EBinop(b, convert(e1), convert(e2));
case EUnop(op, prefix, e): case EUnop(op, prefix, e):
var opStr = op.toString(); var u = unops.get(op);
var u = unops.get(opStr); if( u == null ) throw EInvalidOp(op);
if( u == null ) throw EInvalidOp(opStr);
EUnop(u, !prefix, convert(e)); EUnop(u, !prefix, convert(e));
case ECall(e, params): case ECall(e, params):
ECall(convert(e), map(params, convert)); ECall(convert(e), map(params, convert));
@@ -171,9 +200,11 @@ class Macro {
#if (haxe_ver >= 4) #if (haxe_ver >= 4)
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor)); EFor({ expr : EBinop(OpIn,{ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
#else #elseif (haxe_211 || haxe3)
var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end; var p = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor)); EFor({ expr : EIn({ expr : EConst(CIdent(v)), pos : p },convert(it)), pos : p }, convert(efor));
#else
EFor(v, convert(it), convert(efor));
#end #end
case EBreak: case EBreak:
EBreak; EBreak;
+302 -795
View File
File diff suppressed because it is too large Load Diff
+377 -494
View File
@@ -1,494 +1,377 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * Copyright (C)2008-2017 Haxe Foundation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the * and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions: * Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* 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.
*/ */
package hscript; package hscript;
import hscript.Expr; import hscript.Expr;
class Printer { class Printer {
var buf : StringBuf; var buf : StringBuf;
var tabs : String; var tabs : String;
public function new() { public function new() {
} }
public function exprToString( e : Expr ):String { public function exprToString( e : Expr ) {
buf = new StringBuf(); buf = new StringBuf();
tabs = ""; tabs = "";
expr(e); expr(e);
return buf.toString(); return buf.toString();
} }
public function typeToString( t : CType ):String { public function typeToString( t : CType ) {
buf = new StringBuf(); buf = new StringBuf();
tabs = ""; tabs = "";
type(t); type(t);
return buf.toString(); return buf.toString();
} }
inline function add<T>(s:T):Void buf.add(s); inline function add<T>(s:T) buf.add(s);
function type( t : CType ):Void { function type( t : CType ) {
switch( t ) { switch( t ) {
case CTOpt(t): case CTOpt(t):
add('?'); add('?');
type(t); type(t);
case CTPath(path, params): case CTPath(path, params):
add(path.join(".")); add(path.join("."));
if( params != null ) { if( params != null ) {
add("<"); add("<");
var first = true; var first = true;
for( p in params ) { for( p in params ) {
if( first ) first = false else add(", "); if( first ) first = false else add(", ");
type(p); type(p);
} }
add(">"); add(">");
} }
case CTNamed(name, t): case CTNamed(name, t):
add(name); add(name);
add(':'); add(':');
type(t); type(t);
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))): case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
add('('); add('(');
for (a in args) for (a in args)
switch a { switch a {
case CTNamed(_, _): type(a); case CTNamed(_, _): type(a);
default: type(CTNamed('_', a)); default: type(CTNamed('_', a));
} }
add(')->'); add(')->');
type(ret); type(ret);
case CTFun(args, ret): case CTFun(args, ret):
if( args.length == 0 ) if( args.length == 0 )
add("Void -> "); add("Void -> ");
else { else {
for( a in args ) { for( a in args ) {
type(a); type(a);
add(" -> "); add(" -> ");
} }
} }
type(ret); type(ret);
case CTAnon(fields): case CTAnon(fields):
add("{"); add("{");
var first = true; var first = true;
for( f in fields ) { for( f in fields ) {
if( first ) { first = false; add(" "); } else add(", "); if( first ) { first = false; add(" "); } else add(", ");
add(f.name + " : "); add(f.name + " : ");
type(f.t); type(f.t);
} }
add(first ? "}" : " }"); add(first ? "}" : " }");
case CTParent(t): case CTParent(t):
add("("); add("(");
type(t); type(t);
add(")"); add(")");
case CTExpr(e): }
expr(e); }
}
} function addType( t : CType ) {
if( t != null ) {
function addType( t : CType ):Void { add(" : ");
if( t != null ) { type(t);
add(" : "); }
type(t); }
}
} function expr( e : Expr ) {
if( e == null ) {
function expr( e : Expr ):Void { add("??NULL??");
if( e == null ) { return;
add("??NULL??"); }
return; switch( #if hscriptPos e.e #else e #end ) {
} case EImport(c, n):
switch(Tools.expr(e)) { add("import " + c);
case EPackage(n): if(n != null)
add('package'); add(' as $n');
if(n != null) case EClass(name, fields, extend, interfaces):
add(' $n'); add('class $name');
add(';\n'); if (extend != null)
case EImport(c, n, u): add(' extends $extend');
add('${u ? 'using' : 'import'} $c'); for(_interface in interfaces) {
if(n != null) add(' implements $_interface');
add(' as $n'); }
case EClass(name, fields, extend, interfaces, fnal): add(' {\n');
var isFinal = fnal != null && fnal; tabs += "\t";
if(isFinal) //for(field in fields) {
add('final '); // expr(field);
add('class $name'); //}
if (extend != null)
add(' extends $extend'); tabs = tabs.substr(1);
for(_interface in interfaces) { add("}");
add(' implements $_interface'); case EConst(c):
} switch( c ) {
tabs += "\t"; case CInt(i): add(i);
add(" {\n"); case CFloat(f): add(f);
for( e in fields ) { case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
add(tabs); }
expr(e); case EIdent(v):
//add(";\n"); add(v);
} case EVar(n, t, e): // TODO: static, public, override
//for(field in fields) { add("var " + n);
// expr(field); addType(t);
//} if( e != null ) {
add(" = ");
tabs = tabs.substr(1); expr(e);
add("}"); }
case EEnum(en, isAbstract): case EParent(e):
if(isAbstract) { add("("); expr(e); add(")");
add('enum abstract ${en.name}('); case EBlock(el):
if(en.underlyingType != null) if( el.length == 0 ) {
type(en.underlyingType); add("{}");
else } else {
add('Int'); tabs += "\t";
add(')'); add("{\n");
if(en.fields.length == 0) { for( e in el ) {
add(' {}'); add(tabs);
return; expr(e);
} add(";\n");
tabs += "\t"; }
add(" {\n"); tabs = tabs.substr(1);
for(e in en.fields) { add("}");
add(tabs); }
add(e.name); case EField(e, f, s):
if(e.value != null) { expr(e);
add(" = "); add((s == true ? "?." : ".") + f);
expr(e.value); case EBinop(op, e1, e2):
} expr(e1);
add(";\n"); add(" " + op + " ");
} expr(e2);
tabs = tabs.substr(1); case EUnop(op, pre, e):
add("}"); if( pre ) {
} else { add(op);
add('enum ${en.name}'); expr(e);
if(en.fields.length == 0) { } else {
add(' {}'); expr(e);
return; add(op);
} }
tabs += "\t"; case ECall(e, args):
add(" {\n"); if( e == null )
for(e in en.fields) { expr(e);
add(tabs); else switch( #if hscriptPos e.e #else e #end ) {
add(e.name); case EField(_), EIdent(_), EConst(_):
if(e.args.length > 0) { expr(e);
add("("); default:
var first = true; add("(");
for( a in e.args ) { expr(e);
if( first ) first = false else add(", "); add(")");
if( a.opt ) add("?"); }
add(a.name); add("(");
addType(a.t); var first = true;
} for( a in args ) {
add(')'); if( first ) first = false else add(", ");
} expr(a);
add(";\n"); }
} add(")");
tabs = tabs.substr(1); case EIf(cond,e1,e2):
add("}"); add("if( ");
} expr(cond);
case ECast(e, t): add(" ) ");
var safe = t != null; expr(e1);
add("cast "); if( e2 != null ) {
if(safe) add("("); add(" else ");
expr(e); expr(e2);
if(safe) { }
add(", "); case EWhile(cond,e):
addType(t); add("while( ");
add(")"); expr(cond);
} add(" ) ");
case ERegex(e, f): expr(e);
add('~/$e/$f'); case EDoWhile(cond,e):
add(';\n'); add("do ");
case EConst(c): expr(e);
switch( c ) { add(" while ( ");
case CInt(i): add(i); expr(cond);
case CFloat(f): add(f); add(" )");
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"'); case EFor(v, it, e, ithv):
} if(ithv != null)
case EIdent(v): add("for( "+ithv+" => "+v+" in ");
add(v); else
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _): add("for( "+v+" in ");
if(p) add("public "); expr(it);
else if(pr) add("private "); add(" ) ");
if(s) add("static "); expr(e);
if(isInline) add("inline "); case EBreak:
if(isFinal) add("final " + n); add("break");
else add("var " + n); case EContinue:
add("continue");
if(get != null || set != null) { case EFunction(params, e, name, ret): // TODO: static, public, override
add("("); add("function");
switch(get) { if( name != null )
case ADefault: add("default, "); add(" " + name);
case ANull: add("null, "); add("(");
case AGet: add("get, "); var first = true;
case ADynamic: add("dynamic, "); for( a in params ) {
case ANever: add("never, "); if( first ) first = false else add(", ");
default: if( a.opt ) add("?");
} add(a.name);
switch(set) { addType(a.t);
case ADefault: add("default"); }
case ANull: add("null"); add(")");
case ASet: add("set"); addType(ret);
case ADynamic: add("dynamic"); add(" ");
case ANever: add("never"); expr(e);
default: case EReturn(e):
} add("return");
add(")"); if( e != null ) {
} add(" ");
expr(e);
addType(t); }
if( e != null ) { case EArray(e,index):
add(" = "); expr(e);
expr(e); add("[");
} expr(index);
case EParent(e): add("]");
add("("); expr(e); add(")"); case EArrayDecl(el, _):
case EBlock(el): add("[");
if( el.length == 0 ) { var first = true;
add("{}"); for( e in el ) {
} else { if( first ) first = false else add(", ");
tabs += "\t"; expr(e);
add("{\n"); }
for( e in el ) { add("]");
add(tabs); case ENew(cl, args):
expr(e); add("new " + cl + "(");
add(";\n"); var first = true;
} for( e in args ) {
tabs = tabs.substr(1); if( first ) first = false else add(", ");
add("}"); expr(e);
} }
case EField(e, f, s): add(")");
expr(e); case EThrow(e):
add((s == true ? "?." : ".") + f); add("throw ");
case EBinop(op, e1, e2): expr(e);
expr(e1); case ETry(e, v, t, ecatch):
add(" " + op.toString() + " "); add("try ");
expr(e2); expr(e);
case EUnop(op, pre, e): add(" catch( " + v);
if( pre ) { addType(t);
add(op); add(") ");
expr(e); expr(ecatch);
} else { case EObject(fl):
expr(e); if( fl.length == 0 ) {
add(op); add("{}");
} } else {
case ECall(e, args): tabs += "\t";
if( e == null ) add("{\n");
expr(e); for( f in fl ) {
else switch( Tools.expr(e)) { add(tabs);
case EField(_), EIdent(_), EConst(_): add(f.name+" : ");
expr(e); expr(f.e);
default: add(",\n");
add("("); }
expr(e); tabs = tabs.substr(1);
add(")"); add("}");
} }
add("("); case ETernary(c,e1,e2):
var first = true; expr(c);
for( a in args ) { add(" ? ");
if( first ) first = false else add(", "); expr(e1);
expr(a); add(" : ");
} expr(e2);
add(")"); case ESwitch(e, cases, def):
case EIf(cond,e1,e2): add("switch( ");
add("if( "); expr(e);
expr(cond); add(") {");
add(" ) "); for( c in cases ) {
expr(e1); add("case ");
if( e2 != null ) { var first = true;
add(" else "); for( v in c.values ) {
expr(e2); if( first ) first = false else add(", ");
} expr(v);
case EWhile(cond,e): }
add("while( "); add(": ");
expr(cond); expr(c.expr);
add(" ) "); add(";\n");
expr(e); }
case EDoWhile(cond,e): if( def != null ) {
add("do "); add("default: ");
expr(e); expr(def);
add(" while ( "); add(";\n");
expr(cond); }
add(" )"); add("}");
case EFor(v, it, e, ithv): case EMeta(name, args, e):
if(ithv != null) add("@");
add("for( "+ithv+" => "+v+" in "); add(name);
else if( args != null && args.length > 0 ) {
add("for( "+v+" in "); add("(");
expr(it); var first = true;
add(" ) "); for( a in args ) {
expr(e); if( first ) first = false else add(", ");
case EBreak: expr(e);
add("break"); }
case EContinue: add(")");
add("continue"); }
case EFunction(params, e, name, ret): // TODO: static, public, override add(" ");
add("function"); expr(e);
if( name != null ) case ECheckType(e, t):
add(" " + name); add("(");
add("("); expr(e);
var first = true; add(" : ");
for( a in params ) { addType(t);
if( first ) first = false else add(", "); add(")");
if( a.opt ) add("?"); }
add(a.name); }
addType(a.t);
} public static function toString( e : Expr ) {
add(")"); return new Printer().exprToString(e);
addType(ret); }
add(" ");
expr(e); public static function errorToString( e : Expr.Error ) {
case EReturn(e): var message = switch( #if hscriptPos e.e #else e #end ) {
add("return"); case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
if( e != null ) { case EUnexpected(s): "Unexpected token: \""+s+"\"";
add(" "); case EUnterminatedString: "Unterminated string";
expr(e); case EUnterminatedComment: "Unterminated comment";
} case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
case EArray(e,index): case EUnknownVariable(v): "Unknown variable: "+v;
expr(e); case EInvalidIterator(v): "Invalid iterator: "+v;
add("["); case EInvalidOp(op): "Invalid operator: "+op;
expr(index); case EInvalidAccess(f): "Invalid access to field " + f;
add("]"); case ECustom(msg): msg;
case EArrayDecl(el, _): case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
add("["); case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
var first = true; };
for( e in el ) { #if hscriptPos
if( first ) first = false else add(", "); return e.origin + ":" + e.line + ": " + message;
expr(e); #else
} return message;
add("]"); #end
case ENew(cl, args, params): }
add("new " + cl);
if(params != null) {
add("<"); }
var first = true;
for( p in params ) {
if( first ) first = false else add(", ");
type(p);
}
add(">");
}
add("(");
var first = true;
for( e in args ) {
if( first ) first = false else add(", ");
expr(e);
}
add(")");
case EThrow(e):
add("throw ");
expr(e);
case ETry(e, v, t, ecatch):
add("try ");
expr(e);
add(" catch( " + v);
addType(t);
add(") ");
expr(ecatch);
case EObject(fl):
if( fl.length == 0 ) {
add("{}");
} else {
tabs += "\t";
add("{\n");
for( f in fl ) {
add(tabs);
add(f.name+" : ");
expr(f.e);
add(",\n");
}
tabs = tabs.substr(1);
add("}");
}
case ETernary(c,e1,e2):
expr(c);
add(" ? ");
expr(e1);
add(" : ");
expr(e2);
case ESwitch(e, cases, def):
add("switch( ");
expr(e);
add(") {");
for( c in cases ) {
add("case ");
var first = true;
for( v in c.values ) {
if( first ) first = false else add(", ");
expr(v);
}
add(": ");
expr(c.expr);
add(";\n");
}
if( def != null ) {
add("default: ");
expr(def);
add(";\n");
}
add("}");
case EMeta(name, args, e):
add("@");
add(name);
if( args != null && args.length > 0 ) {
add("(");
var first = true;
for( a in args ) {
if( first ) first = false else add(", ");
expr(e);
}
add(")");
}
add(" ");
expr(e);
case ECheckType(e, t):
add("(");
expr(e);
add(" : ");
addType(t);
add(")");
}
}
public static function toString( e : Expr ):String {
return new Printer().exprToString(e);
}
public static function errorToString( e : Expr.Error ):String {
var message = switch( #if hscriptPos e.e #else e #end ) {
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
case EUnexpected(s): "Unexpected token: \""+s+"\"";
case EUnterminatedString: "Unterminated string";
case EUnterminatedComment: "Unterminated comment";
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
case EUnknownVariable(v): "Unknown variable: "+v;
case EInvalidIterator(v): "Invalid iterator: "+v;
case EInvalidOp(op): "Invalid operator: "+op;
case EInvalidAccess(f): "Invalid access to field " + f;
case ECustom(msg): msg;
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
};
#if hscriptPos
return e.origin + ":" + e.line + ": " + message;
#else
return message;
#end
}
}
-178
View File
@@ -1,178 +0,0 @@
package hscript;
import hscript.utils.UnsafeReflect;
import hscript.Interp;
import hscript.Expr.FieldPropertyAccess;
/**
* Special variable that handles 'getter/setter' function calls
* depending of the read/write access combination.
*
* Example:
* ```haxe
* public var myvar(get, set):Int;
* var _myvar:Int = 10;
*
* function get_myvar():Int {
* return _myvar;
* }
*
* function set_myvar(val:Int):Int {
* if(val > 10) return _myvar = val;
* return val;
* }
* ```
*
* @see https://haxe.org/manual/class-field-property.html
*/
@:access(hscript.Interp)
class Property {
private static inline var GET = 'get_';
private static inline var SET = 'set_';
/**
* Name of the attached field.
*/
public final name:String;
/**
* The current value. If isn't initialized, it's always `null`.
*/
public var r:Dynamic;
/**
* The getter property kind
*/
public final getter:FieldPropertyAccess;
/**
* The setter property kind
*/
public final setter:FieldPropertyAccess;
/**
* If the field is declared as static.
*/
public var isStatic(get, never):Bool;
function get_isStatic() {
return __isStatic && interp.allowStaticVariables;
}
var isVar:Bool;
var interp:Interp;
@:allow(hscript.Interp)
private var getterFunc(get, never):String;
private inline function get_getterFunc():String {
return '$GET$name';
}
@:allow(hscript.Interp)
private var setterFunc(get, never):String;
private inline function get_setterFunc():String {
return '$SET$name';
}
public function new(name:String, r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic:Bool, interp:Interp) {
this.name = name;
this.r = r;
this.getter = getter;
this.setter = setter;
this.isVar = isVar;
this.__isStatic = isStatic;
this.interp = interp;
}
// Internal flags to gain access to the current field value (if isn't a property field)
var __allowReadAccess:Bool = false;
var __allowWriteAccess:Bool = false;
// Internal flag to gain access if the field is accessed with @:bypassAccessor
var __allowSetGet:Bool = true;
final __isStatic:Bool = false;
public function get(isBypassAccessor:Bool) {
if(isBypassAccessor) __allowSetGet = false;
var r:Dynamic = callGetter();
if(isBypassAccessor) __allowSetGet = true;
return r;
}
public function set(value:Dynamic, isBypassAccessor:Bool) {
if(isBypassAccessor) __allowSetGet = false;
var r:Dynamic = callSetter(value);
if(isBypassAccessor) __allowSetGet = true;
return r;
}
private function callGetter():Dynamic {
switch (getter) {
case AGet | ADynamic:
var fName:String = getterFunc;
if (!__allowReadAccess && __allowSetGet) {
if (varExists(fName)) {
return callAccessor(fName);
} else
interp.error(ECustom('Method $fName required by property $name is missing'));
} else {
if ((setter == ADefault || setter == ANull) || isVar) {
return r;
}
else
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
}
case ANever:
interp.error(ECustom('This expression cannot be accessed for reading'));
default:
}
return r;
}
private function callSetter(val:Dynamic):Dynamic {
switch (setter) {
case ASet | ADynamic:
var fName:String = setterFunc;
if (!__allowWriteAccess && __allowSetGet) {
if (varExists(fName))
return callAccessor(fName, true, val);
else
interp.error(ECustom('Method $fName required by property $name is missing'));
} else {
if ((getter == ADefault || getter == ANull) || isVar) {
return r = val;
}
else
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
}
case ANever:
interp.error(ECustom('This expression cannot be accessed for writing'));
default:
}
return r = val;
}
private function callAccessor(f:String, isWrite:Bool = false, ?value:Dynamic):Dynamic {
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
var rt:Dynamic = null;
if (fn != null && Reflect.isFunction(fn)) {
if (isWrite) __allowWriteAccess = true;
else __allowReadAccess = true;
rt = UnsafeReflect.callMethodUnsafe(null, fn, isWrite ? [value] : []);
if (isWrite) __allowWriteAccess = false;
else __allowReadAccess = false;
return rt;
} else
interp.error(ECustom('Method $f required by property ${f.substr(3)} is missing'));
return rt;
}
private inline function varExists(n:String) {
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n);
}
}
+113 -143
View File
@@ -1,144 +1,114 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * Copyright (C)2008-2017 Haxe Foundation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the * and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions: * Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* 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.
*/ */
package hscript; package hscript;
import hscript.Expr; import hscript.Expr;
class Tools { class Tools {
public static function iter( e : Expr, f : Expr -> Void ):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 EImport(c): f(e);
case EClass(_, e, _, _): for( a in e ) f(a); 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);
case EField(e, _): f(e); case EField(e, _): f(e);
case EBinop(_, e1, e2): f(e1); f(e2); case EBinop(_, e1, e2): f(e1); f(e2);
case EUnop(_, _, e): f(e); case EUnop(_, _, e): f(e);
case ECall(e, args): f(e); for( a in args ) f(a); case ECall(e, args): f(e); for( a in args ) f(a);
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2); case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
case EWhile(c, e): f(c); f(e); case EWhile(c, e): f(c); f(e);
case EDoWhile(c, e): f(c); f(e); case EDoWhile(c, e): f(c); f(e);
case EFor(_, it, e): f(it); f(e); case EFor(_, it, e): f(it); f(e);
case EBreak,EContinue: case EBreak,EContinue:
case EFunction(_, e, _, _): f(e); case EFunction(_, e, _, _): f(e);
case EReturn(e): if( e != null ) f(e); case EReturn(e): if( e != null ) f(e);
case EArray(e, i): f(e); f(i); case EArray(e, i): f(e); f(i);
case EArrayDecl(el): for( e in el ) f(e); case EArrayDecl(el): for( e in el ) f(e);
case ENew(_,el): for( e in el ) f(e); case ENew(_,el): for( e in el ) f(e);
case EThrow(e): f(e); case EThrow(e): f(e);
case ETry(e, _, _, c): f(e); f(c); case ETry(e, _, _, c): f(e); f(c);
case EObject(fl): for( fi in fl ) f(fi.e); case EObject(fl): for( fi in fl ) f(fi.e);
case ETernary(c, e1, e2): f(c); f(e1); f(e2); case ETernary(c, e1, e2): f(c); f(e1); f(e2);
case ESwitch(e, cases, def): case ESwitch(e, cases, def):
f(e); f(e);
for( c in cases ) { for( c in cases ) {
for( v in c.values ) f(v); for( v in c.values ) f(v);
f(c.expr); f(c.expr);
} }
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);
default:
} }
} }
public static function map( e : Expr, f : Expr -> Expr ):Expr { public static function map( e : Expr, f : Expr -> Expr ) {
var edef = switch( expr(e) ) { var edef = switch( expr(e) ) {
case EConst(_), EIdent(_), EBreak, EContinue: expr(e); case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate); case EVar(n, t, e): EVar(n, t, if( e != null ) f(e) else null);
case EParent(e): EParent(f(e)); case EParent(e): EParent(f(e));
case EBlock(el): EBlock([for( e in el ) f(e)]); case EBlock(el): EBlock([for( e in el ) f(e)]);
case EField(e, fi): EField(f(e),fi); case EField(e, fi): EField(f(e),fi);
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2)); case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
case EUnop(op, pre, e): EUnop(op, pre, f(e)); case EUnop(op, pre, e): EUnop(op, pre, f(e));
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]); case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null); case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
case EWhile(c, e): EWhile(f(c),f(e)); case EWhile(c, e): EWhile(f(c),f(e));
case EDoWhile(c, e): EDoWhile(f(c),f(e)); case EDoWhile(c, e): EDoWhile(f(c),f(e));
case EFor(v, it, e): EFor(v, f(it), f(e)); case EFor(v, it, e): EFor(v, f(it), f(e));
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate); case EFunction(args, e, name, t): EFunction(args, f(e), name, t);
case EReturn(e): EReturn(if( e != null ) f(e) else null); case EReturn(e): EReturn(if( e != null ) f(e) else null);
case EArray(e, i): EArray(f(e),f(i)); case EArray(e, i): EArray(f(e),f(i));
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]); case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]); case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
case EThrow(e): EThrow(f(e)); case EThrow(e): EThrow(f(e));
case ETry(e, v, t, c): ETry(f(e), v, t, f(c)); case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]); case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2)); case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
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 EImport(c): EImport(c);
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces); case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
default: expr(e); }
} return mk(edef, e);
return mk(edef, e); }
}
public static inline function expr( e : Expr ) : ExprDef {
public static inline function expr( e : Expr ) : ExprDef { #if hscriptPos
#if hscriptPos return e.e;
return e.e; #else
#else return e;
return e; #end
#end }
}
public static inline function mk( e : ExprDef, p : Expr ) {
public static inline function mk( e : ExprDef, p : Expr ):Expr { #if hscriptPos
#if hscriptPos return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line }; #else
#else return e;
return e; #end
#end }
}
/**
* DO NOT USE INLINE ON THIS FUNCTION
**/
public static function argCount(func: haxe.Constraints.Function): Int {
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
#if cpp
return untyped __cpp__("{0}->__ArgCount()", func);
#elseif js
return untyped js.Syntax.code("{0}.length", func);
#elseif hl
var ft = hl.Type.getDynamic(func);
if (ft.kind != HFun)
return -1;
return ft.getArgsCount();
#else
return -1;
#end
}
public static function isUppercase(s:String) {
if(s.length == 0) return false;
var c:Int = StringTools.fastCodeAt(s, 0);
if(StringTools.isEof(c)) return false; // Just in case :3
return c >= 65 && c <= 90; // A-Z
}
public static inline function isCustomAbstract(obj:Dynamic):Bool
return obj != null && obj is IHScriptAbstractBehaviour;
} }
+52 -326
View File
@@ -10,10 +10,10 @@ import haxe.macro.Type.FieldKind;
import haxe.macro.Type.ClassField; import haxe.macro.Type.ClassField;
import haxe.macro.Type.VarAccess; import haxe.macro.Type.VarAccess;
import haxe.macro.*; import haxe.macro.*;
import Sys;
using StringTools; using StringTools;
// BIG TODO: make typed classes scriptable
class ClassExtendMacro { class ClassExtendMacro {
public static inline final FUNC_PREFIX = "_HX_SUPER__"; public static inline final FUNC_PREFIX = "_HX_SUPER__";
public static inline final CLASS_SUFFIX = "_HSX"; public static inline final CLASS_SUFFIX = "_HSX";
@@ -29,7 +29,6 @@ class ClassExtendMacro {
for(apply in Config.ALLOWED_CUSTOM_CLASSES) { for(apply in Config.ALLOWED_CUSTOM_CLASSES) {
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())"); Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())");
} }
//Context.onAfterTyping(buildTyped);
#end #end
#end #end
} }
@@ -61,20 +60,20 @@ class ClassExtendMacro {
if(key == "away3d.tools.commands.SphereMaker") return fields; // Error: Unknown identifier if(key == "away3d.tools.commands.SphereMaker") return fields; // Error: Unknown identifier
if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier
if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined
if(fkey == "hscript.CustomClassHandler.CustomTemplateClass") return fields; // Error: Redefined
if(fkey == "hscript.CustomClass") return fields; // Error: Redefined
if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined
if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields; if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields;
if(cl.module.contains("_")) return fields; // Weird issue, sorry if(cl.module.contains("_")) return fields; // Weird issue, sorry
var superFields = []; var superFields = [];
if(false && cl.superClass != null) { if(cl.superClass != null) {
var _superFields = cl.superClass.t.get().fields.get(); var _superFields = cl.superClass.t.get().fields.get();
_superFields = []; // Comment to enable super support, (broken) _superFields = []; // Comment to enable super support, (broken)
for(field in _superFields) {
if(!field.kind.match(FMethod(_))) // only catch methods
continue;
function convertField(field:ClassField) {
try { try {
var nfield = FixedTypeTools.toSimpleField(field); var nfield = @:privateAccess TypeTools.toField(field);
switch ([field.kind, field.type]) { switch ([field.kind, field.type]) {
case [FMethod(kind), TFun(args, ret)]: case [FMethod(kind), TFun(args, ret)]:
if(kind == MethInline) if(kind == MethInline)
@@ -87,9 +86,9 @@ class ClassExtendMacro {
switch(nfield.kind) { switch(nfield.kind) {
case FFun(fun): case FFun(fun):
if (fun.params != null && fun.params.length > 0) if (fun.params != null && fun.params.length > 0)
return null; continue;
//sfun.ret = Utils.fixStdTypes(fun.ret); fun.ret = Utils.fixStdTypes(fun.ret);
var metas = nfield.meta; var metas = nfield.meta;
var defaultValues:Map<String, Dynamic> = []; var defaultValues:Map<String, Dynamic> = [];
@@ -108,7 +107,7 @@ class ClassExtendMacro {
if(m.name == ":generic") if(m.name == ":generic")
isGeneric = true; isGeneric = true;
} }
if(isGeneric) return null; if(isGeneric) continue;
if(defaultEntry != null) if(defaultEntry != null)
metas.remove(defaultEntry); metas.remove(defaultEntry);
@@ -120,80 +119,20 @@ class ClassExtendMacro {
arg.opt = false; arg.opt = false;
} }
arg.type = null;//Utils.fixStdTypes(arg.type); arg.type = Utils.fixStdTypes(arg.type);
//if(arg.opt) { if(arg.opt) {
// if(arg.type.getParameters()[0].name != "Null") if(arg.type.getParameters()[0].name != "Null")
// arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>}; arg.type = TPath({name: "Null", params: [TPType(arg.type)], pack: []});//macro {Null<Dynamic>};
//} }
} }
trace(nfield.name);
default: default:
} }
return nfield; superFields.push(nfield);
} catch(e) { } catch(e) {
trace(field.name, e);
return null;
} }
} }
var didPrint = false;
var fieldNames = [for(f in fields) f.name];
/*for(field in _superFields) {
if(fieldNames.contains(field.name))
continue;
if(!field.kind.match(FMethod(_))) // only catch methods
continue;
if(field.name.startsWith("get_")) {
var access = FixedTypeTools.getAccess(field);
if(access.contains(AInline) || access.contains(AFinal) || field.isFinal)
continue;
var name = field.name;
superFields.push({
name: field.name,
pos: field.pos,
kind: FFun({
ret: null,
params: [],
expr: macro {
return super.$name();
},
args: []
}),
access: access,
meta: field.meta.get(),
});
//var f = convertField(field);
//if(f != null)
// superFields.push(f);
if(field.name == "get_bgColor") {
if(!didPrint) {
trace(cl.name);
didPrint = true;
}
trace("> " + field.name + " : " + access, field);
}
}
}*/
// want to get this working
/*for(field in _superFields) {
if(fieldNames.contains(field.name))
continue;
if(!field.kind.match(FMethod(_))) // only catch methods
continue;
var f = convertField(field);
if(f != null)
superFields.push(f);
}*/
//superFields = []; //superFields = [];
} }
@@ -213,20 +152,11 @@ class ClassExtendMacro {
continue; continue;
if (f.name == "new") { if (f.name == "new") {
hasNew = true; hasNew = true;
switch (f.kind) {
case FFun(fn):
var constructor:Field = buildConstructor(fn.args);
shadowClass.fields.push(constructor);
definedFields.push(f.name);
default:
continue;
}
continue; continue;
} }
if (f.name.startsWith(FUNC_PREFIX)) if (f.name.startsWith(FUNC_PREFIX))
continue; continue;
if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline) || f.access.contains(AFinal)) if (f.access.contains(ADynamic) || f.access.contains(AStatic) || f.access.contains(AExtern) || f.access.contains(AInline))
continue; continue;
if(f.name == "hget" || f.name == "hset") continue; // sorry, no overwriting the hget and hset in custom classes, yet if(f.name == "hget" || f.name == "hset") continue; // sorry, no overwriting the hget and hset in custom classes, yet
@@ -257,22 +187,21 @@ class ClassExtendMacro {
overrideExpr = macro { overrideExpr = macro {
var name:String = $v{name}; var name:String = $v{name};
if (__interp != null && __class__fields.contains(name)) { if (__interp != null) {
var v:Dynamic = null; var v:Dynamic = null;
if (Reflect.isFunction(v = __interp.variables.get(name))) { if (__interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
return v($a{arguments}); return v($a{arguments});
} }
} }
return super.$name($a{arguments}); return super.$name($a{arguments});
}; };
} else { } else {
overrideExpr = macro { overrideExpr = macro {
var name:String = $v{name}; var name:String = $v{name};
if (__interp != null && __class__fields.contains(name)) { if (__interp != null) {
var v:Dynamic = null; var v:Dynamic = null;
if (Reflect.isFunction(v = __interp.variables.get(name))) { if (__interp != null && __interp.variables.exists(name) && Reflect.isFunction(v = __interp.variables.get(name))) {
v($a{arguments}); v($a{arguments});
return; return;
} }
@@ -339,103 +268,21 @@ class ClassExtendMacro {
pack: cl.pack.copy(), pack: cl.pack.copy(),
name: cl.name name: cl.name
}, [ }, [
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]} {name: "IHScriptCustomBehaviour", pack: ["hscript"]}
], false, true, false); ], false, true, false);
shadowClass.name = '${cl.name}$CLASS_SUFFIX'; shadowClass.name = '${cl.name}$CLASS_SUFFIX';
var imports = Context.getLocalImports().copy(); var imports = Context.getLocalImports().copy();
Utils.setupMetas(shadowClass, imports); Utils.setupMetas(shadowClass, imports);
Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect");
// Adding hscript getters and setters // Adding hscript getters and setters
shadowClass.fields.push({
name: "__cachedFieldSet",
pos: Context.currentPos(),
kind: FVar(macro: Map<String, Dynamic>),
access: [APublic, AStatic]
});
shadowClass.fields.push({ shadowClass.fields.push({
name: "__interp", name: "__interp",
pos: Context.currentPos(), pos: Context.currentPos(),
kind: FVar(macro: hscript.Interp), kind: FVar(TPath({
access: [APublic] pack: ['hscript'],
}); name: 'Interp'
/* }))
shadowClass.fields.push({
name: "__custom__variables",
pos: Context.currentPos(),
kind: FVar(macro: Map<String, Dynamic>),
access: [APublic]
});
*/
shadowClass.fields.push({
name: "__allowSetGet",
pos: Context.currentPos(),
kind: FVar(macro: Bool, macro true),
access: [APublic]
});
shadowClass.fields.push({
name: "__real_fields",
pos: Context.currentPos(),
kind: FVar(macro: Array<String>),
access: [APublic]
});
shadowClass.fields.push({
name: "__class__fields",
pos: Context.currentPos(),
kind: FVar(macro: Array<String>),
access: [APublic]
});
shadowClass.fields.push({
name: "__callGetter",
pos: Context.currentPos(),
kind: FFun({
ret: macro: Dynamic,
params: [],
expr: macro {
return null;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: macro: String
}
]
}),
access: [APublic]
});
shadowClass.fields.push({
name: "__callSetter",
pos: Context.currentPos(),
kind: FFun({
ret: macro: Dynamic,
params: [],
expr: macro {
return null;
},
args: [
{
name: "name",
opt: false,
meta: [],
type: macro: String
},
{
name: "val",
opt: false,
meta: [],
type: macro: Dynamic
}
]
}),
access: [APublic]
}); });
// Todo: make it possible to override // Todo: make it possible to override
@@ -480,120 +327,44 @@ class ClassExtendMacro {
var hgetField = if(hasHgetInSuper) { var hgetField = if(hasHgetInSuper) {
macro { macro {
if (__interp != null) { if(this.__interp.variables.exists("get_" + name))
if(__class__fields.contains(name)) { return this.__interp.variables.get("get_" + name)();
var v:Dynamic = __interp.variables.get(name); if (this.__interp.variables.exists(name))
var ba:Bool = @:privateAccess __interp.isBypassAccessor; return this.__interp.variables.get(name);
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).get(ba);
return v;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.getField(name);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
}
return super.hget(name); return super.hget(name);
} }
} else { } else {
macro { macro {
if (__interp != null) { if(this.__interp.variables.exists("get_" + name))
if(__class__fields.contains(name)) { return this.__interp.variables.get("get_" + name)();
var v:Dynamic = __interp.variables.get(name); if (this.__interp.variables.exists(name))
var ba:Bool = @:privateAccess __interp.isBypassAccessor; return this.__interp.variables.get(name);
if(v != null && v is hscript.Property) return Reflect.getProperty(this, name);
return cast(v, hscript.Property).get(ba);
return v;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.getField(name);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
}
return UnsafeReflect.getProperty(this, name);
} }
} }
var hsetField = if(hasHsetInSuper) { var hsetField = if(hasHsetInSuper) {
macro { macro {
if (__interp != null) { if(this.__interp.variables.exists("set_" + name)) {
if(__class__fields.contains(name)) { return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
var v:Dynamic = __interp.variables.get(name);
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).set(val, ba);
__interp.variables.set(name, val);
return val;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.setField(name, val);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
} }
if (this.__interp.variables.exists(name)) {
if(__real_fields.contains(name)) { this.__interp.variables.set(name, val);
UnsafeReflect.setProperty(this, name, val); return val;
return UnsafeReflect.field(this, name);
} }
return super.hset(name, val); return super.hset(name, val);
} }
} else { } else {
macro { macro {
if (__interp != null) { if(this.__interp.variables.exists("set_" + name)) {
if(__class__fields.contains(name)) { return this.__interp.variables.get("set_" + name)(val); // TODO: Prevent recursion from setting it in the function
var v:Dynamic = __interp.variables.get(name);
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
if(v != null && v is hscript.Property)
return cast(v, hscript.Property).set(val, ba);
__interp.variables.set(name, val);
return val;
}
else @:privateAccess {
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
while(cls != null) {
if(cls.hasField(name))
return cls.setField(name, val);
var prev:hscript.CustomClass = cast cls.__upperClass;
if(prev == null)
break;
cls = prev;
}
}
} }
if (this.__interp.variables.exists(name)) {
if(__real_fields.contains(name)) { this.__interp.variables.set(name, val);
UnsafeReflect.setProperty(this, name, val); return val;
return UnsafeReflect.field(this, name);
} }
//__custom__variables.set(name, val); Reflect.setProperty(this, name, val);
return val; return Reflect.field(this, name);
} }
} }
@@ -606,7 +377,7 @@ class ClassExtendMacro {
pos: Context.currentPos(), pos: Context.currentPos(),
access: hasHsetInSuper ? [AOverride, APublic] : [APublic], access: hasHsetInSuper ? [AOverride, APublic] : [APublic],
kind: FFun({ kind: FFun({
ret: macro: Dynamic, ret: TPath({name: 'Dynamic', pack: []}),
params: [], params: [],
expr: hsetField, expr: hsetField,
args: [ args: [
@@ -614,13 +385,13 @@ class ClassExtendMacro {
name: "name", name: "name",
opt: false, opt: false,
meta: [], meta: [],
type: macro: String type: TPath({name: "String", pack: []})
}, },
{ {
name: "val", name: "val",
opt: false, opt: false,
meta: [], meta: [],
type: macro: Dynamic type: TPath({name: "Dynamic", pack: []})
} }
] ]
}) })
@@ -631,7 +402,7 @@ class ClassExtendMacro {
pos: Context.currentPos(), pos: Context.currentPos(),
access: hasHgetInSuper ? [AOverride, APublic] : [APublic], access: hasHgetInSuper ? [AOverride, APublic] : [APublic],
kind: FFun({ kind: FFun({
ret: macro: Dynamic, ret: TPath({name: 'Dynamic', pack: []}),
params: [], params: [],
expr: hgetField, expr: hgetField,
args: [ args: [
@@ -639,7 +410,7 @@ class ClassExtendMacro {
name: "name", name: "name",
opt: false, opt: false,
meta: [], meta: [],
type: macro: String type: TPath({name: "String", pack: []})
} }
] ]
}) })
@@ -657,51 +428,6 @@ class ClassExtendMacro {
return fields; return fields;
} }
static function buildConstructor(constArgs:Array<FunctionArg>):Field {
var superCallArgs:Array<Expr> = [for (arg in constArgs) macro $i{arg.name}];
return {
name: 'new',
access: [APublic],
pos: Context.currentPos(),
kind: FFun({
args: constArgs,
expr: macro {
// Call the super constructor with appropriate args
super($a{superCallArgs});
if(__cachedFieldSet != null) {
for(k => v in __cachedFieldSet) {
Reflect.setProperty(this, k, v);
}
__cachedFieldSet.clear();
__cachedFieldSet = null;
}
}
}),
};
}
static function buildTyped(modules:Array<haxe.macro.Type.ModuleType>) {
for(m in modules) {
switch(m) {
case TClassDecl(c):
var cl = c.get();
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface)
continue;
if (cl.params.length == 0)
continue;
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC"))
buildTypedClass(cl);
default:
}
}
}
static function buildTypedClass(cl:ClassType) {}
static function buildShadowClass(cl:ClassType) {}
} }
#else #else
class ClassExtendMacro { class ClassExtendMacro {
-529
View File
@@ -1,529 +0,0 @@
package hscript.macros;
/*
* Copyright (C)2005-2019 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
import Type as StdType;
using Lambda;
/**
This class provides some utility methods to work with types. It is
best used through 'using haxe.macro.TypeTools' syntax and then provides
additional methods on haxe.macro.Type instances.
**/
#if hl
@:hlNative("macro")
#end
class FixedTypeTools {
static function nullable(complexType:ComplexType):ComplexType
return macro:Null<$complexType>;
public static function toField(cf:ClassField):Field {
function varAccessToString(va:VarAccess, getOrSet:String):String {
return {
switch (va) {
case AccNormal | AccCtor: "default";
case AccNo: "null";
case AccNever: "never";
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
case AccCall: getOrSet;
case AccInline: "default";
case AccRequire(_, _): "default";
}
}
}
var access = cf.isPublic ? [APublic] : [APrivate];
if (cf.meta.has(":final")) {
access.push(AFinal);
}
if (cf.params.length != 0)
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
return {
name: cf.name,
doc: cf.doc,
access: access,
kind: switch ([cf.kind, cf.type]) {
case [FVar(read, write), ret]:
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
case [FMethod(_), TFun(args, ret)]:
Sys.println("Converting " + cf.name);
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: toComplexType(a.t),
}
],
ret: toComplexType(ret),
expr: null,
});
case [FMethod(_), TLazy(f)]:
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
switch(f()) {
case TFun(args, ret):
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: toComplexType(a.t),
}
],
ret: toComplexType(ret),
expr: null,
});
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
}
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
},
pos: cf.pos,
meta: cf.meta.get(),
}
}
public static function getAccess(cf:ClassField):Array<Access> {
var access = cf.isPublic ? [APublic] : [APrivate];
if (cf.meta.has(":final") || cf.isFinal) {
access.push(AFinal);
}
switch ([cf.kind, cf.type]) {
case [FMethod(kind), TFun(_, _)] | [FMethod(kind), TLazy(_)]:
if(kind == MethInline)
access.push(AInline);
if(kind == MethDynamic)
access.push(ADynamic);
default:
}
return access;
}
public static function toSimpleField(cf:ClassField):Field {
function varAccessToString(va:VarAccess, getOrSet:String):String {
return {
switch (va) {
case AccNormal | AccCtor: "default";
case AccNo: "null";
case AccNever: "never";
case AccResolve: throw "Invalid " + StdType.enumConstructor(cf.type) + " in varAccessToString";
case AccCall: getOrSet;
case AccInline: "default";
case AccRequire(_, _): "default";
}
}
}
var access = cf.isPublic ? [APublic] : [APrivate];
if (cf.meta.has(":final")) {
access.push(AFinal);
}
if (cf.params.length != 0)
throw "Invalid " + StdType.enumConstructor(cf.type) + " has more than 0 params";
return {
name: cf.name,
doc: cf.doc,
access: access,
kind: switch ([cf.kind, cf.type]) {
case [FVar(read, write), ret]:
FProp(varAccessToString(read, "get"), varAccessToString(write, "set"), toComplexType(ret), null);
case [FMethod(_), TFun(args, ret)]:
Sys.println("Converting " + cf.name);
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: null,//toComplexType(a.t),
}
],
ret: null,//toComplexType(ret),
expr: null,
});
case [FMethod(_), TLazy(f)]:
Sys.println("Converting lazy " + cf.name + " in " + cf.pos);
switch(f()) {
case TFun(args, ret):
FFun({
args: [
for (a in args)
{
name: a.name,
opt: a.opt,
type: null,//toComplexType(a.t),
}
],
ret: null,//toComplexType(ret),
expr: null,
});
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
}
default:
throw "Invalid " + StdType.enumConstructor(cf.type) + " when converting to Field , " + cf.kind + ", " + cf.type;
},
pos: cf.pos,
meta: cf.meta.get(),
}
}
/**
Returns a syntax-level type corresponding to Type `t`.
This function is mostly inverse to `ComplexTypeTools.toType`, but may
lose some information on types that do not have a corresponding syntax
version, such as monomorphs. In these cases, the result is null.
If `t` is null, an internal exception is thrown.
**/
public static function toComplexType(type:Null<Type>):Null<ComplexType>
return {
#if macro
Context.toComplexType(type);
#else
switch (type) {
case null:
null;
case TMono(_.get() => t):
t == null ? null : toComplexType(t);
case TEnum(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
case TInst(_.get() => classType, params):
switch (classType.kind) {
case KTypeParameter(_):
TPath({
name: classType.name,
pack: [],
});
default:
TPath(toTypePath(classType, params));
}
case TType(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
case TFun(args, ret):
TFunction([for (a in args) a.opt ? nullable(toComplexType(a.t)) : toComplexType(a.t)], toComplexType(ret));
case TAnonymous(_.get() => {fields: fields}):
TAnonymous([for (cf in fields) toField(cf)]);
case TDynamic(t):
if (t == null) {
macro:Dynamic;
} else {
var ct = toComplexType(t);
macro:Dynamic<$ct>;
}
case TLazy(f):
toComplexType(f());
case TAbstract(_.get() => baseType, params):
TPath(toTypePath(baseType, params));
default:
throw "Invalid type";
}
#end
}
static function toTypeParam(type:Type):TypeParam
return {
switch (type) {
case TInst(_.get() => {kind: KExpr(e)}, _): TPExpr(e);
case _: TPType(toComplexType(type));
}
}
static function toTypePath(baseType:BaseType, params:Array<Type>):TypePath
return {
var module = baseType.module;
{
pack: baseType.pack,
name: module.substring(module.lastIndexOf(".") + 1),
sub: baseType.name,
params: [for (t in params) toTypeParam(t)],
}
}
#if macro
/**
Follows all typedefs of `t` to reach the actual type.
If `once` is true, this function does not call itself recursively,
otherwise it does. This can be useful in cases where intermediate
typedefs might be of interest.
Affected types are monomorphs `TMono` and typedefs `TType(t,pl)`.
If `t` is null, an internal exception is thrown.
Usage example with monomorphs:
var t = Context.typeof(macro null); // TMono(<mono>)
var ts = Context.typeof(macro "foo"); //TInst(String,[])
Context.unify(t, ts);
trace(t); // TMono(<mono>)
trace(t.follow()); //TInst(String,[])
Usage example with typedefs:
var t = Context.typeof(macro ("foo" :MyString)); // typedef MyString = String
trace(t); // TType(MyString,[])
trace(t.follow()); //TInst(String,[])
**/
static public inline function follow(t:Type, ?once:Bool):Type
return Context.follow(t, once);
/**
Like `follow`, follows all typedefs of `t` to reach the actual type.
Will however follow also abstracts to their underlying implementation,
if they are not a @:coreType abstract
If `t` is null, an internal exception is thrown.
Usage example:
var t = Context.typeof(macro new Map<String, String>());
trace(t); // TAbstract(Map,[TInst(String,[]),TInst(String,[])])
trace(t.followWithAbstracts()); // TInst(haxe.ds.StringMap, [TInst(String,[])])
**/
static public inline function followWithAbstracts(t:Type, once:Bool = false):Type
return Context.followWithAbstracts(t, once);
/**
Returns true if `t1` and `t2` unify, false otherwise.
**/
static public inline function unify(t1:Type, t2:Type):Bool
return Context.unify(t1, t2);
/**
Tries to extract the class instance stored inside `t`.
If `t` is a class instance `TInst(c,pl)`, c is returned.
If `t` is of a different type, an exception of type String is thrown.
If `t` is null, the result is null.
**/
static public function getClass(t:Type)
return t == null ? null : switch (follow(t)) {
case TInst(c, _): c.get();
case _: throw "Class instance expected";
}
/**
Tries to extract the enum instance stored inside `t`.
If `t` is an enum instance `TEnum(e,pl)`, e is returned.
If `t` is of a different type, an exception of type String is thrown.
If `t` is null, the result is null.
**/
static public function getEnum(t:Type)
return t == null ? null : switch (follow(t)) {
case TEnum(e, _): e.get();
case _: throw "Enum instance expected";
}
/**
Applies the type parameters `typeParameters` to type `t` with the given
types `concreteTypes`.
This function replaces occurrences of type parameters in `t` if they are
part of `typeParameters`. The array index of such a type parameter is
then used to lookup the concrete type in `concreteTypes`.
If `typeParameters.length` is not equal to `concreteTypes.length`, an
exception of type `String` is thrown.
If `typeParameters.length` is 0, `t` is returned unchanged.
If either argument is `null`, the result is unspecified.
**/
static public function applyTypeParameters(t:Type, typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>):Type {
if (typeParameters.length != concreteTypes.length)
throw 'Incompatible arguments: ${typeParameters.length} type parameters and ${concreteTypes.length} concrete types';
else if (typeParameters.length == 0)
return t;
#if (neko || eval)
return @:privateAccess Context.load("apply_params", 3)(typeParameters, concreteTypes, t);
#else
return applyParams(typeParameters, concreteTypes, t);
#end
}
#if !neko
private static function applyParams(typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>, t:Type):Type {
return null;
}
#end
/**
Transforms `t` by calling `f` on each of its subtypes.
If `t` is a compound type, `f` is called on each of its components.
Otherwise `t` is returned unchanged.
The following types are considered compound:
- TInst, TEnum, TType and TAbstract with type parameters
- TFun
- TAnonymous
If `t` or `f` are null, the result is unspecified.
**/
static public function map(t:Type, f:Type->Type):Type {
return switch (t) {
case TMono(tm):
switch (tm.get()) {
case null: t;
case var t: f(t);
}
case TEnum(_, []) | TInst(_, []) | TType(_, []):
t;
case TEnum(en, tl):
TEnum(en, tl.map(f));
case TInst(cl, tl):
TInst(cl, tl.map(f));
case TType(t2, tl):
TType(t2, tl.map(f));
case TAbstract(a, tl):
TAbstract(a, tl.map(f));
case TFun(args, ret):
TFun(args.map(function(arg) return {
name: arg.name,
opt: arg.opt,
t: f(arg.t)
}), f(ret));
case TAnonymous(an):
TAnonymous(@:privateAccess Context.load("map_anon_ref", 2)(an, f));
case TDynamic(t2):
t == t2 ? t : TDynamic(f(t2));
case TLazy(ft):
var ft = ft();
var ft2 = f(ft);
ft == ft2 ? t : ft2;
}
}
/**
Calls function `f` on each component of type `t`.
If `t` is not a compound type, this operation has no effect.
The following types are considered compound:
- TInst, TEnum, TType and TAbstract with type parameters
- TFun
- TAnonymous
If `t` or `f` are null, the result is unspecified.
**/
static public function iter(t:Type, f:Type->Void):Void {
switch (t) {
case TMono(tm):
var t = tm.get();
if (t != null)
f(t);
case TEnum(_, tl) | TInst(_, tl) | TType(_, tl) | TAbstract(_, tl):
for (t in tl)
f(t);
case TDynamic(t2):
if (t != t2)
f(t2);
case TLazy(ft):
f(ft());
case TAnonymous(an):
for (field in an.get().fields)
f(field.type);
case TFun(args, ret):
for (arg in args)
f(arg.t);
f(ret);
}
}
/**
Converts type `t` to a human-readable String representation.
**/
static public function toString(t:Type):String {
#if (neko || eval)
return @:privateAccess Context.load("s_type", 1)(t);
#else
return null;
#end
}
/**
Changes the name of the variable in the typed expression.
**/
static public function setVarName(t:TVar, name:String) {
@:privateAccess Context.load("set_var_name", 2)(t, name);
}
/**
Converts type `t` to `ModuleType`.
**/
static public function toModuleType(t:Type):ModuleType {
#if (neko || eval)
return @:privateAccess Context.load("type_to_module_type", 1)(t);
#else
return null;
#end
}
/**
Creates a type from the `ModuleType` argument.
**/
static public function fromModuleType(mt:ModuleType):Type {
#if (neko || eval)
return @:privateAccess Context.load("module_type_to_type", 1)(mt);
#else
return null;
#end
}
#end
/**
Resolves the field named `name` on class `c`.
If `isStatic` is true, the classes' static fields are checked. Otherwise
the classes' member fields are checked.
If the field is found, it is returned. Otherwise if `c` has a super
class, `findField` recursively checks that super class. Otherwise null
is returned.
If any argument is null, the result is unspecified.
**/
static public function findField(c:ClassType, name:String, isStatic:Bool = false):Null<ClassField> {
var field = (isStatic ? c.statics : c.fields).get().find(function(field) return field.name == name);
return if (field != null) field; else if (c.superClass != null) findField(c.superClass.t.get(), name, isStatic); else null;
}
}
@@ -10,16 +10,14 @@ import haxe.macro.Compiler;
using StringTools; using StringTools;
class AbstractHandler { class UsingHandler {
public static function init() { public static function init() {
#if HSCRIPT_ABSTRACT_SUPPORT
#if !display #if !display
if(Context.defined("display")) return; if(Context.defined("display")) return;
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) { for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())'); Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.UsingHandler.build())');
} }
#end #end
#end
} }
public static function build():Array<Field> { public static function build():Array<Field> {
-184
View File
@@ -1,184 +0,0 @@
package hscript.utils;
#if cpp
import cpp.ObjectType;
#end
@:analyzer(ignore)
class UnsafeReflect {
public #if !cpp inline #end static function hasField(o:Dynamic, field:String):Bool {
#if cpp
untyped {
return o.__HasField(field);
}
#else
return Reflect.hasField(o, field);
#end
}
public #if !cpp inline #end static function field(o:Dynamic, field:String):Dynamic {
#if cpp
untyped {
return o.__Field(field, untyped __cpp__("::hx::paccNever"));
}
#else
return Reflect.field(o, field);
#end
}
public #if !cpp inline #end static function setField(o:Dynamic, field:String, value:Dynamic):Void {
#if cpp
untyped {
o.__SetField(field, value, untyped __cpp__("::hx::paccNever"));
}
#else
return Reflect.setField(o, field, value);
#end
}
public #if !cpp inline #end static function getProperty(o:Dynamic, field:String):Dynamic {
#if cpp
untyped {
return o.__Field(field, untyped __cpp__("::hx::paccAlways"));
}
#else
return Reflect.getProperty(o, field);
#end
}
public #if !cpp inline #end static function setProperty(o:Dynamic, field:String, value:Dynamic):Void {
#if cpp
untyped {
o.__SetField(field, value, untyped __cpp__("::hx::paccAlways"));
}
#else
Reflect.setProperty(o, field, value);
#end
}
public #if !cpp inline #end static function callFieldUnsafe(o:Dynamic, field:String, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
var func:Dynamic = o.__Field(field, untyped __cpp__("::hx::paccDynamic"));
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, Reflect.field(o, field), args);
#end
}
public inline static function callMethod(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
return Reflect.callMethod(o, func, args);
}
public #if !cpp inline #end static function callMethodSafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
if (func == null)
throw cpp.ErrorConstants.nullFunctionPointer;
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public #if !cpp inline #end static function callMethodUnsafe(o:Dynamic, func:haxe.Constraints.Function, args:Array<Dynamic>):Dynamic {
#if cpp
untyped {
untyped func.__SetThis(o);
return untyped func.__Run(args);
}
#else
return Reflect.callMethod(o, func, args);
#end
}
public inline static function fields(o:Dynamic):Array<String>
return Reflect.fields(o);
/*untyped {
if (o == null)
return new Array();
var a:Array<String> = [];
o.__GetFields(a);
return a;
}*/
public #if !cpp inline #end static function isFunction(f:Dynamic):Bool
#if cpp
untyped {
return f.__GetType() == ObjectType.vtFunction;
}
#else
return Reflect.isFunction(f);
#end
public inline static function compare<T>(a:T, b:T):Int {
return Reflect.compare(a, b);
//return (a == b) ? 0 : (((a : Dynamic) > (b : Dynamic)) ? 1 : -1);
}
public inline static function compareMethods(f1:Dynamic, f2:Dynamic):Bool {
return Reflect.compareMethods(f1, f2);
}
public #if !cpp inline #end static function isObject(v:Dynamic):Bool {
#if cpp
untyped {
var t:Int = v.__GetType();
return t == ObjectType.vtObject || t == ObjectType.vtClass || t == ObjectType.vtString || t == ObjectType.vtArray;
}
#else
return Reflect.isObject(v);
#end
}
public #if !cpp inline #end static function isEnumValue(v:Dynamic):Bool {
#if cpp
untyped {
return v.__GetType() == ObjectType.vtEnum;
}
#else
return Reflect.isEnumValue(v);
#end
}
public #if !cpp inline #end static function deleteField(o:Dynamic, field:String):Bool {
#if cpp
untyped {
return untyped __global__.__hxcpp_anon_remove(o, field);
}
#else
return Reflect.deleteField(o, field);
#end
}
public #if !cpp inline #end static function copy<T>(o:Null<T>):Null<T> {
#if cpp
if (o == null)
return null;
var t:Int = untyped o.__GetType();
if (t == ObjectType.vtString)
return o;
if (t == ObjectType.vtArray)
return untyped o.__Field("copy", untyped __cpp__("::hx::paccDynamic"))();
var o2:Dynamic = {};
for (f in UnsafeReflect.fields(o))
UnsafeReflect.setField(o2, f, UnsafeReflect.field(o, f));
return o2;
#else
return Reflect.copy(o);
#end
}
@:overload(function(f:Array<Dynamic>->Void):Dynamic {})
public static function makeVarArgs(f:Array<Dynamic>->Dynamic):Dynamic {
#if cpp
return untyped __global__.__hxcpp_create_var_args(f);
#else
return inline Reflect.makeVarArgs(f);
#end
}
}
-82
View File
@@ -1,82 +0,0 @@
package hscript.utils;
@:structInit
class UsingEntry {
public var call:Dynamic->String->Array<Dynamic>->Dynamic;
public var fields:Array<String>;
public function hasField(name:String) {
return fields.contains(name);
}
}
/**
* Special class that handles static extension function calls.
*
* A static extension allows pseudo-extending
* existing types without modifying their source.
* In Haxe this is achieved by declaring a static method with a first argument
* of the extending type and then bringing the defining class into context through `using`.
*
* Example:
* ```haxe
* class IntExtender {
* static public function triple(i:Int) {
* return i * 3;
* }
* }
*
* using IntExtender;
*
* trace(12.triple()); // 36
* ```
*
* @see https://haxe.org/manual/lf-static-extension.html
*/
class UsingHandler {
// Predefined static extension classes
public static final defaultExtension:Map<String, UsingEntry> = [
"StringTools" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L45
fields: Type.getClassFields(StringTools),
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
if (f == "isEof") // has @:noUsing
return null;
return switch (Type.typeof(o)) {
case TInt if (f == 'hex'):
StringTools.hex(o, args[0]);
case TClass(String):
var field = UnsafeReflect.field(StringTools, f);
if (UnsafeReflect.isFunction(field)) UnsafeReflect.callMethodUnsafe(StringTools, field, [o].concat(args)); else null;
default:
null;
}
}
},
"Lambda" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L62
fields: Type.getClassFields(Lambda),
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
if (o != null && o.iterator != null) {
var field = UnsafeReflect.field(Lambda, f);
if (UnsafeReflect.isFunction(field)) {
return UnsafeReflect.callMethodUnsafe(Lambda, field, [o].concat(args));
}
}
return null;
}
}
];
@:allow(hscript.CustomClass)
@:allow(hscript.CustomClassHandler)
public var usingEntries(default, null):Map<String, UsingEntry> = [];
public function new() {}
public function registerEntry(name:String, entry:Dynamic->String->Array<Dynamic>->Dynamic, fields:Array<String>) {
usingEntries.set(name, {call: entry, fields: fields});
}
public inline function entryExists(name:String):Bool {
return usingEntries.exists(name);
}
}