Compare commits

..
Author SHA1 Message Date
gabry 75a21abecd revert accidental deletion of blocklist 2026-07-20 19:49:11 +02:00
gabry 763999c376 fix this binding loss on js 2026-07-20 19:10:23 +02:00
Jaime Humberto Macias Bustamante c1b23320c3 fixed set call with nullable values 2026-07-18 21:48:23 -07:00
Jaime Humberto Macias Bustamante 266bb67c93 moved import blacklist to Config.hx 2026-07-08 22:11:51 -07:00
Jaime Humberto Macias Bustamante 6276ddfc2c Update ClassExtendMacro.hx
i need a break...
2026-06-22 21:17:50 -07:00
Jaime Humberto Macias Bustamante b8ead38556 Squashed commit of the following:
commit 24abfa436e
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Sat Jun 20 23:29:32 2026 -0700

    Update CustomClassHandler.hx

    forgot to change this too...

commit 92e458876e
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Sat Jun 20 23:23:10 2026 -0700

    remove direct function call handling

    after testing, it turns out that trying to handle the direct getter/setter function will be so complex than I thought.

commit 44d8b1e0e1
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Sat Jun 20 19:39:17 2026 -0700

    better static field filtering

commit ff649efadf
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Sat Jun 20 18:50:03 2026 -0700

    better accessor bypass handling

