Compare commits
47
Commits
@@ -1,6 +1,8 @@
|
||||
hscript-improved
|
||||
=======
|
||||
|
||||
- [Features](docs/FEATURES.md)
|
||||
|
||||
How to install
|
||||
```
|
||||
haxelib git hscript-improved https://github.com/CodenameCrew/hscript-improved.git
|
||||
@@ -18,7 +20,9 @@ or set this in build.hxml
|
||||
-D CUSTOM_CLASSES
|
||||
```
|
||||
|
||||
Warning: custom class system is still in development, would like help to test it. For now, you can only override functions from the current class, not from the extended part, like you cant override update in FlxText because FlxText doesnt have a update function overriden. Also you cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
|
||||
Current Custom Class Limitations :
|
||||
|
||||
- You cannot create custom classes that extends a typed class (those ones that has `<T>`), this will be implemented in the future.
|
||||
|
||||
-----------
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# FEATURES
|
||||
|
||||
- Custom Classes
|
||||
- Final Classes
|
||||
- Static Classes
|
||||
- Allow for type check (`is`)
|
||||
- Allow extending other custom classes
|
||||
- Enums
|
||||
|
||||
```haxe
|
||||
enum TypeValue {
|
||||
NUMBER(n:Int);
|
||||
DECIMAL(d:Float, ?p:Int);
|
||||
CHARACTER(s:String);
|
||||
BOOLEAN(b:Bool);
|
||||
}
|
||||
|
||||
var type = TypeValue.DECIMAL(10.1234, 2);
|
||||
// You need to type the full enum field for each case
|
||||
// i.e. you can't type the enum field directly (limitation for now)
|
||||
switch(type) {
|
||||
case TypeValue.NUMBER(number):
|
||||
trace("number: " + number);
|
||||
case TypeValue.DECIMAL(decimal, precision):
|
||||
if(precision != null)
|
||||
trace("decimal: " + decimal + " | rounded decimal: " + roundDecimal(decimal, precision));
|
||||
else
|
||||
trace("decimal: " + decimal);
|
||||
case TypeValue.CHARACTER(char):
|
||||
trace("character: " + char);
|
||||
default:
|
||||
trace("unknown type");
|
||||
}
|
||||
|
||||
function roundDecimal(Value:Float, Precision:Int) {
|
||||
var mult:Float = Math.pow(10, Precision);
|
||||
return Math.fround(Value * mult) / mult;
|
||||
}
|
||||
```
|
||||
|
||||
- Enum matching with arguments for switch statements (for real and scripted enums)
|
||||
- Property Fields (`(get, set)` variables)
|
||||
|
||||
```haxe
|
||||
public var myvar(get, set):Int;
|
||||
var _myvar:Int = 10;
|
||||
|
||||
function get_myvar():Int {
|
||||
return _myvar;
|
||||
}
|
||||
|
||||
function set_myvar(val:Int):Int {
|
||||
if(val > 10) return _myvar = val;
|
||||
return val;
|
||||
}
|
||||
```
|
||||
|
||||
- `@:isVar` metadata support
|
||||
|
||||
- Static extension (`using`)
|
||||
|
||||
```haxe
|
||||
using StringTools;
|
||||
|
||||
class IntExtender {
|
||||
static public function triple(i:Int) {
|
||||
return i * 3;
|
||||
}
|
||||
}
|
||||
|
||||
// need to create/import the custom class
|
||||
// before setting the extension (limitation for now)
|
||||
using IntExtender;
|
||||
|
||||
var str = " Hello World! ";
|
||||
trace(str.trim()); // "Hello World!"
|
||||
trace(12.triple()); // 36
|
||||
```
|
||||
|
||||
- Support for real and custom classes
|
||||
- Misc.
|
||||
- Allow using type parameters for creating objects (i.e. `var a = new TypedObject<Int>();`)
|
||||
- Allow `package` declaration. Ignored by the interpreter.
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "hscript",
|
||||
"name": "hscript-improved",
|
||||
"url": "https://github.com/HaxeFoundation/hscript",
|
||||
"license": "MIT",
|
||||
"description": "Haxe Script is a scripting engine for a subset of the Haxe language",
|
||||
|
||||
+536
-536
File diff suppressed because it is too large
Load Diff
+8
-4
@@ -124,6 +124,8 @@ class Bytes {
|
||||
#end
|
||||
bout.addByte(Type.enumIndex(e));
|
||||
switch( e ) {
|
||||
case EPackage(n):
|
||||
// TODO
|
||||
case EImport(c):
|
||||
// TODO
|
||||
case EClass(_, _, _, _):
|
||||
@@ -132,6 +134,8 @@ class Bytes {
|
||||
// TODO
|
||||
case ECast(e, _):
|
||||
// TODO
|
||||
case ERegex(e, f):
|
||||
// TODO
|
||||
case EConst(c):
|
||||
doEncodeConst(c);
|
||||
case EIdent(v):
|
||||
@@ -152,11 +156,11 @@ class Bytes {
|
||||
doEncode(e);
|
||||
doEncodeString(f);
|
||||
case EBinop(op,e1,e2):
|
||||
doEncodeString(op);
|
||||
doEncodeString(op.toString());
|
||||
doEncode(e1);
|
||||
doEncode(e2);
|
||||
case EUnop(op,prefix,e):
|
||||
doEncodeString(op);
|
||||
doEncodeString(op.toString()); // maybe doEncodeInt
|
||||
bout.addByte(prefix?1:0);
|
||||
doEncode(e);
|
||||
case ECall(e,el):
|
||||
@@ -274,11 +278,11 @@ class Bytes {
|
||||
var e = doDecode();
|
||||
EField(e,doDecodeString());
|
||||
case 6:
|
||||
var op = doDecodeString();
|
||||
var op = Binop.fromString(doDecodeString());
|
||||
var e1 = doDecode();
|
||||
EBinop(op,e1,doDecode());
|
||||
case 7:
|
||||
var op = doDecodeString();
|
||||
var op = Unop.fromString(doDecodeString());
|
||||
var prefix = bin.get(pin++) != 0;
|
||||
EUnop(op,prefix,doDecode());
|
||||
case 8:
|
||||
|
||||
+30
-16
@@ -1073,10 +1073,10 @@ class Checker {
|
||||
case EUnop(op, _, e):
|
||||
var et = typeExpr(e, Value);
|
||||
switch( op ) {
|
||||
case "++", "--", "-":
|
||||
case OpIncrement | OpDecrement | OpNeg:
|
||||
unify(et,TInt,e);
|
||||
return et;
|
||||
case "!":
|
||||
case OpNot:
|
||||
unify(et,TBool,e);
|
||||
return et;
|
||||
default:
|
||||
@@ -1113,11 +1113,11 @@ class Checker {
|
||||
return TVoid;
|
||||
case EBinop(op, e1, e2):
|
||||
switch( op ) {
|
||||
case "&", "|", "^", ">>", ">>>", "<<":
|
||||
case OpAnd, OpOr, OpXor, OpShr, OpUshr, OpShl:
|
||||
typeExprWith(e1,TInt);
|
||||
typeExprWith(e2,TInt);
|
||||
return TInt;
|
||||
case "=":
|
||||
case OpAssign:
|
||||
if( allowDefine ) {
|
||||
switch( edef(e1) ) {
|
||||
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
|
||||
@@ -1133,7 +1133,7 @@ class Checker {
|
||||
}
|
||||
typeExprWith(e2,vt);
|
||||
return vt;
|
||||
case "+":
|
||||
case OpAdd:
|
||||
var t1 = typeExpr(e1,WithType(TInt));
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
tryUnify(t1,t2);
|
||||
@@ -1150,14 +1150,14 @@ class Checker {
|
||||
unify(t1, TFloat, e1);
|
||||
unify(t2, TFloat, e2);
|
||||
}
|
||||
case "-", "*", "/", "%":
|
||||
case OpSub, OpMult, OpDiv, OpMod:
|
||||
var t1 = typeExpr(e1,WithType(TInt));
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
if( !tryUnify(t1,t2) )
|
||||
unify(t2,t1,e2);
|
||||
switch( [follow(t1), follow(t2)]) {
|
||||
case [TInt, TInt]:
|
||||
if( op == "/" ) return TFloat;
|
||||
if( op == OpDiv ) return TFloat;
|
||||
return TInt;
|
||||
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
|
||||
return TFloat;
|
||||
@@ -1165,21 +1165,21 @@ class Checker {
|
||||
unify(t1, TFloat, e1);
|
||||
unify(t2, TFloat, e2);
|
||||
}
|
||||
case "&&", "||":
|
||||
case OpBoolAnd, OpBoolOr:
|
||||
typeExprWith(e1,TBool);
|
||||
typeExprWith(e2,TBool);
|
||||
return TBool;
|
||||
case "...":
|
||||
case OpInterval:
|
||||
typeExprWith(e1,TInt);
|
||||
typeExprWith(e2,TInt);
|
||||
return makeIterator(TInt);
|
||||
case "==", "!=":
|
||||
case OpEq, OpNeq:
|
||||
var t1 = typeExpr(e1,Value);
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
if( !tryUnify(t1,t2) )
|
||||
unify(t2,t1,e2);
|
||||
return TBool;
|
||||
case ">", "<", ">=", "<=":
|
||||
case OpGt, OpLt, OpGte, OpLte:
|
||||
var t1 = typeExpr(e1,Value);
|
||||
var t2 = typeExpr(e2,WithType(t1));
|
||||
if( !tryUnify(t1,t2) )
|
||||
@@ -1190,12 +1190,26 @@ class Checker {
|
||||
error("Cannot compare "+typeStr(t1), expr);
|
||||
}
|
||||
return TBool;
|
||||
case OpAddAssign, OpSubAssign, OpMultAssign, OpDivAssign, OpModAssign, OpAndAssign, OpOrAssign, OpXorAssign, OpShlAssign, OpShrAssign, OpUshrAssign, OpNcoalAssign:
|
||||
var baseOp = switch(op) {
|
||||
case OpAddAssign: OpAdd;
|
||||
case OpSubAssign: OpSub;
|
||||
case OpMultAssign: OpMult;
|
||||
case OpDivAssign: OpDiv;
|
||||
case OpModAssign: OpMod;
|
||||
case OpAndAssign: OpAnd;
|
||||
case OpOrAssign: OpOr;
|
||||
case OpXorAssign: OpXor;
|
||||
case OpShlAssign: OpShl;
|
||||
case OpShrAssign: OpShr;
|
||||
case OpUshrAssign: OpUshr;
|
||||
case OpNcoalAssign: OpNcoal;
|
||||
default: op;
|
||||
};
|
||||
var t = typeExpr(mk(EBinop(baseOp,e1,e2),expr),withType);
|
||||
return typeExpr(mk(EBinop(OpAssign,e1,e2),expr), withType);
|
||||
default:
|
||||
if( op.charCodeAt(op.length-1) == "=".code ) {
|
||||
var t = typeExpr(mk(EBinop(op.substr(0,op.length-1),e1,e2),expr),withType);
|
||||
return typeExpr(mk(EBinop("=",e1,e2),expr), withType);
|
||||
}
|
||||
error("Unsupported operation "+op, expr);
|
||||
error("Unsupported operation "+op.toString(), expr);
|
||||
}
|
||||
case ETry(etry, v, et, ecatch):
|
||||
var vt = typeExpr(etry, withType);
|
||||
|
||||
+37
-21
@@ -13,7 +13,6 @@ using Lambda;
|
||||
* @author Jamextreme140
|
||||
*/
|
||||
@:access(hscript.CustomClassHandler)
|
||||
@:access(hscript.Property)
|
||||
class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
public var className(get, never):String;
|
||||
|
||||
@@ -48,6 +47,12 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
__interp.staticVariables = __class.ogInterp.staticVariables;
|
||||
__interp.customClasses = __class.ogInterp.customClasses;
|
||||
|
||||
for(f => v in __class.__interp.variables) {
|
||||
if(f == 'new') continue;
|
||||
if (!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
}
|
||||
|
||||
for (f in __class.fields) {
|
||||
switch (Tools.expr(f)) {
|
||||
case EVar(n): __class__fields.push(n);
|
||||
@@ -59,11 +64,6 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
@:privateAccess __interp.exprReturn(f);
|
||||
}
|
||||
|
||||
for (f => v in __class.__interp.variables) {
|
||||
if (!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
}
|
||||
|
||||
__interp.scriptObject = this;
|
||||
|
||||
initializing = true;
|
||||
@@ -124,25 +124,40 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
if(__cachedFieldSet != null)
|
||||
UnsafeReflect.setField(__class.cl, "__cachedFieldSet", __cachedFieldSet);
|
||||
|
||||
var disallowCopy = Type.getInstanceFields(__class.cl);
|
||||
__superClass = Type.createInstance(__class.cl, args);
|
||||
__superClass.__real_fields = disallowCopy;
|
||||
var disallowCopy:Array<String> = {
|
||||
var fieldMap:Map<String, String> = []; // Prevent duplicate values
|
||||
for(f in Reflect.fields(__superClass).concat(Type.getInstanceFields(Type.getClass(__superClass))))
|
||||
fieldMap.set(f, f);
|
||||
|
||||
fieldMap.array();
|
||||
}
|
||||
this.__real_fields = disallowCopy;
|
||||
@:privateAccess __interp.__instanceFields = __interp.__instanceFields.concat(disallowCopy);
|
||||
__superClass.__real_fields = this.__real_fields;
|
||||
__superClass.__class__fields = this.__class__fields;
|
||||
__superClass.__interp = this.__interp;
|
||||
}
|
||||
}
|
||||
|
||||
public function call(name:String, ?args:Array<Dynamic>, ?toSuper:Bool = false):Dynamic {
|
||||
// TODO: optimize this
|
||||
var fnName = toSuper ? '_HX_SUPER__$name' : name;
|
||||
var fn:Dynamic = __interp.variables.get(fnName);
|
||||
if(toSuper && fn == null)
|
||||
fn = __interp.variables.get(name);
|
||||
var superFnName:Null<String> = toSuper ? '_HX_SUPER__$name' : null;
|
||||
var fn:Dynamic = {
|
||||
if(toSuper && __interp.variables.exists(superFnName)) {
|
||||
__interp.variables.get(superFnName);
|
||||
}
|
||||
else
|
||||
__interp.variables.get(name);
|
||||
};
|
||||
|
||||
if (fn != null && Reflect.isFunction(fn))
|
||||
return UnsafeReflect.callMethodUnsafe(null, fn, (args == null) ? [] : args);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -158,9 +173,9 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
var f = __interp.variables.get(name);
|
||||
if (f != null && allowProperty && f is Property) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callGetter(name);
|
||||
prop.__allowSetGet = null;
|
||||
//prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.get(!__allowSetGet);
|
||||
//prop.__allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
return f;
|
||||
@@ -170,9 +185,9 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
var f = getField(name, false);
|
||||
if (f != null && f is Property) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callSetter(name, val);
|
||||
prop.__allowSetGet = null;
|
||||
//prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.set(val, !__allowSetGet);
|
||||
//prop.__allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
__interp.variables.set(name, val);
|
||||
@@ -338,6 +353,7 @@ class CustomClass implements IHScriptCustomClassBehaviour {
|
||||
return cls;
|
||||
}
|
||||
|
||||
// TODO: scriptable "toString" function
|
||||
public function toString():String
|
||||
return className;
|
||||
}
|
||||
|
||||
@@ -56,39 +56,35 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
||||
__interp.staticVariables = ogInterp.staticVariables;
|
||||
__interp.customClasses = ogInterp.customClasses;
|
||||
|
||||
for(e in fields.copy()) {
|
||||
var validField:Bool = false;
|
||||
for(f => v in ogInterp.variables)
|
||||
if(!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
|
||||
for(i => e in fields.copy()) {
|
||||
var isValid:Bool = false;
|
||||
var staticField:Bool = false;
|
||||
var fieldName:String = "";
|
||||
var fieldName:String = null;
|
||||
switch (Tools.expr(e)) {
|
||||
case EVar(n, _, _, _, isStatic):
|
||||
validField = true;
|
||||
staticField = isStatic;
|
||||
fieldName = n;
|
||||
case EFunction(_, _, n, _, _, isStatic, _, _, _, _):
|
||||
validField = true;
|
||||
case EVar(n, _, _, _, isStatic) | EFunction(_, _, n, _, _, isStatic):
|
||||
isValid = true;
|
||||
staticField = isStatic;
|
||||
fieldName = n;
|
||||
default:
|
||||
}
|
||||
|
||||
if(staticField && validField) {
|
||||
if(staticField && isValid) {
|
||||
__interp.exprReturn(e);
|
||||
__staticFields.push(fieldName);
|
||||
fields.remove(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(f => v in ogInterp.variables)
|
||||
if(!__interp.variables.exists(f))
|
||||
__interp.variables.set(f, v);
|
||||
}
|
||||
|
||||
public function hnew(args:Array<Dynamic>):Dynamic
|
||||
return new CustomClass(this, args);
|
||||
|
||||
@:allow(hscript.Interp)
|
||||
function hasField(name:String) {
|
||||
inline function hasField(name:String) {
|
||||
return __staticFields.contains(name);
|
||||
}
|
||||
|
||||
@@ -96,9 +92,9 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
||||
var f = __interp.variables.get(name);
|
||||
if(f is Property && allowProperty) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callGetter(name);
|
||||
prop.__allowSetGet = null;
|
||||
//prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.get(!__allowSetGet);
|
||||
//prop.__allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
return f;
|
||||
@@ -108,9 +104,9 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
||||
var f = getField(name, false);
|
||||
if(f is Property) {
|
||||
var prop:Property = cast f;
|
||||
prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.callSetter(name, val);
|
||||
prop.__allowSetGet = null;
|
||||
//prop.__allowSetGet = this.__allowSetGet;
|
||||
var r = prop.set(val, !__allowSetGet);
|
||||
//prop.__allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
__interp.variables.set(name, val);
|
||||
@@ -118,6 +114,12 @@ class CustomClassHandler implements IHScriptCustomConstructor implements IHScrip
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
if(name == 'new') {
|
||||
return Reflect.makeVarArgs(function(args:Array<Dynamic>):Dynamic {
|
||||
return inline this.hnew(args);
|
||||
});
|
||||
}
|
||||
|
||||
if(hasField(name)) {
|
||||
return getField(name);
|
||||
}
|
||||
|
||||
+403
-242
@@ -1,242 +1,403 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||
|
||||
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||
|
||||
enum Const {
|
||||
CInt( v : Int );
|
||||
CFloat( f : Float );
|
||||
CString( s : String );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
@:structInit
|
||||
final class Expr {
|
||||
public var e : ExprDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : String, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<ObjectField> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
|
||||
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||
ECast(e:Expr, ?t:CType);
|
||||
}
|
||||
|
||||
@: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>;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class EnumField {
|
||||
public var name : String;
|
||||
public var args : Array<Argument>;
|
||||
}
|
||||
|
||||
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>;
|
||||
}
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||
|
||||
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||
|
||||
enum abstract Binop(Int) from Int to Int {
|
||||
var OpAdd = 0;
|
||||
var OpSub = 1;
|
||||
var OpMult = 2;
|
||||
var OpDiv = 3;
|
||||
var OpMod = 4;
|
||||
var OpAnd = 5;
|
||||
var OpOr = 6;
|
||||
var OpXor = 7;
|
||||
var OpShl = 8;
|
||||
var OpShr = 9;
|
||||
var OpUshr = 10;
|
||||
var OpEq = 11;
|
||||
var OpNeq = 12;
|
||||
var OpGte = 13;
|
||||
var OpLte = 14;
|
||||
var OpGt = 15;
|
||||
var OpLt = 16;
|
||||
var OpBoolOr = 17;
|
||||
var OpBoolAnd = 18;
|
||||
var OpIs = 19;
|
||||
var OpAssign = 20;
|
||||
var OpNcoal = 21;
|
||||
var OpInterval = 22;
|
||||
var OpArrow = 23;
|
||||
var OpAddAssign = 24;
|
||||
var OpSubAssign = 25;
|
||||
var OpMultAssign = 26;
|
||||
var OpDivAssign = 27;
|
||||
var OpModAssign = 28;
|
||||
var OpAndAssign = 29;
|
||||
var OpOrAssign = 30;
|
||||
var OpXorAssign = 31;
|
||||
var OpShlAssign = 32;
|
||||
var OpShrAssign = 33;
|
||||
var OpUshrAssign = 34;
|
||||
var OpNcoalAssign = 35;
|
||||
var OpArrowFn = 36;
|
||||
|
||||
public static inline function fromString(s:String):Binop {
|
||||
return switch(s) {
|
||||
case "+": OpAdd;
|
||||
case "-": OpSub;
|
||||
case "*": OpMult;
|
||||
case "/": OpDiv;
|
||||
case "%": OpMod;
|
||||
case "&": OpAnd;
|
||||
case "|": OpOr;
|
||||
case "^": OpXor;
|
||||
case "<<": OpShl;
|
||||
case ">>": OpShr;
|
||||
case ">>>": OpUshr;
|
||||
case "==": OpEq;
|
||||
case "!=": OpNeq;
|
||||
case ">=": OpGte;
|
||||
case "<=": OpLte;
|
||||
case ">": OpGt;
|
||||
case "<": OpLt;
|
||||
case "||": OpBoolOr;
|
||||
case "&&": OpBoolAnd;
|
||||
case "is": OpIs;
|
||||
case "=": OpAssign;
|
||||
case "??": OpNcoal;
|
||||
case "...": OpInterval;
|
||||
case "->": OpArrow;
|
||||
case "=>": OpArrowFn;
|
||||
case "+=": OpAddAssign;
|
||||
case "-=": OpSubAssign;
|
||||
case "*=": OpMultAssign;
|
||||
case "/=": OpDivAssign;
|
||||
case "%=": OpModAssign;
|
||||
case "&=": OpAndAssign;
|
||||
case "|=": OpOrAssign;
|
||||
case "^=": OpXorAssign;
|
||||
case "<<=": OpShlAssign;
|
||||
case ">>=": OpShrAssign;
|
||||
case ">>>=": OpUshrAssign;
|
||||
case _ if (s == "??" + "="): OpNcoalAssign;
|
||||
default: -1;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function toString():String {
|
||||
return switch(this) {
|
||||
case OpAdd: "+";
|
||||
case OpSub: "-";
|
||||
case OpMult: "*";
|
||||
case OpDiv: "/";
|
||||
case OpMod: "%";
|
||||
case OpAnd: "&";
|
||||
case OpOr: "|";
|
||||
case OpXor: "^";
|
||||
case OpShl: "<<";
|
||||
case OpShr: ">>";
|
||||
case OpUshr: ">>>";
|
||||
case OpEq: "==";
|
||||
case OpNeq: "!=";
|
||||
case OpGte: ">=";
|
||||
case OpLte: "<=";
|
||||
case OpGt: ">";
|
||||
case OpLt: "<";
|
||||
case OpBoolOr: "||";
|
||||
case OpBoolAnd: "&&";
|
||||
case OpIs: "is";
|
||||
case OpAssign: "=";
|
||||
case OpNcoal: "??";
|
||||
case OpInterval: "...";
|
||||
case OpArrow: "->";
|
||||
case OpArrowFn: "=>";
|
||||
case OpAddAssign: "+=";
|
||||
case OpSubAssign: "-=";
|
||||
case OpMultAssign: "*=";
|
||||
case OpDivAssign: "/=";
|
||||
case OpModAssign: "%=";
|
||||
case OpAndAssign: "&=";
|
||||
case OpOrAssign: "|=";
|
||||
case OpXorAssign: "^=";
|
||||
case OpShlAssign: "<<=";
|
||||
case OpShrAssign: ">>=";
|
||||
case OpUshrAssign: ">>>=";
|
||||
case OpNcoalAssign: "??" + "=";
|
||||
default: "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum abstract Unop(Int) from Int to Int {
|
||||
var OpNot = 0;
|
||||
var OpNeg = 1;
|
||||
var OpIncrement = 2;
|
||||
var OpDecrement = 3;
|
||||
var OpNegBits = 4;
|
||||
|
||||
public static inline function fromString(s:String):Unop {
|
||||
return switch(s) {
|
||||
case "!": OpNot;
|
||||
case "-": OpNeg;
|
||||
case "++": OpIncrement;
|
||||
case "--": OpDecrement;
|
||||
case "~": OpNegBits;
|
||||
default: -1;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function toString():String {
|
||||
return switch(this) {
|
||||
case OpNot: "!";
|
||||
case OpNeg: "-";
|
||||
case OpIncrement: "++";
|
||||
case OpDecrement: "--";
|
||||
case OpNegBits: "~";
|
||||
default: "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||
|
||||
enum Const {
|
||||
CInt( v : Int );
|
||||
CFloat( f : Float );
|
||||
CString( s : String, ?i : Bool );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
@:structInit
|
||||
final class Expr {
|
||||
public var e : ExprDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : Binop, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : Unop, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<ObjectField> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
|
||||
EPackage( ?n:String );
|
||||
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||
ECast(e:Expr, ?t:CType);
|
||||
ERegex(e:String, flags:String);
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class ObjectField {
|
||||
public var name : String;
|
||||
public var e : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class SwitchCase {
|
||||
public var values : Array<Expr>;
|
||||
public var expr : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class Argument {
|
||||
public var name : String;
|
||||
public var t : CType;
|
||||
public var opt : Bool;
|
||||
public var value : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class MetadataEntry {
|
||||
public var name : String;
|
||||
public var params : Array<Expr>;
|
||||
}
|
||||
|
||||
typedef Metadata = Array<MetadataEntry>;
|
||||
|
||||
@:structInit
|
||||
final class EnumDecl {
|
||||
public var name : String;
|
||||
public var fields : Array<EnumField>;
|
||||
public var underlyingType : Null<CType>;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class EnumField {
|
||||
public var name : String;
|
||||
public var args : Array<Argument>;
|
||||
public var value : Null<Expr>;
|
||||
}
|
||||
|
||||
enum CType {
|
||||
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||
CTFun( args : Array<CType>, ret : CType );
|
||||
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||
CTParent( t : CType );
|
||||
CTOpt( t : CType );
|
||||
CTNamed( n : String, t : CType );
|
||||
CTExpr( e : Expr ); // for type parameters only
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
class Error {
|
||||
public var e : ErrorDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
public function new(e, pmin, pmax, origin, line) {
|
||||
this.e = e;
|
||||
this.pmin = pmin;
|
||||
this.pmax = pmax;
|
||||
this.origin = origin;
|
||||
this.line = line;
|
||||
}
|
||||
public function toString(): String {
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ErrorDef {
|
||||
#else
|
||||
enum Error {
|
||||
#end
|
||||
EInvalidChar( c : Int );
|
||||
EUnexpected( s : String );
|
||||
EUnterminatedString;
|
||||
EUnterminatedComment;
|
||||
EInvalidPreprocessor( msg : String );
|
||||
EUnknownVariable( v : String );
|
||||
EInvalidIterator( v : String );
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String );
|
||||
ECustom( msg : String );
|
||||
EInvalidClass( className : String);
|
||||
EAlreadyExistingClass( className : String);
|
||||
}
|
||||
|
||||
|
||||
enum ModuleDecl {
|
||||
DPackage( path : Array<String> );
|
||||
DImport( path : Array<String>, ?everything : Bool );
|
||||
DClass( c : ClassDecl );
|
||||
DTypedef( c : TypeDecl );
|
||||
}
|
||||
|
||||
typedef ModuleType = {
|
||||
var name : String;
|
||||
var params : {}; // TODO : not yet parsed
|
||||
var meta : Metadata;
|
||||
var isPrivate : Bool;
|
||||
}
|
||||
|
||||
typedef ClassDecl = {> ModuleType,
|
||||
var extend : Null<CType>;
|
||||
var implement : Array<CType>;
|
||||
var fields : Array<FieldDecl>;
|
||||
var isExtern : Bool;
|
||||
}
|
||||
|
||||
typedef TypeDecl = {> ModuleType,
|
||||
var t : CType;
|
||||
}
|
||||
|
||||
typedef FieldDecl = {
|
||||
var name : String;
|
||||
var meta : Metadata;
|
||||
var kind : FieldKind;
|
||||
var access : Array<FieldAccess>;
|
||||
}
|
||||
|
||||
enum abstract FieldAccess(UInt8) {
|
||||
var APublic;
|
||||
var APrivate;
|
||||
var AInline;
|
||||
var AOverride;
|
||||
var AStatic;
|
||||
var AMacro;
|
||||
}
|
||||
|
||||
enum abstract FieldPropertyAccess(UInt8) {
|
||||
var ADefault;
|
||||
var ANull;
|
||||
var AGet;
|
||||
var ASet;
|
||||
var ADynamic;
|
||||
var ANever;
|
||||
}
|
||||
|
||||
enum FieldKind {
|
||||
KFunction( f : FunctionDecl );
|
||||
KVar( v : VarDecl );
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class FunctionDecl {
|
||||
public var args : Array<Argument>;
|
||||
public var body : Expr;
|
||||
public var ret : Null<CType>;
|
||||
}
|
||||
|
||||
typedef VarDecl = {
|
||||
var get : Null<String>;
|
||||
var set : Null<String>;
|
||||
var expr : Null<Expr>;
|
||||
var type : Null<CType>;
|
||||
}
|
||||
|
||||
+119
-3
@@ -2,13 +2,13 @@ package hscript;
|
||||
|
||||
import hscript.utils.UnsafeReflect;
|
||||
|
||||
// TODO: EnumTools for scripted enums
|
||||
/**
|
||||
* Wrapper class for enums, both for real and scripted.
|
||||
* Use EnumTools and EnumValueTools for enum operations.
|
||||
*/
|
||||
@:structInit
|
||||
class HEnum implements IHScriptCustomBehaviour {
|
||||
private var enumValues(default, null) = {};
|
||||
var enumValues(default, null) = {};
|
||||
|
||||
public function setEnum(name:String, enumValue:Dynamic):Void {
|
||||
UnsafeReflect.setField(enumValues, name, enumValue);
|
||||
@@ -20,6 +20,10 @@ class HEnum implements IHScriptCustomBehaviour {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getEnumValues():Dynamic {
|
||||
return enumValues;
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
return getEnum(name);
|
||||
}
|
||||
@@ -57,10 +61,122 @@ class HEnumValue {
|
||||
if (args.length != other.args.length)
|
||||
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])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@:nullSafety
|
||||
class EnumTools {
|
||||
public static function getConstructors(e:Dynamic):Array<String> {
|
||||
if(Std.isOfType(e, HEnum)) {
|
||||
var henum:HEnum = cast e;
|
||||
return UnsafeReflect.fields(henum.getEnumValues());
|
||||
}
|
||||
return Type.getEnumConstructs(cast e);
|
||||
}
|
||||
|
||||
public static function createByName(e:Dynamic, constr:String, ?params:Array<Dynamic>):Dynamic {
|
||||
if(Std.isOfType(e, HEnum)) {
|
||||
var henum:HEnum = cast e;
|
||||
var constructor = henum.getEnum(constr);
|
||||
if(constructor == null)
|
||||
throw 'Constructor $constr not found in enum';
|
||||
if(Std.isOfType(constructor, HEnumValue))
|
||||
return constructor;
|
||||
if(Reflect.isFunction(constructor))
|
||||
return constructor(params == null ? [] : params);
|
||||
throw 'Invalid constructor type';
|
||||
}
|
||||
return Type.createEnum(cast e, constr, params);
|
||||
}
|
||||
|
||||
public static function createByIndex(e:Dynamic, index:Int, ?params:Array<Dynamic>):Dynamic {
|
||||
if(Std.isOfType(e, HEnum)) {
|
||||
var constructors = getConstructors(e);
|
||||
if(index < 0 || index >= constructors.length)
|
||||
throw 'Index $index out of bounds for enum';
|
||||
return createByName(e, constructors[index], params);
|
||||
}
|
||||
return Type.createEnumIndex(cast e, index, params);
|
||||
}
|
||||
}
|
||||
|
||||
@:nullSafety
|
||||
class EnumValueTools {
|
||||
public static function getType(e:Dynamic):Null<String> {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.enumName;
|
||||
}
|
||||
var en = Type.getEnum(e);
|
||||
if(en != null)
|
||||
return Type.getEnumName(en);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getName(e:Dynamic):String {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.fieldName;
|
||||
}
|
||||
return Type.enumConstructor(e);
|
||||
}
|
||||
|
||||
public static function getParameters(e:Dynamic):Array<Dynamic> {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.args.copy();
|
||||
}
|
||||
return Type.enumParameters(e);
|
||||
}
|
||||
|
||||
public static function getIndex(e:Dynamic):Int {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.index;
|
||||
}
|
||||
return Type.enumIndex(e);
|
||||
}
|
||||
|
||||
public static function equals(a:Dynamic, b:Dynamic):Bool {
|
||||
if(Std.isOfType(a, HEnumValue) && Std.isOfType(b, HEnumValue)) {
|
||||
var hva:HEnumValue = cast a;
|
||||
var hvb:HEnumValue = cast b;
|
||||
return hva.compare(hvb);
|
||||
}
|
||||
return Type.enumEq(a, b);
|
||||
}
|
||||
|
||||
public static function match(e:Dynamic, pattern:Dynamic):Bool {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
if(Std.isOfType(pattern, HEnumValue)) {
|
||||
var hp:HEnumValue = cast pattern;
|
||||
if(hv.enumName != hp.enumName || hv.fieldName != hp.fieldName)
|
||||
return false;
|
||||
if(hp.args.length == 0)
|
||||
return true;
|
||||
if(hv.args.length != hp.args.length)
|
||||
return false;
|
||||
for(i in 0...hp.args.length) {
|
||||
var pa = hp.args[i];
|
||||
if(pa != null && hv.args[i] != pa)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(Reflect.isObject(pattern)) {
|
||||
var patternName = UnsafeReflect.hasField(pattern, "name") ? UnsafeReflect.field(pattern, "name") : null;
|
||||
if(patternName != null && patternName != hv.fieldName)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return Type.enumEq(e, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
+514
-296
File diff suppressed because it is too large
Load Diff
+5
-4
@@ -151,12 +151,13 @@ class Macro {
|
||||
case EField(e, f):
|
||||
EField(convert(e), f);
|
||||
case EBinop(op, e1, e2):
|
||||
var b = binops.get(op);
|
||||
if( b == null ) throw EInvalidOp(op);
|
||||
var b = binops.get(op.toString());
|
||||
if( b == null ) throw EInvalidOp(op.toString());
|
||||
EBinop(b, convert(e1), convert(e2));
|
||||
case EUnop(op, prefix, e):
|
||||
var u = unops.get(op);
|
||||
if( u == null ) throw EInvalidOp(op);
|
||||
var opStr = op.toString();
|
||||
var u = unops.get(opStr);
|
||||
if( u == null ) throw EInvalidOp(opStr);
|
||||
EUnop(u, !prefix, convert(e));
|
||||
case ECall(e, params):
|
||||
ECall(convert(e), map(params, convert));
|
||||
|
||||
+391
-172
@@ -43,6 +43,7 @@ enum Token {
|
||||
TDoubleDot;
|
||||
TMeta( s : String );
|
||||
TPrepro( s : String );
|
||||
TRegex( e : String, f:String );
|
||||
}
|
||||
|
||||
@:structInit
|
||||
@@ -72,6 +73,11 @@ class Parser {
|
||||
**/
|
||||
public var allowJSON : Bool;
|
||||
|
||||
/**
|
||||
activate Regular Expression parsing
|
||||
**/
|
||||
public var allowRegex : Bool;
|
||||
|
||||
/**
|
||||
allow types declarations
|
||||
**/
|
||||
@@ -115,6 +121,8 @@ class Parser {
|
||||
|
||||
#end
|
||||
|
||||
static inline var regexFlags: String = "igmsu";
|
||||
|
||||
public function new() {
|
||||
line = 1;
|
||||
opChars = "+*/-=!><&|^%~";
|
||||
@@ -207,7 +215,7 @@ class Parser {
|
||||
return null;
|
||||
}
|
||||
|
||||
inline function push(tk: Token):Void {
|
||||
@:analyzer(fusion) inline function push(tk: Token):Void {
|
||||
#if hscriptPos
|
||||
tokens.push( { t : tk, min : tokenMin, max : tokenMax } );
|
||||
tokenMin = oldTokenMin;
|
||||
@@ -217,17 +225,17 @@ class Parser {
|
||||
#end
|
||||
}
|
||||
|
||||
inline function ensure(tk:Token):Void {
|
||||
@:analyzer(fusion) inline function ensure(tk:Token):Void {
|
||||
var t = token();
|
||||
if( t != tk ) unexpected(t);
|
||||
}
|
||||
|
||||
inline function ensureToken(tk:Token):Void {
|
||||
@:analyzer(fusion) inline function ensureToken(tk:Token):Void {
|
||||
var t = token();
|
||||
if( !Type.enumEq(t,tk) ) unexpected(t);
|
||||
}
|
||||
|
||||
function maybe(tk:Token):Bool {
|
||||
@:analyzer(fusion) inline function maybe(tk:Token):Bool {
|
||||
var t = token();
|
||||
if( Type.enumEq(t, tk) )
|
||||
return true;
|
||||
@@ -245,7 +253,7 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
inline function expr(e:Expr):#if hscriptPos ExprDef #else Expr #end {
|
||||
@:analyzer(fusion) inline function expr(e:Expr):#if hscriptPos ExprDef #else Expr #end {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#else
|
||||
@@ -253,7 +261,7 @@ class Parser {
|
||||
#end
|
||||
}
|
||||
|
||||
inline function pmin(e:Expr):Int {
|
||||
@:analyzer(fusion) inline function pmin(e:Expr):Int {
|
||||
#if hscriptPos
|
||||
return e == null ? 0 : e.pmin;
|
||||
#else
|
||||
@@ -261,7 +269,7 @@ class Parser {
|
||||
#end
|
||||
}
|
||||
|
||||
inline function pmax(e:Expr):Int {
|
||||
@:analyzer(fusion) inline function pmax(e:Expr):Int {
|
||||
#if hscriptPos
|
||||
return e == null ? 0 : e.pmax;
|
||||
#else
|
||||
@@ -269,7 +277,7 @@ class Parser {
|
||||
#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( e == null ) return null;
|
||||
if( pmin == null ) pmin = tokenMin;
|
||||
@@ -280,7 +288,7 @@ class Parser {
|
||||
#end
|
||||
}
|
||||
|
||||
function isBlock(e:Expr):Bool {
|
||||
@:analyzer(fusion) inline function isBlock(e:Expr):Bool {
|
||||
if( e == null ) return false;
|
||||
return switch( expr(e) ) {
|
||||
case EBlock(_), EObject(_), ESwitch(_), EEnum(_, _): true;
|
||||
@@ -300,7 +308,7 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
function parseFullExpr( exprs : Array<Expr> ):Void {
|
||||
@:analyzer(fusion) function parseFullExpr( exprs : Array<Expr> ):Void {
|
||||
var e = parseExpr();
|
||||
exprs.push(e);
|
||||
|
||||
@@ -332,7 +340,7 @@ class Parser {
|
||||
if( !allowJSON )
|
||||
unexpected(tk);
|
||||
switch( c ) {
|
||||
case CString(s): id = s;
|
||||
case CString(s, _): id = s;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
case TBrClose:
|
||||
@@ -363,12 +371,17 @@ class Parser {
|
||||
var p1 = tokenMin;
|
||||
#end
|
||||
switch( tk ) {
|
||||
case TId(id): // TODO: direct access to classes by typing their path
|
||||
case TId(id):
|
||||
var e = parseStructure(id, oldPos);
|
||||
if( e == null )
|
||||
e = mk(EIdent(id));
|
||||
return parseExprNext(e);
|
||||
case TConst(c):
|
||||
switch(c) {
|
||||
case CString(s, i):
|
||||
if(i) return parseExprNext(interpolateString(s));
|
||||
default:
|
||||
}
|
||||
return parseExprNext(mk(EConst(c)));
|
||||
case TPOpen:
|
||||
tk = token();
|
||||
@@ -513,6 +526,8 @@ class Parser {
|
||||
var e = parseExpr();
|
||||
isVar = false;
|
||||
return mk(EMeta(id, args, e),p1);
|
||||
case TRegex(e, f) if(allowRegex):
|
||||
return mk(ERegex(e, f), p1);
|
||||
default:
|
||||
return unexpected(tk);
|
||||
}
|
||||
@@ -589,27 +604,28 @@ class Parser {
|
||||
return switch( expr(e) ) {
|
||||
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));
|
||||
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 )
|
||||
return mk(EBinop(op,e1,e),pmin(e1),pmax(e1));
|
||||
return mk(EBinop(binop,e1,e),pmin(e1),pmax(e1));
|
||||
return switch( expr(e) ) {
|
||||
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)) )
|
||||
mk(EBinop(op2,makeBinop(op,e1,e2),e3),pmin(e1),pmax(e3));
|
||||
else
|
||||
mk(EBinop(op, e1, e), pmin(e1), pmax(e));
|
||||
mk(EBinop(binop, e1, e), pmin(e1), pmax(e));
|
||||
case ETernary(e2,e3,e4):
|
||||
if( opRightAssoc.exists(op) )
|
||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
||||
mk(EBinop(binop,e1,e),pmin(e1),pmax(e));
|
||||
else
|
||||
mk(ETernary(makeBinop(op, e1, e2), e3, e4), pmin(e1), pmax(e));
|
||||
default:
|
||||
mk(EBinop(op,e1,e),pmin(e1),pmax(e));
|
||||
mk(EBinop(binop,e1,e),pmin(e1),pmax(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -957,6 +973,16 @@ class Parser {
|
||||
var tk = token();
|
||||
push(tk);
|
||||
mk(EFunction(inf.args, inf.body, name, inf.ret, nextIsPublic, nextIsStatic, nextIsOverride, nextIsPrivate, nextIsFinal, nextIsInline),p1,pmax(inf.body));
|
||||
case "package":
|
||||
var tk = token();
|
||||
push(tk);
|
||||
if(tk == TSemicolon)
|
||||
return mk(EPackage(null), p1);
|
||||
|
||||
var pkg:String = parsePath().join('.');
|
||||
ensure(TSemicolon);
|
||||
push(TSemicolon);
|
||||
mk(EPackage(pkg), p1);
|
||||
case "import" | "using":
|
||||
var isUsing = id == "using";
|
||||
var oldReadPos = readPos;
|
||||
@@ -1021,72 +1047,62 @@ class Parser {
|
||||
}
|
||||
|
||||
case "class":
|
||||
// example: class ClassName
|
||||
var tk = token();
|
||||
var name = null;
|
||||
|
||||
switch (tk) {
|
||||
case TId(id): name = id;
|
||||
default: push(tk);
|
||||
// example: class ClassName<K, V>
|
||||
var name:String = null;
|
||||
var ct = parseType(); // this is for handling type parameters
|
||||
switch(ct) {
|
||||
case CTPath(path, params):
|
||||
name = path.join(".");
|
||||
default:
|
||||
error(EUnexpected(Std.string(ct)), p1, tokenMax);
|
||||
}
|
||||
|
||||
var extend:String = null;
|
||||
var interfaces:Array<String> = [];
|
||||
// optional - example: extends BaseClass
|
||||
|
||||
while( true ) {
|
||||
var t = token();
|
||||
switch( t ) {
|
||||
case TId("extends"):
|
||||
var e = parseType();
|
||||
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);
|
||||
if(maybe(TId("extends"))) {
|
||||
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]);
|
||||
}
|
||||
extend = buf.toString();
|
||||
default:
|
||||
push(t);
|
||||
break;
|
||||
error(ECustom('${Std.string(e)} is not a valid path.'), p1, tokenMax);
|
||||
}
|
||||
}
|
||||
|
||||
/*while(true) {
|
||||
tk = token();
|
||||
trace(tk);
|
||||
switch (tk) {
|
||||
case TId(id):
|
||||
if (id == "extends") {
|
||||
tk = token();
|
||||
if(extend != null) {
|
||||
unexpected(tk);
|
||||
} else {
|
||||
switch (tk) {
|
||||
case TId(id): extend = id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
|
||||
var interfaces:Array<String> = [];
|
||||
var tk:Token = null;
|
||||
if(maybe(TId("implements"))) {
|
||||
// handled manually for multiple implements
|
||||
while(true) {
|
||||
tk = token();
|
||||
switch(tk) {
|
||||
case TId("implements"): continue;
|
||||
case TId("extends"):
|
||||
error(ECustom('Implements must come after extends.'), p1, tokenMax);
|
||||
case TId(_):
|
||||
push(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") {
|
||||
tk = token();
|
||||
switch (tk) {
|
||||
case TId(id): interfaces.push(id);
|
||||
default: unexpected(tk);
|
||||
}
|
||||
} else {
|
||||
//push(tk);
|
||||
}
|
||||
|
||||
case TBrOpen:
|
||||
push(tk);
|
||||
break;
|
||||
|
||||
default:
|
||||
//push(tk);
|
||||
default:
|
||||
push(tk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
var fields = [];
|
||||
ensure(TBrOpen);
|
||||
@@ -1102,39 +1118,64 @@ class Parser {
|
||||
push(tk);
|
||||
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 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);
|
||||
|
||||
// TODO: optimize this
|
||||
var fields:Array<EnumField> = [];
|
||||
var fieldName:String = '';
|
||||
var enumArgs:Array<Argument> = null;
|
||||
//var tk = token();
|
||||
var fieldValue:Expr = null;
|
||||
|
||||
while(!maybe(TBrClose)) {
|
||||
var tk = token();
|
||||
|
||||
switch(tk) {
|
||||
//case TBrClose:
|
||||
// break;
|
||||
case TSemicolon | TComma:
|
||||
if(fieldName.trim().length == 0) continue;
|
||||
|
||||
fields.push({
|
||||
name: fieldName,
|
||||
args: enumArgs == null ? [] : enumArgs
|
||||
args: enumArgs == null ? [] : enumArgs,
|
||||
value: fieldValue
|
||||
});
|
||||
fieldName = '';
|
||||
enumArgs = null;
|
||||
fieldValue = null;
|
||||
case TPOpen:
|
||||
if(isAbstract) {
|
||||
error(ECustom("Enum abstract fields cannot have parameters"), tokenMin, tokenMax);
|
||||
break;
|
||||
}
|
||||
if(enumArgs != null) {
|
||||
error(ECustom("Cannot have multiple argument lists in one enum constructor"), tokenMin, tokenMax);
|
||||
break;
|
||||
}
|
||||
enumArgs = parseFunctionArgs(true);
|
||||
case TOp("="):
|
||||
if(!isAbstract) {
|
||||
error(ECustom("Only enum abstract fields can have values"), tokenMin, tokenMax);
|
||||
break;
|
||||
}
|
||||
fieldValue = parseExpr();
|
||||
default:
|
||||
if(tk.match(TId("var"))) continue;
|
||||
if(fieldName.trim().length != 0) {
|
||||
error(ECustom("Expected comma or semicolon"), tokenMin, tokenMax);
|
||||
break;
|
||||
@@ -1144,7 +1185,7 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
mk(EEnum({ name: name, fields: fields }, false), p1);
|
||||
mk(EEnum({ name: name, fields: fields, underlyingType: underlyingType }, isAbstract), p1);
|
||||
case "cast":
|
||||
var tk = token();
|
||||
var e:Expr = null;
|
||||
@@ -1160,14 +1201,15 @@ class Parser {
|
||||
e = parseExpr();
|
||||
}
|
||||
|
||||
mk(ECast(e, t));
|
||||
mk(ECast(e, t), p1);
|
||||
case "return":
|
||||
var tk = token();
|
||||
push(tk);
|
||||
var e = if( tk == TSemicolon ) null else parseExpr();
|
||||
mk(EReturn(e),p1,if( e == null ) tokenMax else pmax(e));
|
||||
case "new":
|
||||
var a = [];
|
||||
// TODO: maybe use CTPath for this
|
||||
var a:Array<String> = [];
|
||||
var params:Null<Array<CType>> = null;
|
||||
a.push(getIdent());
|
||||
while( true ) {
|
||||
@@ -1344,7 +1386,7 @@ class Parser {
|
||||
push(tk);
|
||||
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());
|
||||
case TId(op) if( opPriority.exists(op) ):
|
||||
@@ -1376,17 +1418,15 @@ class Parser {
|
||||
var done = false;
|
||||
while( !done ) {
|
||||
var name = null, opt = false;
|
||||
switch( tk ) {
|
||||
case TQuestion:
|
||||
opt = true;
|
||||
tk = token();
|
||||
default:
|
||||
if( tk == TQuestion ) {
|
||||
opt = true;
|
||||
tk = token();
|
||||
}
|
||||
switch( tk ) {
|
||||
case TId(id): name = id;
|
||||
case TId(id):
|
||||
name = id;
|
||||
default:
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
var arg : Argument = { name : name, opt: false, value: null, t: null };
|
||||
args.push(arg);
|
||||
@@ -1401,13 +1441,12 @@ class Parser {
|
||||
}
|
||||
}
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TComma:
|
||||
tk = token();
|
||||
case TPClose:
|
||||
done = true;
|
||||
default:
|
||||
unexpected(tk);
|
||||
if( tk == TComma ) {
|
||||
tk = token();
|
||||
} else if( tk == TPClose ) {
|
||||
done = true;
|
||||
} else {
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1454,31 +1493,32 @@ class Parser {
|
||||
if( op == "<" ) {
|
||||
params = [];
|
||||
while( true ) {
|
||||
switch( token() ) {
|
||||
case TConst(c):
|
||||
params.push(CTExpr(mk(EConst(c))));
|
||||
case tk:
|
||||
push(tk);
|
||||
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;
|
||||
var tt = token();
|
||||
switch( tt ) {
|
||||
case TConst(c):
|
||||
params.push(CTExpr(mk(EConst(c))));
|
||||
default:
|
||||
push(tt);
|
||||
params.push(parseType());
|
||||
}
|
||||
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
|
||||
push(t);
|
||||
default:
|
||||
@@ -1608,16 +1648,101 @@ class Parser {
|
||||
while( true ) {
|
||||
args.push(parseExpr());
|
||||
tk = token();
|
||||
switch( tk ) {
|
||||
case TComma:
|
||||
default:
|
||||
if( tk == etk ) break;
|
||||
unexpected(tk);
|
||||
break;
|
||||
}
|
||||
if( tk == etk )
|
||||
break;
|
||||
if( tk != TComma )
|
||||
unexpected(tk);
|
||||
}
|
||||
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) {
|
||||
#if hscriptPos
|
||||
@@ -1853,8 +1978,9 @@ class Parser {
|
||||
return StringTools.fastCodeAt(input, readPos++);
|
||||
}
|
||||
|
||||
function readString( until:Int ):String {
|
||||
function readString( until:Int, regex:Bool = false, interpolate:Bool = false ):String {
|
||||
var c = 0;
|
||||
var prev = 0;
|
||||
var b = new StringBuf();
|
||||
var esc = false;
|
||||
var old = line;
|
||||
@@ -1901,18 +2027,93 @@ class Parser {
|
||||
b.addChar(k);
|
||||
default: invalidChar(c);
|
||||
}
|
||||
} else if( c == 92 )
|
||||
} else if( c == 92 && !regex)
|
||||
esc = true;
|
||||
else if( c == until )
|
||||
break;
|
||||
else if( c == until ) {
|
||||
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 {
|
||||
if( c == 10 ) line++;
|
||||
b.addChar(c);
|
||||
if(regex)
|
||||
prev = c;
|
||||
}
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
function readFlags():String {
|
||||
if(!allowRegex) return null;
|
||||
var c = 0;
|
||||
var b = new StringBuf();
|
||||
var old = line;
|
||||
var s = input;
|
||||
#if hscriptPos
|
||||
var p1 = readPos - 1;
|
||||
#end
|
||||
|
||||
while(true) {
|
||||
var c = readChar();
|
||||
if( StringTools.isEof(c) ) {
|
||||
line = old;
|
||||
error(EUnterminatedString, p1, p1);
|
||||
break;
|
||||
}
|
||||
// semicolon
|
||||
if(c == 59) {
|
||||
this.char = c;
|
||||
break;
|
||||
}
|
||||
|
||||
var f = String.fromCharCode(c);
|
||||
if(regexFlags.indexOf(f) != -1)
|
||||
b.addChar(c);
|
||||
else
|
||||
invalidChar(c);
|
||||
}
|
||||
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
function token():Token {
|
||||
//function token(?infos : Null<haxe.PosInfos>) {
|
||||
//function ttrace(v:Dynamic, ?infos : Null<haxe.PosInfos>) {
|
||||
@@ -1975,7 +2176,9 @@ class Parser {
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
n = n * 10 + (char - 48);
|
||||
continue;
|
||||
case '_'.code:
|
||||
continue;
|
||||
case "e".code, "E".code:
|
||||
var tk = token();
|
||||
var pow : Null<Int> = null;
|
||||
@@ -2004,46 +2207,48 @@ class Parser {
|
||||
invalidChar(char);
|
||||
}
|
||||
exp = 1.;
|
||||
continue;
|
||||
case "x".code:
|
||||
if( n > 0 || exp > 0 )
|
||||
invalidChar(char);
|
||||
// read hexa
|
||||
var n = 0;
|
||||
var hex = 0;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
||||
n = (n << 4) + char - 48;
|
||||
case 65,66,67,68,69,70: // A-F
|
||||
n = (n << 4) + (char - 55);
|
||||
case 97,98,99,100,101,102: // a-f
|
||||
n = (n << 4) + (char - 87);
|
||||
case '_'.code:
|
||||
default:
|
||||
this.char = char;
|
||||
return TConst(CInt(n));
|
||||
if( char >= 48 && char <= 57 ) {
|
||||
hex = (hex << 4) + char - 48;
|
||||
continue;
|
||||
} else if( char >= 65 && char <= 70 ) {
|
||||
hex = (hex << 4) + char - 55;
|
||||
continue;
|
||||
} else if( char >= 97 && char <= 102 ) {
|
||||
hex = (hex << 4) + char - 87;
|
||||
continue;
|
||||
} else if( char == '_'.code ) {
|
||||
continue;
|
||||
}
|
||||
this.char = char;
|
||||
return TConst(CInt(hex));
|
||||
}
|
||||
case "b".code: // Custom thing, not supported in haxe
|
||||
if( n > 0 || exp > 0 )
|
||||
invalidChar(char);
|
||||
// read binary
|
||||
var n = 0;
|
||||
var bin = 0;
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
switch( char ) {
|
||||
case 48,49: // 0-1
|
||||
n = (n << 1) + char - 48;
|
||||
case '_'.code:
|
||||
default:
|
||||
this.char = char;
|
||||
return TConst(CInt(n));
|
||||
if( char == 48 || char == 49 ) {
|
||||
bin = (bin << 1) + char - 48;
|
||||
continue;
|
||||
} else if( char == '_'.code ) {
|
||||
continue;
|
||||
}
|
||||
this.char = char;
|
||||
return TConst(CInt(bin));
|
||||
}
|
||||
default:
|
||||
this.char = char;
|
||||
var i = Std.int(n);
|
||||
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((i == n) ? CInt(i) : CFloat(n)) );
|
||||
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : ((n % 1 == 0) ? CInt(Std.int(n)) : CFloat(n)) );
|
||||
}
|
||||
}
|
||||
case ";".code: return TSemicolon;
|
||||
@@ -2080,7 +2285,10 @@ class Parser {
|
||||
case "}".code: return TBrClose;
|
||||
case "[".code: return TBkOpen;
|
||||
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:
|
||||
char = readChar();
|
||||
switch (char) {
|
||||
@@ -2136,16 +2344,23 @@ class Parser {
|
||||
invalidChar(char);
|
||||
default:
|
||||
if( ops[char] ) {
|
||||
var op = String.fromCharCode(char);
|
||||
var buf = new StringBuf();
|
||||
buf.addChar(char);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) char = 0;
|
||||
if( !ops[char] ) {
|
||||
this.char = char;
|
||||
return TOp(op);
|
||||
return TOp(buf.toString());
|
||||
}
|
||||
var pop = buf.toString();
|
||||
buf.addChar(char);
|
||||
var op = buf.toString();
|
||||
if( allowRegex && op == "~/" ) {
|
||||
var e = readString(char, true);
|
||||
var f = readFlags();
|
||||
return TRegex(e, f);
|
||||
}
|
||||
var pop = op;
|
||||
op += String.fromCharCode(char);
|
||||
if( !opPriority.exists(op) && opPriority.exists(pop) ) {
|
||||
if( op == "//" || op == "/*" )
|
||||
return tokenComment(op,char);
|
||||
@@ -2155,16 +2370,17 @@ class Parser {
|
||||
}
|
||||
}
|
||||
if( idents[char] ) {
|
||||
var id = String.fromCharCode(char);
|
||||
var buf = new StringBuf();
|
||||
buf.addChar(char);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( StringTools.isEof(char) ) char = 0;
|
||||
if( !idents[char] ) {
|
||||
this.char = char;
|
||||
//if(id == "is") return TOp("is");
|
||||
return TId(id);
|
||||
return TId(buf.toString());
|
||||
}
|
||||
id += String.fromCharCode(char);
|
||||
buf.addChar(char);
|
||||
}
|
||||
}
|
||||
invalidChar(char);
|
||||
@@ -2187,14 +2403,16 @@ class Parser {
|
||||
push(TPOpen);
|
||||
parseExpr();
|
||||
case TId(id):
|
||||
var buf = new StringBuf();
|
||||
buf.add(id);
|
||||
while(true) {
|
||||
var tk = token();
|
||||
if(tk == TDot) {
|
||||
id += ".";
|
||||
buf.add(".");
|
||||
tk = token();
|
||||
switch(tk) {
|
||||
case TId(id2):
|
||||
id += id2;
|
||||
buf.add(id2);
|
||||
default: unexpected(tk);
|
||||
}
|
||||
} else {
|
||||
@@ -2202,9 +2420,9 @@ class Parser {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mk(EIdent(id), tokenMin, tokenMax);
|
||||
mk(EIdent(buf.toString()), tokenMin, tokenMax);
|
||||
case TOp("!"):
|
||||
mk(EUnop("!", true, parsePreproCond()), tokenMin, tokenMax);
|
||||
mk(EUnop(OpNot, true, parsePreproCond()), tokenMin, tokenMax);
|
||||
default:
|
||||
unexpected(tk);
|
||||
}
|
||||
@@ -2222,13 +2440,13 @@ class Parser {
|
||||
error(EInvalidPreprocessor("Can't eval " + expr(e).getName() + " with " + expr(e2).getName()), readPos, readPos);
|
||||
return false;
|
||||
}
|
||||
case EUnop("!", _, e):
|
||||
case EUnop(OpNot, _, e):
|
||||
return !evalPreproCond(e);
|
||||
case EParent(e):
|
||||
return evalPreproCond(e);
|
||||
case EBinop("&&", e1, e2):
|
||||
case EBinop(OpBoolAnd, e1, e2):
|
||||
return evalPreproCond(e1) && evalPreproCond(e2);
|
||||
case EBinop("||", e1, e2):
|
||||
case EBinop(OpBoolOr, e1, e2):
|
||||
return evalPreproCond(e1) || evalPreproCond(e2);
|
||||
default:
|
||||
error(EInvalidPreprocessor("Can't eval " + expr(e).getName()), readPos, readPos);
|
||||
@@ -2336,7 +2554,7 @@ class Parser {
|
||||
return switch(c) {
|
||||
case CInt(v): Std.string(v);
|
||||
case CFloat(f): Std.string(f);
|
||||
case CString(s): s; // TODO : escape + quote
|
||||
case CString(s, _): s; // TODO : escape + quote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2360,6 +2578,7 @@ class Parser {
|
||||
case TDoubleDot: ":";
|
||||
case TMeta(id): "@" + id;
|
||||
case TPrepro(id): "#" + id;
|
||||
case TRegex(e, f): '~/$e/$f';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+494
-462
@@ -1,462 +1,494 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Printer {
|
||||
|
||||
var buf : StringBuf;
|
||||
var tabs : String;
|
||||
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function exprToString( e : Expr ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
expr(e);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public function typeToString( t : CType ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
type(t);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
inline function add<T>(s:T):Void buf.add(s);
|
||||
|
||||
function type( t : CType ):Void {
|
||||
switch( t ) {
|
||||
case CTOpt(t):
|
||||
add('?');
|
||||
type(t);
|
||||
case CTPath(path, params):
|
||||
add(path.join("."));
|
||||
if( params != null ) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
case CTNamed(name, t):
|
||||
add(name);
|
||||
add(':');
|
||||
type(t);
|
||||
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||
add('(');
|
||||
for (a in args)
|
||||
switch a {
|
||||
case CTNamed(_, _): type(a);
|
||||
default: type(CTNamed('_', a));
|
||||
}
|
||||
add(')->');
|
||||
type(ret);
|
||||
case CTFun(args, ret):
|
||||
if( args.length == 0 )
|
||||
add("Void -> ");
|
||||
else {
|
||||
for( a in args ) {
|
||||
type(a);
|
||||
add(" -> ");
|
||||
}
|
||||
}
|
||||
type(ret);
|
||||
case CTAnon(fields):
|
||||
add("{");
|
||||
var first = true;
|
||||
for( f in fields ) {
|
||||
if( first ) { first = false; add(" "); } else add(", ");
|
||||
add(f.name + " : ");
|
||||
type(f.t);
|
||||
}
|
||||
add(first ? "}" : " }");
|
||||
case CTParent(t):
|
||||
add("(");
|
||||
type(t);
|
||||
add(")");
|
||||
case CTExpr(e):
|
||||
expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
function addType( t : CType ):Void {
|
||||
if( t != null ) {
|
||||
add(" : ");
|
||||
type(t);
|
||||
}
|
||||
}
|
||||
|
||||
function expr( e : Expr ):Void {
|
||||
if( e == null ) {
|
||||
add("??NULL??");
|
||||
return;
|
||||
}
|
||||
switch(Tools.expr(e)) {
|
||||
case EImport(c, n, u):
|
||||
add('${u ? 'using' : 'import'} $c');
|
||||
if(n != null)
|
||||
add(' as $n');
|
||||
case EClass(name, fields, extend, interfaces, fnal):
|
||||
var isFinal = fnal != null && fnal;
|
||||
if(isFinal)
|
||||
add('final ');
|
||||
add('class $name');
|
||||
if (extend != null)
|
||||
add(' extends $extend');
|
||||
for(_interface in interfaces) {
|
||||
add(' implements $_interface');
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for( e in fields ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
//add(";\n");
|
||||
}
|
||||
//for(field in fields) {
|
||||
// expr(field);
|
||||
//}
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case EEnum(en, _): // TODO: enum abstracts
|
||||
add('enum ${en.name}');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.args.length > 0) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in e.args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(')');
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case ECast(e, t):
|
||||
var safe = t != null;
|
||||
add("cast ");
|
||||
if(safe) add("(");
|
||||
expr(e);
|
||||
if(safe) {
|
||||
add(", ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
case EConst(c):
|
||||
switch( c ) {
|
||||
case CInt(i): add(i);
|
||||
case CFloat(f): add(f);
|
||||
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
||||
}
|
||||
case EIdent(v):
|
||||
add(v);
|
||||
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
|
||||
if(p) add("public ");
|
||||
else if(pr) add("private ");
|
||||
if(s) add("static ");
|
||||
if(isInline) add("inline ");
|
||||
if(isFinal) add("final " + n);
|
||||
else add("var " + n);
|
||||
|
||||
if(get != null || set != null) {
|
||||
add("(");
|
||||
switch(get) {
|
||||
case ADefault: add("default, ");
|
||||
case ANull: add("null, ");
|
||||
case AGet: add("get, ");
|
||||
case ADynamic: add("dynamic, ");
|
||||
case ANever: add("never, ");
|
||||
default:
|
||||
}
|
||||
switch(set) {
|
||||
case ADefault: add("default");
|
||||
case ANull: add("null");
|
||||
case ASet: add("set");
|
||||
case ADynamic: add("dynamic");
|
||||
case ANever: add("never");
|
||||
default:
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
|
||||
addType(t);
|
||||
if( e != null ) {
|
||||
add(" = ");
|
||||
expr(e);
|
||||
}
|
||||
case EParent(e):
|
||||
add("("); expr(e); add(")");
|
||||
case EBlock(el):
|
||||
if( el.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( e in el ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case EField(e, f, s):
|
||||
expr(e);
|
||||
add((s == true ? "?." : ".") + f);
|
||||
case EBinop(op, e1, e2):
|
||||
expr(e1);
|
||||
add(" " + op + " ");
|
||||
expr(e2);
|
||||
case EUnop(op, pre, e):
|
||||
if( pre ) {
|
||||
add(op);
|
||||
expr(e);
|
||||
} else {
|
||||
expr(e);
|
||||
add(op);
|
||||
}
|
||||
case ECall(e, args):
|
||||
if( e == null )
|
||||
expr(e);
|
||||
else switch( Tools.expr(e)) {
|
||||
case EField(_), EIdent(_), EConst(_):
|
||||
expr(e);
|
||||
default:
|
||||
add("(");
|
||||
expr(e);
|
||||
add(")");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(a);
|
||||
}
|
||||
add(")");
|
||||
case EIf(cond,e1,e2):
|
||||
add("if( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e1);
|
||||
if( e2 != null ) {
|
||||
add(" else ");
|
||||
expr(e2);
|
||||
}
|
||||
case EWhile(cond,e):
|
||||
add("while( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EDoWhile(cond,e):
|
||||
add("do ");
|
||||
expr(e);
|
||||
add(" while ( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
case EFor(v, it, e, ithv):
|
||||
if(ithv != null)
|
||||
add("for( "+ithv+" => "+v+" in ");
|
||||
else
|
||||
add("for( "+v+" in ");
|
||||
expr(it);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EBreak:
|
||||
add("break");
|
||||
case EContinue:
|
||||
add("continue");
|
||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||
add("function");
|
||||
if( name != null )
|
||||
add(" " + name);
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(")");
|
||||
addType(ret);
|
||||
add(" ");
|
||||
expr(e);
|
||||
case EReturn(e):
|
||||
add("return");
|
||||
if( e != null ) {
|
||||
add(" ");
|
||||
expr(e);
|
||||
}
|
||||
case EArray(e,index):
|
||||
expr(e);
|
||||
add("[");
|
||||
expr(index);
|
||||
add("]");
|
||||
case EArrayDecl(el, _):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add("]");
|
||||
case ENew(cl, args, params):
|
||||
add("new " + cl);
|
||||
if(params != null) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( e in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
case EThrow(e):
|
||||
add("throw ");
|
||||
expr(e);
|
||||
case ETry(e, v, t, ecatch):
|
||||
add("try ");
|
||||
expr(e);
|
||||
add(" catch( " + v);
|
||||
addType(t);
|
||||
add(") ");
|
||||
expr(ecatch);
|
||||
case EObject(fl):
|
||||
if( fl.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( f in fl ) {
|
||||
add(tabs);
|
||||
add(f.name+" : ");
|
||||
expr(f.e);
|
||||
add(",\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case ETernary(c,e1,e2):
|
||||
expr(c);
|
||||
add(" ? ");
|
||||
expr(e1);
|
||||
add(" : ");
|
||||
expr(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
add("switch( ");
|
||||
expr(e);
|
||||
add(") {");
|
||||
for( c in cases ) {
|
||||
add("case ");
|
||||
var first = true;
|
||||
for( v in c.values ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(v);
|
||||
}
|
||||
add(": ");
|
||||
expr(c.expr);
|
||||
add(";\n");
|
||||
}
|
||||
if( def != null ) {
|
||||
add("default: ");
|
||||
expr(def);
|
||||
add(";\n");
|
||||
}
|
||||
add("}");
|
||||
case EMeta(name, args, e):
|
||||
add("@");
|
||||
add(name);
|
||||
if( args != null && args.length > 0 ) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
case ECheckType(e, t):
|
||||
add("(");
|
||||
expr(e);
|
||||
add(" : ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
public static function toString( e : Expr ):String {
|
||||
return new Printer().exprToString(e);
|
||||
}
|
||||
|
||||
public static function errorToString( e : Expr.Error ):String {
|
||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||
case EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
#else
|
||||
return message;
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Printer {
|
||||
|
||||
var buf : StringBuf;
|
||||
var tabs : String;
|
||||
|
||||
public function new() {
|
||||
}
|
||||
|
||||
public function exprToString( e : Expr ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
expr(e);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public function typeToString( t : CType ):String {
|
||||
buf = new StringBuf();
|
||||
tabs = "";
|
||||
type(t);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
inline function add<T>(s:T):Void buf.add(s);
|
||||
|
||||
function type( t : CType ):Void {
|
||||
switch( t ) {
|
||||
case CTOpt(t):
|
||||
add('?');
|
||||
type(t);
|
||||
case CTPath(path, params):
|
||||
add(path.join("."));
|
||||
if( params != null ) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
case CTNamed(name, t):
|
||||
add(name);
|
||||
add(':');
|
||||
type(t);
|
||||
case CTFun(args, ret) if (Lambda.exists(args, function (a) return a.match(CTNamed(_, _)))):
|
||||
add('(');
|
||||
for (a in args)
|
||||
switch a {
|
||||
case CTNamed(_, _): type(a);
|
||||
default: type(CTNamed('_', a));
|
||||
}
|
||||
add(')->');
|
||||
type(ret);
|
||||
case CTFun(args, ret):
|
||||
if( args.length == 0 )
|
||||
add("Void -> ");
|
||||
else {
|
||||
for( a in args ) {
|
||||
type(a);
|
||||
add(" -> ");
|
||||
}
|
||||
}
|
||||
type(ret);
|
||||
case CTAnon(fields):
|
||||
add("{");
|
||||
var first = true;
|
||||
for( f in fields ) {
|
||||
if( first ) { first = false; add(" "); } else add(", ");
|
||||
add(f.name + " : ");
|
||||
type(f.t);
|
||||
}
|
||||
add(first ? "}" : " }");
|
||||
case CTParent(t):
|
||||
add("(");
|
||||
type(t);
|
||||
add(")");
|
||||
case CTExpr(e):
|
||||
expr(e);
|
||||
}
|
||||
}
|
||||
|
||||
function addType( t : CType ):Void {
|
||||
if( t != null ) {
|
||||
add(" : ");
|
||||
type(t);
|
||||
}
|
||||
}
|
||||
|
||||
function expr( e : Expr ):Void {
|
||||
if( e == null ) {
|
||||
add("??NULL??");
|
||||
return;
|
||||
}
|
||||
switch(Tools.expr(e)) {
|
||||
case EPackage(n):
|
||||
add('package');
|
||||
if(n != null)
|
||||
add(' $n');
|
||||
add(';\n');
|
||||
case EImport(c, n, u):
|
||||
add('${u ? 'using' : 'import'} $c');
|
||||
if(n != null)
|
||||
add(' as $n');
|
||||
case EClass(name, fields, extend, interfaces, fnal):
|
||||
var isFinal = fnal != null && fnal;
|
||||
if(isFinal)
|
||||
add('final ');
|
||||
add('class $name');
|
||||
if (extend != null)
|
||||
add(' extends $extend');
|
||||
for(_interface in interfaces) {
|
||||
add(' implements $_interface');
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for( e in fields ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
//add(";\n");
|
||||
}
|
||||
//for(field in fields) {
|
||||
// expr(field);
|
||||
//}
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case EEnum(en, isAbstract):
|
||||
if(isAbstract) {
|
||||
add('enum abstract ${en.name}(');
|
||||
if(en.underlyingType != null)
|
||||
type(en.underlyingType);
|
||||
else
|
||||
add('Int');
|
||||
add(')');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.value != null) {
|
||||
add(" = ");
|
||||
expr(e.value);
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
} else {
|
||||
add('enum ${en.name}');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.args.length > 0) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in e.args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(')');
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case ECast(e, t):
|
||||
var safe = t != null;
|
||||
add("cast ");
|
||||
if(safe) add("(");
|
||||
expr(e);
|
||||
if(safe) {
|
||||
add(", ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
case ERegex(e, f):
|
||||
add('~/$e/$f');
|
||||
add(';\n');
|
||||
case EConst(c):
|
||||
switch( c ) {
|
||||
case CInt(i): add(i);
|
||||
case CFloat(f): add(f);
|
||||
case CString(s): add('"'); add(s.split('"').join('\\"').split("\n").join("\\n").split("\r").join("\\r").split("\t").join("\\t")); add('"');
|
||||
}
|
||||
case EIdent(v):
|
||||
add(v);
|
||||
case EVar(n, t, e, p, s, pr, isFinal, isInline, get, set, _):
|
||||
if(p) add("public ");
|
||||
else if(pr) add("private ");
|
||||
if(s) add("static ");
|
||||
if(isInline) add("inline ");
|
||||
if(isFinal) add("final " + n);
|
||||
else add("var " + n);
|
||||
|
||||
if(get != null || set != null) {
|
||||
add("(");
|
||||
switch(get) {
|
||||
case ADefault: add("default, ");
|
||||
case ANull: add("null, ");
|
||||
case AGet: add("get, ");
|
||||
case ADynamic: add("dynamic, ");
|
||||
case ANever: add("never, ");
|
||||
default:
|
||||
}
|
||||
switch(set) {
|
||||
case ADefault: add("default");
|
||||
case ANull: add("null");
|
||||
case ASet: add("set");
|
||||
case ADynamic: add("dynamic");
|
||||
case ANever: add("never");
|
||||
default:
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
|
||||
addType(t);
|
||||
if( e != null ) {
|
||||
add(" = ");
|
||||
expr(e);
|
||||
}
|
||||
case EParent(e):
|
||||
add("("); expr(e); add(")");
|
||||
case EBlock(el):
|
||||
if( el.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( e in el ) {
|
||||
add(tabs);
|
||||
expr(e);
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case EField(e, f, s):
|
||||
expr(e);
|
||||
add((s == true ? "?." : ".") + f);
|
||||
case EBinop(op, e1, e2):
|
||||
expr(e1);
|
||||
add(" " + op.toString() + " ");
|
||||
expr(e2);
|
||||
case EUnop(op, pre, e):
|
||||
if( pre ) {
|
||||
add(op);
|
||||
expr(e);
|
||||
} else {
|
||||
expr(e);
|
||||
add(op);
|
||||
}
|
||||
case ECall(e, args):
|
||||
if( e == null )
|
||||
expr(e);
|
||||
else switch( Tools.expr(e)) {
|
||||
case EField(_), EIdent(_), EConst(_):
|
||||
expr(e);
|
||||
default:
|
||||
add("(");
|
||||
expr(e);
|
||||
add(")");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(a);
|
||||
}
|
||||
add(")");
|
||||
case EIf(cond,e1,e2):
|
||||
add("if( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e1);
|
||||
if( e2 != null ) {
|
||||
add(" else ");
|
||||
expr(e2);
|
||||
}
|
||||
case EWhile(cond,e):
|
||||
add("while( ");
|
||||
expr(cond);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EDoWhile(cond,e):
|
||||
add("do ");
|
||||
expr(e);
|
||||
add(" while ( ");
|
||||
expr(cond);
|
||||
add(" )");
|
||||
case EFor(v, it, e, ithv):
|
||||
if(ithv != null)
|
||||
add("for( "+ithv+" => "+v+" in ");
|
||||
else
|
||||
add("for( "+v+" in ");
|
||||
expr(it);
|
||||
add(" ) ");
|
||||
expr(e);
|
||||
case EBreak:
|
||||
add("break");
|
||||
case EContinue:
|
||||
add("continue");
|
||||
case EFunction(params, e, name, ret): // TODO: static, public, override
|
||||
add("function");
|
||||
if( name != null )
|
||||
add(" " + name);
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(")");
|
||||
addType(ret);
|
||||
add(" ");
|
||||
expr(e);
|
||||
case EReturn(e):
|
||||
add("return");
|
||||
if( e != null ) {
|
||||
add(" ");
|
||||
expr(e);
|
||||
}
|
||||
case EArray(e,index):
|
||||
expr(e);
|
||||
add("[");
|
||||
expr(index);
|
||||
add("]");
|
||||
case EArrayDecl(el, _):
|
||||
add("[");
|
||||
var first = true;
|
||||
for( e in el ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add("]");
|
||||
case ENew(cl, args, params):
|
||||
add("new " + cl);
|
||||
if(params != null) {
|
||||
add("<");
|
||||
var first = true;
|
||||
for( p in params ) {
|
||||
if( first ) first = false else add(", ");
|
||||
type(p);
|
||||
}
|
||||
add(">");
|
||||
}
|
||||
add("(");
|
||||
var first = true;
|
||||
for( e in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
case EThrow(e):
|
||||
add("throw ");
|
||||
expr(e);
|
||||
case ETry(e, v, t, ecatch):
|
||||
add("try ");
|
||||
expr(e);
|
||||
add(" catch( " + v);
|
||||
addType(t);
|
||||
add(") ");
|
||||
expr(ecatch);
|
||||
case EObject(fl):
|
||||
if( fl.length == 0 ) {
|
||||
add("{}");
|
||||
} else {
|
||||
tabs += "\t";
|
||||
add("{\n");
|
||||
for( f in fl ) {
|
||||
add(tabs);
|
||||
add(f.name+" : ");
|
||||
expr(f.e);
|
||||
add(",\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
case ETernary(c,e1,e2):
|
||||
expr(c);
|
||||
add(" ? ");
|
||||
expr(e1);
|
||||
add(" : ");
|
||||
expr(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
add("switch( ");
|
||||
expr(e);
|
||||
add(") {");
|
||||
for( c in cases ) {
|
||||
add("case ");
|
||||
var first = true;
|
||||
for( v in c.values ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(v);
|
||||
}
|
||||
add(": ");
|
||||
expr(c.expr);
|
||||
add(";\n");
|
||||
}
|
||||
if( def != null ) {
|
||||
add("default: ");
|
||||
expr(def);
|
||||
add(";\n");
|
||||
}
|
||||
add("}");
|
||||
case EMeta(name, args, e):
|
||||
add("@");
|
||||
add(name);
|
||||
if( args != null && args.length > 0 ) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
expr(e);
|
||||
}
|
||||
add(")");
|
||||
}
|
||||
add(" ");
|
||||
expr(e);
|
||||
case ECheckType(e, t):
|
||||
add("(");
|
||||
expr(e);
|
||||
add(" : ");
|
||||
addType(t);
|
||||
add(")");
|
||||
}
|
||||
}
|
||||
|
||||
public static function toString( e : Expr ):String {
|
||||
return new Printer().exprToString(e);
|
||||
}
|
||||
|
||||
public static function errorToString( e : Expr.Error ):String {
|
||||
var message = switch( #if hscriptPos e.e #else e #end ) {
|
||||
case EInvalidChar(c): "Invalid character: '"+(StringTools.isEof(c) ? "EOF (End Of File)" : String.fromCharCode(c))+"' ("+c+")";
|
||||
case EUnexpected(s): "Unexpected token: \""+s+"\"";
|
||||
case EUnterminatedString: "Unterminated string";
|
||||
case EUnterminatedComment: "Unterminated comment";
|
||||
case EInvalidPreprocessor(str): "Invalid preprocessor (" + str + ")";
|
||||
case EUnknownVariable(v): "Unknown variable: "+v;
|
||||
case EInvalidIterator(v): "Invalid iterator: "+v;
|
||||
case EInvalidOp(op): "Invalid operator: "+op;
|
||||
case EInvalidAccess(f): "Invalid access to field " + f;
|
||||
case ECustom(msg): msg;
|
||||
case EInvalidClass(cla): "Invalid class: " + cla + " was not found.";
|
||||
case EAlreadyExistingClass(cla): 'Custom Class named $cla already exists.';
|
||||
};
|
||||
#if hscriptPos
|
||||
return e.origin + ":" + e.line + ": " + message;
|
||||
#else
|
||||
return message;
|
||||
#end
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+84
-19
@@ -26,39 +26,98 @@ import hscript.Expr.FieldPropertyAccess;
|
||||
* @see https://haxe.org/manual/class-field-property.html
|
||||
*/
|
||||
@:access(hscript.Interp)
|
||||
@:structInit
|
||||
class Property {
|
||||
private static inline var GET = 'get_';
|
||||
private static inline var SET = 'set_';
|
||||
|
||||
/**
|
||||
* Name of the attached field.
|
||||
*/
|
||||
public final name:String;
|
||||
|
||||
/**
|
||||
* The current value. If isn't initialized, it's always `null`.
|
||||
*/
|
||||
public var r:Dynamic;
|
||||
public var getter:FieldPropertyAccess;
|
||||
public var setter:FieldPropertyAccess;
|
||||
|
||||
/**
|
||||
* The getter property kind
|
||||
*/
|
||||
public final getter:FieldPropertyAccess;
|
||||
|
||||
/**
|
||||
* The setter property kind
|
||||
*/
|
||||
public final setter:FieldPropertyAccess;
|
||||
|
||||
/**
|
||||
* If the field is declared as static.
|
||||
*/
|
||||
public var isStatic(get, never):Bool;
|
||||
function get_isStatic() {
|
||||
return __isStatic && interp.allowStaticVariables;
|
||||
}
|
||||
|
||||
var isVar:Bool;
|
||||
var interp:Interp;
|
||||
|
||||
public function new(r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, interp:Interp) {
|
||||
@:allow(hscript.Interp)
|
||||
private var getterFunc(get, never):String;
|
||||
private inline function get_getterFunc():String {
|
||||
return '$GET$name';
|
||||
}
|
||||
|
||||
@:allow(hscript.Interp)
|
||||
private var setterFunc(get, never):String;
|
||||
private inline function get_setterFunc():String {
|
||||
return '$SET$name';
|
||||
}
|
||||
|
||||
public function new(name:String, r:Dynamic, getter:FieldPropertyAccess, setter:FieldPropertyAccess, isVar:Bool, isStatic:Bool, interp:Interp) {
|
||||
this.name = name;
|
||||
this.r = r;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.isVar = isVar;
|
||||
this.__isStatic = isStatic;
|
||||
this.interp = interp;
|
||||
}
|
||||
|
||||
// Internal flags to gain access to the current field value (if isn't a property field)
|
||||
var __allowReadAccess:Bool = false;
|
||||
var __allowWriteAccess:Bool = false;
|
||||
var __allowSetGet:Null<Bool> = null;
|
||||
// Internal flag to gain access if the field is accessed with @:bypassAccessor
|
||||
var __allowSetGet:Bool = true;
|
||||
|
||||
public function callGetter(name:String) {
|
||||
final __isStatic:Bool = false;
|
||||
|
||||
public function get(isBypassAccessor:Bool) {
|
||||
if(isBypassAccessor) __allowSetGet = false;
|
||||
var r:Dynamic = callGetter();
|
||||
if(isBypassAccessor) __allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
public function set(value:Dynamic, isBypassAccessor:Bool) {
|
||||
if(isBypassAccessor) __allowSetGet = false;
|
||||
var r:Dynamic = callSetter(value);
|
||||
if(isBypassAccessor) __allowSetGet = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
private function callGetter():Dynamic {
|
||||
switch (getter) {
|
||||
case AGet | ADynamic:
|
||||
var fName:String = 'get_$name';
|
||||
if (!__allowReadAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) {
|
||||
if (interp.varExists(fName)) {
|
||||
var fName:String = getterFunc;
|
||||
if (!__allowReadAccess && __allowSetGet) {
|
||||
if (varExists(fName)) {
|
||||
return callAccessor(fName);
|
||||
} else
|
||||
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||
} else {
|
||||
if ((setter == ADefault || setter == ANull) || isVar)
|
||||
if ((setter == ADefault || setter == ANull) || isVar) {
|
||||
return r;
|
||||
}
|
||||
else
|
||||
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||
}
|
||||
@@ -70,18 +129,19 @@ class Property {
|
||||
return r;
|
||||
}
|
||||
|
||||
public function callSetter(name:String, val:Dynamic) {
|
||||
private function callSetter(val:Dynamic):Dynamic {
|
||||
switch (setter) {
|
||||
case ASet | ADynamic:
|
||||
var fName:String = 'set_$name';
|
||||
if (!__allowWriteAccess && (__allowSetGet != null && __allowSetGet || !interp.isBypassAccessor)) {
|
||||
if (interp.varExists(fName))
|
||||
return callAccessor(fName, [val], true);
|
||||
var fName:String = setterFunc;
|
||||
if (!__allowWriteAccess && __allowSetGet) {
|
||||
if (varExists(fName))
|
||||
return callAccessor(fName, val);
|
||||
else
|
||||
interp.error(ECustom('Method $fName required by property $name is missing'));
|
||||
} else {
|
||||
if ((getter == ADefault || getter == ANull) || isVar)
|
||||
if ((getter == ADefault || getter == ANull) || isVar) {
|
||||
return r = val;
|
||||
}
|
||||
else
|
||||
interp.error(ECustom('Field $name cannot be accessed because it is not a real variable${interp.isBypassAccessor ? '. Add @:isVar to enable it' : ''}'));
|
||||
}
|
||||
@@ -93,14 +153,15 @@ class Property {
|
||||
return r = val;
|
||||
}
|
||||
|
||||
private function callAccessor(f:String, ?args:Array<Dynamic>, isWrite:Bool = false):Dynamic {
|
||||
var fn = interp.variables.get(f);
|
||||
private function callAccessor(f:String, ?value:Dynamic):Dynamic {
|
||||
var fn = isStatic ? interp.staticVariables.get(f) : interp.variables.get(f);
|
||||
var rt:Dynamic = null;
|
||||
var isWrite:Bool = value != null;
|
||||
if (fn != null && Reflect.isFunction(fn)) {
|
||||
if (isWrite) __allowWriteAccess = true;
|
||||
else __allowReadAccess = true;
|
||||
|
||||
rt = UnsafeReflect.callMethodUnsafe(null, fn, args == null ? [] : args);
|
||||
rt = UnsafeReflect.callMethodUnsafe(null, fn, isWrite ? [value] : []);
|
||||
|
||||
if (isWrite) __allowWriteAccess = false;
|
||||
else __allowReadAccess = false;
|
||||
@@ -111,4 +172,8 @@ class Property {
|
||||
|
||||
return rt;
|
||||
}
|
||||
|
||||
private inline function varExists(n:String) {
|
||||
return isStatic ? interp.staticVariables.exists(n) : interp.variables.exists(n);
|
||||
}
|
||||
}
|
||||
|
||||
+143
-136
@@ -1,137 +1,144 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||
switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_):
|
||||
case EImport(c): f(e);
|
||||
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||
case EVar(_, _, e): if( e != null ) f(e);
|
||||
case EParent(e): f(e);
|
||||
case EBlock(el): for( e in el ) f(e);
|
||||
case EField(e, _): f(e);
|
||||
case EBinop(_, e1, e2): f(e1); f(e2);
|
||||
case EUnop(_, _, e): f(e);
|
||||
case ECall(e, args): f(e); for( a in args ) f(a);
|
||||
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
||||
case EWhile(c, e): f(c); f(e);
|
||||
case EDoWhile(c, e): f(c); f(e);
|
||||
case EFor(_, it, e): f(it); f(e);
|
||||
case EBreak,EContinue:
|
||||
case EFunction(_, e, _, _): f(e);
|
||||
case EReturn(e): if( e != null ) f(e);
|
||||
case EArray(e, i): f(e); f(i);
|
||||
case EArrayDecl(el): for( e in el ) f(e);
|
||||
case ENew(_,el): for( e in el ) f(e);
|
||||
case EThrow(e): f(e);
|
||||
case ETry(e, _, _, c): f(e); f(c);
|
||||
case EObject(fl): for( fi in fl ) f(fi.e);
|
||||
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
f(e);
|
||||
for( c in cases ) {
|
||||
for( v in c.values ) f(v);
|
||||
f(c.expr);
|
||||
}
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||
case ECheckType(e,_): f(e);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
||||
var edef = switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
||||
case EParent(e): EParent(f(e));
|
||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||
case EField(e, fi): EField(f(e),fi);
|
||||
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
||||
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
||||
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
||||
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
||||
case EWhile(c, e): EWhile(f(c),f(e));
|
||||
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||
case EArray(e, i): EArray(f(e),f(i));
|
||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||
case EThrow(e): EThrow(f(e));
|
||||
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||
case ECheckType(e,t): ECheckType(f(e), t);
|
||||
case EImport(c): EImport(c);
|
||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||
default: expr(e);
|
||||
}
|
||||
return mk(edef, e);
|
||||
}
|
||||
|
||||
public static inline function expr( e : Expr ) : ExprDef {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
||||
#if hscriptPos
|
||||
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT USE INLINE ON THIS FUNCTION
|
||||
**/
|
||||
public static function argCount(func: haxe.Constraints.Function): Int {
|
||||
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
|
||||
#if cpp
|
||||
return untyped __cpp__("{0}->__ArgCount()", func);
|
||||
#elseif js
|
||||
return untyped js.Syntax.code("{0}.length", func);
|
||||
#elseif hl
|
||||
var ft = hl.Type.getDynamic(func);
|
||||
if (ft.kind != HFun)
|
||||
return -1;
|
||||
return ft.getArgsCount();
|
||||
#else
|
||||
return -1;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
||||
return obj != null && obj is IHScriptAbstractBehaviour;
|
||||
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
import hscript.Expr;
|
||||
|
||||
class Tools {
|
||||
|
||||
public static function iter( e : Expr, f : Expr -> Void ):Void {
|
||||
switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_):
|
||||
case EImport(c): f(e);
|
||||
case EClass(_, e, _, _): for( a in e ) f(a);
|
||||
case EVar(_, _, e): if( e != null ) f(e);
|
||||
case EParent(e): f(e);
|
||||
case EBlock(el): for( e in el ) f(e);
|
||||
case EField(e, _): f(e);
|
||||
case EBinop(_, e1, e2): f(e1); f(e2);
|
||||
case EUnop(_, _, e): f(e);
|
||||
case ECall(e, args): f(e); for( a in args ) f(a);
|
||||
case EIf(c, e1, e2): f(c); f(e1); if( e2 != null ) f(e2);
|
||||
case EWhile(c, e): f(c); f(e);
|
||||
case EDoWhile(c, e): f(c); f(e);
|
||||
case EFor(_, it, e): f(it); f(e);
|
||||
case EBreak,EContinue:
|
||||
case EFunction(_, e, _, _): f(e);
|
||||
case EReturn(e): if( e != null ) f(e);
|
||||
case EArray(e, i): f(e); f(i);
|
||||
case EArrayDecl(el): for( e in el ) f(e);
|
||||
case ENew(_,el): for( e in el ) f(e);
|
||||
case EThrow(e): f(e);
|
||||
case ETry(e, _, _, c): f(e); f(c);
|
||||
case EObject(fl): for( fi in fl ) f(fi.e);
|
||||
case ETernary(c, e1, e2): f(c); f(e1); f(e2);
|
||||
case ESwitch(e, cases, def):
|
||||
f(e);
|
||||
for( c in cases ) {
|
||||
for( v in c.values ) f(v);
|
||||
f(c.expr);
|
||||
}
|
||||
if( def != null ) f(def);
|
||||
case EMeta(name, args, e): if( args != null ) for( a in args ) f(a); f(e);
|
||||
case ECheckType(e,_): f(e);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
public static function map( e : Expr, f : Expr -> Expr ):Expr {
|
||||
var edef = switch( expr(e) ) {
|
||||
case EConst(_), EIdent(_), EBreak, EContinue: expr(e);
|
||||
case EVar(n, t, e, isPublic, isStatic, isPrivate): EVar(n, t, if( e != null ) f(e) else null, isPublic, isStatic, isPrivate);
|
||||
case EParent(e): EParent(f(e));
|
||||
case EBlock(el): EBlock([for( e in el ) f(e)]);
|
||||
case EField(e, fi): EField(f(e),fi);
|
||||
case EBinop(op, e1, e2): EBinop(op, f(e1), f(e2));
|
||||
case EUnop(op, pre, e): EUnop(op, pre, f(e));
|
||||
case ECall(e, args): ECall(f(e),[for( a in args ) f(a)]);
|
||||
case EIf(c, e1, e2): EIf(f(c),f(e1),if( e2 != null ) f(e2) else null);
|
||||
case EWhile(c, e): EWhile(f(c),f(e));
|
||||
case EDoWhile(c, e): EDoWhile(f(c),f(e));
|
||||
case EFor(v, it, e): EFor(v, f(it), f(e));
|
||||
case EFunction(args, e, name, t, isPublic, isStatic, isOverride, isPrivate): EFunction(args, f(e), name, t, isPublic, isStatic, isOverride, isPrivate);
|
||||
case EReturn(e): EReturn(if( e != null ) f(e) else null);
|
||||
case EArray(e, i): EArray(f(e),f(i));
|
||||
case EArrayDecl(el): EArrayDecl([for( e in el ) f(e)]);
|
||||
case ENew(cl,el): ENew(cl,[for( e in el ) f(e)]);
|
||||
case EThrow(e): EThrow(f(e));
|
||||
case ETry(e, v, t, c): ETry(f(e), v, t, f(c));
|
||||
case EObject(fl): EObject([for( fi in fl ) { name : fi.name, e : f(fi.e) }]);
|
||||
case ETernary(c, e1, e2): ETernary(f(c), f(e1), f(e2));
|
||||
case ESwitch(e, cases, def): ESwitch(f(e), [for( c in cases ) { values : [for( v in c.values ) f(v)], expr : f(c.expr) } ], def == null ? null : f(def));
|
||||
case EMeta(name, args, e): EMeta(name, args == null ? null : [for( a in args ) f(a)], f(e));
|
||||
case ECheckType(e,t): ECheckType(f(e), t);
|
||||
case EImport(c): EImport(c);
|
||||
case EClass(name, el, extend, interfaces): EClass(name, [for( e in el ) f(e)], extend, interfaces);
|
||||
default: expr(e);
|
||||
}
|
||||
return mk(edef, e);
|
||||
}
|
||||
|
||||
public static inline function expr( e : Expr ) : ExprDef {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function mk( e : ExprDef, p : Expr ):Expr {
|
||||
#if hscriptPos
|
||||
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
|
||||
#else
|
||||
return e;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT USE INLINE ON THIS FUNCTION
|
||||
**/
|
||||
public static function argCount(func: haxe.Constraints.Function): Int {
|
||||
// https://github.com/pisayesiwsi/hscript-iris/blob/dev/crowplexus/hscript/Tools.hx#L206
|
||||
#if cpp
|
||||
return untyped __cpp__("{0}->__ArgCount()", func);
|
||||
#elseif js
|
||||
return untyped js.Syntax.code("{0}.length", func);
|
||||
#elseif hl
|
||||
var ft = hl.Type.getDynamic(func);
|
||||
if (ft.kind != HFun)
|
||||
return -1;
|
||||
return ft.getArgsCount();
|
||||
#else
|
||||
return -1;
|
||||
#end
|
||||
}
|
||||
|
||||
public static function isUppercase(s:String) {
|
||||
if(s.length == 0) return false;
|
||||
var c:Int = StringTools.fastCodeAt(s, 0);
|
||||
if(StringTools.isEof(c)) return false; // Just in case :3
|
||||
return c >= 65 && c <= 90; // A-Z
|
||||
}
|
||||
|
||||
public static inline function isCustomAbstract(obj:Dynamic):Bool
|
||||
return obj != null && obj is IHScriptAbstractBehaviour;
|
||||
|
||||
}
|
||||
@@ -12,12 +12,14 @@ using StringTools;
|
||||
|
||||
class AbstractHandler {
|
||||
public static function init() {
|
||||
#if HSCRIPT_ABSTRACT_SUPPORT
|
||||
#if !display
|
||||
if(Context.defined("display")) return;
|
||||
for(apply in Config.ALLOWED_ABSTRACT_AND_ENUM) {
|
||||
Compiler.addGlobalMetadata(apply, '@:build(hscript.macros.AbstractHandler.build())');
|
||||
}
|
||||
#end
|
||||
#end
|
||||
}
|
||||
|
||||
public static function build():Array<Field> {
|
||||
|
||||
@@ -508,8 +508,9 @@ class ClassExtendMacro {
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callGetter(name);
|
||||
return cast(v, hscript.Property).get(ba);
|
||||
return v;
|
||||
}
|
||||
else @:privateAccess {
|
||||
@@ -565,8 +566,9 @@ class ClassExtendMacro {
|
||||
if (__interp != null) {
|
||||
if(__class__fields.contains(name)) {
|
||||
var v:Dynamic = __interp.variables.get(name);
|
||||
var ba:Bool = @:privateAccess __interp.isBypassAccessor;
|
||||
if(v != null && v is hscript.Property)
|
||||
return cast(v, hscript.Property).callSetter(name, val);
|
||||
return cast(v, hscript.Property).set(val, ba);
|
||||
__interp.variables.set(name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class UsingHandler {
|
||||
usingEntries.set(name, {call: entry, fields: fields});
|
||||
}
|
||||
|
||||
public function entryExists(name:String):Bool {
|
||||
public inline function entryExists(name:String):Bool {
|
||||
return usingEntries.exists(name);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user