Compare commits
40
Commits
@@ -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/CodenameCrew/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.
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ class TestHScript extends TestCase {
|
|||||||
assertScript("- 123",-123);
|
assertScript("- 123",-123);
|
||||||
assertScript("1.546",1.546);
|
assertScript("1.546",1.546);
|
||||||
assertScript(".545",.545);
|
assertScript(".545",.545);
|
||||||
|
assertScript("1e5",100000);
|
||||||
|
assertScript("1.2e2",120);
|
||||||
|
assertScript("100e-2",1);
|
||||||
|
assertScript("1.2e-1",0.12);
|
||||||
assertScript("'bla'","bla");
|
assertScript("'bla'","bla");
|
||||||
assertScript("null",null);
|
assertScript("null",null);
|
||||||
assertScript("true",true);
|
assertScript("true",true);
|
||||||
@@ -53,6 +57,7 @@ class TestHScript extends TestCase {
|
|||||||
assertScript("3 * 2 // + 5 \n + 6",12);
|
assertScript("3 * 2 // + 5 \n + 6",12);
|
||||||
assertScript("3 /* 2\n */ + 5",8);
|
assertScript("3 /* 2\n */ + 5",8);
|
||||||
assertScript("[55,66,77][1]",66);
|
assertScript("[55,66,77][1]",66);
|
||||||
|
assertScript("[11,22,33,][2]", 33);
|
||||||
assertScript("var a = [55]; a[0] *= 2; a[0]",110);
|
assertScript("var a = [55]; a[0] *= 2; a[0]",110);
|
||||||
assertScript("x",55,{ x : 55 });
|
assertScript("x",55,{ x : 55 });
|
||||||
assertScript("var y = 33; y",33);
|
assertScript("var y = 33; y",33);
|
||||||
|
|||||||
@@ -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,3 +1,4 @@
|
|||||||
--macro keep('IntIterator')
|
--macro keep('IntIterator')
|
||||||
--macro hscript.macros.AbstractHandler.init()
|
--macro hscript.macros.AbstractHandler.init()
|
||||||
|
--macro hscript.macros.UsingMacro.init()
|
||||||
--macro hscript.macros.ClassExtendMacro.init()
|
--macro hscript.macros.ClassExtendMacro.init()
|
||||||
|
|||||||
+1
-1
@@ -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
File diff suppressed because it is too large
Load Diff
+8
-9
@@ -124,17 +124,16 @@ class Bytes {
|
|||||||
#end
|
#end
|
||||||
bout.addByte(Type.enumIndex(e));
|
bout.addByte(Type.enumIndex(e));
|
||||||
switch( e ) {
|
switch( e ) {
|
||||||
case EPackage(n):
|
case EIgnore(_):
|
||||||
// TODO
|
|
||||||
case EImport(c):
|
case EImport(c):
|
||||||
// TODO
|
// TODO
|
||||||
case EClass(_, _, _, _):
|
case EClass(_, _, _, _):
|
||||||
// TODO
|
// TODO
|
||||||
case EEnum(en):
|
case ERedirect(_, _):
|
||||||
// TODO
|
// TODO
|
||||||
case ECast(e, _):
|
case EUsing(name):
|
||||||
// TODO
|
// TODO
|
||||||
case ERegex(e, f):
|
case EEnum(name, fields):
|
||||||
// TODO
|
// TODO
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
doEncodeConst(c);
|
doEncodeConst(c);
|
||||||
@@ -156,11 +155,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):
|
||||||
@@ -278,11 +277,11 @@ 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:
|
||||||
|
|||||||
+16
-33
@@ -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);
|
||||||
|
|||||||
+7
-3
@@ -12,6 +12,11 @@ class Config {
|
|||||||
"openfl.display.BlendMode",
|
"openfl.display.BlendMode",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Runs support for using in specific classes.
|
||||||
|
public static final ALLOWED_USING = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
// Incase any of your files fail
|
// Incase any of your files fail
|
||||||
// These are the module names
|
// These are the module names
|
||||||
public static final DISALLOW_CUSTOM_CLASSES = [
|
public static final DISALLOW_CUSTOM_CLASSES = [
|
||||||
@@ -22,8 +27,7 @@ class Config {
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
@:unreflective
|
public static final DISALLOW_USING = [
|
||||||
public static final IMPORT_BLACKLIST:Array<String> = [
|
|
||||||
// "flixel.FlxG"
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
+179
-118
@@ -1,163 +1,219 @@
|
|||||||
package hscript;
|
package hscript;
|
||||||
|
|
||||||
/**
|
import hscript.Interp.DeclaredVar;
|
||||||
* Provides handlers for static custom class fields and instantiation.
|
import hscript.utils.UnsafeReflect;
|
||||||
*/
|
using StringTools;
|
||||||
@:access(hscript.Property)
|
|
||||||
class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{
|
@:deprecated('Switch to new Custom Class instead')
|
||||||
|
class CustomClassHandler implements IHScriptCustomConstructor {
|
||||||
|
public static var staticHandler = new StaticHandler();
|
||||||
|
|
||||||
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 var cl:Class<Dynamic>;
|
||||||
|
|
||||||
private var __interp:Interp;
|
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
|
||||||
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) {
|
//this.cl = extend == null ? CustomTemplateClass : Type.resolveClass('${extend}_HSX');
|
||||||
if(ogInterp.customClasses.exists(extend)) {
|
if(cl == null)
|
||||||
var customCls:CustomClassHandler = ogInterp.customClasses.get(extend);
|
ogInterp.error(EInvalidClass(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() {
|
// TODO: clean this up, it sucks, i hate it
|
||||||
__interp = new Interp();
|
// TODO: make static vars work correctly
|
||||||
__interp.errorHandler = ogInterp.errorHandler;
|
var interp = new Interp();
|
||||||
__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 _class:IHScriptCustomClassBehaviour = Type.createInstance(cl, args);
|
||||||
if(!__interp.variables.exists(f))
|
|
||||||
__interp.variables.set(f, v);
|
|
||||||
|
|
||||||
for(i => e in fields.copy()) {
|
//var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
|
||||||
var isValid:Bool = false;
|
//var capturedLocals:Map<String, DeclaredVar> = [];
|
||||||
var staticField:Bool = false;
|
//for(k=>e in __capturedLocals)
|
||||||
var fieldName:String = null;
|
// if (e != null && e.depth <= 0)
|
||||||
switch (Tools.expr(e)) {
|
// capturedLocals.set(k, e);
|
||||||
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
|
|
||||||
isValid = true;
|
|
||||||
staticField = isStatic;
|
|
||||||
fieldName = n;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if(staticField && isValid) {
|
var disallowCopy = Type.getInstanceFields(cl);
|
||||||
__interp.exprReturn(e);
|
|
||||||
__staticFields.push(fieldName);
|
_class.__real_fields = disallowCopy;
|
||||||
fields.remove(e);
|
|
||||||
|
// todo: make it so you can use variables from the same scope as where the class was defined
|
||||||
|
|
||||||
|
//for (key => value in capturedLocals) {
|
||||||
|
// if(!disallowCopy.contains(key)) {
|
||||||
|
// interp.locals.set(key, {r: value, depth: -1});
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
for (key => value in ogInterp.variables) {
|
||||||
|
if(!disallowCopy.contains(key)) {
|
||||||
|
interp.variables.set(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for(key => value in ogInterp.customClasses) {
|
||||||
|
if(!disallowCopy.contains(key)) {
|
||||||
public function hnew(args:Array<Dynamic>):Dynamic
|
interp.customClasses.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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// todo: clone static vars, but make it so setting it only sets it on the class
|
||||||
if(hasField(name)) {
|
// todo: clone public vars
|
||||||
return getField(name);
|
|
||||||
}
|
|
||||||
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hset(name:String, val:Dynamic):Dynamic {
|
//trace("Before: " + [for(key => value in interp.variables) key]);
|
||||||
if(hasField(name))
|
|
||||||
return setField(name, val);
|
|
||||||
|
|
||||||
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
interp.variables.set("super", staticHandler);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// UNUSED
|
var comparisonMap:Map<String, Dynamic> = [];
|
||||||
public function __callGetter(name:String):Dynamic {
|
for(key => value in interp.variables) {
|
||||||
return null;
|
comparisonMap.set(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
//_class.__custom__variables = interp.variables;
|
||||||
return null;
|
|
||||||
|
//trace(fields);
|
||||||
|
for(expr in fields) {
|
||||||
|
@:privateAccess
|
||||||
|
interp.exprReturn(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//trace("After: " + [for(key => value in interp.variables) key]);
|
||||||
|
|
||||||
|
// get only variables that were not set before
|
||||||
|
var classVariables = [
|
||||||
|
for(key => value in interp.variables)
|
||||||
|
if(!comparisonMap.exists(key) || comparisonMap[key] != value)
|
||||||
|
key => value
|
||||||
|
];
|
||||||
|
//for(variable => value in classVariables) {
|
||||||
|
// if(variable == "this" || variable == "super" || variable == "new") continue;
|
||||||
|
// @:privateAccess
|
||||||
|
// if(!interp.__instanceFields.contains(variable)) {
|
||||||
|
// interp.__instanceFields.push(variable);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//_class.__class__fields = [for(key => value in classVariables) key];
|
||||||
|
|
||||||
|
//trace(_class.__class__fields);
|
||||||
|
//@:privateAccess
|
||||||
|
//trace(interp.__instanceFields);
|
||||||
|
|
||||||
|
//_class.__interp = interp;
|
||||||
|
//_class.__allowSetGet = false;
|
||||||
|
interp.scriptObject = _class;
|
||||||
|
|
||||||
|
for(variable => value in interp.variables) {
|
||||||
|
if(variable == "this" || variable == "super" || variable == "new") continue;
|
||||||
|
|
||||||
|
if(variable.startsWith("set_") || variable.startsWith("get_")) {
|
||||||
|
//_class.__allowSetGet = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newFunc = interp.variables.get("new");
|
||||||
|
if(newFunc != null) {
|
||||||
|
var comparisonMap:Map<String, Dynamic> = [];
|
||||||
|
for(key => value in interp.variables) {
|
||||||
|
comparisonMap.set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnsafeReflect.callMethodUnsafe(null, newFunc, args);
|
||||||
|
|
||||||
|
// get only variables that were not set before
|
||||||
|
var classVariables = [
|
||||||
|
for(key => value in interp.variables)
|
||||||
|
if(!comparisonMap.exists(key) || comparisonMap[key] != value)
|
||||||
|
key => value
|
||||||
|
];
|
||||||
|
for(variable => value in classVariables) {
|
||||||
|
if(variable == "this" || variable == "super" || variable == "new") continue;
|
||||||
|
@:privateAccess
|
||||||
|
if(!interp.__instanceFields.contains(variable)) {
|
||||||
|
interp.__instanceFields.push(variable);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if(!_class.__class__fields.contains(variable)) {
|
||||||
|
_class.__class__fields.push(variable);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return _class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toString():String {
|
public function toString():String {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
class CustomTemplateClass implements IHScriptCustomClassBehaviour implements IHScriptCustomAccessBehaviour {
|
||||||
|
public var __interp:Interp;
|
||||||
|
public var __customClass:hscript.customclass.CustomClass;
|
||||||
|
public var __allowSetGet:Bool = true;
|
||||||
|
public var __custom__variables:Map<String, Dynamic>;
|
||||||
|
public var __real_fields:Array<String>;
|
||||||
|
public var __class__fields:Array<String>;
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||||
|
return __callSetter(name, val);
|
||||||
|
if (__custom__variables.exists(name)) {
|
||||||
|
__custom__variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
if(__real_fields.contains(name)) {
|
||||||
|
UnsafeReflect.setProperty(this, name, val);
|
||||||
|
return UnsafeReflect.field(this, name);
|
||||||
|
}
|
||||||
|
__custom__variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||||
|
return __callGetter(name);
|
||||||
|
if (__custom__variables.exists(name))
|
||||||
|
return __custom__variables.get(name);
|
||||||
|
|
||||||
|
return UnsafeReflect.getProperty(this, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callGetter(name:String):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var v = __custom__variables.get("get_" + name)();
|
||||||
|
__allowSetGet = true;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var v = __custom__variables.get("set_" + name)(val);
|
||||||
|
__allowSetGet = true;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is for backwards compatibility with old hscript-improved, since some scripts use it
|
* This is for backwards compatibility with old hscript-improved, since some scripts use it
|
||||||
**/
|
*/
|
||||||
@:dox(hide)
|
@:dox(hide)
|
||||||
@:keep
|
@:keep
|
||||||
class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustomAccessBehaviour {
|
class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustomAccessBehaviour {
|
||||||
public var __interp:Interp;
|
public var __interp:Interp;
|
||||||
public var __allowSetGet:Bool = true;
|
public var __allowSetGet:Bool = true;
|
||||||
|
public var __allowPrivateAccess:Bool = true;
|
||||||
|
|
||||||
public function hset(name:String, val:Dynamic):Dynamic {
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
var variables = __interp.variables;
|
var variables = __interp.variables;
|
||||||
@@ -187,3 +243,8 @@ class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustom
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
final class StaticHandler {
|
||||||
|
public function new() {}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|||||||
+245
-403
@@ -1,403 +1,245 @@
|
|||||||
/*
|
/*
|
||||||
* 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;
|
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||||
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||||
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||||
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||||
|
|
||||||
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||||
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||||
|
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||||
enum abstract Binop(Int) from Int to Int {
|
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||||
var OpAdd = 0;
|
|
||||||
var OpSub = 1;
|
enum Const {
|
||||||
var OpMult = 2;
|
CInt( v : Int );
|
||||||
var OpDiv = 3;
|
CFloat( f : Float );
|
||||||
var OpMod = 4;
|
CString( s : String );
|
||||||
var OpAnd = 5;
|
}
|
||||||
var OpOr = 6;
|
|
||||||
var OpXor = 7;
|
#if hscriptPos
|
||||||
var OpShl = 8;
|
@:structInit
|
||||||
var OpShr = 9;
|
final class Expr {
|
||||||
var OpUshr = 10;
|
public var e : ExprDef;
|
||||||
var OpEq = 11;
|
public var pmin : Int;
|
||||||
var OpNeq = 12;
|
public var pmax : Int;
|
||||||
var OpGte = 13;
|
public var origin : String;
|
||||||
var OpLte = 14;
|
public var line : Int;
|
||||||
var OpGt = 15;
|
}
|
||||||
var OpLt = 16;
|
enum ExprDef {
|
||||||
var OpBoolOr = 17;
|
#else
|
||||||
var OpBoolAnd = 18;
|
typedef ExprDef = Expr;
|
||||||
var OpIs = 19;
|
enum Expr {
|
||||||
var OpAssign = 20;
|
#end
|
||||||
var OpNcoal = 21;
|
EIgnore(skip:Bool);
|
||||||
var OpInterval = 22;
|
EConst( c : Const );
|
||||||
var OpArrow = 23;
|
EIdent( v : String );
|
||||||
var OpAddAssign = 24;
|
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess );
|
||||||
var OpSubAssign = 25;
|
EParent( e : Expr );
|
||||||
var OpMultAssign = 26;
|
EBlock( e : Array<Expr> );
|
||||||
var OpDivAssign = 27;
|
EField( e : Expr, f : String , ?safe : Bool );
|
||||||
var OpModAssign = 28;
|
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||||
var OpAndAssign = 29;
|
EUnop( op : String, prefix : Bool, e : Expr );
|
||||||
var OpOrAssign = 30;
|
ECall( e : Expr, params : Array<Expr> );
|
||||||
var OpXorAssign = 31;
|
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||||
var OpShlAssign = 32;
|
EWhile( cond : Expr, e : Expr );
|
||||||
var OpShrAssign = 33;
|
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||||
var OpUshrAssign = 34;
|
EBreak;
|
||||||
var OpNcoalAssign = 35;
|
EContinue;
|
||||||
var OpArrowFn = 36;
|
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 );
|
||||||
public static inline function fromString(s:String):Binop {
|
EArray( e : Expr, index : Expr );
|
||||||
return switch(s) {
|
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||||
case "+": OpAdd;
|
ENew( cl : String, params : Array<Expr> );
|
||||||
case "-": OpSub;
|
EThrow( e : Expr );
|
||||||
case "*": OpMult;
|
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||||
case "/": OpDiv;
|
EObject( fl : Array<ObjectField> );
|
||||||
case "%": OpMod;
|
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||||
case "&": OpAnd;
|
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||||
case "|": OpOr;
|
EDoWhile( cond : Expr, e : Expr);
|
||||||
case "^": OpXor;
|
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||||
case "<<": OpShl;
|
ECheckType( e : Expr, t : CType );
|
||||||
case ">>": OpShr;
|
|
||||||
case ">>>": OpUshr;
|
EImport( c : String, ?asname:String );
|
||||||
case "==": OpEq;
|
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||||
case "!=": OpNeq;
|
ERedirect( name:String, className:String, ?cl:Class<Dynamic> );
|
||||||
case ">=": OpGte;
|
EUsing(name:String);
|
||||||
case "<=": OpLte;
|
EEnum(name:String, fields:Array<EnumType>);
|
||||||
case ">": OpGt;
|
}
|
||||||
case "<": OpLt;
|
|
||||||
case "||": OpBoolOr;
|
@:structInit
|
||||||
case "&&": OpBoolAnd;
|
final class ObjectField {
|
||||||
case "is": OpIs;
|
public var name : String;
|
||||||
case "=": OpAssign;
|
public var e : Expr;
|
||||||
case "??": OpNcoal;
|
}
|
||||||
case "...": OpInterval;
|
|
||||||
case "->": OpArrow;
|
@:structInit
|
||||||
case "=>": OpArrowFn;
|
final class SwitchCase {
|
||||||
case "+=": OpAddAssign;
|
public var values : Array<Expr>;
|
||||||
case "-=": OpSubAssign;
|
public var expr : Expr;
|
||||||
case "*=": OpMultAssign;
|
}
|
||||||
case "/=": OpDivAssign;
|
|
||||||
case "%=": OpModAssign;
|
@:structInit
|
||||||
case "&=": OpAndAssign;
|
final class Argument {
|
||||||
case "|=": OpOrAssign;
|
public var name : String;
|
||||||
case "^=": OpXorAssign;
|
public var t : CType;
|
||||||
case "<<=": OpShlAssign;
|
public var opt : Bool;
|
||||||
case ">>=": OpShrAssign;
|
public var value : Expr;
|
||||||
case ">>>=": OpUshrAssign;
|
}
|
||||||
case _ if (s == "??" + "="): OpNcoalAssign;
|
|
||||||
default: -1;
|
@:structInit
|
||||||
}
|
final class MetadataEntry {
|
||||||
}
|
public var name : String;
|
||||||
|
public var params : Array<Expr>;
|
||||||
public inline function toString():String {
|
}
|
||||||
return switch(this) {
|
|
||||||
case OpAdd: "+";
|
typedef Metadata = Array<MetadataEntry>;
|
||||||
case OpSub: "-";
|
|
||||||
case OpMult: "*";
|
enum CType {
|
||||||
case OpDiv: "/";
|
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||||
case OpMod: "%";
|
CTFun( args : Array<CType>, ret : CType );
|
||||||
case OpAnd: "&";
|
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||||
case OpOr: "|";
|
CTParent( t : CType );
|
||||||
case OpXor: "^";
|
CTOpt( t : CType );
|
||||||
case OpShl: "<<";
|
CTNamed( n : String, t : CType );
|
||||||
case OpShr: ">>";
|
}
|
||||||
case OpUshr: ">>>";
|
|
||||||
case OpEq: "==";
|
#if hscriptPos
|
||||||
case OpNeq: "!=";
|
class Error {
|
||||||
case OpGte: ">=";
|
public var e : ErrorDef;
|
||||||
case OpLte: "<=";
|
public var pmin : Int;
|
||||||
case OpGt: ">";
|
public var pmax : Int;
|
||||||
case OpLt: "<";
|
public var origin : String;
|
||||||
case OpBoolOr: "||";
|
public var line : Int;
|
||||||
case OpBoolAnd: "&&";
|
public function new(e, pmin, pmax, origin, line) {
|
||||||
case OpIs: "is";
|
this.e = e;
|
||||||
case OpAssign: "=";
|
this.pmin = pmin;
|
||||||
case OpNcoal: "??";
|
this.pmax = pmax;
|
||||||
case OpInterval: "...";
|
this.origin = origin;
|
||||||
case OpArrow: "->";
|
this.line = line;
|
||||||
case OpArrowFn: "=>";
|
}
|
||||||
case OpAddAssign: "+=";
|
public function toString(): String {
|
||||||
case OpSubAssign: "-=";
|
return Printer.errorToString(this);
|
||||||
case OpMultAssign: "*=";
|
}
|
||||||
case OpDivAssign: "/=";
|
}
|
||||||
case OpModAssign: "%=";
|
enum ErrorDef {
|
||||||
case OpAndAssign: "&=";
|
#else
|
||||||
case OpOrAssign: "|=";
|
enum Error {
|
||||||
case OpXorAssign: "^=";
|
#end
|
||||||
case OpShlAssign: "<<=";
|
EInvalidChar( c : Int );
|
||||||
case OpShrAssign: ">>=";
|
EUnexpected( s : String );
|
||||||
case OpUshrAssign: ">>>=";
|
EUnterminatedString;
|
||||||
case OpNcoalAssign: "??" + "=";
|
EUnterminatedComment;
|
||||||
default: "?";
|
EInvalidPreprocessor( msg : String );
|
||||||
}
|
EUnknownVariable( v : String );
|
||||||
}
|
EInvalidIterator( v : String );
|
||||||
}
|
EInvalidOp( op : String );
|
||||||
|
EInvalidAccess( f : String );
|
||||||
enum abstract Unop(Int) from Int to Int {
|
ECustom( msg : String );
|
||||||
var OpNot = 0;
|
EInvalidClass( className : String);
|
||||||
var OpNeg = 1;
|
EAlreadyExistingClass( className : String);
|
||||||
var OpIncrement = 2;
|
}
|
||||||
var OpDecrement = 3;
|
|
||||||
var OpNegBits = 4;
|
|
||||||
|
enum ModuleDecl {
|
||||||
public static inline function fromString(s:String):Unop {
|
DPackage( path : Array<String> );
|
||||||
return switch(s) {
|
DImport( path : Array<String>, ?everything : Bool, ?asname:String );
|
||||||
case "!": OpNot;
|
DUsing( path : Array<String>);
|
||||||
case "-": OpNeg;
|
DTypedef( c : TypeDecl );
|
||||||
case "++": OpIncrement;
|
DClass( c : ClassDecl );
|
||||||
case "--": OpDecrement;
|
}
|
||||||
case "~": OpNegBits;
|
|
||||||
default: -1;
|
typedef ModuleType = {
|
||||||
}
|
var name : String;
|
||||||
}
|
var params : {}; // TODO : not yet parsed
|
||||||
|
var meta : Metadata;
|
||||||
public inline function toString():String {
|
var isPrivate : Bool;
|
||||||
return switch(this) {
|
}
|
||||||
case OpNot: "!";
|
|
||||||
case OpNeg: "-";
|
typedef ClassDecl = {> ModuleType,
|
||||||
case OpIncrement: "++";
|
var extend : Null<CType>;
|
||||||
case OpDecrement: "--";
|
var implement : Array<CType>;
|
||||||
case OpNegBits: "~";
|
var fields : Array<FieldDecl>;
|
||||||
default: "?";
|
var isExtern : Bool;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
typedef TypeDecl = {> ModuleType,
|
||||||
|
var t : CType;
|
||||||
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
}
|
||||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
|
||||||
|
typedef FieldDecl = {
|
||||||
enum Const {
|
var name : String;
|
||||||
CInt( v : Int );
|
var meta : Metadata;
|
||||||
CFloat( f : Float );
|
var kind : FieldKind;
|
||||||
CString( s : String, ?i : Bool );
|
var access : Array<FieldAccess>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if hscriptPos
|
enum abstract FieldAccess(UInt8) {
|
||||||
@:structInit
|
var APublic;
|
||||||
final class Expr {
|
var APrivate;
|
||||||
public var e : ExprDef;
|
var AInline;
|
||||||
public var pmin : Int;
|
var AOverride;
|
||||||
public var pmax : Int;
|
var AStatic;
|
||||||
public var origin : String;
|
var AMacro;
|
||||||
public var line : Int;
|
}
|
||||||
}
|
|
||||||
enum ExprDef {
|
enum FieldKind {
|
||||||
#else
|
KFunction( f : FunctionDecl );
|
||||||
typedef ExprDef = Expr;
|
KVar( v : VarDecl );
|
||||||
enum Expr {
|
}
|
||||||
#end
|
|
||||||
EConst( c : Const );
|
@:structInit
|
||||||
EIdent( v : String );
|
final class FunctionDecl {
|
||||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
public var args : Array<Argument>;
|
||||||
EParent( e : Expr );
|
public var body : Expr;
|
||||||
EBlock( e : Array<Expr> );
|
public var ret : Null<CType>;
|
||||||
EField( e : Expr, f : String , ?safe : Bool );
|
}
|
||||||
EBinop( op : Binop, e1 : Expr, e2 : Expr );
|
|
||||||
EUnop( op : Unop, prefix : Bool, e : Expr );
|
typedef VarDecl = {
|
||||||
ECall( e : Expr, params : Array<Expr> );
|
var get : FieldPropertyAccess;
|
||||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
var set : FieldPropertyAccess;
|
||||||
EWhile( cond : Expr, e : Expr );
|
var isFinal : Bool;
|
||||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
var expr : Null<Expr>;
|
||||||
EBreak;
|
var type : Null<CType>;
|
||||||
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 );
|
typedef TypeParamDecl = {};
|
||||||
EArray( e : Expr, index : Expr );
|
|
||||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
enum EnumType {
|
||||||
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
ESimple(name: String);
|
||||||
EThrow( e : Expr );
|
EConstructor(name: String, args: Array<Argument>);
|
||||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
}
|
||||||
EObject( fl : Array<ObjectField> );
|
|
||||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
enum abstract FieldPropertyAccess(UInt8) {
|
||||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
var ADefault;
|
||||||
EDoWhile( cond : Expr, e : Expr);
|
var ANull;
|
||||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
var AGet;
|
||||||
ECheckType( e : Expr, t : CType );
|
var ASet;
|
||||||
|
var ADynamic;
|
||||||
EPackage( ?n:String );
|
var ANever;
|
||||||
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 );
|
enum AccessContext {
|
||||||
ECast(e:Expr, ?t:CType);
|
CInner(cl:String);
|
||||||
ERegex(e:String, flags:String);
|
COuter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@: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>;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package hscript;
|
package hscript;
|
||||||
|
|
||||||
/**
|
interface IHScriptCustomAccessBehaviour {
|
||||||
* Same Interface as IHScriptCustomBehaviour but for Property.
|
|
||||||
*/
|
|
||||||
interface IHScriptCustomAccessBehaviour extends IHScriptCustomBehaviour {
|
|
||||||
var __allowSetGet:Bool;
|
var __allowSetGet:Bool;
|
||||||
|
var __allowPrivateAccess:Bool;
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic;
|
||||||
|
public function hget(name:String):Dynamic;
|
||||||
|
|
||||||
public function __callGetter(name:String):Dynamic;
|
public function __callGetter(name:String):Dynamic;
|
||||||
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
package hscript;
|
package hscript;
|
||||||
|
|
||||||
/**
|
interface IHScriptCustomClassBehaviour {
|
||||||
* Special Interface to make a class usable for Custom Classes.
|
public var __customClass:hscript.customclass.CustomClass;
|
||||||
*/
|
|
||||||
interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{
|
|
||||||
public var __interp:Interp;
|
|
||||||
public var __real_fields:Array<String>;
|
public var __real_fields:Array<String>;
|
||||||
public var __class__fields:Array<String>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
+1101
-863
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
|||||||
|
package hscript;
|
||||||
|
|
||||||
|
class InterpConfig {
|
||||||
|
// Automatic import redirect for certain classes
|
||||||
|
public static final IMPORT_REDIRECTS = [
|
||||||
|
"Type" => "hscript.proxy.ProxyType"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Incase an import fails
|
||||||
|
// These are the module names
|
||||||
|
@:unreflective
|
||||||
|
public static final DISALLOW_IMPORT = [
|
||||||
|
"Type"
|
||||||
|
];
|
||||||
|
}
|
||||||
+4
-7
@@ -127,8 +127,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";
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,13 +149,12 @@ class Macro {
|
|||||||
case EField(e, f):
|
case EField(e, f):
|
||||||
EField(convert(e), f);
|
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));
|
||||||
|
|||||||
+359
-523
File diff suppressed because it is too large
Load Diff
+414
-494
@@ -1,494 +1,414 @@
|
|||||||
/*
|
/*
|
||||||
* 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 ):String {
|
||||||
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 ):String {
|
||||||
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):Void buf.add(s);
|
||||||
|
|
||||||
function type( t : CType ):Void {
|
function type( t : CType ):Void {
|
||||||
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 ):Void {
|
||||||
|
if( t != null ) {
|
||||||
function addType( t : CType ):Void {
|
add(" : ");
|
||||||
if( t != null ) {
|
type(t);
|
||||||
add(" : ");
|
}
|
||||||
type(t);
|
}
|
||||||
}
|
|
||||||
}
|
function expr( e : Expr ):Void {
|
||||||
|
if( e == null ) {
|
||||||
function expr( e : Expr ):Void {
|
add("??NULL??");
|
||||||
if( e == null ) {
|
return;
|
||||||
add("??NULL??");
|
}
|
||||||
return;
|
switch( Tools.expr(e) ) {
|
||||||
}
|
case EIgnore(_):
|
||||||
switch(Tools.expr(e)) {
|
case EImport(c, n):
|
||||||
case EPackage(n):
|
add("import " + c);
|
||||||
add('package');
|
if(n != null)
|
||||||
if(n != null)
|
add(' as $n');
|
||||||
add(' $n');
|
case EClass(name, fields, extend, interfaces):
|
||||||
add(';\n');
|
add('class $name');
|
||||||
case EImport(c, n, u):
|
if (extend != null)
|
||||||
add('${u ? 'using' : 'import'} $c');
|
add(' extends $extend');
|
||||||
if(n != null)
|
for(_interface in interfaces) {
|
||||||
add(' as $n');
|
add(' implements $_interface');
|
||||||
case EClass(name, fields, extend, interfaces, fnal):
|
}
|
||||||
var isFinal = fnal != null && fnal;
|
add(' {\n');
|
||||||
if(isFinal)
|
tabs += "\t";
|
||||||
add('final ');
|
//for(field in fields) {
|
||||||
add('class $name');
|
// expr(field);
|
||||||
if (extend != null)
|
//}
|
||||||
add(' extends $extend');
|
|
||||||
for(_interface in interfaces) {
|
tabs = tabs.substr(1);
|
||||||
add(' implements $_interface');
|
add("}");
|
||||||
}
|
case ERedirect(n, cl):
|
||||||
tabs += "\t";
|
add('typedef $n = $cl');
|
||||||
add(" {\n");
|
case EConst(c):
|
||||||
for( e in fields ) {
|
switch( c ) {
|
||||||
add(tabs);
|
case CInt(i): add(i);
|
||||||
expr(e);
|
case CFloat(f): add(f);
|
||||||
//add(";\n");
|
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
||||||
}
|
}
|
||||||
//for(field in fields) {
|
case EIdent(v):
|
||||||
// expr(field);
|
add(v);
|
||||||
//}
|
case EVar(n, t, e): // TODO: static, public, override
|
||||||
|
add("var " + n);
|
||||||
tabs = tabs.substr(1);
|
addType(t);
|
||||||
add("}");
|
if( e != null ) {
|
||||||
case EEnum(en, isAbstract):
|
add(" = ");
|
||||||
if(isAbstract) {
|
expr(e);
|
||||||
add('enum abstract ${en.name}(');
|
}
|
||||||
if(en.underlyingType != null)
|
case EParent(e):
|
||||||
type(en.underlyingType);
|
add("("); expr(e); add(")");
|
||||||
else
|
case EBlock(el):
|
||||||
add('Int');
|
if( el.length == 0 ) {
|
||||||
add(')');
|
add("{}");
|
||||||
if(en.fields.length == 0) {
|
} else {
|
||||||
add(' {}');
|
tabs += "\t";
|
||||||
return;
|
add("{\n");
|
||||||
}
|
for( e in el ) {
|
||||||
tabs += "\t";
|
add(tabs);
|
||||||
add(" {\n");
|
expr(e);
|
||||||
for(e in en.fields) {
|
add(";\n");
|
||||||
add(tabs);
|
}
|
||||||
add(e.name);
|
tabs = tabs.substr(1);
|
||||||
if(e.value != null) {
|
add("}");
|
||||||
add(" = ");
|
}
|
||||||
expr(e.value);
|
case EField(e, f, s):
|
||||||
}
|
expr(e);
|
||||||
add(";\n");
|
add((s == true ? "?." : ".") + f);
|
||||||
}
|
case EBinop(op, e1, e2):
|
||||||
tabs = tabs.substr(1);
|
expr(e1);
|
||||||
add("}");
|
add(" " + op + " ");
|
||||||
} else {
|
expr(e2);
|
||||||
add('enum ${en.name}');
|
case EUnop(op, pre, e):
|
||||||
if(en.fields.length == 0) {
|
if( pre ) {
|
||||||
add(' {}');
|
add(op);
|
||||||
return;
|
expr(e);
|
||||||
}
|
} else {
|
||||||
tabs += "\t";
|
expr(e);
|
||||||
add(" {\n");
|
add(op);
|
||||||
for(e in en.fields) {
|
}
|
||||||
add(tabs);
|
case ECall(e, args):
|
||||||
add(e.name);
|
if( e == null )
|
||||||
if(e.args.length > 0) {
|
expr(e);
|
||||||
add("(");
|
else switch( #if hscriptPos e.e #else e #end ) {
|
||||||
var first = true;
|
case EField(_), EIdent(_), EConst(_):
|
||||||
for( a in e.args ) {
|
expr(e);
|
||||||
if( first ) first = false else add(", ");
|
default:
|
||||||
if( a.opt ) add("?");
|
add("(");
|
||||||
add(a.name);
|
expr(e);
|
||||||
addType(a.t);
|
add(")");
|
||||||
}
|
}
|
||||||
add(')');
|
add("(");
|
||||||
}
|
var first = true;
|
||||||
add(";\n");
|
for( a in args ) {
|
||||||
}
|
if( first ) first = false else add(", ");
|
||||||
tabs = tabs.substr(1);
|
expr(a);
|
||||||
add("}");
|
}
|
||||||
}
|
add(")");
|
||||||
case ECast(e, t):
|
case EIf(cond,e1,e2):
|
||||||
var safe = t != null;
|
add("if( ");
|
||||||
add("cast ");
|
expr(cond);
|
||||||
if(safe) add("(");
|
add(" ) ");
|
||||||
expr(e);
|
expr(e1);
|
||||||
if(safe) {
|
if( e2 != null ) {
|
||||||
add(", ");
|
add(" else ");
|
||||||
addType(t);
|
expr(e2);
|
||||||
add(")");
|
}
|
||||||
}
|
case EWhile(cond,e):
|
||||||
case ERegex(e, f):
|
add("while( ");
|
||||||
add('~/$e/$f');
|
expr(cond);
|
||||||
add(';\n');
|
add(" ) ");
|
||||||
case EConst(c):
|
expr(e);
|
||||||
switch( c ) {
|
case EDoWhile(cond,e):
|
||||||
case CInt(i): add(i);
|
add("do ");
|
||||||
case CFloat(f): add(f);
|
expr(e);
|
||||||
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
add(" while ( ");
|
||||||
}
|
expr(cond);
|
||||||
case EIdent(v):
|
add(" )");
|
||||||
add(v);
|
case EFor(v, it, e, ithv):
|
||||||
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
|
if(ithv != null)
|
||||||
if(p) add("public ");
|
add("for( "+ithv+" => "+v+" in ");
|
||||||
else if(pr) add("private ");
|
else
|
||||||
if(s) add("static ");
|
add("for( "+v+" in ");
|
||||||
if(isInline) add("inline ");
|
expr(it);
|
||||||
if(isFinal) add("final " + n);
|
add(" ) ");
|
||||||
else add("var " + n);
|
expr(e);
|
||||||
|
case EBreak:
|
||||||
if(get != null || set != null) {
|
add("break");
|
||||||
add("(");
|
case EContinue:
|
||||||
switch(get) {
|
add("continue");
|
||||||
case ADefault: add("default, ");
|
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||||
case ANull: add("null, ");
|
add("function");
|
||||||
case AGet: add("get, ");
|
if( name != null )
|
||||||
case ADynamic: add("dynamic, ");
|
add(" " + name);
|
||||||
case ANever: add("never, ");
|
add("(");
|
||||||
default:
|
var first = true;
|
||||||
}
|
for( a in params ) {
|
||||||
switch(set) {
|
if( first ) first = false else add(", ");
|
||||||
case ADefault: add("default");
|
if( a.opt ) add("?");
|
||||||
case ANull: add("null");
|
add(a.name);
|
||||||
case ASet: add("set");
|
addType(a.t);
|
||||||
case ADynamic: add("dynamic");
|
}
|
||||||
case ANever: add("never");
|
add(")");
|
||||||
default:
|
addType(ret);
|
||||||
}
|
add(" ");
|
||||||
add(")");
|
expr(e);
|
||||||
}
|
case EReturn(e):
|
||||||
|
add("return");
|
||||||
addType(t);
|
if( e != null ) {
|
||||||
if( e != null ) {
|
add(" ");
|
||||||
add(" = ");
|
expr(e);
|
||||||
expr(e);
|
}
|
||||||
}
|
case EArray(e,index):
|
||||||
case EParent(e):
|
expr(e);
|
||||||
add("("); expr(e); add(")");
|
add("[");
|
||||||
case EBlock(el):
|
expr(index);
|
||||||
if( el.length == 0 ) {
|
add("]");
|
||||||
add("{}");
|
case EArrayDecl(el, _):
|
||||||
} else {
|
add("[");
|
||||||
tabs += "\t";
|
var first = true;
|
||||||
add("{\n");
|
for( e in el ) {
|
||||||
for( e in el ) {
|
if( first ) first = false else add(", ");
|
||||||
add(tabs);
|
expr(e);
|
||||||
expr(e);
|
}
|
||||||
add(";\n");
|
add("]");
|
||||||
}
|
case ENew(cl, args):
|
||||||
tabs = tabs.substr(1);
|
add("new " + cl + "(");
|
||||||
add("}");
|
var first = true;
|
||||||
}
|
for( e in args ) {
|
||||||
case EField(e, f, s):
|
if( first ) first = false else add(", ");
|
||||||
expr(e);
|
expr(e);
|
||||||
add((s == true ? "?." : ".") + f);
|
}
|
||||||
case EBinop(op, e1, e2):
|
add(")");
|
||||||
expr(e1);
|
case EThrow(e):
|
||||||
add(" " + op.toString() + " ");
|
add("throw ");
|
||||||
expr(e2);
|
expr(e);
|
||||||
case EUnop(op, pre, e):
|
case ETry(e, v, t, ecatch):
|
||||||
if( pre ) {
|
add("try ");
|
||||||
add(op);
|
expr(e);
|
||||||
expr(e);
|
add(" catch( " + v);
|
||||||
} else {
|
addType(t);
|
||||||
expr(e);
|
add(") ");
|
||||||
add(op);
|
expr(ecatch);
|
||||||
}
|
case EObject(fl):
|
||||||
case ECall(e, args):
|
if( fl.length == 0 ) {
|
||||||
if( e == null )
|
add("{}");
|
||||||
expr(e);
|
} else {
|
||||||
else switch( Tools.expr(e)) {
|
tabs += "\t";
|
||||||
case EField(_), EIdent(_), EConst(_):
|
add("{\n");
|
||||||
expr(e);
|
for( f in fl ) {
|
||||||
default:
|
add(tabs);
|
||||||
add("(");
|
add(f.name+" : ");
|
||||||
expr(e);
|
expr(f.e);
|
||||||
add(")");
|
add(",\n");
|
||||||
}
|
}
|
||||||
add("(");
|
tabs = tabs.substr(1);
|
||||||
var first = true;
|
add("}");
|
||||||
for( a in args ) {
|
}
|
||||||
if( first ) first = false else add(", ");
|
case ETernary(c,e1,e2):
|
||||||
expr(a);
|
expr(c);
|
||||||
}
|
add(" ? ");
|
||||||
add(")");
|
expr(e1);
|
||||||
case EIf(cond,e1,e2):
|
add(" : ");
|
||||||
add("if( ");
|
expr(e2);
|
||||||
expr(cond);
|
case ESwitch(e, cases, def):
|
||||||
add(" ) ");
|
add("switch( ");
|
||||||
expr(e1);
|
expr(e);
|
||||||
if( e2 != null ) {
|
add(") {");
|
||||||
add(" else ");
|
for( c in cases ) {
|
||||||
expr(e2);
|
add("case ");
|
||||||
}
|
var first = true;
|
||||||
case EWhile(cond,e):
|
for( v in c.values ) {
|
||||||
add("while( ");
|
if( first ) first = false else add(", ");
|
||||||
expr(cond);
|
expr(v);
|
||||||
add(" ) ");
|
}
|
||||||
expr(e);
|
add(": ");
|
||||||
case EDoWhile(cond,e):
|
expr(c.expr);
|
||||||
add("do ");
|
add(";\n");
|
||||||
expr(e);
|
}
|
||||||
add(" while ( ");
|
if( def != null ) {
|
||||||
expr(cond);
|
add("default: ");
|
||||||
add(" )");
|
expr(def);
|
||||||
case EFor(v, it, e, ithv):
|
add(";\n");
|
||||||
if(ithv != null)
|
}
|
||||||
add("for( "+ithv+" => "+v+" in ");
|
add("}");
|
||||||
else
|
case EMeta(name, args, e):
|
||||||
add("for( "+v+" in ");
|
add("@");
|
||||||
expr(it);
|
add(name);
|
||||||
add(" ) ");
|
if( args != null && args.length > 0 ) {
|
||||||
expr(e);
|
add("(");
|
||||||
case EBreak:
|
var first = true;
|
||||||
add("break");
|
for( a in args ) {
|
||||||
case EContinue:
|
if( first ) first = false else add(", ");
|
||||||
add("continue");
|
expr(e);
|
||||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
}
|
||||||
add("function");
|
add(")");
|
||||||
if( name != null )
|
}
|
||||||
add(" " + name);
|
add(" ");
|
||||||
add("(");
|
expr(e);
|
||||||
var first = true;
|
case ECheckType(e, t):
|
||||||
for( a in params ) {
|
add("(");
|
||||||
if( first ) first = false else add(", ");
|
expr(e);
|
||||||
if( a.opt ) add("?");
|
add(" : ");
|
||||||
add(a.name);
|
addType(t);
|
||||||
addType(a.t);
|
add(")");
|
||||||
}
|
case EUsing(name):
|
||||||
add(")");
|
add("using ");
|
||||||
addType(ret);
|
add(name);
|
||||||
add(" ");
|
case EEnum(name, params):
|
||||||
expr(e);
|
if (params.length == 0) {
|
||||||
case EReturn(e):
|
add("enum " + name + " {}");
|
||||||
add("return");
|
return;
|
||||||
if( e != null ) {
|
}
|
||||||
add(" ");
|
add("enum " + name + " {\n");
|
||||||
expr(e);
|
tabs += "\t";
|
||||||
}
|
for (p in params) {
|
||||||
case EArray(e,index):
|
add(tabs);
|
||||||
expr(e);
|
switch p {
|
||||||
add("[");
|
case EConstructor(name, args):
|
||||||
expr(index);
|
add(name);
|
||||||
add("]");
|
add("(");
|
||||||
case EArrayDecl(el, _):
|
for (a in args)
|
||||||
add("[");
|
addArgument(a);
|
||||||
var first = true;
|
add(")");
|
||||||
for( e in el ) {
|
case ESimple(name):
|
||||||
if( first ) first = false else add(", ");
|
add(name);
|
||||||
expr(e);
|
}
|
||||||
}
|
add(";\n");
|
||||||
add("]");
|
}
|
||||||
case ENew(cl, args, params):
|
tabs = tabs.substr(1);
|
||||||
add("new " + cl);
|
add(tabs);
|
||||||
if(params != null) {
|
add("}");
|
||||||
add("<");
|
}
|
||||||
var first = true;
|
}
|
||||||
for( p in params ) {
|
|
||||||
if( first ) first = false else add(", ");
|
function addArgument(a: Argument) {
|
||||||
type(p);
|
if (a.opt)
|
||||||
}
|
add("?");
|
||||||
add(">");
|
add(a.name);
|
||||||
}
|
addType(a.t);
|
||||||
add("(");
|
}
|
||||||
var first = true;
|
|
||||||
for( e in args ) {
|
public static function toString( e : Expr ):String {
|
||||||
if( first ) first = false else add(", ");
|
return new Printer().exprToString(e);
|
||||||
expr(e);
|
}
|
||||||
}
|
|
||||||
add(")");
|
public static function errorToString( e : Expr.Error ):String {
|
||||||
case EThrow(e):
|
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||||
add("throw ");
|
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||||
expr(e);
|
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||||
case ETry(e, v, t, ecatch):
|
case EUnterminatedString: "Unterminated string";
|
||||||
add("try ");
|
case EUnterminatedComment: "Unterminated comment";
|
||||||
expr(e);
|
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||||
add(" catch( " + v);
|
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||||
addType(t);
|
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||||
add(") ");
|
case EInvalidOp(op): "Invalid operator: "+op;
|
||||||
expr(ecatch);
|
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||||
case EObject(fl):
|
case ECustom(msg): msg;
|
||||||
if( fl.length == 0 ) {
|
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||||
add("{}");
|
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||||
} else {
|
};
|
||||||
tabs += "\t";
|
#if hscriptPos
|
||||||
add("{\n");
|
return e.origin + ":" + e.line + ": " + message;
|
||||||
for( f in fl ) {
|
#else
|
||||||
add(tabs);
|
return message;
|
||||||
add(f.name+" : ");
|
#end
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+259
-143
@@ -1,144 +1,260 @@
|
|||||||
/*
|
/*
|
||||||
* 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 {
|
using StringTools;
|
||||||
|
|
||||||
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
class Tools {
|
||||||
switch( expr(e) ) {
|
|
||||||
case EConst(_), EIdent(_):
|
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||||
case EImport(c): f(e);
|
switch( expr(e) ) {
|
||||||
case EClass(_, e, _, _): for( a in e ) f(a);
|
case EConst(_), EIdent(_):
|
||||||
case EVar(_, _, e): if( e != null ) f(e);
|
case EImport(c): f(e);
|
||||||
case EParent(e): f(e);
|
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||||
case EBlock(el): for( e in el ) f(e);
|
case EVar(_, _, e): if( e != null ) f(e);
|
||||||
case EField(e, _): f(e);
|
case EParent(e): f(e);
|
||||||
case EBinop(_, e1, e2): f(e1); f(e2);
|
case EBlock(el): for( e in el ) f(e);
|
||||||
case EUnop(_, _, e): f(e);
|
case EField(e, _): f(e);
|
||||||
case ECall(e, args): f(e); for( a in args ) f(a);
|
case EBinop(_, e1, e2): f(e1); f(e2);
|
||||||
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
case EUnop(_, _, e): f(e);
|
||||||
case EWhile(c, e): f(c); f(e);
|
case ECall(e, args): f(e); for( a in args ) f(a);
|
||||||
case EDoWhile(c, e): f(c); f(e);
|
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
||||||
case EFor(_, it, e): f(it); f(e);
|
case EWhile(c, e): f(c); f(e);
|
||||||
case EBreak,EContinue:
|
case EDoWhile(c, e): f(c); f(e);
|
||||||
case EFunction(_, e, _, _): f(e);
|
case EFor(_, it, e): f(it); f(e);
|
||||||
case EReturn(e): if( e != null ) f(e);
|
case EBreak,EContinue:
|
||||||
case EArray(e, i): f(e); f(i);
|
case EFunction(_, e, _, _): f(e);
|
||||||
case EArrayDecl(el): for( e in el ) f(e);
|
case EReturn(e): if( e != null ) f(e);
|
||||||
case ENew(_,el): for( e in el ) f(e);
|
case EArray(e, i): f(e); f(i);
|
||||||
case EThrow(e): f(e);
|
case EArrayDecl(el): for( e in el ) f(e);
|
||||||
case ETry(e, _, _, c): f(e); f(c);
|
case ENew(_,el): for( e in el ) f(e);
|
||||||
case EObject(fl): for( fi in fl ) f(fi.e);
|
case EThrow(e): f(e);
|
||||||
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
case ETry(e, _, _, c): f(e); f(c);
|
||||||
case ESwitch(e, cases, def):
|
case EObject(fl): for( fi in fl ) f(fi.e);
|
||||||
f(e);
|
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
||||||
for( c in cases ) {
|
case ESwitch(e, cases, def):
|
||||||
for( v in c.values ) f(v);
|
f(e);
|
||||||
f(c.expr);
|
for( c in cases ) {
|
||||||
}
|
for( v in c.values ) f(v);
|
||||||
if( def != null ) f(def);
|
f(c.expr);
|
||||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
}
|
||||||
case ECheckType(e,_): f(e);
|
if( def != null ) f(def);
|
||||||
default:
|
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||||
}
|
case ECheckType(e,_): f(e);
|
||||||
}
|
default:
|
||||||
|
}
|
||||||
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
}
|
||||||
var edef = switch( expr(e) ) {
|
|
||||||
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
||||||
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
var edef = switch( expr(e) ) {
|
||||||
case EParent(e): EParent(f(e));
|
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
||||||
case EField(e, fi): EField(f(e),fi);
|
case EParent(e): EParent(f(e));
|
||||||
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||||
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
case EField(e, fi): EField(f(e),fi);
|
||||||
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
||||||
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
||||||
case EWhile(c, e): EWhile(f(c),f(e));
|
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
||||||
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
||||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
case EWhile(c, e): EWhile(f(c),f(e));
|
||||||
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||||
case EArray(e, i): EArray(f(e),f(i));
|
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
||||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
case EArray(e, i): EArray(f(e),f(i));
|
||||||
case EThrow(e): EThrow(f(e));
|
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||||
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
case EThrow(e): EThrow(f(e));
|
||||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
||||||
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 EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||||
case ECheckType(e,t): ECheckType(f(e), t);
|
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 EImport(c): EImport(c);
|
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
case ECheckType(e,t): ECheckType(f(e), t);
|
||||||
default: expr(e);
|
case EImport(c): EImport(c);
|
||||||
}
|
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||||
return mk(edef, e);
|
default: #if hscriptPos e.e #else e #end;
|
||||||
}
|
}
|
||||||
|
return mk(edef, e);
|
||||||
public static inline function expr( e : Expr ) : ExprDef {
|
}
|
||||||
#if hscriptPos
|
|
||||||
return e.e;
|
public static inline function expr( e : Expr ) : ExprDef {
|
||||||
#else
|
#if hscriptPos
|
||||||
return e;
|
return e.e;
|
||||||
#end
|
#else
|
||||||
}
|
return e;
|
||||||
|
#end
|
||||||
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
}
|
||||||
#if hscriptPos
|
|
||||||
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
||||||
#else
|
#if hscriptPos
|
||||||
return e;
|
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||||
#end
|
#else
|
||||||
}
|
return e;
|
||||||
|
#end
|
||||||
/**
|
}
|
||||||
* DO NOT USE INLINE ON THIS FUNCTION
|
|
||||||
**/
|
@:access(hscript.Interp)
|
||||||
public static function argCount(func: haxe.Constraints.Function): Int {
|
public static function clearClasses() {
|
||||||
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
|
#if CUSTOM_CLASSES
|
||||||
#if cpp
|
Interp._customClasses.clear();
|
||||||
return untyped __cpp__("{0}->__ArgCount()", func);
|
Interp._customClassAliases.clear();
|
||||||
#elseif js
|
#end
|
||||||
return untyped js.Syntax.code("{0}.length", func);
|
}
|
||||||
#elseif hl
|
|
||||||
var ft = hl.Type.getDynamic(func);
|
public static function removeInnerClass(name: String): String {
|
||||||
if (ft.kind != HFun)
|
var ll = name.lastIndexOf(".");
|
||||||
return -1;
|
if (name.indexOf(".") != ll) { // checks if there are 2 or more dots
|
||||||
return ft.getArgsCount();
|
// wtf did i make -neo
|
||||||
#else
|
// this is awesome -crow
|
||||||
return -1;
|
return name.substr(0, name.lastIndexOf(".", ll - 1)) + "." + name.substr(ll + 1);
|
||||||
#end
|
}
|
||||||
}
|
// only one dot or no dots (will work since -1 + 1 = 0)
|
||||||
|
return name.substr(ll + 1);
|
||||||
public static function isUppercase(s:String) {
|
}
|
||||||
if(s.length == 0) return false;
|
|
||||||
var c:Int = StringTools.fastCodeAt(s, 0);
|
// TODO: maybe use this function for import since also check for innerclasses
|
||||||
if(StringTools.isEof(c)) return false; // Just in case :3
|
public static function getClass(name: String): Dynamic {
|
||||||
return c >= 65 && c <= 90; // A-Z
|
var splitClassName = [for (e in name.split(".")) e.trim()];
|
||||||
}
|
var realClassName = splitClassName.join(".");
|
||||||
|
|
||||||
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
var c: Dynamic = Type.resolveClass(realClassName);
|
||||||
return obj != null && obj is IHScriptAbstractBehaviour;
|
if (c == null) // try importing as enum
|
||||||
|
try
|
||||||
|
c = Type.resolveEnum(name);
|
||||||
|
|
||||||
|
if (c == null) {
|
||||||
|
// lastly try removing any inner class from it
|
||||||
|
// this allows you to import stuff like
|
||||||
|
// flixel.text.FlxText.FlxTextBorderStyle
|
||||||
|
// without the script crashing immediately
|
||||||
|
var className = removeInnerClass(realClassName);
|
||||||
|
if (className != name) {
|
||||||
|
c = Type.resolveClass(className);
|
||||||
|
if (c == null)
|
||||||
|
c = Type.resolveEnum(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isIterable(v: Dynamic): Bool {
|
||||||
|
// TODO: test for php and lua, they might have issues with this check
|
||||||
|
return v != null && v.iterator != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT USE INLINE ON THIS FUNCTION
|
||||||
|
**/
|
||||||
|
public static function argCount(func: haxe.Constraints.Function): Int {
|
||||||
|
#if cpp
|
||||||
|
return untyped __cpp__("{0}->__ArgCount()", func);
|
||||||
|
#elseif js
|
||||||
|
return untyped js.Syntax.code("{0}.length", func);
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getClassDeclFields(classDecl:hscript.Expr.ClassDecl, onlyStatic:Bool = false):Array<FieldDecl> {
|
||||||
|
var fields = classDecl.fields.filter(function(field:FieldDecl) {
|
||||||
|
var isStatic = field.access.contains(AStatic);
|
||||||
|
return onlyStatic ? isStatic : !isStatic;
|
||||||
|
});
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L217
|
||||||
|
*/
|
||||||
|
class EnumValue {
|
||||||
|
public var enumName: String;
|
||||||
|
public var name: String;
|
||||||
|
public var index: Int;
|
||||||
|
public var args: Array<Dynamic>;
|
||||||
|
public var enumParent:Dynamic;
|
||||||
|
|
||||||
|
public function new(enumName: String, name: String, index: Int, enumParent:Dynamic, ?args: Array<Dynamic>) {
|
||||||
|
this.enumName = enumName;
|
||||||
|
this.name = name;
|
||||||
|
this.index = index;
|
||||||
|
this.enumParent = enumParent;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString(): String {
|
||||||
|
if (args == null)
|
||||||
|
return enumName + "." + name;
|
||||||
|
return enumName + "." + name + "(" + [for (arg in args) arg].join(", ") + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
public inline function getEnumName(): String
|
||||||
|
return this.enumName;
|
||||||
|
|
||||||
|
public inline function getConstructorArgs(): Array<Dynamic>
|
||||||
|
return this.args != null ? this.args : [];
|
||||||
|
|
||||||
|
public function compare(other: EnumValue): Bool {
|
||||||
|
if (enumName != other.enumName || name != other.name)
|
||||||
|
return false;
|
||||||
|
if (args == null && other.args == null)
|
||||||
|
return true;
|
||||||
|
if (args == null || other.args == null)
|
||||||
|
return false;
|
||||||
|
if (args.length != other.args.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i in 0...args.length) {
|
||||||
|
// TODO: allow deep comparison, like arrays
|
||||||
|
if (args[i] != other.args[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HScriptEnum implements IHScriptCustomBehaviour {
|
||||||
|
public var enumValues(default, null) = {};
|
||||||
|
|
||||||
|
public function new() {}
|
||||||
|
|
||||||
|
public function setEnum(name:String, enumValue:Dynamic) {
|
||||||
|
Reflect.setField(enumValues, name, enumValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEnumValue(name:String):Null<Dynamic> {
|
||||||
|
if(Reflect.hasField(enumValues, name)) return Reflect.field(enumValues, name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
return getEnumValue(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,512 @@
|
|||||||
|
package hscript.customclass;
|
||||||
|
|
||||||
|
import hscript.utils.UnsafeReflect;
|
||||||
|
import haxe.Constraints.Function;
|
||||||
|
import hscript.Expr;
|
||||||
|
import hscript.Expr.FieldPropertyAccess;
|
||||||
|
import hscript.Expr.VarDecl;
|
||||||
|
import hscript.Expr.FunctionDecl;
|
||||||
|
import hscript.Expr.FieldDecl;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Custom Class core.
|
||||||
|
*
|
||||||
|
* Provides handlers for custom classes.
|
||||||
|
*
|
||||||
|
* Rest in peace, CustomClassHandler.hx
|
||||||
|
*
|
||||||
|
* Based on Polymod Hscript class system
|
||||||
|
* @see https://github.com/larsiusprime/polymod/tree/master/polymod/hscript/_internal
|
||||||
|
*/
|
||||||
|
@:access(hscript.customclass.CustomClassDecl)
|
||||||
|
class CustomClass implements IHScriptCustomAccessBehaviour {
|
||||||
|
public var interp:Interp;
|
||||||
|
|
||||||
|
public var superClass:Dynamic;
|
||||||
|
public var superConstructor(default, null):Dynamic;
|
||||||
|
|
||||||
|
public var superIsCustomClass(get, never):Bool;
|
||||||
|
private function get_superIsCustomClass():Bool
|
||||||
|
return (superClass != null && superClass is CustomClass);
|
||||||
|
|
||||||
|
public var className(get, never):String;
|
||||||
|
private function get_className():String {
|
||||||
|
return __class.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private var __class:CustomClassDecl;
|
||||||
|
private var __cachedSuperFields:Null<Map<String, Dynamic>> = null;
|
||||||
|
|
||||||
|
private var __cachedFieldDecls:Map<String, FieldDecl> = [];
|
||||||
|
private var __cachedFunctionDecls:Map<String, FunctionDecl> = [];
|
||||||
|
private var __cachedVarDecls:Map<String, VarDecl> = [];
|
||||||
|
|
||||||
|
public var accessContext:AccessContext = COuter;
|
||||||
|
public var __allowSetGet:Bool = false;
|
||||||
|
public var __allowPrivateAccess:Bool = false;
|
||||||
|
|
||||||
|
private var isInline(default, null):Bool = false;
|
||||||
|
private var ogVariables(default, null):Map<String, Dynamic>;
|
||||||
|
private var initializing(default, null):Bool = false; // Allows final variables to be initialized
|
||||||
|
|
||||||
|
public function new(__class:CustomClassDecl, args:Array<Dynamic>, ?extendFieldDecl:Map<String, Dynamic>, ?ogInterp:Interp, ?callNew:Bool = true) {
|
||||||
|
this.__class = __class;
|
||||||
|
this.interp = new Interp(this);
|
||||||
|
|
||||||
|
if (ogInterp != null) {
|
||||||
|
interp.importFailedCallback = ogInterp.importFailedCallback;
|
||||||
|
interp.errorHandler = ogInterp.errorHandler;
|
||||||
|
interp.allowStaticVariables = ogInterp.allowStaticVariables;
|
||||||
|
interp.staticVariables = ogInterp.staticVariables;
|
||||||
|
// todo: make it so you can use variables from the same scope as where the class was defined
|
||||||
|
if(__class.isInline != null && __class.isInline) {
|
||||||
|
isInline = __class.isInline;
|
||||||
|
ogVariables = ogInterp.variables;
|
||||||
|
interp.allowPublicVariables = __class.staticInterp.allowPublicVariables;
|
||||||
|
interp.publicVariables = __class.staticInterp.publicVariables;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildImports();
|
||||||
|
buildUsings();
|
||||||
|
|
||||||
|
if (extendFieldDecl != null)
|
||||||
|
__cachedSuperFields = extendFieldDecl;
|
||||||
|
|
||||||
|
buildClass();
|
||||||
|
|
||||||
|
if (hasFunction('new') && callNew) {
|
||||||
|
buildSuperConstructor();
|
||||||
|
initializing = true;
|
||||||
|
callFunction('new', args);
|
||||||
|
initializing = false;
|
||||||
|
|
||||||
|
if (this.superClass == null && this.__class.classDecl.extend != null)
|
||||||
|
this.interp.error(ECustom("super() not called"));
|
||||||
|
} else if (__class.classDecl.extend != null) {
|
||||||
|
createSuperClass(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildClass() {
|
||||||
|
if (__cachedSuperFields == null)
|
||||||
|
__cachedSuperFields = [];
|
||||||
|
|
||||||
|
for (f in __class.classDecl.fields) {
|
||||||
|
if (f.access.contains(AStatic))
|
||||||
|
continue; // Skip static field. It's handled by CustomClassDecl.hx
|
||||||
|
__cachedFieldDecls.set(f.name, f);
|
||||||
|
switch (f.kind) {
|
||||||
|
case KFunction(fn):
|
||||||
|
__cachedFunctionDecls.set(f.name, fn);
|
||||||
|
#if hscriptPos
|
||||||
|
var fexpr:Expr = {
|
||||||
|
e: ExprDef.EFunction(fn.args, fn.body, f.name, fn.ret, false, false),
|
||||||
|
pmin: fn.body.pmin,
|
||||||
|
pmax: fn.body.pmax,
|
||||||
|
line: fn.body.line,
|
||||||
|
origin: fn.body.origin
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
var fexpr = Expr.EFunction(fn.args, fn.body, f.name, fn.ret, false, false);
|
||||||
|
#end
|
||||||
|
var func:Function = this.interp.expr(fexpr);
|
||||||
|
this.interp.variables.set(f.name, func);
|
||||||
|
case KVar(v):
|
||||||
|
if(v.get != ADefault || v.set != ADefault)
|
||||||
|
__allowSetGet = true;
|
||||||
|
__cachedVarDecls.set(f.name, v);
|
||||||
|
if (v.expr != null) {
|
||||||
|
var varValue = this.interp.expr(v.expr);
|
||||||
|
this.interp.variables.set(f.name, varValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!__cachedSuperFields.empty()) {
|
||||||
|
for (f => v in __cachedSuperFields) {
|
||||||
|
this.hset(f, v);
|
||||||
|
}
|
||||||
|
__cachedSuperFields.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSuperConstructor() {
|
||||||
|
superConstructor = Reflect.makeVarArgs(function(args:Array<Dynamic>) {
|
||||||
|
createSuperClass(args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createSuperClass(?args:Array<Dynamic>) {
|
||||||
|
if (args == null)
|
||||||
|
args = [];
|
||||||
|
|
||||||
|
if(__class.superClassDecl is CustomClassDecl)
|
||||||
|
superClass = new CustomClass(__class.superClassDecl, args, __cachedSuperFields, this.interp);
|
||||||
|
else {
|
||||||
|
if (__cachedSuperFields != null) {
|
||||||
|
Reflect.setField(__class.superClassDecl, "__cachedFields", __cachedSuperFields); // Static field
|
||||||
|
}
|
||||||
|
|
||||||
|
var disallowCopy = Type.getInstanceFields(__class.superClassDecl);
|
||||||
|
|
||||||
|
superClass = Type.createInstance(__class.superClassDecl, args);
|
||||||
|
superClass.__customClass = this;
|
||||||
|
superClass.__real_fields = disallowCopy;
|
||||||
|
|
||||||
|
if(isInline) {
|
||||||
|
for(s => v in ogVariables)
|
||||||
|
if(!disallowCopy.contains(s))
|
||||||
|
interp.variables.set(s, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildImports() {
|
||||||
|
var i:Int = 0;
|
||||||
|
for (_import in __class.imports) {
|
||||||
|
var importedClass = _import.fullPath;
|
||||||
|
var importAlias = _import.as;
|
||||||
|
|
||||||
|
if (Interp.customClassExist(importedClass) && this.interp.importFailedCallback != null) {
|
||||||
|
this.interp.importFailedCallback(importedClass.split("."), importAlias);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if hscriptPos
|
||||||
|
var e:Expr = {
|
||||||
|
e: ExprDef.EImport(importedClass, importAlias),
|
||||||
|
pmin: 0,
|
||||||
|
pmax: 0,
|
||||||
|
origin: this.className,
|
||||||
|
line: i
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
var e = Expr.EImport(importedClass, importAlias);
|
||||||
|
#end
|
||||||
|
this.interp.expr(e);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline function buildUsings() {
|
||||||
|
for (us in __class.usings) {
|
||||||
|
@:privateAccess this.interp.useUsing(us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callFunction(name:String, ?args:Array<Dynamic>):Dynamic {
|
||||||
|
var r:Dynamic = null;
|
||||||
|
|
||||||
|
if (hasField(name)) {
|
||||||
|
var fn = getFunction(name);
|
||||||
|
try {
|
||||||
|
if (fn == null)
|
||||||
|
interp.error(ECustom('${name} is not a function'));
|
||||||
|
|
||||||
|
r = UnsafeReflect.callMethodUnsafe(null, fn, args == null ? [] : args);
|
||||||
|
} catch (e:hscript.Expr.Error) {
|
||||||
|
// A script error occurred while executing the custom class function.
|
||||||
|
// Purge the function from the cache so it is not called again.
|
||||||
|
purgeFunction(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var fixedArgs = [];
|
||||||
|
for (a in args) {
|
||||||
|
if ((a is CustomClass)) {
|
||||||
|
var customClass:CustomClass = cast(a, CustomClass);
|
||||||
|
fixedArgs.push(customClass.superClass != null ? customClass.getSuperclass() : customClass);
|
||||||
|
} else {
|
||||||
|
fixedArgs.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var superFn:Function = null;
|
||||||
|
if(superClass is CustomClass) {
|
||||||
|
superFn = cast(superClass, CustomClass).hget(name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var fixedName = '_HX_SUPER__${name}';
|
||||||
|
superFn = Reflect.field(superClass, fixedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (superFn == null || !Reflect.isFunction(superFn)) {
|
||||||
|
this.interp.error(ECustom('Error while calling function super.${name}(): EInvalidAccess'
|
||||||
|
+ '\n'
|
||||||
|
+ 'InvalidAccess error: Super function "${name}" does not exist! Define it or call the correct superclass function.'));
|
||||||
|
}
|
||||||
|
r = Reflect.callMethod((superClass is CustomClass) ? null : superClass, superFn, fixedArgs);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field check
|
||||||
|
|
||||||
|
private function hasField(name:String):Bool {
|
||||||
|
return __cachedFieldDecls.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getField(name:String):FieldDecl {
|
||||||
|
return __cachedFieldDecls != null ? __cachedFieldDecls.get(name) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasVar(name:String):Bool {
|
||||||
|
return __cachedVarDecls.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getVar(name:String):VarDecl {
|
||||||
|
return __cachedVarDecls.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasFunction(name:String):Bool {
|
||||||
|
return __cachedFunctionDecls.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFunction(name:String):Function {
|
||||||
|
var fn = this.interp.variables.get(name);
|
||||||
|
return Reflect.isFunction(fn) ? fn : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuperClass field check
|
||||||
|
|
||||||
|
private function cacheSuperField(name:String, value:Dynamic) {
|
||||||
|
if (__cachedSuperFields != null) {
|
||||||
|
__cachedSuperFields.set(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var __superClassFieldList:Array<String> = null;
|
||||||
|
|
||||||
|
public function superHasField(name:String):Bool {
|
||||||
|
if (superClass == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Reflect.hasField(this, name) is REALLY expensive so we use a cache.
|
||||||
|
if (__superClassFieldList == null) {
|
||||||
|
__superClassFieldList = [];
|
||||||
|
|
||||||
|
if(superClass is CustomClass) {
|
||||||
|
var cls:Null<Dynamic> = superClass;
|
||||||
|
while(cls != null && cls is CustomClass) {
|
||||||
|
var currentClass = cast(cls, CustomClass);
|
||||||
|
var fields = [for(f in currentClass.__cachedFieldDecls.keys()) f];
|
||||||
|
__superClassFieldList.concat(fields);
|
||||||
|
|
||||||
|
var next = currentClass.superClass;
|
||||||
|
if(next == null)
|
||||||
|
break;
|
||||||
|
cls = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last fetched class is a real class
|
||||||
|
if(!(cls is CustomClass))
|
||||||
|
__superClassFieldList.concat(Reflect.fields(cls).concat(Type.getInstanceFields(Type.getClass(cls))));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var realFields = Reflect.fields(superClass).concat(Type.getInstanceFields(Type.getClass(superClass)));
|
||||||
|
__superClassFieldList.concat(realFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return __superClassFieldList.indexOf(name) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a function from the cache.
|
||||||
|
* This is useful when a function is broken and needs to be skipped.
|
||||||
|
* @param name The name of the function to remove from the cache.
|
||||||
|
*/
|
||||||
|
private function purgeFunction(name:String):Void {
|
||||||
|
if (__cachedFunctionDecls != null) {
|
||||||
|
__cachedFunctionDecls.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access fields
|
||||||
|
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
switch (name) {
|
||||||
|
case "superClass": return this.superClass;
|
||||||
|
case "createSuperClass": return this.createSuperClass;
|
||||||
|
case "hasFunction": return this.hasFunction;
|
||||||
|
case "callFunction": return this.callFunction;
|
||||||
|
default:
|
||||||
|
if (hasFunction(name)) {
|
||||||
|
var fn:Function = Reflect.makeVarArgs(function(args:Array<Dynamic>) {
|
||||||
|
return this.callFunction(name, args);
|
||||||
|
});
|
||||||
|
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasVar(name)) {
|
||||||
|
var v = getVar(name);
|
||||||
|
var getter = v.get;
|
||||||
|
var isInner = switch (accessContext) {
|
||||||
|
case CInner(cl): return cl == this.className;
|
||||||
|
default: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value:Dynamic = null;
|
||||||
|
|
||||||
|
if(getter == ANever || getter == ANull && (!isInner || !__allowPrivateAccess))
|
||||||
|
throw 'field $name cannot be accessed for reading';
|
||||||
|
|
||||||
|
if (__allowSetGet && getter == AGet) {
|
||||||
|
if (hasFunction('get_$name'))
|
||||||
|
value = __callGetter(name);
|
||||||
|
else
|
||||||
|
throw 'Method get_$name required by property $name is missing';
|
||||||
|
}
|
||||||
|
else if (this.interp.variables.exists(name))
|
||||||
|
value = this.interp.variables.get(name);
|
||||||
|
else {
|
||||||
|
if (v.expr != null) {
|
||||||
|
value = this.interp.expr(v.expr);
|
||||||
|
this.interp.variables.set(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.superClass != null) {
|
||||||
|
if (superHasField(name)) {
|
||||||
|
// Anonymous structure as a super class???
|
||||||
|
if (Type.getClass(this.superClass) == null) {
|
||||||
|
// Anonymous structure
|
||||||
|
if (Reflect.hasField(this.superClass, name))
|
||||||
|
return Reflect.field(this.superClass, name);
|
||||||
|
else
|
||||||
|
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '[ANONYMOUS STRUCTURE]'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.superClass is CustomClass) {
|
||||||
|
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
|
||||||
|
|
||||||
|
superCustomClass.__allowSetGet = this.__allowSetGet;
|
||||||
|
superCustomClass.__allowPrivateAccess = this.__allowPrivateAccess;
|
||||||
|
superCustomClass.accessContext = switch (accessContext) {
|
||||||
|
case CInner(_): CInner(superCustomClass.className);
|
||||||
|
default: COuter;
|
||||||
|
}
|
||||||
|
return superCustomClass.hget(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real Class
|
||||||
|
if (__allowSetGet)
|
||||||
|
Reflect.getProperty(this.superClass, name);
|
||||||
|
else
|
||||||
|
Reflect.field(this.superClass, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '" + Type.getClassName(Type.getClass(this.superClass)) + "'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw "field '" + name + "' does not exist in custom class '" + this.className + "'";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
switch (name) {
|
||||||
|
default:
|
||||||
|
if (hasVar(name)) {
|
||||||
|
var v = getVar(name);
|
||||||
|
var setter = v.set;
|
||||||
|
var isInner = switch (accessContext) {
|
||||||
|
case CInner(cl): return cl == this.className;
|
||||||
|
default: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setter == ANever || setter == ANull && (!isInner || !__allowPrivateAccess) || (v.isFinal && !initializing))
|
||||||
|
throw 'field $name cannot be accessed for writing';
|
||||||
|
|
||||||
|
if (__allowSetGet && setter == ASet) {
|
||||||
|
if (hasFunction('set_$name'))
|
||||||
|
return __callSetter(name, val);
|
||||||
|
else
|
||||||
|
throw 'Method set_$name required by property $name is missing';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interp.variables.set(name, val);
|
||||||
|
}
|
||||||
|
else if (this.superClass != null) {
|
||||||
|
if (superHasField(name)) {
|
||||||
|
if (Type.getClass(this.superClass) == null) {
|
||||||
|
// Anonymous structure
|
||||||
|
if (Reflect.hasField(this.superClass, name)) {
|
||||||
|
Reflect.setField(this.superClass, name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '[ANONYMOUS STRUCTURE]'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.superClass is CustomClass) {
|
||||||
|
var superCustomClass:CustomClass = cast(this.superClass, CustomClass);
|
||||||
|
|
||||||
|
superCustomClass.__allowSetGet = this.__allowSetGet;
|
||||||
|
superCustomClass.__allowPrivateAccess = this.__allowPrivateAccess;
|
||||||
|
superCustomClass.accessContext = switch (accessContext) {
|
||||||
|
case CInner(_): CInner(superCustomClass.className);
|
||||||
|
default: COuter;
|
||||||
|
}
|
||||||
|
return superCustomClass.hset(name, val);
|
||||||
|
}
|
||||||
|
// Real Class
|
||||||
|
|
||||||
|
if (__allowSetGet)
|
||||||
|
Reflect.setProperty(this.superClass, name, val);
|
||||||
|
else
|
||||||
|
Reflect.setField(this.superClass, name, val);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw "field '" + name + "' does not exist in custom class '" + this.className + "' or super class '" + Type.getClassName(Type.getClass(this.superClass)) + "'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw "field '" + name + "' does not exist in custom class '" + this.className + "'";
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callGetter(name:String):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var r = callFunction('get_$name');
|
||||||
|
__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var r = callFunction('set_$name', [val]);
|
||||||
|
__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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():Null<Dynamic> {
|
||||||
|
var cls:Null<Dynamic> = this.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
package hscript.customclass;
|
||||||
|
|
||||||
|
import hscript.Expr.AccessContext;
|
||||||
|
import hscript.proxy.ProxyType;
|
||||||
|
import hscript.customclass.utils.FunctionUtils;
|
||||||
|
import haxe.Constraints.Function;
|
||||||
|
import hscript.Expr.FieldDecl;
|
||||||
|
import hscript.Expr.VarDecl;
|
||||||
|
import hscript.Expr.FunctionDecl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ACTUAL "StaticHandler"
|
||||||
|
* @author Jamextreme140
|
||||||
|
*/
|
||||||
|
@:access(hscript.Interp)
|
||||||
|
@:structInit
|
||||||
|
class CustomClassDecl implements IHScriptCustomAccessBehaviour {
|
||||||
|
public var classDecl:Expr.ClassDecl; //This holds the class instantiation info
|
||||||
|
public var imports:Map<String, CustomClassImport>;
|
||||||
|
public var usings:Array<String>;
|
||||||
|
public var pkg:Null<Array<String>> = null;
|
||||||
|
public var ogInterp:Null<Interp> = null;
|
||||||
|
public var isInline:Null<Bool> = null;
|
||||||
|
|
||||||
|
public var staticInterp:Interp = new Interp();
|
||||||
|
|
||||||
|
public var superClassDecl(default, null):Dynamic = null; //This holds the super class reference.
|
||||||
|
|
||||||
|
var _cachedStaticFields:Map<String, FieldDecl> = [];
|
||||||
|
var _cachedStaticFunctions:Map<String, FunctionDecl> = [];
|
||||||
|
var _cachedStaticVariables:Map<String, VarDecl> = [];
|
||||||
|
|
||||||
|
public var __allowSetGet:Bool = true;
|
||||||
|
|
||||||
|
public var __allowPrivateAccess:Bool = false;
|
||||||
|
|
||||||
|
public var accessContext:AccessContext = COuter;
|
||||||
|
|
||||||
|
public final name:String;
|
||||||
|
|
||||||
|
public function new(classDecl:Expr.ClassDecl, imports:Map<String, CustomClassImport>, usings:Array<String>, ?pkg:Array<String>, ?ogInterp:Interp, ?isInline:Bool) {
|
||||||
|
this.classDecl = classDecl;
|
||||||
|
this.imports = imports;
|
||||||
|
this.usings = usings;
|
||||||
|
this.pkg = pkg;
|
||||||
|
this.ogInterp = ogInterp;
|
||||||
|
this.isInline = isInline;
|
||||||
|
|
||||||
|
// Cache the classname
|
||||||
|
var pkg = pkg != null ? '${pkg.join(".")}.' : "";
|
||||||
|
var className = classDecl.name;
|
||||||
|
this.name = '$pkg$className';
|
||||||
|
|
||||||
|
if(ogInterp != null) {
|
||||||
|
staticInterp.importFailedCallback = ogInterp.importFailedCallback;
|
||||||
|
staticInterp.errorHandler = ogInterp.errorHandler;
|
||||||
|
staticInterp.allowStaticVariables = ogInterp.allowStaticVariables;
|
||||||
|
staticInterp.staticVariables = ogInterp.staticVariables;
|
||||||
|
|
||||||
|
if(isInline != null && isInline) {
|
||||||
|
// uses public variables from the same scope as where the class was defined
|
||||||
|
staticInterp.variables = ogInterp.variables;
|
||||||
|
staticInterp.allowPublicVariables = ogInterp.allowPublicVariables;
|
||||||
|
staticInterp.publicVariables = ogInterp.publicVariables;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheImports();
|
||||||
|
processUsings();
|
||||||
|
cacheFields();
|
||||||
|
if(classDecl.extend != null)
|
||||||
|
buildSuperClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cacheImports() {
|
||||||
|
// This will make imported classes available for Static Functions
|
||||||
|
var i:Int = 0;
|
||||||
|
for(s => imp in imports) {
|
||||||
|
var importedClass = imp.fullPath;
|
||||||
|
var importAlias = imp.as;
|
||||||
|
|
||||||
|
if(this.staticInterp.variables.exists(imp.name)) continue; // class is already imported
|
||||||
|
|
||||||
|
if (Interp.customClassExist(importedClass) && this.staticInterp.importFailedCallback != null) {
|
||||||
|
this.staticInterp.importFailedCallback(importedClass.split("."), importAlias);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if hscriptPos
|
||||||
|
var e:Expr = {
|
||||||
|
e: ExprDef.EImport(importedClass, importAlias),
|
||||||
|
pmin: 0,
|
||||||
|
pmax: 0,
|
||||||
|
origin: this.classDecl.name,
|
||||||
|
line: i
|
||||||
|
};
|
||||||
|
i++;
|
||||||
|
#else
|
||||||
|
var e = Expr.EImport(importedClass, importAlias);
|
||||||
|
#end
|
||||||
|
this.staticInterp.expr(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cacheFields() {
|
||||||
|
for (f in classDecl.fields) {
|
||||||
|
if (f.access.contains(AStatic)) {
|
||||||
|
_cachedStaticFields.set(f.name, f);
|
||||||
|
switch (f.kind) {
|
||||||
|
case KFunction(fn):
|
||||||
|
_cachedStaticFunctions.set(f.name, fn);
|
||||||
|
#if hscriptPos
|
||||||
|
var fexpr:Expr = {
|
||||||
|
e: ExprDef.EFunction(fn.args, fn.body, f.name, fn.ret, false, false),
|
||||||
|
pmin: fn.body.pmin,
|
||||||
|
pmax: fn.body.pmax,
|
||||||
|
line: fn.body.line,
|
||||||
|
origin: fn.body.origin
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
var fexpr = Expr.EFunction(fn.args, fn.body, f.name, fn.ret, false, false);
|
||||||
|
#end
|
||||||
|
var func:Function = this.staticInterp.expr(fexpr);
|
||||||
|
this.staticInterp.variables.set(f.name, func);
|
||||||
|
case KVar(v):
|
||||||
|
if(v.get != ADefault || v.set != ADefault)
|
||||||
|
__allowSetGet = true;
|
||||||
|
_cachedStaticVariables.set(f.name, v);
|
||||||
|
if (v.expr != null) {
|
||||||
|
var varValue = this.staticInterp.expr(v.expr);
|
||||||
|
this.staticInterp.variables.set(f.name, varValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processUsings() {
|
||||||
|
for(us in usings) {
|
||||||
|
this.staticInterp.useUsing(us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSuperClass() {
|
||||||
|
var extendString = new Printer().typeToString(classDecl.extend);
|
||||||
|
if (this.pkg != null && extendString.indexOf(".") == -1) {
|
||||||
|
extendString = this.pkg.join(".") + "." + extendString;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cls:Dynamic = Type.resolveClass('${extendString}_HSX');
|
||||||
|
if(cls == null)
|
||||||
|
cls = ProxyType.resolveClass(extendString);
|
||||||
|
|
||||||
|
superClassDecl = cls;
|
||||||
|
|
||||||
|
if(superClassDecl == null)
|
||||||
|
staticInterp.error(ECustom("could not resolve super class: " + extendString));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function callFunction(name:String, ?args:Array<Dynamic>):Dynamic {
|
||||||
|
var func:Function = getFunction(name);
|
||||||
|
|
||||||
|
return FunctionUtils.callStaticFunction(name, this, staticInterp, func, args != null ? args : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasField(name:String):Bool {
|
||||||
|
return _cachedStaticFields.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasFunction(name:String) {
|
||||||
|
return _cachedStaticFunctions.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFunction(name:String):Function {
|
||||||
|
var fn = this.staticInterp.variables.get(name);
|
||||||
|
return Reflect.isFunction(fn) ? fn : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hasVar(name:String):Bool {
|
||||||
|
return _cachedStaticVariables.exists(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getVar(name:String):VarDecl {
|
||||||
|
return _cachedStaticVariables.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a function from the cache.
|
||||||
|
* This is useful when a function is broken and needs to be skipped.
|
||||||
|
* @param name The name of the function to remove from the cache.
|
||||||
|
*/
|
||||||
|
private function purgeFunction(name:String):Void {
|
||||||
|
if (_cachedStaticFunctions != null) {
|
||||||
|
_cachedStaticFunctions.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hget(name:String):Dynamic {
|
||||||
|
if(hasVar(name)) {
|
||||||
|
var v = getVar(name);
|
||||||
|
var getter = v.get;
|
||||||
|
var isInner = switch (accessContext) {
|
||||||
|
case CInner(cl): return cl == this.toString();
|
||||||
|
default: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var r:Dynamic = null;
|
||||||
|
|
||||||
|
if (getter == ANever || getter == ANull && (!isInner || !__allowPrivateAccess))
|
||||||
|
throw 'field $name cannot be accessed for reading';
|
||||||
|
|
||||||
|
if(__allowSetGet && getter == AGet){
|
||||||
|
if(hasFunction('get_$name'))
|
||||||
|
r = __callGetter(name);
|
||||||
|
else
|
||||||
|
throw 'Method get_$name required by property $name is missing';
|
||||||
|
}
|
||||||
|
else if (this.staticInterp.variables.exists(name))
|
||||||
|
r = this.staticInterp.variables.get(name);
|
||||||
|
else {
|
||||||
|
if(v.expr != null) {
|
||||||
|
r = this.staticInterp.expr(v.expr);
|
||||||
|
this.staticInterp.variables.set(name, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if(hasFunction(name)) {
|
||||||
|
// TODO: optimize this
|
||||||
|
var fn:Function = Reflect.makeVarArgs(function(args:Array<Dynamic>) {
|
||||||
|
return this.callFunction(name, args);
|
||||||
|
});
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "static field '" + name + "' does not exist in custom class '" + this.classDecl.name + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hset(name:String, val:Dynamic):Dynamic {
|
||||||
|
if (hasVar(name)) {
|
||||||
|
var v = getVar(name);
|
||||||
|
var setter = v.set;
|
||||||
|
var isInner = switch (accessContext) {
|
||||||
|
case CInner(cl): return cl == this.toString();
|
||||||
|
default: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setter == ANever || setter == ANull && (!isInner || !__allowPrivateAccess) || v.isFinal)
|
||||||
|
throw 'field $name cannot be accessed for writing';
|
||||||
|
|
||||||
|
if (__allowSetGet && setter == ASet) {
|
||||||
|
if (hasFunction('set_$name'))
|
||||||
|
return __callSetter(name, val);
|
||||||
|
else
|
||||||
|
throw 'Method set_$name required by property $name is missing';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.staticInterp.variables.set(name, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "static field '" + name + "' does not exist in custom class '" + this.classDecl.name + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callGetter(name:String):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var r = callFunction('get_${name}');
|
||||||
|
__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||||
|
__allowSetGet = false;
|
||||||
|
var r = callFunction('set_${name}', [val]);
|
||||||
|
__allowSetGet = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef CustomClassImport = {
|
||||||
|
var ?name:String;
|
||||||
|
var ?pkg:Array<String>;
|
||||||
|
var ?fullPath:String; // pkg.pkg.pkg.name
|
||||||
|
var ?as:Null<String>; // import pkg.Name as OtherName
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package hscript.customclass.utils;
|
||||||
|
|
||||||
|
import hscript.utils.UnsafeReflect;
|
||||||
|
import haxe.Constraints.Function;
|
||||||
|
|
||||||
|
@:access(hscript.customclass.CustomClassDecl)
|
||||||
|
class FunctionUtils {
|
||||||
|
public static inline function callStaticFunction(name:String, classDecl:CustomClassDecl, interp:Interp, fn:Function, args:Array<Dynamic> = null) {
|
||||||
|
var r:Dynamic = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (fn == null)
|
||||||
|
interp.error(ECustom('${name} is not a function'));
|
||||||
|
|
||||||
|
r = UnsafeReflect.callMethodUnsafe(null, fn, args);
|
||||||
|
} catch (e:hscript.Expr.Error) {
|
||||||
|
// A script error occurred while executing the custom class function.
|
||||||
|
// Purge the function from the cache so it is not called again.
|
||||||
|
classDecl.purgeFunction(name);
|
||||||
|
interp.error(#if hscriptPos e.e #else e #end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,14 +12,12 @@ using StringTools;
|
|||||||
|
|
||||||
class AbstractHandler {
|
class AbstractHandler {
|
||||||
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.AbstractHandler.build())');
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
#end
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function build():Array<Field> {
|
public static function build():Array<Field> {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -62,7 +61,6 @@ class ClassExtendMacro {
|
|||||||
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.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
|
||||||
@@ -256,27 +254,41 @@ class ClassExtendMacro {
|
|||||||
if (returns) {
|
if (returns) {
|
||||||
overrideExpr = macro {
|
overrideExpr = macro {
|
||||||
var name:String = $v{name};
|
var name:String = $v{name};
|
||||||
|
/*
|
||||||
if (__interp != null && __class__fields.contains(name)) {
|
if (__custom__variables != null) {
|
||||||
var v:Dynamic = null;
|
if(__custom__variables.exists(name)) {
|
||||||
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
var v:Dynamic = null;
|
||||||
return v($a{arguments});
|
if (Reflect.isFunction(v = __custom__variables.get(name))) {
|
||||||
|
return v($a{arguments});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
if (__customClass != null && @:privateAccess __customClass.hasFunction(name)) {
|
||||||
|
return __customClass.callFunction(name, [$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 (__custom__variables != null) {
|
||||||
var v:Dynamic = null;
|
if(__custom__variables.exists(name)) {
|
||||||
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
var v:Dynamic = null;
|
||||||
v($a{arguments});
|
if (Reflect.isFunction(v = __custom__variables.get(name))) {
|
||||||
return;
|
v($a{arguments});
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
if (__customClass != null && @:privateAccess __customClass.hasFunction(name)) {
|
||||||
|
__customClass.callFunction(name, [$a{arguments}]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
super.$name($a{arguments});
|
super.$name($a{arguments});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -339,6 +351,7 @@ class ClassExtendMacro {
|
|||||||
pack: cl.pack.copy(),
|
pack: cl.pack.copy(),
|
||||||
name: cl.name
|
name: cl.name
|
||||||
}, [
|
}, [
|
||||||
|
{name: "IHScriptCustomBehaviour", pack: ["hscript"]},
|
||||||
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
|
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
|
||||||
], false, true, false);
|
], false, true, false);
|
||||||
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
||||||
@@ -346,21 +359,28 @@ class ClassExtendMacro {
|
|||||||
Utils.setupMetas(shadowClass, imports);
|
Utils.setupMetas(shadowClass, imports);
|
||||||
Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect");
|
Utils.processImport(imports, "hscript.utils.UnsafeReflect", "UnsafeReflect");
|
||||||
|
|
||||||
// Adding hscript getters and setters
|
|
||||||
|
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__cachedFieldSet",
|
name: "__cachedFields",
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FVar(macro: Map<String, Dynamic>),
|
kind: FVar(macro: Map<String, Dynamic>),
|
||||||
access: [APublic, AStatic]
|
access: [APublic, AStatic]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Adding hscript getters and setters
|
||||||
|
/*
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__interp",
|
name: "__interp",
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FVar(macro: hscript.Interp),
|
kind: FVar(macro: hscript.Interp),
|
||||||
access: [APublic]
|
access: [APublic]
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
shadowClass.fields.push({
|
||||||
|
name: "__customClass",
|
||||||
|
pos: Context.currentPos(),
|
||||||
|
kind: FVar(macro: hscript.customclass.CustomClass),
|
||||||
|
access: [APublic]
|
||||||
|
});
|
||||||
/*
|
/*
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__custom__variables",
|
name: "__custom__variables",
|
||||||
@@ -368,28 +388,30 @@ class ClassExtendMacro {
|
|||||||
kind: FVar(macro: Map<String, Dynamic>),
|
kind: FVar(macro: Map<String, Dynamic>),
|
||||||
access: [APublic]
|
access: [APublic]
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__allowSetGet",
|
name: "__allowSetGet",
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FVar(macro: Bool, macro true),
|
kind: FVar(macro: Bool, macro true),
|
||||||
access: [APublic]
|
access: [APublic]
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__real_fields",
|
name: "__real_fields",
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FVar(macro: Array<String>),
|
kind: FVar(macro: Array<String>),
|
||||||
access: [APublic]
|
access: [APublic]
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__class__fields",
|
name: "__class__fields",
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FVar(macro: Array<String>),
|
kind: FVar(macro: Array<String>),
|
||||||
access: [APublic]
|
access: [APublic]
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
// Unneccessary since the get/set call is already handled.
|
||||||
|
/*
|
||||||
shadowClass.fields.push({
|
shadowClass.fields.push({
|
||||||
name: "__callGetter",
|
name: "__callGetter",
|
||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
@@ -397,7 +419,10 @@ class ClassExtendMacro {
|
|||||||
ret: macro: Dynamic,
|
ret: macro: Dynamic,
|
||||||
params: [],
|
params: [],
|
||||||
expr: macro {
|
expr: macro {
|
||||||
return null;
|
__allowSetGet = false;
|
||||||
|
var v = __custom__variables.get("get_" + name)();
|
||||||
|
__allowSetGet = true;
|
||||||
|
return v;
|
||||||
},
|
},
|
||||||
args: [
|
args: [
|
||||||
{
|
{
|
||||||
@@ -418,7 +443,10 @@ class ClassExtendMacro {
|
|||||||
ret: macro: Dynamic,
|
ret: macro: Dynamic,
|
||||||
params: [],
|
params: [],
|
||||||
expr: macro {
|
expr: macro {
|
||||||
return null;
|
__allowSetGet = false;
|
||||||
|
var v = __custom__variables.get("set_" + name)(val);
|
||||||
|
__allowSetGet = true;
|
||||||
|
return v;
|
||||||
},
|
},
|
||||||
args: [
|
args: [
|
||||||
{
|
{
|
||||||
@@ -437,7 +465,7 @@ class ClassExtendMacro {
|
|||||||
}),
|
}),
|
||||||
access: [APublic]
|
access: [APublic]
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
// Todo: make it possible to override
|
// Todo: make it possible to override
|
||||||
if(cl.name == "FunkinShader" || cl.name == "CustomShader" || cl.name == "MultiThreadedScript") {
|
if(cl.name == "FunkinShader" || cl.name == "CustomShader" || cl.name == "MultiThreadedScript") {
|
||||||
Context.defineModule(cl.module, [shadowClass], imports);
|
Context.defineModule(cl.module, [shadowClass], imports);
|
||||||
@@ -480,84 +508,43 @@ class ClassExtendMacro {
|
|||||||
|
|
||||||
var hgetField = if(hasHgetInSuper) {
|
var hgetField = if(hasHgetInSuper) {
|
||||||
macro {
|
macro {
|
||||||
if (__interp != null) {
|
/*
|
||||||
if(__class__fields.contains(name)) {
|
if(__custom__variables != null) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
return __callGetter(name);
|
||||||
if(v != null && v is hscript.Property)
|
if (__custom__variables.exists(name))
|
||||||
return cast(v, hscript.Property).get(ba);
|
return __custom__variables.get(name);
|
||||||
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(__class__fields.contains(name)) {
|
if(__custom__variables != null) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
return __callGetter(name);
|
||||||
if(v != null && v is hscript.Property)
|
if (__custom__variables.exists(name))
|
||||||
return cast(v, hscript.Property).get(ba);
|
return __custom__variables.get(name);
|
||||||
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);
|
return UnsafeReflect.getProperty(this, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var hsetField = if(hasHsetInSuper) {
|
var hsetField = if(hasHsetInSuper) {
|
||||||
macro {
|
macro {
|
||||||
if (__interp != null) {
|
/*
|
||||||
if(__class__fields.contains(name)) {
|
if(__custom__variables != null) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
return __callSetter(name, val);
|
||||||
if(v != null && v is hscript.Property)
|
if (__custom__variables.exists(name)) {
|
||||||
return cast(v, hscript.Property).set(val, ba);
|
__custom__variables.set(name, val);
|
||||||
__interp.variables.set(name, val);
|
|
||||||
return 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(__real_fields.contains(name)) {
|
if(__real_fields != null && __real_fields.contains(name)) {
|
||||||
UnsafeReflect.setProperty(this, name, val);
|
UnsafeReflect.setProperty(this, name, val);
|
||||||
return UnsafeReflect.field(this, name);
|
return UnsafeReflect.field(this, name);
|
||||||
}
|
}
|
||||||
@@ -565,34 +552,21 @@ class ClassExtendMacro {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
macro {
|
macro {
|
||||||
if (__interp != null) {
|
/*
|
||||||
if(__class__fields.contains(name)) {
|
if(__custom__variables != null) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
return __callSetter(name, val);
|
||||||
if(v != null && v is hscript.Property)
|
if (__custom__variables.exists(name)) {
|
||||||
return cast(v, hscript.Property).set(val, ba);
|
__custom__variables.set(name, val);
|
||||||
__interp.variables.set(name, val);
|
|
||||||
return 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(__real_fields.contains(name)) {
|
if(__real_fields != null && __real_fields.contains(name)) {
|
||||||
UnsafeReflect.setProperty(this, name, val);
|
UnsafeReflect.setProperty(this, name, val);
|
||||||
return UnsafeReflect.field(this, name);
|
return UnsafeReflect.field(this, name);
|
||||||
}
|
}
|
||||||
//__custom__variables.set(name, val);
|
//if(__custom__variables != null) __custom__variables.set(name, val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -644,7 +618,7 @@ class ClassExtendMacro {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
/*var p = new Printer();
|
/*var p = new Printer();
|
||||||
var aa = p.printTypeDefinition(shadowClass);
|
var aa = p.printTypeDefinition(shadowClass);
|
||||||
if(aa.length < 5024)
|
if(aa.length < 5024)
|
||||||
@@ -667,41 +641,22 @@ class ClassExtendMacro {
|
|||||||
pos: Context.currentPos(),
|
pos: Context.currentPos(),
|
||||||
kind: FFun({
|
kind: FFun({
|
||||||
args: constArgs,
|
args: constArgs,
|
||||||
expr: macro {
|
expr: macro
|
||||||
|
{
|
||||||
// Call the super constructor with appropriate args
|
// Call the super constructor with appropriate args
|
||||||
super($a{superCallArgs});
|
super($a{superCallArgs});
|
||||||
|
|
||||||
if(__cachedFieldSet != null) {
|
if(__cachedFields != null) {
|
||||||
for(k => v in __cachedFieldSet) {
|
for(k => v in __cachedFields) {
|
||||||
Reflect.setProperty(this, k, v);
|
Reflect.setProperty(this, k, v);
|
||||||
|
trace(k);
|
||||||
}
|
}
|
||||||
__cachedFieldSet.clear();
|
__cachedFields = null;
|
||||||
__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 {
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package hscript.macros;
|
||||||
|
|
||||||
|
#if macro
|
||||||
|
import Type.ValueType;
|
||||||
|
import haxe.macro.Compiler;
|
||||||
|
import haxe.macro.Context;
|
||||||
|
import haxe.macro.Expr;
|
||||||
|
|
||||||
|
using Lambda;
|
||||||
|
using StringTools;
|
||||||
|
using haxe.macro.Tools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro used for the `using Class;` keyword
|
||||||
|
*
|
||||||
|
* you can make classes be able to be used specifing the classes/packages on Config.hx!
|
||||||
|
* or implementing the interface `hscript.utils.UsingClass`
|
||||||
|
* ```haxe
|
||||||
|
* public static final ALLOWED_USING = ["my.pack.VeryNiceTools"];
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* ```haxe
|
||||||
|
* package my.pack;
|
||||||
|
* // @:usableEntry() // optional
|
||||||
|
* // @:usableEntry(forceAny) // optional // forces the class to be called with any type
|
||||||
|
* // @:usableEntry(onlyBasic) // optional // only basic types will be allowed
|
||||||
|
* // @:usableEntry(onlyBasic, forceAny) // optional // only basic types will be allowed, and the class will be called with any type
|
||||||
|
* class VeryNiceTools implements hscript.utils.UsingClass {}
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @author NeeEoo
|
||||||
|
* @see https://github.com/pisayesiwsi/hscript-iris/blob/master/crowplexus/iris/macro/UsingMacro.macro.hx
|
||||||
|
**/
|
||||||
|
class UsingMacro {
|
||||||
|
public static inline final USING_PREFIX = "_HX_USING__";
|
||||||
|
|
||||||
|
public static var unallowedMetas:Array<String> = [":noUsing", ":noUse"];
|
||||||
|
|
||||||
|
public static function init() {
|
||||||
|
#if !display
|
||||||
|
if(Context.defined("display")) return;
|
||||||
|
for(apply in Config.ALLOWED_USING) {
|
||||||
|
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.UsingMacro.build())");
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function build() {
|
||||||
|
var cls: haxe.macro.Type.ClassType = Context.getLocalClass().get();
|
||||||
|
var fields = Context.getBuildFields();
|
||||||
|
|
||||||
|
var key = cls.module;
|
||||||
|
var fkey = cls.module + "." + cls.name;
|
||||||
|
var packName = (cls.pack.length > 0 ? cls.pack.join(".") + "." : "") + cls.name;
|
||||||
|
|
||||||
|
if(cls.meta.get().find(function(m) return m.name == ':usingProcessed') != null) return fields;
|
||||||
|
if (Config.DISALLOW_USING.contains(key) || Config.DISALLOW_USING.contains(fkey) || Config.DISALLOW_USING.contains(packName))
|
||||||
|
return fields;
|
||||||
|
|
||||||
|
var entryField = cls.meta.get().find(function(m) return m.name == ':usableEntry');
|
||||||
|
var hasParams = entryField != null && entryField.params != null;
|
||||||
|
var forceAny = false;
|
||||||
|
var onlyBasic = false;
|
||||||
|
if (hasParams) {
|
||||||
|
for (i in 0...entryField.params.length) {
|
||||||
|
if (entryField.params[i].expr.match(EConst(CIdent("onlyBasic"))))
|
||||||
|
onlyBasic = true;
|
||||||
|
if (entryField.params[i].expr.match(EConst(CIdent("forceAny"))))
|
||||||
|
forceAny = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var data: Array<Array<String>> = [];
|
||||||
|
|
||||||
|
for (field in fields) {
|
||||||
|
// functions marked with @:noUsing won't be able to be used by variables
|
||||||
|
// also if you want it to be usable in source, but not in the script, use @:noUse
|
||||||
|
for(m in field.meta)
|
||||||
|
if(unallowedMetas.contains(m.name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// It's called "static extensions" for some reason
|
||||||
|
if(!field.access.contains(AStatic))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (field.kind) {
|
||||||
|
default:
|
||||||
|
case FFun(f):
|
||||||
|
if (f.args.length == 0)
|
||||||
|
continue;
|
||||||
|
var arg = f.args[0];
|
||||||
|
if (arg.type == null)
|
||||||
|
continue;
|
||||||
|
var type = arg.type;
|
||||||
|
|
||||||
|
var valueType: String = switch (type) {
|
||||||
|
case TPath({name: "Int", pack: []}):
|
||||||
|
"TInt";
|
||||||
|
case TPath({name: "Float", pack: []}):
|
||||||
|
"TFloat";
|
||||||
|
case TPath({name: "Single", pack: []}):
|
||||||
|
"TFloat";
|
||||||
|
case TPath({name: "String", pack: []}):
|
||||||
|
"TClass(String)";
|
||||||
|
case TPath({name: "Bool", pack: []}):
|
||||||
|
"TBool";
|
||||||
|
case TPath({name: "Array", pack: []}):
|
||||||
|
"TClass(Array)";
|
||||||
|
case TPath({name: "Map", pack: []}):
|
||||||
|
"TClass(haxe.Constraints.IMap)";
|
||||||
|
case TPath({name: "Dynamic", pack: []}):
|
||||||
|
null;
|
||||||
|
case TPath({name: "Class", pack: []}):
|
||||||
|
"TClass(null)"; // this feels wrong
|
||||||
|
case TPath({name: "Enum", pack: []}):
|
||||||
|
"TEnum(null)";
|
||||||
|
// case TPath({name: "Void", pack: []}): "ValueType.TVoid";
|
||||||
|
default:
|
||||||
|
null; // null acts as a wildcard
|
||||||
|
}
|
||||||
|
|
||||||
|
// MIGHT CRASH COMPILATION? YEAH, IT CRASH ON TYPE PARAMETERS
|
||||||
|
if (!onlyBasic && valueType == null) {
|
||||||
|
var rtype:haxe.macro.Type = null;
|
||||||
|
|
||||||
|
try {rtype = type.toType();} catch(e) {}
|
||||||
|
|
||||||
|
if(rtype != null) {
|
||||||
|
switch (rtype) {
|
||||||
|
case TInst(t, []):
|
||||||
|
valueType = "TClass(" + t.toString() + ")";
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceAny) {
|
||||||
|
valueType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.push([field.name, valueType]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.length == 0)
|
||||||
|
return fields;
|
||||||
|
|
||||||
|
fields.push({
|
||||||
|
name: '$USING_PREFIX${packName.replace(".", "_")}',
|
||||||
|
access: [APrivate, AStatic],
|
||||||
|
kind: FVar(macro : Map<String, Type.ValueType>, {
|
||||||
|
var arr: Array<Expr> = [];
|
||||||
|
for (i in data)
|
||||||
|
if (i[1] != null)
|
||||||
|
arr.push(macro $v{i[0]} => ${Context.parse("Type.ValueType." + i[1], Context.currentPos())});
|
||||||
|
else
|
||||||
|
arr.push(macro $v{i[0]} => null);
|
||||||
|
macro $a{arr};
|
||||||
|
}),
|
||||||
|
pos: cls.pos,
|
||||||
|
});
|
||||||
|
|
||||||
|
//var printer = new haxe.macro.Printer();
|
||||||
|
//trace(printer.printField(fields[fields.length - 1]));
|
||||||
|
|
||||||
|
cls.meta.add(':usingProcessed', [], cls.pos);
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
package hscript.proxy;
|
||||||
|
|
||||||
|
import hscript.customclass.CustomClass;
|
||||||
|
import hscript.customclass.CustomClassDecl;
|
||||||
|
import hscript.Tools.HScriptEnum;
|
||||||
|
import hscript.Tools.EnumValue as HScriptEnumValue;
|
||||||
|
|
||||||
|
abstract OneOfTwo<T1, T2>(Dynamic) from T1 from T2 to T1 to T2 {}
|
||||||
|
|
||||||
|
@:allow(hscript.customclass.CustomClass)
|
||||||
|
@:allow(hscript.customclass.CustomClassDecl)
|
||||||
|
class ProxyType {
|
||||||
|
/**
|
||||||
|
Returns the class of `o`, if `o` is a class instance.
|
||||||
|
|
||||||
|
If `o` is null or of a different type, null is returned.
|
||||||
|
|
||||||
|
In general, type parameter information cannot be obtained at runtime.
|
||||||
|
**/
|
||||||
|
inline static function getClass<T>(o:OneOfTwo<T, CustomClass>):Null<Dynamic> {
|
||||||
|
if(o is CustomClass)
|
||||||
|
@:privateAccess return cast(o, CustomClass).__class;
|
||||||
|
return Type.getClass(cast o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the enum of enum instance `o`.
|
||||||
|
|
||||||
|
An enum instance is the result of using an enum constructor. Given an
|
||||||
|
`enum Color { Red; }`, `getEnum(Red)` returns `Enum<Color>`.
|
||||||
|
|
||||||
|
If `o` is null, null is returned.
|
||||||
|
|
||||||
|
In general, type parameter information cannot be obtained at runtime.
|
||||||
|
**/
|
||||||
|
inline static function getEnum(o:OneOfTwo<EnumValue, HScriptEnumValue>):Dynamic {
|
||||||
|
// TODO: SUPPORT HSCRIPT ENUMS
|
||||||
|
var isScripted:Bool = Std.isOfType(o, HScriptEnumValue);
|
||||||
|
if(isScripted) {
|
||||||
|
return cast(o, HScriptEnumValue).enumParent;
|
||||||
|
}
|
||||||
|
return Type.getEnum(cast o);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the super-class of class `c`.
|
||||||
|
|
||||||
|
If `c` has no super class, null is returned.
|
||||||
|
|
||||||
|
If `c` is null, the result is unspecified.
|
||||||
|
|
||||||
|
In general, type parameter information cannot be obtained at runtime.
|
||||||
|
**/
|
||||||
|
inline static function getSuperClass(c:OneOfTwo<Class<Dynamic>, CustomClassDecl>):Dynamic {
|
||||||
|
if(c is CustomClassDecl) {
|
||||||
|
return cast(c, CustomClassDecl).superClassDecl;
|
||||||
|
}
|
||||||
|
return Type.getSuperClass(cast c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the name of class `c`, including its path.
|
||||||
|
|
||||||
|
If `c` is inside a package, the package structure is returned dot-
|
||||||
|
separated, with another dot separating the class name:
|
||||||
|
`pack1.pack2.(...).packN.ClassName`
|
||||||
|
If `c` is a sub-type of a Haxe module, that module is not part of the
|
||||||
|
package structure.
|
||||||
|
|
||||||
|
If `c` has no package, the class name is returned.
|
||||||
|
|
||||||
|
If `c` is null, the result is unspecified.
|
||||||
|
|
||||||
|
The class name does not include any type parameters.
|
||||||
|
**/
|
||||||
|
inline static function getClassName(c:OneOfTwo<Class<Dynamic>, CustomClassDecl>):String {
|
||||||
|
if(c is CustomClassDecl) {
|
||||||
|
var cls:CustomClassDecl = cast c;
|
||||||
|
var name = cls.classDecl.name;
|
||||||
|
var pkg = cls.pkg != null ? '${cls.pkg.join(".")}.' : "";
|
||||||
|
return '$pkg$name';
|
||||||
|
}
|
||||||
|
return Type.getClassName(cast c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the name of enum `e`, including its path.
|
||||||
|
|
||||||
|
If `e` is inside a package, the package structure is returned dot-
|
||||||
|
separated, with another dot separating the enum name:
|
||||||
|
`pack1.pack2.(...).packN.EnumName`
|
||||||
|
If `e` is a sub-type of a Haxe module, that module is not part of the
|
||||||
|
package structure.
|
||||||
|
|
||||||
|
If `e` has no package, the enum name is returned.
|
||||||
|
|
||||||
|
If `e` is null, the result is unspecified.
|
||||||
|
|
||||||
|
The enum name does not include any type parameters.
|
||||||
|
**/
|
||||||
|
inline static function getEnumName(e:Enum<Dynamic>):String {
|
||||||
|
var isScripted:Bool = Std.isOfType(e, HScriptEnumValue);
|
||||||
|
if (isScripted)
|
||||||
|
return cast(e, HScriptEnumValue).getEnumName();
|
||||||
|
return Type.getEnumName(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Resolves a class by name.
|
||||||
|
|
||||||
|
If `name` is the path of an existing class, that class is returned.
|
||||||
|
|
||||||
|
Otherwise null is returned.
|
||||||
|
|
||||||
|
If `name` is null or the path to a different type, the result is
|
||||||
|
unspecified.
|
||||||
|
|
||||||
|
The class name must not include any type parameters.
|
||||||
|
**/
|
||||||
|
inline static function resolveClass(name:String):Dynamic {
|
||||||
|
if(Interp.customClassExist(name)) {
|
||||||
|
return Interp.getCustomClass(name);
|
||||||
|
}
|
||||||
|
return Type.resolveClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Resolves an enum by name.
|
||||||
|
|
||||||
|
If `name` is the path of an existing enum, that enum is returned.
|
||||||
|
|
||||||
|
Otherwise null is returned.
|
||||||
|
|
||||||
|
If `name` is null the result is unspecified.
|
||||||
|
|
||||||
|
If `name` is the path to a different type, null is returned.
|
||||||
|
|
||||||
|
The enum name must not include any type parameters.
|
||||||
|
**/
|
||||||
|
inline static function resolveEnum(name:String):Enum<Dynamic> {
|
||||||
|
return Type.resolveEnum(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates an instance of class `cl`, using `args` as arguments to the
|
||||||
|
class constructor.
|
||||||
|
|
||||||
|
This function guarantees that the class constructor is called.
|
||||||
|
|
||||||
|
Default values of constructors arguments are not guaranteed to be
|
||||||
|
taken into account.
|
||||||
|
|
||||||
|
If `cl` or `args` are null, or if the number of elements in `args` does
|
||||||
|
not match the expected number of constructor arguments, or if any
|
||||||
|
argument has an invalid type, or if `cl` has no own constructor, the
|
||||||
|
result is unspecified.
|
||||||
|
|
||||||
|
In particular, default values of constructor arguments are not
|
||||||
|
guaranteed to be taken into account.
|
||||||
|
**/
|
||||||
|
inline static function createInstance<T>(cl:OneOfTwo<Class<T>, CustomClassDecl>, args:Array<Dynamic>):T {
|
||||||
|
// TODO: somehow pass the ogInterp argument without breaking the original functionality
|
||||||
|
if(cl is CustomClassDecl) {
|
||||||
|
return cast new CustomClass(cast cl, args);
|
||||||
|
}
|
||||||
|
return Type.createInstance(cast cl, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates an instance of class `cl`.
|
||||||
|
|
||||||
|
This function guarantees that the class constructor is not called.
|
||||||
|
|
||||||
|
If `cl` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function createEmptyInstance<T>(cl:OneOfTwo<Class<T>, CustomClassDecl>):T {
|
||||||
|
// TODO: same as above
|
||||||
|
if(cl is CustomClassDecl)
|
||||||
|
return cast new CustomClass(cast cl, [], null, null, false);
|
||||||
|
return Type.createEmptyInstance(cast cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates an instance of enum `e` by calling its constructor `constr` with
|
||||||
|
arguments `params`.
|
||||||
|
|
||||||
|
If `e` or `constr` is null, or if enum `e` has no constructor named
|
||||||
|
`constr`, or if the number of elements in `params` does not match the
|
||||||
|
expected number of constructor arguments, or if any argument has an
|
||||||
|
invalid type, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function createEnum<T>(e:OneOfTwo<Enum<T>, HScriptEnum>, constr:String, ?params:Array<Dynamic>):T {
|
||||||
|
// TODO: SUPPORT HSCRIPT ENUMS
|
||||||
|
var isScripted:Bool = Std.isOfType(e, HScriptEnum);
|
||||||
|
if(isScripted) {
|
||||||
|
var scriptEnum:HScriptEnum = cast e;
|
||||||
|
var enumToCreate = scriptEnum.getEnumValue(constr);
|
||||||
|
if(Reflect.isFunction(enumToCreate)) {
|
||||||
|
return Reflect.callMethod(null, enumToCreate, params);
|
||||||
|
}
|
||||||
|
return enumToCreate;
|
||||||
|
}
|
||||||
|
return Type.createEnum(cast e, constr, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Creates an instance of enum `e` by calling its constructor number
|
||||||
|
`index` with arguments `params`.
|
||||||
|
|
||||||
|
The constructor indices are preserved from Haxe syntax, so the first
|
||||||
|
declared is index 0, the next index 1 etc.
|
||||||
|
|
||||||
|
If `e` or `constr` is null, or if enum `e` has no constructor named
|
||||||
|
`constr`, or if the number of elements in `params` does not match the
|
||||||
|
expected number of constructor arguments, or if any argument has an
|
||||||
|
invalid type, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function createEnumIndex<T>(e:Enum<T>, index:Int, ?params:Array<Dynamic>):T {
|
||||||
|
// TODO: SUPPORT HSCRIPT ENUMS
|
||||||
|
return Type.createEnumIndex(e, index, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of the instance fields of class `c`, including
|
||||||
|
inherited fields.
|
||||||
|
|
||||||
|
This only includes fields which are known at compile-time. In
|
||||||
|
particular, using `getInstanceFields(getClass(obj))` will not include
|
||||||
|
any fields which were added to `obj` at runtime.
|
||||||
|
|
||||||
|
The order of the fields in the returned Array is unspecified.
|
||||||
|
|
||||||
|
If `c` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function getInstanceFields(c:OneOfTwo<Class<Dynamic>, CustomClassDecl>):Array<String> {
|
||||||
|
if(c is CustomClassDecl) {
|
||||||
|
var cls:CustomClassDecl = cast c;
|
||||||
|
return [for(f in Tools.getClassDeclFields(cls.classDecl)) f.name];
|
||||||
|
}
|
||||||
|
return Type.getInstanceFields(cast c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of static fields of class `c`.
|
||||||
|
|
||||||
|
This does not include static fields of parent classes.
|
||||||
|
|
||||||
|
The order of the fields in the returned Array is unspecified.
|
||||||
|
|
||||||
|
If `c` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function getClassFields(c:OneOfTwo<Class<Dynamic>, CustomClassDecl>):Array<String> {
|
||||||
|
if(c is CustomClassDecl) {
|
||||||
|
var cls:CustomClassDecl = cast c;
|
||||||
|
return [for(f in Tools.getClassDeclFields(cls.classDecl, true)) f.name];
|
||||||
|
}
|
||||||
|
return Type.getClassFields(cast c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of the names of all constructors of enum `e`.
|
||||||
|
|
||||||
|
The order of the constructor names in the returned Array is preserved
|
||||||
|
from the original syntax.
|
||||||
|
|
||||||
|
If `e` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function getEnumConstructs(e:OneOfTwo<Enum<Dynamic>, HScriptEnum>):Array<String> {
|
||||||
|
// TODO: SUPPORT HSCRIPT ENUMS
|
||||||
|
return Type.getEnumConstructs(cast e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the runtime type of value `v`.
|
||||||
|
|
||||||
|
The result corresponds to the type `v` has at runtime, which may vary
|
||||||
|
per platform. Assumptions regarding this should be minimized to avoid
|
||||||
|
surprises.
|
||||||
|
**/
|
||||||
|
inline static function typeof(v:Dynamic):Type.ValueType {
|
||||||
|
return Type.typeof(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Recursively compares two enum instances `a` and `b` by value.
|
||||||
|
|
||||||
|
Unlike `a == b`, this function performs a deep equality check on the
|
||||||
|
arguments of the constructors, if exists.
|
||||||
|
|
||||||
|
If `a` or `b` are null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function enumEq(a:Dynamic, b:Dynamic):Bool {
|
||||||
|
var isScripted:Bool = Std.isOfType(a, HScriptEnumValue) && Std.isOfType(b, HScriptEnumValue);
|
||||||
|
if (isScripted)
|
||||||
|
return cast(a, HScriptEnumValue).compare(cast(b, HScriptEnumValue));
|
||||||
|
return Type.enumEq(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the constructor name of enum instance `e`.
|
||||||
|
|
||||||
|
The result String does not contain any constructor arguments.
|
||||||
|
|
||||||
|
If `e` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function enumConstructor(e:Dynamic):String {
|
||||||
|
if (Std.isOfType(e, HScriptEnumValue))
|
||||||
|
return cast(e, HScriptEnumValue).name;
|
||||||
|
return Type.enumConstructor(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of the constructor arguments of enum instance `e`.
|
||||||
|
|
||||||
|
If `e` has no arguments, the result is [].
|
||||||
|
|
||||||
|
Otherwise the result are the values that were used as arguments to `e`,
|
||||||
|
in the order of their declaration.
|
||||||
|
|
||||||
|
If `e` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function enumParameters(e:Dynamic):Array<Dynamic> {
|
||||||
|
if (Std.isOfType(e, HScriptEnumValue))
|
||||||
|
return cast(e, HScriptEnumValue).args;
|
||||||
|
return Type.enumParameters(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the index of enum instance `e`.
|
||||||
|
|
||||||
|
This corresponds to the original syntactic position of `e`. The index of
|
||||||
|
the first declared constructor is 0, the next one is 1 etc.
|
||||||
|
|
||||||
|
If `e` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function enumIndex(e:Dynamic):Int {
|
||||||
|
if (Std.isOfType(e, HScriptEnumValue))
|
||||||
|
return cast(e, HScriptEnumValue).index;
|
||||||
|
return Type.enumIndex(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns a list of all constructors of enum `e` that require no
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
This may return the empty Array `[]` if all constructors of `e` require
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
Otherwise an instance of `e` constructed through each of its non-
|
||||||
|
argument constructors is returned, in the order of the constructor
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
If `e` is null, the result is unspecified.
|
||||||
|
**/
|
||||||
|
inline static function allEnums<T>(e:OneOfTwo<Enum<T>, HScriptEnum>):Array<T> {
|
||||||
|
// TODO: SUPPORT HSCRIPT ENUMS
|
||||||
|
var isScripted:Bool = Std.isOfType(e, HScriptEnum);
|
||||||
|
if(isScripted) {
|
||||||
|
var hEnum:HScriptEnum = cast e;
|
||||||
|
return [for(en in Reflect.fields(hEnum.enumValues)) Reflect.field(hEnum, en)];
|
||||||
|
}
|
||||||
|
return Type.allEnums(cast e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package hscript.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to mark classes that can be used with the `using` keyword.
|
||||||
|
* You can also add @:usableEntry to your class.
|
||||||
|
* If you wanna force the class to be called with any type, you can add @:usableEntry(forceAny)
|
||||||
|
**/
|
||||||
|
@:autoBuild(hscript.macros.UsingMacro.build())
|
||||||
|
interface UsingClass {}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package hscript.utils;
|
||||||
|
|
||||||
|
typedef UsingCall = (o: Dynamic, f: String, args: Array<Dynamic>) -> Dynamic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code based on Using system from "hscript-iris"
|
||||||
|
* @see https://github.com/pisayesiwsi/hscript-iris/blob/master/crowplexus/iris/utils/UsingEntry.hx
|
||||||
|
*/
|
||||||
|
class UsingEntry {
|
||||||
|
public var name: String;
|
||||||
|
public var call: UsingCall;
|
||||||
|
|
||||||
|
public function new(name: String, call: UsingCall) {
|
||||||
|
this.name = name;
|
||||||
|
this.call = call;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,82 +1,45 @@
|
|||||||
package hscript.utils;
|
package hscript.utils;
|
||||||
|
|
||||||
@:structInit
|
import hscript.utils.UsingEntry.UsingCall;
|
||||||
class UsingEntry {
|
import StringTools;
|
||||||
public var call:Dynamic->String->Array<Dynamic>->Dynamic;
|
import Lambda;
|
||||||
public var fields:Array<String>;
|
|
||||||
|
|
||||||
public function hasField(name:String) {
|
class UsingHandler {
|
||||||
return fields.contains(name);
|
public static var usingEntries:Array<UsingEntry> = [
|
||||||
}
|
new UsingEntry("StringTools", function(o: Dynamic, f: String, args: Array<Dynamic>): Dynamic {
|
||||||
}
|
if (f == "isEof") // has @:noUsing
|
||||||
|
return null;
|
||||||
/**
|
switch (Type.typeof(o)) {
|
||||||
* Special class that handles static extension function calls.
|
case TInt if (f == "hex"):
|
||||||
*
|
return StringTools.hex(o, args[0]);
|
||||||
* A static extension allows pseudo-extending
|
case TClass(String):
|
||||||
* existing types without modifying their source.
|
if (Reflect.hasField(StringTools, f)) {
|
||||||
* In Haxe this is achieved by declaring a static method with a first argument
|
var field = Reflect.field(StringTools, f);
|
||||||
* of the extending type and then bringing the defining class into context through `using`.
|
if (Reflect.isFunction(field)) {
|
||||||
*
|
return Reflect.callMethod(StringTools, field, [o].concat(args));
|
||||||
* Example:
|
}
|
||||||
* ```haxe
|
}
|
||||||
* class IntExtender {
|
default:
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
return null;
|
||||||
"Lambda" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L62
|
}),
|
||||||
fields: Type.getClassFields(Lambda),
|
new UsingEntry("Lambda", function(o: Dynamic, f: String, args: Array<Dynamic>): Dynamic {
|
||||||
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
if (Tools.isIterable(o)) {
|
||||||
if (o != null && o.iterator != null) {
|
// TODO: Check if the values are Iterable<T>
|
||||||
var field = UnsafeReflect.field(Lambda, f);
|
if (Reflect.hasField(Lambda, f)) {
|
||||||
if (UnsafeReflect.isFunction(field)) {
|
var field = Reflect.field(Lambda, f);
|
||||||
return UnsafeReflect.callMethodUnsafe(Lambda, field, [o].concat(args));
|
if (Reflect.isFunction(field)) {
|
||||||
|
return Reflect.callMethod(Lambda, field, [o].concat(args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
];
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
@:allow(hscript.CustomClass)
|
public static function registerUsingGlobal(name: String, call:UsingCall):UsingEntry {
|
||||||
@:allow(hscript.CustomClassHandler)
|
var entry = new UsingEntry(name, call);
|
||||||
public var usingEntries(default, null):Map<String, UsingEntry> = [];
|
usingEntries.push(entry);
|
||||||
|
return entry;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user