commit 4625529be7
Author: Crimson-is-stupid <89041944+Crimson-is-stupid@users.noreply.github.com>
Date:   Thu Jun 4 09:32:25 2026 +0300

    Reimplement Trigraph Fix (#18)

    * replace all "??=" with "??" + "="

    * Update Expr.hx

commit b9da833bb5
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Wed Jun 3 17:14:08 2026 -0700

    better callAccessor + optimize "__allowGetSet"

commit 0c08f64274
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Wed Jun 3 16:57:58 2026 -0700

    Update Property.hx

commit 3add08e0ee
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Fri May 29 10:23:56 2026 -0700

    some docs + small optimizations

commit 77fae88890
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Thu Apr 30 11:32:13 2026 -0700

    oversight again...

commit 2a301ea591
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Thu Apr 30 11:27:07 2026 -0700

    fixed small oversight

commit 634d819cc2
Author: Jaime Humberto Macias Bustamante <jamextreme140@outlook.com>
Date:   Thu Apr 30 11:02:47 2026 -0700

    Refactor property fields

    Now you can call directly the getter/setter functions without triggering them again.
2026-06-20 23:46:55 -07:00
Crimson-is-stupidandGitHub 1972ae6a82 Reimplement Trigraph Fix (#18)
* replace all "??=" with "??" + "="

* Update Expr.hx
2026-06-03 23:32:25 -07:00
Jaime Humberto Macias Bustamante 7f3de28e02 Update Interp.hx 2026-04-30 09:30:10 -07:00
Jaime Humberto Macias Bustamante 0322624729 New Ops fixes 2026-04-21 11:01:22 -07:00
HEIHUAaandGitHub 68358bb084 cache+optimize+fix (#17)
* 更新 Interp.hx

* exprReturn

* Binop

* exprReturn repair

* exprReturn repair

* Revert "Merge branch 'cache' of https://github.com/HEIHUAa/hscript-improved into cache"

This reverts commit 2bc31b672c, reversing
changes made to 188031c416.

* Unop

* Fix override not applying across multiple inheritance levels.

* 更新 Interp.hx

* 更新 README.md

* ++
2026-04-21 10:48:42 -07:00
Jaime Humberto Macias Bustamante 65ab73d93f fix enum abstract field declaration + implicit string
now enum abstract are parsed correctly.
2026-03-18 01:05:20 -07:00
Jaime Humberto Macias Bustamante fff4f68d66 small optimization + docs check 2026-03-16 21:41:56 -07:00
HEIHUAaandGitHub 65fe06feba Implement enum abstract + fully qualified path functionality. (#15)
* enum

* path functionality

* allowTypes
2026-03-16 21:05:53 -07:00
Jaime Humberto Macias Bustamante b980b73f9e small optimizations 2026-03-08 21:07:41 -07:00
Yoshman29 5d2ab05fc9 (IMPORTANT) added new define for abstracthandler 2026-01-29 20:46:54 +01:00
Jaime Humberto Macias Bustamante b82aad097a Property resolve optimization 2026-01-10 20:35:20 -07:00
Jaime Humberto Macias Bustamante df1bc5c68b Multiple implements support 2026-01-08 15:13:59 -07:00
HEIHUAaandGitHub 1033e2fd10 Parser optimization (#12) 2026-01-08 14:08:37 -07:00
Jaime Humberto Macias Bustamante f9b5ce71b4 Class Path fix + more optimizations 2025-12-27 13:34:56 -07:00
Jaime Humberto Macias Bustamante 951a0898ce more optimizations
- some functions are inlined now to improve performance.
- "hasScriptObject" and "inCustomClass" has been turned to a real variable to reduce the amount of null checks.
- some condition has been reordered to improve performance.
2025-12-15 15:54:28 -07:00
Jaime Humberto Macias Bustamante 22b4b25f5a small static extension fix + small optimization 2025-12-07 14:29:50 -07:00
Jaime Humberto Macias Bustamante a69d51f474 Update Interp.hx 2025-09-21 12:14:32 -07:00
Jaime Humberto Macias Bustamante 9c3069d62e forgot this 2025-09-19 16:53:03 -07:00
Jaime Humberto Macias Bustamante c91ca46eb4 Warning message handling + optimization
Now Duplicated Custom Class declaration will be ignored and prints a warning message.
2025-09-19 16:37:11 -07:00
TBar09andGitHub 115bd453b9 Added static imports (#10)
* Added static imports

* Update Interp.hx
2025-09-08 08:53:37 -07:00
Jaime Humberto Macias Bustamante 826282aa72 Merge branch 'feature/string-interpolation' into codename-dev 2025-09-06 19:42:39 -07:00
Jaime Humberto Macias Bustamante 9fa4a548e5 String Interpolation Support
implementation from hscript-iris (by inky03)

Note: it needs optimization
2025-09-06 19:39:57 -07:00
Jaime Humberto Macias Bustamante 18f4ebccd9 Fix small bug with slash literal ("\/") 2025-09-06 19:31:48 -07:00
Jaime Humberto Macias Bustamante 8dcebe3930 Regular Expression support (regex) 2025-09-06 19:31:48 -07:00
Jaime Humberto Macias Bustamante 3b8b017d4d Fix small bug with slash literal ("\/") 2025-09-03 22:00:32 -07:00
Jaime Humberto Macias Bustamante d344ede669 Regular Expression support (regex) 2025-09-03 20:13:39 -07:00
Jaime Humberto Macias Bustamante 85f51df7eb fixed accessing class fields from objects
this shouldn't happen, unless "useRedirects" is on.
2025-08-19 19:24:00 -07:00
FrakitsandGitHub 5dce82eaf6 Update haxelib.json 2025-08-15 15:07:28 +03:00
Jaime Humberto Macias Bustamante 0b4675b4ad static property accessor call 2025-08-14 03:07:44 -07:00
Jaime Humberto Macias Bustamante e4861a606a Features Documentation 2025-08-04 13:40:48 -07:00
Jaime Humberto Macias Bustamante bbe9fd255d fixed package parsing issue 2025-08-03 21:46:04 -07:00
Jaime Humberto Macias Bustamante 6bd3f26746 package syntax support
For now it's just sugar syntax.
2025-08-03 21:28:59 -07:00
Jaime Humberto Macias Bustamante 83aa0f3856 fixed variable set bug 2025-08-03 01:08:06 -07:00
Jaime Humberto Macias Bustamante f97a7b8a55 Merge branch 'codename-dev' of github.com:CodenameCrew/hscript-improved into codename-dev 2025-08-03 00:08:46 -07:00
Jaime Humberto Macias Bustamante f936877339 MyCustomClass.new + Optimization
You can now pass the custom class constructor as a field.
2025-08-03 00:08:43 -07:00
Jamextreme140andGitHub 9fbe8a6316 Update README.md 2025-08-02 02:45:30 -07:00
Jaime Humberto Macias Bustamante 7f087eab03 fixed getting property fields on superclass
Basically "Type.getInstanceFields" doesn't take into account property fields, so it uses "Reflect.fields" to fetch the rest of fields.
2025-08-01 16:55:13 -07:00
Jaime Humberto Macias Bustamante 056a2bd791 fixed calling superclass functions 2025-07-29 13:23:13 -07:00
20 changed files with 2906 additions and 1954 deletions
+5 -1
View File
@@ -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.
----------- -----------
+83
View File
@@ -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
View File
@@ -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",
+536 -536
View File
File diff suppressed because it is too large Load Diff
+8 -4
View File
@@ -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
View File
@@ -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);
+5
View File
@@ -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"
];
} }
+37 -21
View File
@@ -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,25 +124,40 @@ 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
__interp.error(ECustom('$name doesn\'t exists or is not a function')); // If not found in current class, try parent class recursively
if (__superClass != null && __superClass is CustomClass)
return cast(__superClass, CustomClass).call(name, args, toSuper);
__interp.error(ECustom('$name doesn\'t exists or is not a function'));
return null; 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;
} }
+23 -21
View File
@@ -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);
} }
+403 -242
View File
@@ -1,242 +1,403 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * Copyright (C)2008-2017 Haxe Foundation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the * and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions: * Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
package hscript; package hscript;
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end; typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end; typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
typedef Int32 = #if cpp cpp.Int32 #else Int #end; typedef Int32 = #if cpp cpp.Int32 #else Int #end;
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end; typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end; typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end; typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end; enum abstract Binop(Int) from Int to Int {
var OpAdd = 0;
enum Const { var OpSub = 1;
CInt( v : Int ); var OpMult = 2;
CFloat( f : Float ); var OpDiv = 3;
CString( s : String ); var OpMod = 4;
} var OpAnd = 5;
var OpOr = 6;
#if hscriptPos var OpXor = 7;
@:structInit var OpShl = 8;
final class Expr { var OpShr = 9;
public var e : ExprDef; var OpUshr = 10;
public var pmin : Int; var OpEq = 11;
public var pmax : Int; var OpNeq = 12;
public var origin : String; var OpGte = 13;
public var line : Int; var OpLte = 14;
} var OpGt = 15;
enum ExprDef { var OpLt = 16;
#else var OpBoolOr = 17;
typedef ExprDef = Expr; var OpBoolAnd = 18;
enum Expr { var OpIs = 19;
#end var OpAssign = 20;
EConst( c : Const ); var OpNcoal = 21;
EIdent( v : String ); var OpInterval = 22;
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool ); var OpArrow = 23;
EParent( e : Expr ); var OpAddAssign = 24;
EBlock( e : Array<Expr> ); var OpSubAssign = 25;
EField( e : Expr, f : String , ?safe : Bool ); var OpMultAssign = 26;
EBinop( op : String, e1 : Expr, e2 : Expr ); var OpDivAssign = 27;
EUnop( op : String, prefix : Bool, e : Expr ); var OpModAssign = 28;
ECall( e : Expr, params : Array<Expr> ); var OpAndAssign = 29;
EIf( cond : Expr, e1 : Expr, ?e2 : Expr ); var OpOrAssign = 30;
EWhile( cond : Expr, e : Expr ); var OpXorAssign = 31;
EFor( v : String, it : Expr, e : Expr, ?ithv: String); var OpShlAssign = 32;
EBreak; var OpShrAssign = 33;
EContinue; var OpUshrAssign = 34;
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool ); var OpNcoalAssign = 35;
EReturn( ?e : Expr ); var OpArrowFn = 36;
EArray( e : Expr, index : Expr );
EArrayDecl( e : Array<Expr>, ?wantedType: CType ); public static inline function fromString(s:String):Binop {
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> ); return switch(s) {
EThrow( e : Expr ); case "+": OpAdd;
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr ); case "-": OpSub;
EObject( fl : Array<ObjectField> ); case "*": OpMult;
ETernary( cond : Expr, e1 : Expr, e2 : Expr ); case "/": OpDiv;
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr ); case "%": OpMod;
EDoWhile( cond : Expr, e : Expr); case "&": OpAnd;
EMeta( name : String, args : Array<Expr>, e : Expr ); case "|": OpOr;
ECheckType( e : Expr, t : CType ); case "^": OpXor;
case "<<": OpShl;
EImport( c : String, ?asname:String, ?isUsing:Bool ); case ">>": OpShr;
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool ); case ">>>": OpUshr;
EEnum( en:EnumDecl, ?isAbstract:Bool ); case "==": OpEq;
ECast(e:Expr, ?t:CType); case "!=": OpNeq;
} case ">=": OpGte;
case "<=": OpLte;
@:structInit case ">": OpGt;
final class ObjectField { case "<": OpLt;
public var name : String; case "||": OpBoolOr;
public var e : Expr; case "&&": OpBoolAnd;
} case "is": OpIs;
case "=": OpAssign;
@:structInit case "??": OpNcoal;
final class SwitchCase { case "...": OpInterval;
public var values : Array<Expr>; case "->": OpArrow;
public var expr : Expr; case "=>": OpArrowFn;
} case "+=": OpAddAssign;
case "-=": OpSubAssign;
@:structInit case "*=": OpMultAssign;
final class Argument { case "/=": OpDivAssign;
public var name : String; case "%=": OpModAssign;
public var t : CType; case "&=": OpAndAssign;
public var opt : Bool; case "|=": OpOrAssign;
public var value : Expr; case "^=": OpXorAssign;
} case "<<=": OpShlAssign;
case ">>=": OpShrAssign;
@:structInit case ">>>=": OpUshrAssign;
final class MetadataEntry { case _ if (s == "??" + "="): OpNcoalAssign;
public var name : String; default: -1;
public var params : Array<Expr>; }
} }
typedef Metadata = Array<MetadataEntry>; public inline function toString():String {
return switch(this) {
@:structInit case OpAdd: "+";
final class EnumDecl { case OpSub: "-";
public var name : String; case OpMult: "*";
public var fields : Array<EnumField>; case OpDiv: "/";
} case OpMod: "%";
case OpAnd: "&";
@:structInit case OpOr: "|";
final class EnumField { case OpXor: "^";
public var name : String; case OpShl: "<<";
public var args : Array<Argument>; case OpShr: ">>";
} case OpUshr: ">>>";
case OpEq: "==";
enum CType { case OpNeq: "!=";
CTPath( path : Array<String>, ?params : Array<CType> ); case OpGte: ">=";
CTFun( args : Array<CType>, ret : CType ); case OpLte: "<=";
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> ); case OpGt: ">";
CTParent( t : CType ); case OpLt: "<";
CTOpt( t : CType ); case OpBoolOr: "||";
CTNamed( n : String, t : CType ); case OpBoolAnd: "&&";
CTExpr( e : Expr ); // for type parameters only case OpIs: "is";
} case OpAssign: "=";
case OpNcoal: "??";
#if hscriptPos case OpInterval: "...";
class Error { case OpArrow: "->";
public var e : ErrorDef; case OpArrowFn: "=>";
public var pmin : Int; case OpAddAssign: "+=";
public var pmax : Int; case OpSubAssign: "-=";
public var origin : String; case OpMultAssign: "*=";
public var line : Int; case OpDivAssign: "/=";
public function new(e, pmin, pmax, origin, line) { case OpModAssign: "%=";
this.e = e; case OpAndAssign: "&=";
this.pmin = pmin; case OpOrAssign: "|=";
this.pmax = pmax; case OpXorAssign: "^=";
this.origin = origin; case OpShlAssign: "<<=";
this.line = line; case OpShrAssign: ">>=";
} case OpUshrAssign: ">>>=";
public function toString(): String { case OpNcoalAssign: "??" + "=";
return Printer.errorToString(this); default: "?";
} }
} }
enum ErrorDef { }
#else
enum Error { enum abstract Unop(Int) from Int to Int {
#end var OpNot = 0;
EInvalidChar( c : Int ); var OpNeg = 1;
EUnexpected( s : String ); var OpIncrement = 2;
EUnterminatedString; var OpDecrement = 3;
EUnterminatedComment; var OpNegBits = 4;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String ); public static inline function fromString(s:String):Unop {
EInvalidIterator( v : String ); return switch(s) {
EInvalidOp( op : String ); case "!": OpNot;
EInvalidAccess( f : String ); case "-": OpNeg;
ECustom( msg : String ); case "++": OpIncrement;
EInvalidClass( className : String); case "--": OpDecrement;
EAlreadyExistingClass( className : String); case "~": OpNegBits;
} default: -1;
}
}
enum ModuleDecl {
DPackage( path : Array<String> ); public inline function toString():String {
DImport( path : Array<String>, ?everything : Bool ); return switch(this) {
DClass( c : ClassDecl ); case OpNot: "!";
DTypedef( c : TypeDecl ); case OpNeg: "-";
} case OpIncrement: "++";
case OpDecrement: "--";
typedef ModuleType = { case OpNegBits: "~";
var name : String; default: "?";
var params : {}; // TODO : not yet parsed }
var meta : Metadata; }
var isPrivate : Bool; }
}
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
typedef ClassDecl = {> ModuleType, typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
var extend : Null<CType>;
var implement : Array<CType>; enum Const {
var fields : Array<FieldDecl>; CInt( v : Int );
var isExtern : Bool; CFloat( f : Float );
} CString( s : String, ?i : Bool );
}
typedef TypeDecl = {> ModuleType,
var t : CType; #if hscriptPos
} @:structInit
final class Expr {
typedef FieldDecl = { public var e : ExprDef;
var name : String; public var pmin : Int;
var meta : Metadata; public var pmax : Int;
var kind : FieldKind; public var origin : String;
var access : Array<FieldAccess>; public var line : Int;
} }
enum ExprDef {
enum abstract FieldAccess(UInt8) { #else
var APublic; typedef ExprDef = Expr;
var APrivate; enum Expr {
var AInline; #end
var AOverride; EConst( c : Const );
var AStatic; EIdent( v : String );
var AMacro; EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
} EParent( e : Expr );
EBlock( e : Array<Expr> );
enum abstract FieldPropertyAccess(UInt8) { EField( e : Expr, f : String , ?safe : Bool );
var ADefault; EBinop( op : Binop, e1 : Expr, e2 : Expr );
var ANull; EUnop( op : Unop, prefix : Bool, e : Expr );
var AGet; ECall( e : Expr, params : Array<Expr> );
var ASet; EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
var ADynamic; EWhile( cond : Expr, e : Expr );
var ANever; EFor( v : String, it : Expr, e : Expr, ?ithv: String);
} EBreak;
EContinue;
enum FieldKind { EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
KFunction( f : FunctionDecl ); EReturn( ?e : Expr );
KVar( v : VarDecl ); EArray( e : Expr, index : Expr );
} EArrayDecl( e : Array<Expr>, ?wantedType: CType );
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
@:structInit EThrow( e : Expr );
final class FunctionDecl { ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
public var args : Array<Argument>; EObject( fl : Array<ObjectField> );
public var body : Expr; ETernary( cond : Expr, e1 : Expr, e2 : Expr );
public var ret : Null<CType>; ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
} EDoWhile( cond : Expr, e : Expr);
EMeta( name : String, args : Array<Expr>, e : Expr );
typedef VarDecl = { ECheckType( e : Expr, t : CType );
var get : Null<String>;
var set : Null<String>; EPackage( ?n:String );
var expr : Null<Expr>; EImport( c : String, ?asname:String, ?isUsing:Bool );
var type : Null<CType>; EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
} EEnum( en:EnumDecl, ?isAbstract:Bool );
ECast(e:Expr, ?t:CType);
ERegex(e:String, flags:String);
}
@:structInit
final class ObjectField {
public var name : String;
public var e : Expr;
}
@:structInit
final class SwitchCase {
public var values : Array<Expr>;
public var expr : Expr;
}
@:structInit
final class Argument {
public var name : String;
public var t : CType;
public var opt : Bool;
public var value : Expr;
}
@:structInit
final class MetadataEntry {
public var name : String;
public var params : Array<Expr>;
}
typedef Metadata = Array<MetadataEntry>;
@:structInit
final class EnumDecl {
public var name : String;
public var fields : Array<EnumField>;
public var underlyingType : Null<CType>;
}
@:structInit
final class EnumField {
public var name : String;
public var args : Array<Argument>;
public var value : Null<Expr>;
}
enum CType {
CTPath( path : Array<String>, ?params : Array<CType> );
CTFun( args : Array<CType>, ret : CType );
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
CTParent( t : CType );
CTOpt( t : CType );
CTNamed( n : String, t : CType );
CTExpr( e : Expr ); // for type parameters only
}
#if hscriptPos
class Error {
public var e : ErrorDef;
public var pmin : Int;
public var pmax : Int;
public var origin : String;
public var line : Int;
public function new(e, pmin, pmax, origin, line) {
this.e = e;
this.pmin = pmin;
this.pmax = pmax;
this.origin = origin;
this.line = line;
}
public function toString(): String {
return Printer.errorToString(this);
}
}
enum ErrorDef {
#else
enum Error {
#end
EInvalidChar( c : Int );
EUnexpected( s : String );
EUnterminatedString;
EUnterminatedComment;
EInvalidPreprocessor( msg : String );
EUnknownVariable( v : String );
EInvalidIterator( v : String );
EInvalidOp( op : String );
EInvalidAccess( f : String );
ECustom( msg : String );
EInvalidClass( className : String);
EAlreadyExistingClass( className : String);
}
enum ModuleDecl {
DPackage( path : Array<String> );
DImport( path : Array<String>, ?everything : Bool );
DClass( c : ClassDecl );
DTypedef( c : TypeDecl );
}
typedef ModuleType = {
var name : String;
var params : {}; // TODO : not yet parsed
var meta : Metadata;
var isPrivate : Bool;
}
typedef ClassDecl = {> ModuleType,
var extend : Null<CType>;
var implement : Array<CType>;
var fields : Array<FieldDecl>;
var isExtern : Bool;
}
typedef TypeDecl = {> ModuleType,
var t : CType;
}
typedef FieldDecl = {
var name : String;
var meta : Metadata;
var kind : FieldKind;
var access : Array<FieldAccess>;
}
enum abstract FieldAccess(UInt8) {
var APublic;
var APrivate;
var AInline;
var AOverride;
var AStatic;
var AMacro;
}
enum abstract FieldPropertyAccess(UInt8) {
var ADefault;
var ANull;
var AGet;
var ASet;
var ADynamic;
var ANever;
}
enum FieldKind {
KFunction( f : FunctionDecl );
KVar( v : VarDecl );
}
@:structInit
final class FunctionDecl {
public var args : Array<Argument>;
public var body : Expr;
public var ret : Null<CType>;
}
typedef VarDecl = {
var get : Null<String>;
var set : Null<String>;
var expr : Null<Expr>;
var type : Null<CType>;
}
+119 -3
View File
@@ -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);
}
}
+529 -311
View File
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -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));
+391 -172
View File
@@ -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 var e = parseType();
switch(e) {
while( true ) { case CTPath(path, params):
var t = token(); var buf = new StringBuf();
switch( t ) { for(i in 0...path.length) {
case TId("extends"): if(i > 0) buf.add(".");
var e = parseType(); buf.add(path[i]);
switch(e) {
case CTPath(path, params):
if(extend != null) {
error(ECustom('Cannot extend a class twice.'), 0, 0);
}
extend = path.join(".");
default:
error(ECustom('${Std.string(e)} is not a valid path.'), 0, 0);
} }
extend = buf.toString();
default: default:
push(t); error(ECustom('${Std.string(e)} is not a valid path.'), p1, tokenMax);
break;
} }
} }
/*while(true) { var interfaces:Array<String> = [];
tk = token(); var tk:Token = null;
trace(tk); if(maybe(TId("implements"))) {
switch (tk) { // handled manually for multiple implements
case TId(id): while(true) {
if (id == "extends") { tk = token();
tk = token(); switch(tk) {
if(extend != null) { case TId("implements"): continue;
unexpected(tk); case TId("extends"):
} else { error(ECustom('Implements must come after extends.'), p1, tokenMax);
switch (tk) { case TId(_):
case TId(id): extend = id; push(tk);
default: unexpected(tk); var e = parseType();
} switch(e) {
case CTPath(path, params):
var buf = new StringBuf();
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(); push(tk);
switch (tk) { break;
case TId(id): interfaces.push(id); }
default: unexpected(tk);
}
} else {
//push(tk);
}
case TBrOpen:
push(tk);
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,13 +1441,12 @@ class Parser {
} }
} }
tk = token(); tk = token();
switch( tk ) { if( tk == TComma ) {
case TComma: tk = token();
tk = token(); } else if( tk == TPClose ) {
case TPClose: done = true;
done = true; } else {
default: unexpected(tk);
unexpected(tk);
} }
} }
} }
@@ -1454,31 +1493,32 @@ class Parser {
if( op == "<" ) { if( op == "<" ) {
params = []; params = [];
while( true ) { while( true ) {
switch( token() ) { var tt = token();
case TConst(c): switch( tt ) {
params.push(CTExpr(mk(EConst(c)))); case TConst(c):
case tk: params.push(CTExpr(mk(EConst(c))));
push(tk); default:
params.push(parseType()); push(tt);
} params.push(parseType());
t = token();
switch( t ) {
case TComma: continue;
case TOp(op):
if( op == ">" ) break;
if( op.charCodeAt(0) == ">".code ) {
#if hscriptPos
tokens.add({ t : TOp(op.substr(1)), min : tokenMax - op.length - 1, max : tokenMax });
#else
tokens.add(TOp(op.substr(1)));
#end
break;
} }
default: t = token();
switch( t ) {
case TComma: continue;
case TOp(op):
if( op == ">" ) break;
if( op.charCodeAt(0) == ">".code ) {
#if hscriptPos
tokens.add({ t : TOp(op.substr(1)), min : tokenMax - op.length - 1, max : tokenMax });
#else
tokens.add(TOp(op.substr(1)));
#end
break;
}
default:
}
unexpected(t);
break;
} }
unexpected(t);
break;
}
} else } else
push(t); push(t);
default: default:
@@ -1608,16 +1648,101 @@ class Parser {
while( true ) { while( true ) {
args.push(parseExpr()); args.push(parseExpr());
tk = token(); tk = token();
switch( tk ) { if( tk == etk )
case TComma: break;
default: if( tk != TComma )
if( tk == etk ) break; unexpected(tk);
unexpected(tk);
break;
}
} }
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
@@ -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 ) {
break; if(regex && prev == 92) {
b.addChar(c);
prev = c;
}
else
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';
} }
} }
+494 -462
View File
@@ -1,462 +1,494 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * Copyright (C)2008-2017 Haxe Foundation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the * and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions: * Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
package hscript; package hscript;
import hscript.Expr; import hscript.Expr;
class Printer { class Printer {
var buf : StringBuf; var buf : StringBuf;
var tabs : String; var tabs : String;
public function new() { public function new() {
} }
public function exprToString( e : Expr ):String { public function exprToString( e : Expr ):String {
buf = new StringBuf(); buf = new StringBuf();
tabs = ""; tabs = "";
expr(e); expr(e);
return buf.toString(); return buf.toString();
} }
public function typeToString( t : CType ):String { public function typeToString( t : CType ):String {
buf = new StringBuf(); buf = new StringBuf();
tabs = ""; tabs = "";
type(t); type(t);
return buf.toString(); return buf.toString();
} }
inline function add<T>(s:T):Void buf.add(s); inline function add<T>(s:T):Void buf.add(s);
function type( t : CType ):Void { function type( t : CType ):Void {
switch( t ) { switch( t ) {
case CTOpt(t): case CTOpt(t):
add('?'); add('?');
type(t); type(t);
case CTPath(path, params): case CTPath(path, params):
add(path.join(".")); add(path.join("."));
if( params != null ) { if( params != null ) {
add("<"); add("<");
var first = true; var first = true;
for( p in params ) { for( p in params ) {
if( first ) first = false else add(", "); if( first ) first = false else add(", ");
type(p); type(p);
} }
add(">"); add(">");
} }
case CTNamed(name, t): case CTNamed(name, t):
add(name); add(name);
add(':'); add(':');
type(t); type(t);
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))): case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
add('('); add('(');
for (a in args) for (a in args)
switch a { switch a {
case CTNamed(_, _): type(a); case CTNamed(_, _): type(a);
default: type(CTNamed('_', a)); default: type(CTNamed('_', a));
} }
add(')->'); add(')->');
type(ret); type(ret);
case CTFun(args, ret): case CTFun(args, ret):
if( args.length == 0 ) if( args.length == 0 )
add("Void -> "); add("Void -> ");
else { else {
for( a in args ) { for( a in args ) {
type(a); type(a);
add(" -> "); add(" -> ");
} }
} }
type(ret); type(ret);
case CTAnon(fields): case CTAnon(fields):
add("{"); add("{");
var first = true; var first = true;
for( f in fields ) { for( f in fields ) {
if( first ) { first = false; add(" "); } else add(", "); if( first ) { first = false; add(" "); } else add(", ");
add(f.name + " : "); add(f.name + " : ");
type(f.t); type(f.t);
} }
add(first ? "}" : " }"); add(first ? "}" : " }");
case CTParent(t): case CTParent(t):
add("("); add("(");
type(t); type(t);
add(")"); add(")");
case CTExpr(e): case CTExpr(e):
expr(e); expr(e);
} }
} }
function addType( t : CType ):Void { function addType( t : CType ):Void {
if( t != null ) { if( t != null ) {
add(" : "); add(" : ");
type(t); type(t);
} }
} }
function expr( e : Expr ):Void { function expr( e : Expr ):Void {
if( e == null ) { if( e == null ) {
add("??NULL??"); add("??NULL??");
return; return;
} }
switch(Tools.expr(e)) { switch(Tools.expr(e)) {
case EImport(c, n, u): case EPackage(n):
add('${u ? 'using' : 'import'} $c'); add('package');
if(n != null) if(n != null)
add(' as $n'); add(' $n');
case EClass(name, fields, extend, interfaces, fnal): add(';\n');
var isFinal = fnal != null && fnal; case EImport(c, n, u):
if(isFinal) add('${u ? 'using' : 'import'} $c');
add('final '); if(n != null)
add('class $name'); add(' as $n');
if (extend != null) case EClass(name, fields, extend, interfaces, fnal):
add(' extends $extend'); var isFinal = fnal != null && fnal;
for(_interface in interfaces) { if(isFinal)
add(' implements $_interface'); add('final ');
} add('class $name');
tabs += "\t"; if (extend != null)
add(" {\n"); add(' extends $extend');
for( e in fields ) { for(_interface in interfaces) {
add(tabs); add(' implements $_interface');
expr(e); }
//add(";\n"); tabs += "\t";
} add(" {\n");
//for(field in fields) { for( e in fields ) {
// expr(field); add(tabs);
//} expr(e);
//add(";\n");
tabs = tabs.substr(1); }
add("}"); //for(field in fields) {
case EEnum(en, _): // TODO: enum abstracts // expr(field);
add('enum ${en.name}'); //}
if(en.fields.length == 0) {
add(' {}'); tabs = tabs.substr(1);
return; add("}");
} case EEnum(en, isAbstract):
tabs += "\t"; if(isAbstract) {
add(" {\n"); add('enum abstract ${en.name}(');
if(en.underlyingType != null)
for(e in en.fields) { type(en.underlyingType);
add(tabs); else
add(e.name); add('Int');
if(e.args.length > 0) { add(')');
add("("); if(en.fields.length == 0) {
var first = true; add(' {}');
for( a in e.args ) { return;
if( first ) first = false else add(", "); }
if( a.opt ) add("?"); tabs += "\t";
add(a.name); add(" {\n");
addType(a.t); for(e in en.fields) {
} add(tabs);
add(')'); add(e.name);
} if(e.value != null) {
add(";\n"); add(" = ");
} expr(e.value);
}
tabs = tabs.substr(1); add(";\n");
add("}"); }
case ECast(e, t): tabs = tabs.substr(1);
var safe = t != null; add("}");
add("cast "); } else {
if(safe) add("("); add('enum ${en.name}');
expr(e); if(en.fields.length == 0) {
if(safe) { add(' {}');
add(", "); return;
addType(t); }
add(")"); tabs += "\t";
} add(" {\n");
case EConst(c): for(e in en.fields) {
switch( c ) { add(tabs);
case CInt(i): add(i); add(e.name);
case CFloat(f): add(f); if(e.args.length > 0) {
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"'); add("(");
} var first = true;
case EIdent(v): for( a in e.args ) {
add(v); if( first ) first = false else add(", ");
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _): if( a.opt ) add("?");
if(p) add("public "); add(a.name);
else if(pr) add("private "); addType(a.t);
if(s) add("static "); }
if(isInline) add("inline "); add(')');
if(isFinal) add("final " + n); }
else add("var " + n); add(";\n");
}
if(get != null || set != null) { tabs = tabs.substr(1);
add("("); add("}");
switch(get) { }
case ADefault: add("default, "); case ECast(e, t):
case ANull: add("null, "); var safe = t != null;
case AGet: add("get, "); add("cast ");
case ADynamic: add("dynamic, "); if(safe) add("(");
case ANever: add("never, "); expr(e);
default: if(safe) {
} add(", ");
switch(set) { addType(t);
case ADefault: add("default"); add(")");
case ANull: add("null"); }
case ASet: add("set"); case ERegex(e, f):
case ADynamic: add("dynamic"); add('~/$e/$f');
case ANever: add("never"); add(';\n');
default: case EConst(c):
} switch( c ) {
add(")"); case CInt(i): add(i);
} case CFloat(f): add(f);
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
addType(t); }
if( e != null ) { case EIdent(v):
add(" = "); add(v);
expr(e); case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
} if(p) add("public ");
case EParent(e): else if(pr) add("private ");
add("("); expr(e); add(")"); if(s) add("static ");
case EBlock(el): if(isInline) add("inline ");
if( el.length == 0 ) { if(isFinal) add("final " + n);
add("{}"); else add("var " + n);
} else {
tabs += "\t"; if(get != null || set != null) {
add("{\n"); add("(");
for( e in el ) { switch(get) {
add(tabs); case ADefault: add("default, ");
expr(e); case ANull: add("null, ");
add(";\n"); case AGet: add("get, ");
} case ADynamic: add("dynamic, ");
tabs = tabs.substr(1); case ANever: add("never, ");
add("}"); default:
} }
case EField(e, f, s): switch(set) {
expr(e); case ADefault: add("default");
add((s == true ? "?." : ".") + f); case ANull: add("null");
case EBinop(op, e1, e2): case ASet: add("set");
expr(e1); case ADynamic: add("dynamic");
add(" " + op + " "); case ANever: add("never");
expr(e2); default:
case EUnop(op, pre, e): }
if( pre ) { add(")");
add(op); }
expr(e);
} else { addType(t);
expr(e); if( e != null ) {
add(op); add(" = ");
} expr(e);
case ECall(e, args): }
if( e == null ) case EParent(e):
expr(e); add("("); expr(e); add(")");
else switch( Tools.expr(e)) { case EBlock(el):
case EField(_), EIdent(_), EConst(_): if( el.length == 0 ) {
expr(e); add("{}");
default: } else {
add("("); tabs += "\t";
expr(e); add("{\n");
add(")"); for( e in el ) {
} add(tabs);
add("("); expr(e);
var first = true; add(";\n");
for( a in args ) { }
if( first ) first = false else add(", "); tabs = tabs.substr(1);
expr(a); add("}");
} }
add(")"); case EField(e, f, s):
case EIf(cond,e1,e2): expr(e);
add("if( "); add((s == true ? "?." : ".") + f);
expr(cond); case EBinop(op, e1, e2):
add(" ) "); expr(e1);
expr(e1); add(" " + op.toString() + " ");
if( e2 != null ) { expr(e2);
add(" else "); case EUnop(op, pre, e):
expr(e2); if( pre ) {
} add(op);
case EWhile(cond,e): expr(e);
add("while( "); } else {
expr(cond); expr(e);
add(" ) "); add(op);
expr(e); }
case EDoWhile(cond,e): case ECall(e, args):
add("do "); if( e == null )
expr(e); expr(e);
add(" while ( "); else switch( Tools.expr(e)) {
expr(cond); case EField(_), EIdent(_), EConst(_):
add(" )"); expr(e);
case EFor(v, it, e, ithv): default:
if(ithv != null) add("(");
add("for( "+ithv+" => "+v+" in "); expr(e);
else add(")");
add("for( "+v+" in "); }
expr(it); add("(");
add(" ) "); var first = true;
expr(e); for( a in args ) {
case EBreak: if( first ) first = false else add(", ");
add("break"); expr(a);
case EContinue: }
add("continue"); add(")");
case EFunction(params, e, name, ret): // TODO: static, public, override case EIf(cond,e1,e2):
add("function"); add("if( ");
if( name != null ) expr(cond);
add(" " + name); add(" ) ");
add("("); expr(e1);
var first = true; if( e2 != null ) {
for( a in params ) { add(" else ");
if( first ) first = false else add(", "); expr(e2);
if( a.opt ) add("?"); }
add(a.name); case EWhile(cond,e):
addType(a.t); add("while( ");
} expr(cond);
add(")"); add(" ) ");
addType(ret); expr(e);
add(" "); case EDoWhile(cond,e):
expr(e); add("do ");
case EReturn(e): expr(e);
add("return"); add(" while ( ");
if( e != null ) { expr(cond);
add(" "); add(" )");
expr(e); case EFor(v, it, e, ithv):
} if(ithv != null)
case EArray(e,index): add("for( "+ithv+" => "+v+" in ");
expr(e); else
add("["); add("for( "+v+" in ");
expr(index); expr(it);
add("]"); add(" ) ");
case EArrayDecl(el, _): expr(e);
add("["); case EBreak:
var first = true; add("break");
for( e in el ) { case EContinue:
if( first ) first = false else add(", "); add("continue");
expr(e); case EFunction(params, e, name, ret): // TODO: static, public, override
} add("function");
add("]"); if( name != null )
case ENew(cl, args, params): add(" " + name);
add("new " + cl); add("(");
if(params != null) { var first = true;
add("<"); for( a in params ) {
var first = true; if( first ) first = false else add(", ");
for( p in params ) { if( a.opt ) add("?");
if( first ) first = false else add(", "); add(a.name);
type(p); addType(a.t);
} }
add(">"); add(")");
} addType(ret);
add("("); add(" ");
var first = true; expr(e);
for( e in args ) { case EReturn(e):
if( first ) first = false else add(", "); add("return");
expr(e); if( e != null ) {
} add(" ");
add(")"); expr(e);
case EThrow(e): }
add("throw "); case EArray(e,index):
expr(e); expr(e);
case ETry(e, v, t, ecatch): add("[");
add("try "); expr(index);
expr(e); add("]");
add(" catch( " + v); case EArrayDecl(el, _):
addType(t); add("[");
add(") "); var first = true;
expr(ecatch); for( e in el ) {
case EObject(fl): if( first ) first = false else add(", ");
if( fl.length == 0 ) { expr(e);
add("{}"); }
} else { add("]");
tabs += "\t"; case ENew(cl, args, params):
add("{\n"); add("new " + cl);
for( f in fl ) { if(params != null) {
add(tabs); add("<");
add(f.name+" : "); var first = true;
expr(f.e); for( p in params ) {
add(",\n"); if( first ) first = false else add(", ");
} type(p);
tabs = tabs.substr(1); }
add("}"); add(">");
} }
case ETernary(c,e1,e2): add("(");
expr(c); var first = true;
add(" ? "); for( e in args ) {
expr(e1); if( first ) first = false else add(", ");
add(" : "); expr(e);
expr(e2); }
case ESwitch(e, cases, def): add(")");
add("switch( "); case EThrow(e):
expr(e); add("throw ");
add(") {"); expr(e);
for( c in cases ) { case ETry(e, v, t, ecatch):
add("case "); add("try ");
var first = true; expr(e);
for( v in c.values ) { add(" catch( " + v);
if( first ) first = false else add(", "); addType(t);
expr(v); add(") ");
} expr(ecatch);
add(": "); case EObject(fl):
expr(c.expr); if( fl.length == 0 ) {
add(";\n"); add("{}");
} } else {
if( def != null ) { tabs += "\t";
add("default: "); add("{\n");
expr(def); for( f in fl ) {
add(";\n"); add(tabs);
} add(f.name+" : ");
add("}"); expr(f.e);
case EMeta(name, args, e): add(",\n");
add("@"); }
add(name); tabs = tabs.substr(1);
if( args != null && args.length > 0 ) { add("}");
add("("); }
var first = true; case ETernary(c,e1,e2):
for( a in args ) { expr(c);
if( first ) first = false else add(", "); add(" ? ");
expr(e); expr(e1);
} add(" : ");
add(")"); expr(e2);
} case ESwitch(e, cases, def):
add(" "); add("switch( ");
expr(e); expr(e);
case ECheckType(e, t): add(") {");
add("("); for( c in cases ) {
expr(e); add("case ");
add(" : "); var first = true;
addType(t); for( v in c.values ) {
add(")"); if( first ) first = false else add(", ");
} expr(v);
} }
add(": ");
public static function toString( e : Expr ):String { expr(c.expr);
return new Printer().exprToString(e); add(";\n");
} }
if( def != null ) {
public static function errorToString( e : Expr.Error ):String { add("default: ");
var message = switch( #if hscriptPos e.e #else e #end ) { expr(def);
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")"; add(";\n");
case EUnexpected(s): "Unexpected token: \""+s+"\""; }
case EUnterminatedString: "Unterminated string"; add("}");
case EUnterminatedComment: "Unterminated comment"; case EMeta(name, args, e):
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")"; add("@");
case EUnknownVariable(v): "Unknown variable: "+v; add(name);
case EInvalidIterator(v): "Invalid iterator: "+v; if( args != null && args.length > 0 ) {
case EInvalidOp(op): "Invalid operator: "+op; add("(");
case EInvalidAccess(f): "Invalid access to field " + f; var first = true;
case ECustom(msg): msg; for( a in args ) {
case EInvalidClass(cla): "Invalid class: " + cla + " was not found."; if( first ) first = false else add(", ");
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.'; expr(e);
}; }
#if hscriptPos add(")");
return e.origin + ":" + e.line + ": " + message; }
#else add(" ");
return message; expr(e);
#end case ECheckType(e, t):
} add("(");
expr(e);
add(" : ");
} addType(t);
add(")");
}
}
public static function toString( e : Expr ):String {
return new Printer().exprToString(e);
}
public static function errorToString( e : Expr.Error ):String {
var message = switch( #if hscriptPos e.e #else e #end ) {
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
case EUnexpected(s): "Unexpected token: \""+s+"\"";
case EUnterminatedString: "Unterminated string";
case EUnterminatedComment: "Unterminated comment";
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
case EUnknownVariable(v): "Unknown variable: "+v;
case EInvalidIterator(v): "Invalid iterator: "+v;
case EInvalidOp(op): "Invalid operator: "+op;
case EInvalidAccess(f): "Invalid access to field " + f;
case ECustom(msg): msg;
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
};
#if hscriptPos
return e.origin + ":" + e.line + ": " + message;
#else
return message;
#end
}
}
+83 -19
View File
@@ -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);
}
} }
+143 -136
View File
@@ -1,137 +1,144 @@
/* /*
* Copyright (C)2008-2017 Haxe Foundation * Copyright (C)2008-2017 Haxe Foundation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation * to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the * and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions: * Software is furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
package hscript; package hscript;
import hscript.Expr; import hscript.Expr;
class Tools { class Tools {
public static function iter( e : Expr, f : Expr -> Void ):Void { public static function iter( e : Expr, f : Expr -> Void ):Void {
switch( expr(e) ) { switch( expr(e) ) {
case EConst(_), EIdent(_): case EConst(_), EIdent(_):
case EImport(c): f(e); case EImport(c): f(e);
case EClass(_, e, _, _): for( a in e ) f(a); case EClass(_, e, _, _): for( a in e ) f(a);
case EVar(_, _, e): if( e != null ) f(e); case EVar(_, _, e): if( e != null ) f(e);
case EParent(e): f(e); case EParent(e): f(e);
case EBlock(el): for( e in el ) f(e); case EBlock(el): for( e in el ) f(e);
case EField(e, _): f(e); case EField(e, _): f(e);
case EBinop(_, e1, e2): f(e1); f(e2); case EBinop(_, e1, e2): f(e1); f(e2);
case EUnop(_, _, e): f(e); case EUnop(_, _, e): f(e);
case ECall(e, args): f(e); for( a in args ) f(a); case ECall(e, args): f(e); for( a in args ) f(a);
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2); case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
case EWhile(c, e): f(c); f(e); case EWhile(c, e): f(c); f(e);
case EDoWhile(c, e): f(c); f(e); case EDoWhile(c, e): f(c); f(e);
case EFor(_, it, e): f(it); f(e); case EFor(_, it, e): f(it); f(e);
case EBreak,EContinue: case EBreak,EContinue:
case EFunction(_, e, _, _): f(e); case EFunction(_, e, _, _): f(e);
case EReturn(e): if( e != null ) f(e); case EReturn(e): if( e != null ) f(e);
case EArray(e, i): f(e); f(i); case EArray(e, i): f(e); f(i);
case EArrayDecl(el): for( e in el ) f(e); case EArrayDecl(el): for( e in el ) f(e);
case ENew(_,el): for( e in el ) f(e); case ENew(_,el): for( e in el ) f(e);
case EThrow(e): f(e); case EThrow(e): f(e);
case ETry(e, _, _, c): f(e); f(c); case ETry(e, _, _, c): f(e); f(c);
case EObject(fl): for( fi in fl ) f(fi.e); case EObject(fl): for( fi in fl ) f(fi.e);
case ETernary(c, e1, e2): f(c); f(e1); f(e2); case ETernary(c, e1, e2): f(c); f(e1); f(e2);
case ESwitch(e, cases, def): case ESwitch(e, cases, def):
f(e); f(e);
for( c in cases ) { for( c in cases ) {
for( v in c.values ) f(v); for( v in c.values ) f(v);
f(c.expr); f(c.expr);
} }
if( def != null ) f(def); if( def != null ) f(def);
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e); case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
case ECheckType(e,_): f(e); case ECheckType(e,_): f(e);
default: default:
} }
} }
public static function map( e : Expr, f : Expr -> Expr ):Expr { public static function map( e : Expr, f : Expr -> Expr ):Expr {
var edef = switch( expr(e) ) { var edef = switch( expr(e) ) {
case EConst(_), EIdent(_), EBreak, EContinue: expr(e); case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate); case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
case EParent(e): EParent(f(e)); case EParent(e): EParent(f(e));
case EBlock(el): EBlock([for( e in el ) f(e)]); case EBlock(el): EBlock([for( e in el ) f(e)]);
case EField(e, fi): EField(f(e),fi); case EField(e, fi): EField(f(e),fi);
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2)); case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
case EUnop(op, pre, e): EUnop(op, pre, f(e)); case EUnop(op, pre, e): EUnop(op, pre, f(e));
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]); case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null); case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
case EWhile(c, e): EWhile(f(c),f(e)); case EWhile(c, e): EWhile(f(c),f(e));
case EDoWhile(c, e): EDoWhile(f(c),f(e)); case EDoWhile(c, e): EDoWhile(f(c),f(e));
case EFor(v, it, e): EFor(v, f(it), f(e)); case EFor(v, it, e): EFor(v, f(it), f(e));
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate); case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
case EReturn(e): EReturn(if( e != null ) f(e) else null); case EReturn(e): EReturn(if( e != null ) f(e) else null);
case EArray(e, i): EArray(f(e),f(i)); case EArray(e, i): EArray(f(e),f(i));
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]); case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]); case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
case EThrow(e): EThrow(f(e)); case EThrow(e): EThrow(f(e));
case ETry(e, v, t, c): ETry(f(e), v, t, f(c)); case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]); case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2)); case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def)); case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e)); case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
case ECheckType(e,t): ECheckType(f(e), t); case ECheckType(e,t): ECheckType(f(e), t);
case EImport(c): EImport(c); case EImport(c): EImport(c);
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces); case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
default: expr(e); default: expr(e);
} }
return mk(edef, e); return mk(edef, e);
} }
public static inline function expr( e : Expr ) : ExprDef { public static inline function expr( e : Expr ) : ExprDef {
#if hscriptPos #if hscriptPos
return e.e; return e.e;
#else #else
return e; return e;
#end #end
} }
public static inline function mk( e : ExprDef, p : Expr ):Expr { public static inline function mk( e : ExprDef, p : Expr ):Expr {
#if hscriptPos #if hscriptPos
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line }; return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
#else #else
return e; return e;
#end #end
} }
/** /**
* DO NOT USE INLINE ON THIS FUNCTION * DO NOT USE INLINE ON THIS FUNCTION
**/ **/
public static function argCount(func: haxe.Constraints.Function): Int { public static function argCount(func: haxe.Constraints.Function): Int {
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206 // https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
#if cpp #if cpp
return untyped __cpp__("{0}->__ArgCount()", func); return untyped __cpp__("{0}->__ArgCount()", func);
#elseif js #elseif js
return untyped js.Syntax.code("{0}.length", func); return untyped js.Syntax.code("{0}.length", func);
#elseif hl #elseif hl
var ft = hl.Type.getDynamic(func); var ft = hl.Type.getDynamic(func);
if (ft.kind != HFun) if (ft.kind != HFun)
return -1; return -1;
return ft.getArgsCount(); return ft.getArgsCount();
#else #else
return -1; return -1;
#end #end
} }
public static inline function isCustomAbstract(obj:Dynamic):Bool public static function isUppercase(s:String) {
return obj != null && obj is IHScriptAbstractBehaviour; if(s.length == 0) return false;
var c:Int = StringTools.fastCodeAt(s, 0);
if(StringTools.isEof(c)) return false; // Just in case :3
return c >= 65 && c <= 90; // A-Z
}
public static inline function isCustomAbstract(obj:Dynamic):Bool
return obj != null && obj is IHScriptAbstractBehaviour;
} }
+2
View File
@@ -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> {
+8 -4
View File
@@ -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;
} }
+1 -1
View File
@@ -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);
} }
} }