Compare commits
43
Commits
@@ -1,6 +1,8 @@
|
|||||||
hscript-improved
|
hscript-improved
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
- [Features](docs/FEATURES.md)
|
||||||
|
|
||||||
How to install
|
How to install
|
||||||
```
|
```
|
||||||
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git
|
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git
|
||||||
@@ -18,7 +20,9 @@ or set this in build.hxml
|
|||||||
-D CUSTOM_CLASSES
|
-D CUSTOM_CLASSES
|
||||||
```
|
```
|
||||||
|
|
||||||
Warning: custom class system is still in development, would like help to test it. For now, 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. Also you cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
|
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,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "hscript",
|
"name": "hscript-improved",
|
||||||
"url": "https://github.com/HaxeFoundation/hscript",
|
"url": "https://github.com/HaxeFoundation/hscript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||||
|
|||||||
+11
-11
@@ -170,7 +170,7 @@ class Async {
|
|||||||
return mk(EField(e, f), inf);
|
return mk(EField(e, f), inf);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function binop(op, e1, e2, inf) {
|
inline function binop(op:Binop, e1, e2, inf) {
|
||||||
return mk(EBinop(op, e1, e2), inf);
|
return mk(EBinop(op, e1, e2), inf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +294,7 @@ class Async {
|
|||||||
var efor = block([
|
var efor = block([
|
||||||
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
|
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
|
||||||
fun("_", block([
|
fun("_", block([
|
||||||
mk(EIf(mk(EUnop("!", true, call( field(it, "hasNext", it), [], it)),it), currentBreak(it)),it),
|
mk(EIf(mk(EUnop(Unop.OpNot, true, call( field(it, "hasNext", it), [], it)),it), currentBreak(it)),it),
|
||||||
mk(EVar(v, call(field(it, "next",it), [], it)), it),
|
mk(EVar(v, call(field(it, "next",it), [], it)), it),
|
||||||
toCps(eloop, loop, exit),
|
toCps(eloop, loop, exit),
|
||||||
], it),"_loop" + id),
|
], it),"_loop" + id),
|
||||||
@@ -303,11 +303,11 @@ class Async {
|
|||||||
currentLoop = oldLoop;
|
currentLoop = oldLoop;
|
||||||
currentBreak = oldBreak;
|
currentBreak = oldBreak;
|
||||||
return efor;
|
return efor;
|
||||||
case EUnop(op = "!", prefix, eop):
|
case EUnop(op = Unop.OpNot, prefix, eop):
|
||||||
return toCps(eop, fun("_r",call(rest, [mk(EUnop(op, prefix, ident("_r",e)),e)], e)), exit);
|
return toCps(eop, fun("_r",call(rest, [mk(EUnop(op, prefix, ident("_r",e)),e)], e)), exit);
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
switch( op ) {
|
switch( op ) {
|
||||||
case "=", "+=", "-=", "/=", "*=", "%=", "&=", "|=", "^=":
|
case OpAssign, OpAddAssign, OpSubAssign, OpDivAssign, OpMultAssign, OpModAssign, OpAndAssign, OpOrAssign, OpXorAssign:
|
||||||
switch( expr(e1) ) {
|
switch( expr(e1) ) {
|
||||||
case EIdent(_):
|
case EIdent(_):
|
||||||
var id = "_r" + uid++;
|
var id = "_r" + uid++;
|
||||||
@@ -326,14 +326,14 @@ class Async {
|
|||||||
default:
|
default:
|
||||||
throw "assert " + e1;
|
throw "assert " + e1;
|
||||||
}
|
}
|
||||||
case "||":
|
case OpBoolOr:
|
||||||
var id1 = "_r" + uid++;
|
var id1 = "_r" + uid++;
|
||||||
var id2 = "_r" + uid++;
|
var id2 = "_r" + uid++;
|
||||||
return toCps(e1, fun(id1, mk(EIf(binop("==", ident(id1,e1), ident("true",e1), e1),call(rest,[ident("true",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
return toCps(e1, fun(id1, mk(EIf(binop(OpEq, ident(id1,e1), ident("true",e1), e1),call(rest,[ident("true",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
||||||
case "&&":
|
case OpBoolAnd:
|
||||||
var id1 = "_r" + uid++;
|
var id1 = "_r" + uid++;
|
||||||
var id2 = "_r" + uid++;
|
var id2 = "_r" + uid++;
|
||||||
return toCps(e1, fun(id1, mk(EIf(binop("!=", ident(id1,e1), ident("true",e1), e1),call(rest,[ident("false",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
return toCps(e1, fun(id1, mk(EIf(binop(OpNeq, ident(id1,e1), ident("true",e1), e1),call(rest,[ident("false",e1)],e1),toCps(e2, rest, exit)),e)), exit);
|
||||||
default:
|
default:
|
||||||
var id1 = "_r" + uid++;
|
var id1 = "_r" + uid++;
|
||||||
var id2 = "_r" + uid++;
|
var id2 = "_r" + uid++;
|
||||||
@@ -364,7 +364,7 @@ class Async {
|
|||||||
fields.reverse();
|
fields.reverse();
|
||||||
for( f in fields )
|
for( f in fields )
|
||||||
rest = toCps(f.e, fun("_r", block([
|
rest = toCps(f.e, fun("_r", block([
|
||||||
binop("=", mk(EField(ident(id,f.e), f.name),f.e), ident("_r",f.e), f.e),
|
binop(OpAssign, mk(EField(ident(id,f.e), f.name),f.e), ident("_r",f.e), f.e),
|
||||||
rest,
|
rest,
|
||||||
],f.e)),exit);
|
],f.e)),exit);
|
||||||
return block([
|
return block([
|
||||||
@@ -378,7 +378,7 @@ class Async {
|
|||||||
while( i >= 0 ) {
|
while( i >= 0 ) {
|
||||||
var e = el[i];
|
var e = el[i];
|
||||||
rest = toCps(e, fun("_r", block([
|
rest = toCps(e, fun("_r", block([
|
||||||
binop("=", mk(EArray(ident(id,e), mk(EConst(CInt(i)),e)),e), ident("_r",e), e),
|
binop(OpAssign, mk(EArray(ident(id,e), mk(EConst(CInt(i)),e)),e), ident("_r",e), e),
|
||||||
rest,
|
rest,
|
||||||
],e)), exit);
|
],e)), exit);
|
||||||
i--;
|
i--;
|
||||||
@@ -396,7 +396,7 @@ class Async {
|
|||||||
return block([e, retNull(rest, e)], e);
|
return block([e, retNull(rest, e)], e);
|
||||||
return block([
|
return block([
|
||||||
mk(EVar(v, t),e),
|
mk(EVar(v, t),e),
|
||||||
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), retNull(rest,e)], e)), exit),
|
toCps(ev, fun("_r", block([binop(OpAssign, ident(v,e), ident("_r",e), e), retNull(rest,e)], e)), exit),
|
||||||
],e);
|
],e);
|
||||||
case EConst(_), EIdent(_), EUnop(_), EField(_):
|
case EConst(_), EIdent(_), EUnop(_), EField(_):
|
||||||
return call(rest, [e], e);
|
return call(rest, [e], e);
|
||||||
|
|||||||
+8
-4
@@ -124,6 +124,8 @@ class Bytes {
|
|||||||
#end
|
#end
|
||||||
bout.addByte(Type.enumIndex(e));
|
bout.addByte(Type.enumIndex(e));
|
||||||
switch( e ) {
|
switch( e ) {
|
||||||
|
case EPackage(n):
|
||||||
|
// TODO
|
||||||
case EImport(c):
|
case EImport(c):
|
||||||
// TODO
|
// TODO
|
||||||
case EClass(_, _, _, _):
|
case EClass(_, _, _, _):
|
||||||
@@ -132,6 +134,8 @@ class Bytes {
|
|||||||
// TODO
|
// TODO
|
||||||
case ECast(e, _):
|
case ECast(e, _):
|
||||||
// TODO
|
// TODO
|
||||||
|
case ERegex(e, f):
|
||||||
|
// TODO
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
doEncodeConst(c);
|
doEncodeConst(c);
|
||||||
case EIdent(v):
|
case EIdent(v):
|
||||||
@@ -152,11 +156,11 @@ class Bytes {
|
|||||||
doEncode(e);
|
doEncode(e);
|
||||||
doEncodeString(f);
|
doEncodeString(f);
|
||||||
case EBinop(op,e1,e2):
|
case EBinop(op,e1,e2):
|
||||||
doEncodeString(op);
|
doEncodeString(op.toString());
|
||||||
doEncode(e1);
|
doEncode(e1);
|
||||||
doEncode(e2);
|
doEncode(e2);
|
||||||
case EUnop(op,prefix,e):
|
case EUnop(op,prefix,e):
|
||||||
doEncodeString(op);
|
doEncodeString(op.toString()); // maybe doEncodeInt
|
||||||
bout.addByte(prefix?1:0);
|
bout.addByte(prefix?1:0);
|
||||||
doEncode(e);
|
doEncode(e);
|
||||||
case ECall(e,el):
|
case ECall(e,el):
|
||||||
@@ -274,11 +278,11 @@ class Bytes {
|
|||||||
var e = doDecode();
|
var e = doDecode();
|
||||||
EField(e,doDecodeString());
|
EField(e,doDecodeString());
|
||||||
case 6:
|
case 6:
|
||||||
var op = doDecodeString();
|
var op = Binop.fromString(doDecodeString());
|
||||||
var e1 = doDecode();
|
var e1 = doDecode();
|
||||||
EBinop(op,e1,doDecode());
|
EBinop(op,e1,doDecode());
|
||||||
case 7:
|
case 7:
|
||||||
var op = doDecodeString();
|
var op = Unop.fromString(doDecodeString());
|
||||||
var prefix = bin.get(pin++) != 0;
|
var prefix = bin.get(pin++) != 0;
|
||||||
EUnop(op,prefix,doDecode());
|
EUnop(op,prefix,doDecode());
|
||||||
case 8:
|
case 8:
|
||||||
|
|||||||
+30
-16
@@ -1073,10 +1073,10 @@ class Checker {
|
|||||||
case EUnop(op, _, e):
|
case EUnop(op, _, e):
|
||||||
var et = typeExpr(e, Value);
|
var et = typeExpr(e, Value);
|
||||||
switch( op ) {
|
switch( op ) {
|
||||||
case "++", "--", "-":
|
case OpIncrement | OpDecrement | OpNeg:
|
||||||
unify(et,TInt,e);
|
unify(et,TInt,e);
|
||||||
return et;
|
return et;
|
||||||
case "!":
|
case OpNot:
|
||||||
unify(et,TBool,e);
|
unify(et,TBool,e);
|
||||||
return et;
|
return et;
|
||||||
default:
|
default:
|
||||||
@@ -1113,11 +1113,11 @@ class Checker {
|
|||||||
return TVoid;
|
return TVoid;
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
switch( op ) {
|
switch( op ) {
|
||||||
case "&", "|", "^", ">>", ">>>", "<<":
|
case OpAnd, OpOr, OpXor, OpShr, OpUshr, OpShl:
|
||||||
typeExprWith(e1,TInt);
|
typeExprWith(e1,TInt);
|
||||||
typeExprWith(e2,TInt);
|
typeExprWith(e2,TInt);
|
||||||
return TInt;
|
return TInt;
|
||||||
case "=":
|
case OpAssign:
|
||||||
if( allowDefine ) {
|
if( allowDefine ) {
|
||||||
switch( edef(e1) ) {
|
switch( edef(e1) ) {
|
||||||
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
|
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
|
||||||
@@ -1133,7 +1133,7 @@ class Checker {
|
|||||||
}
|
}
|
||||||
typeExprWith(e2,vt);
|
typeExprWith(e2,vt);
|
||||||
return vt;
|
return vt;
|
||||||
case "+":
|
case OpAdd:
|
||||||
var t1 = typeExpr(e1,WithType(TInt));
|
var t1 = typeExpr(e1,WithType(TInt));
|
||||||
var t2 = typeExpr(e2,WithType(t1));
|
var t2 = typeExpr(e2,WithType(t1));
|
||||||
tryUnify(t1,t2);
|
tryUnify(t1,t2);
|
||||||
@@ -1150,14 +1150,14 @@ class Checker {
|
|||||||
unify(t1, TFloat, e1);
|
unify(t1, TFloat, e1);
|
||||||
unify(t2, TFloat, e2);
|
unify(t2, TFloat, e2);
|
||||||
}
|
}
|
||||||
case "-", "*", "/", "%":
|
case OpSub, OpMult, OpDiv, OpMod:
|
||||||
var t1 = typeExpr(e1,WithType(TInt));
|
var t1 = typeExpr(e1,WithType(TInt));
|
||||||
var t2 = typeExpr(e2,WithType(t1));
|
var t2 = typeExpr(e2,WithType(t1));
|
||||||
if( !tryUnify(t1,t2) )
|
if( !tryUnify(t1,t2) )
|
||||||
unify(t2,t1,e2);
|
unify(t2,t1,e2);
|
||||||
switch( [follow(t1), follow(t2)]) {
|
switch( [follow(t1), follow(t2)]) {
|
||||||
case [TInt, TInt]:
|
case [TInt, TInt]:
|
||||||
if( op == "/" ) return TFloat;
|
if( op == OpDiv ) return TFloat;
|
||||||
return TInt;
|
return TInt;
|
||||||
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
|
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
|
||||||
return TFloat;
|
return TFloat;
|
||||||
@@ -1165,21 +1165,21 @@ class Checker {
|
|||||||
unify(t1, TFloat, e1);
|
unify(t1, TFloat, e1);
|
||||||
unify(t2, TFloat, e2);
|
unify(t2, TFloat, e2);
|
||||||
}
|
}
|
||||||
case "&&", "||":
|
case OpBoolAnd, OpBoolOr:
|
||||||
typeExprWith(e1,TBool);
|
typeExprWith(e1,TBool);
|
||||||
typeExprWith(e2,TBool);
|
typeExprWith(e2,TBool);
|
||||||
return TBool;
|
return TBool;
|
||||||
case "...":
|
case OpInterval:
|
||||||
typeExprWith(e1,TInt);
|
typeExprWith(e1,TInt);
|
||||||
typeExprWith(e2,TInt);
|
typeExprWith(e2,TInt);
|
||||||
return makeIterator(TInt);
|
return makeIterator(TInt);
|
||||||
case "==", "!=":
|
case OpEq, OpNeq:
|
||||||
var t1 = typeExpr(e1,Value);
|
var t1 = typeExpr(e1,Value);
|
||||||
var t2 = typeExpr(e2,WithType(t1));
|
var t2 = typeExpr(e2,WithType(t1));
|
||||||
if( !tryUnify(t1,t2) )
|
if( !tryUnify(t1,t2) )
|
||||||
unify(t2,t1,e2);
|
unify(t2,t1,e2);
|
||||||
return TBool;
|
return TBool;
|
||||||
case ">", "<", ">=", "<=":
|
case OpGt, OpLt, OpGte, OpLte:
|
||||||
var t1 = typeExpr(e1,Value);
|
var t1 = typeExpr(e1,Value);
|
||||||
var t2 = typeExpr(e2,WithType(t1));
|
var t2 = typeExpr(e2,WithType(t1));
|
||||||
if( !tryUnify(t1,t2) )
|
if( !tryUnify(t1,t2) )
|
||||||
@@ -1190,12 +1190,26 @@ class Checker {
|
|||||||
error("Cannot compare "+typeStr(t1), expr);
|
error("Cannot compare "+typeStr(t1), expr);
|
||||||
}
|
}
|
||||||
return TBool;
|
return TBool;
|
||||||
|
case OpAddAssign, OpSubAssign, OpMultAssign, OpDivAssign, OpModAssign, OpAndAssign, OpOrAssign, OpXorAssign, OpShlAssign, OpShrAssign, OpUshrAssign, OpNcoalAssign:
|
||||||
|
var baseOp = switch(op) {
|
||||||
|
case OpAddAssign: OpAdd;
|
||||||
|
case OpSubAssign: OpSub;
|
||||||
|
case OpMultAssign: OpMult;
|
||||||
|
case OpDivAssign: OpDiv;
|
||||||
|
case OpModAssign: OpMod;
|
||||||
|
case OpAndAssign: OpAnd;
|
||||||
|
case OpOrAssign: OpOr;
|
||||||
|
case OpXorAssign: OpXor;
|
||||||
|
case OpShlAssign: OpShl;
|
||||||
|
case OpShrAssign: OpShr;
|
||||||
|
case OpUshrAssign: OpUshr;
|
||||||
|
case OpNcoalAssign: OpNcoal;
|
||||||
|
default: op;
|
||||||
|
};
|
||||||
|
var t = typeExpr(mk(EBinop(baseOp,e1,e2),expr),withType);
|
||||||
|
return typeExpr(mk(EBinop(OpAssign,e1,e2),expr), withType);
|
||||||
default:
|
default:
|
||||||
if( op.charCodeAt(op.length-1) == "=".code ) {
|
error("Unsupported operation "+op.toString(), expr);
|
||||||
var t = typeExpr(mk(EBinop(op.substr(0,op.length-1),e1,e2),expr),withType);
|
|
||||||
return typeExpr(mk(EBinop("=",e1,e2),expr), withType);
|
|
||||||
}
|
|
||||||
error("Unsupported operation "+op, expr);
|
|
||||||
}
|
}
|
||||||
case ETry(etry, v, et, ecatch):
|
case ETry(etry, v, et, ecatch):
|
||||||
var vt = typeExpr(etry, withType);
|
var vt = typeExpr(etry, withType);
|
||||||
|
|||||||
@@ -21,4 +21,9 @@ class Config {
|
|||||||
public static final DISALLOW_ABSTRACT_AND_ENUM = [
|
public static final DISALLOW_ABSTRACT_AND_ENUM = [
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@:unreflective
|
||||||
|
public static final IMPORT_BLACKLIST:Array<String> = [
|
||||||
|
// "flixel.FlxG"
|
||||||
|
];
|
||||||
}
|
}
|
||||||
+36
-20
@@ -13,7 +13,6 @@ using Lambda;
|
|||||||
* @author Jamextreme140
|
* @author Jamextreme140
|
||||||
*/
|
*/
|
||||||
@:access(hscript.CustomClassHandler)
|
@:access(hscript.CustomClassHandler)
|
||||||
@:access(hscript.Property)
|
|
||||||
class CustomClass implements IHScriptCustomClassBehaviour {
|
class CustomClass implements IHScriptCustomClassBehaviour {
|
||||||
public var className(get, never):String;
|
public var className(get, never):String;
|
||||||
|
|
||||||
@@ -48,6 +47,12 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
|||||||
__interp.staticVariables = __class.ogInterp.staticVariables;
|
__interp.staticVariables = __class.ogInterp.staticVariables;
|
||||||
__interp.customClasses = __class.ogInterp.customClasses;
|
__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) {
|
for (f in __class.fields) {
|
||||||
switch (Tools.expr(f)) {
|
switch (Tools.expr(f)) {
|
||||||
case EVar(n): __class__fields.push(n);
|
case EVar(n): __class__fields.push(n);
|
||||||
@@ -59,11 +64,6 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
|||||||
@:privateAccess __interp.exprReturn(f);
|
@:privateAccess __interp.exprReturn(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (f => v in __class.__interp.variables) {
|
|
||||||
if (!__interp.variables.exists(f))
|
|
||||||
__interp.variables.set(f, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
__interp.scriptObject = this;
|
__interp.scriptObject = this;
|
||||||
|
|
||||||
initializing = true;
|
initializing = true;
|
||||||
@@ -124,24 +124,39 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
|||||||
if(__cachedFieldSet != null)
|
if(__cachedFieldSet != null)
|
||||||
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
|
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
|
||||||
|
|
||||||
var disallowCopy = Type.getInstanceFields(__class.cl);
|
|
||||||
__superClass = Type.createInstance(__class.cl, args);
|
__superClass = Type.createInstance(__class.cl, args);
|
||||||
__superClass.__real_fields = disallowCopy;
|
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.__class__fields = this.__class__fields;
|
||||||
__superClass.__interp = this.__interp;
|
__superClass.__interp = this.__interp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
|
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
|
||||||
// TODO: optimize this
|
var superFnName:Null<String> = toSuper ? '_HX_SUPER__$name' : null;
|
||||||
var fnName = toSuper ? '_HX_SUPER__$name' : name;
|
var fn:Dynamic = {
|
||||||
var fn:Dynamic = __interp.variables.get(fnName);
|
if(toSuper && __interp.variables.exists(superFnName)) {
|
||||||
if(toSuper && fn == null)
|
__interp.variables.get(superFnName);
|
||||||
fn = __interp.variables.get(name);
|
}
|
||||||
|
else
|
||||||
|
__interp.variables.get(name);
|
||||||
|
};
|
||||||
|
|
||||||
if (fn != null && Reflect.isFunction(fn))
|
if (fn != null && Reflect.isFunction(fn))
|
||||||
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
|
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
|
||||||
else
|
|
||||||
|
// 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'));
|
__interp.error(ECustom('$name doesn\'t exists or is not a function'));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -158,9 +173,9 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
|||||||
var f = __interp.variables.get(name);
|
var f = __interp.variables.get(name);
|
||||||
if (f != null && allowProperty && f is Property) {
|
if (f != null && allowProperty && f is Property) {
|
||||||
var prop:Property = cast f;
|
var prop:Property = cast f;
|
||||||
prop.__allowSetGet = this.__allowSetGet;
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
var r = prop.callGetter(name);
|
var r = prop.get(!__allowSetGet);
|
||||||
prop.__allowSetGet = null;
|
//prop.__allowSetGet = true;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
@@ -170,9 +185,9 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
|||||||
var f = getField(name, false);
|
var f = getField(name, false);
|
||||||
if (f != null && f is Property) {
|
if (f != null && f is Property) {
|
||||||
var prop:Property = cast f;
|
var prop:Property = cast f;
|
||||||
prop.__allowSetGet = this.__allowSetGet;
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
var r = prop.callSetter(name, val);
|
var r = prop.set(val, !__allowSetGet);
|
||||||
prop.__allowSetGet = null;
|
//prop.__allowSetGet = true;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
__interp.variables.set(name, val);
|
__interp.variables.set(name, val);
|
||||||
@@ -338,6 +353,7 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
|||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: scriptable "toString" function
|
||||||
public function toString():String
|
public function toString():String
|
||||||
return className;
|
return className;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,39 +56,35 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
|||||||
__interp.staticVariables = ogInterp.staticVariables;
|
__interp.staticVariables = ogInterp.staticVariables;
|
||||||
__interp.customClasses = ogInterp.customClasses;
|
__interp.customClasses = ogInterp.customClasses;
|
||||||
|
|
||||||
for(e in fields.copy()) {
|
for(f => v in ogInterp.variables)
|
||||||
var validField:Bool = false;
|
if(!__interp.variables.exists(f))
|
||||||
|
__interp.variables.set(f, v);
|
||||||
|
|
||||||
|
for(i => e in fields.copy()) {
|
||||||
|
var isValid:Bool = false;
|
||||||
var staticField:Bool = false;
|
var staticField:Bool = false;
|
||||||
var fieldName:String = "";
|
var fieldName:String = null;
|
||||||
switch (Tools.expr(e)) {
|
switch (Tools.expr(e)) {
|
||||||
case EVar(n, _, _, _, isStatic):
|
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
|
||||||
validField = true;
|
isValid = true;
|
||||||
staticField = isStatic;
|
|
||||||
fieldName = n;
|
|
||||||
case EFunction(_, _, n, _, _, isStatic, _, _, _, _):
|
|
||||||
validField = true;
|
|
||||||
staticField = isStatic;
|
staticField = isStatic;
|
||||||
fieldName = n;
|
fieldName = n;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
if(staticField && validField) {
|
if(staticField && isValid) {
|
||||||
__interp.exprReturn(e);
|
__interp.exprReturn(e);
|
||||||
__staticFields.push(fieldName);
|
__staticFields.push(fieldName);
|
||||||
fields.remove(e);
|
fields.remove(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(f => v in ogInterp.variables)
|
|
||||||
if(!__interp.variables.exists(f))
|
|
||||||
__interp.variables.set(f, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hnew(args:Array<Dynamic>):Dynamic
|
public function hnew(args:Array<Dynamic>):Dynamic
|
||||||
return new CustomClass(this, args);
|
return new CustomClass(this, args);
|
||||||
|
|
||||||
@:allow(hscript.Interp)
|
@:allow(hscript.Interp)
|
||||||
function hasField(name:String) {
|
inline function hasField(name:String) {
|
||||||
return __staticFields.contains(name);
|
return __staticFields.contains(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +92,9 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
|||||||
var f = __interp.variables.get(name);
|
var f = __interp.variables.get(name);
|
||||||
if(f is Property && allowProperty) {
|
if(f is Property && allowProperty) {
|
||||||
var prop:Property = cast f;
|
var prop:Property = cast f;
|
||||||
prop.__allowSetGet = this.__allowSetGet;
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
var r = prop.callGetter(name);
|
var r = prop.get(!__allowSetGet);
|
||||||
prop.__allowSetGet = null;
|
//prop.__allowSetGet = true;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return f;
|
return f;
|
||||||
@@ -108,9 +104,9 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
|||||||
var f = getField(name, false);
|
var f = getField(name, false);
|
||||||
if(f is Property) {
|
if(f is Property) {
|
||||||
var prop:Property = cast f;
|
var prop:Property = cast f;
|
||||||
prop.__allowSetGet = this.__allowSetGet;
|
//prop.__allowSetGet = this.__allowSetGet;
|
||||||
var r = prop.callSetter(name, val);
|
var r = prop.set(val, !__allowSetGet);
|
||||||
prop.__allowSetGet = null;
|
//prop.__allowSetGet = true;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
__interp.variables.set(name, val);
|
__interp.variables.set(name, val);
|
||||||
@@ -118,6 +114,12 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function hget(name:String):Dynamic {
|
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)) {
|
if(hasField(name)) {
|
||||||
return getField(name);
|
return getField(name);
|
||||||
}
|
}
|
||||||
|
|||||||
+164
-3
@@ -28,13 +28,170 @@ typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #e
|
|||||||
|
|
||||||
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||||
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||||
|
|
||||||
|
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 UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||||
|
|
||||||
enum Const {
|
enum Const {
|
||||||
CInt( v : Int );
|
CInt( v : Int );
|
||||||
CFloat( f : Float );
|
CFloat( f : Float );
|
||||||
CString( s : String );
|
CString( s : String, ?i : Bool );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
@@ -57,8 +214,8 @@ enum Expr {
|
|||||||
EParent( e : Expr );
|
EParent( e : Expr );
|
||||||
EBlock( e : Array<Expr> );
|
EBlock( e : Array<Expr> );
|
||||||
EField( e : Expr, f : String , ?safe : Bool );
|
EField( e : Expr, f : String , ?safe : Bool );
|
||||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
EBinop( op : Binop, e1 : Expr, e2 : Expr );
|
||||||
EUnop( op : String, prefix : Bool, e : Expr );
|
EUnop( op : Unop, prefix : Bool, e : Expr );
|
||||||
ECall( e : Expr, params : Array<Expr> );
|
ECall( e : Expr, params : Array<Expr> );
|
||||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||||
EWhile( cond : Expr, e : Expr );
|
EWhile( cond : Expr, e : Expr );
|
||||||
@@ -79,10 +236,12 @@ enum Expr {
|
|||||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||||
ECheckType( e : Expr, t : CType );
|
ECheckType( e : Expr, t : CType );
|
||||||
|
|
||||||
|
EPackage( ?n:String );
|
||||||
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||||
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||||
ECast(e:Expr, ?t:CType);
|
ECast(e:Expr, ?t:CType);
|
||||||
|
ERegex(e:String, flags:String);
|
||||||
}
|
}
|
||||||
|
|
||||||
@:structInit
|
@:structInit
|
||||||
@@ -117,12 +276,14 @@ typedef Metadata = Array<MetadataEntry>;
|
|||||||
final class EnumDecl {
|
final class EnumDecl {
|
||||||
public var name : String;
|
public var name : String;
|
||||||
public var fields : Array<EnumField>;
|
public var fields : Array<EnumField>;
|
||||||
|
public var underlyingType : Null<CType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:structInit
|
@:structInit
|
||||||
final class EnumField {
|
final class EnumField {
|
||||||
public var name : String;
|
public var name : String;
|
||||||
public var args : Array<Argument>;
|
public var args : Array<Argument>;
|
||||||
|
public var value : Null<Expr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CType {
|
enum CType {
|
||||||
|
|||||||
+119
-3
@@ -2,13 +2,13 @@ package hscript;
|
|||||||
|
|
||||||
import hscript.utils.UnsafeReflect;
|
import hscript.utils.UnsafeReflect;
|
||||||
|
|
||||||
// TODO: EnumTools for scripted enums
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class for enums, both for real and scripted.
|
* Wrapper class for enums, both for real and scripted.
|
||||||
|
* Use EnumTools and EnumValueTools for enum operations.
|
||||||
*/
|
*/
|
||||||
@:structInit
|
@:structInit
|
||||||
class HEnum implements IHScriptCustomBehaviour {
|
class HEnum implements IHScriptCustomBehaviour {
|
||||||
private var enumValues(default, null) = {};
|
var enumValues(default, null) = {};
|
||||||
|
|
||||||
public function setEnum(name:String, enumValue:Dynamic):Void {
|
public function setEnum(name:String, enumValue:Dynamic):Void {
|
||||||
UnsafeReflect.setField(enumValues, name, enumValue);
|
UnsafeReflect.setField(enumValues, name, enumValue);
|
||||||
@@ -20,6 +20,10 @@ class HEnum implements IHScriptCustomBehaviour {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEnumValues():Dynamic {
|
||||||
|
return enumValues;
|
||||||
|
}
|
||||||
|
|
||||||
public function hget(name:String):Dynamic {
|
public function hget(name:String):Dynamic {
|
||||||
return getEnum(name);
|
return getEnum(name);
|
||||||
}
|
}
|
||||||
@@ -57,10 +61,122 @@ class HEnumValue {
|
|||||||
if (args.length != other.args.length)
|
if (args.length != other.args.length)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (i in 0...args.length) // TODO: allow deep comparison, like arrays
|
for (i in 0...args.length)
|
||||||
if (args[i] != other.args[i])
|
if (args[i] != other.args[i])
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+446
-228
File diff suppressed because it is too large
Load Diff
+5
-4
@@ -151,12 +151,13 @@ class Macro {
|
|||||||
case EField(e, f):
|
case EField(e, f):
|
||||||
EField(convert(e), f);
|
EField(convert(e), f);
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
var b = binops.get(op);
|
var b = binops.get(op.toString());
|
||||||
if( b == null ) throw EInvalidOp(op);
|
if( b == null ) throw EInvalidOp(op.toString());
|
||||||
EBinop(b, convert(e1), convert(e2));
|
EBinop(b, convert(e1), convert(e2));
|
||||||
case EUnop(op, prefix, e):
|
case EUnop(op, prefix, e):
|
||||||
var u = unops.get(op);
|
var opStr = op.toString();
|
||||||
if( u == null ) throw EInvalidOp(op);
|
var u = unops.get(opStr);
|
||||||
|
if( u == null ) throw EInvalidOp(opStr);
|
||||||
EUnop(u, !prefix, convert(e));
|
EUnop(u, !prefix, convert(e));
|
||||||
case ECall(e, params):
|
case ECall(e, params):
|
||||||
ECall(convert(e), map(params, convert));
|
ECall(convert(e), map(params, convert));
|
||||||
|
|||||||
+356
-137
@@ -43,6 +43,7 @@ enum Token {
|
|||||||
TDoubleDot;
|
TDoubleDot;
|
||||||
TMeta( s : String );
|
TMeta( s : String );
|
||||||
TPrepro( s : String );
|
TPrepro( s : String );
|
||||||
|
TRegex( e : String, f:String );
|
||||||
}
|
}
|
||||||
|
|
||||||
@:structInit
|
@:structInit
|
||||||
@@ -72,6 +73,11 @@ class Parser {
|
|||||||
**/
|
**/
|
||||||
public var allowJSON : Bool;
|
public var allowJSON : Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
activate Regular Expression parsing
|
||||||
|
**/
|
||||||
|
public var allowRegex : Bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
allow types declarations
|
allow types declarations
|
||||||
**/
|
**/
|
||||||
@@ -115,6 +121,8 @@ class Parser {
|
|||||||
|
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
static inline var regexFlags: String = "igmsu";
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
line = 1;
|
line = 1;
|
||||||
opChars = "+*/-=!><&|^%~";
|
opChars = "+*/-=!><&|^%~";
|
||||||
@@ -207,7 +215,7 @@ class Parser {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function push(tk: Token):Void {
|
@:analyzer(fusion) inline function push(tk: Token):Void {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
tokens.push( { t : tk, min : tokenMin, max : tokenMax } );
|
tokens.push( { t : tk, min : tokenMin, max : tokenMax } );
|
||||||
tokenMin = oldTokenMin;
|
tokenMin = oldTokenMin;
|
||||||
@@ -217,17 +225,17 @@ class Parser {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function ensure(tk:Token):Void {
|
@:analyzer(fusion) inline function ensure(tk:Token):Void {
|
||||||
var t = token();
|
var t = token();
|
||||||
if( t != tk ) unexpected(t);
|
if( t != tk ) unexpected(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function ensureToken(tk:Token):Void {
|
@:analyzer(fusion) inline function ensureToken(tk:Token):Void {
|
||||||
var t = token();
|
var t = token();
|
||||||
if( !Type.enumEq(t,tk) ) unexpected(t);
|
if( !Type.enumEq(t,tk) ) unexpected(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybe(tk:Token):Bool {
|
@:analyzer(fusion) inline function maybe(tk:Token):Bool {
|
||||||
var t = token();
|
var t = token();
|
||||||
if( Type.enumEq(t, tk) )
|
if( Type.enumEq(t, tk) )
|
||||||
return true;
|
return true;
|
||||||
@@ -245,7 +253,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function expr(e:Expr):#if hscriptPos ExprDef #else Expr #end {
|
@:analyzer(fusion) inline function expr(e:Expr):#if hscriptPos ExprDef #else Expr #end {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e.e;
|
return e.e;
|
||||||
#else
|
#else
|
||||||
@@ -253,7 +261,7 @@ class Parser {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function pmin(e:Expr):Int {
|
@:analyzer(fusion) inline function pmin(e:Expr):Int {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e == null ? 0 : e.pmin;
|
return e == null ? 0 : e.pmin;
|
||||||
#else
|
#else
|
||||||
@@ -261,7 +269,7 @@ class Parser {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function pmax(e:Expr):Int {
|
@:analyzer(fusion) inline function pmax(e:Expr):Int {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
return e == null ? 0 : e.pmax;
|
return e == null ? 0 : e.pmax;
|
||||||
#else
|
#else
|
||||||
@@ -269,7 +277,7 @@ class Parser {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function mk(e:#if hscriptPos ExprDef #else Expr #end,?pmin:Int,?pmax:Int) : Expr {
|
@:analyzer(fusion) inline function mk(e:#if hscriptPos ExprDef #else Expr #end,?pmin:Int,?pmax:Int) : Expr {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
if( e == null ) return null;
|
if( e == null ) return null;
|
||||||
if( pmin == null ) pmin = tokenMin;
|
if( pmin == null ) pmin = tokenMin;
|
||||||
@@ -280,7 +288,7 @@ class Parser {
|
|||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
function isBlock(e:Expr):Bool {
|
@:analyzer(fusion) inline function isBlock(e:Expr):Bool {
|
||||||
if( e == null ) return false;
|
if( e == null ) return false;
|
||||||
return switch( expr(e) ) {
|
return switch( expr(e) ) {
|
||||||
case EBlock(_), EObject(_), ESwitch(_), EEnum(_, _): true;
|
case EBlock(_), EObject(_), ESwitch(_), EEnum(_, _): true;
|
||||||
@@ -300,7 +308,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFullExpr( exprs : Array<Expr> ):Void {
|
@:analyzer(fusion) function parseFullExpr( exprs : Array<Expr> ):Void {
|
||||||
var e = parseExpr();
|
var e = parseExpr();
|
||||||
exprs.push(e);
|
exprs.push(e);
|
||||||
|
|
||||||
@@ -332,7 +340,7 @@ class Parser {
|
|||||||
if( !allowJSON )
|
if( !allowJSON )
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
switch( c ) {
|
switch( c ) {
|
||||||
case CString(s): id = s;
|
case CString(s, _): id = s;
|
||||||
default: unexpected(tk);
|
default: unexpected(tk);
|
||||||
}
|
}
|
||||||
case TBrClose:
|
case TBrClose:
|
||||||
@@ -363,12 +371,17 @@ class Parser {
|
|||||||
var p1 = tokenMin;
|
var p1 = tokenMin;
|
||||||
#end
|
#end
|
||||||
switch( tk ) {
|
switch( tk ) {
|
||||||
case TId(id): // TODO: direct access to classes by typing their path
|
case TId(id):
|
||||||
var e = parseStructure(id, oldPos);
|
var e = parseStructure(id, oldPos);
|
||||||
if( e == null )
|
if( e == null )
|
||||||
e = mk(EIdent(id));
|
e = mk(EIdent(id));
|
||||||
return parseExprNext(e);
|
return parseExprNext(e);
|
||||||
case TConst(c):
|
case TConst(c):
|
||||||
|
switch(c) {
|
||||||
|
case CString(s, i):
|
||||||
|
if(i) return parseExprNext(interpolateString(s));
|
||||||
|
default:
|
||||||
|
}
|
||||||
return parseExprNext(mk(EConst(c)));
|
return parseExprNext(mk(EConst(c)));
|
||||||
case TPOpen:
|
case TPOpen:
|
||||||
tk = token();
|
tk = token();
|
||||||
@@ -513,6 +526,8 @@ class Parser {
|
|||||||
var e = parseExpr();
|
var e = parseExpr();
|
||||||
isVar = false;
|
isVar = false;
|
||||||
return mk(EMeta(id, args, e),p1);
|
return mk(EMeta(id, args, e),p1);
|
||||||
|
case TRegex(e, f) if(allowRegex):
|
||||||
|
return mk(ERegex(e, f), p1);
|
||||||
default:
|
default:
|
||||||
return unexpected(tk);
|
return unexpected(tk);
|
||||||
}
|
}
|
||||||
@@ -589,27 +604,28 @@ class Parser {
|
|||||||
return switch( expr(e) ) {
|
return switch( expr(e) ) {
|
||||||
case EBinop(bop, e1, e2): mk(EBinop(bop, makeUnop(op, e1), e2), pmin(e1), pmax(e2));
|
case EBinop(bop, e1, e2): mk(EBinop(bop, makeUnop(op, e1), e2), pmin(e1), pmax(e2));
|
||||||
case ETernary(e1, e2, e3): mk(ETernary(makeUnop(op, e1), e2, e3), pmin(e1), pmax(e3));
|
case ETernary(e1, e2, e3): mk(ETernary(makeUnop(op, e1), e2, e3), pmin(e1), pmax(e3));
|
||||||
default: mk(EUnop(op,true,e),pmin(e),pmax(e));
|
default: mk(EUnop(Unop.fromString(op),true,e),pmin(e),pmax(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeBinop( op:String, e1:Expr, e:Expr ):Expr {
|
@:analyzer(fusion) inline function makeBinop( op:String, e1:Expr, e:Expr ):Expr {
|
||||||
|
var binop = Binop.fromString(op);
|
||||||
if( e == null && resumeErrors )
|
if( e == null && resumeErrors )
|
||||||
return mk(EBinop(op,e1,e),pmin(e1),pmax(e1));
|
return mk(EBinop(binop,e1,e),pmin(e1),pmax(e1));
|
||||||
return switch( expr(e) ) {
|
return switch( expr(e) ) {
|
||||||
case EBinop(op2,e2,e3):
|
case EBinop(op2,e2,e3):
|
||||||
var delta = opPriority.get(op) - opPriority.get(op2);
|
var delta = opPriority.get(op) - opPriority.get(op2.toString());
|
||||||
if( delta < 0 || (delta == 0 && !opRightAssoc.exists(op)) )
|
if( delta < 0 || (delta == 0 && !opRightAssoc.exists(op)) )
|
||||||
mk(EBinop(op2,makeBinop(op,e1,e2),e3),pmin(e1),pmax(e3));
|
mk(EBinop(op2,makeBinop(op,e1,e2),e3),pmin(e1),pmax(e3));
|
||||||
else
|
else
|
||||||
mk(EBinop(op, e1, e), pmin(e1), pmax(e));
|
mk(EBinop(binop, e1, e), pmin(e1), pmax(e));
|
||||||
case ETernary(e2,e3,e4):
|
case ETernary(e2,e3,e4):
|
||||||
if( opRightAssoc.exists(op) )
|
if( opRightAssoc.exists(op) )
|
||||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
mk(EBinop(binop,e1,e),pmin(e1),pmax(e));
|
||||||
else
|
else
|
||||||
mk(ETernary(makeBinop(op, e1, e2), e3, e4), pmin(e1), pmax(e));
|
mk(ETernary(makeBinop(op, e1, e2), e3, e4), pmin(e1), pmax(e));
|
||||||
default:
|
default:
|
||||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
mk(EBinop(binop,e1,e),pmin(e1),pmax(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -957,6 +973,16 @@ class Parser {
|
|||||||
var tk = token();
|
var tk = token();
|
||||||
push(tk);
|
push(tk);
|
||||||
mk(EFunction(inf.args, inf.body, name, inf.ret, nextIsPublic, nextIsStatic, nextIsOverride, nextIsPrivate, nextIsFinal, nextIsInline),p1,pmax(inf.body));
|
mk(EFunction(inf.args, inf.body, name, inf.ret, nextIsPublic, nextIsStatic, nextIsOverride, nextIsPrivate, nextIsFinal, nextIsInline),p1,pmax(inf.body));
|
||||||
|
case "package":
|
||||||
|
var tk = token();
|
||||||
|
push(tk);
|
||||||
|
if(tk == TSemicolon)
|
||||||
|
return mk(EPackage(null), p1);
|
||||||
|
|
||||||
|
var pkg:String = parsePath().join('.');
|
||||||
|
ensure(TSemicolon);
|
||||||
|
push(TSemicolon);
|
||||||
|
mk(EPackage(pkg), p1);
|
||||||
case "import" | "using":
|
case "import" | "using":
|
||||||
var isUsing = id == "using";
|
var isUsing = id == "using";
|
||||||
var oldReadPos = readPos;
|
var oldReadPos = readPos;
|
||||||
@@ -1021,72 +1047,62 @@ class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "class":
|
case "class":
|
||||||
// example: class ClassName
|
// example: class ClassName<K, V>
|
||||||
var tk = token();
|
var name:String = null;
|
||||||
var name = null;
|
var ct = parseType(); // this is for handling type parameters
|
||||||
|
switch(ct) {
|
||||||
switch (tk) {
|
case CTPath(path, params):
|
||||||
case TId(id): name = id;
|
name = path.join(".");
|
||||||
default: push(tk);
|
default:
|
||||||
|
error(EUnexpected(Std.string(ct)), p1, tokenMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
var extend:String = null;
|
var extend:String = null;
|
||||||
var interfaces:Array<String> = [];
|
if(maybe(TId("extends"))) {
|
||||||
// optional - example: extends BaseClass
|
|
||||||
|
|
||||||
while( true ) {
|
|
||||||
var t = token();
|
|
||||||
switch( t ) {
|
|
||||||
case TId("extends"):
|
|
||||||
var e = parseType();
|
var e = parseType();
|
||||||
switch(e) {
|
switch(e) {
|
||||||
case CTPath(path, params):
|
case CTPath(path, params):
|
||||||
if(extend != null) {
|
var buf = new StringBuf();
|
||||||
error(ECustom('Cannot extend a class twice.'), 0, 0);
|
for(i in 0...path.length) {
|
||||||
|
if(i > 0) buf.add(".");
|
||||||
|
buf.add(path[i]);
|
||||||
}
|
}
|
||||||
extend = path.join(".");
|
extend = buf.toString();
|
||||||
default:
|
default:
|
||||||
error(ECustom('${Std.string(e)} is not a valid path.'), 0, 0);
|
error(ECustom('${Std.string(e)} is not a valid path.'), p1, tokenMax);
|
||||||
}
|
|
||||||
default:
|
|
||||||
push(t);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*while(true) {
|
var interfaces:Array<String> = [];
|
||||||
|
var tk:Token = null;
|
||||||
|
if(maybe(TId("implements"))) {
|
||||||
|
// handled manually for multiple implements
|
||||||
|
while(true) {
|
||||||
tk = token();
|
tk = token();
|
||||||
trace(tk);
|
switch(tk) {
|
||||||
switch (tk) {
|
case TId("implements"): continue;
|
||||||
case TId(id):
|
case TId("extends"):
|
||||||
if (id == "extends") {
|
error(ECustom('Implements must come after extends.'), p1, tokenMax);
|
||||||
tk = token();
|
case TId(_):
|
||||||
if(extend != null) {
|
push(tk);
|
||||||
unexpected(tk);
|
var e = parseType();
|
||||||
} else {
|
switch(e) {
|
||||||
switch (tk) {
|
case CTPath(path, params):
|
||||||
case TId(id): extend = id;
|
var buf = new StringBuf();
|
||||||
default: unexpected(tk);
|
for(i in 0...path.length) {
|
||||||
|
if(i > 0) buf.add(".");
|
||||||
|
buf.add(path[i]);
|
||||||
}
|
}
|
||||||
|
interfaces.push(buf.toString());
|
||||||
|
default:
|
||||||
|
error(ECustom('${Std.string(e)} is not a valid path.'), p1, tokenMax);
|
||||||
}
|
}
|
||||||
} else if (id == "implements") {
|
default:
|
||||||
tk = token();
|
|
||||||
switch (tk) {
|
|
||||||
case TId(id): interfaces.push(id);
|
|
||||||
default: unexpected(tk);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//push(tk);
|
|
||||||
}
|
|
||||||
|
|
||||||
case TBrOpen:
|
|
||||||
push(tk);
|
push(tk);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
//push(tk);
|
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var fields = [];
|
var fields = [];
|
||||||
ensure(TBrOpen);
|
ensure(TBrOpen);
|
||||||
@@ -1102,39 +1118,64 @@ class Parser {
|
|||||||
push(tk);
|
push(tk);
|
||||||
mk(EClass(name, fields, extend, interfaces, nextIsFinal, nextIsPrivate), p1);
|
mk(EClass(name, fields, extend, interfaces, nextIsFinal, nextIsPrivate), p1);
|
||||||
|
|
||||||
case "enum": // TODO: enum abstract
|
case "enum":
|
||||||
|
var isAbstract = maybe(TId("abstract"));
|
||||||
var name = getIdent();
|
var name = getIdent();
|
||||||
|
var underlyingType:CType = null;
|
||||||
|
|
||||||
|
if(isAbstract) {
|
||||||
|
ensure(TPOpen);
|
||||||
|
if(allowTypes) {
|
||||||
|
underlyingType = parseType();
|
||||||
|
ensure(TPClose);
|
||||||
|
} else {
|
||||||
|
var t = token();
|
||||||
|
while(t != TPClose && t != TEof) {
|
||||||
|
t = token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ensure(TBrOpen);
|
ensure(TBrOpen);
|
||||||
|
|
||||||
// TODO: optimize this
|
|
||||||
var fields:Array<EnumField> = [];
|
var fields:Array<EnumField> = [];
|
||||||
var fieldName:String = '';
|
var fieldName:String = '';
|
||||||
var enumArgs:Array<Argument> = null;
|
var enumArgs:Array<Argument> = null;
|
||||||
//var tk = token();
|
var fieldValue:Expr = null;
|
||||||
|
|
||||||
while(!maybe(TBrClose)) {
|
while(!maybe(TBrClose)) {
|
||||||
var tk = token();
|
var tk = token();
|
||||||
|
|
||||||
switch(tk) {
|
switch(tk) {
|
||||||
//case TBrClose:
|
|
||||||
// break;
|
|
||||||
case TSemicolon | TComma:
|
case TSemicolon | TComma:
|
||||||
if(fieldName.trim().length == 0) continue;
|
if(fieldName.trim().length == 0) continue;
|
||||||
|
|
||||||
fields.push({
|
fields.push({
|
||||||
name: fieldName,
|
name: fieldName,
|
||||||
args: enumArgs == null ? [] : enumArgs
|
args: enumArgs == null ? [] : enumArgs,
|
||||||
|
value: fieldValue
|
||||||
});
|
});
|
||||||
fieldName = '';
|
fieldName = '';
|
||||||
enumArgs = null;
|
enumArgs = null;
|
||||||
|
fieldValue = null;
|
||||||
case TPOpen:
|
case TPOpen:
|
||||||
|
if(isAbstract) {
|
||||||
|
error(ECustom("Enum abstract fields cannot have parameters"), tokenMin, tokenMax);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(enumArgs != null) {
|
if(enumArgs != null) {
|
||||||
error(ECustom("Cannot have multiple argument lists in one enum constructor"), tokenMin, tokenMax);
|
error(ECustom("Cannot have multiple argument lists in one enum constructor"), tokenMin, tokenMax);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
enumArgs = parseFunctionArgs(true);
|
enumArgs = parseFunctionArgs(true);
|
||||||
|
case TOp("="):
|
||||||
|
if(!isAbstract) {
|
||||||
|
error(ECustom("Only enum abstract fields can have values"), tokenMin, tokenMax);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fieldValue = parseExpr();
|
||||||
default:
|
default:
|
||||||
|
if(tk.match(TId("var"))) continue;
|
||||||
if(fieldName.trim().length != 0) {
|
if(fieldName.trim().length != 0) {
|
||||||
error(ECustom("Expected comma or semicolon"), tokenMin, tokenMax);
|
error(ECustom("Expected comma or semicolon"), tokenMin, tokenMax);
|
||||||
break;
|
break;
|
||||||
@@ -1144,7 +1185,7 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mk(EEnum({ name: name, fields: fields }, false), p1);
|
mk(EEnum({ name: name, fields: fields, underlyingType: underlyingType }, isAbstract), p1);
|
||||||
case "cast":
|
case "cast":
|
||||||
var tk = token();
|
var tk = token();
|
||||||
var e:Expr = null;
|
var e:Expr = null;
|
||||||
@@ -1160,14 +1201,15 @@ class Parser {
|
|||||||
e = parseExpr();
|
e = parseExpr();
|
||||||
}
|
}
|
||||||
|
|
||||||
mk(ECast(e, t));
|
mk(ECast(e, t), p1);
|
||||||
case "return":
|
case "return":
|
||||||
var tk = token();
|
var tk = token();
|
||||||
push(tk);
|
push(tk);
|
||||||
var e = if( tk == TSemicolon ) null else parseExpr();
|
var e = if( tk == TSemicolon ) null else parseExpr();
|
||||||
mk(EReturn(e),p1,if( e == null ) tokenMax else pmax(e));
|
mk(EReturn(e),p1,if( e == null ) tokenMax else pmax(e));
|
||||||
case "new":
|
case "new":
|
||||||
var a = [];
|
// TODO: maybe use CTPath for this
|
||||||
|
var a:Array<String> = [];
|
||||||
var params:Null<Array<CType>> = null;
|
var params:Null<Array<CType>> = null;
|
||||||
a.push(getIdent());
|
a.push(getIdent());
|
||||||
while( true ) {
|
while( true ) {
|
||||||
@@ -1344,7 +1386,7 @@ class Parser {
|
|||||||
push(tk);
|
push(tk);
|
||||||
return e1;
|
return e1;
|
||||||
}
|
}
|
||||||
return parseExprNext(mk(EUnop(op,false,e1),pmin(e1)));
|
return parseExprNext(mk(EUnop(Unop.fromString(op),false,e1),pmin(e1)));
|
||||||
}
|
}
|
||||||
return makeBinop(op,e1,parseExpr());
|
return makeBinop(op,e1,parseExpr());
|
||||||
case TId(op) if( opPriority.exists(op) ):
|
case TId(op) if( opPriority.exists(op) ):
|
||||||
@@ -1376,17 +1418,15 @@ class Parser {
|
|||||||
var done = false;
|
var done = false;
|
||||||
while( !done ) {
|
while( !done ) {
|
||||||
var name = null, opt = false;
|
var name = null, opt = false;
|
||||||
switch( tk ) {
|
if( tk == TQuestion ) {
|
||||||
case TQuestion:
|
|
||||||
opt = true;
|
opt = true;
|
||||||
tk = token();
|
tk = token();
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
switch( tk ) {
|
switch( tk ) {
|
||||||
case TId(id): name = id;
|
case TId(id):
|
||||||
|
name = id;
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
var arg : Argument = { name : name, opt: false, value: null, t: null };
|
var arg : Argument = { name : name, opt: false, value: null, t: null };
|
||||||
args.push(arg);
|
args.push(arg);
|
||||||
@@ -1401,12 +1441,11 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
tk = token();
|
tk = token();
|
||||||
switch( tk ) {
|
if( tk == TComma ) {
|
||||||
case TComma:
|
|
||||||
tk = token();
|
tk = token();
|
||||||
case TPClose:
|
} else if( tk == TPClose ) {
|
||||||
done = true;
|
done = true;
|
||||||
default:
|
} else {
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1454,11 +1493,12 @@ class Parser {
|
|||||||
if( op == "<" ) {
|
if( op == "<" ) {
|
||||||
params = [];
|
params = [];
|
||||||
while( true ) {
|
while( true ) {
|
||||||
switch( token() ) {
|
var tt = token();
|
||||||
|
switch( tt ) {
|
||||||
case TConst(c):
|
case TConst(c):
|
||||||
params.push(CTExpr(mk(EConst(c))));
|
params.push(CTExpr(mk(EConst(c))));
|
||||||
case tk:
|
default:
|
||||||
push(tk);
|
push(tt);
|
||||||
params.push(parseType());
|
params.push(parseType());
|
||||||
}
|
}
|
||||||
t = token();
|
t = token();
|
||||||
@@ -1608,17 +1648,102 @@ class Parser {
|
|||||||
while( true ) {
|
while( true ) {
|
||||||
args.push(parseExpr());
|
args.push(parseExpr());
|
||||||
tk = token();
|
tk = token();
|
||||||
switch( tk ) {
|
if( tk == etk )
|
||||||
case TComma:
|
|
||||||
default:
|
|
||||||
if( tk == etk ) break;
|
|
||||||
unexpected(tk);
|
|
||||||
break;
|
break;
|
||||||
}
|
if( tk != TComma )
|
||||||
|
unexpected(tk);
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From hscript-iris: https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Parser.hx#L409
|
||||||
|
// by inky03
|
||||||
|
function interpolateString(s:String):Expr {
|
||||||
|
var exprs:Array<Expr> = [];
|
||||||
|
var dollarPos:Int = s.indexOf('$');
|
||||||
|
|
||||||
|
if(dollarPos == -1)
|
||||||
|
return mk(EConst(CString(s)));
|
||||||
|
|
||||||
|
final singleFirst:EReg = ~/[a-zA-Z_]/i;
|
||||||
|
final singleExpr:EReg = ~/[a-zA-Z0-9_]/i;
|
||||||
|
// TODO: optimize this using regex
|
||||||
|
while(dollarPos > -1) {
|
||||||
|
var pos:Int = dollarPos;
|
||||||
|
var pre:String = s.substr(0, pos);
|
||||||
|
var next:String = s.charAt(++pos);
|
||||||
|
if(next == '{') {
|
||||||
|
if (pre != '')
|
||||||
|
exprs.push(mk(EConst(CString(pre))));
|
||||||
|
var exprStr:String = '';
|
||||||
|
var depth:Int = 1;
|
||||||
|
while (true) {
|
||||||
|
next = s.charAt(++pos);
|
||||||
|
if (next == '{') {
|
||||||
|
depth++;
|
||||||
|
} else if (next == '}') {
|
||||||
|
depth--;
|
||||||
|
}
|
||||||
|
if (depth < 1)
|
||||||
|
break;
|
||||||
|
if (pos >= s.length) {
|
||||||
|
error(EUnterminatedString, pos, pos);
|
||||||
|
}
|
||||||
|
exprStr += next;
|
||||||
|
}
|
||||||
|
if (exprStr.trim() == '') {
|
||||||
|
error(ECustom("Expression cannot be empty"), pos, pos);
|
||||||
|
}
|
||||||
|
var prevChar = char;
|
||||||
|
var prevInput = input;
|
||||||
|
var prevReadPos = readPos; // a bit stupid innit???
|
||||||
|
#if hscriptPos
|
||||||
|
var prevOrigin = origin;
|
||||||
|
#end
|
||||||
|
var expr = parseString('($exprStr)' #if hscriptPos, origin #end);
|
||||||
|
readPos = prevReadPos; // rolling back parser state because otherwise we get problems...
|
||||||
|
input = prevInput;
|
||||||
|
char = prevChar;
|
||||||
|
#if hscriptPos
|
||||||
|
origin = prevOrigin;
|
||||||
|
#end
|
||||||
|
exprs.push(expr);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
else if(singleFirst.match(next)) {
|
||||||
|
if (pre != '')
|
||||||
|
exprs.push(mk(EConst(CString(pre))));
|
||||||
|
var ident: String = '';
|
||||||
|
while(singleExpr.match(next)) {
|
||||||
|
ident += next;
|
||||||
|
next = s.charAt(++pos);
|
||||||
|
}
|
||||||
|
exprs.push(mk(EIdent(ident)));
|
||||||
|
}
|
||||||
|
else if (next == '$') {
|
||||||
|
var secondToNext: String = s.charAt(pos);
|
||||||
|
if (secondToNext == "$") { // if its another dollar, skip...
|
||||||
|
s = pre + s.substr(pos, pos + 1); // remove $ ahead of the current one
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
exprs.push(mk(EConst(CString(pre + '$'))));
|
||||||
|
}
|
||||||
|
s = s.substr(pos++);
|
||||||
|
dollarPos = s.indexOf('$');
|
||||||
|
}
|
||||||
|
if (exprs.length == 0) {
|
||||||
|
return mk(EConst(CString(s)));
|
||||||
|
} else {
|
||||||
|
exprs.push(mk(EConst(CString(s))));
|
||||||
|
var expr:Null<Expr> = exprs.shift();
|
||||||
|
while(true) {
|
||||||
|
if(exprs.length == 0) break;
|
||||||
|
expr = mk(EBinop(OpAdd, expr, exprs.shift()));
|
||||||
|
}
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function checkAccess(get:FieldPropertyAccess, set:FieldPropertyAccess, ?expr:Expr, ?type:CType) {
|
function checkAccess(get:FieldPropertyAccess, set:FieldPropertyAccess, ?expr:Expr, ?type:CType) {
|
||||||
#if hscriptPos
|
#if hscriptPos
|
||||||
var p1 = tokenMin;
|
var p1 = tokenMin;
|
||||||
@@ -1853,8 +1978,9 @@ class Parser {
|
|||||||
return StringTools.fastCodeAt(input, readPos++);
|
return StringTools.fastCodeAt(input, readPos++);
|
||||||
}
|
}
|
||||||
|
|
||||||
function readString( until:Int ):String {
|
function readString( until:Int, regex:Bool = false, interpolate:Bool = false ):String {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
|
var prev = 0;
|
||||||
var b = new StringBuf();
|
var b = new StringBuf();
|
||||||
var esc = false;
|
var esc = false;
|
||||||
var old = line;
|
var old = line;
|
||||||
@@ -1901,18 +2027,93 @@ class Parser {
|
|||||||
b.addChar(k);
|
b.addChar(k);
|
||||||
default: invalidChar(c);
|
default: invalidChar(c);
|
||||||
}
|
}
|
||||||
} else if( c == 92 )
|
} else if( c == 92 && !regex)
|
||||||
esc = true;
|
esc = true;
|
||||||
else if( c == until )
|
else if( c == until ) {
|
||||||
|
if(regex && prev == 92) {
|
||||||
|
b.addChar(c);
|
||||||
|
prev = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
else if (c == 36 && interpolate) { // brace for impact !!
|
||||||
|
// From hscript-iris: https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Parser.hx#L1665
|
||||||
|
// by inky03
|
||||||
|
// TODO: optimize this
|
||||||
|
b.addChar(c);
|
||||||
|
var next = readChar();
|
||||||
|
if (next == 123) {
|
||||||
|
b.addChar(next);
|
||||||
|
var depth:Int = 0;
|
||||||
|
while (true) {
|
||||||
|
next = readChar();
|
||||||
|
if (StringTools.isEof(next)) {
|
||||||
|
error(EUnterminatedString, p1, p1);
|
||||||
|
}
|
||||||
|
b.addChar(next);
|
||||||
|
if (next == "'".code) {
|
||||||
|
var nextStr:String = readString("'".code, false, true);
|
||||||
|
for (char in nextStr) {
|
||||||
|
b.addChar(char);
|
||||||
|
}
|
||||||
|
b.addChar("'".code);
|
||||||
|
next = readChar();
|
||||||
|
b.addChar(next);
|
||||||
|
}
|
||||||
|
if (next == 125) {
|
||||||
|
depth--;
|
||||||
|
if (depth < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
readPos--;
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if( c == 10 ) line++;
|
if( c == 10 ) line++;
|
||||||
b.addChar(c);
|
b.addChar(c);
|
||||||
|
if(regex)
|
||||||
|
prev = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readFlags():String {
|
||||||
|
if(!allowRegex) return null;
|
||||||
|
var c = 0;
|
||||||
|
var b = new StringBuf();
|
||||||
|
var old = line;
|
||||||
|
var s = input;
|
||||||
|
#if hscriptPos
|
||||||
|
var p1 = readPos - 1;
|
||||||
|
#end
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
var c = readChar();
|
||||||
|
if( StringTools.isEof(c) ) {
|
||||||
|
line = old;
|
||||||
|
error(EUnterminatedString, p1, p1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// semicolon
|
||||||
|
if(c == 59) {
|
||||||
|
this.char = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var f = String.fromCharCode(c);
|
||||||
|
if(regexFlags.indexOf(f) != -1)
|
||||||
|
b.addChar(c);
|
||||||
|
else
|
||||||
|
invalidChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
function token():Token {
|
function token():Token {
|
||||||
//function token(?infos : Null<haxe.PosInfos>) {
|
//function token(?infos : Null<haxe.PosInfos>) {
|
||||||
//function ttrace(v:Dynamic, ?infos : Null<haxe.PosInfos>) {
|
//function ttrace(v:Dynamic, ?infos : Null<haxe.PosInfos>) {
|
||||||
@@ -1975,7 +2176,9 @@ class Parser {
|
|||||||
switch( char ) {
|
switch( char ) {
|
||||||
case 48,49,50,51,52,53,54,55,56,57:
|
case 48,49,50,51,52,53,54,55,56,57:
|
||||||
n = n * 10 + (char - 48);
|
n = n * 10 + (char - 48);
|
||||||
|
continue;
|
||||||
case '_'.code:
|
case '_'.code:
|
||||||
|
continue;
|
||||||
case "e".code, "E".code:
|
case "e".code, "E".code:
|
||||||
var tk = token();
|
var tk = token();
|
||||||
var pow : Null<Int> = null;
|
var pow : Null<Int> = null;
|
||||||
@@ -2004,46 +2207,48 @@ class Parser {
|
|||||||
invalidChar(char);
|
invalidChar(char);
|
||||||
}
|
}
|
||||||
exp = 1.;
|
exp = 1.;
|
||||||
|
continue;
|
||||||
case "x".code:
|
case "x".code:
|
||||||
if( n > 0 || exp > 0 )
|
if( n > 0 || exp > 0 )
|
||||||
invalidChar(char);
|
invalidChar(char);
|
||||||
// read hexa
|
// read hexa
|
||||||
var n = 0;
|
var hex = 0;
|
||||||
while( true ) {
|
while( true ) {
|
||||||
char = readChar();
|
char = readChar();
|
||||||
switch( char ) {
|
if( char >= 48 && char <= 57 ) {
|
||||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
hex = (hex << 4) + char - 48;
|
||||||
n = (n << 4) + char - 48;
|
continue;
|
||||||
case 65,66,67,68,69,70: // A-F
|
} else if( char >= 65 && char <= 70 ) {
|
||||||
n = (n << 4) + (char - 55);
|
hex = (hex << 4) + char - 55;
|
||||||
case 97,98,99,100,101,102: // a-f
|
continue;
|
||||||
n = (n << 4) + (char - 87);
|
} else if( char >= 97 && char <= 102 ) {
|
||||||
case '_'.code:
|
hex = (hex << 4) + char - 87;
|
||||||
default:
|
continue;
|
||||||
this.char = char;
|
} else if( char == '_'.code ) {
|
||||||
return TConst(CInt(n));
|
continue;
|
||||||
}
|
}
|
||||||
|
this.char = char;
|
||||||
|
return TConst(CInt(hex));
|
||||||
}
|
}
|
||||||
case "b".code: // Custom thing, not supported in haxe
|
case "b".code: // Custom thing, not supported in haxe
|
||||||
if( n > 0 || exp > 0 )
|
if( n > 0 || exp > 0 )
|
||||||
invalidChar(char);
|
invalidChar(char);
|
||||||
// read binary
|
// read binary
|
||||||
var n = 0;
|
var bin = 0;
|
||||||
while( true ) {
|
while( true ) {
|
||||||
char = readChar();
|
char = readChar();
|
||||||
switch( char ) {
|
if( char == 48 || char == 49 ) {
|
||||||
case 48,49: // 0-1
|
bin = (bin << 1) + char - 48;
|
||||||
n = (n << 1) + char - 48;
|
continue;
|
||||||
case '_'.code:
|
} else if( char == '_'.code ) {
|
||||||
default:
|
continue;
|
||||||
this.char = char;
|
|
||||||
return TConst(CInt(n));
|
|
||||||
}
|
}
|
||||||
|
this.char = char;
|
||||||
|
return TConst(CInt(bin));
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
this.char = char;
|
this.char = char;
|
||||||
var i = Std.int(n);
|
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((n % 1 == 0) ? CInt(Std.int(n)) : CFloat(n)) );
|
||||||
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((i == n) ? CInt(i) : CFloat(n)) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ";".code: return TSemicolon;
|
case ";".code: return TSemicolon;
|
||||||
@@ -2080,7 +2285,10 @@ class Parser {
|
|||||||
case "}".code: return TBrClose;
|
case "}".code: return TBrClose;
|
||||||
case "[".code: return TBkOpen;
|
case "[".code: return TBkOpen;
|
||||||
case "]".code: return TBkClose;
|
case "]".code: return TBkClose;
|
||||||
case "'".code, '"'.code: return TConst( CString(readString(char)) );
|
case "'".code:
|
||||||
|
return TConst( CString(readString(char, false, true), true) );
|
||||||
|
case '"'.code:
|
||||||
|
return TConst( CString(readString(char), false) );
|
||||||
case "?".code:
|
case "?".code:
|
||||||
char = readChar();
|
char = readChar();
|
||||||
switch (char) {
|
switch (char) {
|
||||||
@@ -2136,16 +2344,23 @@ class Parser {
|
|||||||
invalidChar(char);
|
invalidChar(char);
|
||||||
default:
|
default:
|
||||||
if( ops[char] ) {
|
if( ops[char] ) {
|
||||||
var op = String.fromCharCode(char);
|
var buf = new StringBuf();
|
||||||
|
buf.addChar(char);
|
||||||
while( true ) {
|
while( true ) {
|
||||||
char = readChar();
|
char = readChar();
|
||||||
if( StringTools.isEof(char) ) char = 0;
|
if( StringTools.isEof(char) ) char = 0;
|
||||||
if( !ops[char] ) {
|
if( !ops[char] ) {
|
||||||
this.char = char;
|
this.char = char;
|
||||||
return TOp(op);
|
return TOp(buf.toString());
|
||||||
|
}
|
||||||
|
var pop = buf.toString();
|
||||||
|
buf.addChar(char);
|
||||||
|
var op = buf.toString();
|
||||||
|
if( allowRegex && op == "~/" ) {
|
||||||
|
var e = readString(char, true);
|
||||||
|
var f = readFlags();
|
||||||
|
return TRegex(e, f);
|
||||||
}
|
}
|
||||||
var pop = op;
|
|
||||||
op += String.fromCharCode(char);
|
|
||||||
if( !opPriority.exists(op) && opPriority.exists(pop) ) {
|
if( !opPriority.exists(op) && opPriority.exists(pop) ) {
|
||||||
if( op == "//" || op == "/*" )
|
if( op == "//" || op == "/*" )
|
||||||
return tokenComment(op,char);
|
return tokenComment(op,char);
|
||||||
@@ -2155,16 +2370,17 @@ class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( idents[char] ) {
|
if( idents[char] ) {
|
||||||
var id = String.fromCharCode(char);
|
var buf = new StringBuf();
|
||||||
|
buf.addChar(char);
|
||||||
while( true ) {
|
while( true ) {
|
||||||
char = readChar();
|
char = readChar();
|
||||||
if( StringTools.isEof(char) ) char = 0;
|
if( StringTools.isEof(char) ) char = 0;
|
||||||
if( !idents[char] ) {
|
if( !idents[char] ) {
|
||||||
this.char = char;
|
this.char = char;
|
||||||
//if(id == "is") return TOp("is");
|
//if(id == "is") return TOp("is");
|
||||||
return TId(id);
|
return TId(buf.toString());
|
||||||
}
|
}
|
||||||
id += String.fromCharCode(char);
|
buf.addChar(char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidChar(char);
|
invalidChar(char);
|
||||||
@@ -2187,14 +2403,16 @@ class Parser {
|
|||||||
push(TPOpen);
|
push(TPOpen);
|
||||||
parseExpr();
|
parseExpr();
|
||||||
case TId(id):
|
case TId(id):
|
||||||
|
var buf = new StringBuf();
|
||||||
|
buf.add(id);
|
||||||
while(true) {
|
while(true) {
|
||||||
var tk = token();
|
var tk = token();
|
||||||
if(tk == TDot) {
|
if(tk == TDot) {
|
||||||
id += ".";
|
buf.add(".");
|
||||||
tk = token();
|
tk = token();
|
||||||
switch(tk) {
|
switch(tk) {
|
||||||
case TId(id2):
|
case TId(id2):
|
||||||
id += id2;
|
buf.add(id2);
|
||||||
default: unexpected(tk);
|
default: unexpected(tk);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2202,9 +2420,9 @@ class Parser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mk(EIdent(id), tokenMin, tokenMax);
|
mk(EIdent(buf.toString()), tokenMin, tokenMax);
|
||||||
case TOp("!"):
|
case TOp("!"):
|
||||||
mk(EUnop("!", true, parsePreproCond()), tokenMin, tokenMax);
|
mk(EUnop(OpNot, true, parsePreproCond()), tokenMin, tokenMax);
|
||||||
default:
|
default:
|
||||||
unexpected(tk);
|
unexpected(tk);
|
||||||
}
|
}
|
||||||
@@ -2222,13 +2440,13 @@ class Parser {
|
|||||||
error(EInvalidPreprocessor("Can't eval " + expr(e).getName() + " with " + expr(e2).getName()), readPos, readPos);
|
error(EInvalidPreprocessor("Can't eval " + expr(e).getName() + " with " + expr(e2).getName()), readPos, readPos);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case EUnop("!", _, e):
|
case EUnop(OpNot, _, e):
|
||||||
return !evalPreproCond(e);
|
return !evalPreproCond(e);
|
||||||
case EParent(e):
|
case EParent(e):
|
||||||
return evalPreproCond(e);
|
return evalPreproCond(e);
|
||||||
case EBinop("&&", e1, e2):
|
case EBinop(OpBoolAnd, e1, e2):
|
||||||
return evalPreproCond(e1) && evalPreproCond(e2);
|
return evalPreproCond(e1) && evalPreproCond(e2);
|
||||||
case EBinop("||", e1, e2):
|
case EBinop(OpBoolOr, e1, e2):
|
||||||
return evalPreproCond(e1) || evalPreproCond(e2);
|
return evalPreproCond(e1) || evalPreproCond(e2);
|
||||||
default:
|
default:
|
||||||
error(EInvalidPreprocessor("Can't eval " + expr(e).getName()), readPos, readPos);
|
error(EInvalidPreprocessor("Can't eval " + expr(e).getName()), readPos, readPos);
|
||||||
@@ -2336,7 +2554,7 @@ class Parser {
|
|||||||
return switch(c) {
|
return switch(c) {
|
||||||
case CInt(v): Std.string(v);
|
case CInt(v): Std.string(v);
|
||||||
case CFloat(f): Std.string(f);
|
case CFloat(f): Std.string(f);
|
||||||
case CString(s): s; // TODO : escape + quote
|
case CString(s, _): s; // TODO : escape + quote
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2360,6 +2578,7 @@ class Parser {
|
|||||||
case TDoubleDot: ":";
|
case TDoubleDot: ":";
|
||||||
case TMeta(id): "@" + id;
|
case TMeta(id): "@" + id;
|
||||||
case TPrepro(id): "#" + id;
|
case TPrepro(id): "#" + id;
|
||||||
|
case TRegex(e, f): '~/$e/$f';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+36
-4
@@ -116,6 +116,11 @@ class Printer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch(Tools.expr(e)) {
|
switch(Tools.expr(e)) {
|
||||||
|
case EPackage(n):
|
||||||
|
add('package');
|
||||||
|
if(n != null)
|
||||||
|
add(' $n');
|
||||||
|
add(';\n');
|
||||||
case EImport(c, n, u):
|
case EImport(c, n, u):
|
||||||
add('${u ? 'using' : 'import'} $c');
|
add('${u ? 'using' : 'import'} $c');
|
||||||
if(n != null)
|
if(n != null)
|
||||||
@@ -143,7 +148,32 @@ class Printer {
|
|||||||
|
|
||||||
tabs = tabs.substr(1);
|
tabs = tabs.substr(1);
|
||||||
add("}");
|
add("}");
|
||||||
case EEnum(en, _): // TODO: enum abstracts
|
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}');
|
add('enum ${en.name}');
|
||||||
if(en.fields.length == 0) {
|
if(en.fields.length == 0) {
|
||||||
add(' {}');
|
add(' {}');
|
||||||
@@ -151,7 +181,6 @@ class Printer {
|
|||||||
}
|
}
|
||||||
tabs += "\t";
|
tabs += "\t";
|
||||||
add(" {\n");
|
add(" {\n");
|
||||||
|
|
||||||
for(e in en.fields) {
|
for(e in en.fields) {
|
||||||
add(tabs);
|
add(tabs);
|
||||||
add(e.name);
|
add(e.name);
|
||||||
@@ -168,9 +197,9 @@ class Printer {
|
|||||||
}
|
}
|
||||||
add(";\n");
|
add(";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
tabs = tabs.substr(1);
|
tabs = tabs.substr(1);
|
||||||
add("}");
|
add("}");
|
||||||
|
}
|
||||||
case ECast(e, t):
|
case ECast(e, t):
|
||||||
var safe = t != null;
|
var safe = t != null;
|
||||||
add("cast ");
|
add("cast ");
|
||||||
@@ -181,6 +210,9 @@ class Printer {
|
|||||||
addType(t);
|
addType(t);
|
||||||
add(")");
|
add(")");
|
||||||
}
|
}
|
||||||
|
case ERegex(e, f):
|
||||||
|
add('~/$e/$f');
|
||||||
|
add(';\n');
|
||||||
case EConst(c):
|
case EConst(c):
|
||||||
switch( c ) {
|
switch( c ) {
|
||||||
case CInt(i): add(i);
|
case CInt(i): add(i);
|
||||||
@@ -244,7 +276,7 @@ class Printer {
|
|||||||
add((s == true ? "?." : ".") + f);
|
add((s == true ? "?." : ".") + f);
|
||||||
case EBinop(op, e1, e2):
|
case EBinop(op, e1, e2):
|
||||||
expr(e1);
|
expr(e1);
|
||||||
add(" " + op + " ");
|
add(" " + op.toString() + " ");
|
||||||
expr(e2);
|
expr(e2);
|
||||||
case EUnop(op, pre, e):
|
case EUnop(op, pre, e):
|
||||||
if( pre ) {
|
if( pre ) {
|
||||||
|
|||||||
+83
-19
@@ -26,39 +26,98 @@ import hscript.Expr.FieldPropertyAccess;
|
|||||||
* @see https://haxe.org/manual/class-field-property.html
|
* @see https://haxe.org/manual/class-field-property.html
|
||||||
*/
|
*/
|
||||||
@:access(hscript.Interp)
|
@:access(hscript.Interp)
|
||||||
@:structInit
|
|
||||||
class Property {
|
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;
|
public var r:Dynamic;
|
||||||
public var getter:FieldPropertyAccess;
|
|
||||||
public var setter:FieldPropertyAccess;
|
/**
|
||||||
|
* 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 isVar:Bool;
|
||||||
var interp:Interp;
|
var interp:Interp;
|
||||||
|
|
||||||
public function new(r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, 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.r = r;
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
this.setter = setter;
|
this.setter = setter;
|
||||||
this.isVar = isVar;
|
this.isVar = isVar;
|
||||||
|
this.__isStatic = isStatic;
|
||||||
this.interp = interp;
|
this.interp = interp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal flags to gain access to the current field value (if isn't a property field)
|
||||||
var __allowReadAccess:Bool = false;
|
var __allowReadAccess:Bool = false;
|
||||||
var __allowWriteAccess:Bool = false;
|
var __allowWriteAccess:Bool = false;
|
||||||
var __allowSetGet:Null<Bool> = null;
|
// Internal flag to gain access if the field is accessed with @:bypassAccessor
|
||||||
|
var __allowSetGet:Bool = true;
|
||||||
|
|
||||||
public function callGetter(name:String) {
|
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) {
|
switch (getter) {
|
||||||
case AGet | ADynamic:
|
case AGet | ADynamic:
|
||||||
var fName:String = 'get_$name';
|
var fName:String = getterFunc;
|
||||||
if (!__allowReadAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) {
|
if (!__allowReadAccess && __allowSetGet) {
|
||||||
if (interp.varExists(fName)) {
|
if (varExists(fName)) {
|
||||||
return callAccessor(fName);
|
return callAccessor(fName);
|
||||||
} else
|
} else
|
||||||
interp.error(ECustom('Method $fName required by property $name is missing'));
|
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||||
} else {
|
} else {
|
||||||
if ((setter == ADefault || setter == ANull) || isVar)
|
if ((setter == ADefault || setter == ANull) || isVar) {
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||||
}
|
}
|
||||||
@@ -70,18 +129,19 @@ class Property {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function callSetter(name:String, val:Dynamic) {
|
private function callSetter(val:Dynamic):Dynamic {
|
||||||
switch (setter) {
|
switch (setter) {
|
||||||
case ASet | ADynamic:
|
case ASet | ADynamic:
|
||||||
var fName:String = 'set_$name';
|
var fName:String = setterFunc;
|
||||||
if (!__allowWriteAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) {
|
if (!__allowWriteAccess && __allowSetGet) {
|
||||||
if (interp.varExists(fName))
|
if (varExists(fName))
|
||||||
return callAccessor(fName, [val], true);
|
return callAccessor(fName, true, val);
|
||||||
else
|
else
|
||||||
interp.error(ECustom('Method $fName required by property $name is missing'));
|
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||||
} else {
|
} else {
|
||||||
if ((getter == ADefault || getter == ANull) || isVar)
|
if ((getter == ADefault || getter == ANull) || isVar) {
|
||||||
return r = val;
|
return r = val;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||||
}
|
}
|
||||||
@@ -93,14 +153,14 @@ class Property {
|
|||||||
return r = val;
|
return r = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function callAccessor(f:String, ?args:Array<Dynamic>, isWrite:Bool = false):Dynamic {
|
private function callAccessor(f:String, isWrite:Bool = false, ?value:Dynamic):Dynamic {
|
||||||
var fn = interp.variables.get(f);
|
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
|
||||||
var rt:Dynamic = null;
|
var rt:Dynamic = null;
|
||||||
if (fn != null && Reflect.isFunction(fn)) {
|
if (fn != null && Reflect.isFunction(fn)) {
|
||||||
if (isWrite) __allowWriteAccess = true;
|
if (isWrite) __allowWriteAccess = true;
|
||||||
else __allowReadAccess = true;
|
else __allowReadAccess = true;
|
||||||
|
|
||||||
rt = UnsafeReflect.callMethodUnsafe(null, fn, args == null ? [] : args);
|
rt = UnsafeReflect.callMethodUnsafe(null, fn, isWrite ? [value] : []);
|
||||||
|
|
||||||
if (isWrite) __allowWriteAccess = false;
|
if (isWrite) __allowWriteAccess = false;
|
||||||
else __allowReadAccess = false;
|
else __allowReadAccess = false;
|
||||||
@@ -111,4 +171,8 @@ class Property {
|
|||||||
|
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline function varExists(n:String) {
|
||||||
|
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,13 @@ class Tools {
|
|||||||
#end
|
#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
|
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
||||||
return obj != null && obj is IHScriptAbstractBehaviour;
|
return obj != null && obj is IHScriptAbstractBehaviour;
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,14 @@ using StringTools;
|
|||||||
|
|
||||||
class AbstractHandler {
|
class AbstractHandler {
|
||||||
public static function init() {
|
public static function init() {
|
||||||
|
#if HSCRIPT_ABSTRACT_SUPPORT
|
||||||
#if !display
|
#if !display
|
||||||
if(Context.defined("display")) return;
|
if(Context.defined("display")) return;
|
||||||
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
|
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function build():Array<Field> {
|
public static function build():Array<Field> {
|
||||||
|
|||||||
@@ -483,8 +483,9 @@ class ClassExtendMacro {
|
|||||||
if (__interp != null) {
|
if (__interp != null) {
|
||||||
if(__class__fields.contains(name)) {
|
if(__class__fields.contains(name)) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
if(v != null && v is hscript.Property)
|
if(v != null && v is hscript.Property)
|
||||||
return cast(v, hscript.Property).callGetter(name);
|
return cast(v, hscript.Property).get(ba);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
else @:privateAccess {
|
else @:privateAccess {
|
||||||
@@ -508,8 +509,9 @@ class ClassExtendMacro {
|
|||||||
if (__interp != null) {
|
if (__interp != null) {
|
||||||
if(__class__fields.contains(name)) {
|
if(__class__fields.contains(name)) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
if(v != null && v is hscript.Property)
|
if(v != null && v is hscript.Property)
|
||||||
return cast(v, hscript.Property).callGetter(name);
|
return cast(v, hscript.Property).get(ba);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
else @:privateAccess {
|
else @:privateAccess {
|
||||||
@@ -535,8 +537,9 @@ class ClassExtendMacro {
|
|||||||
if (__interp != null) {
|
if (__interp != null) {
|
||||||
if(__class__fields.contains(name)) {
|
if(__class__fields.contains(name)) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
if(v != null && v is hscript.Property)
|
if(v != null && v is hscript.Property)
|
||||||
return cast(v, hscript.Property).callSetter(name, val);
|
return cast(v, hscript.Property).set(val, ba);
|
||||||
__interp.variables.set(name, val);
|
__interp.variables.set(name, val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -565,8 +568,9 @@ class ClassExtendMacro {
|
|||||||
if (__interp != null) {
|
if (__interp != null) {
|
||||||
if(__class__fields.contains(name)) {
|
if(__class__fields.contains(name)) {
|
||||||
var v:Dynamic = __interp.variables.get(name);
|
var v:Dynamic = __interp.variables.get(name);
|
||||||
|
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||||
if(v != null && v is hscript.Property)
|
if(v != null && v is hscript.Property)
|
||||||
return cast(v, hscript.Property).callSetter(name, val);
|
return cast(v, hscript.Property).set(val, ba);
|
||||||
__interp.variables.set(name, val);
|
__interp.variables.set(name, val);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class UsingHandler {
|
|||||||
usingEntries.set(name, {call: entry, fields: fields});
|
usingEntries.set(name, {call: entry, fields: fields});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function entryExists(name:String):Bool {
|
public inline function entryExists(name:String):Bool {
|
||||||
return usingEntries.exists(name);
|
return usingEntries.exists(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user