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
18 changed files with 2698 additions and 1944 deletions
-1
View File
@@ -22,7 +22,6 @@ or set this in build.hxml
Current Custom Class Limitations : Current Custom Class Limitations :
- 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.
- You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future. - You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
----------- -----------
+536 -536
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -156,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):
@@ -278,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"
];
} }
+13 -9
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;
@@ -153,8 +152,12 @@ class CustomClass implements IHScriptCustomClassBehaviour {
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;
} }
@@ -170,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;
@@ -182,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);
@@ -350,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;
} }
+15 -20
View File
@@ -60,23 +60,19 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
if(!__interp.variables.exists(f)) if(!__interp.variables.exists(f))
__interp.variables.set(f, v); __interp.variables.set(f, v);
for(e in fields.copy()) { for(i => e in fields.copy()) {
var validField:Bool = false; 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);
@@ -88,7 +84,7 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
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);
@@ -119,10 +115,9 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
public function hget(name:String):Dynamic { public function hget(name:String):Dynamic {
if(name == 'new') { if(name == 'new') {
var __constructor = Reflect.makeVarArgs(function(args:Array<Dynamic>) { return Reflect.makeVarArgs(function(args:Array<Dynamic>):Dynamic {
return this.hnew(args); return inline this.hnew(args);
}); });
return __constructor;
} }
if(hasField(name)) { if(hasField(name)) {
+403 -244
View File
@@ -1,244 +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;
EPackage( ?n:String ); case ">>": OpShr;
EImport( c : String, ?asname:String, ?isUsing:Bool ); case ">>>": OpUshr;
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool ); case "==": OpEq;
EEnum( en:EnumDecl, ?isAbstract:Bool ); case "!=": OpNeq;
ECast(e:Expr, ?t:CType); case ">=": OpGte;
ERegex(e:String, flags:String); case "<=": OpLte;
} case ">": OpGt;
case "<": OpLt;
@:structInit case "||": OpBoolOr;
final class ObjectField { case "&&": OpBoolAnd;
public var name : String; case "is": OpIs;
public var e : Expr; case "=": OpAssign;
} case "??": OpNcoal;
case "...": OpInterval;
@:structInit case "->": OpArrow;
final class SwitchCase { case "=>": OpArrowFn;
public var values : Array<Expr>; case "+=": OpAddAssign;
public var expr : Expr; case "-=": OpSubAssign;
} case "*=": OpMultAssign;
case "/=": OpDivAssign;
@:structInit case "%=": OpModAssign;
final class Argument { case "&=": OpAndAssign;
public var name : String; case "|=": OpOrAssign;
public var t : CType; case "^=": OpXorAssign;
public var opt : Bool; case "<<=": OpShlAssign;
public var value : Expr; case ">>=": OpShrAssign;
} case ">>>=": OpUshrAssign;
case _ if (s == "??" + "="): OpNcoalAssign;
@:structInit default: -1;
final class MetadataEntry { }
public var name : String; }
public var params : Array<Expr>;
} public inline function toString():String {
return switch(this) {
typedef Metadata = Array<MetadataEntry>; case OpAdd: "+";
case OpSub: "-";
@:structInit case OpMult: "*";
final class EnumDecl { case OpDiv: "/";
public var name : String; case OpMod: "%";
public var fields : Array<EnumField>; case OpAnd: "&";
} case OpOr: "|";
case OpXor: "^";
@:structInit case OpShl: "<<";
final class EnumField { case OpShr: ">>";
public var name : String; case OpUshr: ">>>";
public var args : Array<Argument>; case OpEq: "==";
} case OpNeq: "!=";
case OpGte: ">=";
enum CType { case OpLte: "<=";
CTPath( path : Array<String>, ?params : Array<CType> ); case OpGt: ">";
CTFun( args : Array<CType>, ret : CType ); case OpLt: "<";
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> ); case OpBoolOr: "||";
CTParent( t : CType ); case OpBoolAnd: "&&";
CTOpt( t : CType ); case OpIs: "is";
CTNamed( n : String, t : CType ); case OpAssign: "=";
CTExpr( e : Expr ); // for type parameters only case OpNcoal: "??";
} case OpInterval: "...";
case OpArrow: "->";
#if hscriptPos case OpArrowFn: "=>";
class Error { case OpAddAssign: "+=";
public var e : ErrorDef; case OpSubAssign: "-=";
public var pmin : Int; case OpMultAssign: "*=";
public var pmax : Int; case OpDivAssign: "/=";
public var origin : String; case OpModAssign: "%=";
public var line : Int; case OpAndAssign: "&=";
public function new(e, pmin, pmax, origin, line) { case OpOrAssign: "|=";
this.e = e; case OpXorAssign: "^=";
this.pmin = pmin; case OpShlAssign: "<<=";
this.pmax = pmax; case OpShrAssign: ">>=";
this.origin = origin; case OpUshrAssign: ">>>=";
this.line = line; case OpNcoalAssign: "??" + "=";
} default: "?";
public function toString(): String { }
return Printer.errorToString(this); }
} }
}
enum ErrorDef { enum abstract Unop(Int) from Int to Int {
#else var OpNot = 0;
enum Error { var OpNeg = 1;
#end var OpIncrement = 2;
EInvalidChar( c : Int ); var OpDecrement = 3;
EUnexpected( s : String ); var OpNegBits = 4;
EUnterminatedString;
EUnterminatedComment; public static inline function fromString(s:String):Unop {
EInvalidPreprocessor( msg : String ); return switch(s) {
EUnknownVariable( v : String ); case "!": OpNot;
EInvalidIterator( v : String ); case "-": OpNeg;
EInvalidOp( op : String ); case "++": OpIncrement;
EInvalidAccess( f : String ); case "--": OpDecrement;
ECustom( msg : String ); case "~": OpNegBits;
EInvalidClass( className : String); default: -1;
EAlreadyExistingClass( className : String); }
} }
public inline function toString():String {
enum ModuleDecl { return switch(this) {
DPackage( path : Array<String> ); case OpNot: "!";
DImport( path : Array<String>, ?everything : Bool ); case OpNeg: "-";
DClass( c : ClassDecl ); case OpIncrement: "++";
DTypedef( c : TypeDecl ); case OpDecrement: "--";
} case OpNegBits: "~";
default: "?";
typedef ModuleType = { }
var name : String; }
var params : {}; // TODO : not yet parsed }
var meta : Metadata;
var isPrivate : Bool; typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
} typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
typedef ClassDecl = {> ModuleType, enum Const {
var extend : Null<CType>; CInt( v : Int );
var implement : Array<CType>; CFloat( f : Float );
var fields : Array<FieldDecl>; CString( s : String, ?i : Bool );
var isExtern : Bool; }
}
#if hscriptPos
typedef TypeDecl = {> ModuleType, @:structInit
var t : CType; final class Expr {
} public var e : ExprDef;
public var pmin : Int;
typedef FieldDecl = { public var pmax : Int;
var name : String; public var origin : String;
var meta : Metadata; public var line : Int;
var kind : FieldKind; }
var access : Array<FieldAccess>; enum ExprDef {
} #else
typedef ExprDef = Expr;
enum abstract FieldAccess(UInt8) { enum Expr {
var APublic; #end
var APrivate; EConst( c : Const );
var AInline; EIdent( v : String );
var AOverride; EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
var AStatic; EParent( e : Expr );
var AMacro; EBlock( e : Array<Expr> );
} EField( e : Expr, f : String , ?safe : Bool );
EBinop( op : Binop, e1 : Expr, e2 : Expr );
enum abstract FieldPropertyAccess(UInt8) { EUnop( op : Unop, prefix : Bool, e : Expr );
var ADefault; ECall( e : Expr, params : Array<Expr> );
var ANull; EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
var AGet; EWhile( cond : Expr, e : Expr );
var ASet; EFor( v : String, it : Expr, e : Expr, ?ithv: String);
var ADynamic; EBreak;
var ANever; EContinue;
} EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
EReturn( ?e : Expr );
enum FieldKind { EArray( e : Expr, index : Expr );
KFunction( f : FunctionDecl ); EArrayDecl( e : Array<Expr>, ?wantedType: CType );
KVar( v : VarDecl ); ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
} EThrow( e : Expr );
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
@:structInit EObject( fl : Array<ObjectField> );
final class FunctionDecl { ETernary( cond : Expr, e1 : Expr, e2 : Expr );
public var args : Array<Argument>; ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
public var body : Expr; EDoWhile( cond : Expr, e : Expr);
public var ret : Null<CType>; EMeta( name : String, args : Array<Expr>, e : Expr );
} ECheckType( e : Expr, t : CType );
typedef VarDecl = { EPackage( ?n:String );
var get : Null<String>; EImport( c : String, ?asname:String, ?isUsing:Bool );
var set : Null<String>; EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
var expr : Null<Expr>; EEnum( en:EnumDecl, ?isAbstract:Bool );
var type : Null<CType>; 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);
}
}
+520 -306
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));
+332 -172
View File
@@ -215,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;
@@ -225,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;
@@ -253,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
@@ -261,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
@@ -269,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
@@ -277,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;
@@ -288,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;
@@ -308,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);
@@ -340,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:
@@ -371,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();
@@ -599,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));
} }
} }
@@ -1041,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);
@@ -1122,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;
@@ -1164,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;
@@ -1187,7 +1208,8 @@ class Parser {
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 ) {
@@ -1364,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) ):
@@ -1396,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);
@@ -1421,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);
} }
} }
} }
@@ -1474,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:
@@ -1628,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
@@ -1873,8 +1978,9 @@ class Parser {
return StringTools.fastCodeAt(input, readPos++); return StringTools.fastCodeAt(input, readPos++);
} }
function readString( until:Int, regex:Bool = false ):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;
@@ -1923,11 +2029,53 @@ class Parser {
} }
} else if( c == 92 && !regex) } 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();
@@ -2028,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;
@@ -2057,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;
@@ -2133,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) {
@@ -2189,17 +2344,19 @@ class Parser {
invalidChar(char); invalidChar(char);
default: default:
if( ops[char] ) { if( ops[char] ) {
var op:String = 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 = op; var pop = buf.toString();
op += String.fromCharCode(char); buf.addChar(char);
if( allowRegex && op == "~/") { var op = buf.toString();
if( allowRegex && op == "~/" ) {
var e = readString(char, true); var e = readString(char, true);
var f = readFlags(); var f = readFlags();
return TRegex(e, f); return TRegex(e, f);
@@ -2213,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);
@@ -2245,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 {
@@ -2260,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);
} }
@@ -2280,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);
@@ -2394,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
} }
} }
@@ -2418,7 +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 == null ? '' : f}'; case TRegex(e, f): '~/$e/$f';
} }
} }
+494 -470
View File
@@ -1,470 +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 EPackage(n): case EPackage(n):
add('package'); add('package');
if(n != null) if(n != null)
add(' $n'); add(' $n');
add(';\n'); add(';\n');
case EImport(c, n, u): case EImport(c, n, u):
add('${u ? 'using' : 'import'} $c'); add('${u ? 'using' : 'import'} $c');
if(n != null) if(n != null)
add(' as $n'); add(' as $n');
case EClass(name, fields, extend, interfaces, fnal): case EClass(name, fields, extend, interfaces, fnal):
var isFinal = fnal != null && fnal; var isFinal = fnal != null && fnal;
if(isFinal) if(isFinal)
add('final '); add('final ');
add('class $name'); add('class $name');
if (extend != null) if (extend != null)
add(' extends $extend'); add(' extends $extend');
for(_interface in interfaces) { for(_interface in interfaces) {
add(' implements $_interface'); add(' implements $_interface');
} }
tabs += "\t"; tabs += "\t";
add(" {\n"); add(" {\n");
for( e in fields ) { for( e in fields ) {
add(tabs); add(tabs);
expr(e); expr(e);
//add(";\n"); //add(";\n");
} }
//for(field in fields) { //for(field in fields) {
// expr(field); // expr(field);
//} //}
tabs = tabs.substr(1); tabs = tabs.substr(1);
add("}"); add("}");
case EEnum(en, _): // TODO: enum abstracts case EEnum(en, isAbstract):
add('enum ${en.name}'); if(isAbstract) {
if(en.fields.length == 0) { add('enum abstract ${en.name}(');
add(' {}'); if(en.underlyingType != null)
return; type(en.underlyingType);
} else
tabs += "\t"; add('Int');
add(" {\n"); add(')');
if(en.fields.length == 0) {
for(e in en.fields) { add(' {}');
add(tabs); return;
add(e.name); }
if(e.args.length > 0) { tabs += "\t";
add("("); add(" {\n");
var first = true; for(e in en.fields) {
for( a in e.args ) { add(tabs);
if( first ) first = false else add(", "); add(e.name);
if( a.opt ) add("?"); if(e.value != null) {
add(a.name); add(" = ");
addType(a.t); expr(e.value);
} }
add(')'); add(";\n");
} }
add(";\n"); tabs = tabs.substr(1);
} add("}");
} else {
tabs = tabs.substr(1); add('enum ${en.name}');
add("}"); if(en.fields.length == 0) {
case ECast(e, t): add(' {}');
var safe = t != null; return;
add("cast "); }
if(safe) add("("); tabs += "\t";
expr(e); add(" {\n");
if(safe) { for(e in en.fields) {
add(", "); add(tabs);
addType(t); add(e.name);
add(")"); if(e.args.length > 0) {
} add("(");
case ERegex(e, f): var first = true;
add('~/$e/$f'); for( a in e.args ) {
add(';\n'); if( first ) first = false else add(", ");
case EConst(c): if( a.opt ) add("?");
switch( c ) { add(a.name);
case CInt(i): add(i); addType(a.t);
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('"'); add(')');
} }
case EIdent(v): add(";\n");
add(v); }
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _): tabs = tabs.substr(1);
if(p) add("public "); add("}");
else if(pr) add("private "); }
if(s) add("static "); case ECast(e, t):
if(isInline) add("inline "); var safe = t != null;
if(isFinal) add("final " + n); add("cast ");
else add("var " + n); if(safe) add("(");
expr(e);
if(get != null || set != null) { if(safe) {
add("("); add(", ");
switch(get) { addType(t);
case ADefault: add("default, "); add(")");
case ANull: add("null, "); }
case AGet: add("get, "); case ERegex(e, f):
case ADynamic: add("dynamic, "); add('~/$e/$f');
case ANever: add("never, "); add(';\n');
default: case EConst(c):
} switch( c ) {
switch(set) { case CInt(i): add(i);
case ADefault: add("default"); case CFloat(f): add(f);
case ANull: add("null"); case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
case ASet: add("set"); }
case ADynamic: add("dynamic"); case EIdent(v):
case ANever: add("never"); add(v);
default: case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
} if(p) add("public ");
add(")"); else if(pr) add("private ");
} if(s) add("static ");
if(isInline) add("inline ");
addType(t); if(isFinal) add("final " + n);
if( e != null ) { else add("var " + n);
add(" = ");
expr(e); if(get != null || set != null) {
} add("(");
case EParent(e): switch(get) {
add("("); expr(e); add(")"); case ADefault: add("default, ");
case EBlock(el): case ANull: add("null, ");
if( el.length == 0 ) { case AGet: add("get, ");
add("{}"); case ADynamic: add("dynamic, ");
} else { case ANever: add("never, ");
tabs += "\t"; default:
add("{\n"); }
for( e in el ) { switch(set) {
add(tabs); case ADefault: add("default");
expr(e); case ANull: add("null");
add(";\n"); case ASet: add("set");
} case ADynamic: add("dynamic");
tabs = tabs.substr(1); case ANever: add("never");
add("}"); default:
} }
case EField(e, f, s): add(")");
expr(e); }
add((s == true ? "?." : ".") + f);
case EBinop(op, e1, e2): addType(t);
expr(e1); if( e != null ) {
add(" " + op + " "); add(" = ");
expr(e2); expr(e);
case EUnop(op, pre, e): }
if( pre ) { case EParent(e):
add(op); add("("); expr(e); add(")");
expr(e); case EBlock(el):
} else { if( el.length == 0 ) {
expr(e); add("{}");
add(op); } else {
} tabs += "\t";
case ECall(e, args): add("{\n");
if( e == null ) for( e in el ) {
expr(e); add(tabs);
else switch( Tools.expr(e)) { expr(e);
case EField(_), EIdent(_), EConst(_): add(";\n");
expr(e); }
default: tabs = tabs.substr(1);
add("("); add("}");
expr(e); }
add(")"); case EField(e, f, s):
} expr(e);
add("("); add((s == true ? "?." : ".") + f);
var first = true; case EBinop(op, e1, e2):
for( a in args ) { expr(e1);
if( first ) first = false else add(", "); add(" " + op.toString() + " ");
expr(a); expr(e2);
} case EUnop(op, pre, e):
add(")"); if( pre ) {
case EIf(cond,e1,e2): add(op);
add("if( "); expr(e);
expr(cond); } else {
add(" ) "); expr(e);
expr(e1); add(op);
if( e2 != null ) { }
add(" else "); case ECall(e, args):
expr(e2); if( e == null )
} expr(e);
case EWhile(cond,e): else switch( Tools.expr(e)) {
add("while( "); case EField(_), EIdent(_), EConst(_):
expr(cond); expr(e);
add(" ) "); default:
expr(e); add("(");
case EDoWhile(cond,e): expr(e);
add("do "); add(")");
expr(e); }
add(" while ( "); add("(");
expr(cond); var first = true;
add(" )"); for( a in args ) {
case EFor(v, it, e, ithv): if( first ) first = false else add(", ");
if(ithv != null) expr(a);
add("for( "+ithv+" => "+v+" in "); }
else add(")");
add("for( "+v+" in "); case EIf(cond,e1,e2):
expr(it); add("if( ");
add(" ) "); expr(cond);
expr(e); add(" ) ");
case EBreak: expr(e1);
add("break"); if( e2 != null ) {
case EContinue: add(" else ");
add("continue"); expr(e2);
case EFunction(params, e, name, ret): // TODO: static, public, override }
add("function"); case EWhile(cond,e):
if( name != null ) add("while( ");
add(" " + name); expr(cond);
add("("); add(" ) ");
var first = true; expr(e);
for( a in params ) { case EDoWhile(cond,e):
if( first ) first = false else add(", "); add("do ");
if( a.opt ) add("?"); expr(e);
add(a.name); add(" while ( ");
addType(a.t); expr(cond);
} add(" )");
add(")"); case EFor(v, it, e, ithv):
addType(ret); if(ithv != null)
add(" "); add("for( "+ithv+" => "+v+" in ");
expr(e); else
case EReturn(e): add("for( "+v+" in ");
add("return"); expr(it);
if( e != null ) { add(" ) ");
add(" "); expr(e);
expr(e); case EBreak:
} add("break");
case EArray(e,index): case EContinue:
expr(e); add("continue");
add("["); case EFunction(params, e, name, ret): // TODO: static, public, override
expr(index); add("function");
add("]"); if( name != null )
case EArrayDecl(el, _): add(" " + name);
add("["); add("(");
var first = true; var first = true;
for( e in el ) { for( a in params ) {
if( first ) first = false else add(", "); if( first ) first = false else add(", ");
expr(e); if( a.opt ) add("?");
} add(a.name);
add("]"); addType(a.t);
case ENew(cl, args, params): }
add("new " + cl); add(")");
if(params != null) { addType(ret);
add("<"); add(" ");
var first = true; expr(e);
for( p in params ) { case EReturn(e):
if( first ) first = false else add(", "); add("return");
type(p); if( e != null ) {
} add(" ");
add(">"); expr(e);
} }
add("("); case EArray(e,index):
var first = true; expr(e);
for( e in args ) { add("[");
if( first ) first = false else add(", "); expr(index);
expr(e); add("]");
} case EArrayDecl(el, _):
add(")"); add("[");
case EThrow(e): var first = true;
add("throw "); for( e in el ) {
expr(e); if( first ) first = false else add(", ");
case ETry(e, v, t, ecatch): expr(e);
add("try "); }
expr(e); add("]");
add(" catch( " + v); case ENew(cl, args, params):
addType(t); add("new " + cl);
add(") "); if(params != null) {
expr(ecatch); add("<");
case EObject(fl): var first = true;
if( fl.length == 0 ) { for( p in params ) {
add("{}"); if( first ) first = false else add(", ");
} else { type(p);
tabs += "\t"; }
add("{\n"); add(">");
for( f in fl ) { }
add(tabs); add("(");
add(f.name+" : "); var first = true;
expr(f.e); for( e in args ) {
add(",\n"); if( first ) first = false else add(", ");
} expr(e);
tabs = tabs.substr(1); }
add("}"); add(")");
} case EThrow(e):
case ETernary(c,e1,e2): add("throw ");
expr(c); expr(e);
add(" ? "); case ETry(e, v, t, ecatch):
expr(e1); add("try ");
add(" : "); expr(e);
expr(e2); add(" catch( " + v);
case ESwitch(e, cases, def): addType(t);
add("switch( "); add(") ");
expr(e); expr(ecatch);
add(") {"); case EObject(fl):
for( c in cases ) { if( fl.length == 0 ) {
add("case "); add("{}");
var first = true; } else {
for( v in c.values ) { tabs += "\t";
if( first ) first = false else add(", "); add("{\n");
expr(v); for( f in fl ) {
} add(tabs);
add(": "); add(f.name+" : ");
expr(c.expr); expr(f.e);
add(";\n"); add(",\n");
} }
if( def != null ) { tabs = tabs.substr(1);
add("default: "); add("}");
expr(def); }
add(";\n"); case ETernary(c,e1,e2):
} expr(c);
add("}"); add(" ? ");
case EMeta(name, args, e): expr(e1);
add("@"); add(" : ");
add(name); expr(e2);
if( args != null && args.length > 0 ) { case ESwitch(e, cases, def):
add("("); add("switch( ");
var first = true; expr(e);
for( a in args ) { add(") {");
if( first ) first = false else add(", "); for( c in cases ) {
expr(e); add("case ");
} var first = true;
add(")"); for( v in c.values ) {
} if( first ) first = false else add(", ");
add(" "); expr(v);
expr(e); }
case ECheckType(e, t): add(": ");
add("("); expr(c.expr);
expr(e); add(";\n");
add(" : "); }
addType(t); if( def != null ) {
add(")"); add("default: ");
} expr(def);
} add(";\n");
}
public static function toString( e : Expr ):String { add("}");
return new Printer().exprToString(e); case EMeta(name, args, e):
} add("@");
add(name);
public static function errorToString( e : Expr.Error ):String { if( args != null && args.length > 0 ) {
var message = switch( #if hscriptPos e.e #else e #end ) { add("(");
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")"; var first = true;
case EUnexpected(s): "Unexpected token: \""+s+"\""; for( a in args ) {
case EUnterminatedString: "Unterminated string"; if( first ) first = false else add(", ");
case EUnterminatedComment: "Unterminated comment"; expr(e);
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")"; }
case EUnknownVariable(v): "Unknown variable: "+v; add(")");
case EInvalidIterator(v): "Invalid iterator: "+v; }
case EInvalidOp(op): "Invalid operator: "+op; add(" ");
case EInvalidAccess(f): "Invalid access to field " + f; expr(e);
case ECustom(msg): msg; case ECheckType(e, t):
case EInvalidClass(cla): "Invalid class: " + cla + " was not found."; add("(");
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.'; expr(e);
}; add(" : ");
#if hscriptPos addType(t);
return e.origin + ":" + e.line + ": " + message; add(")");
#else }
return message; }
#end
} 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
}
}
+68 -18
View File
@@ -26,15 +26,33 @@ 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 GET = 'get_';
private static inline var SET = 'set_'; private static inline var SET = 'set_';
public var r:Dynamic; /**
public var getter:FieldPropertyAccess; * Name of the attached field.
public var setter:FieldPropertyAccess; */
public final name:String;
/**
* The current value. If isn't initialized, it's always `null`.
*/
public var r:Dynamic;
/**
* The getter property kind
*/
public final getter:FieldPropertyAccess;
/**
* The setter property kind
*/
public final setter:FieldPropertyAccess;
/**
* If the field is declared as static.
*/
public var isStatic(get, never):Bool; public var isStatic(get, never):Bool;
function get_isStatic() { function get_isStatic() {
return __isStatic && interp.allowStaticVariables; return __isStatic && interp.allowStaticVariables;
@@ -43,7 +61,20 @@ class Property {
var isVar:Bool; var isVar:Bool;
var interp:Interp; var interp:Interp;
public function new(r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic: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;
@@ -52,23 +83,41 @@ class Property {
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;
final __isStatic:Bool = false; final __isStatic:Bool = false;
public function callGetter(name:String) { 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 (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' : ''}'));
} }
@@ -80,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 (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' : ''}'));
} }
@@ -103,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 = isStatic ? interp.staticVariables.get(f) : 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;
@@ -122,7 +172,7 @@ class Property {
return rt; return rt;
} }
private function varExists(n:String) { private inline function varExists(n:String) {
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n); 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);
} }
} }