Compare commits
98
Commits
+1
-1
@@ -1,4 +1,4 @@
|
||||
/hscript.swf
|
||||
/release.zip
|
||||
|
||||
dump/*
|
||||
tests/bin/*
|
||||
@@ -1,16 +1,28 @@
|
||||
hscript-improved
|
||||
=======
|
||||
|
||||
- [Features](docs/FEATURES.md)
|
||||
|
||||
How to install
|
||||
```
|
||||
haxelib git hscript-improved https://github.com/FNF-CNE-Devs/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
|
||||
|
||||
```xml
|
||||
<define name="CUSTOM_CLASSES" />
|
||||
```
|
||||
Warning: custom classes are sometimes broken, would like help to fix them. You can only override functions from the current class, not from the extended part, like you cant override update in FlxText because FlxText doesnt have a update function overriden
|
||||
|
||||
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.
|
||||
|
||||
-----------
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# FEATURES
|
||||
|
||||
- Custom Classes
|
||||
- Final Classes
|
||||
- Static Classes
|
||||
- Allow for type check (`is`)
|
||||
- Allow extending other custom classes
|
||||
- Enums
|
||||
|
||||
```haxe
|
||||
enum TypeValue {
|
||||
NUMBER(n:Int);
|
||||
DECIMAL(d:Float, ?p:Int);
|
||||
CHARACTER(s:String);
|
||||
BOOLEAN(b:Bool);
|
||||
}
|
||||
|
||||
var type = TypeValue.DECIMAL(10.1234, 2);
|
||||
// You need to type the full enum field for each case
|
||||
// i.e. you can't type the enum field directly (limitation for now)
|
||||
switch(type) {
|
||||
case TypeValue.NUMBER(number):
|
||||
trace("number: " + number);
|
||||
case TypeValue.DECIMAL(decimal, precision):
|
||||
if(precision != null)
|
||||
trace("decimal: " + decimal + " | rounded decimal: " + roundDecimal(decimal, precision));
|
||||
else
|
||||
trace("decimal: " + decimal);
|
||||
case TypeValue.CHARACTER(char):
|
||||
trace("character: " + char);
|
||||
default:
|
||||
trace("unknown type");
|
||||
}
|
||||
|
||||
function roundDecimal(Value:Float, Precision:Int) {
|
||||
var mult:Float = Math.pow(10, Precision);
|
||||
return Math.fround(Value * mult) / mult;
|
||||
}
|
||||
```
|
||||
|
||||
- Enum matching with arguments for switch statements (for real and scripted enums)
|
||||
- Property Fields (`(get, set)` variables)
|
||||
|
||||
```haxe
|
||||
public var myvar(get, set):Int;
|
||||
var _myvar:Int = 10;
|
||||
|
||||
function get_myvar():Int {
|
||||
return _myvar;
|
||||
}
|
||||
|
||||
function set_myvar(val:Int):Int {
|
||||
if(val > 10) return _myvar = val;
|
||||
return val;
|
||||
}
|
||||
```
|
||||
|
||||
- `@:isVar` metadata support
|
||||
|
||||
- Static extension (`using`)
|
||||
|
||||
```haxe
|
||||
using StringTools;
|
||||
|
||||
class IntExtender {
|
||||
static public function triple(i:Int) {
|
||||
return i * 3;
|
||||
}
|
||||
}
|
||||
|
||||
// need to create/import the custom class
|
||||
// before setting the extension (limitation for now)
|
||||
using IntExtender;
|
||||
|
||||
var str = " Hello World! ";
|
||||
trace(str.trim()); // "Hello World!"
|
||||
trace(12.triple()); // 36
|
||||
```
|
||||
|
||||
- Support for real and custom classes
|
||||
- Misc.
|
||||
- Allow using type parameters for creating objects (i.e. `var a = new TypedObject<Int>();`)
|
||||
- Allow `package` declaration. Ignored by the interpreter.
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
--macro keep('IntIterator')
|
||||
--macro hscript.macros.UsingHandler.init()
|
||||
--macro hscript.macros.AbstractHandler.init()
|
||||
--macro hscript.macros.ClassExtendMacro.init()
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "hscript",
|
||||
"name": "hscript-improved",
|
||||
"url": "https://github.com/HaxeFoundation/hscript",
|
||||
"license": "MIT",
|
||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||
|
||||
+536
-536
File diff suppressed because it is too large
Load Diff
+12
-4
@@ -124,10 +124,18 @@ class Bytes {
|
||||
#end
|
||||
bout.addByte(Type.enumIndex(e));
|
||||
switch( e ) {
|
||||
case EPackage(n):
|
||||
// TODO
|
||||
case EImport(c):
|
||||
// TODO
|
||||
case EClass(_, _, _, _):
|
||||
// TODO
|
||||
case EEnum(en):
|
||||
// TODO
|
||||
case ECast(e, _):
|
||||
// TODO
|
||||
case ERegex(e, f):
|
||||
// TODO
|
||||
case EConst(c):
|
||||
doEncodeConst(c);
|
||||
case EIdent(v):
|
||||
@@ -148,11 +156,11 @@ class Bytes {
|
||||
doEncode(e);
|
||||
doEncodeString(f);
|
||||
case EBinop(op,e1,e2):
|
||||
doEncodeString(op);
|
||||
doEncodeString(op.toString());
|
||||
doEncode(e1);
|
||||
doEncode(e2);
|
||||
case EUnop(op,prefix,e):
|
||||
doEncodeString(op);
|
||||
doEncodeString(op.toString()); // maybe doEncodeInt
|
||||
bout.addByte(prefix?1:0);
|
||||
doEncode(e);
|
||||
case ECall(e,el):
|
||||
@@ -270,11 +278,11 @@ class Bytes {
|
||||
var e = doDecode();
|
||||
EField(e,doDecodeString());
|
||||
case 6:
|
||||
var op = doDecodeString();
|
||||
var op = Binop.fromString(doDecodeString());
|
||||
var e1 = doDecode();
|
||||
EBinop(op,e1,doDecode());
|
||||
case 7:
|
||||
var op = doDecodeString();
|
||||
var op = Unop.fromString(doDecodeString());
|
||||
var prefix = bin.get(pin++) != 0;
|
||||
EUnop(op,prefix,doDecode());
|
||||
case 8:
|
||||
|
||||
+33
-16
@@ -422,6 +422,9 @@ class Checker {
|
||||
return makeType(t,e);
|
||||
case CTOpt(t):
|
||||
return makeType(t,e);
|
||||
case CTExpr(_):
|
||||
error("Unsupported expr type parameter", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1070,10 +1073,10 @@ class Checker {
|
||||
case EUnop(op, _, e):
|
||||
var et = typeExpr(e, Value);
|
||||
switch( op ) {
|
||||
case "++", "--", "-":
|
||||
case OpIncrement | OpDecrement | OpNeg:
|
||||
unify(et,TInt,e);
|
||||
return et;
|
||||
case "!":
|
||||
case OpNot:
|
||||
unify(et,TBool,e);
|
||||
return et;
|
||||
default:
|
||||
@@ -1110,11 +1113,11 @@ class Checker {
|
||||
return TVoid;
|
||||
case EBinop(op, e1, e2):
|
||||
switch( op ) {
|
||||
case "&", "|", "^", ">>", ">>>", "<<":
|
||||
case OpAnd, OpOr, OpXor, OpShr, OpUshr, OpShl:
|
||||
typeExprWith(e1,TInt);
|
||||
typeExprWith(e2,TInt);
|
||||
return TInt;
|
||||
case "=":
|
||||
case OpAssign:
|
||||
if( allowDefine ) {
|
||||
switch( edef(e1) ) {
|
||||
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
|
||||
@@ -1130,7 +1133,7 @@ class Checker {
|
||||
}
|
||||
typeExprWith(e2,vt);
|
||||
return vt;
|
||||
case "+":
|
||||
case OpAdd:
|
||||
var t1 = typeExpr(e1,WithType(TInt));
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
tryUnify(t1,t2);
|
||||
@@ -1147,14 +1150,14 @@ class Checker {
|
||||
unify(t1, TFloat, e1);
|
||||
unify(t2, TFloat, e2);
|
||||
}
|
||||
case "-", "*", "/", "%":
|
||||
case OpSub, OpMult, OpDiv, OpMod:
|
||||
var t1 = typeExpr(e1,WithType(TInt));
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
if( !tryUnify(t1,t2) )
|
||||
unify(t2,t1,e2);
|
||||
switch( [follow(t1), follow(t2)]) {
|
||||
case [TInt, TInt]:
|
||||
if( op == "/" ) return TFloat;
|
||||
if( op == OpDiv ) return TFloat;
|
||||
return TInt;
|
||||
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
|
||||
return TFloat;
|
||||
@@ -1162,21 +1165,21 @@ class Checker {
|
||||
unify(t1, TFloat, e1);
|
||||
unify(t2, TFloat, e2);
|
||||
}
|
||||
case "&&", "||":
|
||||
case OpBoolAnd, OpBoolOr:
|
||||
typeExprWith(e1,TBool);
|
||||
typeExprWith(e2,TBool);
|
||||
return TBool;
|
||||
case "...":
|
||||
case OpInterval:
|
||||
typeExprWith(e1,TInt);
|
||||
typeExprWith(e2,TInt);
|
||||
return makeIterator(TInt);
|
||||
case "==", "!=":
|
||||
case OpEq, OpNeq:
|
||||
var t1 = typeExpr(e1,Value);
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
if( !tryUnify(t1,t2) )
|
||||
unify(t2,t1,e2);
|
||||
return TBool;
|
||||
case ">", "<", ">=", "<=":
|
||||
case OpGt, OpLt, OpGte, OpLte:
|
||||
var t1 = typeExpr(e1,Value);
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
if( !tryUnify(t1,t2) )
|
||||
@@ -1187,12 +1190,26 @@ class Checker {
|
||||
error("Cannot compare "+typeStr(t1), expr);
|
||||
}
|
||||
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:
|
||||
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);
|
||||
error("Unsupported operation "+op.toString(), expr);
|
||||
}
|
||||
case ETry(etry, v, et, ecatch):
|
||||
var vt = typeExpr(etry, withType);
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
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;
|
||||
}
|
||||
+119
-172
@@ -1,151 +1,147 @@
|
||||
package hscript;
|
||||
|
||||
import hscript.Interp.DeclaredVar;
|
||||
import hscript.utils.UnsafeReflect;
|
||||
using StringTools;
|
||||
|
||||
class CustomClassHandler implements IHScriptCustomConstructor {
|
||||
public static var staticHandler = new StaticHandler();
|
||||
|
||||
/**
|
||||
* Provides handlers for static custom class fields and instantiation.
|
||||
*/
|
||||
@:access(hscript.Property)
|
||||
class CustomClassHandler implements IHScriptCustomConstructor implements IHScriptCustomAccessBehaviour{
|
||||
public var ogInterp:Interp;
|
||||
public var name:String;
|
||||
public var fields:Array<Expr>;
|
||||
public var extend:String;
|
||||
public var extend:Null<String>;
|
||||
public var interfaces:Array<String>;
|
||||
public final isFinal:Bool;
|
||||
|
||||
public var cl:Class<Dynamic>;
|
||||
public var cl:Dynamic;
|
||||
|
||||
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>) {
|
||||
private var __interp:Interp;
|
||||
private var __staticFields:Array<String> = [];
|
||||
|
||||
public var __allowSetGet:Bool = true;
|
||||
|
||||
public function new(ogInterp:Interp, name:String, fields:Array<Expr>, ?extend:String, ?interfaces:Array<String>, ?isFinal:Bool) {
|
||||
this.ogInterp = ogInterp;
|
||||
this.name = name;
|
||||
this.fields = fields;
|
||||
this.extend = extend;
|
||||
this.interfaces = interfaces;
|
||||
this.isFinal = isFinal != null ? isFinal : false;
|
||||
|
||||
this.cl = extend == null ? CustomTemplateClass : Type.resolveClass('${extend}_HSX');
|
||||
if(cl == null)
|
||||
ogInterp.error(EInvalidClass(extend));
|
||||
if(extend != null) {
|
||||
if(ogInterp.customClasses.exists(extend)) {
|
||||
var customCls:CustomClassHandler = ogInterp.customClasses.get(extend);
|
||||
if(customCls.isFinal)
|
||||
ogInterp.error(ECustom('Cannot extend a final class'));
|
||||
this.cl = customCls;
|
||||
}
|
||||
else
|
||||
this.cl = Type.resolveClass('${extend}_HSX');
|
||||
|
||||
if(cl == null)
|
||||
ogInterp.error(EInvalidClass(extend));
|
||||
}
|
||||
|
||||
initStatic();
|
||||
}
|
||||
|
||||
public function hnew(args:Array<Dynamic>):Dynamic {
|
||||
// TODO: clean this up, it sucks, i hate it
|
||||
// TODO: make static vars work correctly
|
||||
var interp = new Interp();
|
||||
@:access(hscript.Interp)
|
||||
function initStatic() {
|
||||
__interp = new Interp();
|
||||
__interp.errorHandler = ogInterp.errorHandler;
|
||||
__interp.importFailedCallback = ogInterp.importFailedCallback;
|
||||
|
||||
interp.errorHandler = ogInterp.errorHandler;
|
||||
//__interp.variables = ogInterp.variables;
|
||||
__interp.usingHandler.usingEntries = ogInterp.usingHandler.usingEntries;
|
||||
__interp.publicVariables = ogInterp.publicVariables;
|
||||
__interp.staticVariables = ogInterp.staticVariables;
|
||||
__interp.customClasses = ogInterp.customClasses;
|
||||
|
||||
var _class:IHScriptCustomClassBehaviour = Type.createInstance(cl, args);
|
||||
for(f => v in ogInterp.variables)
|
||||
if(!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
|
||||
//var __capturedLocals = ogInterp.duplicate(ogInterp.locals);
|
||||
//var capturedLocals:Map<String, DeclaredVar> = [];
|
||||
//for(k=>e in __capturedLocals)
|
||||
// if (e != null && e.depth <= 0)
|
||||
// capturedLocals.set(k, e);
|
||||
|
||||
var disallowCopy = Type.getInstanceFields(cl);
|
||||
|
||||
_class.__real_fields = disallowCopy;
|
||||
|
||||
// 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)) {
|
||||
interp.customClasses.set(key, value);
|
||||
}
|
||||
}
|
||||
// todo: clone static vars, but make it so setting it only sets it on the class
|
||||
// todo: clone public vars
|
||||
|
||||
//trace("Before: " + [for(key => value in interp.variables) key]);
|
||||
|
||||
interp.variables.set("super", staticHandler);
|
||||
|
||||
var comparisonMap:Map<String, Dynamic> = [];
|
||||
for(key => value in interp.variables) {
|
||||
comparisonMap.set(key, value);
|
||||
}
|
||||
|
||||
_class.__custom__variables = interp.variables;
|
||||
|
||||
//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);
|
||||
for(i => e in fields.copy()) {
|
||||
var isValid:Bool = false;
|
||||
var staticField:Bool = false;
|
||||
var fieldName:String = null;
|
||||
switch (Tools.expr(e)) {
|
||||
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
|
||||
isValid = true;
|
||||
staticField = isStatic;
|
||||
fieldName = n;
|
||||
default:
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if(staticField && isValid) {
|
||||
__interp.exprReturn(e);
|
||||
__staticFields.push(fieldName);
|
||||
fields.remove(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hnew(args:Array<Dynamic>):Dynamic
|
||||
return new CustomClass(this, args);
|
||||
|
||||
return _class;
|
||||
@:allow(hscript.Interp)
|
||||
inline function hasField(name:String) {
|
||||
return __staticFields.contains(name);
|
||||
}
|
||||
|
||||
function getField(name:String, allowProperty:Bool = true):Dynamic {
|
||||
var f = __interp.variables.get(name);
|
||||
if(f is Property && allowProperty) {
|
||||
var prop:Property = cast f;
|
||||
//prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.get(!__allowSetGet);
|
||||
//prop.__allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
function setField(name:String, val:Dynamic):Dynamic {
|
||||
var f = getField(name, false);
|
||||
if(f is Property) {
|
||||
var prop:Property = cast f;
|
||||
//prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.set(val, !__allowSetGet);
|
||||
//prop.__allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
if(name == 'new') {
|
||||
return Reflect.makeVarArgs(function(args:Array<Dynamic>):Dynamic {
|
||||
return inline this.hnew(args);
|
||||
});
|
||||
}
|
||||
|
||||
if(hasField(name)) {
|
||||
return getField(name);
|
||||
}
|
||||
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if(hasField(name))
|
||||
return setField(name, val);
|
||||
|
||||
throw "field '"+ name+ "' does not exist in class '"+ this.name+ "'";
|
||||
return null;
|
||||
}
|
||||
|
||||
// UNUSED
|
||||
public function __callGetter(name:String):Dynamic {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function toString():String {
|
||||
@@ -153,51 +149,6 @@ class CustomClassHandler implements IHScriptCustomConstructor {
|
||||
}
|
||||
}
|
||||
|
||||
class CustomTemplateClass implements IHScriptCustomClassBehaviour implements IHScriptCustomAccessBehaviour {
|
||||
public var __interp:Interp;
|
||||
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
|
||||
@@ -236,7 +187,3 @@ class TemplateClass implements IHScriptCustomBehaviour implements IHScriptCustom
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
final class StaticHandler {
|
||||
public function new() {}
|
||||
}
|
||||
+403
-218
@@ -1,218 +1,403 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
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 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 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 UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||
|
||||
enum Const {
|
||||
CInt( v : Int );
|
||||
CFloat( f : Float );
|
||||
CString( s : String );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
@:structInit
|
||||
final class Expr {
|
||||
public var e : ExprDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : String, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<ObjectField> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
|
||||
EImport( c : String, ?asname:String );
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||
}
|
||||
|
||||
@: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>;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
#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 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>;
|
||||
}
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
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 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 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;
|
||||
|
||||
enum abstract Binop(Int) from Int to Int {
|
||||
var OpAdd = 0;
|
||||
var OpSub = 1;
|
||||
var OpMult = 2;
|
||||
var OpDiv = 3;
|
||||
var OpMod = 4;
|
||||
var OpAnd = 5;
|
||||
var OpOr = 6;
|
||||
var OpXor = 7;
|
||||
var OpShl = 8;
|
||||
var OpShr = 9;
|
||||
var OpUshr = 10;
|
||||
var OpEq = 11;
|
||||
var OpNeq = 12;
|
||||
var OpGte = 13;
|
||||
var OpLte = 14;
|
||||
var OpGt = 15;
|
||||
var OpLt = 16;
|
||||
var OpBoolOr = 17;
|
||||
var OpBoolAnd = 18;
|
||||
var OpIs = 19;
|
||||
var OpAssign = 20;
|
||||
var OpNcoal = 21;
|
||||
var OpInterval = 22;
|
||||
var OpArrow = 23;
|
||||
var OpAddAssign = 24;
|
||||
var OpSubAssign = 25;
|
||||
var OpMultAssign = 26;
|
||||
var OpDivAssign = 27;
|
||||
var OpModAssign = 28;
|
||||
var OpAndAssign = 29;
|
||||
var OpOrAssign = 30;
|
||||
var OpXorAssign = 31;
|
||||
var OpShlAssign = 32;
|
||||
var OpShrAssign = 33;
|
||||
var OpUshrAssign = 34;
|
||||
var OpNcoalAssign = 35;
|
||||
var OpArrowFn = 36;
|
||||
|
||||
public static inline function fromString(s:String):Binop {
|
||||
return switch(s) {
|
||||
case "+": OpAdd;
|
||||
case "-": OpSub;
|
||||
case "*": OpMult;
|
||||
case "/": OpDiv;
|
||||
case "%": OpMod;
|
||||
case "&": OpAnd;
|
||||
case "|": OpOr;
|
||||
case "^": OpXor;
|
||||
case "<<": OpShl;
|
||||
case ">>": OpShr;
|
||||
case ">>>": OpUshr;
|
||||
case "==": OpEq;
|
||||
case "!=": OpNeq;
|
||||
case ">=": OpGte;
|
||||
case "<=": OpLte;
|
||||
case ">": OpGt;
|
||||
case "<": OpLt;
|
||||
case "||": OpBoolOr;
|
||||
case "&&": OpBoolAnd;
|
||||
case "is": OpIs;
|
||||
case "=": OpAssign;
|
||||
case "??": OpNcoal;
|
||||
case "...": OpInterval;
|
||||
case "->": OpArrow;
|
||||
case "=>": OpArrowFn;
|
||||
case "+=": OpAddAssign;
|
||||
case "-=": OpSubAssign;
|
||||
case "*=": OpMultAssign;
|
||||
case "/=": OpDivAssign;
|
||||
case "%=": OpModAssign;
|
||||
case "&=": OpAndAssign;
|
||||
case "|=": OpOrAssign;
|
||||
case "^=": OpXorAssign;
|
||||
case "<<=": OpShlAssign;
|
||||
case ">>=": OpShrAssign;
|
||||
case ">>>=": OpUshrAssign;
|
||||
case _ if (s == "??" + "="): OpNcoalAssign;
|
||||
default: -1;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function toString():String {
|
||||
return switch(this) {
|
||||
case OpAdd: "+";
|
||||
case OpSub: "-";
|
||||
case OpMult: "*";
|
||||
case OpDiv: "/";
|
||||
case OpMod: "%";
|
||||
case OpAnd: "&";
|
||||
case OpOr: "|";
|
||||
case OpXor: "^";
|
||||
case OpShl: "<<";
|
||||
case OpShr: ">>";
|
||||
case OpUshr: ">>>";
|
||||
case OpEq: "==";
|
||||
case OpNeq: "!=";
|
||||
case OpGte: ">=";
|
||||
case OpLte: "<=";
|
||||
case OpGt: ">";
|
||||
case OpLt: "<";
|
||||
case OpBoolOr: "||";
|
||||
case OpBoolAnd: "&&";
|
||||
case OpIs: "is";
|
||||
case OpAssign: "=";
|
||||
case OpNcoal: "??";
|
||||
case OpInterval: "...";
|
||||
case OpArrow: "->";
|
||||
case OpArrowFn: "=>";
|
||||
case OpAddAssign: "+=";
|
||||
case OpSubAssign: "-=";
|
||||
case OpMultAssign: "*=";
|
||||
case OpDivAssign: "/=";
|
||||
case OpModAssign: "%=";
|
||||
case OpAndAssign: "&=";
|
||||
case OpOrAssign: "|=";
|
||||
case OpXorAssign: "^=";
|
||||
case OpShlAssign: "<<=";
|
||||
case OpShrAssign: ">>=";
|
||||
case OpUshrAssign: ">>>=";
|
||||
case OpNcoalAssign: "??" + "=";
|
||||
default: "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum abstract Unop(Int) from Int to Int {
|
||||
var OpNot = 0;
|
||||
var OpNeg = 1;
|
||||
var OpIncrement = 2;
|
||||
var OpDecrement = 3;
|
||||
var OpNegBits = 4;
|
||||
|
||||
public static inline function fromString(s:String):Unop {
|
||||
return switch(s) {
|
||||
case "!": OpNot;
|
||||
case "-": OpNeg;
|
||||
case "++": OpIncrement;
|
||||
case "--": OpDecrement;
|
||||
case "~": OpNegBits;
|
||||
default: -1;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function toString():String {
|
||||
return switch(this) {
|
||||
case OpNot: "!";
|
||||
case OpNeg: "-";
|
||||
case OpIncrement: "++";
|
||||
case OpDecrement: "--";
|
||||
case OpNegBits: "~";
|
||||
default: "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||
|
||||
enum Const {
|
||||
CInt( v : Int );
|
||||
CFloat( f : Float );
|
||||
CString( s : String, ?i : Bool );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
@:structInit
|
||||
final class Expr {
|
||||
public var e : ExprDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : Binop, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : Unop, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<ObjectField> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
|
||||
EPackage( ?n:String );
|
||||
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||
ECast(e:Expr, ?t:CType);
|
||||
ERegex(e:String, flags:String);
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class ObjectField {
|
||||
public var name : String;
|
||||
public var e : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class SwitchCase {
|
||||
public var values : Array<Expr>;
|
||||
public var expr : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class Argument {
|
||||
public var name : String;
|
||||
public var t : CType;
|
||||
public var opt : Bool;
|
||||
public var value : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class MetadataEntry {
|
||||
public var name : String;
|
||||
public var params : Array<Expr>;
|
||||
}
|
||||
|
||||
typedef Metadata = Array<MetadataEntry>;
|
||||
|
||||
@:structInit
|
||||
final class EnumDecl {
|
||||
public var name : String;
|
||||
public var fields : Array<EnumField>;
|
||||
public var underlyingType : Null<CType>;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class EnumField {
|
||||
public var name : String;
|
||||
public var args : Array<Argument>;
|
||||
public var value : Null<Expr>;
|
||||
}
|
||||
|
||||
enum CType {
|
||||
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||
CTFun( args : Array<CType>, ret : CType );
|
||||
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||
CTParent( t : CType );
|
||||
CTOpt( t : CType );
|
||||
CTNamed( n : String, t : CType );
|
||||
CTExpr( e : Expr ); // for type parameters only
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
class Error {
|
||||
public var e : ErrorDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
public function new(e, pmin, pmax, origin, line) {
|
||||
this.e = e;
|
||||
this.pmin = pmin;
|
||||
this.pmax = pmax;
|
||||
this.origin = origin;
|
||||
this.line = line;
|
||||
}
|
||||
public function toString(): String {
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ErrorDef {
|
||||
#else
|
||||
enum Error {
|
||||
#end
|
||||
EInvalidChar( c : Int );
|
||||
EUnexpected( s : String );
|
||||
EUnterminatedString;
|
||||
EUnterminatedComment;
|
||||
EInvalidPreprocessor( msg : String );
|
||||
EUnknownVariable( v : String );
|
||||
EInvalidIterator( v : String );
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String );
|
||||
ECustom( msg : String );
|
||||
EInvalidClass( className : String);
|
||||
EAlreadyExistingClass( className : String);
|
||||
}
|
||||
|
||||
|
||||
enum ModuleDecl {
|
||||
DPackage( path : Array<String> );
|
||||
DImport( path : Array<String>, ?everything : Bool );
|
||||
DClass( c : ClassDecl );
|
||||
DTypedef( c : TypeDecl );
|
||||
}
|
||||
|
||||
typedef ModuleType = {
|
||||
var name : String;
|
||||
var params : {}; // TODO : not yet parsed
|
||||
var meta : Metadata;
|
||||
var isPrivate : Bool;
|
||||
}
|
||||
|
||||
typedef ClassDecl = {> ModuleType,
|
||||
var extend : Null<CType>;
|
||||
var implement : Array<CType>;
|
||||
var fields : Array<FieldDecl>;
|
||||
var isExtern : Bool;
|
||||
}
|
||||
|
||||
typedef TypeDecl = {> ModuleType,
|
||||
var t : CType;
|
||||
}
|
||||
|
||||
typedef FieldDecl = {
|
||||
var name : String;
|
||||
var meta : Metadata;
|
||||
var kind : FieldKind;
|
||||
var access : Array<FieldAccess>;
|
||||
}
|
||||
|
||||
enum abstract FieldAccess(UInt8) {
|
||||
var APublic;
|
||||
var APrivate;
|
||||
var AInline;
|
||||
var AOverride;
|
||||
var AStatic;
|
||||
var AMacro;
|
||||
}
|
||||
|
||||
enum abstract FieldPropertyAccess(UInt8) {
|
||||
var ADefault;
|
||||
var ANull;
|
||||
var AGet;
|
||||
var ASet;
|
||||
var ADynamic;
|
||||
var ANever;
|
||||
}
|
||||
|
||||
enum FieldKind {
|
||||
KFunction( f : FunctionDecl );
|
||||
KVar( v : VarDecl );
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class FunctionDecl {
|
||||
public var args : Array<Argument>;
|
||||
public var body : Expr;
|
||||
public var ret : Null<CType>;
|
||||
}
|
||||
|
||||
typedef VarDecl = {
|
||||
var get : Null<String>;
|
||||
var set : Null<String>;
|
||||
var expr : Null<Expr>;
|
||||
var type : Null<CType>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
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,11 +1,11 @@
|
||||
package hscript;
|
||||
|
||||
interface IHScriptCustomAccessBehaviour {
|
||||
/**
|
||||
* Same Interface as IHScriptCustomBehaviour but for Property.
|
||||
*/
|
||||
interface IHScriptCustomAccessBehaviour extends IHScriptCustomBehaviour {
|
||||
var __allowSetGet:Bool;
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic;
|
||||
public function hget(name:String):Dynamic;
|
||||
|
||||
public function __callGetter(name:String):Dynamic;
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
||||
}
|
||||
@@ -1,6 +1,23 @@
|
||||
package hscript;
|
||||
|
||||
/**
|
||||
* Special Interface for handling field access behaviour.
|
||||
* Basically works like the operator overload `@:op(a.b)`
|
||||
* for an abstract.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Field Read Access
|
||||
* @param name - Field Name
|
||||
* @return Dynamic - The returned field
|
||||
*/
|
||||
public function hget(name:String):Dynamic;
|
||||
}
|
||||
@@ -1,16 +1,11 @@
|
||||
package hscript;
|
||||
|
||||
interface IHScriptCustomClassBehaviour {
|
||||
/**
|
||||
* Special Interface to make a class usable for Custom Classes.
|
||||
*/
|
||||
interface IHScriptCustomClassBehaviour extends IHScriptCustomAccessBehaviour{
|
||||
public var __interp:Interp;
|
||||
public var __custom__variables:Map<String, Dynamic>;
|
||||
public var __allowSetGet:Bool;
|
||||
public var __real_fields:Array<String>;
|
||||
public var __class__fields:Array<String>;
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic;
|
||||
public function hget(name:String):Dynamic;
|
||||
|
||||
public function __callGetter(name:String):Dynamic;
|
||||
|
||||
public function __callSetter(name:String, val:Dynamic):Dynamic;
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package hscript;
|
||||
|
||||
/**
|
||||
* Special Interface for handling new instances of an object.
|
||||
*/
|
||||
interface IHScriptCustomConstructor {
|
||||
public function hnew(args:Array<Dynamic>):Dynamic;
|
||||
}
|
||||
+852
-325
File diff suppressed because it is too large
Load Diff
+7
-4
@@ -127,6 +127,8 @@ class Macro {
|
||||
tf.push( { name : f.name, meta : meta, doc : null, access : [], kind : FVar(convertType(f.t), null), pos : p } );
|
||||
}
|
||||
TAnonymous(tf);
|
||||
case CTExpr(_):
|
||||
throw "assert";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -149,12 +151,13 @@ class Macro {
|
||||
case EField(e, f):
|
||||
EField(convert(e), f);
|
||||
case EBinop(op, e1, e2):
|
||||
var b = binops.get(op);
|
||||
if( b == null ) throw EInvalidOp(op);
|
||||
var b = binops.get(op.toString());
|
||||
if( b == null ) throw EInvalidOp(op.toString());
|
||||
EBinop(b, convert(e1), convert(e2));
|
||||
case EUnop(op, prefix, e):
|
||||
var u = unops.get(op);
|
||||
if( u == null ) throw EInvalidOp(op);
|
||||
var opStr = op.toString();
|
||||
var u = unops.get(opStr);
|
||||
if( u == null ) throw EInvalidOp(opStr);
|
||||
EUnop(u, !prefix, convert(e));
|
||||
case ECall(e, params):
|
||||
ECall(convert(e), map(params, convert));
|
||||
|
||||
+585
-171
File diff suppressed because it is too large
Load Diff
+494
-377
@@ -1,377 +1,494 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Printer {
|
||||
|
||||
var buf : StringBuf;
|
||||
var tabs : String;
|
||||
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function exprToString( e : Expr ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
expr(e);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public function typeToString( t : CType ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
type(t);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
inline function add<T>(s:T):Void buf.add(s);
|
||||
|
||||
function type( t : CType ):Void {
|
||||
switch( t ) {
|
||||
case CTOpt(t):
|
||||
add('?');
|
||||
type(t);
|
||||
case CTPath(path, params):
|
||||
add(path.join("."));
|
||||
if( params != null ) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
case CTNamed(name, t):
|
||||
add(name);
|
||||
add(':');
|
||||
type(t);
|
||||
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||
add('(');
|
||||
for (a in args)
|
||||
switch a {
|
||||
case CTNamed(_, _): type(a);
|
||||
default: type(CTNamed('_', a));
|
||||
}
|
||||
add(')->');
|
||||
type(ret);
|
||||
case CTFun(args, ret):
|
||||
if( args.length == 0 )
|
||||
add("Void -> ");
|
||||
else {
|
||||
for( a in args ) {
|
||||
type(a);
|
||||
add(" -> ");
|
||||
}
|
||||
}
|
||||
type(ret);
|
||||
case CTAnon(fields):
|
||||
add("{");
|
||||
var first = true;
|
||||
for( f in fields ) {
|
||||
if( first ) { first = false; add(" "); } else add(", ");
|
||||
add(f.name + " : ");
|
||||
type(f.t);
|
||||
}
|
||||
add(first ? "}" : " }");
|
||||
case CTParent(t):
|
||||
add("(");
|
||||
type(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
function addType( t : CType ):Void {
|
||||
if( t != null ) {
|
||||
add(" : ");
|
||||
type(t);
|
||||
}
|
||||
}
|
||||
|
||||
function expr( e : Expr ):Void {
|
||||
if( e == null ) {
|
||||
add("??NULL??");
|
||||
return;
|
||||
}
|
||||
switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EImport(c, n):
|
||||
add("import " + c);
|
||||
if(n != null)
|
||||
add(' as $n');
|
||||
case EClass(name, fields, extend, interfaces):
|
||||
add('class $name');
|
||||
if (extend != null)
|
||||
add(' extends $extend');
|
||||
for(_interface in interfaces) {
|
||||
add(' implements $_interface');
|
||||
}
|
||||
add(' {\n');
|
||||
tabs += "\t";
|
||||
//for(field in fields) {
|
||||
// expr(field);
|
||||
//}
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case EConst(c):
|
||||
switch( c ) {
|
||||
case CInt(i): add(i);
|
||||
case CFloat(f): add(f);
|
||||
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
||||
}
|
||||
case EIdent(v):
|
||||
add(v);
|
||||
case EVar(n, t, e): // TODO: static, public, override
|
||||
add("var " + n);
|
||||
addType(t);
|
||||
if( e != null ) {
|
||||
add(" = ");
|
||||
expr(e);
|
||||
}
|
||||
case EParent(e):
|
||||
add("("); expr(e); add(")");
|
||||
case EBlock(el):
|
||||
if( el.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( e in el ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case EField(e, f, s):
|
||||
expr(e);
|
||||
add((s == true ? "?." : ".") + f);
|
||||
case EBinop(op, e1, e2):
|
||||
expr(e1);
|
||||
add(" " + op + " ");
|
||||
expr(e2);
|
||||
case EUnop(op, pre, e):
|
||||
if( pre ) {
|
||||
add(op);
|
||||
expr(e);
|
||||
} else {
|
||||
expr(e);
|
||||
add(op);
|
||||
}
|
||||
case ECall(e, args):
|
||||
if( e == null )
|
||||
expr(e);
|
||||
else switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EField(_), EIdent(_), EConst(_):
|
||||
expr(e);
|
||||
default:
|
||||
add("(");
|
||||
expr(e);
|
||||
add(")");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(a);
|
||||
}
|
||||
add(")");
|
||||
case EIf(cond,e1,e2):
|
||||
add("if( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e1);
|
||||
if( e2 != null ) {
|
||||
add(" else ");
|
||||
expr(e2);
|
||||
}
|
||||
case EWhile(cond,e):
|
||||
add("while( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EDoWhile(cond,e):
|
||||
add("do ");
|
||||
expr(e);
|
||||
add(" while ( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
case EFor(v, it, e, ithv):
|
||||
if(ithv != null)
|
||||
add("for( "+ithv+" => "+v+" in ");
|
||||
else
|
||||
add("for( "+v+" in ");
|
||||
expr(it);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EBreak:
|
||||
add("break");
|
||||
case EContinue:
|
||||
add("continue");
|
||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||
add("function");
|
||||
if( name != null )
|
||||
add(" " + name);
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(")");
|
||||
addType(ret);
|
||||
add(" ");
|
||||
expr(e);
|
||||
case EReturn(e):
|
||||
add("return");
|
||||
if( e != null ) {
|
||||
add(" ");
|
||||
expr(e);
|
||||
}
|
||||
case EArray(e,index):
|
||||
expr(e);
|
||||
add("[");
|
||||
expr(index);
|
||||
add("]");
|
||||
case EArrayDecl(el, _):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add("]");
|
||||
case ENew(cl, args):
|
||||
add("new " + cl + "(");
|
||||
var first = true;
|
||||
for( e in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
case EThrow(e):
|
||||
add("throw ");
|
||||
expr(e);
|
||||
case ETry(e, v, t, ecatch):
|
||||
add("try ");
|
||||
expr(e);
|
||||
add(" catch( " + v);
|
||||
addType(t);
|
||||
add(") ");
|
||||
expr(ecatch);
|
||||
case EObject(fl):
|
||||
if( fl.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( f in fl ) {
|
||||
add(tabs);
|
||||
add(f.name+" : ");
|
||||
expr(f.e);
|
||||
add(",\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case ETernary(c,e1,e2):
|
||||
expr(c);
|
||||
add(" ? ");
|
||||
expr(e1);
|
||||
add(" : ");
|
||||
expr(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
add("switch( ");
|
||||
expr(e);
|
||||
add(") {");
|
||||
for( c in cases ) {
|
||||
add("case ");
|
||||
var first = true;
|
||||
for( v in c.values ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(v);
|
||||
}
|
||||
add(": ");
|
||||
expr(c.expr);
|
||||
add(";\n");
|
||||
}
|
||||
if( def != null ) {
|
||||
add("default: ");
|
||||
expr(def);
|
||||
add(";\n");
|
||||
}
|
||||
add("}");
|
||||
case EMeta(name, args, e):
|
||||
add("@");
|
||||
add(name);
|
||||
if( args != null && args.length > 0 ) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
case ECheckType(e, t):
|
||||
add("(");
|
||||
expr(e);
|
||||
add(" : ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
public static function toString( e : Expr ):String {
|
||||
return new Printer().exprToString(e);
|
||||
}
|
||||
|
||||
public static function errorToString( e : Expr.Error ):String {
|
||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||
case EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
#else
|
||||
return message;
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Printer {
|
||||
|
||||
var buf : StringBuf;
|
||||
var tabs : String;
|
||||
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function exprToString( e : Expr ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
expr(e);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public function typeToString( t : CType ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
type(t);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
inline function add<T>(s:T):Void buf.add(s);
|
||||
|
||||
function type( t : CType ):Void {
|
||||
switch( t ) {
|
||||
case CTOpt(t):
|
||||
add('?');
|
||||
type(t);
|
||||
case CTPath(path, params):
|
||||
add(path.join("."));
|
||||
if( params != null ) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
case CTNamed(name, t):
|
||||
add(name);
|
||||
add(':');
|
||||
type(t);
|
||||
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||
add('(');
|
||||
for (a in args)
|
||||
switch a {
|
||||
case CTNamed(_, _): type(a);
|
||||
default: type(CTNamed('_', a));
|
||||
}
|
||||
add(')->');
|
||||
type(ret);
|
||||
case CTFun(args, ret):
|
||||
if( args.length == 0 )
|
||||
add("Void -> ");
|
||||
else {
|
||||
for( a in args ) {
|
||||
type(a);
|
||||
add(" -> ");
|
||||
}
|
||||
}
|
||||
type(ret);
|
||||
case CTAnon(fields):
|
||||
add("{");
|
||||
var first = true;
|
||||
for( f in fields ) {
|
||||
if( first ) { first = false; add(" "); } else add(", ");
|
||||
add(f.name + " : ");
|
||||
type(f.t);
|
||||
}
|
||||
add(first ? "}" : " }");
|
||||
case CTParent(t):
|
||||
add("(");
|
||||
type(t);
|
||||
add(")");
|
||||
case CTExpr(e):
|
||||
expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
function addType( t : CType ):Void {
|
||||
if( t != null ) {
|
||||
add(" : ");
|
||||
type(t);
|
||||
}
|
||||
}
|
||||
|
||||
function expr( e : Expr ):Void {
|
||||
if( e == null ) {
|
||||
add("??NULL??");
|
||||
return;
|
||||
}
|
||||
switch(Tools.expr(e)) {
|
||||
case EPackage(n):
|
||||
add('package');
|
||||
if(n != null)
|
||||
add(' $n');
|
||||
add(';\n');
|
||||
case EImport(c, n, u):
|
||||
add('${u ? 'using' : 'import'} $c');
|
||||
if(n != null)
|
||||
add(' as $n');
|
||||
case EClass(name, fields, extend, interfaces, fnal):
|
||||
var isFinal = fnal != null && fnal;
|
||||
if(isFinal)
|
||||
add('final ');
|
||||
add('class $name');
|
||||
if (extend != null)
|
||||
add(' extends $extend');
|
||||
for(_interface in interfaces) {
|
||||
add(' implements $_interface');
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for( e in fields ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
//add(";\n");
|
||||
}
|
||||
//for(field in fields) {
|
||||
// expr(field);
|
||||
//}
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case EEnum(en, isAbstract):
|
||||
if(isAbstract) {
|
||||
add('enum abstract ${en.name}(');
|
||||
if(en.underlyingType != null)
|
||||
type(en.underlyingType);
|
||||
else
|
||||
add('Int');
|
||||
add(')');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.value != null) {
|
||||
add(" = ");
|
||||
expr(e.value);
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
} else {
|
||||
add('enum ${en.name}');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.args.length > 0) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in e.args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(')');
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case ECast(e, t):
|
||||
var safe = t != null;
|
||||
add("cast ");
|
||||
if(safe) add("(");
|
||||
expr(e);
|
||||
if(safe) {
|
||||
add(", ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
case ERegex(e, f):
|
||||
add('~/$e/$f');
|
||||
add(';\n');
|
||||
case EConst(c):
|
||||
switch( c ) {
|
||||
case CInt(i): add(i);
|
||||
case CFloat(f): add(f);
|
||||
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
||||
}
|
||||
case EIdent(v):
|
||||
add(v);
|
||||
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
|
||||
if(p) add("public ");
|
||||
else if(pr) add("private ");
|
||||
if(s) add("static ");
|
||||
if(isInline) add("inline ");
|
||||
if(isFinal) add("final " + n);
|
||||
else add("var " + n);
|
||||
|
||||
if(get != null || set != null) {
|
||||
add("(");
|
||||
switch(get) {
|
||||
case ADefault: add("default, ");
|
||||
case ANull: add("null, ");
|
||||
case AGet: add("get, ");
|
||||
case ADynamic: add("dynamic, ");
|
||||
case ANever: add("never, ");
|
||||
default:
|
||||
}
|
||||
switch(set) {
|
||||
case ADefault: add("default");
|
||||
case ANull: add("null");
|
||||
case ASet: add("set");
|
||||
case ADynamic: add("dynamic");
|
||||
case ANever: add("never");
|
||||
default:
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
|
||||
addType(t);
|
||||
if( e != null ) {
|
||||
add(" = ");
|
||||
expr(e);
|
||||
}
|
||||
case EParent(e):
|
||||
add("("); expr(e); add(")");
|
||||
case EBlock(el):
|
||||
if( el.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( e in el ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case EField(e, f, s):
|
||||
expr(e);
|
||||
add((s == true ? "?." : ".") + f);
|
||||
case EBinop(op, e1, e2):
|
||||
expr(e1);
|
||||
add(" " + op.toString() + " ");
|
||||
expr(e2);
|
||||
case EUnop(op, pre, e):
|
||||
if( pre ) {
|
||||
add(op);
|
||||
expr(e);
|
||||
} else {
|
||||
expr(e);
|
||||
add(op);
|
||||
}
|
||||
case ECall(e, args):
|
||||
if( e == null )
|
||||
expr(e);
|
||||
else switch( Tools.expr(e)) {
|
||||
case EField(_), EIdent(_), EConst(_):
|
||||
expr(e);
|
||||
default:
|
||||
add("(");
|
||||
expr(e);
|
||||
add(")");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(a);
|
||||
}
|
||||
add(")");
|
||||
case EIf(cond,e1,e2):
|
||||
add("if( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e1);
|
||||
if( e2 != null ) {
|
||||
add(" else ");
|
||||
expr(e2);
|
||||
}
|
||||
case EWhile(cond,e):
|
||||
add("while( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EDoWhile(cond,e):
|
||||
add("do ");
|
||||
expr(e);
|
||||
add(" while ( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
case EFor(v, it, e, ithv):
|
||||
if(ithv != null)
|
||||
add("for( "+ithv+" => "+v+" in ");
|
||||
else
|
||||
add("for( "+v+" in ");
|
||||
expr(it);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EBreak:
|
||||
add("break");
|
||||
case EContinue:
|
||||
add("continue");
|
||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||
add("function");
|
||||
if( name != null )
|
||||
add(" " + name);
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(")");
|
||||
addType(ret);
|
||||
add(" ");
|
||||
expr(e);
|
||||
case EReturn(e):
|
||||
add("return");
|
||||
if( e != null ) {
|
||||
add(" ");
|
||||
expr(e);
|
||||
}
|
||||
case EArray(e,index):
|
||||
expr(e);
|
||||
add("[");
|
||||
expr(index);
|
||||
add("]");
|
||||
case EArrayDecl(el, _):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add("]");
|
||||
case ENew(cl, args, params):
|
||||
add("new " + cl);
|
||||
if(params != null) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( e in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
case EThrow(e):
|
||||
add("throw ");
|
||||
expr(e);
|
||||
case ETry(e, v, t, ecatch):
|
||||
add("try ");
|
||||
expr(e);
|
||||
add(" catch( " + v);
|
||||
addType(t);
|
||||
add(") ");
|
||||
expr(ecatch);
|
||||
case EObject(fl):
|
||||
if( fl.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( f in fl ) {
|
||||
add(tabs);
|
||||
add(f.name+" : ");
|
||||
expr(f.e);
|
||||
add(",\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case ETernary(c,e1,e2):
|
||||
expr(c);
|
||||
add(" ? ");
|
||||
expr(e1);
|
||||
add(" : ");
|
||||
expr(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
add("switch( ");
|
||||
expr(e);
|
||||
add(") {");
|
||||
for( c in cases ) {
|
||||
add("case ");
|
||||
var first = true;
|
||||
for( v in c.values ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(v);
|
||||
}
|
||||
add(": ");
|
||||
expr(c.expr);
|
||||
add(";\n");
|
||||
}
|
||||
if( def != null ) {
|
||||
add("default: ");
|
||||
expr(def);
|
||||
add(";\n");
|
||||
}
|
||||
add("}");
|
||||
case EMeta(name, args, e):
|
||||
add("@");
|
||||
add(name);
|
||||
if( args != null && args.length > 0 ) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
case ECheckType(e, t):
|
||||
add("(");
|
||||
expr(e);
|
||||
add(" : ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
public static function toString( e : Expr ):String {
|
||||
return new Printer().exprToString(e);
|
||||
}
|
||||
|
||||
public static function errorToString( e : Expr.Error ):String {
|
||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||
case EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
#else
|
||||
return message;
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
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, 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, ?value:Dynamic):Dynamic {
|
||||
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
|
||||
var rt:Dynamic = null;
|
||||
var isWrite:Bool = value != 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);
|
||||
}
|
||||
}
|
||||
+143
-113
@@ -1,114 +1,144 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||
switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_):
|
||||
case EImport(c): f(e);
|
||||
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||
case EVar(_, _, e): if( e != null ) f(e);
|
||||
case EParent(e): f(e);
|
||||
case EBlock(el): for( e in el ) f(e);
|
||||
case EField(e, _): f(e);
|
||||
case EBinop(_, e1, e2): f(e1); f(e2);
|
||||
case EUnop(_, _, e): f(e);
|
||||
case ECall(e, args): f(e); for( a in args ) f(a);
|
||||
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
||||
case EWhile(c, e): f(c); f(e);
|
||||
case EDoWhile(c, e): f(c); f(e);
|
||||
case EFor(_, it, e): f(it); f(e);
|
||||
case EBreak,EContinue:
|
||||
case EFunction(_, e, _, _): f(e);
|
||||
case EReturn(e): if( e != null ) f(e);
|
||||
case EArray(e, i): f(e); f(i);
|
||||
case EArrayDecl(el): for( e in el ) f(e);
|
||||
case ENew(_,el): for( e in el ) f(e);
|
||||
case EThrow(e): f(e);
|
||||
case ETry(e, _, _, c): f(e); f(c);
|
||||
case EObject(fl): for( fi in fl ) f(fi.e);
|
||||
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
f(e);
|
||||
for( c in cases ) {
|
||||
for( v in c.values ) f(v);
|
||||
f(c.expr);
|
||||
}
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||
case ECheckType(e,_): f(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
||||
var edef = switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
||||
case EParent(e): EParent(f(e));
|
||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||
case EField(e, fi): EField(f(e),fi);
|
||||
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
||||
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
||||
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
||||
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
||||
case EWhile(c, e): EWhile(f(c),f(e));
|
||||
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||
case EArray(e, i): EArray(f(e),f(i));
|
||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||
case EThrow(e): EThrow(f(e));
|
||||
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||
case ECheckType(e,t): ECheckType(f(e), t);
|
||||
case EImport(c): EImport(c);
|
||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||
}
|
||||
return mk(edef, e);
|
||||
}
|
||||
|
||||
public static inline function expr( e : Expr ) : ExprDef {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#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 };
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||
switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_):
|
||||
case EImport(c): f(e);
|
||||
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||
case EVar(_, _, e): if( e != null ) f(e);
|
||||
case EParent(e): f(e);
|
||||
case EBlock(el): for( e in el ) f(e);
|
||||
case EField(e, _): f(e);
|
||||
case EBinop(_, e1, e2): f(e1); f(e2);
|
||||
case EUnop(_, _, e): f(e);
|
||||
case ECall(e, args): f(e); for( a in args ) f(a);
|
||||
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
||||
case EWhile(c, e): f(c); f(e);
|
||||
case EDoWhile(c, e): f(c); f(e);
|
||||
case EFor(_, it, e): f(it); f(e);
|
||||
case EBreak,EContinue:
|
||||
case EFunction(_, e, _, _): f(e);
|
||||
case EReturn(e): if( e != null ) f(e);
|
||||
case EArray(e, i): f(e); f(i);
|
||||
case EArrayDecl(el): for( e in el ) f(e);
|
||||
case ENew(_,el): for( e in el ) f(e);
|
||||
case EThrow(e): f(e);
|
||||
case ETry(e, _, _, c): f(e); f(c);
|
||||
case EObject(fl): for( fi in fl ) f(fi.e);
|
||||
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
f(e);
|
||||
for( c in cases ) {
|
||||
for( v in c.values ) f(v);
|
||||
f(c.expr);
|
||||
}
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||
case ECheckType(e,_): f(e);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
||||
var edef = switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
||||
case EParent(e): EParent(f(e));
|
||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||
case EField(e, fi): EField(f(e),fi);
|
||||
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
||||
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
||||
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
||||
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
||||
case EWhile(c, e): EWhile(f(c),f(e));
|
||||
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||
case EArray(e, i): EArray(f(e),f(i));
|
||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||
case EThrow(e): EThrow(f(e));
|
||||
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||
case ECheckType(e,t): ECheckType(f(e), t);
|
||||
case EImport(c): EImport(c);
|
||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||
default: expr(e);
|
||||
}
|
||||
return mk(edef, e);
|
||||
}
|
||||
|
||||
public static inline function expr( e : Expr ) : ExprDef {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#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 };
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT USE INLINE ON THIS FUNCTION
|
||||
**/
|
||||
public static function argCount(func: haxe.Constraints.Function): Int {
|
||||
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
|
||||
#if cpp
|
||||
return untyped __cpp__("{0}->__ArgCount()", func);
|
||||
#elseif js
|
||||
return untyped js.Syntax.code("{0}.length", func);
|
||||
#elseif hl
|
||||
var ft = hl.Type.getDynamic(func);
|
||||
if (ft.kind != HFun)
|
||||
return -1;
|
||||
return ft.getArgsCount();
|
||||
#else
|
||||
return -1;
|
||||
#end
|
||||
}
|
||||
|
||||
public static function isUppercase(s:String) {
|
||||
if(s.length == 0) return false;
|
||||
var c:Int = StringTools.fastCodeAt(s, 0);
|
||||
if(StringTools.isEof(c)) return false; // Just in case :3
|
||||
return c >= 65 && c <= 90; // A-Z
|
||||
}
|
||||
|
||||
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
||||
return obj != null && obj is IHScriptAbstractBehaviour;
|
||||
|
||||
}
|
||||
@@ -10,14 +10,16 @@ import haxe.macro.Compiler;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class UsingHandler {
|
||||
class AbstractHandler {
|
||||
public static function init() {
|
||||
#if HSCRIPT_ABSTRACT_SUPPORT
|
||||
#if !display
|
||||
if(Context.defined("display")) return;
|
||||
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.UsingHandler.build())');
|
||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
|
||||
}
|
||||
#end
|
||||
#end
|
||||
}
|
||||
|
||||
public static function build():Array<Field> {
|
||||
@@ -10,10 +10,10 @@ import haxe.macro.Type.FieldKind;
|
||||
import haxe.macro.Type.ClassField;
|
||||
import haxe.macro.Type.VarAccess;
|
||||
import haxe.macro.*;
|
||||
import Sys;
|
||||
|
||||
using StringTools;
|
||||
|
||||
// BIG TODO: make typed classes scriptable
|
||||
class ClassExtendMacro {
|
||||
public static inline final FUNC_PREFIX = "_HX_SUPER__";
|
||||
public static inline final CLASS_SUFFIX = "_HSX";
|
||||
@@ -29,6 +29,7 @@ class ClassExtendMacro {
|
||||
for(apply in Config.ALLOWED_CUSTOM_CLASSES) {
|
||||
Compiler.addGlobalMetadata(apply, "@:build(hscript.macros.ClassExtendMacro.build())");
|
||||
}
|
||||
//Context.onAfterTyping(buildTyped);
|
||||
#end
|
||||
#end
|
||||
}
|
||||
@@ -61,6 +62,7 @@ class ClassExtendMacro {
|
||||
if(key == "away3d.tools.commands.Weld") return fields; // Error: Unknown identifier
|
||||
if(fkey == "hscript.CustomClassHandler.TemplateClass") return fields; // Error: Redefined
|
||||
if(fkey == "hscript.CustomClassHandler.CustomTemplateClass") return fields; // Error: Redefined
|
||||
if(fkey == "hscript.CustomClass") return fields; // Error: Redefined
|
||||
if(key == "sys.thread.EventLoop") return fields; // Error: cant override force inlined
|
||||
if(Config.DISALLOW_CUSTOM_CLASSES.contains(cl.module) || Config.DISALLOW_CUSTOM_CLASSES.contains(fkey)) return fields;
|
||||
if(cl.module.contains("_")) return fields; // Weird issue, sorry
|
||||
@@ -211,6 +213,15 @@ class ClassExtendMacro {
|
||||
continue;
|
||||
if (f.name == "new") {
|
||||
hasNew = true;
|
||||
switch (f.kind) {
|
||||
case FFun(fn):
|
||||
var constructor:Field = buildConstructor(fn.args);
|
||||
|
||||
shadowClass.fields.push(constructor);
|
||||
definedFields.push(f.name);
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (f.name.startsWith(FUNC_PREFIX))
|
||||
@@ -246,27 +257,24 @@ class ClassExtendMacro {
|
||||
overrideExpr = macro {
|
||||
var name:String = $v{name};
|
||||
|
||||
if (__custom__variables != null) {
|
||||
if(__custom__variables.exists(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __custom__variables.get(name))) {
|
||||
return v($a{arguments});
|
||||
}
|
||||
if (__interp != null && __class__fields.contains(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||
return v($a{arguments});
|
||||
}
|
||||
}
|
||||
|
||||
return super.$name($a{arguments});
|
||||
};
|
||||
} else {
|
||||
overrideExpr = macro {
|
||||
var name:String = $v{name};
|
||||
|
||||
if (__custom__variables != null) {
|
||||
if(__custom__variables.exists(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __custom__variables.get(name))) {
|
||||
v($a{arguments});
|
||||
return;
|
||||
}
|
||||
if (__interp != null && __class__fields.contains(name)) {
|
||||
var v:Dynamic = null;
|
||||
if (Reflect.isFunction(v = __interp.variables.get(name))) {
|
||||
v($a{arguments});
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.$name($a{arguments});
|
||||
@@ -331,7 +339,6 @@ class ClassExtendMacro {
|
||||
pack: cl.pack.copy(),
|
||||
name: cl.name
|
||||
}, [
|
||||
{name: "IHScriptCustomAccessBehaviour", pack: ["hscript"]},
|
||||
{name: "IHScriptCustomClassBehaviour", pack: ["hscript"]}
|
||||
], false, true, false);
|
||||
shadowClass.name = '${cl.name}$CLASS_SUFFIX';
|
||||
@@ -341,20 +348,27 @@ class ClassExtendMacro {
|
||||
|
||||
// Adding hscript getters and setters
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "__cachedFieldSet",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(macro: Map<String, Dynamic>),
|
||||
access: [APublic, AStatic]
|
||||
});
|
||||
|
||||
shadowClass.fields.push({
|
||||
name: "__interp",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(macro: hscript.Interp),
|
||||
access: [APublic]
|
||||
});
|
||||
|
||||
/*
|
||||
shadowClass.fields.push({
|
||||
name: "__custom__variables",
|
||||
pos: Context.currentPos(),
|
||||
kind: FVar(macro: Map<String, Dynamic>),
|
||||
access: [APublic]
|
||||
});
|
||||
|
||||
*/
|
||||
shadowClass.fields.push({
|
||||
name: "__allowSetGet",
|
||||
pos: Context.currentPos(),
|
||||
@@ -383,10 +397,7 @@ class ClassExtendMacro {
|
||||
ret: macro: Dynamic,
|
||||
params: [],
|
||||
expr: macro {
|
||||
__allowSetGet = false;
|
||||
var v = __custom__variables.get("get_" + name)();
|
||||
__allowSetGet = true;
|
||||
return v;
|
||||
return null;
|
||||
},
|
||||
args: [
|
||||
{
|
||||
@@ -407,10 +418,7 @@ class ClassExtendMacro {
|
||||
ret: macro: Dynamic,
|
||||
params: [],
|
||||
expr: macro {
|
||||
__allowSetGet = false;
|
||||
var v = __custom__variables.get("set_" + name)(val);
|
||||
__allowSetGet = true;
|
||||
return v;
|
||||
return null;
|
||||
},
|
||||
args: [
|
||||
{
|
||||
@@ -472,30 +480,81 @@ class ClassExtendMacro {
|
||||
|
||||
var hgetField = if(hasHgetInSuper) {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||
return __callGetter(name);
|
||||
if (__custom__variables.exists(name))
|
||||
return __custom__variables.get(name);
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callGetter(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);
|
||||
}
|
||||
} else {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("get_" + name))
|
||||
return __callGetter(name);
|
||||
if (__custom__variables.exists(name))
|
||||
return __custom__variables.get(name);
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).get(ba);
|
||||
return v;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.getField(name);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UnsafeReflect.getProperty(this, name);
|
||||
}
|
||||
}
|
||||
|
||||
var hsetField = if(hasHsetInSuper) {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||
return __callSetter(name, val);
|
||||
if (__custom__variables.exists(name)) {
|
||||
__custom__variables.set(name, val);
|
||||
return val;
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callSetter(name, val);
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.setField(name, val);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(__real_fields.contains(name)) {
|
||||
UnsafeReflect.setProperty(this, name, val);
|
||||
return UnsafeReflect.field(this, name);
|
||||
@@ -504,17 +563,34 @@ class ClassExtendMacro {
|
||||
}
|
||||
} else {
|
||||
macro {
|
||||
if(__allowSetGet && __custom__variables.exists("set_" + name))
|
||||
return __callSetter(name, val);
|
||||
if (__custom__variables.exists(name)) {
|
||||
__custom__variables.set(name, val);
|
||||
return val;
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).set(val, ba);
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
else @:privateAccess {
|
||||
var cls:hscript.CustomClass = cast __interp.__customClass.__upperClass;
|
||||
while(cls != null) {
|
||||
if(cls.hasField(name))
|
||||
return cls.setField(name, val);
|
||||
|
||||
var prev:hscript.CustomClass = cast cls.__upperClass;
|
||||
if(prev == null)
|
||||
break;
|
||||
cls = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(__real_fields.contains(name)) {
|
||||
UnsafeReflect.setProperty(this, name, val);
|
||||
return UnsafeReflect.field(this, name);
|
||||
}
|
||||
__custom__variables.set(name, val);
|
||||
//__custom__variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -579,6 +655,51 @@ class ClassExtendMacro {
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
static function buildConstructor(constArgs:Array<FunctionArg>):Field {
|
||||
var superCallArgs:Array<Expr> = [for (arg in constArgs) macro $i{arg.name}];
|
||||
|
||||
return {
|
||||
name: 'new',
|
||||
access: [APublic],
|
||||
pos: Context.currentPos(),
|
||||
kind: FFun({
|
||||
args: constArgs,
|
||||
expr: macro {
|
||||
// Call the super constructor with appropriate args
|
||||
super($a{superCallArgs});
|
||||
|
||||
if(__cachedFieldSet != null) {
|
||||
for(k => v in __cachedFieldSet) {
|
||||
Reflect.setProperty(this, k, v);
|
||||
}
|
||||
__cachedFieldSet.clear();
|
||||
__cachedFieldSet = null;
|
||||
}
|
||||
}
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
static function buildTyped(modules:Array<haxe.macro.Type.ModuleType>) {
|
||||
for(m in modules) {
|
||||
switch(m) {
|
||||
case TClassDecl(c):
|
||||
var cl = c.get();
|
||||
if (cl.isAbstract || cl.isExtern || cl.isFinal || cl.isInterface)
|
||||
continue;
|
||||
if (cl.params.length == 0)
|
||||
continue;
|
||||
if (!cl.name.endsWith("_Impl_") && !cl.name.endsWith(CLASS_SUFFIX) && !cl.name.endsWith("_HSC"))
|
||||
buildTypedClass(cl);
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function buildTypedClass(cl:ClassType) {}
|
||||
|
||||
static function buildShadowClass(cl:ClassType) {}
|
||||
}
|
||||
#else
|
||||
class ClassExtendMacro {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package hscript.utils;
|
||||
|
||||
@:structInit
|
||||
class UsingEntry {
|
||||
public var call:Dynamic->String->Array<Dynamic>->Dynamic;
|
||||
public var fields:Array<String>;
|
||||
|
||||
public function hasField(name:String) {
|
||||
return fields.contains(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special class that handles static extension function calls.
|
||||
*
|
||||
* A static extension allows pseudo-extending
|
||||
* existing types without modifying their source.
|
||||
* In Haxe this is achieved by declaring a static method with a first argument
|
||||
* of the extending type and then bringing the defining class into context through `using`.
|
||||
*
|
||||
* Example:
|
||||
* ```haxe
|
||||
* class IntExtender {
|
||||
* static public function triple(i:Int) {
|
||||
* return i * 3;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* using IntExtender;
|
||||
*
|
||||
* trace(12.triple()); // 36
|
||||
* ```
|
||||
*
|
||||
* @see https://haxe.org/manual/lf-static-extension.html
|
||||
*/
|
||||
class UsingHandler {
|
||||
// Predefined static extension classes
|
||||
public static final defaultExtension:Map<String, UsingEntry> = [
|
||||
"StringTools" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L45
|
||||
fields: Type.getClassFields(StringTools),
|
||||
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||
if (f == "isEof") // has @:noUsing
|
||||
return null;
|
||||
return switch (Type.typeof(o)) {
|
||||
case TInt if (f == 'hex'):
|
||||
StringTools.hex(o, args[0]);
|
||||
case TClass(String):
|
||||
var field = UnsafeReflect.field(StringTools, f);
|
||||
if (UnsafeReflect.isFunction(field)) UnsafeReflect.callMethodUnsafe(StringTools, field, [o].concat(args)); else null;
|
||||
default:
|
||||
null;
|
||||
}
|
||||
}
|
||||
},
|
||||
"Lambda" => { // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/iris/Iris.hx#L62
|
||||
fields: Type.getClassFields(Lambda),
|
||||
call: function(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic {
|
||||
if (o != null && o.iterator != null) {
|
||||
var field = UnsafeReflect.field(Lambda, f);
|
||||
if (UnsafeReflect.isFunction(field)) {
|
||||
return UnsafeReflect.callMethodUnsafe(Lambda, field, [o].concat(args));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@:allow(hscript.CustomClass)
|
||||
@:allow(hscript.CustomClassHandler)
|
||||
public var usingEntries(default, null):Map<String, UsingEntry> = [];
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function registerEntry(name:String, entry:Dynamic->String->Array<Dynamic>->Dynamic, fields:Array<String>) {
|
||||
usingEntries.set(name, {call: entry, fields: fields});
|
||||
}
|
||||
|
||||
public inline function entryExists(name:String):Bool {
|
||||
return usingEntries.exists(name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user